From patchwork Wed May 1 13:58:19 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julien Grall X-Patchwork-Id: 163215 Delivered-To: patch@linaro.org Received: by 2002:a92:7e86:0:0:0:0:0 with SMTP id q6csp4554529ill; Wed, 1 May 2019 06:58:44 -0700 (PDT) X-Google-Smtp-Source: APXvYqyrs+zAaSuiXBWyOHG9Uni/W2r5rKOYvaQpZGDbv33BU2n8wZhS/pJ86HeD4hUjGf4ZPUp+ X-Received: by 2002:a62:e00e:: with SMTP id f14mr21269569pfh.257.1556719124230; Wed, 01 May 2019 06:58:44 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1556719124; cv=none; d=google.com; s=arc-20160816; b=r2qDLdMaLk6pryqoei2fsTxI40USWF9F73ZFp9T85BPHTqaZ8X07ceD/xHP5YcKBRV x+ogvU6uAnIRnORg27txknMh+Y40Hm3IeBZsblEdMMUuO5tgvmxAy/NXVadyE/nuklcq cBaf7AzJrGi9yilj1WCdFzFennVUJLKXK82tuZ5ANw3gFSq0ypQksgzFZblymc8hBGay aG4r1nKwR4fSdKqwgwD2Fy0RP4RQRfJhJ0j50KkFFWnEb1vOg6wI3euUyVqQnARB9SGW j/fnh2g9THtS9bj6Ek5tMzk2gXbjdRCV39gFkbAcRxhGFit7CPUg+kZGRQUpleUnx7nE akjQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from; bh=RRNlFnqXMqQvNnwIE+ccVcQmv5RrD38ma5PTwmHlVq8=; b=lSWx/aS2m+sJl5OCmfjhZjaMkwAglz3Nwh6EGuhshHgPHZqKUtNWHVTzYpQsuz553l ATrhH3vVyhHvC5LHTFGM6VGx4dtNY6Up+SiiMCEc51u2NiOIHiQc4Y2zgwmTmPILKmE3 8pml0PUZxPgOPUSB85XN09Jry0IO2Lt4W9DdcyVZcYtSMr/bb5NSawUFec1MMYILWeUt JfWKGIAU/saWukuH0VoLUSuiOfG0Yfcsj379wwU5Ew6t88bvI2o9Ag1DYC/LAFYXds7v ho9D27sWdmf8vdc6oLcz9HKcEbsKpwGn6DdZR6PX2hPiMO3TGPM/7TvQFgcOv6uR9jHk ZVAA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id gn14si40588495plb.7.2019.05.01.06.58.43; Wed, 01 May 2019 06:58:44 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726582AbfEAN6n (ORCPT + 30 others); Wed, 1 May 2019 09:58:43 -0400 Received: from foss.arm.com ([217.140.101.70]:59650 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726617AbfEAN6l (ORCPT ); Wed, 1 May 2019 09:58:41 -0400 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 119E015AD; Wed, 1 May 2019 06:58:41 -0700 (PDT) Received: from e108454-lin.cambridge.arm.com (e108454-lin.cambridge.arm.com [10.1.196.50]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 9201E3F5AF; Wed, 1 May 2019 06:58:38 -0700 (PDT) From: Julien Grall To: linux-kernel@vger.kernel.org, iommu@lists.linux-foundation.org Cc: logang@deltatee.com, douliyangs@gmail.com, miquel.raynal@bootlin.com, marc.zyngier@arm.com, jason@lakedaemon.net, tglx@linutronix.de, joro@8bytes.org, robin.murphy@arm.com, bigeasy@linutronix.de, linux-rt-users@vger.kernel.org, Julien Grall , Eric Auguer Subject: [PATCH v3 2/7] iommu/dma-iommu: Split iommu_dma_map_msi_msg() in two parts Date: Wed, 1 May 2019 14:58:19 +0100 Message-Id: <20190501135824.25586-3-julien.grall@arm.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20190501135824.25586-1-julien.grall@arm.com> References: <20190501135824.25586-1-julien.grall@arm.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On RT, iommu_dma_map_msi_msg() may be called from non-preemptible context. This will lead to a splat with CONFIG_DEBUG_ATOMIC_SLEEP as the function is using spin_lock (they can sleep on RT). iommu_dma_map_msi_msg() is used to map the MSI page in the IOMMU PT and update the MSI message with the IOVA. Only the part to lookup for the MSI page requires to be called in preemptible context. As the MSI page cannot change over the lifecycle of the MSI interrupt, the lookup can be cached and re-used later on. iomma_dma_map_msi_msg() is now split in two functions: - iommu_dma_prepare_msi(): This function will prepare the mapping in the IOMMU and store the cookie in the structure msi_desc. This function should be called in preemptible context. - iommu_dma_compose_msi_msg(): This function will update the MSI message with the IOVA when the device is behind an IOMMU. Signed-off-by: Julien Grall Reviewed-by: Robin Murphy Reviewed-by: Eric Auguer --- Changes in v3: - Update the comment to use kerneldoc format - Fix typoes in the comments - More use of msi_desc_set_iommu_cookie - Add Robin's and Eric's reviewed-by Changes in v2: - Rework the commit message to use imperative mood - Use the MSI accessor to get/set the iommu cookie - Don't use ternary on return - Select CONFIG_IRQ_MSI_IOMMU - Pass an msi_desc rather than the irq number --- drivers/iommu/Kconfig | 1 + drivers/iommu/dma-iommu.c | 46 +++++++++++++++++++++++++++++++++++++--------- include/linux/dma-iommu.h | 25 +++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 9 deletions(-) -- 2.11.0 Acked-by: Joerg Roedel diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index 6f07f3b21816..eb1c8cd243f9 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -94,6 +94,7 @@ config IOMMU_DMA bool select IOMMU_API select IOMMU_IOVA + select IRQ_MSI_IOMMU select NEED_SG_DMA_LENGTH config FSL_PAMU diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 77aabe637a60..f847904098f7 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -888,17 +888,18 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev, return NULL; } -void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg) +int iommu_dma_prepare_msi(struct msi_desc *desc, phys_addr_t msi_addr) { - struct device *dev = msi_desc_to_dev(irq_get_msi_desc(irq)); + struct device *dev = msi_desc_to_dev(desc); struct iommu_domain *domain = iommu_get_domain_for_dev(dev); struct iommu_dma_cookie *cookie; struct iommu_dma_msi_page *msi_page; - phys_addr_t msi_addr = (u64)msg->address_hi << 32 | msg->address_lo; unsigned long flags; - if (!domain || !domain->iova_cookie) - return; + if (!domain || !domain->iova_cookie) { + desc->iommu_cookie = NULL; + return 0; + } cookie = domain->iova_cookie; @@ -911,7 +912,36 @@ void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg) msi_page = iommu_dma_get_msi_page(dev, msi_addr, domain); spin_unlock_irqrestore(&cookie->msi_lock, flags); - if (WARN_ON(!msi_page)) { + msi_desc_set_iommu_cookie(desc, msi_page); + + if (!msi_page) + return -ENOMEM; + return 0; +} + +void iommu_dma_compose_msi_msg(struct msi_desc *desc, + struct msi_msg *msg) +{ + struct device *dev = msi_desc_to_dev(desc); + const struct iommu_domain *domain = iommu_get_domain_for_dev(dev); + const struct iommu_dma_msi_page *msi_page; + + msi_page = msi_desc_get_iommu_cookie(desc); + + if (!domain || !domain->iova_cookie || WARN_ON(!msi_page)) + return; + + msg->address_hi = upper_32_bits(msi_page->iova); + msg->address_lo &= cookie_msi_granule(domain->iova_cookie) - 1; + msg->address_lo += lower_32_bits(msi_page->iova); +} + +void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg) +{ + struct msi_desc *desc = irq_get_msi_desc(irq); + phys_addr_t msi_addr = (u64)msg->address_hi << 32 | msg->address_lo; + + if (WARN_ON(iommu_dma_prepare_msi(desc, msi_addr))) { /* * We're called from a void callback, so the best we can do is * 'fail' by filling the message with obviously bogus values. @@ -922,8 +952,6 @@ void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg) msg->address_lo = ~0U; msg->data = ~0U; } else { - msg->address_hi = upper_32_bits(msi_page->iova); - msg->address_lo &= cookie_msi_granule(cookie) - 1; - msg->address_lo += lower_32_bits(msi_page->iova); + iommu_dma_compose_msi_msg(desc, msg); } } diff --git a/include/linux/dma-iommu.h b/include/linux/dma-iommu.h index e760dc5d1fa8..0b781a98ee73 100644 --- a/include/linux/dma-iommu.h +++ b/include/linux/dma-iommu.h @@ -71,12 +71,26 @@ void iommu_dma_unmap_resource(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir, unsigned long attrs); /* The DMA API isn't _quite_ the whole story, though... */ +/* + * iommu_dma_prepare_msi() - Map the MSI page in the IOMMU device + * + * The MSI page will be stored in @desc. + * + * Return: 0 on success otherwise an error describing the failure. + */ +int iommu_dma_prepare_msi(struct msi_desc *desc, phys_addr_t msi_addr); + +/* Update the MSI message if required. */ +void iommu_dma_compose_msi_msg(struct msi_desc *desc, + struct msi_msg *msg); + void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg); void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list); #else struct iommu_domain; +struct msi_desc; struct msi_msg; struct device; @@ -99,6 +113,17 @@ static inline void iommu_put_dma_cookie(struct iommu_domain *domain) { } +static inline int iommu_dma_prepare_msi(struct msi_desc *desc, + phys_addr_t msi_addr) +{ + return 0; +} + +static inline void iommu_dma_compose_msi_msg(struct msi_desc *desc, + struct msi_msg *msg) +{ +} + static inline void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg) { }