From: Jason Gunthorpe <jgg@nvidia.com>
To: Michael Shavit <mshavit@google.com>
Cc: iommu@lists.linux.dev, linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, will@kernel.org,
robin.murphy@arm.com, nicolinc@nvidia.com,
jean-philippe@linaro.org
Subject: Re: [PATCH v4 6/8] iommu/arm-smmu-v3: Move CD table to arm_smmu_master
Date: Thu, 3 Aug 2023 15:47:52 -0300 [thread overview]
Message-ID: <ZMv2WJX6b2UBBelt@nvidia.com> (raw)
In-Reply-To: <CAKHBV26OsQYRCifuD0UjSf5uqcvMSK2tizjFULLv8DTdz0zD2g@mail.gmail.com>
On Fri, Aug 04, 2023 at 01:56:12AM +0800, Michael Shavit wrote:
> This patch introduces a subtle bug.
>
> Previously, the arm-smmu-v3 driver could get away with skipping the
> clearing of the CD entry on detach, since the table belonged to the
> domain and wouldn't be re-written on re-attach. When we switch to the
> master-owned table model, that CDTE in the master's table can get
> written to with different CD domains. When the CD domain get's
> switched to a new one without first being cleared, arm_smmu_write_ctx
> will mis-interpret its call as an ASID update instead of an entirely
> new Cd.
I'm not surprised, I think arm_smmu_write_ctx is a little too clever
for its own good..
I would have written it by computing the full target CD entry,
extracted directly from the domain.
Something like:
struct cd_entry {
__le64 val[4];
};
static void arm_smmu_get_domain_cd_value(struct arm_smmu_domain *domain,
struct arm_smmu_master *master,
bool quiet, struct cd_entry *entry)
{
struct arm_smmu_ctx_desc_cfg *cd_table = &master->cd_table;
struct arm_smmu_ctx_desc *cd = &domain->cd;
u64 val0;
if (!domain) {
memset(entry, 0, sizeof(*entry));
return;
}
val0 = cd->tcr |
#ifdef __BIG_ENDIAN
CTXDESC_CD_0_ENDI |
#endif
CTXDESC_CD_0_R | CTXDESC_CD_0_A |
(cd->mm ? 0 : CTXDESC_CD_0_ASET) | CTXDESC_CD_0_AA64 |
FIELD_PREP(CTXDESC_CD_0_ASID, cd->asid) | CTXDESC_CD_0_V;
if (cd_table->stall_enabled)
val0 |= CTXDESC_CD_0_S;
if (quiet)
val0 |= CTXDESC_CD_0_TCR_EPD0;
entry->val[0] = cpu_to_le64(val0);
entry->val[1] = cpu_to_le64(cd->ttbr & CTXDESC_CD_1_TTB0_MASK);
entry->val[2] = 0;
entry->val[3] = cpu_to_le64(cd->mair);
}
int arm_smmu_write_ctx_desc(struct arm_smmu_master *master, int ssid,
struct arm_smmu_ctx_desc *cd)
{
struct arm_smmu_ctx_desc_cfg *cd_table = &master->cd_table;
struct cd_entry *cur_cd;
struct cd_entry new_cd;
if (WARN_ON(ssid >= (1 << cd_table->max_cds_bits)))
return -E2BIG;
new_cd = arm_smmu_get_cd_ptr(master, ssid);
if (!new_cd)
return -ENOMEM;
arm_smmu_get_domain_cd_value(domain, master, cd == &quiet_cd, &new_cd);
/*
* The SMMU accesses 64-bit values atomically. See IHI0070Ca 3.21.3
* "Configuration structures and configuration invalidation completion"
*
* The size of single-copy atomic reads made by the SMMU is
* IMPLEMENTATION DEFINED but must be at least 64 bits. Any single
* field within an aligned 64-bit span of a structure can be altered
* without first making the structure invalid.
*/
/*
* Changing only dword 0 is common enough that we give it a fast path.
*/
if (cur_cd->val[1] != new_cd.val[1] ||
cur_cd->val[2] != new_cd.val[2] ||
cur_cd->val[3] != new_cd.val[3]) {
/* Make it invalid so we can update all 4 values */
if (le64_to_cpu(cur_cd->val[0]) & CTXDESC_CD_0_V) {
if (le64_to_cpu(new_cd.val[0]) & CTXDESC_CD_0_V)
WRITE_ONCE(cur_cd->val[0], 0);
else
WRITE_ONCE(cur_cd->val[0], new_cd.val[0]);
arm_smmu_sync_cd(master, ssid, true);
}
cur_cd->val[1] = new_cd.val[1];
cur_cd->val[2] = new_cd.val[2];
cur_cd->val[3] = new_cd.val[3];
/*
* CD entry may be live, and the SMMU might read dwords of this
* CD in any order. Ensure that it observes valid values before
* reading V=1.
*/
if (le64_to_cpu(new_cd.val[0]) & CTXDESC_CD_0_V)
arm_smmu_sync_cd(master, ssid, true);
}
if (cur_cd->val[0] == new_cd.val[0])
return 0;
WRITE_ONCE(cur_cd->val[0], new_cd.val[0]);
arm_smmu_sync_cd(master, ssid, true);
}
Jason
WARNING: multiple messages have this Message-ID (diff)
From: Jason Gunthorpe <jgg@nvidia.com>
To: Michael Shavit <mshavit@google.com>
Cc: iommu@lists.linux.dev, linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, will@kernel.org,
robin.murphy@arm.com, nicolinc@nvidia.com,
jean-philippe@linaro.org
Subject: Re: [PATCH v4 6/8] iommu/arm-smmu-v3: Move CD table to arm_smmu_master
Date: Thu, 3 Aug 2023 15:47:52 -0300 [thread overview]
Message-ID: <ZMv2WJX6b2UBBelt@nvidia.com> (raw)
In-Reply-To: <CAKHBV26OsQYRCifuD0UjSf5uqcvMSK2tizjFULLv8DTdz0zD2g@mail.gmail.com>
On Fri, Aug 04, 2023 at 01:56:12AM +0800, Michael Shavit wrote:
> This patch introduces a subtle bug.
>
> Previously, the arm-smmu-v3 driver could get away with skipping the
> clearing of the CD entry on detach, since the table belonged to the
> domain and wouldn't be re-written on re-attach. When we switch to the
> master-owned table model, that CDTE in the master's table can get
> written to with different CD domains. When the CD domain get's
> switched to a new one without first being cleared, arm_smmu_write_ctx
> will mis-interpret its call as an ASID update instead of an entirely
> new Cd.
I'm not surprised, I think arm_smmu_write_ctx is a little too clever
for its own good..
I would have written it by computing the full target CD entry,
extracted directly from the domain.
Something like:
struct cd_entry {
__le64 val[4];
};
static void arm_smmu_get_domain_cd_value(struct arm_smmu_domain *domain,
struct arm_smmu_master *master,
bool quiet, struct cd_entry *entry)
{
struct arm_smmu_ctx_desc_cfg *cd_table = &master->cd_table;
struct arm_smmu_ctx_desc *cd = &domain->cd;
u64 val0;
if (!domain) {
memset(entry, 0, sizeof(*entry));
return;
}
val0 = cd->tcr |
#ifdef __BIG_ENDIAN
CTXDESC_CD_0_ENDI |
#endif
CTXDESC_CD_0_R | CTXDESC_CD_0_A |
(cd->mm ? 0 : CTXDESC_CD_0_ASET) | CTXDESC_CD_0_AA64 |
FIELD_PREP(CTXDESC_CD_0_ASID, cd->asid) | CTXDESC_CD_0_V;
if (cd_table->stall_enabled)
val0 |= CTXDESC_CD_0_S;
if (quiet)
val0 |= CTXDESC_CD_0_TCR_EPD0;
entry->val[0] = cpu_to_le64(val0);
entry->val[1] = cpu_to_le64(cd->ttbr & CTXDESC_CD_1_TTB0_MASK);
entry->val[2] = 0;
entry->val[3] = cpu_to_le64(cd->mair);
}
int arm_smmu_write_ctx_desc(struct arm_smmu_master *master, int ssid,
struct arm_smmu_ctx_desc *cd)
{
struct arm_smmu_ctx_desc_cfg *cd_table = &master->cd_table;
struct cd_entry *cur_cd;
struct cd_entry new_cd;
if (WARN_ON(ssid >= (1 << cd_table->max_cds_bits)))
return -E2BIG;
new_cd = arm_smmu_get_cd_ptr(master, ssid);
if (!new_cd)
return -ENOMEM;
arm_smmu_get_domain_cd_value(domain, master, cd == &quiet_cd, &new_cd);
/*
* The SMMU accesses 64-bit values atomically. See IHI0070Ca 3.21.3
* "Configuration structures and configuration invalidation completion"
*
* The size of single-copy atomic reads made by the SMMU is
* IMPLEMENTATION DEFINED but must be at least 64 bits. Any single
* field within an aligned 64-bit span of a structure can be altered
* without first making the structure invalid.
*/
/*
* Changing only dword 0 is common enough that we give it a fast path.
*/
if (cur_cd->val[1] != new_cd.val[1] ||
cur_cd->val[2] != new_cd.val[2] ||
cur_cd->val[3] != new_cd.val[3]) {
/* Make it invalid so we can update all 4 values */
if (le64_to_cpu(cur_cd->val[0]) & CTXDESC_CD_0_V) {
if (le64_to_cpu(new_cd.val[0]) & CTXDESC_CD_0_V)
WRITE_ONCE(cur_cd->val[0], 0);
else
WRITE_ONCE(cur_cd->val[0], new_cd.val[0]);
arm_smmu_sync_cd(master, ssid, true);
}
cur_cd->val[1] = new_cd.val[1];
cur_cd->val[2] = new_cd.val[2];
cur_cd->val[3] = new_cd.val[3];
/*
* CD entry may be live, and the SMMU might read dwords of this
* CD in any order. Ensure that it observes valid values before
* reading V=1.
*/
if (le64_to_cpu(new_cd.val[0]) & CTXDESC_CD_0_V)
arm_smmu_sync_cd(master, ssid, true);
}
if (cur_cd->val[0] == new_cd.val[0])
return 0;
WRITE_ONCE(cur_cd->val[0], new_cd.val[0]);
arm_smmu_sync_cd(master, ssid, true);
}
Jason
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
next prev parent reply other threads:[~2023-08-03 18:47 UTC|newest]
Thread overview: 52+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-08-02 16:32 [PATCH v4 0/8] Refactor the SMMU's CD table ownership Michael Shavit
2023-08-02 16:32 ` Michael Shavit
2023-08-02 16:32 ` [PATCH v4 1/8] iommu/arm-smmu-v3: Move ctx_desc out of s1_cfg Michael Shavit
2023-08-02 16:32 ` Michael Shavit
2023-08-04 19:19 ` Nicolin Chen
2023-08-04 19:19 ` Nicolin Chen
2023-08-02 16:32 ` [PATCH v4 2/8] iommu/arm-smmu-v3: Replace s1_cfg with cdtab_cfg Michael Shavit
2023-08-02 16:32 ` Michael Shavit
2023-08-04 19:25 ` Nicolin Chen
2023-08-04 19:25 ` Nicolin Chen
2023-08-02 16:32 ` [PATCH v4 3/8] iommu/arm-smmu-v3: Encapsulate ctx_desc_cfg init in alloc_cd_tables Michael Shavit
2023-08-02 16:32 ` Michael Shavit
2023-08-04 19:27 ` Nicolin Chen
2023-08-04 19:27 ` Nicolin Chen
2023-08-02 16:32 ` [PATCH v4 4/8] iommu/arm-smmu-v3: move stall_enabled to the cd table Michael Shavit
2023-08-02 16:32 ` Michael Shavit
2023-08-04 23:32 ` Nicolin Chen
2023-08-04 23:32 ` Nicolin Chen
2023-08-07 12:21 ` Michael Shavit
2023-08-07 12:21 ` Michael Shavit
2023-08-02 16:32 ` [PATCH v4 5/8] iommu/arm-smmu-v3: Refactor write_ctx_desc Michael Shavit
2023-08-02 16:32 ` Michael Shavit
2023-08-04 20:22 ` Nicolin Chen
2023-08-04 20:22 ` Nicolin Chen
2023-08-07 12:26 ` Michael Shavit
2023-08-07 12:26 ` Michael Shavit
2023-08-02 16:32 ` [PATCH v4 6/8] iommu/arm-smmu-v3: Move CD table to arm_smmu_master Michael Shavit
2023-08-02 16:32 ` Michael Shavit
2023-08-03 17:56 ` Michael Shavit
2023-08-03 17:56 ` Michael Shavit
2023-08-03 18:47 ` Jason Gunthorpe [this message]
2023-08-03 18:47 ` Jason Gunthorpe
2023-08-07 12:19 ` Michael Shavit
2023-08-07 12:19 ` Michael Shavit
2023-08-07 22:41 ` Jason Gunthorpe
2023-08-07 22:41 ` Jason Gunthorpe
2023-08-04 22:25 ` Nicolin Chen
2023-08-04 22:25 ` Nicolin Chen
2023-08-04 22:46 ` Jason Gunthorpe
2023-08-04 22:46 ` Jason Gunthorpe
2023-08-04 23:11 ` Nicolin Chen
2023-08-04 23:11 ` Nicolin Chen
2023-08-02 16:32 ` [PATCH v4 7/8] iommu/arm-smmu-v3: Skip cd sync if CD table isn't active Michael Shavit
2023-08-02 16:32 ` Michael Shavit
2023-08-04 19:59 ` Nicolin Chen
2023-08-04 19:59 ` Nicolin Chen
2023-08-07 15:02 ` Michael Shavit
2023-08-07 15:02 ` Michael Shavit
2023-08-02 16:32 ` [PATCH v4 8/8] iommu/arm-smmu-v3: Rename cdcfg to cd_table Michael Shavit
2023-08-02 16:32 ` Michael Shavit
2023-08-04 19:31 ` Nicolin Chen
2023-08-04 19:31 ` Nicolin Chen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ZMv2WJX6b2UBBelt@nvidia.com \
--to=jgg@nvidia.com \
--cc=iommu@lists.linux.dev \
--cc=jean-philippe@linaro.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mshavit@google.com \
--cc=nicolinc@nvidia.com \
--cc=robin.murphy@arm.com \
--cc=will@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.