aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/sysdev/dart.h6
-rw-r--r--arch/powerpc/sysdev/dart_iommu.c49
2 files changed, 48 insertions, 7 deletions
diff --git a/arch/powerpc/sysdev/dart.h b/arch/powerpc/sysdev/dart.h
index c2d05763ccbe..1c8817c4835e 100644
--- a/arch/powerpc/sysdev/dart.h
+++ b/arch/powerpc/sysdev/dart.h
@@ -47,8 +47,12 @@
47/* U4 registers */ 47/* U4 registers */
48#define DART_BASE_U4_BASE_MASK 0xffffff 48#define DART_BASE_U4_BASE_MASK 0xffffff
49#define DART_BASE_U4_BASE_SHIFT 0 49#define DART_BASE_U4_BASE_SHIFT 0
50#define DART_CNTL_U4_FLUSHTLB 0x20000000
51#define DART_CNTL_U4_ENABLE 0x80000000 50#define DART_CNTL_U4_ENABLE 0x80000000
51#define DART_CNTL_U4_IONE 0x40000000
52#define DART_CNTL_U4_FLUSHTLB 0x20000000
53#define DART_CNTL_U4_IDLE 0x10000000
54#define DART_CNTL_U4_PAR_EN 0x08000000
55#define DART_CNTL_U4_IONE_MASK 0x07ffffff
52#define DART_SIZE_U4_SIZE_MASK 0x1fff 56#define DART_SIZE_U4_SIZE_MASK 0x1fff
53#define DART_SIZE_U4_SIZE_SHIFT 0 57#define DART_SIZE_U4_SIZE_SHIFT 0
54 58
diff --git a/arch/powerpc/sysdev/dart_iommu.c b/arch/powerpc/sysdev/dart_iommu.c
index 6232091cc72b..7c7f34ce4986 100644
--- a/arch/powerpc/sysdev/dart_iommu.c
+++ b/arch/powerpc/sysdev/dart_iommu.c
@@ -101,8 +101,8 @@ retry:
101 if (l == (1L << limit)) { 101 if (l == (1L << limit)) {
102 if (limit < 4) { 102 if (limit < 4) {
103 limit++; 103 limit++;
104 reg = DART_IN(DART_CNTL); 104 reg = DART_IN(DART_CNTL);
105 reg &= ~inv_bit; 105 reg &= ~inv_bit;
106 DART_OUT(DART_CNTL, reg); 106 DART_OUT(DART_CNTL, reg);
107 goto retry; 107 goto retry;
108 } else 108 } else
@@ -111,11 +111,39 @@ retry:
111 } 111 }
112} 112}
113 113
114static inline void dart_tlb_invalidate_one(unsigned long bus_rpn)
115{
116 unsigned int reg;
117 unsigned int l, limit;
118
119 reg = DART_CNTL_U4_ENABLE | DART_CNTL_U4_IONE |
120 (bus_rpn & DART_CNTL_U4_IONE_MASK);
121 DART_OUT(DART_CNTL, reg);
122
123 limit = 0;
124wait_more:
125 l = 0;
126 while ((DART_IN(DART_CNTL) & DART_CNTL_U4_IONE) && l < (1L << limit)) {
127 rmb();
128 l++;
129 }
130
131 if (l == (1L << limit)) {
132 if (limit < 4) {
133 limit++;
134 goto wait_more;
135 } else
136 panic("DART: TLB did not flush after waiting a long "
137 "time. Buggy U4 ?");
138 }
139}
140
114static void dart_flush(struct iommu_table *tbl) 141static void dart_flush(struct iommu_table *tbl)
115{ 142{
116 if (dart_dirty) 143 if (dart_dirty) {
117 dart_tlb_invalidate_all(); 144 dart_tlb_invalidate_all();
118 dart_dirty = 0; 145 dart_dirty = 0;
146 }
119} 147}
120 148
121static void dart_build(struct iommu_table *tbl, long index, 149static void dart_build(struct iommu_table *tbl, long index,
@@ -124,6 +152,7 @@ static void dart_build(struct iommu_table *tbl, long index,
124{ 152{
125 unsigned int *dp; 153 unsigned int *dp;
126 unsigned int rpn; 154 unsigned int rpn;
155 long l;
127 156
128 DBG("dart: build at: %lx, %lx, addr: %x\n", index, npages, uaddr); 157 DBG("dart: build at: %lx, %lx, addr: %x\n", index, npages, uaddr);
129 158
@@ -135,7 +164,8 @@ static void dart_build(struct iommu_table *tbl, long index,
135 /* On U3, all memory is contigous, so we can move this 164 /* On U3, all memory is contigous, so we can move this
136 * out of the loop. 165 * out of the loop.
137 */ 166 */
138 while (npages--) { 167 l = npages;
168 while (l--) {
139 rpn = virt_to_abs(uaddr) >> DART_PAGE_SHIFT; 169 rpn = virt_to_abs(uaddr) >> DART_PAGE_SHIFT;
140 170
141 *(dp++) = DARTMAP_VALID | (rpn & DARTMAP_RPNMASK); 171 *(dp++) = DARTMAP_VALID | (rpn & DARTMAP_RPNMASK);
@@ -143,7 +173,14 @@ static void dart_build(struct iommu_table *tbl, long index,
143 uaddr += DART_PAGE_SIZE; 173 uaddr += DART_PAGE_SIZE;
144 } 174 }
145 175
146 dart_dirty = 1; 176 if (dart_is_u4) {
177 rpn = index;
178 mb(); /* make sure all updates have reached memory */
179 while (npages--)
180 dart_tlb_invalidate_one(rpn++);
181 } else {
182 dart_dirty = 1;
183 }
147} 184}
148 185
149 186