@@ -4050,7 +4050,7 @@ static Property vtd_properties[] = {
DEFINE_PROP_UINT8("aw-bits", IntelIOMMUState, aw_bits,
VTD_HOST_ADDRESS_WIDTH),
DEFINE_PROP_BOOL("caching-mode", IntelIOMMUState, caching_mode, FALSE),
- DEFINE_PROP_BOOL("x-scalable-mode", IntelIOMMUState, scalable_mode, FALSE),
+ DEFINE_PROP_STRING("x-scalable-mode", IntelIOMMUState, scalable_mode_str),
DEFINE_PROP_BOOL("dma-drain", IntelIOMMUState, dma_drain, true),
DEFINE_PROP_END_OF_LIST(),
};
@@ -4419,6 +4419,7 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn)
static int vtd_dev_get_iommu_attr(PCIBus *bus, void *opaque, int32_t devfn,
IOMMUAttr attr, void *data)
{
+ IntelIOMMUState *s = opaque;
int ret = 0;
assert(0 <= devfn && devfn < PCI_DEVFN_MAX);
@@ -4428,8 +4429,7 @@ static int vtd_dev_get_iommu_attr(PCIBus *bus, void *opaque, int32_t devfn,
{
bool *pdata = data;
- /* return false until vSVA is ready */
- *pdata = false;
+ *pdata = s->scalable_modern ? true : false;
break;
}
default:
@@ -4523,6 +4523,8 @@ static int vtd_dev_set_iommu_context(PCIBus *bus, void *opaque,
VTDHostIOMMUContext *vtd_dev_icx;
assert(0 <= devfn && devfn < PCI_DEVFN_MAX);
+ /* only modern scalable supports set_ioimmu_context */
+ assert(s->scalable_modern);
vtd_bus = vtd_find_add_bus(s, bus);
@@ -4557,6 +4559,8 @@ static void vtd_dev_unset_iommu_context(PCIBus *bus, void *opaque, int devfn)
VTDHostIOMMUContext *vtd_dev_icx;
assert(0 <= devfn && devfn < PCI_DEVFN_MAX);
+ /* only modern scalable supports unset_ioimmu_context */
+ assert(s->scalable_modern);
vtd_bus = vtd_find_add_bus(s, bus);
@@ -4784,8 +4788,13 @@ static void vtd_init(IntelIOMMUState *s)
}
/* TODO: read cap/ecap from host to decide which cap to be exposed. */
- if (s->scalable_mode) {
+ if (s->scalable_mode && !s->scalable_modern) {
s->ecap |= VTD_ECAP_SMTS | VTD_ECAP_SRS | VTD_ECAP_SLTS;
+ } else if (s->scalable_mode && s->scalable_modern) {
+ s->ecap |= VTD_ECAP_SMTS | VTD_ECAP_SRS | VTD_ECAP_PASID |
+ VTD_ECAP_FLTS | VTD_ECAP_PSS(VTD_PASID_SS) |
+ VTD_ECAP_VCS;
+ s->vccap |= VTD_VCCAP_PAS;
}
if (!s->cap_finalized) {
@@ -4926,6 +4935,28 @@ static bool vtd_decide_config(IntelIOMMUState *s, Error **errp)
return false;
}
+ if (s->scalable_mode_str &&
+ (strcmp(s->scalable_mode_str, "off") &&
+ strcmp(s->scalable_mode_str, "modern") &&
+ strcmp(s->scalable_mode_str, "legacy"))) {
+ error_setg(errp, "Invalid x-scalable-mode config,"
+ "Please use \"modern\", \"legacy\" or \"off\"");
+ return false;
+ }
+
+ if (s->scalable_mode_str &&
+ !strcmp(s->scalable_mode_str, "legacy")) {
+ s->scalable_mode = true;
+ s->scalable_modern = false;
+ } else if (s->scalable_mode_str &&
+ !strcmp(s->scalable_mode_str, "modern")) {
+ s->scalable_mode = true;
+ s->scalable_modern = true;
+ } else {
+ s->scalable_mode = false;
+ s->scalable_modern = false;
+ }
+
return true;
}
@@ -197,7 +197,9 @@
#define VTD_ECAP_MHMV (15ULL << 20)
#define VTD_ECAP_SRS (1ULL << 31)
#define VTD_ECAP_SMTS (1ULL << 43)
+#define VTD_ECAP_VCS (1ULL << 44)
#define VTD_ECAP_SLTS (1ULL << 46)
+#define VTD_ECAP_FLTS (1ULL << 47)
/* 1st level related caps */
#define VTD_CAP_FL1GP (1ULL << 56)
@@ -209,6 +211,7 @@
#define VTD_ECAP_PSS(val) (((val) & 0x1fULL) << 35)
#define VTD_ECAP_PASID (1ULL << 40)
+#define VTD_PASID_SS (19)
#define VTD_GET_PSS(val) (((val) >> 35) & 0x1f)
#define VTD_ECAP_PSS_MASK (0x1fULL << 35)
@@ -263,6 +263,8 @@ struct IntelIOMMUState {
bool caching_mode; /* RO - is cap CM enabled? */
bool scalable_mode; /* RO - is Scalable Mode supported? */
+ char *scalable_mode_str; /* RO - admin's Scalable Mode config */
+ bool scalable_modern; /* RO - is modern SM supported? */
dma_addr_t root; /* Current root table pointer */
bool root_scalable; /* Type of root table (scalable or not) */