]> xenbits.xensource.com Git - xen.git/commitdiff
x86: Emulate accesses to PCI window registers cf8/cfc to synchronise
authorKeir Fraser <keir.fraser@citrix.com>
Fri, 11 Apr 2008 12:19:55 +0000 (13:19 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Fri, 11 Apr 2008 12:19:55 +0000 (13:19 +0100)
with accesses by teh hypervisor itself. All users of cf8/cfc go
through new access functions which take the appropriate spinlock.

Based on a patch by Haitao Shan <haitao.shan@intel.com>

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
16 files changed:
xen/arch/x86/Makefile
xen/arch/x86/cpu/amd.c
xen/arch/x86/domain_build.c
xen/arch/x86/pci.c [new file with mode: 0644]
xen/arch/x86/traps.c
xen/drivers/passthrough/amd/iommu_detect.c
xen/drivers/passthrough/amd/iommu_init.c
xen/drivers/passthrough/amd/pci_amd_iommu.c
xen/drivers/passthrough/pci-direct.h [deleted file]
xen/drivers/passthrough/vtd/dmar.c
xen/drivers/passthrough/vtd/intremap.c
xen/drivers/passthrough/vtd/iommu.c
xen/drivers/passthrough/vtd/qinval.c
xen/drivers/passthrough/vtd/utils.c
xen/include/asm-x86/domain.h
xen/include/xen/pci.h [new file with mode: 0644]

index 086a7b530fa19d1f9681724010a06213cee4baa9..334a996eb61885f751f738432cff2b510aebc3a4 100644 (file)
@@ -31,6 +31,7 @@ obj-y += mm.o
 obj-y += mpparse.o
 obj-y += nmi.o
 obj-y += numa.o
+obj-y += pci.o
 obj-y += physdev.o
 obj-y += rwlock.o
 obj-y += setup.o
index 909a73f3fa8b11778dcd330e702d9e7868a01b92..f0253152bcf5897135f4f624c3e08e074ea7eaa9 100644 (file)
@@ -3,6 +3,7 @@
 #include <xen/bitops.h>
 #include <xen/mm.h>
 #include <xen/smp.h>
+#include <xen/pci.h>
 #include <asm/io.h>
 #include <asm/msr.h>
 #include <asm/processor.h>
@@ -66,19 +67,6 @@ static int c1_ramping_may_cause_clock_drift(struct cpuinfo_x86 *c)
        return 1;
 }
 
-/* PCI access functions. Should be safe to use 0xcf8/0xcfc port accesses here. */
-static u8 pci_read_byte(u32 bus, u32 dev, u32 fn, u32 reg)
-{
-       outl((1U<<31) | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3), 0xcf8);
-       return inb(0xcfc + (reg & 3));
-}
-
-static void pci_write_byte(u32 bus, u32 dev, u32 fn, u32 reg, u8 val)
-{
-       outl((1U<<31) | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3), 0xcf8);
-       outb(val, 0xcfc + (reg & 3));
-}
-
 /*
  * Disable C1-Clock ramping if enabled in PMM7.CpuLowPwrEnh on 8th-generation
  * cores only. Assume BIOS has setup all Northbridges equivalently.
@@ -90,12 +78,12 @@ static void disable_c1_ramping(void)
 
        for (node=0; node < NR_CPUS; node++) {
                /* PMM7: bus=0, dev=0x18+node, function=0x3, register=0x87. */
-               pmm7 = pci_read_byte(0, 0x18+node, 0x3, 0x87);
+               pmm7 = pci_conf_read8(0, 0x18+node, 0x3, 0x87);
                /* Invalid read means we've updated every Northbridge. */
                if (pmm7 == 0xFF)
                        break;
                pmm7 &= 0xFC; /* clear pmm7[1:0] */
-               pci_write_byte(0, 0x18+node, 0x3, 0x87, pmm7);
+               pci_conf_write8(0, 0x18+node, 0x3, 0x87, pmm7);
                printk ("AMD: Disabling C1 Clock Ramping Node #%x\n", node);
        }
 }
index f37146bb4621d61dacf63848d0a23d396412eb21..56106bae2f02ebf1a9b3d99742cd37e96938c8f3 100644 (file)
@@ -957,6 +957,8 @@ int __init construct_dom0(
     rc |= ioports_deny_access(dom0, 0x40, 0x43);
     /* PIT Channel 2 / PC Speaker Control. */
     rc |= ioports_deny_access(dom0, 0x61, 0x61);
+    /* PCI configuration spaces. */
+    rc |= ioports_deny_access(dom0, 0xcf8, 0xcff);
     /* Command-line I/O ranges. */
     process_dom0_ioports_disable();
 
diff --git a/xen/arch/x86/pci.c b/xen/arch/x86/pci.c
new file mode 100644 (file)
index 0000000..341457b
--- /dev/null
@@ -0,0 +1,118 @@
+/******************************************************************************
+ * pci.c
+ * 
+ * PCI access functions.
+ */
+
+#include <xen/config.h>
+#include <xen/pci.h>
+#include <xen/spinlock.h>
+#include <asm/io.h>
+
+#define PCI_CONF_ADDRESS(bus, dev, func, reg) \
+    (0x80000000 | (bus << 16) | (dev << 11) | (func << 8) | (reg & ~3))
+
+static DEFINE_SPINLOCK(pci_config_lock);
+
+uint32_t pci_conf_read(uint32_t cf8, uint8_t offset, uint8_t bytes)
+{
+    unsigned long flags;
+    uint32_t value;
+
+    BUG_ON((offset + bytes) > 4);
+
+    spin_lock_irqsave(&pci_config_lock, flags);
+
+    outl(cf8, 0xcf8);
+
+    switch ( bytes )
+    {
+    case 1:
+        value = inb(0xcfc + offset);
+        break;
+    case 2:
+        value = inw(0xcfc + offset);
+        break;
+    case 4:
+        value = inl(0xcfc + offset);
+        break;
+    default:
+        value = 0;
+        BUG();
+    }
+
+    spin_unlock_irqrestore(&pci_config_lock, flags);
+
+    return value;
+}
+
+void pci_conf_write(uint32_t cf8, uint8_t offset, uint8_t bytes, uint32_t data)
+{
+    unsigned long flags;
+
+    BUG_ON((offset + bytes) > 4);
+
+    spin_lock_irqsave(&pci_config_lock, flags);
+
+    outl(cf8, 0xcf8);
+
+    switch ( bytes )
+    {
+    case 1:
+        outb((uint8_t)data, 0xcfc + offset);
+        break;
+    case 2:
+        outw((uint16_t)data, 0xcfc + offset);
+        break;
+    case 4:
+        outl(data, 0xcfc + offset);
+        break;
+    }
+
+    spin_unlock_irqrestore(&pci_config_lock, flags);
+}
+
+uint8_t pci_conf_read8(
+    unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg)
+{
+    BUG_ON((bus > 255) || (dev > 31) || (func > 7) || (reg > 255));
+    return pci_conf_read(PCI_CONF_ADDRESS(bus, dev, func, reg), reg & 3, 1);
+}
+
+uint16_t pci_conf_read16(
+    unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg)
+{
+    BUG_ON((bus > 255) || (dev > 31) || (func > 7) || (reg > 255));
+    return pci_conf_read(PCI_CONF_ADDRESS(bus, dev, func, reg), reg & 2, 2);
+}
+
+uint32_t pci_conf_read32(
+    unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg)
+{
+    BUG_ON((bus > 255) || (dev > 31) || (func > 7) || (reg > 255));
+    return pci_conf_read(PCI_CONF_ADDRESS(bus, dev, func, reg), 0, 4);
+}
+
+void pci_conf_write8(
+    unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg,
+    uint8_t data)
+{
+    BUG_ON((bus > 255) || (dev > 31) || (func > 7) || (reg > 255));
+    pci_conf_write(PCI_CONF_ADDRESS(bus, dev, func, reg), reg & 3, 1, data);
+}
+
+void pci_conf_write16(
+    unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg,
+    uint16_t data)
+{
+    BUG_ON((bus > 255) || (dev > 31) || (func > 7) || (reg > 255));
+    pci_conf_write(PCI_CONF_ADDRESS(bus, dev, func, reg), reg & 2, 2, data);
+}
+
+void pci_conf_write32(
+    unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg,
+    uint32_t data)
+{
+    BUG_ON((bus > 255) || (dev > 31) || (func > 7) || (reg > 255));
+    pci_conf_write(PCI_CONF_ADDRESS(bus, dev, func, reg), 0, 4, data);
+}
index 6cc373b5b5b6ba2c64beaf45c7806a76c2010593..d9e1b57b22303aa813164835492610997dfa8335 100644 (file)
@@ -1353,7 +1353,7 @@ static int read_gate_descriptor(unsigned int gate_sel,
 #endif
 
 /* Has the guest requested sufficient permission for this I/O access? */
-static inline int guest_io_okay(
+static int guest_io_okay(
     unsigned int port, unsigned int bytes,
     struct vcpu *v, struct cpu_user_regs *regs)
 {
@@ -1395,19 +1395,130 @@ static inline int guest_io_okay(
 }
 
 /* Has the administrator granted sufficient permission for this I/O access? */
-static inline int admin_io_okay(
+static int admin_io_okay(
     unsigned int port, unsigned int bytes,
     struct vcpu *v, struct cpu_user_regs *regs)
 {
     return ioports_access_permitted(v->domain, port, port + bytes - 1);
 }
 
-#define guest_inb_okay(_p, _d, _r) admin_io_okay(_p, 1, _d, _r)
-#define guest_inw_okay(_p, _d, _r) admin_io_okay(_p, 2, _d, _r)
-#define guest_inl_okay(_p, _d, _r) admin_io_okay(_p, 4, _d, _r)
-#define guest_outb_okay(_p, _d, _r) admin_io_okay(_p, 1, _d, _r)
-#define guest_outw_okay(_p, _d, _r) admin_io_okay(_p, 2, _d, _r)
-#define guest_outl_okay(_p, _d, _r) admin_io_okay(_p, 4, _d, _r)
+static uint32_t guest_io_read(
+    unsigned int port, unsigned int bytes,
+    struct vcpu *v, struct cpu_user_regs *regs)
+{
+    extern uint32_t pci_conf_read(
+        uint32_t cf8, uint8_t offset, uint8_t bytes);
+
+    uint32_t data = 0;
+    unsigned int shift = 0;
+
+    if ( admin_io_okay(port, bytes, v, regs) )
+    {
+        switch ( bytes )
+        {
+        case 1: return inb(port);
+        case 2: return inw(port);
+        case 4: return inl(port);
+        }
+    }
+
+    while ( bytes != 0 )
+    {
+        unsigned int size = 1;
+        uint32_t sub_data = 0xff;
+
+        if ( (port == 0x42) || (port == 0x43) || (port == 0x61) )
+        {
+            sub_data = pv_pit_handler(port, 0, 0);
+        }
+        else if ( (port & 0xfffc) == 0xcf8 )
+        {
+            size = min(bytes, 4 - (port & 3));
+            sub_data = v->domain->arch.pci_cf8 >> ((port & 3) * 8);
+        }
+        else if ( ((port & 0xfffc) == 0xcfc) && IS_PRIV(v->domain) )
+        {
+            size = min(bytes, 4 - (port & 3));
+            if ( size == 3 )
+                size = 2;
+            sub_data = pci_conf_read(v->domain->arch.pci_cf8, port & 3, size);
+        }
+
+        if ( size == 4 )
+            return sub_data;
+
+        data |= (sub_data & ((1u << (size * 8)) - 1)) << shift;
+        shift += size * 8;
+        port += size;
+        bytes -= size;
+    }
+
+    return data;
+}
+
+static void guest_io_write(
+    unsigned int port, unsigned int bytes, uint32_t data,
+    struct vcpu *v, struct cpu_user_regs *regs)
+{
+    extern void pci_conf_write(
+        uint32_t cf8, uint8_t offset, uint8_t bytes, uint32_t data);
+
+    if ( admin_io_okay(port, bytes, v, regs) )
+    {
+        switch ( bytes ) {
+        case 1:
+            outb((uint8_t)data, port);
+            if ( pv_post_outb_hook )
+                pv_post_outb_hook(port, (uint8_t)data);
+            break;
+        case 2:
+            outw((uint16_t)data, port);
+            break;
+        case 4:
+            outl(data, port);
+            break;
+        }
+        return;
+    }
+
+    while ( bytes != 0 )
+    {
+        unsigned int size = 1;
+
+        if ( (port == 0x42) || (port == 0x43) || (port == 0x61) )
+        {
+            pv_pit_handler(port, (uint8_t)data, 1);
+        }
+        else if ( (port & 0xfffc) == 0xcf8 )
+        {
+            size = min(bytes, 4 - (port & 3));
+            if ( size == 4 )
+            {
+                v->domain->arch.pci_cf8 = data;
+            }
+            else
+            {
+                uint32_t mask = ((1u << (size * 8)) - 1) << ((port & 3) * 8);
+                v->domain->arch.pci_cf8 &= ~mask;
+                v->domain->arch.pci_cf8 |= (data << ((port & 3) * 8)) & mask;
+            }
+        }
+        else if ( ((port & 0xfffc) == 0xcfc) && IS_PRIV(v->domain) )
+        {
+            size = min(bytes, 4 - (port & 3));
+            if ( size == 3 )
+                size = 2;
+            pci_conf_write(v->domain->arch.pci_cf8, port & 3, size, data);
+        }
+
+        if ( size == 4 )
+            return;
+
+        port += size;
+        bytes -= size;
+        data >>= size * 8;
+    }
+}
 
 /* I/O emulation support. Helper routines for, and type of, the stack stub.*/
 void host_to_guest_gpr_switch(struct cpu_user_regs *)
@@ -1526,7 +1637,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
 
     /* REX prefix. */
     if ( rex & 8 ) /* REX.W */
-        op_bytes = 4; /* emulating only opcodes not supporting 64-bit operands */
+        op_bytes = 4; /* emulate only opcodes not supporting 64-bit operands */
     modrm_reg = (rex & 4) << 1;  /* REX.R */
     /* REX.X does not need to be decoded. */
     modrm_rm  = (rex & 1) << 3;  /* REX.B */
@@ -1555,7 +1666,8 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
         {
             if ( !read_descriptor(data_sel, v, regs,
                                   &data_base, &data_limit, &ar,
-                                  _SEGMENT_WR|_SEGMENT_S|_SEGMENT_DPL|_SEGMENT_P) )
+                                  _SEGMENT_WR|_SEGMENT_S|_SEGMENT_DPL|
+                                  _SEGMENT_P) )
                 goto fail;
             if ( !(ar & _SEGMENT_S) ||
                  !(ar & _SEGMENT_P) ||
@@ -1602,69 +1714,39 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
         case 0x6c: /* INSB */
             op_bytes = 1;
         case 0x6d: /* INSW/INSL */
-            if ( data_limit < op_bytes - 1 ||
-                 rd_ad(edi) > data_limit - (op_bytes - 1) ||
+            if ( (data_limit < (op_bytes - 1)) ||
+                 (rd_ad(edi) > (data_limit - (op_bytes - 1))) ||
                  !guest_io_okay(port, op_bytes, v, regs) )
                 goto fail;
-            switch ( op_bytes )
-            {
-            case 1:
-                /* emulate PIT counter 2 */
-                data = (u8)(guest_inb_okay(port, v, regs) ? inb(port) : 
-                       ((port == 0x42 || port == 0x43 || port == 0x61) ?
-                       pv_pit_handler(port, 0, 0) : ~0)); 
-                break;
-            case 2:
-                data = (u16)(guest_inw_okay(port, v, regs) ? inw(port) : ~0);
-                break;
-            case 4:
-                data = (u32)(guest_inl_okay(port, v, regs) ? inl(port) : ~0);
-                break;
-            }
-            if ( (rc = copy_to_user((void *)data_base + rd_ad(edi), &data, op_bytes)) != 0 )
+            data = guest_io_read(port, op_bytes, v, regs);
+            if ( (rc = copy_to_user((void *)data_base + rd_ad(edi),
+                                    &data, op_bytes)) != 0 )
             {
                 propagate_page_fault(data_base + rd_ad(edi) + op_bytes - rc,
                                      PFEC_write_access);
                 return EXCRET_fault_fixed;
             }
-            wr_ad(edi, regs->edi + (int)((regs->eflags & EF_DF) ? -op_bytes : op_bytes));
+            wr_ad(edi, regs->edi + (int)((regs->eflags & EF_DF)
+                                         ? -op_bytes : op_bytes));
             break;
 
         case 0x6e: /* OUTSB */
             op_bytes = 1;
         case 0x6f: /* OUTSW/OUTSL */
-            if ( data_limit < op_bytes - 1 ||
-                 rd_ad(esi) > data_limit - (op_bytes - 1) ||
-                 !guest_io_okay(port, op_bytes, v, regs) )
+            if ( (data_limit < (op_bytes - 1)) ||
+                 (rd_ad(esi) > (data_limit - (op_bytes - 1))) ||
+                  !guest_io_okay(port, op_bytes, v, regs) )
                 goto fail;
-            rc = copy_from_user(&data, (void *)data_base + rd_ad(esi), op_bytes);
-            if ( rc != 0 )
+            if ( (rc = copy_from_user(&data, (void *)data_base + rd_ad(esi),
+                                      op_bytes)) != 0 )
             {
-                propagate_page_fault(data_base + rd_ad(esi) + op_bytes - rc, 0);
+                propagate_page_fault(data_base + rd_ad(esi)
+                                     + op_bytes - rc, 0);
                 return EXCRET_fault_fixed;
             }
-            switch ( op_bytes )
-            {
-            case 1:
-                if ( guest_outb_okay(port, v, regs) )
-                {
-                    outb((u8)data, port);
-                    if ( pv_post_outb_hook )
-                        pv_post_outb_hook(port, data);
-                }
-                else if ( port == 0x42 || port == 0x43 || port == 0x61 )
-                    pv_pit_handler(port, data, 1);
-                break;
-            case 2:
-                if ( guest_outw_okay(port, v, regs) )
-                    outw((u16)data, port);
-                break;
-            case 4:
-                if ( guest_outl_okay(port, v, regs) )
-                    outl((u32)data, port);
-                break;
-            }
-            wr_ad(esi, regs->esi + (int)((regs->eflags & EF_DF) ? -op_bytes : op_bytes));
+            guest_io_write(port, op_bytes, data, v, regs);
+            wr_ad(esi, regs->esi + (int)((regs->eflags & EF_DF)
+                                         ? -op_bytes : op_bytes));
             break;
         }
 
@@ -1728,31 +1810,17 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
     exec_in:
         if ( !guest_io_okay(port, op_bytes, v, regs) )
             goto fail;
-        switch ( op_bytes )
+        if ( admin_io_okay(port, op_bytes, v, regs) )
         {
-        case 1:
-            if ( guest_inb_okay(port, v, regs) )
-                io_emul(regs);
-            else if ( port == 0x42 || port == 0x43 || port == 0x61 )
-            {
-                regs->eax &= ~0xffUL;
-                regs->eax |= pv_pit_handler(port, 0, 0);
-            } 
-            else
-                regs->eax |= (u8)~0;
-            break;
-        case 2:
-            if ( guest_inw_okay(port, v, regs) )
-                io_emul(regs);
-            else
-                regs->eax |= (u16)~0;
-            break;
-        case 4:
-            if ( guest_inl_okay(port, v, regs) )
-                io_emul(regs);
+            io_emul(regs);            
+        }
+        else
+        {
+            if ( op_bytes == 4 )
+                regs->eax = 0;
             else
-                regs->eax = (u32)~0;
-            break;
+                regs->eax &= ~((1u << (op_bytes * 8)) - 1);
+            regs->eax |= guest_io_read(port, op_bytes, v, regs);
         }
         bpmatch = check_guest_io_breakpoint(v, port, op_bytes);
         goto done;
@@ -1771,26 +1839,15 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
     exec_out:
         if ( !guest_io_okay(port, op_bytes, v, regs) )
             goto fail;
-        switch ( op_bytes )
+        if ( admin_io_okay(port, op_bytes, v, regs) )
         {
-        case 1:
-            if ( guest_outb_okay(port, v, regs) )
-            {
-                io_emul(regs);
-                if ( pv_post_outb_hook )
-                    pv_post_outb_hook(port, regs->eax);
-            }
-            else if ( port == 0x42 || port == 0x43 || port == 0x61 )
-                pv_pit_handler(port, regs->eax, 1);
-            break;
-        case 2:
-            if ( guest_outw_okay(port, v, regs) )
-                io_emul(regs);
-            break;
-        case 4:
-            if ( guest_outl_okay(port, v, regs) )
-                io_emul(regs);
-            break;
+            io_emul(regs);            
+            if ( (op_bytes == 1) && pv_post_outb_hook )
+                pv_post_outb_hook(port, regs->eax);
+        }
+        else
+        {
+            guest_io_write(port, op_bytes, regs->eax, v, regs);
         }
         bpmatch = check_guest_io_breakpoint(v, port, op_bytes);
         goto done;
index 96ad02bbf72966fa82380862af203ec4b567a3cc..d7ffa4e2160392c923cf6a5168fcbf4668b2a962 100644 (file)
@@ -21,9 +21,9 @@
 #include <xen/config.h>
 #include <xen/errno.h>
 #include <xen/iommu.h>
+#include <xen/pci.h>
 #include <asm/amd-iommu.h>
 #include <asm/hvm/svm/amd-iommu-proto.h>
-#include "../pci-direct.h"
 #include "../pci_regs.h"
 
 static int __init valid_bridge_bus_config(
@@ -31,9 +31,9 @@ static int __init valid_bridge_bus_config(
 {
     int pri_bus;
 
-    pri_bus = read_pci_config_byte(bus, dev, func, PCI_PRIMARY_BUS);
-    *sec_bus = read_pci_config_byte(bus, dev, func, PCI_SECONDARY_BUS);
-    *sub_bus = read_pci_config_byte(bus, dev, func, PCI_SUBORDINATE_BUS);
+    pri_bus = pci_conf_read8(bus, dev, func, PCI_PRIMARY_BUS);
+    *sec_bus = pci_conf_read8(bus, dev, func, PCI_SECONDARY_BUS);
+    *sub_bus = pci_conf_read8(bus, dev, func, PCI_SUBORDINATE_BUS);
 
     return ((pri_bus == bus) && (*sec_bus > bus) && (*sub_bus >= *sec_bus));
 }
@@ -59,12 +59,11 @@ int __init get_iommu_last_downstream_bus(struct amd_iommu *iommu)
         }
         func = PCI_FUNC(devfn);
  
-        if ( !VALID_PCI_VENDOR_ID(
-            read_pci_config_16(bus, dev, func, PCI_VENDOR_ID)) )
+        if ( !VALID_PCI_VENDOR_ID(pci_conf_read16(bus, dev, func,
+                                                  PCI_VENDOR_ID)) )
             continue;
 
-        hdr_type = read_pci_config_byte(bus, dev, func,
-                                        PCI_HEADER_TYPE);
+        hdr_type = pci_conf_read8(bus, dev, func, PCI_HEADER_TYPE);
         if ( func == 0 )
             multi_func = IS_PCI_MULTI_FUNCTION(hdr_type);
 
@@ -92,9 +91,9 @@ int __init get_iommu_capabilities(u8 bus, u8 dev, u8 func, u8 cap_ptr,
     u32 cap_header, cap_range, misc_info;
     u64 mmio_bar;
 
-    mmio_bar = (u64)read_pci_config(
+    mmio_bar = (u64)pci_conf_read32(
         bus, dev, func, cap_ptr + PCI_CAP_MMIO_BAR_HIGH_OFFSET) << 32;
-    mmio_bar |= read_pci_config(bus, dev, func,
+    mmio_bar |= pci_conf_read32(bus, dev, func,
                                 cap_ptr + PCI_CAP_MMIO_BAR_LOW_OFFSET);
     iommu->mmio_base_phys = mmio_bar & (u64)~0x3FFF;
 
@@ -108,7 +107,7 @@ int __init get_iommu_capabilities(u8 bus, u8 dev, u8 func, u8 cap_ptr,
     iommu->bdf = (bus << 8) | PCI_DEVFN(dev, func);
     iommu->cap_offset = cap_ptr;
 
-    cap_header = read_pci_config(bus, dev, func, cap_ptr);
+    cap_header = pci_conf_read32(bus, dev, func, cap_ptr);
     iommu->revision = get_field_from_reg_u32(
         cap_header, PCI_CAP_REV_MASK, PCI_CAP_REV_SHIFT);
     iommu->iotlb_support = get_field_from_reg_u32(
@@ -118,7 +117,7 @@ int __init get_iommu_capabilities(u8 bus, u8 dev, u8 func, u8 cap_ptr,
     iommu->pte_not_present_cached = get_field_from_reg_u32(
         cap_header, PCI_CAP_NP_CACHE_MASK, PCI_CAP_NP_CACHE_SHIFT);
 
-    cap_range = read_pci_config(bus, dev, func,
+    cap_range = pci_conf_read32(bus, dev, func,
                                 cap_ptr + PCI_CAP_RANGE_OFFSET);
     iommu->unit_id = get_field_from_reg_u32(
         cap_range, PCI_CAP_UNIT_ID_MASK, PCI_CAP_UNIT_ID_SHIFT);
@@ -129,7 +128,7 @@ int __init get_iommu_capabilities(u8 bus, u8 dev, u8 func, u8 cap_ptr,
     iommu->last_devfn = get_field_from_reg_u32(
         cap_range, PCI_CAP_LAST_DEVICE_MASK, PCI_CAP_LAST_DEVICE_SHIFT);
 
-    misc_info = read_pci_config(bus, dev, func,
+    misc_info = pci_conf_read32(bus, dev, func,
                                 cap_ptr + PCI_MISC_INFO_OFFSET);
     iommu->msi_number = get_field_from_reg_u32(
         misc_info, PCI_CAP_MSI_NUMBER_MASK, PCI_CAP_MSI_NUMBER_SHIFT);
@@ -146,14 +145,13 @@ static int __init scan_caps_for_iommu(
     int count, error = 0;
 
     count = 0;
-    cap_ptr = read_pci_config_byte(bus, dev, func,
-                                   PCI_CAPABILITY_LIST);
+    cap_ptr = pci_conf_read8(bus, dev, func, PCI_CAPABILITY_LIST);
     while ( (cap_ptr >= PCI_MIN_CAP_OFFSET) &&
             (count < PCI_MAX_CAP_BLOCKS) &&
             !error )
     {
         cap_ptr &= PCI_CAP_PTR_MASK;
-        cap_header = read_pci_config(bus, dev, func, cap_ptr);
+        cap_header = pci_conf_read32(bus, dev, func, cap_ptr);
         cap_id = get_field_from_reg_u32(
             cap_header, PCI_CAP_ID_MASK, PCI_CAP_ID_SHIFT);
 
@@ -182,12 +180,11 @@ static int __init scan_functions_for_iommu(
 
     func = 0;
     count = 1;
-    while ( VALID_PCI_VENDOR_ID(read_pci_config_16(bus, dev, func,
-                                                   PCI_VENDOR_ID)) &&
+    while ( VALID_PCI_VENDOR_ID(pci_conf_read16(bus, dev, func,
+                                                PCI_VENDOR_ID)) &&
             !error && (func < count) )
     {
-        hdr_type = read_pci_config_byte(bus, dev, func,
-                                        PCI_HEADER_TYPE);
+        hdr_type = pci_conf_read8(bus, dev, func, PCI_HEADER_TYPE);
 
         if ( func == 0 && IS_PCI_MULTI_FUNCTION(hdr_type) )
             count = PCI_MAX_FUNC_COUNT;
index bb01d7915a8cff4764d58ccddf2673c7a278a179..f36c0e86c425b45d6b61b14eb4da96c9af1485c4 100644 (file)
 
 #include <xen/config.h>
 #include <xen/errno.h>
+#include <xen/pci.h>
 #include <asm/amd-iommu.h>
 #include <asm/hvm/svm/amd-iommu-proto.h>
 #include <asm-x86/fixmap.h>
-#include "../pci-direct.h"
 #include "../pci_regs.h"
 
 extern int nr_amd_iommus;
index 4f562757f790002ff1e6db4df0eb07c3d90944d2..6a6b5484b336b1fa3279dac7a1137ce3126ed752 100644 (file)
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
+#include <xen/sched.h>
+#include <xen/pci.h>
 #include <asm/amd-iommu.h>
 #include <asm/hvm/svm/amd-iommu-proto.h>
 #include <asm/hvm/svm/amd-iommu-acpi.h>
-#include <xen/sched.h>
 #include <asm/mm.h>
-#include "../pci-direct.h"
 #include "../pci_regs.h"
 
 struct list_head amd_iommu_head;
@@ -316,7 +316,7 @@ void __init amd_iommu_setup_dom0_devices(void)
         {
             for ( func = 0; func < 8; func++ )
             {
-                l = read_pci_config(bus, dev, func, PCI_VENDOR_ID);
+                l = pci_conf_read32(bus, dev, func, PCI_VENDOR_ID);
                 /* some broken boards return 0 or ~0 if a slot is empty: */
                 if ( (l == 0xffffffff) || (l == 0x00000000) ||
                      (l == 0x0000ffff) || (l == 0xffff0000) )
diff --git a/xen/drivers/passthrough/pci-direct.h b/xen/drivers/passthrough/pci-direct.h
deleted file mode 100644 (file)
index 9203438..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef ASM_PCI_DIRECT_H
-#define ASM_PCI_DIRECT_H 1
-
-#include <xen/types.h>
-#include <asm/io.h>
-
-/* Direct PCI access. This is used for PCI accesses in early boot before
-   the PCI subsystem works. */
-
-#define PDprintk(x...)
-
-static inline u32 read_pci_config(u8 bus, u8 slot, u8 func, u8 offset)
-{
-    u32 v;
-    outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
-    v = inl(0xcfc);
-    if (v != 0xffffffff)
-        PDprintk("%x reading 4 from %x: %x\n", slot, offset, v);
-    return v;
-}
-
-static inline u8 read_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset)
-{
-    u8 v;
-    outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
-    v = inb(0xcfc + (offset&3));
-    PDprintk("%x reading 1 from %x: %x\n", slot, offset, v);
-    return v;
-}
-
-static inline u16 read_pci_config_16(u8 bus, u8 slot, u8 func, u8 offset)
-{
-    u16 v;
-    outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
-    v = inw(0xcfc + (offset&2));
-    PDprintk("%x reading 2 from %x: %x\n", slot, offset, v);
-    return v;
-}
-
-static inline void write_pci_config(
-    u8 bus, u8 slot, u8 func, u8 offset, u32 val)
-{
-    PDprintk("%x writing to %x: %x\n", slot, offset, val);
-    outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
-    outl(val, 0xcfc);
-}
-
-#endif
index 0685d84010cb546774d11d3aab7520881e2bc69a..9498914044ec7d4c6b90820fa94d630ea4316056 100644 (file)
@@ -25,9 +25,9 @@
 #include <xen/acpi.h>
 #include <xen/mm.h>
 #include <xen/xmalloc.h>
+#include <xen/pci.h>
 #include <asm/string.h>
 #include "dmar.h"
-#include "../pci-direct.h"
 #include "../pci_regs.h"
 
 int vtd_enabled;
@@ -233,7 +233,7 @@ static int scope_device_count(void *start, void *end)
                    / sizeof(struct acpi_pci_path);
         while ( --depth > 0 )
         {
-            bus = read_pci_config_byte(
+            bus = pci_conf_read8(
                 bus, path->dev, path->fn, PCI_SECONDARY_BUS);
             path++;
         }
@@ -250,9 +250,9 @@ static int scope_device_count(void *start, void *end)
             dprintk(XENLOG_INFO VTDPREFIX,
                     "found bridge: bdf = %x:%x:%x\n",
                     bus, path->dev, path->fn);
-            sec_bus = read_pci_config_byte(
+            sec_bus = pci_conf_read8(
                 bus, path->dev, path->fn, PCI_SECONDARY_BUS);
-            sub_bus = read_pci_config_byte(
+            sub_bus = pci_conf_read8(
                 bus, path->dev, path->fn, PCI_SUBORDINATE_BUS);
 
             while ( sec_bus <= sub_bus )
@@ -261,7 +261,7 @@ static int scope_device_count(void *start, void *end)
                 {
                     for ( func = 0; func < 8; func++ )
                     {
-                        l = read_pci_config(
+                        l = pci_conf_read32(
                             sec_bus, dev, func, PCI_VENDOR_ID);
 
                         /* some broken boards return 0 or
@@ -355,7 +355,7 @@ static int __init acpi_parse_dev_scope(
 
         while ( --depth > 0 )
         {
-            bus = read_pci_config_byte(
+            bus = pci_conf_read8(
                 bus, path->dev, path->fn, PCI_SECONDARY_BUS);
             path++;
         }
@@ -374,9 +374,9 @@ static int __init acpi_parse_dev_scope(
             dprintk(XENLOG_INFO VTDPREFIX,
                     "found bridge: bus = %x dev = %x func = %x\n",
                     bus, path->dev, path->fn);
-            sec_bus = read_pci_config_byte(
+            sec_bus = pci_conf_read8(
                 bus, path->dev, path->fn, PCI_SECONDARY_BUS);
-            sub_bus = read_pci_config_byte(
+            sub_bus = pci_conf_read8(
                 bus, path->dev, path->fn, PCI_SUBORDINATE_BUS);
 
             while ( sec_bus <= sub_bus )
@@ -385,7 +385,7 @@ static int __init acpi_parse_dev_scope(
                 {
                     for ( func = 0; func < 8; func++ )
                     {
-                        l = read_pci_config(
+                        l = pci_conf_read32(
                             sec_bus, dev, func, PCI_VENDOR_ID);
 
                         /* some broken boards return 0 or
index 288deb47fb363849e67edafe2b865bb514384ef5..040d7ea5d455d760f7dec6860dd095e8c744f1da 100644 (file)
 #include <xen/sched.h>
 #include <xen/iommu.h>
 #include <xen/time.h>
+#include <xen/pci.h>
 #include "iommu.h"
 #include "dmar.h"
 #include "vtd.h"
-#include "../pci-direct.h"
 #include "../pci_regs.h"
 #include "msi.h"
 #include "extern.h"
index d6078a82197a1209208fbd8b43ff58d944407cf6..59babdfd66ca7712ffd915cbf61ba7d127b75e98 100644 (file)
 #include <xen/sched.h>
 #include <xen/xmalloc.h>
 #include <xen/domain_page.h>
-#include <asm/paging.h>
 #include <xen/iommu.h>
 #include <xen/numa.h>
 #include <xen/time.h>
+#include <xen/pci.h>
+#include <asm/paging.h>
 #include "iommu.h"
 #include "dmar.h"
-#include "../pci-direct.h"
 #include "../pci_regs.h"
 #include "msi.h"
 #include "extern.h"
@@ -1228,13 +1228,13 @@ static int __pci_find_next_cap(u8 bus, unsigned int devfn, u8 pos, int cap)
 
     while ( ttl-- )
     {
-        pos = read_pci_config_byte(bus, PCI_SLOT(devfn), PCI_FUNC(devfn), pos);
+        pos = pci_conf_read8(bus, PCI_SLOT(devfn), PCI_FUNC(devfn), pos);
         if ( pos < 0x40 )
             break;
 
         pos &= ~3;
-        id = read_pci_config_byte(bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
-                                  pos + PCI_CAP_LIST_ID);
+        id = pci_conf_read8(bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
+                            pos + PCI_CAP_LIST_ID);
 
         if ( id == 0xff )
             break;
@@ -1258,13 +1258,13 @@ int pdev_type(struct pci_dev *dev)
     u16 class_device;
     u16 status;
 
-    class_device = read_pci_config_16(dev->bus, PCI_SLOT(dev->devfn),
-                                      PCI_FUNC(dev->devfn), PCI_CLASS_DEVICE);
+    class_device = pci_conf_read16(dev->bus, PCI_SLOT(dev->devfn),
+                                   PCI_FUNC(dev->devfn), PCI_CLASS_DEVICE);
     if ( class_device == PCI_CLASS_BRIDGE_PCI )
         return DEV_TYPE_PCI_BRIDGE;
 
-    status = read_pci_config_16(dev->bus, PCI_SLOT(dev->devfn),
-                                PCI_FUNC(dev->devfn), PCI_STATUS);
+    status = pci_conf_read16(dev->bus, PCI_SLOT(dev->devfn),
+                             PCI_FUNC(dev->devfn), PCI_STATUS);
 
     if ( !(status & PCI_STATUS_CAP_LIST) )
         return DEV_TYPE_PCI;
@@ -1292,7 +1292,7 @@ static int domain_context_mapping(
     switch ( type )
     {
     case DEV_TYPE_PCI_BRIDGE:
-        sec_bus = read_pci_config_byte(
+        sec_bus = pci_conf_read8(
             pdev->bus, PCI_SLOT(pdev->devfn),
             PCI_FUNC(pdev->devfn), PCI_SECONDARY_BUS);
 
@@ -1302,7 +1302,7 @@ static int domain_context_mapping(
             bus2bridge[sec_bus].devfn =  pdev->devfn;
         }
 
-        sub_bus = read_pci_config_byte(
+        sub_bus = pci_conf_read8(
             pdev->bus, PCI_SLOT(pdev->devfn),
             PCI_FUNC(pdev->devfn), PCI_SUBORDINATE_BUS);
 
@@ -1425,10 +1425,10 @@ static int domain_context_unmap(
     switch ( type )
     {
     case DEV_TYPE_PCI_BRIDGE:
-        sec_bus = read_pci_config_byte(
+        sec_bus = pci_conf_read8(
             pdev->bus, PCI_SLOT(pdev->devfn),
             PCI_FUNC(pdev->devfn), PCI_SECONDARY_BUS);
-        sub_bus = read_pci_config_byte(
+        sub_bus = pci_conf_read8(
             pdev->bus, PCI_SLOT(pdev->devfn),
             PCI_FUNC(pdev->devfn), PCI_SUBORDINATE_BUS);
 
@@ -1781,7 +1781,7 @@ void __init setup_dom0_devices(void)
         {
             for ( func = 0; func < 8; func++ )
             {
-                l = read_pci_config(bus, dev, func, PCI_VENDOR_ID);
+                l = pci_conf_read32(bus, dev, func, PCI_VENDOR_ID);
                 /* some broken boards return 0 or ~0 if a slot is empty: */
                 if ( (l == 0xffffffff) || (l == 0x00000000) ||
                      (l == 0x0000ffff) || (l == 0xffff0000) )
index 57a13fbcd77a414cc92a2ccd8b762d811439a287..21025986ff750ab78ab991f138fb5065fe284844 100644 (file)
 #include <xen/sched.h>
 #include <xen/iommu.h>
 #include <xen/time.h>
+#include <xen/pci.h>
 #include "iommu.h"
 #include "dmar.h"
 #include "vtd.h"
-#include "../pci-direct.h"
 #include "../pci_regs.h"
 #include "msi.h"
 #include "extern.h"
index 9267e30df00dadc0ace857a86fb6b017c2c2f70b..3c33a2c300f78bd822bb5e6291d4d89fa40d6c64 100644 (file)
@@ -21,9 +21,9 @@
 #include <xen/delay.h>
 #include <xen/iommu.h>
 #include <xen/time.h>
+#include <xen/pci.h>
 #include "iommu.h"
 #include "dmar.h"
-#include "../pci-direct.h"
 #include "../pci_regs.h"
 #include "msi.h"
 #include "vtd.h"
@@ -37,7 +37,7 @@ int is_usb_device(struct pci_dev *pdev)
     u8 bus = pdev->bus;
     u8 dev = PCI_SLOT(pdev->devfn);
     u8 func = PCI_FUNC(pdev->devfn);
-    u16 class = read_pci_config_16(bus, dev, func, PCI_CLASS_DEVICE);
+    u16 class = pci_conf_read16(bus, dev, func, PCI_CLASS_DEVICE);
     return (class == 0xc03);
 }
 
@@ -46,9 +46,9 @@ int vtd_hw_check(void)
     u16 vendor, device;
     u8 revision, stepping;
 
-    vendor   = read_pci_config_16(0, 0, 0, PCI_VENDOR_ID);
-    device   = read_pci_config_16(0, 0, 0, PCI_DEVICE_ID);
-    revision = read_pci_config_byte(0, 0, 0, PCI_REVISION_ID);
+    vendor   = pci_conf_read16(0, 0, 0, PCI_VENDOR_ID);
+    device   = pci_conf_read16(0, 0, 0, PCI_DEVICE_ID);
+    revision = pci_conf_read8(0, 0, 0, PCI_REVISION_ID);
     stepping = revision & 0xf;
 
     if ( (vendor == INTEL) && (device == SEABURG) )
@@ -103,18 +103,18 @@ static u8 find_cap_offset(u8 bus, u8 dev, u8 func, u8 cap)
     u8 pos = PCI_CAPABILITY_LIST;
     u16 status;
 
-    status = read_pci_config_16(bus, dev, func, PCI_STATUS);
+    status = pci_conf_read16(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);
+        pos = pci_conf_read8(bus, dev, func, pos);
         if ( pos < 0x40 )
             break;
 
         pos &= ~3;
-        id = read_pci_config_byte(bus, dev, func, pos + PCI_CAP_LIST_ID);
+        id = pci_conf_read8(bus, dev, func, pos + PCI_CAP_LIST_ID);
 
         if ( id == 0xff )
             break;
@@ -143,13 +143,13 @@ void pdev_flr(u8 bus, u8 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);
+        dev_cap = pci_conf_read32(bus, dev, func, pos + PCI_EXP_DEVCAP);
         if ( dev_cap & PCI_EXP_DEVCAP_FLR )
         {
-            write_pci_config(bus, dev, func,
+            pci_conf_write32(bus, dev, func,
                              pos + PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_FLR);
             do {
-                dev_status = read_pci_config(bus, dev, func,
+                dev_status = pci_conf_read32(bus, dev, func,
                                              pos + PCI_EXP_DEVSTA);
             } while ( dev_status & PCI_EXP_DEVSTA_TRPND );
 
@@ -169,23 +169,23 @@ void pdev_flr(u8 bus, u8 devfn)
             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);
+                config[i] = pci_conf_read32(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_conf_read32(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);
+            pci_conf_write32(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);
+            pci_conf_write32(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]);
+                pci_conf_write32(bus, dev, func, i*4, config[i]);
 
             flr = 1;
         }
index dad9f9723d013b3f725069dbbec9d55850b9d681..99281c68a3bb0e4dd55ca8c31f7fd1bcd0841c21 100644 (file)
@@ -209,6 +209,7 @@ struct arch_domain
 
     /* I/O-port admin-specified access capabilities. */
     struct rangeset *ioport_caps;
+    uint32_t pci_cf8;
 
     struct hvm_domain hvm_domain;
 
diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h
new file mode 100644 (file)
index 0000000..2e4d783
--- /dev/null
@@ -0,0 +1,29 @@
+/******************************************************************************
+ * pci.h
+ * 
+ * PCI access functions.
+ */
+
+#ifndef __XEN_PCI_H__
+#define __XEN_PCI_H__
+
+#include <xen/config.h>
+#include <xen/types.h>
+
+uint8_t pci_conf_read8(
+    unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg);
+uint16_t pci_conf_read16(
+    unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg);
+uint32_t pci_conf_read32(
+    unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg);
+void pci_conf_write8(
+    unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg,
+    uint8_t data);
+void pci_conf_write16(
+    unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg,
+    uint16_t data);
+void pci_conf_write32(
+    unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg,
+    uint32_t data);
+
+#endif /* __XEN_PCI_H__ */