diff options
author | Keir Fraser <keir.fraser@citrix.com> | 2008-04-11 13:19:55 +0100 |
---|---|---|
committer | Keir Fraser <keir.fraser@citrix.com> | 2008-04-11 13:19:55 +0100 |
commit | 812471f0d1fb3b455297c3f8130e291eade85abf (patch) | |
tree | 5731cd269cd67913619bc741953b54429a461788 /xen/arch/x86/pci.c | |
parent | aa3ca83fdad5dca6e898a116cb9b585ed4dd4e09 (diff) | |
download | xen-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.c | 118 |
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); +} |