Commit d05a9ed7 authored by Andrew Morton's avatar Andrew Morton Committed by Anton Blanchard

[PATCH] provide bus to node mapping for Summit

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.
parent 9f319fe0
......@@ -26,6 +26,7 @@ obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o
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
......
......@@ -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);
......
/*
* 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);
}
#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(char *oem_id, char *oem_table_id)
}
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 */
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment