Skip to content

Commit 24f27d3

Browse files
LuBaolujoergroedel
authored andcommitted
iommu/vt-d: Enlightened PASID allocation
Enabling IOMMU in a guest requires communication with the host driver for certain aspects. Use of PASID ID to enable Shared Virtual Addressing (SVA) requires managing PASID's in the host. VT-d 3.0 spec provides a Virtual Command Register (VCMD) to facilitate this. Writes to this register in the guest are trapped by vIOMMU which proxies the call to the host driver. This virtual command interface consists of a capability register, a virtual command register, and a virtual response register. Refer to section 10.4.42, 10.4.43, 10.4.44 for more information. This patch adds the enlightened PASID allocation/free interfaces via the virtual command interface. Signed-off-by: Liu Yi L <[email protected]> Signed-off-by: Lu Baolu <[email protected]> Signed-off-by: Jacob Pan <[email protected]> Reviewed-by: Eric Auger <[email protected]> Reviewed-by: Kevin Tian <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Joerg Roedel <[email protected]>
1 parent 6ee1b77 commit 24f27d3

File tree

3 files changed

+70
-1
lines changed

3 files changed

+70
-1
lines changed

drivers/iommu/intel-pasid.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,63 @@
2727
static DEFINE_SPINLOCK(pasid_lock);
2828
u32 intel_pasid_max_id = PASID_MAX;
2929

30+
int vcmd_alloc_pasid(struct intel_iommu *iommu, unsigned int *pasid)
31+
{
32+
unsigned long flags;
33+
u8 status_code;
34+
int ret = 0;
35+
u64 res;
36+
37+
raw_spin_lock_irqsave(&iommu->register_lock, flags);
38+
dmar_writeq(iommu->reg + DMAR_VCMD_REG, VCMD_CMD_ALLOC);
39+
IOMMU_WAIT_OP(iommu, DMAR_VCRSP_REG, dmar_readq,
40+
!(res & VCMD_VRSP_IP), res);
41+
raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
42+
43+
status_code = VCMD_VRSP_SC(res);
44+
switch (status_code) {
45+
case VCMD_VRSP_SC_SUCCESS:
46+
*pasid = VCMD_VRSP_RESULT_PASID(res);
47+
break;
48+
case VCMD_VRSP_SC_NO_PASID_AVAIL:
49+
pr_info("IOMMU: %s: No PASID available\n", iommu->name);
50+
ret = -ENOSPC;
51+
break;
52+
default:
53+
ret = -ENODEV;
54+
pr_warn("IOMMU: %s: Unexpected error code %d\n",
55+
iommu->name, status_code);
56+
}
57+
58+
return ret;
59+
}
60+
61+
void vcmd_free_pasid(struct intel_iommu *iommu, unsigned int pasid)
62+
{
63+
unsigned long flags;
64+
u8 status_code;
65+
u64 res;
66+
67+
raw_spin_lock_irqsave(&iommu->register_lock, flags);
68+
dmar_writeq(iommu->reg + DMAR_VCMD_REG,
69+
VCMD_CMD_OPERAND(pasid) | VCMD_CMD_FREE);
70+
IOMMU_WAIT_OP(iommu, DMAR_VCRSP_REG, dmar_readq,
71+
!(res & VCMD_VRSP_IP), res);
72+
raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
73+
74+
status_code = VCMD_VRSP_SC(res);
75+
switch (status_code) {
76+
case VCMD_VRSP_SC_SUCCESS:
77+
break;
78+
case VCMD_VRSP_SC_INVALID_PASID:
79+
pr_info("IOMMU: %s: Invalid PASID\n", iommu->name);
80+
break;
81+
default:
82+
pr_warn("IOMMU: %s: Unexpected error code %d\n",
83+
iommu->name, status_code);
84+
}
85+
}
86+
3087
/*
3188
* Per device pasid table management:
3289
*/

drivers/iommu/intel-pasid.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,16 @@
2323
#define is_pasid_enabled(entry) (((entry)->lo >> 3) & 0x1)
2424
#define get_pasid_dir_size(entry) (1 << ((((entry)->lo >> 9) & 0x7) + 7))
2525

26+
/* Virtual command interface for enlightened pasid management. */
27+
#define VCMD_CMD_ALLOC 0x1
28+
#define VCMD_CMD_FREE 0x2
29+
#define VCMD_VRSP_IP 0x1
30+
#define VCMD_VRSP_SC(e) (((e) >> 1) & 0x3)
31+
#define VCMD_VRSP_SC_SUCCESS 0
32+
#define VCMD_VRSP_SC_NO_PASID_AVAIL 1
33+
#define VCMD_VRSP_SC_INVALID_PASID 1
34+
#define VCMD_VRSP_RESULT_PASID(e) (((e) >> 8) & 0xfffff)
35+
#define VCMD_CMD_OPERAND(e) ((e) << 8)
2636
/*
2737
* Domain ID reserved for pasid entries programmed for first-level
2838
* only and pass-through transfer modes.
@@ -111,5 +121,6 @@ int intel_pasid_setup_nested(struct intel_iommu *iommu,
111121
struct dmar_domain *domain, int addr_width);
112122
void intel_pasid_tear_down_entry(struct intel_iommu *iommu,
113123
struct device *dev, int pasid);
114-
124+
int vcmd_alloc_pasid(struct intel_iommu *iommu, unsigned int *pasid);
125+
void vcmd_free_pasid(struct intel_iommu *iommu, unsigned int pasid);
115126
#endif /* __INTEL_PASID_H */

include/linux/intel-iommu.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@
169169
#define ecap_smpwc(e) (((e) >> 48) & 0x1)
170170
#define ecap_flts(e) (((e) >> 47) & 0x1)
171171
#define ecap_slts(e) (((e) >> 46) & 0x1)
172+
#define ecap_vcs(e) (((e) >> 44) & 0x1)
172173
#define ecap_smts(e) (((e) >> 43) & 0x1)
173174
#define ecap_dit(e) ((e >> 41) & 0x1)
174175
#define ecap_pasid(e) ((e >> 40) & 0x1)

0 commit comments

Comments
 (0)