Sophie

Sophie

distrib > CentOS > 5 > x86_64 > by-pkgid > ea32411352494358b8d75a78402a4713 > files > 4995

kernel-2.6.18-238.19.1.el5.centos.plus.src.rpm

From: Paolo Bonzini <pbonzini@redhat.com>
Date: Mon, 9 Aug 2010 19:23:51 -0400
Subject: [virt] xen: fix passthrough of SR-IOV VF
Message-id: <1281381831-15207-1-git-send-email-pbonzini@redhat.com>
Patchwork-id: 27480
O-Subject: [RHEL5.5 PATCH] xen: fix passthrough of SR-IOV VF
Bugzilla: 582886
RH-Acked-by: Andrew Jones <drjones@redhat.com>

Bugzilla: 582886

Upstream status: backport of changesets 103 + 998 + 999 + 1003

Brew build: https://brewweb.devel.redhat.com/taskinfo?taskID=2651766

This patch virtualizes vendor, device and BAR fields in the PCI config
space, because they're dummy for a VF's host-level PCI config space.
pciback can do so by always extracting the values installed in dom0
kernel's own PCI structures, rather than interrogating the underlying
PCI config space directly.

It's a backport of upstream changesets 103, 998, 999, and 1003.  It is
considerably easier to review all of them at the same time.

The patch has already been tested by QE.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

diff --git a/drivers/xen/pciback/conf_space_header.c b/drivers/xen/pciback/conf_space_header.c
index 61089c6..a417a19 100644
--- a/drivers/xen/pciback/conf_space_header.c
+++ b/drivers/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 (!dev->is_enabled)
+		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)
 {
 	if (!dev->is_enabled && is_enable_cmd(value)) {
@@ -65,8 +84,15 @@ static int rom_write(struct pci_dev *dev, int offset, u32 value, void *data)
 	 */
 	if (value == ~PCI_ROM_ADDRESS_ENABLE)
 		bar->which = 1;
-	else
+	else {
+		u32 tmpval;
+		pci_read_config_dword(dev, offset, &tmpval);
+		if (tmpval != bar->val && value == bar->val) {
+			/* Allow restoration of bar value. */
+			pci_write_config_dword(dev, offset, bar->val);
+		}
 		bar->which = 0;
+	}
 
 	/* Do we need to support enabling/disabling the rom address here? */
 
@@ -92,8 +118,15 @@ static int bar_write(struct pci_dev *dev, int offset, u32 value, void *data)
 	 */
 	if (value == ~0)
 		bar->which = 1;
-	else
+	else {
+		u32 tmpval;
+		pci_read_config_dword(dev, offset, &tmpval);
+		if (tmpval != bar->val && value == bar->val) {
+			/* Allow restoration of bar value. */
+			pci_write_config_dword(dev, offset, bar->val);
+		}
 		bar->which = 0;
+	}
 
 	return 0;
 }
@@ -117,10 +150,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)
@@ -161,6 +210,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)
 {
@@ -188,9 +253,19 @@ static int bist_write(struct pci_dev *dev, int offset, u8 value, void *data)
 
 static 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,
 	},
 	{