From patchwork Wed Feb 21 22:59:21 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jordan Crouse X-Patchwork-Id: 10234327 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 25D0760385 for ; Wed, 21 Feb 2018 23:07:07 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1792A27E71 for ; Wed, 21 Feb 2018 23:07:07 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0C94D285CC; Wed, 21 Feb 2018 23:07:07 +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=-1.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 3B2F127E71 for ; Wed, 21 Feb 2018 23:07:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=hJo3vlznjod0t2wEG12VoWZPDjuDDj71fmOQrCUrfdg=; b=V0ixi+Ak7GFQ4GZrSVkbF4XzXm 1hAiwvo5zUhdV14SQrfH/x9wj9A9L05EF3ZX9Vm9TdT17e/7WFcPBaVjbDfgxJvq7TCOyqKNAKZNc FMOrS3yrTGtawQ3Z7QBWFOIZXL3d3BtFyFyATaWm07FAt0jEoa6glvsAgDqJyfzUvwJ3bmZTIAKXs 8uM7iR9GdzTemjJRGHMiB9D3vneeQ0k/kHyuRxEWhXtGI0ARgFeGnxpshnA+UrHuhiEFaNzksCxMH EMkMcGNokyNpK+8xdkA+uLVjj0tHlq1+zl3m2esgz59hF21E1SnQXW8TQ2R2yOqIZ0znO64V+iPKa 6z2tu1Vg==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.89 #1 (Red Hat Linux)) id 1eodTV-0002z0-RT; Wed, 21 Feb 2018 23:06:57 +0000 Received: from smtp.codeaurora.org ([198.145.29.96]) by bombadil.infradead.org with esmtps (Exim 4.89 #1 (Red Hat Linux)) id 1eodMy-0005R7-GQ for linux-arm-kernel@lists.infradead.org; Wed, 21 Feb 2018 23:00:47 +0000 Received: by smtp.codeaurora.org (Postfix, from userid 1000) id 3A6B261160; Wed, 21 Feb 2018 22:59:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1519254001; bh=Il8jCjTRW1Y9yVfDJrpguPwi78J3z1RMeRyF4WCOGPA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=hgsd8bIKg5wiD8SidYV6lSfhhPykRSiflF1E8FpLkAo3hxoI9p9a2BSxhSo2QVHS6 YCvspyf/IKm3g3bxxPToRM/buqvVvTFa32UMmN7iIGvbCKU1im3eNpj9lRp1AbEE5c 7ISC4eVmbzlB3Rvs5O5QhS8muRlrRu0jhoxmNN88= Received: from jcrouse-lnx.qualcomm.com (i-global254.qualcomm.com [199.106.103.254]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (No client certificate requested) (Authenticated sender: jcrouse@smtp.codeaurora.org) by smtp.codeaurora.org (Postfix) with ESMTPSA id 6AC8C60F8E; Wed, 21 Feb 2018 22:59:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1519253987; bh=Il8jCjTRW1Y9yVfDJrpguPwi78J3z1RMeRyF4WCOGPA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=SfXCkvT82kD1rmz1sZL8LkoLxT+5R52TRFfswifxjmDfBfmwH2RiNexLPwgf3tvJF DZ4Ly7iwzFP7rpevXPAWm6EwhFSty57R1LmVT7wguJVCjdqpDoGS5bF+rgcSKFA7uP 8uyudwRVo5HHjgtDb46OHfBJBD7GbZsZuy9WF4h0= DMARC-Filter: OpenDMARC Filter v1.3.2 smtp.codeaurora.org 6AC8C60F8E Authentication-Results: pdx-caf-mail.web.codeaurora.org; dmarc=none (p=none dis=none) header.from=codeaurora.org Authentication-Results: pdx-caf-mail.web.codeaurora.org; spf=none smtp.mailfrom=jcrouse@codeaurora.org From: Jordan Crouse To: freedreno@lists.freedesktop.org Subject: [PATCH 11/14] drm/msm: Add support for iommu-sva PASIDs Date: Wed, 21 Feb 2018 15:59:21 -0700 Message-Id: <20180221225924.30737-12-jcrouse@codeaurora.org> X-Mailer: git-send-email 2.16.1 In-Reply-To: <20180221225924.30737-1-jcrouse@codeaurora.org> References: <20180221225924.30737-1-jcrouse@codeaurora.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180221_150013_015001_14BA16C1 X-CRM114-Status: GOOD ( 19.40 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jean-philippe.brucker@arm.com, linux-arm-msm@vger.kernel.org, dri-devel@lists.freedesktop.org, tfiga@chromium.org, iommu@lists.linux-foundation.org, vivek.gautam@codeaurora.org, linux-arm-kernel@lists.infradead.org MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP The IOMMU core can support creating multiple pagetables for a specific domai and making them available to a client driver that has the means to manage the pagetable itself. PASIDs are unique indexes to a software created pagetable with the same format and characteristics as the parent IOMMU device. The IOMMU driver allocates the pagetable and tracks it with a unique token (PASID) - it does not touch the actual hardware. The client driver is expected to be able to manage the pagetables and do something interesting with them. Some flavors of the MSM GPU are able to allow each DRM instance to have its own pagetable (and virtual memory space) and switch them asynchronously at the beginning of a command. This protects against accidental or malicious corruption or copying of buffers from other instances. The first step is to add a MMU implementation that can allocate a PASID and set up a msm_mmu struct to abstract (most) of the details from the rest of the system. Signed-off-by: Jordan Crouse --- drivers/gpu/drm/msm/msm_iommu.c | 184 ++++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/msm/msm_mmu.h | 6 ++ 2 files changed, 190 insertions(+) diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c index fdbe1a8372f0..de8669c9a5a1 100644 --- a/drivers/gpu/drm/msm/msm_iommu.c +++ b/drivers/gpu/drm/msm/msm_iommu.c @@ -15,6 +15,9 @@ * this program. If not, see . */ +#include +#include + #include "msm_drv.h" #include "msm_mmu.h" @@ -34,12 +37,29 @@ static int msm_fault_handler(struct iommu_domain *domain, struct device *dev, return 0; } +static bool msm_iommu_check_per_instance(struct msm_iommu *iommu) +{ + int val; + + if (!IS_ENABLED(CONFIG_IOMMU_SVA)) + return false; + + if (iommu_domain_get_attr(iommu->domain, DOMAIN_ATTR_ENABLE_TTBR1, + &val)) + return false; + + return val ? true : false; +} + static int msm_iommu_attach(struct msm_mmu *mmu, const char * const *names, int cnt) { struct msm_iommu *iommu = to_msm_iommu(mmu); int ret; + if (msm_iommu_check_per_instance(iommu)) + msm_mmu_set_feature(mmu, MMU_FEATURE_PER_INSTANCE_TABLES); + pm_runtime_get_sync(mmu->dev); ret = iommu_attach_device(iommu->domain, mmu->dev); pm_runtime_put_sync(mmu->dev); @@ -112,3 +132,167 @@ struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain) return &iommu->base; } + +struct pasid_entry { + int pasid; + u64 ttbr; + u32 asid; + struct hlist_node node; +}; + +DECLARE_HASHTABLE(pasid_table, 4); + +static int install_pasid_cb(int pasid, u64 ttbr, u32 asid, void *data) +{ + struct pasid_entry *entry = kzalloc(sizeof(*entry), GFP_KERNEL); + + if (!entry) + return -ENOMEM; + + entry->pasid = pasid; + entry->ttbr = ttbr; + entry->asid = asid; + + /* FIXME: Assume that we'll never have a pasid conflict? */ + /* FIXME: locks? RCU? */ + hash_add(pasid_table, &entry->node, pasid); + return 0; +} + +static void remove_pasid_cb(int pasid, void *data) +{ + struct pasid_entry *entry; + + hash_for_each_possible(pasid_table, entry, node, pasid) { + if (pasid == entry->pasid) { + hash_del(&entry->node); + kfree(entry); + return; + } + } +} + +struct msm_iommu_pasid { + struct msm_mmu base; + int pasid; + u64 ttbr; + u32 asid; +}; +#define to_msm_iommu_pasid(x) container_of(x, struct msm_iommu_pasid, base) + +static int msm_iommu_pasid_attach(struct msm_mmu *mmu, + const char * const *names, int cnt) +{ + return 0; +} + +static int msm_iommu_pasid_map(struct msm_mmu *mmu, uint64_t iova, + struct sg_table *sgt, unsigned len, int prot) +{ + struct msm_iommu_pasid *pasid = to_msm_iommu_pasid(mmu); + int ret; + + ret = iommu_sva_map_sg(pasid->pasid, iova, sgt->sgl, sgt->nents, prot); + WARN_ON(ret < 0); + + return (ret == len) ? 0 : -EINVAL; +} + +static int msm_iommu_pasid_unmap(struct msm_mmu *mmu, uint64_t iova, + struct sg_table *sgt, unsigned len) +{ + struct msm_iommu_pasid *pasid = to_msm_iommu_pasid(mmu); + + iommu_sva_unmap(pasid->pasid, iova, len); + + return 0; +} + +static void msm_iommu_pasid_detach(struct msm_mmu *mmu, + const char * const *names, int cnt) +{ +} + +static void msm_iommu_pasid_destroy(struct msm_mmu *mmu) +{ + struct msm_iommu_pasid *pasid = to_msm_iommu_pasid(mmu); + + iommu_sva_free_pasid(pasid->pasid); + kfree(pasid); +} + +static const struct msm_mmu_funcs pasid_funcs = { + .attach = msm_iommu_pasid_attach, + .detach = msm_iommu_pasid_detach, + .map = msm_iommu_pasid_map, + .unmap = msm_iommu_pasid_unmap, + .destroy = msm_iommu_pasid_destroy, +}; + +static const struct arm_smmu_pasid_ops msm_iommu_pasid_ops = { + .install_pasid = install_pasid_cb, + .remove_pasid = remove_pasid_cb, +}; + +struct msm_mmu *msm_iommu_pasid_new(struct msm_mmu *parent) +{ + struct msm_iommu *parent_iommu = to_msm_iommu(parent); + struct msm_iommu_pasid *pasid; + int id; + + if (!msm_mmu_has_feature(parent, MMU_FEATURE_PER_INSTANCE_TABLES)) + return ERR_PTR(-EOPNOTSUPP); + + pasid = kzalloc(sizeof(*pasid), GFP_KERNEL); + if (!pasid) + return ERR_PTR(-ENOMEM); + + arm_smmu_add_pasid_ops(parent_iommu->domain, &msm_iommu_pasid_ops, + NULL); + + id = iommu_sva_alloc_pasid(parent_iommu->domain, parent->dev); + if (id < 0) { + kfree(pasid); + return ERR_PTR(id); + } + + pasid->pasid = id; + msm_mmu_init(&pasid->base, parent->dev, &pasid_funcs); + + return &pasid->base; +} + +/* Given a pasid return the TTBR and ASID associated with it */ +int msm_iommu_pasid_info(struct msm_mmu *mmu, u64 *ttbr, u32 *asid) +{ + struct msm_iommu_pasid *pasid; + struct pasid_entry *entry; + + if (mmu->funcs->map != msm_iommu_pasid_map) + return -ENODEV; + + pasid = to_msm_iommu_pasid(mmu); + + if (!pasid->ttbr) { + /* Find the pasid entry in the hash */ + hash_for_each_possible(pasid_table, entry, node, pasid->pasid) { + if (pasid->pasid == entry->pasid) { + pasid->ttbr = entry->ttbr; + pasid->asid = entry->asid; + goto out; + } + } + + WARN(1, "Couldn't find the entry for pasid %d\n", pasid->pasid); + return -EINVAL; + } + +out: + if (*ttbr) + *ttbr = pasid->ttbr; + + if (*asid) + *asid = pasid->asid; + + return 0; +} diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h index 85df78d71398..29436b9daa73 100644 --- a/drivers/gpu/drm/msm/msm_mmu.h +++ b/drivers/gpu/drm/msm/msm_mmu.h @@ -30,6 +30,9 @@ struct msm_mmu_funcs { void (*destroy)(struct msm_mmu *mmu); }; +/* MMU features */ +#define MMU_FEATURE_PER_INSTANCE_TABLES (1 << 0) + struct msm_mmu { const struct msm_mmu_funcs *funcs; struct device *dev; @@ -48,6 +51,9 @@ static inline void msm_mmu_init(struct msm_mmu *mmu, struct device *dev, struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain); struct msm_mmu *msm_gpummu_new(struct device *dev, struct msm_gpu *gpu); +struct msm_mmu *msm_iommu_pasid_new(struct msm_mmu *parent); +int msm_iommu_pasid_info(struct msm_mmu *mmu, u64 *ttbr, u32 *asid); + static inline void msm_mmu_set_fault_handler(struct msm_mmu *mmu, void *arg, int (*handler)(void *arg, unsigned long iova, int flags)) {