All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sheng Yang <sheng@linux.intel.com>
To: Avi Kivity <avi@redhat.com>, Anthony Liguori <anthony@codemonkey.ws>
Cc: kvm@vger.kernel.org, Sheng Yang <sheng@linux.intel.com>
Subject: [PATCH 3/4] Support for device capability
Date: Fri, 21 Nov 2008 17:04:26 +0800	[thread overview]
Message-ID: <1227258267-22901-4-git-send-email-sheng@linux.intel.com> (raw)
In-Reply-To: <1227258267-22901-1-git-send-email-sheng@linux.intel.com>

This framework can be easily extended to support device capability, like
MSI/MSI-x.

Signed-off-by: Sheng Yang <sheng@linux.intel.com>
---
 qemu/hw/device-assignment.c |   96 ++++++++++++++++++++++++++++++++++++++++--
 qemu/hw/device-assignment.h |    3 +
 2 files changed, 94 insertions(+), 5 deletions(-)

diff --git a/qemu/hw/device-assignment.c b/qemu/hw/device-assignment.c
index c7e92a7..14b5911 100644
--- a/qemu/hw/device-assignment.c
+++ b/qemu/hw/device-assignment.c
@@ -245,11 +245,41 @@ uint8_t pci_find_cap_offset(struct pci_dev *pci_dev, uint8_t cap)
     return 0;
 }
 
+static int access_capability_config(AssignedDevice *pci_dev,
+				    uint32_t address, int len)
+{
+    if (address >= pci_dev->cap.start &&
+	    (address + len) < pci_dev->cap.start + pci_dev->cap.length)
+	return 1;
+    return 0;
+}
+
+static void check_cap_state(AssignedDevice *pci_dev,
+			    uint32_t address, uint32_t* val)
+{
+    return;
+}
+
+static void assigned_dev_pci_write_cap_config(AssignedDevice *pci_dev,
+				uint32_t address, uint32_t val, int len)
+{
+    if (access_capability_config(pci_dev, address, len)) {
+	int i;
+	for (i = 0; i < len; i++) {
+	    check_cap_state(pci_dev, address + i, &val);
+	    pci_dev->cap.config[address + i - pci_dev->cap.start] = val;
+	    val >>= 8;
+	}
+	return;
+    }
+}
+
 static void assigned_dev_pci_write_config(PCIDevice *d, uint32_t address,
                                           uint32_t val, int len)
 {
     int fd;
     ssize_t ret;
+    AssignedDevice *pci_dev = (AssignedDevice *)d;
 
     DEBUG("(%x.%x): address=%04x val=0x%08x len=%d\n",
           ((d->devfn >> 3) & 0x1F), (d->devfn & 0x7),
@@ -267,11 +297,16 @@ static void assigned_dev_pci_write_config(PCIDevice *d, uint32_t address,
         return;
     }
 
+    if (pci_dev->cap.available && access_capability_config(pci_dev, address, len)) {
+	assigned_dev_pci_write_cap_config(pci_dev, address, val, len);
+	return;
+    }
+
     DEBUG("NON BAR (%x.%x): address=%04x val=0x%08x len=%d\n",
           ((d->devfn >> 3) & 0x1F), (d->devfn & 0x7),
           (uint16_t) address, val, len);
 
-    fd = ((AssignedDevice *)d)->real_device.config_fd;
+    fd = pci_dev->real_device.config_fd;
 
 again:
     ret = pwrite(fd, &val, len, address);
@@ -286,14 +321,46 @@ again:
     }
 }
 
+static uint32_t assigned_dev_pci_read_cap_config(AssignedDevice *pci_dev,
+					uint32_t address, int len)
+{
+    uint32_t val = 0;
+
+    if (access_capability_config(pci_dev, address, len)) {
+	switch(len) {
+	default:
+	case 4:
+	    if (address < pci_dev->cap.start + pci_dev->cap.length - 4) {
+		val = le32_to_cpu(*(uint32_t *)(pci_dev->cap.config
+			    + address - pci_dev->cap.start));
+		break;
+	    }
+	    /* fall through */
+	case 2:
+	    if (address < pci_dev->cap.start + pci_dev->cap.length - 2) {
+		val = le16_to_cpu(*(uint16_t *)(pci_dev->cap.config
+			    + address - pci_dev->cap.start));
+		break;
+	    }
+	    /* fall through */
+	case 1:
+	    val = pci_dev->cap.config[address - pci_dev->cap.start];
+	    break;
+	}
+    }
+    return val;
+}
+
 static uint32_t assigned_dev_pci_read_config(PCIDevice *d, uint32_t address,
                                              int len)
 {
     uint32_t val = 0;
     int fd;
     ssize_t ret;
+    AssignedDevice *pci_dev = (AssignedDevice *)d;
 
-    if ((address >= 0x10 && address <= 0x24) || address == 0x34 ||
+    if ((address >= 0x10 && address <= 0x24) ||
+	(!pci_dev->cap.available && address == 0x34) ||
         address == 0x3c || address == 0x3d) {
         val = pci_default_read_config(d, address, len);
         DEBUG("(%x.%x): address=%04x val=0x%08x len=%d\n",
@@ -305,7 +372,18 @@ static uint32_t assigned_dev_pci_read_config(PCIDevice *d, uint32_t address,
     if (address == 0xFC)
         goto do_log;
 
-    fd = ((AssignedDevice *)d)->real_device.config_fd;
+    if (pci_dev->cap.available) {
+	if (address == 0x34) {
+	    val = pci_dev->cap.start;
+	    goto do_log;
+	}
+	if (access_capability_config(pci_dev, address, len)) {
+	    val = assigned_dev_pci_read_cap_config(pci_dev, address, len);
+	    goto do_log;
+	}
+    }
+
+    fd = pci_dev->real_device.config_fd;
 
 again:
     ret = pread(fd, &val, len, address);
@@ -325,9 +403,9 @@ do_log:
 
     /* kill the special capabilities */
     if (address == 4 && len == 4)
-        val &= ~0x100000;
+	val &= ~0x100000;
     else if (address == 6)
-        val &= ~0x10;
+	val &= ~0x10;
 
     return val;
 }
@@ -535,6 +613,12 @@ void assigned_dev_update_irq(PCIDevice *d)
     }
 }
 
+static void init_dev_cap_config(AssignedDevice *dev)
+{
+#define ASSIGNED_DEVICE_CAPABILITY_START_ADDR 0x40
+    dev->cap.start = ASSIGNED_DEVICE_CAPABILITY_START_ADDR;
+}
+
 struct PCIDevice *init_assigned_device(AssignedDevInfo *adev, PCIBus *bus)
 {
     int r;
@@ -576,6 +660,8 @@ struct PCIDevice *init_assigned_device(AssignedDevInfo *adev, PCIBus *bus)
     dev->h_busnr = adev->bus;
     dev->h_devfn = PCI_DEVFN(adev->dev, adev->func);
 
+    init_dev_cap_config(dev);
+
     memset(&assigned_dev_data, 0, sizeof(assigned_dev_data));
     assigned_dev_data.assigned_dev_id  =
 	calc_assigned_dev_id(dev->h_busnr, (uint32_t)dev->h_devfn);
diff --git a/qemu/hw/device-assignment.h b/qemu/hw/device-assignment.h
index d0667be..531a489 100644
--- a/qemu/hw/device-assignment.h
+++ b/qemu/hw/device-assignment.h
@@ -84,6 +84,9 @@ typedef struct {
     struct {
 #define ASSIGNED_DEVICE_CAP_MSI (1 << 0)
 	int available;
+#define ASSIGNED_DEVICE_CAPABILITY_LENGTH 0x60
+	uint8_t config[ASSIGNED_DEVICE_CAPABILITY_LENGTH];
+	unsigned int start, length;
     } cap;
 } AssignedDevice;
 
-- 
1.5.4.5


  parent reply	other threads:[~2008-11-21  9:08 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-11-21  9:04 [PATCH 0/4] Userspace for MSI support of KVM Sheng Yang
2008-11-21  9:04 ` [PATCH 1/4] Add dependence for libpci Sheng Yang
2008-11-21  9:04 ` [PATCH 2/4] Figure out device capability Sheng Yang
2008-11-21  9:04 ` Sheng Yang [this message]
2008-11-23 12:28   ` [PATCH 3/4] Support for " Avi Kivity
2008-11-24  7:24     ` Sheng Yang
2008-11-25 14:39       ` Avi Kivity
2008-11-21  9:04 ` [PATCH 4/4] Add MSI capability support Sheng Yang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1227258267-22901-4-git-send-email-sheng@linux.intel.com \
    --to=sheng@linux.intel.com \
    --cc=anthony@codemonkey.ws \
    --cc=avi@redhat.com \
    --cc=kvm@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.