Devices that use Intel ENQCMD to submit work must use global PASIDs in
that the PASID are stored in a per CPU MSR. When such device need to
submit work for in-kernel DMA with PASID, it must allocate PASIDs from
the same global number space to avoid conflict.
This patch introduces IOMMU SVA APIs to reserve and release global PASIDs.
It is expected that device drivers will use the allocated PASIDs to attach
to appropriate IOMMU domains for use.
Signed-off-by: Jacob Pan <jacob.jun.pan@linux.intel.com>
---
drivers/iommu/iommu-sva.c | 33 +++++++++++++++++++++++++++++++++
include/linux/iommu.h | 14 ++++++++++++++
2 files changed, 47 insertions(+)
diff --git a/drivers/iommu/iommu-sva.c b/drivers/iommu/iommu-sva.c
index c434b95dc8eb..84b9de84b3e0 100644
--- a/drivers/iommu/iommu-sva.c
+++ b/drivers/iommu/iommu-sva.c
@@ -148,6 +148,39 @@ u32 iommu_sva_get_pasid(struct iommu_sva *handle)
}
EXPORT_SYMBOL_GPL(iommu_sva_get_pasid);
+/**
+ * @brief
+ * Reserve a PASID from the SVA global number space.
+ *
+ * @param min starting range, inclusive
+ * @param max ending range, inclusive
+ * @return The reserved PASID on success or IOMMU_PASID_INVALID on failure.
+ */
+ioasid_t iommu_sva_reserve_pasid(ioasid_t min, ioasid_t max)
+{
+ int ret;
+
+ if (!pasid_valid(min) || !pasid_valid(max) ||
+ min == 0 || max < min)
+ return IOMMU_PASID_INVALID;
+
+ ret = ida_alloc_range(&iommu_global_pasid_ida, min, max, GFP_KERNEL);
+ if (ret < 0)
+ return IOMMU_PASID_INVALID;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(iommu_sva_reserve_pasid);
+
+void iommu_sva_release_pasid(ioasid_t pasid)
+{
+ if (!pasid_valid(pasid))
+ return;
+
+ ida_free(&iommu_global_pasid_ida, pasid);
+}
+EXPORT_SYMBOL_GPL(iommu_sva_release_pasid);
+
/*
* I/O page fault handler for SVA
*/
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 54f535ff9868..0471089dc1d0 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -1187,6 +1187,9 @@ struct iommu_sva *iommu_sva_bind_device(struct device *dev,
struct mm_struct *mm);
void iommu_sva_unbind_device(struct iommu_sva *handle);
u32 iommu_sva_get_pasid(struct iommu_sva *handle);
+ioasid_t iommu_sva_reserve_pasid(ioasid_t min, ioasid_t max);
+void iommu_sva_release_pasid(ioasid_t pasid);
+
#else
static inline struct iommu_sva *
iommu_sva_bind_device(struct device *dev, struct mm_struct *mm)
@@ -1202,6 +1205,17 @@ static inline u32 iommu_sva_get_pasid(struct iommu_sva *handle)
{
return IOMMU_PASID_INVALID;
}
+
+static inline ioasid_t iommu_sva_reserve_pasid(ioasid_t min, ioasid_t max)
+{
+ return IOMMU_PASID_INVALID;
+}
+
+static inline void iommu_sva_release_pasid(ioasid_t pasid)
+{
+
+}
+
static inline void mm_pasid_init(struct mm_struct *mm) {}
static inline void mm_pasid_drop(struct mm_struct *mm) {}
#endif /* CONFIG_IOMMU_SVA */
--
2.25.1
> From: Jacob Pan <jacob.jun.pan@linux.intel.com>
> Sent: Tuesday, March 28, 2023 7:22 AM
>
> +/**
> + * @brief
> + * Reserve a PASID from the SVA global number space.
> + *
> + * @param min starting range, inclusive
> + * @param max ending range, inclusive
> + * @return The reserved PASID on success or IOMMU_PASID_INVALID on
> failure.
> + */
> +ioasid_t iommu_sva_reserve_pasid(ioasid_t min, ioasid_t max)
> +{
> + int ret;
> +
> + if (!pasid_valid(min) || !pasid_valid(max) ||
> + min == 0 || max < min)
> + return IOMMU_PASID_INVALID;
> +
> + ret = ida_alloc_range(&iommu_global_pasid_ida, min, max,
> GFP_KERNEL);
> + if (ret < 0)
> + return IOMMU_PASID_INVALID;
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(iommu_sva_reserve_pasid);
> +
Look at this function. There is no single word about sva except
in the function name.
sva is just one user of global pasids.
when a driver supports sva it has to always use global pasids even
for non-sva usages like dma pasid.
but this doesn't mean that we should build the API around sva.
it's really about global pasids.
let's just call it clearly as iommu_alloc_global_pasid(min, max).
Then we can define a wrapper iommu_reserve_global_pasid(pasid)
as iommu_alloc_global_pasid(pasid, pasid).
for PASID#0 driver calls iommu_reserve_global_pasid(0).
for dma pasid driver calls iommu_alloc_global_pasid() to get a random
one instead of reserving pasid#1.
this would be future proof when the same driver starts to allocate
more pasids for other usages e..g siov.
Hi Kevin,
On Tue, 28 Mar 2023 07:35:43 +0000, "Tian, Kevin" <kevin.tian@intel.com>
wrote:
> > From: Jacob Pan <jacob.jun.pan@linux.intel.com>
> > Sent: Tuesday, March 28, 2023 7:22 AM
> >
> > +/**
> > + * @brief
> > + * Reserve a PASID from the SVA global number space.
> > + *
> > + * @param min starting range, inclusive
> > + * @param max ending range, inclusive
> > + * @return The reserved PASID on success or IOMMU_PASID_INVALID on
> > failure.
> > + */
> > +ioasid_t iommu_sva_reserve_pasid(ioasid_t min, ioasid_t max)
> > +{
> > + int ret;
> > +
> > + if (!pasid_valid(min) || !pasid_valid(max) ||
> > + min == 0 || max < min)
> > + return IOMMU_PASID_INVALID;
> > +
> > + ret = ida_alloc_range(&iommu_global_pasid_ida, min, max,
> > GFP_KERNEL);
> > + if (ret < 0)
> > + return IOMMU_PASID_INVALID;
> > +
> > + return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(iommu_sva_reserve_pasid);
> > +
>
> Look at this function. There is no single word about sva except
> in the function name.
>
> sva is just one user of global pasids.
>
> when a driver supports sva it has to always use global pasids even
> for non-sva usages like dma pasid.
>
> but this doesn't mean that we should build the API around sva.
>
> it's really about global pasids.
>
> let's just call it clearly as iommu_alloc_global_pasid(min, max).
>
> Then we can define a wrapper iommu_reserve_global_pasid(pasid)
> as iommu_alloc_global_pasid(pasid, pasid).
>
> for PASID#0 driver calls iommu_reserve_global_pasid(0).
>
> for dma pasid driver calls iommu_alloc_global_pasid() to get a random
> one instead of reserving pasid#1.
>
> this would be future proof when the same driver starts to allocate
> more pasids for other usages e..g siov.
I don't have strong preference here. Jason and others?
For the DMA vs. SVA use cases, these APIs are used to carve out PASIDs from
the SVA space. Let it be the entire global space or a subset, we don't care.
We just don't want conflicts with SVA. e.g. if the SVA space shrank in the
future, this still works.
Thanks,
Jacob
On Tue, Mar 28, 2023 at 08:31:10AM -0700, Jacob Pan wrote: > > this would be future proof when the same driver starts to allocate > > more pasids for other usages e..g siov. > I don't have strong preference here. Jason and others? Oh I'm all for getting the word SVA out of the PASID infrastructure. SVA has nothing to do with PASID other than it requires it to work. Jason
Hi Jason, On Tue, 28 Mar 2023 12:55:40 -0300, Jason Gunthorpe <jgg@nvidia.com> wrote: > On Tue, Mar 28, 2023 at 08:31:10AM -0700, Jacob Pan wrote: > > > > this would be future proof when the same driver starts to allocate > > > more pasids for other usages e..g siov. > > I don't have strong preference here. Jason and others? > > Oh I'm all for getting the word SVA out of the PASID infrastructure. > > SVA has nothing to do with PASID other than it requires it to work. > I will move pasid allocation code to iommu.c then. Thanks, Jacob
On 3/28/23 7:21 AM, Jacob Pan wrote:
> Devices that use Intel ENQCMD to submit work must use global PASIDs in
> that the PASID are stored in a per CPU MSR. When such device need to
> submit work for in-kernel DMA with PASID, it must allocate PASIDs from
> the same global number space to avoid conflict.
>
> This patch introduces IOMMU SVA APIs to reserve and release global PASIDs.
> It is expected that device drivers will use the allocated PASIDs to attach
> to appropriate IOMMU domains for use.
>
> Signed-off-by: Jacob Pan <jacob.jun.pan@linux.intel.com>
> ---
> drivers/iommu/iommu-sva.c | 33 +++++++++++++++++++++++++++++++++
> include/linux/iommu.h | 14 ++++++++++++++
> 2 files changed, 47 insertions(+)
>
> diff --git a/drivers/iommu/iommu-sva.c b/drivers/iommu/iommu-sva.c
> index c434b95dc8eb..84b9de84b3e0 100644
> --- a/drivers/iommu/iommu-sva.c
> +++ b/drivers/iommu/iommu-sva.c
> @@ -148,6 +148,39 @@ u32 iommu_sva_get_pasid(struct iommu_sva *handle)
> }
> EXPORT_SYMBOL_GPL(iommu_sva_get_pasid);
>
> +/**
> + * @brief
> + * Reserve a PASID from the SVA global number space.
> + *
> + * @param min starting range, inclusive
> + * @param max ending range, inclusive
> + * @return The reserved PASID on success or IOMMU_PASID_INVALID on failure.
> + */
> +ioasid_t iommu_sva_reserve_pasid(ioasid_t min, ioasid_t max)
> +{
> + int ret;
> +
> + if (!pasid_valid(min) || !pasid_valid(max) ||
> + min == 0 || max < min)
I still think we should make "min == 0" a valid case. The ARM/AMD/Intel
drivers should reserve PASID 0 for special usage with this interface.
Probably we should also make "min == max" a valid case. Both @min and
@max are inclusive.
> + return IOMMU_PASID_INVALID;
> +
> + ret = ida_alloc_range(&iommu_global_pasid_ida, min, max, GFP_KERNEL);
> + if (ret < 0)
> + return IOMMU_PASID_INVALID;
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(iommu_sva_reserve_pasid);
> +
> +void iommu_sva_release_pasid(ioasid_t pasid)
> +{
> + if (!pasid_valid(pasid))
The caller should never release an invalid pasid. So perhaps,
if (WARN_ON(!pasid_valid(pasid)))
return;
to discover bugs during development.
> + return;
> +
> + ida_free(&iommu_global_pasid_ida, pasid);
> +}
> +EXPORT_SYMBOL_GPL(iommu_sva_release_pasid);
> +
> /*
> * I/O page fault handler for SVA
> */
> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
> index 54f535ff9868..0471089dc1d0 100644
> --- a/include/linux/iommu.h
> +++ b/include/linux/iommu.h
> @@ -1187,6 +1187,9 @@ struct iommu_sva *iommu_sva_bind_device(struct device *dev,
> struct mm_struct *mm);
> void iommu_sva_unbind_device(struct iommu_sva *handle);
> u32 iommu_sva_get_pasid(struct iommu_sva *handle);
> +ioasid_t iommu_sva_reserve_pasid(ioasid_t min, ioasid_t max);
> +void iommu_sva_release_pasid(ioasid_t pasid);
> +
> #else
> static inline struct iommu_sva *
> iommu_sva_bind_device(struct device *dev, struct mm_struct *mm)
> @@ -1202,6 +1205,17 @@ static inline u32 iommu_sva_get_pasid(struct iommu_sva *handle)
> {
> return IOMMU_PASID_INVALID;
> }
> +
> +static inline ioasid_t iommu_sva_reserve_pasid(ioasid_t min, ioasid_t max)
> +{
> + return IOMMU_PASID_INVALID;
> +}
> +
> +static inline void iommu_sva_release_pasid(ioasid_t pasid)
> +{
> +
> +}
> +
> static inline void mm_pasid_init(struct mm_struct *mm) {}
> static inline void mm_pasid_drop(struct mm_struct *mm) {}
> #endif /* CONFIG_IOMMU_SVA */
Best regards,
baolu
Hi Baolu,
On Tue, 28 Mar 2023 13:11:12 +0800, Baolu Lu <baolu.lu@linux.intel.com>
wrote:
> On 3/28/23 7:21 AM, Jacob Pan wrote:
> > Devices that use Intel ENQCMD to submit work must use global PASIDs in
> > that the PASID are stored in a per CPU MSR. When such device need to
> > submit work for in-kernel DMA with PASID, it must allocate PASIDs from
> > the same global number space to avoid conflict.
> >
> > This patch introduces IOMMU SVA APIs to reserve and release global
> > PASIDs. It is expected that device drivers will use the allocated
> > PASIDs to attach to appropriate IOMMU domains for use.
> >
> > Signed-off-by: Jacob Pan <jacob.jun.pan@linux.intel.com>
> > ---
> > drivers/iommu/iommu-sva.c | 33 +++++++++++++++++++++++++++++++++
> > include/linux/iommu.h | 14 ++++++++++++++
> > 2 files changed, 47 insertions(+)
> >
> > diff --git a/drivers/iommu/iommu-sva.c b/drivers/iommu/iommu-sva.c
> > index c434b95dc8eb..84b9de84b3e0 100644
> > --- a/drivers/iommu/iommu-sva.c
> > +++ b/drivers/iommu/iommu-sva.c
> > @@ -148,6 +148,39 @@ u32 iommu_sva_get_pasid(struct iommu_sva *handle)
> > }
> > EXPORT_SYMBOL_GPL(iommu_sva_get_pasid);
> >
> > +/**
> > + * @brief
> > + * Reserve a PASID from the SVA global number space.
> > + *
> > + * @param min starting range, inclusive
> > + * @param max ending range, inclusive
> > + * @return The reserved PASID on success or IOMMU_PASID_INVALID on
> > failure.
> > + */
> > +ioasid_t iommu_sva_reserve_pasid(ioasid_t min, ioasid_t max)
> > +{
> > + int ret;
> > +
> > + if (!pasid_valid(min) || !pasid_valid(max) ||
> > + min == 0 || max < min)
>
> I still think we should make "min == 0" a valid case. The ARM/AMD/Intel
> drivers should reserve PASID 0 for special usage with this interface.
>
> Probably we should also make "min == max" a valid case. Both @min and
> @max are inclusive.
I agreed, 0 should not be special.
>
> > + return IOMMU_PASID_INVALID;
> > +
> > + ret = ida_alloc_range(&iommu_global_pasid_ida, min, max,
> > GFP_KERNEL);
> > + if (ret < 0)
> > + return IOMMU_PASID_INVALID;
> > +
> > + return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(iommu_sva_reserve_pasid);
> > +
> > +void iommu_sva_release_pasid(ioasid_t pasid)
> > +{
> > + if (!pasid_valid(pasid))
>
> The caller should never release an invalid pasid. So perhaps,
>
> if (WARN_ON(!pasid_valid(pasid)))
> return;
>
good point!
> to discover bugs during development.
>
> > + return;
> > +
> > + ida_free(&iommu_global_pasid_ida, pasid);
> > +}
> > +EXPORT_SYMBOL_GPL(iommu_sva_release_pasid);
> > +
> > /*
> > * I/O page fault handler for SVA
> > */
> > diff --git a/include/linux/iommu.h b/include/linux/iommu.h
> > index 54f535ff9868..0471089dc1d0 100644
> > --- a/include/linux/iommu.h
> > +++ b/include/linux/iommu.h
> > @@ -1187,6 +1187,9 @@ struct iommu_sva *iommu_sva_bind_device(struct
> > device *dev, struct mm_struct *mm);
> > void iommu_sva_unbind_device(struct iommu_sva *handle);
> > u32 iommu_sva_get_pasid(struct iommu_sva *handle);
> > +ioasid_t iommu_sva_reserve_pasid(ioasid_t min, ioasid_t max);
> > +void iommu_sva_release_pasid(ioasid_t pasid);
> > +
> > #else
> > static inline struct iommu_sva *
> > iommu_sva_bind_device(struct device *dev, struct mm_struct *mm)
> > @@ -1202,6 +1205,17 @@ static inline u32 iommu_sva_get_pasid(struct
> > iommu_sva *handle) {
> > return IOMMU_PASID_INVALID;
> > }
> > +
> > +static inline ioasid_t iommu_sva_reserve_pasid(ioasid_t min, ioasid_t
> > max) +{
> > + return IOMMU_PASID_INVALID;
> > +}
> > +
> > +static inline void iommu_sva_release_pasid(ioasid_t pasid)
> > +{
> > +
> > +}
> > +
> > static inline void mm_pasid_init(struct mm_struct *mm) {}
> > static inline void mm_pasid_drop(struct mm_struct *mm) {}
> > #endif /* CONFIG_IOMMU_SVA */
>
> Best regards,
> baolu
Thanks,
Jacob
© 2016 - 2026 Red Hat, Inc.