Virtio headers are moved to zephyr/drivers/ as they have no reason to be top-level headers since virtio is a driver class. Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
72 lines
2.1 KiB
C
72 lines
2.1 KiB
C
/*
|
|
* Copyright (c) 2025 Antmicro <www.antmicro.com>
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr/logging/log.h>
|
|
#include <zephyr/sys/byteorder.h>
|
|
#include <zephyr/drivers/virtio.h>
|
|
#include <zephyr/drivers/virtio/virtqueue.h>
|
|
#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");
|
|
}
|
|
}
|