Commit 94e8ca6e authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull remoteproc updates from Bjorn Andersson:
 "Support for remoteprocs that will perform recovery without help from
  Linux is introduced.

  The virtio integration is transitioned towards remoteproc_virtio.c and
  represented by a platform_device, in preparation for instantiating
  virtio instances from DeviceTree.

  The iMX remoteproc driver has a couple of sparse warnings corrected
  and a couple of error message printouts are cleaned up. The keystone
  driver is transitioned to use the gpiod API"

* tag 'rproc-v6.1' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux:
  remoteproc: virtio: Fix warning on bindings by removing the of_match_table
  remoteproc: Support attach recovery after rproc crash
  remoteproc: Introduce rproc features
  remoteproc: virtio: Create platform device for the remoteproc_virtio
  remoteproc: Move rproc_vdev management to remoteproc_virtio.c
  remoteproc: core: Introduce rproc_add_rvdev function
  remoteproc: core: Introduce rproc_rvdev_add_device function
  remoteproc: Harden rproc_handle_vdev() against integer overflow
  remoteproc/keystone: Switch to using gpiod API
  drivers/remoteproc: Fix repeated words in comments
  remoteproc: imx_dsp_rproc: fix argument 2 of rproc_mem_entry_init
  remoteproc: imx_rproc: Simplify some error message
parents e5df1d3e ccf22a48
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -599,7 +599,7 @@ static int imx_dsp_rproc_add_carveout(struct imx_dsp_rproc *priv)
		}

		/* Register memory region */
		mem = rproc_mem_entry_init(dev, cpu_addr, (dma_addr_t)att->sa,
		mem = rproc_mem_entry_init(dev, (void __force *)cpu_addr, (dma_addr_t)att->sa,
					   att->size, da, NULL, NULL, "dsp_mem");

		if (mem)
@@ -635,7 +635,7 @@ static int imx_dsp_rproc_add_carveout(struct imx_dsp_rproc *priv)
		}

		/* Register memory region */
		mem = rproc_mem_entry_init(dev, cpu_addr, (dma_addr_t)rmem->base,
		mem = rproc_mem_entry_init(dev, (void __force *)cpu_addr, (dma_addr_t)rmem->base,
					   rmem->size, da, NULL, NULL, it.node->name);

		if (mem)
+5 −9
Original line number Diff line number Diff line
@@ -646,7 +646,6 @@ static int imx_rproc_xtr_mbox_init(struct rproc *rproc)
	struct imx_rproc *priv = rproc->priv;
	struct device *dev = priv->dev;
	struct mbox_client *cl;
	int ret;

	if (!of_get_property(dev->of_node, "mbox-names", NULL))
		return 0;
@@ -659,18 +658,15 @@ static int imx_rproc_xtr_mbox_init(struct rproc *rproc)
	cl->rx_callback = imx_rproc_rx_callback;

	priv->tx_ch = mbox_request_channel_byname(cl, "tx");
	if (IS_ERR(priv->tx_ch)) {
		ret = PTR_ERR(priv->tx_ch);
		return dev_err_probe(cl->dev, ret,
				     "failed to request tx mailbox channel: %d\n", ret);
	}
	if (IS_ERR(priv->tx_ch))
		return dev_err_probe(cl->dev, PTR_ERR(priv->tx_ch),
				     "failed to request tx mailbox channel\n");

	priv->rx_ch = mbox_request_channel_byname(cl, "rx");
	if (IS_ERR(priv->rx_ch)) {
		mbox_free_channel(priv->tx_ch);
		ret = PTR_ERR(priv->rx_ch);
		return dev_err_probe(cl->dev, ret,
				     "failed to request rx mailbox channel: %d\n", ret);
		return dev_err_probe(cl->dev, PTR_ERR(priv->rx_ch),
				     "failed to request rx mailbox channel\n");
	}

	return 0;
+9 −7
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@
#include <linux/workqueue.h>
#include <linux/of_address.h>
#include <linux/of_reserved_mem.h>
#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
#include <linux/remoteproc.h>
@@ -59,10 +59,10 @@ struct keystone_rproc {
	int num_mems;
	struct regmap *dev_ctrl;
	struct reset_control *reset;
	struct gpio_desc *kick_gpio;
	u32 boot_offset;
	int irq_ring;
	int irq_fault;
	int kick_gpio;
	struct work_struct workqueue;
};

@@ -232,10 +232,10 @@ static void keystone_rproc_kick(struct rproc *rproc, int vqid)
{
	struct keystone_rproc *ksproc = rproc->priv;

	if (WARN_ON(ksproc->kick_gpio < 0))
	if (!ksproc->kick_gpio)
		return;

	gpio_set_value(ksproc->kick_gpio, 1);
	gpiod_set_value(ksproc->kick_gpio, 1);
}

/*
@@ -432,9 +432,9 @@ static int keystone_rproc_probe(struct platform_device *pdev)
		goto disable_clk;
	}

	ksproc->kick_gpio = of_get_named_gpio_flags(np, "kick-gpios", 0, NULL);
	if (ksproc->kick_gpio < 0) {
		ret = ksproc->kick_gpio;
	ksproc->kick_gpio = gpiod_get(dev, "kick", GPIOD_ASIS);
	ret = PTR_ERR_OR_ZERO(ksproc->kick_gpio);
	if (ret) {
		dev_err(dev, "failed to get gpio for virtio kicks, status = %d\n",
			ret);
		goto disable_clk;
@@ -466,6 +466,7 @@ static int keystone_rproc_probe(struct platform_device *pdev)

release_mem:
	of_reserved_mem_device_release(dev);
	gpiod_put(ksproc->kick_gpio);
disable_clk:
	pm_runtime_put_sync(dev);
disable_rpm:
@@ -480,6 +481,7 @@ static int keystone_rproc_remove(struct platform_device *pdev)
	struct keystone_rproc *ksproc = platform_get_drvdata(pdev);

	rproc_del(ksproc->rproc);
	gpiod_put(ksproc->kick_gpio);
	pm_runtime_put_sync(&pdev->dev);
	pm_runtime_disable(&pdev->dev);
	rproc_free(ksproc->rproc);
+66 −157
Original line number Diff line number Diff line
@@ -23,9 +23,7 @@
#include <linux/panic_notifier.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/dma-map-ops.h>
#include <linux/dma-mapping.h>
#include <linux/dma-direct.h> /* XXX: pokes into bus_dma_range */
#include <linux/firmware.h>
#include <linux/string.h>
#include <linux/debugfs.h>
@@ -346,7 +344,7 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
		if (rproc_check_carveout_da(rproc, mem, rsc->vring[i].da, size))
			return -ENOMEM;
	} else {
		/* Register carveout in in list */
		/* Register carveout in list */
		mem = rproc_mem_entry_init(dev, NULL, 0,
					   size, rsc->vring[i].da,
					   rproc_alloc_carveout,
@@ -384,7 +382,7 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
	return 0;
}

static int
int
rproc_parse_vring(struct rproc_vdev *rvdev, struct fw_rsc_vdev *rsc, int i)
{
	struct rproc *rproc = rvdev->rproc;
@@ -435,57 +433,17 @@ void rproc_free_vring(struct rproc_vring *rvring)
	}
}

static int rproc_vdev_do_start(struct rproc_subdev *subdev)
{
	struct rproc_vdev *rvdev = container_of(subdev, struct rproc_vdev, subdev);

	return rproc_add_virtio_dev(rvdev, rvdev->id);
}

static void rproc_vdev_do_stop(struct rproc_subdev *subdev, bool crashed)
void rproc_add_rvdev(struct rproc *rproc, struct rproc_vdev *rvdev)
{
	struct rproc_vdev *rvdev = container_of(subdev, struct rproc_vdev, subdev);
	int ret;

	ret = device_for_each_child(&rvdev->dev, NULL, rproc_remove_virtio_dev);
	if (ret)
		dev_warn(&rvdev->dev, "can't remove vdev child device: %d\n", ret);
}

/**
 * rproc_rvdev_release() - release the existence of a rvdev
 *
 * @dev: the subdevice's dev
 */
static void rproc_rvdev_release(struct device *dev)
{
	struct rproc_vdev *rvdev = container_of(dev, struct rproc_vdev, dev);

	of_reserved_mem_device_release(dev);
	dma_release_coherent_memory(dev);

	kfree(rvdev);
	if (rvdev && rproc)
		list_add_tail(&rvdev->node, &rproc->rvdevs);
}

static int copy_dma_range_map(struct device *to, struct device *from)
void rproc_remove_rvdev(struct rproc_vdev *rvdev)
{
	const struct bus_dma_region *map = from->dma_range_map, *new_map, *r;
	int num_ranges = 0;

	if (!map)
		return 0;

	for (r = map; r->size; r++)
		num_ranges++;

	new_map = kmemdup(map, array_size(num_ranges + 1, sizeof(*map)),
			  GFP_KERNEL);
	if (!new_map)
		return -ENOMEM;
	to->dma_range_map = new_map;
	return 0;
	if (rvdev)
		list_del(&rvdev->node);
}

/**
 * rproc_handle_vdev() - handle a vdev fw resource
 * @rproc: the remote processor
@@ -520,12 +478,13 @@ static int rproc_handle_vdev(struct rproc *rproc, void *ptr,
	struct fw_rsc_vdev *rsc = ptr;
	struct device *dev = &rproc->dev;
	struct rproc_vdev *rvdev;
	int i, ret;
	char name[16];
	size_t rsc_size;
	struct rproc_vdev_data rvdev_data;
	struct platform_device *pdev;

	/* make sure resource isn't truncated */
	if (struct_size(rsc, vring, rsc->num_of_vrings) + rsc->config_len >
			avail) {
	rsc_size = struct_size(rsc, vring, rsc->num_of_vrings);
	if (size_add(rsc_size, rsc->config_len) > avail) {
		dev_err(dev, "vdev rsc is truncated\n");
		return -EINVAL;
	}
@@ -545,93 +504,19 @@ static int rproc_handle_vdev(struct rproc *rproc, void *ptr,
		return -EINVAL;
	}

	rvdev = kzalloc(sizeof(*rvdev), GFP_KERNEL);
	if (!rvdev)
		return -ENOMEM;

	kref_init(&rvdev->refcount);

	rvdev->id = rsc->id;
	rvdev->rproc = rproc;
	rvdev->index = rproc->nb_vdev++;

	/* Initialise vdev subdevice */
	snprintf(name, sizeof(name), "vdev%dbuffer", rvdev->index);
	rvdev->dev.parent = &rproc->dev;
	rvdev->dev.release = rproc_rvdev_release;
	dev_set_name(&rvdev->dev, "%s#%s", dev_name(rvdev->dev.parent), name);
	dev_set_drvdata(&rvdev->dev, rvdev);

	ret = device_register(&rvdev->dev);
	if (ret) {
		put_device(&rvdev->dev);
		return ret;
	}

	ret = copy_dma_range_map(&rvdev->dev, rproc->dev.parent);
	if (ret)
		goto free_rvdev;

	/* Make device dma capable by inheriting from parent's capabilities */
	set_dma_ops(&rvdev->dev, get_dma_ops(rproc->dev.parent));
	rvdev_data.id = rsc->id;
	rvdev_data.index = rproc->nb_vdev++;
	rvdev_data.rsc_offset = offset;
	rvdev_data.rsc = rsc;

	ret = dma_coerce_mask_and_coherent(&rvdev->dev,
					   dma_get_mask(rproc->dev.parent));
	if (ret) {
		dev_warn(dev,
			 "Failed to set DMA mask %llx. Trying to continue... (%pe)\n",
			 dma_get_mask(rproc->dev.parent), ERR_PTR(ret));
	}

	/* parse the vrings */
	for (i = 0; i < rsc->num_of_vrings; i++) {
		ret = rproc_parse_vring(rvdev, rsc, i);
		if (ret)
			goto free_rvdev;
	pdev = platform_device_register_data(dev, "rproc-virtio", rvdev_data.index, &rvdev_data,
					     sizeof(rvdev_data));
	if (IS_ERR(pdev)) {
		dev_err(dev, "failed to create rproc-virtio device\n");
		return PTR_ERR(pdev);
	}

	/* remember the resource offset*/
	rvdev->rsc_offset = offset;

	/* allocate the vring resources */
	for (i = 0; i < rsc->num_of_vrings; i++) {
		ret = rproc_alloc_vring(rvdev, i);
		if (ret)
			goto unwind_vring_allocations;
	}

	list_add_tail(&rvdev->node, &rproc->rvdevs);

	rvdev->subdev.start = rproc_vdev_do_start;
	rvdev->subdev.stop = rproc_vdev_do_stop;

	rproc_add_subdev(rproc, &rvdev->subdev);

	return 0;

unwind_vring_allocations:
	for (i--; i >= 0; i--)
		rproc_free_vring(&rvdev->vring[i]);
free_rvdev:
	device_unregister(&rvdev->dev);
	return ret;
}

void rproc_vdev_release(struct kref *ref)
{
	struct rproc_vdev *rvdev = container_of(ref, struct rproc_vdev, refcount);
	struct rproc_vring *rvring;
	struct rproc *rproc = rvdev->rproc;
	int id;

	for (id = 0; id < ARRAY_SIZE(rvdev->vring); id++) {
		rvring = &rvdev->vring[id];
		rproc_free_vring(rvring);
	}

	rproc_remove_subdev(rproc, &rvdev->subdev);
	list_del(&rvdev->node);
	device_unregister(&rvdev->dev);
}

/**
@@ -1365,7 +1250,7 @@ void rproc_resource_cleanup(struct rproc *rproc)

	/* clean up remote vdev entries */
	list_for_each_entry_safe(rvdev, rvtmp, &rproc->rvdevs, node)
		kref_put(&rvdev->refcount, rproc_vdev_release);
		platform_device_unregister(rvdev->pdev);

	rproc_coredump_cleanup(rproc);
}
@@ -1885,6 +1770,45 @@ static int __rproc_detach(struct rproc *rproc)
	return 0;
}

static int rproc_attach_recovery(struct rproc *rproc)
{
	int ret;

	ret = __rproc_detach(rproc);
	if (ret)
		return ret;

	return __rproc_attach(rproc);
}

static int rproc_boot_recovery(struct rproc *rproc)
{
	const struct firmware *firmware_p;
	struct device *dev = &rproc->dev;
	int ret;

	ret = rproc_stop(rproc, true);
	if (ret)
		return ret;

	/* generate coredump */
	rproc->ops->coredump(rproc);

	/* load firmware */
	ret = request_firmware(&firmware_p, rproc->firmware, dev);
	if (ret < 0) {
		dev_err(dev, "request_firmware failed: %d\n", ret);
		return ret;
	}

	/* boot the remote processor up again */
	ret = rproc_start(rproc, firmware_p);

	release_firmware(firmware_p);

	return ret;
}

/**
 * rproc_trigger_recovery() - recover a remoteproc
 * @rproc: the remote processor
@@ -1899,7 +1823,6 @@ static int __rproc_detach(struct rproc *rproc)
 */
int rproc_trigger_recovery(struct rproc *rproc)
{
	const struct firmware *firmware_p;
	struct device *dev = &rproc->dev;
	int ret;

@@ -1913,24 +1836,10 @@ int rproc_trigger_recovery(struct rproc *rproc)

	dev_err(dev, "recovering %s\n", rproc->name);

	ret = rproc_stop(rproc, true);
	if (ret)
		goto unlock_mutex;

	/* generate coredump */
	rproc->ops->coredump(rproc);

	/* load firmware */
	ret = request_firmware(&firmware_p, rproc->firmware, dev);
	if (ret < 0) {
		dev_err(dev, "request_firmware failed: %d\n", ret);
		goto unlock_mutex;
	}

	/* boot the remote processor up again */
	ret = rproc_start(rproc, firmware_p);

	release_firmware(firmware_p);
	if (rproc_has_feature(rproc, RPROC_FEAT_ATTACH_ON_RECOVERY))
		ret = rproc_attach_recovery(rproc);
	else
		ret = rproc_boot_recovery(rproc);

unlock_mutex:
	mutex_unlock(&rproc->lock);
+34 −4
Original line number Diff line number Diff line
@@ -24,16 +24,43 @@ struct rproc_debug_trace {
	struct rproc_mem_entry trace_mem;
};

/**
 * struct rproc_vdev_data - remoteproc virtio device data
 * @rsc_offset: offset of the vdev's resource entry
 * @id: virtio device id (as in virtio_ids.h)
 * @index: vdev position versus other vdev declared in resource table
 * @rsc: pointer to the vdev resource entry. Valid only during vdev init as
 *       the resource can be cached by rproc.
 */
struct rproc_vdev_data {
	u32 rsc_offset;
	unsigned int id;
	u32 index;
	struct fw_rsc_vdev *rsc;
};

static inline bool rproc_has_feature(struct rproc *rproc, unsigned int feature)
{
	return test_bit(feature, rproc->features);
}

static inline int rproc_set_feature(struct rproc *rproc, unsigned int feature)
{
	if (feature >= RPROC_MAX_FEATURES)
		return -EINVAL;

	set_bit(feature, rproc->features);

	return 0;
}

/* from remoteproc_core.c */
void rproc_release(struct kref *kref);
irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int vq_id);
void rproc_vdev_release(struct kref *ref);
int rproc_of_parse_firmware(struct device *dev, int index,
			    const char **fw_name);

/* from remoteproc_virtio.c */
int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id);
int rproc_remove_virtio_dev(struct device *dev, void *data);
irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int vq_id);

/* from remoteproc_debugfs.c */
void rproc_remove_trace_file(struct dentry *tfile);
@@ -83,6 +110,7 @@ static inline void rproc_char_device_remove(struct rproc *rproc)

void rproc_free_vring(struct rproc_vring *rvring);
int rproc_alloc_vring(struct rproc_vdev *rvdev, int i);
int rproc_parse_vring(struct rproc_vdev *rvdev, struct fw_rsc_vdev *rsc, int i);

phys_addr_t rproc_va_to_pa(void *cpu_addr);
int rproc_trigger_recovery(struct rproc *rproc);
@@ -95,6 +123,8 @@ struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
						       const struct firmware *fw);
struct rproc_mem_entry *
rproc_find_carveout_by_name(struct rproc *rproc, const char *name, ...);
void rproc_add_rvdev(struct rproc *rproc, struct rproc_vdev *rvdev);
void rproc_remove_rvdev(struct rproc_vdev *rvdev);

static inline int rproc_prepare_device(struct rproc *rproc)
{
Loading