aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/kernel/pci-calgary.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86_64/kernel/pci-calgary.c')
-rw-r--r--arch/x86_64/kernel/pci-calgary.c218
1 files changed, 162 insertions, 56 deletions
diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c
index 37a770859e71..3215675ab128 100644
--- a/arch/x86_64/kernel/pci-calgary.c
+++ b/arch/x86_64/kernel/pci-calgary.c
@@ -41,6 +41,13 @@
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>
45
46#ifdef CONFIG_CALGARY_IOMMU_ENABLED_BY_DEFAULT
47int use_calgary __read_mostly = 1;
48#else
49int use_calgary __read_mostly = 0;
50#endif /* CONFIG_CALGARY_DEFAULT_ENABLED */
44 51
45#define PCI_DEVICE_ID_IBM_CALGARY 0x02a1 52#define PCI_DEVICE_ID_IBM_CALGARY 0x02a1
46#define PCI_VENDOR_DEVICE_ID_CALGARY \ 53#define PCI_VENDOR_DEVICE_ID_CALGARY \
@@ -115,14 +122,35 @@ static const unsigned long phb_offsets[] = {
115 0xB000 /* PHB3 */ 122 0xB000 /* PHB3 */
116}; 123};
117 124
125/* PHB debug registers */
126
127static const unsigned long phb_debug_offsets[] = {
128 0x4000 /* PHB 0 DEBUG */,
129 0x5000 /* PHB 1 DEBUG */,
130 0x6000 /* PHB 2 DEBUG */,
131 0x7000 /* PHB 3 DEBUG */
132};
133
134/*
135 * STUFF register for each debug PHB,
136 * byte 1 = start bus number, byte 2 = end bus number
137 */
138
139#define PHB_DEBUG_STUFF_OFFSET 0x0020
140
118unsigned int specified_table_size = TCE_TABLE_SIZE_UNSPECIFIED; 141unsigned int specified_table_size = TCE_TABLE_SIZE_UNSPECIFIED;
119static int translate_empty_slots __read_mostly = 0; 142static int translate_empty_slots __read_mostly = 0;
120static int calgary_detected __read_mostly = 0; 143static int calgary_detected __read_mostly = 0;
121 144
145static struct rio_table_hdr *rio_table_hdr __initdata;
146static struct scal_detail *scal_devs[MAX_NUMNODES] __initdata;
147static struct rio_detail *rio_devs[MAX_NUMNODES * 4] __initdata;
148
122struct calgary_bus_info { 149struct calgary_bus_info {
123 void *tce_space; 150 void *tce_space;
124 unsigned char translation_disabled; 151 unsigned char translation_disabled;
125 signed char phbid; 152 signed char phbid;
153 void __iomem *bbar;
126}; 154};
127 155
128static struct calgary_bus_info bus_info[MAX_PHB_BUS_NUM] = { { NULL, 0, 0 }, }; 156static struct calgary_bus_info bus_info[MAX_PHB_BUS_NUM] = { { NULL, 0, 0 }, };
@@ -475,6 +503,11 @@ static struct dma_mapping_ops calgary_dma_ops = {
475 .unmap_sg = calgary_unmap_sg, 503 .unmap_sg = calgary_unmap_sg,
476}; 504};
477 505
506static inline void __iomem * busno_to_bbar(unsigned char num)
507{
508 return bus_info[num].bbar;
509}
510
478static inline int busno_to_phbid(unsigned char num) 511static inline int busno_to_phbid(unsigned char num)
479{ 512{
480 return bus_info[num].phbid; 513 return bus_info[num].phbid;
@@ -620,14 +653,9 @@ static void __init calgary_reserve_peripheral_mem_2(struct pci_dev *dev)
620static void __init calgary_reserve_regions(struct pci_dev *dev) 653static void __init calgary_reserve_regions(struct pci_dev *dev)
621{ 654{
622 unsigned int npages; 655 unsigned int npages;
623 void __iomem *bbar;
624 unsigned char busnum;
625 u64 start; 656 u64 start;
626 struct iommu_table *tbl = dev->sysdata; 657 struct iommu_table *tbl = dev->sysdata;
627 658
628 bbar = tbl->bbar;
629 busnum = dev->bus->number;
630
631 /* reserve bad_dma_address in case it's a legal address */ 659 /* reserve bad_dma_address in case it's a legal address */
632 iommu_range_reserve(tbl, bad_dma_address, 1); 660 iommu_range_reserve(tbl, bad_dma_address, 1);
633 661
@@ -740,7 +768,7 @@ static void __init calgary_increase_split_completion_timeout(void __iomem *bbar,
740{ 768{
741 u64 val64; 769 u64 val64;
742 void __iomem *target; 770 void __iomem *target;
743 unsigned long phb_shift = -1; 771 unsigned int phb_shift = ~0; /* silence gcc */
744 u64 mask; 772 u64 mask;
745 773
746 switch (busno_to_phbid(busnum)) { 774 switch (busno_to_phbid(busnum)) {
@@ -828,33 +856,6 @@ static void __init calgary_disable_translation(struct pci_dev *dev)
828 del_timer_sync(&tbl->watchdog_timer); 856 del_timer_sync(&tbl->watchdog_timer);
829} 857}
830 858
831static inline unsigned int __init locate_register_space(struct pci_dev *dev)
832{
833 int rionodeid;
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}
857
858static void __init calgary_init_one_nontraslated(struct pci_dev *dev) 859static void __init calgary_init_one_nontraslated(struct pci_dev *dev)
859{ 860{
860 pci_dev_get(dev); 861 pci_dev_get(dev);
@@ -864,23 +865,15 @@ static void __init calgary_init_one_nontraslated(struct pci_dev *dev)
864 865
865static int __init calgary_init_one(struct pci_dev *dev) 866static int __init calgary_init_one(struct pci_dev *dev)
866{ 867{
867 u32 address;
868 void __iomem *bbar; 868 void __iomem *bbar;
869 int ret; 869 int ret;
870 870
871 BUG_ON(dev->bus->number >= MAX_PHB_BUS_NUM); 871 BUG_ON(dev->bus->number >= MAX_PHB_BUS_NUM);
872 872
873 address = locate_register_space(dev); 873 bbar = busno_to_bbar(dev->bus->number);
874 /* map entire 1MB of Calgary config space */
875 bbar = ioremap_nocache(address, 1024 * 1024);
876 if (!bbar) {
877 ret = -ENODATA;
878 goto done;
879 }
880
881 ret = calgary_setup_tar(dev, bbar); 874 ret = calgary_setup_tar(dev, bbar);
882 if (ret) 875 if (ret)
883 goto iounmap; 876 goto done;
884 877
885 pci_dev_get(dev); 878 pci_dev_get(dev);
886 dev->bus->self = dev; 879 dev->bus->self = dev;
@@ -888,17 +881,66 @@ static int __init calgary_init_one(struct pci_dev *dev)
888 881
889 return 0; 882 return 0;
890 883
891iounmap:
892 iounmap(bbar);
893done: 884done:
894 return ret; 885 return ret;
895} 886}
896 887
888static int __init calgary_locate_bbars(void)
889{
890 int ret;
891 int rioidx, phb, bus;
892 void __iomem *bbar;
893 void __iomem *target;
894 unsigned long offset;
895 u8 start_bus, end_bus;
896 u32 val;
897
898 ret = -ENODATA;
899 for (rioidx = 0; rioidx < rio_table_hdr->num_rio_dev; rioidx++) {
900 struct rio_detail *rio = rio_devs[rioidx];
901
902 if ((rio->type != COMPAT_CALGARY) && (rio->type != ALT_CALGARY))
903 continue;
904
905 /* map entire 1MB of Calgary config space */
906 bbar = ioremap_nocache(rio->BBAR, 1024 * 1024);
907 if (!bbar)
908 goto error;
909
910 for (phb = 0; phb < PHBS_PER_CALGARY; phb++) {
911 offset = phb_debug_offsets[phb] | PHB_DEBUG_STUFF_OFFSET;
912 target = calgary_reg(bbar, offset);
913
914 val = be32_to_cpu(readl(target));
915 start_bus = (u8)((val & 0x00FF0000) >> 16);
916 end_bus = (u8)((val & 0x0000FF00) >> 8);
917 for (bus = start_bus; bus <= end_bus; bus++) {
918 bus_info[bus].bbar = bbar;
919 bus_info[bus].phbid = phb;
920 }
921 }
922 }
923
924 return 0;
925
926error:
927 /* scan bus_info and iounmap any bbars we previously ioremap'd */
928 for (bus = 0; bus < ARRAY_SIZE(bus_info); bus++)
929 if (bus_info[bus].bbar)
930 iounmap(bus_info[bus].bbar);
931
932 return ret;
933}
934
897static int __init calgary_init(void) 935static int __init calgary_init(void)
898{ 936{
899 int ret = -ENODEV; 937 int ret;
900 struct pci_dev *dev = NULL; 938 struct pci_dev *dev = NULL;
901 939
940 ret = calgary_locate_bbars();
941 if (ret)
942 return ret;
943
902 do { 944 do {
903 dev = pci_get_device(PCI_VENDOR_ID_IBM, 945 dev = pci_get_device(PCI_VENDOR_ID_IBM,
904 PCI_DEVICE_ID_IBM_CALGARY, 946 PCI_DEVICE_ID_IBM_CALGARY,
@@ -921,7 +963,7 @@ static int __init calgary_init(void)
921 963
922error: 964error:
923 do { 965 do {
924 dev = pci_find_device_reverse(PCI_VENDOR_ID_IBM, 966 dev = pci_get_device_reverse(PCI_VENDOR_ID_IBM,
925 PCI_DEVICE_ID_IBM_CALGARY, 967 PCI_DEVICE_ID_IBM_CALGARY,
926 dev); 968 dev);
927 if (!dev) 969 if (!dev)
@@ -962,13 +1004,56 @@ static inline int __init determine_tce_table_size(u64 ram)
962 return ret; 1004 return ret;
963} 1005}
964 1006
1007static int __init build_detail_arrays(void)
1008{
1009 unsigned long ptr;
1010 int i, scal_detail_size, rio_detail_size;
1011
1012 if (rio_table_hdr->num_scal_dev > MAX_NUMNODES){
1013 printk(KERN_WARNING
1014 "Calgary: MAX_NUMNODES too low! Defined as %d, "
1015 "but system has %d nodes.\n",
1016 MAX_NUMNODES, rio_table_hdr->num_scal_dev);
1017 return -ENODEV;
1018 }
1019
1020 switch (rio_table_hdr->version){
1021 case 2:
1022 scal_detail_size = 11;
1023 rio_detail_size = 13;
1024 break;
1025 case 3:
1026 scal_detail_size = 12;
1027 rio_detail_size = 15;
1028 break;
1029 default:
1030 printk(KERN_WARNING
1031 "Calgary: Invalid Rio Grande Table Version: %d\n",
1032 rio_table_hdr->version);
1033 return -EPROTO;
1034 }
1035
1036 ptr = ((unsigned long)rio_table_hdr) + 3;
1037 for (i = 0; i < rio_table_hdr->num_scal_dev;
1038 i++, ptr += scal_detail_size)
1039 scal_devs[i] = (struct scal_detail *)ptr;
1040
1041 for (i = 0; i < rio_table_hdr->num_rio_dev;
1042 i++, ptr += rio_detail_size)
1043 rio_devs[i] = (struct rio_detail *)ptr;
1044
1045 return 0;
1046}
1047
965void __init detect_calgary(void) 1048void __init detect_calgary(void)
966{ 1049{
967 u32 val; 1050 u32 val;
968 int bus; 1051 int bus;
969 void *tbl; 1052 void *tbl;
970 int calgary_found = 0; 1053 int calgary_found = 0;
971 int phb = -1; 1054 unsigned long ptr;
1055 int offset;
1056 int ret;
972 1057
973 /* 1058 /*
974 * if the user specified iommu=off or iommu=soft or we found 1059 * if the user specified iommu=off or iommu=soft or we found
@@ -977,25 +1062,47 @@ void __init detect_calgary(void)
977 if (swiotlb || no_iommu || iommu_detected) 1062 if (swiotlb || no_iommu || iommu_detected)
978 return; 1063 return;
979 1064
1065 if (!use_calgary)
1066 return;
1067
980 if (!early_pci_allowed()) 1068 if (!early_pci_allowed())
981 return; 1069 return;
982 1070
1071 ptr = (unsigned long)phys_to_virt(get_bios_ebda());
1072
1073 rio_table_hdr = NULL;
1074 offset = 0x180;
1075 while (offset) {
1076 /* The block id is stored in the 2nd word */
1077 if (*((unsigned short *)(ptr + offset + 2)) == 0x4752){
1078 /* set the pointer past the offset & block id */
1079 rio_table_hdr = (struct rio_table_hdr *)(ptr + offset + 4);
1080 break;
1081 }
1082 /* The next offset is stored in the 1st word. 0 means no more */
1083 offset = *((unsigned short *)(ptr + offset));
1084 }
1085 if (!rio_table_hdr) {
1086 printk(KERN_ERR "Calgary: Unable to locate "
1087 "Rio Grande Table in EBDA - bailing!\n");
1088 return;
1089 }
1090
1091 ret = build_detail_arrays();
1092 if (ret) {
1093 printk(KERN_ERR "Calgary: build_detail_arrays ret %d\n", ret);
1094 return;
1095 }
1096
983 specified_table_size = determine_tce_table_size(end_pfn * PAGE_SIZE); 1097 specified_table_size = determine_tce_table_size(end_pfn * PAGE_SIZE);
984 1098
985 for (bus = 0; bus < MAX_PHB_BUS_NUM; bus++) { 1099 for (bus = 0; bus < MAX_PHB_BUS_NUM; bus++) {
986 int dev; 1100 int dev;
987 struct calgary_bus_info *info = &bus_info[bus]; 1101 struct calgary_bus_info *info = &bus_info[bus];
988 info->phbid = -1;
989 1102
990 if (read_pci_config(bus, 0, 0, 0) != PCI_VENDOR_DEVICE_ID_CALGARY) 1103 if (read_pci_config(bus, 0, 0, 0) != PCI_VENDOR_DEVICE_ID_CALGARY)
991 continue; 1104 continue;
992 1105
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) 1106 if (info->translation_disabled)
1000 continue; 1107 continue;
1001 1108
@@ -1010,7 +1117,6 @@ void __init detect_calgary(void)
1010 if (!tbl) 1117 if (!tbl)
1011 goto cleanup; 1118 goto cleanup;
1012 info->tce_space = tbl; 1119 info->tce_space = tbl;
1013 info->phbid = phb;
1014 calgary_found = 1; 1120 calgary_found = 1;
1015 break; 1121 break;
1016 } 1122 }