On 15/01/18 15:12, Auger Eric wrote:
[...]
>> +/*
>> + * viommu_get_req_size - compute request size
>> + *
>> + * A virtio-iommu request is split into one device-read-only part (top) and
>> one
>> + * device-write-only part (bottom). Given a request, return the sizes of
>> the two
>> + * parts in @top and @bottom.
> for all but virtio_iommu_req_probe, which has a variable bottom size
The comment still stands for the probe request, viommu_get_req_size will
return @bottom depending on viommu->probe_size.
[...]
>> +/* Must be called with request_lock held */
>> +static int _viommu_send_reqs_sync(struct viommu_dev *viommu,
>> + struct viommu_request *req, int nr,
>> + int *nr_sent)
>> +{
>> +int i, ret;
>> +ktime_t timeout;
>> +LIST_HEAD(pending);
>> +int nr_received = 0;
>> +struct scatterlist *sg[2];
>> +/*
>> + * Yes, 1s timeout. As a guest, we don't necessarily have a precise
>> + * notion of time and this just prevents locking up a CPU if the device
>> + * dies.
>> + */
>> +unsigned long timeout_ms = 1000;
>> +
>> +*nr_sent = 0;
>> +
>> +for (i = 0; i < nr; i++, req++) {
>> +req->written = 0;
>> +
>> +sg[0] = >top;
>> +sg[1] = >bottom;
>> +
>> +ret = virtqueue_add_sgs(viommu->vq, sg, 1, 1, req,
>> +GFP_ATOMIC);
>> +if (ret)
>> +break;
>> +
>> +list_add_tail(>list, );
>> +}
>> +
>> +if (i && !virtqueue_kick(viommu->vq))
>> +return -EPIPE;
>> +
>> +timeout = ktime_add_ms(ktime_get(), timeout_ms * i);
> I don't really understand how you choose your timeout value: 1s per sent
> request.
1s isn't a good timeout value, but I don't know what's good. In a
prototype I have, even 1s isn't enough. The attach request (for nested
mode) requires my device to pin down the whole guest memory, and the guest
ends up timing out on the fastmodel because the request takes too long and
the model timer runs too fast...
I was tempted to simply remove this timeout, but I still think having a
way out when the host device fails is preferable. Otherwise this
completely locks up the CPU.
>> +while (nr_received < i && ktime_before(ktime_get(), timeout)) {
>> +nr_received += viommu_receive_resp(viommu, i - nr_received,
>> + );
>> +if (nr_received < i) {
>> +/*
>> + * FIXME: what's a good way to yield to host? A second
>> + * virtqueue_kick won't have any effect since we haven't
>> + * added any descriptor.
>> + */
>> +udelay(10);
> could you explain why udelay gets used here?
I was hoping this could switch to the host quicker than cpu_relax(),
allowing it to handle the request faster (on ARM udelay could do WFE
instead of YIELD). The value is completely arbitrary.
Maybe I can replace this with cpu_relax for now. I'd like to refine this
function anyway when working on performance improvements, but I'm not too
hopeful we'll get something nicer here.
[...]
>> +/*
>> + * viommu_send_req_sync - send one request and wait for reply
>> + *
>> + * @top: pointer to a virtio_iommu_req_* structure
>> + *
>> + * Returns 0 if the request was successful, or an error number otherwise. No
>> + * distinction is done between transport and request errors.
>> + */
>> +static int viommu_send_req_sync(struct viommu_dev *viommu, void *top)
>> +{
>> +int ret;
>> +int nr_sent;
>> +void *bottom;
>> +struct viommu_request req = {0};
> ^
> drivers/iommu/virtio-iommu.c:326:9: warning: (near initialization for
> ‘req.top’) [-Wmissing-braces]
Ok
[...]
>> +/*
>> + * viommu_del_mappings - remove mappings from the internal tree
>> + *
>> + * @vdomain: the domain
>> + * @iova: start of the range
>> + * @size: size of the range. A size of 0 corresponds to the entire address
>> + * space.
>> + * @out_mapping: if not NULL, the first removed mapping is returned in
>> there.
>> + * This allows the caller to reuse the buffer for the unmap request. Caller
>> + * must always free the returned mapping, whether the function succeeds or
>> + * not.
> if unmapped > 0?
Ok
>> + *
>> + * On success, returns the number of unmapped bytes (>= size)
>> + */
>> +static size_t viommu_del_mappings(struct viommu_domain *vdomain,
>> + unsigned long iova, size_t size,
>> + struct viommu_mapping **out_mapping)
>> +{
>> +size_t unmapped = 0;
>> +unsigned long flags;
>> +unsigned long last = iova + size - 1;
>> +struct viommu_mapping *mapping = NULL;
>> +struct interval_tree_node *node, *next;
>> +
>> +spin_lock_irqsave(>mappings_lock, flags);
>> +next = interval_tree_iter_first(>mappings, iova, last);
>> +
>> +if (next)