[SLOF] [PATCH v1 07/27] virtio: add virtio 1.0 capability parsing
Nikunj A Dadhania
nikunj at linux.vnet.ibm.com
Wed Jan 13 22:16:54 AEDT 2016
Signed-off-by: Nikunj A Dadhania <nikunj at linux.vnet.ibm.com>
---
lib/libvirtio/virtio.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++++
lib/libvirtio/virtio.h | 3 +-
2 files changed, 137 insertions(+), 1 deletion(-)
diff --git a/lib/libvirtio/virtio.c b/lib/libvirtio/virtio.c
index 7e0d6a3..bcf050b 100644
--- a/lib/libvirtio/virtio.c
+++ b/lib/libvirtio/virtio.c
@@ -14,6 +14,7 @@
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
+#include <stddef.h>
#include <cpu.h>
#include <cache.h>
#include <byteorder.h>
@@ -31,6 +32,140 @@
#define VIRTIOHDR_ISR_STATUS 19
#define VIRTIOHDR_DEVICE_CONFIG 20
+/* PCI defines */
+#define PCI_BASE_ADDR_SPACE_IO 0x01
+#define PCI_BASE_ADDR_SPACE_MEM 0x00
+#define PCI_BASE_ADDR_MEM_MASK (~0x0fUL)
+#define PCI_BASE_ADDR_IO_MASK (~0x03UL)
+
+#define PCI_BASE_ADDR_REG_0 0x10
+#define PCI_CONFIG_CAP_REG 0x34
+
+#define PCI_CAP_ID_VNDR 0x9
+
+#define VIRTIO_PCI_CAP_COMMON 1
+#define VIRTIO_PCI_CAP_NOTIFY 2
+#define VIRTIO_PCI_CAP_ISR 3
+#define VIRTIO_PCI_CAP_DEVICE 4
+#define VIRTIO_PCI_CAP_PCI 5
+
+#define VIRTIO_CAP_VNDR 0
+#define VIRTIO_CAP_NEXT 1
+#define VIRTIO_CAP_LEN 2
+#define VIRTIO_CAP_CFG_TYPE 3
+#define VIRTIO_CAP_BAR 4
+#define VIRTIO_CAP_OFFSET 8
+#define VIRTIO_CAP_LENGTH 12
+
+#define le64 uint64_t
+#define le32 uint32_t
+#define le16 uint16_t
+
+struct virtio_dev_common {
+ le32 dev_features_sel;
+ le32 dev_features;
+ le32 drv_features_sel;
+ le32 drv_features;
+ le16 msix_config;
+ le16 num_queues;
+ uint8_t dev_status;
+ uint8_t cfg_generation;
+
+ le16 q_select;
+ le16 q_size;
+ le16 q_msix_vec;
+ le16 q_enable;
+ le16 q_notify_off;
+ le64 q_desc;
+ le64 q_avail;
+ le64 q_used;
+} __attribute__ ((packed));
+
+static void virtio_process_cap(struct virtio_device *dev, uint8_t cap_ptr)
+{
+ struct virtio_cap *cap;
+ uint8_t cfg_type, bar;
+ uint32_t offset;
+ uint64_t addr = 0;
+
+ cfg_type = SLOF_pci_config_read8(cap_ptr + VIRTIO_CAP_CFG_TYPE);
+ bar = SLOF_pci_config_read8(cap_ptr + VIRTIO_CAP_BAR);
+ offset = SLOF_pci_config_read32(cap_ptr + VIRTIO_CAP_OFFSET);
+
+ switch(cfg_type) {
+ case VIRTIO_PCI_CAP_COMMON:
+ cap = &dev->common;
+ break;
+ case VIRTIO_PCI_CAP_NOTIFY:
+ cap = &dev->notify;
+ dev->notify_off_mul = SLOF_pci_config_read32(cap_ptr + sizeof(struct virtio_cap));
+ break;
+ case VIRTIO_PCI_CAP_ISR:
+ cap = &dev->isr;
+ break;
+ case VIRTIO_PCI_CAP_DEVICE:
+ cap = &dev->device;
+ break;
+ default:
+ cap = NULL;
+ }
+
+ if (cap && cfg_type) {
+ cap->bar = bar;
+ addr = SLOF_pci_config_read32(PCI_BASE_ADDR_REG_0 + 4 * cap->bar);
+ if (addr & PCI_BASE_ADDR_SPACE_IO) {
+ cap->is_io = 1;
+ addr = addr & PCI_BASE_ADDR_IO_MASK;
+ } else if (addr & 4) {
+ addr = SLOF_pci_config_read32(PCI_BASE_ADDR_REG_0 + 4 * cap->bar) |
+ (SLOF_pci_config_read32(PCI_BASE_ADDR_REG_0 + 4 * (cap->bar + 1)) << 32);
+ addr = (uint64_t)SLOF_translate_my_address((void *)addr);
+ addr = addr & PCI_BASE_ADDR_MEM_MASK;
+ }
+ else {
+ cap->is_io = 0;
+ addr = addr & PCI_BASE_ADDR_MEM_MASK;
+ }
+ cap->addr = (void *)addr + offset;
+ cap->cap_id = cfg_type;
+ }
+ return;
+}
+/**
+ * Setup virtio device details, gets called from SLOF routines
+ * Determines legacy or modern device.
+ */
+void virtio_setup_device(struct virtio_device *dev)
+{
+ uint8_t cap_ptr, cap_vndr;
+ uint64_t addr = 0;
+
+ cap_ptr = SLOF_pci_config_read8(PCI_CONFIG_CAP_REG);
+ while (cap_ptr != 0)
+ {
+ cap_vndr = SLOF_pci_config_read8(cap_ptr + VIRTIO_CAP_VNDR);
+ if (cap_vndr == PCI_CAP_ID_VNDR)
+ virtio_process_cap(dev, cap_ptr);
+ cap_ptr = SLOF_pci_config_read8(cap_ptr+VIRTIO_CAP_NEXT);
+ }
+ if (dev->common.cap_id && dev->notify.cap_id && dev->isr.cap_id && dev->device.cap_id)
+ dev->is_modern = 1;
+ else {
+ dev->is_modern = 0;
+ dev->legacy.cap_id = 0;
+ dev->legacy.bar = 0;
+ addr = SLOF_pci_config_read32(PCI_BASE_ADDR_REG_0);
+ if (addr & PCI_BASE_ADDR_SPACE_IO) {
+ dev->legacy.is_io = 1;
+ addr = addr & PCI_BASE_ADDR_IO_MASK;
+ } else {
+ dev->legacy.is_io = 0;
+ addr = addr & PCI_BASE_ADDR_MEM_MASK;
+ }
+ dev->legacy.addr = (void *)addr;
+ }
+ return;
+}
/**
* Calculate ring size according to queue size number
diff --git a/lib/libvirtio/virtio.h b/lib/libvirtio/virtio.h
index 56e044b..eee3144 100644
--- a/lib/libvirtio/virtio.h
+++ b/lib/libvirtio/virtio.h
@@ -74,7 +74,7 @@ struct vring_used {
/* Structure shared with SLOF and is 16bytes */
struct virtio_cap {
- uint64_t addr;
+ void *addr;
uint8_t bar;
uint8_t is_io;
uint8_t cap_id;
@@ -116,6 +116,7 @@ extern void virtio_fill_desc(struct vring_desc *desc,
uint16_t flags, uint16_t next);
extern int virtio_queue_init_vq(struct virtio_device *dev, struct vqs *vq, unsigned int id);
+extern void virtio_setup_device(struct virtio_device *dev);
extern void virtio_reset_device(struct virtio_device *dev);
extern void virtio_queue_notify(struct virtio_device *dev, int queue);
extern void virtio_set_status(struct virtio_device *dev, int status);
--
2.5.0
More information about the SLOF
mailing list