aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/pci.c
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2008-04-11 13:19:55 +0100
committerKeir Fraser <keir.fraser@citrix.com>2008-04-11 13:19:55 +0100
commit812471f0d1fb3b455297c3f8130e291eade85abf (patch)
tree5731cd269cd67913619bc741953b54429a461788 /xen/arch/x86/pci.c
parentaa3ca83fdad5dca6e898a116cb9b585ed4dd4e09 (diff)
downloadxen-812471f0d1fb3b455297c3f8130e291eade85abf.tar.gz
xen-812471f0d1fb3b455297c3f8130e291eade85abf.tar.bz2
xen-812471f0d1fb3b455297c3f8130e291eade85abf.zip
x86: Emulate accesses to PCI window registers cf8/cfc to synchronise
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>
Diffstat (limited to 'xen/arch/x86/pci.c')
-rw-r--r--xen/arch/x86/pci.c118
1 files changed, 118 insertions, 0 deletions
diff --git a/xen/arch/x86/pci.c b/xen/arch/x86/pci.c
new file mode 100644
index 0000000000..341457b4bc
--- /dev/null
+++ b/xen/arch/x86/pci.c
@@ -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);
+}