msi-x for virtio block device
This commit is contained in:
parent
255e24fa6b
commit
513fb8a813
5 changed files with 20 additions and 31 deletions
|
|
@ -150,7 +150,6 @@ struct msix_table_entry {
|
|||
uint32_t control;
|
||||
};
|
||||
// only uses first table entry
|
||||
bool msix_cap_configure(struct bdf bdf, uint8_t cap_offset, uint64_t addr, uint32_t msg,
|
||||
struct msix_table_entry **table_out, uint64_t **pba_out);
|
||||
bool msix_cap_configure(struct bdf bdf, uint8_t cap_offset, uint64_t addr, uint32_t msg);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -91,7 +91,6 @@ struct virtio_blk_context {
|
|||
struct virtq_avail *avail;
|
||||
struct virtq_used *used;
|
||||
volatile le16 *queue0_notify_location;
|
||||
volatile uint8_t *interrupt_byte;
|
||||
struct queued_op *request_head;
|
||||
};
|
||||
#define VIRTIO_BLK_NOTIFY(ctx) do { (ctx).queue0_notify_location->value = 0; } while (0)
|
||||
|
|
|
|||
|
|
@ -178,4 +178,6 @@ void virtio_descriptor_fill(struct virtq_desc *desc, uint64_t addr, uint32_t len
|
|||
// TODO interface without making it device visible, for bulk submission
|
||||
void virtio_avail_queue_add(struct virtq_avail *avail, uint16_t desc_idx);
|
||||
|
||||
#define VIRTIO_MSI_NO_VECTOR 0xffff
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -262,9 +262,9 @@ msi_cap_configure(struct bdf bdf, uint8_t cap_offset, unsigned icount, uint64_t
|
|||
|
||||
#define MSIX_VECTOR_ENABLE(entry) do { entry.control &= ~1u; } while (0)
|
||||
|
||||
bool msix_cap_configure(struct bdf bdf, uint8_t cap_offset, uint64_t addr, uint32_t msg,
|
||||
struct msix_table_entry **table_out, uint64_t **pba_out)
|
||||
{
|
||||
// TODO do we want more than 1 vector? 1 for queues and 1 for config?
|
||||
// TODO do we want to read the pending bits later?
|
||||
bool msix_cap_configure(struct bdf bdf, uint8_t cap_offset, uint64_t addr, uint32_t msg) {
|
||||
if (cap_offset == 0) return false;
|
||||
uint32_t dword0 = pci_config_read_u32(bdf, cap_offset);
|
||||
uint32_t dword1 = pci_config_read_u32(bdf, cap_offset + 4);
|
||||
|
|
@ -292,8 +292,5 @@ bool msix_cap_configure(struct bdf bdf, uint8_t cap_offset, uint64_t addr, uint3
|
|||
dword0 = (dword0 & 0xFFFFu) | ((uint32_t)control << 16);
|
||||
pci_config_write_u32(bdf, cap_offset, dword0);
|
||||
|
||||
*table_out = table;
|
||||
*pba_out = pba;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,20 +15,16 @@ void virtio_blk_device_init(struct bdf bdf, struct virtio_blk_context *ctx) {
|
|||
ASSERT(virtio_dev_is_of_kind(bdf, VIRTIO_DEV_KIND_BLOCK));
|
||||
ASSERT(pci_config_read_u8(bdf, PCI_HEADER_HEADER_TYPE) == 0); // expect endpoint
|
||||
|
||||
struct virtio_cap cap_common, cap_notify, cap_device, cap_isr;
|
||||
struct virtio_cap cap_common, cap_notify, cap_device;
|
||||
ASSERT(virtio_find_cap_of_type(bdf, VIRTIO_PCI_CAP_COMMON_CFG, &cap_common));
|
||||
ASSERT(virtio_find_cap_of_type(bdf, VIRTIO_PCI_CAP_NOTIFY_CFG, &cap_notify));
|
||||
ASSERT(virtio_find_cap_of_type(bdf, VIRTIO_PCI_CAP_DEVICE_CFG, &cap_device));
|
||||
ASSERT(virtio_find_cap_of_type(bdf, VIRTIO_PCI_CAP_ISR_CFG, &cap_isr));
|
||||
struct pci_bar bar = pci_config_get_bar(bdf, cap_common.barno);
|
||||
struct pa pa = pa_from_value(bar.base_address + cap_common.offset);
|
||||
volatile struct virtio_pci_common_cfg *cfg = pa_to_pointer(pa);
|
||||
bar = pci_config_get_bar(bdf, cap_device.barno);
|
||||
pa = pa_from_value(bar.base_address + cap_device.offset);
|
||||
volatile struct virtio_blk_config *dev_cfg = pa_to_pointer(pa);
|
||||
bar = pci_config_get_bar(bdf, cap_isr.barno);
|
||||
pa = pa_from_value(bar.base_address + cap_isr.offset);
|
||||
volatile uint8_t *interrupt_byte = pa_to_pointer(pa);
|
||||
|
||||
// TODO read configuration correctly (make sure `generation` doesn't change; p.24)
|
||||
uint8_t wanted_status = 0;
|
||||
|
|
@ -115,6 +111,13 @@ void virtio_blk_device_init(struct bdf bdf, struct virtio_blk_context *ctx) {
|
|||
cfg->queue_enable = CPU_TO_LE16(1);
|
||||
ASSERT(LE16_TO_CPU(cfg->queue_enable));
|
||||
|
||||
// use MSIX vector 0
|
||||
cfg->config_msix_vector = CPU_TO_LE16(0);
|
||||
ASSERT(LE16_TO_CPU(cfg->config_msix_vector) == 0);
|
||||
// TODO if we have more than 1 queue we need to set this for every queue
|
||||
cfg->queue_msix_vector = CPU_TO_LE16(0);
|
||||
ASSERT(LE16_TO_CPU(cfg->queue_msix_vector) == 0);
|
||||
|
||||
// finish device initialization
|
||||
wanted_status |= VIRTIO_DEV_STATUS_DRIVER_OK;
|
||||
virtio_cfg_set_status(cfg, wanted_status);
|
||||
|
|
@ -128,7 +131,6 @@ void virtio_blk_device_init(struct bdf bdf, struct virtio_blk_context *ctx) {
|
|||
ctx->avail = ppn_to_pointer(queue_driver_ppn);
|
||||
ctx->used = ppn_to_pointer(queue_device_ppn);
|
||||
ctx->queue0_notify_location = queue0_notify_location;
|
||||
ctx->interrupt_byte = interrupt_byte;
|
||||
ctx->request_head = NULL;
|
||||
}
|
||||
|
||||
|
|
@ -173,23 +175,17 @@ unsigned virtio_blk_init(void) {
|
|||
printlinef(" cap %d (0x%x)", id, id);
|
||||
}
|
||||
|
||||
uint8_t msi_cap_offset = pci_find_cap_by_id(bdf, PCI_CAP_ID_MSI);
|
||||
uint64_t msi_addr = MSI_MAKE_ADDRESS(lapic_id);
|
||||
uint32_t msi_data = MSI_MAKE_MESSAGE(VIRTIO_INTERRUPT_VECTOR_BASE + num_devices);
|
||||
bool msi_enabled = msi_cap_configure(bdf, msi_cap_offset, 1, msi_addr, msi_data);
|
||||
|
||||
if (msi_enabled) {
|
||||
uint8_t msix_cap_offset = pci_find_cap_by_id(bdf, PCI_CAP_ID_MSIX);
|
||||
bool msix_enabled = msix_cap_configure(bdf, msix_cap_offset, msi_addr, msi_data);
|
||||
if (msix_enabled) {
|
||||
virtio_blk_device_init(bdf, &virtio_blk_devices[num_devices]);
|
||||
num_devices++;
|
||||
printlinef("initialized virtio block device %x with msi-x", pci_bdf_pack(bdf));
|
||||
} else {
|
||||
uint8_t msix_cap_offset = pci_find_cap_by_id(bdf, PCI_CAP_ID_MSIX);
|
||||
bool msix_enabled = msix_cap_configure(bdf, msix_cap_offset);
|
||||
if (msix_enabled) {
|
||||
virtio_blk_device_init(bdf, &virtio_blk_devices[num_devices]);
|
||||
num_devices++;
|
||||
} else {
|
||||
printlinef("could not enable msi or msi-x for %x, skip", pci_bdf_pack(bdf));
|
||||
}
|
||||
printlinef("could not enable msi-x for %x, skip", pci_bdf_pack(bdf));
|
||||
}
|
||||
}
|
||||
return num_devices;
|
||||
|
|
@ -223,11 +219,7 @@ static struct queued_op *find_queued(struct virtio_blk_context *ctx, uint16_t de
|
|||
|
||||
void virtio_blk_on_used_notif(struct virtio_blk_context *ctx) {
|
||||
ASSERT(slab_cache_initialized);
|
||||
// read interrupt byte to clear it
|
||||
uint8_t interrupt_status = *ctx->interrupt_byte;
|
||||
if (interrupt_status & 2) TODO(); // configuration change
|
||||
// we don't check if bit 1 (interrupt) is set; simply move through our queue.
|
||||
// we will notice if there is work or not.
|
||||
|
||||
while (ctx->used_idx_to_handle < LE16_TO_CPU(ctx->used->idx)) {
|
||||
// TODO overflow?
|
||||
struct virtq_used_elem *used_elem = ctx->used->ring + ctx->used_idx_to_handle;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue