From patchwork Wed Jul 22 21:39:48 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: wdavis@nvidia.com X-Patchwork-Id: 498845 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id CAAAD140D19 for ; Thu, 23 Jul 2015 07:54:13 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753502AbbGVVyK (ORCPT ); Wed, 22 Jul 2015 17:54:10 -0400 Received: from hqemgate15.nvidia.com ([216.228.121.64]:2962 "EHLO hqemgate15.nvidia.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753330AbbGVVyD (ORCPT ); Wed, 22 Jul 2015 17:54:03 -0400 Received: from hqnvupgp08.nvidia.com (Not Verified[216.228.121.13]) by hqemgate15.nvidia.com id ; Wed, 22 Jul 2015 14:54:39 -0700 Received: from HQMAIL106.nvidia.com ([172.20.12.94]) by hqnvupgp08.nvidia.com (PGP Universal service); Wed, 22 Jul 2015 14:54:02 -0700 X-PGP-Universal: processed; by hqnvupgp08.nvidia.com on Wed, 22 Jul 2015 14:54:02 -0700 Received: from HQMAIL110.nvidia.com (172.18.146.15) by HQMAIL106.nvidia.com (172.18.146.12) with Microsoft SMTP Server (TLS) id 15.0.1044.25; Wed, 22 Jul 2015 21:54:02 +0000 Received: from HQMAIL101.nvidia.com (172.20.187.10) by hqmail110.nvidia.com (172.18.146.15) with Microsoft SMTP Server (TLS) id 15.0.1044.25; Wed, 22 Jul 2015 21:54:01 +0000 Received: from hqnvemgw01.nvidia.com (172.20.150.20) by HQMAIL101.nvidia.com (172.20.187.10) with Microsoft SMTP Server id 15.0.1044.25 via Frontend Transport; Wed, 22 Jul 2015 14:54:01 -0700 Received: from wdavis-lt.nvidia.com (Not Verified[10.20.168.59]) by hqnvemgw01.nvidia.com with MailMarshal (v7, 1, 2, 5326) id ; Wed, 22 Jul 2015 14:54:01 -0700 From: Will Davis To: Bjorn Helgaas , Alex Williamson , Joerg Roedel CC: , , "Konrad Wilk" , Mark Hounschell , "David S. Miller" , Jonathan Corbet , "Terence Ripperda" , John Hubbard , "Jerome Glisse" Subject: [PATCH v4 03/12] dma-debug: add checking for map/unmap_peer_resource Date: Wed, 22 Jul 2015 16:39:48 -0500 Message-ID: <1437601197-6481-4-git-send-email-wdavis@nvidia.com> X-Mailer: git-send-email 2.4.6 In-Reply-To: <1437601197-6481-1-git-send-email-wdavis@nvidia.com> References: <1437601197-6481-1-git-send-email-wdavis@nvidia.com> X-NVConfidentiality: public MIME-Version: 1.0 Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org Add debug callbacks for the new dma_map_peer_resource and dma_unmap_peer_resource functions. Also add a callback for dma_peer_mapping_error. Most of the time this will be identical to dma_mapping_error, except where the dma_addr_t is not as wide as dma_peer_addr_t. Guard these new callbacks behind a CONFIG_HAS_DMA_P2P check. Signed-off-by: Will Davis Reviewed-by: Terence Ripperda Reviewed-by: John Hubbard --- include/linux/dma-debug.h | 39 ++++++++++++++++++++- lib/dma-debug.c | 86 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 122 insertions(+), 3 deletions(-) diff --git a/include/linux/dma-debug.h b/include/linux/dma-debug.h index fe8cb61..4ff8364 100644 --- a/include/linux/dma-debug.h +++ b/include/linux/dma-debug.h @@ -43,7 +43,21 @@ extern void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr); extern void debug_dma_unmap_page(struct device *dev, dma_addr_t addr, size_t size, int direction, bool map_single); - +#ifdef CONFIG_HAS_DMA_P2P +extern void debug_dma_map_peer_resource(struct device *dev, + struct device *peer, + struct resource *resource, + size_t offset, size_t size, + int direction, + dma_peer_addr_t dma_addr); + +extern void debug_dma_peer_mapping_error(struct device *dev, + dma_peer_addr_t dma_addr); + +extern void debug_dma_unmap_peer_resource(struct device *dev, + dma_peer_addr_t addr, + size_t size, int direction); +#endif extern void debug_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, int mapped_ents, int direction); @@ -120,6 +134,29 @@ static inline void debug_dma_unmap_page(struct device *dev, dma_addr_t addr, { } +#ifdef CONFIG_HAS_DMA_P2P +static inline void debug_dma_map_peer_resource(struct device *dev, + struct device *peer, + struct resource *resource, + size_t offset, size_t size, + int direction, + dma_peer_addr_t dma_addr) +{ +} + +static inline void debug_dma_peer_mapping_error(struct device *dev, + dma_peer_addr_t dma_addr) +{ +} + +static inline void debug_dma_unmap_peer_resource(struct device *dev, + dma_peer_addr_t addr, + size_t size, + int direction) +{ +} +#endif + static inline void debug_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, int mapped_ents, int direction) { diff --git a/lib/dma-debug.c b/lib/dma-debug.c index ae4b65e..622f569 100644 --- a/lib/dma-debug.c +++ b/lib/dma-debug.c @@ -43,6 +43,7 @@ enum { dma_debug_page, dma_debug_sg, dma_debug_coherent, + dma_debug_peer_resource, }; enum map_err_types { @@ -64,7 +65,8 @@ enum map_err_types { * @direction: enum dma_data_direction * @sg_call_ents: 'nents' from dma_map_sg * @sg_mapped_ents: 'mapped_ents' from dma_map_sg - * @map_err_type: track whether dma_mapping_error() was checked + * @map_err_type: track whether dma_mapping_error() or dma_peer_mapping_error() + * was called * @stacktrace: support backtraces when a violation is detected */ struct dma_debug_entry { @@ -1250,6 +1252,23 @@ out: put_hash_bucket(bucket, &flags); } +static void check_mapping_error(struct dma_debug_entry *entry, bool peer) +{ + if (peer && !(entry->type == dma_debug_peer_resource)) + err_printk(entry->dev, entry, "DMA-API: device driver calls " + "dma_peer_mapping_error() on dma_addr_t " + "[device address=0x%016llx] [size=%llu bytes]\n", + (unsigned long long)entry->dev_addr, + entry->size); + + if (!peer && (entry->type == dma_debug_peer_resource)) + err_printk(entry->dev, entry, "DMA-API: device driver calls " + "dma_mapping_error() on dma_peer_addr_t " + "[device address=0x%016llx] [size=%llu bytes]\n", + (unsigned long long)entry->dev_addr, + entry->size); +} + void debug_dma_map_page(struct device *dev, struct page *page, size_t offset, size_t size, int direction, dma_addr_t dma_addr, bool map_single) @@ -1289,7 +1308,9 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset, } EXPORT_SYMBOL(debug_dma_map_page); -void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr) +static void debug_dma_mapping_error_common(struct device *dev, + u64 dma_addr, + bool peer) { struct dma_debug_entry ref; struct dma_debug_entry *entry; @@ -1319,12 +1340,18 @@ void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr) */ if (entry->map_err_type == MAP_ERR_NOT_CHECKED) { entry->map_err_type = MAP_ERR_CHECKED; + check_mapping_error(entry, peer); break; } } put_hash_bucket(bucket, &flags); } + +void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr) +{ + debug_dma_mapping_error_common(dev, (u64)dma_addr, false); +} EXPORT_SYMBOL(debug_dma_mapping_error); void debug_dma_unmap_page(struct device *dev, dma_addr_t addr, @@ -1348,6 +1375,61 @@ void debug_dma_unmap_page(struct device *dev, dma_addr_t addr, } EXPORT_SYMBOL(debug_dma_unmap_page); +#ifdef CONFIG_HAS_DMA_P2P +void debug_dma_map_peer_resource(struct device *dev, struct device *peer, + struct resource *resource, size_t offset, + size_t size, int direction, + dma_peer_addr_t dma_addr) +{ + 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_peer_resource; + entry->pfn = resource->start >> PAGE_SHIFT; + entry->offset = offset, + entry->dev_addr = dma_addr; + entry->size = size; + entry->direction = direction; + + add_dma_entry(entry); +} +EXPORT_SYMBOL(debug_dma_map_peer_resource); + +void debug_dma_peer_mapping_error(struct device *dev, dma_peer_addr_t dma_addr) +{ + debug_dma_mapping_error_common(dev, (u64)dma_addr, true); +} +EXPORT_SYMBOL(debug_dma_peer_mapping_error); + +void debug_dma_unmap_peer_resource(struct device *dev, dma_peer_addr_t addr, + size_t size, int direction) +{ + struct dma_debug_entry ref = { + .type = dma_debug_peer_resource, + .dev = dev, + .dev_addr = addr, + .size = size, + .direction = direction, + }; + + if (unlikely(dma_debug_disabled())) + return; + + check_unmap(&ref); +} +EXPORT_SYMBOL(debug_dma_unmap_peer_resource); +#endif + void debug_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, int mapped_ents, int direction) {