Skip to contentSkip to conversation

"big box" x86 changes

GIT PULL In review Ingo Molnar 13 participants 52 messages Apr 26, 2008 – Apr 30, 2008

Subsystems (10)
lore
Share & tools
lore
#0 lore raw

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
index 2eb1610..0fac346 100644
@@ -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
index bf6303e..e0101d9 100644
@@ -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
index 6d2df8d..af86e43 100644
@@ -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
index 90e092d..815b650 100644
@@ -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
index cbd42e5..645ee5e 100644
@@ -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
index d31d6b7..e25c57b 100644
@@ -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
index 388b113..50a18e4 100644
@@ -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
index 0cca626..e900757 100644
@@ -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
index 86808e6..1f476e4 100644
@@ -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
index cdd6828..e9c5caf 100644
@@ -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
index 7d8c467..8fbd198 100644
@@ -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
index 42f3e4c..21d1e0e 100644
@@ -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
index a5ef5f5..b60b2ab 100644
@@ -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
index 3de9f9b..f098a6e 100644
@@ -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
index 579745c..0908fca 100644
@@ -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
index e041ced..a67921c 100644
@@ -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
index 081816a..f3c761d 100644
@@ -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
index 9207fd4..a199416 100644
@@ -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
new file mode 100644
index 0000000..0229439
@@ -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
index c4bddae..3b0db9b 100644
@@ -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	0x20000
 
 extern 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
index 2d1955c..a6dbcf4 100644
@@ -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
index 9248e09..be288b5 100644
@@ -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
index d8200ac..e77b321 100644
@@ -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
index f991359..4a55bf3 100644
@@ -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;
[… more lines in the raw message]

Lines of this file are not shown. View the raw message.

include/asm-x86/bootparam.h +14 -0
index 5115135..e865990 100644

Lines of this file are not shown. View the raw message.

include/asm-x86/e820_64.h +2 -1
index f478c57..71c4d68 100644

Lines of this file are not shown. View the raw message.

include/asm-x86/pci.h +2 -0
index ddd8e24..30bbde0 100644

Lines of this file are not shown. View the raw message.

include/asm-x86/topology.h +16 -0
index 2207326..0e6d6b0 100644

Lines of this file are not shown. View the raw message.

include/linux/acpi.h +5 -0
index 2c7e003..41f7ce7 100644

Lines of this file are not shown. View the raw message.

include/linux/ide.h +1 -2
index f20410d..13779aa 100644

Lines of this file are not shown. View the raw message.

include/linux/mm.h +1 -0
index b695875..286d315 100644

Lines of this file are not shown. View the raw message.

include/linux/pci.h +10 -1
index 2924913..abc998f 100644

Lines of this file are not shown. View the raw message.

mm/bootmem.c +106 -51

157 lines not on this page · raw message

mm/sparse.c +34 -3
index 98d6b39..7e91913 100644

Lines of this file are not shown. View the raw message.

net/core/skbuff.c +1 -1
index 4fe605f..94448e6 100644

Lines of this file are not shown. View the 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.

#1 lore raw
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/
#2 lore raw
Quoted 5 lines · Stefan Richter
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?

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

#3 lore raw
In reply to Ingo Molnar
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

#4 lore raw

[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
index cbd42e5..f95fdab 100644
@@ -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
index 17bdf23..de9c870 100644
@@ -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
index 0cca626..e900757 100644
@@ -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
index f478c57..4c6ad98 100644
@@ -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
index b695875..286d315 100644
@@ -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
index 98d6b39..7e91913 100644
@@ -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
#5 lore raw

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_NUMA

arch/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

#6 lore raw

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
Index: linux-x86.q/arch/x86/mm/init_64.c
===================================================================
@@ -810,7 +810,7 @@ void free_initrd_mem(unsigned long start
 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(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
Index: linux-x86.q/arch/x86/mm/init_64.c
===================================================================
@@ -810,10 +810,8 @@ void free_initrd_mem(unsigned long start
 
 void __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;
#7 lore raw

[git pull] "big box" x86 changes, bootmem/sparsemem, #2

In reply to Linus Torvalds

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

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
index cbd42e5..f95fdab 100644
@@ -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
index 17bdf23..de9c870 100644
@@ -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
index 0cca626..5fbb865 100644
@@ -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
index f478c57..4c6ad98 100644
@@ -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
index b695875..286d315 100644
@@ -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
index 98d6b39..7e91913 100644
@@ -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
#8 lore raw

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

#9 lore raw

[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-linus

Ok, 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
index 79f0d52..645ee5e 100644
@@ -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
index b04e2c0..60e64c8 100644
@@ -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
index 0cca626..5fbb865 100644
@@ -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
index b5e02e3..71c4d68 100644
@@ -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
index b695875..286d315 100644
@@ -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
index 98d6b39..7e91913 100644
@@ -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
#10 lore raw

Re: [git pull] "big box" x86 changes, bootmem/sparsemem

In reply to Ingo Molnar

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-linus

the 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

#11 lore raw

Re: [git pull] "big box" x86 changes, bootmem/sparsemem

Quoted 10 lines · Johannes Weiner
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

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

#12 lore raw

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 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

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.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.

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

#13 lore raw

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.

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]>
---
 mm/bootmem.c |   27 +++++++++++++++++++++++++--
 1 file changed, 25 insertions(+), 2 deletions(-)
mm/bootmem.c +25 -2
Index: linux-x86.q/mm/bootmem.c
===================================================================
@@ -493,8 +493,31 @@ int __init reserve_bootmem(unsigned long
 void __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)
#14 lore raw

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 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.

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]>

---

  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 __init reserve_bootmem(unsigned long
void __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();
}

Quoted 2 lines

unsigned long __init free_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

#15 lore raw

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 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.

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]>

---

  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 __init reserve_bootmem(unsigned long
void __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();
}

Quoted 8 lines
Quoted 2 lines

unsigned long __init free_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

#16 lore raw

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 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.

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]>

---

  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 __init reserve_bootmem(unsigned long
void __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();
}

Quoted 2 lines

unsigned long __init free_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

#17 lore raw

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 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.

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]>

---

  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 __init reserve_bootmem(unsigned long
void __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();
}

Quoted 2 lines

unsigned long __init free_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

#18 lore raw

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 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.

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]>

---

  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 __init reserve_bootmem(unsigned long
void __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();
}

Quoted 2 lines

unsigned long __init free_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

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.

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

#19 lore raw

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 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.

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]>

---

  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 __init reserve_bootmem(unsigned long
void __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();
}

Quoted 2 lines

unsigned long __init free_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

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.

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

#20 lore raw

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 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.

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]>

---

  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 __init reserve_bootmem(unsigned long
void __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();
}

Quoted 2 lines

unsigned long __init free_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

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.

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

#21 lore raw

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 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.

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]>

---

  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 __init reserve_bootmem(unsigned long
void __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();
}

Quoted 2 lines

unsigned long __init free_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

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.

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

#22 lore raw

Re: [patch] mm: node-setup agnostic free_bootmem()

In reply to Ingo Molnar

Hi 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 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.

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]>
---
 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 long
 void __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

#23 lore raw

Re: [patch] mm: node-setup agnostic free_bootmem()

Quoted 32 lines · Johannes Weiner
Quoted 32 lines

void __init free_bootmem(unsigned long addr, unsigned long size) {

mm/bootmem.c +25 -2
 	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 3 lines
Quoted 1 line

unsigned long __init free_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

#24 lore raw

Re: [patch] mm: node-setup agnostic free_bootmem()

Hi,

Quoted 34 lines · Ingo Molnar
Quoted 32 lines · Johannes Weiner
Quoted 32 lines

void __init free_bootmem(unsigned long addr, unsigned long size) {

mm/bootmem.c +25 -2
 	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 6 lines
Quoted 3 lines
Quoted 1 line

unsigned long __init free_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

#25 lore raw

Re: [git pull] "big box" x86 changes, bootmem/sparsemem

In reply to Johannes Weiner
Quoted 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-linus

the 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].

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/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.

this thread is for reserve_bootmem ?

You patch is regarding to free_bootmem, and it doesn't work with intel cross node boxes.

YH

#26 lore raw

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-linus

the 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

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

#27 lore raw

[git pull] "big box" x86 changes, boot protocol

In reply to Linus Torvalds

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-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
index 2eb1610..0fac346 100644
@@ -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
index 6d2df8d..af86e43 100644
@@ -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
index cbd42e5..79f0d52 100644
@@ -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
index d31d6b7..e25c57b 100644
@@ -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
index 17bdf23..b04e2c0 100644
@@ -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
index 5115135..e865990 100644
@@ -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
index f478c57..b5e02e3 100644
@@ -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__*/
maintainer
#28 lore raw

Re: [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-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 ;-)

...

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.

#29 lore raw

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 Seed
#30 lore raw

Re: [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

#31 lore raw

Re: [git pull] "big box" x86 changes, boot protocol

In reply to Adrian Bunk
Quoted 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

#32 lore raw

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 use memmove() 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
Index: linux-x86.q/arch/x86/kernel/e820_64.c
===================================================================
@@ -100,7 +100,7 @@ void __init free_early(unsigned long sta
 	for (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;
#33 lore raw

Re: [git pull] "big box" x86 changes, boot protocol

In reply to Andrew Morton
Quoted 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

#34 lore raw

Re: [git pull] "big box" x86 changes, boot protocol

In reply to Ingo Molnar

Documentation/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
index 2eb1610..0fac346 100644
@@ -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.

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 +10 -2
index 0fac346..86fbbd0 100644
@@ -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
reviewer Acked-by
#35 lore raw

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 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.

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
index 0fac346..86fbbd0 100644
@@ -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

#36 lore raw

Re: [git pull] "big box" x86 changes, boot protocol

In reply to Ian Campbell
Quoted 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

#37 lore raw

[RFC git pull] "big box" x86 changes, GART

In reply to Linus Torvalds

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-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
index 479926d..02f4dba 100644
@@ -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
index 388b113..50a18e4 100644
@@ -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
index c07455d..bffcf45 100644
@@ -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
index 90958ed..248e577 100644
@@ -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
#38 lore raw

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-linus

it 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

#39 lore raw

[git pull] "big box" x86 changes, PCI

In reply to Linus Torvalds

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-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
index 90e092d..815b650 100644
@@ -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
index 60e64c8..2f5c488 100644
@@ -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
index 86808e6..1f476e4 100644
@@ -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
index cdd6828..e9c5caf 100644
@@ -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
index 7d8c467..8fbd198 100644
@@ -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
index 2664cb3..1a9c0c6 100644
@@ -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 do
 		return 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 do
 		kfree(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 do
 
 	if (bus && (pci_probe & PCI_USE__CRS))
 		get_current_resources(device, busnum, domain, bus);
-	
 	return bus;
 }
 
arch/x86/pci/common.c +18 -4
index 75fcc29..2a4d751 100644
@@ -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
index 42f3e4c..21d1e0e 100644
@@ -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
index a5ef5f5..b60b2ab 100644
@@ -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
index 3de9f9b..343c363 100644
@@ -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
index 579745c..0908fca 100644
@@ -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
index e041ced..a67921c 100644
@@ -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
index 081816a..f3c761d 100644
@@ -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
index 9207fd4..a199416 100644
@@ -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
new file mode 100644
index 0000000..0229439
@@ -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
index c4bddae..8ef86b5 100644
@@ -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	0x20000
 
 extern 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
index 2d1955c..a6dbcf4 100644
@@ -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
index 9248e09..be288b5 100644
@@ -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
index f991359..4a55bf3 100644
@@ -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
index ddd8e24..30bbde0 100644
@@ -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
index 2207326..0e6d6b0 100644
@@ -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
index 2c7e003..41f7ce7 100644
@@ -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
index 2924913..abc998f 100644
@@ -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 */
#40 lore raw

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-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:

Quoted 8 lines
   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.

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

#41 lore raw

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-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.)

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

#42 lore raw

Re: [git pull] "big box" x86 changes, PCI

In reply to Ingo Molnar

On 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¥

#43 lore raw

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 is

not" + " 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 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.

by hand, will need to check if mmconf is enabled or not. will check if can factor out it.

YH

#44 lore raw

PATCH 1/1 x86/pci: remove flag in pci_cfg_space_size_ext

In reply to Jesse Barnes

so let pci_cfg_space_size call it directly without flag.

arch/x86/pci/fixup.c +1 -1
index b60b2ab..ff3a6a3 100644
@@ -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
index 4a55bf3..3706ce7 100644
@@ -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
index 8f53f4b..e9b4fcb 100644
@@ -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);
 
#45 lore raw

Re: [PATCH] x86/pci: remove flag in pci_cfg_space_size_ext

Quoted 3 lines · Yinghai Lu

so let pci_cfg_space_size call it directly without flag.

Thanks Yinghai.

Ingo, I assume you'll roll this in?

Jesse

#46 lore raw

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_size call it directly without flag.

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

#47 lore raw

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_size call it directly without flag.

Quoted 8 lines
Quoted 5 lines
Quoted 1 line

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

#48 lore raw
In reply to Ingo Molnar
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

#49 lore raw
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

#50 lore raw
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

#51 lore raw

Re: [RFC git pull] "big box" x86 changes II

In reply to Yinghai Lu

And BTW the Unisys ES7000 boxes supported that much (and more) memory for quite some time too.

-Andi