--- zzzz-none-000/linux-3.10.107/drivers/remoteproc/remoteproc_virtio.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/remoteproc/remoteproc_virtio.c 2021-02-04 17:41:59.000000000 +0000 @@ -30,7 +30,7 @@ #include "remoteproc_internal.h" /* kick the remote processor, and let it know which virtqueue to poke at */ -static void rproc_virtio_notify(struct virtqueue *vq) +static bool rproc_virtio_notify(struct virtqueue *vq) { struct rproc_vring *rvring = vq->priv; struct rproc *rproc = rvring->rvdev->rproc; @@ -39,6 +39,7 @@ dev_dbg(&rproc->dev, "kicking vq index: %d\n", notifyid); rproc->ops->kick(rproc, notifyid); + return true; } /** @@ -68,17 +69,19 @@ EXPORT_SYMBOL(rproc_vq_interrupt); static struct virtqueue *rp_find_vq(struct virtio_device *vdev, - unsigned id, + unsigned int id, void (*callback)(struct virtqueue *vq), - const char *name) + const char *name, bool ctx) { struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); struct rproc *rproc = vdev_to_rproc(vdev); struct device *dev = &rproc->dev; + struct rproc_mem_entry *mem; struct rproc_vring *rvring; + struct fw_rsc_vdev *rsc; struct virtqueue *vq; void *addr; - int len, size, ret; + int len, size; /* we're temporarily limited to two virtqueues per rvdev */ if (id >= ARRAY_SIZE(rvdev->vring)) @@ -87,27 +90,29 @@ if (!name) return NULL; - ret = rproc_alloc_vring(rvdev, id); - if (ret) - return ERR_PTR(ret); + /* Search allocated memory region by name */ + mem = rproc_find_carveout_by_name(rproc, "vdev%dvring%d", rvdev->index, + id); + if (!mem || !mem->va) + return ERR_PTR(-ENOMEM); rvring = &rvdev->vring[id]; - addr = rvring->va; + addr = mem->va; len = rvring->len; /* zero vring */ size = vring_size(len, rvring->align); memset(addr, 0, size); - dev_dbg(dev, "vring%d: va %p qsz %d notifyid %d\n", - id, addr, len, rvring->notifyid); + dev_dbg(dev, "vring%d: va %pK qsz %d notifyid %d\n", + id, addr, len, rvring->notifyid); /* * Create the new vq, and tell virtio we're not interested in * the 'weak' smp barriers, since we're talking with a real device. */ - vq = vring_new_virtqueue(id, len, rvring->align, vdev, false, addr, - rproc_virtio_notify, callback, name); + vq = vring_new_virtqueue(id, len, rvring->align, vdev, false, ctx, + addr, rproc_virtio_notify, callback, name); if (!vq) { dev_err(dev, "vring_new_virtqueue %s failed\n", name); rproc_free_vring(rvring); @@ -117,6 +122,10 @@ rvring->vq = vq; vq->priv = rvring; + /* Update vring in resource table */ + rsc = (void *)rproc->table_ptr + rvdev->rsc_offset; + rsc->vring[id].da = mem->da; + return vq; } @@ -129,43 +138,37 @@ rvring = vq->priv; rvring->vq = NULL; vring_del_virtqueue(vq); - rproc_free_vring(rvring); } } static void rproc_virtio_del_vqs(struct virtio_device *vdev) { - struct rproc *rproc = vdev_to_rproc(vdev); - - /* power down the remote processor before deleting vqs */ - rproc_shutdown(rproc); - __rproc_virtio_del_vqs(vdev); } -static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs, - struct virtqueue *vqs[], - vq_callback_t *callbacks[], - const char *names[]) +static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned int nvqs, + struct virtqueue *vqs[], + vq_callback_t *callbacks[], + const char * const names[], + const bool * ctx, + struct irq_affinity *desc) { - struct rproc *rproc = vdev_to_rproc(vdev); - int i, ret; + int i, ret, queue_idx = 0; for (i = 0; i < nvqs; ++i) { - vqs[i] = rp_find_vq(vdev, i, callbacks[i], names[i]); + if (!names[i]) { + vqs[i] = NULL; + continue; + } + + vqs[i] = rp_find_vq(vdev, queue_idx++, callbacks[i], names[i], + ctx ? ctx[i] : false); if (IS_ERR(vqs[i])) { ret = PTR_ERR(vqs[i]); goto error; } } - /* now that the vqs are all set, boot the remote processor */ - ret = rproc_boot(rproc); - if (ret) { - dev_err(&rproc->dev, "rproc_boot() failed %d\n", ret); - goto error; - } - return 0; error: @@ -206,7 +209,7 @@ } /* provide the vdev features as retrieved from the firmware */ -static u32 rproc_virtio_get_features(struct virtio_device *vdev) +static u64 rproc_virtio_get_features(struct virtio_device *vdev) { struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); struct fw_rsc_vdev *rsc; @@ -216,7 +219,7 @@ return rsc->dfeatures; } -static void rproc_virtio_finalize_features(struct virtio_device *vdev) +static int rproc_virtio_finalize_features(struct virtio_device *vdev) { struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); struct fw_rsc_vdev *rsc; @@ -226,15 +229,20 @@ /* Give virtio_ring a chance to accept features */ vring_transport_features(vdev); + /* Make sure we don't have any features > 32 bits! */ + BUG_ON((u32)vdev->features != vdev->features); + /* * Remember the finalized features of our vdev, and provide it * to the remote processor once it is powered on. */ - rsc->gfeatures = vdev->features[0]; + rsc->gfeatures = vdev->features; + + return 0; } -static void rproc_virtio_get(struct virtio_device *vdev, unsigned offset, - void *buf, unsigned len) +static void rproc_virtio_get(struct virtio_device *vdev, unsigned int offset, + void *buf, unsigned int len) { struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); struct fw_rsc_vdev *rsc; @@ -251,8 +259,8 @@ memcpy(buf, cfg + offset, len); } -static void rproc_virtio_set(struct virtio_device *vdev, unsigned offset, - const void *buf, unsigned len) +static void rproc_virtio_set(struct virtio_device *vdev, unsigned int offset, + const void *buf, unsigned int len) { struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); struct fw_rsc_vdev *rsc; @@ -289,14 +297,13 @@ * Never call this function directly; it will be called by the driver * core when needed. */ -static void rproc_vdev_release(struct device *dev) +static void rproc_virtio_dev_release(struct device *dev) { struct virtio_device *vdev = dev_to_virtio(dev); struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); struct rproc *rproc = vdev_to_rproc(vdev); - list_del(&rvdev->node); - kfree(rvdev); + kref_put(&rvdev->refcount, rproc_vdev_release); put_device(&rproc->dev); } @@ -320,7 +327,7 @@ vdev->id.device = id, vdev->config = &rproc_virtio_config_ops, vdev->dev.parent = dev; - vdev->dev.release = rproc_vdev_release; + vdev->dev.release = rproc_virtio_dev_release; /* * We're indirectly making a non-temporary copy of the rproc pointer @@ -332,9 +339,12 @@ */ get_device(&rproc->dev); + /* Reference the vdev and vring allocations */ + kref_get(&rvdev->refcount); + ret = register_virtio_device(vdev); if (ret) { - put_device(&rproc->dev); + put_device(&vdev->dev); dev_err(dev, "failed to register vdev: %d\n", ret); goto out; }