Skip to content

Commit 3cc2dac

Browse files
mcgrofIngo Molnar
authored andcommitted
drivers/video/fbdev/atyfb: Replace MTRR UC hole with strong UC
Replace a WC MTRR call followed by a UC MTRR "hole" call with a single WC MTRR call and use strong UC to protect the MMIO region and account for the device's architecture and MTRR size requirements. The atyfb driver relies on two overlapping MTRRs. It does this to account for the fact that, on some devices, it has the MMIO region bundled together with the framebuffer on the same PCI BAR and the hardware requirement on MTRRs on both base and size to be powers of two. In the worst case, the PCI BAR is of 16 MiB while the MMIO region is on the last 4 KiB of the same PCI BAR. If we use just one MTRR for WC, we can only end up with an 8 MiB or 16 MiB framebuffer. Using a 16 MiB WC framebuffer area is unacceptable since we need the MMIO region to not be write-combined. An 8 MiB WC framebuffer option does not let use quite a bit of framebuffer space, it would reduce the resolution capability of the device considerably. An alternative is to use many MTRRs but on some systems that could mean not having enough MTRRs to cover the framebuffer. The current solution is to issue a 16 MiB WC MTRR followed by a 4 KiB UC MTRR on the last 4 KiB. Its worth mentioning and documenting that the current ioremap*() strategy as well: the first ioremap() is used only for the MMIO region, a second ioremap() call is used for the framebuffer *and* the MMIO region, the MMIO region then ends up mmapped twice. Two ioremap() calls are used since in some situations the framebuffer actually ends up on a separate auxiliary PCI BAR, but this is not always true. In the worst case, the PCI BAR is shared for both MMIO and the framebuffer. By allowing overlapping ioremap() calls, the driver enables two types of devices with one simple ioremap() strategy. See also: 2f9e897 ("x86/mm/mtrr, pat: Document Write Combining MTRR type effects on PAT / non-PAT pages") By default, Linux today defaults both pci_mmap_page_range() and ioremap_nocache() to use _PAGE_CACHE_MODE_UC_MINUS. On x86, ioremap() aliases ioremap_nocache(). The preferred value for Linux may soon change, however, the goal is to use _PAGE_CACHE_MODE_UC by default in the future. We can use ioremap_uc() to set PCD=1, PWT=1 on non-PAT systems and use a PAT value of UC for PAT systems. This will ensure the same settings are in place regardless of what Linux decides to use by default later and to not regress our MTRR strategy since the effective memory type will differ depending on the value used. Using a WC MTRR on such an area will be nullified. This technique can be used to protect the MMIO region in this driver's case and address the restrictions of the device's architecture as well as restrictions set upon us by powers of 2 when using MTRRs. This allows us to replace the two MTRR calls with a single 16 MiB WC MTRR and use page-attribute settings for non-PAT and PAT entry values for PAT systems to ensure the appropriate effective memory type won't have a write-combining effect on the MMIO region on both non-PAT and PAT systems. The framebuffer area will be sure to get the write-combined effective memory type by white-listing it with ioremap_wc(). We ensure the desired effective memory types are set by: 0) Using one ioremap_uc() for the MMIO region alone. This will set the page attribute settings for the MMIO region to PCD=1, PWT=1 for non-PAT systems while using a strong UC value on PAT systems. 1) Fixing the framebuffer ioremapped area to exclude the MMIO region and using ioremap_wc() instead to whitelist the area we want for write-combining. In both cases, an implementation defined (as per 2f9e897) effective memory type of WC is used for the framebuffer for non-PAT systems. Signed-off-by: Luis R. Rodriguez <mcgrof@suse.com> Signed-off-by: Borislav Petkov <bp@suse.de> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Andrzej Hajda <a.hajda@samsung.com> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Antonino Daplas <adaplas@gmail.com> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Dave Airlie <airlied@redhat.com> Cc: Davidlohr Bueso <dbueso@suse.de> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Jean-Christophe Plagniol-Villard <plagnioj@jcrosoft.com> Cc: Juergen Gross <jgross@suse.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Mathias Krause <minipli@googlemail.com> Cc: Mel Gorman <mgorman@suse.de> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Rob Clark <robdclark@gmail.com> Cc: Suresh Siddha <sbsiddha@gmail.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Tomi Valkeinen <tomi.valkeinen@ti.com> Cc: Toshi Kani <toshi.kani@hp.com> Cc: Ville Syrjälä <syrjala@sci.fi> Cc: Vlastimil Babka <vbabka@suse.cz> Cc: arnd@arndb.de Cc: benh@kernel.crashing.org Cc: dan.j.williams@intel.com Cc: geert@linux-m68k.org Cc: hch@lst.de Cc: hmh@hmh.eng.br Cc: linux-fbdev@vger.kernel.org Cc: linux-mm@kvack.org Cc: linux-pci@vger.kernel.org Cc: mpe@ellerman.id.au Cc: mst@redhat.com Cc: ralf@linux-mips.org Cc: ross.zwisler@linux.intel.com Cc: stefan.bader@canonical.com Cc: tj@kernel.org Cc: ville.syrjala@linux.intel.com Link: http://lkml.kernel.org/r/1435196060-27350-3-git-send-email-mcgrof@do-not-panic.com Link: http://lkml.kernel.org/r/1436491499-3289-4-git-send-email-mcgrof@do-not-panic.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
1 parent f55de6e commit 3cc2dac

File tree

2 files changed

+14
-23
lines changed

2 files changed

+14
-23
lines changed

drivers/video/fbdev/aty/atyfb.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,6 @@ struct atyfb_par {
184184
spinlock_t int_lock;
185185
#ifdef CONFIG_MTRR
186186
int mtrr_aper;
187-
int mtrr_reg;
188187
#endif
189188
u32 mem_cntl;
190189
struct crtc saved_crtc;

drivers/video/fbdev/aty/atyfb_base.c

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2630,21 +2630,13 @@ static int aty_init(struct fb_info *info)
26302630

26312631
#ifdef CONFIG_MTRR
26322632
par->mtrr_aper = -1;
2633-
par->mtrr_reg = -1;
26342633
if (!nomtrr) {
2635-
/* Cover the whole resource. */
2634+
/*
2635+
* Only the ioremap_wc()'d area will get WC here
2636+
* since ioremap_uc() was used on the entire PCI BAR.
2637+
*/
26362638
par->mtrr_aper = mtrr_add(par->res_start, par->res_size,
26372639
MTRR_TYPE_WRCOMB, 1);
2638-
if (par->mtrr_aper >= 0 && !par->aux_start) {
2639-
/* Make a hole for mmio. */
2640-
par->mtrr_reg = mtrr_add(par->res_start + 0x800000 -
2641-
GUI_RESERVE, GUI_RESERVE,
2642-
MTRR_TYPE_UNCACHABLE, 1);
2643-
if (par->mtrr_reg < 0) {
2644-
mtrr_del(par->mtrr_aper, 0, 0);
2645-
par->mtrr_aper = -1;
2646-
}
2647-
}
26482640
}
26492641
#endif
26502642

@@ -2776,10 +2768,6 @@ static int aty_init(struct fb_info *info)
27762768
par->pll_ops->set_pll(info, &par->saved_pll);
27772769

27782770
#ifdef CONFIG_MTRR
2779-
if (par->mtrr_reg >= 0) {
2780-
mtrr_del(par->mtrr_reg, 0, 0);
2781-
par->mtrr_reg = -1;
2782-
}
27832771
if (par->mtrr_aper >= 0) {
27842772
mtrr_del(par->mtrr_aper, 0, 0);
27852773
par->mtrr_aper = -1;
@@ -3466,7 +3454,11 @@ static int atyfb_setup_generic(struct pci_dev *pdev, struct fb_info *info,
34663454
}
34673455

34683456
info->fix.mmio_start = raddr;
3469-
par->ati_regbase = ioremap(info->fix.mmio_start, 0x1000);
3457+
/*
3458+
* By using strong UC we force the MTRR to never have an
3459+
* effect on the MMIO region on both non-PAT and PAT systems.
3460+
*/
3461+
par->ati_regbase = ioremap_uc(info->fix.mmio_start, 0x1000);
34703462
if (par->ati_regbase == NULL)
34713463
return -ENOMEM;
34723464

@@ -3503,7 +3495,10 @@ static int atyfb_setup_generic(struct pci_dev *pdev, struct fb_info *info,
35033495
*/
35043496
info->fix.smem_len = 0x800000;
35053497

3506-
info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
3498+
aty_fudge_framebuffer_len(info);
3499+
3500+
info->screen_base = ioremap_wc(info->fix.smem_start,
3501+
info->fix.smem_len);
35073502
if (info->screen_base == NULL) {
35083503
ret = -ENOMEM;
35093504
goto atyfb_setup_generic_fail;
@@ -3575,6 +3570,7 @@ static int atyfb_pci_probe(struct pci_dev *pdev,
35753570
return -ENOMEM;
35763571
}
35773572
par = info->par;
3573+
par->bus_type = PCI;
35783574
info->fix = atyfb_fix;
35793575
info->device = &pdev->dev;
35803576
par->pci_id = pdev->device;
@@ -3744,10 +3740,6 @@ static void atyfb_remove(struct fb_info *info)
37443740
#endif
37453741

37463742
#ifdef CONFIG_MTRR
3747-
if (par->mtrr_reg >= 0) {
3748-
mtrr_del(par->mtrr_reg, 0, 0);
3749-
par->mtrr_reg = -1;
3750-
}
37513743
if (par->mtrr_aper >= 0) {
37523744
mtrr_del(par->mtrr_aper, 0, 0);
37533745
par->mtrr_aper = -1;

0 commit comments

Comments
 (0)