# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1211881079 -3600
# Node ID 2ec56b04abf48d091310e6f778297d82f328eefe
# Parent b38e8c9f7a693e7dc1d6fcf63f11e616b5dec12c
vt-d: Do FLR of assigned devices with VT-d
Currently there is a pdev_flr() function to do FLR before device
assignment in qemu, but most of devices don't have FLR capability.
What's more, should do FLR before assignment and deassignment for
keeping correct device status. If the device doesn't have FLR
capablility, this patch implemented to enter D3hot and return to D0 to
do FLR. And exposed pdev_flr() in VT-d utils, then it can be invoked
by assignment and deassignment functions.
Signed-off-by: Weidong Han <weidong.han@xxxxxxxxx>
Signed-off-by: Anthony Xu <anthony.xu@xxxxxxxxx>
xen-unstable changeset: 16875:74a9bfccddba0fedd59c57e5f1a76d83a4178d7c
xen-unstable date: Thu Jan 24 14:39:38 2008 +0000
---
tools/ioemu/hw/pass-through.c | 55 ------------------
xen/arch/x86/hvm/vmx/vtd/intel-iommu.c | 4 +
xen/arch/x86/hvm/vmx/vtd/utils.c | 97 ++++++++++++++++++++++++++++++++-
3 files changed, 101 insertions(+), 55 deletions(-)
diff -r b38e8c9f7a69 -r 2ec56b04abf4 tools/ioemu/hw/pass-through.c
--- a/tools/ioemu/hw/pass-through.c Fri May 23 11:16:44 2008 +0100
+++ b/tools/ioemu/hw/pass-through.c Tue May 27 10:37:59 2008 +0100
@@ -56,56 +56,6 @@ static int next_bdf(char **str, int *seg
return 1;
}
-uint8_t find_cap_offset(struct pci_dev *pci_dev, uint8_t cap)
-{
- int id;
- int max_cap = 48;
- int pos = PCI_CAPABILITY_LIST;
- int status;
-
- status = pci_read_byte(pci_dev, PCI_STATUS);
- if ( (status & PCI_STATUS_CAP_LIST) == 0 )
- return 0;
-
- while ( max_cap-- )
- {
- pos = pci_read_byte(pci_dev, pos);
- if ( pos < 0x40 )
- break;
-
- pos &= ~3;
- id = pci_read_byte(pci_dev, pos + PCI_CAP_LIST_ID);
-
- if ( id == 0xff )
- break;
- if ( id == cap )
- return pos;
-
- pos += PCI_CAP_LIST_NEXT;
- }
- return 0;
-}
-
-void pdev_flr(struct pci_dev *pci_dev)
-{
- int pos;
- int dev_cap;
- int dev_status;
-
- pos = find_cap_offset(pci_dev, PCI_CAP_ID_EXP);
- if ( pos )
- {
- dev_cap = pci_read_long(pci_dev, pos + PCI_EXP_DEVCAP);
- if ( dev_cap & PCI_EXP_DEVCAP_FLR )
- {
- pci_write_word(pci_dev, pos + PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_FLR);
- do {
- dev_status = pci_read_long(pci_dev, pos + PCI_EXP_DEVSTA);
- } while (dev_status & PCI_EXP_DEVSTA_TRPND);
- }
- }
-}
-
/* Being called each time a mmio region has been updated */
void pt_iomem_map(PCIDevice *d, int i, uint32_t e_phys, uint32_t e_size,
int type)
@@ -273,7 +223,7 @@ static int pt_register_regions(struct pt
PCIDevice *d = &assigned_device->dev;
/* Register PIO/MMIO BARs */
- for ( i=0; i < PCI_BAR_ENTRIES; i++ )
+ for ( i = 0; i < PCI_BAR_ENTRIES; i++ )
{
if ( pci_dev->base_addr[i] )
{
@@ -358,9 +308,6 @@ struct pt_dev * register_real_device(PCI
assigned_device->pci_dev = pci_dev;
- /* Issue PCIe FLR */
- pdev_flr(pci_dev);
-
/* Assign device */
machine_bdf.reg = 0;
machine_bdf.bus = r_bus;
diff -r b38e8c9f7a69 -r 2ec56b04abf4 xen/arch/x86/hvm/vmx/vtd/intel-iommu.c
--- a/xen/arch/x86/hvm/vmx/vtd/intel-iommu.c Fri May 23 11:16:44 2008 +0100
+++ b/xen/arch/x86/hvm/vmx/vtd/intel-iommu.c Tue May 27 10:37:59 2008 +0100
@@ -40,6 +40,8 @@ extern void print_iommu_regs(struct acpi
extern void print_iommu_regs(struct acpi_drhd_unit *drhd);
extern void print_vtd_entries(struct domain *d, int bus, int devfn,
unsigned long gmfn);
+
+void pdev_flr(u8 bus, u8 devfn);
static spinlock_t domid_bitmap_lock; /* protect domain id bitmap */
static int domid_bitmap_size; /* domain id bitmap size in bit */
@@ -1424,6 +1426,7 @@ void return_devices_to_dom0(struct domai
dprintk(XENLOG_INFO VTDPREFIX,
"return_devices_to_dom0: bdf = %x:%x:%x\n",
pdev->bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+ pdev_flr(pdev->bus, pdev->devfn);
reassign_device_ownership(d, dom0, pdev->bus, pdev->devfn);
}
@@ -1862,6 +1865,7 @@ int assign_device(struct domain *d, u8 b
"assign_device: bus = %x dev = %x func = %x\n",
bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+ pdev_flr(bus, devfn);
reassign_device_ownership(dom0, d, bus, devfn);
/* Setup rmrr identify mapping */
diff -r b38e8c9f7a69 -r 2ec56b04abf4 xen/arch/x86/hvm/vmx/vtd/utils.c
--- a/xen/arch/x86/hvm/vmx/vtd/utils.c Fri May 23 11:16:44 2008 +0100
+++ b/xen/arch/x86/hvm/vmx/vtd/utils.c Tue May 27 10:37:59 2008 +0100
@@ -22,7 +22,7 @@
#include <xen/irq.h>
#include <xen/spinlock.h>
#include <xen/sched.h>
-#include <asm/delay.h>
+#include <xen/delay.h>
#include <asm/iommu.h>
#include <asm/hvm/vmx/intel-iommu.h>
#include "dmar.h"
@@ -93,6 +93,101 @@ void disable_pmr(struct iommu *iommu)
"Disabled protected memory registers\n");
}
+static u8 find_cap_offset(u8 bus, u8 dev, u8 func, u8 cap)
+{
+ u8 id;
+ int max_cap = 48;
+ u8 pos = PCI_CAPABILITY_LIST;
+ u16 status;
+
+ status = read_pci_config_16(bus, dev, func, PCI_STATUS);
+ if ( (status & PCI_STATUS_CAP_LIST) == 0 )
+ return 0;
+
+ while ( max_cap-- )
+ {
+ pos = read_pci_config_byte(bus, dev, func, pos);
+ if ( pos < 0x40 )
+ break;
+
+ pos &= ~3;
+ id = read_pci_config_byte(bus, dev, func, pos + PCI_CAP_LIST_ID);
+
+ if ( id == 0xff )
+ break;
+ else if ( id == cap )
+ return pos;
+
+ pos += PCI_CAP_LIST_NEXT;
+ }
+
+ return 0;
+}
+
+#define PCI_D3hot (3)
+#define PCI_CONFIG_DWORD_SIZE (64)
+#define PCI_EXP_DEVCAP_FLR (1 << 28)
+#define PCI_EXP_DEVCTL_FLR (1 << 15)
+
+void pdev_flr(u8 bus, u8 devfn)
+{
+ u8 pos;
+ u32 dev_cap, dev_status, pm_ctl;
+ int flr = 0;
+ u8 dev = PCI_SLOT(devfn);
+ u8 func = PCI_FUNC(devfn);
+
+ pos = find_cap_offset(bus, dev, func, PCI_CAP_ID_EXP);
+ if ( pos != 0 )
+ {
+ dev_cap = read_pci_config(bus, dev, func, pos + PCI_EXP_DEVCAP);
+ if ( dev_cap & PCI_EXP_DEVCAP_FLR )
+ {
+ write_pci_config(bus, dev, func,
+ pos + PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_FLR);
+ do {
+ dev_status = read_pci_config(bus, dev, func,
+ pos + PCI_EXP_DEVSTA);
+ } while ( dev_status & PCI_EXP_DEVSTA_TRPND );
+
+ flr = 1;
+ }
+ }
+
+ /* If this device doesn't support function level reset,
+ * program device from D0 t0 D3hot, and then return to D0
+ * to implement function level reset
+ */
+ if ( flr == 0 )
+ {
+ pos = find_cap_offset(bus, dev, func, PCI_CAP_ID_PM);
+ if ( pos != 0 )
+ {
+ int i;
+ u32 config[PCI_CONFIG_DWORD_SIZE];
+ for ( i = 0; i < PCI_CONFIG_DWORD_SIZE; i++ )
+ config[i] = read_pci_config(bus, dev, func, i*4);
+
+ /* Enter D3hot without soft reset */
+ pm_ctl = read_pci_config(bus, dev, func, pos + PCI_PM_CTRL);
+ pm_ctl |= PCI_PM_CTRL_NO_SOFT_RESET;
+ pm_ctl &= ~PCI_PM_CTRL_STATE_MASK;
+ pm_ctl |= PCI_D3hot;
+ write_pci_config(bus, dev, func, pos + PCI_PM_CTRL, pm_ctl);
+ mdelay(10);
+
+ /* From D3hot to D0 */
+ write_pci_config(bus, dev, func, pos + PCI_PM_CTRL, 0);
+ mdelay(10);
+
+ /* Write saved configurations to device */
+ for ( i = 0; i < PCI_CONFIG_DWORD_SIZE; i++ )
+ write_pci_config(bus, dev, func, i*4, config[i]);
+
+ flr = 1;
+ }
+ }
+}
void print_iommu_regs(struct acpi_drhd_unit *drhd)
{
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|