|
| 1 | +/* |
| 2 | + * Copyright (c) 2025 Antmicro <www.antmicro.com> |
| 3 | + * |
| 4 | + * SPDX-License-Identifier: Apache-2.0 |
| 5 | + */ |
| 6 | + |
| 7 | +#include <zephyr/logging/log.h> |
| 8 | +#include <zephyr/sys/byteorder.h> |
| 9 | +#include <zephyr/virtio/virtio.h> |
| 10 | +#include <zephyr/virtio/virtqueue.h> |
| 11 | +#include "virtio_common.h" |
| 12 | + |
| 13 | +LOG_MODULE_REGISTER(virtio_common, CONFIG_VIRTIO_LOG_LEVEL); |
| 14 | + |
| 15 | +void virtio_isr(const struct device *dev, uint8_t isr_status, uint16_t virtqueue_count) |
| 16 | +{ |
| 17 | + if (isr_status & VIRTIO_QUEUE_INTERRUPT) { |
| 18 | + for (int i = 0; i < virtqueue_count; i++) { |
| 19 | + struct virtq *vq = virtio_get_virtqueue(dev, i); |
| 20 | + uint16_t used_idx = sys_le16_to_cpu(vq->used->idx); |
| 21 | + |
| 22 | + while (vq->last_used_idx != used_idx) { |
| 23 | + uint16_t idx = vq->last_used_idx % vq->num; |
| 24 | + uint16_t idx_le = sys_cpu_to_le16(idx); |
| 25 | + uint16_t chain_head_le = vq->used->ring[idx_le].id; |
| 26 | + uint16_t chain_head = sys_le16_to_cpu(chain_head_le); |
| 27 | + uint32_t used_len = sys_le32_to_cpu( |
| 28 | + vq->used->ring[idx_le].len |
| 29 | + ); |
| 30 | + |
| 31 | + /* |
| 32 | + * We are making a copy here, because chain will be |
| 33 | + * returned before invoking the callback and may be |
| 34 | + * overwritten by the time callback is called. This |
| 35 | + * is to allow callback to immediately place the |
| 36 | + * descriptors back in the avail_ring |
| 37 | + */ |
| 38 | + struct virtq_receive_callback_entry cbe = |
| 39 | + vq->recv_cbs[chain_head]; |
| 40 | + |
| 41 | + uint16_t next = chain_head; |
| 42 | + bool last = false; |
| 43 | + |
| 44 | + /* |
| 45 | + * We are done processing the descriptor chain, and |
| 46 | + * we can add used descriptors back to the free stack. |
| 47 | + * The only thing left to do is calling the callback |
| 48 | + * associated with the chain, but it was saved above on |
| 49 | + * the stack, so other code is free to use the descriptors |
| 50 | + */ |
| 51 | + while (!last) { |
| 52 | + uint16_t curr = next; |
| 53 | + uint16_t curr_le = sys_cpu_to_le16(curr); |
| 54 | + |
| 55 | + next = vq->desc[curr_le].next; |
| 56 | + last = !(vq->desc[curr_le].flags & VIRTQ_DESC_F_NEXT); |
| 57 | + virtq_add_free_desc(vq, curr); |
| 58 | + } |
| 59 | + |
| 60 | + vq->last_used_idx++; |
| 61 | + |
| 62 | + if (cbe.cb) { |
| 63 | + cbe.cb(cbe.opaque, used_len); |
| 64 | + } |
| 65 | + } |
| 66 | + } |
| 67 | + } |
| 68 | + if (isr_status & VIRTIO_DEVICE_CONFIGURATION_INTERRUPT) { |
| 69 | + LOG_ERR("device configuration change interrupt is currently unsupported"); |
| 70 | + } |
| 71 | +} |
0 commit comments