aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuis R. Rodriguez <mcgrof@suse.com>2015-07-09 21:24:58 -0400
committerIngo Molnar <mingo@kernel.org>2015-07-21 04:47:05 -0400
commit3cc2dac5be3f23414a4efdee0b26d79bed297cac (patch)
treeeb40eac38948fd2248611e14109d618e0db474ef
parentf55de6ec375da89f89f1a76e1b998e5f14878c06 (diff)
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: 2f9e897353fc ("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 2f9e897353fc) 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>
-rw-r--r--drivers/video/fbdev/aty/atyfb.h1
-rw-r--r--drivers/video/fbdev/aty/atyfb_base.c36
2 files changed, 14 insertions, 23 deletions
diff --git a/drivers/video/fbdev/aty/atyfb.h b/drivers/video/fbdev/aty/atyfb.h
index 1f39a62f899b..89ec4398d201 100644
--- a/drivers/video/fbdev/aty/atyfb.h
+++ b/drivers/video/fbdev/aty/atyfb.h
@@ -184,7 +184,6 @@ struct atyfb_par {
184 spinlock_t int_lock; 184 spinlock_t int_lock;
185#ifdef CONFIG_MTRR 185#ifdef CONFIG_MTRR
186 int mtrr_aper; 186 int mtrr_aper;
187 int mtrr_reg;
188#endif 187#endif
189 u32 mem_cntl; 188 u32 mem_cntl;
190 struct crtc saved_crtc; 189 struct crtc saved_crtc;
diff --git a/drivers/video/fbdev/aty/atyfb_base.c b/drivers/video/fbdev/aty/atyfb_base.c
index de8f7e082c87..7770a8485fb5 100644
--- a/drivers/video/fbdev/aty/atyfb_base.c
+++ b/drivers/video/fbdev/aty/atyfb_base.c
@@ -2630,21 +2630,13 @@ static int aty_init(struct fb_info *info)
2630 2630
2631#ifdef CONFIG_MTRR 2631#ifdef CONFIG_MTRR
2632 par->mtrr_aper = -1; 2632 par->mtrr_aper = -1;
2633 par->mtrr_reg = -1;
2634 if (!nomtrr) { 2633 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 */
2636 par->mtrr_aper = mtrr_add(par->res_start, par->res_size, 2638 par->mtrr_aper = mtrr_add(par->res_start, par->res_size,
2637 MTRR_TYPE_WRCOMB, 1); 2639 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 }
2648 } 2640 }
2649#endif 2641#endif
2650 2642
@@ -2776,10 +2768,6 @@ aty_init_exit:
2776 par->pll_ops->set_pll(info, &par->saved_pll); 2768 par->pll_ops->set_pll(info, &par->saved_pll);
2777 2769
2778#ifdef CONFIG_MTRR 2770#ifdef CONFIG_MTRR
2779 if (par->mtrr_reg >= 0) {
2780 mtrr_del(par->mtrr_reg, 0, 0);
2781 par->mtrr_reg = -1;
2782 }
2783 if (par->mtrr_aper >= 0) { 2771 if (par->mtrr_aper >= 0) {
2784 mtrr_del(par->mtrr_aper, 0, 0); 2772 mtrr_del(par->mtrr_aper, 0, 0);
2785 par->mtrr_aper = -1; 2773 par->mtrr_aper = -1;
@@ -3466,7 +3454,11 @@ static int atyfb_setup_generic(struct pci_dev *pdev, struct fb_info *info,
3466 } 3454 }
3467 3455
3468 info->fix.mmio_start = raddr; 3456 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);
3470 if (par->ati_regbase == NULL) 3462 if (par->ati_regbase == NULL)
3471 return -ENOMEM; 3463 return -ENOMEM;
3472 3464
@@ -3503,7 +3495,10 @@ static int atyfb_setup_generic(struct pci_dev *pdev, struct fb_info *info,
3503 */ 3495 */
3504 info->fix.smem_len = 0x800000; 3496 info->fix.smem_len = 0x800000;
3505 3497
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);
3507 if (info->screen_base == NULL) { 3502 if (info->screen_base == NULL) {
3508 ret = -ENOMEM; 3503 ret = -ENOMEM;
3509 goto atyfb_setup_generic_fail; 3504 goto atyfb_setup_generic_fail;
@@ -3575,6 +3570,7 @@ static int atyfb_pci_probe(struct pci_dev *pdev,
3575 return -ENOMEM; 3570 return -ENOMEM;
3576 } 3571 }
3577 par = info->par; 3572 par = info->par;
3573 par->bus_type = PCI;
3578 info->fix = atyfb_fix; 3574 info->fix = atyfb_fix;
3579 info->device = &pdev->dev; 3575 info->device = &pdev->dev;
3580 par->pci_id = pdev->device; 3576 par->pci_id = pdev->device;
@@ -3744,10 +3740,6 @@ static void atyfb_remove(struct fb_info *info)
3744#endif 3740#endif
3745 3741
3746#ifdef CONFIG_MTRR 3742#ifdef CONFIG_MTRR
3747 if (par->mtrr_reg >= 0) {
3748 mtrr_del(par->mtrr_reg, 0, 0);
3749 par->mtrr_reg = -1;
3750 }
3751 if (par->mtrr_aper >= 0) { 3743 if (par->mtrr_aper >= 0) {
3752 mtrr_del(par->mtrr_aper, 0, 0); 3744 mtrr_del(par->mtrr_aper, 0, 0);
3753 par->mtrr_aper = -1; 3745 par->mtrr_aper = -1;