Xudong Hao
2013-Mar-26 09:38 UTC
[PATCH v2] xen/SandyBridge: reserve pages when integrated graphics
SNB graphics devices have a bug that prevent them from accessing certain memory ranges, namely anything below 1M and in the pages listed in the table. Xen does not initialize below 1MB to heap, i.e. below 1MB pages don''t be allocated, so it''s unnecessary to reserve memory below the 1 MB mark that has not already been reserved. So reserve those pages listed in the table at xen boot if set detect a SNB gfx device on the CPU to avoid GPU hangs. Changes in v2: - using MFNs directly rather than passing a string to parse, suggestion by Jan Beulich Signed-off-by: Xudong Hao <xudong.hao@intel.com> --- xen/arch/x86/mm.c | 20 ++++++++++++++++++++ xen/common/page_alloc.c | 23 +++++++++++++++++++++++ xen/drivers/passthrough/vtd/quirks.c | 2 +- xen/include/asm-x86/mm.h | 1 + xen/include/asm-x86/pci.h | 5 +++++ 5 files changed, 50 insertions(+), 1 deletion(-) diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index add93ac..ee09b55 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -121,6 +121,7 @@ #include <xen/trace.h> #include <asm/setup.h> #include <asm/fixmap.h> +#include <asm/pci.h> /* Mapping of the fixmap space needed early. */ l1_pgentry_t __attribute__ ((__section__ (".bss.page_aligned"))) @@ -5597,6 +5598,25 @@ void arch_dump_shared_mem_info(void) mem_sharing_get_nr_saved_mfns()); } +unsigned long *__init get_platform_badpages(int *array_size) +{ + u32 igd_id; + static unsigned long __initdata bad_pages[] = { + 0x20050000, + 0x20110000, + 0x20130000, + 0x20138000, + 0x40004000, + }; + + *array_size = ARRAY_SIZE(bad_pages); + igd_id = pci_conf_read32(0, 0, 2, 0, 0); + if (!IS_SNB_GFX(igd_id)) + return NULL; + + return bad_pages; +} + /* * Local variables: * mode: C diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c index 9e9fb15..45ba327 100644 --- a/xen/common/page_alloc.c +++ b/xen/common/page_alloc.c @@ -152,6 +152,10 @@ void __init init_boot_pages(paddr_t ps, paddr_t pe) { unsigned long bad_spfn, bad_epfn; const char *p; +#ifdef CONFIG_X86 + unsigned long *badpage = NULL; + int i, array_size; +#endif ps = round_pgup(ps); pe = round_pgdown(pe); @@ -162,6 +166,25 @@ void __init init_boot_pages(paddr_t ps, paddr_t pe) bootmem_region_add(ps >> PAGE_SHIFT, pe >> PAGE_SHIFT); +#ifdef CONFIG_X86 + /* + * Here we put platform-specific memory range workarounds, i.e. + * memory known to be corrupt or otherwise in need to be reserved on + * specific platforms. + * We get these certain pages and remove them from memory region list. + */ + badpage = get_platform_badpages(&array_size); + if ( badpage ) + { + for ( i = 0; i < array_size; i++ ) + { + bootmem_region_zap(*badpage >> PAGE_SHIFT, + (*badpage >> PAGE_SHIFT) + 1); + badpage++; + } + } +#endif + /* Check new pages against the bad-page list. */ p = opt_badpage; while ( *p != ''\0'' ) diff --git a/xen/drivers/passthrough/vtd/quirks.c b/xen/drivers/passthrough/vtd/quirks.c index d79a155..70d57de 100644 --- a/xen/drivers/passthrough/vtd/quirks.c +++ b/xen/drivers/passthrough/vtd/quirks.c @@ -31,6 +31,7 @@ #include <xen/keyhandler.h> #include <asm/msi.h> #include <asm/irq.h> +#include <asm/pci.h> #include <mach_apic.h> #include "iommu.h" #include "dmar.h" @@ -47,7 +48,6 @@ #define IS_CTG(id) (id == 0x2a408086) #define IS_ILK(id) (id == 0x00408086 || id == 0x00448086 || id== 0x00628086 || id == 0x006A8086) #define IS_CPT(id) (id == 0x01008086 || id == 0x01048086) -#define IS_SNB_GFX(id) (id == 0x01068086 || id == 0x01168086 || id == 0x01268086 || id == 0x01028086 || id == 0x01128086 || id == 0x01228086 || id == 0x010A8086) static u32 __read_mostly ioh_id; static u32 __initdata igd_id; diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h index 4f89dae..8328893 100644 --- a/xen/include/asm-x86/mm.h +++ b/xen/include/asm-x86/mm.h @@ -322,6 +322,7 @@ int is_iomem_page(unsigned long mfn); void clear_superpage_mark(struct page_info *page); +unsigned long *get_platform_badpages(int *array_size); /* Per page locks: * page_lock() is used for two purposes: pte serialization, and memory sharing. * diff --git a/xen/include/asm-x86/pci.h b/xen/include/asm-x86/pci.h index 7bcb702..e0598fd 100644 --- a/xen/include/asm-x86/pci.h +++ b/xen/include/asm-x86/pci.h @@ -1,6 +1,11 @@ #ifndef __X86_PCI_H__ #define __X86_PCI_H__ +#define IS_SNB_GFX(id) (id == 0x01068086 || id == 0x01168086 \ + || id == 0x01268086 || id == 0x01028086 \ + || id == 0x01128086 || id == 0x01228086 \ + || id == 0x010A8086 ) + struct arch_pci_dev { vmask_t used_vectors; }; -- 1.7.12.1
Jan Beulich
2013-Mar-26 09:40 UTC
Re: [PATCH v2] xen/SandyBridge: reserve pages when integrated graphics
>>> On 26.03.13 at 10:38, Xudong Hao <xudong.hao@intel.com> wrote: > SNB graphics devices have a bug that prevent them from accessing certain > memory ranges, namely anything below 1M and in the pages listed in the > table. > > Xen does not initialize below 1MB to heap, i.e. below 1MB pages don''t be > allocated, so it''s unnecessary to reserve memory below the 1 MB mark > that has not already been reserved. > > So reserve those pages listed in the table at xen boot if set detect a > SNB gfx device on the CPU to avoid GPU hangs. > > Changes in v2: > - using MFNs directly rather than passing a string to parse, suggestion by Jan > Beulich > > Signed-off-by: Xudong Hao <xudong.hao@intel.com>Looks good to me, but needs an ack from Keir. Jan
Keir Fraser
2013-Mar-26 11:15 UTC
Re: [PATCH v2] xen/SandyBridge: reserve pages when integrated graphics
On 26/03/2013 09:38, "Xudong Hao" <xudong.hao@intel.com> wrote:> SNB graphics devices have a bug that prevent them from accessing certain > memory ranges, namely anything below 1M and in the pages listed in the > table. > > Xen does not initialize below 1MB to heap, i.e. below 1MB pages don''t be > allocated, so it''s unnecessary to reserve memory below the 1 MB mark > that has not already been reserved. > > So reserve those pages listed in the table at xen boot if set detect a > SNB gfx device on the CPU to avoid GPU hangs. > > Changes in v2: > - using MFNs directly rather than passing a string to parse, suggestion by Jan > Beulich > > Signed-off-by: Xudong Hao <xudong.hao@intel.com>Acked-by: Keir Fraser <keir@xen.org>> --- > xen/arch/x86/mm.c | 20 ++++++++++++++++++++ > xen/common/page_alloc.c | 23 +++++++++++++++++++++++ > xen/drivers/passthrough/vtd/quirks.c | 2 +- > xen/include/asm-x86/mm.h | 1 + > xen/include/asm-x86/pci.h | 5 +++++ > 5 files changed, 50 insertions(+), 1 deletion(-) > > diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c > index add93ac..ee09b55 100644 > --- a/xen/arch/x86/mm.c > +++ b/xen/arch/x86/mm.c > @@ -121,6 +121,7 @@ > #include <xen/trace.h> > #include <asm/setup.h> > #include <asm/fixmap.h> > +#include <asm/pci.h> > > /* Mapping of the fixmap space needed early. */ > l1_pgentry_t __attribute__ ((__section__ (".bss.page_aligned"))) > @@ -5597,6 +5598,25 @@ void arch_dump_shared_mem_info(void) > mem_sharing_get_nr_saved_mfns()); > } > > +unsigned long *__init get_platform_badpages(int *array_size) > +{ > + u32 igd_id; > + static unsigned long __initdata bad_pages[] = { > + 0x20050000, > + 0x20110000, > + 0x20130000, > + 0x20138000, > + 0x40004000, > + }; > + > + *array_size = ARRAY_SIZE(bad_pages); > + igd_id = pci_conf_read32(0, 0, 2, 0, 0); > + if (!IS_SNB_GFX(igd_id)) > + return NULL; > + > + return bad_pages; > +} > + > /* > * Local variables: > * mode: C > diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c > index 9e9fb15..45ba327 100644 > --- a/xen/common/page_alloc.c > +++ b/xen/common/page_alloc.c > @@ -152,6 +152,10 @@ void __init init_boot_pages(paddr_t ps, paddr_t pe) > { > unsigned long bad_spfn, bad_epfn; > const char *p; > +#ifdef CONFIG_X86 > + unsigned long *badpage = NULL; > + int i, array_size; > +#endif > > ps = round_pgup(ps); > pe = round_pgdown(pe); > @@ -162,6 +166,25 @@ void __init init_boot_pages(paddr_t ps, paddr_t pe) > > bootmem_region_add(ps >> PAGE_SHIFT, pe >> PAGE_SHIFT); > > +#ifdef CONFIG_X86 > + /* > + * Here we put platform-specific memory range workarounds, i.e. > + * memory known to be corrupt or otherwise in need to be reserved on > + * specific platforms. > + * We get these certain pages and remove them from memory region list. > + */ > + badpage = get_platform_badpages(&array_size); > + if ( badpage ) > + { > + for ( i = 0; i < array_size; i++ ) > + { > + bootmem_region_zap(*badpage >> PAGE_SHIFT, > + (*badpage >> PAGE_SHIFT) + 1); > + badpage++; > + } > + } > +#endif > + > /* Check new pages against the bad-page list. */ > p = opt_badpage; > while ( *p != ''\0'' ) > diff --git a/xen/drivers/passthrough/vtd/quirks.c > b/xen/drivers/passthrough/vtd/quirks.c > index d79a155..70d57de 100644 > --- a/xen/drivers/passthrough/vtd/quirks.c > +++ b/xen/drivers/passthrough/vtd/quirks.c > @@ -31,6 +31,7 @@ > #include <xen/keyhandler.h> > #include <asm/msi.h> > #include <asm/irq.h> > +#include <asm/pci.h> > #include <mach_apic.h> > #include "iommu.h" > #include "dmar.h" > @@ -47,7 +48,6 @@ > #define IS_CTG(id) (id == 0x2a408086) > #define IS_ILK(id) (id == 0x00408086 || id == 0x00448086 || id=> 0x00628086 || id == 0x006A8086) > #define IS_CPT(id) (id == 0x01008086 || id == 0x01048086) > -#define IS_SNB_GFX(id) (id == 0x01068086 || id == 0x01168086 || id => 0x01268086 || id == 0x01028086 || id == 0x01128086 || id == 0x01228086 || id > == 0x010A8086) > > static u32 __read_mostly ioh_id; > static u32 __initdata igd_id; > diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h > index 4f89dae..8328893 100644 > --- a/xen/include/asm-x86/mm.h > +++ b/xen/include/asm-x86/mm.h > @@ -322,6 +322,7 @@ int is_iomem_page(unsigned long mfn); > > void clear_superpage_mark(struct page_info *page); > > +unsigned long *get_platform_badpages(int *array_size); > /* Per page locks: > * page_lock() is used for two purposes: pte serialization, and memory > sharing. > * > diff --git a/xen/include/asm-x86/pci.h b/xen/include/asm-x86/pci.h > index 7bcb702..e0598fd 100644 > --- a/xen/include/asm-x86/pci.h > +++ b/xen/include/asm-x86/pci.h > @@ -1,6 +1,11 @@ > #ifndef __X86_PCI_H__ > #define __X86_PCI_H__ > > +#define IS_SNB_GFX(id) (id == 0x01068086 || id == 0x01168086 \ > + || id == 0x01268086 || id == 0x01028086 \ > + || id == 0x01128086 || id == 0x01228086 \ > + || id == 0x010A8086 ) > + > struct arch_pci_dev { > vmask_t used_vectors; > };