文章标题
来源:互联网 发布:wings上央视知乎 编辑:程序博客网 时间:2024/06/05 16:53
- Vring
struct vring { uint32_t num; struct vring_desc *desc; struct vring_avail *avail; struct vring_used *used;};struct vring_desc { /* Address (guest-physical). */ uint64_t addr; /* Length. */ uint32_t len; /* The flags as indicated above. */ uint16_t flags; /* We chain unused descriptors via this, too */ uint16_t next;};struct vring_avail { uint16_t flags; uint16_t idx; // ring[] 的index uint16_t ring[];};struct vring_used { uint16_t flags; uint16_t idx; // ring[] 的index struct vring_used_elem ring[];};/* u32 is used here for ids for padding reasons. */struct vring_used_elem { /* Index of start of used descriptor chain. */ uint32_t id; /* Total length of the descriptor chain which was used (written to) */ uint32_t len;};struct XX_virtqueue { uint32_t id; uint32_t to_host_event; uint32_t from_host_event; uint16_t last_avail_idx; //第一个vring_avail中ring【】可用的索引。 struct vring vring;};static inline int virtqueue_add(struct virtqueue *_vq, struct scatterlist *sgs[], unsigned int total_sg, unsigned int out_sgs, unsigned int in_sgs, void *data, gfp_t gfp, bool rpmsg){ struct vring_virtqueue *vq = to_vvq(_vq); struct scatterlist *sg; struct vring_desc *desc; unsigned int i, n, avail, descs_used, uninitialized_var(prev); int head; bool indirect; START_USE(vq); BUG_ON(data == NULL); if (unlikely(vq->broken)) { END_USE(vq); return -EIO; } BUG_ON(total_sg > vq->vring.num); BUG_ON(total_sg == 0); /* free_head 是desc[] 数组的索引(类似于模拟的链表), 表示free 的desc 的 的第一个索引. */ head = vq->free_head; /* If the host supports indirect descriptor tables, and we have multiple * buffers, then go indirect. FIXME: tune this threshold */ if (!rpmsg && vq->indirect && total_sg > 1 && vq->vq.num_free) desc = alloc_indirect(_vq, total_sg, gfp); // 间接分配描述符 else desc = NULL; if (desc) { /* Use a single buffer which doesn't continue */ vq->vring.desc[head].flags = cpu_to_virtio16(_vq->vdev, VRING_DESC_F_INDIRECT); vq->vring.desc[head].addr = cpu_to_virtio64(_vq->vdev, virt_to_phys(desc)); /* avoid kmemleak false positive (hidden by virt_to_phys) */ kmemleak_ignore(desc); vq->vring.desc[head].len = cpu_to_virtio32(_vq->vdev, total_sg * sizeof(struct vring_desc)); /* Set up rest to use this indirect table. */ i = 0; descs_used = 1; indirect = true; } else { desc = vq->vring.desc; i = head; // free desc head descs_used = total_sg; // total used sg indirect = false; } if (vq->vq.num_free < descs_used) { pr_debug("Can't add buf len %i - avail = %i\n", descs_used, vq->vq.num_free); /* FIXME: for historical reasons, we force a notify here if * there are outgoing parts to the buffer. Presumably the * host should service the ring ASAP. */ if (out_sgs) vq->notify(&vq->vq); END_USE(vq); return -ENOSPC; } /* We're about to use some buffers from the free list. */ vq->vq.num_free -= descs_used; // remove the used from num_free for (n = 0; n < out_sgs; n++) { for (sg = sgs[n]; sg; sg = sg_next(sg)) { vring_desc_set(_vq->vdev, desc + i, sg, VRING_DESC_F_NEXT, rpmsg); prev = i; /* desc 使用next 成员链接起来 */ i = virtio16_to_cpu(_vq->vdev, desc[i].next); } } for (; n < (out_sgs + in_sgs); n++) { for (sg = sgs[n]; sg; sg = sg_next(sg)) { vring_desc_set(_vq->vdev, desc + i, sg, VRING_DESC_F_NEXT | VRING_DESC_F_WRITE, rpmsg); prev = i; i = virtio16_to_cpu(_vq->vdev, desc[i].next); } } // 获取使用的desc 的索引; /* Last one doesn't continue. 将使用的最后一个索引的.next 成员设置为NULL, 因为其后面没有了。 */ desc[prev].flags &= cpu_to_virtio16(_vq->vdev, ~VRING_DESC_F_NEXT); /* Update free pointer */ if (indirect) vq->free_head = virtio16_to_cpu(_vq->vdev, vq->vring.desc[head].next); else vq->free_head = i; // 重新标记free_head 的索引, 因为已经使用到i了。 /* Set token. */ vq->data[head] = data; /* Put entry in available array (but don't update avail->idx until they * do sync). */ avail = vq->avail_idx_shadow & (vq->vring.num - 1); vq->vring.avail->ring[avail] = cpu_to_virtio16(_vq->vdev, head); // 更新vring.avail->ring 中第一个可用的ring 结构,为其填入 可用的desc 的head。 /* Descriptors and available array need to be set before we expose the * new available array entries. */ virtio_wmb(vq->weak_barriers); vq->avail_idx_shadow++; vq->vring.avail->idx = cpu_to_virtio16(_vq->vdev, vq->avail_idx_shadow); // 更新vring.avail->idx +1; vq->num_added++; pr_debug("Added buffer head %i to %p\n", head, vq); END_USE(vq); /* This is very unlikely, but theoretically possible. Kick * just in case. */ if (unlikely(vq->num_added == (1 << 16) - 1)) virtqueue_kick(_vq); return 0;}
0 0
- 文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题 文章标题 文章标题 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- Test
- yum本地源配置
- C++学习笔记
- Servlet表单
- laravel框架帮助函数
- 文章标题
- 白宫聊天机器人开源啦!
- 120 mongodb collections vs single collection - which one is more efficient?
- Android 推送 整合小米、个推、jpush
- ImageLoader 详解
- Fiddler 对Android APP 抓包
- SLua在Unity5.4版本报错
- 反编译python的pyc/pyo字节码文件
- 书籍-传承至今的智慧载体