文章标题

来源:互联网 发布:wings上央视知乎 编辑:程序博客网 时间:2024/06/05 16:53
  1. 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
原创粉丝点击