aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/kernel/pci-calgary.c
diff options
context:
space:
mode:
authorLaurent Vivier <Laurent.Vivier@bull.net>2006-12-06 20:14:06 -0500
committerAndi Kleen <andi@basil.nowhere.org>2006-12-06 20:14:06 -0500
commitb34e90b8f0f30151349134f87b5dc6ef75a5218c (patch)
tree201c7cb4e3303dcf00547748c9c86a48d4cf45cb /arch/x86_64/kernel/pci-calgary.c
parent58db85482743f5e3495d168c641c60ce1d3dfb06 (diff)
[PATCH] Calgary: use BIOS supplied BBARs and topology information
Find the BBAR register address of each Calgary using the "Extended BIOS Data Area" rather than calculating it ourselves. Also get the bus topology (what PHB each bus is on) from Calgary rather than calculating it ourselves. This patch fixes http://bugzilla.kernel.org/show_bug.cgi?id=7407. Signed-off-by: Laurent Vivier <Laurent.Vivier@bull.net> Signed-off-by: Muli Ben-Yehuda <muli@il.ibm.com> Signed-off-by: Jon Mason <jdmason@kudzu.us> Signed-off-by: Andi Kleen <ak@suse.de>
Diffstat (limited to 'arch/x86_64/kernel/pci-calgary.c')
-rw-r--r--arch/x86_64/kernel/pci-calgary.c161
1 files changed, 125 insertions, 36 deletions
diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c
index f53b581dfd0b..afc0a53505f1 100644
--- a/arch/x86_64/kernel/pci-calgary.c
+++ b/arch/x86_64/kernel/pci-calgary.c
@@ -41,6 +41,7 @@
41#include <asm/pci-direct.h> 41#include <asm/pci-direct.h>
42#include <asm/system.h> 42#include <asm/system.h>
43#include <asm/dma.h> 43#include <asm/dma.h>
44#include <asm/rio.h>
44 45
45#define PCI_DEVICE_ID_IBM_CALGARY 0x02a1 46#define PCI_DEVICE_ID_IBM_CALGARY 0x02a1
46#define PCI_VENDOR_DEVICE_ID_CALGARY \ 47#define PCI_VENDOR_DEVICE_ID_CALGARY \
@@ -115,14 +116,35 @@ static const unsigned long phb_offsets[] = {
115 0xB000 /* PHB3 */ 116 0xB000 /* PHB3 */
116}; 117};
117 118
119/* PHB debug registers */
120
121static const unsigned long phb_debug_offsets[] = {
122 0x4000 /* PHB 0 DEBUG */,
123 0x5000 /* PHB 1 DEBUG */,
124 0x6000 /* PHB 2 DEBUG */,
125 0x7000 /* PHB 3 DEBUG */
126};
127
128/*
129 * STUFF register for each debug PHB,
130 * byte 1 = start bus number, byte 2 = end bus number
131 */
132
133#define PHB_DEBUG_STUFF_OFFSET 0x0020
134
118unsigned int specified_table_size = TCE_TABLE_SIZE_UNSPECIFIED; 135unsigned int specified_table_size = TCE_TABLE_SIZE_UNSPECIFIED;
119static int translate_empty_slots __read_mostly = 0; 136static int translate_empty_slots __read_mostly = 0;
120static int calgary_detected __read_mostly = 0; 137static int calgary_detected __read_mostly = 0;
121 138
139static struct rio_table_hdr *rio_table_hdr __initdata;
140static struct scal_detail *scal_devs[MAX_NUMNODES] __initdata;
141static struct rio_detail *rio_devs[MAX_NUMNODES*4] __initdata;
142
122struct calgary_bus_info { 143struct calgary_bus_info {
123 void *tce_space; 144 void *tce_space;
124 unsigned char translation_disabled; 145 unsigned char translation_disabled;
125 signed char phbid; 146 signed char phbid;
147 void __iomem *bbar;
126}; 148};
127 149
128static struct calgary_bus_info bus_info[MAX_PHB_BUS_NUM] = { { NULL, 0, 0 }, }; 150static struct calgary_bus_info bus_info[MAX_PHB_BUS_NUM] = { { NULL, 0, 0 }, };
@@ -475,6 +497,11 @@ static struct dma_mapping_ops calgary_dma_ops = {
475 .unmap_sg = calgary_unmap_sg, 497 .unmap_sg = calgary_unmap_sg,
476}; 498};
477 499
500static inline void __iomem * busno_to_bbar(unsigned char num)
501{
502 return bus_info[num].bbar;
503}
504
478static inline int busno_to_phbid(unsigned char num) 505static inline int busno_to_phbid(unsigned char num)
479{ 506{
480 return bus_info[num].phbid; 507 return bus_info[num].phbid;
@@ -828,31 +855,9 @@ static void __init calgary_disable_translation(struct pci_dev *dev)
828 del_timer_sync(&tbl->watchdog_timer); 855 del_timer_sync(&tbl->watchdog_timer);
829} 856}
830 857
831static inline unsigned int __init locate_register_space(struct pci_dev *dev) 858static inline void __iomem * __init locate_register_space(struct pci_dev *dev)
832{ 859{
833 int rionodeid; 860 return busno_to_bbar(dev->bus->number);
834 u32 address;
835
836 /*
837 * Each Calgary has four busses. The first four busses (first Calgary)
838 * have RIO node ID 2, then the next four (second Calgary) have RIO
839 * node ID 3, the next four (third Calgary) have node ID 2 again, etc.
840 * We use a gross hack - relying on the dev->bus->number ordering,
841 * modulo 14 - to decide which Calgary a given bus is on. Busses 0, 1,
842 * 2 and 4 are on the first Calgary (id 2), 6, 8, a and c are on the
843 * second (id 3), and then it repeats modulo 14.
844 */
845 rionodeid = (dev->bus->number % 14 > 4) ? 3 : 2;
846 /*
847 * register space address calculation as follows:
848 * FE0MB-8MB*OneBasedChassisNumber+1MB*(RioNodeId-ChassisBase)
849 * ChassisBase is always zero for x366/x260/x460
850 * RioNodeId is 2 for first Calgary, 3 for second Calgary
851 */
852 address = START_ADDRESS -
853 (0x800000 * (ONE_BASED_CHASSIS_NUM + dev->bus->number / 14)) +
854 (0x100000) * (rionodeid - CHASSIS_BASE);
855 return address;
856} 861}
857 862
858static void __init calgary_init_one_nontraslated(struct pci_dev *dev) 863static void __init calgary_init_one_nontraslated(struct pci_dev *dev)
@@ -864,15 +869,12 @@ static void __init calgary_init_one_nontraslated(struct pci_dev *dev)
864 869
865static int __init calgary_init_one(struct pci_dev *dev) 870static int __init calgary_init_one(struct pci_dev *dev)
866{ 871{
867 u32 address;
868 void __iomem *bbar; 872 void __iomem *bbar;
869 int ret; 873 int ret;
870 874
871 BUG_ON(dev->bus->number >= MAX_PHB_BUS_NUM); 875 BUG_ON(dev->bus->number >= MAX_PHB_BUS_NUM);
872 876
873 address = locate_register_space(dev); 877 bbar = locate_register_space(dev);
874 /* map entire 1MB of Calgary config space */
875 bbar = ioremap_nocache(address, 1024 * 1024);
876 if (!bbar) { 878 if (!bbar) {
877 ret = -ENODATA; 879 ret = -ENODATA;
878 goto done; 880 goto done;
@@ -898,6 +900,35 @@ static int __init calgary_init(void)
898{ 900{
899 int ret = -ENODEV; 901 int ret = -ENODEV;
900 struct pci_dev *dev = NULL; 902 struct pci_dev *dev = NULL;
903 int rio, phb, bus;
904 void __iomem *bbar;
905 void __iomem *target;
906 u8 start_bus, end_bus;
907 u32 val;
908
909 for (rio = 0; rio < rio_table_hdr->num_rio_dev; rio++) {
910
911 if ( (rio_devs[rio]->type != COMPAT_CALGARY) &&
912 (rio_devs[rio]->type != ALT_CALGARY) )
913 continue;
914
915 /* map entire 1MB of Calgary config space */
916 bbar = ioremap_nocache(rio_devs[rio]->BBAR, 1024 * 1024);
917
918 for (phb = 0; phb < PHBS_PER_CALGARY; phb++) {
919
920 target = calgary_reg(bbar, phb_debug_offsets[phb] |
921 PHB_DEBUG_STUFF_OFFSET);
922 val = be32_to_cpu(readl(target));
923 start_bus = (u8)((val & 0x00FF0000) >> 16);
924 end_bus = (u8)((val & 0x0000FF00) >> 8);
925 for (bus = start_bus; bus <= end_bus; bus++) {
926 bus_info[bus].bbar = bbar;
927 bus_info[bus].phbid = phb;
928 }
929 }
930 }
931
901 932
902 do { 933 do {
903 dev = pci_get_device(PCI_VENDOR_ID_IBM, 934 dev = pci_get_device(PCI_VENDOR_ID_IBM,
@@ -962,13 +993,55 @@ static inline int __init determine_tce_table_size(u64 ram)
962 return ret; 993 return ret;
963} 994}
964 995
996static int __init build_detail_arrays(void)
997{
998 unsigned long ptr;
999 int i, scal_detail_size, rio_detail_size;
1000
1001 if (rio_table_hdr->num_scal_dev > MAX_NUMNODES){
1002 printk(KERN_WARNING
1003 "Calgary: MAX_NUMNODES too low! Defined as %d, "
1004 "but system has %d nodes.\n",
1005 MAX_NUMNODES, rio_table_hdr->num_scal_dev);
1006 return -ENODEV;
1007 }
1008
1009 switch (rio_table_hdr->version){
1010 default:
1011 printk(KERN_WARNING
1012 "Calgary: Invalid Rio Grande Table Version: %d\n",
1013 rio_table_hdr->version);
1014 return -ENODEV;
1015 case 2:
1016 scal_detail_size = 11;
1017 rio_detail_size = 13;
1018 break;
1019 case 3:
1020 scal_detail_size = 12;
1021 rio_detail_size = 15;
1022 break;
1023 }
1024
1025 ptr = ((unsigned long)rio_table_hdr) + 3;
1026 for (i = 0; i < rio_table_hdr->num_scal_dev;
1027 i++, ptr += scal_detail_size)
1028 scal_devs[i] = (struct scal_detail *)ptr;
1029
1030 for (i = 0; i < rio_table_hdr->num_rio_dev;
1031 i++, ptr += rio_detail_size)
1032 rio_devs[i] = (struct rio_detail *)ptr;
1033
1034 return 0;
1035}
1036
965void __init detect_calgary(void) 1037void __init detect_calgary(void)
966{ 1038{
967 u32 val; 1039 u32 val;
968 int bus; 1040 int bus;
969 void *tbl; 1041 void *tbl;
970 int calgary_found = 0; 1042 int calgary_found = 0;
971 int phb = -1; 1043 unsigned long ptr;
1044 int offset;
972 1045
973 /* 1046 /*
974 * if the user specified iommu=off or iommu=soft or we found 1047 * if the user specified iommu=off or iommu=soft or we found
@@ -980,6 +1053,29 @@ void __init detect_calgary(void)
980 if (!early_pci_allowed()) 1053 if (!early_pci_allowed())
981 return; 1054 return;
982 1055
1056 ptr = (unsigned long)phys_to_virt(get_bios_ebda());
1057
1058 rio_table_hdr = NULL;
1059 offset = 0x180;
1060 while (offset) {
1061 /* The block id is stored in the 2nd word */
1062 if (*((unsigned short *)(ptr + offset + 2)) == 0x4752){
1063 /* set the pointer past the offset & block id */
1064 rio_table_hdr = (struct rio_table_hdr *)(ptr+offset+4);
1065 break;
1066 }
1067 /* The next offset is stored in the 1st word. 0 means no more */
1068 offset = *((unsigned short *)(ptr + offset));
1069 }
1070 if (!rio_table_hdr){
1071 printk(KERN_ERR "Calgary: Unable to locate "
1072 "Rio Grande Table in EBDA - bailing!\n");
1073 return;
1074 }
1075
1076 if (build_detail_arrays())
1077 return;
1078
983 specified_table_size = determine_tce_table_size(end_pfn * PAGE_SIZE); 1079 specified_table_size = determine_tce_table_size(end_pfn * PAGE_SIZE);
984 1080
985 for (bus = 0; bus < MAX_PHB_BUS_NUM; bus++) { 1081 for (bus = 0; bus < MAX_PHB_BUS_NUM; bus++) {
@@ -990,12 +1086,6 @@ void __init detect_calgary(void)
990 if (read_pci_config(bus, 0, 0, 0) != PCI_VENDOR_DEVICE_ID_CALGARY) 1086 if (read_pci_config(bus, 0, 0, 0) != PCI_VENDOR_DEVICE_ID_CALGARY)
991 continue; 1087 continue;
992 1088
993 /*
994 * There are 4 PHBs per Calgary chip. Set phb to which phb (0-3)
995 * it is connected to releative to the clagary chip.
996 */
997 phb = (phb + 1) % PHBS_PER_CALGARY;
998
999 if (info->translation_disabled) 1089 if (info->translation_disabled)
1000 continue; 1090 continue;
1001 1091
@@ -1010,7 +1100,6 @@ void __init detect_calgary(void)
1010 if (!tbl) 1100 if (!tbl)
1011 goto cleanup; 1101 goto cleanup;
1012 info->tce_space = tbl; 1102 info->tce_space = tbl;
1013 info->phbid = phb;
1014 calgary_found = 1; 1103 calgary_found = 1;
1015 break; 1104 break;
1016 } 1105 }