void VirtioBlk::irq_handler() { debug2("<VirtioBlk> IRQ handler\n"); //Virtio Std. § 4.1.5.5, steps 1-3 // Step 1. read ISR unsigned char isr = hw::inp(iobase() + VIRTIO_PCI_ISR); // Step 2. A) - one of the queues have changed if (isr & 1) { // This now means service RX & TX interchangeably service_RX(); } // Step 2. B) if (isr & 2) { debug("\t <VirtioBlk> Configuration change:\n"); // Getting the MAC + status //debug("\t Old status: 0x%x\n", config.status); get_config(); //debug("\t New status: 0x%x \n", config.status); } }
VirtioBlk::VirtioBlk(hw::PCI_Device& d) : Virtio(d), hw::Drive(), req(queue_size(0), 0, iobase()), inflight(0) { INFO("VirtioBlk", "Driver initializing"); { auto& reqs = Statman::get().create( Stat::UINT32, blkname() + ".requests"); this->requests = &reqs.get_uint32(); *this->requests = 0; auto& err = Statman::get().create( Stat::UINT32, blkname() + ".errors"); this->errors = &err.get_uint32(); *this->errors = 0; } uint32_t needed_features = FEAT(VIRTIO_BLK_F_BLK_SIZE); negotiate_features(needed_features); CHECK(features() & FEAT(VIRTIO_BLK_F_BARRIER), "Barrier is enabled"); CHECK(features() & FEAT(VIRTIO_BLK_F_SIZE_MAX), "Size-max is known"); CHECK(features() & FEAT(VIRTIO_BLK_F_SEG_MAX), "Seg-max is known"); CHECK(features() & FEAT(VIRTIO_BLK_F_GEOMETRY), "Geometry structure is used"); CHECK(features() & FEAT(VIRTIO_BLK_F_RO), "Device is read-only"); CHECK(features() & FEAT(VIRTIO_BLK_F_BLK_SIZE), "Block-size is known"); CHECK(features() & FEAT(VIRTIO_BLK_F_SCSI), "SCSI is enabled :("); CHECK(features() & FEAT(VIRTIO_BLK_F_FLUSH), "Flush enabled"); CHECK ((features() & needed_features) == needed_features, "Negotiated needed features"); // Step 1 - Initialize REQ queue auto success = assign_queue(0, (uint32_t) req.queue_desc()); CHECK(success, "Request queue assigned (0x%x) to device", (uint32_t) req.queue_desc()); // Step 3 - Fill receive queue with buffers // DEBUG: Disable INFO("VirtioBlk", "Queue size: %i\tRequest size: %u\n", req.size(), sizeof(request_t)); // Get device configuration get_config(); // Signal setup complete. setup_complete((features() & needed_features) == needed_features); CHECK((features() & needed_features) == needed_features, "Signalled driver OK"); // Hook up IRQ handler (inherited from Virtio) if (is_msix()) { // update IRQ subscriptions IRQ_manager::get().subscribe(irq() + 0, {this, &VirtioBlk::service_RX}); IRQ_manager::get().subscribe(irq() + 1, {this, &VirtioBlk::msix_conf_handler}); } else { auto del(delegate<void()>{this, &VirtioBlk::irq_handler}); IRQ_manager::get().subscribe(irq(), del); } // Done INFO("VirtioBlk", "Block device with %llu sectors capacity", config.capacity); }
bool Virtio::assign_queue(uint16_t index, uint32_t queue_desc){ hw::outpw(iobase() + VIRTIO_PCI_QUEUE_SEL, index); hw::outpd(iobase() + VIRTIO_PCI_QUEUE_PFN, OS::page_nr_from_addr(queue_desc)); return hw::inpd(iobase() + VIRTIO_PCI_QUEUE_PFN) == OS::page_nr_from_addr(queue_desc); }
uint32_t Virtio::queue_size(uint16_t index){ hw::outpw(iobase() + VIRTIO_PCI_QUEUE_SEL, index); return hw::inpw(iobase() + VIRTIO_PCI_QUEUE_SIZE); }