Enable PASID for DMA API users
Subsystems (9)
cover Enable PASID for DMA API users
Modern accelerators such as Intel's Data Streaming Accelerator (DSA) can perform DMA requests with PASID, which is a finer granularity than the device's requester ID(RID). In fact, work submissions on DSA shared work queues require PASID.
DMA mapping API is the de facto standard for in-kernel DMA. However, it operates on a per device/RID basis which is not PASID-aware.
This patch introduces the following driver facing API that enables DMA API PASID usage: ioasid_t iommu_enable_pasid_dma(struct device *dev);
A PASID field is added to struct device for the purposes of storing kernel DMA PASID and flushing device IOTLBs. A separate use case in interrupt message store (IMS) also hinted adding a PASID field to struct device.
https://lore.kernel.org/all/[email protected]/
IMS virtualization and DMA API does not overlap.
Once enabled, device drivers can continue to use DMA APIs as-is. There is no difference in terms of mapping in dma_handle between without PASID and with PASID. The DMA mapping performed by IOMMU will be identical for both requests with and without PASID (legacy), let it be IOVA or PA in case of pass-through.
In addition, this set converts the current support for in-kernel PASID DMA from SVA lib to DMA API. There have been security and functional issues with the kernel SVA approach:
(https://lore.kernel.org/linux-iommu/[email protected]/)
The highlights are as the following:
- The lack of IOTLB synchronization upon kernel page table updates. (vmalloc, module/BPF loading, CONFIG_DEBUG_PAGEALLOC etc.)
- Other than slight more protection, using kernel virtual address (KVA) has little advantage over physical address.
There are also no use cases yet where DMA engines need kernel virtual addresses for in-kernel DMA.
Once this set is accepted, more cleanup patches will follow. The plan is to remove the usage of sva_bind_device() for in-kernel usages. Removing page requests and other special cases around kernel SVA in VT-d driver.
Jacob Pan (4):
ioasid: Reserve a global PASID for in-kernel DMA
iommu: Add PASID support for DMA mapping API users iommu/vt-d: Support PASID DMA for in-kernel usage
dmaengine: idxd: Use DMA API for in-kernel DMA with PASID
.../admin-guide/kernel-parameters.txt | 6 - drivers/dma/Kconfig | 10 -- drivers/dma/idxd/idxd.h | 1 - drivers/dma/idxd/init.c | 59 +++------- drivers/dma/idxd/sysfs.c | 7 -- .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 2 +- drivers/iommu/dma-iommu.c | 71 ++++++++++++ drivers/iommu/intel/iommu.c | 109 +++++++++++++++++- drivers/iommu/intel/pasid.c | 7 ++ drivers/iommu/intel/pasid.h | 3 +- drivers/iommu/intel/svm.c | 2 +- drivers/iommu/ioasid.c | 2 + include/linux/device.h | 1 + include/linux/dma-iommu.h | 7 ++ include/linux/intel-iommu.h | 3 +- include/linux/ioasid.h | 4 + include/linux/iommu.h | 4 + 17 files changed, 226 insertions(+), 72 deletions(-)
Signature · 1 line
2.25.1
PATCH 1/4 ioasid: Reserve a global PASID for in-kernel DMA
In-kernel DMA is managed by DMA mapping APIs, which supports per device addressing mode for legacy DMA requests. With the introduction of Process Address Space ID (PASID), device DMA can now target at a finer granularity per PASID + Requester ID (RID).
However, for in-kernel DMA there is no need to differentiate between legacy DMA and DMA with PASID in terms of mapping. DMA address mapping for RID+PASID can be made identical to the RID. The benefit for the drivers is the continuation of DMA mapping APIs without change.
This patch reserves a special IOASID for devices that perform in-kernel DMA requests with PASID. This global IOASID is excluded from the IOASID allocator. The analogous case is PASID #0, a special PASID reserved for DMA requests without PASID (legacy). We could have different kernel PASIDs for individual devices, but for simplicity reasons, a globally reserved one will fit the bill.
--- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 2 +- drivers/iommu/intel/iommu.c | 4 ++-- drivers/iommu/intel/pasid.h | 3 +-- drivers/iommu/intel/svm.c | 2 +- drivers/iommu/ioasid.c | 2 ++ include/linux/ioasid.h | 4 ++++ 6 files changed, 11 insertions(+), 6 deletions(-)
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c +1 -1
@@ -329,7 +329,7 @@ __arm_smmu_sva_bind(struct device *dev, struct mm_struct *mm)return ERR_PTR (-ENOMEM );/* Allocate a PASID for this mm if necessary */ - ret =iommu_sva_alloc_pasid (mm,1 , (1U << master->ssid_bits) -1 ); + ret =iommu_sva_alloc_pasid (mm,IOASID_ALLOC_BASE , (1U << master->ssid_bits) -1 );if (ret) goto err_free_bond;
drivers/iommu/intel/iommu.c +2 -2
@@ -3253,7 +3253,7 @@ static ioasid_t intel_vcmd_ioasid_alloc(ioasid_t min, ioasid_t max, void *data)* PASID range. Host can partition guest PASID range based on * policies but it is out of guest's control. */ -if (min <PASID_MIN || max > intel_pasid_max_id) +if (min <IOASID_ALLOC_BASE || max > intel_pasid_max_id)return INVALID_IOASID ;if (vcmd_alloc_pasid (iommu, &ioasid))
@@ -4824,7 +4824,7 @@ static int aux_domain_add_dev(struct dmar_domain *domain,u32 pasid;/* No private data needed for the default pasid */ - pasid =ioasid_alloc (NULL ,PASID_MIN , + pasid =ioasid_alloc (NULL ,IOASID_ALLOC_BASE ,pci_max_pasids (to_pci_dev (dev)) -1 ,NULL );if (pasid ==INVALID_IOASID ) {
drivers/iommu/intel/pasid.h +1 -2
@@ -10,8 +10,7 @@#ifndef __INTEL_PASID_H#define __INTEL_PASID_H -#define PASID_RID2PASID 0x0 -#define PASID_MIN 0x1 +#define PASID_RID2PASID IOASID_DMA_NO_PASID#define PASID_MAX 0x100000#define PASID_PTE_MASK 0x3F#define PASID_PTE_PRESENT 1
drivers/iommu/intel/svm.c +1 -1
@@ -511,7 +511,7 @@ static int intel_svm_alloc_pasid(struct device *dev, struct mm_struct *mm,ioasid_t max_pasid =dev_is_pci (dev) ?pci_max_pasids (to_pci_dev (dev)) : intel_pasid_max_id; -return iommu_sva_alloc_pasid (mm,PASID_MIN , max_pasid -1 ); +return iommu_sva_alloc_pasid (mm,IOASID_ALLOC_BASE , max_pasid -1 ); }static void intel_svm_free_pasid (struct mm_struct *mm)
drivers/iommu/ioasid.c +2 -0
@@ -317,6 +317,8 @@ ioasid_t ioasid_alloc(struct ioasid_set *set, ioasid_t min, ioasid_t max, data->private = private;refcount_set (&data->refs,1 ); +if (min <IOASID_ALLOC_BASE ) + min =IOASID_ALLOC_BASE ;/* * Custom allocator needs allocator data to perform platform specific * operations.
include/linux/ioasid.h +4 -0
@@ -6,6 +6,10 @@#include <linux/errno.h> #define INVALID_IOASID ((ioasid_t)-1) +#define IOASID_DMA_NO_PASID 0/* For DMA request w/o PASID */ +#define IOASID_DMA_PASID 1/* For in-kernel DMA w/ PASID */ +#define IOASID_ALLOC_BASE 2/* Start of the allocation */ +typedef unsigned int ioasid_t ;typedef ioasid_t (*ioasid_alloc_fn_t )(ioasid_t min,ioasid_t max,void *data);typedef void (*ioasid_free_fn_t )(ioasid_t ioasid,void *data);
Signature · 1 line
2.25.1
Re: [PATCH 1/4] ioasid: Reserve a global PASID for in-kernel DMA
Hi Jacob,
Quoted 32 lines · Jacob Pan
In-kernel DMA is managed by DMA mapping APIs, which supports per device addressing mode for legacy DMA requests. With the introduction of Process Address Space ID (PASID), device DMA can now target at a finer granularity per PASID + Requester ID (RID).
However, for in-kernel DMA there is no need to differentiate between legacy DMA and DMA with PASID in terms of mapping. DMA address mapping for RID+PASID can be made identical to the RID. The benefit for the drivers is the continuation of DMA mapping APIs without change.
This patch reserves a special IOASID for devices that perform in-kernel DMA requests with PASID. This global IOASID is excluded from the IOASID allocator. The analogous case is PASID #0, a special PASID reserved for DMA requests without PASID (legacy). We could have different kernel PASIDs for individual devices, but for simplicity reasons, a globally reserved one will fit the bill.
Signed-off-by Jacob Pan <[email protected]>--- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 2 +- drivers/iommu/intel/iommu.c | 4 ++-- drivers/iommu/intel/pasid.h | 3 +-- drivers/iommu/intel/svm.c | 2 +- drivers/iommu/ioasid.c | 2 ++ include/linux/ioasid.h | 4 ++++ 6 files changed, 11 insertions(+), 6 deletions(-)drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c +0
-0
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c __arm_smmu_sva_bind(struct device *dev, struct mm_struct *mm) · line 332
Quoted 5 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c +1
-1@@ -329,7 +329,7 @@ __arm_smmu_sva_bind(struct device *dev, struct mm_struct *mm)return ERR_PTR (-ENOMEM );/* Allocate a PASID for this mm if necessary */ - ret =iommu_sva_alloc_pasid (mm,1 , (1U << master->ssid_bits) -1 ); + ret =iommu_sva_alloc_pasid (mm,IOASID_ALLOC_BASE , (1U << master->ssid_bits) -1 );
I'd rather keep hardware limits as parameters here. PASID#0 is reserved by the SMMUv3 hardware so we have to pass at least 1 here, but VT-d could change RID_PASID and pass 0. On the other hand IOASID_DMA_PASID depends on device drivers needs and is not needed on all systems, so I think could stay within the ioasid allocator. Could VT-d do an ioasid_alloc()/ioasid_get() to reserve this global PASID, storing it under the device_domain_lock?
This looks like we're just one step away from device drivers needing multiple PASIDs for kernel DMA so I'm trying to figure out how to evolve the API towards that. It's probably as simple as keeping a kernel IOASID set at first, but then we'll probably want to optimize by having multiple overlapping sets for each device driver (all separate from the SVA set).
Thanks,
Jean
Re: [PATCH 1/4] ioasid: Reserve a global PASID for in-kernel DMA
Hi Jean-Philippe,
Quoted 43 lines · Jean-Philippe Brucker
Hi Jacob,
Quoted 38 lines · Jacob Pan
In-kernel DMA is managed by DMA mapping APIs, which supports per device addressing mode for legacy DMA requests. With the introduction of Process Address Space ID (PASID), device DMA can now target at a finer granularity per PASID + Requester ID (RID).
However, for in-kernel DMA there is no need to differentiate between legacy DMA and DMA with PASID in terms of mapping. DMA address mapping for RID+PASID can be made identical to the RID. The benefit for the drivers is the continuation of DMA mapping APIs without change.
This patch reserves a special IOASID for devices that perform in-kernel DMA requests with PASID. This global IOASID is excluded from the IOASID allocator. The analogous case is PASID #0, a special PASID reserved for DMA requests without PASID (legacy). We could have different kernel PASIDs for individual devices, but for simplicity reasons, a globally reserved one will fit the bill.
Signed-off-by Jacob Pan <[email protected]>--- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 2 +- drivers/iommu/intel/iommu.c | 4 ++-- drivers/iommu/intel/pasid.h | 3 +-- drivers/iommu/intel/svm.c | 2 +- drivers/iommu/ioasid.c | 2 ++ include/linux/ioasid.h | 4 ++++ 6 files changed, 11 insertions(+), 6 deletions(-)(quoted diff) +0
-0
b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.cindexee66d1f4cb81..ac79a37ffe06100644 ---a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c+++b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c@@ -329,7 +329,7 @@__arm_smmu_sva_bind(struct device *dev, struct mm_struct *mm)returnERR_PTR(-ENOMEM);(quoted diff) +0
-1/* Allocate a PASID for this mm if necessary */ - ret = iommu_sva_alloc_pasid(mm, 1, (1U << master->ssid_bits) -1);
(quoted diff) +1
-0+ ret = iommu_sva_alloc_pasid(mm, IOASID_ALLOC_BASE, (1U <<Quoted 1 line
master->ssid_bits) - 1);
Quoted 8 lines
I'd rather keep hardware limits as parameters here. PASID#0 is reserved by the SMMUv3 hardware so we have to pass at least 1 here, but VT-d could change
RID_PASIDand pass 0. On the other handIOASID_DMA_PASIDdepends on device drivers needs and is not needed on all systems, so I think could stay within the ioasid allocator. Could VT-d do an ioasid_alloc()/ioasid_get() to reserve this global PASID, storing it under thedevice_domain_lock?
Yes, this works. We can delegate DMA PASID allocation to vendor drivers. My proposal here is driven by simplicity.
Quoted 5 lines
This looks like we're just one step away from device drivers needing multiple PASIDs for kernel DMA so I'm trying to figure out how to evolve the API towards that. It's probably as simple as keeping a kernel IOASID set at first, but then we'll probably want to optimize by having multiple overlapping sets for each device driver (all separate from the SVA set).
Sounds reasonable to start with a kernel set for in-kernel DMA once we need multiple ones. But I am not sure what *overlapping* sets mean here, could you explain?
Quoted 1 line
Thanks,
Jacob
_______________________________________________
iommu mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH 1/4] ioasid: Reserve a global PASID for in-kernel DMA
Quoted 8 lines · Jacob Pan
Quoted 5 lines
This looks like we're just one step away from device drivers needing multiple PASIDs for kernel DMA so I'm trying to figure out how to evolve the API towards that. It's probably as simple as keeping a kernel IOASID set at first, but then we'll probably want to optimize by having multiple overlapping sets for each device driver (all separate from the SVA set).
Sounds reasonable to start with a kernel set for in-kernel DMA once we need multiple ones. But I am not sure what *overlapping* sets mean here, could you explain?
Given that each device uses a separate PASID table, we could allocate the same set of PASID values for different device drivers. We just need to make sure that those values are different from PASIDs allocated for user SVA.
Thanks,
Jean
Re: [PATCH 1/4] ioasid: Reserve a global PASID for in-kernel DMA
Quoted 6 lines · Jean-Philippe Brucker
Quoted 5 lines · Jacob Pan
Quoted 5 lines
This looks like we're just one step away from device drivers needing multiple PASIDs for kernel DMA so I'm trying to figure out how to evolve the API towards that. It's probably as simple as keeping a kernel IOASID set at first, but then we'll probably want to optimize by having multiple overlapping sets for each device driver (all separate from the SVA set).
Quoted 8 lines
Quoted 3 lines
Sounds reasonable to start with a kernel set for in-kernel DMA once we need multiple ones. But I am not sure what *overlapping* sets mean here, could you explain?
Given that each device uses a separate PASID table, we could allocate the same set of PASID values for different device drivers. We just need to make sure that those values are different from PASIDs allocated for user SVA.
Why does user SVA need global values anyhow?
Jason
_______________________________________________
iommu mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH 1/4] ioasid: Reserve a global PASID for in-kernel DMA
Hi Jason,
Quoted 12 lines · Jason Gunthorpe
Quoted 11 lines · Jean-Philippe Brucker
Quoted 9 lines · Jacob Pan
Quoted 6 lines
This looks like we're just one step away from device drivers needing multiple PASIDs for kernel DMA so I'm trying to figure out how to evolve the API towards that. It's probably as simple as keeping a kernel IOASID set at first, but then we'll probably want to optimize by having multiple overlapping sets for each device driver (all separate from the SVA set).
Sounds reasonable to start with a kernel set for in-kernel DMA once we need multiple ones. But I am not sure what *overlapping* sets mean here, could you explain?
Quoted 7 lines
Quoted 4 lines
Given that each device uses a separate PASID table, we could allocate the same set of PASID values for different device drivers. We just need to make sure that those values are different from PASIDs allocated for user SVA.
Why does user SVA need global values anyhow?
Currently, we have mm.pasid for user SVA. mm is global. We could have per device PASID for dedicated devices (not shared across mm's), but that would make things a lot more complex. I am thinking multiple PASIDs per mm is needed, right?
For VT-d, the shared workqueue (SWQ) requires global PASIDs in that we cannot have two processes use the same PASID to submit work on a workqueue shared by the two processes. Each process's PASID must be unique to the SWQ's PASID table.
Quoted 1 line
Jason
Thanks,
Jacob
RE: [PATCH 1/4] ioasid: Reserve a global PASID for in-kernel DMA
Quoted 33 lines
From: Jacob Pan <[email protected]>
Sent: Saturday, December 11, 2021 2:06 AMHi Jason,
Quoted 10 lines · Jason Gunthorpe
Quoted 9 lines · Jean-Philippe Brucker
Quoted 8 lines · Jacob Pan
Quoted 6 lines
This looks like we're just one step away from device drivers needing multiple PASIDs for kernel DMA so I'm trying to figure out how to evolve the API towards that. It's probably as simple as keeping a kernel IOASID set at first, but then we'll probably want to optimize by having multiple overlapping sets for each device driver (all separate from the SVA set).
Sounds reasonable to start with a kernel set for in-kernel DMA once we need multiple ones. But I am not sure what *overlapping* sets
mean
Quoted 9 lines
Quoted 6 lines
Quoted 1 line
here, could you explain?
Given that each device uses a separate PASID table, we could allocate the same set of PASID values for different device drivers. We just need to make sure that those values are different from PASIDs allocated for user SVA.
Why does user SVA need global values anyhow?
Currently, we have mm.pasid for user SVA. mm is global. We could have per device PASID for dedicated devices (not shared across mm's), but that would make things a lot more complex. I am thinking multiple PASIDs per mm is needed, right?
Quoted 6 lines
For VT-d, the shared workqueue (SWQ) requires global PASIDs in that we cannot have two processes use the same PASID to submit work on a workqueue
shared by the two processes. Each process's PASID must be unique to the SWQ's PASID table.
Uniqueness is not the main argument of using global PASIDs for SWQ, since it can be defined either in per-RID or in global PASID space. No SVA architecture can allow two processes to use the same PASID to submit work unless they share mm! 😊
IMO the real reason is that SWQ for user SVA must be accessed via ENQCMD instruction which fetches the PASID from a CPU MSR (managed as part of XSAVE state). This assumes a single PASID representing the address space for the user task regardless how many devices are attached to this task. Otherwise the kernel doesn't know when to set which PASID if multiple PASIDs per mm.
Then this single PASID has to be global cross all attached devices to ensure uniqueness.
Of course SWQ is only one configuration for user SVA. In theory multiple per-device PASIDs are still feasible for non-SWQ cases. But given mm is global and the SWQ restriction, it's not worthwhile of adding that complexity...
Thanks
Kevin
_______________________________________________
iommu mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH 1/4] ioasid: Reserve a global PASID for in-kernel DMA
Quoted 7 lines · Kevin
Uniqueness is not the main argument of using global PASIDs for SWQ, since it can be defined either in per-RID or in global PASID space. No SVA architecture can allow two processes to use the same PASID to submit work unless they share mm! 😊
IMO the real reason is that SWQ for user SVA must be accessed via ENQCMD instruction which fetches the PASID from a CPU MSR
This really should have been inside a comment in the struct mm
"pasid is the value used by x86 ENQCMD"
(and if we phrase it that way I wonder why it is in a struct mm not some process or task related struct, since it has nothing to do with page tables)
And, IMHO, the IOMMU part of the code should avoid using this field. IOMMU should be able to create arbitarily many "SVA" iommu_domains for use by PASID even if they can't be used with ENQCMD. Such is proper layering.
Jason
_______________________________________________
iommu mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/iommu
PATCH 2/4 iommu: Add PASID support for DMA mapping API users
In reply to Jacob PanDMA mapping API is the de facto standard for in-kernel DMA. It operates on a per device/RID basis which is not PASID-aware.
Some modern devices such as Intel Data Streaming Accelerator, PASID is required for certain work submissions. To allow such devices use DMA mapping API, we need the following functionalities:
1. Provide device a way to retrieve a kernel PASID for work submission
2. Enable the kernel PASID on the IOMMU
3. Establish address space for the kernel PASID that matches the default domain. Let it be IOVA or physical address in case of pass-through.
This patch introduces a driver facing API that enables DMA API PASID usage. Once enabled, device drivers can continue to use DMA APIs as is. There is no difference in dma_handle between without PASID and with PASID.
To manage device IOTLB flush at PASID level, this patch also introduces a .pasid field to struct device. This also serves as a flag indicating whether PASID is being used for the device to perform in-kernel DMA.
--- drivers/iommu/dma-iommu.c | 71 +++++++++++++++++++++++++++++++++++++++ include/linux/device.h | 1 + include/linux/dma-iommu.h | 7 ++++ include/linux/iommu.h | 4 +++ 4 files changed, 83 insertions(+)
drivers/iommu/dma-iommu.c +71 -0
@@ -167,6 +167,77 @@ void iommu_put_dma_cookie(struct iommu_domain *domain) domain->iova_cookie =NULL ; } +/** +* iommu_enable_pasid_dma --Enable in-kernel DMA request with PASID +* @dev: Device to be enabled +* +* DMA request with PASID will be mapped the same way as the legacy DMA. +* If the device is in pass-through, PASID will also pass-through. If the +* device is in IOVA map, the supervisor PASID will point to the same IOVA +* page table. +* +* @return the kernel PASID to be used for DMA or INVALID_IOASID on failure +*/ +ioasid_t iommu_enable_pasid_dma (struct device *dev) +{ +struct iommu_domain *dom; + +if (dev->pasid) { +dev_err (dev,"PASID DMA already enabled\n" ); +return IOASID_DMA_PASID ; + } + dom =iommu_get_domain_for_dev (dev); + +if (!dom) { +dev_err (dev,"No IOMMU domain\n" ); +return INVALID_IOASID ; + } + +/* +* Use the reserved kernel PASID for all devices. For now, +* there is no need to have different PASIDs for in-kernel use. +*/ +if (!dom->ops->enable_pasid_dma || dom->ops->enable_pasid_dma (dev,IOASID_DMA_PASID )) +return INVALID_IOASID ; +/* Used for device IOTLB flush */ + dev->pasid =IOASID_DMA_PASID ; + +return IOASID_DMA_PASID ; +} +EXPORT_SYMBOL (iommu_enable_pasid_dma); + +/** +* iommu_disable_pasid_dma --Disable in-kernel DMA request with PASID +* @dev: Device's PASID DMA to be disabled +* +* It is the device driver's responsibility to ensure no more incoming DMA +* requests with the kernel PASID before calling this function. IOMMU driver +* ensures PASID cache, IOTLBs related to the kernel PASID are cleared and +* drained. +* +* @return 0 on success or error code on failure +*/ +int iommu_disable_pasid_dma (struct device *dev) +{ +struct iommu_domain *dom; +int ret =0 ; + +if (!dev->pasid) { +dev_err (dev,"PASID DMA not enabled\n" ); +return -ENODEV ; + } + dom =iommu_get_domain_for_dev (dev); +if (!dom->ops->disable_pasid_dma) +return -ENOTSUPP ; + + ret = dom->ops->disable_pasid_dma (dev); +if (!ret) + dev->pasid =0 ; + +return ret; +} +EXPORT_SYMBOL (iommu_disable_pasid_dma); +/** * iommu_dma_get_resv_regions - Reserved region driver helper * @dev: Device from iommu_get_resv_regions()
include/linux/device.h +1 -0
@@ -559,6 +559,7 @@ struct device {void (*release)(struct device *dev);struct iommu_group *iommu_group;struct dev_iommu *iommu; +u32 pasid;/* For in-kernel DMA w/ PASID */ enum device_removable removable;
include/linux/dma-iommu.h +7 -0
@@ -18,6 +18,13 @@ int iommu_get_dma_cookie(struct iommu_domain *domain);int iommu_get_msi_cookie (struct iommu_domain *domain,dma_addr_t base);void iommu_put_dma_cookie (struct iommu_domain *domain); +/* +* For devices that can do DMA request with PASID, setup a system PASID. +* Address modes (IOVA, PA) are selected by the platform code. +*/ +ioasid_t iommu_enable_pasid_dma (struct device *dev); +int iommu_disable_pasid_dma (struct device *dev); +/* Setup call for arch DMA mapping code */ void iommu_setup_dma_ops (struct device *dev,u64 dma_base,u64 dma_limit);int iommu_dma_init_fq (struct iommu_domain *domain);
include/linux/iommu.h +4 -0
@@ -236,6 +236,8 @@ struct iommu_iotlb_gather {* - IOMMU_DOMAIN_IDENTITY: must use an identity domain * - IOMMU_DOMAIN_DMA: must use a dma domain * - 0: use the default setting +* @enable_pasid_dma: Set up PASID for in-kernel DMA +* @disable_pasid_dma: Disable in-kernel DMA with PASID on the device * @pgsize_bitmap: bitmap of all possible supported page sizes * @owner: Driver module providing these ops */
@@ -310,6 +312,8 @@ struct iommu_ops {int (*def_domain_type)(struct device *dev); +int (*enable_pasid_dma)(struct device *dev,u32 pasid); +int (*disable_pasid_dma)(struct device *dev);unsigned long pgsize_bitmap;struct module *owner; };
Signature · 1 line
2.25.1
Lu Baolu
maintainerRe: [PATCH 2/4] iommu: Add PASID support for DMA mapping API users
Hi Jacob,
Quoted 11 lines · Jacob Pan
DMA mapping API is the de facto standard for in-kernel DMA. It operates on a per device/RID basis which is not PASID-aware.
Some modern devices such as Intel Data Streaming Accelerator, PASID is required for certain work submissions. To allow such devices use DMA mapping API, we need the following functionalities:
1. Provide device a way to retrieve a kernel PASID for work submission
2. Enable the kernel PASID on the IOMMU
3. Establish address space for the kernel PASID that matches the default domain. Let it be IOVA or physical address in case of pass-through.
Quoted 4 lines
This patch introduces a driver facing API that enables DMA API PASID usage. Once enabled, device drivers can continue to use DMA APIs as is. There is no difference in
dma_handlebetween without PASID and with PASID.
Can a device issue DMA requests with PASID even there's no system IOMMU or the system IOMMU is disabled?
Best regards,
baolu
_______________________________________________
iommu mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH 2/4] iommu: Add PASID support for DMA mapping API users
Hi Lu,
Quoted 14 lines · Lu Baolu
Hi Jacob,
Quoted 11 lines · Jacob Pan
DMA mapping API is the de facto standard for in-kernel DMA. It operates on a per device/RID basis which is not PASID-aware.
Some modern devices such as Intel Data Streaming Accelerator, PASID is required for certain work submissions. To allow such devices use DMA mapping API, we need the following functionalities:
1. Provide device a way to retrieve a kernel PASID for work submission
2. Enable the kernel PASID on the IOMMU
3. Establish address space for the kernel PASID that matches the default domain. Let it be IOVA or physical address in case of pass-through.
Quoted 8 lines
Quoted 4 lines
This patch introduces a driver facing API that enables DMA API PASID usage. Once enabled, device drivers can continue to use DMA APIs as is. There is no difference in
dma_handlebetween without PASID and with PASID.Can a device issue DMA requests with PASID even there's no system IOMMU or the system IOMMU is disabled?
Good point.
If IOMMU is not enabled, device cannot issue DMA requests with PASID. This API will not be available. Forgot to add dummy functions to the header.
Quoted 2 lines
Best regards,
baolu
Thanks,
Jacob
RE: [PATCH 2/4] iommu: Add PASID support for DMA mapping API users
Quoted 11 lines
From: Jacob Pan <[email protected]>
Sent: Thursday, December 9, 2021 2:50 AMQuoted 1 line
Can a device issue DMA requests with PASID even there's no system
IOMMU
Quoted 2 lines
or the system IOMMU is disabled?
Good point.
If IOMMU is not enabled, device cannot issue DMA requests with PASID. This API will not be available. Forgot to add dummy functions to the header.
PASID is a PCI thing, not defined by IOMMU.
I think the key is physically if IOMMU is disabled, how will root complex handle a PCI memory request including a PASID TLP prefix? Does it block such request due to no IOMMU to consume PASID or simply ignore PASID and continue routing the request to the memory controller?
If block, then having an iommu interface makes sense.
If ignore, possibly a DMA API call makes more sense instead, implying that this extension can be used even when iommu is disabled.
I think that is what Baolu wants to point out.
Thanks
Kevin
Lu Baolu
maintainerRe: [PATCH 2/4] iommu: Add PASID support for DMA mapping API users
Quoted 19 lines · Kevin
Quoted 11 lines
From: Jacob Pan <[email protected]>
Sent: Thursday, December 9, 2021 2:50 AMQuoted 1 line
Can a device issue DMA requests with PASID even there's no system
IOMMU
Quoted 2 lines
or the system IOMMU is disabled?
Good point.
If IOMMU is not enabled, device cannot issue DMA requests with PASID. This API will not be available. Forgot to add dummy functions to the header.PASID is a PCI thing, not defined by IOMMU.
I think the key is physically if IOMMU is disabled, how will root complex handle a PCI memory request including a PASID TLP prefix? Does it block such request due to no IOMMU to consume PASID or simply ignore PASID and continue routing the request to the memory controller?
Quoted 6 lines
If block, then having an iommu interface makes sense.
If ignore, possibly a DMA API call makes more sense instead, implying that this extension can be used even when iommu is disabled.
I think that is what Baolu wants to point out.
Yes, exactly. Imagining in the VM guest environment, do we require a vIOMMU for this functionality? vIOMMU is not performance friendly if we put aside the security considerations.
Best regards,
baolu
Re: [PATCH 2/4] iommu: Add PASID support for DMA mapping API users
Hi Lu,
Quoted 20 lines · Lu Baolu
Quoted 19 lines · Kevin
Quoted 11 lines
From: Jacob Pan <[email protected]>
Sent: Thursday, December 9, 2021 2:50 AMQuoted 1 line
Can a device issue DMA requests with PASID even there's no system
IOMMU
Quoted 2 lines
or the system IOMMU is disabled?
Good point.
If IOMMU is not enabled, device cannot issue DMA requests with PASID. This API will not be available. Forgot to add dummy functions to the header.PASID is a PCI thing, not defined by IOMMU.
I think the key is physically if IOMMU is disabled, how will root complex handle a PCI memory request including a PASID TLP prefix? Does it block such request due to no IOMMU to consume PASID or simply ignore PASID and continue routing the request to the memory controller?
Quoted 7 lines
Quoted 6 lines
If block, then having an iommu interface makes sense.
If ignore, possibly a DMA API call makes more sense instead, implying that this extension can be used even when iommu is disabled.
I think that is what Baolu wants to point out.
Thanks for clarifying, very good point.
Looking at the PCIe spec. I don't see specific rules for RC to ignore or block PASID TLP if not enabled.
"- A Root Complex that supports PASID TLP Prefixes must have a device specific mechanism for enabling them. By default usage of PASID TLP Prefixes is disabled
- Root Complexes may optionally support TLPs with PASID TLP Prefixes. The
mechanism used to detect whether a Root Complex supports the PASID TLP Prefix is implementation specific
"
For all practical purposes, why would someone sets up PASID for DMA just to be ignored? An IOMMU interface makes sense to me.
Quoted 4 lines
Yes, exactly. Imagining in the VM guest environment, do we require a vIOMMU for this functionality? vIOMMU is not performance friendly if we put aside the security considerations.
The primary use case for accelerators to use in-kernel DMA will be in pass-through mode. vIOMMU should be able to do PT with good performance, right? no nesting, IO page faults.
Quoted 2 lines
Best regards,
baolu
Thanks,
Jacob
Re: [PATCH 2/4] iommu: Add PASID support for DMA mapping API users
Quoted 19 lines · Jacob Pan
Hi Lu,
Quoted 14 lines · Lu Baolu
Quoted 13 lines · Kevin
Quoted 11 lines
From: Jacob Pan <[email protected]>
Sent: Thursday, December 9, 2021 2:50 AMQuoted 1 line
Can a device issue DMA requests with PASID even there's no system
IOMMU
Quoted 2 lines
or the system IOMMU is disabled?
Good point.
If IOMMU is not enabled, device cannot issue DMA requests with PASID. This API will not be available. Forgot to add dummy functions to the header.PASID is a PCI thing, not defined by IOMMU.
True, but RP is just a forwarding agent on these EETLP prefixes. I'm not sure how RP's will behave if they receive a TLP they don't understand and I suspect they might pull the system down via some UR type response when IOMMU isn't enabled.
Quoted 13 lines
Quoted 6 lines
Quoted 6 lines
I think the key is physically if IOMMU is disabled, how will root complex handle a PCI memory request including a PASID TLP prefix? Does it block such request due to no IOMMU to consume PASID or simply ignore PASID and continue routing the request to the memory controller?
Quoted 7 lines
Quoted 6 lines
If block, then having an iommu interface makes sense.
If ignore, possibly a DMA API call makes more sense instead, implying that this extension can be used even when iommu is disabled.
I think that is what Baolu wants to point out.
Quoted 9 lines
Thanks for clarifying, very good point.
Looking at the PCIe spec. I don't see specific rules for RC to ignore or block PASID TLP if not enabled.
"- A Root Complex that supports PASID TLP Prefixes must have a device specific mechanism for enabling them. By default usage of PASID TLP Prefixes is disabled
- Root Complexes may optionally support TLPs with PASID TLP Prefixes. The
mechanism used to detect whether a Root Complex supports the PASID TLP Prefix is implementation specific
Isn't implementation specific mechanism is IOMMU?
Quoted 11 lines
"
For all practical purposes, why would someone sets up PASID for DMA just to be ignored? An IOMMU interface makes sense to me.Quoted 4 lines
Yes, exactly. Imagining in the VM guest environment, do we require a vIOMMU for this functionality? vIOMMU is not performance friendly if we put aside the security considerations.
The primary use case for accelerators to use in-kernel DMA will be in pass-through mode. vIOMMU should be able to do PT with good performance, right? no nesting, IO page faults.
But from an enabling perspective when PASID is in use we have to mandate either the presence of an IOMMU, or some hypercall that will do the required plumbing for PASID isn't it?
_______________________________________________
iommu mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH 2/4] iommu: Add PASID support for DMA mapping API users
Hi Ashok,
Quoted 7 lines · Ashok
Quoted 4 lines
Prefixes is disabled
- Root Complexes may optionally support TLPs with PASID TLP Prefixes.
The mechanism used to detect whether a Root Complex supports the PASID TLP Prefix is implementation specificIsn't implementation specific mechanism is IOMMU?
I agree. In case of VT-d it would be in ecap.pasid bit.
Quoted 8 lines
Quoted 8 lines
"
For all practical purposes, why would someone sets up PASID for DMA just to be ignored? An IOMMU interface makes sense to me.Quoted 4 lines
Yes, exactly. Imagining in the VM guest environment, do we require a vIOMMU for this functionality? vIOMMU is not performance friendly if we put aside the security considerations.
Quoted 7 lines
Quoted 3 lines
The primary use case for accelerators to use in-kernel DMA will be in pass-through mode. vIOMMU should be able to do PT with good performance, right? no nesting, IO page faults.
But from an enabling perspective when PASID is in use we have to mandate either the presence of an IOMMU, or some hypercall that will do the required plumbing for PASID isn't it?
So the point is that we need either vIOMMU or virtio IOMMU to use PASID? For the purpose of this discussion to decide whether iommu API or DMA API should be used, I am still convinced it should be iommu API.
Unlike IOMMU on/off for DMA API (which is transparent to the driver), using PASID is not transparent. Other than enabling the PASID, the driver has to program the PASID explicitly. There is no point of doing this dance knowing the PASID might be ignored.
Thanks,
Jacob
PATCH 3/4 iommu/vt-d: Support PASID DMA for in-kernel usage
In reply to Jacob PanBetween DMA requests with and without PASID (legacy), DMA mapping APIs are used indiscriminately on a device. Therefore, we should always match the addressing mode of the legacy DMA when enabling kernel PASID.
This patch adds support for VT-d driver where the kernel PASID is programmed to match RIDPASID. i.e. if the device is in pass-through, the kernel PASID is also in pass-through; if the device is in IOVA mode, the kernel PASID will also be using the same IOVA space.
There is additional handling for IOTLB and device TLB flush w.r.t. the kernel PASID. On VT-d, PASID-selective IOTLB flush is also on a per-domain basis; whereas device TLB flush is per device. Note that IOTLBs are used even when devices are in pass-through mode. ATS is enabled device-wide, but the device drivers can choose to manage ATS at per PASID level whenever control is available.
--- drivers/iommu/intel/iommu.c | 105 +++++++++++++++++++++++++++++++++++- drivers/iommu/intel/pasid.c | 7 +++ include/linux/intel-iommu.h | 3 +- 3 files changed, 113 insertions(+), 2 deletions(-)
drivers/iommu/intel/iommu.c +104 -1
@@ -1743,7 +1743,14 @@ static void domain_flush_piotlb(struct intel_iommu *iommu,if (domain->default_pasid)qi_flush_piotlb (iommu, did, domain->default_pasid, addr, npages, ih); - +if (domain->kernel_pasid && !domain_type_is_si (domain)) { +/* +* REVISIT: we only do PASID IOTLB inval for FL, we could have SL +* for PASID in the future such as vIOMMU PT. this doesn't get hit. +*/ +qi_flush_piotlb (iommu, did, domain->kernel_pasid, + addr, npages, ih); + }if (!list_empty (&domain->devices))qi_flush_piotlb (iommu, did,PASID_RID2PASID , addr, npages, ih); }
@@ -5695,6 +5702,100 @@ static void intel_iommu_iotlb_sync_map(struct iommu_domain *domain, } } +static int intel_enable_pasid_dma (struct device *dev,u32 pasid) +{ +struct intel_iommu *iommu =device_to_iommu (dev,NULL ,NULL ); +struct device_domain_info *info; +unsigned long flags; +int ret =0 ; + + info =get_domain_info (dev); +if (!info) +return -ENODEV ; + +if (!dev_is_pci (dev) || !sm_supported (info->iommu)) +return -EINVAL ; + +if (intel_iommu_enable_pasid (info->iommu, dev)) +return -ENODEV ; + +spin_lock_irqsave (&device_domain_lock, flags); +spin_lock (&iommu->lock); +/* +* Store PASID for IOTLB flush, but only needed for non-passthrough +* unmap case. For passthrough, we only need to do IOTLB flush during +* PASID teardown. Flush covers all devices in the same domain as the +* domain ID is the same for the same SL. +*/ + info->domain->kernel_pasid = pasid; + +/* +* Tracks how many attached devices are using the kernel PASID. Clear +* the domain kernel PASID when all users called disable_pasid_dma(). +*/ +atomic_inc (&info->domain->kernel_pasid_user); + +/* +* Addressing modes (IOVA vs. PA) is a per device choice made by the +* platform code. We must treat legacy DMA (request w/o PASID) and +* DMA w/ PASID identially in terms of mapping. Here we just set up +* the kernel PASID to match the mapping of RID2PASID/PASID0. +*/ +if (hw_pass_through &&domain_type_is_si (info->domain)) { + ret =intel_pasid_setup_pass_through (info->iommu, info->domain, + dev, pasid); +if (ret) +dev_err (dev,"Failed kernel PASID %d in BYPASS" , pasid); + + }else if (domain_use_first_level (info->domain)) { +/* We are using FL for IOVA, this is the default option */ + ret =domain_setup_first_level (info->iommu, info->domain, dev, + pasid); +if (ret) +dev_err (dev,"Failed kernel PASID %d IOVA FL" , pasid); + }else { + ret =intel_pasid_setup_second_level (info->iommu, info->domain, + dev, pasid); +if (ret) +dev_err (dev,"Failed kernel SPASID %d IOVA SL" , pasid); + } + +spin_unlock (&iommu->lock); +spin_unlock_irqrestore (&device_domain_lock, flags); + +return ret; +} + +static int intel_disable_pasid_dma (struct device *dev) +{ +struct intel_iommu *iommu =device_to_iommu (dev,NULL ,NULL ); +struct device_domain_info *info; +unsigned long flags; +int ret =0 ; + + info =get_domain_info (dev); +if (!info) +return -ENODEV ; + +if (!dev_is_pci (dev) || !sm_supported (info->iommu)) +return -EINVAL ; + +spin_lock_irqsave (&device_domain_lock, flags); +spin_lock (&iommu->lock); + +/* Tear down kernel PASID for this device */ +intel_pasid_tear_down_entry (info->iommu, info->dev, + info->domain->kernel_pasid, + false); +/* Clear the domain kernel PASID when there is no users */ +if (atomic_dec_and_test (&info->domain->kernel_pasid_user)) + info->domain->kernel_pasid =0 ; + +spin_unlock (&iommu->lock); +spin_unlock_irqrestore (&device_domain_lock, flags); +return ret; +} +const struct iommu_ops intel_iommu_ops = { .capable = intel_iommu_capable, .domain_alloc = intel_iommu_domain_alloc,
@@ -5732,6 +5833,8 @@ const struct iommu_ops intel_iommu_ops = { .sva_get_pasid = intel_svm_get_pasid, .page_response = intel_svm_page_response, #endif + .enable_pasid_dma = intel_enable_pasid_dma, + .disable_pasid_dma = intel_disable_pasid_dma, };static void quirk_iommu_igfx (struct pci_dev *dev)
drivers/iommu/intel/pasid.c +7 -0
@@ -505,6 +505,13 @@ devtlb_invalidation_with_pasid(struct intel_iommu *iommu,qi_flush_dev_iotlb (iommu, sid, pfsid, qdep,0 ,64 -VTD_PAGE_SHIFT ); else qi_flush_dev_iotlb_pasid(iommu, sid, pfsid, pasid, qdep, 0, 64 - VTD_PAGE_SHIFT); +/* +* Flush the kernel PASID if used by the device. This is the case where +* a device driver uses IOVA via DMA map APIs for request with PASID. +*/ +if (dev->pasid) +qi_flush_dev_iotlb_pasid (iommu, sid, pfsid, dev->pasid, qdep,0 , +64 -VTD_PAGE_SHIFT ); } void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
include/linux/intel-iommu.h +2 -1
@@ -567,7 +567,8 @@ struct dmar_domain {* The default pasid used for non-SVM * traffic on mediated devices. */ - +u32 kernel_pasid;/* for in-kernel DMA w/ PASID */ +atomic_t kernel_pasid_user;/* count of kernel_pasid users */ struct iommu_domain domain;/* generic domain data structure for iommu core */ };
Signature · 6 lines
2.25.1 _______________________________________________ iommu mailing list [email protected] https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH 3/4] iommu/vt-d: Support PASID DMA for in-kernel usage
Quoted 42 lines · Jacob Pan
Between DMA requests with and without PASID (legacy), DMA mapping APIs are used indiscriminately on a device. Therefore, we should always match the addressing mode of the legacy DMA when enabling kernel PASID.
This patch adds support for VT-d driver where the kernel PASID is programmed to match RIDPASID. i.e. if the device is in pass-through, the kernel PASID is also in pass-through; if the device is in IOVA mode, the kernel PASID will also be using the same IOVA space.
There is additional handling for IOTLB and device TLB flush w.r.t. the kernel PASID. On VT-d, PASID-selective IOTLB flush is also on a per-domain basis; whereas device TLB flush is per device. Note that IOTLBs are used even when devices are in pass-through mode. ATS is enabled device-wide, but the device drivers can choose to manage ATS at per PASID level whenever control is available.
Signed-off-by Jacob Pan <[email protected]>drivers/iommu/intel/iommu.c | 105 +++++++++++++++++++++++++++++++++++- drivers/iommu/intel/pasid.c | 7 +++ include/linux/intel-iommu.h | 3 +- 3 files changed, 113 insertions(+), 2 deletions(-)drivers/iommu/intel/iommu.c +9
-1+++ b/drivers/iommu/intel/iommu.c@@ -1743,7 +1743,14 @@ static void domain_flush_piotlb(struct intel_iommu *iommu,if (domain->default_pasid)qi_flush_piotlb (iommu, did, domain->default_pasid, addr, npages, ih); - +if (domain->kernel_pasid && !domain_type_is_si (domain)) { +/* +* REVISIT: we only do PASID IOTLB inval for FL, we could have SL +* for PASID in the future such as vIOMMU PT. this doesn't get hit. +*/ +qi_flush_piotlb (iommu, did, domain->kernel_pasid, + addr, npages, ih); + }if (!list_empty (&domain->devices))qi_flush_piotlb (iommu, did,PASID_RID2PASID , addr, npages, ih); }
drivers/iommu/intel/iommu.c static void intel_iommu_iotlb_sync_map(struct iommu_domain *domain, · line 5706
Quoted 5 lines
drivers/iommu/intel/iommu.c +2
-0@@ -5695,6 +5702,100 @@ static void intel_iommu_iotlb_sync_map(struct iommu_domain *domain, } } +static int intel_enable_pasid_dma (struct device *dev,u32 pasid) +{
This seems like completely the wrong kind of op.
At the level of the iommu driver things should be iommu_domain centric
The op should be
int attach_dev_pasid(struct iommu_domain *domain, struct device *dev, ioasid_t pasid)
Where 'dev' purpose is to provide the RID
The iommu_domain passed in should be the 'default domain' ie the table used for on-demand mapping, or the passthrough page table.
drivers/iommu/intel/iommu.c static void intel_iommu_iotlb_sync_map(struct iommu_domain *domain, · line 5708
Quoted 2 lines
drivers/iommu/intel/iommu.c +2
-0+struct intel_iommu *iommu =device_to_iommu (dev,NULL ,NULL ); +struct device_domain_info *info;
I don't even want to know why an iommu driver is tracking its own per-device state. That seems like completely wrong layering.
Jason
Re: [PATCH 3/4] iommu/vt-d: Support PASID DMA for in-kernel usage
Hi Jason,
Quoted 57 lines · Jason Gunthorpe
Quoted 44 lines · Jacob Pan
Between DMA requests with and without PASID (legacy), DMA mapping APIs are used indiscriminately on a device. Therefore, we should always match the addressing mode of the legacy DMA when enabling kernel PASID.
This patch adds support for VT-d driver where the kernel PASID is programmed to match RIDPASID. i.e. if the device is in pass-through, the kernel PASID is also in pass-through; if the device is in IOVA mode, the kernel PASID will also be using the same IOVA space.
There is additional handling for IOTLB and device TLB flush w.r.t. the kernel PASID. On VT-d, PASID-selective IOTLB flush is also on a per-domain basis; whereas device TLB flush is per device. Note that IOTLBs are used even when devices are in pass-through mode. ATS is enabled device-wide, but the device drivers can choose to manage ATS at per PASID level whenever control is available.
Signed-off-by Jacob Pan <[email protected]>drivers/iommu/intel/iommu.c | 105 +++++++++++++++++++++++++++++++++++- drivers/iommu/intel/pasid.c | 7 +++ include/linux/intel-iommu.h | 3 +- 3 files changed, 113 insertions(+), 2 deletions(-)drivers/iommu/intel/iommu.c +4
-1+++ b/drivers/iommu/intel/iommu.c@@ -1743,7 +1743,14 @@ static void domain_flush_piotlb(struct intel_iommu *iommu, if (domain->default_pasid)qi_flush_piotlb (iommu, did, domain->default_pasid, addr, npages, ih); - +if (domain->kernel_pasid && !domain_type_is_si (domain)) { +/* +* REVISIT: we only do PASID IOTLB inval for FL, we could have SL
drivers/iommu/intel/iommu.c +1
-0+* for PASID in the future such as vIOMMU PT. this doesn't get hit.
drivers/iommu/intel/iommu.c +4
-0+*/ +qi_flush_piotlb (iommu, did, domain->kernel_pasid, + addr, npages, ih); + }if (!list_empty (&domain->devices)) qi_flush_piotlb(iommu, did, PASID_RID2PASID, addr,npages, ih); }
drivers/iommu/intel/iommu.c static void intel_iommu_iotlb_sync_map(struct · line 5706
Quoted 5 lines
drivers/iommu/intel/iommu.c +2
-0@@ -5695,6 +5702,100 @@ static void intel_iommu_iotlb_sync_map(struct iommu_domain *domain, } } +static int intel_enable_pasid_dma (struct device *dev,u32 pasid) +{This seems like completely the wrong kind of op.
At the level of the iommu driver things should be
iommu_domaincentricThe op should be
Quoted 8 lines
int
attach_dev_pasid(struct iommu_domain *domain, struct device *dev, ioasid_t pasid)Where 'dev' purpose is to provide the RID
The
iommu_domainpassed in should be the 'default domain' ie the table used for on-demand mapping, or the passthrough page table.
Makes sense. DMA API is device centric, iommu API is domain centric. It should be the common IOMMU code to get the default domain then pass to vendor drivers. Then we can enforce default domain behavior across all vendor drivers.
i.e.
dom = iommu_get_dma_domain(dev); attach_dev_pasid(dom, dev, pasid);
Quoted 6 lines
drivers/iommu/intel/iommu.c static void intel_iommu_iotlb_sync_map(struct · line 5708
Quoted 2 lines
drivers/iommu/intel/iommu.c +2
-0+struct intel_iommu *iommu =device_to_iommu (dev,NULL ,NULL ); +struct device_domain_info *info;I don't even want to know why an iommu driver is tracking its own per-device state. That seems like completely wrong layering.
This is for IOTLB and deTLB flush. IOTLB is flushed at per domain level, devTLB is per device.
For multi-device groups, this is a need to track how many devices are using the kernel DMA PASID.
Are you suggesting we add the tracking info in the generic layer? i.e. iommu_group.
We could also have a generic device domain info to replace what is in VT-d and FSL IOMMU driver, etc.
Thanks,
Jacob
_______________________________________________
iommu mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/iommu
Lu Baolu
maintainerRe: [PATCH 3/4] iommu/vt-d: Support PASID DMA for in-kernel usage
Quoted 86 lines · Jacob Pan
Hi Jason,
Quoted 57 lines · Jason Gunthorpe
Quoted 44 lines · Jacob Pan
Between DMA requests with and without PASID (legacy), DMA mapping APIs are used indiscriminately on a device. Therefore, we should always match the addressing mode of the legacy DMA when enabling kernel PASID.
This patch adds support for VT-d driver where the kernel PASID is programmed to match RIDPASID. i.e. if the device is in pass-through, the kernel PASID is also in pass-through; if the device is in IOVA mode, the kernel PASID will also be using the same IOVA space.
There is additional handling for IOTLB and device TLB flush w.r.t. the kernel PASID. On VT-d, PASID-selective IOTLB flush is also on a per-domain basis; whereas device TLB flush is per device. Note that IOTLBs are used even when devices are in pass-through mode. ATS is enabled device-wide, but the device drivers can choose to manage ATS at per PASID level whenever control is available.
Signed-off-by Jacob Pan <[email protected]>drivers/iommu/intel/iommu.c | 105 +++++++++++++++++++++++++++++++++++- drivers/iommu/intel/pasid.c | 7 +++ include/linux/intel-iommu.h | 3 +- 3 files changed, 113 insertions(+), 2 deletions(-)drivers/iommu/intel/iommu.c +4
-1+++ b/drivers/iommu/intel/iommu.c@@ -1743,7 +1743,14 @@ static void domain_flush_piotlb(struct intel_iommu *iommu, if (domain->default_pasid)qi_flush_piotlb (iommu, did, domain->default_pasid, addr, npages, ih); - +if (domain->kernel_pasid && !domain_type_is_si (domain)) { +/* +* REVISIT: we only do PASID IOTLB inval for FL, we could have SL
drivers/iommu/intel/iommu.c +1
-0+* for PASID in the future such as vIOMMU PT. this doesn't get hit.
drivers/iommu/intel/iommu.c +4
-0+*/ +qi_flush_piotlb (iommu, did, domain->kernel_pasid, + addr, npages, ih); + }if (!list_empty (&domain->devices)) qi_flush_piotlb(iommu, did, PASID_RID2PASID, addr,npages, ih); }
drivers/iommu/intel/iommu.c static void intel_iommu_iotlb_sync_map(struct · line 5706
Quoted 5 lines
drivers/iommu/intel/iommu.c +2
-0@@ -5695,6 +5702,100 @@ static void intel_iommu_iotlb_sync_map(struct iommu_domain *domain, } } +static int intel_enable_pasid_dma (struct device *dev,u32 pasid) +{This seems like completely the wrong kind of op.
At the level of the iommu driver things should be
iommu_domaincentricThe op should be
Quoted 8 lines
int
attach_dev_pasid(struct iommu_domain *domain, struct device *dev, ioasid_t pasid)Where 'dev' purpose is to provide the RID
The
iommu_domainpassed in should be the 'default domain' ie the table used for on-demand mapping, or the passthrough page table.Makes sense. DMA API is device centric, iommu API is domain centric. It should be the common IOMMU code to get the default domain then pass to vendor drivers. Then we can enforce default domain behavior across all vendor drivers.
i.e.dom = iommu_get_dma_domain(dev); attach_dev_pasid(dom, dev, pasid);Quoted 6 lines
drivers/iommu/intel/iommu.c static void intel_iommu_iotlb_sync_map(struct · line 5708
Quoted 2 lines
drivers/iommu/intel/iommu.c +2
-0+struct intel_iommu *iommu =device_to_iommu (dev,NULL ,NULL ); +struct device_domain_info *info;I don't even want to know why an iommu driver is tracking its own per-device state. That seems like completely wrong layering.
This is for IOTLB and deTLB flush. IOTLB is flushed at per domain level, devTLB is per device.
Quoted 8 lines
For multi-device groups, this is a need to track how many devices are using the kernel DMA PASID.
Are you suggesting we add the tracking info in the generic layer? i.e.
iommu_group.We could also have a generic device domain info to replace what is in VT-d and FSL IOMMU driver, etc.
The store place of per-device iommu driver private data has already been standardized. The iommu core provides below interfaces for this purpose:
void dev_iommu_priv_set(struct device *dev, void *priv); void *dev_iommu_priv_get(struct device *dev);
If we have anything generic among different vendor iommu drivers, perhaps we could move them into dev->iommu.
Best regards,
baolu
Re: [PATCH 3/4] iommu/vt-d: Support PASID DMA for in-kernel usage
Hi Lu,
Quoted 97 lines · Lu Baolu
Quoted 87 lines · Jacob Pan
Hi Jason,
Quoted 58 lines · Jason Gunthorpe
Quoted 45 lines · Jacob Pan
Between DMA requests with and without PASID (legacy), DMA mapping APIs are used indiscriminately on a device. Therefore, we should always match the addressing mode of the legacy DMA when enabling kernel PASID.
This patch adds support for VT-d driver where the kernel PASID is programmed to match RIDPASID. i.e. if the device is in pass-through, the kernel PASID is also in pass-through; if the device is in IOVA mode, the kernel PASID will also be using the same IOVA space.
There is additional handling for IOTLB and device TLB flush w.r.t. the kernel PASID. On VT-d, PASID-selective IOTLB flush is also on a per-domain basis; whereas device TLB flush is per device. Note that IOTLBs are used even when devices are in pass-through mode. ATS is enabled device-wide, but the device drivers can choose to manage ATS at per PASID level whenever control is available.
Signed-off-by Jacob Pan <[email protected]>drivers/iommu/intel/iommu.c | 105 +++++++++++++++++++++++++++++++++++- drivers/iommu/intel/pasid.c | 7 +++ include/linux/intel-iommu.h | 3 +- 3 files changed, 113 insertions(+), 2 deletions(-)drivers/iommu/intel/iommu.c +4
-1+++ b/drivers/iommu/intel/iommu.c@@ -1743,7 +1743,14 @@ static void domain_flush_piotlb(struct intel_iommu *iommu, if (domain->default_pasid)qi_flush_piotlb (iommu, did, domain->default_pasid, addr, npages, ih); - +if (domain->kernel_pasid && !domain_type_is_si (domain)) { +/* +* REVISIT: we only do PASID IOTLB inval for FL, we could have SL
drivers/iommu/intel/iommu.c +1
-0+* for PASID in the future such as vIOMMU PT. this doesn't get hit.
drivers/iommu/intel/iommu.c +4
-0+*/ +qi_flush_piotlb (iommu, did, domain->kernel_pasid, + addr, npages, ih); + }if (!list_empty (&domain->devices)) qi_flush_piotlb(iommu, did, PASID_RID2PASID, addr,npages, ih); }
drivers/iommu/intel/iommu.c static void intel_iommu_iotlb_sync_map(struct · line 5706
Quoted 5 lines
drivers/iommu/intel/iommu.c +2
-0@@ -5695,6 +5702,100 @@ static void intel_iommu_iotlb_sync_map(struct iommu_domain *domain, } } +static int intel_enable_pasid_dma (struct device *dev,u32 pasid) +{This seems like completely the wrong kind of op.
At the level of the iommu driver things should be
iommu_domaincentricThe op should be
Quoted 8 lines
int
attach_dev_pasid(struct iommu_domain *domain, struct device *dev, ioasid_t pasid)Where 'dev' purpose is to provide the RID
The
iommu_domainpassed in should be the 'default domain' ie the table used for on-demand mapping, or the passthrough page table.Makes sense. DMA API is device centric, iommu API is domain centric. It should be the common IOMMU code to get the default domain then pass to vendor drivers. Then we can enforce default domain behavior across all vendor drivers.
i.e.dom = iommu_get_dma_domain(dev); attach_dev_pasid(dom, dev, pasid);Quoted 6 lines
drivers/iommu/intel/iommu.c static void intel_iommu_iotlb_sync_map(struct · line 5708
Quoted 2 lines
drivers/iommu/intel/iommu.c +2
-0+struct intel_iommu *iommu =device_to_iommu (dev,NULL ,NULL ); +struct device_domain_info *info;I don't even want to know why an iommu driver is tracking its own per-device state. That seems like completely wrong layering.
This is for IOTLB and deTLB flush. IOTLB is flushed at per domain level, devTLB is per device.
Quoted 8 lines
For multi-device groups, this is a need to track how many devices are using the kernel DMA PASID.
Are you suggesting we add the tracking info in the generic layer? i.e.
iommu_group.We could also have a generic device domain info to replace what is in VT-d and FSL IOMMU driver, etc.
Quoted 9 lines
The store place of per-device iommu driver private data has already been standardized. The iommu core provides below interfaces for this purpose:
void
dev_iommu_priv_set(struct device *dev, void *priv); void *dev_iommu_priv_get(struct device *dev);If we have anything generic among different vendor iommu drivers, perhaps we could move them into
dev->iommu.
Yes, good suggestion. DMA PASID should be a generic feature, not suitable for the opaque private date. Can we agree on adding the following flag for devTLB invalidation?
@@ -379,6 +379,7 @@ struct dev_iommu {
struct iommu_fwspec *fwspec;
struct iommu_device *iommu_dev;
void *priv;+ u32 pasid_dma_enabled : 1;
};
For DMA PASID storage, can we store it in the iommu_domain instead of iommu_group? In the end, this PASID is only used for the default domain. It will be easier to refcount how many attached devices are using the PASID. Destroy the PASID when no devices in the group are using PASID DMA. IOTLB flush is per domain also.
Jason, do you have guidance here?
Quoted 2 lines
Best regards,
baolu
Thanks,
Jacob
Re: [PATCH 3/4] iommu/vt-d: Support PASID DMA for in-kernel usage
Quoted 2 lines · Jacob Pan
For DMA PASID storage, can we store it in the
iommu_domaininstead ofiommu_group?
It doesn't make sense to put in the domain, the domain should be only the page table and not have any relation to how things are matched to it
Jason
Lu Baolu
maintainerRe: [PATCH 3/4] iommu/vt-d: Support PASID DMA for in-kernel usage
In reply to Jacob PanQuoted 117 lines · Jacob Pan
Quoted 94 lines · Lu Baolu
Quoted 85 lines · Jacob Pan
Hi Jason,
Quoted 57 lines · Jason Gunthorpe
Quoted 45 lines · Jacob Pan
Between DMA requests with and without PASID (legacy), DMA mapping APIs are used indiscriminately on a device. Therefore, we should always match the addressing mode of the legacy DMA when enabling kernel PASID.
This patch adds support for VT-d driver where the kernel PASID is programmed to match RIDPASID. i.e. if the device is in pass-through, the kernel PASID is also in pass-through; if the device is in IOVA mode, the kernel PASID will also be using the same IOVA space.
There is additional handling for IOTLB and device TLB flush w.r.t. the kernel PASID. On VT-d, PASID-selective IOTLB flush is also on a per-domain basis; whereas device TLB flush is per device. Note that IOTLBs are used even when devices are in pass-through mode. ATS is enabled device-wide, but the device drivers can choose to manage ATS at per PASID level whenever control is available.
Signed-off-by Jacob Pan<[email protected]>drivers/iommu/intel/iommu.c | 105 +++++++++++++++++++++++++++++++++++- drivers/iommu/intel/pasid.c | 7 +++ include/linux/intel-iommu.h | 3 +- 3 files changed, 113 insertions(+), 2 deletions(-)drivers/iommu/intel/iommu.c +4
-1+++ b/drivers/iommu/intel/iommu.c@@ -1743,7 +1743,14 @@ static void domain_flush_piotlb(struct intel_iommu *iommu, if (domain->default_pasid)qi_flush_piotlb (iommu, did, domain->default_pasid, addr, npages, ih); - +if (domain->kernel_pasid && !domain_type_is_si (domain)) { +/* +* REVISIT: we only do PASID IOTLB inval for FL, we could have SL
drivers/iommu/intel/iommu.c +1
-0+* for PASID in the future such as vIOMMU PT. this doesn't get hit.
drivers/iommu/intel/iommu.c +4
-0+*/ +qi_flush_piotlb (iommu, did, domain->kernel_pasid, + addr, npages, ih); + }if (!list_empty (&domain->devices)) qi_flush_piotlb(iommu, did, PASID_RID2PASID, addr,npages, ih); }
drivers/iommu/intel/iommu.c static void intel_iommu_iotlb_sync_map(struct · line 5706
Quoted 5 lines
drivers/iommu/intel/iommu.c +2
-0@@ -5695,6 +5702,100 @@ static void intel_iommu_iotlb_sync_map(struct iommu_domain *domain, } } +static int intel_enable_pasid_dma (struct device *dev,u32 pasid) +{This seems like completely the wrong kind of op.
At the level of the iommu driver things should be
iommu_domaincentricThe op should be
Quoted 8 lines
int
attach_dev_pasid(struct iommu_domain *domain, struct device *dev, ioasid_t pasid)Where 'dev' purpose is to provide the RID
The
iommu_domainpassed in should be the 'default domain' ie the table used for on-demand mapping, or the passthrough page table.Makes sense. DMA API is device centric, iommu API is domain centric. It should be the common IOMMU code to get the default domain then pass to vendor drivers. Then we can enforce default domain behavior across all vendor drivers.
i.e.dom = iommu_get_dma_domain(dev); attach_dev_pasid(dom, dev, pasid);Quoted 5 lines
drivers/iommu/intel/iommu.c static void intel_iommu_iotlb_sync_map(struct · line 5708
Quoted 2 lines
drivers/iommu/intel/iommu.c +2
-0+struct intel_iommu *iommu =device_to_iommu (dev,NULL ,NULL ); +struct device_domain_info *info;I don't even want to know why an iommu driver is tracking its own per-device state. That seems like completely wrong layering.
This is for IOTLB and deTLB flush. IOTLB is flushed at per domain level, devTLB is per device.
Quoted 8 lines
For multi-device groups, this is a need to track how many devices are using the kernel DMA PASID.
Are you suggesting we add the tracking info in the generic layer? i.e.
iommu_group.We could also have a generic device domain info to replace what is in VT-d and FSL IOMMU driver, etc.
Quoted 9 lines
The store place of per-device iommu driver private data has already been standardized. The iommu core provides below interfaces for this purpose:
void
dev_iommu_priv_set(struct device *dev, void *priv); void *dev_iommu_priv_get(struct device *dev);If we have anything generic among different vendor iommu drivers, perhaps we could move them into
dev->iommu.Yes, good suggestion. DMA PASID should be a generic feature, not suitable for the opaque private date. Can we agree on adding the following flag for devTLB invalidation?
(quoted diff) +1
-0@@ -379,6 +379,7 @@ struct dev_iommu { struct iommu_fwspec *fwspec; struct iommu_device *iommu_dev; void *priv; + u32 pasid_dma_enabled : 1; };
Quoted 5 lines
For DMA PASID storage, can we store it in the
iommu_domaininstead ofiommu_group? In the end, this PASID is only used for the default domain. It will be easier to refcount how many attached devices are using the PASID. Destroy the PASID when no devices in the group are using PASID DMA. IOTLB flush is per domain also.
Tying pasid to an iommu_domain is not a good idea. An iommu_domain represents an I/O address translation table. It could be attached to a device or a PASID on the device.
Perhaps the dev_iommu is a reasonable place for this.
@@ -390,6 +390,8 @@ struct dev_iommu {
struct iommu_fwspec *fwspec;
struct iommu_device *iommu_dev;
void *priv;
+ unsigned int pasid_bits;
+ u32 kernel_dma_pasid;};
@pasid_bits is a static attribute of a device which supports PASID feature. It reads the PASID bitwidth that the device could support. The vendor iommu driver could set this when the PASID feature is about to be enabled. Normally, it's the MIN of device and iommu capabilities.
@kernel_dma_pasid is the PASID value used for kernel DMA if it's enabled. It reads INVALID_IOASID if kernel DMA with PASID is not enabled.
Best regards,
baolu
Re: [PATCH 3/4] iommu/vt-d: Support PASID DMA for in-kernel usage
Hi Lu,
Quoted 121 lines · Lu Baolu
Quoted 120 lines · Jacob Pan
Quoted 100 lines · Lu Baolu
Quoted 87 lines · Jacob Pan
Hi Jason,
Quoted 58 lines · Jason Gunthorpe
Quoted 45 lines · Jacob Pan
Between DMA requests with and without PASID (legacy), DMA mapping APIs are used indiscriminately on a device. Therefore, we should always match the addressing mode of the legacy DMA when enabling kernel PASID.
This patch adds support for VT-d driver where the kernel PASID is programmed to match RIDPASID. i.e. if the device is in pass-through, the kernel PASID is also in pass-through; if the device is in IOVA mode, the kernel PASID will also be using the same IOVA space.
There is additional handling for IOTLB and device TLB flush w.r.t. the kernel PASID. On VT-d, PASID-selective IOTLB flush is also on a per-domain basis; whereas device TLB flush is per device. Note that IOTLBs are used even when devices are in pass-through mode. ATS is enabled device-wide, but the device drivers can choose to manage ATS at per PASID level whenever control is available.
Signed-off-by Jacob Pan<[email protected]>drivers/iommu/intel/iommu.c | 105 +++++++++++++++++++++++++++++++++++- drivers/iommu/intel/pasid.c | 7 +++ include/linux/intel-iommu.h | 3 +- 3 files changed, 113 insertions(+), 2 deletions(-)(quoted diff) +0
-0
b/drivers/iommu/intel/iommu.cindex60253bc436bb..a2ef6b9e4bfc100644 +++b/drivers/iommu/intel/iommu.c(quoted diff) +3
-1@@ -1743,7 +1743,14 @@ static void domain_flush_piotlb(struct intel_iommu *iommu, if (domain->default_pasid) qi_flush_piotlb(iommu, did, domain->default_pasid, addr, npages, ih); - + if (domain->kernel_pasid && !domain_type_is_si(domain)) { + /* + * REVISIT: we only do PASID IOTLB inval for FL, wecould have SL
(quoted diff) +1
-0+ * for PASID in the future such as vIOMMU PT. thisdoesn't get hit.
drivers/iommu/intel/iommu.c +4
-0+*/ +qi_flush_piotlb (iommu, did, domain->kernel_pasid, + addr, npages, ih); + }if (!list_empty (&domain->devices)) qi_flush_piotlb(iommu, did, PASID_RID2PASID,addr, npages, ih); }
drivers/iommu/intel/iommu.c static void · line 5706
Quoted 5 lines
drivers/iommu/intel/iommu.c +2
-0@@ -5695,6 +5702,100 @@ static void intel_iommu_iotlb_sync_map(struct iommu_domain *domain, } } +static int intel_enable_pasid_dma (struct device *dev,u32 pasid) +{This seems like completely the wrong kind of op.
At the level of the iommu driver things should be
iommu_domaincentricThe op should be
Quoted 8 lines
int
attach_dev_pasid(struct iommu_domain *domain, struct device *dev, ioasid_t pasid)Where 'dev' purpose is to provide the RID
The
iommu_domainpassed in should be the 'default domain' ie the table used for on-demand mapping, or the passthrough page table.Makes sense. DMA API is device centric, iommu API is domain centric. It should be the common IOMMU code to get the default domain then pass to vendor drivers. Then we can enforce default domain behavior across all vendor drivers.
i.e.dom = iommu_get_dma_domain(dev); attach_dev_pasid(dom, dev, pasid);Quoted 6 lines
Review static void · line 5709
Quoted 3 lines
(quoted diff) +2
-0+ struct intel_iommu *iommu = device_to_iommu(dev, NULL, NULL); + struct device_domain_info *info;I don't even want to know why an iommu driver is tracking its own per-device state. That seems like completely wrong layering.
This is for IOTLB and deTLB flush. IOTLB is flushed at per domain level, devTLB is per device.
Quoted 8 lines
For multi-device groups, this is a need to track how many devices are using the kernel DMA PASID.
Are you suggesting we add the tracking info in the generic layer? i.e.
iommu_group.We could also have a generic device domain info to replace what is in VT-d and FSL IOMMU driver, etc.
The store place of per-device iommu driver private data has already been standardized. The iommu core provides below interfaces for this purpose:
Quoted 6 lines
void
dev_iommu_priv_set(struct device *dev, void *priv); void *dev_iommu_priv_get(struct device *dev);If we have anything generic among different vendor iommu drivers, perhaps we could move them into
dev->iommu.Yes, good suggestion. DMA PASID should be a generic feature, not suitable for the opaque private date. Can we agree on adding the following flag for devTLB invalidation?
(quoted diff) +1
-0@@ -379,6 +379,7 @@ struct dev_iommu { struct iommu_fwspec *fwspec; struct iommu_device *iommu_dev; void *priv; + u32 pasid_dma_enabled : 1; };
Quoted 10 lines
Quoted 5 lines
For DMA PASID storage, can we store it in the
iommu_domaininstead ofiommu_group? In the end, this PASID is only used for the default domain. It will be easier to refcount how many attached devices are using the PASID. Destroy the PASID when no devices in the group are using PASID DMA. IOTLB flush is per domain also.Tying pasid to an
iommu_domainis not a good idea. Aniommu_domainrepresents an I/O address translation table. It could be attached to a device or a PASID on the device.
I don;t think we can avoid storing PASID at domain level or the group's default domain. IOTLB flush is per domain. Default domain of DMA type is already tying to PASID0, right?
Quoted 15 lines
Perhaps the
dev_iommuis a reasonable place for this.(quoted diff) +2
-0@@ -390,6 +390,8 @@ struct dev_iommu { struct iommu_fwspec *fwspec; struct iommu_device *iommu_dev; void *priv; + unsigned int pasid_bits; + u32 kernel_dma_pasid; };@pasid_bits is a static attribute of a device which supports PASID feature. It reads the PASID bitwidth that the device could support. The vendor iommu driver could set this when the PASID feature is about to be enabled. Normally, it's the MIN of device and iommu capabilities.
Quoted 4 lines
@kernel_dma_pasid is the PASID value used for kernel DMA if it's enabled. It reads
INVALID_IOASIDif kernel DMA with PASID is not enabled.
This essentially goes back to the same layering as struct device.pasid, just embedded under device.iommu.pasid. That is fine but we still need a per domain PASID info. I see the the following functionalities:
1. per device PASID info for devTLB flush
2. per domain PASID info for IOTLB flush for all attached devices The PASID info includes PASID value, user/device count, enabled status.
Though both DMA API PASID and RIDPASID (0) are mapped identically, RIDPASID TLB flush is implied for all devices attached to a domain. That is why we don't need to track it.
For DMA API PASID, it is opt-in by device drivers, therefore we must track on a per-domain basis to see how many attached devices are using this PASID. This will avoid blindly flushing IOTLBs for DMA API PASID. dma_unmap() does not tell you which PASIDs to flush.
In this patchset, I store per domain DMA API PASID info in VT-d only dmar_domain. (VT-d is the only user so far). If we were to store it the generic layer, this could be simpler.
Quoted 2 lines
Best regards,
baolu
Thanks,
Jacob
Re: [PATCH 3/4] iommu/vt-d: Support PASID DMA for in-kernel usage
Quoted 7 lines · Jacob Pan
Quoted 3 lines
Tying pasid to an
iommu_domainis not a good idea. Aniommu_domainrepresents an I/O address translation table. It could be attached to a device or a PASID on the device.I don;t think we can avoid storing PASID at domain level or the group's default domain. IOTLB flush is per domain. Default domain of DMA type is already tying to PASID0, right?
No, it is just wrong.
If the HW requires a list of everything that is connected to the iommu_domain then it's private iommu_domain should have that list.
But it is a *list* not a single PASID.
If one device has 10 PASID's pointing to this domain you must flush them all if that is what the HW requires.
Jason
_______________________________________________
iommu mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH 3/4] iommu/vt-d: Support PASID DMA for in-kernel usage
Hi Jason,
Quoted 6 lines · Jason Gunthorpe
Quoted 4 lines · Jacob Pan
Quoted 3 lines
Tying pasid to an
iommu_domainis not a good idea. Aniommu_domainrepresents an I/O address translation table. It could be attached to a device or a PASID on the device.
Quoted 9 lines
Quoted 3 lines
I don;t think we can avoid storing PASID at domain level or the group's default domain. IOTLB flush is per domain. Default domain of DMA type is already tying to PASID0, right?
No, it is just wrong.
If the HW requires a list of everything that is connected to the
iommu_domainthen it's privateiommu_domainshould have that list.
What I have in this patchset is in the private dmar_domain
struct dmar_domain {
...
u32 kernel_pasid; /* for in-kernel DMA w/PASID */ atomic_t kernel_pasid_user; /* count of kernel_pasid users
*/ struct iommu_domain domain; /* generic domain data structure for
iommu core */
};
Perhaps I am missing the point. "private domain" is still "domain level" as what I stated. Confused :(
Quoted 2 lines
But it is a *list* not a single PASID.
We could have a list when real use case comes.
Quoted 3 lines
If one device has 10 PASID's pointing to this domain you must flush them all if that is what the HW requires.
Yes. My point is that other than PASID 0 is a given, we must track the 10 PASIDs to avoid wasted flush. It also depend on how TLBs are tagged and flush granularity available. But at the API level, should we support all the cases?
Quoted 1 line
Jason
Thanks,
Jacob
_______________________________________________
iommu mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH 3/4] iommu/vt-d: Support PASID DMA for in-kernel usage
Quoted 7 lines · Jacob Pan
Quoted 3 lines
If one device has 10 PASID's pointing to this domain you must flush them all if that is what the HW requires.
Yes. My point is that other than PASID 0 is a given, we must track the 10 PASIDs to avoid wasted flush. It also depend on how TLBs are tagged and flush granularity available. But at the API level, should we support all the cases?
Yes, iommufd will expose all the cases to userspace and anything is possible.
A scheme that can only attach a domain to one PASID is functionally useless except for this IDXD problem, so don't make something so broken.
Jason
PATCH 4/4 dmaengine: idxd: Use DMA API for in-kernel DMA with PASID
In reply to Jacob PanIn-kernel DMA should be managed by DMA mapping API. The existing kernel PASID support is based on the SVA machinery in SVA lib that is intended for user process SVA. The binding between a kernel PASID and kernel mapping has many flaws. See discussions in the link below.
This patch utilizes iommu_enable_pasid_dma() to enable DSA to perform DMA requests with PASID under the same mapping managed by DMA mapping API. In addition, SVA-related bits for kernel DMA are removed. As a result, DSA users shall use DMA mapping API to obtain DMA handles instead of using kernel virtual addresses.
--- .../admin-guide/kernel-parameters.txt | 6 -- drivers/dma/Kconfig | 10 ---- drivers/dma/idxd/idxd.h | 1 - drivers/dma/idxd/init.c | 59 ++++++------------- drivers/dma/idxd/sysfs.c | 7 --- 5 files changed, 19 insertions(+), 64 deletions(-)
Documentation/admin-guide/kernel-parameters.txt +0 -6
@@ -1751,12 +1751,6 @@ In such case C2/C3 won't be used again. idle=nomwait: Disable mwait for CPU C-states - idxd.sva= [HW] - Format: <bool> - Allow force disabling of Shared Virtual Memory (SVA) - support for the idxd driver. By default it is set to - true (1). - idxd.tc_override= [HW] Format: <bool> Allow override of default traffic class configuration
drivers/dma/Kconfig +0 -10
@@ -313,16 +313,6 @@ config INTEL_IDXD_COMPAT If unsure, say N. -# Config symbol that collects all the dependencies that's necessary to -# support shared virtual memory for the devices supported by idxd. -config INTEL_IDXD_SVM - bool "Accelerator Shared Virtual Memory Support" - depends on INTEL_IDXD - depends on INTEL_IOMMU_SVM - depends on PCI_PRI - depends on PCI_PASID - depends on PCI_IOV - config INTEL_IDXD_PERFMON bool "Intel Data Accelerators performance monitor support" depends on INTEL_IDXD
drivers/dma/idxd/idxd.h +0 -1
@@ -262,7 +262,6 @@ struct idxd_device {struct idxd_wq **wqs;struct idxd_engine **engines; -struct iommu_sva *sva;unsigned int pasid;int num_groups;
drivers/dma/idxd/init.c +19 -40
92 lines not on this page · raw message
drivers/dma/idxd/sysfs.c +0 -7
@@ -776,13 +776,6 @@ static ssize_t wq_name_store(struct device *dev,if (strlen (buf) >WQ_NAME_SIZE ||strlen (buf) ==0 )return -EINVAL ; -/* -* This is temporarily placed here until we have SVM support for -* dmaengine. -*/ -if (wq->type ==IDXD_WQT_KERNEL &&device_pasid_enabled (wq->idxd)) -return -EOPNOTSUPP ; -memset (wq->name,0 ,WQ_NAME_SIZE +1 );strncpy (wq->name, buf,WQ_NAME_SIZE );strreplace (wq->name,'\n' ,'\0' );
Signature · 6 lines
2.25.1 _______________________________________________ iommu mailing list [email protected] https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH 4/4] dmaengine: idxd: Use DMA API for in-kernel DMA with PASID
Quoted 5 lines · Jacob Pan
In-kernel DMA should be managed by DMA mapping API. The existing kernel PASID support is based on the SVA machinery in SVA lib that is intended for user process SVA. The binding between a kernel PASID and kernel mapping has many flaws. See discussions in the link below.
Quoted 8 lines
This patch utilizes
iommu_enable_pasid_dma()to enable DSA to perform DMA requests with PASID under the same mapping managed by DMA mapping API. In addition, SVA-related bits for kernel DMA are removed. As a result, DSA users shall use DMA mapping API to obtain DMA handles instead of using kernel virtual addresses.
Also cc Vinod and dmaengine@vger
Quoted 176 lines
--- .../admin-guide/kernel-parameters.txt | 6 -- drivers/dma/Kconfig | 10 ---- drivers/dma/idxd/idxd.h | 1 - drivers/dma/idxd/init.c | 59 ++++++------------- drivers/dma/idxd/sysfs.c | 7 --- 5 files changed, 19 insertions(+), 64 deletions(-)Documentation/admin-guide/kernel-parameters.txt +0
-6@@ -1751,12 +1751,6 @@ In such case C2/C3 won't be used again. idle=nomwait: Disable mwait for CPU C-states - idxd.sva= [HW] - Format: <bool> - Allow force disabling of Shared Virtual Memory (SVA) - support for the idxd driver. By default it is set to - true (1). - idxd.tc_override= [HW] Format: <bool> Allow override of default traffic class configurationdrivers/dma/Kconfig +0
-10@@ -313,16 +313,6 @@ config INTEL_IDXD_COMPAT If unsure, say N. -# Config symbol that collects all the dependencies that's necessary to -# support shared virtual memory for the devices supported by idxd. -config INTEL_IDXD_SVM - bool "Accelerator Shared Virtual Memory Support" - depends on INTEL_IDXD - depends on INTEL_IOMMU_SVM - depends on PCI_PRI - depends on PCI_PASID - depends on PCI_IOV - config INTEL_IDXD_PERFMON bool "Intel Data Accelerators performance monitor support" depends on INTEL_IDXDdrivers/dma/idxd/idxd.h +0
-1@@ -262,7 +262,6 @@ struct idxd_device {struct idxd_wq **wqs;struct idxd_engine **engines; -struct iommu_sva *sva;unsigned int pasid;int num_groups;drivers/dma/idxd/init.c +19
-40@@ -16,6 +16,7 @@#include <linux/idr.h> #include <linux/intel-svm.h> #include <linux/iommu.h> +#include <linux/dma-iommu.h> #include <uapi/linux/idxd.h> #include <linux/dmaengine.h> #include "../dmaengine.h" @@ -28,10 +29,6 @@ MODULE_LICENSE("GPL v2");MODULE_AUTHOR ("Intel Corporation" );MODULE_IMPORT_NS (IDXD ); -static bool sva = true; -module_param (sva, bool,0644 ); -MODULE_PARM_DESC (sva,"Toggle SVA support on/off" ); -bool tc_override;module_param (tc_override, bool,0644 );MODULE_PARM_DESC (tc_override,"Override traffic class defaults" );@@ -530,36 +527,22 @@ static struct idxd_device *idxd_alloc(struct pci_dev *pdev, struct idxd_driver_dstatic int idxd_enable_system_pasid (struct idxd_device *idxd) { -int flags; -unsigned int pasid; -struct iommu_sva *sva; - - flags =SVM_FLAG_SUPERVISOR_MODE ; - - sva =iommu_sva_bind_device (&idxd->pdev->dev,NULL , &flags); -if (IS_ERR (sva)) { -dev_warn (&idxd->pdev->dev, -"iommu sva bind failed: %ld\n" ,PTR_ERR (sva)); -return PTR_ERR (sva); - } +u32 pasid; - pasid =iommu_sva_get_pasid (sva); -if (pasid ==IOMMU_PASID_INVALID ) { -iommu_sva_unbind_device (sva); + pasid =iommu_enable_pasid_dma (&idxd->pdev->dev); +if (pasid ==INVALID_IOASID ) { +dev_err (&idxd->pdev->dev,"No kernel DMA PASID\n" );return -ENODEV ; } - - idxd->sva = sva; idxd->pasid = pasid; -dev_dbg (&idxd->pdev->dev,"system pasid: %u\n" , pasid); +return 0 ; }static void idxd_disable_system_pasid (struct idxd_device *idxd) { - -iommu_sva_unbind_device (idxd->sva); - idxd->sva =NULL ; +iommu_disable_pasid_dma (&idxd->pdev->dev); + idxd->pasid =0 ; }static int idxd_probe (struct idxd_device *idxd)@@ -575,21 +558,17 @@ static int idxd_probe(struct idxd_device *idxd)dev_dbg (dev,"IDXD reset complete\n" ); -if (IS_ENABLED (CONFIG_INTEL_IDXD_SVM ) && sva) { - rc =iommu_dev_enable_feature (dev,IOMMU_DEV_FEAT_SVA ); -if (rc ==0 ) { - rc =idxd_enable_system_pasid (idxd); -if (rc <0 ) { -iommu_dev_disable_feature (dev,IOMMU_DEV_FEAT_SVA ); -dev_warn (dev,"Failed to enable PASID. No SVA support: %d\n" , rc); - }else { -set_bit (IDXD_FLAG_PASID_ENABLED , &idxd->flags); - } - }else { -dev_warn (dev,"Unable to turn on SVA feature.\n" ); - } - }else if (!sva) { -dev_warn (dev,"User forced SVA off via module param.\n" ); +/* +* Try to enable both in-kernel and user DMA request with PASID. +* PASID is supported unless both user and kernel PASID are +* supported. Do not fail probe here in that idxd can still be +* used w/o PASID or IOMMU. +*/ +if (iommu_dev_enable_feature (dev,IOMMU_DEV_FEAT_SVA ) || +idxd_enable_system_pasid (idxd)) { +dev_warn (dev,"Failed to enable PASID\n" ); + }else { +set_bit (IDXD_FLAG_PASID_ENABLED , &idxd->flags); }idxd_read_caps (idxd);drivers/dma/idxd/sysfs.c +0
-7@@ -776,13 +776,6 @@ static ssize_t wq_name_store(struct device *dev,if (strlen (buf) >WQ_NAME_SIZE ||strlen (buf) ==0 )return -EINVAL ; -/* -* This is temporarily placed here until we have SVM support for -* dmaengine. -*/ -if (wq->type ==IDXD_WQT_KERNEL &&device_pasid_enabled (wq->idxd)) -return -EOPNOTSUPP ; -memset (wq->name,0 ,WQ_NAME_SIZE +1 );strncpy (wq->name, buf,WQ_NAME_SIZE );strreplace (wq->name,'\n' ,'\0' );
Vinod Koul
maintainerRe: [PATCH 4/4] dmaengine: idxd: Use DMA API for in-kernel DMA with PASID
Quoted 13 lines · Dave Jiang
Quoted 11 lines · Jacob Pan
In-kernel DMA should be managed by DMA mapping API. The existing kernel PASID support is based on the SVA machinery in SVA lib that is intended for user process SVA. The binding between a kernel PASID and kernel mapping has many flaws. See discussions in the link below.
This patch utilizes
iommu_enable_pasid_dma()to enable DSA to perform DMA requests with PASID under the same mapping managed by DMA mapping API. In addition, SVA-related bits for kernel DMA are removed. As a result, DSA users shall use DMA mapping API to obtain DMA handles instead of using kernel virtual addresses.
Quoted 6 lines
Quoted 2 lines
Acked-by Dave Jiang <[email protected]>Also cc Vinod and dmaengine@vger
Pls resend collecting acks. I dont have this in my queue
Signature · 1 line
~Vinod
Re: [PATCH 4/4] dmaengine: idxd: Use DMA API for in-kernel DMA with PASID
Hi Vinod,
Quoted 1 line · Vinod Koul
Pls resend collecting acks. I dont have this in my queue
Will do. Sorry I missed the dmaengine list.
Thanks,
Jacob
Re: [PATCH 4/4] dmaengine: idxd: Use DMA API for in-kernel DMA with PASID
In reply to Jacob PanQuoted 10 lines · Jacob Pan
In-kernel DMA should be managed by DMA mapping API. The existing kernel PASID support is based on the SVA machinery in SVA lib that is intended for user process SVA. The binding between a kernel PASID and kernel mapping has many flaws. See discussions in the link below.
This patch utilizes
iommu_enable_pasid_dma()to enable DSA to perform DMA requests with PASID under the same mapping managed by DMA mapping API. In addition, SVA-related bits for kernel DMA are removed. As a result, DSA users shall use DMA mapping API to obtain DMA handles instead of using kernel virtual addresses.
Er, shouldn't this be adding dma_map/etc type calls?
You can't really say a driver is using the DMA API without actually calling the DMA API..
drivers/dma/idxd/init.c static int idxd_probe(struct idxd_device *idxd) · line 572
Quoted 12 lines
drivers/dma/idxd/init.c +11
-0+/* +* Try to enable both in-kernel and user DMA request with PASID. +* PASID is supported unless both user and kernel PASID are +* supported. Do not fail probe here in that idxd can still be +* used w/o PASID or IOMMU. +*/ +if (iommu_dev_enable_feature (dev,IOMMU_DEV_FEAT_SVA ) || +idxd_enable_system_pasid (idxd)) { +dev_warn (dev,"Failed to enable PASID\n" ); + }else { +set_bit (IDXD_FLAG_PASID_ENABLED , &idxd->flags); }
Huh? How can the driver keep going if PASID isn't supported? I thought the whole point of this was because the device cannot do DMA without PASID at all?
Jason
Dave Jiang
reviewerRe: [PATCH 4/4] dmaengine: idxd: Use DMA API for in-kernel DMA with PASID
Quoted 16 lines · Jason Gunthorpe
Quoted 10 lines · Jacob Pan
In-kernel DMA should be managed by DMA mapping API. The existing kernel PASID support is based on the SVA machinery in SVA lib that is intended for user process SVA. The binding between a kernel PASID and kernel mapping has many flaws. See discussions in the link below.
This patch utilizes
iommu_enable_pasid_dma()to enable DSA to perform DMA requests with PASID under the same mapping managed by DMA mapping API. In addition, SVA-related bits for kernel DMA are removed. As a result, DSA users shall use DMA mapping API to obtain DMA handles instead of using kernel virtual addresses.Er, shouldn't this be adding dma_map/etc type calls?
You can't really say a driver is using the DMA API without actually calling the DMA API..
Quoted 15 lines
drivers/dma/idxd/init.c static int idxd_probe(struct idxd_device *idxd) · line 572
Quoted 12 lines
drivers/dma/idxd/init.c +11
-0+/* +* Try to enable both in-kernel and user DMA request with PASID. +* PASID is supported unless both user and kernel PASID are +* supported. Do not fail probe here in that idxd can still be +* used w/o PASID or IOMMU. +*/ +if (iommu_dev_enable_feature (dev,IOMMU_DEV_FEAT_SVA ) || +idxd_enable_system_pasid (idxd)) { +dev_warn (dev,"Failed to enable PASID\n" ); + }else { +set_bit (IDXD_FLAG_PASID_ENABLED , &idxd->flags); }Huh? How can the driver keep going if PASID isn't supported? I thought the whole point of this was because the device cannot do DMA without PASID at all?
There are 2 types of WQ supported with the DSA devices. A dedicated WQ type and a shared WQ type. The dedicated WQ type can support DMA with and without PASID. The shared wq type must have a PASID to operate. The driver can support dedicated WQ only without PASID usage when there is no PASID support.
Quoted 2 lines
Jason
Re: [PATCH 4/4] dmaengine: idxd: Use DMA API for in-kernel DMA with PASID
Quoted 34 lines · Dave Jiang
Quoted 16 lines · Jason Gunthorpe
Quoted 10 lines · Jacob Pan
In-kernel DMA should be managed by DMA mapping API. The existing kernel PASID support is based on the SVA machinery in SVA lib that is intended for user process SVA. The binding between a kernel PASID and kernel mapping has many flaws. See discussions in the link below.
This patch utilizes
iommu_enable_pasid_dma()to enable DSA to perform DMA requests with PASID under the same mapping managed by DMA mapping API. In addition, SVA-related bits for kernel DMA are removed. As a result, DSA users shall use DMA mapping API to obtain DMA handles instead of using kernel virtual addresses.Er, shouldn't this be adding dma_map/etc type calls?
You can't really say a driver is using the DMA API without actually calling the DMA API..
Quoted 15 lines
drivers/dma/idxd/init.c static int idxd_probe(struct idxd_device *idxd) · line 572
Quoted 12 lines
drivers/dma/idxd/init.c +11
-0+/* +* Try to enable both in-kernel and user DMA request with PASID. +* PASID is supported unless both user and kernel PASID are +* supported. Do not fail probe here in that idxd can still be +* used w/o PASID or IOMMU. +*/ +if (iommu_dev_enable_feature (dev,IOMMU_DEV_FEAT_SVA ) || +idxd_enable_system_pasid (idxd)) { +dev_warn (dev,"Failed to enable PASID\n" ); + }else { +set_bit (IDXD_FLAG_PASID_ENABLED , &idxd->flags); }Huh? How can the driver keep going if PASID isn't supported? I thought the whole point of this was because the device cannot do DMA without PASID at all?
Quoted 5 lines
There are 2 types of WQ supported with the DSA devices. A dedicated WQ type and a shared WQ type. The dedicated WQ type can support DMA with and without PASID. The shared wq type must have a PASID to operate. The driver can support dedicated WQ only without PASID usage when there is no PASID support.
Can you add to the cover letter why does the kernel require to use the shared WQ?
Jason
RE: [PATCH 4/4] dmaengine: idxd: Use DMA API for in-kernel DMA with PASID
Quoted 23 lines
From: Jason Gunthorpe <[email protected]>
Sent: Thursday, December 9, 2021 1:51 AMQuoted 16 lines
Quoted 7 lines
Quoted 7 lines
drivers/dma/idxd/init.c +7
-0+/* +* Try to enable both in-kernel and user DMA request with PASID. +* PASID is supported unless both user and kernel PASID are +* supported. Do not fail probe here in that idxd can still be +* used w/o PASID or IOMMU. +*/ + if (iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA) ||Quoted 8 lines
drivers/dma/idxd/init.c static int idxd_probe(struct idxd_device *idxd) · line 572
Quoted 5 lines
drivers/dma/idxd/init.c +4
-0+ idxd_enable_system_pasid(idxd)) { + dev_warn(dev, "Failed to enable PASID\n"); + } else { +set_bit (IDXD_FLAG_PASID_ENABLED , &idxd->flags); }Huh? How can the driver keep going if PASID isn't supported? I thought the whole point of this was because the device cannot do DMA without PASID at all?
Quoted 1 line
There are 2 types of WQ supported with the DSA devices. A dedicated WQ
type
Quoted 1 line
and a shared WQ type. The dedicated WQ type can support DMA with and
without
Quoted 8 lines
Quoted 3 lines
PASID. The shared wq type must have a PASID to operate. The driver can support dedicated WQ only without PASID usage when there is no PASID support.
Can you add to the cover letter why does the kernel require to use the shared WQ?
Jason
Two reasons:
On native the shared WQ is useful when the kernel wants to offload some memory operations (e.g. page-zeroing) to DSA. When #CPUs are more than #WQs, this allows per-cpu lock-less submissions using ENQCMD(PASID, payload) instruction.
In guest the virtual DSA HW may only contain a WQ in shared mode (unchangeable by the guest) when the host admin wants to share the limited WQ resource among many VMs. Then there is no choice in guest regardless whether it's for user or kernel controlled DMA.
Thanks
Kevin
Re: [PATCH 4/4] dmaengine: idxd: Use DMA API for in-kernel DMA with PASID
Hi Kevin,
Quoted 43 lines · Kevin
Quoted 27 lines
From: Jason Gunthorpe <[email protected]>
Sent: Thursday, December 9, 2021 1:51 AMQuoted 19 lines
Quoted 10 lines
Quoted 10 lines
(quoted diff) +2
-0+ /* + * Try to enable both in-kernel and user DMA requestwith PASID.
(quoted diff) +1
-0+ * PASID is supported unless both user and kernel PASIDare
(quoted diff) +1
-0+ * supported. Do not fail probe here in that idxd canstill be
drivers/dma/idxd/init.c +3
-0+* used w/o PASID or IOMMU. +*/ + if (iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA) ||Quoted 8 lines
drivers/dma/idxd/init.c static int idxd_probe(struct idxd_device *idxd) · line 572
Quoted 5 lines
drivers/dma/idxd/init.c +4
-0+ idxd_enable_system_pasid(idxd)) { + dev_warn(dev, "Failed to enable PASID\n"); + } else { +set_bit (IDXD_FLAG_PASID_ENABLED , &idxd->flags); }Huh? How can the driver keep going if PASID isn't supported? I thought the whole point of this was because the device cannot do DMA without PASID at all?
Quoted 2 lines
There are 2 types of WQ supported with the DSA devices. A dedicated WQ
type
Quoted 1 line
and a shared WQ type. The dedicated WQ type can support DMA with and
without
Quoted 8 lines
Quoted 3 lines
PASID. The shared wq type must have a PASID to operate. The driver can support dedicated WQ only without PASID usage when there is no PASID support.
Can you add to the cover letter why does the kernel require to use the shared WQ?
Jason
Two reasons:
On native the shared WQ is useful when the kernel wants to offload some memory operations (e.g. page-zeroing) to DSA. When #CPUs are more than #WQs, this allows per-cpu lock-less submissions using
ENQCMD(PASID, payload)instruction.
Quoted 4 lines
In guest the virtual DSA HW may only contain a WQ in shared mode (unchangeable by the guest) when the host admin wants to share the limited WQ resource among many VMs. Then there is no choice in guest regardless whether it's for user or kernel controlled DMA.
I will add these to the next cover letter.
Thanks,
Jacob
Re: [PATCH 4/4] dmaengine: idxd: Use DMA API for in-kernel DMA with PASID
In reply to Jason GunthorpeHi Jason,
Quoted 10 lines · Jason Gunthorpe
Quoted 5 lines
This patch utilizes
iommu_enable_pasid_dma()to enable DSA to perform DMA requests with PASID under the same mapping managed by DMA mapping API. In addition, SVA-related bits for kernel DMA are removed. As a result, DSA users shall use DMA mapping API to obtain DMA handles instead of using kernel virtual addresses.Er, shouldn't this be adding dma_map/etc type calls?
You can't really say a driver is using the DMA API without actually calling the DMA API..
The IDXD driver is not aware of addressing mode, it is up to the user of dmaengine API to prepare the buffer mappings. Here we only set up the PASID such that it can be picked up during DMA work submission. I tested with /drivers/dma/dmatest.c which does dma_map_page(), map_single etc. also tested with other pieces under development.
Thanks,
Jacob
Re: [PATCH 4/4] dmaengine: idxd: Use DMA API for in-kernel DMA with PASID
Quoted 12 lines · Jacob Pan
Hi Jason,
Quoted 8 lines · Jason Gunthorpe
Quoted 5 lines
This patch utilizes
iommu_enable_pasid_dma()to enable DSA to perform DMA requests with PASID under the same mapping managed by DMA mapping API. In addition, SVA-related bits for kernel DMA are removed. As a result, DSA users shall use DMA mapping API to obtain DMA handles instead of using kernel virtual addresses.Er, shouldn't this be adding dma_map/etc type calls?
Quoted 7 lines
Quoted 2 lines
You can't really say a driver is using the DMA API without actually calling the DMA API..
The IDXD driver is not aware of addressing mode, it is up to the user of dmaengine API to prepare the buffer mappings. Here we only set up the PASID such that it can be picked up during DMA work submission. I tested with /drivers/dma/dmatest.c which does
dma_map_page(),map_singleetc. also tested with other pieces under development.
Ignoring the work, doesn't IDXD prepare the DMA queues itself, don't those need the DMA API?
I'm still very confused how this can radically change from using kSVA to DMA API and NOT introduce some more changes than this. They are not the same thing, they do not use the same IOVA's. Did you test this with bypass mode off?
Jason
Re: [PATCH 4/4] dmaengine: idxd: Use DMA API for in-kernel DMA with PASID
Hi Jason,
Quoted 15 lines · Jason Gunthorpe
Quoted 14 lines · Jacob Pan
Hi Jason,
Quoted 10 lines · Jason Gunthorpe
Quoted 5 lines
This patch utilizes
iommu_enable_pasid_dma()to enable DSA to perform DMA requests with PASID under the same mapping managed by DMA mapping API. In addition, SVA-related bits for kernel DMA are removed. As a result, DSA users shall use DMA mapping API to obtain DMA handles instead of using kernel virtual addresses.Er, shouldn't this be adding dma_map/etc type calls?
You can't really say a driver is using the DMA API without actually calling the DMA API..
Quoted 9 lines
Quoted 5 lines
The IDXD driver is not aware of addressing mode, it is up to the user of dmaengine API to prepare the buffer mappings. Here we only set up the PASID such that it can be picked up during DMA work submission. I tested with /drivers/dma/dmatest.c which does
dma_map_page(),map_singleetc. also tested with other pieces under development.Ignoring the work, doesn't IDXD prepare the DMA queues itself, don't those need the DMA API?
Do you mean wq completion record address? It is already using DMA API.
wq->compls = dma_alloc_coherent(dev, wq->compls_size, &wq->compls_addr, GFP_KERNEL); desc->compl_dma = wq->compls_addr + idxd->data->compl_size * i;
Quoted 2 lines
I'm still very confused how this can radically change from using kSVA to DMA API and NOT introduce some more changes than this. They are not
I am guessing the confusion comes from that fact the user of kSVA is not merged. We were in the process of upstreaming then abandon it. Perhaps that is why you don't see removing kSVA code?
Quoted 2 lines
the same thing, they do not use the same IOVA's. Did you test this with bypass mode off?
Yes with dmatest. IOVA is the default, I separated out the SATC patch which will put internal accelerators in bypass mode. It can also be verified by iommu debugfs dump of DMA PASID (2) and PASID 0 (RIDPASID) are pointing to he same default domain. e.g
PASID PASID_table_entry 0 0x0000000119ed7004:0x0000000000800002:0x000000000000004d 1 0x0000000000000001:0x0000000000800001:0x000000000000010d 2 0x0000000119ed7004:0x0000000000800002:0x000000000000004d
Quoted 2 lines
Jason
Thanks,
Jacob
_______________________________________________
iommu mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH 4/4] dmaengine: idxd: Use DMA API for in-kernel DMA with PASID
Quoted 25 lines · Jacob Pan
Hi Jason,
Quoted 21 lines · Jason Gunthorpe
Quoted 19 lines · Jacob Pan
Hi Jason,
Quoted 10 lines · Jason Gunthorpe
Quoted 5 lines
This patch utilizes
iommu_enable_pasid_dma()to enable DSA to perform DMA requests with PASID under the same mapping managed by DMA mapping API. In addition, SVA-related bits for kernel DMA are removed. As a result, DSA users shall use DMA mapping API to obtain DMA handles instead of using kernel virtual addresses.Er, shouldn't this be adding dma_map/etc type calls?
You can't really say a driver is using the DMA API without actually calling the DMA API..
The IDXD driver is not aware of addressing mode, it is up to the user of dmaengine API to prepare the buffer mappings. Here we only set up the PASID such that it can be picked up during DMA work submission. I tested with /drivers/dma/dmatest.c which does
dma_map_page(),map_singleetc. also tested with other pieces under development.
Quoted 7 lines
Quoted 3 lines
Ignoring the work, doesn't IDXD prepare the DMA queues itself, don't those need the DMA API?
Do you mean wq completion record address? It is already using DMA API.
wq->compls = dma_alloc_coherent(dev, wq->compls_size, &wq->compls_addr, GFP_KERNEL); desc->compl_dma = wq->compls_addr + idxd->data->compl_size * i;
I would have expected something on the queue submission side too?
Quoted 6 lines
Quoted 2 lines
the same thing, they do not use the same IOVA's. Did you test this with bypass mode off?
Yes with dmatest. IOVA is the default, I separated out the SATC patch which will put internal accelerators in bypass mode. It can also be verified by iommu debugfs dump of DMA PASID (2) and PASID 0 (RIDPASID) are pointing to he same default domain. e.g
Well, OK then..
Jason
Dave Jiang
reviewerRe: [PATCH 4/4] dmaengine: idxd: Use DMA API for in-kernel DMA with PASID
Quoted 24 lines · Jason Gunthorpe
Quoted 23 lines · Jacob Pan
Hi Jason,
Quoted 19 lines · Jason Gunthorpe
Quoted 18 lines · Jacob Pan
Hi Jason,
Quoted 9 lines · Jason Gunthorpe
Quoted 5 lines
This patch utilizes
iommu_enable_pasid_dma()to enable DSA to perform DMA requests with PASID under the same mapping managed by DMA mapping API. In addition, SVA-related bits for kernel DMA are removed. As a result, DSA users shall use DMA mapping API to obtain DMA handles instead of using kernel virtual addresses.Er, shouldn't this be adding dma_map/etc type calls?
You can't really say a driver is using the DMA API without actually calling the DMA API..
The IDXD driver is not aware of addressing mode, it is up to the user of dmaengine API to prepare the buffer mappings. Here we only set up the PASID such that it can be picked up during DMA work submission. I tested with /drivers/dma/dmatest.c which does
dma_map_page(),map_singleetc. also tested with other pieces under development.
Quoted 8 lines
Quoted 7 lines
Quoted 3 lines
Ignoring the work, doesn't IDXD prepare the DMA queues itself, don't those need the DMA API?
Do you mean wq completion record address? It is already using DMA API.
wq->compls = dma_alloc_coherent(dev, wq->compls_size, &wq->compls_addr, GFP_KERNEL); desc->compl_dma = wq->compls_addr + idxd->data->compl_size * i;I would have expected something on the queue submission side too?
DSA is different than typical DMA devices in the past. Instead of a software descriptor ring where the device DMA to fetch the descriptors after the software ringing a doorbell or writing a head index, the descriptors are submitted directly to the device via a CPU instruction (i.e. MOVDIR64B or ENQCMD(S)). The CPU takes the KVA of the 64B descriptor and writes to the device atomically. No DMA mapping is necessary in this case.
Quoted 10 lines
Quoted 7 lines
Quoted 3 lines
the same thing, they do not use the same IOVA's. Did you test this with bypass mode off?
Yes with dmatest. IOVA is the default, I separated out the SATC patch which will put internal accelerators in bypass mode. It can also be verified by iommu debugfs dump of DMA PASID (2) and PASID 0 (RIDPASID) are pointing to he same default domain. e.g
Well, OK then..
Jason
RE: [PATCH 4/4] dmaengine: idxd: Use DMA API for in-kernel DMA with PASID
Quoted 9 lines
From: Jiang, Dave <[email protected]>
Sent: Thursday, December 9, 2021 8:12 AMQuoted 6 lines
Quoted 5 lines
Quoted 1 line
Do you mean wq completion record address? It is already using DMA API.
wq->compls = dma_alloc_coherent(dev, wq->compls_size, &wq->compls_addr, GFP_KERNEL); desc->compl_dma = wq->compls_addr + idxd->data->compl_size * i;I would have expected something on the queue submission side too?
Quoted 8 lines
DSA is different than typical DMA devices in the past. Instead of a software descriptor ring where the device DMA to fetch the descriptors after the software ringing a doorbell or writing a head index, the descriptors are submitted directly to the device via a CPU instruction (i.e. MOVDIR64B or ENQCMD(S)). The CPU takes the KVA of the 64B descriptor and writes to the device atomically. No DMA mapping is necessary in this case.
To be accurate, the cpu reads the 64B descriptor from KVA and then write the descriptor to the device atomically.
kernel test robot
build botRe: [PATCH 4/4] dmaengine: idxd: Use DMA API for in-kernel DMA with PASID
In reply to Jacob PanI love your patch! Yet something to improve:
Hi Jacob,
I love your patch! Yet something to improve:
[auto build test ERROR on joro-iommu/next]
[also build test ERROR on vkoul-dmaengine/next linux/master linus/master v5.16-rc4 next-20211208] [If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Jacob-Pan/Enable-PASID-for-DMA-API-users/20211208-063637 base: https://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git next config: x86_64-randconfig-a013-20211208 (https://download.01.org/0day-ci/archive/20211209/202112090231.mEK0hpuw-lkp(a)intel.com/config) compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
reproduce (this is a W=1 build):
# https://github.com/0day-ci/linux/commit/018108bcd08fc145526791870b4b58edeecfca1e
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Jacob-Pan/Enable-PASID-for-DMA-API-users/20211208-063637 git checkout 018108bcd08fc145526791870b4b58edeecfca1e
# save the config file to linux build tree
mkdir build_dir
make W=1 O=build_dir ARCH=x86_64 SHELL=/bin/bash drivers/dma/idxd/
If you fix the issue, kindly add following tag as appropriate
All errors (new ones prefixed by >>):
drivers/dma/idxd/init.c: In function 'idxd_enable_system_pasid':
>> drivers/dma/idxd/init.c:532:10: error: implicit declaration of function 'iommu_enable_pasid_dma'; did you mean 'iommu_enable_nesting'? [-Werror=implicit-function-declaration]
532 | pasid = iommu_enable_pasid_dma(&idxd->pdev->dev);
| ^~~~~~~~~~~~~~~~~~~~~~
| iommu_enable_nesting
drivers/dma/idxd/init.c: In function 'idxd_disable_system_pasid':
>> drivers/dma/idxd/init.c:544:2: error: implicit declaration of function 'iommu_disable_pasid_dma' [-Werror=implicit-function-declaration]
544 | iommu_disable_pasid_dma(&idxd->pdev->dev);
| ^~~~~~~~~~~~~~~~~~~~~~~cc1: some warnings being treated as errors
vim +532 drivers/dma/idxd/init.c
527
528 static int idxd_enable_system_pasid(struct idxd_device *idxd)
529 {
530 u32 pasid;
531
> 532 pasid = iommu_enable_pasid_dma(&idxd->pdev->dev);
533 if (pasid == INVALID_IOASID) {
534 dev_err(&idxd->pdev->dev, "No kernel DMA PASID\n");
535 return -ENODEV;
536 }
537 idxd->pasid = pasid;
538
539 return 0;
540 }
541
542 static void idxd_disable_system_pasid(struct idxd_device *idxd)
543 {
> 544 iommu_disable_pasid_dma(&idxd->pdev->dev); 545 idxd->pasid = 0;
546 }
547
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
Quoted 4 lines · Jacob Pan
Modern accelerators such as Intel's Data Streaming Accelerator (DSA) can perform DMA requests with PASID, which is a finer granularity than the device's requester ID(RID). In fact, work submissions on DSA shared work queues require PASID.
Lets use plain langauge please:
DSA HW cannot do DMA from its RID, so always requires a PASID, even for kernel controlled DMA.
To allow it to use the DMA API we must associate a PASID with the iommu_domain that the DMA API is already using for the device's RID.
This way DMA tagged with the PASID will be treated exactly the same as DMA originating from the RID.
Quoted 5 lines
DMA mapping API is the de facto standard for in-kernel DMA. However, it operates on a per device/RID basis which is not PASID-aware.
This patch introduces the following driver facing API that enables DMA API PASID usage:
ioasid_tiommu_enable_pasid_dma(struct device *dev);
This is the wrong API, IMHO
It should be more like
int iommu_get_dma_api_pasid(struct device *dev, ioasid_t *pasid); void iommu_destroy_dma_api_pasid(struct device *dev);
Quoted 2 lines
A PASID field is added to struct device for the purposes of storing kernel DMA PASID and flushing device IOTLBs. A separate use case in interrupt
And this really should not be touching the struct device at all.
At worst the PASID should be stored in the iommu_group.
Quoted 3 lines
message store (IMS) also hinted adding a PASID field to struct device.
https://lore.kernel.org/all/[email protected]/
IMS virtualization and DMA API does not overlap.
This is under debate, I'm skeptical it will happen considering the new direction for this work.
Quoted 5 lines
Once enabled, device drivers can continue to use DMA APIs as-is. There is no difference in terms of mapping in
dma_handlebetween without PASID and with PASID. The DMA mapping performed by IOMMU will be identical for both requests with and without PASID (legacy), let it be IOVA or PA in case of pass-through.
In other words all this does is connect the PASID to the normal DMA-API owned iommu_domain.
Jason
Hi Jason,
Thanks for the quick review.
Quoted 8 lines · Jason Gunthorpe
Quoted 4 lines · Jacob Pan
Modern accelerators such as Intel's Data Streaming Accelerator (DSA) can perform DMA requests with PASID, which is a finer granularity than the device's requester ID(RID). In fact, work submissions on DSA shared work queues require PASID.
Lets use plain langauge please:
Quoted 9 lines
DSA HW cannot do DMA from its RID, so always requires a PASID, even for kernel controlled DMA.
To allow it to use the DMA API we must associate a PASID with the
iommu_domainthat the DMA API is already using for the device's RID.This way DMA tagged with the PASID will be treated exactly the same as DMA originating from the RID.
Exactly, will incorporate in the next version.
Quoted 11 lines
Quoted 5 lines
DMA mapping API is the de facto standard for in-kernel DMA. However, it operates on a per device/RID basis which is not PASID-aware.
This patch introduces the following driver facing API that enables DMA API PASID usage:
ioasid_tiommu_enable_pasid_dma(struct device *dev);This is the wrong API, IMHO
It should be more like
int
iommu_get_dma_api_pasid(struct device *dev, ioasid_t *pasid);
This works. I had ioasid_t *pasid in my previous version but thinking we can simplify the interface since we can have the reserved INVALID_IOASID for return status.
But it seems to me _get_ does not convey the message that this API actually enables/attaches the kernel DMA PASID. Perhaps call it iommu_attach_dma_api_pasid() as you suggested in the ops function?
Quoted 2 lines
void
iommu_destroy_dma_api_pasid(struct device *dev);
Sounds good
Quoted 6 lines
Quoted 3 lines
A PASID field is added to struct device for the purposes of storing kernel DMA PASID and flushing device IOTLBs. A separate use case in interrupt
And this really should not be touching the struct device at all.
I was thinking RID is per device, this PASID == RID. We could put in pci_dev but there are non-PCI devices use SSID/PASID.
Quoted 2 lines
At worst the PASID should be stored in the
iommu_group.
This also makes sense, default domain is stored per group. To support multiple devices per group, we still need a per device flag for devTLB flush. Right?
i.e. while doing iova unmap, IOTLBs are flush for all devices, but we only need to flush the device TLBs for devices that has kernel DMA PASID.
Quoted 7 lines
Quoted 3 lines
message store (IMS) also hinted adding a PASID field to struct device.
https://lore.kernel.org/all/[email protected]/
IMS virtualization and DMA API does not overlap.This is under debate, I'm skeptical it will happen considering the new direction for this work.
Good to know, thanks.
Quoted 9 lines
Quoted 5 lines
Once enabled, device drivers can continue to use DMA APIs as-is. There is no difference in terms of mapping in
dma_handlebetween without PASID and with PASID. The DMA mapping performed by IOMMU will be identical for both requests with and without PASID (legacy), let it be IOVA or PA in case of pass-through.In other words all this does is connect the PASID to the normal DMA-API owned
iommu_domain.
Exactly! will incorporate.
Thanks,
Jacob