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.c83
1 files changed, 48 insertions, 35 deletions
diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c
index d91cb843f54d..146924ba5df5 100644
--- a/arch/x86_64/kernel/pci-calgary.c
+++ b/arch/x86_64/kernel/pci-calgary.c
@@ -1,9 +1,11 @@
1/* 1/*
2 * Derived from arch/powerpc/kernel/iommu.c 2 * Derived from arch/powerpc/kernel/iommu.c
3 * 3 *
4 * Copyright (C) 2006 Jon Mason <jdmason@us.ibm.com>, IBM Corporation 4 * Copyright (C) IBM Corporation, 2006
5 * Copyright (C) 2006 Muli Ben-Yehuda <muli@il.ibm.com>, IBM Corporation
6 * 5 *
6 * Author: Jon Mason <jdmason@us.ibm.com>
7 * Author: Muli Ben-Yehuda <muli@il.ibm.com>
8
7 * This program is free software; you can redistribute it and/or modify 9 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by 10 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or 11 * the Free Software Foundation; either version 2 of the License, or
@@ -83,7 +85,8 @@
83#define CSR_AGENT_MASK 0xffe0ffff 85#define CSR_AGENT_MASK 0xffe0ffff
84 86
85#define MAX_NUM_OF_PHBS 8 /* how many PHBs in total? */ 87#define MAX_NUM_OF_PHBS 8 /* how many PHBs in total? */
86#define MAX_PHB_BUS_NUM (MAX_NUM_OF_PHBS * 2) /* max dev->bus->number */ 88#define MAX_NUM_CHASSIS 8 /* max number of chassis */
89#define MAX_PHB_BUS_NUM (MAX_NUM_OF_PHBS * MAX_NUM_CHASSIS * 2) /* max dev->bus->number */
87#define PHBS_PER_CALGARY 4 90#define PHBS_PER_CALGARY 4
88 91
89/* register offsets in Calgary's internal register space */ 92/* register offsets in Calgary's internal register space */
@@ -108,7 +111,8 @@ static const unsigned long phb_offsets[] = {
108 0xB000 /* PHB3 */ 111 0xB000 /* PHB3 */
109}; 112};
110 113
111void* tce_table_kva[MAX_NUM_OF_PHBS * MAX_NUMNODES]; 114static char bus_to_phb[MAX_PHB_BUS_NUM];
115void* tce_table_kva[MAX_PHB_BUS_NUM];
112unsigned int specified_table_size = TCE_TABLE_SIZE_UNSPECIFIED; 116unsigned int specified_table_size = TCE_TABLE_SIZE_UNSPECIFIED;
113static int translate_empty_slots __read_mostly = 0; 117static int translate_empty_slots __read_mostly = 0;
114static int calgary_detected __read_mostly = 0; 118static int calgary_detected __read_mostly = 0;
@@ -117,7 +121,7 @@ static int calgary_detected __read_mostly = 0;
117 * the bitmap of PHBs the user requested that we disable 121 * the bitmap of PHBs the user requested that we disable
118 * translation on. 122 * translation on.
119 */ 123 */
120static DECLARE_BITMAP(translation_disabled, MAX_NUMNODES * MAX_PHB_BUS_NUM); 124static DECLARE_BITMAP(translation_disabled, MAX_PHB_BUS_NUM);
121 125
122static void tce_cache_blast(struct iommu_table *tbl); 126static void tce_cache_blast(struct iommu_table *tbl);
123 127
@@ -450,7 +454,7 @@ static struct dma_mapping_ops calgary_dma_ops = {
450 454
451static inline int busno_to_phbid(unsigned char num) 455static inline int busno_to_phbid(unsigned char num)
452{ 456{
453 return bus_to_phb(num) % PHBS_PER_CALGARY; 457 return bus_to_phb[num];
454} 458}
455 459
456static inline unsigned long split_queue_offset(unsigned char num) 460static inline unsigned long split_queue_offset(unsigned char num)
@@ -810,7 +814,7 @@ static int __init calgary_init(void)
810 int i, ret = -ENODEV; 814 int i, ret = -ENODEV;
811 struct pci_dev *dev = NULL; 815 struct pci_dev *dev = NULL;
812 816
813 for (i = 0; i <= num_online_nodes() * MAX_NUM_OF_PHBS; i++) { 817 for (i = 0; i < MAX_PHB_BUS_NUM; i++) {
814 dev = pci_get_device(PCI_VENDOR_ID_IBM, 818 dev = pci_get_device(PCI_VENDOR_ID_IBM,
815 PCI_DEVICE_ID_IBM_CALGARY, 819 PCI_DEVICE_ID_IBM_CALGARY,
816 dev); 820 dev);
@@ -820,7 +824,7 @@ static int __init calgary_init(void)
820 calgary_init_one_nontraslated(dev); 824 calgary_init_one_nontraslated(dev);
821 continue; 825 continue;
822 } 826 }
823 if (!tce_table_kva[i] && !translate_empty_slots) { 827 if (!tce_table_kva[dev->bus->number] && !translate_empty_slots) {
824 pci_dev_put(dev); 828 pci_dev_put(dev);
825 continue; 829 continue;
826 } 830 }
@@ -840,7 +844,7 @@ error:
840 pci_dev_put(dev); 844 pci_dev_put(dev);
841 continue; 845 continue;
842 } 846 }
843 if (!tce_table_kva[i] && !translate_empty_slots) 847 if (!tce_table_kva[dev->bus->number] && !translate_empty_slots)
844 continue; 848 continue;
845 calgary_disable_translation(dev); 849 calgary_disable_translation(dev);
846 calgary_free_tar(dev); 850 calgary_free_tar(dev);
@@ -874,9 +878,10 @@ static inline int __init determine_tce_table_size(u64 ram)
874void __init detect_calgary(void) 878void __init detect_calgary(void)
875{ 879{
876 u32 val; 880 u32 val;
877 int bus, table_idx; 881 int bus;
878 void *tbl; 882 void *tbl;
879 int detected = 0; 883 int calgary_found = 0;
884 int phb = -1;
880 885
881 /* 886 /*
882 * if the user specified iommu=off or iommu=soft or we found 887 * if the user specified iommu=off or iommu=soft or we found
@@ -887,38 +892,46 @@ void __init detect_calgary(void)
887 892
888 specified_table_size = determine_tce_table_size(end_pfn * PAGE_SIZE); 893 specified_table_size = determine_tce_table_size(end_pfn * PAGE_SIZE);
889 894
890 for (bus = 0, table_idx = 0; 895 for (bus = 0; bus < MAX_PHB_BUS_NUM; bus++) {
891 bus <= num_online_nodes() * MAX_PHB_BUS_NUM; 896 int dev;
892 bus++) { 897
893 BUG_ON(bus > MAX_NUMNODES * MAX_PHB_BUS_NUM); 898 tce_table_kva[bus] = NULL;
899 bus_to_phb[bus] = -1;
900
894 if (read_pci_config(bus, 0, 0, 0) != PCI_VENDOR_DEVICE_ID_CALGARY) 901 if (read_pci_config(bus, 0, 0, 0) != PCI_VENDOR_DEVICE_ID_CALGARY)
895 continue; 902 continue;
903
904 /*
905 * There are 4 PHBs per Calgary chip. Set phb to which phb (0-3)
906 * it is connected to releative to the clagary chip.
907 */
908 phb = (phb + 1) % PHBS_PER_CALGARY;
909
896 if (test_bit(bus, translation_disabled)) { 910 if (test_bit(bus, translation_disabled)) {
897 printk(KERN_INFO "Calgary: translation is disabled for " 911 printk(KERN_INFO "Calgary: translation is disabled for "
898 "PHB 0x%x\n", bus); 912 "PHB 0x%x\n", bus);
899 /* skip this phb, don't allocate a tbl for it */ 913 /* skip this phb, don't allocate a tbl for it */
900 tce_table_kva[table_idx] = NULL;
901 table_idx++;
902 continue; 914 continue;
903 } 915 }
904 /* 916 /*
905 * scan the first slot of the PCI bus to see if there 917 * Scan the slots of the PCI bus to see if there is a device present.
906 * are any devices present 918 * The parent bus will be the zero-ith device, so start at 1.
907 */ 919 */
908 val = read_pci_config(bus, 1, 0, 0); 920 for (dev = 1; dev < 8; dev++) {
909 if (val != 0xffffffff || translate_empty_slots) { 921 val = read_pci_config(bus, dev, 0, 0);
910 tbl = alloc_tce_table(); 922 if (val != 0xffffffff || translate_empty_slots) {
911 if (!tbl) 923 tbl = alloc_tce_table();
912 goto cleanup; 924 if (!tbl)
913 detected = 1; 925 goto cleanup;
914 } else 926 tce_table_kva[bus] = tbl;
915 tbl = NULL; 927 bus_to_phb[bus] = phb;
916 928 calgary_found = 1;
917 tce_table_kva[table_idx] = tbl; 929 break;
918 table_idx++; 930 }
931 }
919 } 932 }
920 933
921 if (detected) { 934 if (calgary_found) {
922 iommu_detected = 1; 935 iommu_detected = 1;
923 calgary_detected = 1; 936 calgary_detected = 1;
924 printk(KERN_INFO "PCI-DMA: Calgary IOMMU detected. " 937 printk(KERN_INFO "PCI-DMA: Calgary IOMMU detected. "
@@ -927,9 +940,9 @@ void __init detect_calgary(void)
927 return; 940 return;
928 941
929cleanup: 942cleanup:
930 for (--table_idx; table_idx >= 0; --table_idx) 943 for (--bus; bus >= 0; --bus)
931 if (tce_table_kva[table_idx]) 944 if (tce_table_kva[bus])
932 free_tce_table(tce_table_kva[table_idx]); 945 free_tce_table(tce_table_kva[bus]);
933} 946}
934 947
935int __init calgary_iommu_init(void) 948int __init calgary_iommu_init(void)
@@ -1000,7 +1013,7 @@ static int __init calgary_parse_options(char *p)
1000 if (p == endp) 1013 if (p == endp)
1001 break; 1014 break;
1002 1015
1003 if (bridge <= (num_online_nodes() * MAX_PHB_BUS_NUM)) { 1016 if (bridge < MAX_PHB_BUS_NUM) {
1004 printk(KERN_INFO "Calgary: disabling " 1017 printk(KERN_INFO "Calgary: disabling "
1005 "translation for PHB 0x%x\n", bridge); 1018 "translation for PHB 0x%x\n", bridge);
1006 set_bit(bridge, translation_disabled); 1019 set_bit(bridge, translation_disabled);