Commit 688cb30bdc3e398d97682a6a58f825821ee838c2
1 parent
51e8513615
Exists in
master
and in
7 other branches
[SPARC64]: Eliminate PCI IOMMU dma mapping size limit.
The hairy fast allocator in the sparc64 PCI IOMMU code has a hard limit of 256 pages. Certain devices can exceed this when performing very large I/Os. So replace with a more simple allocator, based largely upon the arch/ppc64/kernel/iommu.c code. Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 2 changed files with 145 additions and 248 deletions Side-by-side Diff
arch/sparc64/kernel/pci_iommu.c
... | ... | @@ -49,12 +49,6 @@ |
49 | 49 | |
50 | 50 | /* Ensure completion of previous PIO writes. */ |
51 | 51 | (void) pci_iommu_read(iommu->write_complete_reg); |
52 | - | |
53 | - /* Now update everyone's flush point. */ | |
54 | - for (entry = 0; entry < PBM_NCLUSTERS; entry++) { | |
55 | - iommu->alloc_info[entry].flush = | |
56 | - iommu->alloc_info[entry].next; | |
57 | - } | |
58 | 52 | } |
59 | 53 | |
60 | 54 | #define IOPTE_CONSISTENT(CTX) \ |
61 | 55 | |
62 | 56 | |
63 | 57 | |
64 | 58 | |
65 | 59 | |
... | ... | @@ -80,37 +74,78 @@ |
80 | 74 | iopte_val(*iopte) = val; |
81 | 75 | } |
82 | 76 | |
77 | +/* Based largely upon the ppc64 iommu allocator. */ | |
78 | +static long pci_arena_alloc(struct pci_iommu *iommu, unsigned long npages) | |
79 | +{ | |
80 | + struct pci_iommu_arena *arena = &iommu->arena; | |
81 | + unsigned long n, i, start, end, limit; | |
82 | + int pass; | |
83 | + | |
84 | + limit = arena->limit; | |
85 | + start = arena->hint; | |
86 | + pass = 0; | |
87 | + | |
88 | +again: | |
89 | + n = find_next_zero_bit(arena->map, limit, start); | |
90 | + end = n + npages; | |
91 | + if (unlikely(end >= limit)) { | |
92 | + if (likely(pass < 1)) { | |
93 | + limit = start; | |
94 | + start = 0; | |
95 | + __iommu_flushall(iommu); | |
96 | + pass++; | |
97 | + goto again; | |
98 | + } else { | |
99 | + /* Scanned the whole thing, give up. */ | |
100 | + return -1; | |
101 | + } | |
102 | + } | |
103 | + | |
104 | + for (i = n; i < end; i++) { | |
105 | + if (test_bit(i, arena->map)) { | |
106 | + start = i + 1; | |
107 | + goto again; | |
108 | + } | |
109 | + } | |
110 | + | |
111 | + for (i = n; i < end; i++) | |
112 | + __set_bit(i, arena->map); | |
113 | + | |
114 | + arena->hint = end; | |
115 | + | |
116 | + return n; | |
117 | +} | |
118 | + | |
119 | +static void pci_arena_free(struct pci_iommu_arena *arena, unsigned long base, unsigned long npages) | |
120 | +{ | |
121 | + unsigned long i; | |
122 | + | |
123 | + for (i = base; i < (base + npages); i++) | |
124 | + __clear_bit(i, arena->map); | |
125 | +} | |
126 | + | |
83 | 127 | void pci_iommu_table_init(struct pci_iommu *iommu, int tsbsize, u32 dma_offset, u32 dma_addr_mask) |
84 | 128 | { |
85 | - unsigned long i, tsbbase, order; | |
129 | + unsigned long i, tsbbase, order, sz, num_tsb_entries; | |
86 | 130 | |
131 | + num_tsb_entries = tsbsize / sizeof(iopte_t); | |
132 | + | |
87 | 133 | /* Setup initial software IOMMU state. */ |
88 | 134 | spin_lock_init(&iommu->lock); |
89 | 135 | iommu->ctx_lowest_free = 1; |
90 | 136 | iommu->page_table_map_base = dma_offset; |
91 | 137 | iommu->dma_addr_mask = dma_addr_mask; |
92 | 138 | |
93 | - switch (tsbsize / (8 * 1024)) { | |
94 | - case 64: | |
95 | - iommu->page_table_sz_bits = 16; | |
96 | - break; | |
97 | - case 128: | |
98 | - iommu->page_table_sz_bits = 17; | |
99 | - break; | |
100 | - default: | |
101 | - prom_printf("PCI_IOMMU: Illegal TSB size %d\n", | |
102 | - tsbsize / (8 * 1024)); | |
139 | + /* Allocate and initialize the free area map. */ | |
140 | + sz = num_tsb_entries / 8; | |
141 | + sz = (sz + 7UL) & ~7UL; | |
142 | + iommu->arena.map = kmalloc(sz, GFP_KERNEL); | |
143 | + if (!iommu->arena.map) { | |
144 | + prom_printf("PCI_IOMMU: Error, kmalloc(arena.map) failed.\n"); | |
103 | 145 | prom_halt(); |
104 | - break; | |
105 | - }; | |
106 | - | |
107 | - iommu->lowest_consistent_map = | |
108 | - 1 << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS); | |
109 | - | |
110 | - for (i = 0; i < PBM_NCLUSTERS; i++) { | |
111 | - iommu->alloc_info[i].flush = 0; | |
112 | - iommu->alloc_info[i].next = 0; | |
113 | 146 | } |
147 | + memset(iommu->arena.map, 0, sz); | |
148 | + iommu->arena.limit = num_tsb_entries; | |
114 | 149 | |
115 | 150 | /* Allocate and initialize the dummy page which we |
116 | 151 | * set inactive IO PTEs to point to. |
117 | 152 | |
118 | 153 | |
119 | 154 | |
120 | 155 | |
121 | 156 | |
122 | 157 | |
123 | 158 | |
... | ... | @@ -132,116 +167,26 @@ |
132 | 167 | } |
133 | 168 | iommu->page_table = (iopte_t *)tsbbase; |
134 | 169 | |
135 | - for (i = 0; i < tsbsize / sizeof(iopte_t); i++) | |
170 | + for (i = 0; i < num_tsb_entries; i++) | |
136 | 171 | iopte_make_dummy(iommu, &iommu->page_table[i]); |
137 | 172 | } |
138 | 173 | |
139 | -static iopte_t *alloc_streaming_cluster(struct pci_iommu *iommu, unsigned long npages) | |
174 | +static inline iopte_t *alloc_npages(struct pci_iommu *iommu, unsigned long npages) | |
140 | 175 | { |
141 | - iopte_t *iopte, *limit, *first; | |
142 | - unsigned long cnum, ent, flush_point; | |
176 | + long entry; | |
143 | 177 | |
144 | - cnum = 0; | |
145 | - while ((1UL << cnum) < npages) | |
146 | - cnum++; | |
147 | - iopte = (iommu->page_table + | |
148 | - (cnum << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS))); | |
178 | + entry = pci_arena_alloc(iommu, npages); | |
179 | + if (unlikely(entry < 0)) | |
180 | + return NULL; | |
149 | 181 | |
150 | - if (cnum == 0) | |
151 | - limit = (iommu->page_table + | |
152 | - iommu->lowest_consistent_map); | |
153 | - else | |
154 | - limit = (iopte + | |
155 | - (1 << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS))); | |
156 | - | |
157 | - iopte += ((ent = iommu->alloc_info[cnum].next) << cnum); | |
158 | - flush_point = iommu->alloc_info[cnum].flush; | |
159 | - | |
160 | - first = iopte; | |
161 | - for (;;) { | |
162 | - if (IOPTE_IS_DUMMY(iommu, iopte)) { | |
163 | - if ((iopte + (1 << cnum)) >= limit) | |
164 | - ent = 0; | |
165 | - else | |
166 | - ent = ent + 1; | |
167 | - iommu->alloc_info[cnum].next = ent; | |
168 | - if (ent == flush_point) | |
169 | - __iommu_flushall(iommu); | |
170 | - break; | |
171 | - } | |
172 | - iopte += (1 << cnum); | |
173 | - ent++; | |
174 | - if (iopte >= limit) { | |
175 | - iopte = (iommu->page_table + | |
176 | - (cnum << | |
177 | - (iommu->page_table_sz_bits - PBM_LOGCLUSTERS))); | |
178 | - ent = 0; | |
179 | - } | |
180 | - if (ent == flush_point) | |
181 | - __iommu_flushall(iommu); | |
182 | - if (iopte == first) | |
183 | - goto bad; | |
184 | - } | |
185 | - | |
186 | - /* I've got your streaming cluster right here buddy boy... */ | |
187 | - return iopte; | |
188 | - | |
189 | -bad: | |
190 | - printk(KERN_EMERG "pci_iommu: alloc_streaming_cluster of npages(%ld) failed!\n", | |
191 | - npages); | |
192 | - return NULL; | |
182 | + return iommu->page_table + entry; | |
193 | 183 | } |
194 | 184 | |
195 | -static void free_streaming_cluster(struct pci_iommu *iommu, dma_addr_t base, | |
196 | - unsigned long npages, unsigned long ctx) | |
185 | +static inline void free_npages(struct pci_iommu *iommu, dma_addr_t base, unsigned long npages) | |
197 | 186 | { |
198 | - unsigned long cnum, ent; | |
199 | - | |
200 | - cnum = 0; | |
201 | - while ((1UL << cnum) < npages) | |
202 | - cnum++; | |
203 | - | |
204 | - ent = (base << (32 - IO_PAGE_SHIFT + PBM_LOGCLUSTERS - iommu->page_table_sz_bits)) | |
205 | - >> (32 + PBM_LOGCLUSTERS + cnum - iommu->page_table_sz_bits); | |
206 | - | |
207 | - /* If the global flush might not have caught this entry, | |
208 | - * adjust the flush point such that we will flush before | |
209 | - * ever trying to reuse it. | |
210 | - */ | |
211 | -#define between(X,Y,Z) (((Z) - (Y)) >= ((X) - (Y))) | |
212 | - if (between(ent, iommu->alloc_info[cnum].next, iommu->alloc_info[cnum].flush)) | |
213 | - iommu->alloc_info[cnum].flush = ent; | |
214 | -#undef between | |
187 | + pci_arena_free(&iommu->arena, base >> IO_PAGE_SHIFT, npages); | |
215 | 188 | } |
216 | 189 | |
217 | -/* We allocate consistent mappings from the end of cluster zero. */ | |
218 | -static iopte_t *alloc_consistent_cluster(struct pci_iommu *iommu, unsigned long npages) | |
219 | -{ | |
220 | - iopte_t *iopte; | |
221 | - | |
222 | - iopte = iommu->page_table + (1 << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS)); | |
223 | - while (iopte > iommu->page_table) { | |
224 | - iopte--; | |
225 | - if (IOPTE_IS_DUMMY(iommu, iopte)) { | |
226 | - unsigned long tmp = npages; | |
227 | - | |
228 | - while (--tmp) { | |
229 | - iopte--; | |
230 | - if (!IOPTE_IS_DUMMY(iommu, iopte)) | |
231 | - break; | |
232 | - } | |
233 | - if (tmp == 0) { | |
234 | - u32 entry = (iopte - iommu->page_table); | |
235 | - | |
236 | - if (entry < iommu->lowest_consistent_map) | |
237 | - iommu->lowest_consistent_map = entry; | |
238 | - return iopte; | |
239 | - } | |
240 | - } | |
241 | - } | |
242 | - return NULL; | |
243 | -} | |
244 | - | |
245 | 190 | static int iommu_alloc_ctx(struct pci_iommu *iommu) |
246 | 191 | { |
247 | 192 | int lowest = iommu->ctx_lowest_free; |
... | ... | @@ -279,7 +224,7 @@ |
279 | 224 | struct pcidev_cookie *pcp; |
280 | 225 | struct pci_iommu *iommu; |
281 | 226 | iopte_t *iopte; |
282 | - unsigned long flags, order, first_page, ctx; | |
227 | + unsigned long flags, order, first_page; | |
283 | 228 | void *ret; |
284 | 229 | int npages; |
285 | 230 | |
... | ... | @@ -297,9 +242,10 @@ |
297 | 242 | iommu = pcp->pbm->iommu; |
298 | 243 | |
299 | 244 | spin_lock_irqsave(&iommu->lock, flags); |
300 | - iopte = alloc_consistent_cluster(iommu, size >> IO_PAGE_SHIFT); | |
301 | - if (iopte == NULL) { | |
302 | - spin_unlock_irqrestore(&iommu->lock, flags); | |
245 | + iopte = alloc_npages(iommu, size >> IO_PAGE_SHIFT); | |
246 | + spin_unlock_irqrestore(&iommu->lock, flags); | |
247 | + | |
248 | + if (unlikely(iopte == NULL)) { | |
303 | 249 | free_pages(first_page, order); |
304 | 250 | return NULL; |
305 | 251 | } |
306 | 252 | |
307 | 253 | |
... | ... | @@ -308,31 +254,15 @@ |
308 | 254 | ((iopte - iommu->page_table) << IO_PAGE_SHIFT)); |
309 | 255 | ret = (void *) first_page; |
310 | 256 | npages = size >> IO_PAGE_SHIFT; |
311 | - ctx = 0; | |
312 | - if (iommu->iommu_ctxflush) | |
313 | - ctx = iommu_alloc_ctx(iommu); | |
314 | 257 | first_page = __pa(first_page); |
315 | 258 | while (npages--) { |
316 | - iopte_val(*iopte) = (IOPTE_CONSISTENT(ctx) | | |
259 | + iopte_val(*iopte) = (IOPTE_CONSISTENT(0UL) | | |
317 | 260 | IOPTE_WRITE | |
318 | 261 | (first_page & IOPTE_PAGE)); |
319 | 262 | iopte++; |
320 | 263 | first_page += IO_PAGE_SIZE; |
321 | 264 | } |
322 | 265 | |
323 | - { | |
324 | - int i; | |
325 | - u32 daddr = *dma_addrp; | |
326 | - | |
327 | - npages = size >> IO_PAGE_SHIFT; | |
328 | - for (i = 0; i < npages; i++) { | |
329 | - pci_iommu_write(iommu->iommu_flush, daddr); | |
330 | - daddr += IO_PAGE_SIZE; | |
331 | - } | |
332 | - } | |
333 | - | |
334 | - spin_unlock_irqrestore(&iommu->lock, flags); | |
335 | - | |
336 | 266 | return ret; |
337 | 267 | } |
338 | 268 | |
... | ... | @@ -342,7 +272,7 @@ |
342 | 272 | struct pcidev_cookie *pcp; |
343 | 273 | struct pci_iommu *iommu; |
344 | 274 | iopte_t *iopte; |
345 | - unsigned long flags, order, npages, i, ctx; | |
275 | + unsigned long flags, order, npages; | |
346 | 276 | |
347 | 277 | npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT; |
348 | 278 | pcp = pdev->sysdata; |
349 | 279 | |
... | ... | @@ -352,47 +282,8 @@ |
352 | 282 | |
353 | 283 | spin_lock_irqsave(&iommu->lock, flags); |
354 | 284 | |
355 | - if ((iopte - iommu->page_table) == | |
356 | - iommu->lowest_consistent_map) { | |
357 | - iopte_t *walk = iopte + npages; | |
358 | - iopte_t *limit; | |
285 | + free_npages(iommu, dvma, npages); | |
359 | 286 | |
360 | - limit = (iommu->page_table + | |
361 | - (1 << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS))); | |
362 | - while (walk < limit) { | |
363 | - if (!IOPTE_IS_DUMMY(iommu, walk)) | |
364 | - break; | |
365 | - walk++; | |
366 | - } | |
367 | - iommu->lowest_consistent_map = | |
368 | - (walk - iommu->page_table); | |
369 | - } | |
370 | - | |
371 | - /* Data for consistent mappings cannot enter the streaming | |
372 | - * buffers, so we only need to update the TSB. We flush | |
373 | - * the IOMMU here as well to prevent conflicts with the | |
374 | - * streaming mapping deferred tlb flush scheme. | |
375 | - */ | |
376 | - | |
377 | - ctx = 0; | |
378 | - if (iommu->iommu_ctxflush) | |
379 | - ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL; | |
380 | - | |
381 | - for (i = 0; i < npages; i++, iopte++) | |
382 | - iopte_make_dummy(iommu, iopte); | |
383 | - | |
384 | - if (iommu->iommu_ctxflush) { | |
385 | - pci_iommu_write(iommu->iommu_ctxflush, ctx); | |
386 | - } else { | |
387 | - for (i = 0; i < npages; i++) { | |
388 | - u32 daddr = dvma + (i << IO_PAGE_SHIFT); | |
389 | - | |
390 | - pci_iommu_write(iommu->iommu_flush, daddr); | |
391 | - } | |
392 | - } | |
393 | - | |
394 | - iommu_free_ctx(iommu, ctx); | |
395 | - | |
396 | 287 | spin_unlock_irqrestore(&iommu->lock, flags); |
397 | 288 | |
398 | 289 | order = get_order(size); |
399 | 290 | |
400 | 291 | |
401 | 292 | |
402 | 293 | |
... | ... | @@ -418,25 +309,27 @@ |
418 | 309 | iommu = pcp->pbm->iommu; |
419 | 310 | strbuf = &pcp->pbm->stc; |
420 | 311 | |
421 | - if (direction == PCI_DMA_NONE) | |
422 | - BUG(); | |
312 | + if (unlikely(direction == PCI_DMA_NONE)) | |
313 | + goto bad_no_ctx; | |
423 | 314 | |
424 | 315 | oaddr = (unsigned long)ptr; |
425 | 316 | npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK); |
426 | 317 | npages >>= IO_PAGE_SHIFT; |
427 | 318 | |
428 | 319 | spin_lock_irqsave(&iommu->lock, flags); |
320 | + base = alloc_npages(iommu, npages); | |
321 | + ctx = 0; | |
322 | + if (iommu->iommu_ctxflush) | |
323 | + ctx = iommu_alloc_ctx(iommu); | |
324 | + spin_unlock_irqrestore(&iommu->lock, flags); | |
429 | 325 | |
430 | - base = alloc_streaming_cluster(iommu, npages); | |
431 | - if (base == NULL) | |
326 | + if (unlikely(!base)) | |
432 | 327 | goto bad; |
328 | + | |
433 | 329 | bus_addr = (iommu->page_table_map_base + |
434 | 330 | ((base - iommu->page_table) << IO_PAGE_SHIFT)); |
435 | 331 | ret = bus_addr | (oaddr & ~IO_PAGE_MASK); |
436 | 332 | base_paddr = __pa(oaddr & IO_PAGE_MASK); |
437 | - ctx = 0; | |
438 | - if (iommu->iommu_ctxflush) | |
439 | - ctx = iommu_alloc_ctx(iommu); | |
440 | 333 | if (strbuf->strbuf_enabled) |
441 | 334 | iopte_protection = IOPTE_STREAMING(ctx); |
442 | 335 | else |
443 | 336 | |
... | ... | @@ -447,12 +340,13 @@ |
447 | 340 | for (i = 0; i < npages; i++, base++, base_paddr += IO_PAGE_SIZE) |
448 | 341 | iopte_val(*base) = iopte_protection | base_paddr; |
449 | 342 | |
450 | - spin_unlock_irqrestore(&iommu->lock, flags); | |
451 | - | |
452 | 343 | return ret; |
453 | 344 | |
454 | 345 | bad: |
455 | - spin_unlock_irqrestore(&iommu->lock, flags); | |
346 | + iommu_free_ctx(iommu, ctx); | |
347 | +bad_no_ctx: | |
348 | + if (printk_ratelimit()) | |
349 | + WARN_ON(1); | |
456 | 350 | return PCI_DMA_ERROR_CODE; |
457 | 351 | } |
458 | 352 | |
459 | 353 | |
... | ... | @@ -527,10 +421,13 @@ |
527 | 421 | struct pci_iommu *iommu; |
528 | 422 | struct pci_strbuf *strbuf; |
529 | 423 | iopte_t *base; |
530 | - unsigned long flags, npages, ctx; | |
424 | + unsigned long flags, npages, ctx, i; | |
531 | 425 | |
532 | - if (direction == PCI_DMA_NONE) | |
533 | - BUG(); | |
426 | + if (unlikely(direction == PCI_DMA_NONE)) { | |
427 | + if (printk_ratelimit()) | |
428 | + WARN_ON(1); | |
429 | + return; | |
430 | + } | |
534 | 431 | |
535 | 432 | pcp = pdev->sysdata; |
536 | 433 | iommu = pcp->pbm->iommu; |
537 | 434 | |
538 | 435 | |
... | ... | @@ -556,13 +453,14 @@ |
556 | 453 | |
557 | 454 | /* Step 1: Kick data out of streaming buffers if necessary. */ |
558 | 455 | if (strbuf->strbuf_enabled) |
559 | - pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction); | |
456 | + pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, | |
457 | + npages, direction); | |
560 | 458 | |
561 | - /* Step 2: Clear out first TSB entry. */ | |
562 | - iopte_make_dummy(iommu, base); | |
459 | + /* Step 2: Clear out TSB entries. */ | |
460 | + for (i = 0; i < npages; i++) | |
461 | + iopte_make_dummy(iommu, base + i); | |
563 | 462 | |
564 | - free_streaming_cluster(iommu, bus_addr - iommu->page_table_map_base, | |
565 | - npages, ctx); | |
463 | + free_npages(iommu, bus_addr - iommu->page_table_map_base, npages); | |
566 | 464 | |
567 | 465 | iommu_free_ctx(iommu, ctx); |
568 | 466 | |
... | ... | @@ -667,6 +565,8 @@ |
667 | 565 | pci_map_single(pdev, |
668 | 566 | (page_address(sglist->page) + sglist->offset), |
669 | 567 | sglist->length, direction); |
568 | + if (unlikely(sglist->dma_address == PCI_DMA_ERROR_CODE)) | |
569 | + return 0; | |
670 | 570 | sglist->dma_length = sglist->length; |
671 | 571 | return 1; |
672 | 572 | } |
673 | 573 | |
674 | 574 | |
675 | 575 | |
676 | 576 | |
... | ... | @@ -675,22 +575,30 @@ |
675 | 575 | iommu = pcp->pbm->iommu; |
676 | 576 | strbuf = &pcp->pbm->stc; |
677 | 577 | |
678 | - if (direction == PCI_DMA_NONE) | |
679 | - BUG(); | |
578 | + if (unlikely(direction == PCI_DMA_NONE)) | |
579 | + goto bad_no_ctx; | |
680 | 580 | |
681 | 581 | /* Step 1: Prepare scatter list. */ |
682 | 582 | |
683 | 583 | npages = prepare_sg(sglist, nelems); |
684 | 584 | |
685 | - /* Step 2: Allocate a cluster. */ | |
585 | + /* Step 2: Allocate a cluster and context, if necessary. */ | |
686 | 586 | |
687 | 587 | spin_lock_irqsave(&iommu->lock, flags); |
688 | 588 | |
689 | - base = alloc_streaming_cluster(iommu, npages); | |
589 | + base = alloc_npages(iommu, npages); | |
590 | + ctx = 0; | |
591 | + if (iommu->iommu_ctxflush) | |
592 | + ctx = iommu_alloc_ctx(iommu); | |
593 | + | |
594 | + spin_unlock_irqrestore(&iommu->lock, flags); | |
595 | + | |
690 | 596 | if (base == NULL) |
691 | 597 | goto bad; |
692 | - dma_base = iommu->page_table_map_base + ((base - iommu->page_table) << IO_PAGE_SHIFT); | |
693 | 598 | |
599 | + dma_base = iommu->page_table_map_base + | |
600 | + ((base - iommu->page_table) << IO_PAGE_SHIFT); | |
601 | + | |
694 | 602 | /* Step 3: Normalize DMA addresses. */ |
695 | 603 | used = nelems; |
696 | 604 | |
697 | 605 | |
698 | 606 | |
699 | 607 | |
... | ... | @@ -702,30 +610,28 @@ |
702 | 610 | } |
703 | 611 | used = nelems - used; |
704 | 612 | |
705 | - /* Step 4: Choose a context if necessary. */ | |
706 | - ctx = 0; | |
707 | - if (iommu->iommu_ctxflush) | |
708 | - ctx = iommu_alloc_ctx(iommu); | |
709 | - | |
710 | - /* Step 5: Create the mappings. */ | |
613 | + /* Step 4: Create the mappings. */ | |
711 | 614 | if (strbuf->strbuf_enabled) |
712 | 615 | iopte_protection = IOPTE_STREAMING(ctx); |
713 | 616 | else |
714 | 617 | iopte_protection = IOPTE_CONSISTENT(ctx); |
715 | 618 | if (direction != PCI_DMA_TODEVICE) |
716 | 619 | iopte_protection |= IOPTE_WRITE; |
717 | - fill_sg (base, sglist, used, nelems, iopte_protection); | |
620 | + | |
621 | + fill_sg(base, sglist, used, nelems, iopte_protection); | |
622 | + | |
718 | 623 | #ifdef VERIFY_SG |
719 | 624 | verify_sglist(sglist, nelems, base, npages); |
720 | 625 | #endif |
721 | 626 | |
722 | - spin_unlock_irqrestore(&iommu->lock, flags); | |
723 | - | |
724 | 627 | return used; |
725 | 628 | |
726 | 629 | bad: |
727 | - spin_unlock_irqrestore(&iommu->lock, flags); | |
728 | - return PCI_DMA_ERROR_CODE; | |
630 | + iommu_free_ctx(iommu, ctx); | |
631 | +bad_no_ctx: | |
632 | + if (printk_ratelimit()) | |
633 | + WARN_ON(1); | |
634 | + return 0; | |
729 | 635 | } |
730 | 636 | |
731 | 637 | /* Unmap a set of streaming mode DMA translations. */ |
... | ... | @@ -738,8 +644,10 @@ |
738 | 644 | unsigned long flags, ctx, i, npages; |
739 | 645 | u32 bus_addr; |
740 | 646 | |
741 | - if (direction == PCI_DMA_NONE) | |
742 | - BUG(); | |
647 | + if (unlikely(direction == PCI_DMA_NONE)) { | |
648 | + if (printk_ratelimit()) | |
649 | + WARN_ON(1); | |
650 | + } | |
743 | 651 | |
744 | 652 | pcp = pdev->sysdata; |
745 | 653 | iommu = pcp->pbm->iommu; |
... | ... | @@ -751,7 +659,8 @@ |
751 | 659 | if (sglist[i].dma_length == 0) |
752 | 660 | break; |
753 | 661 | i--; |
754 | - npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) - bus_addr) >> IO_PAGE_SHIFT; | |
662 | + npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) - | |
663 | + bus_addr) >> IO_PAGE_SHIFT; | |
755 | 664 | |
756 | 665 | base = iommu->page_table + |
757 | 666 | ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); |
758 | 667 | |
... | ... | @@ -772,11 +681,11 @@ |
772 | 681 | if (strbuf->strbuf_enabled) |
773 | 682 | pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction); |
774 | 683 | |
775 | - /* Step 2: Clear out first TSB entry. */ | |
776 | - iopte_make_dummy(iommu, base); | |
684 | + /* Step 2: Clear out the TSB entries. */ | |
685 | + for (i = 0; i < npages; i++) | |
686 | + iopte_make_dummy(iommu, base + i); | |
777 | 687 | |
778 | - free_streaming_cluster(iommu, bus_addr - iommu->page_table_map_base, | |
779 | - npages, ctx); | |
688 | + free_npages(iommu, bus_addr - iommu->page_table_map_base, npages); | |
780 | 689 | |
781 | 690 | iommu_free_ctx(iommu, ctx); |
782 | 691 |
include/asm-sparc64/pbm.h
... | ... | @@ -27,23 +27,27 @@ |
27 | 27 | * PCI bus. |
28 | 28 | */ |
29 | 29 | |
30 | -#define PBM_LOGCLUSTERS 3 | |
31 | -#define PBM_NCLUSTERS (1 << PBM_LOGCLUSTERS) | |
32 | - | |
33 | 30 | struct pci_controller_info; |
34 | 31 | |
35 | 32 | /* This contains the software state necessary to drive a PCI |
36 | 33 | * controller's IOMMU. |
37 | 34 | */ |
35 | +struct pci_iommu_arena { | |
36 | + unsigned long *map; | |
37 | + unsigned int hint; | |
38 | + unsigned int limit; | |
39 | +}; | |
40 | + | |
38 | 41 | struct pci_iommu { |
39 | 42 | /* This protects the controller's IOMMU and all |
40 | 43 | * streaming buffers underneath. |
41 | 44 | */ |
42 | 45 | spinlock_t lock; |
43 | 46 | |
47 | + struct pci_iommu_arena arena; | |
48 | + | |
44 | 49 | /* IOMMU page table, a linear array of ioptes. */ |
45 | 50 | iopte_t *page_table; /* The page table itself. */ |
46 | - int page_table_sz_bits; /* log2 of ow many pages does it map? */ | |
47 | 51 | |
48 | 52 | /* Base PCI memory space address where IOMMU mappings |
49 | 53 | * begin. |
50 | 54 | |
... | ... | @@ -62,28 +66,12 @@ |
62 | 66 | */ |
63 | 67 | unsigned long write_complete_reg; |
64 | 68 | |
65 | - /* The lowest used consistent mapping entry. Since | |
66 | - * we allocate consistent maps out of cluster 0 this | |
67 | - * is relative to the beginning of closter 0. | |
68 | - */ | |
69 | - u32 lowest_consistent_map; | |
70 | - | |
71 | 69 | /* In order to deal with some buggy third-party PCI bridges that |
72 | 70 | * do wrong prefetching, we never mark valid mappings as invalid. |
73 | 71 | * Instead we point them at this dummy page. |
74 | 72 | */ |
75 | 73 | unsigned long dummy_page; |
76 | 74 | unsigned long dummy_page_pa; |
77 | - | |
78 | - /* If PBM_NCLUSTERS is ever decreased to 4 or lower, | |
79 | - * or if largest supported page_table_sz * 8K goes above | |
80 | - * 2GB, you must increase the size of the type of | |
81 | - * these counters. You have been duly warned. -DaveM | |
82 | - */ | |
83 | - struct { | |
84 | - u16 next; | |
85 | - u16 flush; | |
86 | - } alloc_info[PBM_NCLUSTERS]; | |
87 | 75 | |
88 | 76 | /* CTX allocation. */ |
89 | 77 | unsigned long ctx_lowest_free; |