From patchwork Mon Nov 12 06:44:57 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Baolu Lu X-Patchwork-Id: 10678205 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id AFF5D15E9 for ; Mon, 12 Nov 2018 06:48:38 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9CB9B29EB2 for ; Mon, 12 Nov 2018 06:48:38 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 90A7529EB9; Mon, 12 Nov 2018 06:48:38 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B3D5C29EB2 for ; Mon, 12 Nov 2018 06:48:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731935AbeKLQju (ORCPT ); Mon, 12 Nov 2018 11:39:50 -0500 Received: from mga17.intel.com ([192.55.52.151]:53355 "EHLO mga17.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731284AbeKLQju (ORCPT ); Mon, 12 Nov 2018 11:39:50 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga007.jf.intel.com ([10.7.209.58]) by fmsmga107.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 11 Nov 2018 22:47:57 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,494,1534834800"; d="scan'208";a="88579653" Received: from allen-box.sh.intel.com ([10.239.161.122]) by orsmga007.jf.intel.com with ESMTP; 11 Nov 2018 22:47:54 -0800 From: Lu Baolu To: Joerg Roedel , David Woodhouse , Alex Williamson , Kirti Wankhede Cc: ashok.raj@intel.com, sanjay.k.kumar@intel.com, jacob.jun.pan@intel.com, kevin.tian@intel.com, Jean-Philippe Brucker , yi.l.liu@intel.com, yi.y.sun@intel.com, peterx@redhat.com, tiwei.bie@intel.com, Zeng Xin , iommu@lists.linux-foundation.org, kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Lu Baolu , Jacob Pan Subject: [RFC PATCH 1/5] iommu: Add APIs for IOMMU PASID management Date: Mon, 12 Nov 2018 14:44:57 +0800 Message-Id: <20181112064501.2290-2-baolu.lu@linux.intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181112064501.2290-1-baolu.lu@linux.intel.com> References: <20181112064501.2290-1-baolu.lu@linux.intel.com> Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This adds APIs for IOMMU drivers and device drivers to manage the PASIDs used for DMA transfer and translation. It bases on I/O ASID allocator for PASID namespace management and relies on vendor specific IOMMU drivers for paravirtual PASIDs. Below APIs are added: * iommu_pasid_init(pasid) - Initialize a PASID consumer. The vendor specific IOMMU drivers are able to set the PASID range imposed by IOMMU hardware through a callback in iommu_ops. * iommu_pasid_exit(pasid) - The PASID consumer stops consuming any PASID. * iommu_pasid_alloc(pasid, min, max, private, *ioasid) - Allocate a PASID and associate a @private data with this PASID. The PASID value is stored in @ioaisd if returning success. * iommu_pasid_free(pasid, ioasid) - Free a PASID to the pool so that it could be consumed by others. This also adds below helpers to lookup or iterate PASID items associated with a consumer. * iommu_pasid_for_each(pasid, func, data) - Iterate PASID items of the consumer identified by @pasid, and call @func() against each item. An error returned from @func() will break the iteration. * iommu_pasid_find(pasid, ioasid) - Retrieve the private data associated with @ioasid. Cc: Ashok Raj Cc: Jacob Pan Cc: Kevin Tian Cc: Jean-Philippe Brucker Signed-off-by: Lu Baolu --- drivers/iommu/Kconfig | 1 + drivers/iommu/iommu.c | 89 +++++++++++++++++++++++++++++++++++++++++++ include/linux/iommu.h | 73 +++++++++++++++++++++++++++++++++++ 3 files changed, 163 insertions(+) diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index d9a25715650e..39f2bb76c7b8 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -1,6 +1,7 @@ # IOMMU_API always gets selected by whoever wants it. config IOMMU_API bool + select IOASID menuconfig IOMMU_SUPPORT bool "IOMMU Hardware Support" diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 0b7c96d1425e..570b244897bb 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -2082,3 +2082,92 @@ void iommu_detach_device_aux(struct iommu_domain *domain, struct device *dev) } } EXPORT_SYMBOL_GPL(iommu_detach_device_aux); + +/* + * APIs for PASID used by IOMMU and the device drivers which depend + * on IOMMU. + */ +struct iommu_pasid *iommu_pasid_init(struct bus_type *bus) +{ + struct iommu_pasid *pasid; + int ret; + + if (!bus || !bus->iommu_ops) + return NULL; + + pasid = kzalloc(sizeof(*pasid), GFP_KERNEL); + if (!pasid) + return NULL; + + pasid->ops = bus->iommu_ops; + /* + * The default range of an IOMMU PASID is from 0 to the full + * 20bit integer. + */ + pasid->min = 0; + pasid->max = 0x100000; + /* + * Give vendor specific iommu drivers a chance to set the pasid + * limits imposed by the iommu hardware. + */ + if (bus->iommu_ops->pasid_init) { + ret = bus->iommu_ops->pasid_init(pasid); + if (ret) { + kfree(pasid); + return NULL; + } + } + + return pasid; +} +EXPORT_SYMBOL_GPL(iommu_pasid_init); + +void iommu_pasid_exit(struct iommu_pasid *pasid) +{ + kfree(pasid); +} +EXPORT_SYMBOL_GPL(iommu_pasid_exit); + +int iommu_pasid_alloc(struct iommu_pasid *pasid, ioasid_t min, + ioasid_t max, void *private, ioasid_t *ioasid) +{ + ioasid_t start, end, hw, val; + int ret = -EAGAIN; + + start = max_t(int, min, pasid->min); + end = min_t(int, max, pasid->max); + + if (pasid->ops->pasid_alloc) + ret = pasid->ops->pasid_alloc(pasid, start, end, &hw); + + if (ret == -EAGAIN) + val = ioasid_alloc(&pasid->set, start, end, private); + else if (ret == 0) + val = ioasid_alloc(&pasid->set, hw, hw + 1, private); + else + goto hw_ret; + + if (val == INVALID_IOASID) + goto ioasid_ret; + + *ioasid = val; + + return 0; + +ioasid_ret: + if (pasid->ops->pasid_free) + pasid->ops->pasid_free(pasid, hw); + +hw_ret: + return -ENODEV; +} +EXPORT_SYMBOL_GPL(iommu_pasid_alloc); + +void iommu_pasid_free(struct iommu_pasid *pasid, ioasid_t ioasid) +{ + if (pasid->ops->pasid_free) + pasid->ops->pasid_free(pasid, ioasid); + + ioasid_free(ioasid); +} +EXPORT_SYMBOL_GPL(iommu_pasid_free); diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 9bf1b3f2457a..4f5202c8170b 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -20,6 +20,7 @@ #define __LINUX_IOMMU_H #include +#include #include #include #include @@ -48,6 +49,7 @@ struct bus_type; struct device; struct iommu_domain; struct notifier_block; +struct iommu_pasid; /* iommu fault flags */ #define IOMMU_FAULT_READ 0x0 @@ -194,6 +196,9 @@ enum iommu_dev_attr { * @of_xlate: add OF master IDs to iommu grouping * @get_dev_attr: get per device IOMMU attributions * @set_dev_attr: set per device IOMMU attributions + * @pasid_init: initialize a pasid consumer + * @pasid_alloc: allocate a pasid from low level driver + * @pasid_free: free a pasid to low level driver * @pgsize_bitmap: bitmap of all possible supported page sizes */ struct iommu_ops { @@ -246,6 +251,12 @@ struct iommu_ops { int (*attach_dev_aux)(struct iommu_domain *domain, struct device *dev); void (*detach_dev_aux)(struct iommu_domain *domain, struct device *dev); + /* IOMMU pasid callbacks */ + int (*pasid_init)(struct iommu_pasid *pasid); + int (*pasid_alloc)(struct iommu_pasid *pasid, ioasid_t start, + ioasid_t end, ioasid_t *ioasid); + void (*pasid_free)(struct iommu_pasid *pasid, ioasid_t ioasid); + unsigned long pgsize_bitmap; }; @@ -428,12 +439,41 @@ extern int iommu_attach_device_aux(struct iommu_domain *domain, extern void iommu_detach_device_aux(struct iommu_domain *domain, struct device *dev); +/* + * Per IOMMU PASID consumer data. + */ +struct iommu_pasid { + ioasid_t max; + ioasid_t min; + struct ioasid_set set; + const struct iommu_ops *ops; + + /* vendor specific iommu private data */ + void *priv; +}; + +struct iommu_pasid *iommu_pasid_init(struct bus_type *bus); +void iommu_pasid_exit(struct iommu_pasid *pasid); +int iommu_pasid_alloc(struct iommu_pasid *pasid, ioasid_t min, + ioasid_t max, void *private, ioasid_t *ioasid); +void iommu_pasid_free(struct iommu_pasid *pasid, ioasid_t iosid); +static inline int +iommu_pasid_for_each(struct iommu_pasid *pasid, ioasid_iter_t func, void *data) +{ + return ioasid_for_each(&pasid->set, func, data); +} +static inline void* +iommu_pasid_find(struct iommu_pasid *pasid, ioasid_t ioasid) +{ + return ioasid_find(&pasid->set, ioasid); +} #else /* CONFIG_IOMMU_API */ struct iommu_ops {}; struct iommu_group {}; struct iommu_fwspec {}; struct iommu_device {}; +struct iommu_pasid {}; static inline bool iommu_present(struct bus_type *bus) { @@ -734,6 +774,39 @@ static inline void iommu_detach_device_aux(struct iommu_domain *domain, struct device *dev) { } + +static inline struct iommu_pasid * +iommu_pasid_init(struct bus_type *bus) +{ + return NULL; +} + +static inline void iommu_pasid_exit(struct iommu_pasid *pasid) +{ +} + +static inline int +iommu_pasid_alloc(struct iommu_pasid *pasid, ioasid_t min, + ioasid_t max, void *private, ioasid_t *ioasid) +{ + return -ENODEV; +} + +static inline void iommu_pasid_free(struct iommu_pasid *pasid, ioasid_t iosid) +{ +} + +static inline int +iommu_pasid_for_each(struct iommu_pasid *pasid, ioasid_iter_t func, void *data) +{ + return -ENODEV; +} + +static inline void* +iommu_pasid_find(struct iommu_pasid *pasid, ioasid_t ioasid) +{ + return NULL; +} #endif /* CONFIG_IOMMU_API */ #ifdef CONFIG_IOMMU_DEBUGFS From patchwork Mon Nov 12 06:44:58 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Baolu Lu X-Patchwork-Id: 10678197 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id BB0BC15E9 for ; Mon, 12 Nov 2018 06:48:10 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A8D4D29D86 for ; Mon, 12 Nov 2018 06:48:10 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 97C4C29DAF; Mon, 12 Nov 2018 06:48:10 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3539829D86 for ; Mon, 12 Nov 2018 06:48:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732012AbeKLQj5 (ORCPT ); Mon, 12 Nov 2018 11:39:57 -0500 Received: from mga17.intel.com ([192.55.52.151]:53355 "EHLO mga17.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731284AbeKLQjx (ORCPT ); Mon, 12 Nov 2018 11:39:53 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga007.jf.intel.com ([10.7.209.58]) by fmsmga107.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 11 Nov 2018 22:48:00 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,494,1534834800"; d="scan'208";a="88579665" Received: from allen-box.sh.intel.com ([10.239.161.122]) by orsmga007.jf.intel.com with ESMTP; 11 Nov 2018 22:47:57 -0800 From: Lu Baolu To: Joerg Roedel , David Woodhouse , Alex Williamson , Kirti Wankhede Cc: ashok.raj@intel.com, sanjay.k.kumar@intel.com, jacob.jun.pan@intel.com, kevin.tian@intel.com, Jean-Philippe Brucker , yi.l.liu@intel.com, yi.y.sun@intel.com, peterx@redhat.com, tiwei.bie@intel.com, Zeng Xin , iommu@lists.linux-foundation.org, kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Lu Baolu , Jacob Pan Subject: [RFC PATCH 2/5] iommu/vt-d: Initialize a PASID consumer Date: Mon, 12 Nov 2018 14:44:58 +0800 Message-Id: <20181112064501.2290-3-baolu.lu@linux.intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181112064501.2290-1-baolu.lu@linux.intel.com> References: <20181112064501.2290-1-baolu.lu@linux.intel.com> Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This adds the Intel vt-d specific ops to initialize a PASID consumer. Cc: Ashok Raj Cc: Jacob Pan Cc: Kevin Tian Signed-off-by: Liu Yi L Signed-off-by: Lu Baolu --- drivers/iommu/intel-iommu.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 49a278a699b0..769b7059d52f 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -5597,6 +5597,35 @@ static int intel_iommu_domain_get_attr(struct iommu_domain *domain, return ret; } +static int intel_iommu_pasid_init(struct iommu_pasid *pasid) +{ + struct dmar_drhd_unit *drhd; + struct intel_iommu *iommu = NULL, *temp; + + /* + * Iterate the iommu units and get a scalable mode capable one + * for virtual command usages. Return failure if scalable mode + * doesn't support by any unit. + */ + rcu_read_lock(); + for_each_active_iommu(temp, drhd) { + if (sm_supported(temp)) { + iommu = temp; + break; + } + } + rcu_read_unlock(); + + if (!iommu) + return -ENODEV; + + pasid->max = intel_pasid_max_id; + pasid->min = PASID_MIN; + pasid->priv = iommu; + + return 0; +} + const struct iommu_ops intel_iommu_ops = { .capable = intel_iommu_capable, .domain_alloc = intel_iommu_domain_alloc, @@ -5616,6 +5645,7 @@ const struct iommu_ops intel_iommu_ops = { .domain_get_attr = intel_iommu_domain_get_attr, .get_dev_attr = intel_iommu_get_dev_attr, .set_dev_attr = intel_iommu_set_dev_attr, + .pasid_init = intel_iommu_pasid_init, .pgsize_bitmap = INTEL_IOMMU_PGSIZES, }; From patchwork Mon Nov 12 06:44:59 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Baolu Lu X-Patchwork-Id: 10678203 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7EAE615E9 for ; Mon, 12 Nov 2018 06:48:32 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 694CD204FF for ; Mon, 12 Nov 2018 06:48:32 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5843828BAE; Mon, 12 Nov 2018 06:48:32 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1F730204FF for ; Mon, 12 Nov 2018 06:48:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732080AbeKLQkR (ORCPT ); Mon, 12 Nov 2018 11:40:17 -0500 Received: from mga17.intel.com ([192.55.52.151]:53355 "EHLO mga17.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731996AbeKLQj4 (ORCPT ); Mon, 12 Nov 2018 11:39:56 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga007.jf.intel.com ([10.7.209.58]) by fmsmga107.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 11 Nov 2018 22:48:04 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,494,1534834800"; d="scan'208";a="88579687" Received: from allen-box.sh.intel.com ([10.239.161.122]) by orsmga007.jf.intel.com with ESMTP; 11 Nov 2018 22:48:01 -0800 From: Lu Baolu To: Joerg Roedel , David Woodhouse , Alex Williamson , Kirti Wankhede Cc: ashok.raj@intel.com, sanjay.k.kumar@intel.com, jacob.jun.pan@intel.com, kevin.tian@intel.com, Jean-Philippe Brucker , yi.l.liu@intel.com, yi.y.sun@intel.com, peterx@redhat.com, tiwei.bie@intel.com, Zeng Xin , iommu@lists.linux-foundation.org, kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Lu Baolu , Jacob Pan Subject: [RFC PATCH 3/5] iommu/vt-d: Enlightened PASID allocation Date: Mon, 12 Nov 2018 14:44:59 +0800 Message-Id: <20181112064501.2290-4-baolu.lu@linux.intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181112064501.2290-1-baolu.lu@linux.intel.com> References: <20181112064501.2290-1-baolu.lu@linux.intel.com> Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP If Intel IOMMU runs in caching mode, a.k.a. virtual IOMMU, the IOMMU driver should rely on the emulation software to allocate and free PASID IDs. The Intel vt-d spec revision 3.0 defines a register set to support this. This includes a capability register, a virtual command register and a virtual response register. Refer to section 10.4.42, 10.4.43, 10.4.44 for more information. This patch adds the enlightened PASID allocation/free interfaces via the virtual command register. Cc: Ashok Raj Cc: Jacob Pan Cc: Kevin Tian Signed-off-by: Liu Yi L Signed-off-by: Lu Baolu --- drivers/iommu/intel-pasid.c | 70 +++++++++++++++++++++++++++++++++++++ drivers/iommu/intel-pasid.h | 13 ++++++- include/linux/intel-iommu.h | 2 ++ 3 files changed, 84 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/intel-pasid.c b/drivers/iommu/intel-pasid.c index 839f83974aca..fb42f0c2493e 100644 --- a/drivers/iommu/intel-pasid.c +++ b/drivers/iommu/intel-pasid.c @@ -28,6 +28,76 @@ static DEFINE_SPINLOCK(pasid_lock); u32 intel_pasid_max_id = PASID_MAX; static DEFINE_IDR(pasid_idr); +int vcmd_alloc_pasid(struct intel_iommu *iommu, unsigned int *pasid) +{ + u64 res; + u64 cap; + u8 err_code; + unsigned long flags; + int ret = 0; + + if (!ecap_vcs(iommu->ecap)) { + pr_warn("IOMMU: %s: Hardware doesn't support virtual command\n", + iommu->name); + return -ENODEV; + } + + cap = dmar_readq(iommu->reg + DMAR_VCCAP_REG); + if (!(cap & DMA_VCS_PAS)) { + pr_warn("IOMMU: %s: Emulation software doesn't support PASID allocation\n", + iommu->name); + return -ENODEV; + } + + raw_spin_lock_irqsave(&iommu->register_lock, flags); + dmar_writeq(iommu->reg + DMAR_VCMD_REG, VCMD_CMD_ALLOC); + IOMMU_WAIT_OP(iommu, DMAR_VCRSP_REG, dmar_readq, + !(res & VCMD_VRSP_IP), res); + raw_spin_unlock_irqrestore(&iommu->register_lock, flags); + + err_code = VCMD_VRSP_EC(res); + switch (err_code) { + case VCMD_VRSP_EC_SUCCESS: + *pasid = VCMD_VRSP_RESULE(res); + break; + case VCMD_VRSP_EC_UNAVAIL: + pr_info("IOMMU: %s: No PASID available\n", iommu->name); + ret = -ENOMEM; + break; + default: + ret = -ENODEV; + pr_warn("IOMMU: %s: Unkonwn error code %d\n", + iommu->name, err_code); + } + + return ret; +} + +void vcmd_free_pasid(struct intel_iommu *iommu, unsigned int pasid) +{ + u64 res; + u8 err_code; + unsigned long flags; + + raw_spin_lock_irqsave(&iommu->register_lock, flags); + dmar_writeq(iommu->reg + DMAR_VCMD_REG, (pasid << 8) | VCMD_CMD_FREE); + IOMMU_WAIT_OP(iommu, DMAR_VCRSP_REG, dmar_readq, + !(res & VCMD_VRSP_IP), res); + raw_spin_unlock_irqrestore(&iommu->register_lock, flags); + + err_code = VCMD_VRSP_EC(res); + switch (err_code) { + case VCMD_VRSP_EC_SUCCESS: + break; + case VCMD_VRSP_EC_INVAL: + pr_info("IOMMU: %s: Invalid PASID\n", iommu->name); + break; + default: + pr_warn("IOMMU: %s: Unkonwn error code %d\n", + iommu->name, err_code); + } +} + int intel_pasid_alloc_id(void *ptr, int start, int end, gfp_t gfp) { int ret, min, max; diff --git a/drivers/iommu/intel-pasid.h b/drivers/iommu/intel-pasid.h index 381545ff9fb7..c80787d02e2d 100644 --- a/drivers/iommu/intel-pasid.h +++ b/drivers/iommu/intel-pasid.h @@ -19,6 +19,16 @@ #define PASID_PDE_SHIFT 6 #define MAX_NR_PASID_BITS 20 +/* Virtual command interface for enlightened pasid management. */ +#define VCMD_CMD_ALLOC 0x1 +#define VCMD_CMD_FREE 0x2 +#define VCMD_VRSP_IP 0x1 +#define VCMD_VRSP_EC(e) (((e) >> 1) & 0x3) +#define VCMD_VRSP_EC_SUCCESS 0 +#define VCMD_VRSP_EC_UNAVAIL 1 +#define VCMD_VRSP_EC_INVAL 1 +#define VCMD_VRSP_RESULE(e) (((e) >> 8) & 0xfffff) + /* * Domain ID reserved for pasid entries programmed for first-level * only and pass-through transfer modes. @@ -69,5 +79,6 @@ int intel_pasid_setup_pass_through(struct intel_iommu *iommu, struct device *dev, int pasid); void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev, int pasid); - +int vcmd_alloc_pasid(struct intel_iommu *iommu, unsigned int *pasid); +void vcmd_free_pasid(struct intel_iommu *iommu, unsigned int pasid); #endif /* __INTEL_PASID_H */ diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h index b563a61a6c39..4605eef3686c 100644 --- a/include/linux/intel-iommu.h +++ b/include/linux/intel-iommu.h @@ -173,6 +173,7 @@ #define ecap_smpwc(e) (((e) >> 48) & 0x1) #define ecap_flts(e) (((e) >> 47) & 0x1) #define ecap_slts(e) (((e) >> 46) & 0x1) +#define ecap_vcs(e) (((e) >> 45) & 0x1) #define ecap_smts(e) (((e) >> 43) & 0x1) #define ecap_dit(e) ((e >> 41) & 0x1) #define ecap_pasid(e) ((e >> 40) & 0x1) @@ -289,6 +290,7 @@ /* PRS_REG */ #define DMA_PRS_PPR ((u32)1) +#define DMA_VCS_PAS ((u64)1) #define IOMMU_WAIT_OP(iommu, offset, op, cond, sts) \ do { \ From patchwork Mon Nov 12 06:45:00 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Baolu Lu X-Patchwork-Id: 10678201 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 010B615A6 for ; Mon, 12 Nov 2018 06:48:23 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E3C6C29D8B for ; Mon, 12 Nov 2018 06:48:22 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D64B629DBE; Mon, 12 Nov 2018 06:48:22 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 67A2429D8B for ; Mon, 12 Nov 2018 06:48:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732035AbeKLQkB (ORCPT ); Mon, 12 Nov 2018 11:40:01 -0500 Received: from mga17.intel.com ([192.55.52.151]:53355 "EHLO mga17.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731284AbeKLQkA (ORCPT ); Mon, 12 Nov 2018 11:40:00 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga007.jf.intel.com ([10.7.209.58]) by fmsmga107.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 11 Nov 2018 22:48:07 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,494,1534834800"; d="scan'208";a="88579707" Received: from allen-box.sh.intel.com ([10.239.161.122]) by orsmga007.jf.intel.com with ESMTP; 11 Nov 2018 22:48:04 -0800 From: Lu Baolu To: Joerg Roedel , David Woodhouse , Alex Williamson , Kirti Wankhede Cc: ashok.raj@intel.com, sanjay.k.kumar@intel.com, jacob.jun.pan@intel.com, kevin.tian@intel.com, Jean-Philippe Brucker , yi.l.liu@intel.com, yi.y.sun@intel.com, peterx@redhat.com, tiwei.bie@intel.com, Zeng Xin , iommu@lists.linux-foundation.org, kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Lu Baolu , Jacob Pan Subject: [RFC PATCH 4/5] iommu/vt-d: Allocate and free a pasid Date: Mon, 12 Nov 2018 14:45:00 +0800 Message-Id: <20181112064501.2290-5-baolu.lu@linux.intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181112064501.2290-1-baolu.lu@linux.intel.com> References: <20181112064501.2290-1-baolu.lu@linux.intel.com> Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This adds the Intel vt-d specific ops to allocate and free a pasid value. Cc: Ashok Raj Cc: Jacob Pan Cc: Kevin Tian Signed-off-by: Liu Yi L Signed-off-by: Lu Baolu --- drivers/iommu/intel-iommu.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 769b7059d52f..8dbd0c601dab 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -5626,6 +5626,37 @@ static int intel_iommu_pasid_init(struct iommu_pasid *pasid) return 0; } +static int intel_iommu_pasid_alloc(struct iommu_pasid *pasid, ioasid_t start, + ioasid_t end, ioasid_t *ioasid) +{ + struct intel_iommu *iommu; + + iommu = pasid->priv; + if (!iommu) + return -EINVAL; + + /* + * In caching mode, PASID ID should be allocated and freed + * through the virtual command registers. Otherwise, rely + * on the iommu global idr. + */ + if (!cap_caching_mode(iommu->cap)) + return -EAGAIN; + + return vcmd_alloc_pasid(iommu, ioasid); +} + +static void intel_iommu_pasid_free(struct iommu_pasid *pasid, ioasid_t ioasid) +{ + struct intel_iommu *iommu; + + iommu = pasid->priv; + if (!iommu || !cap_caching_mode(iommu->cap)) + return; + + vcmd_free_pasid(iommu, ioasid); +} + const struct iommu_ops intel_iommu_ops = { .capable = intel_iommu_capable, .domain_alloc = intel_iommu_domain_alloc, @@ -5646,6 +5677,8 @@ const struct iommu_ops intel_iommu_ops = { .get_dev_attr = intel_iommu_get_dev_attr, .set_dev_attr = intel_iommu_set_dev_attr, .pasid_init = intel_iommu_pasid_init, + .pasid_alloc = intel_iommu_pasid_alloc, + .pasid_free = intel_iommu_pasid_free, .pgsize_bitmap = INTEL_IOMMU_PGSIZES, }; From patchwork Mon Nov 12 06:45:01 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Baolu Lu X-Patchwork-Id: 10678199 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1E6AE15E9 for ; Mon, 12 Nov 2018 06:48:18 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 088D129D86 for ; Mon, 12 Nov 2018 06:48:18 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id EDF9E29DAF; Mon, 12 Nov 2018 06:48:17 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4360329D86 for ; Mon, 12 Nov 2018 06:48:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732063AbeKLQkF (ORCPT ); Mon, 12 Nov 2018 11:40:05 -0500 Received: from mga17.intel.com ([192.55.52.151]:53355 "EHLO mga17.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732030AbeKLQkE (ORCPT ); Mon, 12 Nov 2018 11:40:04 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga007.jf.intel.com ([10.7.209.58]) by fmsmga107.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 11 Nov 2018 22:48:11 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.54,494,1534834800"; d="scan'208";a="88579722" Received: from allen-box.sh.intel.com ([10.239.161.122]) by orsmga007.jf.intel.com with ESMTP; 11 Nov 2018 22:48:07 -0800 From: Lu Baolu To: Joerg Roedel , David Woodhouse , Alex Williamson , Kirti Wankhede Cc: ashok.raj@intel.com, sanjay.k.kumar@intel.com, jacob.jun.pan@intel.com, kevin.tian@intel.com, Jean-Philippe Brucker , yi.l.liu@intel.com, yi.y.sun@intel.com, peterx@redhat.com, tiwei.bie@intel.com, Zeng Xin , iommu@lists.linux-foundation.org, kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Lu Baolu , Jacob Pan Subject: [RFC PATCH 5/5] iommu/vt-d: Use global pasid allocator Date: Mon, 12 Nov 2018 14:45:01 +0800 Message-Id: <20181112064501.2290-6-baolu.lu@linux.intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181112064501.2290-1-baolu.lu@linux.intel.com> References: <20181112064501.2290-1-baolu.lu@linux.intel.com> Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This uses global pasid allocator in the Intel iommu driver. Cc: Ashok Raj Cc: Jacob Pan Cc: Kevin Tian Signed-off-by: Liu Yi L Signed-off-by: Lu Baolu --- drivers/iommu/intel-iommu.c | 20 +++++++++++++++----- drivers/iommu/intel-pasid.c | 36 ------------------------------------ drivers/iommu/intel-pasid.h | 3 --- drivers/iommu/intel-svm.c | 24 +++++++++++++----------- include/linux/intel-iommu.h | 3 +++ 5 files changed, 31 insertions(+), 55 deletions(-) diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 8dbd0c601dab..e15b81afcbbc 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -1698,7 +1698,11 @@ static void free_dmar_iommu(struct intel_iommu *iommu) if (ecap_prs(iommu->ecap)) intel_svm_finish_prq(iommu); } + + iommu_pasid_exit(iommu->svm_pasid); #endif + + iommu_pasid_exit(iommu->aux_pasid); } static struct dmar_domain *alloc_domain(int flags) @@ -5050,7 +5054,7 @@ static void auxiliary_unlink_device(struct dmar_domain *domain, domain->auxd_refcnt--; if (!domain->auxd_refcnt && domain->default_pasid > 0) - intel_pasid_free_id(domain->default_pasid); + iommu_pasid_free(info->iommu->aux_pasid, domain->default_pasid); } static int domain_add_dev_auxd(struct dmar_domain *domain, @@ -5067,9 +5071,10 @@ static int domain_add_dev_auxd(struct dmar_domain *domain, spin_lock_irqsave(&device_domain_lock, flags); if (domain->default_pasid <= 0) { - domain->default_pasid = intel_pasid_alloc_id(domain, PASID_MIN, - pci_max_pasids(to_pci_dev(dev)), GFP_ATOMIC); - if (domain->default_pasid < 0) { + ret = iommu_pasid_alloc(iommu->aux_pasid, PASID_MIN, + pci_max_pasids(to_pci_dev(dev)), + domain, &domain->default_pasid); + if (ret) { pr_err("Can't allocate default pasid\n"); ret = -ENODEV; goto pasid_failed; @@ -5099,7 +5104,7 @@ static int domain_add_dev_auxd(struct dmar_domain *domain, attach_failed: spin_unlock(&iommu->lock); if (!domain->auxd_refcnt && domain->default_pasid > 0) - intel_pasid_free_id(domain->default_pasid); + iommu_pasid_free(iommu->aux_pasid, domain->default_pasid); pasid_failed: spin_unlock_irqrestore(&device_domain_lock, flags); @@ -5525,6 +5530,7 @@ static int intel_iommu_enable_auxd(struct device *dev) { struct device_domain_info *info; struct dmar_domain *domain; + struct intel_iommu *iommu; unsigned long flags; if (!scalable_mode_support()) @@ -5539,6 +5545,10 @@ static int intel_iommu_enable_auxd(struct device *dev) info->auxd_enabled = 1; spin_unlock_irqrestore(&device_domain_lock, flags); + iommu = info->iommu; + if (!iommu->aux_pasid) + iommu->aux_pasid = iommu_pasid_init(&pci_bus_type); + return 0; } diff --git a/drivers/iommu/intel-pasid.c b/drivers/iommu/intel-pasid.c index fb42f0c2493e..68eaef3bd4fd 100644 --- a/drivers/iommu/intel-pasid.c +++ b/drivers/iommu/intel-pasid.c @@ -26,7 +26,6 @@ */ static DEFINE_SPINLOCK(pasid_lock); u32 intel_pasid_max_id = PASID_MAX; -static DEFINE_IDR(pasid_idr); int vcmd_alloc_pasid(struct intel_iommu *iommu, unsigned int *pasid) { @@ -98,41 +97,6 @@ void vcmd_free_pasid(struct intel_iommu *iommu, unsigned int pasid) } } -int intel_pasid_alloc_id(void *ptr, int start, int end, gfp_t gfp) -{ - int ret, min, max; - - min = max_t(int, start, PASID_MIN); - max = min_t(int, end, intel_pasid_max_id); - - WARN_ON(in_interrupt()); - idr_preload(gfp); - spin_lock(&pasid_lock); - ret = idr_alloc(&pasid_idr, ptr, min, max, GFP_ATOMIC); - spin_unlock(&pasid_lock); - idr_preload_end(); - - return ret; -} - -void intel_pasid_free_id(int pasid) -{ - spin_lock(&pasid_lock); - idr_remove(&pasid_idr, pasid); - spin_unlock(&pasid_lock); -} - -void *intel_pasid_lookup_id(int pasid) -{ - void *p; - - spin_lock(&pasid_lock); - p = idr_find(&pasid_idr, pasid); - spin_unlock(&pasid_lock); - - return p; -} - /* * Per device pasid table management: */ diff --git a/drivers/iommu/intel-pasid.h b/drivers/iommu/intel-pasid.h index c80787d02e2d..029f82ce9f4a 100644 --- a/drivers/iommu/intel-pasid.h +++ b/drivers/iommu/intel-pasid.h @@ -60,9 +60,6 @@ struct pasid_table { }; extern u32 intel_pasid_max_id; -int intel_pasid_alloc_id(void *ptr, int start, int end, gfp_t gfp); -void intel_pasid_free_id(int pasid); -void *intel_pasid_lookup_id(int pasid); int intel_pasid_alloc_table(struct device *dev); void intel_pasid_free_table(struct device *dev); struct pasid_table *intel_pasid_get_table(struct device *dev); diff --git a/drivers/iommu/intel-svm.c b/drivers/iommu/intel-svm.c index 27cf1963207d..bb57a024eae7 100644 --- a/drivers/iommu/intel-svm.c +++ b/drivers/iommu/intel-svm.c @@ -261,6 +261,9 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_ BUG_ON(!mm); } + if (!iommu->svm_pasid) + iommu->svm_pasid = iommu_pasid_init(&pci_bus_type); + mutex_lock(&pasid_mutex); if (pasid && !(flags & SVM_FLAG_PRIVATE_PASID)) { struct intel_svm *t; @@ -325,15 +328,14 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_ pasid_max = intel_pasid_max_id; /* Do not use PASID 0 in caching mode (virtualised IOMMU) */ - ret = intel_pasid_alloc_id(svm, - !!cap_caching_mode(iommu->cap), - pasid_max - 1, GFP_KERNEL); - if (ret < 0) { + ret = iommu_pasid_alloc(iommu->svm_pasid, + !!cap_caching_mode(iommu->cap), + pasid_max - 1, svm, &svm->pasid); + if (ret) { kfree(svm); kfree(sdev); goto out; } - svm->pasid = ret; svm->notifier.ops = &intel_mmuops; svm->mm = mm; svm->flags = flags; @@ -343,7 +345,7 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_ if (mm) { ret = mmu_notifier_register(&svm->notifier, mm); if (ret) { - intel_pasid_free_id(svm->pasid); + iommu_pasid_free(iommu->svm_pasid, svm->pasid); kfree(svm); kfree(sdev); goto out; @@ -356,7 +358,7 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_ if (ret) { if (mm) mmu_notifier_unregister(&svm->notifier, mm); - intel_pasid_free_id(svm->pasid); + iommu_pasid_free(iommu->svm_pasid, svm->pasid); kfree(svm); kfree(sdev); goto out; @@ -389,7 +391,7 @@ int intel_svm_unbind_mm(struct device *dev, int pasid) if (!iommu) goto out; - svm = intel_pasid_lookup_id(pasid); + svm = iommu_pasid_find(iommu->svm_pasid, pasid); if (!svm) goto out; @@ -411,7 +413,7 @@ int intel_svm_unbind_mm(struct device *dev, int pasid) kfree_rcu(sdev, rcu); if (list_empty(&svm->devs)) { - intel_pasid_free_id(svm->pasid); + iommu_pasid_free(iommu->svm_pasid, svm->pasid); if (svm->mm) mmu_notifier_unregister(&svm->notifier, svm->mm); @@ -446,7 +448,7 @@ int intel_svm_is_pasid_valid(struct device *dev, int pasid) if (!iommu) goto out; - svm = intel_pasid_lookup_id(pasid); + svm = iommu_pasid_find(iommu->svm_pasid, pasid); if (!svm) goto out; @@ -545,7 +547,7 @@ static irqreturn_t prq_event_thread(int irq, void *d) if (!svm || svm->pasid != req->pasid) { rcu_read_lock(); - svm = intel_pasid_lookup_id(req->pasid); + svm = iommu_pasid_find(iommu->svm_pasid, req->pasid); /* It *can't* go away, because the driver is not permitted * to unbind the mm while any page faults are outstanding. * So we only need RCU to protect the internal idr code. */ diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h index 4605eef3686c..d79f99388293 100644 --- a/include/linux/intel-iommu.h +++ b/include/linux/intel-iommu.h @@ -552,6 +552,7 @@ struct intel_iommu { #ifdef CONFIG_INTEL_IOMMU_SVM struct page_req_dsc *prq; unsigned char prq_name[16]; /* Name for PRQ interrupt */ + struct iommu_pasid *svm_pasid; /* SVM PASID consumer */ #endif struct q_inval *qi; /* Queued invalidation info */ u32 *iommu_state; /* Store iommu states between suspend and resume.*/ @@ -564,6 +565,8 @@ struct intel_iommu { struct iommu_device iommu; /* IOMMU core code handle */ int node; u32 flags; /* Software defined flags */ + + struct iommu_pasid *aux_pasid; /* Aux-domain pasid consumer */ }; /* PCI domain-device relationship */