From patchwork Fri Sep 27 16:10:06 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefano Stabellini X-Patchwork-Id: 2956291 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id DA219BFF0B for ; Fri, 27 Sep 2013 17:04:06 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id A4C8A20272 for ; Fri, 27 Sep 2013 17:04:05 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 401B620211 for ; Fri, 27 Sep 2013 17:04:04 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1VPb3V-0005ff-Ak; Fri, 27 Sep 2013 16:38:14 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1VPb2m-0002YR-96; Fri, 27 Sep 2013 16:37:28 +0000 Received: from smtp.citrix.com ([66.165.176.89]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1VPb1t-0002RI-Ni for linux-arm-kernel@lists.infradead.org; Fri, 27 Sep 2013 16:36:34 +0000 X-IronPort-AV: E=Sophos;i="4.90,994,1371081600"; d="scan'208";a="58131166" Received: from accessns.citrite.net (HELO FTLPEX01CL01.citrite.net) ([10.9.154.239]) by FTLPIPO01.CITRIX.COM with ESMTP; 27 Sep 2013 16:36:17 +0000 Received: from ukmail1.uk.xensource.com (10.80.16.128) by smtprelay.citrix.com (10.13.107.78) with Microsoft SMTP Server id 14.2.342.4; Fri, 27 Sep 2013 12:36:16 -0400 Received: from kaball.uk.xensource.com ([10.80.2.59]) by ukmail1.uk.xensource.com with esmtp (Exim 4.69) (envelope-from ) id 1VPacx-0002hO-44; Fri, 27 Sep 2013 17:10:47 +0100 From: Stefano Stabellini To: Subject: [PATCH v6 18/19] swiotlb-xen: introduce a rbtree to track phys to bus mappings Date: Fri, 27 Sep 2013 17:10:06 +0100 Message-ID: <1380298207-29151-18-git-send-email-stefano.stabellini@eu.citrix.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: References: MIME-Version: 1.0 X-DLP: MIA2 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130927_123633_989370_B9CAB04B X-CRM114-Status: GOOD ( 17.68 ) X-Spam-Score: -9.3 (---------) Cc: Ian.Campbell@citrix.com, Stefano Stabellini , linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, konrad.wilk@oracle.com X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-6.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Introduce a second red-back tree to track phys to bus mappings created after the initialization of the swiotlb buffer. Signed-off-by: Stefano Stabellini --- drivers/xen/swiotlb-xen.c | 99 +++++++++++++++++++++++++++++++++++++------- 1 files changed, 83 insertions(+), 16 deletions(-) diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c index 3011736..022bcaf 100644 --- a/drivers/xen/swiotlb-xen.c +++ b/drivers/xen/swiotlb-xen.c @@ -79,7 +79,8 @@ struct xen_dma_info { dma_addr_t dma_addr; phys_addr_t phys_addr; size_t size; - struct rb_node rbnode; + struct rb_node rbnode_dma; + struct rb_node rbnode_phys; }; /* @@ -96,8 +97,13 @@ static struct xen_dma_info *xen_dma_seg; * mappings. */ static struct rb_root bus_to_phys = RB_ROOT; +/* + * This tree keeps track of physical address to bus address + * mappings apart from the ones belonging to the initial swiotlb buffer. + */ +static struct rb_root phys_to_bus = RB_ROOT; -static int xen_dma_add_entry(struct xen_dma_info *new) +static int xen_dma_add_entry_bus(struct xen_dma_info *new) { struct rb_node **link = &bus_to_phys.rb_node; struct rb_node *parent = NULL; @@ -106,7 +112,7 @@ static int xen_dma_add_entry(struct xen_dma_info *new) while (*link) { parent = *link; - entry = rb_entry(parent, struct xen_dma_info, rbnode); + entry = rb_entry(parent, struct xen_dma_info, rbnode_dma); if (new->dma_addr == entry->dma_addr) goto err_out; @@ -118,8 +124,41 @@ static int xen_dma_add_entry(struct xen_dma_info *new) else link = &(*link)->rb_right; } - rb_link_node(&new->rbnode, parent, link); - rb_insert_color(&new->rbnode, &bus_to_phys); + rb_link_node(&new->rbnode_dma, parent, link); + rb_insert_color(&new->rbnode_dma, &bus_to_phys); + goto out; + +err_out: + rc = -EINVAL; + pr_warn("%s: cannot add phys=%pa -> dma=%pa: phys=%pa -> dma=%pa already exists\n", + __func__, &new->phys_addr, &new->dma_addr, &entry->phys_addr, &entry->dma_addr); +out: + return rc; +} + +static int xen_dma_add_entry_phys(struct xen_dma_info *new) +{ + struct rb_node **link = &phys_to_bus.rb_node; + struct rb_node *parent = NULL; + struct xen_dma_info *entry; + int rc = 0; + + while (*link) { + parent = *link; + entry = rb_entry(parent, struct xen_dma_info, rbnode_phys); + + if (new->dma_addr == entry->dma_addr) + goto err_out; + if (new->phys_addr == entry->phys_addr) + goto err_out; + + if (new->phys_addr < entry->phys_addr) + link = &(*link)->rb_left; + else + link = &(*link)->rb_right; + } + rb_link_node(&new->rbnode_phys, parent, link); + rb_insert_color(&new->rbnode_phys, &phys_to_bus); goto out; err_out: @@ -130,13 +169,22 @@ out: return rc; } +static int xen_dma_add_entry(struct xen_dma_info *new) +{ + int rc; + if ((rc = xen_dma_add_entry_bus(new) < 0) || + (rc = xen_dma_add_entry_phys(new) < 0)) + return rc; + return 0; +} + static struct xen_dma_info *xen_get_dma_info_from_dma(dma_addr_t dma_addr) { struct rb_node *n = bus_to_phys.rb_node; struct xen_dma_info *entry; while (n) { - entry = rb_entry(n, struct xen_dma_info, rbnode); + entry = rb_entry(n, struct xen_dma_info, rbnode_dma); if (entry->dma_addr <= dma_addr && entry->dma_addr + entry->size > dma_addr) { return entry; @@ -150,11 +198,30 @@ static struct xen_dma_info *xen_get_dma_info_from_dma(dma_addr_t dma_addr) return NULL; } -static dma_addr_t xen_phys_to_bus(phys_addr_t paddr) +static struct xen_dma_info *xen_get_dma_info_from_phys(phys_addr_t phys) { - int nr_seg; - unsigned long offset; - char *vaddr; + struct rb_node *n = phys_to_bus.rb_node; + struct xen_dma_info *entry; + + while (n) { + entry = rb_entry(n, struct xen_dma_info, rbnode_phys); + if (entry->phys_addr <= phys && + entry->phys_addr + entry->size > phys) { + return entry; + } + if (phys < entry->phys_addr) + n = n->rb_left; + else + n = n->rb_right; + } + + return NULL; +} + +/* Only looks into the initial buffer allocation in case of + * XENFEAT_auto_translated_physmap guests. */ +static dma_addr_t xen_phys_to_bus_quick(phys_addr_t paddr) { int nr_seg; + unsigned long offset; char *vaddr; if (!xen_feature(XENFEAT_auto_translated_physmap)) return phys_to_machine(XPADDR(paddr)).maddr; @@ -184,7 +251,7 @@ static phys_addr_t xen_bus_to_phys(dma_addr_t baddr) static dma_addr_t xen_virt_to_bus(void *address) { - return xen_phys_to_bus(virt_to_phys(address)); + return xen_phys_to_bus_quick(virt_to_phys(address)); } static int check_pages_physically_contiguous(unsigned long pfn, @@ -424,7 +491,7 @@ xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size, * Do not use virt_to_phys(ret) because on ARM it doesn't correspond * to *dma_handle. */ phys = *dma_handle; - dev_addr = xen_phys_to_bus(phys); + dev_addr = xen_phys_to_bus_quick(phys); if (!xen_feature(XENFEAT_auto_translated_physmap) && ((dev_addr + size - 1 <= dma_mask)) && !range_straddles_page_boundary(phys, size)) @@ -503,7 +570,7 @@ dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page, struct dma_attrs *attrs) { phys_addr_t map, phys = page_to_phys(page) + offset; - dma_addr_t dev_addr = xen_phys_to_bus(phys); + dma_addr_t dev_addr = xen_phys_to_bus_quick(phys); BUG_ON(dir == DMA_NONE); /* @@ -527,7 +594,7 @@ dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page, if (map == SWIOTLB_MAP_ERROR) return DMA_ERROR_CODE; - dev_addr = xen_phys_to_bus(map); + dev_addr = xen_phys_to_bus_quick(map); /* * Ensure that the address returned is DMA'ble @@ -656,7 +723,7 @@ xen_swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, for_each_sg(sgl, sg, nelems, i) { phys_addr_t paddr = sg_phys(sg); - dma_addr_t dev_addr = xen_phys_to_bus(paddr); + dma_addr_t dev_addr = xen_phys_to_bus_quick(paddr); if (swiotlb_force || xen_feature(XENFEAT_auto_translated_physmap) || @@ -682,7 +749,7 @@ xen_swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, sg_dma_len(sgl) = 0; return DMA_ERROR_CODE; } - sg->dma_address = xen_phys_to_bus(map); + sg->dma_address = xen_phys_to_bus_quick(map); } else sg->dma_address = dev_addr; sg_dma_len(sg) = sg->length;