Received: by 2002:a25:86ce:0:0:0:0:0 with SMTP id y14csp739588ybm; Tue, 21 May 2019 02:44:35 -0700 (PDT) X-Google-Smtp-Source: APXvYqwLrYvhDnAzd7PYth0xl2dKzhbAfw/i98ePDF4cFJR9i72OSk9VGS6kzSczmOm82R/GPJEE X-Received: by 2002:a63:7b1e:: with SMTP id w30mr75901499pgc.406.1558431875670; Tue, 21 May 2019 02:44:35 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1558431875; cv=none; d=google.com; s=arc-20160816; b=oCUdN6i42IciPs4VD1iHqYLxhMcziBJ5c98tf+vFbwNz/zn+Zl7js3akilzu1/X/WO Z367jReZlp5V8FjrUxgBXj+rjQcXNMGwLx05KTUIlrdMa9p1VTZCbEhh33zXa0irXP3T N9kijChXFz7p8zJV/TChoTtwni4OB2tJm5A+CTpYWfu5EgHlMGj0x1fr5JT4oN8blWfM zWcLT0yY/kzEo7YoqBwCeHr+OebTWLtNUn5rUyJtTnQLzHv4PVaIQczs4P3Nmua6hI4O GjU4WC083NHttrCdzoTNMitW5DuWs9vJO9cA33JyU4qM0dX+GGLbD0ufAF2x/Gql7ZQ5 jptw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding :content-language:in-reply-to:mime-version:user-agent:date :message-id:from:references:cc:to:subject; bh=aEFK9zbsGHt1MdbokQgGQxe26risBScTIGui8z2HfHw=; b=GgDh2HVYaWUoqfvTycZds1b4AoJzR3/OQAweQp0Xucm5kHSb9/5twmXbkIekQn84Gu 3cvggNg4a1c6f9TuqiVyH0QWYT2DACAlXJ6cBxvRd+62HUkklmk9oMEc9GhaNISVEV2N Ah4nrrFlBJ3BW7jhn069NM9szdjGk1qj3xdiRCrN1WD1vnr/29DbTdeTTzeVKG867sy6 1+DLmtZgnOiYiMC3dVoTHsk1F7JbwQonRIPkSvbMHHTInXTnaBoKW9ItZzZAUGerxag+ v5MsqjrJ6vjGxH4llPCSzOeG3dxqSt0tbzlLqoUa9kNJUlfMB3vX69JQ+Hu8CYAOV8+D o8VQ== 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; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 59si20813037plp.139.2019.05.21.02.44.20; Tue, 21 May 2019 02:44:35 -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; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727350AbfEUJmK (ORCPT + 99 others); Tue, 21 May 2019 05:42:10 -0400 Received: from mx1.redhat.com ([209.132.183.28]:36804 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726242AbfEUJmK (ORCPT ); Tue, 21 May 2019 05:42:10 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 64A283086228; Tue, 21 May 2019 09:42:04 +0000 (UTC) Received: from [10.36.116.113] (ovpn-116-113.ams2.redhat.com [10.36.116.113]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 4979D60FE6; Tue, 21 May 2019 09:41:55 +0000 (UTC) Subject: Re: [PATCH v3 03/16] iommu: Add I/O ASID allocator To: Jacob Pan , iommu@lists.linux-foundation.org, LKML , Joerg Roedel , David Woodhouse , Alex Williamson , Jean-Philippe Brucker Cc: Yi Liu , "Tian, Kevin" , Raj Ashok , Christoph Hellwig , Lu Baolu , Andriy Shevchenko References: <1556922737-76313-1-git-send-email-jacob.jun.pan@linux.intel.com> <1556922737-76313-4-git-send-email-jacob.jun.pan@linux.intel.com> From: Auger Eric Message-ID: Date: Tue, 21 May 2019 11:41:52 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.4.0 MIME-Version: 1.0 In-Reply-To: <1556922737-76313-4-git-send-email-jacob.jun.pan@linux.intel.com> Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 7bit X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.42]); Tue, 21 May 2019 09:42:09 +0000 (UTC) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi, On 5/4/19 12:32 AM, Jacob Pan wrote: > From: Jean-Philippe Brucker > > Some devices might support multiple DMA address spaces, in particular > those that have the PCI PASID feature. PASID (Process Address Space ID) > allows to share process address spaces with devices (SVA), partition a > device into VM-assignable entities (VFIO mdev) or simply provide > multiple DMA address space to kernel drivers. Add a global PASID > allocator usable by different drivers at the same time. Name it I/O ASID > to avoid confusion with ASIDs allocated by arch code, which are usually > a separate ID space. > > The IOASID space is global. Each device can have its own PASID space, > but by convention the IOMMU ended up having a global PASID space, so > that with SVA, each mm_struct is associated to a single PASID. > > The allocator is primarily used by IOMMU subsystem but in rare occasions > drivers would like to allocate PASIDs for devices that aren't managed by > an IOMMU, using the same ID space as IOMMU. > > Signed-off-by: Jean-Philippe Brucker > Signed-off-by: Jacob Pan > Link: https://lkml.org/lkml/2019/4/26/462 > --- > drivers/iommu/Kconfig | 6 +++ > drivers/iommu/Makefile | 1 + > drivers/iommu/ioasid.c | 140 +++++++++++++++++++++++++++++++++++++++++++++++++ > include/linux/ioasid.h | 67 +++++++++++++++++++++++ > 4 files changed, 214 insertions(+) > create mode 100644 drivers/iommu/ioasid.c > create mode 100644 include/linux/ioasid.h > > diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig > index 6f07f3b..75e7f97 100644 > --- a/drivers/iommu/Kconfig > +++ b/drivers/iommu/Kconfig > @@ -2,6 +2,12 @@ > config IOMMU_IOVA > tristate > > +config IOASID > + bool > + help > + Enable the I/O Address Space ID allocator. A single ID space shared > + between different users. > + > # IOMMU_API always gets selected by whoever wants it. > config IOMMU_API > bool > diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile > index 8c71a15..0efac6f 100644 > --- a/drivers/iommu/Makefile > +++ b/drivers/iommu/Makefile > @@ -7,6 +7,7 @@ obj-$(CONFIG_IOMMU_DMA) += dma-iommu.o > obj-$(CONFIG_IOMMU_IO_PGTABLE) += io-pgtable.o > obj-$(CONFIG_IOMMU_IO_PGTABLE_ARMV7S) += io-pgtable-arm-v7s.o > obj-$(CONFIG_IOMMU_IO_PGTABLE_LPAE) += io-pgtable-arm.o > +obj-$(CONFIG_IOASID) += ioasid.o > obj-$(CONFIG_IOMMU_IOVA) += iova.o > obj-$(CONFIG_OF_IOMMU) += of_iommu.o > obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o > diff --git a/drivers/iommu/ioasid.c b/drivers/iommu/ioasid.c > new file mode 100644 > index 0000000..99f5e0a > --- /dev/null > +++ b/drivers/iommu/ioasid.c > @@ -0,0 +1,140 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * I/O Address Space ID allocator. There is one global IOASID space, split into > + * subsets. Users create a subset with DECLARE_IOASID_SET, then allocate and > + * free IOASIDs with ioasid_alloc and ioasid_free. > + */ > +#include > +#include > +#include > +#include > + > +struct ioasid_data { > + ioasid_t id; > + struct ioasid_set *set; > + void *private; > + struct rcu_head rcu; > +}; > + > +static DEFINE_XARRAY_ALLOC(ioasid_xa); > + > +/** > + * ioasid_set_data - Set private data for an allocated ioasid > + * @ioasid: the ID to set data > + * @data: the private data > + * > + * For IOASID that is already allocated, private data can be set > + * via this API. Future lookup can be done via ioasid_find. > + */ > +int ioasid_set_data(ioasid_t ioasid, void *data) > +{ > + struct ioasid_data *ioasid_data; > + int ret = 0; > + > + ioasid_data = xa_load(&ioasid_xa, ioasid); > + if (ioasid_data) > + ioasid_data->private = data; > + else > + ret = -ENOENT; > + > + /* getter may use the private data */ > + synchronize_rcu(); > + > + return ret; > +} > +EXPORT_SYMBOL_GPL(ioasid_set_data); > + > +/** > + * ioasid_alloc - Allocate an IOASID > + * @set: the IOASID set > + * @min: the minimum ID (inclusive) > + * @max: the maximum ID (inclusive) > + * @private: data private to the caller > + * > + * Allocate an ID between @min and @max (or %0 and %INT_MAX). Return the > + * allocated ID on success, or INVALID_IOASID on failure. The @private pointer > + * is stored internally and can be retrieved with ioasid_find(). > + */ > +ioasid_t ioasid_alloc(struct ioasid_set *set, ioasid_t min, ioasid_t max, > + void *private) > +{ > + int id = INVALID_IOASID; > + struct ioasid_data *data; > + > + data = kzalloc(sizeof(*data), GFP_KERNEL); > + if (!data) > + return INVALID_IOASID; > + > + data->set = set; > + data->private = private; > + > + if (xa_alloc(&ioasid_xa, &id, data, XA_LIMIT(min, max), GFP_KERNEL)) { > + pr_err("Failed to alloc ioasid from %d to %d\n", min, max); > + goto exit_free; > + } > + data->id = id; > + > +exit_free: > + if (id < 0 || id == INVALID_IOASID) { > + kfree(data); > + return INVALID_IOASID; > + } > + return id; > +} > +EXPORT_SYMBOL_GPL(ioasid_alloc); > + > +/** > + * ioasid_free - Free an IOASID > + * @ioasid: the ID to remove > + */ > +void ioasid_free(ioasid_t ioasid) > +{ > + struct ioasid_data *ioasid_data; > + > + ioasid_data = xa_erase(&ioasid_xa, ioasid); > + > + kfree_rcu(ioasid_data, rcu); > +} > +EXPORT_SYMBOL_GPL(ioasid_free); > + > +/** > + * ioasid_find - Find IOASID data > + * @set: the IOASID set > + * @ioasid: the IOASID to find > + * @getter: function to call on the found object > + * > + * The optional getter function allows to take a reference to the found object > + * under the rcu lock. The function can also check if the object is still valid: > + * if @getter returns false, then the object is invalid and NULL is returned. > + * > + * If the IOASID has been allocated for this set, return the private pointer > + * passed to ioasid_alloc. Private data can be NULL if not set. Return an error > + * if the IOASID is not found or not belong to the set. > + */ > +void *ioasid_find(struct ioasid_set *set, ioasid_t ioasid, > + bool (*getter)(void *)) > +{ > + void *priv = NULL; > + struct ioasid_data *ioasid_data; > + > + rcu_read_lock(); > + ioasid_data = xa_load(&ioasid_xa, ioasid); > + if (!ioasid_data) { > + priv = ERR_PTR(-ENOENT); > + goto unlock; > + } > + if (set && ioasid_data->set != set) { > + /* data found but does not belong to the set */ > + priv = ERR_PTR(-EACCES); > + goto unlock; > + } > + /* Now IOASID and its set is verified, we can return the private data */ > + priv = ioasid_data->private; > + if (getter && !getter(priv)) > + priv = NULL; > +unlock: > + rcu_read_unlock(); > + > + return priv; > +} > +EXPORT_SYMBOL_GPL(ioasid_find); > diff --git a/include/linux/ioasid.h b/include/linux/ioasid.h > new file mode 100644 > index 0000000..41de5e4 > --- /dev/null > +++ b/include/linux/ioasid.h > @@ -0,0 +1,67 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +#ifndef __LINUX_IOASID_H > +#define __LINUX_IOASID_H > + > +#define INVALID_IOASID ((ioasid_t)-1) > +typedef unsigned int ioasid_t; > +typedef int (*ioasid_iter_t)(ioasid_t ioasid, void *private, void *data); not used as reported during v2 review: https://lkml.org/lkml/2019/4/25/341 Thanks Eric > +typedef ioasid_t (*ioasid_alloc_fn_t)(ioasid_t min, ioasid_t max, void *data); > +typedef void (*ioasid_free_fn_t)(ioasid_t ioasid, void *data); > + > +struct ioasid_set { > + int dummy; > +}; > + > +struct ioasid_allocator { > + ioasid_alloc_fn_t alloc; > + ioasid_free_fn_t free; > + void *pdata; > + struct list_head list; > +}; > + > +#define DECLARE_IOASID_SET(name) struct ioasid_set name = { 0 } > + > +#ifdef CONFIG_IOASID > +ioasid_t ioasid_alloc(struct ioasid_set *set, ioasid_t min, ioasid_t max, > + void *private); > +void ioasid_free(ioasid_t ioasid); > + > +void *ioasid_find(struct ioasid_set *set, ioasid_t ioasid, > + bool (*getter)(void *)); > +int ioasid_register_allocator(struct ioasid_allocator *allocator); > +void ioasid_unregister_allocator(struct ioasid_allocator *allocator); > + > +int ioasid_set_data(ioasid_t ioasid, void *data); > + > +#else /* !CONFIG_IOASID */ > +static inline ioasid_t ioasid_alloc(struct ioasid_set *set, ioasid_t min, > + ioasid_t max, void *private) > +{ > + return INVALID_IOASID; > +} > + > +static inline void ioasid_free(ioasid_t ioasid) > +{ > +} > + > +static inline void *ioasid_find(struct ioasid_set *set, ioasid_t ioasid, > + bool (*getter)(void *)) > +{ > + return NULL; > +} > +static inline int ioasid_register_allocator(struct ioasid_allocator *allocator) > +{ > + return -ENODEV; > +} > + > +static inline void ioasid_unregister_allocator(struct ioasid_allocator *allocator) > +{ > +} > + > +static inline int ioasid_set_data(ioasid_t ioasid, void *data) > +{ > + return -ENODEV; > +} > + > +#endif /* CONFIG_IOASID */ > +#endif /* __LINUX_IOASID_H */ >