ioasid: Reserve a global PASID for in-kernel DMA
ANBZ: #1675 commit 9ee131fbaf6b93f912ec55b31edfc1c0ac1a05e2 intel-github. 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. Intel-SIG: commit 9ee131fbaf6b ioasid: Reserve a global PASID for in-kernel DMA. Necessary fix to VM boot successfully with DSA PF pass through in SWQ mode. Signed-off-by: Jacob Pan <jacob.jun.pan@linux.intel.com> [ Aubrey Li: amend commit log ] Signed-off-by: Aubrey Li <aubrey.li@linux.intel.com> Signed-off-by: Artie Ding <artie.ding@linux.alibaba.com> Link: https://gitee.com/anolis/cloud-kernel/pulls/522 Reviewed-by: Artie Ding <artie.ding@linux.alibaba.com>
This commit is contained in:
parent
6e4545a89a
commit
784b67485c
|
@ -313,7 +313,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;
|
||||
|
||||
|
|
|
@ -215,14 +215,14 @@ int iommu_attach_dma_pasid(struct device *dev, ioasid_t *pasid)
|
|||
/* TODO: use per dev max_pasid instead of PCI */
|
||||
max = PCI_PASID_MAX;
|
||||
|
||||
id = ioasid_alloc(host_pasid_set, 1, max, dev);
|
||||
id = ioasid_alloc(host_pasid_set, IOASID_ALLOC_BASE, max, dev);
|
||||
if (id == INVALID_IOASID) {
|
||||
ret = -ENOMEM;
|
||||
goto done_unlock;
|
||||
}
|
||||
|
||||
dom->dma_pasid = id;
|
||||
atomic_set(&dom->dma_pasid_users, 1);
|
||||
atomic_set(&dom->dma_pasid_users, 0);
|
||||
}
|
||||
|
||||
ret = iommu_attach_device_pasid(dom, dev, id);
|
||||
|
|
|
@ -3210,7 +3210,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))
|
||||
|
@ -4850,7 +4850,7 @@ static int aux_domain_add_dev(struct dmar_domain *domain,
|
|||
u32 pasid;
|
||||
|
||||
/* No private data needed for the default pasid */
|
||||
pasid = ioasid_alloc(host_pasid_set, PASID_MIN,
|
||||
pasid = ioasid_alloc(host_pasid_set, IOASID_ALLOC_BASE,
|
||||
pci_max_pasids(to_pci_dev(dev)) - 1,
|
||||
NULL);
|
||||
if (pasid == INVALID_IOASID) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -705,7 +705,7 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags,
|
|||
pasid_max = intel_pasid_max_id;
|
||||
|
||||
/* Do not use PASID 0, reserved for RID to PASID */
|
||||
svm->pasid = ioasid_alloc(host_pasid_set, PASID_MIN,
|
||||
svm->pasid = ioasid_alloc(host_pasid_set, IOASID_ALLOC_BASE,
|
||||
pasid_max - 1, svm);
|
||||
if (svm->pasid == INVALID_IOASID) {
|
||||
kfree(svm);
|
||||
|
|
|
@ -804,6 +804,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.
|
||||
|
|
|
@ -3583,10 +3583,15 @@ int iommu_attach_device_pasid(struct iommu_domain *domain,
|
|||
return -EINVAL;
|
||||
|
||||
group = iommu_group_get(dev);
|
||||
if (!group)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&group->mutex);
|
||||
curr = xa_cmpxchg(&group->pasid_array, pasid, NULL, domain, GFP_KERNEL);
|
||||
if (curr)
|
||||
if (curr) {
|
||||
ret = xa_err(curr) ? : -EBUSY;
|
||||
goto out_unlock;
|
||||
}
|
||||
ret = domain->ops->attach_dev_pasid(domain, dev, pasid);
|
||||
if (ret)
|
||||
xa_erase(&group->pasid_array, pasid);
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
#include <uapi/linux/ioasid.h>
|
||||
|
||||
#define INVALID_IOASID ((ioasid_t)-1)
|
||||
#define IOASID_DMA_NO_PASID 0 /* For DMA request w/o PASID */
|
||||
#define IOASID_ALLOC_BASE 1 /* 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);
|
||||
|
@ -167,7 +170,7 @@ extern struct ioasid_user *ioasid_user_get_from_task(struct task_struct *task);
|
|||
extern void ioasid_user_put(struct ioasid_user *iuser);
|
||||
extern void ioasid_user_for_each_id(struct ioasid_user *iuser, void *data,
|
||||
void (*fn)(ioasid_t id, void *data));
|
||||
|
||||
extern struct ioasid_set *host_pasid_set;
|
||||
#else /* CONFIG_IOASID_USER */
|
||||
static inline struct ioasid_user *
|
||||
ioasid_user_get_from_task(struct task_struct *task)
|
||||
|
|
Loading…
Reference in New Issue