aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev/dart_iommu.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2006-07-03 13:49:45 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2006-07-03 13:49:45 -0400
commit026477c1141b67e98e3bd8bdedb7d4b88a3ecd09 (patch)
tree2624a44924c625c367f3cebf937853b9da2de282 /arch/powerpc/sysdev/dart_iommu.c
parent9f2fa466383ce100b90fe52cb4489d7a26bf72a9 (diff)
parent29454dde27d8e340bb1987bad9aa504af7081eba (diff)
Merge branch 'master' of /home/trondmy/kernel/linux-2.6/
Diffstat (limited to 'arch/powerpc/sysdev/dart_iommu.c')
-rw-r--r--arch/powerpc/sysdev/dart_iommu.c50
1 files changed, 43 insertions, 7 deletions
diff --git a/arch/powerpc/sysdev/dart_iommu.c b/arch/powerpc/sysdev/dart_iommu.c
index 6232091cc72b..e32fadde1f77 100644
--- a/arch/powerpc/sysdev/dart_iommu.c
+++ b/arch/powerpc/sysdev/dart_iommu.c
@@ -27,7 +27,6 @@
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 */ 28 */
29 29
30#include <linux/config.h>
31#include <linux/init.h> 30#include <linux/init.h>
32#include <linux/types.h> 31#include <linux/types.h>
33#include <linux/slab.h> 32#include <linux/slab.h>
@@ -101,8 +100,8 @@ retry:
101 if (l == (1L << limit)) { 100 if (l == (1L << limit)) {
102 if (limit < 4) { 101 if (limit < 4) {
103 limit++; 102 limit++;
104 reg = DART_IN(DART_CNTL); 103 reg = DART_IN(DART_CNTL);
105 reg &= ~inv_bit; 104 reg &= ~inv_bit;
106 DART_OUT(DART_CNTL, reg); 105 DART_OUT(DART_CNTL, reg);
107 goto retry; 106 goto retry;
108 } else 107 } else
@@ -111,11 +110,39 @@ retry:
111 } 110 }
112} 111}
113 112
113static inline void dart_tlb_invalidate_one(unsigned long bus_rpn)
114{
115 unsigned int reg;
116 unsigned int l, limit;
117
118 reg = DART_CNTL_U4_ENABLE | DART_CNTL_U4_IONE |
119 (bus_rpn & DART_CNTL_U4_IONE_MASK);
120 DART_OUT(DART_CNTL, reg);
121
122 limit = 0;
123wait_more:
124 l = 0;
125 while ((DART_IN(DART_CNTL) & DART_CNTL_U4_IONE) && l < (1L << limit)) {
126 rmb();
127 l++;
128 }
129
130 if (l == (1L << limit)) {
131 if (limit < 4) {
132 limit++;
133 goto wait_more;
134 } else
135 panic("DART: TLB did not flush after waiting a long "
136 "time. Buggy U4 ?");
137 }
138}
139
114static void dart_flush(struct iommu_table *tbl) 140static void dart_flush(struct iommu_table *tbl)
115{ 141{
116 if (dart_dirty) 142 if (dart_dirty) {
117 dart_tlb_invalidate_all(); 143 dart_tlb_invalidate_all();
118 dart_dirty = 0; 144 dart_dirty = 0;
145 }
119} 146}
120 147
121static void dart_build(struct iommu_table *tbl, long index, 148static void dart_build(struct iommu_table *tbl, long index,
@@ -124,6 +151,7 @@ static void dart_build(struct iommu_table *tbl, long index,
124{ 151{
125 unsigned int *dp; 152 unsigned int *dp;
126 unsigned int rpn; 153 unsigned int rpn;
154 long l;
127 155
128 DBG("dart: build at: %lx, %lx, addr: %x\n", index, npages, uaddr); 156 DBG("dart: build at: %lx, %lx, addr: %x\n", index, npages, uaddr);
129 157
@@ -135,7 +163,8 @@ static void dart_build(struct iommu_table *tbl, long index,
135 /* On U3, all memory is contigous, so we can move this 163 /* On U3, all memory is contigous, so we can move this
136 * out of the loop. 164 * out of the loop.
137 */ 165 */
138 while (npages--) { 166 l = npages;
167 while (l--) {
139 rpn = virt_to_abs(uaddr) >> DART_PAGE_SHIFT; 168 rpn = virt_to_abs(uaddr) >> DART_PAGE_SHIFT;
140 169
141 *(dp++) = DARTMAP_VALID | (rpn & DARTMAP_RPNMASK); 170 *(dp++) = DARTMAP_VALID | (rpn & DARTMAP_RPNMASK);
@@ -143,7 +172,14 @@ static void dart_build(struct iommu_table *tbl, long index,
143 uaddr += DART_PAGE_SIZE; 172 uaddr += DART_PAGE_SIZE;
144 } 173 }
145 174
146 dart_dirty = 1; 175 if (dart_is_u4) {
176 rpn = index;
177 mb(); /* make sure all updates have reached memory */
178 while (npages--)
179 dart_tlb_invalidate_one(rpn++);
180 } else {
181 dart_dirty = 1;
182 }
147} 183}
148 184
149 185