* [PATCH 1/3] iommu/arm-smmu: Don't blindly use first SMR to calculate mask
2019-12-26 22:17 [PATCH 0/3] iommu/arm-smmu: Qualcomm bootsplash/efifb Bjorn Andersson
@ 2019-12-26 22:17 ` Bjorn Andersson
2019-12-26 22:17 ` [PATCH 2/3] iommu/arm-smmu: Expose s2cr and smr structs to impl Bjorn Andersson
` (2 subsequent siblings)
3 siblings, 0 replies; 7+ messages in thread
From: Bjorn Andersson @ 2019-12-26 22:17 UTC (permalink / raw)
To: Will Deacon, Robin Murphy, Joerg Roedel
Cc: linux-arm-kernel, iommu, linux-kernel, linux-arm-msm,
Patrick Daly, Pratik Patel, Rob Clark
With the SMRs inherited from the bootloader the first SMR might actually
be valid and in use. As such probing the SMR mask using the first SMR
might break a stream in use. Search for an unused stream and use this to
probe the SMR mask.
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
Changes since RFC:
- Deal with EXIDS
- Use arm_smmu_gr0_read/write()
drivers/iommu/arm-smmu.c | 27 +++++++++++++++++++++++----
1 file changed, 23 insertions(+), 4 deletions(-)
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 4f1a350d9529..6ca6a4e072c8 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -945,24 +945,43 @@ static void arm_smmu_write_sme(struct arm_smmu_device *smmu, int idx)
*/
static void arm_smmu_test_smr_masks(struct arm_smmu_device *smmu)
{
+ u32 s2cr;
u32 smr;
+ int idx;
if (!smmu->smrs)
return;
+ for (idx = 0; idx < smmu->num_mapping_groups; idx++) {
+ if (smmu->features & ARM_SMMU_FEAT_EXIDS) {
+ s2cr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_S2CR(idx));
+ if (!FIELD_GET(S2CR_EXIDVALID, s2cr))
+ break;
+ } else {
+ smr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_SMR(idx));
+ if (!FIELD_GET(SMR_VALID, smr))
+ break;
+ }
+ }
+
+ if (idx == smmu->num_mapping_groups) {
+ dev_err(smmu->dev, "Unable to compute streamid_mask\n");
+ return;
+ }
+
/*
* SMR.ID bits may not be preserved if the corresponding MASK
* bits are set, so check each one separately. We can reject
* masters later if they try to claim IDs outside these masks.
*/
smr = FIELD_PREP(SMR_ID, smmu->streamid_mask);
- arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_SMR(0), smr);
- smr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_SMR(0));
+ arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_SMR(idx), smr);
+ smr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_SMR(idx));
smmu->streamid_mask = FIELD_GET(SMR_ID, smr);
smr = FIELD_PREP(SMR_MASK, smmu->streamid_mask);
- arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_SMR(0), smr);
- smr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_SMR(0));
+ arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_SMR(idx), smr);
+ smr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_SMR(idx));
smmu->smr_mask_mask = FIELD_GET(SMR_MASK, smr);
}
--
2.24.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 2/3] iommu/arm-smmu: Expose s2cr and smr structs to impl
2019-12-26 22:17 [PATCH 0/3] iommu/arm-smmu: Qualcomm bootsplash/efifb Bjorn Andersson
2019-12-26 22:17 ` [PATCH 1/3] iommu/arm-smmu: Don't blindly use first SMR to calculate mask Bjorn Andersson
@ 2019-12-26 22:17 ` Bjorn Andersson
2019-12-26 22:17 ` [PATCH 3/3] iommu/arm-smmu: Allow inherting stream mapping from bootloader Bjorn Andersson
2020-01-08 9:16 ` [PATCH 0/3] iommu/arm-smmu: Qualcomm bootsplash/efifb Will Deacon
3 siblings, 0 replies; 7+ messages in thread
From: Bjorn Andersson @ 2019-12-26 22:17 UTC (permalink / raw)
To: Will Deacon, Robin Murphy, Joerg Roedel
Cc: linux-arm-kernel, iommu, linux-kernel, linux-arm-msm,
Patrick Daly, Pratik Patel, Rob Clark
Move the arm_smmu_s2cr and arm_smmu_smr structs to the internal header
file, in order to expose them to the platform specific arm-smmu
implementations.
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
Changes since RFC:
- New patch
drivers/iommu/arm-smmu.c | 14 --------------
drivers/iommu/arm-smmu.h | 14 ++++++++++++++
2 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 6ca6a4e072c8..9a9091b9dcc7 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -73,24 +73,10 @@ module_param(disable_bypass, bool, S_IRUGO);
MODULE_PARM_DESC(disable_bypass,
"Disable bypass streams such that incoming transactions from devices that are not attached to an iommu domain will report an abort back to the device and will not be allowed to pass through the SMMU.");
-struct arm_smmu_s2cr {
- struct iommu_group *group;
- int count;
- enum arm_smmu_s2cr_type type;
- enum arm_smmu_s2cr_privcfg privcfg;
- u8 cbndx;
-};
-
#define s2cr_init_val (struct arm_smmu_s2cr){ \
.type = disable_bypass ? S2CR_TYPE_FAULT : S2CR_TYPE_BYPASS, \
}
-struct arm_smmu_smr {
- u16 mask;
- u16 id;
- bool valid;
-};
-
struct arm_smmu_cb {
u64 ttbr[2];
u32 tcr[2];
diff --git a/drivers/iommu/arm-smmu.h b/drivers/iommu/arm-smmu.h
index 62b9f0cec49b..73f94579b926 100644
--- a/drivers/iommu/arm-smmu.h
+++ b/drivers/iommu/arm-smmu.h
@@ -224,6 +224,20 @@ enum arm_smmu_implementation {
QCOM_SMMUV2,
};
+struct arm_smmu_s2cr {
+ struct iommu_group *group;
+ int count;
+ enum arm_smmu_s2cr_type type;
+ enum arm_smmu_s2cr_privcfg privcfg;
+ u8 cbndx;
+};
+
+struct arm_smmu_smr {
+ u16 mask;
+ u16 id;
+ bool valid;
+};
+
struct arm_smmu_device {
struct device *dev;
--
2.24.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 3/3] iommu/arm-smmu: Allow inherting stream mapping from bootloader
2019-12-26 22:17 [PATCH 0/3] iommu/arm-smmu: Qualcomm bootsplash/efifb Bjorn Andersson
2019-12-26 22:17 ` [PATCH 1/3] iommu/arm-smmu: Don't blindly use first SMR to calculate mask Bjorn Andersson
2019-12-26 22:17 ` [PATCH 2/3] iommu/arm-smmu: Expose s2cr and smr structs to impl Bjorn Andersson
@ 2019-12-26 22:17 ` Bjorn Andersson
2020-01-08 9:16 ` [PATCH 0/3] iommu/arm-smmu: Qualcomm bootsplash/efifb Will Deacon
3 siblings, 0 replies; 7+ messages in thread
From: Bjorn Andersson @ 2019-12-26 22:17 UTC (permalink / raw)
To: Will Deacon, Robin Murphy, Joerg Roedel
Cc: linux-arm-kernel, iommu, linux-kernel, linux-arm-msm,
Patrick Daly, Pratik Patel, Rob Clark
The Qualcomm bootloaders leaves the IOMMU with stream mapping for
the display hardware to be able to read the framebuffer memory in DDR,
to continuously display a boot splash or to implement EFI framebuffer.
This patch implements support for implementations to pin stream mappings
and adds the code to the Qualcomm implementation for reading out the
stream mapping from the bootloader, with the result of maintaining the
display hardware's access to DDR until the context bank is enabled.
Heavily based on downstream implementation by Patrick Daly
<pdaly@codeaurora.org>.
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
Changes since RFC:
- Deal with EXIDS
- The onetime handoff has been replaced with a "pinned" state, to deal with
probe deferring in the display driver
- Reads back s2cr for all groups, not only the "valid" ones
drivers/iommu/arm-smmu-qcom.c | 35 +++++++++++++++++++++++++++++++++++
drivers/iommu/arm-smmu.c | 29 +++++++++++++++++++++++------
drivers/iommu/arm-smmu.h | 1 +
3 files changed, 59 insertions(+), 6 deletions(-)
diff --git a/drivers/iommu/arm-smmu-qcom.c b/drivers/iommu/arm-smmu-qcom.c
index 24c071c1d8b0..06e5799dcb87 100644
--- a/drivers/iommu/arm-smmu-qcom.c
+++ b/drivers/iommu/arm-smmu-qcom.c
@@ -3,6 +3,7 @@
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
*/
+#include <linux/bitfield.h>
#include <linux/qcom_scm.h>
#include "arm-smmu.h"
@@ -11,6 +12,39 @@ struct qcom_smmu {
struct arm_smmu_device smmu;
};
+static int qcom_sdm845_smmu500_cfg_probe(struct arm_smmu_device *smmu)
+{
+ u32 s2cr;
+ u32 smr;
+ int i;
+
+ for (i = 0; i < smmu->num_mapping_groups; i++) {
+ smr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_SMR(i));
+ s2cr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_S2CR(i));
+
+ smmu->smrs[i].mask = FIELD_GET(SMR_MASK, smr);
+ smmu->smrs[i].id = FIELD_GET(SMR_ID, smr);
+ if (smmu->features & ARM_SMMU_FEAT_EXIDS)
+ smmu->smrs[i].valid = FIELD_GET(S2CR_EXIDVALID, s2cr);
+ else
+ smmu->smrs[i].valid = FIELD_GET(SMR_VALID, smr);
+
+ smmu->s2crs[i].group = NULL;
+ smmu->s2crs[i].count = 0;
+ smmu->s2crs[i].type = FIELD_GET(S2CR_TYPE, s2cr);
+ smmu->s2crs[i].privcfg = FIELD_GET(S2CR_PRIVCFG, s2cr);
+ smmu->s2crs[i].cbndx = FIELD_GET(S2CR_CBNDX, s2cr);
+
+ if (!smmu->smrs[i].valid)
+ continue;
+
+ smmu->s2crs[i].pinned = true;
+ bitmap_set(smmu->context_map, smmu->s2crs[i].cbndx, 1);
+ }
+
+ return 0;
+}
+
static int qcom_sdm845_smmu500_reset(struct arm_smmu_device *smmu)
{
int ret;
@@ -31,6 +65,7 @@ static int qcom_sdm845_smmu500_reset(struct arm_smmu_device *smmu)
}
static const struct arm_smmu_impl qcom_smmu_impl = {
+ .cfg_probe = qcom_sdm845_smmu500_cfg_probe,
.reset = qcom_sdm845_smmu500_reset,
};
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 9a9091b9dcc7..01f22eff2ec5 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -206,9 +206,19 @@ static int arm_smmu_register_legacy_master(struct device *dev,
return err;
}
-static int __arm_smmu_alloc_bitmap(unsigned long *map, int start, int end)
+static int __arm_smmu_alloc_cb(struct arm_smmu_device *smmu, int start,
+ struct device *dev)
{
+ struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+ unsigned long *map = smmu->context_map;
+ int end = smmu->num_context_banks;
int idx;
+ int i;
+
+ for_each_cfg_sme(fwspec, i, idx) {
+ if (smmu->s2crs[idx].pinned)
+ return smmu->s2crs[idx].cbndx;
+ }
do {
idx = find_next_zero_bit(map, end, start);
@@ -628,7 +638,8 @@ static void arm_smmu_write_context_bank(struct arm_smmu_device *smmu, int idx)
}
static int arm_smmu_init_domain_context(struct iommu_domain *domain,
- struct arm_smmu_device *smmu)
+ struct arm_smmu_device *smmu,
+ struct device *dev)
{
int irq, start, ret = 0;
unsigned long ias, oas;
@@ -742,8 +753,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
ret = -EINVAL;
goto out_unlock;
}
- ret = __arm_smmu_alloc_bitmap(smmu->context_map, start,
- smmu->num_context_banks);
+ ret = __arm_smmu_alloc_cb(smmu, start, dev);
if (ret < 0)
goto out_unlock;
@@ -1015,12 +1025,19 @@ static int arm_smmu_find_sme(struct arm_smmu_device *smmu, u16 id, u16 mask)
static bool arm_smmu_free_sme(struct arm_smmu_device *smmu, int idx)
{
+ bool pinned = smmu->s2crs[idx].pinned;
+ u8 cbndx = smmu->s2crs[idx].cbndx;;
+
if (--smmu->s2crs[idx].count)
return false;
smmu->s2crs[idx] = s2cr_init_val;
- if (smmu->smrs)
+ if (pinned) {
+ smmu->s2crs[idx].pinned = true;
+ smmu->s2crs[idx].cbndx = cbndx;
+ } else if (smmu->smrs) {
smmu->smrs[idx].valid = false;
+ }
return true;
}
@@ -1154,7 +1171,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
return ret;
/* Ensure that the domain is finalised */
- ret = arm_smmu_init_domain_context(domain, smmu);
+ ret = arm_smmu_init_domain_context(domain, smmu, dev);
if (ret < 0)
goto rpm_put;
diff --git a/drivers/iommu/arm-smmu.h b/drivers/iommu/arm-smmu.h
index 73f94579b926..0701e6875964 100644
--- a/drivers/iommu/arm-smmu.h
+++ b/drivers/iommu/arm-smmu.h
@@ -230,6 +230,7 @@ struct arm_smmu_s2cr {
enum arm_smmu_s2cr_type type;
enum arm_smmu_s2cr_privcfg privcfg;
u8 cbndx;
+ bool pinned;
};
struct arm_smmu_smr {
--
2.24.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 0/3] iommu/arm-smmu: Qualcomm bootsplash/efifb
2019-12-26 22:17 [PATCH 0/3] iommu/arm-smmu: Qualcomm bootsplash/efifb Bjorn Andersson
` (2 preceding siblings ...)
2019-12-26 22:17 ` [PATCH 3/3] iommu/arm-smmu: Allow inherting stream mapping from bootloader Bjorn Andersson
@ 2020-01-08 9:16 ` Will Deacon
[not found] ` <CAF2Aj3iKk2LSA5XC76pNiLV8a76BkibUitof-dix8rqkc0qiow@mail.gmail.com>
3 siblings, 1 reply; 7+ messages in thread
From: Will Deacon @ 2020-01-08 9:16 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Robin Murphy, Joerg Roedel, linux-arm-kernel, iommu,
linux-kernel, linux-arm-msm, Patrick Daly, Pratik Patel,
Rob Clark, treding
On Thu, Dec 26, 2019 at 02:17:06PM -0800, Bjorn Andersson wrote:
> These patches implements the stream mapping inheritance that's necessary in
> order to not hit a security violation as the display hardware looses its stream
> mapping during initialization of arm-smmu in various Qualcomm platforms.
>
> This was previously posted as an RFC [1], changes since then involves the
> rebase and migration of the read-back code to the Qualcomm specific
> implementation, the mapping is maintained indefinitely - to handle probe
> deferring clients - and rewritten commit messages.
I don't think we should solve this in a Qualcomm-specific manner. Please can
you take a look at the proposal from Thierry [1] and see whether or not it
works for you?
Thanks,
Will
[1] https://lore.kernel.org/lkml/20191209150748.2471814-1-thierry.reding@gmail.com
^ permalink raw reply [flat|nested] 7+ messages in thread