Skip to contentSkip to conversation

amd iommu: add ats device support

PATCH New Wei Wang 2 participants 12 messages Oct 21, 2011

lore
Share & tools
lore

Wei Wang

author
#0 lore raw

PATCH 1/1 amd iommu: add ats device support

Hi, this patch set enables ats devices on amd systems with following changes:
1) Move vendor independent ATS functions into public directories.
2) Add new ATS helper functions.
3) Add amd specific enablement.

Thanks,
Wei

author
#1 lore raw

PATCH 1/1 Move some ats functions into vendor neutral directories

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1319201416 -7200
# Node ID a559e27ffb2c2a3a90dc25f09205b66668dcdbbb # Parent 121af976b2988de389db139231103ceedd11bb8a Move some ats functions into vendor neutral directories.

xen/drivers/passthrough/pci.c +89 -0
diff -r 121af976b298 -r a559e27ffb2c xen/drivers/passthrough/pci.c
@@ -748,6 +748,95 @@ static int __init setup_dump_pcidevs(voi
 __initcall(setup_dump_pcidevs);
 #endif
 
+int enable_ats_device(int seg, int bus, int devfn)
+{
+    struct pci_ats_dev *pdev = NULL;
+    u32 value;
+    int pos;
+
+    pos = pci_find_ext_capability(seg, bus, devfn, PCI_EXT_CAP_ID_ATS);
+    BUG_ON(!pos);
+
+    if ( iommu_verbose )
+        dprintk(XENLOG_INFO VTDPREFIX,
+                "%04x:%02x:%02x.%u: ATS capability found\n",
+                seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+
+    value = pci_conf_read16(seg, bus, PCI_SLOT(devfn),
+                            PCI_FUNC(devfn), pos + ATS_REG_CTL);
+    if ( value & ATS_ENABLE )
+    {
+        list_for_each_entry ( pdev, &ats_devices, list )
+        {
+            if ( pdev->seg == seg && pdev->bus == bus && pdev->devfn == devfn )
+            {
+                pos = 0;
+                break;
+            }
+        }
+    }
+    if ( pos )
+        pdev = xmalloc(struct pci_ats_dev);
+    if ( !pdev )
+        return -ENOMEM;
+
+    if ( !(value & ATS_ENABLE) )
+    {
+        value |= ATS_ENABLE;
+        pci_conf_write16(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
+                         pos + ATS_REG_CTL, value);
+    }
+
+    if ( pos )
+    {
+        pdev->seg = seg;
+        pdev->bus = bus;
+        pdev->devfn = devfn;
+        value = pci_conf_read16(seg, bus, PCI_SLOT(devfn),
+                                PCI_FUNC(devfn), pos + ATS_REG_CAP);
+        pdev->ats_queue_depth = value & ATS_QUEUE_DEPTH_MASK;
+        list_add(&pdev->list, &ats_devices);
+    }
+
+    if ( iommu_verbose )
+        dprintk(XENLOG_INFO VTDPREFIX,
+                "%04x:%02x:%02x.%u: ATS %s enabled\n",
+                seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
+                pos ? "is" : "was");
+
+    return pos;
+}
+
+void disable_ats_device(int seg, int bus, int devfn)
+{
+    struct pci_ats_dev *pdev;
+    u32 value;
+    int pos;
+
+    pos = pci_find_ext_capability(seg, bus, devfn, PCI_EXT_CAP_ID_ATS);
+    BUG_ON(!pos);
+
+    value = pci_conf_read16(seg, bus, PCI_SLOT(devfn),
+                            PCI_FUNC(devfn), pos + ATS_REG_CTL);
+    value &= ~ATS_ENABLE;
+    pci_conf_write16(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
+                     pos + ATS_REG_CTL, value);
+
+    list_for_each_entry ( pdev, &ats_devices, list )
+    {
+        if ( pdev->seg == seg && pdev->bus == bus && pdev->devfn == devfn )
+        {
+            list_del(&pdev->list);
+            xfree(pdev);
+            break;
+        }
+    }
+
+    if ( iommu_verbose )
+        dprintk(XENLOG_INFO VTDPREFIX,
+                "%04x:%02x:%02x.%u: ATS is disabled\n",
+                seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+}
 
 /*
  * Local variables:
xen/drivers/passthrough/vtd/extern.h +0 -2
diff -r 121af976b298 -r a559e27ffb2c xen/drivers/passthrough/vtd/extern.h
@@ -62,8 +62,6 @@ extern bool_t ats_enabled;
 struct acpi_drhd_unit * find_ats_dev_drhd(struct iommu *iommu);
 
 int ats_device(int seg, int bus, int devfn);
-int enable_ats_device(int seg, int bus, int devfn);
-void disable_ats_device(int seg, int bus, int devfn);
 int invalidate_ats_tcs(struct iommu *iommu);
 
 int dev_invalidate_iotlb(struct iommu *iommu, u16 did,
xen/drivers/passthrough/vtd/x86/ats.c +0 -105

117 lines not on this page · raw message

xen/include/xen/pci.h +17 -0
diff -r 121af976b298 -r a559e27ffb2c xen/include/xen/pci.h
@@ -63,6 +63,20 @@ struct pci_dev {
     u64 vf_rlen[6];
 };
 
+#define ATS_REG_CAP    4
+#define ATS_REG_CTL    6
+#define ATS_QUEUE_DEPTH_MASK     0xF
+#define ATS_ENABLE               (1<<15)
+
+struct pci_ats_dev {
+    struct list_head list;
+    u16 seg;
+    u8 bus;
+    u8 devfn;
+    u16 ats_queue_depth;    /* ATS device invalidation queue depth */
+};
+static LIST_HEAD(ats_devices);
+
 #define for_each_pdev(domain, pdev) \
     list_for_each_entry(pdev, &(domain->arch.pdev_list), domain_list)
 
@@ -136,4 +150,7 @@ void msixtbl_pt_unregister(struct domain
 void msixtbl_pt_cleanup(struct domain *d);
 void pci_enable_acs(struct pci_dev *pdev);
 
+int enable_ats_device(int seg, int bus, int devfn);
+void disable_ats_device(int seg, int bus, int devfn);
+
 #endif /* __XEN_PCI_H__ */
#2 lore raw

Re: [PATCH 1 of 6] Move some ats functions into vendor neutral directories

Quoted 7 lines
Quoted 1 line
Quoted 1 line · Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1319201416 -7200
# Node ID a559e27ffb2c2a3a90dc25f09205b66668dcdbbb # Parent 121af976b2988de389db139231103ceedd11bb8a Move some ats functions into vendor neutral directories.

You move them from an x86-specific place to common code. I suppose Intel had reasons to expect them to be implemented differently in ia64. Hence they should go into e.g. xen/drivers/passthrough/x86/ instead.

Jan

Quoted 274 lines

diff -r 121af976b298 -r a559e27ffb2c xen/drivers/passthrough/pci.c

xen/drivers/passthrough/pci.c +89 -0
@@ -748,6 +748,95 @@ static int __init setup_dump_pcidevs(voi
 __initcall(setup_dump_pcidevs);
 #endif
 
+int enable_ats_device(int seg, int bus, int devfn)
+{
+    struct pci_ats_dev *pdev = NULL;
+    u32 value;
+    int pos;
+
+    pos = pci_find_ext_capability(seg, bus, devfn, PCI_EXT_CAP_ID_ATS);
+    BUG_ON(!pos);
+
+    if ( iommu_verbose )
+        dprintk(XENLOG_INFO VTDPREFIX,
+                "%04x:%02x:%02x.%u: ATS capability found\n",
+                seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+
+    value = pci_conf_read16(seg, bus, PCI_SLOT(devfn),
+                            PCI_FUNC(devfn), pos + ATS_REG_CTL);
+    if ( value & ATS_ENABLE )
+    {
+        list_for_each_entry ( pdev, &ats_devices, list )
+        {
+            if ( pdev->seg == seg && pdev->bus == bus && pdev->devfn == devfn )
+            {
+                pos = 0;
+                break;
+            }
+        }
+    }
+    if ( pos )
+        pdev = xmalloc(struct pci_ats_dev);
+    if ( !pdev )
+        return -ENOMEM;
+
+    if ( !(value & ATS_ENABLE) )
+    {
+        value |= ATS_ENABLE;
+        pci_conf_write16(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
+                         pos + ATS_REG_CTL, value);
+    }
+
+    if ( pos )
+    {
+        pdev->seg = seg;
+        pdev->bus = bus;
+        pdev->devfn = devfn;
+        value = pci_conf_read16(seg, bus, PCI_SLOT(devfn),
+                                PCI_FUNC(devfn), pos + ATS_REG_CAP);
+        pdev->ats_queue_depth = value & ATS_QUEUE_DEPTH_MASK;
+        list_add(&pdev->list, &ats_devices);
+    }
+
+    if ( iommu_verbose )
+        dprintk(XENLOG_INFO VTDPREFIX,
+                "%04x:%02x:%02x.%u: ATS %s enabled\n",
+                seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
+                pos ? "is" : "was");
+
+    return pos;
+}
+
+void disable_ats_device(int seg, int bus, int devfn)
+{
+    struct pci_ats_dev *pdev;
+    u32 value;
+    int pos;
+
+    pos = pci_find_ext_capability(seg, bus, devfn, PCI_EXT_CAP_ID_ATS);
+    BUG_ON(!pos);
+
+    value = pci_conf_read16(seg, bus, PCI_SLOT(devfn),
+                            PCI_FUNC(devfn), pos + ATS_REG_CTL);
+    value &= ~ATS_ENABLE;
+    pci_conf_write16(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
+                     pos + ATS_REG_CTL, value);
+
+    list_for_each_entry ( pdev, &ats_devices, list )
+    {
+        if ( pdev->seg == seg && pdev->bus == bus && pdev->devfn == devfn )
+        {
+            list_del(&pdev->list);
+            xfree(pdev);
+            break;
+        }
+    }
+
+    if ( iommu_verbose )
+        dprintk(XENLOG_INFO VTDPREFIX,
+                "%04x:%02x:%02x.%u: ATS is disabled\n",
+                seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+}
 
 /*
  * Local variables:

diff -r 121af976b298 -r a559e27ffb2c xen/drivers/passthrough/vtd/extern.h

xen/drivers/passthrough/vtd/extern.h +0 -2
@@ -62,8 +62,6 @@ extern bool_t ats_enabled;
 struct acpi_drhd_unit * find_ats_dev_drhd(struct iommu *iommu);
 
 int ats_device(int seg, int bus, int devfn);
-int enable_ats_device(int seg, int bus, int devfn);
-void disable_ats_device(int seg, int bus, int devfn);
 int invalidate_ats_tcs(struct iommu *iommu);
 
 int dev_invalidate_iotlb(struct iommu *iommu, u16 did,

diff -r 121af976b298 -r a559e27ffb2c xen/drivers/passthrough/vtd/x86/ats.c

xen/drivers/passthrough/vtd/x86/ats.c +0 -105
@@ -30,20 +30,6 @@
 
 static LIST_HEAD(ats_dev_drhd_units);
 
-#define ATS_REG_CAP    4
-#define ATS_REG_CTL    6
-#define ATS_QUEUE_DEPTH_MASK     0xF
-#define ATS_ENABLE               (1<<15)
-
-struct pci_ats_dev {
-    struct list_head list;
-    u16 seg;
-    u8 bus;
-    u8 devfn;
-    u16 ats_queue_depth;    /* ATS device invalidation queue depth */
-};
-static LIST_HEAD(ats_devices);
-
 static void parse_ats_param(char *s);
 custom_param("ats", parse_ats_param);
 
@@ -121,97 +107,6 @@ int ats_device(int seg, int bus, int dev
     return pos;
 }
 
-int enable_ats_device(int seg, int bus, int devfn)
-{
-    struct pci_ats_dev *pdev = NULL;
-    u32 value;
-    int pos;
-
-    pos = pci_find_ext_capability(seg, bus, devfn, PCI_EXT_CAP_ID_ATS);
-    BUG_ON(!pos);
-
-    if ( iommu_verbose )
-        dprintk(XENLOG_INFO VTDPREFIX,
-                "%04x:%02x:%02x.%u: ATS capability found\n",
-                seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
-
-    value = pci_conf_read16(seg, bus, PCI_SLOT(devfn),
-                            PCI_FUNC(devfn), pos + ATS_REG_CTL);
-    if ( value & ATS_ENABLE )
-    {
-        list_for_each_entry ( pdev, &ats_devices, list )
-        {
-            if ( pdev->seg == seg && pdev->bus == bus && pdev->devfn == devfn )
-            {
-                pos = 0;
-                break;
-            }
-        }
-    }
-    if ( pos )
-        pdev = xmalloc(struct pci_ats_dev);
-    if ( !pdev )
-        return -ENOMEM;
-
-    if ( !(value & ATS_ENABLE) )
-    {
-        value |= ATS_ENABLE;
-        pci_conf_write16(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
-                         pos + ATS_REG_CTL, value);
-    }
-
-    if ( pos )
-    {
-        pdev->seg = seg;
-        pdev->bus = bus;
-        pdev->devfn = devfn;
-        value = pci_conf_read16(seg, bus, PCI_SLOT(devfn),
-                                PCI_FUNC(devfn), pos + ATS_REG_CAP);
-        pdev->ats_queue_depth = value & ATS_QUEUE_DEPTH_MASK;
-        list_add(&pdev->list, &ats_devices);
-    }
-
-    if ( iommu_verbose )
-        dprintk(XENLOG_INFO VTDPREFIX,
-                "%04x:%02x:%02x.%u: ATS %s enabled\n",
-                seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
-                pos ? "is" : "was");
-
-    return pos;
-}
-
-void disable_ats_device(int seg, int bus, int devfn)
-{
-    struct pci_ats_dev *pdev;
-    u32 value;
-    int pos;
-
-    pos = pci_find_ext_capability(seg, bus, devfn, PCI_EXT_CAP_ID_ATS);
-    BUG_ON(!pos);
-
-    value = pci_conf_read16(seg, bus, PCI_SLOT(devfn),
-                            PCI_FUNC(devfn), pos + ATS_REG_CTL);
-    value &= ~ATS_ENABLE;
-    pci_conf_write16(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
-                     pos + ATS_REG_CTL, value);
-
-    list_for_each_entry ( pdev, &ats_devices, list )
-    {
-        if ( pdev->seg == seg && pdev->bus == bus && pdev->devfn == devfn )
-        {
-            list_del(&pdev->list);
-            xfree(pdev);
-            break;
-        }
-    }
-
-    if ( iommu_verbose )
-        dprintk(XENLOG_INFO VTDPREFIX,
-                "%04x:%02x:%02x.%u: ATS is disabled\n",
-                seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
-}
-
-
 static int device_in_domain(struct iommu *iommu, struct pci_ats_dev *pdev, 
 u16 did)
 {
     struct root_entry *root_entry = NULL;

diff -r 121af976b298 -r a559e27ffb2c xen/include/xen/pci.h

xen/include/xen/pci.h +17 -0
@@ -63,6 +63,20 @@ struct pci_dev {
     u64 vf_rlen[6];
 };
 
+#define ATS_REG_CAP    4
+#define ATS_REG_CTL    6
+#define ATS_QUEUE_DEPTH_MASK     0xF
+#define ATS_ENABLE               (1<<15)
+
+struct pci_ats_dev {
+    struct list_head list;
+    u16 seg;
+    u8 bus;
+    u8 devfn;
+    u16 ats_queue_depth;    /* ATS device invalidation queue depth */
+};
+static LIST_HEAD(ats_devices);
+
 #define for_each_pdev(domain, pdev) \
     list_for_each_entry(pdev, &(domain->arch.pdev_list), domain_list)
 
@@ -136,4 +150,7 @@ void msixtbl_pt_unregister(struct domain
 void msixtbl_pt_cleanup(struct domain *d);
 void pci_enable_acs(struct pci_dev *pdev);
 
+int enable_ats_device(int seg, int bus, int devfn);
+void disable_ats_device(int seg, int bus, int devfn);
+
 #endif /* __XEN_PCI_H__ */

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel

author
#3 lore raw

Re: [PATCH 1 of 6] Move some ats functions into vendor neutral directories

Quoted 9 lines · On Friday 21 October 2011 15:08:50 Jan Beulich wrote:
Quoted 8 lines
Quoted 1 line
Quoted 1 line · Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1319201416 -7200
# Node ID a559e27ffb2c2a3a90dc25f09205b66668dcdbbb # Parent 121af976b2988de389db139231103ceedd11bb8a Move some ats functions into vendor neutral directories.

Quoted 5 lines

You move them from an x86-specific place to common code. I suppose Intel had reasons to expect them to be implemented differently in ia64. Hence they should go into e.g. xen/drivers/passthrough/x86/ instead.

Jan

Well, we don't have that directory yet. Could we change folder structures in passthrough to be architecture first, then vendors, for example:
passthough/x86/vtd
passthough/x86/amd
passthough/ia64/vtd

Thanks,
Wei

Quoted 275 lines
Quoted 275 lines

diff -r 121af976b298 -r a559e27ffb2c xen/drivers/passthrough/pci.c

xen/drivers/passthrough/pci.c +87 -0
@@ -748,6 +748,95 @@ static int __init setup_dump_pcidevs(voi
 __initcall(setup_dump_pcidevs);
 #endif
 
+int enable_ats_device(int seg, int bus, int devfn)
+{
+    struct pci_ats_dev *pdev = NULL;
+    u32 value;
+    int pos;
+
+    pos = pci_find_ext_capability(seg, bus, devfn, PCI_EXT_CAP_ID_ATS);
+    BUG_ON(!pos);
+
+    if ( iommu_verbose )
+        dprintk(XENLOG_INFO VTDPREFIX,
+                "%04x:%02x:%02x.%u: ATS capability found\n",
+                seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+
+    value = pci_conf_read16(seg, bus, PCI_SLOT(devfn),
+                            PCI_FUNC(devfn), pos + ATS_REG_CTL);
+    if ( value & ATS_ENABLE )
+    {
+        list_for_each_entry ( pdev, &ats_devices, list )
+        {
+            if ( pdev->seg == seg && pdev->bus == bus && pdev->devfn ==
 devfn ) +            {
+                pos = 0;
+                break;
+            }
+        }
+    }
+    if ( pos )
+        pdev = xmalloc(struct pci_ats_dev);
+    if ( !pdev )
+        return -ENOMEM;
+
+    if ( !(value & ATS_ENABLE) )
+    {
+        value |= ATS_ENABLE;
+        pci_conf_write16(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
+                         pos + ATS_REG_CTL, value);
+    }
+
+    if ( pos )
+    {
+        pdev->seg = seg;
+        pdev->bus = bus;
+        pdev->devfn = devfn;
+        value = pci_conf_read16(seg, bus, PCI_SLOT(devfn),
+                                PCI_FUNC(devfn), pos + ATS_REG_CAP);
+        pdev->ats_queue_depth = value & ATS_QUEUE_DEPTH_MASK;
+        list_add(&pdev->list, &ats_devices);
+    }
+
+    if ( iommu_verbose )
+        dprintk(XENLOG_INFO VTDPREFIX,
+                "%04x:%02x:%02x.%u: ATS %s enabled\n",
+                seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
+                pos ? "is" : "was");
+
+    return pos;
+}
+
+void disable_ats_device(int seg, int bus, int devfn)
+{
+    struct pci_ats_dev *pdev;
+    u32 value;
+    int pos;
+
+    pos = pci_find_ext_capability(seg, bus, devfn, PCI_EXT_CAP_ID_ATS);
+    BUG_ON(!pos);
+
+    value = pci_conf_read16(seg, bus, PCI_SLOT(devfn),
+                            PCI_FUNC(devfn), pos + ATS_REG_CTL);
+    value &= ~ATS_ENABLE;
+    pci_conf_write16(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
+                     pos + ATS_REG_CTL, value);
+
+    list_for_each_entry ( pdev, &ats_devices, list )
+    {
+        if ( pdev->seg == seg && pdev->bus == bus && pdev->devfn ==
 devfn ) +        {
+            list_del(&pdev->list);
+            xfree(pdev);
+            break;
+        }
+    }
+
+    if ( iommu_verbose )
+        dprintk(XENLOG_INFO VTDPREFIX,
+                "%04x:%02x:%02x.%u: ATS is disabled\n",
+                seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+}
 
 /*
  * Local variables:

diff -r 121af976b298 -r a559e27ffb2c xen/drivers/passthrough/vtd/extern.h

xen/drivers/passthrough/vtd/extern.h +0 -2
@@ -62,8 +62,6 @@ extern bool_t ats_enabled;
 struct acpi_drhd_unit * find_ats_dev_drhd(struct iommu *iommu);
 
 int ats_device(int seg, int bus, int devfn);
-int enable_ats_device(int seg, int bus, int devfn);
-void disable_ats_device(int seg, int bus, int devfn);
 int invalidate_ats_tcs(struct iommu *iommu);
 
 int dev_invalidate_iotlb(struct iommu *iommu, u16 did,

diff -r 121af976b298 -r a559e27ffb2c
xen/drivers/passthrough/vtd/x86/ats.c ---
a/xen/drivers/passthrough/vtd/x86/ats.c Fri Oct 14 10:17:22 2011 +0200
+++ b/xen/drivers/passthrough/vtd/x86/ats.c Fri Oct 21 14:50:16 2011
+0200 @@ -30,20 +30,6 @@

static LIST_HEAD(ats_dev_drhd_units);

xen/drivers/passthrough/vtd/extern.h +0 -103
-#define ATS_REG_CAP    4
-#define ATS_REG_CTL    6
-#define ATS_QUEUE_DEPTH_MASK     0xF
-#define ATS_ENABLE               (1<<15)
-
-struct pci_ats_dev {
-    struct list_head list;
-    u16 seg;
-    u8 bus;
-    u8 devfn;
-    u16 ats_queue_depth;    /* ATS device invalidation queue depth */
-};
-static LIST_HEAD(ats_devices);
-
 static void parse_ats_param(char *s);
 custom_param("ats", parse_ats_param);
@@ -121,97 +107,6 @@ int ats_device(int seg, int bus, int dev
     return pos;
 }
 
-int enable_ats_device(int seg, int bus, int devfn)
-{
-    struct pci_ats_dev *pdev = NULL;
-    u32 value;
-    int pos;
-
-    pos = pci_find_ext_capability(seg, bus, devfn, PCI_EXT_CAP_ID_ATS);
-    BUG_ON(!pos);
-
-    if ( iommu_verbose )
-        dprintk(XENLOG_INFO VTDPREFIX,
-                "%04x:%02x:%02x.%u: ATS capability found\n",
-                seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
-
-    value = pci_conf_read16(seg, bus, PCI_SLOT(devfn),
-                            PCI_FUNC(devfn), pos + ATS_REG_CTL);
-    if ( value & ATS_ENABLE )
-    {
-        list_for_each_entry ( pdev, &ats_devices, list )
-        {
-            if ( pdev->seg == seg && pdev->bus == bus && pdev->devfn ==
 devfn ) -            {
-                pos = 0;
-                break;
-            }
-        }
-    }
-    if ( pos )
-        pdev = xmalloc(struct pci_ats_dev);
-    if ( !pdev )
-        return -ENOMEM;
-
-    if ( !(value & ATS_ENABLE) )
-    {
-        value |= ATS_ENABLE;
-        pci_conf_write16(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
-                         pos + ATS_REG_CTL, value);
-    }
-
-    if ( pos )
-    {
-        pdev->seg = seg;
-        pdev->bus = bus;
-        pdev->devfn = devfn;
-        value = pci_conf_read16(seg, bus, PCI_SLOT(devfn),
-                                PCI_FUNC(devfn), pos + ATS_REG_CAP);
-        pdev->ats_queue_depth = value & ATS_QUEUE_DEPTH_MASK;
-        list_add(&pdev->list, &ats_devices);
-    }
-
-    if ( iommu_verbose )
-        dprintk(XENLOG_INFO VTDPREFIX,
-                "%04x:%02x:%02x.%u: ATS %s enabled\n",
-                seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
-                pos ? "is" : "was");
-
-    return pos;
-}
-
-void disable_ats_device(int seg, int bus, int devfn)
-{
-    struct pci_ats_dev *pdev;
-    u32 value;
-    int pos;
-
-    pos = pci_find_ext_capability(seg, bus, devfn, PCI_EXT_CAP_ID_ATS);
-    BUG_ON(!pos);
-
-    value = pci_conf_read16(seg, bus, PCI_SLOT(devfn),
-                            PCI_FUNC(devfn), pos + ATS_REG_CTL);
-    value &= ~ATS_ENABLE;
-    pci_conf_write16(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
-                     pos + ATS_REG_CTL, value);
-
-    list_for_each_entry ( pdev, &ats_devices, list )
-    {
-        if ( pdev->seg == seg && pdev->bus == bus && pdev->devfn ==
 devfn ) -        {
-            list_del(&pdev->list);
-            xfree(pdev);
-            break;
-        }
-    }
-
-    if ( iommu_verbose )
-        dprintk(XENLOG_INFO VTDPREFIX,
-                "%04x:%02x:%02x.%u: ATS is disabled\n",
-                seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
-}
-
-
 static int device_in_domain(struct iommu *iommu, struct pci_ats_dev

*pdev, u16 did)

 {
     struct root_entry *root_entry = NULL;

diff -r 121af976b298 -r a559e27ffb2c xen/include/xen/pci.h

xen/include/xen/pci.h +17 -0
@@ -63,6 +63,20 @@ struct pci_dev {
     u64 vf_rlen[6];
 };
 
+#define ATS_REG_CAP    4
+#define ATS_REG_CTL    6
+#define ATS_QUEUE_DEPTH_MASK     0xF
+#define ATS_ENABLE               (1<<15)
+
+struct pci_ats_dev {
+    struct list_head list;
+    u16 seg;
+    u8 bus;
+    u8 devfn;
+    u16 ats_queue_depth;    /* ATS device invalidation queue depth */
+};
+static LIST_HEAD(ats_devices);
+
 #define for_each_pdev(domain, pdev) \
     list_for_each_entry(pdev, &(domain->arch.pdev_list), domain_list)
 
@@ -136,4 +150,7 @@ void msixtbl_pt_unregister(struct domain
 void msixtbl_pt_cleanup(struct domain *d);
 void pci_enable_acs(struct pci_dev *pdev);
 
+int enable_ats_device(int seg, int bus, int devfn);
+void disable_ats_device(int seg, int bus, int devfn);
+
 #endif /* __XEN_PCI_H__ */

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel

#4 lore raw

Re: [PATCH 1 of 6] Move some ats functions into vendor neutraldirectories

Quoted 15 lines
Quoted 1 line
Quoted 1 line · On 21.10.11 at 15:57, Wei Wang2 <[email protected]> wrote:
Quoted 9 lines · On Friday 21 October 2011 15:08:50 Jan Beulich wrote:
Quoted 8 lines
Quoted 1 line
Quoted 1 line · Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1319201416 -7200
# Node ID a559e27ffb2c2a3a90dc25f09205b66668dcdbbb # Parent 121af976b2988de389db139231103ceedd11bb8a Move some ats functions into vendor neutral directories.

Quoted 3 lines

You move them from an x86-specific place to common code. I suppose Intel had reasons to expect them to be implemented differently in ia64. Hence they should go into e.g. xen/drivers/passthrough/x86/ instead.

Quoted 6 lines

Well, we don't have that directory yet. Could we change folder structures in
passthrough to be architecture first, then vendors, for example:
passthough/x86/vtd
passthough/x86/amd
passthough/ia64/vtd

That doesn't make sense - VT-d is for both ia64 and x86. Code that is common between vendors but architecture specific would reasonably belong into drivers/passthrough/<arch>/, which is what I recommended.

Jan

author
#5 lore raw

PATCH 1/1 Remove VTD prefix from debug output

In reply to Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1319201420 -7200
# Node ID 1b618fbedd2371b2c4a00118f5fde8b063131d27 # Parent a559e27ffb2c2a3a90dc25f09205b66668dcdbbb Remove VTD prefix from debug output.

xen/drivers/passthrough/pci.c +3 -3
diff -r a559e27ffb2c -r 1b618fbedd23 xen/drivers/passthrough/pci.c
@@ -758,7 +758,7 @@ int enable_ats_device(int seg, int bus, 
     BUG_ON(!pos);
 
     if ( iommu_verbose )
-        dprintk(XENLOG_INFO VTDPREFIX,
+        dprintk(XENLOG_INFO,
                 "%04x:%02x:%02x.%u: ATS capability found\n",
                 seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
 
@@ -799,7 +799,7 @@ int enable_ats_device(int seg, int bus, 
     }
 
     if ( iommu_verbose )
-        dprintk(XENLOG_INFO VTDPREFIX,
+        dprintk(XENLOG_INFO,
                 "%04x:%02x:%02x.%u: ATS %s enabled\n",
                 seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
                 pos ? "is" : "was");
@@ -833,7 +833,7 @@ void disable_ats_device(int seg, int bus
     }
 
     if ( iommu_verbose )
-        dprintk(XENLOG_INFO VTDPREFIX,
+        dprintk(XENLOG_INFO,
                 "%04x:%02x:%02x.%u: ATS is disabled\n",
                 seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
 }
author
#6 lore raw

PATCH 1/1 Fix iommu page size encoding when page order > 0

In reply to Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1319201421 -7200
# Node ID bb1330a1f8c7149fb39578382d9f5dfeef13ffa9 # Parent 1b618fbedd2371b2c4a00118f5fde8b063131d27 Fix iommu page size encoding when page order > 0

xen/drivers/passthrough/amd/iommu_map.c +14 -13
diff -r 1b618fbedd23 -r bb1330a1f8c7 xen/drivers/passthrough/amd/iommu_map.c
@@ -77,23 +77,24 @@ static void invalidate_iommu_pages(struc
 {
     u64 addr_lo, addr_hi;
     u32 cmd[4], entry;
-    u64 mask = 0;
     int sflag = 0, pde = 0;
 
+    ASSERT ( order == 0 || order == 9 || order == 18 );
+
+    /* All pages associated with the domainID are invalidated */
+    if ( order || (io_addr == INV_IOMMU_ALL_PAGES_ADDRESS ) )
+    {
+        sflag = 1;
+        pde = 1;
+    }
+
     /* If sflag == 1, the size of the invalidate command is determined
      by the first zero bit in the address starting from Address[12] */
-    if ( order == 9 || order == 18 )
+    if ( order )
     {
-        mask = ((1ULL << (order - 1)) - 1) << PAGE_SHIFT;
-        io_addr |= mask;
-        sflag = 1;
-    }
-
-    /* All pages associated with the domainID are invalidated */
-    else if ( io_addr == 0x7FFFFFFFFFFFF000ULL )
-    {
-        sflag = 1;
-        pde = 1;
+        u64 mask = 1ULL << (order - 1 + PAGE_SHIFT);
+        io_addr &= ~mask;
+        io_addr |= mask - 1;
     }
 
     addr_lo = io_addr & DMA_32BIT_MASK;
@@ -917,7 +918,7 @@ static void _amd_iommu_flush_pages(struc
 
 void amd_iommu_flush_all_pages(struct domain *d)
 {
-    _amd_iommu_flush_pages(d, 0x7FFFFFFFFFFFFULL, 0);
+    _amd_iommu_flush_pages(d, INV_IOMMU_ALL_PAGES_ADDRESS, 0);
 }
 
 void amd_iommu_flush_pages(struct domain *d,
xen/include/asm-x86/hvm/svm/amd-iommu-defs.h +2 -0
diff -r 1b618fbedd23 -r bb1330a1f8c7 xen/include/asm-x86/hvm/svm/amd-iommu-defs.h
@@ -407,4 +407,6 @@
 #define INT_REMAP_ENTRY_VECTOR_MASK     0x00FF0000
 #define INT_REMAP_ENTRY_VECTOR_SHIFT    16
 
+#define INV_IOMMU_ALL_PAGES_ADDRESS     0x7FFFFFFFFFFFFULL
+
 #endif /* _ASM_X86_64_AMD_IOMMU_DEFS_H */
author
#7 lore raw

PATCH 1/1 Add new ATS helper functions

In reply to Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1319201422 -7200
# Node ID f2fbc041f4a710b66f98e76ad8905dcac7920c18 # Parent bb1330a1f8c7149fb39578382d9f5dfeef13ffa9 Add new ATS helper functions

Signed-off-by Wei Wang <[email protected]>

xen/drivers/passthrough/pci.c +68 -0
diff -r bb1330a1f8c7 -r f2fbc041f4a7 xen/drivers/passthrough/pci.c
@@ -838,6 +838,74 @@ void disable_ats_device(int seg, int bus
                 seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
 }
 
+int pci_ats_enabled(int seg, int bus, int devfn)
+{
+    u32 value;
+    int pos;
+
+    pos = pci_find_ext_capability(seg, bus, devfn, PCI_EXT_CAP_ID_ATS);
+    BUG_ON(!pos);
+
+    value = pci_conf_read16(seg, bus, PCI_SLOT(devfn),
+                            PCI_FUNC(devfn), pos + ATS_REG_CTL);
+    return value & ATS_ENABLE;
+}
+
+static void parse_ats_param(char *s);
+custom_param("ats", parse_ats_param);
+
+bool_t __read_mostly ats_enabled = 1;
+
+static void __init parse_ats_param(char *s)
+{
+    char *ss;
+
+    do {
+        ss = strchr(s, ',');
+        if ( ss )
+            *ss = '\0';
+
+        switch ( parse_bool(s) )
+        {
+        case 0:
+            ats_enabled = 0;
+            break;
+        case 1:
+            ats_enabled = 1;
+            break;
+        }
+
+        s = ss + 1;
+    } while ( ss );
+}
+
+int pci_ats_device(int seg, int bus, int devfn)
+{
+    if ( !ats_enabled )
+        return 0;
+
+    if ( !pci_find_ext_capability(seg, bus, devfn, PCI_EXT_CAP_ID_ATS) )
+        return 0;
+
+    return 1;
+}
+
+struct pci_ats_dev* get_ats_device(int seg, int bus, int devfn)
+{
+    struct pci_ats_dev *pdev;
+
+    if ( !pci_ats_device(seg, bus, devfn) )
+        return NULL;
+
+    list_for_each_entry ( pdev, &ats_devices, list )
+    {
+        if ( pdev->seg == seg && pdev->bus == bus && pdev->devfn == devfn )
+            return pdev;
+    }
+
+    return NULL;
+}
+
 /*
  * Local variables:
  * mode: C
xen/drivers/passthrough/vtd/x86/ats.c +0 -29
diff -r bb1330a1f8c7 -r f2fbc041f4a7 xen/drivers/passthrough/vtd/x86/ats.c
@@ -29,35 +29,6 @@
 #include "../extern.h"
 
 static LIST_HEAD(ats_dev_drhd_units);
-
-static void parse_ats_param(char *s);
-custom_param("ats", parse_ats_param);
-
-bool_t __read_mostly ats_enabled = 1;
-
-static void __init parse_ats_param(char *s)
-{
-    char *ss;
-
-    do {
-        ss = strchr(s, ',');
-        if ( ss )
-            *ss = '\0';
-
-        switch ( parse_bool(s) )
-        {
-        case 0:
-            ats_enabled = 0;
-            break;
-        case 1:
-            ats_enabled = 1;
-            break;
-        }
-
-        s = ss + 1;
-    } while ( ss );
-}
-
 struct acpi_drhd_unit * find_ats_dev_drhd(struct iommu *iommu)
 {
     struct acpi_drhd_unit *drhd;
xen/include/xen/pci.h +3 -0
diff -r bb1330a1f8c7 -r f2fbc041f4a7 xen/include/xen/pci.h
@@ -152,5 +152,8 @@ void pci_enable_acs(struct pci_dev *pdev
 
 int enable_ats_device(int seg, int bus, int devfn);
 void disable_ats_device(int seg, int bus, int devfn);
+int pci_ats_enabled(int seg, int bus, int devfn);
+int pci_ats_device(int seg, int bus, int devfn);
+struct pci_ats_dev* get_ats_device(int seg, int bus, int devfn);
 
 #endif /* __XEN_PCI_H__ */
#8 lore raw

Re: [PATCH 4 of 6] Add new ATS helper functions

Quoted 114 lines
Quoted 1 line
Quoted 1 line · Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1319201422 -7200
# Node ID f2fbc041f4a710b66f98e76ad8905dcac7920c18 # Parent bb1330a1f8c7149fb39578382d9f5dfeef13ffa9 Add new ATS helper functions

Signed-off-by Wei Wang <[email protected]>

diff -r bb1330a1f8c7 -r f2fbc041f4a7 xen/drivers/passthrough/pci.c

xen/drivers/passthrough/pci.c +68 -0
@@ -838,6 +838,74 @@ void disable_ats_device(int seg, int bus
                 seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
 }
 
+int pci_ats_enabled(int seg, int bus, int devfn)
+{
+    u32 value;
+    int pos;
+
+    pos = pci_find_ext_capability(seg, bus, devfn, PCI_EXT_CAP_ID_ATS);
+    BUG_ON(!pos);
+
+    value = pci_conf_read16(seg, bus, PCI_SLOT(devfn),
+                            PCI_FUNC(devfn), pos + ATS_REG_CTL);
+    return value & ATS_ENABLE;
+}
+
+static void parse_ats_param(char *s);
+custom_param("ats", parse_ats_param);
+
+bool_t __read_mostly ats_enabled = 1;
+
+static void __init parse_ats_param(char *s)
+{
+    char *ss;
+
+    do {
+        ss = strchr(s, ',');
+        if ( ss )
+            *ss = '\0';
+
+        switch ( parse_bool(s) )
+        {
+        case 0:
+            ats_enabled = 0;
+            break;
+        case 1:
+            ats_enabled = 1;
+            break;
+        }
+
+        s = ss + 1;
+    } while ( ss );
+}
+
+int pci_ats_device(int seg, int bus, int devfn)
+{
+    if ( !ats_enabled )
+        return 0;
+
+    if ( !pci_find_ext_capability(seg, bus, devfn, PCI_EXT_CAP_ID_ATS) )
+        return 0;
+
+    return 1;
+}
+
+struct pci_ats_dev* get_ats_device(int seg, int bus, int devfn)
+{
+    struct pci_ats_dev *pdev;
+
+    if ( !pci_ats_device(seg, bus, devfn) )
+        return NULL;
+
+    list_for_each_entry ( pdev, &ats_devices, list )
+    {
+        if ( pdev->seg == seg && pdev->bus == bus && pdev->devfn == devfn )
+            return pdev;
+    }
+
+    return NULL;
+}
+
 /*
  * Local variables:
  * mode: C

diff -r bb1330a1f8c7 -r f2fbc041f4a7 xen/drivers/passthrough/vtd/x86/ats.c

xen/drivers/passthrough/vtd/x86/ats.c +0 -19
@@ -29,35 +29,6 @@
 #include "../extern.h"
 
 static LIST_HEAD(ats_dev_drhd_units);
-
-static void parse_ats_param(char *s);
-custom_param("ats", parse_ats_param);
-
-bool_t __read_mostly ats_enabled = 1;
-
-static void __init parse_ats_param(char *s)
-{
-    char *ss;
-
-    do {
-        ss = strchr(s, ',');
-        if ( ss )
-            *ss = '\0';
-
-        switch ( parse_bool(s) )
-        {
-        case 0:
-            ats_enabled = 0;

xen/drivers/passthrough/vtd/x86/ats.c line 60

Quoted 10 lines
xen/drivers/passthrough/vtd/x86/ats.c +0 -10
-            break;
-        case 1:
-            ats_enabled = 1;
-            break;
-        }
-
-        s = ss + 1;
-    } while ( ss );
-}
-

Why don't you move this chunk together with the other movement you do?

Jan

Quoted 21 lines
xen/drivers/passthrough/vtd/x86/ats.c +0 -0
 struct acpi_drhd_unit * find_ats_dev_drhd(struct iommu *iommu)
 {
     struct acpi_drhd_unit *drhd;

diff -r bb1330a1f8c7 -r f2fbc041f4a7 xen/include/xen/pci.h

xen/include/xen/pci.h +3 -0
@@ -152,5 +152,8 @@ void pci_enable_acs(struct pci_dev *pdev
 
 int enable_ats_device(int seg, int bus, int devfn);
 void disable_ats_device(int seg, int bus, int devfn);
+int pci_ats_enabled(int seg, int bus, int devfn);
+int pci_ats_device(int seg, int bus, int devfn);
+struct pci_ats_dev* get_ats_device(int seg, int bus, int devfn);
 
 #endif /* __XEN_PCI_H__ */

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel

author
#9 lore raw

Re: [PATCH 4 of 6] Add new ATS helper functions

Quoted 121 lines · On Friday 21 October 2011 15:11:38 Jan Beulich wrote:
Quoted 121 lines
Quoted 1 line
Quoted 1 line · Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1319201422 -7200
# Node ID f2fbc041f4a710b66f98e76ad8905dcac7920c18 # Parent bb1330a1f8c7149fb39578382d9f5dfeef13ffa9 Add new ATS helper functions

Signed-off-by Wei Wang <[email protected]>

diff -r bb1330a1f8c7 -r f2fbc041f4a7 xen/drivers/passthrough/pci.c

xen/drivers/passthrough/pci.c +67 -0
@@ -838,6 +838,74 @@ void disable_ats_device(int seg, int bus
                 seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
 }
 
+int pci_ats_enabled(int seg, int bus, int devfn)
+{
+    u32 value;
+    int pos;
+
+    pos = pci_find_ext_capability(seg, bus, devfn, PCI_EXT_CAP_ID_ATS);
+    BUG_ON(!pos);
+
+    value = pci_conf_read16(seg, bus, PCI_SLOT(devfn),
+                            PCI_FUNC(devfn), pos + ATS_REG_CTL);
+    return value & ATS_ENABLE;
+}
+
+static void parse_ats_param(char *s);
+custom_param("ats", parse_ats_param);
+
+bool_t __read_mostly ats_enabled = 1;
+
+static void __init parse_ats_param(char *s)
+{
+    char *ss;
+
+    do {
+        ss = strchr(s, ',');
+        if ( ss )
+            *ss = '\0';
+
+        switch ( parse_bool(s) )
+        {
+        case 0:
+            ats_enabled = 0;
+            break;
+        case 1:
+            ats_enabled = 1;
+            break;
+        }
+
+        s = ss + 1;
+    } while ( ss );
+}
+
+int pci_ats_device(int seg, int bus, int devfn)
+{
+    if ( !ats_enabled )
+        return 0;
+
+    if ( !pci_find_ext_capability(seg, bus, devfn, PCI_EXT_CAP_ID_ATS) )
+        return 0;
+
+    return 1;
+}
+
+struct pci_ats_dev* get_ats_device(int seg, int bus, int devfn)
+{
+    struct pci_ats_dev *pdev;
+
+    if ( !pci_ats_device(seg, bus, devfn) )
+        return NULL;
+
+    list_for_each_entry ( pdev, &ats_devices, list )
+    {
+        if ( pdev->seg == seg && pdev->bus == bus && pdev->devfn ==
 devfn ) +            return pdev;
+    }
+
+    return NULL;
+}
+
 /*
  * Local variables:
  * mode: C

diff -r bb1330a1f8c7 -r f2fbc041f4a7
xen/drivers/passthrough/vtd/x86/ats.c ---
a/xen/drivers/passthrough/vtd/x86/ats.c Fri Oct 21 14:50:21 2011 +0200
+++ b/xen/drivers/passthrough/vtd/x86/ats.c Fri Oct 21 14:50:22 2011
+0200 @@ -29,35 +29,6 @@
#include "../extern.h"

static LIST_HEAD(ats_dev_drhd_units);

xen/drivers/passthrough/pci.c +0 -24
-
-static void parse_ats_param(char *s);
-custom_param("ats", parse_ats_param);
-
-bool_t __read_mostly ats_enabled = 1;
-
-static void __init parse_ats_param(char *s)
-{
-    char *ss;
-
-    do {
-        ss = strchr(s, ',');
-        if ( ss )
-            *ss = '\0';
-
-        switch ( parse_bool(s) )
-        {
-        case 0:
-            ats_enabled = 0;
-            break;
-        case 1:
-            ats_enabled = 1;
-            break;
-        }
Quoted 8 lines

xen/drivers/passthrough/pci.c

Quoted 5 lines
xen/drivers/passthrough/pci.c +0 -5
-
-        s = ss + 1;
-    } while ( ss );
-}
-

Why don't you move this chunk together with the other movement you do?

Sure, this should be combined with patch 1. I will fix it in the next try. Thanks,
Wei

Quoted 23 lines

Jan

Quoted 21 lines

struct acpi_drhd_unit * find_ats_dev_drhd(struct iommu *iommu)

 {
     struct acpi_drhd_unit *drhd;

diff -r bb1330a1f8c7 -r f2fbc041f4a7 xen/include/xen/pci.h

xen/include/xen/pci.h +3 -0
@@ -152,5 +152,8 @@ void pci_enable_acs(struct pci_dev *pdev
 
 int enable_ats_device(int seg, int bus, int devfn);
 void disable_ats_device(int seg, int bus, int devfn);
+int pci_ats_enabled(int seg, int bus, int devfn);
+int pci_ats_device(int seg, int bus, int devfn);
+struct pci_ats_dev* get_ats_device(int seg, int bus, int devfn);
 
 #endif /* __XEN_PCI_H__ */

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel

author
#10 lore raw

PATCH 1/1 Add iotlb invalidation command for amd iommu

In reply to Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1319201423 -7200
# Node ID 6009089b0511c843f54435d02dcd72394d7e164f # Parent f2fbc041f4a710b66f98e76ad8905dcac7920c18 Add iotlb invalidation command for amd iommu

xen/drivers/passthrough/amd/iommu_map.c +128 -0
diff -r f2fbc041f4a7 -r 6009089b0511 xen/drivers/passthrough/amd/iommu_map.c
@@ -128,6 +128,75 @@ static void invalidate_iommu_pages(struc
     send_iommu_command(iommu, cmd);
 }
 
+static void invalidate_iotlb_pages(struct amd_iommu *iommu,
+                                   u16 maxpend, u32 pasid, u16 queueid,
+                                   u64 io_addr, u16 dev_id, u16 order)
+{
+    u64 addr_lo, addr_hi;
+    u32 cmd[4], entry;
+    int sflag = 0;
+
+    ASSERT ( order == 0 || order == 9 || order == 18 );
+
+    if ( order || (io_addr == INV_IOMMU_ALL_PAGES_ADDRESS ) )
+        sflag = 1;
+
+    /* If sflag == 1, the size of the invalidate command is determined
+     by the first zero bit in the address starting from Address[12] */
+    if ( order )
+    {
+        u64 mask = 1ULL << (order - 1 + PAGE_SHIFT);
+        io_addr &= ~mask;
+        io_addr |= mask - 1;
+    }
+
+    addr_lo = io_addr & DMA_32BIT_MASK;
+    addr_hi = io_addr >> 32;
+
+    set_field_in_reg_u32(dev_id, 0,
+                         IOMMU_INV_IOTLB_PAGES_DEVICE_ID_MASK,
+                         IOMMU_INV_IOTLB_PAGES_DEVICE_ID_SHIFT, &entry);
+
+    set_field_in_reg_u32(maxpend, entry,
+                         IOMMU_INV_IOTLB_PAGES_MAXPEND_MASK,
+                         IOMMU_INV_IOTLB_PAGES_MAXPEND_SHIFT, &entry);
+
+    set_field_in_reg_u32(pasid & 0xff, entry,
+                         IOMMU_INV_IOTLB_PAGES_PASID1_MASK,
+                         IOMMU_INV_IOTLB_PAGES_PASID1_SHIFT, &entry);
+    cmd[0] = entry;
+
+    set_field_in_reg_u32(IOMMU_CMD_INVALIDATE_IOTLB_PAGES, 0,
+                         IOMMU_CMD_OPCODE_MASK, IOMMU_CMD_OPCODE_SHIFT,
+                         &entry);
+
+    set_field_in_reg_u32(pasid >> 8, entry,
+                         IOMMU_INV_IOTLB_PAGES_PASID2_MASK, 
+                         IOMMU_INV_IOTLB_PAGES_PASID2_SHIFT,
+                         &entry);
+
+    set_field_in_reg_u32(queueid, entry,
+                         IOMMU_INV_IOTLB_PAGES_QUEUEID_MASK, 
+                         IOMMU_INV_IOTLB_PAGES_QUEUEID_SHIFT,
+                         &entry);
+    cmd[1] = entry;
+
+    set_field_in_reg_u32(sflag, 0,
+                         IOMMU_INV_IOTLB_PAGES_S_FLAG_MASK,
+                         IOMMU_INV_IOTLB_PAGES_S_FLAG_MASK, &entry);
+
+    set_field_in_reg_u32((u32)addr_lo >> PAGE_SHIFT, entry,
+                         IOMMU_INV_IOTLB_PAGES_ADDR_LOW_MASK,
+                         IOMMU_INV_IOTLB_PAGES_ADDR_LOW_SHIFT, &entry);
+    cmd[2] = entry;
+
+    set_field_in_reg_u32((u32)addr_hi, 0,
+                         IOMMU_INV_IOTLB_PAGES_ADDR_HIGH_MASK,
+                         IOMMU_INV_IOTLB_PAGES_ADDR_HIGH_SHIFT, &entry);
+    cmd[3] = entry;
+
+    send_iommu_command(iommu, cmd);
+}
 void flush_command_buffer(struct amd_iommu *iommu)
 {
     u32 cmd[4], status;
@@ -896,6 +965,62 @@ int amd_iommu_reserve_domain_unity_map(s
     return 0;
 }
 
+void amd_iommu_flush_iotlb(struct pci_ats_dev *pdev,
+                           uint64_t gaddr, unsigned int order)
+{
+    unsigned long flags;
+    struct amd_iommu *iommu;
+    unsigned int bdf, req_id, queueid, maxpend;
+
+    if ( !ats_enabled )
+        return;
+
+    bdf = (pdev->bus << 8) | pdev->devfn;
+    iommu = find_iommu_for_device(pdev->seg, bdf);
+
+    if ( !iommu )
+    {
+        AMD_IOMMU_DEBUG("%s: Fail to find iommu for device %04x:%02x:%02x.%u\n",
+                        __func__, pdev->seg, pdev->bus, PCI_SLOT(pdev->devfn),
+                        PCI_FUNC(pdev->devfn));
+        return;
+    }
+
+    if ( !iommu->iotlb_support )
+        return;
+
+    req_id = get_dma_requestor_id(iommu->seg, bdf);
+    queueid = req_id;
+    maxpend = (pdev->ats_queue_depth + 32) & 0xff;
+
+    /* send INVALIDATE_IOTLB_PAGES command */
+    spin_lock_irqsave(&iommu->lock, flags);
+    invalidate_iotlb_pages(iommu, maxpend, 0, queueid,
+                           gaddr, req_id, order);
+    flush_command_buffer(iommu);
+    spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+void amd_iommu_flush_all_iotlbs(struct domain *d, 
+                                uint64_t gaddr, unsigned int order)
+{
+    struct pci_ats_dev *ats_pdev;
+    struct pci_dev *pdev;
+
+    if ( !ats_enabled )
+        return;
+
+    for_each_pdev( d, pdev )
+    {
+        ats_pdev = get_ats_device(pdev->seg, pdev->bus, pdev->devfn);
+        if ( ats_pdev == NULL )
+            continue;
+        if ( !pci_ats_enabled(ats_pdev->seg, ats_pdev->bus, ats_pdev->devfn) )
+            continue;
+
+        amd_iommu_flush_iotlb(ats_pdev, gaddr, order);
+    }
+}
 
 /* Flush iommu cache after p2m changes. */
 static void _amd_iommu_flush_pages(struct domain *d,
@@ -914,6 +1039,9 @@ static void _amd_iommu_flush_pages(struc
         flush_command_buffer(iommu);
         spin_unlock_irqrestore(&iommu->lock, flags);
     }
+
+    if ( ats_enabled )
+        amd_iommu_flush_all_iotlbs(d, gaddr, order);
 }
 
 void amd_iommu_flush_all_pages(struct domain *d)
xen/include/asm-x86/hvm/svm/amd-iommu-defs.h +18 -0
diff -r f2fbc041f4a7 -r 6009089b0511 xen/include/asm-x86/hvm/svm/amd-iommu-defs.h
@@ -233,6 +233,24 @@
 #define IOMMU_INV_INT_TABLE_DEVICE_ID_MASK   0x0000FFFF
 #define IOMMU_INV_INT_TABLE_DEVICE_ID_SHIFT  0
 
+/* INVALIDATE_IOTLB_PAGES command */
+#define IOMMU_INV_IOTLB_PAGES_MAXPEND_MASK          0xff000000
+#define IOMMU_INV_IOTLB_PAGES_MAXPEND_SHIFT         24
+#define IOMMU_INV_IOTLB_PAGES_PASID1_MASK           0x00ff0000
+#define IOMMU_INV_IOTLB_PAGES_PASID1_SHIFT          16
+#define IOMMU_INV_IOTLB_PAGES_PASID2_MASK           0x0fff0000
+#define IOMMU_INV_IOTLB_PAGES_PASID2_SHIFT          16
+#define IOMMU_INV_IOTLB_PAGES_QUEUEID_MASK          0x0000ffff
+#define IOMMU_INV_IOTLB_PAGES_QUEUEID_SHIFT         0
+#define IOMMU_INV_IOTLB_PAGES_DEVICE_ID_MASK        0x0000FFFF
+#define IOMMU_INV_IOTLB_PAGES_DEVICE_ID_SHIFT       0
+#define IOMMU_INV_IOTLB_PAGES_ADDR_LOW_MASK         0xFFFFF000
+#define IOMMU_INV_IOTLB_PAGES_ADDR_LOW_SHIFT        12
+#define IOMMU_INV_IOTLB_PAGES_ADDR_HIGH_MASK        0xFFFFFFFF
+#define IOMMU_INV_IOTLB_PAGES_ADDR_HIGH_SHIFT       0
+#define IOMMU_INV_IOTLB_PAGES_S_FLAG_MASK           0x00000001
+#define IOMMU_INV_IOTLB_PAGES_S_FLAG_SHIFT          0
+
 /* Event Log */
 #define IOMMU_EVENT_LOG_BASE_LOW_OFFSET		0x10
 #define IOMMU_EVENT_LOG_BASE_HIGH_OFFSET	0x14
xen/include/asm-x86/hvm/svm/amd-iommu-proto.h +4 -0
diff -r f2fbc041f4a7 -r 6009089b0511 xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
@@ -55,6 +55,8 @@ int amd_iommu_unmap_page(struct domain *
 void amd_iommu_flush_pages(struct domain *d, unsigned long gfn,
                            unsigned int order);
 void amd_iommu_flush_all_pages(struct domain *d);
+void amd_iommu_flush_iotlb(struct pci_ats_dev *pdev,
+                           uint64_t gaddr, unsigned int order);
 
 u64 amd_iommu_get_next_table_from_pte(u32 *entry);
 int amd_iommu_reserve_domain_unity_map(struct domain *domain,
@@ -165,4 +167,6 @@ static inline void __free_amd_iommu_tabl
     free_xenheap_pages(table, order);
 }
 
+extern bool_t ats_enabled;
+
 #endif /* _ASM_X86_64_AMD_IOMMU_PROTO_H */
author
#11 lore raw

PATCH 1/1 Enable ats devices on amd iommu systems

In reply to Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1319201424 -7200
# Node ID 1ccad89116b57c95c0ead34c9f8cc4b67fec9316 # Parent 6009089b0511c843f54435d02dcd72394d7e164f Enable ats devices on amd iommu systems

xen/drivers/passthrough/amd/iommu_map.c +11 -0
diff -r 6009089b0511 -r 1ccad89116b5 xen/drivers/passthrough/amd/iommu_map.c
@@ -368,6 +368,17 @@ void amd_iommu_set_root_page_table(
     dte[0] = entry;
 }
 
+void iommu_dte_set_iotlb(u32 *dte, u8 i)
+{
+    u32 entry;
+
+    entry = dte[3];
+    set_field_in_reg_u32(!!i, entry,
+                         IOMMU_DEV_TABLE_IOTLB_SUPPORT_MASK,
+                         IOMMU_DEV_TABLE_IOTLB_SUPPORT_SHIFT, &entry);
+    dte[3] = entry;
+}
+
 void __init amd_iommu_set_intremap_table(
     u32 *dte, u64 intremap_ptr, u8 int_valid)
 {
xen/drivers/passthrough/amd/pci_amd_iommu.c +44 -10

137 lines not on this page · raw message

xen/include/asm-x86/hvm/svm/amd-iommu-proto.h +1 -0
diff -r 6009089b0511 -r 1ccad89116b5 xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
@@ -75,6 +75,7 @@ void amd_iommu_set_intremap_table(
     u32 *dte, u64 intremap_ptr, u8 int_valid);
 void amd_iommu_set_root_page_table(
     u32 *dte, u64 root_ptr, u16 domain_id, u8 paging_mode, u8 valid);
+void iommu_dte_set_iotlb(u32 *dte, u8 i);
 void invalidate_dev_table_entry(struct amd_iommu *iommu, u16 devic_id);
 
 /* send cmd to iommu */