From: "Michael S. Tsirkin" <mst@redhat.com>
To: Paul Brook <paul@codesourcery.com>, Avi Kivity <avi@redhat.com>,
qemu-devel@nongnu.org, Carsten Otte <cotte@de.ibm.com>,
kvm@vger.kernel.org, Rusty Russell <rusty@rustcorp.com.au>,
vi
Subject: [PATCHv4 03/13] qemu: add routines to manage PCI capabilities
Date: Wed, 10 Jun 2009 15:28:20 +0300 [thread overview]
Message-ID: <20090610122820.GD27174@redhat.com> (raw)
In-Reply-To: <cover.1244635350.git.mst@redhat.com>
Add routines to manage PCI capability list. First user will be MSI-X.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
hw/pci.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
hw/pci.h | 18 +++++++++++++-
2 files changed, 96 insertions(+), 1 deletions(-)
diff --git a/hw/pci.c b/hw/pci.c
index 6740b07..a3f3fd3 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -160,6 +160,12 @@ int pci_device_load(PCIDevice *s, QEMUFile *f)
if (version_id >= 2)
for (i = 0; i < 4; i ++)
s->irq_state[i] = qemu_get_be32(f);
+ /* Clear wmask and used bits for capabilities.
+ Must be restored separately, since capabilities can
+ be placed anywhere in config space. */
+ memset(s->used, 0, PCI_CONFIG_SPACE_SIZE);
+ for (i = PCI_CONFIG_HEADER_SIZE; i < PCI_CONFIG_SPACE_SIZE; ++i)
+ s->wmask[i] = 0xff;
return 0;
}
@@ -865,3 +871,76 @@ PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name)
return (PCIDevice *)dev;
}
+
+static int pci_find_space(PCIDevice *pdev, uint8_t size)
+{
+ int offset = PCI_CONFIG_HEADER_SIZE;
+ int i;
+ for (i = PCI_CONFIG_HEADER_SIZE; i < PCI_CONFIG_SPACE_SIZE; ++i)
+ if (pdev->used[i])
+ offset = i + 1;
+ else if (i - offset + 1 == size)
+ return offset;
+ return 0;
+}
+
+static uint8_t pci_find_capability_list(PCIDevice *pdev, uint8_t cap_id,
+ uint8_t *prev_p)
+{
+ uint8_t next, prev;
+
+ if (!(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST))
+ return 0;
+
+ for (prev = PCI_CAPABILITY_LIST; (next = pdev->config[prev]);
+ prev = next + PCI_CAP_LIST_NEXT)
+ if (pdev->config[next + PCI_CAP_LIST_ID] == cap_id)
+ break;
+
+ if (prev_p)
+ *prev_p = prev;
+ return next;
+}
+
+/* Reserve space and add capability to the linked list in pci config space */
+int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
+{
+ uint8_t offset = pci_find_space(pdev, size);
+ uint8_t *config = pdev->config + offset;
+ if (!offset)
+ return -ENOSPC;
+ config[PCI_CAP_LIST_ID] = cap_id;
+ config[PCI_CAP_LIST_NEXT] = pdev->config[PCI_CAPABILITY_LIST];
+ pdev->config[PCI_CAPABILITY_LIST] = offset;
+ pdev->config[PCI_STATUS] |= PCI_STATUS_CAP_LIST;
+ memset(pdev->used + offset, 0xFF, size);
+ /* Make capability read-only by default */
+ memset(pdev->wmask + offset, 0, size);
+ return offset;
+}
+
+/* Unlink capability from the pci config space. */
+void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
+{
+ uint8_t prev, offset = pci_find_capability_list(pdev, cap_id, &prev);
+ if (!offset)
+ return;
+ pdev->config[prev] = pdev->config[offset + PCI_CAP_LIST_NEXT];
+ /* Make capability writeable again */
+ memset(pdev->wmask + offset, 0xff, size);
+ memset(pdev->used + offset, 0, size);
+
+ if (!pdev->config[PCI_CAPABILITY_LIST])
+ pdev->config[PCI_STATUS] &= ~PCI_STATUS_CAP_LIST;
+}
+
+/* Reserve space for capability at a known offset (to call after load). */
+void pci_reserve_capability(PCIDevice *pdev, uint8_t offset, uint8_t size)
+{
+ memset(pdev->used + offset, 0xff, size);
+}
+
+uint8_t pci_find_capability(PCIDevice *pdev, uint8_t cap_id)
+{
+ return pci_find_capability_list(pdev, cap_id, NULL);
+}
diff --git a/hw/pci.h b/hw/pci.h
index 656badc..2ae72f0 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -121,6 +121,10 @@ typedef struct PCIIORegion {
#define PCI_MIN_GNT 0x3e /* 8 bits */
#define PCI_MAX_LAT 0x3f /* 8 bits */
+/* Capability lists */
+#define PCI_CAP_LIST_ID 0 /* Capability ID */
+#define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */
+
#define PCI_REVISION 0x08 /* obsolete, use PCI_REVISION_ID */
#define PCI_SUBVENDOR_ID 0x2c /* obsolete, use PCI_SUBSYSTEM_VENDOR_ID */
#define PCI_SUBDEVICE_ID 0x2e /* obsolete, use PCI_SUBSYSTEM_ID */
@@ -128,7 +132,7 @@ typedef struct PCIIORegion {
/* Bits in the PCI Status Register (PCI 2.3 spec) */
#define PCI_STATUS_RESERVED1 0x007
#define PCI_STATUS_INT_STATUS 0x008
-#define PCI_STATUS_CAPABILITIES 0x010
+#define PCI_STATUS_CAP_LIST 0x010
#define PCI_STATUS_66MHZ 0x020
#define PCI_STATUS_RESERVED2 0x040
#define PCI_STATUS_FAST_BACK 0x080
@@ -158,6 +162,9 @@ struct PCIDevice {
/* Used to implement R/W bytes */
uint8_t wmask[PCI_CONFIG_SPACE_SIZE];
+ /* Used to allocate config space for capabilities. */
+ uint8_t used[PCI_CONFIG_SPACE_SIZE];
+
/* the following fields are read only */
PCIBus *bus;
int devfn;
@@ -190,6 +197,15 @@ void pci_register_io_region(PCIDevice *pci_dev, int region_num,
uint32_t size, int type,
PCIMapIORegionFunc *map_func);
+int pci_add_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
+
+void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
+
+void pci_reserve_capability(PCIDevice *pci_dev, uint8_t offset, uint8_t size);
+
+uint8_t pci_find_capability(PCIDevice *pci_dev, uint8_t cap_id);
+
+
uint32_t pci_default_read_config(PCIDevice *d,
uint32_t address, int len);
void pci_default_write_config(PCIDevice *d,
--
1.6.3.1.56.g79e1.dirty
WARNING: multiple messages have this Message-ID (diff)
From: "Michael S. Tsirkin" <mst@redhat.com>
To: Paul Brook <paul@codesourcery.com>, Avi Kivity <avi@redhat.com>,
qemu-devel@nongnu.org, Carsten Otte <cotte@de.ibm.com>,
kvm@vger.kernel.org, Rusty Russell <rusty@rustcorp.com.au>,
virtualization@lists.linux-foundation.org,
Christian Borntraeger <borntraeger@de.ibm.com>,
Blue Swirl <blauwirbel@gmail.com>,
Anthony Liguori <anthony@codemonkey.ws>,
Glauber Costa <glommer@redhat.com>
Subject: [Qemu-devel] [PATCHv4 03/13] qemu: add routines to manage PCI capabilities
Date: Wed, 10 Jun 2009 15:28:20 +0300 [thread overview]
Message-ID: <20090610122820.GD27174@redhat.com> (raw)
In-Reply-To: <cover.1244635350.git.mst@redhat.com>
Add routines to manage PCI capability list. First user will be MSI-X.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
hw/pci.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
hw/pci.h | 18 +++++++++++++-
2 files changed, 96 insertions(+), 1 deletions(-)
diff --git a/hw/pci.c b/hw/pci.c
index 6740b07..a3f3fd3 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -160,6 +160,12 @@ int pci_device_load(PCIDevice *s, QEMUFile *f)
if (version_id >= 2)
for (i = 0; i < 4; i ++)
s->irq_state[i] = qemu_get_be32(f);
+ /* Clear wmask and used bits for capabilities.
+ Must be restored separately, since capabilities can
+ be placed anywhere in config space. */
+ memset(s->used, 0, PCI_CONFIG_SPACE_SIZE);
+ for (i = PCI_CONFIG_HEADER_SIZE; i < PCI_CONFIG_SPACE_SIZE; ++i)
+ s->wmask[i] = 0xff;
return 0;
}
@@ -865,3 +871,76 @@ PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name)
return (PCIDevice *)dev;
}
+
+static int pci_find_space(PCIDevice *pdev, uint8_t size)
+{
+ int offset = PCI_CONFIG_HEADER_SIZE;
+ int i;
+ for (i = PCI_CONFIG_HEADER_SIZE; i < PCI_CONFIG_SPACE_SIZE; ++i)
+ if (pdev->used[i])
+ offset = i + 1;
+ else if (i - offset + 1 == size)
+ return offset;
+ return 0;
+}
+
+static uint8_t pci_find_capability_list(PCIDevice *pdev, uint8_t cap_id,
+ uint8_t *prev_p)
+{
+ uint8_t next, prev;
+
+ if (!(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST))
+ return 0;
+
+ for (prev = PCI_CAPABILITY_LIST; (next = pdev->config[prev]);
+ prev = next + PCI_CAP_LIST_NEXT)
+ if (pdev->config[next + PCI_CAP_LIST_ID] == cap_id)
+ break;
+
+ if (prev_p)
+ *prev_p = prev;
+ return next;
+}
+
+/* Reserve space and add capability to the linked list in pci config space */
+int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
+{
+ uint8_t offset = pci_find_space(pdev, size);
+ uint8_t *config = pdev->config + offset;
+ if (!offset)
+ return -ENOSPC;
+ config[PCI_CAP_LIST_ID] = cap_id;
+ config[PCI_CAP_LIST_NEXT] = pdev->config[PCI_CAPABILITY_LIST];
+ pdev->config[PCI_CAPABILITY_LIST] = offset;
+ pdev->config[PCI_STATUS] |= PCI_STATUS_CAP_LIST;
+ memset(pdev->used + offset, 0xFF, size);
+ /* Make capability read-only by default */
+ memset(pdev->wmask + offset, 0, size);
+ return offset;
+}
+
+/* Unlink capability from the pci config space. */
+void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
+{
+ uint8_t prev, offset = pci_find_capability_list(pdev, cap_id, &prev);
+ if (!offset)
+ return;
+ pdev->config[prev] = pdev->config[offset + PCI_CAP_LIST_NEXT];
+ /* Make capability writeable again */
+ memset(pdev->wmask + offset, 0xff, size);
+ memset(pdev->used + offset, 0, size);
+
+ if (!pdev->config[PCI_CAPABILITY_LIST])
+ pdev->config[PCI_STATUS] &= ~PCI_STATUS_CAP_LIST;
+}
+
+/* Reserve space for capability at a known offset (to call after load). */
+void pci_reserve_capability(PCIDevice *pdev, uint8_t offset, uint8_t size)
+{
+ memset(pdev->used + offset, 0xff, size);
+}
+
+uint8_t pci_find_capability(PCIDevice *pdev, uint8_t cap_id)
+{
+ return pci_find_capability_list(pdev, cap_id, NULL);
+}
diff --git a/hw/pci.h b/hw/pci.h
index 656badc..2ae72f0 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -121,6 +121,10 @@ typedef struct PCIIORegion {
#define PCI_MIN_GNT 0x3e /* 8 bits */
#define PCI_MAX_LAT 0x3f /* 8 bits */
+/* Capability lists */
+#define PCI_CAP_LIST_ID 0 /* Capability ID */
+#define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */
+
#define PCI_REVISION 0x08 /* obsolete, use PCI_REVISION_ID */
#define PCI_SUBVENDOR_ID 0x2c /* obsolete, use PCI_SUBSYSTEM_VENDOR_ID */
#define PCI_SUBDEVICE_ID 0x2e /* obsolete, use PCI_SUBSYSTEM_ID */
@@ -128,7 +132,7 @@ typedef struct PCIIORegion {
/* Bits in the PCI Status Register (PCI 2.3 spec) */
#define PCI_STATUS_RESERVED1 0x007
#define PCI_STATUS_INT_STATUS 0x008
-#define PCI_STATUS_CAPABILITIES 0x010
+#define PCI_STATUS_CAP_LIST 0x010
#define PCI_STATUS_66MHZ 0x020
#define PCI_STATUS_RESERVED2 0x040
#define PCI_STATUS_FAST_BACK 0x080
@@ -158,6 +162,9 @@ struct PCIDevice {
/* Used to implement R/W bytes */
uint8_t wmask[PCI_CONFIG_SPACE_SIZE];
+ /* Used to allocate config space for capabilities. */
+ uint8_t used[PCI_CONFIG_SPACE_SIZE];
+
/* the following fields are read only */
PCIBus *bus;
int devfn;
@@ -190,6 +197,15 @@ void pci_register_io_region(PCIDevice *pci_dev, int region_num,
uint32_t size, int type,
PCIMapIORegionFunc *map_func);
+int pci_add_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
+
+void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
+
+void pci_reserve_capability(PCIDevice *pci_dev, uint8_t offset, uint8_t size);
+
+uint8_t pci_find_capability(PCIDevice *pci_dev, uint8_t cap_id);
+
+
uint32_t pci_default_read_config(PCIDevice *d,
uint32_t address, int len);
void pci_default_write_config(PCIDevice *d,
--
1.6.3.1.56.g79e1.dirty
next prev parent reply other threads:[~2009-06-10 12:31 UTC|newest]
Thread overview: 45+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <cover.1244635350.git.mst@redhat.com>
2009-06-10 12:28 ` [PATCHv4 01/13] qemu: make default_write_config use mask table Michael S. Tsirkin
2009-06-10 12:28 ` [Qemu-devel] " Michael S. Tsirkin
2009-06-16 20:40 ` Anthony Liguori
2009-06-16 20:40 ` [Qemu-devel] " Anthony Liguori
2009-06-17 11:49 ` Michael S. Tsirkin
2009-06-17 11:49 ` [Qemu-devel] " Michael S. Tsirkin
2009-06-17 11:49 ` Michael S. Tsirkin
2009-06-16 20:40 ` Anthony Liguori
2009-06-10 12:28 ` Michael S. Tsirkin
2009-06-10 12:28 ` [PATCHv4 02/13] qemu: capability bits in pci save/restore Michael S. Tsirkin
2009-06-10 12:28 ` [Qemu-devel] " Michael S. Tsirkin
2009-06-10 12:28 ` Michael S. Tsirkin
2009-06-10 12:28 ` [PATCHv4 03/13] qemu: add routines to manage PCI capabilities Michael S. Tsirkin
2009-06-10 12:28 ` Michael S. Tsirkin [this message]
2009-06-10 12:28 ` [Qemu-devel] " Michael S. Tsirkin
2009-06-10 12:28 ` [PATCHv4 04/13] qemu: helper routines for pci access Michael S. Tsirkin
2009-06-10 12:28 ` Michael S. Tsirkin
2009-06-10 12:28 ` [Qemu-devel] " Michael S. Tsirkin
2009-06-10 12:28 ` [PATCHv4 05/13] qemu: MSI-X support functions Michael S. Tsirkin
2009-06-10 12:28 ` Michael S. Tsirkin
2009-06-10 12:28 ` [Qemu-devel] " Michael S. Tsirkin
2009-06-10 12:28 ` [PATCHv4 06/13] qemu: add flag to disable MSI-X by default Michael S. Tsirkin
2009-06-10 12:28 ` Michael S. Tsirkin
2009-06-10 12:28 ` [Qemu-devel] " Michael S. Tsirkin
2009-06-10 12:28 ` [PATCHv4 07/13] qemu: minimal MSI/MSI-X implementation for PC Michael S. Tsirkin
2009-06-10 12:28 ` [Qemu-devel] " Michael S. Tsirkin
2009-06-10 12:28 ` Michael S. Tsirkin
2009-06-10 12:28 ` [PATCHv4 08/13] qemu: add support for resizing regions Michael S. Tsirkin
2009-06-10 12:28 ` Michael S. Tsirkin
2009-06-10 12:28 ` [Qemu-devel] " Michael S. Tsirkin
2009-06-10 12:29 ` [PATCHv4 09/13] qemu: virtio support for many interrupt vectors Michael S. Tsirkin
2009-06-10 12:29 ` Michael S. Tsirkin
2009-06-10 12:29 ` [Qemu-devel] " Michael S. Tsirkin
2009-06-10 12:29 ` [PATCHv4 10/13] qemu: MSI-X support in virtio PCI Michael S. Tsirkin
2009-06-10 12:29 ` Michael S. Tsirkin
2009-06-10 12:29 ` [Qemu-devel] " Michael S. Tsirkin
2009-06-10 12:29 ` [PATCHv4 11/13] qemu: request 3 vectors in virtio-net Michael S. Tsirkin
2009-06-10 12:29 ` [Qemu-devel] " Michael S. Tsirkin
2009-06-10 12:29 ` Michael S. Tsirkin
2009-06-10 12:29 ` [PATCHv4 12/13] qemu: virtio save/load bindings Michael S. Tsirkin
2009-06-10 12:29 ` [Qemu-devel] " Michael S. Tsirkin
2009-06-10 12:29 ` Michael S. Tsirkin
2009-06-10 12:29 ` [PATCHv4 13/13] qemu: add pci_get/set_byte Michael S. Tsirkin
2009-06-10 12:29 ` [Qemu-devel] " Michael S. Tsirkin
2009-06-10 12:29 ` Michael S. Tsirkin
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=20090610122820.GD27174@redhat.com \
--to=mst@redhat.com \
--cc=avi@redhat.com \
--cc=cotte@de.ibm.com \
--cc=kvm@vger.kernel.org \
--cc=paul@codesourcery.com \
--cc=qemu-devel@nongnu.org \
--cc=rusty@rustcorp.com.au \
/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.