From 07ab2785fb4d421384cb5429225b15ccd99a8946 Mon Sep 17 00:00:00 2001 From: Travis Geiselbrecht Date: Mon, 3 Jun 2024 01:03:46 -0700 Subject: [PATCH] WIP virtio working on getting MSI-x working --- dev/bus/pci/bus_mgr/bus_mgr.cpp | 18 ++++ dev/bus/pci/bus_mgr/device.cpp | 152 ++++++++++++++++++++++++++++++ dev/bus/pci/bus_mgr/device.h | 8 ++ dev/bus/pci/include/dev/bus/pci.h | 3 + dev/virtio/include/dev/virtio.h | 8 +- dev/virtio/net/virtio-net.cpp | 59 ++++++------ dev/virtio/virtio-device.cpp | 2 +- dev/virtio/virtio-pci-bus.cpp | 79 +++++++++++----- platform/qemu-virt-arm/platform.c | 4 +- 9 files changed, 280 insertions(+), 53 deletions(-) diff --git a/dev/bus/pci/bus_mgr/bus_mgr.cpp b/dev/bus/pci/bus_mgr/bus_mgr.cpp index 75e46d823..c296646fd 100644 --- a/dev/bus/pci/bus_mgr/bus_mgr.cpp +++ b/dev/bus/pci/bus_mgr/bus_mgr.cpp @@ -309,6 +309,24 @@ status_t pci_bus_mgr_allocate_msi(const pci_location_t loc, size_t num_requested return d->allocate_msi(num_requested, irqbase); } +status_t pci_bus_mgr_allocate_msix(const pci_location_t loc, size_t num_requested, uint *irqbase) { + char str[14]; + LTRACEF("%s num_request %zu\n", pci_loc_string(loc, str), num_requested); + + *irqbase = 0; + + device *d = lookup_device_by_loc(loc); + if (!d) { + return ERR_NOT_FOUND; + } + + if (!d->has_msix()) { + return ERR_NO_RESOURCES; + } + + return d->allocate_msix(num_requested, irqbase); +} + status_t pci_bus_mgr_allocate_irq(const pci_location_t loc, uint *irqbase) { char str[14]; LTRACEF("%s\n", pci_loc_string(loc, str)); diff --git a/dev/bus/pci/bus_mgr/device.cpp b/dev/bus/pci/bus_mgr/device.cpp index ec5242b9c..1fba0fe38 100644 --- a/dev/bus/pci/bus_mgr/device.cpp +++ b/dev/bus/pci/bus_mgr/device.cpp @@ -7,6 +7,7 @@ */ #include "device.h" +#include "arch/mmu.h" #include #include @@ -22,6 +23,10 @@ #include #include +#if WITH_KERNEL_VM +#include +#endif + #define LOCAL_TRACE 0 #include "bus_mgr.h" @@ -358,6 +363,153 @@ status_t device::allocate_msi(size_t num_requested, uint *msi_base) { return NO_ERROR; } +status_t device::allocate_msix(size_t num_requested, uint *msi_base) { + LTRACE_ENTRY; + + // for the moment, only deal with 1 + DEBUG_ASSERT(num_requested == 1); + + if (!has_msix()) { + return ERR_NOT_SUPPORTED; + } + + DEBUG_ASSERT(msix_cap_ && msix_cap_->is_msix()); + + // program it into the capability + const uint16_t cap_offset = msix_cap_->config_offset; + + // read the table size and address out of the capability + uint16_t control; + status_t err = pci_read_config_half(loc(), cap_offset + 2, &control); + if (err != NO_ERROR) { + return err; + } + const uint32_t table_count = (control & 0x3f) + 1; + TRACEF("control word %#x table count %u\n", control, table_count); + uint32_t table_offset, pba_offset; + err = pci_read_config_word(loc(), cap_offset + 4, &table_offset); + if (err != NO_ERROR) { + return err; + } + err = pci_read_config_word(loc(), cap_offset + 8, &pba_offset); + if (err != NO_ERROR) { + return err; + } + + // does the device support enough vectors? + if (num_requested > table_count) { + return ERR_NO_RESOURCES; + } + + // ask the platform for interrupts + uint vector_base; + err = platform_allocate_interrupts(num_requested, 0, true, &vector_base); + if (err != NO_ERROR) { + return err; + } + + // Compute what BARs we need to map and where + struct mapping { + explicit mapping(uint32_t offset_bar_word) { + bar = offset_bar_word & 0x3; + offset = offset_bar_word & ~0x3; + length = static_cast(offset_bar_word) * 16; + } + + uint8_t bar; + size_t offset; + size_t length; + }; + + mapping table_map(table_offset); + mapping pba_map(pba_offset); + TRACEF("table offset %#zx, bar %u\n", table_map.offset, table_map.bar); + TRACEF("pba offset %#zx, bar %u\n", pba_map.offset, pba_map.bar); + + auto map_it = [this, &err](mapping &map, void **ptr, bool readonly) -> status_t { +#if WITH_KERNEL_VM + const auto &bar = bars_[map.bar]; + if (!bar.valid || bar.io) { + printf("msi-x bar is not valid\n"); + return ERR_INVALID_ARGS; + } + + paddr_t base = ROUNDDOWN(map.offset, PAGE_SIZE); + size_t length = ROUNDUP(map.length + map.offset - base, PAGE_SIZE); + base += bar.addr; + + err = vmm_alloc_physical(vmm_get_kernel_aspace(), "pci msix var", length, ptr, 0, + base, /* vmm_flags */ 0, + ARCH_MMU_FLAG_UNCACHED_DEVICE | (readonly ? ARCH_MMU_FLAG_PERM_RO : 0)); + if (err != NO_ERROR) { + printf("error mapping msi-x bar\n"); + return err; + } + TRACEF("msi-x bar mapped at %p\n", *ptr); +#else + // no need to map, it's already available at the physical address + if (sizeof(void *) < 8 && (bars[i].addr + bars[i].size) > UINT32_MAX) { + TRACEF("aborting due to 64bit BAR on 32bit arch\n"); + return ERR_NO_MEMORY; + } + bar_map.vaddr = (uint8_t *)(uintptr_t)bars[i].addr; +#endif + return NO_ERROR; + }; + + err = map_it(table_map, &msix_table_map, false); + if (err != NO_ERROR) { + return err; + } + err = map_it(pba_map, &msix_pba_map, true); + if (err != NO_ERROR) { + return err; + } + + // compute the table pointers + msix_table_ptr = (volatile uint32_t *)((uintptr_t)msix_table_map + (table_map.offset - ROUNDDOWN(table_map.offset, PAGE_SIZE))); + msix_pba_ptr = (volatile uint32_t *)((uintptr_t)msix_pba_map + (pba_map.offset - ROUNDDOWN(pba_map.offset, PAGE_SIZE))); + + TRACEF("msix table %p, pba table %p\n", msix_table_ptr, msix_pba_ptr); + + // compute the MSI message to construct + uint64_t msi_address = 0; + uint16_t msi_data = 0; + err = platform_compute_msi_values(vector_base, 0, true, &msi_address, &msi_data); + if (err != NO_ERROR) { + // TODO: return the allocated msi + return err; + } + + // Mask all of the vectors + for (size_t i = 0; i < table_count; i++) { + msix_table_ptr[i * 4] = 0; + msix_table_ptr[i * 4 + 1] = 0; + msix_table_ptr[i * 4 + 2] = 0; + msix_table_ptr[i * 4 + 3] = 1; // masked + } + + // write the requested vectors + for (size_t i = 0; i < num_requested; i++) { + msix_table_ptr[i * 4] = msi_address; + msix_table_ptr[i * 4 + 1] = msi_address >> 32; + msix_table_ptr[i * 4 + 2] = msi_data; + msix_table_ptr[i * 4 + 3] = 0; // not masked + } + + // set up the control register and enable it + control |= (1<<15); // MSI-X enable, no functions masked + pci_write_config_half(loc(), cap_offset + 2, control); + + // write it back to the pci config in the interrupt line offset + pci_write_config_byte(loc(), PCI_CONFIG_INTERRUPT_LINE, vector_base); + + // pass back the allocated irq to the caller + *msi_base = vector_base; + + return NO_ERROR; +} + status_t device::load_bars() { size_t num_bars; diff --git a/dev/bus/pci/bus_mgr/device.h b/dev/bus/pci/bus_mgr/device.h index df2a6d576..80e33b74d 100644 --- a/dev/bus/pci/bus_mgr/device.h +++ b/dev/bus/pci/bus_mgr/device.h @@ -34,6 +34,7 @@ class device { status_t allocate_irq(uint *irq); status_t allocate_msi(size_t num_requested, uint *msi_base); + status_t allocate_msix(size_t num_requested, uint *msi_base); status_t load_config(); status_t load_bars(); @@ -112,6 +113,13 @@ class device { list_node capability_list_ = LIST_INITIAL_VALUE(capability_list_); capability *msi_cap_ = nullptr; capability *msix_cap_ = nullptr; + + // MSI-X saved details + uint32_t msix_table_size = {}; + void *msix_table_map = nullptr; + void *msix_pba_map = nullptr; + volatile uint32_t *msix_table_ptr = nullptr; + volatile uint32_t *msix_pba_ptr = nullptr; }; struct capability { diff --git a/dev/bus/pci/include/dev/bus/pci.h b/dev/bus/pci/include/dev/bus/pci.h index b99a05cea..4b3e8e991 100644 --- a/dev/bus/pci/include/dev/bus/pci.h +++ b/dev/bus/pci/include/dev/bus/pci.h @@ -95,6 +95,9 @@ status_t pci_bus_mgr_read_bars(const pci_location_t loc, pci_bar_t bar[6]); // try to allocate one or more msi vectors for this device status_t pci_bus_mgr_allocate_msi(const pci_location_t loc, size_t num_requested, uint *irqbase); +// try to allocate one or more msi-x vectors for this device +status_t pci_bus_mgr_allocate_msix(const pci_location_t loc, size_t num_requested, uint *irqbase); + // allocate a regular irq for this device and return it in irqbase status_t pci_bus_mgr_allocate_irq(const pci_location_t loc, uint *irqbase); diff --git a/dev/virtio/include/dev/virtio.h b/dev/virtio/include/dev/virtio.h index 3435c7933..b3d802b60 100644 --- a/dev/virtio/include/dev/virtio.h +++ b/dev/virtio/include/dev/virtio.h @@ -13,9 +13,13 @@ __BEGIN_CDECLS -/* detect a virtio mmio hardware block - * returns number of devices found */ +// Detect a virtio mmio hardware block. +// Returns number of devices found. int virtio_mmio_detect(void *ptr, uint count, const uint irqs[], size_t stride); +// Scan pci bus for virtio devices. Only implemented if PCI is present. +// Returns number of devices found. +int virtio_pci_init(void); + __END_CDECLS diff --git a/dev/virtio/net/virtio-net.cpp b/dev/virtio/net/virtio-net.cpp index 04dca5985..3b1013a03 100644 --- a/dev/virtio/net/virtio-net.cpp +++ b/dev/virtio/net/virtio-net.cpp @@ -23,7 +23,7 @@ #include #include -#define LOCAL_TRACE 0 +#define LOCAL_TRACE 1 struct virtio_net_config { uint8_t mac[6]; @@ -111,7 +111,7 @@ STATIC_ASSERT(sizeof(struct virtio_net_hdr) == 12); #define VIRTIO_NET_MSS 1514 struct virtio_net_dev { - struct virtio_device *dev; + virtio_device *dev; bool started; const virtio_net_config *config; @@ -127,12 +127,12 @@ struct virtio_net_dev { struct list_node completed_rx_queue; }; -static enum handler_return virtio_net_irq_driver_callback(struct virtio_device *dev, uint ring, const struct vring_used_elem *e); +static enum handler_return virtio_net_irq_driver_callback(virtio_device *dev, uint ring, const vring_used_elem *e); static int virtio_net_rx_worker(void *arg); -static status_t virtio_net_queue_rx(struct virtio_net_dev *ndev, pktbuf_t *p); +static status_t virtio_net_queue_rx(virtio_net_dev *ndev, pktbuf_t *p, bool do_kick = true); // XXX remove need for this -static struct virtio_net_dev *the_ndev; +static virtio_net_dev *the_ndev; static void dump_feature_bits(uint64_t feature) { printf("virtio-net host features (%#" PRIx64 "):", feature); @@ -202,19 +202,20 @@ status_t virtio_net_init(virtio_device *dev) { dev->set_irq_callbacks(&virtio_net_irq_driver_callback, nullptr); dev->bus()->unmask_interrupt(); - /* set DRIVER_OK */ - dev->bus()->virtio_status_driver_ok(); - /* allocate a pair of virtio rings */ dev->virtio_alloc_ring(RING_RX, RX_RING_SIZE); // rx dev->virtio_alloc_ring(RING_TX, TX_RING_SIZE); // tx + /* set DRIVER_OK */ + dev->bus()->virtio_status_driver_ok(); + the_ndev = ndev; return NO_ERROR; } status_t virtio_net_start(void) { + LTRACE_ENTRY; if (the_ndev->started) return ERR_ALREADY_STARTED; @@ -227,15 +228,17 @@ status_t virtio_net_start(void) { for (uint i = 0; i < RX_RING_SIZE - 1; i++) { pktbuf_t *p = pktbuf_alloc(); if (p) { - virtio_net_queue_rx(the_ndev, p); + virtio_net_queue_rx(the_ndev, p, false); } } + /* kick all at once */ + the_ndev->dev->bus()->virtio_kick(RING_RX); return NO_ERROR; } -static status_t virtio_net_queue_tx_pktbuf(struct virtio_net_dev *ndev, pktbuf_t *p2) { - struct virtio_device *vdev = ndev->dev; +static status_t virtio_net_queue_tx_pktbuf(virtio_net_dev *ndev, pktbuf_t *p2) { + virtio_device *vdev = ndev->dev; uint16_t i; pktbuf_t *p; @@ -247,13 +250,13 @@ static status_t virtio_net_queue_tx_pktbuf(struct virtio_net_dev *ndev, pktbuf_t return ERR_NO_MEMORY; /* point our header to the base of the first pktbuf */ - struct virtio_net_hdr *hdr = (virtio_net_hdr *)pktbuf_append(p, sizeof(struct virtio_net_hdr) - 2); + virtio_net_hdr *hdr = (virtio_net_hdr *)pktbuf_append(p, sizeof(virtio_net_hdr) - 2); memset(hdr, 0, p->dlen); spin_lock_saved_state_t state; spin_lock_irqsave(&ndev->lock, state); - struct vring_desc *desc = {}; + vring_desc *desc = {}; /* only queue if we have enough tx descriptors */ if (ndev->tx_pending_count + 2 <= TX_RING_SIZE) { @@ -301,7 +304,7 @@ static status_t virtio_net_queue_tx_pktbuf(struct virtio_net_dev *ndev, pktbuf_t } /* variant of the above function that copies the buffer into a pktbuf before sending */ -static status_t virtio_net_queue_tx(struct virtio_net_dev *ndev, const void *buf, size_t len) { +static status_t virtio_net_queue_tx(virtio_net_dev *ndev, const void *buf, size_t len) { DEBUG_ASSERT(ndev); DEBUG_ASSERT(buf); @@ -323,25 +326,25 @@ static status_t virtio_net_queue_tx(struct virtio_net_dev *ndev, const void *buf return err; } -static status_t virtio_net_queue_rx(struct virtio_net_dev *ndev, pktbuf_t *p) { - struct virtio_device *vdev = ndev->dev; +static status_t virtio_net_queue_rx(virtio_net_dev *ndev, pktbuf_t *p, bool do_kick) { + virtio_device *vdev = ndev->dev; DEBUG_ASSERT(ndev); DEBUG_ASSERT(p); /* point our header to the base of the pktbuf */ p->data = p->buffer; - struct virtio_net_hdr *hdr = (struct virtio_net_hdr *)p->data; - memset(hdr, 0, sizeof(struct virtio_net_hdr) - 2); + virtio_net_hdr *hdr = (virtio_net_hdr *)p->data; + memset(hdr, 0, sizeof(virtio_net_hdr) - 2); - p->dlen = sizeof(struct virtio_net_hdr) - 2 + VIRTIO_NET_MSS; + p->dlen = sizeof(virtio_net_hdr) - 2 + VIRTIO_NET_MSS; spin_lock_saved_state_t state; spin_lock_irqsave(&ndev->lock, state); /* allocate a chain of descriptors for our transfer */ uint16_t i; - struct vring_desc *desc = vdev->virtio_alloc_desc_chain(RING_RX, 1, &i); + vring_desc *desc = vdev->virtio_alloc_desc_chain(RING_RX, 1, &i); DEBUG_ASSERT(desc); /* shouldn't be possible not to have a descriptor ready */ /* save a pointer to our pktbufs for the irq handler to use */ @@ -357,15 +360,17 @@ static status_t virtio_net_queue_rx(struct virtio_net_dev *ndev, pktbuf_t *p) { vdev->virtio_submit_chain(RING_RX, i); /* kick it off */ - vdev->bus()->virtio_kick(RING_RX); + if (do_kick) { + vdev->bus()->virtio_kick(RING_RX); + } spin_unlock_irqrestore(&ndev->lock, state); return NO_ERROR; } -static enum handler_return virtio_net_irq_driver_callback(struct virtio_device *dev, uint ring, const struct vring_used_elem *e) { - struct virtio_net_dev *ndev = (struct virtio_net_dev *)dev->priv(); +static enum handler_return virtio_net_irq_driver_callback(virtio_device *dev, uint ring, const vring_used_elem *e) { + virtio_net_dev *ndev = (virtio_net_dev *)dev->priv(); LTRACEF("dev %p, ring %u, e %p, id %u, len %u\n", dev, ring, e, e->id, e->len); @@ -375,7 +380,7 @@ static enum handler_return virtio_net_irq_driver_callback(struct virtio_device * uint16_t i = e->id; for (;;) { int next; - struct vring_desc *desc = dev->virtio_desc_index_to_desc(ring, i); + vring_desc *desc = dev->virtio_desc_index_to_desc(ring, i); if (desc->flags & VRING_DESC_F_NEXT) { next = desc->next; @@ -395,7 +400,7 @@ static enum handler_return virtio_net_irq_driver_callback(struct virtio_device * LTRACEF("rx pktbuf %p filled\n", p); /* trim the pktbuf according to the written length in the used element descriptor */ - if (e->len > (sizeof(struct virtio_net_hdr) - 2 + VIRTIO_NET_MSS)) { + if (e->len > (sizeof(virtio_net_hdr) - 2 + VIRTIO_NET_MSS)) { TRACEF("bad used len on RX %u\n", e->len); p->dlen = 0; } else { @@ -431,7 +436,7 @@ static enum handler_return virtio_net_irq_driver_callback(struct virtio_device * } static int virtio_net_rx_worker(void *arg) { - struct virtio_net_dev *ndev = (struct virtio_net_dev *)arg; + virtio_net_dev *ndev = (virtio_net_dev *)arg; for (;;) { event_wait(&ndev->rx_event); @@ -451,7 +456,7 @@ static int virtio_net_rx_worker(void *arg) { LTRACEF("got packet len %u\n", p->dlen); /* process our packet */ - struct virtio_net_hdr *hdr = (virtio_net_hdr *)pktbuf_consume(p, sizeof(struct virtio_net_hdr) - 2); + virtio_net_hdr *hdr = (virtio_net_hdr *)pktbuf_consume(p, sizeof(virtio_net_hdr) - 2); if (hdr) { /* call up into the stack */ minip_rx_driver_callback(p); diff --git a/dev/virtio/virtio-device.cpp b/dev/virtio/virtio-device.cpp index 62c814b1e..e001299ab 100644 --- a/dev/virtio/virtio-device.cpp +++ b/dev/virtio/virtio-device.cpp @@ -25,7 +25,7 @@ #include "virtio_priv.h" -#define LOCAL_TRACE 0 +#define LOCAL_TRACE 1 void virtio_device::virtio_free_desc(uint ring_index, uint16_t desc_index) { LTRACEF("dev %p ring %u index %u free_count %u\n", this, ring_index, desc_index, ring_[ring_index].free_count); diff --git a/dev/virtio/virtio-pci-bus.cpp b/dev/virtio/virtio-pci-bus.cpp index e1946d652..0e7ce3813 100644 --- a/dev/virtio/virtio-pci-bus.cpp +++ b/dev/virtio/virtio-pci-bus.cpp @@ -26,8 +26,11 @@ #if WITH_DEV_VIRTIO_BLOCK #include #endif +#if WITH_DEV_VIRTIO_NET +#include +#endif -#define LOCAL_TRACE 0 +#define LOCAL_TRACE 1 #include @@ -39,19 +42,6 @@ struct virtio_pci_devices { status_t (*init)(pci_location_t loc, const virtio_pci_devices &dev_table_entry, size_t index); }; -static status_t init_block(pci_location_t loc, const virtio_pci_devices &dev_table_entry, size_t index); - -const virtio_pci_devices devices[] = { - { 0x1000, true, nullptr }, // transitional network - { 0x1001, true, &init_block }, // transitional block - { 0x1009, true, nullptr }, // legacy virtio 9p - { 0x1041, false, nullptr }, // non-transitional network - { 0x1042, false, &init_block }, // non-transitional block - { 0x1043, false, nullptr }, // non-transitional console - { 0x1050, false, nullptr }, // non-transitional gpu - { 0x1052, false, nullptr }, // non-transitional input -}; - struct virtio_pci_cap { uint8_t cap_vndr; uint8_t cap_next; @@ -190,12 +180,13 @@ void virtio_pci_bus::register_ring(uint32_t page_size, uint32_t queue_sel, uint3 ccfg->queue_select = queue_sel; LTRACEF("existing queue_size %u\n", ccfg->queue_size); - LTRACEF("existin notify off %u\n", ccfg->queue_notify_off); + LTRACEF("existing notify off %u\n", ccfg->queue_notify_off); ccfg->queue_size = queue_num; ccfg->queue_desc = ring_descriptor_paddr; ccfg->queue_driver = ring_available_paddr; ccfg->queue_device = ring_used_paddr; + ccfg->queue_msix_vector = 0; ccfg->queue_enable = 1; } @@ -208,7 +199,7 @@ handler_return virtio_pci_bus::virtio_pci_irq(void *arg) { LTRACEF("isr status register %p\n", isr_status); // reading status implicitly acks it and resets to 0 - uint32_t irq_status = *isr_status; + uint8_t irq_status = *isr_status; LTRACEF("status %#x\n", irq_status); enum handler_return ret = INT_NO_RESCHEDULE; @@ -217,7 +208,6 @@ handler_return virtio_pci_bus::virtio_pci_irq(void *arg) { if (_ret == INT_RESCHEDULE) { ret = _ret; } - } if (irq_status & 0x2) { /* config change */ auto _ret = bus->dev_->handle_config_interrupt(); @@ -345,7 +335,8 @@ status_t virtio_pci_bus::init(virtio_device *dev, pci_location_t loc, size_t ind } uint irq_base; - err = pci_bus_mgr_allocate_msi(loc_, 1, &irq_base); + // TODO: fall back to msi + err = pci_bus_mgr_allocate_msix(loc_, 1, &irq_base); if (err != NO_ERROR) { // fall back to regular IRQs err = pci_bus_mgr_allocate_irq(loc_, &irq_base); @@ -393,9 +384,50 @@ static status_t init_block(pci_location_t loc, const virtio_pci_devices &dev_tab #endif } -static void virtio_pci_init(uint level) { +static status_t init_net(pci_location_t loc, const virtio_pci_devices &dev_table_entry, size_t index) { LTRACE_ENTRY; +#if WITH_DEV_VIRTIO_NET + // create a virtio_pci_bus object and initialize it based on the location + auto *bus = new virtio_pci_bus(); + auto *dev = new virtio_device(bus); + + auto err = bus->init(dev, loc, index); + if (err != NO_ERROR) { + delete bus; + return err; + } + + // TODO: move the config pointer getter that devices use into the bus + dev->set_config_ptr(bus->device_config()); + + err = virtio_net_init(dev); + if (err != NO_ERROR) { + PANIC_UNIMPLEMENTED; + } + + return err; +#else + return ERR_NOT_FOUND; +#endif +} + + +int virtio_pci_init() { + LTRACE_ENTRY; + + constexpr virtio_pci_devices devices[] = { + { 0x1000, true, &init_net }, // transitional network + { 0x1001, true, &init_block }, // transitional block + { 0x1009, true, nullptr }, // legacy virtio 9p + { 0x1041, false, &init_net }, // non-transitional network + { 0x1042, false, &init_block }, // non-transitional block + { 0x1043, false, nullptr }, // non-transitional console + { 0x1050, false, nullptr }, // non-transitional gpu + { 0x1052, false, nullptr }, // non-transitional input + }; + + int count = 0; for (auto &dev: devices) { for (size_t i = 0; ; i++) { pci_location_t loc; @@ -409,15 +441,18 @@ static void virtio_pci_init(uint level) { // call the init routine if (dev.init) { - dev.init(loc, dev, i); + err = dev.init(loc, dev, i); + if (err != NO_ERROR) { + count++; + } } } } LTRACE_EXIT; -} -LK_INIT_HOOK(virtio_pci, &virtio_pci_init, LK_INIT_LEVEL_PLATFORM + 1); + return count; +} #endif diff --git a/platform/qemu-virt-arm/platform.c b/platform/qemu-virt-arm/platform.c index 018e973f5..92c625e20 100644 --- a/platform/qemu-virt-arm/platform.c +++ b/platform/qemu-virt-arm/platform.c @@ -93,8 +93,10 @@ void platform_init(void) { // assign resources to all devices in case they need it pci_bus_mgr_assign_resources(); - } + // scan for an initialize any virtio devices + virtio_pci_init(); + } /* detect any virtio devices */ uint virtio_irqs[NUM_VIRTIO_TRANSPORTS];