Message ID | 20230201082500.61656-1-manivannan.sadhasivam@linaro.org |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp153811wrn; Wed, 1 Feb 2023 00:34:06 -0800 (PST) X-Google-Smtp-Source: AK7set9y2hQwflAaJx6hYXRFSCcmrsuhdLfhEvUVktsn6wC/TCzQSPpn0Y2q6o82lEvRjIZcZhNa X-Received: by 2002:a05:6402:22b9:b0:4a2:6f53:c417 with SMTP id cx25-20020a05640222b900b004a26f53c417mr3990585edb.32.1675240446492; Wed, 01 Feb 2023 00:34:06 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1675240446; cv=none; d=google.com; s=arc-20160816; b=AFSR1e099ZoxUbueL4pEpX5OvMbSYRh8Tttom3hAd2cquoUmtyfi5usy7W1jWGe8CP jakDwmqSfTKCvDsEtljZhewOEh7dJ6/z6ry7ljKizoDc/jJguMoQFcq71Lo8iqbKzgeY 5MT+od5pcQd2tApWhSODzva/yTsY06qD00RLUB021XfC0iyzxdMPqC7Ea/EuFwi3+yfO 1K9PmXH1JshDIfCinAYfukPnx+yw0g1HLNNRIpkpyKFus4s9/XS9BI6vPDekQsJBOb1h EnBwD00sEQeBwOWgGRbL74Bj+ni4JYLRRo0m+bLTAgpeU0toT4bJzZTjB19hE1fiz27N 7ung== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from:dkim-signature; bh=EhWybcKgTwds/UHsJLPm/Ip1rELEiggR3k8BSANmn/I=; b=wKbJ6UMb9GFHGiD90jZ9JJWbTonP1bGU2pnulVexst8lSUb5ajhI3jAeEpLIr4HH26 91jSiN6J9ROhXS7WwA98IRWLC/TPwHohy1+q52DAdIIufCa/TgJ8cuksxwu/zkJxaHHH yxEZK9YOaYx1sgAYE4xqwHTZuGhpEm3qCUR0txGNCyHcdJhzYj6GfwiY/QQm3YOBr7sT F6ry1fTcBUnGHNQi5mBRfcohVb8bFegqWDzUK3590LyKQDtYArXFzFu/rh7+kBpxkxJH oUzaKsAxWESJsXLzYvEwtI9z0IgED4NBmJJaGDyKbIu2RoqQCvA8RWUr3mb/MlQ+nTHZ ekhg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=ltlOKB2q; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id g6-20020aa7d1c6000000b004a22c3f790asi13491984edp.322.2023.02.01.00.33.43; Wed, 01 Feb 2023 00:34:06 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=ltlOKB2q; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231911AbjBAIZM (ORCPT <rfc822;duw91626@gmail.com> + 99 others); Wed, 1 Feb 2023 03:25:12 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39468 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230156AbjBAIZL (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Wed, 1 Feb 2023 03:25:11 -0500 Received: from mail-pj1-x102c.google.com (mail-pj1-x102c.google.com [IPv6:2607:f8b0:4864:20::102c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5309A5DC03 for <linux-kernel@vger.kernel.org>; Wed, 1 Feb 2023 00:25:10 -0800 (PST) Received: by mail-pj1-x102c.google.com with SMTP id l4-20020a17090a850400b0023013402671so1308796pjn.5 for <linux-kernel@vger.kernel.org>; Wed, 01 Feb 2023 00:25:10 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=EhWybcKgTwds/UHsJLPm/Ip1rELEiggR3k8BSANmn/I=; b=ltlOKB2q4A2HTRmq7Dd6Ig4Vvauzv0PlgyzuE2wbGRTqcZGY3SofmipAwycEkv0A6H Gm5b8ayE3VOW014QJ0/ph3vg0cw9PBWDPFpqogh/P6up8znRkfZi4Bl2T++yh2DImAfg hwKGnGc2PmTDt5bjUNkaY5/e7/EBEIO/qeSSUvfBLlAt3Qe7tvXMU5rjwKjNlpMLEmeN FBjNqHtDakNjnJrzh3h0KRASuGXv0D4LjsI0PHKvtzVoUbN/fHW0IRPIPXdbPWfdbL7y uGymn8832EqR3WcEkA8CMvYvdhzv4m+q2j24yhuGRI4MJj7Vo1lzMtrkZtuVwQUcCMpk yjrA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=EhWybcKgTwds/UHsJLPm/Ip1rELEiggR3k8BSANmn/I=; b=DvPYfUHuzXAIlCw8azcchgeVUuswvv697Z9RiU5EFx8Fyh/DtbN4bOFdwPAi+ZMJWi Rs1+ck1XJ3VwJsxCcCQow4VnwNBN4tqywDgXXEbnq3f3aA8y8t7MiGlHpxDYHULXbYJU oT9Vb/vIeL1MvjrcDT9oMZxB86uvFphVje9ThcDbPs96NaCLKzP4yMfiPqA3VVky+7n6 HdpZUXPoaEO9Xjus/feWIEUMjo7Syi8TpzetNNF+PbXs4fFJF01WVpr37QDVDmAaL3d5 VjW2Dila+VJSRauyLhl1TxiGt+tHyfJGoCswL3PqFurQXJUZJGgj5rUYPh1mrRU02p3W 9jJQ== X-Gm-Message-State: AO0yUKXDVuGaWqmHdKHO1/dsHCIE8QsCj8vrLx8jykJAbxSLxj927oyp MDiUYSK2SjiKuG58k0lOXO2J X-Received: by 2002:a05:6a20:2a1e:b0:bc:74c3:9499 with SMTP id e30-20020a056a202a1e00b000bc74c39499mr1623148pzh.24.1675239909774; Wed, 01 Feb 2023 00:25:09 -0800 (PST) Received: from localhost.localdomain ([59.92.99.243]) by smtp.gmail.com with ESMTPSA id 69-20020a630248000000b0045ff216a0casm9847836pgc.3.2023.02.01.00.25.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 01 Feb 2023 00:25:08 -0800 (PST) From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> To: will@kernel.org, joro@8bytes.org Cc: robin.murphy@arm.com, andersson@kernel.org, johan+linaro@kernel.org, steev@kali.org, linux-arm-kernel@lists.infradead.org, iommu@lists.linux.dev, linux-kernel@vger.kernel.org, Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> Subject: [PATCH] iommu/arm-smmu-qcom: Rework the logic finding the bypass quirk Date: Wed, 1 Feb 2023 13:55:00 +0530 Message-Id: <20230201082500.61656-1-manivannan.sadhasivam@linaro.org> X-Mailer: git-send-email 2.25.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1756616926633629253?= X-GMAIL-MSGID: =?utf-8?q?1756616926633629253?= |
Series |
iommu/arm-smmu-qcom: Rework the logic finding the bypass quirk
|
|
Commit Message
Manivannan Sadhasivam
Feb. 1, 2023, 8:25 a.m. UTC
The logic used to find the quirky firmware that intercepts the writes to
S2CR register to replace bypass type streams with a fault, and ignore the
fault type, is not working with the firmware on newer SoCs like SC8280XP.
The current logic uses the last stream mapping group (num_mapping_groups
- 1) as an index for finding quirky firmware. But on SC8280XP, this
logic is not working as the number of stream mapping groups reported by
the SMMU (163 as on the SC8280XP-CRD device) is not valid for some reason.
So the current logic that checks the (163-1) S2CR entry fails to detect
the quirky firmware on these devices and triggers invalid context fault
for bypass streams.
To fix this issue, rework the logic to find the first non-valid (free)
stream mapping register group (SMR) and use that index to access S2CR
for detecting the bypass quirk.
This also warrants a change in variable name from last_s2cr to free_s2cr.
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 24 +++++++++++++++++-----
1 file changed, 19 insertions(+), 5 deletions(-)
Comments
On Wed, Feb 01, 2023 at 01:55:00PM +0530, Manivannan Sadhasivam wrote: > The logic used to find the quirky firmware that intercepts the writes to > S2CR register to replace bypass type streams with a fault, and ignore the > fault type, is not working with the firmware on newer SoCs like SC8280XP. > > The current logic uses the last stream mapping group (num_mapping_groups > - 1) as an index for finding quirky firmware. But on SC8280XP, this > logic is not working as the number of stream mapping groups reported by > the SMMU (163 as on the SC8280XP-CRD device) is not valid for some reason. > So the current logic that checks the (163-1) S2CR entry fails to detect > the quirky firmware on these devices and triggers invalid context fault > for bypass streams. > > To fix this issue, rework the logic to find the first non-valid (free) > stream mapping register group (SMR) and use that index to access S2CR > for detecting the bypass quirk. > > This also warrants a change in variable name from last_s2cr to free_s2cr. > > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> Reviewed-by: Bjorn Andersson <andersson@kernel.org> Regards, Bjorn > --- > drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 24 +++++++++++++++++----- > 1 file changed, 19 insertions(+), 5 deletions(-) > > diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c > index 78fc0e1bf215..4104f81b8d8f 100644 > --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c > +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c > @@ -267,23 +267,37 @@ static int qcom_smmu_init_context(struct arm_smmu_domain *smmu_domain, > > static int qcom_smmu_cfg_probe(struct arm_smmu_device *smmu) > { > - unsigned int last_s2cr = ARM_SMMU_GR0_S2CR(smmu->num_mapping_groups - 1); > struct qcom_smmu *qsmmu = to_qcom_smmu(smmu); > + u32 free_s2cr; > u32 reg; > u32 smr; > int i; > > + /* > + * Find the first non-valid (free) stream mapping register group and > + * use that index to access S2CR for detecting the bypass quirk. > + */ > + for (i = 0; i < smmu->num_mapping_groups; i++) { > + smr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_SMR(i)); > + > + if (!FIELD_GET(ARM_SMMU_SMR_VALID, smr)) > + break; > + } > + > + free_s2cr = ARM_SMMU_GR0_S2CR(i); > + > /* > * With some firmware versions writes to S2CR of type FAULT are > * ignored, and writing BYPASS will end up written as FAULT in the > - * register. Perform a write to S2CR to detect if this is the case and > - * if so reserve a context bank to emulate bypass streams. > + * register. Perform a write to the first free S2CR to detect if > + * this is the case and if so reserve a context bank to emulate > + * bypass streams. > */ > reg = FIELD_PREP(ARM_SMMU_S2CR_TYPE, S2CR_TYPE_BYPASS) | > FIELD_PREP(ARM_SMMU_S2CR_CBNDX, 0xff) | > FIELD_PREP(ARM_SMMU_S2CR_PRIVCFG, S2CR_PRIVCFG_DEFAULT); > - arm_smmu_gr0_write(smmu, last_s2cr, reg); > - reg = arm_smmu_gr0_read(smmu, last_s2cr); > + arm_smmu_gr0_write(smmu, free_s2cr, reg); > + reg = arm_smmu_gr0_read(smmu, free_s2cr); > if (FIELD_GET(ARM_SMMU_S2CR_TYPE, reg) != S2CR_TYPE_BYPASS) { > qsmmu->bypass_quirk = true; > qsmmu->bypass_cbndx = smmu->num_context_banks - 1; > -- > 2.25.1 >
On Wed, Feb 01, 2023 at 01:55:00PM +0530, Manivannan Sadhasivam wrote: > The logic used to find the quirky firmware that intercepts the writes to > S2CR register to replace bypass type streams with a fault, and ignore the > fault type, is not working with the firmware on newer SoCs like SC8280XP. > > The current logic uses the last stream mapping group (num_mapping_groups > - 1) as an index for finding quirky firmware. But on SC8280XP, this > logic is not working as the number of stream mapping groups reported by > the SMMU (163 as on the SC8280XP-CRD device) is not valid for some reason. NUMSMRG read back as 162 here, both on my CRD and X13s. Was '163' a typo or a real difference? > So the current logic that checks the (163-1) S2CR entry fails to detect > the quirky firmware on these devices and triggers invalid context fault > for bypass streams. > > To fix this issue, rework the logic to find the first non-valid (free) > stream mapping register group (SMR) and use that index to access S2CR > for detecting the bypass quirk. So while this works for the quirk detection, shouldn't we also do something about that bogus NUMSMRG value? At least cap it at 128, which appears to be the maximum according to the specification, for example, by clearing bit 7 when any of the lower bits are set? That would give us 35 (or 36) groups and working quirk detection with just the following smaller patch: diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c index 2ff7a72cf377..0f564a86c352 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c @@ -1744,6 +1744,12 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) return -ENODEV; } + if (size > 0x80) { + dev_warn(smmu->dev, + "invalid number of SMR groups, clearing bit 7\n"); + size -= 0x80; + } + /* Zero-initialised to mark as invalid */ smmu->smrs = devm_kcalloc(smmu->dev, size, sizeof(*smmu->smrs), GFP_KERNEL); I also verified that using index 127 (group 128) for the quirk detection works on my CRD, while the invalid index 128 fails (as do index 161 which would currently be used). > This also warrants a change in variable name from last_s2cr to free_s2cr. > > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> > --- > drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 24 +++++++++++++++++----- > 1 file changed, 19 insertions(+), 5 deletions(-) > > diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c > index 78fc0e1bf215..4104f81b8d8f 100644 > --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c > +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c > @@ -267,23 +267,37 @@ static int qcom_smmu_init_context(struct arm_smmu_domain *smmu_domain, > > static int qcom_smmu_cfg_probe(struct arm_smmu_device *smmu) > { > - unsigned int last_s2cr = ARM_SMMU_GR0_S2CR(smmu->num_mapping_groups - 1); > struct qcom_smmu *qsmmu = to_qcom_smmu(smmu); > + u32 free_s2cr; > u32 reg; > u32 smr; > int i; > > + /* > + * Find the first non-valid (free) stream mapping register group and > + * use that index to access S2CR for detecting the bypass quirk. > + */ > + for (i = 0; i < smmu->num_mapping_groups; i++) { > + smr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_SMR(i)); > + > + if (!FIELD_GET(ARM_SMMU_SMR_VALID, smr)) > + break; > + } > + > + free_s2cr = ARM_SMMU_GR0_S2CR(i); In the unlikely event that there is no free group this would access an invalid index. > + > /* > * With some firmware versions writes to S2CR of type FAULT are > * ignored, and writing BYPASS will end up written as FAULT in the > - * register. Perform a write to S2CR to detect if this is the case and > - * if so reserve a context bank to emulate bypass streams. > + * register. Perform a write to the first free S2CR to detect if > + * this is the case and if so reserve a context bank to emulate > + * bypass streams. > */ > reg = FIELD_PREP(ARM_SMMU_S2CR_TYPE, S2CR_TYPE_BYPASS) | > FIELD_PREP(ARM_SMMU_S2CR_CBNDX, 0xff) | > FIELD_PREP(ARM_SMMU_S2CR_PRIVCFG, S2CR_PRIVCFG_DEFAULT); > - arm_smmu_gr0_write(smmu, last_s2cr, reg); > - reg = arm_smmu_gr0_read(smmu, last_s2cr); > + arm_smmu_gr0_write(smmu, free_s2cr, reg); > + reg = arm_smmu_gr0_read(smmu, free_s2cr); > if (FIELD_GET(ARM_SMMU_S2CR_TYPE, reg) != S2CR_TYPE_BYPASS) { > qsmmu->bypass_quirk = true; > qsmmu->bypass_cbndx = smmu->num_context_banks - 1; Johan
On Mon, Feb 13, 2023 at 05:43:56PM +0100, Johan Hovold wrote: > On Wed, Feb 01, 2023 at 01:55:00PM +0530, Manivannan Sadhasivam wrote: > > The logic used to find the quirky firmware that intercepts the writes to > > S2CR register to replace bypass type streams with a fault, and ignore the > > fault type, is not working with the firmware on newer SoCs like SC8280XP. > > > > The current logic uses the last stream mapping group (num_mapping_groups > > - 1) as an index for finding quirky firmware. But on SC8280XP, this > > logic is not working as the number of stream mapping groups reported by > > the SMMU (163 as on the SC8280XP-CRD device) is not valid for some reason. > > NUMSMRG read back as 162 here, both on my CRD and X13s. Was '163' a typo > or a real difference? > Ah yes, it is 162 indeed. Sorry, typo! > > So the current logic that checks the (163-1) S2CR entry fails to detect > > the quirky firmware on these devices and triggers invalid context fault > > for bypass streams. > > > > To fix this issue, rework the logic to find the first non-valid (free) > > stream mapping register group (SMR) and use that index to access S2CR > > for detecting the bypass quirk. > > So while this works for the quirk detection, shouldn't we also do > something about that bogus NUMSMRG value? At least cap it at 128, which > appears to be the maximum according to the specification, for example, > by clearing bit 7 when any of the lower bits are set? > > That would give us 35 (or 36) groups and working quirk detection with > just the following smaller patch: > I'm not certain if the value is bogus or not. It is clear that the spec specifies 128 as the max but internal qcom document shows that they indeed set 162 on purpose in the hypervisor. So until we get a clear view on that, I'd not cap it. > diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c > index 2ff7a72cf377..0f564a86c352 100644 > --- a/drivers/iommu/arm/arm-smmu/arm-smmu.c > +++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c > @@ -1744,6 +1744,12 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) > return -ENODEV; > } > > + if (size > 0x80) { > + dev_warn(smmu->dev, > + "invalid number of SMR groups, clearing bit 7\n"); > + size -= 0x80; > + } > + > /* Zero-initialised to mark as invalid */ > smmu->smrs = devm_kcalloc(smmu->dev, size, sizeof(*smmu->smrs), > GFP_KERNEL); > > I also verified that using index 127 (group 128) for the quirk detection > works on my CRD, while the invalid index 128 fails (as do index 161 > which would currently be used). > > > This also warrants a change in variable name from last_s2cr to free_s2cr. > > > > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> > > --- > > drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 24 +++++++++++++++++----- > > 1 file changed, 19 insertions(+), 5 deletions(-) > > > > diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c > > index 78fc0e1bf215..4104f81b8d8f 100644 > > --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c > > +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c > > @@ -267,23 +267,37 @@ static int qcom_smmu_init_context(struct arm_smmu_domain *smmu_domain, > > > > static int qcom_smmu_cfg_probe(struct arm_smmu_device *smmu) > > { > > - unsigned int last_s2cr = ARM_SMMU_GR0_S2CR(smmu->num_mapping_groups - 1); > > struct qcom_smmu *qsmmu = to_qcom_smmu(smmu); > > + u32 free_s2cr; > > u32 reg; > > u32 smr; > > int i; > > > > + /* > > + * Find the first non-valid (free) stream mapping register group and > > + * use that index to access S2CR for detecting the bypass quirk. > > + */ > > + for (i = 0; i < smmu->num_mapping_groups; i++) { > > + smr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_SMR(i)); > > + > > + if (!FIELD_GET(ARM_SMMU_SMR_VALID, smr)) > > + break; > > + } > > + > > + free_s2cr = ARM_SMMU_GR0_S2CR(i); > > In the unlikely event that there is no free group this would access an > invalid index. > Hmm, theoretically yes. But what would be the plan of action if that happens? Should we just bail out with error or skip the quirk detection? Thanks, Mani > > + > > /* > > * With some firmware versions writes to S2CR of type FAULT are > > * ignored, and writing BYPASS will end up written as FAULT in the > > - * register. Perform a write to S2CR to detect if this is the case and > > - * if so reserve a context bank to emulate bypass streams. > > + * register. Perform a write to the first free S2CR to detect if > > + * this is the case and if so reserve a context bank to emulate > > + * bypass streams. > > */ > > reg = FIELD_PREP(ARM_SMMU_S2CR_TYPE, S2CR_TYPE_BYPASS) | > > FIELD_PREP(ARM_SMMU_S2CR_CBNDX, 0xff) | > > FIELD_PREP(ARM_SMMU_S2CR_PRIVCFG, S2CR_PRIVCFG_DEFAULT); > > - arm_smmu_gr0_write(smmu, last_s2cr, reg); > > - reg = arm_smmu_gr0_read(smmu, last_s2cr); > > + arm_smmu_gr0_write(smmu, free_s2cr, reg); > > + reg = arm_smmu_gr0_read(smmu, free_s2cr); > > if (FIELD_GET(ARM_SMMU_S2CR_TYPE, reg) != S2CR_TYPE_BYPASS) { > > qsmmu->bypass_quirk = true; > > qsmmu->bypass_cbndx = smmu->num_context_banks - 1; > > Johan
On Tue, Feb 14, 2023 at 01:23:12PM +0530, Manivannan Sadhasivam wrote: > On Mon, Feb 13, 2023 at 05:43:56PM +0100, Johan Hovold wrote: > > On Wed, Feb 01, 2023 at 01:55:00PM +0530, Manivannan Sadhasivam wrote: > > > The logic used to find the quirky firmware that intercepts the writes to > > > S2CR register to replace bypass type streams with a fault, and ignore the > > > fault type, is not working with the firmware on newer SoCs like SC8280XP. > > > > > > The current logic uses the last stream mapping group (num_mapping_groups > > > - 1) as an index for finding quirky firmware. But on SC8280XP, this > > > logic is not working as the number of stream mapping groups reported by > > > the SMMU (163 as on the SC8280XP-CRD device) is not valid for some reason. > > > > NUMSMRG read back as 162 here, both on my CRD and X13s. Was '163' a typo > > or a real difference? > > > > Ah yes, it is 162 indeed. Sorry, typo! > > > > So the current logic that checks the (163-1) S2CR entry fails to detect > > > the quirky firmware on these devices and triggers invalid context fault > > > for bypass streams. > > > > > > To fix this issue, rework the logic to find the first non-valid (free) > > > stream mapping register group (SMR) and use that index to access S2CR > > > for detecting the bypass quirk. > > > > So while this works for the quirk detection, shouldn't we also do > > something about that bogus NUMSMRG value? At least cap it at 128, which > > appears to be the maximum according to the specification, for example, > > by clearing bit 7 when any of the lower bits are set? > > > > That would give us 35 (or 36) groups and working quirk detection with > > just the following smaller patch: > > > > I'm not certain if the value is bogus or not. It is clear that the spec > specifies 128 as the max but internal qcom document shows that they indeed > set 162 on purpose in the hypervisor. > > So until we get a clear view on that, I'd not cap it. But if we fault as soon as we try to do something with those register groups above 128 that also violate the spec, it doesn't seem right to trust the fw value here. Clarification from Qualcomm would be good either way, but if they are indication that it's not just a bug that has left bit 7 set then limiting to 128 also seems reasonable (i.e. not by clearing the high bit, but by using the minimum of 128 and size below). > > diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c > > index 2ff7a72cf377..0f564a86c352 100644 > > --- a/drivers/iommu/arm/arm-smmu/arm-smmu.c > > +++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c > > @@ -1744,6 +1744,12 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) > > return -ENODEV; > > } > > > > + if (size > 0x80) { > > + dev_warn(smmu->dev, > > + "invalid number of SMR groups, clearing bit 7\n"); > > + size -= 0x80; > > + } > > + > > /* Zero-initialised to mark as invalid */ > > smmu->smrs = devm_kcalloc(smmu->dev, size, sizeof(*smmu->smrs), > > GFP_KERNEL); > > > > I also verified that using index 127 (group 128) for the quirk detection > > works on my CRD, while the invalid index 128 fails (as do index 161 > > which would currently be used). > > > > > This also warrants a change in variable name from last_s2cr to free_s2cr. > > > > > > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> > > > --- > > > drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 24 +++++++++++++++++----- > > > 1 file changed, 19 insertions(+), 5 deletions(-) > > > > > > diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c > > > index 78fc0e1bf215..4104f81b8d8f 100644 > > > --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c > > > +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c > > > @@ -267,23 +267,37 @@ static int qcom_smmu_init_context(struct arm_smmu_domain *smmu_domain, > > > > > > static int qcom_smmu_cfg_probe(struct arm_smmu_device *smmu) > > > { > > > - unsigned int last_s2cr = ARM_SMMU_GR0_S2CR(smmu->num_mapping_groups - 1); > > > struct qcom_smmu *qsmmu = to_qcom_smmu(smmu); > > > + u32 free_s2cr; > > > u32 reg; > > > u32 smr; > > > int i; > > > > > > + /* > > > + * Find the first non-valid (free) stream mapping register group and > > > + * use that index to access S2CR for detecting the bypass quirk. > > > + */ > > > + for (i = 0; i < smmu->num_mapping_groups; i++) { > > > + smr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_SMR(i)); > > > + > > > + if (!FIELD_GET(ARM_SMMU_SMR_VALID, smr)) > > > + break; > > > + } > > > + > > > + free_s2cr = ARM_SMMU_GR0_S2CR(i); > > > > In the unlikely event that there is no free group this would access an > > invalid index. > > > > Hmm, theoretically yes. But what would be the plan of action if that happens? > Should we just bail out with error or skip the quirk detection? Yes, skipping quirk detection seems preferable to crashing systems that don't need the quirk. Johan
On Tue, Feb 14, 2023 at 10:07:36AM +0100, Johan Hovold wrote: > On Tue, Feb 14, 2023 at 01:23:12PM +0530, Manivannan Sadhasivam wrote: > > On Mon, Feb 13, 2023 at 05:43:56PM +0100, Johan Hovold wrote: > > > On Wed, Feb 01, 2023 at 01:55:00PM +0530, Manivannan Sadhasivam wrote: > > > > The logic used to find the quirky firmware that intercepts the writes to > > > > S2CR register to replace bypass type streams with a fault, and ignore the > > > > fault type, is not working with the firmware on newer SoCs like SC8280XP. > > > > > > > > The current logic uses the last stream mapping group (num_mapping_groups > > > > - 1) as an index for finding quirky firmware. But on SC8280XP, this > > > > logic is not working as the number of stream mapping groups reported by > > > > the SMMU (163 as on the SC8280XP-CRD device) is not valid for some reason. > > > > > > NUMSMRG read back as 162 here, both on my CRD and X13s. Was '163' a typo > > > or a real difference? > > > > > > > Ah yes, it is 162 indeed. Sorry, typo! > > > > > > So the current logic that checks the (163-1) S2CR entry fails to detect > > > > the quirky firmware on these devices and triggers invalid context fault > > > > for bypass streams. > > > > > > > > To fix this issue, rework the logic to find the first non-valid (free) > > > > stream mapping register group (SMR) and use that index to access S2CR > > > > for detecting the bypass quirk. > > > > > > So while this works for the quirk detection, shouldn't we also do > > > something about that bogus NUMSMRG value? At least cap it at 128, which > > > appears to be the maximum according to the specification, for example, > > > by clearing bit 7 when any of the lower bits are set? > > > > > > That would give us 35 (or 36) groups and working quirk detection with > > > just the following smaller patch: > > > > > > > I'm not certain if the value is bogus or not. It is clear that the spec > > specifies 128 as the max but internal qcom document shows that they indeed > > set 162 on purpose in the hypervisor. > > > > So until we get a clear view on that, I'd not cap it. > > But if we fault as soon as we try to do something with those register > groups above 128 that also violate the spec, it doesn't seem right to > trust the fw value here. I realised that the fault is due to the quirk not being detected properly as writes to groups above index 127 apparently succeeds (including out-of-bounds index 162): qcom_smmu_cfg_probe - index = 127, reg = 200ff, type = 02 qcom_smmu_cfg_probe - index = 128, reg = 100ff, type = 01 qcom_smmu_cfg_probe - index = 161, reg = 100ff, type = 01 qcom_smmu_cfg_probe - index = 162, reg = 100ff, type = 01 So leaving smmu->num_mapping_groups unchanged for now and using the first available group for the detection indeed seems like the right thing to do here (alternatively, never use an index above 127). But perhaps you can update to commit message to reflect this finding (i.e. that the num groups value is probably bogus, and that you at least need to use an index < 128 for quirk detection). By the way, I noticed that the number of groups is reported as 162 on the sa8295p-adp as well. > > > > This also warrants a change in variable name from last_s2cr to free_s2cr. > > > > > > > > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> > > > > --- > > > > drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 24 +++++++++++++++++----- > > > > 1 file changed, 19 insertions(+), 5 deletions(-) > > > > > > > > diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c > > > > index 78fc0e1bf215..4104f81b8d8f 100644 > > > > --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c > > > > +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c > > > > @@ -267,23 +267,37 @@ static int qcom_smmu_init_context(struct arm_smmu_domain *smmu_domain, > > > > > > > > static int qcom_smmu_cfg_probe(struct arm_smmu_device *smmu) > > > > { > > > > - unsigned int last_s2cr = ARM_SMMU_GR0_S2CR(smmu->num_mapping_groups - 1); > > > > struct qcom_smmu *qsmmu = to_qcom_smmu(smmu); > > > > + u32 free_s2cr; > > > > u32 reg; > > > > u32 smr; > > > > int i; > > > > > > > > + /* > > > > + * Find the first non-valid (free) stream mapping register group and > > > > + * use that index to access S2CR for detecting the bypass quirk. > > > > + */ > > > > + for (i = 0; i < smmu->num_mapping_groups; i++) { > > > > + smr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_SMR(i)); > > > > + > > > > + if (!FIELD_GET(ARM_SMMU_SMR_VALID, smr)) > > > > + break; > > > > + } > > > > + > > > > + free_s2cr = ARM_SMMU_GR0_S2CR(i); > > > > > > In the unlikely event that there is no free group this would access an > > > invalid index. > > > > > > > Hmm, theoretically yes. But what would be the plan of action if that happens? > > Should we just bail out with error or skip the quirk detection? > > Yes, skipping quirk detection seems preferable to crashing systems that > don't need the quirk. Perhaps you can move the quirk handling to its own function and simply return early in case there is no free group. Johan
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c index 78fc0e1bf215..4104f81b8d8f 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c @@ -267,23 +267,37 @@ static int qcom_smmu_init_context(struct arm_smmu_domain *smmu_domain, static int qcom_smmu_cfg_probe(struct arm_smmu_device *smmu) { - unsigned int last_s2cr = ARM_SMMU_GR0_S2CR(smmu->num_mapping_groups - 1); struct qcom_smmu *qsmmu = to_qcom_smmu(smmu); + u32 free_s2cr; u32 reg; u32 smr; int i; + /* + * Find the first non-valid (free) stream mapping register group and + * use that index to access S2CR for detecting the bypass quirk. + */ + for (i = 0; i < smmu->num_mapping_groups; i++) { + smr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_SMR(i)); + + if (!FIELD_GET(ARM_SMMU_SMR_VALID, smr)) + break; + } + + free_s2cr = ARM_SMMU_GR0_S2CR(i); + /* * With some firmware versions writes to S2CR of type FAULT are * ignored, and writing BYPASS will end up written as FAULT in the - * register. Perform a write to S2CR to detect if this is the case and - * if so reserve a context bank to emulate bypass streams. + * register. Perform a write to the first free S2CR to detect if + * this is the case and if so reserve a context bank to emulate + * bypass streams. */ reg = FIELD_PREP(ARM_SMMU_S2CR_TYPE, S2CR_TYPE_BYPASS) | FIELD_PREP(ARM_SMMU_S2CR_CBNDX, 0xff) | FIELD_PREP(ARM_SMMU_S2CR_PRIVCFG, S2CR_PRIVCFG_DEFAULT); - arm_smmu_gr0_write(smmu, last_s2cr, reg); - reg = arm_smmu_gr0_read(smmu, last_s2cr); + arm_smmu_gr0_write(smmu, free_s2cr, reg); + reg = arm_smmu_gr0_read(smmu, free_s2cr); if (FIELD_GET(ARM_SMMU_S2CR_TYPE, reg) != S2CR_TYPE_BYPASS) { qsmmu->bypass_quirk = true; qsmmu->bypass_cbndx = smmu->num_context_banks - 1;