@@ -4085,7 +4085,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(),
};
@@ -4454,6 +4454,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);
@@ -4463,8 +4464,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:
@@ -4558,6 +4558,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 unset_ioimmu_context */
+ assert(s->scalable_modern);
vtd_bus = vtd_find_add_bus(s, bus);
@@ -4592,6 +4594,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 set_ioimmu_context */
+ assert(s->scalable_modern);
vtd_bus = vtd_find_add_bus(s, bus);
@@ -4820,8 +4824,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) {
@@ -4962,6 +4971,63 @@ 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")) {
+ if (ioasid_fd < 0) {
+ int fd, version;
+ struct ioasid_info info;
+
+ fd = qemu_open_old("/dev/ioasid", O_RDWR);
+ if (fd < 0) {
+ error_setg(errp, "Failed to open /dev/ioasid, %m");
+ return false;
+ }
+
+ version = ioctl(fd, IOASID_GET_API_VERSION);
+ if (version != IOASID_API_VERSION) {
+ error_setg(errp, "supported ioasid version: %d, "
+ "reported version: %d", IOASID_API_VERSION, version);
+ return false;
+ }
+
+ memset(&info, 0x0, sizeof(info));
+ info.argsz = sizeof(info);
+ if (ioctl(fd, IOASID_GET_INFO, &info)) {
+ error_setg(errp, "Failed to get ioasid info, %m");
+ return false;
+ }
+
+ if ((VTD_PASID_SS + 1) > info.ioasid_bits) {
+ error_setg(errp, "supported pasid bits: %u, reported pasid "
+ "bits: %u", VTD_PASID_SS + 1, info.ioasid_bits);
+ return false;
+ }
+
+ ioasid_fd = fd;
+ ioasid_bits = info.ioasid_bits;
+ }
+ s->ioasid_fd = ioasid_fd;
+ s->ioasid_bits = ioasid_bits;
+ 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)
@@ -262,6 +262,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) */