diff options
-rw-r--r-- | arch/x86_64/kernel/pci-calgary.c | 161 | ||||
-rw-r--r-- | include/asm-x86_64/rio.h | 76 |
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 | |||
121 | static 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 | |||
118 | unsigned int specified_table_size = TCE_TABLE_SIZE_UNSPECIFIED; | 135 | unsigned int specified_table_size = TCE_TABLE_SIZE_UNSPECIFIED; |
119 | static int translate_empty_slots __read_mostly = 0; | 136 | static int translate_empty_slots __read_mostly = 0; |
120 | static int calgary_detected __read_mostly = 0; | 137 | static int calgary_detected __read_mostly = 0; |
121 | 138 | ||
139 | static struct rio_table_hdr *rio_table_hdr __initdata; | ||
140 | static struct scal_detail *scal_devs[MAX_NUMNODES] __initdata; | ||
141 | static struct rio_detail *rio_devs[MAX_NUMNODES*4] __initdata; | ||
142 | |||
122 | struct calgary_bus_info { | 143 | struct 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 | ||
128 | static struct calgary_bus_info bus_info[MAX_PHB_BUS_NUM] = { { NULL, 0, 0 }, }; | 150 | static 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 | ||
500 | static inline void __iomem * busno_to_bbar(unsigned char num) | ||
501 | { | ||
502 | return bus_info[num].bbar; | ||
503 | } | ||
504 | |||
478 | static inline int busno_to_phbid(unsigned char num) | 505 | static 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 | ||
831 | static inline unsigned int __init locate_register_space(struct pci_dev *dev) | 858 | static 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 | ||
858 | static void __init calgary_init_one_nontraslated(struct pci_dev *dev) | 863 | static 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 | ||
865 | static int __init calgary_init_one(struct pci_dev *dev) | 870 | static 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 | ||
996 | static 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 | |||
965 | void __init detect_calgary(void) | 1037 | void __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 | |||
14 | struct 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 | |||
20 | struct 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 | |||
35 | struct 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 | |||
57 | enum { | ||
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 | |||
69 | static 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 */ | ||