mirror of
https://github.com/torvalds/linux.git
synced 2026-05-31 02:24:24 +02:00
iommu/arm-smmu-v3: Introduce struct arm_smmu_vmaster
Use it to store all vSMMU-related data. The vsid (Virtual Stream ID) will be the first use case. Since the vsid reader will be the eventq handler that already holds a streams_mutex, reuse that to fence the vmaster too. Also add a pair of arm_smmu_attach_prepare/commit_vmaster helpers to set or unset the master->vmaster pointer. Put the helpers inside the existing arm_smmu_attach_prepare/commit(). For identity/blocked ops that don't call arm_smmu_attach_prepare/commit(), add a simpler arm_smmu_master_clear_vmaster helper to unset the vmaster. Link: https://patch.msgid.link/r/a7f282e1a531279e25f06c651e95d56f6b120886.1741719725.git.nicolinc@nvidia.com Reviewed-by: Jason Gunthorpe <jgg@nvidia.com> Reviewed-by: Pranjal Shrivastava <praan@google.com> Acked-by: Will Deacon <will@kernel.org> Signed-off-by: Nicolin Chen <nicolinc@nvidia.com> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
This commit is contained in:
parent
2ec0458eb0
commit
f0ea207ed7
|
|
@ -85,6 +85,47 @@ static void arm_smmu_make_nested_domain_ste(
|
|||
}
|
||||
}
|
||||
|
||||
int arm_smmu_attach_prepare_vmaster(struct arm_smmu_attach_state *state,
|
||||
struct arm_smmu_nested_domain *nested_domain)
|
||||
{
|
||||
struct arm_smmu_vmaster *vmaster;
|
||||
unsigned long vsid;
|
||||
int ret;
|
||||
|
||||
iommu_group_mutex_assert(state->master->dev);
|
||||
|
||||
ret = iommufd_viommu_get_vdev_id(&nested_domain->vsmmu->core,
|
||||
state->master->dev, &vsid);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
vmaster = kzalloc(sizeof(*vmaster), GFP_KERNEL);
|
||||
if (!vmaster)
|
||||
return -ENOMEM;
|
||||
vmaster->vsmmu = nested_domain->vsmmu;
|
||||
vmaster->vsid = vsid;
|
||||
state->vmaster = vmaster;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void arm_smmu_attach_commit_vmaster(struct arm_smmu_attach_state *state)
|
||||
{
|
||||
struct arm_smmu_master *master = state->master;
|
||||
|
||||
mutex_lock(&master->smmu->streams_mutex);
|
||||
kfree(master->vmaster);
|
||||
master->vmaster = state->vmaster;
|
||||
mutex_unlock(&master->smmu->streams_mutex);
|
||||
}
|
||||
|
||||
void arm_smmu_master_clear_vmaster(struct arm_smmu_master *master)
|
||||
{
|
||||
struct arm_smmu_attach_state state = { .master = master };
|
||||
|
||||
arm_smmu_attach_commit_vmaster(&state);
|
||||
}
|
||||
|
||||
static int arm_smmu_attach_dev_nested(struct iommu_domain *domain,
|
||||
struct device *dev)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2803,6 +2803,7 @@ int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state,
|
|||
struct arm_smmu_domain *smmu_domain =
|
||||
to_smmu_domain_devices(new_domain);
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* arm_smmu_share_asid() must not see two domains pointing to the same
|
||||
|
|
@ -2832,9 +2833,18 @@ int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state,
|
|||
}
|
||||
|
||||
if (smmu_domain) {
|
||||
if (new_domain->type == IOMMU_DOMAIN_NESTED) {
|
||||
ret = arm_smmu_attach_prepare_vmaster(
|
||||
state, to_smmu_nested_domain(new_domain));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
master_domain = kzalloc(sizeof(*master_domain), GFP_KERNEL);
|
||||
if (!master_domain)
|
||||
if (!master_domain) {
|
||||
kfree(state->vmaster);
|
||||
return -ENOMEM;
|
||||
}
|
||||
master_domain->master = master;
|
||||
master_domain->ssid = state->ssid;
|
||||
if (new_domain->type == IOMMU_DOMAIN_NESTED)
|
||||
|
|
@ -2861,6 +2871,7 @@ int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state,
|
|||
spin_unlock_irqrestore(&smmu_domain->devices_lock,
|
||||
flags);
|
||||
kfree(master_domain);
|
||||
kfree(state->vmaster);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -2893,6 +2904,8 @@ void arm_smmu_attach_commit(struct arm_smmu_attach_state *state)
|
|||
|
||||
lockdep_assert_held(&arm_smmu_asid_lock);
|
||||
|
||||
arm_smmu_attach_commit_vmaster(state);
|
||||
|
||||
if (state->ats_enabled && !master->ats_enabled) {
|
||||
arm_smmu_enable_ats(master);
|
||||
} else if (state->ats_enabled && master->ats_enabled) {
|
||||
|
|
@ -3162,6 +3175,7 @@ static int arm_smmu_attach_dev_identity(struct iommu_domain *domain,
|
|||
struct arm_smmu_ste ste;
|
||||
struct arm_smmu_master *master = dev_iommu_priv_get(dev);
|
||||
|
||||
arm_smmu_master_clear_vmaster(master);
|
||||
arm_smmu_make_bypass_ste(master->smmu, &ste);
|
||||
arm_smmu_attach_dev_ste(domain, dev, &ste, STRTAB_STE_1_S1DSS_BYPASS);
|
||||
return 0;
|
||||
|
|
@ -3180,7 +3194,9 @@ static int arm_smmu_attach_dev_blocked(struct iommu_domain *domain,
|
|||
struct device *dev)
|
||||
{
|
||||
struct arm_smmu_ste ste;
|
||||
struct arm_smmu_master *master = dev_iommu_priv_get(dev);
|
||||
|
||||
arm_smmu_master_clear_vmaster(master);
|
||||
arm_smmu_make_abort_ste(&ste);
|
||||
arm_smmu_attach_dev_ste(domain, dev, &ste,
|
||||
STRTAB_STE_1_S1DSS_TERMINATE);
|
||||
|
|
|
|||
|
|
@ -799,6 +799,11 @@ struct arm_smmu_stream {
|
|||
struct rb_node node;
|
||||
};
|
||||
|
||||
struct arm_smmu_vmaster {
|
||||
struct arm_vsmmu *vsmmu;
|
||||
unsigned long vsid;
|
||||
};
|
||||
|
||||
struct arm_smmu_event {
|
||||
u8 stall : 1,
|
||||
ssv : 1,
|
||||
|
|
@ -824,6 +829,7 @@ struct arm_smmu_master {
|
|||
struct arm_smmu_device *smmu;
|
||||
struct device *dev;
|
||||
struct arm_smmu_stream *streams;
|
||||
struct arm_smmu_vmaster *vmaster; /* use smmu->streams_mutex */
|
||||
/* Locked by the iommu core using the group mutex */
|
||||
struct arm_smmu_ctx_desc_cfg cd_table;
|
||||
unsigned int num_streams;
|
||||
|
|
@ -972,6 +978,7 @@ struct arm_smmu_attach_state {
|
|||
bool disable_ats;
|
||||
ioasid_t ssid;
|
||||
/* Resulting state */
|
||||
struct arm_smmu_vmaster *vmaster;
|
||||
bool ats_enabled;
|
||||
};
|
||||
|
||||
|
|
@ -1055,9 +1062,30 @@ struct iommufd_viommu *arm_vsmmu_alloc(struct device *dev,
|
|||
struct iommu_domain *parent,
|
||||
struct iommufd_ctx *ictx,
|
||||
unsigned int viommu_type);
|
||||
int arm_smmu_attach_prepare_vmaster(struct arm_smmu_attach_state *state,
|
||||
struct arm_smmu_nested_domain *nested_domain);
|
||||
void arm_smmu_attach_commit_vmaster(struct arm_smmu_attach_state *state);
|
||||
void arm_smmu_master_clear_vmaster(struct arm_smmu_master *master);
|
||||
#else
|
||||
#define arm_smmu_hw_info NULL
|
||||
#define arm_vsmmu_alloc NULL
|
||||
|
||||
static inline int
|
||||
arm_smmu_attach_prepare_vmaster(struct arm_smmu_attach_state *state,
|
||||
struct arm_smmu_nested_domain *nested_domain)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
arm_smmu_attach_commit_vmaster(struct arm_smmu_attach_state *state)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void
|
||||
arm_smmu_master_clear_vmaster(struct arm_smmu_master *master)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_ARM_SMMU_V3_IOMMUFD */
|
||||
|
||||
#endif /* _ARM_SMMU_V3_H */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user