aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86_64/kernel/pci-calgary.c161
-rw-r--r--include/asm-x86_64/rio.h76
2 files changed, 201 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 }
diff --git a/include/asm-x86_64/rio.h b/include/asm-x86_64/rio.h
new file mode 100644
index 000000000000..1f315c39d76e
--- /dev/null
+++ b/include/asm-x86_64/rio.h
@@ -0,0 +1,76 @@
1/*
2 * Derived from include/asm-i386/mach-summit/mach_mpparse.h
3 * and include/asm-i386/mach-default/bios_ebda.h
4 *
5 * Author: Laurent Vivier <Laurent.Vivier@bull.net>
6 *
7 */
8
9#ifndef __ASM_RIO_H
10#define __ASM_RIO_H
11
12#define RIO_TABLE_VERSION 3
13
14struct rio_table_hdr {
15 u8 version; /* Version number of this data structure */
16 u8 num_scal_dev; /* # of Scalability devices */
17 u8 num_rio_dev; /* # of RIO I/O devices */
18} __attribute__((packed));
19
20struct scal_detail {
21 u8 node_id; /* Scalability Node ID */
22 u32 CBAR; /* Address of 1MB register space */
23 u8 port0node; /* Node ID port connected to: 0xFF=None */
24 u8 port0port; /* Port num port connected to: 0,1,2, or */
25 /* 0xFF=None */
26 u8 port1node; /* Node ID port connected to: 0xFF = None */
27 u8 port1port; /* Port num port connected to: 0,1,2, or */
28 /* 0xFF=None */
29 u8 port2node; /* Node ID port connected to: 0xFF = None */
30 u8 port2port; /* Port num port connected to: 0,1,2, or */
31 /* 0xFF=None */
32 u8 chassis_num; /* 1 based Chassis number (1 = boot node) */
33} __attribute__((packed));
34
35struct rio_detail {
36 u8 node_id; /* RIO Node ID */
37 u32 BBAR; /* Address of 1MB register space */
38 u8 type; /* Type of device */
39 u8 owner_id; /* Node ID of Hurricane that owns this */
40 /* node */
41 u8 port0node; /* Node ID port connected to: 0xFF=None */
42 u8 port0port; /* Port num port connected to: 0,1,2, or */
43 /* 0xFF=None */
44 u8 port1node; /* Node ID port connected to: 0xFF=None */
45 u8 port1port; /* Port num port connected to: 0,1,2, or */
46 /* 0xFF=None */
47 u8 first_slot; /* Lowest slot number below this Calgary */
48 u8 status; /* Bit 0 = 1 : the XAPIC is used */
49 /* = 0 : the XAPIC is not used, ie: */
50 /* ints fwded to another XAPIC */
51 /* Bits1:7 Reserved */
52 u8 WP_index; /* instance index - lower ones have */
53 /* lower slot numbers/PCI bus numbers */
54 u8 chassis_num; /* 1 based Chassis number */
55} __attribute__((packed));
56
57enum {
58 HURR_SCALABILTY = 0, /* Hurricane Scalability info */
59 HURR_RIOIB = 2, /* Hurricane RIOIB info */
60 COMPAT_CALGARY = 4, /* Compatibility Calgary */
61 ALT_CALGARY = 5, /* Second Planar Calgary */
62};
63
64/*
65 * there is a real-mode segmented pointer pointing to the
66 * 4K EBDA area at 0x40E.
67 */
68
69static inline unsigned long get_bios_ebda(void)
70{
71 unsigned long address= *(unsigned short *)phys_to_virt(0x40Eul);
72 address <<= 4;
73 return address;
74}
75
76#endif /* __ASM_RIO_H */