"big box" x86 changes
Subsystems (10)
Linus,
the following tree contains the "big box" topic commits of x86.git:
git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86-bigbox.git for-linus
Most of the work has been done by Yinghai Lu who has gone through a heroic effort to fix all the big-box bugs that he encountered on the vanilla Linux kernel on his various up to 256 GB RAM test-systems. Also work is included from Ying Huang for those insane SGI UV boxes.
Most of these patches have been carried in x86.git since around v2.6.23 so they have a good track record in terms of "practical" stability. They have not been problem-free - the tree reflects most of those iterations and fixes that happened in that ~6 months timeframe of testing. They do solve a boatload of problems and inefficiencies on those systems.
Due to the nature of this topic the commits are all across bootmem, driver core and other subsystems - but most of them (obviously) affect arch/x86 - which is why they have been carried there.
The sub-topic that looks most scary in this lot are the mmconf changes that start with this one:
Robert Hancock (1):
x86: validate against acpi motherboard resources
Note that these are not the same changes that you rejected in the past, Yinghai has done a number of delta patches to that to make it more practical and palatable ... i hope. It's still ... somewhat problematic and might still be rejectable.
Another one is the mmconfig enablement in the CPU on Family 10 Opterons is turned into an optional, DMI-driven thing in one of the later patches so that is a lot less scary than it looks - it's still a generic PC and thus tons better than all those crazy subarch hacks that people ended up doing.
So we need a bit of help wrt. how mergable this is, and what else is needed to make it mergable. These changes have been booted all across the x86 spectrum, small and large boxes alike, so i'd be seriously surprised if they caused any widespread breakage.
Ingo
------------------>
Huang, Ying (4):
x86, boot: add free_early to early reservation machanism x86, boot: add linked list of struct setup_data x86, boot: export linked list of struct setup_data via debugfs x86, boot: Document for linked list of struct setup_data
Ingo Molnar (2):
x86: fix k8-bus_64.c build
x86: sanity check gart for buggy device, fix
Robert Hancock (1):
x86: validate against acpi motherboard resources
Yinghai Lu (39):
mm: make mem_map allocation continuous
mm: fix alloc_bootmem_core to use fast searching for all nodes
x86: clear pci_mmcfg_virt when mmcfg get rejected
x86: mmconf enable mcfg early
x86_64: set cfg_size for AMD Family 10h in case MMCONFIG
x86_64: check and enable MMCONFIG for AMD Family 10h
x86_64: check MSR to get MMCONFIG for AMD Family 10h
x86: if acpi=off, force setting the mmconf for fam10h
x86: seperate mmconf for fam10h out from setup_64.c
driver core: try parent numa_node at first before using default
x86: skip it if Fam 10h only handle bus 0
ide: use dev_to_node instead of pcibus_to_node
x86: remove unneeded check in mmconf reject
mm: offset align in alloc_bootmem()
mm: allow reserve_bootmem() cross nodes
x86_64: make reserve_bootmem_generic() use new reserve_bootmem()
x86_64: fix setup_node_bootmem to support big mem excluding with memmap x86 pci: remove checking type for mmconfig probe
x86: change pci_direct_conf1 back not static
x86: get mp_bus_to_node early
x86: use bus conf in NB conf fun1 to get bus range on, on 64-bit
x86: multi pci root bus with different io resource range, on 64-bit x86/acpi: make dev_to_node return online node
x86: double check the multi root bus with fam10h mmconf x86/pci: add pci=skip_isa_align command lines.
net: use numa_node in net_devcice->dev instead of parent
x86_64: don't need set default res if only have one root bus x86_64/mm: check and print vmemmap allocation continuous x86_64/mm: check and print vmemmap allocation continuous -fix
acpi: get boot_cpu_id as early for k8_scan_nodes
x86: work around io allocation overlap of HT links
x86: agp_gart size checking for buggy device
x86: checking aperture size order
x86: add pci=check_enable_amd_mmconf and dmi check
x86 PCI: call dmi_check_pciprobe()
x86_64: allocate gart aperture from 512M
x86: don't call pxm_to_node again
x86: clean up aperture_64.c
x86: reserve dma32 early for gart -fix
Documentation/i386/boot.txt | 26 ++ Documentation/kernel-parameters.txt | 2 + arch/x86/boot/header.S | 6 +- arch/x86/kernel/Makefile | 2 + arch/x86/kernel/acpi/boot.c | 70 +++++ arch/x86/kernel/aperture_64.c | 283 ++++++++++++------ arch/x86/kernel/e820_64.c | 35 ++- arch/x86/kernel/head64.c | 20 ++ arch/x86/kernel/kdebugfs.c | 163 ++++++++++- arch/x86/kernel/mmconf-fam10h_64.c | 243 +++++++++++++++ arch/x86/kernel/pci-dma.c | 11 +- arch/x86/kernel/setup_64.c | 47 +++- arch/x86/mm/init_64.c | 38 ++- arch/x86/mm/k8topology_64.c | 38 +++- arch/x86/mm/numa_64.c | 43 +++- arch/x86/pci/Makefile_32 | 1 + arch/x86/pci/Makefile_64 | 2 +- arch/x86/pci/acpi.c | 81 ++---- arch/x86/pci/common.c | 76 +++++- arch/x86/pci/direct.c | 8 +- arch/x86/pci/fixup.c | 17 + arch/x86/pci/init.c | 17 +- arch/x86/pci/irq.c | 4 +- arch/x86/pci/k8-bus_64.c | 580 +++++++++++++++++++++++++++++++---- arch/x86/pci/legacy.c | 4 +- arch/x86/pci/mmconfig-shared.c | 252 +++++++++++++-- arch/x86/pci/mmconfig_32.c | 4 + arch/x86/pci/mmconfig_64.c | 22 ++- arch/x86/pci/mp_bus_to_node.c | 23 ++ arch/x86/pci/pci.h | 6 +- drivers/acpi/bus.c | 2 + drivers/base/core.c | 14 +- drivers/char/agp/amd64-agp.c | 21 +- drivers/pci/probe.c | 21 ++- include/asm-x86/bootparam.h | 14 + include/asm-x86/e820_64.h | 3 +- include/asm-x86/pci.h | 2 + include/asm-x86/topology.h | 16 + include/linux/acpi.h | 5 + include/linux/ide.h | 3 +- include/linux/mm.h | 1 + include/linux/pci.h | 11 +- mm/bootmem.c | 157 +++++++--- mm/sparse.c | 37 ++- net/core/skbuff.c | 2 +- 45 files changed, 2071 insertions(+), 362 deletions(-) create mode 100644 arch/x86/kernel/mmconf-fam10h_64.c create mode 100644 arch/x86/pci/mp_bus_to_node.c
Documentation/i386/boot.txt +26 -0
@@ -42,6 +42,8 @@ Protocol 2.05: (Kernel 2.6.20) Make protected mode kernel relocatable. Protocol 2.06: (Kernel 2.6.22) Added a field that contains the size of the boot command line +Protocol 2.09: (kernel 2.6.26) Added a field of 64-bit physical + pointer to single linked list of struct setup_data. **** MEMORY LAYOUT
@@ -172,6 +174,8 @@ Offset Proto Name Meaning 0240/8 2.07+ hardware_subarch_data Subarchitecture-specific data 0248/4 2.08+ payload_offset Offset of kernel payload 024C/4 2.08+ payload_length Length of kernel payload +0250/8 2.09+ setup_data 64-bit physical pointer to linked list + of struct setup_data (1) For backwards compatibility, if the setup_sects field contains 0, the real value is 4.
@@ -572,6 +576,28 @@ command line is entered using the following protocol: covered by setup_move_size, so you may need to adjust this field. +Field name: setup_data +Type: write (obligatory) +Offset/size: 0x250/8 +Protocol: 2.09+ + + The 64-bit physical pointer to NULL terminated single linked list of + struct setup_data. This is used to define a more extensible boot + parameters passing mechanism. The definition of struct setup_data is + as follow: + + struct setup_data { + u64 next; + u32 type; + u32 len; + u8 data[0]; + }; + + Where, the next is a 64-bit physical pointer to the next node of + linked list, the next field of the last node is 0; the type is used + to identify the contents of data; the len is the length of data + field; the data holds the real payload. + **** MEMORY LAYOUT OF THE REAL-MODE CODE
Documentation/kernel-parameters.txt +2 -0
@@ -1516,6 +1516,8 @@ and is between 256 and 4096 characters. It is defined in the file This is normally done in pci_enable_device(), so this option is a temporary workaround for broken drivers that don't call it. + skip_isa_align [X86] do not align io start addr, so can + handle more pci cards firmware [ARM] Do not re-enumerate the bus but instead just use the configuration from the bootloader. This is currently used on
arch/x86/boot/header.S +5 -1
@@ -120,7 +120,7 @@ _start: # Part 2 of the header, from the old setup.S .ascii "HdrS" # header signature - .word 0x0208 # header version number (>= 0x0105) + .word 0x0209 # header version number (>= 0x0105) # or else old loadlin-1.5 will fail) .globl realmode_swtch realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
@@ -227,6 +227,10 @@ hardware_subarch_data: .quad 0 payload_offset: .long input_data payload_length: .long input_data_end-input_data +setup_data: .quad 0 # 64-bit physical pointer to + # single linked list of + # struct setup_data + # End of setup header ##################################################### .section ".inittext", "ax"
arch/x86/kernel/Makefile +2 -0
@@ -99,4 +99,6 @@ ifeq ($(CONFIG_X86_64),y) obj-$(CONFIG_GART_IOMMU) += pci-gart_64.o aperture_64.o obj-$(CONFIG_CALGARY_IOMMU) += pci-calgary_64.o tce_64.o obj-$(CONFIG_SWIOTLB) += pci-swiotlb_64.o + + obj-$(CONFIG_PCI_MMCONFIG) += mmconf-fam10h_64.o endif
arch/x86/kernel/acpi/boot.c +70 -0
88 lines not on this page · raw message
arch/x86/kernel/aperture_64.c +191 -92
451 lines not on this page · raw message
arch/x86/kernel/e820_64.c +31 -4
@@ -84,14 +84,41 @@ void __init reserve_early(unsigned long start, unsigned long end, char *name)strncpy (r->name, name,sizeof (r->name) -1 ); } -void __init early_res_to_bootmem (void ) +void __init free_early (unsigned long start,unsigned long end) +{ +struct early_res *r; +int i, j; + +for (i =0 ; i <MAX_EARLY_RES && early_res[i].end; i++) { + r = &early_res[i]; +if (start == r->start && end == r->end) +break ; + } +if (i >=MAX_EARLY_RES || !early_res[i].end) +panic ("free_early on not reserved area: %lx-%lx!" , start, end); + +for (j = i +1 ; j <MAX_EARLY_RES && early_res[j].end; j++) + ; + +memcpy (&early_res[i], &early_res[i +1 ], + (j -1 - i) *sizeof (struct early_res )); + + early_res[j -1 ].end =0 ; +} + +void __init early_res_to_bootmem (unsigned long start,unsigned long end) {int i; +unsigned long final_start, final_end;for (i =0 ; i <MAX_EARLY_RES && early_res[i].end; i++) {struct early_res *r = &early_res[i]; -printk (KERN_INFO "early res: %d [%lx-%lx] %s\n" , i, - r->start, r->end -1 , r->name); -reserve_bootmem_generic (r->start, r->end - r->start); + final_start =max (start, r->start); + final_end =min (end, r->end); +if (final_start >= final_end) +continue ; +printk (KERN_INFO " early res: %d [%lx-%lx] %s\n" , i, + final_start, final_end -1 , r->name); +reserve_bootmem_generic (final_start, final_end - final_start); } }
arch/x86/kernel/head64.c +20 -0
@@ -11,6 +11,7 @@#include <linux/string.h> #include <linux/percpu.h> #include <linux/start_kernel.h> +#include <linux/io.h> #include <asm/processor.h> #include <asm/proto.h>
@@ -100,6 +101,24 @@ static void __init reserve_ebda_region(void)reserve_early (lowmem,0x100000 ,"BIOS reserved" ); } +static void __init reserve_setup_data (void ) +{ +struct setup_data *data; +unsigned long pa_data; +char buf[32 ]; + +if (boot_params.hdr.version <0x0209 ) +return ; + pa_data = boot_params.hdr.setup_data; +while (pa_data) { + data =early_ioremap (pa_data,sizeof (*data)); +sprintf (buf,"setup data %x" , data->type); +reserve_early (pa_data, pa_data+sizeof (*data)+data->len, buf); + pa_data = data->next; +early_iounmap (data,sizeof (*data)); + } +} +void __init x86_64_start_kernel (char * real_mode_data) {int i;
@@ -156,6 +175,7 @@ void __init x86_64_start_kernel(char * real_mode_data)#endif reserve_ebda_region (); +reserve_setup_data ();/* * At this point everything still needed from the boot loader
arch/x86/kernel/kdebugfs.c +158 -5
193 lines not on this page · raw message
arch/x86/kernel/mmconf-fam10h_64.c new file +243 -0
243 lines not on this page · raw message
arch/x86/kernel/pci-dma.c +6 -5
@@ -77,10 +77,14 @@ void __init dma32_reserve_bootmem(void)if (end_pfn <=MAX_DMA32_PFN )return ; +/* +* check aperture_64.c allocate_aperture() for reason about +* using 512M as goal +*/ align =64ULL <<20 ; size =round_up (dma32_bootmem_size, align); dma32_bootmem_ptr =__alloc_bootmem_nopanic (size, align, -__pa (MAX_DMA_ADDRESS )); +512ULL <<20 );if (dma32_bootmem_ptr) dma32_bootmem_size = size;else
@@ -88,7 +92,6 @@ void __init dma32_reserve_bootmem(void) }static void __init dma32_free_bootmem (void ) { -int node;if (end_pfn <=MAX_DMA32_PFN )return ;
@@ -96,9 +99,7 @@ static void __init dma32_free_bootmem(void)if (!dma32_bootmem_ptr)return ; -for_each_online_node (node) -free_bootmem_node (NODE_DATA (node),__pa (dma32_bootmem_ptr), - dma32_bootmem_size); +free_bootmem (__pa (dma32_bootmem_ptr), dma32_bootmem_size); dma32_bootmem_ptr =NULL ; dma32_bootmem_size =0 ;
arch/x86/kernel/setup_64.c +45 -2
95 lines not on this page · raw message
arch/x86/mm/init_64.c +33 -5
@@ -810,7 +810,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)void __init reserve_bootmem_generic (unsigned long phys,unsigned len) {#ifdef CONFIG_NUMA -int nid =phys_to_nid (phys); +int nid, next_nid;#endif unsigned long pfn = phys >>PAGE_SHIFT ;
@@ -829,10 +829,14 @@ void __init reserve_bootmem_generic(unsigned long phys, unsigned len)/* Should check here against the e820 map to avoid double free */ #ifdef CONFIG_NUMA + nid =phys_to_nid (phys); + next_nid =phys_to_nid (phys + len -1 ); +if (nid == next_nid)reserve_bootmem_node (NODE_DATA (nid), phys, len,BOOTMEM_DEFAULT ); -#else -reserve_bootmem (phys, len,BOOTMEM_DEFAULT ); + else#endif +reserve_bootmem (phys, len,BOOTMEM_DEFAULT ); +if (phys+len <=MAX_DMA_PFN *PAGE_SIZE ) { dma_reserve += len /PAGE_SIZE ;set_dma_reserve (dma_reserve);
@@ -926,6 +930,10 @@ const char *arch_vma_name(struct vm_area_struct *vma)/* * Initialise the sparsemem vmemmap using huge-pages at the PMD level. */ +static long __meminitdata addr_start, addr_end; +static void __meminitdata *p_start, *p_end; +static int __meminitdata node_start; +int __meminit vmemmap_populate (struct page *start_page,unsigned long size,int node) {
@@ -960,12 +968,32 @@ vmemmap_populate(struct page *start_page, unsigned long size, int node) PAGE_KERNEL_LARGE);set_pmd (pmd,__pmd (pte_val (entry))); -printk (KERN_DEBUG " [%lx-%lx] PMD ->%p on node %d\n" , - addr, addr + PMD_SIZE - 1, p, node); +/* check to see if we have contiguous blocks */ +if (p_end != p || node_start != node) { +if (p_start) +printk (KERN_DEBUG " [%lx-%lx] PMD -> [%p-%p] on node %d\n" , + addr_start, addr_end-1 , p_start, p_end-1 , node_start); + addr_start = addr; + node_start = node; + p_start = p; + } + addr_end = addr +PMD_SIZE ; + p_end = p + PMD_SIZE; }else {vmemmap_verify ((pte_t *)pmd, node, addr, next); } }return 0 ; } + +void __meminit vmemmap_populate_print_last (void ) +{ +if (p_start) { +printk (KERN_DEBUG " [%lx-%lx] PMD -> [%p-%p] on node %d\n" , + addr_start, addr_end-1 , p_start, p_end-1 , node_start); + p_start =NULL ; + p_end =NULL ; + node_start =0 ; + } +}#endif
arch/x86/mm/k8topology_64.c +37 -1
@@ -13,12 +13,15 @@#include <linux/nodemask.h> #include <asm/io.h> #include <linux/pci_ids.h> +#include <linux/acpi.h> #include <asm/types.h> #include <asm/mmzone.h> #include <asm/proto.h> #include <asm/e820.h> #include <asm/pci-direct.h> #include <asm/numa.h> +#include <asm/mpspec.h> +#include <asm/apic.h> static __init int find_northbridge (void ) {
@@ -44,6 +47,30 @@ static __init int find_northbridge(void)return -1 ; } +static __init void early_get_boot_cpu_id (void ) +{ +/* +* need to get boot_cpu_id so can use that to create apicid_to_node +* in k8_scan_nodes() +*/ +/* +* Find possible boot-time SMP configuration: +*/ +early_find_smp_config (); +#ifdef CONFIG_ACPI +/* +* Read APIC information from ACPI tables. +*/ +early_acpi_boot_init (); +#endif +/* +* get boot-time SMP configuration: +*/ +if (smp_found_config) +early_get_smp_config (); +early_init_lapic_mapping (); +} +int __init k8_scan_nodes (unsigned long start,unsigned long end) {unsigned long prevbase;
@@ -56,6 +83,7 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)unsigned cores;unsigned bits;int j; +unsigned apicid_base;if (!early_pci_allowed ())return -1 ;
@@ -174,11 +202,19 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)/* use the coreid bits from early_identify_cpu */ bits = boot_cpu_data.x86_coreid_bits; cores = (1 <<bits); + apicid_base =0 ; +/* need to get boot_cpu_id early for system with apicid lifting */ +early_get_boot_cpu_id (); +if (boot_cpu_physical_apicid >0 ) { +printk (KERN_INFO "BSP APIC ID: %02x\n" , + boot_cpu_physical_apicid); + apicid_base = boot_cpu_physical_apicid; + }for (i =0 ; i <8 ; i++) {if (nodes[i].start != nodes[i].end) { nodeid = nodeids[i]; -for (j =0 ; j < cores; j++) +for (j = apicid_base; j < cores + apicid_base; j++) apicid_to_node[(nodeid << bits) + j] = i;setup_node_bootmem (i, nodes[i].start, nodes[i].end); }
arch/x86/mm/numa_64.c +37 -6
62 lines not on this page · raw message
arch/x86/pci/Makefile_32 +1 -0
@@ -10,5 +10,6 @@ pci-y += legacy.o irq.o pci-$(CONFIG_X86_VISWS) := visws.o fixup.o pci-$(CONFIG_X86_NUMAQ) := numa.o irq.o +pci-$(CONFIG_NUMA) += mp_bus_to_node.o obj-y += $(pci-y) common.o early.o
arch/x86/pci/Makefile_64 +1 -1
@@ -13,5 +13,5 @@ obj-y += legacy.o irq.o common.o early.o # mmconfig has a 64bit special obj-$(CONFIG_PCI_MMCONFIG) += mmconfig_64.o direct.o mmconfig-shared.o -obj-$(CONFIG_NUMA) += k8-bus_64.o +obj-y += k8-bus_64.o
arch/x86/pci/acpi.c +26 -55
117 lines not on this page · raw message
arch/x86/pci/common.c +70 -6
127 lines not on this page · raw message
arch/x86/pci/direct.c +5 -3
@@ -258,7 +258,8 @@ void __init pci_direct_init(int type) {if (type ==0 )return ; -printk (KERN_INFO "PCI: Using configuration type %d\n" , type); +printk (KERN_INFO "PCI: Using configuration type %d for base access\n" , + type);if (type ==1 ) raw_pci_ops = &pci_direct_conf1;else
@@ -275,8 +276,10 @@ int __init pci_direct_probe(void)if (!region) goto type2; -if (pci_check_type1 ()) +if (pci_check_type1 ()) { + raw_pci_ops = &pci_direct_conf1;return 1 ; + }release_resource (region); type2:
@@ -290,7 +293,6 @@ int __init pci_direct_probe(void) goto fail2;if (pci_check_type2 ()) { -printk (KERN_INFO "PCI: Using configuration type 2\n" ); raw_pci_ops = &pci_direct_conf2;return 2 ; }
arch/x86/pci/fixup.c +17 -0
@@ -493,3 +493,20 @@ static void __devinit pci_siemens_interrupt_controller(struct pci_dev *dev) }DECLARE_PCI_FIXUP_HEADER (PCI_VENDOR_ID_SIEMENS ,0x0015 , pci_siemens_interrupt_controller); + +/* +* Regular PCI devices have 256 bytes, but AMD Family 10h Opteron ext config +* have 4096 bytes. Even if the device is capable, that doesn't mean we can +* access it. Maybe we don't have a way to generate extended config space +* accesses. So check it +*/ +static void fam10h_pci_cfg_space_size (struct pci_dev *dev) +{ + dev->cfg_size =pci_cfg_space_size_ext (dev,0 ); +} + +DECLARE_PCI_FIXUP_HEADER (PCI_VENDOR_ID_AMD ,0x1200 , fam10h_pci_cfg_space_size); +DECLARE_PCI_FIXUP_HEADER (PCI_VENDOR_ID_AMD ,0x1201 , fam10h_pci_cfg_space_size); +DECLARE_PCI_FIXUP_HEADER (PCI_VENDOR_ID_AMD ,0x1202 , fam10h_pci_cfg_space_size); +DECLARE_PCI_FIXUP_HEADER (PCI_VENDOR_ID_AMD ,0x1203 , fam10h_pci_cfg_space_size); +DECLARE_PCI_FIXUP_HEADER (PCI_VENDOR_ID_AMD ,0x1204 , fam10h_pci_cfg_space_size);
arch/x86/pci/init.c +9 -8
@@ -6,16 +6,13 @@in the right sequence from here. */ static __init int pci_access_init (void ) { -int type__maybe_unused =0 ; -#ifdef CONFIG_PCI_DIRECT +int type =0 ; + type =pci_direct_probe ();#endif -#ifdef CONFIG_PCI_MMCONFIG -pci_mmcfg_init (type); -#endif -if (raw_pci_ops) -return 0 ; +pci_mmcfg_early_init (); +#ifdef CONFIG_PCI_BIOS pci_pcbios_init ();#endif
@@ -28,10 +25,14 @@ static __init int pci_access_init(void)#ifdef CONFIG_PCI_DIRECT pci_direct_init (type);#endif -if (!raw_pci_ops) +if (!raw_pci_ops && !raw_pci_ext_ops)printk (KERN_ERR "PCI: Fatal: No config space access function found\n" ); +dmi_check_pciprobe (); + +dmi_check_skip_isa_align (); +return 0 ; }arch_initcall (pci_access_init);
arch/x86/pci/irq.c +3 -1
@@ -136,9 +136,11 @@ static void __init pirq_peer_trick(void) busmap[e->bus] =1 ; }for (i =1 ; i <256 ; i++) { +int node;if (!busmap[i] ||pci_find_bus (0 , i))continue ; -if (pci_scan_bus_with_sysdata (i)) + node =get_mp_bus_to_node (i); +if (pci_scan_bus_on_node (i, &pci_root_ops, node))printk (KERN_INFO "PCI: Discovered primary peer " "bus %02x [IRQ]\n" , i); }
arch/x86/pci/k8-bus_64.c +519 -61
602 lines not on this page · raw message
arch/x86/pci/legacy.c +3 -1
@@ -12,6 +12,7 @@static void __devinit pcibios_fixup_peer_bridges (void ) {int n, devfn; +long node;if (pcibios_last_bus <=0 || pcibios_last_bus >=0xff )return ;
@@ -21,12 +22,13 @@ static void __devinit pcibios_fixup_peer_bridges(void)u32 l;if (pci_find_bus (0 , n))continue ; + node =get_mp_bus_to_node (n);for (devfn =0 ; devfn <256 ; devfn +=8 ) {if (!raw_pci_read (0 , n, devfn,PCI_VENDOR_ID ,2 , &l) && l !=0x0000 && l !=0xffff ) {DBG ("Found device at %02x:%02x [%04x]\n" , n, devfn, l);printk (KERN_INFO "PCI: Discovered peer bus %02x\n" , n); -pci_scan_bus_with_sysdata (n); +pci_scan_bus_on_node (n, &pci_root_ops, node);break ; } }
arch/x86/pci/mmconfig-shared.c +217 -35
330 lines not on this page · raw message
arch/x86/pci/mmconfig_32.c +4 -0
@@ -136,3 +136,7 @@ int __init pci_mmcfg_arch_init(void) raw_pci_ext_ops = &pci_mmcfg;return 1 ; } + +void __init pci_mmcfg_arch_free (void ) +{ +}
arch/x86/pci/mmconfig_64.c +21 -1
@@ -127,7 +127,7 @@ static void __iomem * __init mcfg_ioremap(struct acpi_mcfg_allocation *cfg)int __init pci_mmcfg_arch_init (void ) {int i; - pci_mmcfg_virt =kmalloc (sizeof (*pci_mmcfg_virt) * + pci_mmcfg_virt =kzalloc (sizeof (*pci_mmcfg_virt) * pci_mmcfg_config_num,GFP_KERNEL );if (pci_mmcfg_virt ==NULL ) {printk (KERN_ERR "PCI: Can not allocate memory for mmconfig structures\n" );
@@ -141,9 +141,29 @@ int __init pci_mmcfg_arch_init(void)printk (KERN_ERR "PCI: Cannot map mmconfig aperture for " "segment %d\n" , pci_mmcfg_config[i].pci_segment); +pci_mmcfg_arch_free ();return 0 ; } } raw_pci_ext_ops = &pci_mmcfg;return 1 ; } + +void __init pci_mmcfg_arch_free (void ) +{ +int i; + +if (pci_mmcfg_virt ==NULL ) +return ; + +for (i =0 ; i < pci_mmcfg_config_num; ++i) { +if (pci_mmcfg_virt[i].virt) { +iounmap (pci_mmcfg_virt[i].virt); + pci_mmcfg_virt[i].virt =NULL ; + pci_mmcfg_virt[i].cfg =NULL ; + } + } + +kfree (pci_mmcfg_virt); + pci_mmcfg_virt =NULL ; +}
arch/x86/pci/mp_bus_to_node.c new file +23 -0
@@ -0,0 +1,23 @@ +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/topology.h> + +#define BUS_NR 256 + +static unsigned char mp_bus_to_node[BUS_NR ]; + +void set_mp_bus_to_node (int busnum,int node) +{ +if (busnum >=0 && busnum <BUS_NR ) + mp_bus_to_node[busnum] = (unsigned char ) node; +} + +int get_mp_bus_to_node (int busnum) +{ +int node; + +if (busnum <0 || busnum > (BUS_NR -1 )) +return 0 ; + node = mp_bus_to_node[busnum]; +return node; +}
arch/x86/pci/pci.h +5 -1
@@ -26,6 +26,7 @@#define PCI_ASSIGN_ALL_BUSSES 0x4000#define PCI_CAN_SKIP_ISA_ALIGN 0x8000#define PCI_USE__CRS 0x10000 +#define PCI_CHECK_ENABLE_AMD_MMCONF 0x20000extern unsigned int pci_probe;extern unsigned long pirq_table_addr;
@@ -37,6 +38,9 @@ enum pci_bf_sort_state { pci_dmi_bf, }; +extern void __init dmi_check_pciprobe (void ); +extern void __init dmi_check_skip_isa_align (void ); +/* pci-i386.c */ extern unsigned int pcibios_max_latency;
@@ -97,11 +101,11 @@ extern struct pci_raw_ops pci_direct_conf1;extern int pci_direct_probe (void );extern void pci_direct_init (int type);extern void pci_pcbios_init (void ); -extern void pci_mmcfg_init (int type);/* pci-mmconfig.c */ extern int __init pci_mmcfg_arch_init (void ); +extern void __init pci_mmcfg_arch_free (void );/* * AMD Fam10h CPUs are buggy, and cannot access MMIO config space
drivers/acpi/bus.c +2 -0
@@ -35,6 +35,7 @@#ifdef CONFIG_X86 #include <asm/mpspec.h> #endif +#include <linux/pci.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h>
@@ -784,6 +785,7 @@ static int __init acpi_init(void) result =acpi_bus_init ();if (!result) { +pci_mmcfg_late_init ();if (!(pm_flags &PM_APM )) pm_flags |=PM_ACPI ;else {
drivers/base/core.c +12 -2
@@ -787,6 +787,10 @@ int device_add(struct device *dev) parent =get_device (dev->parent);setup_parent (dev, parent); +/* use parent numa_node */ +if (parent) +set_dev_node (dev,dev_to_node (parent)); +/* first, register with generic layer. */ error =kobject_add (&dev->kobj, dev->kobj.parent,"%s" , dev->bus_id);if (error)
@@ -1306,8 +1310,11 @@ int device_move(struct device *dev, struct device *new_parent) dev->parent = new_parent;if (old_parent)klist_remove (&dev->knode_parent); -if (new_parent) +if (new_parent) {klist_add_tail (&dev->knode_parent, &new_parent->klist_children); +set_dev_node (dev,dev_to_node (new_parent)); + } +if (!dev->class) goto out_put; error =device_move_class_links (dev, old_parent, new_parent);
@@ -1317,9 +1324,12 @@ int device_move(struct device *dev, struct device *new_parent)if (!kobject_move (&dev->kobj, &old_parent->kobj)) {if (new_parent)klist_remove (&dev->knode_parent); -if (old_parent) + dev->parent = old_parent; +if (old_parent) {klist_add_tail (&dev->knode_parent, &old_parent->klist_children); +set_dev_node (dev,dev_to_node (old_parent)); + } }cleanup_glue_dir (dev, new_parent_kobj);put_device (new_parent);
drivers/char/agp/amd64-agp.c +16 -5
@@ -264,11 +264,7 @@ static int __devinit aperture_valid(u64 aper, u32 size) printk(KERN_ERR PFX "No aperture\n");return 0 ; } -if (size <32 *1024 *1024 ) { - printk(KERN_ERR PFX "Aperture too small (%d MB)\n", size>>20); -return 0 ; - } -if ((u64 )aper + size >0x100000000ULL ) { +if ((u64 )aper + size >0x100000000ULL ) { printk(KERN_ERR PFX "Aperture out of bounds\n");return 0 ; }
@@ -276,6 +272,10 @@ static int __devinit aperture_valid(u64 aper, u32 size) printk(KERN_ERR PFX "Aperture pointing to RAM\n");return 0 ; } +if (size <32 *1024 *1024 ) { + printk(KERN_ERR PFX "Aperture too small (%d MB)\n", size>>20); +return 0 ; + }/* Request the Aperture. This catches cases when someone else already put a mapping in there - happens with some very broken BIOS
@@ -331,6 +331,17 @@ static __devinit int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp,pci_read_config_dword (agp,0x10 , &aper_low);pci_read_config_dword (agp,0x14 , &aper_hi); aper = (aper_low & ~((1 <<22 )-1 )) | ((u64 )aper_hi <<32 ); + +/* +* On some sick chips APSIZE is 0. This means it wants 4G +* so let double check that order, and lets trust the AMD NB settings +*/ +if (order >=0 && aper + (32ULL <<(20 + order)) >0x100000000ULL ) { +printk (KERN_INFO "Aperture size %u MB is not right, using settings from NB\n" , +32 << order); + order = nb_order; + } + printk(KERN_INFO PFX "Aperture from AGP @ %Lx size %u MB\n", aper, 32 << order);if (order <0 || !aperture_valid (aper, (32 *1024 *1024 )<<order))return -1 ;
drivers/pci/probe.c +19 -2
@@ -842,11 +842,14 @@ static void set_pcie_port_type(struct pci_dev *pdev)* reading the dword at 0x100 which must either be 0 or a valid extended * capability header. */ -int pci_cfg_space_size (struct pci_dev *dev) +int pci_cfg_space_size_ext (struct pci_dev *dev,unsigned check_exp_pcix) {int pos;u32 status; +if (!check_exp_pcix) + goto skip; + pos =pci_find_capability (dev,PCI_CAP_ID_EXP );if (!pos) { pos =pci_find_capability (dev,PCI_CAP_ID_PCIX );
@@ -858,6 +861,7 @@ int pci_cfg_space_size(struct pci_dev *dev) goto fail; } + skip:if (pci_read_config_dword (dev,256 , &status) !=PCIBIOS_SUCCESSFUL ) goto fail;if (status ==0xffffffff )
@@ -869,6 +873,11 @@ int pci_cfg_space_size(struct pci_dev *dev)return PCI_CFG_SPACE_SIZE ; } +int pci_cfg_space_size (struct pci_dev *dev) +{ +return pci_cfg_space_size_ext (dev,1 ); +} +static void pci_release_bus_bridge_dev (struct device *dev) {kfree (dev);
@@ -964,7 +973,6 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) dev->dev.release = pci_release_dev;pci_dev_get (dev); -set_dev_node (&dev->dev,pcibus_to_node (bus)); dev->dev.dma_mask = &dev->dma_mask; dev->dev.dma_parms = &dev->dma_parms; dev->dev.coherent_dma_mask =0xffffffffull ;
@@ -1080,6 +1088,10 @@ unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)return max; } +void __attribute__((weak))set_pci_bus_resources_arch_default (struct pci_bus *b) +{ +} +struct pci_bus *pci_create_bus (struct device *parent,int bus,struct pci_ops *ops,void *sysdata) {
@@ -1119,6 +1131,9 @@ struct pci_bus * pci_create_bus(struct device *parent, goto dev_reg_err;
Lines of this file are not shown. View the raw message.
mm/bootmem.c +106 -51
157 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Part of the diff is not shown here. View the raw message.
Quoted 1 line · Ingo Molnar
x86: fix k8-bus_64.c build
Is it not necessary to fold this into a previous patch, to keep the tree bisectable?
Signature · 3 lines
Stefan Richter -=====-==--- -=-- ==-=- http://arcgraph.de/sr/
Quoted 5 lines · Stefan Richter
Quoted 1 line · Ingo Molnar
x86: fix k8-bus_64.c buildIs it not necessary to fold this into a previous patch, to keep the tree bisectable?
as i mentioned it i kept the tree as-is, to maintain its impression about its historic behavior. That way people can see how it behaved, what kind of breakages were observed, what time span the changes came in, etc. Those non-bisectable fixlets will be backmerged for a real pull request.
Ingo
Quoted 5 lines · Ingo Molnar
So we need a bit of help wrt. how mergable this is, and what else is needed to make it mergable. These changes have been booted all across the x86 spectrum, small and large boxes alike, so i'd be seriously surprised if they caused any widespread breakage.
I'd like to see this sent as perhaps four independent pulls (where "independent" doesn't necessarily mean that they don't depend on each other and have some ordering, but is more of a "this is the bootup changes" vs "these are bootmem-related" etc, if at all possible.
Quite frankly, from a review standpoint, very few people should need to (or want to) review individual commits when there are 50 of them (they might only care about the changes that 3 or 4 of them make, but they get lost in the noise), but at the same time, if you have a single diffstat like this:
45 files changed, 2071 insertions(+), 362 deletions(-)
then you're also going to have people not able to give good feedback.
In contrast, if you send out an email like this one, but that has the combined diff of say 10 commits in one area, and the diff is a couple of hundred lines of changes rather than almost 2,500 lines, then you'll definitely get people who are able and willing to look at four chunks like that.
IOW, they'd be big enough that people hopefully don't start nitpicking about some *totally* uninteresting small detail, but small enough that people can read it through without losing concentration about a quarter of the way in.
Linus
[git pull] "big box" x86 changes, bootmem/sparsemem
Quoted 4 lines · Linus Torvalds
IOW, they'd be big enough that people hopefully don't start nitpicking about some *totally* uninteresting small detail, but small enough that people can read it through without losing concentration about a quarter of the way in.
ok. Here's the "memory management" type of changes:
git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86-bigbox-bootmem.git for-linus
the other sub-trees will depend on these changes. I think these infrastructure and other improvements are mergable and pullable as-is.
Ingo
------------------>
Yinghai Lu (7):
mm: make mem_map allocation continuous
mm: fix alloc_bootmem_core to use fast searching for all nodes
mm: offset align in alloc_bootmem()
mm: allow reserve_bootmem() cross nodes
x86_64: make reserve_bootmem_generic() use new reserve_bootmem()
x86_64: fix setup_node_bootmem to support big mem excluding with memmap x86_64/mm: check and print vmemmap allocation continuous
arch/x86/kernel/e820_64.c | 13 +++- arch/x86/kernel/setup_64.c | 3 +- arch/x86/mm/init_64.c | 38 +++++++++-- arch/x86/mm/numa_64.c | 43 ++++++++++-- include/asm-x86/e820_64.h | 2 +- include/linux/mm.h | 1 + mm/bootmem.c | 157 +++++++++++++++++++++++++++++-------------- mm/sparse.c | 37 ++++++++++- 8 files changed, 222 insertions(+), 72 deletions(-)
arch/x86/kernel/e820_64.c +9 -4
@@ -84,14 +84,19 @@ void __init reserve_early(unsigned long start, unsigned long end, char *name)strncpy (r->name, name,sizeof (r->name) -1 ); } -void __init early_res_to_bootmem (void ) +void __init early_res_to_bootmem (unsigned long start,unsigned long end) {int i; +unsigned long final_start, final_end;for (i =0 ; i <MAX_EARLY_RES && early_res[i].end; i++) {struct early_res *r = &early_res[i]; -printk (KERN_INFO "early res: %d [%lx-%lx] %s\n" , i, - r->start, r->end -1 , r->name); -reserve_bootmem_generic (r->start, r->end - r->start); + final_start =max (start, r->start); + final_end =min (end, r->end); +if (final_start >= final_end) +continue ; +printk (KERN_INFO " early res: %d [%lx-%lx] %s\n" , i, + final_start, final_end -1 , r->name); +reserve_bootmem_generic (final_start, final_end - final_start); } }
arch/x86/kernel/setup_64.c +1 -2
@@ -190,6 +190,7 @@ contig_initmem_init(unsigned long start_pfn, unsigned long end_pfn) bootmap_size =init_bootmem (bootmap >>PAGE_SHIFT , end_pfn);e820_register_active_regions (0 , start_pfn, end_pfn);free_bootmem_with_active_regions (0 , end_pfn); +early_res_to_bootmem (0 , end_pfn<<PAGE_SHIFT ); reserve_bootmem(bootmap, bootmap_size, BOOTMEM_DEFAULT); }#endif
@@ -397,8 +398,6 @@ void __init setup_arch(char **cmdline_p)contig_initmem_init (0 , end_pfn);#endif -early_res_to_bootmem (); -dma32_reserve_bootmem ();#ifdef CONFIG_ACPI_SLEEP
arch/x86/mm/init_64.c +33 -5
@@ -810,7 +810,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)void __init reserve_bootmem_generic (unsigned long phys,unsigned len) {#ifdef CONFIG_NUMA -int nid =phys_to_nid (phys); +int nid, next_nid;#endif unsigned long pfn = phys >>PAGE_SHIFT ;
@@ -829,10 +829,14 @@ void __init reserve_bootmem_generic(unsigned long phys, unsigned len)/* Should check here against the e820 map to avoid double free */ #ifdef CONFIG_NUMA + nid =phys_to_nid (phys); + next_nid =phys_to_nid (phys + len -1 ); +if (nid == next_nid)reserve_bootmem_node (NODE_DATA (nid), phys, len,BOOTMEM_DEFAULT ); -#else -reserve_bootmem (phys, len,BOOTMEM_DEFAULT ); + else#endif +reserve_bootmem (phys, len,BOOTMEM_DEFAULT ); +if (phys+len <=MAX_DMA_PFN *PAGE_SIZE ) { dma_reserve += len /PAGE_SIZE ;set_dma_reserve (dma_reserve);
@@ -926,6 +930,10 @@ const char *arch_vma_name(struct vm_area_struct *vma)/* * Initialise the sparsemem vmemmap using huge-pages at the PMD level. */ +static long __meminitdata addr_start, addr_end; +static void __meminitdata *p_start, *p_end; +static int __meminitdata node_start; +int __meminit vmemmap_populate (struct page *start_page,unsigned long size,int node) {
@@ -960,12 +968,32 @@ vmemmap_populate(struct page *start_page, unsigned long size, int node) PAGE_KERNEL_LARGE);set_pmd (pmd,__pmd (pte_val (entry))); -printk (KERN_DEBUG " [%lx-%lx] PMD ->%p on node %d\n" , - addr, addr + PMD_SIZE - 1, p, node); +/* check to see if we have contiguous blocks */ +if (p_end != p || node_start != node) { +if (p_start) +printk (KERN_DEBUG " [%lx-%lx] PMD -> [%p-%p] on node %d\n" , + addr_start, addr_end-1 , p_start, p_end-1 , node_start); + addr_start = addr; + node_start = node; + p_start = p; + } + addr_end = addr +PMD_SIZE ; + p_end = p + PMD_SIZE; }else {vmemmap_verify ((pte_t *)pmd, node, addr, next); } }return 0 ; } + +void __meminit vmemmap_populate_print_last (void ) +{ +if (p_start) { +printk (KERN_DEBUG " [%lx-%lx] PMD -> [%p-%p] on node %d\n" , + addr_start, addr_end-1 , p_start, p_end-1 , node_start); + p_start =NULL ; + p_end =NULL ; + node_start =0 ; + } +}#endif
arch/x86/mm/numa_64.c +37 -6
62 lines not on this page · raw message
include/asm-x86/e820_64.h +1 -1
@@ -48,7 +48,7 @@ extern struct e820map e820;extern void update_e820 (void );extern void reserve_early (unsigned long start,unsigned long end,char *name); -extern void early_res_to_bootmem (void ); +extern void early_res_to_bootmem (unsigned long start,unsigned long end);#endif /*!__ASSEMBLY__*/
include/linux/mm.h +1 -0
@@ -1229,6 +1229,7 @@ void vmemmap_verify(pte_t *, int, unsigned long, unsigned long);int vmemmap_populate_basepages (struct page *start_page,unsigned long pages,int node);int vmemmap_populate (struct page *start_page,unsigned long pages,int node); +void vmemmap_populate_print_last (void );#endif /* __KERNEL__ */ #endif /* _LINUX_MM_H */
mm/bootmem.c +106 -51
276 lines not on this page · raw message
mm/sparse.c +34 -3
@@ -295,6 +295,9 @@ struct page __init *sparse_early_mem_map_alloc(unsigned long pnum)return NULL ; } +void __attribute__((weak))__meminit vmemmap_populate_print_last (void ) +{ +}/* * Allocate the accumulated non-linear sections, allocate a mem_map * for each and record the physical to section mapping.
@@ -304,22 +307,50 @@ void __init sparse_init(void)unsigned long pnum;struct page *map;unsigned long *usemap; +unsigned long **usemap_map; +int size; + +/* +* map is using big page (aka 2M in x86 64 bit) +* usemap is less one page (aka 24 bytes) +* so alloc 2M (with 2M align) and 24 bytes in turn will +* make next 2M slip to one more 2M later. +* then in big system, the memory will have a lot of holes... +* here try to allocate 2M pages continously. +* +* powerpc need to call sparse_init_one_section right after each +* sparse_early_mem_map_alloc, so allocate usemap_map at first. +*/ + size =sizeof (unsigned long *) *NR_MEM_SECTIONS ; + usemap_map =alloc_bootmem (size); +if (!usemap_map) +panic ("can not allocate usemap_map\n" );for (pnum =0 ; pnum <NR_MEM_SECTIONS ; pnum++) {if (!present_section_nr (pnum))continue ; + usemap_map[pnum] =sparse_early_usemap_alloc (pnum); + } - map =sparse_early_mem_map_alloc (pnum); -if (!map) +for (pnum =0 ; pnum <NR_MEM_SECTIONS ; pnum++) { +if (!present_section_nr (pnum))continue ; - usemap =sparse_early_usemap_alloc (pnum); + usemap = usemap_map[pnum];if (!usemap)continue ; + map =sparse_early_mem_map_alloc (pnum); +if (!map) +continue ; +sparse_init_one_section (__nr_to_section (pnum), pnum, map, usemap); } + +vmemmap_populate_print_last (); + +free_bootmem (__pa (usemap_map), size); }#ifdef CONFIG_MEMORY_HOTPLUG
Re: [git pull] "big box" x86 changes, bootmem/sparsemem
arch/x86/mm/init_64.c void __init reserve_bootmem_generic(unsigned long phys, unsigned len) · line 839
Quoted 11 lines · Ingo Molnar
#ifdef
CONFIG_NUMAarch/x86/mm/init_64.c +6
-2+ nid =phys_to_nid (phys); + next_nid =phys_to_nid (phys + len -1 ); +if (nid == next_nid)reserve_bootmem_node (NODE_DATA (nid), phys, len,BOOTMEM_DEFAULT ); -#else -reserve_bootmem (phys, len,BOOTMEM_DEFAULT ); + else#endif +reserve_bootmem (phys, len,BOOTMEM_DEFAULT ); +
Noticed this when just trying to read the code to see if it looks sensible (without looking at any real details).
Code like this is *not* acceptable.
We do proper indentations. Improperly indented code is buggy. It doesn't matter if the compiler might generate the same code with or without indentation, it's still totally unacceptable.
Having preprocessor conditionals that mix things up is not an excuse, and it might be an argument for not doing the conditional that way (ie maybe just make sure that when NUMA is not on, nid/next_nid will always be different, and in a way that the compiler can perhaps see statically that they are different - so that you can have the conditional there even with NUMA off, but the compiler will just fold it away?).
Linus
Re: [git pull] "big box" x86 changes, bootmem/sparsemem
Quoted 7 lines · Linus Torvalds
Having preprocessor conditionals that mix things up is not an excuse, and it might be an argument for not doing the conditional that way (ie maybe just make sure that when NUMA is not on, nid/next_nid will always be different, and in a way that the compiler can perhaps see statically that they are different - so that you can have the conditional there even with NUMA off, but the compiler will just fold it away?).
for now i cleaned it up the way below, but i also queued up a cleanup patch separately (second patch attached below) that removes the #ifdef. The current version is the tested one so i'll keep that in the tree and will treat the cleanup separately.
Ingo
------------------------>
Subject: x86_64: make reserve_bootmem_generic() use new reserve_bootmem()
From: Yinghai Lu <[email protected]>
Date: Tue, 18 Mar 2008 12:50:21 -0700
"mm: make reserve_bootmem can crossed the nodes" provides new reserve_bootmem(), let reserve_bootmem_generic() use that.
reserve_bootmem_generic() is used to reserve initramdisk, so this way we can make sure even when bootloader or kexec load ranges cross the node memory boundaries, reserve_bootmem still works.
--- arch/x86/mm/init_64.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
arch/x86/mm/init_64.c +8 -2
@@ -810,7 +810,7 @@ void free_initrd_mem(unsigned long startvoid __init reserve_bootmem_generic (unsigned long phys,unsigned len) {#ifdef CONFIG_NUMA -int nid =phys_to_nid (phys); +int nid, next_nid;#endif unsigned long pfn = phys >>PAGE_SHIFT ;
@@ -829,10 +829,16 @@ void __init reserve_bootmem_generic(unsi/* Should check here against the e820 map to avoid double free */ #ifdef CONFIG_NUMA -reserve_bootmem_node (NODE_DATA (nid), phys, len,BOOTMEM_DEFAULT ); + nid =phys_to_nid (phys); + next_nid =phys_to_nid (phys + len -1 ); +if (nid == next_nid) +reserve_bootmem_node (NODE_DATA (nid), phys, len,BOOTMEM_DEFAULT ); +else +reserve_bootmem (phys, len,BOOTMEM_DEFAULT );#else reserve_bootmem (phys, len,BOOTMEM_DEFAULT );#endif +if (phys+len <=MAX_DMA_PFN *PAGE_SIZE ) { dma_reserve += len /PAGE_SIZE ;set_dma_reserve (dma_reserve);
------------->
Subject: x86: reserve bootmem cleanup
From: Ingo Molnar <[email protected]>
Date: Sat Apr 26 21:50:20 CEST 2008
--- arch/x86/mm/init_64.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-)
arch/x86/mm/init_64.c +1 -7
@@ -810,10 +810,8 @@ void free_initrd_mem(unsigned long startvoid __init reserve_bootmem_generic (unsigned long phys,unsigned len) { -#ifdef CONFIG_NUMA -int nid, next_nid; -#endif unsigned long pfn = phys >>PAGE_SHIFT ; +int nid, next_nid;if (pfn >= end_pfn) {/*
@@ -829,16 +827,12 @@ void __init reserve_bootmem_generic(unsi }/* Should check here against the e820 map to avoid double free */ -#ifdef CONFIG_NUMA nid =phys_to_nid (phys); next_nid =phys_to_nid (phys + len -1 );if (nid == next_nid)reserve_bootmem_node (NODE_DATA (nid), phys, len,BOOTMEM_DEFAULT );else reserve_bootmem (phys, len,BOOTMEM_DEFAULT ); -#else -reserve_bootmem (phys, len,BOOTMEM_DEFAULT ); -#endif if (phys+len <=MAX_DMA_PFN *PAGE_SIZE ) { dma_reserve += len /PAGE_SIZE ;
[git pull] "big box" x86 changes, bootmem/sparsemem, #2
In reply to Linus Torvaldshere's the updated tree:
git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86-bigbox-bootmem-v2.git for-linus
Ingo
------------------>
Yinghai Lu (7):
mm: make mem_map allocation continuous
mm: fix alloc_bootmem_core to use fast searching for all nodes
mm: offset align in alloc_bootmem()
mm: allow reserve_bootmem() cross nodes
x86_64: make reserve_bootmem_generic() use new reserve_bootmem()
x86_64: fix setup_node_bootmem to support big mem excluding with memmap x86_64/mm: check and print vmemmap allocation continuous
arch/x86/kernel/e820_64.c | 13 +++- arch/x86/kernel/setup_64.c | 3 +- arch/x86/mm/init_64.c | 38 +++++++++- arch/x86/mm/numa_64.c | 42 ++++++++++-- include/asm-x86/e820_64.h | 2 +- include/linux/mm.h | 1 + mm/bootmem.c | 164 ++++++++++++++++++++++++++++++-------------- mm/sparse.c | 37 +++++++++- 8 files changed, 228 insertions(+), 72 deletions(-)
arch/x86/kernel/e820_64.c +9 -4
@@ -84,14 +84,19 @@ void __init reserve_early(unsigned long start, unsigned long end, char *name)strncpy (r->name, name,sizeof (r->name) -1 ); } -void __init early_res_to_bootmem (void ) +void __init early_res_to_bootmem (unsigned long start,unsigned long end) {int i; +unsigned long final_start, final_end;for (i =0 ; i <MAX_EARLY_RES && early_res[i].end; i++) {struct early_res *r = &early_res[i]; -printk (KERN_INFO "early res: %d [%lx-%lx] %s\n" , i, - r->start, r->end -1 , r->name); -reserve_bootmem_generic (r->start, r->end - r->start); + final_start =max (start, r->start); + final_end =min (end, r->end); +if (final_start >= final_end) +continue ; +printk (KERN_INFO " early res: %d [%lx-%lx] %s\n" , i, + final_start, final_end -1 , r->name); +reserve_bootmem_generic (final_start, final_end - final_start); } }
arch/x86/kernel/setup_64.c +1 -2
@@ -190,6 +190,7 @@ contig_initmem_init(unsigned long start_pfn, unsigned long end_pfn) bootmap_size =init_bootmem (bootmap >>PAGE_SHIFT , end_pfn);e820_register_active_regions (0 , start_pfn, end_pfn);free_bootmem_with_active_regions (0 , end_pfn); +early_res_to_bootmem (0 , end_pfn<<PAGE_SHIFT ); reserve_bootmem(bootmap, bootmap_size, BOOTMEM_DEFAULT); }#endif
@@ -397,8 +398,6 @@ void __init setup_arch(char **cmdline_p)contig_initmem_init (0 , end_pfn);#endif -early_res_to_bootmem (); -dma32_reserve_bootmem ();#ifdef CONFIG_ACPI_SLEEP
arch/x86/mm/init_64.c +34 -4
@@ -810,7 +810,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)void __init reserve_bootmem_generic (unsigned long phys,unsigned len) {#ifdef CONFIG_NUMA -int nid =phys_to_nid (phys); +int nid, next_nid;#endif unsigned long pfn = phys >>PAGE_SHIFT ;
@@ -829,10 +829,16 @@ void __init reserve_bootmem_generic(unsigned long phys, unsigned len)/* Should check here against the e820 map to avoid double free */ #ifdef CONFIG_NUMA -reserve_bootmem_node (NODE_DATA (nid), phys, len,BOOTMEM_DEFAULT ); + nid =phys_to_nid (phys); + next_nid =phys_to_nid (phys + len -1 ); +if (nid == next_nid) +reserve_bootmem_node (NODE_DATA (nid), phys, len,BOOTMEM_DEFAULT ); +else +reserve_bootmem (phys, len,BOOTMEM_DEFAULT );#else reserve_bootmem (phys, len,BOOTMEM_DEFAULT );#endif +if (phys+len <=MAX_DMA_PFN *PAGE_SIZE ) { dma_reserve += len /PAGE_SIZE ;set_dma_reserve (dma_reserve);
@@ -926,6 +932,10 @@ const char *arch_vma_name(struct vm_area_struct *vma)/* * Initialise the sparsemem vmemmap using huge-pages at the PMD level. */ +static long __meminitdata addr_start, addr_end; +static void __meminitdata *p_start, *p_end; +static int __meminitdata node_start; +int __meminit vmemmap_populate (struct page *start_page,unsigned long size,int node) {
@@ -960,12 +970,32 @@ vmemmap_populate(struct page *start_page, unsigned long size, int node) PAGE_KERNEL_LARGE);set_pmd (pmd,__pmd (pte_val (entry))); -printk (KERN_DEBUG " [%lx-%lx] PMD ->%p on node %d\n" , - addr, addr + PMD_SIZE - 1, p, node); +/* check to see if we have contiguous blocks */ +if (p_end != p || node_start != node) { +if (p_start) +printk (KERN_DEBUG " [%lx-%lx] PMD -> [%p-%p] on node %d\n" , + addr_start, addr_end-1 , p_start, p_end-1 , node_start); + addr_start = addr; + node_start = node; + p_start = p; + } + addr_end = addr +PMD_SIZE ; + p_end = p + PMD_SIZE; }else {vmemmap_verify ((pte_t *)pmd, node, addr, next); } }return 0 ; } + +void __meminit vmemmap_populate_print_last (void ) +{ +if (p_start) { +printk (KERN_DEBUG " [%lx-%lx] PMD -> [%p-%p] on node %d\n" , + addr_start, addr_end-1 , p_start, p_end-1 , node_start); + p_start =NULL ; + p_end =NULL ; + node_start =0 ; + } +}#endif
arch/x86/mm/numa_64.c +36 -6
61 lines not on this page · raw message
include/asm-x86/e820_64.h +1 -1
@@ -48,7 +48,7 @@ extern struct e820map e820;extern void update_e820 (void );extern void reserve_early (unsigned long start,unsigned long end,char *name); -extern void early_res_to_bootmem (void ); +extern void early_res_to_bootmem (unsigned long start,unsigned long end);#endif /*!__ASSEMBLY__*/
include/linux/mm.h +1 -0
@@ -1229,6 +1229,7 @@ void vmemmap_verify(pte_t *, int, unsigned long, unsigned long);int vmemmap_populate_basepages (struct page *start_page,unsigned long pages,int node);int vmemmap_populate (struct page *start_page,unsigned long pages,int node); +void vmemmap_populate_print_last (void );#endif /* __KERNEL__ */ #endif /* _LINUX_MM_H */
mm/bootmem.c +112 -52
282 lines not on this page · raw message
mm/sparse.c +34 -3
@@ -295,6 +295,9 @@ struct page __init *sparse_early_mem_map_alloc(unsigned long pnum)return NULL ; } +void __attribute__((weak))__meminit vmemmap_populate_print_last (void ) +{ +}/* * Allocate the accumulated non-linear sections, allocate a mem_map * for each and record the physical to section mapping.
@@ -304,22 +307,50 @@ void __init sparse_init(void)unsigned long pnum;struct page *map;unsigned long *usemap; +unsigned long **usemap_map; +int size; + +/* +* map is using big page (aka 2M in x86 64 bit) +* usemap is less one page (aka 24 bytes) +* so alloc 2M (with 2M align) and 24 bytes in turn will +* make next 2M slip to one more 2M later. +* then in big system, the memory will have a lot of holes... +* here try to allocate 2M pages continously. +* +* powerpc need to call sparse_init_one_section right after each +* sparse_early_mem_map_alloc, so allocate usemap_map at first. +*/ + size =sizeof (unsigned long *) *NR_MEM_SECTIONS ; + usemap_map =alloc_bootmem (size); +if (!usemap_map) +panic ("can not allocate usemap_map\n" );for (pnum =0 ; pnum <NR_MEM_SECTIONS ; pnum++) {if (!present_section_nr (pnum))continue ; + usemap_map[pnum] =sparse_early_usemap_alloc (pnum); + } - map =sparse_early_mem_map_alloc (pnum); -if (!map) +for (pnum =0 ; pnum <NR_MEM_SECTIONS ; pnum++) { +if (!present_section_nr (pnum))continue ; - usemap =sparse_early_usemap_alloc (pnum); + usemap = usemap_map[pnum];if (!usemap)continue ; + map =sparse_early_mem_map_alloc (pnum); +if (!map) +continue ; +sparse_init_one_section (__nr_to_section (pnum), pnum, map, usemap); } + +vmemmap_populate_print_last (); + +free_bootmem (__pa (usemap_map), size); }#ifdef CONFIG_MEMORY_HOTPLUG
Re: [git pull] "big box" x86 changes, bootmem/sparsemem, #2
Quoted 4 lines · Ingo Molnar
here's the updated tree:
git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86-bigbox-bootmem-v2.git for-linus
Ok, this clashes with the bootparam changes..
Linus
[git pull] "big box" x86 changes, bootmem/sparsemem, #3
Quoted 5 lines · Linus Torvalds
Quoted 3 lines
here's the updated tree:
git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86-bigbox-bootmem-v2.git for-linusOk, this clashes with the bootparam changes..
yeah. I respun the tree against the bootparam changes, you can pull it from:
git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86-bigbox-bootmem-v3.git for-linus
booted this specific tree up once so far. Thanks,
Ingo
------------------>
Yinghai Lu (7):
mm: make mem_map allocation continuous
mm: fix alloc_bootmem_core to use fast searching for all nodes
mm: offset align in alloc_bootmem()
mm: allow reserve_bootmem() cross nodes
x86_64: make reserve_bootmem_generic() use new reserve_bootmem()
x86_64: fix setup_node_bootmem to support big mem excluding with memmap x86_64/mm: check and print vmemmap allocation continuous
arch/x86/kernel/e820_64.c | 13 +++- arch/x86/kernel/setup_64.c | 3 +- arch/x86/mm/init_64.c | 38 +++++++++- arch/x86/mm/numa_64.c | 42 ++++++++++-- include/asm-x86/e820_64.h | 2 +- include/linux/mm.h | 1 + mm/bootmem.c | 164 ++++++++++++++++++++++++++++++-------------- mm/sparse.c | 37 +++++++++- 8 files changed, 228 insertions(+), 72 deletions(-)
arch/x86/kernel/e820_64.c +9 -4
@@ -106,14 +106,19 @@ void __init free_early(unsigned long start, unsigned long end) early_res[j -1 ].end =0 ; } -void __init early_res_to_bootmem (void ) +void __init early_res_to_bootmem (unsigned long start,unsigned long end) {int i; +unsigned long final_start, final_end;for (i =0 ; i <MAX_EARLY_RES && early_res[i].end; i++) {struct early_res *r = &early_res[i]; -printk (KERN_INFO "early res: %d [%lx-%lx] %s\n" , i, - r->start, r->end -1 , r->name); -reserve_bootmem_generic (r->start, r->end - r->start); + final_start =max (start, r->start); + final_end =min (end, r->end); +if (final_start >= final_end) +continue ; +printk (KERN_INFO " early res: %d [%lx-%lx] %s\n" , i, + final_start, final_end -1 , r->name); +reserve_bootmem_generic (final_start, final_end - final_start); } }
arch/x86/kernel/setup_64.c +1 -2
@@ -190,6 +190,7 @@ contig_initmem_init(unsigned long start_pfn, unsigned long end_pfn) bootmap_size =init_bootmem (bootmap >>PAGE_SHIFT , end_pfn);e820_register_active_regions (0 , start_pfn, end_pfn);free_bootmem_with_active_regions (0 , end_pfn); +early_res_to_bootmem (0 , end_pfn<<PAGE_SHIFT ); reserve_bootmem(bootmap, bootmap_size, BOOTMEM_DEFAULT); }#endif
@@ -421,8 +422,6 @@ void __init setup_arch(char **cmdline_p)contig_initmem_init (0 , end_pfn);#endif -early_res_to_bootmem (); -dma32_reserve_bootmem ();#ifdef CONFIG_ACPI_SLEEP
arch/x86/mm/init_64.c +34 -4
@@ -810,7 +810,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)void __init reserve_bootmem_generic (unsigned long phys,unsigned len) {#ifdef CONFIG_NUMA -int nid =phys_to_nid (phys); +int nid, next_nid;#endif unsigned long pfn = phys >>PAGE_SHIFT ;
@@ -829,10 +829,16 @@ void __init reserve_bootmem_generic(unsigned long phys, unsigned len)/* Should check here against the e820 map to avoid double free */ #ifdef CONFIG_NUMA -reserve_bootmem_node (NODE_DATA (nid), phys, len,BOOTMEM_DEFAULT ); + nid =phys_to_nid (phys); + next_nid =phys_to_nid (phys + len -1 ); +if (nid == next_nid) +reserve_bootmem_node (NODE_DATA (nid), phys, len,BOOTMEM_DEFAULT ); +else +reserve_bootmem (phys, len,BOOTMEM_DEFAULT );#else reserve_bootmem (phys, len,BOOTMEM_DEFAULT );#endif +if (phys+len <=MAX_DMA_PFN *PAGE_SIZE ) { dma_reserve += len /PAGE_SIZE ;set_dma_reserve (dma_reserve);
@@ -926,6 +932,10 @@ const char *arch_vma_name(struct vm_area_struct *vma)/* * Initialise the sparsemem vmemmap using huge-pages at the PMD level. */ +static long __meminitdata addr_start, addr_end; +static void __meminitdata *p_start, *p_end; +static int __meminitdata node_start; +int __meminit vmemmap_populate (struct page *start_page,unsigned long size,int node) {
@@ -960,12 +970,32 @@ vmemmap_populate(struct page *start_page, unsigned long size, int node) PAGE_KERNEL_LARGE);set_pmd (pmd,__pmd (pte_val (entry))); -printk (KERN_DEBUG " [%lx-%lx] PMD ->%p on node %d\n" , - addr, addr + PMD_SIZE - 1, p, node); +/* check to see if we have contiguous blocks */ +if (p_end != p || node_start != node) { +if (p_start) +printk (KERN_DEBUG " [%lx-%lx] PMD -> [%p-%p] on node %d\n" , + addr_start, addr_end-1 , p_start, p_end-1 , node_start); + addr_start = addr; + node_start = node; + p_start = p; + } + addr_end = addr +PMD_SIZE ; + p_end = p + PMD_SIZE; }else {vmemmap_verify ((pte_t *)pmd, node, addr, next); } }return 0 ; } + +void __meminit vmemmap_populate_print_last (void ) +{ +if (p_start) { +printk (KERN_DEBUG " [%lx-%lx] PMD -> [%p-%p] on node %d\n" , + addr_start, addr_end-1 , p_start, p_end-1 , node_start); + p_start =NULL ; + p_end =NULL ; + node_start =0 ; + } +}#endif
arch/x86/mm/numa_64.c +36 -6
61 lines not on this page · raw message
include/asm-x86/e820_64.h +1 -1
@@ -49,7 +49,7 @@ extern void update_e820(void);extern void reserve_early (unsigned long start,unsigned long end,char *name);extern void free_early (unsigned long start,unsigned long end); -extern void early_res_to_bootmem (void ); +extern void early_res_to_bootmem (unsigned long start,unsigned long end);#endif /*!__ASSEMBLY__*/
include/linux/mm.h +1 -0
@@ -1229,6 +1229,7 @@ void vmemmap_verify(pte_t *, int, unsigned long, unsigned long);int vmemmap_populate_basepages (struct page *start_page,unsigned long pages,int node);int vmemmap_populate (struct page *start_page,unsigned long pages,int node); +void vmemmap_populate_print_last (void );#endif /* __KERNEL__ */ #endif /* _LINUX_MM_H */
mm/bootmem.c +112 -52
282 lines not on this page · raw message
mm/sparse.c +34 -3
@@ -295,6 +295,9 @@ struct page __init *sparse_early_mem_map_alloc(unsigned long pnum)return NULL ; } +void __attribute__((weak))__meminit vmemmap_populate_print_last (void ) +{ +}/* * Allocate the accumulated non-linear sections, allocate a mem_map * for each and record the physical to section mapping.
@@ -304,22 +307,50 @@ void __init sparse_init(void)unsigned long pnum;struct page *map;unsigned long *usemap; +unsigned long **usemap_map; +int size; + +/* +* map is using big page (aka 2M in x86 64 bit) +* usemap is less one page (aka 24 bytes) +* so alloc 2M (with 2M align) and 24 bytes in turn will +* make next 2M slip to one more 2M later. +* then in big system, the memory will have a lot of holes... +* here try to allocate 2M pages continously. +* +* powerpc need to call sparse_init_one_section right after each +* sparse_early_mem_map_alloc, so allocate usemap_map at first. +*/ + size =sizeof (unsigned long *) *NR_MEM_SECTIONS ; + usemap_map =alloc_bootmem (size); +if (!usemap_map) +panic ("can not allocate usemap_map\n" );for (pnum =0 ; pnum <NR_MEM_SECTIONS ; pnum++) {if (!present_section_nr (pnum))continue ; + usemap_map[pnum] =sparse_early_usemap_alloc (pnum); + } - map =sparse_early_mem_map_alloc (pnum); -if (!map) +for (pnum =0 ; pnum <NR_MEM_SECTIONS ; pnum++) { +if (!present_section_nr (pnum))continue ; - usemap =sparse_early_usemap_alloc (pnum); + usemap = usemap_map[pnum];if (!usemap)continue ; + map =sparse_early_mem_map_alloc (pnum); +if (!map) +continue ; +sparse_init_one_section (__nr_to_section (pnum), pnum, map, usemap); } + +vmemmap_populate_print_last (); + +free_bootmem (__pa (usemap_map), size); }#ifdef CONFIG_MEMORY_HOTPLUG
Re: [git pull] "big box" x86 changes, bootmem/sparsemem
In reply to Ingo MolnarHi Ingo,
Quoted 17 lines · Ingo Molnar
Quoted 4 lines · Linus Torvalds
IOW, they'd be big enough that people hopefully don't start nitpicking about some *totally* uninteresting small detail, but small enough that people can read it through without losing concentration about a quarter of the way in.
ok. Here's the "memory management" type of changes:
git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86-bigbox-bootmem.git for-linusthe other sub-trees will depend on these changes. I think these infrastructure and other improvements are mergable and pullable as-is.
Ingo
------------------>
[...]
Quoted 1 line
mm: allow
reserve_bootmem()cross nodes
I find it sad that this goes in now. I wrote a clean version of reserve_bootmem() [1] and it was rejected with arguments that I did not understand [2] and that were not further explained even though I asked for it [3].
http://lkml.org/lkml/2008/4/16/76
http://lkml.org/lkml/2008/4/16/234
http://lkml.org/lkml/2008/4/16/250
Your comment was rather unfair, because it gave the impression you did not read the thread before replying. And you did not react to other explicit questions from me. If you find my patches to be crap, say so and please explain WHY so I have a chance to improve.
Please, reconsider the bootmem patches; bootmem code looks really bad at the moment.
Hannes
Re: [git pull] "big box" x86 changes, bootmem/sparsemem
Quoted 10 lines · Johannes Weiner
Quoted 1 line
mm: allow
reserve_bootmem()cross nodesI find it sad that this goes in now. I wrote a clean version of
reserve_bootmem()[1] and it was rejected with arguments that I did not understand [2] and that were not further explained even though I asked for it [3].http://lkml.org/lkml/2008/4/16/76
http://lkml.org/lkml/2008/4/16/234
http://lkml.org/lkml/2008/4/16/250
oh, i had your patches applied then undid them due to this:
http://www.ussg.iu.edu/hypermail/linux/kernel/0804.2/0253.html
havent seen a followup to that mail so it was 'issue pending'.
so i very much agree that your changes are cleaner, i just wanted to have one that has all the fixes included.
Would you like to post a patch against current -git or should i extract the cleaner reserve_bootmem() from your previous patch?
Ingo
Re: [git pull] "big box" x86 changes, bootmem/sparsemem
Hi Ingo,
Quoted 13 lines · Ingo Molnar
Quoted 10 lines · Johannes Weiner
Quoted 1 line
mm: allow
reserve_bootmem()cross nodesI find it sad that this goes in now. I wrote a clean version of
reserve_bootmem()[1] and it was rejected with arguments that I did not understand [2] and that were not further explained even though I asked for it [3].http://lkml.org/lkml/2008/4/16/76
http://lkml.org/lkml/2008/4/16/234
http://lkml.org/lkml/2008/4/16/250
Quoted 8 lines
oh, i had your patches applied then undid them due to this:
http://www.ussg.iu.edu/hypermail/linux/kernel/0804.2/0253.htmlhavent seen a followup to that mail so it was 'issue pending'.
so i very much agree that your changes are cleaner, i just wanted to have one that has all the fixes included.
I had planned this to be another patch because there are more then one boundary check I wanted to tighten. I can merge them though if you like.
Quoted 2 lines
Would you like to post a patch against current -git or should i extract the cleaner
reserve_bootmem()from your previous patch?
I just moved and have only sporadic internet access and free time slots available. Would be nice if you could do it!
Quoted 1 line
Ingo
Thanks!
Hannes
PATCH 1/1 mm: node-setup agnostic free_bootmem()
Quoted 6 lines · Johannes Weiner
Quoted 2 lines
so i very much agree that your changes are cleaner, i just wanted to have one that has all the fixes included.
I had planned this to be another patch because there are more then one boundary check I wanted to tighten. I can merge them though if you like.
no, better to have them in separate patches.
Quoted 5 lines
Quoted 2 lines
Would you like to post a patch against current -git or should i extract the cleaner
reserve_bootmem()from your previous patch?I just moved and have only sporadic internet access and free time slots available. Would be nice if you could do it!
sure, find the merged patch below, against latest -git, boot-tested on x86. Is this what you had in mind?
Ingo
---------------->
Subject: mm: node-setup agnostic free_bootmem()
From: Johannes Weiner <[email protected]>
Date: Wed, 16 Apr 2008 13:36:31 +0200
Make free_bootmem() look up the node holding the specified address range which lets it work transparently on single-node and multi-node configurations.
If the address range exceeds the node range, it well be marked free across node boundaries, too.
--- mm/bootmem.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-)
mm/bootmem.c +25 -2
@@ -493,8 +493,31 @@ int __init reserve_bootmem(unsigned longvoid __init free_bootmem (unsigned long addr,unsigned long size) {bootmem_data_t *bdata; -list_for_each_entry (bdata, &bdata_list, list) -free_bootmem_core (bdata, addr, size); +unsigned long pos = addr; +unsigned long partsize = size; + +list_for_each_entry (bdata, &bdata_list, list) { +unsigned long remainder =0 ; + +if (pos < bdata->node_boot_start) +continue ; + +if (PFN_DOWN (pos + partsize) > bdata->node_low_pfn) { + remainder =PFN_DOWN (pos + partsize) - bdata->node_low_pfn; + partsize -= remainder; + } + +free_bootmem_core (bdata, pos, partsize); + +if (!remainder) +return ; + + pos =PFN_PHYS (bdata->node_low_pfn +1 ); + } +printk (KERN_ERR "free_bootmem: request: addr=%lx, size=%lx, " +"state: pos=%lx, partsize=%lx\n" , addr, size, + pos, partsize); +BUG (); }unsigned long __init free_all_bootmem (void )
Re: [patch] mm: node-setup agnostic free_bootmem()
Quoted 84 lines · Ingo Molnar
Quoted 6 lines · Johannes Weiner
Quoted 2 lines
so i very much agree that your changes are cleaner, i just wanted to have one that has all the fixes included.
I had planned this to be another patch because there are more then one boundary check I wanted to tighten. I can merge them though if you like.
no, better to have them in separate patches.
Quoted 5 lines
Quoted 2 lines
Would you like to post a patch against current -git or should i extract the cleaner
reserve_bootmem()from your previous patch?I just moved and have only sporadic internet access and free time slots available. Would be nice if you could do it!
sure, find the merged patch below, against latest -git, boot-tested on x86. Is this what you had in mind?
Ingo
---------------->
Subject: mm: node-setup agnosticfree_bootmem()
From: Johannes Weiner <[email protected]>
Date: Wed, 16 Apr 2008 13:36:31 +0200Make
free_bootmem()look up the node holding the specified address range which lets it work transparently on single-node and multi-node configurations.If the address range exceeds the node range, it well be marked free across node boundaries, too.
Signed-off-by Johannes Weiner <[email protected]>CC Andi Kleen <[email protected]>CC Yinghai Lu <[email protected]>CC Yasunori Goto <[email protected]>CC KAMEZAWA Hiroyuki <[email protected]>CC Christoph Lameter <[email protected]>CC Andrew Morton <[email protected]>Signed-off-by Ingo Molnar <[email protected]>---
mm/bootmem.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-)Index:
linux-x86.q/mm/bootmem.c
===================================================================
---linux-x86.q.orig/mm/bootmem.c
+++linux-x86.q/mm/bootmem.c
@@ -493,8 +493,31 @@ int__initreserve_bootmem(unsigned long
void__initfree_bootmem(unsigned long addr, unsigned long size){ bootmem_data_t *bdata;-
list_for_each_entry(bdata, &bdata_list, list)
-free_bootmem_core(bdata, addr, size);
+ unsigned long pos = addr;
+ unsigned long partsize = size;
+
+list_for_each_entry(bdata, &bdata_list, list){
+ unsigned long remainder = 0;
+
+ if (pos <bdata->node_boot_start)
+ continue;
+
+ if (PFN_DOWN(pos + partsize)>bdata->node_low_pfn) {
+ remainder =PFN_DOWN(pos + partsize)-bdata->node_low_pfn;
+ partsize -= remainder;
+ }
+
+free_bootmem_core(bdata, pos, partsize);
+
+ if (!remainder)
+ return;
+
+ pos =PFN_PHYS(bdata->node_low_pfn + 1);
+ }
+ printk(KERN_ERR "free_bootmem: request: addr=%lx, size=%lx, "
+ "state: pos=%lx, partsize=%lx\n", addr, size,
+ pos, partsize);
+BUG();
}
Quoted 2 lines
unsigned long
__initfree_all_bootmem(void)
it will not work with cross nodes.
for example: node 0: 0-2g, 4-6g, node1: 2-4g, 6-8g.
and if ramdisk sit cross 2G boundary. you will only free the range before 2g.
YH
Re: [patch] mm: node-setup agnostic free_bootmem()
Hi Yinghai,
Quoted 85 lines · Yinghai Lu
Quoted 84 lines · Ingo Molnar
Quoted 6 lines · Johannes Weiner
Quoted 2 lines
so i very much agree that your changes are cleaner, i just wanted to have one that has all the fixes included.
I had planned this to be another patch because there are more then one boundary check I wanted to tighten. I can merge them though if you like.
no, better to have them in separate patches.
Quoted 5 lines
Quoted 2 lines
Would you like to post a patch against current -git or should i extract the cleaner
reserve_bootmem()from your previous patch?I just moved and have only sporadic internet access and free time slots available. Would be nice if you could do it!
sure, find the merged patch below, against latest -git, boot-tested on x86. Is this what you had in mind?
Ingo
---------------->
Subject: mm: node-setup agnosticfree_bootmem()
From: Johannes Weiner <[email protected]>
Date: Wed, 16 Apr 2008 13:36:31 +0200Make
free_bootmem()look up the node holding the specified address range which lets it work transparently on single-node and multi-node configurations.If the address range exceeds the node range, it well be marked free across node boundaries, too.
Signed-off-by Johannes Weiner <[email protected]>CC Andi Kleen <[email protected]>CC Yinghai Lu <[email protected]>CC Yasunori Goto <[email protected]>CC KAMEZAWA Hiroyuki <[email protected]>CC Christoph Lameter <[email protected]>CC Andrew Morton <[email protected]>Signed-off-by Ingo Molnar <[email protected]>---
mm/bootmem.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-)Index:
linux-x86.q/mm/bootmem.c
===================================================================
---linux-x86.q.orig/mm/bootmem.c
+++linux-x86.q/mm/bootmem.c
@@ -493,8 +493,31 @@ int__initreserve_bootmem(unsigned long
void__initfree_bootmem(unsigned long addr, unsigned long size){ bootmem_data_t *bdata;-
list_for_each_entry(bdata, &bdata_list, list)
-free_bootmem_core(bdata, addr, size);
+ unsigned long pos = addr;
+ unsigned long partsize = size;
+
+list_for_each_entry(bdata, &bdata_list, list){
+ unsigned long remainder = 0;
+
+ if (pos <bdata->node_boot_start)
+ continue;
+
+ if (PFN_DOWN(pos + partsize)>bdata->node_low_pfn) {
+ remainder =PFN_DOWN(pos + partsize)-bdata->node_low_pfn;
+ partsize -= remainder;
+ }
+
+free_bootmem_core(bdata, pos, partsize);
+
+ if (!remainder)
+ return;
+
+ pos =PFN_PHYS(bdata->node_low_pfn + 1);
+ }
+ printk(KERN_ERR "free_bootmem: request: addr=%lx, size=%lx, "
+ "state: pos=%lx, partsize=%lx\n", addr, size,
+ pos, partsize);
+BUG();
}
Quoted 8 lines
Quoted 2 lines
unsigned long
__initfree_all_bootmem(void)it will not work with cross nodes.
for example: node 0: 0-2g, 4-6g, node1: 2-4g, 6-8g.
and if ramdisk sit cross 2G boundary. you will only free the range before 2g.
Yes, you stated that several times but this is not a technical argument:
These setups are afaik not yet supported by the kernel at all. And you could not explain the node layout with the patch that implements support for these configurations.
So as long as you don't explain in technical detail why my patch won't work, I will have to ignore your objections.
My opinion is that my patch should go in as is and the patch that adds support for these node-setups should change bootmem accordingly, if needed at all.
Hannes
Re: [patch] mm: node-setup agnostic free_bootmem()
Quoted 96 lines · Johannes Weiner
Hi Yinghai,
Quoted 90 lines · Yinghai Lu
Quoted 84 lines · Ingo Molnar
Quoted 6 lines · Johannes Weiner
Quoted 2 lines
so i very much agree that your changes are cleaner, i just wanted to have one that has all the fixes included.
I had planned this to be another patch because there are more then one boundary check I wanted to tighten. I can merge them though if you like.
no, better to have them in separate patches.
Quoted 5 lines
Quoted 2 lines
Would you like to post a patch against current -git or should i extract the cleaner
reserve_bootmem()from your previous patch?I just moved and have only sporadic internet access and free time slots available. Would be nice if you could do it!
sure, find the merged patch below, against latest -git, boot-tested on x86. Is this what you had in mind?
Ingo
---------------->
Subject: mm: node-setup agnosticfree_bootmem()
From: Johannes Weiner <[email protected]>
Date: Wed, 16 Apr 2008 13:36:31 +0200Make
free_bootmem()look up the node holding the specified address range which lets it work transparently on single-node and multi-node configurations.If the address range exceeds the node range, it well be marked free across node boundaries, too.
Signed-off-by Johannes Weiner <[email protected]>CC Andi Kleen <[email protected]>CC Yinghai Lu <[email protected]>CC Yasunori Goto <[email protected]>CC KAMEZAWA Hiroyuki <[email protected]>CC Christoph Lameter <[email protected]>CC Andrew Morton <[email protected]>Signed-off-by Ingo Molnar <[email protected]>---
mm/bootmem.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-)Index:
linux-x86.q/mm/bootmem.c
===================================================================
---linux-x86.q.orig/mm/bootmem.c
+++linux-x86.q/mm/bootmem.c
@@ -493,8 +493,31 @@ int__initreserve_bootmem(unsigned long
void__initfree_bootmem(unsigned long addr, unsigned long size){ bootmem_data_t *bdata;-
list_for_each_entry(bdata, &bdata_list, list)
-free_bootmem_core(bdata, addr, size);
+ unsigned long pos = addr;
+ unsigned long partsize = size;
+
+list_for_each_entry(bdata, &bdata_list, list){
+ unsigned long remainder = 0;
+
+ if (pos <bdata->node_boot_start)
+ continue;
+
+ if (PFN_DOWN(pos + partsize)>bdata->node_low_pfn) {
+ remainder =PFN_DOWN(pos + partsize)-bdata->node_low_pfn;
+ partsize -= remainder;
+ }
+
+free_bootmem_core(bdata, pos, partsize);
+
+ if (!remainder)
+ return;
+
+ pos =PFN_PHYS(bdata->node_low_pfn + 1);
+ }
+ printk(KERN_ERR "free_bootmem: request: addr=%lx, size=%lx, "
+ "state: pos=%lx, partsize=%lx\n", addr, size,
+ pos, partsize);
+BUG();
}Quoted 2 lines
unsigned long
__initfree_all_bootmem(void)it will not work with cross nodes.
Quoted 8 lines
Quoted 3 lines
for example: node 0: 0-2g, 4-6g, node1: 2-4g, 6-8g.
and if ramdisk sit cross 2G boundary. you will only free the range before 2g.Yes, you stated that several times but this is not a technical argument:
These setups are afaik not yet supported by the kernel at all. And you could not explain the node layout with the patch that implements support for these configurations.
I looked at Suresh's patch, and it still only has one bdata for one node.
YH
Re: [patch] mm: node-setup agnostic free_bootmem()
Quoted 102 lines · Yinghai Lu
Quoted 100 lines · Johannes Weiner
Hi Yinghai,
Quoted 93 lines · Yinghai Lu
Quoted 84 lines · Ingo Molnar
Quoted 6 lines · Johannes Weiner
Quoted 2 lines
so i very much agree that your changes are cleaner, i just wanted to have one that has all the fixes included.
I had planned this to be another patch because there are more then one boundary check I wanted to tighten. I can merge them though if you like.
no, better to have them in separate patches.
Quoted 5 lines
Quoted 2 lines
Would you like to post a patch against current -git or should i extract the cleaner
reserve_bootmem()from your previous patch?I just moved and have only sporadic internet access and free time slots available. Would be nice if you could do it!
sure, find the merged patch below, against latest -git, boot-tested on x86. Is this what you had in mind?
Ingo
---------------->
Subject: mm: node-setup agnosticfree_bootmem()
From: Johannes Weiner <[email protected]>
Date: Wed, 16 Apr 2008 13:36:31 +0200Make
free_bootmem()look up the node holding the specified address range which lets it work transparently on single-node and multi-node configurations.If the address range exceeds the node range, it well be marked free across node boundaries, too.
Signed-off-by Johannes Weiner <[email protected]>CC Andi Kleen <[email protected]>CC Yinghai Lu <[email protected]>CC Yasunori Goto <[email protected]>CC KAMEZAWA Hiroyuki <[email protected]>CC Christoph Lameter <[email protected]>CC Andrew Morton <[email protected]>Signed-off-by Ingo Molnar <[email protected]>---
mm/bootmem.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-)Index:
linux-x86.q/mm/bootmem.c
===================================================================
---linux-x86.q.orig/mm/bootmem.c
+++linux-x86.q/mm/bootmem.c
@@ -493,8 +493,31 @@ int__initreserve_bootmem(unsigned long
void__initfree_bootmem(unsigned long addr, unsigned long size){ bootmem_data_t *bdata;-
list_for_each_entry(bdata, &bdata_list, list)
-free_bootmem_core(bdata, addr, size);
+ unsigned long pos = addr;
+ unsigned long partsize = size;
+
+list_for_each_entry(bdata, &bdata_list, list){
+ unsigned long remainder = 0;
+
+ if (pos <bdata->node_boot_start)
+ continue;
+
+ if (PFN_DOWN(pos + partsize)>bdata->node_low_pfn) {
+ remainder =PFN_DOWN(pos + partsize)-bdata->node_low_pfn;
+ partsize -= remainder;
+ }
+
+free_bootmem_core(bdata, pos, partsize);
+
+ if (!remainder)
+ return;
+
+ pos =PFN_PHYS(bdata->node_low_pfn + 1);
+ }
+ printk(KERN_ERR "free_bootmem: request: addr=%lx, size=%lx, "
+ "state: pos=%lx, partsize=%lx\n", addr, size,
+ pos, partsize);
+BUG();
}Quoted 2 lines
unsigned long
__initfree_all_bootmem(void)it will not work with cross nodes.
for example: node 0: 0-2g, 4-6g, node1: 2-4g, 6-8g.
and if ramdisk sit cross 2G boundary. you will only free the range before 2g.
Quoted 6 lines
Quoted 4 lines
Yes, you stated that several times but this is not a technical argument:
These setups are afaik not yet supported by the kernel at all. And you could not explain the node layout with the patch that implements support for these configurations.I looked at Suresh's patch, and it still only has one bdata for one node.
Suresh's patch already in the Linus tree.
commit 6ec6e0d9f2fd7cb6ca6bc3bfab5ae7b5cdd8c36f
Author: Suresh Siddha <[email protected]> Date: Tue Mar 25 10:14:35 2008 -0700
srat, x86: add support for nodes spanning other nodes
For example, If the physical address layout on a two node system with 8 GB memory is something like:
node 0: 0-2GB, 4-6GB
node 1: 2-4GB, 6-8GB
Current kernels fail to boot/detect this NUMA topology.
ACPI SRAT tables can expose such a topology which needs to be supported.
YH
Re: [patch] mm: node-setup agnostic free_bootmem()
Hi,
Quoted 122 lines · Yinghai Lu
Quoted 102 lines · Yinghai Lu
Quoted 100 lines · Johannes Weiner
Hi Yinghai,
Quoted 93 lines · Yinghai Lu
Quoted 84 lines · Ingo Molnar
Quoted 6 lines · Johannes Weiner
Quoted 2 lines
so i very much agree that your changes are cleaner, i just wanted to have one that has all the fixes included.
I had planned this to be another patch because there are more then one boundary check I wanted to tighten. I can merge them though if you like.
no, better to have them in separate patches.
Quoted 5 lines
Quoted 2 lines
Would you like to post a patch against current -git or should i extract the cleaner
reserve_bootmem()from your previous patch?I just moved and have only sporadic internet access and free time slots available. Would be nice if you could do it!
sure, find the merged patch below, against latest -git, boot-tested on x86. Is this what you had in mind?
Ingo
---------------->
Subject: mm: node-setup agnosticfree_bootmem()
From: Johannes Weiner <[email protected]>
Date: Wed, 16 Apr 2008 13:36:31 +0200Make
free_bootmem()look up the node holding the specified address range which lets it work transparently on single-node and multi-node configurations.If the address range exceeds the node range, it well be marked free across node boundaries, too.
Signed-off-by Johannes Weiner <[email protected]>CC Andi Kleen <[email protected]>CC Yinghai Lu <[email protected]>CC Yasunori Goto <[email protected]>CC KAMEZAWA Hiroyuki <[email protected]>CC Christoph Lameter <[email protected]>CC Andrew Morton <[email protected]>Signed-off-by Ingo Molnar <[email protected]>---
mm/bootmem.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-)Index:
linux-x86.q/mm/bootmem.c
===================================================================
---linux-x86.q.orig/mm/bootmem.c
+++linux-x86.q/mm/bootmem.c
@@ -493,8 +493,31 @@ int__initreserve_bootmem(unsigned long
void__initfree_bootmem(unsigned long addr, unsigned long size){ bootmem_data_t *bdata;-
list_for_each_entry(bdata, &bdata_list, list)
-free_bootmem_core(bdata, addr, size);
+ unsigned long pos = addr;
+ unsigned long partsize = size;
+
+list_for_each_entry(bdata, &bdata_list, list){
+ unsigned long remainder = 0;
+
+ if (pos <bdata->node_boot_start)
+ continue;
+
+ if (PFN_DOWN(pos + partsize)>bdata->node_low_pfn) {
+ remainder =PFN_DOWN(pos + partsize)-bdata->node_low_pfn;
+ partsize -= remainder;
+ }
+
+free_bootmem_core(bdata, pos, partsize);
+
+ if (!remainder)
+ return;
+
+ pos =PFN_PHYS(bdata->node_low_pfn + 1);
+ }
+ printk(KERN_ERR "free_bootmem: request: addr=%lx, size=%lx, "
+ "state: pos=%lx, partsize=%lx\n", addr, size,
+ pos, partsize);
+BUG();
}Quoted 2 lines
unsigned long
__initfree_all_bootmem(void)it will not work with cross nodes.
for example: node 0: 0-2g, 4-6g, node1: 2-4g, 6-8g.
and if ramdisk sit cross 2G boundary. you will only free the range before 2g.Quoted 6 lines
Quoted 4 lines
Yes, you stated that several times but this is not a technical argument:
These setups are afaik not yet supported by the kernel at all. And you could not explain the node layout with the patch that implements support for these configurations.I looked at Suresh's patch, and it still only has one bdata for one node.
Suresh's patch already in the Linus tree.
commit6ec6e0d9f2fd7cb6ca6bc3bfab5ae7b5cdd8c36fAuthor: Suresh Siddha <[email protected]> Date: Tue Mar 25 10:14:35 2008 -0700srat, x86: add support for nodes spanning other nodes
For example, If the physical address layout on a two node system with 8 GB memory is something like:
node 0: 0-2GB, 4-6GB
node 1: 2-4GB, 6-8GB
Quoted 7 lines
Current kernels fail to boot/detect this NUMA topology.
ACPI SRAT tables can expose such a topology which needs to be supported.
Signed-off-by Suresh Siddha <[email protected]>Signed-off-by Ingo Molnar <[email protected]>Signed-off-by Thomas Gleixner <[email protected]>
Okay, so we have one bdata for node 0 and one for node 1. Does that mean that both have overlapping pfn ranges?
[1 ||||| ]
[2 ||||| ]
Like this? How are the ||||| represented in the bootmem maps of each bdata?
Hannes
Re: [patch] mm: node-setup agnostic free_bootmem()
Quoted 135 lines · Johannes Weiner
Hi,
Quoted 122 lines · Yinghai Lu
Quoted 102 lines · Yinghai Lu
Quoted 100 lines · Johannes Weiner
Hi Yinghai,
Quoted 93 lines · Yinghai Lu
Quoted 84 lines · Ingo Molnar
Quoted 6 lines · Johannes Weiner
Quoted 2 lines
so i very much agree that your changes are cleaner, i just wanted to have one that has all the fixes included.
I had planned this to be another patch because there are more then one boundary check I wanted to tighten. I can merge them though if you like.
no, better to have them in separate patches.
Quoted 5 lines
Quoted 2 lines
Would you like to post a patch against current -git or should i extract the cleaner
reserve_bootmem()from your previous patch?I just moved and have only sporadic internet access and free time slots available. Would be nice if you could do it!
sure, find the merged patch below, against latest -git, boot-tested on x86. Is this what you had in mind?
Ingo
---------------->
Subject: mm: node-setup agnosticfree_bootmem()
From: Johannes Weiner <[email protected]>
Date: Wed, 16 Apr 2008 13:36:31 +0200Make
free_bootmem()look up the node holding the specified address range which lets it work transparently on single-node and multi-node configurations.If the address range exceeds the node range, it well be marked free across node boundaries, too.
Signed-off-by Johannes Weiner <[email protected]>CC Andi Kleen <[email protected]>CC Yinghai Lu <[email protected]>CC Yasunori Goto <[email protected]>CC KAMEZAWA Hiroyuki <[email protected]>CC Christoph Lameter <[email protected]>CC Andrew Morton <[email protected]>Signed-off-by Ingo Molnar <[email protected]>---
mm/bootmem.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-)Index:
linux-x86.q/mm/bootmem.c
===================================================================
---linux-x86.q.orig/mm/bootmem.c
+++linux-x86.q/mm/bootmem.c
@@ -493,8 +493,31 @@ int__initreserve_bootmem(unsigned long
void__initfree_bootmem(unsigned long addr, unsigned long size){ bootmem_data_t *bdata;-
list_for_each_entry(bdata, &bdata_list, list)
-free_bootmem_core(bdata, addr, size);
+ unsigned long pos = addr;
+ unsigned long partsize = size;
+
+list_for_each_entry(bdata, &bdata_list, list){
+ unsigned long remainder = 0;
+
+ if (pos <bdata->node_boot_start)
+ continue;
+
+ if (PFN_DOWN(pos + partsize)>bdata->node_low_pfn) {
+ remainder =PFN_DOWN(pos + partsize)-bdata->node_low_pfn;
+ partsize -= remainder;
+ }
+
+free_bootmem_core(bdata, pos, partsize);
+
+ if (!remainder)
+ return;
+
+ pos =PFN_PHYS(bdata->node_low_pfn + 1);
+ }
+ printk(KERN_ERR "free_bootmem: request: addr=%lx, size=%lx, "
+ "state: pos=%lx, partsize=%lx\n", addr, size,
+ pos, partsize);
+BUG();
}Quoted 2 lines
unsigned long
__initfree_all_bootmem(void)it will not work with cross nodes.
for example: node 0: 0-2g, 4-6g, node1: 2-4g, 6-8g.
and if ramdisk sit cross 2G boundary. you will only free the range before 2g.Quoted 6 lines
Quoted 4 lines
Yes, you stated that several times but this is not a technical argument:
These setups are afaik not yet supported by the kernel at all. And you could not explain the node layout with the patch that implements support for these configurations.I looked at Suresh's patch, and it still only has one bdata for one node.
Suresh's patch already in the Linus tree.
commit6ec6e0d9f2fd7cb6ca6bc3bfab5ae7b5cdd8c36fAuthor: Suresh Siddha <[email protected]> Date: Tue Mar 25 10:14:35 2008 -0700srat, x86: add support for nodes spanning other nodes
For example, If the physical address layout on a two node system with 8 GB memory is something like:
node 0: 0-2GB, 4-6GB
node 1: 2-4GB, 6-8GBQuoted 7 lines
Current kernels fail to boot/detect this NUMA topology.
ACPI SRAT tables can expose such a topology which needs to be supported.
Signed-off-by Suresh Siddha <[email protected]>Signed-off-by Ingo Molnar <[email protected]>Signed-off-by Thomas Gleixner <[email protected]>
Quoted 7 lines
Okay, so we have one bdata for node 0 and one for node 1. Does that mean that both have overlapping pfn ranges?
[1 ||||| ]
[2 ||||| ]Like this? How are the ||||| represented in the bootmem maps of each bdata?
Yes.
YH
Re: [patch] mm: node-setup agnostic free_bootmem()
Hi,
Quoted 139 lines · Yinghai Lu
Quoted 138 lines · Johannes Weiner
Hi,
Quoted 122 lines · Yinghai Lu
Quoted 102 lines · Yinghai Lu
Quoted 100 lines · Johannes Weiner
Hi Yinghai,
Quoted 93 lines · Yinghai Lu
Quoted 84 lines · Ingo Molnar
Quoted 6 lines · Johannes Weiner
Quoted 2 lines
so i very much agree that your changes are cleaner, i just wanted to have one that has all the fixes included.
I had planned this to be another patch because there are more then one boundary check I wanted to tighten. I can merge them though if you like.
no, better to have them in separate patches.
Quoted 5 lines
Quoted 2 lines
Would you like to post a patch against current -git or should i extract the cleaner
reserve_bootmem()from your previous patch?I just moved and have only sporadic internet access and free time slots available. Would be nice if you could do it!
sure, find the merged patch below, against latest -git, boot-tested on x86. Is this what you had in mind?
Ingo
---------------->
Subject: mm: node-setup agnosticfree_bootmem()
From: Johannes Weiner <[email protected]>
Date: Wed, 16 Apr 2008 13:36:31 +0200Make
free_bootmem()look up the node holding the specified address range which lets it work transparently on single-node and multi-node configurations.If the address range exceeds the node range, it well be marked free across node boundaries, too.
Signed-off-by Johannes Weiner <[email protected]>CC Andi Kleen <[email protected]>CC Yinghai Lu <[email protected]>CC Yasunori Goto <[email protected]>CC KAMEZAWA Hiroyuki <[email protected]>CC Christoph Lameter <[email protected]>CC Andrew Morton <[email protected]>Signed-off-by Ingo Molnar <[email protected]>---
mm/bootmem.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-)Index:
linux-x86.q/mm/bootmem.c
===================================================================
---linux-x86.q.orig/mm/bootmem.c
+++linux-x86.q/mm/bootmem.c
@@ -493,8 +493,31 @@ int__initreserve_bootmem(unsigned long
void__initfree_bootmem(unsigned long addr, unsigned long size){ bootmem_data_t *bdata;-
list_for_each_entry(bdata, &bdata_list, list)
-free_bootmem_core(bdata, addr, size);
+ unsigned long pos = addr;
+ unsigned long partsize = size;
+
+list_for_each_entry(bdata, &bdata_list, list){
+ unsigned long remainder = 0;
+
+ if (pos <bdata->node_boot_start)
+ continue;
+
+ if (PFN_DOWN(pos + partsize)>bdata->node_low_pfn) {
+ remainder =PFN_DOWN(pos + partsize)-bdata->node_low_pfn;
+ partsize -= remainder;
+ }
+
+free_bootmem_core(bdata, pos, partsize);
+
+ if (!remainder)
+ return;
+
+ pos =PFN_PHYS(bdata->node_low_pfn + 1);
+ }
+ printk(KERN_ERR "free_bootmem: request: addr=%lx, size=%lx, "
+ "state: pos=%lx, partsize=%lx\n", addr, size,
+ pos, partsize);
+BUG();
}Quoted 2 lines
unsigned long
__initfree_all_bootmem(void)it will not work with cross nodes.
for example: node 0: 0-2g, 4-6g, node1: 2-4g, 6-8g.
and if ramdisk sit cross 2G boundary. you will only free the range before 2g.Quoted 6 lines
Quoted 4 lines
Yes, you stated that several times but this is not a technical argument:
These setups are afaik not yet supported by the kernel at all. And you could not explain the node layout with the patch that implements support for these configurations.I looked at Suresh's patch, and it still only has one bdata for one node.
Suresh's patch already in the Linus tree.
commit6ec6e0d9f2fd7cb6ca6bc3bfab5ae7b5cdd8c36fAuthor: Suresh Siddha <[email protected]> Date: Tue Mar 25 10:14:35 2008 -0700srat, x86: add support for nodes spanning other nodes
For example, If the physical address layout on a two node system with 8 GB memory is something like:
node 0: 0-2GB, 4-6GB
node 1: 2-4GB, 6-8GBQuoted 7 lines
Current kernels fail to boot/detect this NUMA topology.
ACPI SRAT tables can expose such a topology which needs to be supported.
Signed-off-by Suresh Siddha <[email protected]>Signed-off-by Ingo Molnar <[email protected]>Signed-off-by Thomas Gleixner <[email protected]>Okay, so we have one bdata for node 0 and one for node 1. Does that mean that both have overlapping pfn ranges?
Quoted 6 lines
Quoted 4 lines
[1 ||||| ]
[2 ||||| ]Like this? How are the ||||| represented in the bootmem maps of each bdata?
Yes.
Okay. So they share the same PFNs. Now imagine the following scenario:
node0: 0-2GB, 4-6GB
node1: 2-4GB, 6-8GB
/* Marks the range on node0 and node1 */free_bootmem(1.5G, 2G);
/* Frees all bootmem on both nodes */
free_all_bootmem_node(NODE_DATA(0));
free_all_bootmem_node(NODE_DATA(1));
Aren't the same page descriptors send to __free_bootmem_pages() twice?
Hannes
Re: [patch] mm: node-setup agnostic free_bootmem()
Quoted 156 lines · Johannes Weiner
Hi,
Quoted 139 lines · Yinghai Lu
Quoted 138 lines · Johannes Weiner
Hi,
Quoted 122 lines · Yinghai Lu
Quoted 102 lines · Yinghai Lu
Quoted 100 lines · Johannes Weiner
Hi Yinghai,
Quoted 93 lines · Yinghai Lu
Quoted 84 lines · Ingo Molnar
Quoted 6 lines · Johannes Weiner
Quoted 2 lines
so i very much agree that your changes are cleaner, i just wanted to have one that has all the fixes included.
I had planned this to be another patch because there are more then one boundary check I wanted to tighten. I can merge them though if you like.
no, better to have them in separate patches.
Quoted 5 lines
Quoted 2 lines
Would you like to post a patch against current -git or should i extract the cleaner
reserve_bootmem()from your previous patch?I just moved and have only sporadic internet access and free time slots available. Would be nice if you could do it!
sure, find the merged patch below, against latest -git, boot-tested on x86. Is this what you had in mind?
Ingo
---------------->
Subject: mm: node-setup agnosticfree_bootmem()
From: Johannes Weiner <[email protected]>
Date: Wed, 16 Apr 2008 13:36:31 +0200Make
free_bootmem()look up the node holding the specified address range which lets it work transparently on single-node and multi-node configurations.If the address range exceeds the node range, it well be marked free across node boundaries, too.
Signed-off-by Johannes Weiner <[email protected]>CC Andi Kleen <[email protected]>CC Yinghai Lu <[email protected]>CC Yasunori Goto <[email protected]>CC KAMEZAWA Hiroyuki <[email protected]>CC Christoph Lameter <[email protected]>CC Andrew Morton <[email protected]>Signed-off-by Ingo Molnar <[email protected]>---
mm/bootmem.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-)Index:
linux-x86.q/mm/bootmem.c
===================================================================
---linux-x86.q.orig/mm/bootmem.c
+++linux-x86.q/mm/bootmem.c
@@ -493,8 +493,31 @@ int__initreserve_bootmem(unsigned long
void__initfree_bootmem(unsigned long addr, unsigned long size){ bootmem_data_t *bdata;-
list_for_each_entry(bdata, &bdata_list, list)
-free_bootmem_core(bdata, addr, size);
+ unsigned long pos = addr;
+ unsigned long partsize = size;
+
+list_for_each_entry(bdata, &bdata_list, list){
+ unsigned long remainder = 0;
+
+ if (pos <bdata->node_boot_start)
+ continue;
+
+ if (PFN_DOWN(pos + partsize)>bdata->node_low_pfn) {
+ remainder =PFN_DOWN(pos + partsize)-bdata->node_low_pfn;
+ partsize -= remainder;
+ }
+
+free_bootmem_core(bdata, pos, partsize);
+
+ if (!remainder)
+ return;
+
+ pos =PFN_PHYS(bdata->node_low_pfn + 1);
+ }
+ printk(KERN_ERR "free_bootmem: request: addr=%lx, size=%lx, "
+ "state: pos=%lx, partsize=%lx\n", addr, size,
+ pos, partsize);
+BUG();
}Quoted 2 lines
unsigned long
__initfree_all_bootmem(void)it will not work with cross nodes.
for example: node 0: 0-2g, 4-6g, node1: 2-4g, 6-8g.
and if ramdisk sit cross 2G boundary. you will only free the range before 2g.Quoted 6 lines
Quoted 4 lines
Yes, you stated that several times but this is not a technical argument:
These setups are afaik not yet supported by the kernel at all. And you could not explain the node layout with the patch that implements support for these configurations.I looked at Suresh's patch, and it still only has one bdata for one node.
Suresh's patch already in the Linus tree.
commit6ec6e0d9f2fd7cb6ca6bc3bfab5ae7b5cdd8c36fAuthor: Suresh Siddha <[email protected]> Date: Tue Mar 25 10:14:35 2008 -0700srat, x86: add support for nodes spanning other nodes
For example, If the physical address layout on a two node system with 8 GB memory is something like:
node 0: 0-2GB, 4-6GB
node 1: 2-4GB, 6-8GBQuoted 7 lines
Current kernels fail to boot/detect this NUMA topology.
ACPI SRAT tables can expose such a topology which needs to be supported.
Signed-off-by Suresh Siddha <[email protected]>Signed-off-by Ingo Molnar <[email protected]>Signed-off-by Thomas Gleixner <[email protected]>Okay, so we have one bdata for node 0 and one for node 1. Does that mean that both have overlapping pfn ranges?
Quoted 6 lines
Quoted 4 lines
[1 ||||| ]
[2 ||||| ]Like this? How are the ||||| represented in the bootmem maps of each bdata?
Yes.
Okay. So they share the same PFNs. Now imagine the following scenario:
node0: 0-2GB, 4-6GB
node1: 2-4GB, 6-8GB
Quoted 8 lines
/* Marks the range on node0 and node1 */
free_bootmem(1.5G, 2G);/* Frees all bootmem on both nodes */
free_all_bootmem_node(NODE_DATA(0));
free_all_bootmem_node(NODE_DATA(1));Aren't the same page descriptors send to
__free_bootmem_pages()twice?
yeah, there is some problem....
may need to ask every node took another node_bootmem_not_use_map ...to record the holes.
YH
Re: [patch] mm: node-setup agnostic free_bootmem()
In reply to Ingo MolnarHi Ingo,
Quoted 10 lines · Ingo Molnar
Quoted 6 lines · Johannes Weiner
Quoted 2 lines
so i very much agree that your changes are cleaner, i just wanted to have one that has all the fixes included.
I had planned this to be another patch because there are more then one boundary check I wanted to tighten. I can merge them though if you like.
no, better to have them in separate patches.
Okay.
Quoted 63 lines
Quoted 5 lines
Quoted 2 lines
Would you like to post a patch against current -git or should i extract the cleaner
reserve_bootmem()from your previous patch?I just moved and have only sporadic internet access and free time slots available. Would be nice if you could do it!
sure, find the merged patch below, against latest -git, boot-tested on x86. Is this what you had in mind?
Ingo
---------------->
Subject: mm: node-setup agnosticfree_bootmem()
From: Johannes Weiner <[email protected]>
Date: Wed, 16 Apr 2008 13:36:31 +0200Make
free_bootmem()look up the node holding the specified address range which lets it work transparently on single-node and multi-node configurations.If the address range exceeds the node range, it well be marked free across node boundaries, too.
Signed-off-by Johannes Weiner <[email protected]>CC Andi Kleen <[email protected]>CC Yinghai Lu <[email protected]>CC Yasunori Goto <[email protected]>CC KAMEZAWA Hiroyuki <[email protected]>CC Christoph Lameter <[email protected]>CC Andrew Morton <[email protected]>Signed-off-by Ingo Molnar <[email protected]>--- mm/bootmem.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-)Index:
linux-x86.q/mm/bootmem.c
===================================================================mm/bootmem.c +18
-2@@ -493,8 +493,31 @@ int __init reserve_bootmem(unsigned longvoid __init free_bootmem (unsigned long addr,unsigned long size) {bootmem_data_t *bdata; -list_for_each_entry (bdata, &bdata_list, list) -free_bootmem_core (bdata, addr, size); +unsigned long pos = addr; +unsigned long partsize = size; + +list_for_each_entry (bdata, &bdata_list, list) { +unsigned long remainder =0 ; + +if (pos < bdata->node_boot_start) +continue ; + +if (PFN_DOWN (pos + partsize) > bdata->node_low_pfn) { + remainder =PFN_DOWN (pos + partsize) - bdata->node_low_pfn; + partsize -= remainder; + } + +free_bootmem_core (bdata, pos, partsize); + +if (!remainder) +return ;
mm/bootmem.c int __init reserve_bootmem(unsigned long · line 523
Quoted 10 lines
mm/bootmem.c +7
-0+ + pos =PFN_PHYS (bdata->node_low_pfn +1 ); + } +printk (KERN_ERR "free_bootmem: request: addr=%lx, size=%lx, " +"state: pos=%lx, partsize=%lx\n" , addr, size, + pos, partsize); +BUG (); }unsigned long __init free_all_bootmem (void )
Yes, looks good. But needs explicit testing, I guess.
Hannes
Re: [patch] mm: node-setup agnostic free_bootmem()
Quoted 32 lines · Johannes Weiner
Quoted 32 lines
void
__initfree_bootmem(unsigned long addr, unsigned long size){mm/bootmem.c +25
-2bootmem_data_t *bdata; -list_for_each_entry (bdata, &bdata_list, list) -free_bootmem_core (bdata, addr, size); +unsigned long pos = addr; +unsigned long partsize = size; + +list_for_each_entry (bdata, &bdata_list, list) { +unsigned long remainder =0 ; + +if (pos < bdata->node_boot_start) +continue ; + +if (PFN_DOWN (pos + partsize) > bdata->node_low_pfn) { + remainder =PFN_DOWN (pos + partsize) - bdata->node_low_pfn; + partsize -= remainder; + } + +free_bootmem_core (bdata, pos, partsize); + +if (!remainder) +return ; + + pos =PFN_PHYS (bdata->node_low_pfn +1 ); + } +printk (KERN_ERR "free_bootmem: request: addr=%lx, size=%lx, " +"state: pos=%lx, partsize=%lx\n" , addr, size, + pos, partsize); +BUG (); }
Quoted 3 lines
Quoted 1 line
unsigned long
__initfree_all_bootmem(void)Yes, looks good. But needs explicit testing, I guess.
yep, but as Yinghai Lu has pointed it out, this removes a cross-node allocation fix. That fix has to be preserved in any cleanup, agreed?
in general bootmem should assume the weirdest of NUMA topologies and be defensive about them. Topologies will only become more complex, never less complex.
Ingo
Re: [patch] mm: node-setup agnostic free_bootmem()
Hi,
Quoted 34 lines · Ingo Molnar
Quoted 32 lines · Johannes Weiner
Quoted 32 lines
void
__initfree_bootmem(unsigned long addr, unsigned long size){mm/bootmem.c +25
-2bootmem_data_t *bdata; -list_for_each_entry (bdata, &bdata_list, list) -free_bootmem_core (bdata, addr, size); +unsigned long pos = addr; +unsigned long partsize = size; + +list_for_each_entry (bdata, &bdata_list, list) { +unsigned long remainder =0 ; + +if (pos < bdata->node_boot_start) +continue ; + +if (PFN_DOWN (pos + partsize) > bdata->node_low_pfn) { + remainder =PFN_DOWN (pos + partsize) - bdata->node_low_pfn; + partsize -= remainder; + } + +free_bootmem_core (bdata, pos, partsize); + +if (!remainder) +return ; + + pos =PFN_PHYS (bdata->node_low_pfn +1 ); + } +printk (KERN_ERR "free_bootmem: request: addr=%lx, size=%lx, " +"state: pos=%lx, partsize=%lx\n" , addr, size, + pos, partsize); +BUG (); }
Quoted 6 lines
Quoted 3 lines
Quoted 1 line
unsigned long
__initfree_all_bootmem(void)Yes, looks good. But needs explicit testing, I guess.
yep, but as Yinghai Lu has pointed it out, this removes a cross-node allocation fix. That fix has to be preserved in any cleanup, agreed?
Yes, if Yinghai is right, my patch should be dropped, of course.
Quoted 3 lines
in general bootmem should assume the weirdest of NUMA topologies and be defensive about them. Topologies will only become more complex, never less complex.
Okay.
Hannes
Re: [git pull] "big box" x86 changes, bootmem/sparsemem
In reply to Johannes WeinerQuoted 33 lines · Johannes Weiner
Hi Ingo,
Quoted 17 lines · Ingo Molnar
Quoted 4 lines · Linus Torvalds
IOW, they'd be big enough that people hopefully don't start nitpicking about some *totally* uninteresting small detail, but small enough that people can read it through without losing concentration about a quarter of the way in.
ok. Here's the "memory management" type of changes:
git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86-bigbox-bootmem.git for-linusthe other sub-trees will depend on these changes. I think these infrastructure and other improvements are mergable and pullable as-is.
Ingo
------------------>
[...]
Quoted 1 line
mm: allow
reserve_bootmem()cross nodesI find it sad that this goes in now. I wrote a clean version of
reserve_bootmem()[1] and it was rejected with arguments that I did not understand [2] and that were not further explained even though I asked for it [3].
Quoted 8 lines
http://lkml.org/lkml/2008/4/16/76
http://lkml.org/lkml/2008/4/16/234
http://lkml.org/lkml/2008/4/16/250Your comment was rather unfair, because it gave the impression you did not read the thread before replying. And you did not react to other explicit questions from me. If you find my patches to be crap, say so and please explain WHY so I have a chance to improve.
this thread is for reserve_bootmem ?
You patch is regarding to free_bootmem, and it doesn't work with intel cross node boxes.
YH
Re: [git pull] "big box" x86 changes, bootmem/sparsemem
Hi,
Quoted 38 lines · Yinghai Lu
Quoted 37 lines · Johannes Weiner
Hi Ingo,
Quoted 17 lines · Ingo Molnar
Quoted 4 lines · Linus Torvalds
IOW, they'd be big enough that people hopefully don't start nitpicking about some *totally* uninteresting small detail, but small enough that people can read it through without losing concentration about a quarter of the way in.
ok. Here's the "memory management" type of changes:
git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86-bigbox-bootmem.git for-linusthe other sub-trees will depend on these changes. I think these infrastructure and other improvements are mergable and pullable as-is.
Ingo
------------------>
[...]
Quoted 1 line
mm: allow
reserve_bootmem()cross nodesI find it sad that this goes in now. I wrote a clean version of
reserve_bootmem()[1] and it was rejected with arguments that I did not understand [2] and that were not further explained even though I asked for it [3].http://lkml.org/lkml/2008/4/16/76
http://lkml.org/lkml/2008/4/16/234
http://lkml.org/lkml/2008/4/16/250
Quoted 6 lines
Quoted 4 lines
Your comment was rather unfair, because it gave the impression you did not read the thread before replying. And you did not react to other explicit questions from me. If you find my patches to be crap, say so and please explain WHY so I have a chance to improve.
this thread is for
reserve_bootmem?
Sorry, my mistake. I was referring to
5a982cbc7b3fe6cf72266f319286f29963c71b9e: mm: fix boundary checking in free_bootmem_core
Hannes
[git pull] "big box" x86 changes, boot protocol
In reply to Linus TorvaldsLinus, please pull the following x86 changes from:
git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86-bigbox-bootparam.git for-linus
these are boot parameter extensions for really large SGI UV boxes. The change was seen and acked by the boot protocol guys. (well, Peter that is ;-)
Thanks,
Ingo
------------------>
Huang, Ying (4):
x86, boot: add free_early to early reservation machanism x86, boot: add linked list of struct setup_data x86, boot: export linked list of struct setup_data via debugfs x86, boot: Document for linked list of struct setup_data
Documentation/i386/boot.txt | 26 +++++++ arch/x86/boot/header.S | 6 ++- arch/x86/kernel/e820_64.c | 22 ++++++ arch/x86/kernel/head64.c | 20 +++++ arch/x86/kernel/kdebugfs.c | 163 +++++++++++++++++++++++++++++++++++++++++-- arch/x86/kernel/setup_64.c | 24 ++++++ include/asm-x86/bootparam.h | 14 ++++ include/asm-x86/e820_64.h | 1 + 8 files changed, 270 insertions(+), 6 deletions(-)
Documentation/i386/boot.txt +26 -0
@@ -42,6 +42,8 @@ Protocol 2.05: (Kernel 2.6.20) Make protected mode kernel relocatable. Protocol 2.06: (Kernel 2.6.22) Added a field that contains the size of the boot command line +Protocol 2.09: (kernel 2.6.26) Added a field of 64-bit physical + pointer to single linked list of struct setup_data. **** MEMORY LAYOUT
@@ -172,6 +174,8 @@ Offset Proto Name Meaning 0240/8 2.07+ hardware_subarch_data Subarchitecture-specific data 0248/4 2.08+ payload_offset Offset of kernel payload 024C/4 2.08+ payload_length Length of kernel payload +0250/8 2.09+ setup_data 64-bit physical pointer to linked list + of struct setup_data (1) For backwards compatibility, if the setup_sects field contains 0, the real value is 4.
@@ -572,6 +576,28 @@ command line is entered using the following protocol: covered by setup_move_size, so you may need to adjust this field. +Field name: setup_data +Type: write (obligatory) +Offset/size: 0x250/8 +Protocol: 2.09+ + + The 64-bit physical pointer to NULL terminated single linked list of + struct setup_data. This is used to define a more extensible boot + parameters passing mechanism. The definition of struct setup_data is + as follow: + + struct setup_data { + u64 next; + u32 type; + u32 len; + u8 data[0]; + }; + + Where, the next is a 64-bit physical pointer to the next node of + linked list, the next field of the last node is 0; the type is used + to identify the contents of data; the len is the length of data + field; the data holds the real payload. + **** MEMORY LAYOUT OF THE REAL-MODE CODE
arch/x86/boot/header.S +5 -1
@@ -120,7 +120,7 @@ _start: # Part 2 of the header, from the old setup.S .ascii "HdrS" # header signature - .word 0x0208 # header version number (>= 0x0105) + .word 0x0209 # header version number (>= 0x0105) # or else old loadlin-1.5 will fail) .globl realmode_swtch realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
@@ -227,6 +227,10 @@ hardware_subarch_data: .quad 0 payload_offset: .long input_data payload_length: .long input_data_end-input_data +setup_data: .quad 0 # 64-bit physical pointer to + # single linked list of + # struct setup_data + # End of setup header ##################################################### .section ".inittext", "ax"
arch/x86/kernel/e820_64.c +22 -0
@@ -84,6 +84,28 @@ void __init reserve_early(unsigned long start, unsigned long end, char *name)strncpy (r->name, name,sizeof (r->name) -1 ); } +void __init free_early (unsigned long start,unsigned long end) +{ +struct early_res *r; +int i, j; + +for (i =0 ; i <MAX_EARLY_RES && early_res[i].end; i++) { + r = &early_res[i]; +if (start == r->start && end == r->end) +break ; + } +if (i >=MAX_EARLY_RES || !early_res[i].end) +panic ("free_early on not reserved area: %lx-%lx!" , start, end); + +for (j = i +1 ; j <MAX_EARLY_RES && early_res[j].end; j++) + ; + +memcpy (&early_res[i], &early_res[i +1 ], + (j -1 - i) *sizeof (struct early_res )); + + early_res[j -1 ].end =0 ; +} +void __init early_res_to_bootmem (void ) {int i;
arch/x86/kernel/head64.c +20 -0
@@ -11,6 +11,7 @@#include <linux/string.h> #include <linux/percpu.h> #include <linux/start_kernel.h> +#include <linux/io.h> #include <asm/processor.h> #include <asm/proto.h>
@@ -100,6 +101,24 @@ static void __init reserve_ebda_region(void)reserve_early (lowmem,0x100000 ,"BIOS reserved" ); } +static void __init reserve_setup_data (void ) +{ +struct setup_data *data; +unsigned long pa_data; +char buf[32 ]; + +if (boot_params.hdr.version <0x0209 ) +return ; + pa_data = boot_params.hdr.setup_data; +while (pa_data) { + data =early_ioremap (pa_data,sizeof (*data)); +sprintf (buf,"setup data %x" , data->type); +reserve_early (pa_data, pa_data+sizeof (*data)+data->len, buf); + pa_data = data->next; +early_iounmap (data,sizeof (*data)); + } +} +void __init x86_64_start_kernel (char * real_mode_data) {int i;
@@ -156,6 +175,7 @@ void __init x86_64_start_kernel(char * real_mode_data)#endif reserve_ebda_region (); +reserve_setup_data ();/* * At this point everything still needed from the boot loader
arch/x86/kernel/kdebugfs.c +158 -5
193 lines not on this page · raw message
arch/x86/kernel/setup_64.c +24 -0
@@ -264,6 +264,28 @@ void __attribute__((weak)) __init memory_setup(void)machine_specific_memory_setup (); } +static void __init parse_setup_data (void ) +{ +struct setup_data *data; +unsigned long pa_data; + +if (boot_params.hdr.version <0x0209 ) +return ; + pa_data = boot_params.hdr.setup_data; +while (pa_data) { + data =early_ioremap (pa_data,PAGE_SIZE ); +switch (data->type) { +default : +break ; + } +#ifndef CONFIG_DEBUG_BOOT_PARAMS +free_early (pa_data, pa_data+sizeof (*data)+data->len); +#endif + pa_data = data->next; +early_iounmap (data,PAGE_SIZE ); + } +} +/* * setup_arch - architecture-specific boot-time initializations *
@@ -316,6 +338,8 @@ void __init setup_arch(char **cmdline_p)strlcpy (command_line, boot_command_line,COMMAND_LINE_SIZE ); *cmdline_p = command_line; +parse_setup_data (); +parse_early_param ();#ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT
include/asm-x86/bootparam.h +14 -0
@@ -9,6 +9,17 @@#include <asm/ist.h> #include <video/edid.h> +/* setup data types */ +#define SETUP_NONE 0 + +/* extensible setup data list node */ +struct setup_data { +u64 next; +u32 type; +u32 len; +u8 data[0 ]; +}; +struct setup_header {__u8 setup_sects;__u16 root_flags;
@@ -46,6 +57,9 @@ struct setup_header {__u32 cmdline_size;__u32 hardware_subarch;__u64 hardware_subarch_data; +__u32 payload_offset; +__u32 payload_length; +__u64 setup_data; } __attribute__((packed));struct sys_desc_table {
include/asm-x86/e820_64.h +1 -0
@@ -48,6 +48,7 @@ extern struct e820map e820;extern void update_e820 (void );extern void reserve_early (unsigned long start,unsigned long end,char *name); +extern void free_early (unsigned long start,unsigned long end);extern void early_res_to_bootmem (void );#endif /*!__ASSEMBLY__*/
Andrew Morton
maintainerRe: [git pull] "big box" x86 changes, boot protocol
Quoted 19 lines · On Sat, 26 Apr 2008 21:54:07 +0200 Ingo Molnar <[email protected]> wrote:
Linus, please pull the following x86 changes from:
git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86-bigbox-bootparam.git for-linusthese are boot parameter extensions for really large SGI UV boxes. The change was seen and acked by the boot protocol guys. (well, Peter that is ;-)
...
arch/x86/kernel/e820_64.c +8
-0+void __init free_early (unsigned long start,unsigned long end) +{ +struct early_res *r; +int i, j; + +for (i =0 ; i <MAX_EARLY_RES && early_res[i].end; i++) { + r = &early_res[i]; +if (start == r->start && end == r->end)
arch/x86/kernel/e820_64.c void __init reserve_early(unsigned long start, unsigned long end, char *name) · line 104
Quoted 10 lines
arch/x86/kernel/e820_64.c +10
-0+break ; + } +if (i >=MAX_EARLY_RES || !early_res[i].end) +panic ("free_early on not reserved area: %lx-%lx!" , start, end); + +for (j = i +1 ; j <MAX_EARLY_RES && early_res[j].end; j++) + ; + +memcpy (&early_res[i], &early_res[i +1 ], + (j -1 - i) *sizeof (struct early_res ));
nit: memcpy() shouldn't be used for overlapping copies. It happens to be OK (for dst<src) in the kernel implementations. We hope.
Quoted 34 lines
arch/x86/kernel/kdebugfs.c +33
-0+ early_res[j -1 ].end =0 ; +} + +static ssize_t +setup_data_read (struct file *file,char __user *user_buf,size_t count, +loff_t *ppos) +{ +struct setup_data_node *node = file->private_data; +unsigned long remain; +loff_t pos = *ppos; +struct page *pg; +void *p; +u64 pa; + +if (pos <0 ) +return -EINVAL ; +if (pos >= node->len) +return 0 ; + +if (count > node->len - pos) + count = node->len - pos; + pa = node->paddr +sizeof (struct setup_data ) + pos; + pg =pfn_to_page ((pa + count -1 ) >>PAGE_SHIFT ); +if (PageHighMem (pg)) { + p =ioremap_cache (pa, count); +if (!p) +return -ENXIO ; + }else { + p =__va (pa); + } + + remain =copy_to_user (user_buf, p, count); +
arch/x86/kernel/kdebugfs.c line 64
Quoted 10 lines
arch/x86/kernel/kdebugfs.c +10
-0+if (PageHighMem (pg)) +iounmap (p); + +if (remain) +return -EFAULT ; + + *ppos = pos + count; + +return count; +}
nit2: a read() function should return the number of bytes copied, and should advance the file pointer by that much. This code fails to do this when a partial copy_to_user() occurs.
But we've made that mistake in many places and it doesn't appear to matter.
Re: [git pull] "big box" x86 changes, boot protocol
Quoted 17 lines · Andrew Morton
On Sat, 26 Apr 2008 21:54:07 +0200 Ingo Molnar <[email protected]> wrote:
...Quoted 15 lines
arch/x86/kernel/e820_64.c +14
-0+void __init free_early (unsigned long start,unsigned long end) +{ +struct early_res *r; +int i, j; + +for (i =0 ; i <MAX_EARLY_RES && early_res[i].end; i++) { + r = &early_res[i]; +if (start == r->start && end == r->end) +break ; + } +if (i >=MAX_EARLY_RES || !early_res[i].end) +panic ("free_early on not reserved area: %lx-%lx!" , start, end); + +for (j = i +1 ; j <MAX_EARLY_RES && early_res[j].end; j++)
Quoted 8 lines
arch/x86/kernel/e820_64.c void __init reserve_early(unsigned long start, unsigned long end, char *name) · line 104
Quoted 4 lines
arch/x86/kernel/e820_64.c +4
-0+ ; + +memcpy (&early_res[i], &early_res[i +1 ], + (j -1 - i) *sizeof (struct early_res ));nit:
memcpy()shouldn't be used for overlapping copies. It happens to be OK (for dst<src) in the kernel implementations. We hope.
...
We always use the gcc builtin for memcpy() here.
cu
Adrian
Signature · 4 lines
"Is there not promise of rain?" Ling Tan asked suddenly out
of the darkness. There had been need of rain for many days.
"Only a promise," Lao Er said.
Pearl S. Buck - Dragon SeedH. Peter Anvin
reviewerRe: [git pull] "big box" x86 changes, boot protocol
Quoted 9 lines · Adrian Bunk
Quoted 6 lines
arch/x86/kernel/e820_64.c void __init reserve_early(unsigned long start, unsigned long end, char *name) · line 104
Quoted 2 lines
arch/x86/kernel/e820_64.c +2
-0+memcpy (&early_res[i], &early_res[i +1 ], + (j -1 - i) *sizeof (struct early_res ));nit:
memcpy()shouldn't be used for overlapping copies. It happens to be OK (for dst<src) in the kernel implementations. We hope.
...We always use the gcc builtin for
memcpy()here.
You have to do something pretty weird for memcpy() to not work for
dst <= src even with overlap; this usually involves architectures that have explicit cache control instructions to establish the dst in the cache, if used before src is read.
This is not an issue on x86, though.
-hpa
Re: [git pull] "big box" x86 changes, boot protocol
In reply to Adrian BunkQuoted 11 lines · Adrian Bunk
Quoted 9 lines · Andrew Morton
On Sat, 26 Apr 2008 21:54:07 +0200 Ingo Molnar <[email protected]> wrote:
...arch/x86/kernel/e820_64.c void __init reserve_early(unsigned long start, unsigned long end, char *name) · line 104
Quoted 3 lines
arch/x86/kernel/e820_64.c +3
-0+ +memcpy (&early_res[i], &early_res[i +1 ], + (j -1 - i) *sizeof (struct early_res ));nit:
memcpy()shouldn't be used for overlapping copies. It happens to be OK (for dst<src) in the kernel implementations. We hope.
...
Quoted 1 line
We always use the gcc builtin for
memcpy()here.
It's probably hard to write a reasonable x86 memcpy() that wouldn't happen to do the right thing for this case, but I do agee - we should still use memmove() for this, just to make it clear that it does overlapping things.
Linus
Re: [git pull] "big box" x86 changes, boot protocol
Quoted 6 lines · Linus Torvalds
Quoted 1 line
We always use the gcc builtin for
memcpy()here.It's probably hard to write a reasonable x86
memcpy()that wouldn't happen to do the right thing for this case, but I do agee - we should still usememmove()for this, just to make it clear that it does overlapping things.
agreed, i queued up the patch below.
Ingo
------------->
Subject: bootprotocol: cleanup
From: Ingo Molnar <[email protected]>
Date: Sat Apr 26 23:14:36 CEST 2008
--- arch/x86/kernel/e820_64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/kernel/e820_64.c +1 -1
@@ -100,7 +100,7 @@ void __init free_early(unsigned long stafor (j = i +1 ; j <MAX_EARLY_RES && early_res[j].end; j++) ; -memcpy (&early_res[i], &early_res[i +1 ], +memmove (&early_res[i], &early_res[i +1 ], (j -1 - i) *sizeof (struct early_res )); early_res[j -1 ].end =0 ;
Re: [git pull] "big box" x86 changes, boot protocol
In reply to Andrew MortonQuoted 7 lines · Andrew Morton
arch/x86/kernel/e820_64.c void __init reserve_early(unsigned long start, unsigned long end, char *name) · line 104
Quoted 3 lines
arch/x86/kernel/e820_64.c +2
-0+memcpy (&early_res[i], &early_res[i +1 ], + (j -1 - i) *sizeof (struct early_res ));nit:
memcpy()shouldn't be used for overlapping copies. It happens to be OK (for dst<src) in the kernel implementations. We hope.
Definitely shouldn't be assumed. At one point in the distant past I had a ppc memcpy which would clobber a destination cacheline before reading the source, so source and dest within a cacheline's distance would be trouble, regardless of the direction. Arch-specific code which knows about the arch-specific details of memcpy might be safer, I guess, but its still fairly brittle.
J
Re: [git pull] "big box" x86 changes, boot protocol
In reply to Ingo MolnarDocumentation/i386/boot.txt Protocol 2.05: (Kernel 2.6.20) Make protected mode kernel relocatable. · line 47
Quoted 11 lines · Ingo Molnar
Documentation/i386/boot.txt +2
-0@@ -42,6 +42,8 @@ Protocol 2.05: (Kernel 2.6.20) Make protected mode kernel relocatable. Protocol 2.06: (Kernel 2.6.22) Added a field that contains the size of the boot command line +Protocol 2.09: (kernel 2.6.26) Added a field of 64-bit physical + pointer to single linked list of struct setup_data.
How about this. I can redo against current Linus but that will need fixups here.
From cfed8d4043fc03ed948518076db602919b111a16 Mon Sep 17 00:00:00 2001
From: Ian Campbell <[email protected]>
Date: Sun, 27 Apr 2008 12:19:11 +0100
Subject: [PATCH] Backfill x86 boot protocol documentation.
--- Documentation/i386/boot.txt | 12 ++++++++++-- 1 files changed, 10 insertions(+), 2 deletions(-)
Documentation/i386/boot.txt +10 -2
@@ -40,9 +40,17 @@ Protocol 2.05: (Kernel 2.6.20) Make protected mode kernel relocatable. Introduce relocatable_kernel and kernel_alignment fields. Protocol 2.06: (Kernel 2.6.22) Added a field that contains the size of - the boot command line + the boot command line. -Protocol 2.09: (kernel 2.6.26) Added a field of 64-bit physical +Protocol 2.07: (Kernel 2.6.24) Added paravirtualised boot protocol. + Introduced hardware_subarch and hardware_subarch_data + and KEEP_SEGMENTS flag in load_flags. + +Protocol 2.08: (Kernel 2.6.26) Added crc32 checksum and ELF format + payload. Introduced payload_offset and payload length + fields to aid in locating the payload. + +Protocol 2.09: (Kernel 2.6.26) Added a field of 64-bit physical pointer to single linked list of struct setup_data. **** MEMORY LAYOUT
Signature · 10 lines
1.5.5.1 -- Ian Campbell Computer Science is the only discipline in which we view adding a new wing to a building as being maintenance -- Jim Horning
Re: [git pull] "big box" x86 changes, boot protocol
Quoted 30 lines · Ian Campbell
How about this. I can redo against current Linus but that will need fixups here.
From
cfed8d4043fc03ed948518076db602919b111a16Mon Sep 17 00:00:00 2001
From: Ian Campbell <[email protected]>
Date: Sun, 27 Apr 2008 12:19:11 +0100
Subject: [PATCH] Backfill x86 boot protocol documentation.Signed-off-by Ian Campbell <[email protected]>Cc Ingo Molnar <[email protected]>Cc Rusty Russell <[email protected]>Cc Jeremy Fitzhardinge <[email protected]>--- Documentation/i386/boot.txt | 12 ++++++++++-- 1 files changed, 10 insertions(+), 2 deletions(-)Documentation/i386/boot.txt +2
-2@@ -40,9 +40,17 @@ Protocol 2.05: (Kernel 2.6.20) Make protected mode kernel relocatable. Introduce relocatable_kernel and kernel_alignment fields. Protocol 2.06: (Kernel 2.6.22) Added a field that contains the size of - the boot command line + the boot command line. -Protocol 2.09: (kernel 2.6.26) Added a field of 64-bit physical +Protocol 2.07: (Kernel 2.6.24) Added paravirtualised boot protocol.
Documentation/i386/boot.txt Protocol 2.05: (Kernel 2.6.20) Make protected mode kernel relocatable. · line 55
Quoted 10 lines
Documentation/i386/boot.txt +8
-0+ Introduced hardware_subarch and hardware_subarch_data + and KEEP_SEGMENTS flag in load_flags. + +Protocol 2.08: (Kernel 2.6.26) Added crc32 checksum and ELF format + payload. Introduced payload_offset and payload length + fields to aid in locating the payload. + +Protocol 2.09: (Kernel 2.6.26) Added a field of 64-bit physical pointer to single linked list of struct setup_data.
Since this is a documentation fix, it can wait until post-window.
-hpa
Re: [git pull] "big box" x86 changes, boot protocol
In reply to Ian CampbellQuoted 2 lines · Ian Campbell
How about this. I can redo against current Linus but that will need fixups here.
no need - your patch is fine - thanks, applied.
Ingo
[RFC git pull] "big box" x86 changes, GART
In reply to Linus TorvaldsLinus, please pull the x86 "big box & GART" subtopic tree from:
git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86-bigbox-gart.git for-linus
it also touches drivers/char/agp/amd64-agp.c.
Thanks,
Ingo
------------------>
Pavel Machek (1):
x86: iommu: use symbolic constants, not hardcoded numbers
Yinghai Lu (5):
x86: agp_gart size checking for buggy device
x86: checking aperture size order
x86_64: allocate gart aperture from 512M
x86: clean up aperture_64.c
x86: reserve dma32 early for gart fix
arch/x86/kernel/aperture_64.c | 283 +++++++++++++++++++++++++++------------- arch/x86/kernel/pci-dma.c | 11 +- arch/x86/kernel/pci-gart_64.c | 10 +- drivers/char/agp/amd64-agp.c | 46 +++---- include/asm-x86/gart.h | 21 +++ 5 files changed, 242 insertions(+), 129 deletions(-)
arch/x86/kernel/aperture_64.c +191 -92
@@ -35,6 +35,18 @@ int fallback_aper_force __initdata;int fix_aperture__initdata =1 ; +struct bus_dev_range { +int bus; +int dev_base; +int dev_limit; +}; + +static struct bus_dev_range bus_dev_ranges[]__initdata = { + {0x00 ,0x18 ,0x20 }, + {0xff ,0x00 ,0x20 }, + {0xfe ,0x00 ,0x20 } +}; +static struct resource gart_resource = { .name ="GART" , .flags =IORESOURCE_MEM ,
@@ -55,8 +67,9 @@ static u32 __init allocate_aperture(void)u32 aper_size;void *p; -if (fallback_aper_order >7 ) - fallback_aper_order =7 ; +/* aper_size should <= 1G */ +if (fallback_aper_order >5 ) + fallback_aper_order =5 ; aper_size = (32 *1024 *1024 ) << fallback_aper_order;/*
@@ -65,7 +78,20 @@ static u32 __init allocate_aperture(void)* memory. Unfortunately we cannot move it up because that would * make the IOMMU useless. */ - p =__alloc_bootmem_nopanic (aper_size, aper_size,0 ); +/* +* using 512M as goal, in case kexec will load kernel_big +* that will do the on position decompress, and could overlap with +* that positon with gart that is used. +* sequende: +* kernel_small +* ==> kexec (with kdump trigger path or previous doesn't shutdown gart) +* ==> kernel_small(gart area become e820_reserved) +* ==> kexec (with kdump trigger path or previous doesn't shutdown gart) +* ==> kerne_big (uncompressed size will be big than 64M or 128M) +* so don't use 512M below as gart iommu, leave the space for kernel +* code for safe +*/ + p =__alloc_bootmem_nopanic (aper_size, aper_size,512ULL <<20 );if (!p ||__pa (p)+aper_size >0xffffffff ) { printk(KERN_ERR "Cannot allocate aperture memory hole (%p,%uK)\n",
@@ -83,7 +109,7 @@ static u32 __init allocate_aperture(void)return (u32 )__pa (p); } -static int __init aperture_valid (u64 aper_base,u32 aper_size) +static int __init aperture_valid (u64 aper_base,u32 aper_size,u32 min_size) {if (!aper_base)return 0 ;
@@ -96,8 +122,9 @@ static int __init aperture_valid(u64 aper_base, u32 aper_size)printk (KERN_ERR "Aperture pointing to e820 RAM. Ignoring.\n" );return 0 ; } -if (aper_size <64 *1024 *1024 ) { -printk (KERN_ERR "Aperture too small (%d MB)\n" , aper_size>>20 ); +if (aper_size < min_size) { +printk (KERN_ERR "Aperture too small (%d MB) than (%d MB)\n" , + aper_size>>20 , min_size>>20 );return 0 ; }
@@ -105,47 +132,51 @@ static int __init aperture_valid(u64 aper_base, u32 aper_size) }/* Find a PCI capability */ -static __u32 __init find_cap (int num,int slot,int func,int cap) +static __u32 __init find_cap (int bus,int slot,int func,int cap) {int bytes;u8 pos; -if (!(read_pci_config_16 (num, slot, func,PCI_STATUS ) & +if (!(read_pci_config_16 (bus, slot, func,PCI_STATUS ) &PCI_STATUS_CAP_LIST ))return 0 ; - pos =read_pci_config_byte (num, slot, func,PCI_CAPABILITY_LIST ); + pos =read_pci_config_byte (bus, slot, func,PCI_CAPABILITY_LIST );for (bytes =0 ; bytes <48 && pos >=0x40 ; bytes++) {u8 id; pos &= ~3 ; - id =read_pci_config_byte (num, slot, func, pos+PCI_CAP_LIST_ID ); + id =read_pci_config_byte (bus, slot, func, pos+PCI_CAP_LIST_ID );if (id ==0xff )break ;if (id == cap)return pos; - pos =read_pci_config_byte (num, slot, func, + pos =read_pci_config_byte (bus, slot, func, pos+PCI_CAP_LIST_NEXT ); }return 0 ; }/* Read a standard AGPv3 bridge header */ -static __u32 __init read_agp (int num,int slot,int func,int cap,u32 *order) +static __u32 __init read_agp (int bus,int slot,int func,int cap,u32 *order) {u32 apsize;u32 apsizereg;int nbits;u32 aper_low, aper_hi;u64 aper; +u32 old_order; -printk (KERN_INFO "AGP bridge at %02x:%02x:%02x\n" , num, slot, func); - apsizereg =read_pci_config_16 (num, slot, func, cap +0x14 ); +printk (KERN_INFO "AGP bridge at %02x:%02x:%02x\n" , bus, slot, func); + apsizereg =read_pci_config_16 (bus, slot, func, cap +0x14 );if (apsizereg ==0xffffffff ) {printk (KERN_ERR "APSIZE in AGP bridge unreadable\n" );return 0 ; } +/* old_order could be the value from NB gart setting */ + old_order = *order; + apsize = apsizereg &0xfff ;/* Some BIOS use weird encodings not in the AGPv3 table. */ if (apsize &0xff )
@@ -155,14 +186,26 @@ static __u32 __init read_agp(int num, int slot, int func, int cap, u32 *order)if ((int )*order <0 )/* < 32MB */ *order =0 ; - aper_low =read_pci_config (num, slot, func,0x10 ); - aper_hi =read_pci_config (num, slot, func,0x14 ); + aper_low =read_pci_config (bus, slot, func,0x10 ); + aper_hi =read_pci_config (bus, slot, func,0x14 ); aper = (aper_low & ~((1 <<22 )-1 )) | ((u64 )aper_hi <<32 ); +/* +* On some sick chips, APSIZE is 0. It means it wants 4G +* so let double check that order, and lets trust AMD NB settings: +*/ +printk (KERN_INFO "Aperture from AGP @ %Lx old size %u MB\n" , + aper,32 << old_order); +if (aper + (32ULL <<(20 + *order)) >0x100000000ULL ) { +printk (KERN_INFO "Aperture size %u MB (APSIZE %x) is not right, using settings from NB\n" , +32 << *order, apsizereg); + *order = old_order; + } +printk (KERN_INFO "Aperture from AGP @ %Lx size %u MB (APSIZE %x)\n" , aper,32 << *order, apsizereg); -if (!aperture_valid (aper, (32 *1024 *1024 ) << *order)) +if (!aperture_valid (aper, (32 *1024 *1024 ) << *order,32 <<20 ))return 0 ;return (u32 )aper; }
@@ -182,15 +225,15 @@ static __u32 __init read_agp(int num, int slot, int func, int cap, u32 *order)*/ static __u32 __init search_agp_bridge (u32 *order,int *valid_agp) { -int num, slot, func; +int bus, slot, func;/* Poor man's PCI discovery */ -for (num =0 ; num <256 ; num++) { +for (bus =0 ; bus <256 ; bus++) {for (slot =0 ; slot <32 ; slot++) {for (func =0 ; func <8 ; func++) {u32 class, cap;u8 type; - class =read_pci_config (num, slot, func, + class =read_pci_config (bus, slot, func,PCI_CLASS_REVISION );if (class ==0xffffffff )break ;
@@ -199,17 +242,17 @@ static __u32 __init search_agp_bridge(u32 *order, int *valid_agp)case PCI_CLASS_BRIDGE_HOST :case PCI_CLASS_BRIDGE_OTHER :/* needed? */ /* AGP bridge? */ - cap =find_cap (num, slot, func, + cap =find_cap (bus, slot, func,PCI_CAP_ID_AGP );if (!cap)break ; *valid_agp =1 ; -return read_agp (num, slot, func, cap, +return read_agp (bus, slot, func, cap, order); }/* No multi-function device? */ - type =read_pci_config_byte (num, slot, func, + type =read_pci_config_byte (bus, slot, func,PCI_HEADER_TYPE );if (!(type &0x80 ))break ;
@@ -249,38 +292,49 @@ void __init early_gart_iommu_check(void)* or BIOS forget to put that in reserved. * try to update e820 to make that region as reserved. */ -int fix, num; +int fix, slot;u32 ctl;u32 aper_size =0 , aper_order =0 , last_aper_order =0 ;u64 aper_base =0 , last_aper_base =0 ;int aper_enabled =0 , last_aper_enabled =0 ; +int i;if (!early_pci_allowed ())return ; fix =0 ; -for (num =24 ; num <32 ; num++) { -if (!early_is_k8_nb (read_pci_config (0 , num,3 ,0x00 ))) -continue ; - - ctl =read_pci_config (0 , num,3 ,0x90 ); - aper_enabled = ctl &1 ; - aper_order = (ctl >>1 ) &7 ; - aper_size = (32 *1024 *1024 ) << aper_order; - aper_base =read_pci_config (0 , num,3 ,0x94 ) &0x7fff ; - aper_base <<=25 ; - -if ((last_aper_order && aper_order != last_aper_order) || - (last_aper_base && aper_base != last_aper_base) || - (last_aper_enabled && aper_enabled != last_aper_enabled)) { - fix =1 ; -break ; +for (i =0 ; i <ARRAY_SIZE (bus_dev_ranges); i++) { +int bus; +int dev_base, dev_limit; + + bus = bus_dev_ranges[i].bus; + dev_base = bus_dev_ranges[i].dev_base; + dev_limit = bus_dev_ranges[i].dev_limit; + +for (slot = dev_base; slot < dev_limit; slot++) { +if (!early_is_k8_nb (read_pci_config (bus, slot,3 ,0x00 ))) +continue ; + + ctl =read_pci_config (bus, slot,3 ,AMD64_GARTAPERTURECTL ); + aper_enabled = ctl &AMD64_GARTEN ; + aper_order = (ctl >>1 ) &7 ; + aper_size = (32 *1024 *1024 ) << aper_order; + aper_base =read_pci_config (bus, slot,3 ,AMD64_GARTAPERTUREBASE ) &0x7fff ; + aper_base <<=25 ; + +if ((last_aper_order && aper_order != last_aper_order) || + (last_aper_base && aper_base != last_aper_base) || + (last_aper_enabled && aper_enabled != last_aper_enabled)) { + fix =1 ; + goto out; + } + last_aper_order = aper_order; + last_aper_base = aper_base; + last_aper_enabled = aper_enabled; } - last_aper_order = aper_order; - last_aper_base = aper_base; - last_aper_enabled = aper_enabled; } +out:if (!fix && !aper_enabled)return ;
@@ -288,8 +342,8 @@ void __init early_gart_iommu_check(void) fix =1 ;if (gart_fix_e820 && !fix && aper_enabled) { -if (e820_any_mapped (aper_base, aper_base + aper_size, -E820_RAM )) { +if (!e820_all_mapped (aper_base, aper_base + aper_size, +E820_RESERVED )) {/* reserved it, so we can resuse it in second kernel */ printk (KERN_INFO "update e820 for GART\n" );add_memory_region (aper_base, aper_size,E820_RESERVED );
@@ -299,23 +353,35 @@ void __init early_gart_iommu_check(void) }/* different nodes have different setting, disable them all at first*/ -for (num =24 ; num <32 ; num++) { -if (!early_is_k8_nb (read_pci_config (0 , num,3 ,0x00 ))) -continue ; +for (i =0 ; i <ARRAY_SIZE (bus_dev_ranges); i++) { +int bus; +int dev_base, dev_limit; + + bus = bus_dev_ranges[i].bus; + dev_base = bus_dev_ranges[i].dev_base; + dev_limit = bus_dev_ranges[i].dev_limit; - ctl =read_pci_config (0 , num,3 ,0x90 ); - ctl &= ~1 ; -write_pci_config (0 , num,3 ,0x90 , ctl); +for (slot = dev_base; slot < dev_limit; slot++) { +if (!early_is_k8_nb (read_pci_config (bus, slot,3 ,0x00 ))) +continue ; + + ctl =read_pci_config (bus, slot,3 ,AMD64_GARTAPERTURECTL ); + ctl &= ~AMD64_GARTEN ; +write_pci_config (bus, slot,3 ,AMD64_GARTAPERTURECTL , ctl); + } } } +static int __initdata printed_gart_size_msg; +void __init gart_iommu_hole_init (void ) { +u32 agp_aper_base =0 , agp_aper_order =0 ;u32 aper_size, aper_alloc =0 , aper_order =0 , last_aper_order =0 ;u64 aper_base, last_aper_base =0 ; -int fix, num, valid_agp =0 ; -int node; +int fix, slot, valid_agp =0 ; +int i, node;if (gart_iommu_aperture_disabled || !fix_aperture || !early_pci_allowed ())
@@ -323,38 +389,63 @@ void __init gart_iommu_hole_init(void)printk (KERN_INFO "Checking aperture...\n" ); +if (!fallback_aper_force) + agp_aper_base =search_agp_bridge (&agp_aper_order, &valid_agp); + fix =0 ; node =0 ; -for (num =24 ; num <32 ; num++) { -if (!early_is_k8_nb (read_pci_config (0 , num,3 ,0x00 ))) -continue ; - - iommu_detected =1 ; - gart_iommu_aperture =1 ; - - aper_order = (read_pci_config (0 , num,3 ,0x90 ) >>1 ) &7 ; - aper_size = (32 *1024 *1024 ) << aper_order; - aper_base =read_pci_config (0 , num,3 ,0x94 ) &0x7fff ; - aper_base <<=25 ; - -printk (KERN_INFO "Node %d: aperture @ %Lx size %u MB\n" , - node, aper_base, aper_size >>20 ); - node++; - -if (!aperture_valid (aper_base, aper_size)) { - fix =1 ; -break ; - } +for (i =0 ; i <ARRAY_SIZE (bus_dev_ranges); i++) { +int bus; +int dev_base, dev_limit; + + bus = bus_dev_ranges[i].bus; + dev_base = bus_dev_ranges[i].dev_base; + dev_limit = bus_dev_ranges[i].dev_limit; + +for (slot = dev_base; slot < dev_limit; slot++) { +if (!early_is_k8_nb (read_pci_config (bus, slot,3 ,0x00 ))) +continue ; + + iommu_detected =1 ; + gart_iommu_aperture =1 ; + + aper_order = (read_pci_config (bus, slot,3 ,AMD64_GARTAPERTURECTL ) >>1 ) &7 ; + aper_size = (32 *1024 *1024 ) << aper_order; + aper_base =read_pci_config (bus, slot,3 ,AMD64_GARTAPERTUREBASE ) &0x7fff ; + aper_base <<=25 ; + +printk (KERN_INFO "Node %d: aperture @ %Lx size %u MB\n" , + node, aper_base, aper_size >>20 ); + node++; + +if (!aperture_valid (aper_base, aper_size,64 <<20 )) { +if (valid_agp && agp_aper_base && + agp_aper_base == aper_base && + agp_aper_order == aper_order) { +/* the same between two setting from NB and agp */ +if (!no_iommu && end_pfn >MAX_DMA32_PFN && !printed_gart_size_msg) { +printk (KERN_ERR "you are using iommu with agp, but GART size is less than 64M\n" ); +printk (KERN_ERR "please increase GART size in your BIOS setup\n" ); +printk (KERN_ERR "if BIOS doesn't have that option, contact your HW vendor!\n" ); + printed_gart_size_msg =1 ; + } + }else { + fix =1 ; + goto out; + } + } -if ((last_aper_order && aper_order != last_aper_order) || - (last_aper_base && aper_base != last_aper_base)) { - fix =1 ; -break ; +if ((last_aper_order && aper_order != last_aper_order) || + (last_aper_base && aper_base != last_aper_base)) { + fix =1 ; + goto out; + } + last_aper_order = aper_order; + last_aper_base = aper_base; } - last_aper_order = aper_order; - last_aper_base = aper_base; } +out:if (!fix && !fallback_aper_force) {if (last_aper_base) {unsigned long n = (32 *1024 *1024 ) << last_aper_order;
@@ -364,8 +455,10 @@ void __init gart_iommu_hole_init(void)return ; } -if (!fallback_aper_force) - aper_alloc =search_agp_bridge (&aper_order, &valid_agp); +if (!fallback_aper_force) { + aper_alloc = agp_aper_base; + aper_order = agp_aper_order; + }if (aper_alloc) {/* Got the aperture from the AGP bridge */
@@ -401,16 +494,22 @@ void __init gart_iommu_hole_init(void) }/* Fix up the north bridges */ -for (num =24 ; num <32 ; num++) { -if (!early_is_k8_nb (read_pci_config (0 , num,3 ,0x00 ))) -continue ; - -/* -* Don't enable translation yet. That is done later. -* Assume this BIOS didn't initialise the GART so -* just overwrite all previous bits -*/ -write_pci_config (0 , num,3 ,0x90 , aper_order<<1 ); -write_pci_config (0 , num,3 ,0x94 , aper_alloc>>25 ); +for (i =0 ; i <ARRAY_SIZE (bus_dev_ranges); i++) { +int bus; +int dev_base, dev_limit; + + bus = bus_dev_ranges[i].bus; + dev_base = bus_dev_ranges[i].dev_base; + dev_limit = bus_dev_ranges[i].dev_limit; +for (slot = dev_base; slot < dev_limit; slot++) { +if (!early_is_k8_nb (read_pci_config (bus, slot,3 ,0x00 ))) +continue ; + +/* Don't enable translation yet. That is done later. +Assume this BIOS didn't initialise the GART so +just overwrite all previous bits */ +write_pci_config (bus, slot,3 ,AMD64_GARTAPERTURECTL , aper_order <<1 ); +write_pci_config (bus, slot,3 ,AMD64_GARTAPERTUREBASE , aper_alloc >>25 ); + } } }
arch/x86/kernel/pci-dma.c +6 -5
@@ -77,10 +77,14 @@ void __init dma32_reserve_bootmem(void)if (end_pfn <=MAX_DMA32_PFN )return ; +/* +* check aperture_64.c allocate_aperture() for reason about +* using 512M as goal +*/ align =64ULL <<20 ; size =round_up (dma32_bootmem_size, align); dma32_bootmem_ptr =__alloc_bootmem_nopanic (size, align, -__pa (MAX_DMA_ADDRESS )); +512ULL <<20 );if (dma32_bootmem_ptr) dma32_bootmem_size = size;else
@@ -88,7 +92,6 @@ void __init dma32_reserve_bootmem(void) }static void __init dma32_free_bootmem (void ) { -int node;if (end_pfn <=MAX_DMA32_PFN )return ;
@@ -96,9 +99,7 @@ static void __init dma32_free_bootmem(void)if (!dma32_bootmem_ptr)return ; -for_each_online_node (node) -free_bootmem_node (NODE_DATA (node),__pa (dma32_bootmem_ptr), - dma32_bootmem_size); +free_bootmem (__pa (dma32_bootmem_ptr), dma32_bootmem_size); dma32_bootmem_ptr =NULL ; dma32_bootmem_size =0 ;
arch/x86/kernel/pci-gart_64.c +5 -5
@@ -598,13 +598,13 @@ static __init int init_k8_gatt(struct agp_kern_info *info) dev = k8_northbridges[i]; gatt_reg =__pa (gatt) >>12 ; gatt_reg <<=4 ; -pci_write_config_dword (dev,0x98 , gatt_reg); -pci_read_config_dword (dev,0x90 , &ctl); +pci_write_config_dword (dev,AMD64_GARTTABLEBASE , gatt_reg); +pci_read_config_dword (dev,AMD64_GARTAPERTURECTL , &ctl); - ctl |=1 ; - ctl &= ~((1 <<4 ) | (1 <<5 )); + ctl |=GARTEN ; + ctl &= ~(DISGARTCPU |DISGARTIO ); -pci_write_config_dword (dev,0x90 , ctl); +pci_write_config_dword (dev,AMD64_GARTAPERTURECTL , ctl); }flush_gart ();
drivers/char/agp/amd64-agp.c +19 -27
84 lines not on this page · raw message
include/asm-x86/gart.h +21 -0
@@ -5,6 +5,7 @@ extern void pci_iommu_shutdown(void);extern void no_iommu_init (void );extern int force_iommu, no_iommu;extern int iommu_detected; +extern int agp_amd64_init (void );#ifdef CONFIG_GART_IOMMU extern void gart_iommu_init (void );extern void gart_iommu_shutdown (void );
@@ -31,4 +32,24 @@ static inline void gart_iommu_shutdown(void)#endif +/* PTE bits. */ +#define GPTE_VALID 1 +#define GPTE_COHERENT 2 + +/* Aperture control register bits. */ +#define GARTEN (1<<0) +#define DISGARTCPU (1<<4) +#define DISGARTIO (1<<5) + +/* GART cache control register bits. */ +#define INVGART (1<<0) +#define GARTPTEERR (1<<1) + +/* K8 On-cpu GART registers */ +#define AMD64_GARTAPERTURECTL 0x90 +#define AMD64_GARTAPERTUREBASE 0x94 +#define AMD64_GARTTABLEBASE 0x98 +#define AMD64_GARTCACHECTL 0x9c +#define AMD64_GARTEN (1<<0) +#endif
Re: [RFC git pull] "big box" x86 changes, GART
Quoted 5 lines · Ingo Molnar
Linus, please pull the x86 "big box & GART" subtopic tree from:
git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86-bigbox-gart.git for-linusit also touches
drivers/char/agp/amd64-agp.c.
forgot to mention that these changes are pullable standalone, without the MM changes. I just test-booted it on a GART box to make sure:
PCI-DMA: using GART IOMMU.
Ingo
[git pull] "big box" x86 changes, PCI
In reply to Linus Torvaldsok, this is the final chunk of the "big box" topic - the PCI changes.
These are the largest, and while i tried to reduce their number it's still 19 commits - but it's all around the same topic. The bulk of the new code is in a single file. The tree can be pulled from:
git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86-bigbox-pci.git for-linus
this depends on the bootmem changes which are now upstream. These changes too have been in linux-next for some time and the cross-arch (build) success rate is high, as in:
http://www.tglx.de/autoqa-cgi/index?run=89&tree=1
all but the last few patches have been in x86.git for a longer time and more than 95% of the changes are for arch/x86. (see the dates of the patches. The "15 Feb 2008" ones are older than their timestamp - that's when we imported those changes into a date-aware repository.)
i booted up this tree 5 times on x86, mixed 64-bit/32-bit.
Ingo
------------------>
Robert Hancock (1):
x86: validate against acpi motherboard resources
Yinghai Lu (18):
x86: clear pci_mmcfg_virt when mmcfg get rejected
x86: mmconf enable mcfg early
x86_64: set cfg_size for AMD Family 10h in case MMCONFIG
x86_64: check and enable MMCONFIG for AMD Family 10h
x86_64: check MSR to get MMCONFIG for AMD Family 10h
x86: if acpi=off, force setting the mmconf for fam10h
x86: seperate mmconf for fam10h out from setup_64.c driver core: try parent numa_node at first before using default
x86: remove unneeded check in mmconf reject
x86 pci: remove checking type for mmconfig probe
x86: get mp_bus_to_node early
x86: use bus conf in NB conf fun1 to get bus range on, on 64-bit
x86: multi pci root bus with different io resource range, on 64-bit
x86: double check the multi root bus with fam10h mmconf
x86_64: don't need set default res if only have one root bus
acpi: get boot_cpu_id as early for k8_scan_nodes
x86: work around io allocation overlap of HT links
x86: add pci=check_enable_amd_mmconf and dmi check
arch/x86/kernel/Makefile | 2 + arch/x86/kernel/acpi/boot.c | 70 +++++ arch/x86/kernel/mmconf-fam10h_64.c | 243 +++++++++++++++ arch/x86/kernel/setup_64.c | 20 ++ arch/x86/mm/k8topology_64.c | 38 +++- arch/x86/pci/Makefile_32 | 1 + arch/x86/pci/Makefile_64 | 2 +- arch/x86/pci/acpi.c | 27 +- arch/x86/pci/common.c | 22 ++- arch/x86/pci/direct.c | 8 +- arch/x86/pci/fixup.c | 17 + arch/x86/pci/init.c | 13 +- arch/x86/pci/irq.c | 4 +- arch/x86/pci/k8-bus_64.c | 575 ++++++++++++++++++++++++++++++++---- arch/x86/pci/legacy.c | 4 +- arch/x86/pci/mmconfig-shared.c | 247 +++++++++++++--- arch/x86/pci/mmconfig_32.c | 4 + arch/x86/pci/mmconfig_64.c | 22 ++- arch/x86/pci/mp_bus_to_node.c | 23 ++ arch/x86/pci/pci.h | 3 +- drivers/acpi/bus.c | 2 + drivers/base/core.c | 14 +- drivers/pci/probe.c | 21 ++- include/asm-x86/pci.h | 2 + include/asm-x86/topology.h | 16 + include/linux/acpi.h | 5 + include/linux/pci.h | 11 +- 27 files changed, 1284 insertions(+), 132 deletions(-) create mode 100644 arch/x86/kernel/mmconf-fam10h_64.c create mode 100644 arch/x86/pci/mp_bus_to_node.c
arch/x86/kernel/Makefile +2 -0
@@ -99,4 +99,6 @@ ifeq ($(CONFIG_X86_64),y) obj-$(CONFIG_GART_IOMMU) += pci-gart_64.o aperture_64.o obj-$(CONFIG_CALGARY_IOMMU) += pci-calgary_64.o tce_64.o obj-$(CONFIG_SWIOTLB) += pci-swiotlb_64.o + + obj-$(CONFIG_PCI_MMCONFIG) += mmconf-fam10h_64.o endif
arch/x86/kernel/acpi/boot.c +70 -0
88 lines not on this page · raw message
arch/x86/kernel/mmconf-fam10h_64.c new file +243 -0
243 lines not on this page · raw message
arch/x86/kernel/setup_64.c +20 -0
@@ -29,6 +29,7 @@#include <linux/crash_dump.h> #include <linux/root_dev.h> #include <linux/pci.h> +#include <asm/pci-direct.h> #include <linux/efi.h> #include <linux/acpi.h> #include <linux/kallsyms.h>
@@ -40,6 +41,7 @@#include <linux/dmi.h> #include <linux/dma-mapping.h> #include <linux/ctype.h> +#include <linux/sort.h> #include <linux/uaccess.h> #include <linux/init_ohci1394_dma.h>
@@ -287,6 +289,18 @@ static void __init parse_setup_data(void) } } +#ifdef CONFIG_PCI_MMCONFIG +extern void __cpuinit fam10h_check_enable_mmcfg (void ); +extern void __init check_enable_amd_mmconf_dmi (void ); +#else +void __cpuinit fam10h_check_enable_mmcfg (void ) +{ +} +void __init check_enable_amd_mmconf_dmi (void ) +{ +} +#endif +/* * setup_arch - architecture-specific boot-time initializations *
@@ -508,6 +522,9 @@ void __init setup_arch(char **cmdline_p) conswitchp = &dummy_con;#endif #endif + +/* do this before identify_cpu for boot cpu */ +check_enable_amd_mmconf_dmi (); }static int __cpuinit get_model_name (struct cpuinfo_x86 *c)
@@ -760,6 +777,9 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)/* MFENCE stops RDTSC speculation */ set_cpu_cap (c,X86_FEATURE_MFENCE_RDTSC ); +if (c->x86 ==0x10 ) +fam10h_check_enable_mmcfg (); +if (amd_apic_timer_broken ()) disable_apic_timer =1 ;
arch/x86/mm/k8topology_64.c +37 -1
@@ -13,12 +13,15 @@#include <linux/nodemask.h> #include <asm/io.h> #include <linux/pci_ids.h> +#include <linux/acpi.h> #include <asm/types.h> #include <asm/mmzone.h> #include <asm/proto.h> #include <asm/e820.h> #include <asm/pci-direct.h> #include <asm/numa.h> +#include <asm/mpspec.h> +#include <asm/apic.h> static __init int find_northbridge (void ) {
@@ -44,6 +47,30 @@ static __init int find_northbridge(void)return -1 ; } +static __init void early_get_boot_cpu_id (void ) +{ +/* +* need to get boot_cpu_id so can use that to create apicid_to_node +* in k8_scan_nodes() +*/ +/* +* Find possible boot-time SMP configuration: +*/ +early_find_smp_config (); +#ifdef CONFIG_ACPI +/* +* Read APIC information from ACPI tables. +*/ +early_acpi_boot_init (); +#endif +/* +* get boot-time SMP configuration: +*/ +if (smp_found_config) +early_get_smp_config (); +early_init_lapic_mapping (); +} +int __init k8_scan_nodes (unsigned long start,unsigned long end) {unsigned long prevbase;
@@ -56,6 +83,7 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)unsigned cores;unsigned bits;int j; +unsigned apicid_base;if (!early_pci_allowed ())return -1 ;
@@ -174,11 +202,19 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)/* use the coreid bits from early_identify_cpu */ bits = boot_cpu_data.x86_coreid_bits; cores = (1 <<bits); + apicid_base =0 ; +/* need to get boot_cpu_id early for system with apicid lifting */ +early_get_boot_cpu_id (); +if (boot_cpu_physical_apicid >0 ) { +printk (KERN_INFO "BSP APIC ID: %02x\n" , + boot_cpu_physical_apicid); + apicid_base = boot_cpu_physical_apicid; + }for (i =0 ; i <8 ; i++) {if (nodes[i].start != nodes[i].end) { nodeid = nodeids[i]; -for (j =0 ; j < cores; j++) +for (j = apicid_base; j < cores + apicid_base; j++) apicid_to_node[(nodeid << bits) + j] = i;setup_node_bootmem (i, nodes[i].start, nodes[i].end); }
arch/x86/pci/Makefile_32 +1 -0
@@ -10,5 +10,6 @@ pci-y += legacy.o irq.o pci-$(CONFIG_X86_VISWS) := visws.o fixup.o pci-$(CONFIG_X86_NUMAQ) := numa.o irq.o +pci-$(CONFIG_NUMA) += mp_bus_to_node.o obj-y += $(pci-y) common.o early.o
arch/x86/pci/Makefile_64 +1 -1
@@ -13,5 +13,5 @@ obj-y += legacy.o irq.o common.o early.o # mmconfig has a 64bit special obj-$(CONFIG_PCI_MMCONFIG) += mmconfig_64.o direct.o mmconfig-shared.o -obj-$(CONFIG_NUMA) += k8-bus_64.o +obj-y += k8-bus_64.o
arch/x86/pci/acpi.c +17 -10
@@ -191,7 +191,10 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do {struct pci_bus *bus;struct pci_sysdata *sd; +int node; +#ifdef CONFIG_ACPI_NUMA int pxm; +#endif dmi_check_system (acpi_pciprobe_dmi_table);
@@ -201,6 +204,17 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int doreturn NULL ; } + node =-1 ; +#ifdef CONFIG_ACPI_NUMA + pxm =acpi_get_pxm (device->handle); +if (pxm >=0 ) + node =pxm_to_node (pxm); +if (node !=-1 ) +set_mp_bus_to_node (busnum, node); +else + node =get_mp_bus_to_node (busnum); +#endif +/* Allocate per-root-bus (not per bus) arch-specific data. * TODO: leak; this memory is never freed. * It's arguable whether it's worth the trouble to care.
@@ -212,13 +226,7 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do } sd->domain = domain; - sd->node =-1 ; - - pxm =acpi_get_pxm (device->handle); -#ifdef CONFIG_ACPI_NUMA -if (pxm >=0 ) - sd->node =pxm_to_node (pxm); -#endif + sd->node = node;/* * Maybe the desired pci bus has been already scanned. In such case * it is unnecessary to scan the pci bus with the given domain,busnum.
@@ -238,9 +246,9 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int dokfree (sd);#ifdef CONFIG_ACPI_NUMA -if (bus !=NULL ) { +if (bus) {if (pxm >=0 ) { -printk ("bus %d -> pxm %d -> node %d\n" , +printk (KERN_DEBUG "bus %02x -> pxm %d -> node %d\n" , busnum, pxm,pxm_to_node (pxm)); } }
@@ -248,7 +256,6 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int doif (bus && (pci_probe &PCI_USE__CRS ))get_current_resources (device, busnum, domain, bus); -return bus; }
arch/x86/pci/common.c +18 -4
@@ -342,9 +342,14 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum)return NULL ; } + sd->node =get_mp_bus_to_node (busnum); +printk (KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n" , busnum); + bus =pci_scan_bus_parented (NULL , busnum, &pci_root_ops, sd); +if (!bus) +kfree (sd); -return pci_scan_bus_parented (NULL , busnum, &pci_root_ops, sd); +return bus; }extern u8 pci_cache_line_size;
@@ -420,6 +425,10 @@ char * __devinit pcibios_setup(char *str) pci_probe &= ~PCI_PROBE_MMCONF ; return NULL; } +else if (!strcmp (str,"check_enable_amd_mmconf" )) { + pci_probe |=PCI_CHECK_ENABLE_AMD_MMCONF ; +return NULL ; + }#endif else if (!strcmp(str, "noacpi")) {acpi_noirq_set ();
@@ -480,7 +489,7 @@ void pcibios_disable_device (struct pci_dev *dev)pcibios_disable_irq (dev); } -struct pci_bus *__devinit pci_scan_bus_with_sysdata (int busno) +struct pci_bus *pci_scan_bus_on_node (int busno,struct pci_ops *ops,int node) {struct pci_bus *bus =NULL ;struct pci_sysdata *sd;
@@ -495,10 +504,15 @@ struct pci_bus *__devinit pci_scan_bus_with_sysdata(int busno)printk (KERN_ERR "PCI: OOM, skipping PCI bus %02x\n" , busno);return NULL ; } - sd->node =-1 ; - bus =pci_scan_bus (busno, &pci_root_ops, sd); + sd->node = node; + bus =pci_scan_bus (busno, ops, sd);if (!bus)kfree (sd);return bus; } + +struct pci_bus *pci_scan_bus_with_sysdata (int busno) +{ +return pci_scan_bus_on_node (busno, &pci_root_ops,-1 ); +}
arch/x86/pci/direct.c +5 -3
@@ -258,7 +258,8 @@ void __init pci_direct_init(int type) {if (type ==0 )return ; -printk (KERN_INFO "PCI: Using configuration type %d\n" , type); +printk (KERN_INFO "PCI: Using configuration type %d for base access\n" , + type);if (type ==1 ) raw_pci_ops = &pci_direct_conf1;else
@@ -275,8 +276,10 @@ int __init pci_direct_probe(void)if (!region) goto type2; -if (pci_check_type1 ()) +if (pci_check_type1 ()) { + raw_pci_ops = &pci_direct_conf1;return 1 ; + }release_resource (region); type2:
@@ -290,7 +293,6 @@ int __init pci_direct_probe(void) goto fail2;if (pci_check_type2 ()) { -printk (KERN_INFO "PCI: Using configuration type 2\n" ); raw_pci_ops = &pci_direct_conf2;return 2 ; }
arch/x86/pci/fixup.c +17 -0
@@ -493,3 +493,20 @@ static void __devinit pci_siemens_interrupt_controller(struct pci_dev *dev) }DECLARE_PCI_FIXUP_HEADER (PCI_VENDOR_ID_SIEMENS ,0x0015 , pci_siemens_interrupt_controller); + +/* +* Regular PCI devices have 256 bytes, but AMD Family 10h Opteron ext config +* have 4096 bytes. Even if the device is capable, that doesn't mean we can +* access it. Maybe we don't have a way to generate extended config space +* accesses. So check it +*/ +static void fam10h_pci_cfg_space_size (struct pci_dev *dev) +{ + dev->cfg_size =pci_cfg_space_size_ext (dev,0 ); +} + +DECLARE_PCI_FIXUP_HEADER (PCI_VENDOR_ID_AMD ,0x1200 , fam10h_pci_cfg_space_size); +DECLARE_PCI_FIXUP_HEADER (PCI_VENDOR_ID_AMD ,0x1201 , fam10h_pci_cfg_space_size); +DECLARE_PCI_FIXUP_HEADER (PCI_VENDOR_ID_AMD ,0x1202 , fam10h_pci_cfg_space_size); +DECLARE_PCI_FIXUP_HEADER (PCI_VENDOR_ID_AMD ,0x1203 , fam10h_pci_cfg_space_size); +DECLARE_PCI_FIXUP_HEADER (PCI_VENDOR_ID_AMD ,0x1204 , fam10h_pci_cfg_space_size);
arch/x86/pci/init.c +5 -8
@@ -6,16 +6,13 @@in the right sequence from here. */ static __init int pci_access_init (void ) { -int type__maybe_unused =0 ; -#ifdef CONFIG_PCI_DIRECT +int type =0 ; + type =pci_direct_probe ();#endif -#ifdef CONFIG_PCI_MMCONFIG -pci_mmcfg_init (type); -#endif -if (raw_pci_ops) -return 0 ; +pci_mmcfg_early_init (); +#ifdef CONFIG_PCI_BIOS pci_pcbios_init ();#endif
@@ -28,7 +25,7 @@ static __init int pci_access_init(void)#ifdef CONFIG_PCI_DIRECT pci_direct_init (type);#endif -if (!raw_pci_ops) +if (!raw_pci_ops && !raw_pci_ext_ops)printk (KERN_ERR "PCI: Fatal: No config space access function found\n" );
arch/x86/pci/irq.c +3 -1
@@ -136,9 +136,11 @@ static void __init pirq_peer_trick(void) busmap[e->bus] =1 ; }for (i =1 ; i <256 ; i++) { +int node;if (!busmap[i] ||pci_find_bus (0 , i))continue ; -if (pci_scan_bus_with_sysdata (i)) + node =get_mp_bus_to_node (i); +if (pci_scan_bus_on_node (i, &pci_root_ops, node))printk (KERN_INFO "PCI: Discovered primary peer " "bus %02x [IRQ]\n" , i); }
arch/x86/pci/k8-bus_64.c +514 -61
597 lines not on this page · raw message
arch/x86/pci/legacy.c +3 -1
@@ -12,6 +12,7 @@static void __devinit pcibios_fixup_peer_bridges (void ) {int n, devfn; +long node;if (pcibios_last_bus <=0 || pcibios_last_bus >=0xff )return ;
@@ -21,12 +22,13 @@ static void __devinit pcibios_fixup_peer_bridges(void)u32 l;if (pci_find_bus (0 , n))continue ; + node =get_mp_bus_to_node (n);for (devfn =0 ; devfn <256 ; devfn +=8 ) {if (!raw_pci_read (0 , n, devfn,PCI_VENDOR_ID ,2 , &l) && l !=0x0000 && l !=0xffff ) {DBG ("Found device at %02x:%02x [%04x]\n" , n, devfn, l);printk (KERN_INFO "PCI: Discovered peer bus %02x\n" , n); -pci_scan_bus_with_sysdata (n); +pci_scan_bus_on_node (n, &pci_root_ops, node);break ; } }
arch/x86/pci/mmconfig-shared.c +212 -35
325 lines not on this page · raw message
arch/x86/pci/mmconfig_32.c +4 -0
@@ -136,3 +136,7 @@ int __init pci_mmcfg_arch_init(void) raw_pci_ext_ops = &pci_mmcfg;return 1 ; } + +void __init pci_mmcfg_arch_free (void ) +{ +}
arch/x86/pci/mmconfig_64.c +21 -1
@@ -127,7 +127,7 @@ static void __iomem * __init mcfg_ioremap(struct acpi_mcfg_allocation *cfg)int __init pci_mmcfg_arch_init (void ) {int i; - pci_mmcfg_virt =kmalloc (sizeof (*pci_mmcfg_virt) * + pci_mmcfg_virt =kzalloc (sizeof (*pci_mmcfg_virt) * pci_mmcfg_config_num,GFP_KERNEL );if (pci_mmcfg_virt ==NULL ) {printk (KERN_ERR "PCI: Can not allocate memory for mmconfig structures\n" );
@@ -141,9 +141,29 @@ int __init pci_mmcfg_arch_init(void)printk (KERN_ERR "PCI: Cannot map mmconfig aperture for " "segment %d\n" , pci_mmcfg_config[i].pci_segment); +pci_mmcfg_arch_free ();return 0 ; } } raw_pci_ext_ops = &pci_mmcfg;return 1 ; } + +void __init pci_mmcfg_arch_free (void ) +{ +int i; + +if (pci_mmcfg_virt ==NULL ) +return ; + +for (i =0 ; i < pci_mmcfg_config_num; ++i) { +if (pci_mmcfg_virt[i].virt) { +iounmap (pci_mmcfg_virt[i].virt); + pci_mmcfg_virt[i].virt =NULL ; + pci_mmcfg_virt[i].cfg =NULL ; + } + } + +kfree (pci_mmcfg_virt); + pci_mmcfg_virt =NULL ; +}
arch/x86/pci/mp_bus_to_node.c new file +23 -0
@@ -0,0 +1,23 @@ +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/topology.h> + +#define BUS_NR 256 + +static unsigned char mp_bus_to_node[BUS_NR ]; + +void set_mp_bus_to_node (int busnum,int node) +{ +if (busnum >=0 && busnum <BUS_NR ) + mp_bus_to_node[busnum] = (unsigned char ) node; +} + +int get_mp_bus_to_node (int busnum) +{ +int node; + +if (busnum <0 || busnum > (BUS_NR -1 )) +return 0 ; + node = mp_bus_to_node[busnum]; +return node; +}
arch/x86/pci/pci.h +2 -1
@@ -26,6 +26,7 @@#define PCI_ASSIGN_ALL_BUSSES 0x4000#define PCI_CAN_SKIP_ISA_ALIGN 0x8000#define PCI_USE__CRS 0x10000 +#define PCI_CHECK_ENABLE_AMD_MMCONF 0x20000extern unsigned int pci_probe;extern unsigned long pirq_table_addr;
@@ -97,11 +98,11 @@ extern struct pci_raw_ops pci_direct_conf1;extern int pci_direct_probe (void );extern void pci_direct_init (int type);extern void pci_pcbios_init (void ); -extern void pci_mmcfg_init (int type);/* pci-mmconfig.c */ extern int __init pci_mmcfg_arch_init (void ); +extern void __init pci_mmcfg_arch_free (void );/* * AMD Fam10h CPUs are buggy, and cannot access MMIO config space
drivers/acpi/bus.c +2 -0
@@ -35,6 +35,7 @@#ifdef CONFIG_X86 #include <asm/mpspec.h> #endif +#include <linux/pci.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h>
@@ -784,6 +785,7 @@ static int __init acpi_init(void) result =acpi_bus_init ();if (!result) { +pci_mmcfg_late_init ();if (!(pm_flags &PM_APM )) pm_flags |=PM_ACPI ;else {
drivers/base/core.c +12 -2
@@ -787,6 +787,10 @@ int device_add(struct device *dev) parent =get_device (dev->parent);setup_parent (dev, parent); +/* use parent numa_node */ +if (parent) +set_dev_node (dev,dev_to_node (parent)); +/* first, register with generic layer. */ error =kobject_add (&dev->kobj, dev->kobj.parent,"%s" , dev->bus_id);if (error)
@@ -1306,8 +1310,11 @@ int device_move(struct device *dev, struct device *new_parent) dev->parent = new_parent;if (old_parent)klist_remove (&dev->knode_parent); -if (new_parent) +if (new_parent) {klist_add_tail (&dev->knode_parent, &new_parent->klist_children); +set_dev_node (dev,dev_to_node (new_parent)); + } +if (!dev->class) goto out_put; error =device_move_class_links (dev, old_parent, new_parent);
@@ -1317,9 +1324,12 @@ int device_move(struct device *dev, struct device *new_parent)if (!kobject_move (&dev->kobj, &old_parent->kobj)) {if (new_parent)klist_remove (&dev->knode_parent); -if (old_parent) + dev->parent = old_parent; +if (old_parent) {klist_add_tail (&dev->knode_parent, &old_parent->klist_children); +set_dev_node (dev,dev_to_node (old_parent)); + } }cleanup_glue_dir (dev, new_parent_kobj);put_device (new_parent);
drivers/pci/probe.c +19 -2
@@ -842,11 +842,14 @@ static void set_pcie_port_type(struct pci_dev *pdev)* reading the dword at 0x100 which must either be 0 or a valid extended * capability header. */ -int pci_cfg_space_size (struct pci_dev *dev) +int pci_cfg_space_size_ext (struct pci_dev *dev,unsigned check_exp_pcix) {int pos;u32 status; +if (!check_exp_pcix) + goto skip; + pos =pci_find_capability (dev,PCI_CAP_ID_EXP );if (!pos) { pos =pci_find_capability (dev,PCI_CAP_ID_PCIX );
@@ -858,6 +861,7 @@ int pci_cfg_space_size(struct pci_dev *dev) goto fail; } + skip:if (pci_read_config_dword (dev,256 , &status) !=PCIBIOS_SUCCESSFUL ) goto fail;if (status ==0xffffffff )
@@ -869,6 +873,11 @@ int pci_cfg_space_size(struct pci_dev *dev)return PCI_CFG_SPACE_SIZE ; } +int pci_cfg_space_size (struct pci_dev *dev) +{ +return pci_cfg_space_size_ext (dev,1 ); +} +static void pci_release_bus_bridge_dev (struct device *dev) {kfree (dev);
@@ -964,7 +973,6 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) dev->dev.release = pci_release_dev;pci_dev_get (dev); -set_dev_node (&dev->dev,pcibus_to_node (bus)); dev->dev.dma_mask = &dev->dma_mask; dev->dev.dma_parms = &dev->dma_parms; dev->dev.coherent_dma_mask =0xffffffffull ;
@@ -1080,6 +1088,10 @@ unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)return max; } +void __attribute__((weak))set_pci_bus_resources_arch_default (struct pci_bus *b) +{ +} +struct pci_bus *pci_create_bus (struct device *parent,int bus,struct pci_ops *ops,void *sysdata) {
@@ -1119,6 +1131,9 @@ struct pci_bus * pci_create_bus(struct device *parent, goto dev_reg_err; b->bridge =get_device (dev); +if (!parent) +set_dev_node (b->bridge,pcibus_to_node (b)); + b->dev.class = &pcibus_class; b->dev.parent = b->bridge;sprintf (b->dev.bus_id,"%04x:%02x" ,pci_domain_nr (b), bus);
@@ -1136,6 +1151,8 @@ struct pci_bus * pci_create_bus(struct device *parent, b->resource[0 ] = &ioport_resource; b->resource[1 ] = &iomem_resource; +set_pci_bus_resources_arch_default (b); +return b; dev_create_file_err:
include/asm-x86/pci.h +2 -0
@@ -19,6 +19,8 @@ struct pci_sysdata { };/* scan a bus after allocating a pci_sysdata for it */ +extern struct pci_bus *pci_scan_bus_on_node (int busno,struct pci_ops *ops, +int node);extern struct pci_bus *pci_scan_bus_with_sysdata (int busno);static inline int pci_domain_nr (struct pci_bus *bus)
include/asm-x86/topology.h +16 -0
@@ -193,9 +193,25 @@ extern cpumask_t cpu_coregroup_map(int cpu);#define topology_thread_siblings (cpu) (per_cpu(cpu_sibling_map, cpu))#endif +struct pci_bus ; +void set_pci_bus_resources_arch_default (struct pci_bus *b); +#ifdef CONFIG_SMP #define mc_capable () (boot_cpu_data.x86_max_cores > 1)#define smt_capable () (smp_num_siblings > 1)#endif +#ifdef CONFIG_NUMA +extern int get_mp_bus_to_node (int busnum); +extern void set_mp_bus_to_node (int busnum,int node); +#else +static inline int get_mp_bus_to_node (int busnum) +{ +return 0 ; +} +static inline void set_mp_bus_to_node (int busnum,int node) +{ +} +#endif +#endif
include/linux/acpi.h +5 -0
@@ -79,6 +79,7 @@ typedef int (*acpi_table_handler) (struct acpi_table_header *table);typedef int (*acpi_table_entry_handler ) (struct acpi_subtable_header *header,const unsigned long end);char *__acpi_map_table (unsigned long phys_addr,unsigned long size); +int early_acpi_boot_init (void );int acpi_boot_init (void );int acpi_boot_table_init (void );int acpi_numa_init (void );
@@ -235,6 +236,10 @@ int acpi_check_mem_region(resource_size_t start, resource_size_t n,#else /* CONFIG_ACPI */ +static inline int early_acpi_boot_init (void ) +{ +return 0 ; +}static inline int acpi_boot_init (void ) {return 0 ;
include/linux/pci.h +10 -1
@@ -254,7 +254,7 @@ static inline void pci_add_saved_cap(struct pci_dev *pci_dev,#define PCI_NUM_RESOURCES 11#ifndef PCI_BUS_NUM_RESOURCES -#define PCI_BUS_NUM_RESOURCES 8 +#define PCI_BUS_NUM_RESOURCES 16#endif #define PCI_REGION_FLAG_MASK 0x0fU/* These bits of resource flags tell us the PCI region flags */
@@ -666,6 +666,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,void pci_walk_bus (struct pci_bus *top,void (*cb)(struct pci_dev *,void *),void *userdata); +int pci_cfg_space_size_ext (struct pci_dev *dev,unsigned check_exp_pcix);int pci_cfg_space_size (struct pci_dev *dev);unsigned char pci_bus_max_busnr (struct pci_bus *bus);
@@ -1053,5 +1054,13 @@ extern unsigned long pci_cardbus_mem_size;extern int pcibios_add_platform_entries (struct pci_dev *dev); +#ifdef CONFIG_PCI_MMCONFIG +extern void __init pci_mmcfg_early_init (void ); +extern void __init pci_mmcfg_late_init (void ); +#else +static inline void pci_mmcfg_early_init (void ) { } +static inline void pci_mmcfg_late_init (void ) { } +#endif +#endif /* __KERNEL__ */ #endif /* LINUX_PCI_H */
Re: [git pull] "big box" x86 changes, PCI
Quoted 14 lines · Ingo Molnar
ok, this is the final chunk of the "big box" topic - the PCI changes.
These are the largest, and while i tried to reduce their number it's still 19 commits - but it's all around the same topic. The bulk of the new code is in a single file. The tree can be pulled from:
git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86-bigbox-pci.
git for-linusthis depends on the bootmem changes which are now upstream. These changes too have been in linux-next for some time and the cross-arch (build) success rate is high, as in:
Quoted 8 lines
http://www.tglx.de/autoqa-cgi/index?run=89&tree=1all but the last few patches have been in x86.git for a longer time and more than 95% of the changes are for
arch/x86. (see the dates of the patches. The "15 Feb 2008" ones are older than their timestamp - that's when we imported those changes into a date-aware repository.)i booted up this tree 5 times on x86, mixed 64-bit/32-bit.
Only did a quick scan, but the changes look nice so far. I'll take a closer look and give it a try locally tomorrow.
On an unrelated note, can you take a look at the "PCI MSI breaks when booting with nosmp" thread? I posted a patch there that unconditionally enables the local apic with nosmp/maxcpus=0 so that MSI will work correctly. The other option of course is to disable MSI when nosmp/maxcpus=0 and local apic enable code alone.
Thanks,
Jesse
Re: [git pull] "big box" x86 changes, PCI
Quoted 22 lines · Jesse Barnes
Quoted 21 lines · Ingo Molnar
ok, this is the final chunk of the "big box" topic - the PCI changes.
These are the largest, and while i tried to reduce their number it's still 19 commits - but it's all around the same topic. The bulk of the new code is in a single file. The tree can be pulled from:
git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86-bigbox-pci.
git for-linusthis depends on the bootmem changes which are now upstream. These changes too have been in linux-next for some time and the cross-arch (build) success rate is high, as in:
http://www.tglx.de/autoqa-cgi/index?run=89&tree=1all but the last few patches have been in x86.git for a longer time and more than 95% of the changes are for
arch/x86. (see the dates of the patches. The "15 Feb 2008" ones are older than their timestamp - that's when we imported those changes into a date-aware repository.)
Quoted 4 lines
Quoted 1 line
i booted up this tree 5 times on x86, mixed 64-bit/32-bit.
Only did a quick scan, but the changes look nice so far. I'll take a closer look and give it a try locally tomorrow.
ok, great! Let us know if you experience any problems - and please give us an Ack if it looks OK so that we can send the final pull request to Linus :-)
Quoted 5 lines
On an unrelated note, can you take a look at the "PCI MSI breaks when booting with nosmp" thread? I posted a patch there that unconditionally enables the local apic with nosmp/maxcpus=0 so that MSI will work correctly. The other option of course is to disable MSI when nosmp/maxcpus=0 and local apic enable code alone.
yeah - great fix - your patch has been put into x86.git a few minutes after you posted the fix ;-) I think that's been a long-standing problem (== was broken forever), i noticed it happen on a number of Intel SDV boards myself in the past and initially suspected e1000 - it is the first driver that throws a fit with non-working MSI interrupts.
I never managed to track it down (there was nothing to bisect to and far enough in the past kernels simply stopped booting on that hardware) and things like acpi=off regularly dont work on prototype boards anyway. I'm glad you figured it out and it's on the way upstream.
Ingo
Re: [git pull] "big box" x86 changes, PCI
In reply to Ingo MolnarOn Saturday, April 26, 2008 2:55 pm Ingo Molnar wrote:> @@ -184,51 +322,80 @@ static void __init pci_mmcfg_reject_broken(int type)> > cfg = &pci_mmcfg_config[0];> > - /*> - * Handle more broken MCFG tables on Asus etc.> - * They only contain a single entry for bus 0-0.> - */> - if (pci_mmcfg_config_num == 1 &&> - cfg->pci_segment == 0 &&> - (cfg->start_bus_number | cfg->end_bus_number) == 0) {> - printk(KERN_ERR "PCI: start and end of bus number is 0. "> - "Rejected as broken MCFG.\n");> - goto reject;> + for (i = 0; i < pci_mmcfg_config_num; i++) {> + int valid = 0;> + u32 size = (cfg->end_bus_number + 1) << 20;> + cfg = &pci_mmcfg_config[i];> + printk(KERN_NOTICE "PCI: MCFG configuration %d: base %lx "> + "segment %hu buses %u - %u\n",> + i, (unsigned long)cfg->address, cfg->pci_segment,> + (unsigned int)cfg->start_bus_number,> + (unsigned int)cfg->end_bus_number);> +> + if (!early &&> + is_acpi_reserved(cfg->address, cfg->address + size -> 1)) { + printk(KERN_NOTICE "PCI: MCFG area at %Lx> reserved " + "in ACPI motherboard> resources\n",> + cfg->address);> + valid = 1;> + }> +> + if (valid)> + continue;> +> + if (!early)> + printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx is> not" + " reserved in ACPI motherboard> resources\n", + cfg->address);> + /* Don't try to do this check unless configuration> + type 1 is available. how about type 2 ?*/> + if (raw_pci_ops && e820_all_mapped(cfg->address,> + cfg->address + size - 1,> + E820_RESERVED)) {> + printk(KERN_NOTICE> + "PCI: MCFG area at %Lx reserved in E820\n",> + cfg->address);> + valid = 1;> + }> +> + if (!valid)> + goto reject;> } This loop is a bit messy, is there some way of making it clearer? Maybe the early vs. late stuff should be split into separate routines entirely...
Review static void set_pcie_port_type(struct pci_dev *pdev)> * reading the dword at 0x100 which must either be 0 or a valid extended> * capability header.> */> -int pci_cfg_space_size(struct pci_dev *dev)> +int pci_cfg_space_size_ext(struct pci_dev *dev, unsigned check_exp_pcix)> {> int pos;> u32 status;> > + if (!check_exp_pcix)> + goto skip;> +
Quoted 1 line
(quoted diff) +0
-0@@ -842,11 +842,14 @@ static void set_pcie_port_type(struct pci_dev *pdev)> * reading the dword at 0x100 which must either be 0 or a valid extended> * capability header.> */> -int pci_cfg_space_size(struct pci_dev *dev)> +int pci_cfg_space_size_ext(struct pci_dev *dev, unsigned check_exp_pcix)> {> int pos;> u32 status;> > + if (!check_exp_pcix)> + goto skip;> +
Rather than adding a flag to pci_cfg_space_size, you could either factor out the extended space probe into a separate routine and use it from both pci_cfg_space_size and the fixup code, or just make the fixup code do the probe & cfg_size setting by hand, moving the PCI_CFG_SPACE_SIZE and PCI_CFG_SPACE_EXP_SIZE to pci.h. In both cases I'm just trying to avoid having a flag you pass to a routine that changes its behavior significantly enough that a new function would make things more readable.
Other than that, things look pretty good. And the resulting kernel boots fine on my test box, which is nice... Thanks,Jesseÿôèº{.nÇ+‰·Ÿ®‰†+%ŠËÿ±éݶ¥Šwÿº{.nÇ+‰·¥Š{±þG«�éÿŠ{ayºÊ‡Ú™ë,j¢f£¢·hš�ï�êÿ‘êçz_è®(階ŠÝ¢j"�ú¶m§ÿÿ¾«þG«�éÿ¢¸?™¨èÚ&£ø§~�á¶iO•æ¬z·švØ^¶m§ÿÿÃÿ¶ìÿ¢¸?–I¥
Re: [git pull] "big box" x86 changes, PCI
Quoted 52 lines · Jesse Barnes
Quoted 49 lines · Ingo Molnar
arch/x86/pci/mmconfig-shared.c +12
-10@@ -184,51 +322,80 @@ static void __init pci_mmcfg_reject_broken(int type) cfg = &pci_mmcfg_config[0]; -/* -* Handle more broken MCFG tables on Asus etc. -* They only contain a single entry for bus 0-0. -*/ -if (pci_mmcfg_config_num ==1 && - cfg->pci_segment ==0 && - (cfg->start_bus_number | cfg->end_bus_number) ==0 ) { -printk (KERN_ERR "PCI: start and end of bus number is 0. " -"Rejected as broken MCFG.\n" ); - goto reject; + for (i = 0; i < pci_mmcfg_config_num; i++) { + int valid = 0; + u32 size = (cfg->end_bus_number + 1) << 20; + cfg = &pci_mmcfg_config[i]; + printk(KERN_NOTICE "PCI: MCFG configuration %d: base %lx " + "segment %hu buses %u - %u\n", + i, (unsigned long)cfg->address, cfg->pci_segment, + (unsigned int)cfg->start_bus_number, + (unsigned int)cfg->end_bus_number); + + if (!early && + is_acpi_reserved(cfg->address, cfg->address + size -1)) { + printk(KERN_NOTICE "PCI: MCFG area at %Lx
reserved " + "in ACPI motherboard
resources\n",arch/x86/pci/mmconfig-shared.c +9
-0+ cfg->address); + valid =1 ; + } + +if (valid) +continue ; + +if (!early) + printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx isnot" + " reserved in ACPI motherboard
resources\n", +cfg->address);arch/x86/pci/mmconfig-shared.c +9
-0+/* Don't try to do this check unless configuration +type 1 is available. how about type 2 ?*/ +if (raw_pci_ops &&e820_all_mapped (cfg->address, + cfg->address + size -1 , +E820_RESERVED )) { +printk (KERN_NOTICE +"PCI: MCFG area at %Lx reserved in E820\n" , + cfg->address); + valid =1 ;
Quoted 8 lines
arch/x86/pci/mmconfig-shared.c static void __init pci_mmcfg_reject_broken(int type) · line 363
Quoted 5 lines
arch/x86/pci/mmconfig-shared.c +4
-0+ } + +if (!valid) + goto reject; }This loop is a bit messy, is there some way of making it clearer? Maybe the early vs. late stuff should be split into separate routines entirely...
for (i = 0; i < pci_mmcfg_config_num; i++) {
int valid = 0;
u32 size = (cfg->end_bus_number + 1) << 20;
cfg = &pci_mmcfg_config[i];
printk(KERN_NOTICE "PCI: MCFG configuration %d: base %lx "
"segment %hu buses %u - %u\n",
i, (unsigned long)cfg->address, cfg->pci_segment,
(unsigned int)cfg->start_bus_number,
(unsigned int)cfg->end_bus_number);
if (!early &&
============================================> early check..
is_acpi_reserved(cfg->address, cfg->address + size - 1)) {
printk(KERN_NOTICE "PCI: MCFG area at %Lx reserved "
"in ACPI motherboard resources\n",
cfg->address);
valid = 1;
}
if (valid)
continue;
if (!early)
=================================================> check early
printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx is not"
" reserved in ACPI motherboard resources\n",
cfg->address);
/* Don't try to do this check unless configuration
type 1 is available. how about type 2 ?*/
if (raw_pci_ops && e820_all_mapped(cfg->address,
cfg->address + size - 1,
E820_RESERVED)) {
printk(KERN_NOTICE
"PCI: MCFG area at %Lx reserved in E820\n",
cfg->address);
valid = 1;
}
if (!valid)
goto reject;
}
return;only two early check ... , if split that we will get almost same duplicated lines.
Quoted 12 lines
Quoted 12 lines
drivers/pci/probe.c +1
-1@@ -842,11 +842,14 @@ static void set_pcie_port_type(struct pci_dev *pdev)* reading the dword at 0x100 which must either be 0 or a valid extended * capability header. */ -int pci_cfg_space_size (struct pci_dev *dev) +int pci_cfg_space_size_ext (struct pci_dev *dev,unsigned check_exp_pcix) {int pos;u32 status;
Quoted 9 lines
drivers/pci/probe.c static void set_pcie_port_type(struct pci_dev *pdev) · line 852
Quoted 3 lines
drivers/pci/probe.c +3
-0+if (!check_exp_pcix) + goto skip; +Rather than adding a flag to
pci_cfg_space_size, you could either factor out the extended space probe into a separate routine and use it from bothpci_cfg_space_sizeand the fixup code, or just make the fixup code do the probe &cfg_sizesetting by hand, moving thePCI_CFG_SPACE_SIZEandPCI_CFG_SPACE_EXP_SIZEtopci.h.
by hand, will need to check if mmconf is enabled or not. will check if can factor out it.
YH
PATCH 1/1 x86/pci: remove flag in pci_cfg_space_size_ext
In reply to Jesse Barnesso let pci_cfg_space_size call it directly without flag.
arch/x86/pci/fixup.c +1 -1
@@ -502,7 +502,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SIEMENS, 0x0015,*/ static void fam10h_pci_cfg_space_size (struct pci_dev *dev) { - dev->cfg_size =pci_cfg_space_size_ext (dev,0 ); + dev->cfg_size =pci_cfg_space_size_ext (dev); }DECLARE_PCI_FIXUP_HEADER (PCI_VENDOR_ID_AMD ,0x1200 , fam10h_pci_cfg_space_size);
drivers/pci/probe.c +17 -16
@@ -842,13 +842,25 @@ static void set_pcie_port_type(struct pci_dev *pdev)* reading the dword at 0x100 which must either be 0 or a valid extended * capability header. */ -int pci_cfg_space_size_ext (struct pci_dev *dev,unsigned check_exp_pcix) +int pci_cfg_space_size_ext (struct pci_dev *dev) { -int pos;u32 status; -if (!check_exp_pcix) - goto skip; +if (pci_read_config_dword (dev,256 , &status) !=PCIBIOS_SUCCESSFUL ) + goto fail; +if (status ==0xffffffff ) + goto fail; + +return PCI_CFG_SPACE_EXP_SIZE ; + + fail: +return PCI_CFG_SPACE_SIZE ; +} + +int pci_cfg_space_size (struct pci_dev *dev) +{ +int pos; +u32 status; pos =pci_find_capability (dev,PCI_CAP_ID_EXP );if (!pos) {
@@ -861,23 +873,12 @@ int pci_cfg_space_size_ext(struct pci_dev *dev, unsigned check_exp_pcix) goto fail; } - skip: -if (pci_read_config_dword (dev,256 , &status) !=PCIBIOS_SUCCESSFUL ) - goto fail; -if (status ==0xffffffff ) - goto fail; - -return PCI_CFG_SPACE_EXP_SIZE ; +return pci_cfg_space_size_ext (dev); fail:return PCI_CFG_SPACE_SIZE ; } -int pci_cfg_space_size (struct pci_dev *dev) -{ -return pci_cfg_space_size_ext (dev,1 ); -} -static void pci_release_bus_bridge_dev (struct device *dev) {kfree (dev);
include/linux/pci.h +1 -1
@@ -667,7 +667,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,void pci_walk_bus (struct pci_bus *top,void (*cb)(struct pci_dev *,void *),void *userdata); -int pci_cfg_space_size_ext (struct pci_dev *dev,unsigned check_exp_pcix); +int pci_cfg_space_size_ext (struct pci_dev *dev);int pci_cfg_space_size (struct pci_dev *dev);unsigned char pci_bus_max_busnr (struct pci_bus *bus);
Re: [PATCH] x86/pci: remove flag in pci_cfg_space_size_ext
Quoted 3 lines · Yinghai Lu
so let
pci_cfg_space_sizecall it directly without flag.Signed-off-by Yinghai Lu <[email protected]>
Thanks Yinghai.
Ingo, I assume you'll roll this in?
Jesse
Re: [PATCH] x86/pci: remove flag in pci_cfg_space_size_ext
Quoted 8 lines · Jesse Barnes
Quoted 3 lines · Yinghai Lu
so let
pci_cfg_space_sizecall it directly without flag.Signed-off-by Yinghai Lu <[email protected]>Thanks Yinghai.
Ingo, I assume you'll roll this in?
no, i sent the tested tree to Linus, which was unmodified from 3 days ago. Could you queue up this cleanup into the PCI tree please?
Ingo
Re: [PATCH] x86/pci: remove flag in pci_cfg_space_size_ext
Quoted 4 lines · Ingo Molnar
Quoted 3 lines · Jesse Barnes
Quoted 2 lines · Yinghai Lu
so let
pci_cfg_space_sizecall it directly without flag.
Quoted 8 lines
Quoted 5 lines
Quoted 1 line
Signed-off-by Yinghai Lu <[email protected]>Thanks Yinghai.
Ingo, I assume you'll roll this in?
no, i sent the tested tree to Linus, which was unmodified from 3 days ago. Could you queue up this cleanup into the PCI tree please?
Sure, np. Applied. Thanks Yinghai.
Jesse
Quoted 5 lines · Ingo Molnar
Most of the work has been done by Yinghai Lu who has gone through a heroic effort to fix all the big-box bugs that he encountered on the vanilla Linux kernel on his various up to 256 GB RAM test-systems. Also work is included from Ying Huang for those insane SGI UV boxes.
Just to make things clear for the list readers, x86-64 worked fine for years on 256GB systems.
Many of the problems fixed in this tree are either relatively recent regressions or have nothing to do with large boxes or 256GB (like the mmconfig changes)
-Andi
Quoted 9 lines · Andi Kleen
Quoted 5 lines · Ingo Molnar
Most of the work has been done by Yinghai Lu who has gone through a heroic effort to fix all the big-box bugs that he encountered on the vanilla Linux kernel on his various up to 256 GB RAM test-systems. Also work is included from Ying Huang for those insane SGI UV boxes.
Just to make things clear for the list readers, x86-64 worked fine for years on 256GB systems.
Are you sure? I don't know who had 256g ram with x86-64 that earlier. Horus from newisys?
that mean 8 sockets * 8 dimms * 4G.
YH
Quoted 1 line
Are you sure? I don't know who had 256g ram with x86-64 that earlier.
IBM Summit. We tested that a couple of years ago.
I think the worst regressions you had to fix came from the vmemmap merge BTW. It pretty much reintroduced some mistakes in memory placing that the original code had too and which were fixed back then.
-Andi
Re: [RFC git pull] "big box" x86 changes II
In reply to Yinghai LuAnd BTW the Unisys ES7000 boxes supported that much (and more) memory for quite some time too.
-Andi