[PATCH 03/16] remoteproc: Add support to handle device specific resource types

Roger Quadros
2018-11-26T07:52:36Z

From: Suman Anna <s-anna@ti.com>

The remoteproc framework handles a fixed set of resource table entries
today. To make it scalable across multiple platforms, it makes sense
for the framework to provide a way for the device specific implementation
to define and handle vendor specific resource types. These resource types
would be very specific to an implementation instance that it does not
make sense for the framework to handle it. There can be two types of
such resources depending on whether they need to be handled prior to
the loading of the firmware segments or after. A post-loading resource
type is typically needed because it references a loaded segment pointer
for conveying the resource information.

For instance, a remoteproc implementation might want timers information
embedded in the resource table so that the driver could parse the binary
and enable accordingly. Another example would be hwspinlocks that it
is using, to properly share system wide resources. A PRU post-loading
vendor resource handler for interrupts requires the PRU event - interrupt
channel information to be loaded into device memory.

This patch adds a function pointer to the list of rproc_ops for the
driver implementation to handle such custom vendor resources, and
reuses the same handler between pre-loading and post-loading resource
types, with the sub-types in the implementation handling the processing
of those resource types.

Signed-off-by: Suman Anna <s-anna@ti.com>

merge: remoteproc: simplify VENDOR specific resource

We don't need PRE and POST loading as we'll fix the PRU resource
table to be self sufficient.

Earlier it was half baked with channel mapping located elsewhere
in data section thus requiring data section to be loaded before
we can figure out the full INTC map.

Fix vendor resource to be TLV and definition agnostic.

Show in debugfs.

Signed-off-by: Roger Quadros <rogerq@ti.com>
---
drivers/remoteproc/remoteproc_core.c | 36 +++++++++++++++++++++++++++++++++
drivers/remoteproc/remoteproc_debugfs.c | 3 +++
include/linux/remoteproc.h | 15 +++++++++++++-
3 files changed, 53 insertions(+), 1 deletion(-)

diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 581e6e8..9e387ab 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -898,6 +898,41 @@ void rproc_add_carveout(struct rproc *rproc, struct rproc_mem_entry *mem)
EXPORT_SYMBOL(rproc_add_carveout);

/**
+ * rproc_handle_vendor_rsc() - provide implementation specific hook
+ * to handle vendor/custom resources
+ * @rproc: the remote processor
+ * @rsc: vendor resource to be handled by remoteproc drivers
+ * @offset: offset of the resource data in resource table
+ * @avail: size of available data
+ *
+ * Remoteproc implementations might want to add resource table entries
+ * that are not generic enough to be handled by the framework. This
+ * provides a hook to handle such custom resources.
+ *
+ * Returns 0 on success, or an appropriate error code otherwise
+ */
+static int rproc_handle_vendor_rsc(struct rproc *rproc,
+ struct fw_rsc_vendor *rsc,
+ int offset, int avail)
+{
+ struct device *dev = &rproc->dev;
+
+ if (sizeof(*rsc) > avail) {
+ dev_err(dev, "vendor rsc is truncated\n");
+ return -EINVAL;
+ }
+
+ dev_dbg(dev, "vendor rsc:");
+
+ if (!rproc->ops->handle_vendor_rsc) {
+ dev_err(dev, "no vendor rsc handler! ignoring resource\n");
+ return 0;
+ }
+
+ return rproc->ops->handle_vendor_rsc(rproc, (void *)rsc);
+}
+
+/**
* rproc_mem_entry_init() - allocate and initialize rproc_mem_entry struct
* @dev: pointer on device struct
* @va: virtual address
@@ -985,6 +1020,7 @@ static rproc_handle_resource_t rproc_loading_handlers[RSC_LAST] = {
[RSC_CARVEOUT] = (rproc_handle_resource_t)rproc_handle_carveout,
[RSC_DEVMEM] = (rproc_handle_resource_t)rproc_handle_devmem,
[RSC_TRACE] = (rproc_handle_resource_t)rproc_handle_trace,
+ [RSC_VENDOR] = (rproc_handle_resource_t)rproc_handle_vendor_rsc,
[RSC_VDEV] = (rproc_handle_resource_t)rproc_handle_vdev,
};

diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c
index f330a9a..971c8ba 100644
--- a/drivers/remoteproc/remoteproc_debugfs.c
+++ b/drivers/remoteproc/remoteproc_debugfs.c
@@ -254,6 +254,9 @@ static int rproc_rsc_table_show(struct seq_file *seq, void *p)
v->vring[j].pa);
}
break;
+ case RSC_VENDOR:
+ seq_printf(seq, "Entry %d is of type %s [Vendor specific]\n",
+ i, types[hdr->type]);
default:
seq_printf(seq, "Unknown resource type found: %d [hdr: %pK]\n",
hdr->type, hdr);
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 063468b..4881415 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -101,6 +101,7 @@ struct fw_rsc_hdr {
* the remote processor will be writing logs.
* @RSC_VDEV: declare support for a virtio device, and serve as its
* virtio header.
+ * @RSC_VENDOR: vendor specific resource type.
* @RSC_LAST: just keep this one at the end
*
* For more details regarding a specific resource type, please see its
@@ -116,7 +117,8 @@ enum fw_resource_type {
RSC_DEVMEM = 1,
RSC_TRACE = 2,
RSC_VDEV = 3,
- RSC_LAST = 4,
+ RSC_VENDOR = 4,
+ RSC_LAST,
};

#define FW_RSC_ADDR_ANY (-1)
@@ -309,6 +311,14 @@ struct fw_rsc_vdev {
struct rproc;

/**
+ * struct fw_rsc_vendor - vendor specific resource definition
+ * @data: resource data. vendor defined.
+ */
+struct fw_rsc_vendor {
+ u8 data[0];
+} __packed;
+
+/**
* struct rproc_mem_entry - memory entry descriptor
* @va: virtual address
* @dma: dma address
@@ -361,6 +371,7 @@ struct firmware;
* @da_to_va: optional platform hook to perform address translations
* @parse_fw: parse firmware to extract information (e.g. resource table)
* @find_loaded_rsc_table: find the loaded resouce table
+ * @handle_vendor_rsc: hook to handle device specific resource table entries
* @load: load firmware to memory, where the remote processor
* expects to find it
* @sanity_check: sanity check the fw image
@@ -374,6 +385,8 @@ struct rproc_ops {
int (*parse_fw)(struct rproc *rproc, const struct firmware *fw);
struct resource_table *(*find_loaded_rsc_table)(
struct rproc *rproc, const struct firmware *fw);
+ int (*handle_vendor_rsc)(struct rproc *rproc,
+ struct fw_rsc_vendor *rsc);
int (*load)(struct rproc *rproc, const struct firmware *fw);
int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);