文章标题

  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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值