/* * Copyright (c) 2025 Antmicro * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include "virtio_common.h" LOG_MODULE_REGISTER(virtio_common, CONFIG_VIRTIO_LOG_LEVEL); void virtio_isr(const struct device *dev, uint8_t isr_status, uint16_t virtqueue_count) { if (isr_status & VIRTIO_QUEUE_INTERRUPT) { for (int i = 0; i < virtqueue_count; i++) { struct virtq *vq = virtio_get_virtqueue(dev, i); uint16_t used_idx = sys_le16_to_cpu(vq->used->idx); while (vq->last_used_idx != used_idx) { uint16_t idx = vq->last_used_idx % vq->num; uint16_t idx_le = sys_cpu_to_le16(idx); uint16_t chain_head_le = vq->used->ring[idx_le].id; uint16_t chain_head = sys_le16_to_cpu(chain_head_le); uint32_t used_len = sys_le32_to_cpu( vq->used->ring[idx_le].len ); /* * We are making a copy here, because chain will be * returned before invoking the callback and may be * overwritten by the time callback is called. This * is to allow callback to immediately place the * descriptors back in the avail_ring */ struct virtq_receive_callback_entry cbe = vq->recv_cbs[chain_head]; uint16_t next = chain_head; bool last = false; /* * We are done processing the descriptor chain, and * we can add used descriptors back to the free stack. * The only thing left to do is calling the callback * associated with the chain, but it was saved above on * the stack, so other code is free to use the descriptors */ while (!last) { uint16_t curr = next; uint16_t curr_le = sys_cpu_to_le16(curr); next = vq->desc[curr_le].next; last = !(vq->desc[curr_le].flags & VIRTQ_DESC_F_NEXT); virtq_add_free_desc(vq, curr); } vq->last_used_idx++; if (cbe.cb) { cbe.cb(cbe.opaque, used_len); } } } } if (isr_status & VIRTIO_DEVICE_CONFIGURATION_INTERRUPT) { LOG_ERR("device configuration change interrupt is currently unsupported"); } }