summaryrefslogtreecommitdiffstats
path: root/drivers/xen/xen-pciback
diff options
context:
space:
mode:
authorZhao, Yu <yu.zhao@intel.com>2010-03-03 13:27:55 -0500
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2011-07-19 20:58:30 -0400
commitfd5b221b348adf63d413de9adad030e4f13664b7 (patch)
treed641063dc2dc94cd6e04482049a23c8d87998d04 /drivers/xen/xen-pciback
parent6221a9b2a11acfb54e7b41da425e961b31e88553 (diff)
xen/pciback: guest SR-IOV support for PV guest
These changes are for PV guest to use Virtual Function. Because the VF's vendor, device registers in cfg space are 0xffff, which are invalid and ignored by PCI device scan. Values in 'struct pci_dev' are fixed up by SR-IOV code, and using these values will present correct VID and DID to PV guest kernel. And command registers in the cfg space are read only 0, which means we have to emulate MMIO enable bit (VF only uses MMIO resource) so PV kernel can work properly. Acked-by: Jan Beulich <jbeulich@novell.com> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Diffstat (limited to 'drivers/xen/xen-pciback')
-rw-r--r--drivers/xen/xen-pciback/conf_space_header.c71
1 files changed, 66 insertions, 5 deletions
diff --git a/drivers/xen/xen-pciback/conf_space_header.c b/drivers/xen/xen-pciback/conf_space_header.c
index 40166e04a2b..dcd6dd964e3 100644
--- a/drivers/xen/xen-pciback/conf_space_header.c
+++ b/drivers/xen/xen-pciback/conf_space_header.c
@@ -18,6 +18,25 @@ struct pci_bar_info {
#define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
#define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
+static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data)
+{
+ int i;
+ int ret;
+
+ ret = pciback_read_config_word(dev, offset, value, data);
+ if (!atomic_read(&dev->enable_cnt))
+ return ret;
+
+ for (i = 0; i < PCI_ROM_RESOURCE; i++) {
+ if (dev->resource[i].flags & IORESOURCE_IO)
+ *value |= PCI_COMMAND_IO;
+ if (dev->resource[i].flags & IORESOURCE_MEM)
+ *value |= PCI_COMMAND_MEMORY;
+ }
+
+ return ret;
+}
+
static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
{
int err;
@@ -142,10 +161,26 @@ static inline void read_dev_bar(struct pci_dev *dev,
struct pci_bar_info *bar_info, int offset,
u32 len_mask)
{
- pci_read_config_dword(dev, offset, &bar_info->val);
- pci_write_config_dword(dev, offset, len_mask);
- pci_read_config_dword(dev, offset, &bar_info->len_val);
- pci_write_config_dword(dev, offset, bar_info->val);
+ int pos;
+ struct resource *res = dev->resource;
+
+ if (offset == PCI_ROM_ADDRESS || offset == PCI_ROM_ADDRESS1)
+ pos = PCI_ROM_RESOURCE;
+ else {
+ pos = (offset - PCI_BASE_ADDRESS_0) / 4;
+ if (pos && ((res[pos - 1].flags & (PCI_BASE_ADDRESS_SPACE |
+ PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
+ (PCI_BASE_ADDRESS_SPACE_MEMORY |
+ PCI_BASE_ADDRESS_MEM_TYPE_64))) {
+ bar_info->val = res[pos - 1].start >> 32;
+ bar_info->len_val = res[pos - 1].end >> 32;
+ return;
+ }
+ }
+
+ bar_info->val = res[pos].start |
+ (res[pos].flags & PCI_REGION_FLAG_MASK);
+ bar_info->len_val = res[pos].end - res[pos].start + 1;
}
static void *bar_init(struct pci_dev *dev, int offset)
@@ -186,6 +221,22 @@ static void bar_release(struct pci_dev *dev, int offset, void *data)
kfree(data);
}
+static int pciback_read_vendor(struct pci_dev *dev, int offset,
+ u16 *value, void *data)
+{
+ *value = dev->vendor;
+
+ return 0;
+}
+
+static int pciback_read_device(struct pci_dev *dev, int offset,
+ u16 *value, void *data)
+{
+ *value = dev->device;
+
+ return 0;
+}
+
static int interrupt_read(struct pci_dev *dev, int offset, u8 * value,
void *data)
{
@@ -213,9 +264,19 @@ out:
static const struct config_field header_common[] = {
{
+ .offset = PCI_VENDOR_ID,
+ .size = 2,
+ .u.w.read = pciback_read_vendor,
+ },
+ {
+ .offset = PCI_DEVICE_ID,
+ .size = 2,
+ .u.w.read = pciback_read_device,
+ },
+ {
.offset = PCI_COMMAND,
.size = 2,
- .u.w.read = pciback_read_config_word,
+ .u.w.read = command_read,
.u.w.write = command_write,
},
{