iPXE
virtio-pci.h
Go to the documentation of this file.
00001 #ifndef _VIRTIO_PCI_H_
00002 # define _VIRTIO_PCI_H_
00003 
00004 /* A 32-bit r/o bitmask of the features supported by the host */
00005 #define VIRTIO_PCI_HOST_FEATURES        0
00006 
00007 /* A 32-bit r/w bitmask of features activated by the guest */
00008 #define VIRTIO_PCI_GUEST_FEATURES       4
00009 
00010 /* A 32-bit r/w PFN for the currently selected queue */
00011 #define VIRTIO_PCI_QUEUE_PFN            8
00012 
00013 /* A 16-bit r/o queue size for the currently selected queue */
00014 #define VIRTIO_PCI_QUEUE_NUM            12
00015 
00016 /* A 16-bit r/w queue selector */
00017 #define VIRTIO_PCI_QUEUE_SEL            14
00018 
00019 /* A 16-bit r/w queue notifier */
00020 #define VIRTIO_PCI_QUEUE_NOTIFY         16
00021 
00022 /* An 8-bit device status register.  */
00023 #define VIRTIO_PCI_STATUS               18
00024 
00025 /* An 8-bit r/o interrupt status register.  Reading the value will return the
00026  * current contents of the ISR and will also clear it.  This is effectively
00027  * a read-and-acknowledge. */
00028 #define VIRTIO_PCI_ISR                  19
00029 
00030 /* The bit of the ISR which indicates a device configuration change. */
00031 #define VIRTIO_PCI_ISR_CONFIG           0x2
00032 
00033 /* The remaining space is defined by each driver as the per-driver
00034  * configuration space */
00035 #define VIRTIO_PCI_CONFIG               20
00036 
00037 /* Virtio ABI version, this must match exactly */
00038 #define VIRTIO_PCI_ABI_VERSION          0
00039 
00040 /* PCI capability types: */
00041 #define VIRTIO_PCI_CAP_COMMON_CFG       1  /* Common configuration */
00042 #define VIRTIO_PCI_CAP_NOTIFY_CFG       2  /* Notifications */
00043 #define VIRTIO_PCI_CAP_ISR_CFG          3  /* ISR access */
00044 #define VIRTIO_PCI_CAP_DEVICE_CFG       4  /* Device specific configuration */
00045 #define VIRTIO_PCI_CAP_PCI_CFG          5  /* PCI configuration access */
00046 
00047 #define __u8       uint8_t
00048 #define __le16     uint16_t
00049 #define __le32     uint32_t
00050 #define __le64     uint64_t
00051 
00052 /* This is the PCI capability header: */
00053 struct virtio_pci_cap {
00054     __u8 cap_vndr;    /* Generic PCI field: PCI_CAP_ID_VNDR */
00055     __u8 cap_next;    /* Generic PCI field: next ptr. */
00056     __u8 cap_len;     /* Generic PCI field: capability length */
00057     __u8 cfg_type;    /* Identifies the structure. */
00058     __u8 bar;         /* Where to find it. */
00059     __u8 padding[3];  /* Pad to full dword. */
00060     __le32 offset;    /* Offset within bar. */
00061     __le32 length;    /* Length of the structure, in bytes. */
00062 };
00063 
00064 struct virtio_pci_notify_cap {
00065     struct virtio_pci_cap cap;
00066     __le32 notify_off_multiplier; /* Multiplier for queue_notify_off. */
00067 };
00068 
00069 struct virtio_pci_cfg_cap {
00070     struct virtio_pci_cap cap;
00071     __u8 pci_cfg_data[4]; /* Data for BAR access. */
00072 };
00073 
00074 /* Fields in VIRTIO_PCI_CAP_COMMON_CFG: */
00075 struct virtio_pci_common_cfg {
00076     /* About the whole device. */
00077     __le32 device_feature_select; /* read-write */
00078     __le32 device_feature;        /* read-only */
00079     __le32 guest_feature_select;  /* read-write */
00080     __le32 guest_feature;         /* read-write */
00081     __le16 msix_config;           /* read-write */
00082     __le16 num_queues;            /* read-only */
00083     __u8 device_status;           /* read-write */
00084     __u8 config_generation;       /* read-only */
00085 
00086     /* About a specific virtqueue. */
00087     __le16 queue_select;          /* read-write */
00088     __le16 queue_size;            /* read-write, power of 2. */
00089     __le16 queue_msix_vector;     /* read-write */
00090     __le16 queue_enable;          /* read-write */
00091     __le16 queue_notify_off;      /* read-only */
00092     __le32 queue_desc_lo;         /* read-write */
00093     __le32 queue_desc_hi;         /* read-write */
00094     __le32 queue_avail_lo;        /* read-write */
00095     __le32 queue_avail_hi;        /* read-write */
00096     __le32 queue_used_lo;         /* read-write */
00097     __le32 queue_used_hi;         /* read-write */
00098 };
00099 
00100 /* Virtio 1.0 PCI region descriptor. We support memory mapped I/O, port I/O,
00101  * and PCI config space access via the cfg PCI capability as a fallback. */
00102 struct virtio_pci_region {
00103     void *base;
00104     size_t length;
00105     u8 bar;
00106 
00107 /* How to interpret the base field */
00108 #define VIRTIO_PCI_REGION_TYPE_MASK  0x00000003
00109 /* The base field is a memory address */
00110 #define VIRTIO_PCI_REGION_MEMORY     0x00000001
00111 /* The base field is a port address */
00112 #define VIRTIO_PCI_REGION_PORT       0x00000002
00113 /* The base field is an offset within the PCI bar */
00114 #define VIRTIO_PCI_REGION_PCI_CONFIG 0x00000003
00115     unsigned flags;
00116 };
00117 
00118 /* Virtio 1.0 device state */
00119 struct virtio_pci_modern_device {
00120     struct pci_device *pci;
00121 
00122     /* VIRTIO_PCI_CAP_PCI_CFG position */
00123     int cfg_cap_pos;
00124 
00125     /* VIRTIO_PCI_CAP_COMMON_CFG data */
00126     struct virtio_pci_region common;
00127 
00128     /* VIRTIO_PCI_CAP_DEVICE_CFG data */
00129     struct virtio_pci_region device;
00130 
00131     /* VIRTIO_PCI_CAP_ISR_CFG data */
00132     struct virtio_pci_region isr;
00133 
00134     /* VIRTIO_PCI_CAP_NOTIFY_CFG data */
00135     int notify_cap_pos;
00136 };
00137 
00138 static inline u32 vp_get_features(unsigned int ioaddr)
00139 {
00140    return inl(ioaddr + VIRTIO_PCI_HOST_FEATURES);
00141 }
00142 
00143 static inline void vp_set_features(unsigned int ioaddr, u32 features)
00144 {
00145         outl(features, ioaddr + VIRTIO_PCI_GUEST_FEATURES);
00146 }
00147 
00148 static inline void vp_get(unsigned int ioaddr, unsigned offset,
00149                      void *buf, unsigned len)
00150 {
00151    u8 *ptr = buf;
00152    unsigned i;
00153 
00154    for (i = 0; i < len; i++)
00155            ptr[i] = inb(ioaddr + VIRTIO_PCI_CONFIG + offset + i);
00156 }
00157 
00158 static inline u8 vp_get_status(unsigned int ioaddr)
00159 {
00160    return inb(ioaddr + VIRTIO_PCI_STATUS);
00161 }
00162 
00163 static inline void vp_set_status(unsigned int ioaddr, u8 status)
00164 {
00165    if (status == 0)        /* reset */
00166            return;
00167    outb(status, ioaddr + VIRTIO_PCI_STATUS);
00168 }
00169 
00170 static inline u8 vp_get_isr(unsigned int ioaddr)
00171 {
00172    return inb(ioaddr + VIRTIO_PCI_ISR);
00173 }
00174 
00175 static inline void vp_reset(unsigned int ioaddr)
00176 {
00177    outb(0, ioaddr + VIRTIO_PCI_STATUS);
00178    (void)inb(ioaddr + VIRTIO_PCI_ISR);
00179 }
00180 
00181 static inline void vp_notify(unsigned int ioaddr, int queue_index)
00182 {
00183    outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_NOTIFY);
00184 }
00185 
00186 static inline void vp_del_vq(unsigned int ioaddr, int queue_index)
00187 {
00188    /* select the queue */
00189 
00190    outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL);
00191 
00192    /* deactivate the queue */
00193 
00194    outl(0, ioaddr + VIRTIO_PCI_QUEUE_PFN);
00195 }
00196 
00197 struct vring_virtqueue;
00198 
00199 void vp_free_vq(struct vring_virtqueue *vq);
00200 int vp_find_vq(unsigned int ioaddr, int queue_index,
00201                struct vring_virtqueue *vq);
00202 
00203 
00204 /* Virtio 1.0 I/O routines abstract away the three possible HW access
00205  * mechanisms - memory, port I/O, and PCI cfg space access. Also built-in
00206  * are endianness conversions - to LE on write and from LE on read. */
00207 
00208 void vpm_iowrite8(struct virtio_pci_modern_device *vdev,
00209                   struct virtio_pci_region *region, u8 data, size_t offset);
00210 
00211 void vpm_iowrite16(struct virtio_pci_modern_device *vdev,
00212                    struct virtio_pci_region *region, u16 data, size_t offset);
00213 
00214 void vpm_iowrite32(struct virtio_pci_modern_device *vdev,
00215                    struct virtio_pci_region *region, u32 data, size_t offset);
00216 
00217 static inline void vpm_iowrite64(struct virtio_pci_modern_device *vdev,
00218                                  struct virtio_pci_region *region,
00219                                  u64 data, size_t offset_lo, size_t offset_hi)
00220 {
00221     vpm_iowrite32(vdev, region, (u32)data, offset_lo);
00222     vpm_iowrite32(vdev, region, data >> 32, offset_hi);
00223 }
00224 
00225 u8 vpm_ioread8(struct virtio_pci_modern_device *vdev,
00226                struct virtio_pci_region *region, size_t offset);
00227 
00228 u16 vpm_ioread16(struct virtio_pci_modern_device *vdev,
00229                  struct virtio_pci_region *region, size_t offset);
00230 
00231 u32 vpm_ioread32(struct virtio_pci_modern_device *vdev,
00232                  struct virtio_pci_region *region, size_t offset);
00233 
00234 /* Virtio 1.0 device manipulation routines */
00235 
00236 #define COMMON_OFFSET(field) offsetof(struct virtio_pci_common_cfg, field)
00237 
00238 static inline void vpm_reset(struct virtio_pci_modern_device *vdev)
00239 {
00240     vpm_iowrite8(vdev, &vdev->common, 0, COMMON_OFFSET(device_status));
00241     while (vpm_ioread8(vdev, &vdev->common, COMMON_OFFSET(device_status)))
00242         mdelay(1);
00243 }
00244 
00245 static inline u8 vpm_get_status(struct virtio_pci_modern_device *vdev)
00246 {
00247     return vpm_ioread8(vdev, &vdev->common, COMMON_OFFSET(device_status));
00248 }
00249 
00250 static inline void vpm_add_status(struct virtio_pci_modern_device *vdev,
00251                                   u8 status)
00252 {
00253     u8 curr_status = vpm_ioread8(vdev, &vdev->common, COMMON_OFFSET(device_status));
00254     vpm_iowrite8(vdev, &vdev->common,
00255                  curr_status | status, COMMON_OFFSET(device_status));
00256 }
00257 
00258 static inline u64 vpm_get_features(struct virtio_pci_modern_device *vdev)
00259 {
00260     u32 features_lo, features_hi;
00261 
00262     vpm_iowrite32(vdev, &vdev->common, 0, COMMON_OFFSET(device_feature_select));
00263     features_lo = vpm_ioread32(vdev, &vdev->common, COMMON_OFFSET(device_feature));
00264     vpm_iowrite32(vdev, &vdev->common, 1, COMMON_OFFSET(device_feature_select));
00265     features_hi = vpm_ioread32(vdev, &vdev->common, COMMON_OFFSET(device_feature));
00266 
00267     return ((u64)features_hi << 32) | features_lo;
00268 }
00269 
00270 static inline void vpm_set_features(struct virtio_pci_modern_device *vdev,
00271                                     u64 features)
00272 {
00273     u32 features_lo = (u32)features;
00274     u32 features_hi = features >> 32;
00275 
00276     vpm_iowrite32(vdev, &vdev->common, 0, COMMON_OFFSET(guest_feature_select));
00277     vpm_iowrite32(vdev, &vdev->common, features_lo, COMMON_OFFSET(guest_feature));
00278     vpm_iowrite32(vdev, &vdev->common, 1, COMMON_OFFSET(guest_feature_select));
00279     vpm_iowrite32(vdev, &vdev->common, features_hi, COMMON_OFFSET(guest_feature));
00280 }
00281 
00282 static inline void vpm_get(struct virtio_pci_modern_device *vdev,
00283                            unsigned offset, void *buf, unsigned len)
00284 {
00285     u8 *ptr = buf;
00286     unsigned i;
00287 
00288     for (i = 0; i < len; i++)
00289         ptr[i] = vpm_ioread8(vdev, &vdev->device, offset + i);
00290 }
00291 
00292 static inline u8 vpm_get_isr(struct virtio_pci_modern_device *vdev)
00293 {
00294     return vpm_ioread8(vdev, &vdev->isr, 0);
00295 }
00296 
00297 void vpm_notify(struct virtio_pci_modern_device *vdev,
00298                 struct vring_virtqueue *vq);
00299 
00300 int vpm_find_vqs(struct virtio_pci_modern_device *vdev,
00301                  unsigned nvqs, struct vring_virtqueue *vqs);
00302 
00303 int virtio_pci_find_capability(struct pci_device *pci, uint8_t cfg_type);
00304 
00305 int virtio_pci_map_capability(struct pci_device *pci, int cap, size_t minlen,
00306                               u32 align, u32 start, u32 size,
00307                               struct virtio_pci_region *region);
00308 
00309 void virtio_pci_unmap_capability(struct virtio_pci_region *region);
00310 #endif /* _VIRTIO_PCI_H_ */