diff options
Diffstat (limited to 'arch/powerpc/platforms/iseries/iommu.c')
-rw-r--r-- | arch/powerpc/platforms/iseries/iommu.c | 46 |
1 files changed, 25 insertions, 21 deletions
diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c index bea0b703f409..e3bd2015f2c9 100644 --- a/arch/powerpc/platforms/iseries/iommu.c +++ b/arch/powerpc/platforms/iseries/iommu.c | |||
@@ -4,6 +4,7 @@ | |||
4 | * Rewrite, cleanup: | 4 | * Rewrite, cleanup: |
5 | * | 5 | * |
6 | * Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation | 6 | * Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation |
7 | * Copyright (C) 2006 Olof Johansson <olof@lixom.net> | ||
7 | * | 8 | * |
8 | * Dynamic DMA mapping support, iSeries-specific parts. | 9 | * Dynamic DMA mapping support, iSeries-specific parts. |
9 | * | 10 | * |
@@ -31,42 +32,37 @@ | |||
31 | #include <asm/tce.h> | 32 | #include <asm/tce.h> |
32 | #include <asm/machdep.h> | 33 | #include <asm/machdep.h> |
33 | #include <asm/abs_addr.h> | 34 | #include <asm/abs_addr.h> |
35 | #include <asm/prom.h> | ||
34 | #include <asm/pci-bridge.h> | 36 | #include <asm/pci-bridge.h> |
35 | #include <asm/iseries/hv_call_xm.h> | 37 | #include <asm/iseries/hv_call_xm.h> |
36 | 38 | #include <asm/iseries/iommu.h> | |
37 | #include "iommu.h" | ||
38 | |||
39 | extern struct list_head iSeries_Global_Device_List; | ||
40 | |||
41 | 39 | ||
42 | static void tce_build_iSeries(struct iommu_table *tbl, long index, long npages, | 40 | static void tce_build_iSeries(struct iommu_table *tbl, long index, long npages, |
43 | unsigned long uaddr, enum dma_data_direction direction) | 41 | unsigned long uaddr, enum dma_data_direction direction) |
44 | { | 42 | { |
45 | u64 rc; | 43 | u64 rc; |
46 | union tce_entry tce; | 44 | u64 tce, rpn; |
47 | 45 | ||
48 | index <<= TCE_PAGE_FACTOR; | 46 | index <<= TCE_PAGE_FACTOR; |
49 | npages <<= TCE_PAGE_FACTOR; | 47 | npages <<= TCE_PAGE_FACTOR; |
50 | 48 | ||
51 | while (npages--) { | 49 | while (npages--) { |
52 | tce.te_word = 0; | 50 | rpn = virt_to_abs(uaddr) >> TCE_SHIFT; |
53 | tce.te_bits.tb_rpn = virt_to_abs(uaddr) >> TCE_SHIFT; | 51 | tce = (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT; |
54 | 52 | ||
55 | if (tbl->it_type == TCE_VB) { | 53 | if (tbl->it_type == TCE_VB) { |
56 | /* Virtual Bus */ | 54 | /* Virtual Bus */ |
57 | tce.te_bits.tb_valid = 1; | 55 | tce |= TCE_VALID|TCE_ALLIO; |
58 | tce.te_bits.tb_allio = 1; | ||
59 | if (direction != DMA_TO_DEVICE) | 56 | if (direction != DMA_TO_DEVICE) |
60 | tce.te_bits.tb_rdwr = 1; | 57 | tce |= TCE_VB_WRITE; |
61 | } else { | 58 | } else { |
62 | /* PCI Bus */ | 59 | /* PCI Bus */ |
63 | tce.te_bits.tb_rdwr = 1; /* Read allowed */ | 60 | tce |= TCE_PCI_READ; /* Read allowed */ |
64 | if (direction != DMA_TO_DEVICE) | 61 | if (direction != DMA_TO_DEVICE) |
65 | tce.te_bits.tb_pciwr = 1; | 62 | tce |= TCE_PCI_WRITE; |
66 | } | 63 | } |
67 | 64 | ||
68 | rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index, | 65 | rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index, tce); |
69 | tce.te_word); | ||
70 | if (rc) | 66 | if (rc) |
71 | panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%lx\n", | 67 | panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%lx\n", |
72 | rc); | 68 | rc); |
@@ -124,7 +120,7 @@ void iommu_table_getparms_iSeries(unsigned long busno, | |||
124 | 120 | ||
125 | /* itc_size is in pages worth of table, it_size is in # of entries */ | 121 | /* itc_size is in pages worth of table, it_size is in # of entries */ |
126 | tbl->it_size = ((parms->itc_size * TCE_PAGE_SIZE) / | 122 | tbl->it_size = ((parms->itc_size * TCE_PAGE_SIZE) / |
127 | sizeof(union tce_entry)) >> TCE_PAGE_FACTOR; | 123 | TCE_ENTRY_SIZE) >> TCE_PAGE_FACTOR; |
128 | tbl->it_busno = parms->itc_busno; | 124 | tbl->it_busno = parms->itc_busno; |
129 | tbl->it_offset = parms->itc_offset >> TCE_PAGE_FACTOR; | 125 | tbl->it_offset = parms->itc_offset >> TCE_PAGE_FACTOR; |
130 | tbl->it_index = parms->itc_index; | 126 | tbl->it_index = parms->itc_index; |
@@ -142,10 +138,15 @@ void iommu_table_getparms_iSeries(unsigned long busno, | |||
142 | */ | 138 | */ |
143 | static struct iommu_table *iommu_table_find(struct iommu_table * tbl) | 139 | static struct iommu_table *iommu_table_find(struct iommu_table * tbl) |
144 | { | 140 | { |
145 | struct pci_dn *pdn; | 141 | struct device_node *node; |
146 | 142 | ||
147 | list_for_each_entry(pdn, &iSeries_Global_Device_List, Device_List) { | 143 | for (node = NULL; (node = of_find_all_nodes(node)); ) { |
148 | struct iommu_table *it = pdn->iommu_table; | 144 | struct pci_dn *pdn = PCI_DN(node); |
145 | struct iommu_table *it; | ||
146 | |||
147 | if (pdn == NULL) | ||
148 | continue; | ||
149 | it = pdn->iommu_table; | ||
149 | if ((it != NULL) && | 150 | if ((it != NULL) && |
150 | (it->it_type == TCE_PCI) && | 151 | (it->it_type == TCE_PCI) && |
151 | (it->it_offset == tbl->it_offset) && | 152 | (it->it_offset == tbl->it_offset) && |
@@ -161,15 +162,18 @@ void iommu_devnode_init_iSeries(struct device_node *dn) | |||
161 | { | 162 | { |
162 | struct iommu_table *tbl; | 163 | struct iommu_table *tbl; |
163 | struct pci_dn *pdn = PCI_DN(dn); | 164 | struct pci_dn *pdn = PCI_DN(dn); |
165 | u32 *lsn = (u32 *)get_property(dn, "linux,logical-slot-number", NULL); | ||
166 | |||
167 | BUG_ON(lsn == NULL); | ||
164 | 168 | ||
165 | tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL); | 169 | tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL); |
166 | 170 | ||
167 | iommu_table_getparms_iSeries(pdn->busno, pdn->LogicalSlot, 0, tbl); | 171 | iommu_table_getparms_iSeries(pdn->busno, *lsn, 0, tbl); |
168 | 172 | ||
169 | /* Look for existing tce table */ | 173 | /* Look for existing tce table */ |
170 | pdn->iommu_table = iommu_table_find(tbl); | 174 | pdn->iommu_table = iommu_table_find(tbl); |
171 | if (pdn->iommu_table == NULL) | 175 | if (pdn->iommu_table == NULL) |
172 | pdn->iommu_table = iommu_init_table(tbl); | 176 | pdn->iommu_table = iommu_init_table(tbl, -1); |
173 | else | 177 | else |
174 | kfree(tbl); | 178 | kfree(tbl); |
175 | } | 179 | } |