remoteproc_virtio.c 11.3 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0-only
2 3 4 5 6 7 8 9 10 11
/*
 * 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>
 */

12
#include <linux/dma-map-ops.h>
13
#include <linux/export.h>
14
#include <linux/of_reserved_mem.h>
15 16 17 18 19 20 21 22 23 24 25 26
#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 */
27
static bool rproc_virtio_notify(struct virtqueue *vq)
28
{
29 30 31
	struct rproc_vring *rvring = vq->priv;
	struct rproc *rproc = rvring->rvdev->rproc;
	int notifyid = rvring->notifyid;
32

33
	dev_dbg(&rproc->dev, "kicking vq index: %d\n", notifyid);
34

35
	rproc->ops->kick(rproc, notifyid);
36
	return true;
37 38 39 40 41
}

/**
 * rproc_vq_interrupt() - tell remoteproc that a virtqueue is interrupted
 * @rproc: handle to the remote processor
42
 * @notifyid: index of the signalled virtqueue (unique per this @rproc)
43 44 45 46 47
 *
 * This function should be called by the platform-specific rproc driver,
 * when the remote processor signals that a specific virtqueue has pending
 * messages available.
 *
48
 * Return: IRQ_NONE if no message was found in the @notifyid virtqueue,
49 50
 * and otherwise returns IRQ_HANDLED.
 */
51
irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int notifyid)
52
{
53 54
	struct rproc_vring *rvring;

55
	dev_dbg(&rproc->dev, "vq index %d is interrupted\n", notifyid);
56 57 58 59 60 61

	rvring = idr_find(&rproc->notifyids, notifyid);
	if (!rvring || !rvring->vq)
		return IRQ_NONE;

	return vring_interrupt(0, rvring->vq);
62 63 64 65
}
EXPORT_SYMBOL(rproc_vq_interrupt);

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
	struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
71
	struct rproc *rproc = vdev_to_rproc(vdev);
72
	struct device *dev = &rproc->dev;
73
	struct rproc_mem_entry *mem;
74
	struct rproc_vring *rvring;
75
	struct fw_rsc_vdev *rsc;
76 77
	struct virtqueue *vq;
	void *addr;
78
	int len, size;
79

80 81 82 83
	/* we're temporarily limited to two virtqueues per rvdev */
	if (id >= ARRAY_SIZE(rvdev->vring))
		return ERR_PTR(-EINVAL);

84 85 86
	if (!name)
		return NULL;

87 88 89 90 91 92
	/* 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);

93
	rvring = &rvdev->vring[id];
94
	addr = mem->va;
95
	len = rvring->len;
96

97 98 99
	/* zero vring */
	size = vring_size(len, rvring->align);
	memset(addr, 0, size);
100

101
	dev_dbg(dev, "vring%d: va %pK qsz %d notifyid %d\n",
102
		id, addr, len, rvring->notifyid);
103

104 105 106 107
	/*
	 * Create the new vq, and tell virtio we're not interested in
	 * the 'weak' smp barriers, since we're talking with a real device.
	 */
108 109
	vq = vring_new_virtqueue(id, len, rvring->align, vdev, false, ctx,
				 addr, rproc_virtio_notify, callback, name);
110
	if (!vq) {
111
		dev_err(dev, "vring_new_virtqueue %s failed\n", name);
112
		rproc_free_vring(rvring);
113
		return ERR_PTR(-ENOMEM);
114 115
	}

116 117
	rvring->vq = vq;
	vq->priv = rvring;
118

119 120 121 122
	/* Update vring in resource table */
	rsc = (void *)rproc->table_ptr + rvdev->rsc_offset;
	rsc->vring[id].da = mem->da;

123 124 125
	return vq;
}

126
static void __rproc_virtio_del_vqs(struct virtio_device *vdev)
127 128
{
	struct virtqueue *vq, *n;
129
	struct rproc_vring *rvring;
130 131

	list_for_each_entry_safe(vq, n, &vdev->vqs, list) {
132 133
		rvring = vq->priv;
		rvring->vq = NULL;
134 135 136 137
		vring_del_virtqueue(vq);
	}
}

138 139 140 141 142
static void rproc_virtio_del_vqs(struct virtio_device *vdev)
{
	__rproc_virtio_del_vqs(vdev);
}

143
static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
144 145
				 struct virtqueue *vqs[],
				 vq_callback_t *callbacks[],
146
				 const char * const names[],
147
				 const bool * ctx,
148
				 struct irq_affinity *desc)
149
{
150
	int i, ret, queue_idx = 0;
151 152

	for (i = 0; i < nvqs; ++i) {
153 154 155 156 157 158
		if (!names[i]) {
			vqs[i] = NULL;
			continue;
		}

		vqs[i] = rp_find_vq(vdev, queue_idx++, callbacks[i], names[i],
159
				    ctx ? ctx[i] : false);
160 161 162 163 164 165 166 167 168
		if (IS_ERR(vqs[i])) {
			ret = PTR_ERR(vqs[i]);
			goto error;
		}
	}

	return 0;

error:
169
	__rproc_virtio_del_vqs(vdev);
170 171 172 173 174
	return ret;
}

static u8 rproc_virtio_get_status(struct virtio_device *vdev)
{
175 176 177 178 179 180
	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;
181 182 183 184
}

static void rproc_virtio_set_status(struct virtio_device *vdev, u8 status)
{
185 186 187 188 189 190
	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;
191
	dev_dbg(&vdev->dev, "status: %d\n", status);
192 193 194 195
}

static void rproc_virtio_reset(struct virtio_device *vdev)
{
196 197 198 199 200 201
	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;
202 203 204 205
	dev_dbg(&vdev->dev, "reset !\n");
}

/* provide the vdev features as retrieved from the firmware */
206
static u64 rproc_virtio_get_features(struct virtio_device *vdev)
207
{
208
	struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
209 210 211
	struct fw_rsc_vdev *rsc;

	rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset;
212

213
	return rsc->dfeatures;
214 215
}

216 217 218 219 220 221 222 223 224 225
static void rproc_transport_features(struct virtio_device *vdev)
{
	/*
	 * Packed ring isn't enabled on remoteproc for now,
	 * because remoteproc uses vring_new_virtqueue() which
	 * creates virtio rings on preallocated memory.
	 */
	__virtio_clear_bit(vdev, VIRTIO_F_RING_PACKED);
}

226
static int rproc_virtio_finalize_features(struct virtio_device *vdev)
227
{
228
	struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
229 230 231
	struct fw_rsc_vdev *rsc;

	rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset;
232 233 234 235

	/* Give virtio_ring a chance to accept features */
	vring_transport_features(vdev);

236 237 238
	/* Give virtio_rproc a chance to accept features. */
	rproc_transport_features(vdev);

239 240 241
	/* Make sure we don't have any features > 32 bits! */
	BUG_ON((u32)vdev->features != vdev->features);

242 243 244 245
	/*
	 * Remember the finalized features of our vdev, and provide it
	 * to the remote processor once it is powered on.
	 */
246
	rsc->gfeatures = vdev->features;
247 248

	return 0;
249 250
}

251 252
static void rproc_virtio_get(struct virtio_device *vdev, unsigned int offset,
			     void *buf, unsigned int len)
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
{
	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);
}

269 270
static void rproc_virtio_set(struct virtio_device *vdev, unsigned int offset,
			     const void *buf, unsigned int len)
271 272 273 274 275 276 277 278 279 280 281 282 283 284
{
	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);
285 286
}

287
static const struct virtio_config_ops rproc_virtio_config_ops = {
288 289 290 291 292 293 294
	.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,
295 296
	.get		= rproc_virtio_get,
	.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 303 304 305 306
 * added.
 *
 * Never call this function directly; it will be called by the driver
 * core when needed.
 */
307
static void rproc_virtio_dev_release(struct device *dev)
308 309
{
	struct virtio_device *vdev = dev_to_virtio(dev);
310
	struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
311 312
	struct rproc *rproc = vdev_to_rproc(vdev);

313 314
	kfree(vdev);

315
	kref_put(&rvdev->refcount, rproc_vdev_release);
316

317
	put_device(&rproc->dev);
318 319 320
}

/**
321 322
 * rproc_add_virtio_dev() - register an rproc-induced virtio device
 * @rvdev: the remote vdev
323
 * @id: the device type identification (used to match it with a driver).
324
 *
325 326
 * This function registers a virtio device. This vdev's partent is
 * the rproc device.
327
 *
328
 * Return: 0 on success or an appropriate error value otherwise
329
 */
330
int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id)
331
{
332
	struct rproc *rproc = rvdev->rproc;
333
	struct device *dev = &rvdev->dev;
334
	struct virtio_device *vdev;
335
	struct rproc_mem_entry *mem;
336 337
	int ret;

338 339
	if (rproc->ops->kick == NULL) {
		ret = -EINVAL;
340
		dev_err(dev, ".kick method not defined for %s\n", rproc->name);
341 342 343
		goto out;
	}

344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
	/* Try to find dedicated vdev buffer carveout */
	mem = rproc_find_carveout_by_name(rproc, "vdev%dbuffer", rvdev->index);
	if (mem) {
		phys_addr_t pa;

		if (mem->of_resm_idx != -1) {
			struct device_node *np = rproc->dev.parent->of_node;

			/* Associate reserved memory to vdev device */
			ret = of_reserved_mem_device_init_by_idx(dev, np,
								 mem->of_resm_idx);
			if (ret) {
				dev_err(dev, "Can't associate reserved memory\n");
				goto out;
			}
		} else {
			if (mem->va) {
				dev_warn(dev, "vdev %d buffer already mapped\n",
					 rvdev->index);
				pa = rproc_va_to_pa(mem->va);
			} else {
				/* Use dma address as carveout no memmapped yet */
				pa = (phys_addr_t)mem->dma;
			}

			/* Associate vdev buffer memory pool to vdev subdev */
			ret = dma_declare_coherent_memory(dev, pa,
							   mem->da,
372
							   mem->len);
373 374 375 376 377
			if (ret < 0) {
				dev_err(dev, "Failed to associate buffer\n");
				goto out;
			}
		}
378 379 380 381 382 383 384 385 386 387 388 389
	} else {
		struct device_node *np = rproc->dev.parent->of_node;

		/*
		 * If we don't have dedicated buffer, just attempt to re-assign
		 * the reserved memory from our parent. A default memory-region
		 * at index 0 from the parent's memory-regions is assigned for
		 * the rvdev dev to allocate from. Failure is non-critical and
		 * the allocations will fall back to global pools, so don't
		 * check return value either.
		 */
		of_reserved_mem_device_init_by_idx(dev, np, 0);
390 391
	}

392 393 394 395 396 397
	/* Allocate virtio device */
	vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
	if (!vdev) {
		ret = -ENOMEM;
		goto out;
	}
398 399 400
	vdev->id.device	= id,
	vdev->config = &rproc_virtio_config_ops,
	vdev->dev.parent = dev;
401
	vdev->dev.release = rproc_virtio_dev_release;
402 403 404 405 406 407 408 409 410

	/*
	 * 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.
	 */
411
	get_device(&rproc->dev);
412

413 414 415
	/* Reference the vdev and vring allocations */
	kref_get(&rvdev->refcount);

416
	ret = register_virtio_device(vdev);
417
	if (ret) {
418
		put_device(&vdev->dev);
419
		dev_err(dev, "failed to register vdev: %d\n", ret);
420
		goto out;
421 422
	}

423 424 425
	dev_info(dev, "registered %s (type %d)\n", dev_name(&vdev->dev), id);

out:
426 427 428 429
	return ret;
}

/**
430
 * rproc_remove_virtio_dev() - remove an rproc-induced virtio device
431 432
 * @dev: the virtio device
 * @data: must be null
433
 *
434
 * This function unregisters an existing virtio device.
435 436
 *
 * Return: 0
437
 */
438
int rproc_remove_virtio_dev(struct device *dev, void *data)
439
{
440 441 442 443
	struct virtio_device *vdev = dev_to_virtio(dev);

	unregister_virtio_device(vdev);
	return 0;
444
}