Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only
2 : : /*
3 : : * Remote processor messaging transport (OMAP platform-specific bits)
4 : : *
5 : : * Copyright (C) 2011 Texas Instruments, Inc.
6 : : * Copyright (C) 2011 Google, Inc.
7 : : *
8 : : * Ohad Ben-Cohen <ohad@wizery.com>
9 : : * Brian Swetland <swetland@google.com>
10 : : */
11 : :
12 : : #include <linux/dma-mapping.h>
13 : : #include <linux/export.h>
14 : : #include <linux/of_reserved_mem.h>
15 : : #include <linux/remoteproc.h>
16 : : #include <linux/virtio.h>
17 : : #include <linux/virtio_config.h>
18 : : #include <linux/virtio_ids.h>
19 : : #include <linux/virtio_ring.h>
20 : : #include <linux/err.h>
21 : : #include <linux/kref.h>
22 : : #include <linux/slab.h>
23 : :
24 : : #include "remoteproc_internal.h"
25 : :
26 : : /* kick the remote processor, and let it know which virtqueue to poke at */
27 : 0 : static bool rproc_virtio_notify(struct virtqueue *vq)
28 : : {
29 : 0 : struct rproc_vring *rvring = vq->priv;
30 : 0 : struct rproc *rproc = rvring->rvdev->rproc;
31 : 0 : int notifyid = rvring->notifyid;
32 : :
33 : 0 : dev_dbg(&rproc->dev, "kicking vq index: %d\n", notifyid);
34 : :
35 : 0 : rproc->ops->kick(rproc, notifyid);
36 : 0 : return true;
37 : : }
38 : :
39 : : /**
40 : : * rproc_vq_interrupt() - tell remoteproc that a virtqueue is interrupted
41 : : * @rproc: handle to the remote processor
42 : : * @notifyid: index of the signalled virtqueue (unique per this @rproc)
43 : : *
44 : : * This function should be called by the platform-specific rproc driver,
45 : : * when the remote processor signals that a specific virtqueue has pending
46 : : * messages available.
47 : : *
48 : : * Returns IRQ_NONE if no message was found in the @notifyid virtqueue,
49 : : * and otherwise returns IRQ_HANDLED.
50 : : */
51 : 0 : irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int notifyid)
52 : : {
53 : 0 : struct rproc_vring *rvring;
54 : :
55 : 0 : dev_dbg(&rproc->dev, "vq index %d is interrupted\n", notifyid);
56 : :
57 : 0 : rvring = idr_find(&rproc->notifyids, notifyid);
58 [ # # # # ]: 0 : if (!rvring || !rvring->vq)
59 : : return IRQ_NONE;
60 : :
61 : 0 : return vring_interrupt(0, rvring->vq);
62 : : }
63 : : EXPORT_SYMBOL(rproc_vq_interrupt);
64 : :
65 : 0 : static struct virtqueue *rp_find_vq(struct virtio_device *vdev,
66 : : unsigned int id,
67 : : void (*callback)(struct virtqueue *vq),
68 : : const char *name, bool ctx)
69 : : {
70 [ # # ]: 0 : struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
71 [ # # ]: 0 : struct rproc *rproc = vdev_to_rproc(vdev);
72 : 0 : struct device *dev = &rproc->dev;
73 : 0 : struct rproc_mem_entry *mem;
74 : 0 : struct rproc_vring *rvring;
75 : 0 : struct fw_rsc_vdev *rsc;
76 : 0 : struct virtqueue *vq;
77 : 0 : void *addr;
78 : 0 : int len, size;
79 : :
80 : : /* we're temporarily limited to two virtqueues per rvdev */
81 [ # # ]: 0 : if (id >= ARRAY_SIZE(rvdev->vring))
82 : : return ERR_PTR(-EINVAL);
83 : :
84 [ # # ]: 0 : if (!name)
85 : : return NULL;
86 : :
87 : : /* Search allocated memory region by name */
88 : 0 : mem = rproc_find_carveout_by_name(rproc, "vdev%dvring%d", rvdev->index,
89 : : id);
90 [ # # # # ]: 0 : if (!mem || !mem->va)
91 : : return ERR_PTR(-ENOMEM);
92 : :
93 : 0 : rvring = &rvdev->vring[id];
94 : 0 : addr = mem->va;
95 : 0 : len = rvring->len;
96 : :
97 : : /* zero vring */
98 : 0 : size = vring_size(len, rvring->align);
99 : 0 : memset(addr, 0, size);
100 : :
101 : 0 : dev_dbg(dev, "vring%d: va %pK qsz %d notifyid %d\n",
102 : : id, addr, len, rvring->notifyid);
103 : :
104 : : /*
105 : : * Create the new vq, and tell virtio we're not interested in
106 : : * the 'weak' smp barriers, since we're talking with a real device.
107 : : */
108 : 0 : vq = vring_new_virtqueue(id, len, rvring->align, vdev, false, ctx,
109 : : addr, rproc_virtio_notify, callback, name);
110 [ # # ]: 0 : if (!vq) {
111 : 0 : dev_err(dev, "vring_new_virtqueue %s failed\n", name);
112 : 0 : rproc_free_vring(rvring);
113 : 0 : return ERR_PTR(-ENOMEM);
114 : : }
115 : :
116 : 0 : rvring->vq = vq;
117 : 0 : vq->priv = rvring;
118 : :
119 : : /* Update vring in resource table */
120 : 0 : rsc = (void *)rproc->table_ptr + rvdev->rsc_offset;
121 : 0 : rsc->vring[id].da = mem->da;
122 : :
123 : 0 : return vq;
124 : : }
125 : :
126 : 0 : static void __rproc_virtio_del_vqs(struct virtio_device *vdev)
127 : : {
128 : 0 : struct virtqueue *vq, *n;
129 : 0 : struct rproc_vring *rvring;
130 : :
131 [ # # # # ]: 0 : list_for_each_entry_safe(vq, n, &vdev->vqs, list) {
132 : 0 : rvring = vq->priv;
133 : 0 : rvring->vq = NULL;
134 : 0 : vring_del_virtqueue(vq);
135 : : }
136 : : }
137 : :
138 : 0 : static void rproc_virtio_del_vqs(struct virtio_device *vdev)
139 : : {
140 : 0 : __rproc_virtio_del_vqs(vdev);
141 : 0 : }
142 : :
143 : 0 : static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
144 : : struct virtqueue *vqs[],
145 : : vq_callback_t *callbacks[],
146 : : const char * const names[],
147 : : const bool * ctx,
148 : : struct irq_affinity *desc)
149 : : {
150 : 0 : int i, ret, queue_idx = 0;
151 : :
152 [ # # ]: 0 : for (i = 0; i < nvqs; ++i) {
153 [ # # ]: 0 : if (!names[i]) {
154 : 0 : vqs[i] = NULL;
155 : 0 : continue;
156 : : }
157 : :
158 : 0 : vqs[i] = rp_find_vq(vdev, queue_idx++, callbacks[i], names[i],
159 [ # # # # ]: 0 : ctx ? ctx[i] : false);
160 [ # # ]: 0 : if (IS_ERR(vqs[i])) {
161 : 0 : ret = PTR_ERR(vqs[i]);
162 : 0 : goto error;
163 : : }
164 : : }
165 : :
166 : : return 0;
167 : :
168 : : error:
169 : 0 : __rproc_virtio_del_vqs(vdev);
170 : : return ret;
171 : : }
172 : :
173 : 0 : static u8 rproc_virtio_get_status(struct virtio_device *vdev)
174 : : {
175 : 0 : struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
176 : 0 : struct fw_rsc_vdev *rsc;
177 : :
178 : 0 : rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset;
179 : :
180 : 0 : return rsc->status;
181 : : }
182 : :
183 : 0 : static void rproc_virtio_set_status(struct virtio_device *vdev, u8 status)
184 : : {
185 : 0 : struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
186 : 0 : struct fw_rsc_vdev *rsc;
187 : :
188 : 0 : rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset;
189 : :
190 : 0 : rsc->status = status;
191 : 0 : dev_dbg(&vdev->dev, "status: %d\n", status);
192 : 0 : }
193 : :
194 : 0 : static void rproc_virtio_reset(struct virtio_device *vdev)
195 : : {
196 : 0 : struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
197 : 0 : struct fw_rsc_vdev *rsc;
198 : :
199 : 0 : rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset;
200 : :
201 : 0 : rsc->status = 0;
202 : 0 : dev_dbg(&vdev->dev, "reset !\n");
203 : 0 : }
204 : :
205 : : /* provide the vdev features as retrieved from the firmware */
206 : 0 : static u64 rproc_virtio_get_features(struct virtio_device *vdev)
207 : : {
208 : 0 : struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
209 : 0 : struct fw_rsc_vdev *rsc;
210 : :
211 : 0 : rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset;
212 : :
213 : 0 : return rsc->dfeatures;
214 : : }
215 : :
216 : 0 : static void rproc_transport_features(struct virtio_device *vdev)
217 : : {
218 : : /*
219 : : * Packed ring isn't enabled on remoteproc for now,
220 : : * because remoteproc uses vring_new_virtqueue() which
221 : : * creates virtio rings on preallocated memory.
222 : : */
223 : 0 : __virtio_clear_bit(vdev, VIRTIO_F_RING_PACKED);
224 : : }
225 : :
226 : 0 : static int rproc_virtio_finalize_features(struct virtio_device *vdev)
227 : : {
228 : 0 : struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
229 : 0 : struct fw_rsc_vdev *rsc;
230 : :
231 : 0 : rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset;
232 : :
233 : : /* Give virtio_ring a chance to accept features */
234 : 0 : vring_transport_features(vdev);
235 : :
236 : : /* Give virtio_rproc a chance to accept features. */
237 [ # # ]: 0 : rproc_transport_features(vdev);
238 : :
239 : : /* Make sure we don't have any features > 32 bits! */
240 [ # # ]: 0 : BUG_ON((u32)vdev->features != vdev->features);
241 : :
242 : : /*
243 : : * Remember the finalized features of our vdev, and provide it
244 : : * to the remote processor once it is powered on.
245 : : */
246 : 0 : rsc->gfeatures = vdev->features;
247 : :
248 : 0 : return 0;
249 : : }
250 : :
251 : 0 : static void rproc_virtio_get(struct virtio_device *vdev, unsigned int offset,
252 : : void *buf, unsigned int len)
253 : : {
254 [ # # ]: 0 : struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
255 : 0 : struct fw_rsc_vdev *rsc;
256 : 0 : void *cfg;
257 : :
258 : 0 : rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset;
259 : 0 : cfg = &rsc->vring[rsc->num_of_vrings];
260 : :
261 [ # # # # ]: 0 : if (offset + len > rsc->config_len || offset + len < len) {
262 : 0 : dev_err(&vdev->dev, "rproc_virtio_get: access out of bounds\n");
263 : 0 : return;
264 : : }
265 : :
266 : 0 : memcpy(buf, cfg + offset, len);
267 : : }
268 : :
269 : 0 : static void rproc_virtio_set(struct virtio_device *vdev, unsigned int offset,
270 : : const void *buf, unsigned int len)
271 : : {
272 [ # # ]: 0 : struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
273 : 0 : struct fw_rsc_vdev *rsc;
274 : 0 : void *cfg;
275 : :
276 : 0 : rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset;
277 : 0 : cfg = &rsc->vring[rsc->num_of_vrings];
278 : :
279 [ # # # # ]: 0 : if (offset + len > rsc->config_len || offset + len < len) {
280 : 0 : dev_err(&vdev->dev, "rproc_virtio_set: access out of bounds\n");
281 : 0 : return;
282 : : }
283 : :
284 : 0 : memcpy(cfg + offset, buf, len);
285 : : }
286 : :
287 : : static const struct virtio_config_ops rproc_virtio_config_ops = {
288 : : .get_features = rproc_virtio_get_features,
289 : : .finalize_features = rproc_virtio_finalize_features,
290 : : .find_vqs = rproc_virtio_find_vqs,
291 : : .del_vqs = rproc_virtio_del_vqs,
292 : : .reset = rproc_virtio_reset,
293 : : .set_status = rproc_virtio_set_status,
294 : : .get_status = rproc_virtio_get_status,
295 : : .get = rproc_virtio_get,
296 : : .set = rproc_virtio_set,
297 : : };
298 : :
299 : : /*
300 : : * This function is called whenever vdev is released, and is responsible
301 : : * to decrement the remote processor's refcount which was taken when vdev was
302 : : * added.
303 : : *
304 : : * Never call this function directly; it will be called by the driver
305 : : * core when needed.
306 : : */
307 : 0 : static void rproc_virtio_dev_release(struct device *dev)
308 : : {
309 : 0 : struct virtio_device *vdev = dev_to_virtio(dev);
310 : 0 : struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
311 : 0 : struct rproc *rproc = vdev_to_rproc(vdev);
312 : :
313 : 0 : kfree(vdev);
314 : :
315 : 0 : kref_put(&rvdev->refcount, rproc_vdev_release);
316 : :
317 : 0 : put_device(&rproc->dev);
318 : 0 : }
319 : :
320 : : /**
321 : : * rproc_add_virtio_dev() - register an rproc-induced virtio device
322 : : * @rvdev: the remote vdev
323 : : *
324 : : * This function registers a virtio device. This vdev's partent is
325 : : * the rproc device.
326 : : *
327 : : * Returns 0 on success or an appropriate error value otherwise.
328 : : */
329 : 0 : int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id)
330 : : {
331 : 0 : struct rproc *rproc = rvdev->rproc;
332 : 0 : struct device *dev = &rvdev->dev;
333 : 0 : struct virtio_device *vdev;
334 : 0 : struct rproc_mem_entry *mem;
335 : 0 : int ret;
336 : :
337 : : /* Try to find dedicated vdev buffer carveout */
338 : 0 : mem = rproc_find_carveout_by_name(rproc, "vdev%dbuffer", rvdev->index);
339 [ # # ]: 0 : if (mem) {
340 : 0 : phys_addr_t pa;
341 : :
342 [ # # ]: 0 : if (mem->of_resm_idx != -1) {
343 : 0 : struct device_node *np = rproc->dev.parent->of_node;
344 : :
345 : : /* Associate reserved memory to vdev device */
346 : 0 : ret = of_reserved_mem_device_init_by_idx(dev, np,
347 : : mem->of_resm_idx);
348 : 0 : if (ret) {
349 : 0 : dev_err(dev, "Can't associate reserved memory\n");
350 : 0 : goto out;
351 : : }
352 : : } else {
353 [ # # ]: 0 : if (mem->va) {
354 : 0 : dev_warn(dev, "vdev %d buffer already mapped\n",
355 : : rvdev->index);
356 : 0 : pa = rproc_va_to_pa(mem->va);
357 : : } else {
358 : : /* Use dma address as carveout no memmapped yet */
359 : : pa = (phys_addr_t)mem->dma;
360 : : }
361 : :
362 : : /* Associate vdev buffer memory pool to vdev subdev */
363 : 0 : ret = dma_declare_coherent_memory(dev, pa,
364 : : mem->da,
365 : : mem->len);
366 : 0 : if (ret < 0) {
367 : 0 : dev_err(dev, "Failed to associate buffer\n");
368 : 0 : goto out;
369 : : }
370 : : }
371 : : }
372 : :
373 : : /* Allocate virtio device */
374 : 0 : vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
375 [ # # ]: 0 : if (!vdev) {
376 : 0 : ret = -ENOMEM;
377 : 0 : goto out;
378 : : }
379 : 0 : vdev->id.device = id,
380 : 0 : vdev->config = &rproc_virtio_config_ops,
381 : 0 : vdev->dev.parent = dev;
382 : 0 : vdev->dev.release = rproc_virtio_dev_release;
383 : :
384 : : /*
385 : : * We're indirectly making a non-temporary copy of the rproc pointer
386 : : * here, because drivers probed with this vdev will indirectly
387 : : * access the wrapping rproc.
388 : : *
389 : : * Therefore we must increment the rproc refcount here, and decrement
390 : : * it _only_ when the vdev is released.
391 : : */
392 : 0 : get_device(&rproc->dev);
393 : :
394 : : /* Reference the vdev and vring allocations */
395 : 0 : kref_get(&rvdev->refcount);
396 : :
397 : 0 : ret = register_virtio_device(vdev);
398 [ # # ]: 0 : if (ret) {
399 : 0 : put_device(&vdev->dev);
400 : 0 : dev_err(dev, "failed to register vdev: %d\n", ret);
401 : 0 : goto out;
402 : : }
403 : :
404 [ # # ]: 0 : dev_info(dev, "registered %s (type %d)\n", dev_name(&vdev->dev), id);
405 : :
406 : 0 : out:
407 : 0 : return ret;
408 : : }
409 : :
410 : : /**
411 : : * rproc_remove_virtio_dev() - remove an rproc-induced virtio device
412 : : * @dev: the virtio device
413 : : * @data: must be null
414 : : *
415 : : * This function unregisters an existing virtio device.
416 : : */
417 : 0 : int rproc_remove_virtio_dev(struct device *dev, void *data)
418 : : {
419 : 0 : struct virtio_device *vdev = dev_to_virtio(dev);
420 : :
421 : 0 : unregister_virtio_device(vdev);
422 : 0 : return 0;
423 : : }
|