diff options
Diffstat (limited to 'arch/powerpc/sysdev/dart_iommu.c')
-rw-r--r-- | arch/powerpc/sysdev/dart_iommu.c | 49 |
1 files changed, 43 insertions, 6 deletions
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 | ||
114 | static 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; | ||
124 | wait_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 | |||
114 | static void dart_flush(struct iommu_table *tbl) | 141 | static 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 | ||
121 | static void dart_build(struct iommu_table *tbl, long index, | 149 | static 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 | ||