diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-16 13:09:16 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-16 13:09:16 -0400 |
commit | 92d15c2ccbb3e31a3fc71ad28fdb55e1319383c0 (patch) | |
tree | 8d83c0dc3c6b935d8367e331872f242b742f0a8a /arch/x86 | |
parent | f20bf6125605acbbc7eb8c9420d7221c91aa83eb (diff) | |
parent | 644bd2f048972d75eb1979b1fdca257d528ce687 (diff) |
Merge branch 'for-linus' of git://git.kernel.dk/data/git/linux-2.6-block
* 'for-linus' of git://git.kernel.dk/data/git/linux-2.6-block: (63 commits)
Fix memory leak in dm-crypt
SPARC64: sg chaining support
SPARC: sg chaining support
PPC: sg chaining support
PS3: sg chaining support
IA64: sg chaining support
x86-64: enable sg chaining
x86-64: update pci-gart iommu to sg helpers
x86-64: update nommu to sg helpers
x86-64: update calgary iommu to sg helpers
swiotlb: sg chaining support
i386: enable sg chaining
i386 dma_map_sg: convert to using sg helpers
mmc: need to zero sglist on init
Panic in blk_rq_map_sg() from CCISS driver
remove sglist_len
remove blk_queue_max_phys_segments in libata
revert sg segment size ifdefs
Fixup u14-34f ENABLE_SG_CHAINING
qla1280: enable use_sg_chaining option
...
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/kernel/pci-calgary_64.c | 24 | ||||
-rw-r--r-- | arch/x86/kernel/pci-gart_64.c | 65 | ||||
-rw-r--r-- | arch/x86/kernel/pci-nommu_64.c | 5 |
3 files changed, 52 insertions, 42 deletions
diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c index 71da01e73f03..a50b787b3bfa 100644 --- a/arch/x86/kernel/pci-calgary_64.c +++ b/arch/x86/kernel/pci-calgary_64.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/pci_ids.h> | 35 | #include <linux/pci_ids.h> |
36 | #include <linux/pci.h> | 36 | #include <linux/pci.h> |
37 | #include <linux/delay.h> | 37 | #include <linux/delay.h> |
38 | #include <linux/scatterlist.h> | ||
38 | #include <asm/iommu.h> | 39 | #include <asm/iommu.h> |
39 | #include <asm/calgary.h> | 40 | #include <asm/calgary.h> |
40 | #include <asm/tce.h> | 41 | #include <asm/tce.h> |
@@ -384,31 +385,32 @@ static void calgary_unmap_sg(struct device *dev, | |||
384 | struct scatterlist *sglist, int nelems, int direction) | 385 | struct scatterlist *sglist, int nelems, int direction) |
385 | { | 386 | { |
386 | struct iommu_table *tbl = find_iommu_table(dev); | 387 | struct iommu_table *tbl = find_iommu_table(dev); |
388 | struct scatterlist *s; | ||
389 | int i; | ||
387 | 390 | ||
388 | if (!translate_phb(to_pci_dev(dev))) | 391 | if (!translate_phb(to_pci_dev(dev))) |
389 | return; | 392 | return; |
390 | 393 | ||
391 | while (nelems--) { | 394 | for_each_sg(sglist, s, nelems, i) { |
392 | unsigned int npages; | 395 | unsigned int npages; |
393 | dma_addr_t dma = sglist->dma_address; | 396 | dma_addr_t dma = s->dma_address; |
394 | unsigned int dmalen = sglist->dma_length; | 397 | unsigned int dmalen = s->dma_length; |
395 | 398 | ||
396 | if (dmalen == 0) | 399 | if (dmalen == 0) |
397 | break; | 400 | break; |
398 | 401 | ||
399 | npages = num_dma_pages(dma, dmalen); | 402 | npages = num_dma_pages(dma, dmalen); |
400 | iommu_free(tbl, dma, npages); | 403 | iommu_free(tbl, dma, npages); |
401 | sglist++; | ||
402 | } | 404 | } |
403 | } | 405 | } |
404 | 406 | ||
405 | static int calgary_nontranslate_map_sg(struct device* dev, | 407 | static int calgary_nontranslate_map_sg(struct device* dev, |
406 | struct scatterlist *sg, int nelems, int direction) | 408 | struct scatterlist *sg, int nelems, int direction) |
407 | { | 409 | { |
410 | struct scatterlist *s; | ||
408 | int i; | 411 | int i; |
409 | 412 | ||
410 | for (i = 0; i < nelems; i++ ) { | 413 | for_each_sg(sg, s, nelems, i) { |
411 | struct scatterlist *s = &sg[i]; | ||
412 | BUG_ON(!s->page); | 414 | BUG_ON(!s->page); |
413 | s->dma_address = virt_to_bus(page_address(s->page) +s->offset); | 415 | s->dma_address = virt_to_bus(page_address(s->page) +s->offset); |
414 | s->dma_length = s->length; | 416 | s->dma_length = s->length; |
@@ -420,6 +422,7 @@ static int calgary_map_sg(struct device *dev, struct scatterlist *sg, | |||
420 | int nelems, int direction) | 422 | int nelems, int direction) |
421 | { | 423 | { |
422 | struct iommu_table *tbl = find_iommu_table(dev); | 424 | struct iommu_table *tbl = find_iommu_table(dev); |
425 | struct scatterlist *s; | ||
423 | unsigned long vaddr; | 426 | unsigned long vaddr; |
424 | unsigned int npages; | 427 | unsigned int npages; |
425 | unsigned long entry; | 428 | unsigned long entry; |
@@ -428,8 +431,7 @@ static int calgary_map_sg(struct device *dev, struct scatterlist *sg, | |||
428 | if (!translate_phb(to_pci_dev(dev))) | 431 | if (!translate_phb(to_pci_dev(dev))) |
429 | return calgary_nontranslate_map_sg(dev, sg, nelems, direction); | 432 | return calgary_nontranslate_map_sg(dev, sg, nelems, direction); |
430 | 433 | ||
431 | for (i = 0; i < nelems; i++ ) { | 434 | for_each_sg(sg, s, nelems, i) { |
432 | struct scatterlist *s = &sg[i]; | ||
433 | BUG_ON(!s->page); | 435 | BUG_ON(!s->page); |
434 | 436 | ||
435 | vaddr = (unsigned long)page_address(s->page) + s->offset; | 437 | vaddr = (unsigned long)page_address(s->page) + s->offset; |
@@ -454,9 +456,9 @@ static int calgary_map_sg(struct device *dev, struct scatterlist *sg, | |||
454 | return nelems; | 456 | return nelems; |
455 | error: | 457 | error: |
456 | calgary_unmap_sg(dev, sg, nelems, direction); | 458 | calgary_unmap_sg(dev, sg, nelems, direction); |
457 | for (i = 0; i < nelems; i++) { | 459 | for_each_sg(sg, s, nelems, i) { |
458 | sg[i].dma_address = bad_dma_address; | 460 | sg->dma_address = bad_dma_address; |
459 | sg[i].dma_length = 0; | 461 | sg->dma_length = 0; |
460 | } | 462 | } |
461 | return 0; | 463 | return 0; |
462 | } | 464 | } |
diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c index 4918c575d582..cfcc84e6c350 100644 --- a/arch/x86/kernel/pci-gart_64.c +++ b/arch/x86/kernel/pci-gart_64.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
24 | #include <linux/bitops.h> | 24 | #include <linux/bitops.h> |
25 | #include <linux/kdebug.h> | 25 | #include <linux/kdebug.h> |
26 | #include <linux/scatterlist.h> | ||
26 | #include <asm/atomic.h> | 27 | #include <asm/atomic.h> |
27 | #include <asm/io.h> | 28 | #include <asm/io.h> |
28 | #include <asm/mtrr.h> | 29 | #include <asm/mtrr.h> |
@@ -278,10 +279,10 @@ static void gart_unmap_single(struct device *dev, dma_addr_t dma_addr, | |||
278 | */ | 279 | */ |
279 | static void gart_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, int dir) | 280 | static void gart_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, int dir) |
280 | { | 281 | { |
282 | struct scatterlist *s; | ||
281 | int i; | 283 | int i; |
282 | 284 | ||
283 | for (i = 0; i < nents; i++) { | 285 | for_each_sg(sg, s, nents, i) { |
284 | struct scatterlist *s = &sg[i]; | ||
285 | if (!s->dma_length || !s->length) | 286 | if (!s->dma_length || !s->length) |
286 | break; | 287 | break; |
287 | gart_unmap_single(dev, s->dma_address, s->dma_length, dir); | 288 | gart_unmap_single(dev, s->dma_address, s->dma_length, dir); |
@@ -292,14 +293,14 @@ static void gart_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, | |||
292 | static int dma_map_sg_nonforce(struct device *dev, struct scatterlist *sg, | 293 | static int dma_map_sg_nonforce(struct device *dev, struct scatterlist *sg, |
293 | int nents, int dir) | 294 | int nents, int dir) |
294 | { | 295 | { |
296 | struct scatterlist *s; | ||
295 | int i; | 297 | int i; |
296 | 298 | ||
297 | #ifdef CONFIG_IOMMU_DEBUG | 299 | #ifdef CONFIG_IOMMU_DEBUG |
298 | printk(KERN_DEBUG "dma_map_sg overflow\n"); | 300 | printk(KERN_DEBUG "dma_map_sg overflow\n"); |
299 | #endif | 301 | #endif |
300 | 302 | ||
301 | for (i = 0; i < nents; i++ ) { | 303 | for_each_sg(sg, s, nents, i) { |
302 | struct scatterlist *s = &sg[i]; | ||
303 | unsigned long addr = page_to_phys(s->page) + s->offset; | 304 | unsigned long addr = page_to_phys(s->page) + s->offset; |
304 | if (nonforced_iommu(dev, addr, s->length)) { | 305 | if (nonforced_iommu(dev, addr, s->length)) { |
305 | addr = dma_map_area(dev, addr, s->length, dir); | 306 | addr = dma_map_area(dev, addr, s->length, dir); |
@@ -319,23 +320,23 @@ static int dma_map_sg_nonforce(struct device *dev, struct scatterlist *sg, | |||
319 | } | 320 | } |
320 | 321 | ||
321 | /* Map multiple scatterlist entries continuous into the first. */ | 322 | /* Map multiple scatterlist entries continuous into the first. */ |
322 | static int __dma_map_cont(struct scatterlist *sg, int start, int stopat, | 323 | static int __dma_map_cont(struct scatterlist *start, int nelems, |
323 | struct scatterlist *sout, unsigned long pages) | 324 | struct scatterlist *sout, unsigned long pages) |
324 | { | 325 | { |
325 | unsigned long iommu_start = alloc_iommu(pages); | 326 | unsigned long iommu_start = alloc_iommu(pages); |
326 | unsigned long iommu_page = iommu_start; | 327 | unsigned long iommu_page = iommu_start; |
328 | struct scatterlist *s; | ||
327 | int i; | 329 | int i; |
328 | 330 | ||
329 | if (iommu_start == -1) | 331 | if (iommu_start == -1) |
330 | return -1; | 332 | return -1; |
331 | 333 | ||
332 | for (i = start; i < stopat; i++) { | 334 | for_each_sg(start, s, nelems, i) { |
333 | struct scatterlist *s = &sg[i]; | ||
334 | unsigned long pages, addr; | 335 | unsigned long pages, addr; |
335 | unsigned long phys_addr = s->dma_address; | 336 | unsigned long phys_addr = s->dma_address; |
336 | 337 | ||
337 | BUG_ON(i > start && s->offset); | 338 | BUG_ON(s != start && s->offset); |
338 | if (i == start) { | 339 | if (s == start) { |
339 | *sout = *s; | 340 | *sout = *s; |
340 | sout->dma_address = iommu_bus_base; | 341 | sout->dma_address = iommu_bus_base; |
341 | sout->dma_address += iommu_page*PAGE_SIZE + s->offset; | 342 | sout->dma_address += iommu_page*PAGE_SIZE + s->offset; |
@@ -357,17 +358,17 @@ static int __dma_map_cont(struct scatterlist *sg, int start, int stopat, | |||
357 | return 0; | 358 | return 0; |
358 | } | 359 | } |
359 | 360 | ||
360 | static inline int dma_map_cont(struct scatterlist *sg, int start, int stopat, | 361 | static inline int dma_map_cont(struct scatterlist *start, int nelems, |
361 | struct scatterlist *sout, | 362 | struct scatterlist *sout, |
362 | unsigned long pages, int need) | 363 | unsigned long pages, int need) |
363 | { | 364 | { |
364 | if (!need) { | 365 | if (!need) { |
365 | BUG_ON(stopat - start != 1); | 366 | BUG_ON(nelems != 1); |
366 | *sout = sg[start]; | 367 | *sout = *start; |
367 | sout->dma_length = sg[start].length; | 368 | sout->dma_length = start->length; |
368 | return 0; | 369 | return 0; |
369 | } | 370 | } |
370 | return __dma_map_cont(sg, start, stopat, sout, pages); | 371 | return __dma_map_cont(start, nelems, sout, pages); |
371 | } | 372 | } |
372 | 373 | ||
373 | /* | 374 | /* |
@@ -381,6 +382,7 @@ int gart_map_sg(struct device *dev, struct scatterlist *sg, int nents, int dir) | |||
381 | int start; | 382 | int start; |
382 | unsigned long pages = 0; | 383 | unsigned long pages = 0; |
383 | int need = 0, nextneed; | 384 | int need = 0, nextneed; |
385 | struct scatterlist *s, *ps, *start_sg, *sgmap; | ||
384 | 386 | ||
385 | if (nents == 0) | 387 | if (nents == 0) |
386 | return 0; | 388 | return 0; |
@@ -390,8 +392,9 @@ int gart_map_sg(struct device *dev, struct scatterlist *sg, int nents, int dir) | |||
390 | 392 | ||
391 | out = 0; | 393 | out = 0; |
392 | start = 0; | 394 | start = 0; |
393 | for (i = 0; i < nents; i++) { | 395 | start_sg = sgmap = sg; |
394 | struct scatterlist *s = &sg[i]; | 396 | ps = NULL; /* shut up gcc */ |
397 | for_each_sg(sg, s, nents, i) { | ||
395 | dma_addr_t addr = page_to_phys(s->page) + s->offset; | 398 | dma_addr_t addr = page_to_phys(s->page) + s->offset; |
396 | s->dma_address = addr; | 399 | s->dma_address = addr; |
397 | BUG_ON(s->length == 0); | 400 | BUG_ON(s->length == 0); |
@@ -400,29 +403,33 @@ int gart_map_sg(struct device *dev, struct scatterlist *sg, int nents, int dir) | |||
400 | 403 | ||
401 | /* Handle the previous not yet processed entries */ | 404 | /* Handle the previous not yet processed entries */ |
402 | if (i > start) { | 405 | if (i > start) { |
403 | struct scatterlist *ps = &sg[i-1]; | ||
404 | /* Can only merge when the last chunk ends on a page | 406 | /* Can only merge when the last chunk ends on a page |
405 | boundary and the new one doesn't have an offset. */ | 407 | boundary and the new one doesn't have an offset. */ |
406 | if (!iommu_merge || !nextneed || !need || s->offset || | 408 | if (!iommu_merge || !nextneed || !need || s->offset || |
407 | (ps->offset + ps->length) % PAGE_SIZE) { | 409 | (ps->offset + ps->length) % PAGE_SIZE) { |
408 | if (dma_map_cont(sg, start, i, sg+out, pages, | 410 | if (dma_map_cont(start_sg, i - start, sgmap, |
409 | need) < 0) | 411 | pages, need) < 0) |
410 | goto error; | 412 | goto error; |
411 | out++; | 413 | out++; |
414 | sgmap = sg_next(sgmap); | ||
412 | pages = 0; | 415 | pages = 0; |
413 | start = i; | 416 | start = i; |
417 | start_sg = s; | ||
414 | } | 418 | } |
415 | } | 419 | } |
416 | 420 | ||
417 | need = nextneed; | 421 | need = nextneed; |
418 | pages += to_pages(s->offset, s->length); | 422 | pages += to_pages(s->offset, s->length); |
423 | ps = s; | ||
419 | } | 424 | } |
420 | if (dma_map_cont(sg, start, i, sg+out, pages, need) < 0) | 425 | if (dma_map_cont(start_sg, i - start, sgmap, pages, need) < 0) |
421 | goto error; | 426 | goto error; |
422 | out++; | 427 | out++; |
423 | flush_gart(); | 428 | flush_gart(); |
424 | if (out < nents) | 429 | if (out < nents) { |
425 | sg[out].dma_length = 0; | 430 | sgmap = sg_next(sgmap); |
431 | sgmap->dma_length = 0; | ||
432 | } | ||
426 | return out; | 433 | return out; |
427 | 434 | ||
428 | error: | 435 | error: |
@@ -437,8 +444,8 @@ error: | |||
437 | if (panic_on_overflow) | 444 | if (panic_on_overflow) |
438 | panic("dma_map_sg: overflow on %lu pages\n", pages); | 445 | panic("dma_map_sg: overflow on %lu pages\n", pages); |
439 | iommu_full(dev, pages << PAGE_SHIFT, dir); | 446 | iommu_full(dev, pages << PAGE_SHIFT, dir); |
440 | for (i = 0; i < nents; i++) | 447 | for_each_sg(sg, s, nents, i) |
441 | sg[i].dma_address = bad_dma_address; | 448 | s->dma_address = bad_dma_address; |
442 | return 0; | 449 | return 0; |
443 | } | 450 | } |
444 | 451 | ||
diff --git a/arch/x86/kernel/pci-nommu_64.c b/arch/x86/kernel/pci-nommu_64.c index 2a34c6c025a9..e85d4360360c 100644 --- a/arch/x86/kernel/pci-nommu_64.c +++ b/arch/x86/kernel/pci-nommu_64.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/pci.h> | 5 | #include <linux/pci.h> |
6 | #include <linux/string.h> | 6 | #include <linux/string.h> |
7 | #include <linux/dma-mapping.h> | 7 | #include <linux/dma-mapping.h> |
8 | #include <linux/scatterlist.h> | ||
8 | 9 | ||
9 | #include <asm/iommu.h> | 10 | #include <asm/iommu.h> |
10 | #include <asm/processor.h> | 11 | #include <asm/processor.h> |
@@ -57,10 +58,10 @@ static void nommu_unmap_single(struct device *dev, dma_addr_t addr,size_t size, | |||
57 | static int nommu_map_sg(struct device *hwdev, struct scatterlist *sg, | 58 | static int nommu_map_sg(struct device *hwdev, struct scatterlist *sg, |
58 | int nents, int direction) | 59 | int nents, int direction) |
59 | { | 60 | { |
61 | struct scatterlist *s; | ||
60 | int i; | 62 | int i; |
61 | 63 | ||
62 | for (i = 0; i < nents; i++ ) { | 64 | for_each_sg(sg, s, nents, i) { |
63 | struct scatterlist *s = &sg[i]; | ||
64 | BUG_ON(!s->page); | 65 | BUG_ON(!s->page); |
65 | s->dma_address = virt_to_bus(page_address(s->page) +s->offset); | 66 | s->dma_address = virt_to_bus(page_address(s->page) +s->offset); |
66 | if (!check_addr("map_sg", hwdev, s->dma_address, s->length)) | 67 | if (!check_addr("map_sg", hwdev, s->dma_address, s->length)) |