diff options
-rw-r--r-- | include/linux/dma-debug.h | 16 | ||||
-rw-r--r-- | lib/dma-debug.c | 73 |
2 files changed, 89 insertions, 0 deletions
diff --git a/include/linux/dma-debug.h b/include/linux/dma-debug.h index 65f73526ba2c..ee9fdb328549 100644 --- a/include/linux/dma-debug.h +++ b/include/linux/dma-debug.h | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/types.h> | 23 | #include <linux/types.h> |
24 | 24 | ||
25 | struct device; | 25 | struct device; |
26 | struct scatterlist; | ||
26 | 27 | ||
27 | #ifdef CONFIG_DMA_API_DEBUG | 28 | #ifdef CONFIG_DMA_API_DEBUG |
28 | 29 | ||
@@ -36,6 +37,11 @@ extern void debug_dma_map_page(struct device *dev, struct page *page, | |||
36 | extern void debug_dma_unmap_page(struct device *dev, dma_addr_t addr, | 37 | extern void debug_dma_unmap_page(struct device *dev, dma_addr_t addr, |
37 | size_t size, int direction, bool map_single); | 38 | size_t size, int direction, bool map_single); |
38 | 39 | ||
40 | extern void debug_dma_map_sg(struct device *dev, struct scatterlist *sg, | ||
41 | int nents, int mapped_ents, int direction); | ||
42 | |||
43 | extern void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist, | ||
44 | int nelems, int dir); | ||
39 | 45 | ||
40 | #else /* CONFIG_DMA_API_DEBUG */ | 46 | #else /* CONFIG_DMA_API_DEBUG */ |
41 | 47 | ||
@@ -56,6 +62,16 @@ static inline void debug_dma_unmap_page(struct device *dev, dma_addr_t addr, | |||
56 | { | 62 | { |
57 | } | 63 | } |
58 | 64 | ||
65 | static inline void debug_dma_map_sg(struct device *dev, struct scatterlist *sg, | ||
66 | int nents, int mapped_ents, int direction) | ||
67 | { | ||
68 | } | ||
69 | |||
70 | static inline void debug_dma_unmap_sg(struct device *dev, | ||
71 | struct scatterlist *sglist, | ||
72 | int nelems, int dir) | ||
73 | { | ||
74 | } | ||
59 | 75 | ||
60 | #endif /* CONFIG_DMA_API_DEBUG */ | 76 | #endif /* CONFIG_DMA_API_DEBUG */ |
61 | 77 | ||
diff --git a/lib/dma-debug.c b/lib/dma-debug.c index a2ed2b769685..26e40e93e0f2 100644 --- a/lib/dma-debug.c +++ b/lib/dma-debug.c | |||
@@ -17,6 +17,7 @@ | |||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/scatterlist.h> | ||
20 | #include <linux/dma-mapping.h> | 21 | #include <linux/dma-mapping.h> |
21 | #include <linux/dma-debug.h> | 22 | #include <linux/dma-debug.h> |
22 | #include <linux/spinlock.h> | 23 | #include <linux/spinlock.h> |
@@ -619,3 +620,75 @@ void debug_dma_unmap_page(struct device *dev, dma_addr_t addr, | |||
619 | } | 620 | } |
620 | EXPORT_SYMBOL(debug_dma_unmap_page); | 621 | EXPORT_SYMBOL(debug_dma_unmap_page); |
621 | 622 | ||
623 | void debug_dma_map_sg(struct device *dev, struct scatterlist *sg, | ||
624 | int nents, int mapped_ents, int direction) | ||
625 | { | ||
626 | struct dma_debug_entry *entry; | ||
627 | struct scatterlist *s; | ||
628 | int i; | ||
629 | |||
630 | if (unlikely(global_disable)) | ||
631 | return; | ||
632 | |||
633 | for_each_sg(sg, s, mapped_ents, i) { | ||
634 | entry = dma_entry_alloc(); | ||
635 | if (!entry) | ||
636 | return; | ||
637 | |||
638 | entry->type = dma_debug_sg; | ||
639 | entry->dev = dev; | ||
640 | entry->paddr = sg_phys(s); | ||
641 | entry->size = s->length; | ||
642 | entry->dev_addr = s->dma_address; | ||
643 | entry->direction = direction; | ||
644 | entry->sg_call_ents = nents; | ||
645 | entry->sg_mapped_ents = mapped_ents; | ||
646 | |||
647 | check_for_stack(dev, sg_virt(s)); | ||
648 | |||
649 | add_dma_entry(entry); | ||
650 | } | ||
651 | } | ||
652 | EXPORT_SYMBOL(debug_dma_map_sg); | ||
653 | |||
654 | void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist, | ||
655 | int nelems, int dir) | ||
656 | { | ||
657 | struct dma_debug_entry *entry; | ||
658 | struct scatterlist *s; | ||
659 | int mapped_ents = 0, i; | ||
660 | unsigned long flags; | ||
661 | |||
662 | if (unlikely(global_disable)) | ||
663 | return; | ||
664 | |||
665 | for_each_sg(sglist, s, nelems, i) { | ||
666 | |||
667 | struct dma_debug_entry ref = { | ||
668 | .type = dma_debug_sg, | ||
669 | .dev = dev, | ||
670 | .paddr = sg_phys(s), | ||
671 | .dev_addr = s->dma_address, | ||
672 | .size = s->length, | ||
673 | .direction = dir, | ||
674 | .sg_call_ents = 0, | ||
675 | }; | ||
676 | |||
677 | if (mapped_ents && i >= mapped_ents) | ||
678 | break; | ||
679 | |||
680 | if (mapped_ents == 0) { | ||
681 | struct hash_bucket *bucket; | ||
682 | ref.sg_call_ents = nelems; | ||
683 | bucket = get_hash_bucket(&ref, &flags); | ||
684 | entry = hash_bucket_find(bucket, &ref); | ||
685 | if (entry) | ||
686 | mapped_ents = entry->sg_mapped_ents; | ||
687 | put_hash_bucket(bucket, &flags); | ||
688 | } | ||
689 | |||
690 | check_unmap(&ref); | ||
691 | } | ||
692 | } | ||
693 | EXPORT_SYMBOL(debug_dma_unmap_sg); | ||
694 | |||