From fb859bc848e0adb8957c58d2725c826e593a69f5 Mon Sep 17 00:00:00 2001 From: Guy Zana <guy@cloudius-systems.com> Date: Tue, 15 Jan 2013 22:33:48 +0200 Subject: [PATCH] Added pci config capability parsing and moved the virtual call to earlyInitChecks() to the base class --- drivers/driver.cc | 74 ++++++++++++++++++ drivers/driver.hh | 18 +++++ drivers/pci.hh | 29 +++++++ drivers/virtio-vring.hh.orig | 141 +++++++++++++++++++++++++++++++++++ drivers/virtio.cc | 4 - 5 files changed, 262 insertions(+), 4 deletions(-) create mode 100644 drivers/virtio-vring.hh.orig diff --git a/drivers/driver.cc b/drivers/driver.cc index 87543331f..abbf22450 100644 --- a/drivers/driver.cc +++ b/drivers/driver.cc @@ -85,6 +85,12 @@ bool Driver::Init(Device* dev) { if (!dev) return false; + if (!earlyInitChecks()) { + return false; + } + + parse_pci_config(); + debug(fmt("Driver:Init %x:%x") % _vid % _id); setBusMaster(true); @@ -116,6 +122,74 @@ Driver::getFunc() { return _func; } +bool Driver::parse_pci_config(void) +{ + // Parse capabilities + bool parse_ok = parse_pci_capabilities(); + + return parse_ok; +} + +bool Driver::parse_pci_capabilities(void) +{ + // FIXME: check pci device type (act differently if bridge) + u8 capabilities_base = pci_readb(PCI_CAPABILITIES_PTR); + u8 off = capabilities_base; + + while (off != 0) { + if (off > 255) { + return (false); + } + + u8 capability = pci_readb(off + PCI_CAP_OFF_ID); + switch (capability) { + case PCI_CAP_MSIX: + _have_msix = true; + debug(fmt("Have MSI-X!")); + break; + } + + off = pci_readb(off + PCI_CAP_OFF_NEXT); + } + + return true; +} + +bool Driver::parse_pci_msix(void) +{ + return true; +} + +u8 Driver::pci_readb(u8 offset) +{ + return read_pci_config_byte(_bus, _slot, _func, offset); +} + +u16 Driver::pci_readw(u8 offset) +{ + return read_pci_config_word(_bus, _slot, _func, offset); +} + +u32 Driver::pci_readl(u8 offset) +{ + return read_pci_config(_bus, _slot, _func, offset); +} + +void Driver::pci_writeb(u8 offset, u8 val) +{ + write_pci_config_byte(_bus, _slot, _func, offset, val); +} + +void Driver::pci_writew(u8 offset, u16 val) +{ + write_pci_config_word(_bus, _slot, _func, offset, val); +} + +void Driver::pci_writel(u8 offset, u32 val) +{ + write_pci_config(_bus, _slot, _func, offset, val); +} + void Driver::dumpConfig() const { debug(fmt("Driver vid:id= %x:%x") % _vid % _id); } diff --git a/drivers/driver.hh b/drivers/driver.hh index 777999a4f..69dd006ca 100644 --- a/drivers/driver.hh +++ b/drivers/driver.hh @@ -29,6 +29,8 @@ public: virtual void dumpConfig() const; virtual bool Init(Device *d); + bool parse_pci_config(void); + friend std::ostream& operator <<(std::ostream& out, const Driver &d); struct equal { bool operator()(const Driver* d1, const Driver* d2) const @@ -60,11 +62,27 @@ protected: bool allocateBARs(); virtual bool earlyInitChecks(); + // Parsing of extra capabilities + virtual bool parse_pci_capabilities(void); + virtual bool parse_pci_msix(void); + + // Access to PCI address space + virtual u8 pci_readb(u8 offset); + virtual u16 pci_readw(u8 offset); + virtual u32 pci_readl(u8 offset); + virtual void pci_writeb(u8 offset, u8 val); + virtual void pci_writew(u8 offset, u16 val); + virtual void pci_writel(u8 offset, u32 val); + u16 _id; u16 _vid; bool _present; u8 _bus, _slot, _func; Bar* _bars[6]; + + // MSI-X + bool _have_msix; + }; #endif diff --git a/drivers/pci.hh b/drivers/pci.hh index e35c28904..9d4ad96ac 100644 --- a/drivers/pci.hh +++ b/drivers/pci.hh @@ -37,6 +37,35 @@ using processor::outl; PCI_CAPABILITIES_PTR = 0x34, }; + /* Capability Register Offsets */ + enum pci_capabilities_offsets { + PCI_CAP_OFF_ID = 0x0, + PCI_CAP_OFF_NEXT = 0x1 + }; + + enum pci_capabilities { + PCI_CAP_PM = 0x01, // PCI Power Management + PCI_CAP_AGP = 0x02, // AGP + PCI_CAP_VPD = 0x03, // Vital Product Data + PCI_CAP_SLOTID = 0x04, // Slot Identification + PCI_CAP_MSI = 0x05, // Message Signaled Interrupts + PCI_CAP_CHSWP = 0x06, // CompactPCI Hot Swap + PCI_CAP_PCIX = 0x07, // PCI-X + PCI_CAP_HT = 0x08, // HyperTransport + PCI_CAP_VENDOR = 0x09, // Vendor Unique + PCI_CAP_DEBUG = 0x0a, // Debug port + PCI_CAP_CRES = 0x0b, // CompactPCI central resource control + PCI_CAP_HOTPLUG = 0x0c, // PCI Hot-Plug + PCI_CAP_SUBVENDOR = 0x0d, // PCI-PCI bridge subvendor ID + PCI_CAP_AGP8X = 0x0e, // AGP 8x + PCI_CAP_SECDEV = 0x0f, // Secure Device + PCI_CAP_EXPRESS = 0x10, // PCI Express + PCI_CAP_MSIX = 0x11, // MSI-X + PCI_CAP_SATA = 0x12, // SATA + PCI_CAP_PCIAF = 0x13 // PCI Advanced Features + }; + + u32 read_pci_config(u8 bus, u8 slot, u8 func, u8 offset); u16 read_pci_config_word(u8 bus, u8 slot, u8 func, u8 offset); u8 read_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset); diff --git a/drivers/virtio-vring.hh.orig b/drivers/virtio-vring.hh.orig new file mode 100644 index 000000000..bcca69066 --- /dev/null +++ b/drivers/virtio-vring.hh.orig @@ -0,0 +1,141 @@ +#ifndef VIRTIO_VRING_H +#define VIRTIO_VRING_H + +#include "types.hh" +#include "drivers/virtio.hh" + +namespace virtio { + + // Buffer descriptors in the ring + class vring_desc { + public: + enum { + // This marks a buffer as continuing via the next field. + VRING_DESC_F_NEXT=1, + // This marks a buffer as write-only (otherwise read-only). + VRING_DESC_F_WRITE=2, + // This means the buffer contains a list of buffer descriptors. + VRING_DESC_F_INDIRECT=4 + }; + + u64 get_paddr(void); + u32 get_len(void) { return (_len); } + u16 next_idx(void) { return (_next); } + + // flags + bool is_chained(void) { return ((_flags & VRING_DESC_F_NEXT) == VRING_DESC_F_NEXT); }; + bool is_write(void) { return ((_flags & VRING_DESC_F_WRITE) == VRING_DESC_F_WRITE); }; + bool is_indirect(void) { return ((_flags & VRING_DESC_F_INDIRECT) == VRING_DESC_F_INDIRECT); }; + + private: + u64 _paddr; + u32 _len; + u16 _flags; + u16 _next; + }; + + // Guest to host + class vring_avail { + public: + enum { + // Mark that we do not need an interrupt for consuming a descriptor + // from the ring. Unrelieable so it's simply an optimization + VRING_AVAIL_F_NO_INTERRUPT=1 + }; + + void disable_interrupt(void) { _flags |= VRING_AVAIL_F_NO_INTERRUPT; } + void enable_interrupt(void) { _flags = 0; } + + u16 _flags; + // Where we put the next descriptor + u16 _idx; + // There may be no more entries than the queue size read from device + u16 _ring[]; + }; + + class vring_used_elem { + public: + // Index of start of used vring_desc chain. (u32 for padding reasons) + u32 _id; + // Total length of the descriptor chain which was used (written to) + u32 _len; + }; + + // Host to guest + class vring_used { + public: + + enum { + // The Host advise the Guest: don't kick me when + // you add a buffer. It's unreliable, so it's simply an + // optimization. Guest will still kick if it's out of buffers. + VRING_USED_F_NO_NOTIFY=1 + }; + + void disable_interrupt(void) { _flags |= VRING_USED_F_NO_NOTIFY; } + void enable_interrupt(void) { _flags = 0; } + + u16 _flags; + u16 _idx; + vring_used_elem _used_elements[]; + }; + + class vring { + public: + + enum VRING_CONFIG { + + /* We support indirect buffer descriptors */ + VIRTIO_RING_F_INDIRECT_DESC = 28, + + /* The Guest publishes the used index for which it expects an interrupt + * at the end of the avail ring. Host should ignore the avail->flags field. */ + /* The Host publishes the avail index for which it expects a kick + * at the end of the used ring. Guest should ignore the used->flags field. */ + VIRTIO_RING_F_EVENT_IDX = 29, + }; + + vring(unsigned int num); + virtual ~vring(); + +<<<<<<< Updated upstream + u64 get_paddr(void); +======= + // Add a buffer to the next free descriptor, + // Keep chaining until kick is called + bool add_buf(u64 addr, u32 len); + // Notify the device + void kick(void); + + void * get_paddr(void); +>>>>>>> Stashed changes + static unsigned get_size(unsigned int num, unsigned long align); + + // The following is used with USED_EVENT_IDX and AVAIL_EVENT_IDX + // Assuming a given event_idx value from the other size, if + // we have just incremented index from old to new_idx, + // should we trigger an event? + static int need_event(u16 event_idx, u16 new_idx, u16 old); + + private: + // The physical of the physical address handed to the virtio device + void* _vring_ptr; + + // Total number of descriptors in ring + unsigned int _num; + // Flat list of chained descriptors + vring_desc *_desc; + // Available for host consumption + vring_avail *_avail; + // Available for guest consumption + vring_used *_used; + + // next free idx + u16 free_avail_idx; + }; + + +} + +#endif // VIRTIO_VRING_H + diff --git a/drivers/virtio.cc b/drivers/virtio.cc index d05f92c00..38e4ab660 100644 --- a/drivers/virtio.cc +++ b/drivers/virtio.cc @@ -52,10 +52,6 @@ namespace virtio { bool virtio_driver::Init(Device* dev) { - if (!earlyInitChecks()) { - return false; - } - if (!Driver::Init(dev)) { return (false); } -- GitLab