remoteproc_virtio.c revision 41a6ee09ee8dd7ac3a6ac12a24e26279b5d93385
1/* 2 * Remote processor messaging transport (OMAP platform-specific bits) 3 * 4 * Copyright (C) 2011 Texas Instruments, Inc. 5 * Copyright (C) 2011 Google, Inc. 6 * 7 * Ohad Ben-Cohen <ohad@wizery.com> 8 * Brian Swetland <swetland@google.com> 9 * 10 * This software is licensed under the terms of the GNU General Public 11 * License version 2, as published by the Free Software Foundation, and 12 * may be copied, distributed, and modified under those terms. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 */ 19 20#include <linux/export.h> 21#include <linux/remoteproc.h> 22#include <linux/rpmsg.h> 23#include <linux/virtio.h> 24#include <linux/virtio_config.h> 25#include <linux/virtio_ids.h> 26#include <linux/virtio_ring.h> 27#include <linux/err.h> 28#include <linux/kref.h> 29#include <linux/slab.h> 30 31#include "remoteproc_internal.h" 32 33/** 34 * struct rproc_virtio_vq_info - virtqueue state 35 * @vq_id: a unique index of this virtqueue (unique for this @rproc) 36 * @rproc: handle to the remote processor 37 * 38 * Such a struct will be maintained for every virtqueue we're 39 * using to communicate with the remote processor 40 */ 41struct rproc_virtio_vq_info { 42 __u16 vq_id; 43 struct rproc *rproc; 44}; 45 46/* kick the remote processor, and let it know which virtqueue to poke at */ 47static void rproc_virtio_notify(struct virtqueue *vq) 48{ 49 struct rproc_virtio_vq_info *rpvq = vq->priv; 50 struct rproc *rproc = rpvq->rproc; 51 52 dev_dbg(rproc->dev, "kicking vq id: %d\n", rpvq->vq_id); 53 54 rproc->ops->kick(rproc, rpvq->vq_id); 55} 56 57/** 58 * rproc_vq_interrupt() - tell remoteproc that a virtqueue is interrupted 59 * @rproc: handle to the remote processor 60 * @vq_id: index of the signalled virtqueue 61 * 62 * This function should be called by the platform-specific rproc driver, 63 * when the remote processor signals that a specific virtqueue has pending 64 * messages available. 65 * 66 * Returns IRQ_NONE if no message was found in the @vq_id virtqueue, 67 * and otherwise returns IRQ_HANDLED. 68 */ 69irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int vq_id) 70{ 71 return vring_interrupt(0, rproc->rvdev->vq[vq_id]); 72} 73EXPORT_SYMBOL(rproc_vq_interrupt); 74 75static struct virtqueue *rp_find_vq(struct virtio_device *vdev, 76 unsigned id, 77 void (*callback)(struct virtqueue *vq), 78 const char *name) 79{ 80 struct rproc *rproc = vdev_to_rproc(vdev); 81 struct rproc_vdev *rvdev = rproc->rvdev; 82 struct rproc_virtio_vq_info *rpvq; 83 struct virtqueue *vq; 84 void *addr; 85 int ret, len; 86 87 rpvq = kmalloc(sizeof(*rpvq), GFP_KERNEL); 88 if (!rpvq) 89 return ERR_PTR(-ENOMEM); 90 91 rpvq->rproc = rproc; 92 rpvq->vq_id = id; 93 94 addr = rvdev->vring[id].va; 95 len = rvdev->vring[id].len; 96 97 dev_dbg(rproc->dev, "vring%d: va %p qsz %d\n", id, addr, len); 98 99 /* 100 * Create the new vq, and tell virtio we're not interested in 101 * the 'weak' smp barriers, since we're talking with a real device. 102 */ 103 vq = vring_new_virtqueue(len, AMP_VRING_ALIGN, vdev, false, addr, 104 rproc_virtio_notify, callback, name); 105 if (!vq) { 106 dev_err(rproc->dev, "vring_new_virtqueue %s failed\n", name); 107 ret = -ENOMEM; 108 goto free_rpvq; 109 } 110 111 rvdev->vq[id] = vq; 112 vq->priv = rpvq; 113 114 return vq; 115 116free_rpvq: 117 kfree(rpvq); 118 return ERR_PTR(ret); 119} 120 121static void rproc_virtio_del_vqs(struct virtio_device *vdev) 122{ 123 struct virtqueue *vq, *n; 124 struct rproc *rproc = vdev_to_rproc(vdev); 125 126 /* power down the remote processor before deleting vqs */ 127 rproc_shutdown(rproc); 128 129 list_for_each_entry_safe(vq, n, &vdev->vqs, list) { 130 struct rproc_virtio_vq_info *rpvq = vq->priv; 131 vring_del_virtqueue(vq); 132 kfree(rpvq); 133 } 134} 135 136static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs, 137 struct virtqueue *vqs[], 138 vq_callback_t *callbacks[], 139 const char *names[]) 140{ 141 struct rproc *rproc = vdev_to_rproc(vdev); 142 int i, ret; 143 144 /* we maintain two virtqueues per remote processor (for RX and TX) */ 145 if (nvqs != 2) 146 return -EINVAL; 147 148 for (i = 0; i < nvqs; ++i) { 149 vqs[i] = rp_find_vq(vdev, i, callbacks[i], names[i]); 150 if (IS_ERR(vqs[i])) { 151 ret = PTR_ERR(vqs[i]); 152 goto error; 153 } 154 } 155 156 /* now that the vqs are all set, boot the remote processor */ 157 ret = rproc_boot(rproc); 158 if (ret) { 159 dev_err(rproc->dev, "rproc_boot() failed %d\n", ret); 160 goto error; 161 } 162 163 return 0; 164 165error: 166 rproc_virtio_del_vqs(vdev); 167 return ret; 168} 169 170/* 171 * We don't support yet real virtio status semantics. 172 * 173 * The plan is to provide this via the VIRTIO HDR resource entry 174 * which is part of the firmware: this way the remote processor 175 * will be able to access the status values as set by us. 176 */ 177static u8 rproc_virtio_get_status(struct virtio_device *vdev) 178{ 179 return 0; 180} 181 182static void rproc_virtio_set_status(struct virtio_device *vdev, u8 status) 183{ 184 dev_dbg(&vdev->dev, "new status: %d\n", status); 185} 186 187static void rproc_virtio_reset(struct virtio_device *vdev) 188{ 189 dev_dbg(&vdev->dev, "reset !\n"); 190} 191 192/* provide the vdev features as retrieved from the firmware */ 193static u32 rproc_virtio_get_features(struct virtio_device *vdev) 194{ 195 struct rproc *rproc = vdev_to_rproc(vdev); 196 197 /* we only support a single vdev device for now */ 198 return rproc->rvdev->dfeatures; 199} 200 201static void rproc_virtio_finalize_features(struct virtio_device *vdev) 202{ 203 struct rproc *rproc = vdev_to_rproc(vdev); 204 205 /* Give virtio_ring a chance to accept features */ 206 vring_transport_features(vdev); 207 208 /* 209 * Remember the finalized features of our vdev, and provide it 210 * to the remote processor once it is powered on. 211 * 212 * Similarly to the status field, we don't expose yet the negotiated 213 * features to the remote processors at this point. This will be 214 * fixed as part of a small resource table overhaul and then an 215 * extension of the virtio resource entries. 216 */ 217 rproc->rvdev->gfeatures = vdev->features[0]; 218} 219 220static struct virtio_config_ops rproc_virtio_config_ops = { 221 .get_features = rproc_virtio_get_features, 222 .finalize_features = rproc_virtio_finalize_features, 223 .find_vqs = rproc_virtio_find_vqs, 224 .del_vqs = rproc_virtio_del_vqs, 225 .reset = rproc_virtio_reset, 226 .set_status = rproc_virtio_set_status, 227 .get_status = rproc_virtio_get_status, 228}; 229 230/* 231 * This function is called whenever vdev is released, and is responsible 232 * to decrement the remote processor's refcount taken when vdev was 233 * added. 234 * 235 * Never call this function directly; it will be called by the driver 236 * core when needed. 237 */ 238static void rproc_vdev_release(struct device *dev) 239{ 240 struct virtio_device *vdev = dev_to_virtio(dev); 241 struct rproc *rproc = vdev_to_rproc(vdev); 242 243 kref_put(&rproc->refcount, rproc_release); 244} 245 246/** 247 * rproc_add_rpmsg_vdev() - create an rpmsg virtio device 248 * @rproc: the rproc handle 249 * 250 * This function is called if virtio rpmsg support was found in the 251 * firmware of the remote processor. 252 * 253 * Today we only support creating a single rpmsg vdev (virtio device), 254 * but the plan is to remove this limitation. At that point this interface 255 * will be revised/extended. 256 */ 257int rproc_add_rpmsg_vdev(struct rproc *rproc) 258{ 259 struct device *dev = rproc->dev; 260 struct rproc_vdev *rvdev = rproc->rvdev; 261 int ret; 262 263 rvdev->vdev.id.device = VIRTIO_ID_RPMSG, 264 rvdev->vdev.config = &rproc_virtio_config_ops, 265 rvdev->vdev.dev.parent = dev; 266 rvdev->vdev.dev.release = rproc_vdev_release; 267 268 /* 269 * We're indirectly making a non-temporary copy of the rproc pointer 270 * here, because drivers probed with this vdev will indirectly 271 * access the wrapping rproc. 272 * 273 * Therefore we must increment the rproc refcount here, and decrement 274 * it _only_ when the vdev is released. 275 */ 276 kref_get(&rproc->refcount); 277 278 ret = register_virtio_device(&rvdev->vdev); 279 if (ret) { 280 kref_put(&rproc->refcount, rproc_release); 281 dev_err(dev, "failed to register vdev: %d\n", ret); 282 } 283 284 return ret; 285} 286 287/** 288 * rproc_remove_rpmsg_vdev() - remove an rpmsg vdev device 289 * @rproc: the rproc handle 290 * 291 * This function is called whenever @rproc is removed _iff_ an rpmsg 292 * vdev was created beforehand. 293 */ 294void rproc_remove_rpmsg_vdev(struct rproc *rproc) 295{ 296 struct rproc_vdev *rvdev = rproc->rvdev; 297 298 unregister_virtio_device(&rvdev->vdev); 299} 300