From: Matt Dobson, via Martin Bligh


This parses the machine's BIOS tables to populate the
mp_bus_id_to_node[bus] array.  Only affects Summit machines, safe, boring. 
Has been in -mjb tree for ages, and works fine.




 arch/i386/kernel/Makefile                   |    1 
 arch/i386/kernel/setup.c                    |    3 
 arch/i386/kernel/summit.c                   |  162 ++++++++++++++++++++++++++++
 include/asm-i386/mach-summit/mach_mpparse.h |   69 +++++++++++
 include/asm-i386/mpspec.h                   |    4 
 5 files changed, 239 insertions(+)

diff -puN arch/i386/kernel/Makefile~summit-bus-to-node-mapping arch/i386/kernel/Makefile
--- 25/arch/i386/kernel/Makefile~summit-bus-to-node-mapping	2003-06-07 14:20:49.000000000 -0700
+++ 25-akpm/arch/i386/kernel/Makefile	2003-06-07 14:20:49.000000000 -0700
@@ -27,6 +27,7 @@ obj-$(CONFIG_X86_LOCAL_APIC)	+= apic.o n
 obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o
 obj-$(CONFIG_SOFTWARE_SUSPEND)	+= suspend.o suspend_asm.o
 obj-$(CONFIG_X86_NUMAQ)		+= numaq.o
+obj-$(CONFIG_X86_SUMMIT)	+= summit.o
 obj-$(CONFIG_EDD)             	+= edd.o
 obj-$(CONFIG_MODULES)		+= module.o
 obj-y				+= sysenter.o vsyscall.o
diff -puN arch/i386/kernel/setup.c~summit-bus-to-node-mapping arch/i386/kernel/setup.c
--- 25/arch/i386/kernel/setup.c~summit-bus-to-node-mapping	2003-06-07 14:20:49.000000000 -0700
+++ 25-akpm/arch/i386/kernel/setup.c	2003-06-07 14:20:49.000000000 -0700
@@ -980,6 +980,9 @@ void __init setup_arch(char **cmdline_p)
 	if (smp_found_config)
 		get_smp_config();
 #endif
+#ifdef CONFIG_X86_SUMMIT
+	setup_summit();
+#endif
 
 	register_memory(max_low_pfn);
 
diff -puN /dev/null arch/i386/kernel/summit.c
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/arch/i386/kernel/summit.c	2003-06-07 14:20:49.000000000 -0700
@@ -0,0 +1,162 @@
+/*
+ * arch/i386/kernel/summit.c - IBM Summit-Specific Code
+ *
+ * Written By: Matthew Dobson, IBM Corporation
+ *
+ * Copyright (c) 2003 IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <colpatch@us.ibm.com>
+ *
+ */
+
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <mach_mpparse.h>
+
+static void __init setup_pci_node_map_for_wpeg(int wpeg_num, struct rio_table_hdr *rth, 
+		struct scal_detail **scal_nodes, struct rio_detail **rio_nodes){
+	int twst_num = 0, node = 0, first_bus = 0;
+	int i, bus, num_busses;
+
+	for(i = 0; i < rth->num_rio_dev; i++){
+		if (rio_nodes[i]->node_id == rio_nodes[wpeg_num]->owner_id){
+			twst_num = rio_nodes[i]->owner_id;
+			break;
+		}
+	}
+	if (i == rth->num_rio_dev){
+		printk("%s: Couldn't find owner Cyclone for Winnipeg!\n", __FUNCTION__);
+		return;
+	}
+
+	for(i = 0; i < rth->num_scal_dev; i++){
+		if (scal_nodes[i]->node_id == twst_num){
+			node = scal_nodes[i]->node_id;
+			break;
+		}
+	}
+	if (i == rth->num_scal_dev){
+		printk("%s: Couldn't find owner Twister for Cyclone!\n", __FUNCTION__);
+		return;
+	}
+
+	switch (rio_nodes[wpeg_num]->type){
+	case CompatWPEG:
+		/* The Compatability Winnipeg controls the legacy busses
+		   (busses 0 & 1), the 66MHz PCI bus [2 slots] (bus 2), 
+		   and the "extra" busses in case a PCI-PCI bridge card is 
+		   used in either slot (busses 3 & 4): total 5 busses. */
+		num_busses = 5;
+		/* The BIOS numbers the busses starting at 1, and in a 
+		   slightly wierd manner.  You'll have to trust that 
+		   the math used below to determine the number of the 
+		   first bus works. */
+		first_bus = (rio_nodes[wpeg_num]->first_slot - 1) * 2;
+		break;
+	case AltWPEG:
+		/* The Alternate/Secondary Winnipeg controls the 1st 133MHz 
+		   bus [1 slot] & its "extra" bus (busses 0 & 1), the 2nd 
+		   133MHz bus [1 slot] & its "extra" bus (busses 2 & 3), the 
+		   100MHz bus [2 slots] (bus 4), and the "extra" busses for 
+		   the 2 100MHz slots (busses 5 & 6): total 7 busses. */
+		num_busses = 7;
+		first_bus = (rio_nodes[wpeg_num]->first_slot * 2) - 1;
+		break;
+	case LookOutAWPEG:
+	case LookOutBWPEG:
+		printk("%s: LookOut Winnipegs not supported yet!\n", __FUNCTION__);
+		return;
+	default:
+		printk("%s: Unsupported Winnipeg type!\n", __FUNCTION__);
+		return;
+	}
+
+	for(bus = first_bus; bus < first_bus + num_busses; bus++)
+		mp_bus_id_to_node[bus] = node;
+}
+
+static void __init build_detail_arrays(struct rio_table_hdr *rth,
+		struct scal_detail **sd, struct rio_detail **rd){
+	unsigned long ptr;
+	int i, scal_detail_size, rio_detail_size;
+
+	switch (rth->version){
+	default:
+		printk("%s: Bad Rio Grande Table Version: %d\n", __FUNCTION__, rth->version);
+		/* Fall through to default to version 2 spec */
+	case 2:
+		scal_detail_size = 11;
+		rio_detail_size = 13;
+		break;
+	case 3:
+		scal_detail_size = 12;
+		rio_detail_size = 15;
+		break;
+	}
+
+	ptr = (unsigned long)rth + 3;
+	for(i = 0; i < rth->num_scal_dev; i++)
+		sd[i] = (struct scal_detail *)(ptr + (scal_detail_size * i));
+
+	ptr += scal_detail_size * rth->num_scal_dev;
+	for(i = 0; i < rth->num_rio_dev; i++)
+		rd[i] = (struct rio_detail *)(ptr + (rio_detail_size * i));
+}
+
+void __init setup_summit(void)
+{
+	struct rio_table_hdr	*rio_table_hdr = NULL;
+	struct scal_detail	*scal_devs[MAX_NUMNODES];
+	struct rio_detail	*rio_devs[MAX_NUMNODES*2];
+	unsigned long		ptr;
+	unsigned short		offset;
+	int			i;
+
+	memset(mp_bus_id_to_node, -1, sizeof(mp_bus_id_to_node));
+
+	/* The pointer to the EBDA is stored in the word @ phys 0x40E(40:0E) */
+	ptr = *(unsigned short *)phys_to_virt(0x40Eul);
+	ptr = (unsigned long)phys_to_virt(ptr << 4);
+
+	offset = 0x180;
+	while (offset){
+		/* The block id is stored in the 2nd word */
+		if (*((unsigned short *)(ptr + offset + 2)) == 0x4752){
+			/* set the pointer past the offset & block id */
+			rio_table_hdr = (struct rio_table_hdr *)(ptr + offset + 4);
+			break;
+		}
+		/* The next offset is stored in the 1st word.  0 means no more */
+		offset = *((unsigned short *)(ptr + offset));
+	}
+	if (!rio_table_hdr){
+		printk("%s: Unable to locate Rio Grande Table in EBDA - bailing!\n", __FUNCTION__);
+		return;
+	}
+
+	/* Deal with the ugly version 2/3 pointer arithmetic */
+	build_detail_arrays(rio_table_hdr, scal_devs, rio_devs);
+
+	for(i = 0; i < rio_table_hdr->num_rio_dev; i++)
+		if (is_WPEG(rio_devs[i]->type))
+			/* It's a Winnipeg, it's got PCI Busses */
+			setup_pci_node_map_for_wpeg(i, rio_table_hdr, scal_devs, rio_devs);
+}
diff -puN include/asm-i386/mach-summit/mach_mpparse.h~summit-bus-to-node-mapping include/asm-i386/mach-summit/mach_mpparse.h
--- 25/include/asm-i386/mach-summit/mach_mpparse.h~summit-bus-to-node-mapping	2003-06-07 14:20:49.000000000 -0700
+++ 25-akpm/include/asm-i386/mach-summit/mach_mpparse.h	2003-06-07 14:20:49.000000000 -0700
@@ -1,6 +1,8 @@
 #ifndef __ASM_MACH_MPPARSE_H
 #define __ASM_MACH_MPPARSE_H
 
+#include <mach_apic.h>
+
 extern int use_cyclone;
 
 static inline void mpc_oem_bus_info(struct mpc_config_bus *m, char *name, 
@@ -38,4 +40,71 @@ static inline int acpi_madt_oem_check(ch
 	}
 	return 0;
 }
+
+struct rio_table_hdr {
+	unsigned char version;      /* Version number of this data structure           */
+	                            /* Version 3 adds chassis_num & WP_index           */
+	unsigned char num_scal_dev; /* # of Scalability devices (Twisters for Vigil)   */
+	unsigned char num_rio_dev;  /* # of RIO I/O devices (Cyclones and Winnipegs)   */
+} __attribute__((packed));
+
+struct scal_detail {
+	unsigned char node_id;      /* Scalability Node ID                             */
+	unsigned long CBAR;         /* Address of 1MB register space                   */
+	unsigned char port0node;    /* Node ID port connected to: 0xFF=None            */
+	unsigned char port0port;    /* Port num port connected to: 0,1,2, or 0xFF=None */
+	unsigned char port1node;    /* Node ID port connected to: 0xFF = None          */
+	unsigned char port1port;    /* Port num port connected to: 0,1,2, or 0xFF=None */
+	unsigned char port2node;    /* Node ID port connected to: 0xFF = None          */
+	unsigned char port2port;    /* Port num port connected to: 0,1,2, or 0xFF=None */
+	unsigned char chassis_num;  /* 1 based Chassis number (1 = boot node)          */
+} __attribute__((packed));
+
+struct rio_detail {
+	unsigned char node_id;      /* RIO Node ID                                     */
+	unsigned long BBAR;         /* Address of 1MB register space                   */
+	unsigned char type;         /* Type of device                                  */
+	unsigned char owner_id;     /* For WPEG: Node ID of Cyclone that owns this WPEG*/
+	                            /* For CYC:  Node ID of Twister that owns this CYC */
+	unsigned char port0node;    /* Node ID port connected to: 0xFF=None            */
+	unsigned char port0port;    /* Port num port connected to: 0,1,2, or 0xFF=None */
+	unsigned char port1node;    /* Node ID port connected to: 0xFF=None            */
+	unsigned char port1port;    /* Port num port connected to: 0,1,2, or 0xFF=None */
+	unsigned char first_slot;   /* For WPEG: Lowest slot number below this WPEG    */
+	                            /* For CYC:  0                                     */
+	unsigned char status;       /* For WPEG: Bit 0 = 1 : the XAPIC is used         */
+	                            /*                 = 0 : the XAPIC is not used, ie:*/
+	                            /*                     ints fwded to another XAPIC */
+	                            /*           Bits1:7 Reserved                      */
+	                            /* For CYC:  Bits0:7 Reserved                      */
+	unsigned char WP_index;     /* For WPEG: WPEG instance index - lower ones have */
+	                            /*           lower slot numbers/PCI bus numbers    */
+	                            /* For CYC:  No meaning                            */
+	unsigned char chassis_num;  /* 1 based Chassis number                          */
+	                            /* For LookOut WPEGs this field indicates the      */
+	                            /* Expansion Chassis #, enumerated from Boot       */
+	                            /* Node WPEG external port, then Boot Node CYC     */
+	                            /* external port, then Next Vigil chassis WPEG     */
+	                            /* external port, etc.                             */
+	                            /* Shared Lookouts have only 1 chassis number (the */
+	                            /* first one assigned)                             */
+} __attribute__((packed));
+
+
+typedef enum {
+	CompatTwister = 0,  /* Compatibility Twister               */
+	AltTwister    = 1,  /* Alternate Twister of internal 8-way */
+	CompatCyclone = 2,  /* Compatibility Cyclone               */
+	AltCyclone    = 3,  /* Alternate Cyclone of internal 8-way */
+	CompatWPEG    = 4,  /* Compatibility WPEG                  */
+	AltWPEG       = 5,  /* Second Planar WPEG                  */
+	LookOutAWPEG  = 6,  /* LookOut WPEG                        */
+	LookOutBWPEG  = 7,  /* LookOut WPEG                        */
+} node_type;
+
+static inline int is_WPEG(node_type type){
+	return (type == CompatWPEG || type == AltWPEG ||
+		type == LookOutAWPEG || type == LookOutBWPEG);
+}
+
 #endif /* __ASM_MACH_MPPARSE_H */
diff -puN include/asm-i386/mpspec.h~summit-bus-to-node-mapping include/asm-i386/mpspec.h
--- 25/include/asm-i386/mpspec.h~summit-bus-to-node-mapping	2003-06-07 14:20:49.000000000 -0700
+++ 25-akpm/include/asm-i386/mpspec.h	2003-06-07 14:20:49.000000000 -0700
@@ -222,6 +222,10 @@ extern unsigned long mp_lapic_addr;
 extern int pic_mode;
 extern int using_apic_timer;
 
+#ifdef CONFIG_X86_SUMMIT
+extern void setup_summit (void);
+#endif
+
 #ifdef CONFIG_ACPI_BOOT
 extern void mp_register_lapic (u8 id, u8 enabled);
 extern void mp_register_lapic_address (u64 address);

_