From patchwork Tue Dec 16 20:08:53 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julien Grall X-Patchwork-Id: 42353 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-ee0-f71.google.com (mail-ee0-f71.google.com [74.125.83.71]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id A2BD025E25 for ; Tue, 16 Dec 2014 20:11:21 +0000 (UTC) Received: by mail-ee0-f71.google.com with SMTP id c13sf9397056eek.10 for ; Tue, 16 Dec 2014 12:11:20 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:from:to:date:message-id:in-reply-to :references:cc:subject:precedence:list-id:list-unsubscribe:list-post :list-help:list-subscribe:mime-version:content-type :content-transfer-encoding:sender:errors-to:x-original-sender :x-original-authentication-results:mailing-list:list-archive; bh=oeV8sap3kSsLtUQaj6gsSocvBXkSgkPCQUvd9uJ+y2Y=; b=Ug2NoD1/IQwZYjgeWts6nQId4rtcloqQ+osLR8irOFINL1ciV3M5M0Lp96Tf5LoDHU 0PcTcC8jcgS70qjfmHX+R9uekZM2wecNMIqUzPpG2DjbjLgeJ5mZAhpzwHlJIQRn3I41 nPCyH8FGH60YYFpRDQ6Ui/FjeLY7zIN0GVGmufwRD1y/M9bu6XXYeAkw2r8kqC82Rj7o FBOqG519wi9MT3ArVEN7uv4bZ+di/I7oprjhu2tTK3Ft/Oe0sOYDshY97s8veJV4AJ15 7OnXM9kIkAcla/elVxosc5bh5Iln8+s399rWfvbikCSZqX1CxMgj1cFdATq8u7j/itw3 AHzw== X-Gm-Message-State: ALoCoQmmycar3g6JjxSxhNfofou6+puqX6nhmwLZ1RvwCCZ2daWlqmMvYBhMuQVIxPq+1jqayH5b X-Received: by 10.180.82.34 with SMTP id f2mr741323wiy.1.1418760680839; Tue, 16 Dec 2014 12:11:20 -0800 (PST) X-BeenThere: patchwork-forward@linaro.org Received: by 10.152.44.135 with SMTP id e7ls680237lam.76.gmail; Tue, 16 Dec 2014 12:11:20 -0800 (PST) X-Received: by 10.152.87.100 with SMTP id w4mr37557017laz.71.1418760680485; Tue, 16 Dec 2014 12:11:20 -0800 (PST) Received: from mail-la0-f52.google.com (mail-la0-f52.google.com. [209.85.215.52]) by mx.google.com with ESMTPS id zk9si1723021lbb.138.2014.12.16.12.11.20 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 16 Dec 2014 12:11:20 -0800 (PST) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.52 as permitted sender) client-ip=209.85.215.52; Received: by mail-la0-f52.google.com with SMTP id hs14so11751989lab.25 for ; Tue, 16 Dec 2014 12:11:20 -0800 (PST) X-Received: by 10.112.235.137 with SMTP id um9mr18078588lbc.41.1418760680370; Tue, 16 Dec 2014 12:11:20 -0800 (PST) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.112.142.69 with SMTP id ru5csp1148897lbb; Tue, 16 Dec 2014 12:11:19 -0800 (PST) X-Received: by 10.140.91.7 with SMTP id y7mr16465028qgd.41.1418760674714; Tue, 16 Dec 2014 12:11:14 -0800 (PST) Received: from lists.xen.org (lists.xen.org. [50.57.142.19]) by mx.google.com with ESMTPS id x7si2130027qal.33.2014.12.16.12.11.13 (version=TLSv1 cipher=RC4-SHA bits=128/128); Tue, 16 Dec 2014 12:11:14 -0800 (PST) Received-SPF: none (google.com: xen-devel-bounces@lists.xen.org does not designate permitted sender hosts) client-ip=50.57.142.19; Received: from localhost ([127.0.0.1] helo=lists.xen.org) by lists.xen.org with esmtp (Exim 4.72) (envelope-from ) id 1Y0yRC-0004v8-8G; Tue, 16 Dec 2014 20:09:42 +0000 Received: from mail6.bemta5.messagelabs.com ([195.245.231.135]) by lists.xen.org with esmtp (Exim 4.72) (envelope-from ) id 1Y0yRA-0004sc-EK for xen-devel@lists.xenproject.org; Tue, 16 Dec 2014 20:09:40 +0000 Received: from [85.158.139.211] by server-17.bemta-5.messagelabs.com id 87/61-28865-38190945; Tue, 16 Dec 2014 20:09:39 +0000 X-Env-Sender: julien.grall@linaro.org X-Msg-Ref: server-6.tower-206.messagelabs.com!1418760578!13709243!1 X-Originating-IP: [74.125.82.51] X-SpamReason: No, hits=0.0 required=7.0 tests= X-StarScan-Received: X-StarScan-Version: 6.12.5; banners=-,-,- X-VirusChecked: Checked Received: (qmail 13929 invoked from network); 16 Dec 2014 20:09:39 -0000 Received: from mail-wg0-f51.google.com (HELO mail-wg0-f51.google.com) (74.125.82.51) by server-6.tower-206.messagelabs.com with RC4-SHA encrypted SMTP; 16 Dec 2014 20:09:39 -0000 Received: by mail-wg0-f51.google.com with SMTP id x12so18238783wgg.38 for ; Tue, 16 Dec 2014 12:09:38 -0800 (PST) X-Received: by 10.180.11.140 with SMTP id q12mr7757101wib.45.1418760577637; Tue, 16 Dec 2014 12:09:37 -0800 (PST) Received: from chilopoda.uk.xensource.com. ([185.25.64.249]) by mx.google.com with ESMTPSA id b10sm3382705wiw.9.2014.12.16.12.09.36 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 16 Dec 2014 12:09:36 -0800 (PST) From: Julien Grall To: xen-devel@lists.xenproject.org Date: Tue, 16 Dec 2014 20:08:53 +0000 Message-Id: <1418760534-18163-13-git-send-email-julien.grall@linaro.org> X-Mailer: git-send-email 2.1.3 In-Reply-To: <1418760534-18163-1-git-send-email-julien.grall@linaro.org> References: <1418760534-18163-1-git-send-email-julien.grall@linaro.org> Cc: ian.campbell@citrix.com, Andreas Herrmann , manish.jaggi@caviumnetworks.com, Julien Grall , tim@xen.org, stefano.stabellini@citrix.com, Andreas Herrmann Subject: [Xen-devel] [PATCH for 4.6 12/13] xen/iommu: smmu: Introduce automatic stream-id-masking X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: List-Unsubscribe: , List-Post: , List-Help: , List-Subscribe: , MIME-Version: 1.0 Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: julien.grall@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.52 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 List-Archive: From: Andreas Herrmann Try to determine mask/id values that match several stream IDs of a master device when doing Stream ID matching. Thus the number of used SMR groups that are required to map all stream IDs of a master device to a context should be less than the number of SMR groups used so far (currently one SMR group is used for one stream ID). Taken from the Linux ML: http://lists.infradead.org/pipermail/linux-arm-kernel/2014-January/226100.html Changes compare to the Linux ML version: - _fls doesn't exist on Xen so use fls - Use num_s2crs rather than num_streamids in the arm_smmu_free_smrs. This former is the field used to configure SRMS Cc: Andreas Herrmann Signed-off-by: Andreas Herrmann Signed-off-by: Julien Grall --- xen/drivers/passthrough/arm/smmu.c | 177 +++++++++++++++++++++++++++++++++---- 1 file changed, 162 insertions(+), 15 deletions(-) diff --git a/xen/drivers/passthrough/arm/smmu.c b/xen/drivers/passthrough/arm/smmu.c index bfc1069..8a6514f 100644 --- a/xen/drivers/passthrough/arm/smmu.c +++ b/xen/drivers/passthrough/arm/smmu.c @@ -43,6 +43,7 @@ #include #include #include +#include #include @@ -346,8 +347,10 @@ struct arm_smmu_smr { }; struct arm_smmu_master_cfg { - int num_streamids; + u32 num_streamids; u16 streamids[MAX_MASTER_STREAMIDS]; + int num_s2crs; + struct arm_smmu_smr *smrs; }; @@ -392,6 +395,9 @@ struct arm_smmu_device { u32 num_context_irqs; unsigned int *irqs; + u32 smr_mask_mask; + u32 smr_id_mask; + struct list_head list; struct rb_root masters; }; @@ -1113,6 +1119,137 @@ static void arm_smmu_free_pgtables(struct arm_smmu_domain *smmu_domain) kfree(pgd_base); } +/* + * For a given set N of 2**order different stream IDs (no duplicates + * please!) we determine values mask and id such that + * + * (1) (x & mask) == id + * + * for each stream ID x from the given set N. + * + * If the number of bits that are set in mask equals n, then there + * exist 2**n different values y for which + * + * (2) (y & mask) == id + * + * Thus if n equals order we know that for the calculated mask and id + * values there are exactly 2**order == 2**n stream IDs for which (1) + * is true. And we finally can use mask and id to configure an SMR to + * match all stream IDs in the set N. + */ +static int determine_smr_mask(struct arm_smmu_device *smmu, + struct arm_smmu_master_cfg *cfg, + struct arm_smmu_smr *smr, int start, int order) +{ + u16 i, zero_bits_mask, one_bits_mask, const_mask; + int nr; + + nr = 1 << order; + + if (nr == 1) { + /* no mask, use streamid to match and be done with it */ + smr->mask = 0; + smr->id = cfg->streamids[start]; + return 0; + } + + zero_bits_mask = 0; + one_bits_mask = 0xffff; + for (i = start; i < start + nr; i++) { + zero_bits_mask |= cfg->streamids[i]; /* const 0 bits */ + one_bits_mask &= cfg->streamids[i]; /* const 1 bits */ + } + zero_bits_mask = ~zero_bits_mask; + + /* bits having constant values (either 0 or 1) */ + const_mask = zero_bits_mask | one_bits_mask; + + i = hweight16(~const_mask); + if (i == order) { + /* + * We have found a mask/id pair that matches exactly + * nr = 2**order stream IDs which we used for its + * calculation. + */ + smr->mask = ~const_mask; + smr->id = one_bits_mask; + } else { + /* + * No usable mask/id pair for this set of streamids. + * If i > order then mask/id would match more than nr + * streamids. + * If i < order then mask/id would match less than nr + * streamids. (In this case we potentially have used + * some duplicate streamids for the calculation.) + */ + return 1; + } + + if (((smr->mask & smmu->smr_mask_mask) != smr->mask) || + ((smr->id & smmu->smr_id_mask) != smr->id)) + /* insufficient number of mask/id bits */ + return 1; + + return 0; +} + +static int determine_smr_mapping(struct arm_smmu_device *smmu, + struct arm_smmu_master_cfg *cfg, + struct arm_smmu_smr *smrs, int max_smrs) +{ + int nr_sid, nr, i, bit, start; + + /* + * This function is called only once -- when a master is added + * to a domain. If cfg->num_s2crs != 0 then this master + * was already added to a domain. + */ + if (cfg->num_s2crs) + return -EINVAL; + + start = nr = 0; + nr_sid = cfg->num_streamids; + do { + /* + * largest power-of-2 number of streamids for which to + * determine a usable mask/id pair for stream matching + */ + bit = fls(nr_sid) - 1; + if (bit < 0) + return 0; + + /* + * iterate over power-of-2 numbers to determine + * largest possible mask/id pair for stream matching + * of next 2**i streamids + */ + for (i = bit; i >= 0; i--) { + if (!determine_smr_mask(smmu, cfg, + &smrs[cfg->num_s2crs], + start, i)) + break; + } + + if (i < 0) + goto out; + + nr = 1 << i; + nr_sid -= nr; + start += nr; + cfg->num_s2crs++; + } while (cfg->num_s2crs <= max_smrs); + +out: + if (nr_sid) { + /* not enough mapping groups available */ + cfg->num_s2crs = 0; + return -ENOSPC; + } + + return 0; +} + + static void arm_smmu_domain_destroy(struct iommu_domain *domain) { struct arm_smmu_domain *smmu_domain = domain->priv; @@ -1129,7 +1266,7 @@ static void arm_smmu_domain_destroy(struct iommu_domain *domain) static int arm_smmu_master_configure_smrs(struct arm_smmu_device *smmu, struct arm_smmu_master_cfg *cfg) { - int i; + int i, max_smrs, ret; struct arm_smmu_smr *smrs; void __iomem *gr0_base = ARM_SMMU_GR0(smmu); @@ -1139,31 +1276,32 @@ static int arm_smmu_master_configure_smrs(struct arm_smmu_device *smmu, if (cfg->smrs) return -EEXIST; - smrs = kmalloc_array(cfg->num_streamids, sizeof(*smrs), GFP_KERNEL); + max_smrs = min(smmu->num_mapping_groups, cfg->num_streamids); + smrs = kmalloc(sizeof(*smrs) * max_smrs, GFP_KERNEL); if (!smrs) { dev_err(smmu->dev, "failed to allocate %d SMRs\n", - cfg->num_streamids); + max_smrs); return -ENOMEM; } + ret = determine_smr_mapping(smmu, cfg, smrs, max_smrs); + if (ret) + goto err_free_smrs; + /* Allocate the SMRs on the SMMU */ - for (i = 0; i < cfg->num_streamids; ++i) { + for (i = 0; i < cfg->num_s2crs; ++i) { int idx = __arm_smmu_alloc_bitmap(smmu->smr_map, 0, smmu->num_mapping_groups); if (IS_ERR_VALUE(idx)) { dev_err(smmu->dev, "failed to allocate free SMR\n"); - goto err_free_smrs; + goto err_free_bitmap; } - smrs[i] = (struct arm_smmu_smr) { - .idx = idx, - .mask = 0, /* We don't currently share SMRs */ - .id = cfg->streamids[i], - }; + smrs[i].idx = idx; } /* It worked! Now, poke the actual hardware */ - for (i = 0; i < cfg->num_streamids; ++i) { + for (i = 0; i < cfg->num_s2crs; ++i) { u32 reg = SMR_VALID | smrs[i].id << SMR_ID_SHIFT | smrs[i].mask << SMR_MASK_SHIFT; writel_relaxed(reg, gr0_base + ARM_SMMU_GR0_SMR(smrs[i].idx)); @@ -1172,9 +1310,11 @@ static int arm_smmu_master_configure_smrs(struct arm_smmu_device *smmu, cfg->smrs = smrs; return 0; -err_free_smrs: +err_free_bitmap: while (--i >= 0) __arm_smmu_free_bitmap(smmu->smr_map, smrs[i].idx); + cfg->num_s2crs = 0; +err_free_smrs: kfree(smrs); return -ENOSPC; } @@ -1190,13 +1330,15 @@ static void arm_smmu_master_free_smrs(struct arm_smmu_device *smmu, return; /* Invalidate the SMRs before freeing back to the allocator */ - for (i = 0; i < cfg->num_streamids; ++i) { + for (i = 0; i < cfg->num_s2crs; ++i) { u8 idx = smrs[i].idx; writel_relaxed(~SMR_VALID, gr0_base + ARM_SMMU_GR0_SMR(idx)); __arm_smmu_free_bitmap(smmu->smr_map, idx); } + cfg->num_s2crs = 0; + cfg->smrs = NULL; kfree(smrs); } @@ -1213,12 +1355,15 @@ static int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain, if (ret) return ret == -EEXIST ? 0 : ret; - for (i = 0; i < cfg->num_streamids; ++i) { + if (!cfg->num_s2crs) + cfg->num_s2crs = cfg->num_streamids; + for (i = 0; i < cfg->num_s2crs; ++i) { u32 idx, s2cr; idx = cfg->smrs ? cfg->smrs[i].idx : cfg->streamids[i]; s2cr = S2CR_TYPE_TRANS | (smmu_domain->cfg.cbndx << S2CR_CBNDX_SHIFT); + dev_dbg(smmu->dev, "S2CR%d: 0x%x\n", idx, s2cr); writel_relaxed(s2cr, gr0_base + ARM_SMMU_GR0_S2CR(idx)); } @@ -1890,6 +2035,8 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) mask, sid); return -ENODEV; } + smmu->smr_mask_mask = mask; + smmu->smr_id_mask = sid; dev_notice(smmu->dev, "\tstream matching with %u register groups, mask 0x%x",