Release 4.7 drivers/remoteproc/remoteproc_virtio.c
/*
* Remote processor messaging transport (OMAP platform-specific bits)
*
* Copyright (C) 2011 Texas Instruments, Inc.
* Copyright (C) 2011 Google, Inc.
*
* Ohad Ben-Cohen <ohad@wizery.com>
* Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/export.h>
#include <linux/remoteproc.h>
#include <linux/virtio.h>
#include <linux/virtio_config.h>
#include <linux/virtio_ids.h>
#include <linux/virtio_ring.h>
#include <linux/err.h>
#include <linux/kref.h>
#include <linux/slab.h>
#include "remoteproc_internal.h"
/* kick the remote processor, and let it know which virtqueue to poke at */
static bool rproc_virtio_notify(struct virtqueue *vq)
{
struct rproc_vring *rvring = vq->priv;
struct rproc *rproc = rvring->rvdev->rproc;
int notifyid = rvring->notifyid;
dev_dbg(&rproc->dev, "kicking vq index: %d\n", notifyid);
rproc->ops->kick(rproc, notifyid);
return true;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
ohad ben-cohen | ohad ben-cohen | 60 | 93.75% | 3 | 75.00% |
heinz graalfs | heinz graalfs | 4 | 6.25% | 1 | 25.00% |
| Total | 64 | 100.00% | 4 | 100.00% |
/**
* rproc_vq_interrupt() - tell remoteproc that a virtqueue is interrupted
* @rproc: handle to the remote processor
* @notifyid: index of the signalled virtqueue (unique per this @rproc)
*
* This function should be called by the platform-specific rproc driver,
* when the remote processor signals that a specific virtqueue has pending
* messages available.
*
* Returns IRQ_NONE if no message was found in the @notifyid virtqueue,
* and otherwise returns IRQ_HANDLED.
*/
irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int notifyid)
{
struct rproc_vring *rvring;
dev_dbg(&rproc->dev, "vq index %d is interrupted\n", notifyid);
rvring = idr_find(&rproc->notifyids, notifyid);
if (!rvring || !rvring->vq)
return IRQ_NONE;
return vring_interrupt(0, rvring->vq);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
ohad ben-cohen | ohad ben-cohen | 65 | 100.00% | 3 | 100.00% |
| Total | 65 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL(rproc_vq_interrupt);
static struct virtqueue *rp_find_vq(struct virtio_device *vdev,
unsigned id,
void (*callback)(struct virtqueue *vq),
const char *name)
{
struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
struct rproc *rproc = vdev_to_rproc(vdev);
struct device *dev = &rproc->dev;
struct rproc_vring *rvring;
struct virtqueue *vq;
void *addr;
int len, size, ret;
/* we're temporarily limited to two virtqueues per rvdev */
if (id >= ARRAY_SIZE(rvdev->vring))
return ERR_PTR(-EINVAL);
if (!name)
return NULL;
ret = rproc_alloc_vring(rvdev, id);
if (ret)
return ERR_PTR(ret);
rvring = &rvdev->vring[id];
addr = rvring->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);
/*
* 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);
if (!vq) {
dev_err(dev, "vring_new_virtqueue %s failed\n", name);
rproc_free_vring(rvring);
return ERR_PTR(-ENOMEM);
}
rvring->vq = vq;
vq->priv = rvring;
return vq;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
ohad ben-cohen | ohad ben-cohen | 249 | 96.14% | 6 | 75.00% |
michael s. tsirkin | michael s. tsirkin | 8 | 3.09% | 1 | 12.50% |
jason wang | jason wang | 2 | 0.77% | 1 | 12.50% |
| Total | 259 | 100.00% | 8 | 100.00% |
static void __rproc_virtio_del_vqs(struct virtio_device *vdev)
{
struct virtqueue *vq, *n;
struct rproc_vring *rvring;
list_for_each_entry_safe(vq, n, &vdev->vqs, list) {
rvring = vq->priv;
rvring->vq = NULL;
vring_del_virtqueue(vq);
rproc_free_vring(rvring);
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
ohad ben-cohen | ohad ben-cohen | 58 | 100.00% | 4 | 100.00% |
| Total | 58 | 100.00% | 4 | 100.00% |
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);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
ohad ben-cohen | ohad ben-cohen | 32 | 100.00% | 1 | 100.00% |
| Total | 32 | 100.00% | 1 | 100.00% |
static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs,
struct virtqueue *vqs[],
vq_callback_t *callbacks[],
const char * const names[])
{
struct rproc *rproc = vdev_to_rproc(vdev);
int i, ret;
for (i = 0; i < nvqs; ++i) {
vqs[i] = rp_find_vq(vdev, i, callbacks[i], names[i]);
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_nowait(rproc);
if (ret) {
dev_err(&rproc->dev, "rproc_boot() failed %d\n", ret);
goto error;
}
return 0;
error:
__rproc_virtio_del_vqs(vdev);
return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
ohad ben-cohen | ohad ben-cohen | 149 | 98.68% | 4 | 66.67% |
stefan hajnoczi | stefan hajnoczi | 1 | 0.66% | 1 | 16.67% |
lee jones | lee jones | 1 | 0.66% | 1 | 16.67% |
| Total | 151 | 100.00% | 6 | 100.00% |
static u8 rproc_virtio_get_status(struct virtio_device *vdev)
{
struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
struct fw_rsc_vdev *rsc;
rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset;
return rsc->status;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
sjur braendeland | sjur braendeland | 34 | 72.34% | 1 | 50.00% |
ohad ben-cohen | ohad ben-cohen | 13 | 27.66% | 1 | 50.00% |
| Total | 47 | 100.00% | 2 | 100.00% |
static void rproc_virtio_set_status(struct virtio_device *vdev, u8 status)
{
struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
struct fw_rsc_vdev *rsc;
rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset;
rsc->status = status;
dev_dbg(&vdev->dev, "status: %d\n", status);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
sjur braendeland | sjur braendeland | 37 | 58.73% | 1 | 33.33% |
ohad ben-cohen | ohad ben-cohen | 26 | 41.27% | 2 | 66.67% |
| Total | 63 | 100.00% | 3 | 100.00% |
static void rproc_virtio_reset(struct virtio_device *vdev)
{
struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
struct fw_rsc_vdev *rsc;
rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset;
rsc->status = 0;
dev_dbg(&vdev->dev, "reset !\n");
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
sjur braendeland | sjur braendeland | 37 | 63.79% | 1 | 50.00% |
ohad ben-cohen | ohad ben-cohen | 21 | 36.21% | 1 | 50.00% |
| Total | 58 | 100.00% | 2 | 100.00% |
/* provide the vdev features as retrieved from the firmware */
static u64 rproc_virtio_get_features(struct virtio_device *vdev)
{
struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
struct fw_rsc_vdev *rsc;
rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset;
return rsc->dfeatures;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
ohad ben-cohen | ohad ben-cohen | 24 | 51.06% | 2 | 50.00% |
sjur braendeland | sjur braendeland | 22 | 46.81% | 1 | 25.00% |
michael s. tsirkin | michael s. tsirkin | 1 | 2.13% | 1 | 25.00% |
| Total | 47 | 100.00% | 4 | 100.00% |
static int rproc_virtio_finalize_features(struct virtio_device *vdev)
{
struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
struct fw_rsc_vdev *rsc;
rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset;
/* 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;
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
ohad ben-cohen | ohad ben-cohen | 33 | 44.00% | 2 | 40.00% |
sjur braendeland | sjur braendeland | 23 | 30.67% | 1 | 20.00% |
michael s. tsirkin | michael s. tsirkin | 19 | 25.33% | 2 | 40.00% |
| Total | 75 | 100.00% | 5 | 100.00% |
static void rproc_virtio_get(struct virtio_device *vdev, unsigned offset,
void *buf, unsigned len)
{
struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
struct fw_rsc_vdev *rsc;
void *cfg;
rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset;
cfg = &rsc->vring[rsc->num_of_vrings];
if (offset + len > rsc->config_len || offset + len < len) {
dev_err(&vdev->dev, "rproc_virtio_get: access out of bounds\n");
return;
}
memcpy(buf, cfg + offset, len);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
sjur braendeland | sjur braendeland | 108 | 100.00% | 1 | 100.00% |
| Total | 108 | 100.00% | 1 | 100.00% |
static void rproc_virtio_set(struct virtio_device *vdev, unsigned offset,
const void *buf, unsigned len)
{
struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
struct fw_rsc_vdev *rsc;
void *cfg;
rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset;
cfg = &rsc->vring[rsc->num_of_vrings];
if (offset + len > rsc->config_len || offset + len < len) {
dev_err(&vdev->dev, "rproc_virtio_set: access out of bounds\n");
return;
}
memcpy(cfg + offset, buf, len);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
sjur braendeland | sjur braendeland | 109 | 100.00% | 1 | 100.00% |
| Total | 109 | 100.00% | 1 | 100.00% |
static const struct virtio_config_ops rproc_virtio_config_ops = {
.get_features = rproc_virtio_get_features,
.finalize_features = rproc_virtio_finalize_features,
.find_vqs = rproc_virtio_find_vqs,
.del_vqs = rproc_virtio_del_vqs,
.reset = rproc_virtio_reset,
.set_status = rproc_virtio_set_status,
.get_status = rproc_virtio_get_status,
.get = rproc_virtio_get,
.set = rproc_virtio_set,
};
/*
* This function is called whenever vdev is released, and is responsible
* to decrement the remote processor's refcount which was taken when vdev was
* added.
*
* Never call this function directly; it will be called by the driver
* core when needed.
*/
static void rproc_vdev_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);
put_device(&rproc->dev);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
ohad ben-cohen | ohad ben-cohen | 62 | 100.00% | 3 | 100.00% |
| Total | 62 | 100.00% | 3 | 100.00% |
/**
* rproc_add_virtio_dev() - register an rproc-induced virtio device
* @rvdev: the remote vdev
*
* This function registers a virtio device. This vdev's partent is
* the rproc device.
*
* Returns 0 on success or an appropriate error value otherwise.
*/
int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id)
{
struct rproc *rproc = rvdev->rproc;
struct device *dev = &rproc->dev;
struct virtio_device *vdev = &rvdev->vdev;
int ret;
vdev->id.device = id,
vdev->config = &rproc_virtio_config_ops,
vdev->dev.parent = dev;
vdev->dev.release = rproc_vdev_release;
/*
* We're indirectly making a non-temporary copy of the rproc pointer
* here, because drivers probed with this vdev will indirectly
* access the wrapping rproc.
*
* Therefore we must increment the rproc refcount here, and decrement
* it _only_ when the vdev is released.
*/
get_device(&rproc->dev);
ret = register_virtio_device(vdev);
if (ret) {
put_device(&rproc->dev);
dev_err(dev, "failed to register vdev: %d\n", ret);
goto out;
}
dev_info(dev, "registered %s (type %d)\n", dev_name(&vdev->dev), id);
out:
return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
ohad ben-cohen | ohad ben-cohen | 140 | 100.00% | 4 | 100.00% |
| Total | 140 | 100.00% | 4 | 100.00% |
/**
* rproc_remove_virtio_dev() - remove an rproc-induced virtio device
* @rvdev: the remote vdev
*
* This function unregisters an existing virtio device.
*/
void rproc_remove_virtio_dev(struct rproc_vdev *rvdev)
{
unregister_virtio_device(&rvdev->vdev);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
ohad ben-cohen | ohad ben-cohen | 18 | 100.00% | 2 | 100.00% |
| Total | 18 | 100.00% | 2 | 100.00% |
Overall Contributors
| Person | Tokens | Prop | Commits | CommitProp |
ohad ben-cohen | ohad ben-cohen | 1034 | 71.26% | 9 | 47.37% |
sjur braendeland | sjur braendeland | 380 | 26.19% | 1 | 5.26% |
michael s. tsirkin | michael s. tsirkin | 28 | 1.93% | 4 | 21.05% |
heinz graalfs | heinz graalfs | 4 | 0.28% | 1 | 5.26% |
jason wang | jason wang | 2 | 0.14% | 1 | 5.26% |
stephen hemminger | stephen hemminger | 1 | 0.07% | 1 | 5.26% |
lee jones | lee jones | 1 | 0.07% | 1 | 5.26% |
stefan hajnoczi | stefan hajnoczi | 1 | 0.07% | 1 | 5.26% |
| Total | 1451 | 100.00% | 19 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.