"device driver tries to free an " "invalid DMA memory address\n"); } else { err_printk(ref->dev, NULL, "device driver tries to free DMA " "memory it has not allocated [device " "address=0x%016llx] [size=%llu bytes]\n", ref->dev_addr, ref->size); } return; } if (ref->size != entry->size) { err_printk(ref->dev, entry, "device driver frees " "DMA memory with different size " "[device address=0x%016llx] [map size=%llu bytes] " "[unmap size=%llu bytes]\n", ref->dev_addr, entry->size, ref->size); } if (ref->type != entry->type) { err_printk(ref->dev, entry, "device driver frees " "DMA memory with wrong function " "[device address=0x%016llx] [size=%llu bytes] " "[mapped as %s] [unmapped as %s]\n", ref->dev_addr, ref->size, type2name[entry->type], type2name[ref->type]); } else if ((entry->type == dma_debug_coherent || entry->type == dma_debug_noncoherent) && ref->paddr != entry->paddr) { err_printk(ref->dev, entry, "device driver frees " "DMA memory with different CPU address " "[device address=0x%016llx] [size=%llu bytes] " "[cpu alloc address=0x%pa] " "[cpu free address=0x%pa]", ref->dev_addr, ref->size, &entry->paddr, &ref->paddr); } if (ref->sg_call_ents && ref->type == dma_debug_sg && ref->sg_call_ents != entry->sg_call_ents) { err_printk(ref->dev, entry, "device driver frees " "DMA sg list with different entry count " "[map count=%d] [unmap count=%d]\n", entry->sg_call_ents, ref->sg_call_ents); } /* * This may be no bug in reality - but most implementations of the * DMA API don't handle this properly, so check for it here */ if (ref->direction != entry->direction) { err_printk(ref->dev, entry, "device driver frees " "DMA memory with different direction " "[device address=0x%016llx] [size=%llu bytes] " "[mapped with %s] [unmapped with %s]\n", ref->dev_addr, ref->size, dir2name[entry->direction], dir2name[ref->direction]); } /* * Drivers should use dma_mapping_error() to check the returned * addresses of dma_map_single() and dma_map_page(). * If not, print this warning message. See Documentation/core-api/dma-api.rst. */ if (entry->map_err_type == MAP_ERR_NOT_CHECKED) { err_printk(ref->dev, entry, "device driver failed to check map error" "[device address=0x%016llx] [size=%llu bytes] " "[mapped as %s]", ref->dev_addr, ref->size, type2name[entry->type]); } /* * This may be no bug in reality - but DMA API still expects * that entry is unmapped with same attributes as it was mapped. * * DMA_ATTR_UNMAP_VALID lists the attributes that must be identical * between map and unmap. Any attribute outside this set (e.g. * DMA_ATTR_NO_WARN, DMA_ATTR_SKIP_CPU_SYNC) is allowed to differ. */#define DMA_ATTR_UNMAP_VALID \ (DMA_ATTR_NO_KERNEL_MAPPING | DMA_ATTR_FORCE_CONTIGUOUS | \ DMA_ATTR_MMIO | DMA_ATTR_REQUIRE_COHERENT | DMA_ATTR_PRIVILEGED | \ DMA_ATTR_CC_SHARED) if ((ref->attrs & DMA_ATTR_UNMAP_VALID) != (entry->attrs & DMA_ATTR_UNMAP_VALID)) { err_printk(ref->dev, entry, "device driver frees " "DMA memory with different attributes " "[device address=0x%016llx] [size=%llu bytes] " "[mapped with 0x%lx] [unmapped with 0x%lx]\n", ref->dev_addr, ref->size, entry->attrs, ref->attrs); }#undef DMA_ATTR_UNMAP_VALID hash_bucket_del(entry); put_hash_bucket(bucket, flags); /* * Free the entry outside of bucket_lock to avoid ABBA deadlocks * between that and radix_lock. */ dma_entry_free(entry);} static void check_for_stack(struct device *dev, phys_addr_t phys){ void *addr; struct vm_struct *stack_vm_area = task_stack_vm_area(current); if (!stack_vm_area) { /* Stack is direct-mapped. */ if (PhysHighMem(phys)) return; addr = phys_to_virt(phys); if (object_is_on_stack(addr)) err_printk(dev, NULL, "device driver maps memory from stack [addr=%p]\n", addr); } else { /* Stack is vmalloced. */ int i; for (i = 0; i < stack_vm_area->nr_pages; i++) { if (__phys_to_pfn(phys) != page_to_pfn(stack_vm_area->pages[i])) continue; addr = (u8 *)current->stack + i * PAGE_SIZE + (phys % PAGE_SIZE); err_printk(dev, NULL, "device driver maps memory from stack [probable addr=%p]\n", addr); break; } }} static void check_for_illegal_area(struct device *dev, void *addr, unsigned long len){ if (memory_intersects(_stext, _etext, addr, len) || memory_intersects(__start_rodata, __end_rodata, addr, len)) err_printk(dev, NULL, "device driver maps memory from kernel text or rodata [addr=%p] [len=%lu]\n", addr, len);} static void check_sync(struct device *dev, struct dma_debug_entry *ref, bool to_cpu){ struct dma_debug_entry *entry; struct hash_bucket *bucket; unsigned long flags; bucket = get_hash_bucket(ref, &flags); entry = bucket_find_contain(&bucket, ref, &flags); if (!entry) { err_printk(dev, NULL, "device driver tries " "to sync DMA memory it has not allocated " "[device address=0x%016llx] [size=%llu bytes]\n", (unsigned long long)ref->dev_addr, ref->size); goto out; } if (ref->size > entry->size) { err_printk(dev, entry, "device driver syncs" " DMA memory outside allocated range " "[device address=0x%016llx] " "[allocation size=%llu bytes] " "[sync offset+size=%llu]\n", entry->dev_addr, entry->size, ref->size); } if (entry->direction == DMA_BIDIRECTIONAL) goto out; if (ref->direction != entry->direction) { err_printk(dev, entry, "device driver syncs " "DMA memory with different direction " "[device address=0x%016llx] [size=%llu bytes] " "[mapped with %s] [synced with %s]\n", (unsigned long long)ref->dev_addr, entry->size, dir2name[entry->direction], dir2name[ref->direction]); } if (to_cpu && !(entry->direction == DMA_FROM_DEVICE) && !(ref->direction == DMA_TO_DEVICE)) err_printk(dev, entry, "device driver syncs " "device read-only DMA memory for cpu " "[device address=0x%016llx] [size=%llu bytes] " "[mapped with %s] [synced with %s]\n", (unsigned long long)ref->dev_addr, entry->size, dir2name[entry->direction], dir2name[ref->direction]); if (!to_cpu && !(entry->direction == DMA_TO_DEVICE) && !(ref->direction == DMA_FROM_DEVICE)) err_printk(dev, entry, "device driver syncs " "device write-only DMA memory to device " "[device address=0x%016llx] [size=%llu bytes] " "[mapped with %s] [synced with %s]\n", (unsigned long long)ref->dev_addr, entry->size, dir2name[entry->direction], dir2name[ref->direction]); if (ref->sg_call_ents && ref->type == dma_debug_sg && ref->sg_call_ents != entry->sg_call_ents) { err_printk(ref->dev, entry, "device driver syncs " "DMA sg list with different entry count " "[map count=%d] [sync count=%d]\n", entry->sg_call_ents, ref->sg_call_ents); } out: put_hash_bucket(bucket, flags);} static void check_sg_segment(struct device *dev, struct scatterlist *sg){ unsigned int max_seg = dma_get_max_seg_size(dev); u64 start, end, boundary = dma_get_seg_boundary(dev); /* * Either the driver forgot to set dma_parms appropriately, or * whoever generated the list forgot to check them. */ if (sg->length > max_seg) err_printk(dev, NULL, "mapping sg segment longer than device claims to support [len=%u] [max=%u]\n", sg->length, max_seg); /* * In some cases this could potentially be the DMA API * implementation's fault, but it would usually imply that * the scatterlist was built inappropriately to begin with. */ start = sg_dma_address(sg); end = start + sg_dma_len(sg) - 1; if ((start ^ end) & ~boundary) err_printk(dev, NULL, "mapping sg segment across boundary [start=0x%016llx] [end=0x%016llx] [boundary=0x%016llx]\n", start, end, boundary);} void debug_dma_map_single(struct device *dev, const void *addr, unsigned long len){ if (unlikely(dma_debug_disabled())) return; if (!virt_addr_valid(addr)) err_printk(dev, NULL, "device driver maps memory from invalid area [addr=%p] [len=%lu]\n", addr, len); if (is_vmalloc_addr(addr)) err_printk(dev, NULL, "device driver maps memory from vmalloc area [addr=%p] [len=%lu]\n", addr, len);}EXPORT_SYMBOL(debug_dma_map_single); void debug_dma_map_phys(struct device *dev, phys_addr_t phys, size_t size, int direction, dma_addr_t dma_addr, unsigned long attrs){ struct dma_debug_entry *entry; if (unlikely(dma_debug_disabled())) return; if (dma_mapping_error(dev, dma_addr)) return; entry = dma_entry_alloc(); if (!entry) return; entry->dev = dev; entry->type = dma_debug_phy; entry->paddr = phys; entry->dev_addr = dma_addr; entry->size = size; entry->direction = direction; entry->map_err_type = MAP_ERR_NOT_CHECKED; entry->attrs = attrs; if (attrs & DMA_ATTR_MMIO) { unsigned long pfn = PHYS_PFN(phys); if (pfn_valid(pfn) && !PageReserved(pfn_to_page(pfn))) err_printk(dev, entry, "dma_map_resource called for RAM address %pa\n", &phys); } else { check_for_stack(dev, phys); if (!PhysHighMem(phys)) check_for_illegal_area(dev, phys_to_virt(phys), size); } add_dma_entry(entry);} void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr){ struct dma_debug_entry ref; struct dma_debug_entry *entry; struct hash_bucket *bucket; unsigned long flags; if (unlikely(dma_debug_disabled())) return; ref.dev = dev; ref.dev_addr = dma_addr; bucket = get_hash_bucket(&ref, &flags); list_for_each_entry(entry, &bucket->list, list) { if (!exact_match(&ref, entry)) continue; /* * The same physical address can be mapped multiple * times. Without a hardware IOMMU this results in the * same device addresses being put into the dma-debug * hash multiple times too. This can result in false * positives being reported. Therefore we implement a * best-fit algorithm here which updates the first entry * from the hash which fits the reference value and is * not currently listed as being checked. */ if (entry->map_err_type == MAP_ERR_NOT_CHECKED) { entry->map_err_type = MAP_ERR_CHECKED; break; } } put_hash_bucket(bucket, flags);}EXPORT_SYMBOL(debug_dma_mapping_error); void debug_dma_unmap_phys(struct device *dev, dma_addr_t dma_addr, size_t size, int direction, unsigned long attrs){ struct dma_debug_entry ref = { .type = dma_debug_phy, .dev = dev, .dev_addr = dma_addr, .size = size, .direction = direction, .attrs = attrs, }; if (unlikely(dma_debug_disabled())) return; check_unmap(&ref);} void debug_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, int mapped_ents, int direction, unsigned long attrs){ struct dma_debug_entry *entry; struct scatterlist *s; int i; if (unlikely(dma_debug_disabled())) return; for_each_sg(sg, s, nents, i) { check_for_stack(dev, sg_phys(s)); if (!PageHighMem(sg_page(s))) check_for_illegal_area(dev, sg_virt(s), s->length); } for_each_sg(sg, s, mapped_ents, i) { entry = dma_entry_alloc(); if (!entry) return; entry->type = dma_debug_sg; entry->dev = dev; entry->paddr = sg_phys(s); entry->size = sg_dma_len(s); entry->dev_addr = sg_dma_address(s); entry->direction = direction; entry->sg_call_ents = nents; entry->sg_mapped_ents = mapped_ents; entry->attrs = attrs; check_sg_segment(dev, s); add_dma_entry(entry); }} static int get_nr_mapped_entries(struct device *dev, struct dma_debug_entry *ref){ struct dma_debug_entry *entry; struct hash_bucket *bucket; unsigned long flags; int mapped_ents; bucket = get_hash_bucket(ref, &flags); entry = bucket_find_exact(bucket, ref); mapped_ents = 0; if (entry) mapped_ents = entry->sg_mapped_ents; put_hash_bucket(bucket, flags); return mapped_ents;} void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist, int nelems, int dir, unsigned long attrs){ struct scatterlist *s; int mapped_ents = 0, i; if (unlikely(dma_debug_disabled())) return; for_each_sg(sglist, s, nelems, i) { struct dma_debug_entry ref = { .type = dma_debug_sg, .dev = dev, .paddr = sg_phys(s), .dev_addr = sg_dma_address(s), .size = sg_dma_len(s), .direction = dir, .sg_call_ents = nelems, .attrs = attrs, }; if (mapped_ents && i >= mapped_ents) break; if (!i) mapped_ents = get_nr_mapped_entries(dev, &ref); check_unmap(&ref); }} static phys_addr_t virt_to_paddr(void *virt){ struct page *page; if (is_vmalloc_addr(virt)) page = vmalloc_to_page(virt); else page = virt_to_page(virt); return page_to_phys(page) + offset_in_page(virt);} void debug_dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t dma_addr, void *virt, unsigned long attrs){ struct dma_debug_entry *entry; if (unlikely(dma_debug_disabled())) return; if (unlikely(virt == NULL)) return; /* handle vmalloc and linear addresses */ if (!is_vmalloc_addr(virt) && !virt_addr_valid(virt)) return; entry = dma_entry_alloc(); if (!entry) return; entry->type = dma_debug_coherent; entry->dev = dev; entry->paddr = virt_to_paddr(virt); entry->size = size; entry->dev_addr = dma_addr; entry->direction = DMA_BIDIRECTIONAL; entry->attrs = attrs; add_dma_entry(entry);} void debug_dma_free_coherent(struct device *dev, size_t size, void *virt, dma_addr_t dma_addr, unsigned long attrs){ struct dma_debug_entry ref = { .type = dma_debug_coherent, .dev = dev, .dev_addr = dma_addr, .size = size, .direction = DMA_BIDIRECTIONAL, .attrs = attrs, }; Lines 1001–1500 of 1670. Previous lines Load more
"device driver tries to free an " "invalid DMA memory address\n"); } else { err_printk(ref->dev, NULL, "device driver tries to free DMA " "memory it has not allocated [device " "address=0x%016llx] [size=%llu bytes]\n", ref->dev_addr, ref->size); } return; } if (ref->size != entry->size) { err_printk(ref->dev, entry, "device driver frees " "DMA memory with different size " "[device address=0x%016llx] [map size=%llu bytes] " "[unmap size=%llu bytes]\n", ref->dev_addr, entry->size, ref->size); } if (ref->type != entry->type) { err_printk(ref->dev, entry, "device driver frees " "DMA memory with wrong function " "[device address=0x%016llx] [size=%llu bytes] " "[mapped as %s] [unmapped as %s]\n", ref->dev_addr, ref->size, type2name[entry->type], type2name[ref->type]); } else if ((entry->type == dma_debug_coherent || entry->type == dma_debug_noncoherent) && ref->paddr != entry->paddr) { err_printk(ref->dev, entry, "device driver frees " "DMA memory with different CPU address " "[device address=0x%016llx] [size=%llu bytes] " "[cpu alloc address=0x%pa] " "[cpu free address=0x%pa]", ref->dev_addr, ref->size, &entry->paddr, &ref->paddr); } if (ref->sg_call_ents && ref->type == dma_debug_sg && ref->sg_call_ents != entry->sg_call_ents) { err_printk(ref->dev, entry, "device driver frees " "DMA sg list with different entry count " "[map count=%d] [unmap count=%d]\n", entry->sg_call_ents, ref->sg_call_ents); } /* * This may be no bug in reality - but most implementations of the * DMA API don't handle this properly, so check for it here */ if (ref->direction != entry->direction) { err_printk(ref->dev, entry, "device driver frees " "DMA memory with different direction " "[device address=0x%016llx] [size=%llu bytes] " "[mapped with %s] [unmapped with %s]\n", ref->dev_addr, ref->size, dir2name[entry->direction], dir2name[ref->direction]); } /* * Drivers should use dma_mapping_error() to check the returned * addresses of dma_map_single() and dma_map_page(). * If not, print this warning message. See Documentation/core-api/dma-api.rst. */ if (entry->map_err_type == MAP_ERR_NOT_CHECKED) { err_printk(ref->dev, entry, "device driver failed to check map error" "[device address=0x%016llx] [size=%llu bytes] " "[mapped as %s]", ref->dev_addr, ref->size, type2name[entry->type]); } /* * This may be no bug in reality - but DMA API still expects * that entry is unmapped with same attributes as it was mapped. * * DMA_ATTR_UNMAP_VALID lists the attributes that must be identical * between map and unmap. Any attribute outside this set (e.g. * DMA_ATTR_NO_WARN, DMA_ATTR_SKIP_CPU_SYNC) is allowed to differ. */ #define DMA_ATTR_UNMAP_VALID \ (DMA_ATTR_NO_KERNEL_MAPPING | DMA_ATTR_FORCE_CONTIGUOUS | \ DMA_ATTR_MMIO | DMA_ATTR_REQUIRE_COHERENT | DMA_ATTR_PRIVILEGED | \ DMA_ATTR_CC_SHARED) if ((ref->attrs & DMA_ATTR_UNMAP_VALID) != (entry->attrs & DMA_ATTR_UNMAP_VALID)) { err_printk(ref->dev, entry, "device driver frees " "DMA memory with different attributes " "[device address=0x%016llx] [size=%llu bytes] " "[mapped with 0x%lx] [unmapped with 0x%lx]\n", ref->dev_addr, ref->size, entry->attrs, ref->attrs); } #undef DMA_ATTR_UNMAP_VALID hash_bucket_del(entry); put_hash_bucket(bucket, flags); /* * Free the entry outside of bucket_lock to avoid ABBA deadlocks * between that and radix_lock. */ dma_entry_free(entry); } static void check_for_stack(struct device *dev, phys_addr_t phys) { void *addr; struct vm_struct *stack_vm_area = task_stack_vm_area(current); if (!stack_vm_area) { /* Stack is direct-mapped. */ if (PhysHighMem(phys)) return; addr = phys_to_virt(phys); if (object_is_on_stack(addr)) err_printk(dev, NULL, "device driver maps memory from stack [addr=%p]\n", addr); } else { /* Stack is vmalloced. */ int i; for (i = 0; i < stack_vm_area->nr_pages; i++) { if (__phys_to_pfn(phys) != page_to_pfn(stack_vm_area->pages[i])) continue; addr = (u8 *)current->stack + i * PAGE_SIZE + (phys % PAGE_SIZE); err_printk(dev, NULL, "device driver maps memory from stack [probable addr=%p]\n", addr); break; } } } static void check_for_illegal_area(struct device *dev, void *addr, unsigned long len) { if (memory_intersects(_stext, _etext, addr, len) || memory_intersects(__start_rodata, __end_rodata, addr, len)) err_printk(dev, NULL, "device driver maps memory from kernel text or rodata [addr=%p] [len=%lu]\n", addr, len); } static void check_sync(struct device *dev, struct dma_debug_entry *ref, bool to_cpu) { struct dma_debug_entry *entry; struct hash_bucket *bucket; unsigned long flags; bucket = get_hash_bucket(ref, &flags); entry = bucket_find_contain(&bucket, ref, &flags); if (!entry) { err_printk(dev, NULL, "device driver tries " "to sync DMA memory it has not allocated " "[device address=0x%016llx] [size=%llu bytes]\n", (unsigned long long)ref->dev_addr, ref->size); goto out; } if (ref->size > entry->size) { err_printk(dev, entry, "device driver syncs" " DMA memory outside allocated range " "[device address=0x%016llx] " "[allocation size=%llu bytes] " "[sync offset+size=%llu]\n", entry->dev_addr, entry->size, ref->size); } if (entry->direction == DMA_BIDIRECTIONAL) goto out; if (ref->direction != entry->direction) { err_printk(dev, entry, "device driver syncs " "DMA memory with different direction " "[device address=0x%016llx] [size=%llu bytes] " "[mapped with %s] [synced with %s]\n", (unsigned long long)ref->dev_addr, entry->size, dir2name[entry->direction], dir2name[ref->direction]); } if (to_cpu && !(entry->direction == DMA_FROM_DEVICE) && !(ref->direction == DMA_TO_DEVICE)) err_printk(dev, entry, "device driver syncs " "device read-only DMA memory for cpu " "[device address=0x%016llx] [size=%llu bytes] " "[mapped with %s] [synced with %s]\n", (unsigned long long)ref->dev_addr, entry->size, dir2name[entry->direction], dir2name[ref->direction]); if (!to_cpu && !(entry->direction == DMA_TO_DEVICE) && !(ref->direction == DMA_FROM_DEVICE)) err_printk(dev, entry, "device driver syncs " "device write-only DMA memory to device " "[device address=0x%016llx] [size=%llu bytes] " "[mapped with %s] [synced with %s]\n", (unsigned long long)ref->dev_addr, entry->size, dir2name[entry->direction], dir2name[ref->direction]); if (ref->sg_call_ents && ref->type == dma_debug_sg && ref->sg_call_ents != entry->sg_call_ents) { err_printk(ref->dev, entry, "device driver syncs " "DMA sg list with different entry count " "[map count=%d] [sync count=%d]\n", entry->sg_call_ents, ref->sg_call_ents); } out: put_hash_bucket(bucket, flags); } static void check_sg_segment(struct device *dev, struct scatterlist *sg) { unsigned int max_seg = dma_get_max_seg_size(dev); u64 start, end, boundary = dma_get_seg_boundary(dev); /* * Either the driver forgot to set dma_parms appropriately, or * whoever generated the list forgot to check them. */ if (sg->length > max_seg) err_printk(dev, NULL, "mapping sg segment longer than device claims to support [len=%u] [max=%u]\n", sg->length, max_seg); /* * In some cases this could potentially be the DMA API * implementation's fault, but it would usually imply that * the scatterlist was built inappropriately to begin with. */ start = sg_dma_address(sg); end = start + sg_dma_len(sg) - 1; if ((start ^ end) & ~boundary) err_printk(dev, NULL, "mapping sg segment across boundary [start=0x%016llx] [end=0x%016llx] [boundary=0x%016llx]\n", start, end, boundary); } void debug_dma_map_single(struct device *dev, const void *addr, unsigned long len) { if (unlikely(dma_debug_disabled())) return; if (!virt_addr_valid(addr)) err_printk(dev, NULL, "device driver maps memory from invalid area [addr=%p] [len=%lu]\n", addr, len); if (is_vmalloc_addr(addr)) err_printk(dev, NULL, "device driver maps memory from vmalloc area [addr=%p] [len=%lu]\n", addr, len); } EXPORT_SYMBOL(debug_dma_map_single); void debug_dma_map_phys(struct device *dev, phys_addr_t phys, size_t size, int direction, dma_addr_t dma_addr, unsigned long attrs) { struct dma_debug_entry *entry; if (unlikely(dma_debug_disabled())) return; if (dma_mapping_error(dev, dma_addr)) return; entry = dma_entry_alloc(); if (!entry) return; entry->dev = dev; entry->type = dma_debug_phy; entry->paddr = phys; entry->dev_addr = dma_addr; entry->size = size; entry->direction = direction; entry->map_err_type = MAP_ERR_NOT_CHECKED; entry->attrs = attrs; if (attrs & DMA_ATTR_MMIO) { unsigned long pfn = PHYS_PFN(phys); if (pfn_valid(pfn) && !PageReserved(pfn_to_page(pfn))) err_printk(dev, entry, "dma_map_resource called for RAM address %pa\n", &phys); } else { check_for_stack(dev, phys); if (!PhysHighMem(phys)) check_for_illegal_area(dev, phys_to_virt(phys), size); } add_dma_entry(entry); } void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { struct dma_debug_entry ref; struct dma_debug_entry *entry; struct hash_bucket *bucket; unsigned long flags; if (unlikely(dma_debug_disabled())) return; ref.dev = dev; ref.dev_addr = dma_addr; bucket = get_hash_bucket(&ref, &flags); list_for_each_entry(entry, &bucket->list, list) { if (!exact_match(&ref, entry)) continue; /* * The same physical address can be mapped multiple * times. Without a hardware IOMMU this results in the * same device addresses being put into the dma-debug * hash multiple times too. This can result in false * positives being reported. Therefore we implement a * best-fit algorithm here which updates the first entry * from the hash which fits the reference value and is * not currently listed as being checked. */ if (entry->map_err_type == MAP_ERR_NOT_CHECKED) { entry->map_err_type = MAP_ERR_CHECKED; break; } } put_hash_bucket(bucket, flags); } EXPORT_SYMBOL(debug_dma_mapping_error); void debug_dma_unmap_phys(struct device *dev, dma_addr_t dma_addr, size_t size, int direction, unsigned long attrs) { struct dma_debug_entry ref = { .type = dma_debug_phy, .dev = dev, .dev_addr = dma_addr, .size = size, .direction = direction, .attrs = attrs, }; if (unlikely(dma_debug_disabled())) return; check_unmap(&ref); } void debug_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, int mapped_ents, int direction, unsigned long attrs) { struct dma_debug_entry *entry; struct scatterlist *s; int i; if (unlikely(dma_debug_disabled())) return; for_each_sg(sg, s, nents, i) { check_for_stack(dev, sg_phys(s)); if (!PageHighMem(sg_page(s))) check_for_illegal_area(dev, sg_virt(s), s->length); } for_each_sg(sg, s, mapped_ents, i) { entry = dma_entry_alloc(); if (!entry) return; entry->type = dma_debug_sg; entry->dev = dev; entry->paddr = sg_phys(s); entry->size = sg_dma_len(s); entry->dev_addr = sg_dma_address(s); entry->direction = direction; entry->sg_call_ents = nents; entry->sg_mapped_ents = mapped_ents; entry->attrs = attrs; check_sg_segment(dev, s); add_dma_entry(entry); } } static int get_nr_mapped_entries(struct device *dev, struct dma_debug_entry *ref) { struct dma_debug_entry *entry; struct hash_bucket *bucket; unsigned long flags; int mapped_ents; bucket = get_hash_bucket(ref, &flags); entry = bucket_find_exact(bucket, ref); mapped_ents = 0; if (entry) mapped_ents = entry->sg_mapped_ents; put_hash_bucket(bucket, flags); return mapped_ents; } void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist, int nelems, int dir, unsigned long attrs) { struct scatterlist *s; int mapped_ents = 0, i; if (unlikely(dma_debug_disabled())) return; for_each_sg(sglist, s, nelems, i) { struct dma_debug_entry ref = { .type = dma_debug_sg, .dev = dev, .paddr = sg_phys(s), .dev_addr = sg_dma_address(s), .size = sg_dma_len(s), .direction = dir, .sg_call_ents = nelems, .attrs = attrs, }; if (mapped_ents && i >= mapped_ents) break; if (!i) mapped_ents = get_nr_mapped_entries(dev, &ref); check_unmap(&ref); } } static phys_addr_t virt_to_paddr(void *virt) { struct page *page; if (is_vmalloc_addr(virt)) page = vmalloc_to_page(virt); else page = virt_to_page(virt); return page_to_phys(page) + offset_in_page(virt); } void debug_dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t dma_addr, void *virt, unsigned long attrs) { struct dma_debug_entry *entry; if (unlikely(dma_debug_disabled())) return; if (unlikely(virt == NULL)) return; /* handle vmalloc and linear addresses */ if (!is_vmalloc_addr(virt) && !virt_addr_valid(virt)) return; entry = dma_entry_alloc(); if (!entry) return; entry->type = dma_debug_coherent; entry->dev = dev; entry->paddr = virt_to_paddr(virt); entry->size = size; entry->dev_addr = dma_addr; entry->direction = DMA_BIDIRECTIONAL; entry->attrs = attrs; add_dma_entry(entry); } void debug_dma_free_coherent(struct device *dev, size_t size, void *virt, dma_addr_t dma_addr, unsigned long attrs) { struct dma_debug_entry ref = { .type = dma_debug_coherent, .dev = dev, .dev_addr = dma_addr, .size = size, .direction = DMA_BIDIRECTIONAL, .attrs = attrs, };