2017-03-24 19:30:39

by Wendy Liang

[permalink] [raw]
Subject: [RFC LINUX PATCH 00/19] Allow master to restart without restarting slave


This patch allows remoteproc master to restart without restarting the slave

remoteproc master starts a remote, it will check the following:
* if the remote is running,
* if yes, it will check if therere is firmware checksum in the rsc table
* if yes, it will calculate the firmware checksum with the loadable
firmware sections, and compare the one in the rsc table
* if the checksum matches, remtoeproc thinks it is already running
the firmware, and it will not reboot the remote. However, it will
set the virtio status to request virtio remotepro reset. The
remote should reset virtio related when it sees the virtio status
shows the master requested reset.

* if the remote is running, but not running the expected firmware, it will
stop the remote and then boot it.

* if the remote is not running, it will load the firmware and start the
remote.

Wendy Liang (19):
remoteproc: Add is_runinng to remoteproc ops
remtoeproc: Add an operation to check if remote is running
remoteproc: Add a running independent state
remoteproc: sysfs: Add running independent state
remoteproc: check if remote is running the fw before reload fw
remoteproc: elf loader: Add get checksum firmware implementation
remoteproc: Add firmware checksum resource entry
remoteproc: add a function to set fw checksum rsc
remoteproc: check firmware checksum in rproc_is_running_fw()
remoteproc: Add rproc resource with id struct
remoteproc: Add rproc_idr_alloc/remove wrapper
remoteproc: use rproc_id_rsc for data got from idr_find()
remoteproc: add config_wait_complete to rproc_vdev
remoteproc virtio: handle rproc vdev notification
remoteproc: virtio: rename rproc_virtio_notify to rproc_vq_notify
remoteproc: virtio: use rproc_virtio_notify() to notify vdev changes
remoteproc: virtio: kick in reset virtio
remoteproc: shutdown: set state to OFFLINE after stopping remote
remoteproc: virtio: idr_alloc for rvdev

drivers/remoteproc/Kconfig | 1 +
drivers/remoteproc/remoteproc_core.c | 251 ++++++++++++++++++++++++-----
drivers/remoteproc/remoteproc_elf_loader.c | 109 +++++++++++++
drivers/remoteproc/remoteproc_internal.h | 32 ++++
drivers/remoteproc/remoteproc_sysfs.c | 7 +-
drivers/remoteproc/remoteproc_virtio.c | 105 ++++++++++--
include/linux/remoteproc.h | 24 ++-
7 files changed, 479 insertions(+), 50 deletions(-)

--
1.9.1


2017-03-24 19:30:28

by Wendy Liang

[permalink] [raw]
Subject: [RFC LINUX PATCH 09/19] remoteproc: check firmware checksum in rproc_is_running_fw()

From: Wendy Liang <[email protected]>

In rproc_is_running_fw() function, set the firmware checksum in resource
in the resource table and compared it with the one in the loaded resource
table.

If the firmware checksum in the loaded resource table matches the one
calculated with the firmware, the remote is running with the expected
firmware.

Signed-off-by: Wendy Liang <[email protected]>
Signed-off-by: Michal Simek <[email protected]>
---
drivers/remoteproc/remoteproc_core.c | 29 ++++++++++++++++++++++++++---
1 file changed, 26 insertions(+), 3 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 447c28b..e4fb289 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -956,10 +956,33 @@ struct fw_rsc_fw_chksum *rproc_handle_fw_chksum(struct rproc *rproc,
*/
static bool rproc_is_running_fw(struct rproc *rproc, const struct firmware *fw)
{
- (void)rproc;
- (void) fw;
+ struct resource_table *loaded_table;
+ struct fw_rsc_fw_chksum *rsc, *loaded_rsc;
+ int rsc_fw_chksum_offset;

- return false;
+ rsc = rproc_handle_fw_chksum(rproc, fw, &rsc_fw_chksum_offset);
+ if (!rsc)
+ return false;
+
+ if (!rproc_is_running(rproc))
+ return false;
+
+ /* look for the loaded resource table */
+ loaded_table = rproc_find_loaded_rsc_table(rproc, fw);
+ if (!loaded_table)
+ return false;
+
+ loaded_rsc = (void *)loaded_table + rsc_fw_chksum_offset;
+ if (!loaded_rsc->algo || !loaded_rsc->chksum)
+ return false;
+
+ if (strncmp(rsc->algo, loaded_rsc->algo, strlen(rsc->algo)))
+ return false;
+
+ if (memcmp(rsc->chksum, loaded_rsc->chksum, sizeof(rsc->chksum)))
+ return false;
+
+ return true;
}

/*
--
1.9.1

2017-03-24 19:30:45

by Wendy Liang

[permalink] [raw]
Subject: [RFC LINUX PATCH 07/19] remoteproc: Add firmware checksum resource entry

From: Wendy Liang <[email protected]>

Add a firmware checksum resource entry type to store the checksum
of the firmware in the resource table.

In the remoteproc driver firmware booting process, it can check
if the remote already runs the expected firmware so that it can
decide if it needs to restart the remote if the remote already
runs.

Signed-off-by: Wendy Liang <[email protected]>
Signed-off-by: Michal Simek <[email protected]>
---
include/linux/remoteproc.h | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index b740b93..303210b 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -116,7 +116,8 @@ enum fw_resource_type {
RSC_TRACE = 2,
RSC_VDEV = 3,
RSC_RPROC_MEM = 4,
- RSC_LAST = 5,
+ RSC_FW_CHKSUM = 5,
+ RSC_LAST = 6,
};

#define FW_RSC_ADDR_ANY (-1)
@@ -327,6 +328,20 @@ struct fw_rsc_rproc_mem {
} __packed;

/**
+ * struct fw_rsc_fw_chksum - firmware checksum
+ * @algo: algorithm to generate the cheksum
+ * @chksum: checksum of the firmware loadable sections.
+ *
+ * This resource entry provides checksum for the firmware loadable sections.
+ * It is used to check if the remote already runs with the expected firmware to
+ * decide if it needs to start the remote if the remote is already running.
+ */
+struct fw_rsc_fw_chksum {
+ u8 algo[16];
+ u8 chksum[64];
+} __packed;
+
+/**
* struct rproc_mem_entry - memory entry descriptor
* @va: virtual address
* @dma: dma address
--
1.9.1

2017-03-24 19:31:16

by Wendy Liang

[permalink] [raw]
Subject: [RFC LINUX PATCH 18/19] remoteproc: shutdown: set state to OFFLINE after stopping remote

From: Wendy Liang <[email protected]>

Set rproc state to OFFLINE right after it stops the remote.
Some remoteproc virtio operations depends on rproc state. And thus,
we should set the rproc state to OFFLINE right after it stops
the remote.

Signed-off-by: Wendy Liang <[email protected]>
Signed-off-by: Michal Simek <[email protected]>
---
drivers/remoteproc/remoteproc_core.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index ffd1de2..62c0356 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -1369,6 +1369,7 @@ void rproc_shutdown(struct rproc *rproc)
{
struct device *dev = &rproc->dev;
int ret;
+ int pre_rproc_state;

ret = mutex_lock_interruptible(&rproc->lock);
if (ret) {
@@ -1391,6 +1392,9 @@ void rproc_shutdown(struct rproc *rproc)
goto out;
}

+ pre_rproc_state = rproc->state;
+ rproc->state = RPROC_OFFLINE;
+
/* clean up all acquired resources */
rproc_resource_cleanup(rproc);

@@ -1402,11 +1406,9 @@ void rproc_shutdown(struct rproc *rproc)
rproc->table_ptr = NULL;

/* if in crash state, unlock crash handler */
- if (rproc->state == RPROC_CRASHED)
+ if (pre_rproc_state == RPROC_CRASHED)
complete_all(&rproc->crash_comp);

- rproc->state = RPROC_OFFLINE;
-
dev_info(dev, "stopped remote processor %s\n", rproc->name);

out:
--
1.9.1

2017-03-24 19:31:26

by Wendy Liang

[permalink] [raw]
Subject: [RFC LINUX PATCH 17/19] remoteproc: virtio: kick in reset virtio

From: Wendy Liang <[email protected]>

Kick the remote in virtio reset.
In order to be backward compatible, only set the vdev
status to NEEDS_RESET and kick the remote if the remote is
RUNNING_INDEPENDENT, that is only if the remote is already
running.

Signed-off-by: Wendy Liang <[email protected]>
Signed-off-by: Michal Simek <[email protected]>
---
drivers/remoteproc/remoteproc_virtio.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c
index d43e15b..bf3be6f1 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -231,8 +231,19 @@ static void rproc_virtio_reset(struct virtio_device *vdev)

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

- rsc->status = 0;
dev_dbg(&vdev->dev, "reset !\n");
+ if (rvdev->rproc->state == RPROC_RUNNING_INDEPENDENT) {
+ rsc->status = VIRTIO_CONFIG_S_NEEDS_RESET;
+ virtio_mb(false);
+ rproc_virtio_notify(rvdev);
+ while (rsc->status) {
+ if (!wait_for_completion_timeout(
+ &rvdev->config_wait_complete, HZ))
+ break;
+ }
+ } else {
+ rsc->status = 0;
+ }
}

/* provide the vdev features as retrieved from the firmware */
--
1.9.1

2017-03-24 19:31:38

by Wendy Liang

[permalink] [raw]
Subject: [RFC LINUX PATCH 16/19] remoteproc: virtio: use rproc_virtio_notify() to notify vdev changes

From: Wendy Liang <[email protected]>

Use rproc_virtio_notify() to notify vdev config changes.

Signed-off-by: Wendy Liang <[email protected]>
Signed-off-by: Michal Simek <[email protected]>
---
drivers/remoteproc/remoteproc_virtio.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)

diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c
index cc421f3..d43e15b 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -29,6 +29,20 @@

#include "remoteproc_internal.h"

+/* kick the remote processor, and let it know the virtio dev has update */
+static bool rproc_virtio_notify(struct rproc_vdev *rvdev)
+{
+ struct rproc *rproc;
+ struct fw_rsc_vdev *rsc;
+
+ if (!rvdev)
+ return false;
+ rproc = rvdev->rproc;
+ rsc = (void *)rproc->table_ptr + rvdev->rsc_offset;
+ rproc->ops->kick(rproc, rsc->notifyid);
+ return true;
+}
+
/* kick the remote processor, and let it know which virtqueue to poke at */
static bool rproc_vq_notify(struct virtqueue *vq)
{
--
1.9.1

2017-03-24 19:31:51

by Wendy Liang

[permalink] [raw]
Subject: [RFC LINUX PATCH 11/19] remoteproc: Add rproc_idr_alloc/remove wrapper

From: Wendy Liang <[email protected]>

Add rproc_idr_alloc()/rproc_idr_remove() wrapper for
id allocation/removal.

Signed-off-by: Wendy Liang <[email protected]>
Signed-off-by: Michal Simek <[email protected]>
---
drivers/remoteproc/remoteproc_core.c | 46 ++++++++++++++++++++++++++++++++
drivers/remoteproc/remoteproc_internal.h | 6 +++++
2 files changed, 52 insertions(+)

diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index e4fb289..d711345 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -140,6 +140,52 @@ static void rproc_disable_iommu(struct rproc *rproc)
}

/**
+ * rproc_idr_alloc() - allocate id with idr_alloc()
+ * @rproc: handle of a remote processor
+ * @ptr: pointer to the resource to allocate id for
+ * @rsc_type: type of the resource for which to allocate id
+ * @start: start id
+ * @end: end id
+ *
+ * This function returns an ID from idr_alloc() or negative number
+ * if it fails.
+ */
+int rproc_idr_alloc(struct rproc *rproc, void *ptr, unsigned int rsc_type,
+ int start, int end)
+{
+ struct rproc_id_rsc *rsc;
+ int ret;
+
+ rsc = kzalloc(sizeof(*rsc), GFP_KERNEL);
+ if (!rsc)
+ return -ENOMEM;
+
+ rsc->rsc_ptr = ptr;
+ rsc->rsc_type = rsc_type;
+
+ ret = idr_alloc(&rproc->notifyids, rsc, start, end, GFP_KERNEL);
+ if (ret < 0)
+ kfree(rsc);
+ return ret;
+}
+
+/**
+ * rproc_idr_remove() - remove id with idr_remove()
+ * @rproc: handle of a remote processor
+ * @id: id to remove
+ */
+void rproc_idr_remove(struct rproc *rproc, int id)
+{
+ struct rproc_id_rsc *rsc;
+
+ rsc = idr_find(&rproc->notifyids, id);
+ if (!rsc)
+ return;
+ idr_remove(&rproc->notifyids, id);
+ kfree(rsc);
+}
+
+/**
* rproc_da_to_va() - lookup the kernel virtual address for a remoteproc address
* @rproc: handle of a remote processor
* @da: remoteproc device address to translate
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index 7e25621..865bd1c 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -94,6 +94,12 @@ struct dentry *rproc_create_trace_file(const char *name, struct rproc *rproc,
int rproc_init_sysfs(void);
void rproc_exit_sysfs(void);

+/* rproc idr_alloc wrapper */
+int rproc_idr_alloc(struct rproc *rproc, void *ptr, unsigned int rsc_type,
+ int start, int end);
+/* rproc idr_remove wrapper */
+void rproc_idr_remove(struct rproc *rproc, int id);
+
void rproc_free_vring(struct rproc_vring *rvring);
int rproc_alloc_vring(struct rproc_vdev *rvdev, int i);

--
1.9.1

2017-03-24 19:32:02

by Wendy Liang

[permalink] [raw]
Subject: [RFC LINUX PATCH 19/19] remoteproc: virtio: idr_alloc for rvdev

From: Wendy Liang <[email protected]>

use idr_alloc to allocate notifyid for rvdev and set it
to the resource table.

Signed-off-by: Wendy Liang <[email protected]>
Signed-off-by: Michal Simek <[email protected]>
---
drivers/remoteproc/remoteproc_core.c | 4 +---
drivers/remoteproc/remoteproc_virtio.c | 29 +++++++++++++++++++++++++++++
2 files changed, 30 insertions(+), 3 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 62c0356..35cebd8 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -271,12 +271,10 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)

/*
* Assign an rproc-wide unique index for this vring
- * TODO: assign a notifyid for rvdev updates as well
- * TODO: support predefined notifyids (via resource table)
*/
ret = rproc_idr_alloc(rproc, rvring, RPROC_IDR_VRING, 0, 0);
if (ret < 0) {
- dev_err(dev, "idr_alloc failed: %d\n", ret);
+ dev_err(dev, "rvfing idr_alloc failed: %d\n", ret);
dma_free_coherent(dev->parent, size, va, dma);
return ret;
}
diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c
index bf3be6f1..117e7e3 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -361,6 +361,8 @@ int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id)
struct device *dev = &rproc->dev;
struct virtio_device *vdev = &rvdev->vdev;
int ret;
+ int idr_start, idr_end;
+ struct fw_rsc_vdev *rsc;

vdev->id.device = id,
vdev->config = &rproc_virtio_config_ops,
@@ -381,6 +383,27 @@ int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id)
/* Reference the vdev and vring allocations */
kref_get(&rvdev->refcount);

+ /*
+ * Assign an rproc-wide unique index for this rvdev
+ */
+ rsc = (void *)rproc->table_ptr + rvdev->rsc_offset;
+ idr_start = 0;
+ idr_end = 0;
+ if (rsc->notifyid != FW_RSC_ADDR_ANY) {
+ if (!idr_find(&rproc->notifyids, rsc->notifyid)) {
+ idr_start = rsc->notifyid;
+ idr_end = idr_start + 1;
+ }
+ }
+
+ ret = rproc_idr_alloc(rproc, rvdev, RPROC_IDR_VDEV,
+ idr_start, idr_end);
+ if (ret < 0) {
+ dev_err(dev, "rvdev idr_alloc failed: %d\n", ret);
+ return ret;
+ }
+ rsc->notifyid = ret;
+
ret = register_virtio_device(vdev);
if (ret) {
put_device(&rproc->dev);
@@ -402,5 +425,11 @@ int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id)
*/
void rproc_remove_virtio_dev(struct rproc_vdev *rvdev)
{
+ struct rproc *rproc = rvdev->rproc;
+ struct fw_rsc_vdev *rsc;
+
+ rsc = (void *)rproc->table_ptr + rvdev->rsc_offset;
+ rproc_idr_remove(rproc, rsc->notifyid);
+
unregister_virtio_device(&rvdev->vdev);
}
--
1.9.1

2017-03-24 19:32:12

by Wendy Liang

[permalink] [raw]
Subject: [RFC LINUX PATCH 13/19] remoteproc: add config_wait_complete to rproc_vdev

From: Wendy Liang <[email protected]>

Add config_wait_complete to rproc_vdev.
This attribute is used for vdev config operation to
wait for the remote to respond. When there is a
notification comes from the remote, it can wake up
the waiting client by marking this attribute.

Signed-off-by: Wendy Liang <[email protected]>
Signed-off-by: Michal Simek <[email protected]>
---
drivers/remoteproc/remoteproc_virtio.c | 1 +
include/linux/remoteproc.h | 2 ++
2 files changed, 3 insertions(+)

diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c
index e45e17b..c6f7ca4 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -340,6 +340,7 @@ int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id)
vdev->dev.parent = dev;
vdev->dev.release = rproc_virtio_dev_release;

+ init_completion(&rvdev->config_wait_complete);
/*
* We're indirectly making a non-temporary copy of the rproc pointer
* here, because drivers probed with this vdev will indirectly
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 303210b..4ce7579 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -534,6 +534,7 @@ struct rproc_vring {
* @vdev: the virio device
* @vring: the vrings for this vdev
* @rsc_offset: offset of the vdev's resource entry
+ * @config_wait_complete: mark asynchronous vdev config wait complete
*/
struct rproc_vdev {
struct kref refcount;
@@ -546,6 +547,7 @@ struct rproc_vdev {
struct virtio_device vdev;
struct rproc_vring vring[RVDEV_NUM_VRINGS];
u32 rsc_offset;
+ struct completion config_wait_complete;
};

struct rproc *rproc_get_by_phandle(phandle phandle);
--
1.9.1

2017-03-24 19:32:22

by Wendy Liang

[permalink] [raw]
Subject: [RFC LINUX PATCH 10/19] remoteproc: Add rproc resource with id struct

From: Wendy Liang <[email protected]>

Add a struct to keep the rproc resources which have been
assinged with ids.

Signed-off-by: Wendy Liang <[email protected]>
Signed-off-by: Michal Simek <[email protected]>
---
drivers/remoteproc/remoteproc_internal.h | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)

diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index f03e07a..7e25621 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -23,6 +23,28 @@
#include <linux/irqreturn.h>
#include <linux/firmware.h>

+
+/**
+ * enum rproc_id_rsc_type - types of data which needs idr
+ *
+ * @RPROC_IDR_VDEV: rproc vdev data type
+ * @RPROC_IDR_VRING: rpring vring data type
+ */
+enum rproc_id_rsc_type {
+ RPROC_IDR_VDEV = 0,
+ RPROC_IDR_VRING = 1,
+};
+
+/**
+ * struct rproc_id_rsc - rproc resource with assigned id
+ * @rsc_type: type of resource
+ * @rsc_ptr: pointer to the resource data;
+ */
+struct rproc_id_rsc {
+ unsigned int rsc_type;
+ void *rsc_ptr;
+};
+
struct rproc;

/**
--
1.9.1

2017-03-24 19:32:35

by Wendy Liang

[permalink] [raw]
Subject: [RFC LINUX PATCH 12/19] remoteproc: use rproc_id_rsc for data got from idr_find()

From: Wendy Liang <[email protected]>

As not just rproc_vring can have notifyid, rproc uses rproc_id_rsc
for the resource which has notifyid. And thus, the data got from
idr_find() can be something else rather than rproc_vring.
And thus, add the virtio_interrupt() to handle interrupt not
just for vrings, and change the existing vq_interrupt() to call
virtio_interrupt().

Signed-off-by: Wendy Liang <[email protected]>
Signed-off-by: Michal Simek <[email protected]>
---
drivers/remoteproc/remoteproc_core.c | 7 +++---
drivers/remoteproc/remoteproc_internal.h | 1 +
drivers/remoteproc/remoteproc_virtio.c | 42 +++++++++++++++++++++++++++-----
3 files changed, 41 insertions(+), 9 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index d711345..ffd1de2 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -274,7 +274,7 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
* TODO: assign a notifyid for rvdev updates as well
* TODO: support predefined notifyids (via resource table)
*/
- ret = idr_alloc(&rproc->notifyids, rvring, 0, 0, GFP_KERNEL);
+ ret = rproc_idr_alloc(rproc, rvring, RPROC_IDR_VRING, 0, 0);
if (ret < 0) {
dev_err(dev, "idr_alloc failed: %d\n", ret);
dma_free_coherent(dev->parent, size, va, dma);
@@ -337,8 +337,9 @@ void rproc_free_vring(struct rproc_vring *rvring)
int idx = rvring->rvdev->vring - rvring;
struct fw_rsc_vdev *rsc;

- dma_free_coherent(rproc->dev.parent, size, rvring->va, rvring->dma);
- idr_remove(&rproc->notifyids, rvring->notifyid);
+ dma_free_coherent(rproc->dev.parent, size, rvring->va,
+ rvring->dma);
+ rproc_idr_remove(rproc, rvring->notifyid);

/* reset resource entry info */
rsc = (void *)rproc->table_ptr + rvring->rvdev->rsc_offset;
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index 865bd1c..0cfc942 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -72,6 +72,7 @@ struct rproc_fw_ops {

/* from remoteproc_core.c */
void rproc_release(struct kref *kref);
+irqreturn_t rproc_virtio_interrupt(struct rproc *rproc, int notifyid);
irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int vq_id);
int rproc_boot_nowait(struct rproc *rproc);
void rproc_vdev_release(struct kref *ref);
diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c
index 0142cc3..e45e17b 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -43,7 +43,7 @@ static bool rproc_virtio_notify(struct virtqueue *vq)
}

/**
- * rproc_vq_interrupt() - tell remoteproc that a virtqueue is interrupted
+ * rproc_virtio_interrupt() - tell remoteproc that a vdev is interrupted
* @rproc: handle to the remote processor
* @notifyid: index of the signalled virtqueue (unique per this @rproc)
*
@@ -54,17 +54,47 @@ static bool rproc_virtio_notify(struct virtqueue *vq)
* Returns IRQ_NONE if no message was found in the @notifyid virtqueue,
* and otherwise returns IRQ_HANDLED.
*/
-irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int notifyid)
+irqreturn_t rproc_virtio_interrupt(struct rproc *rproc, int notifyid)
{
+ struct rproc_id_rsc *rsc;
struct rproc_vring *rvring;

- dev_dbg(&rproc->dev, "vq index %d is interrupted\n", notifyid);
+ dev_dbg(&rproc->dev, "virtio index %d is interrupted\n", notifyid);
+
+ rsc = idr_find(&rproc->notifyids, notifyid);
+ if (!rsc || !rsc->rsc_ptr)
+ return IRQ_NONE;

- rvring = idr_find(&rproc->notifyids, notifyid);
- if (!rvring || !rvring->vq)
+ if (rsc->rsc_type == RPROC_IDR_VRING) {
+ rvring = rsc->rsc_ptr;
+ if (!rvring->vq)
+ return IRQ_NONE;
+ return vring_interrupt(0, rvring->vq);
+ } else if (rsc->rsc_type == RPROC_IDR_VDEV) {
+ dev_info(&rproc->dev, "vdev intr is not supported yet.\n");
return IRQ_NONE;
+ }

- return vring_interrupt(0, rvring->vq);
+ dev_err(&rproc->dev, "Unknown rsc type: 0x%x\n", rsc->rsc_type);
+ return IRQ_NONE;
+}
+EXPORT_SYMBOL(rproc_virtio_interrupt);
+
+/**
+ * rproc_vq_interrupt() - tell remoteproc that a virtqueue is interrupted
+ * @rproc: handle to the remote processor
+ * @notifyid: index of the signalled virtqueue (unique per this @rproc)
+ *
+ * This function should be called by the platform-specific rproc driver,
+ * when the remote processor signals that a specific virtqueue has pending
+ * messages available.
+ *
+ * Returns IRQ_NONE if no message was found in the @notifyid virtqueue,
+ * and otherwise returns IRQ_HANDLED.
+ */
+irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int notifyid)
+{
+ return rproc_virtio_interrupt(rproc, notifyid);
}
EXPORT_SYMBOL(rproc_vq_interrupt);

--
1.9.1

2017-03-24 19:32:52

by Wendy Liang

[permalink] [raw]
Subject: [RFC LINUX PATCH 04/19] remoteproc: sysfs: Add running independent state

From: Wendy Liang <[email protected]>

Show running independent state to indicate the remote
runs and it is not started by the remoteproc driver.

Signed-off-by: Wendy Liang <[email protected]>
Signed-off-by: Michal Simek <[email protected]>
---
drivers/remoteproc/remoteproc_sysfs.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_sysfs.c b/drivers/remoteproc/remoteproc_sysfs.c
index 47be411..616057d 100644
--- a/drivers/remoteproc/remoteproc_sysfs.c
+++ b/drivers/remoteproc/remoteproc_sysfs.c
@@ -74,6 +74,7 @@ static ssize_t firmware_store(struct device *dev,
[RPROC_RUNNING] = "running",
[RPROC_CRASHED] = "crashed",
[RPROC_DELETED] = "deleted",
+ [RPROC_RUNNING_INDEPENDENT] = "running_independent",
[RPROC_LAST] = "invalid",
};

@@ -97,14 +98,16 @@ static ssize_t state_store(struct device *dev,
int ret = 0;

if (sysfs_streq(buf, "start")) {
- if (rproc->state == RPROC_RUNNING)
+ if (rproc->state == RPROC_RUNNING ||
+ rproc->state == RPROC_RUNNING_INDEPENDENT)
return -EBUSY;

ret = rproc_boot(rproc);
if (ret)
dev_err(&rproc->dev, "Boot failed: %d\n", ret);
} else if (sysfs_streq(buf, "stop")) {
- if (rproc->state != RPROC_RUNNING)
+ if (rproc->state != RPROC_RUNNING &&
+ rproc->state != RPROC_RUNNING_INDEPENDENT)
return -EINVAL;

rproc_shutdown(rproc);
--
1.9.1

2017-03-24 19:32:57

by Wendy Liang

[permalink] [raw]
Subject: [RFC LINUX PATCH 14/19] remoteproc virtio: handle rproc vdev notification

From: Wendy Liang <[email protected]>

If there is a vdev notification from the remote, rproc virtio
will mark the config_wait_complete to wake up any client who
is waiting for the remote to respond.

Signed-off-by: Wendy Liang <[email protected]>
Signed-off-by: Michal Simek <[email protected]>
---
drivers/remoteproc/remoteproc_virtio.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c
index c6f7ca4..577344e 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -58,6 +58,7 @@ irqreturn_t rproc_virtio_interrupt(struct rproc *rproc, int notifyid)
{
struct rproc_id_rsc *rsc;
struct rproc_vring *rvring;
+ struct rproc_vdev *rvdev;

dev_dbg(&rproc->dev, "virtio index %d is interrupted\n", notifyid);

@@ -71,8 +72,9 @@ irqreturn_t rproc_virtio_interrupt(struct rproc *rproc, int notifyid)
return IRQ_NONE;
return vring_interrupt(0, rvring->vq);
} else if (rsc->rsc_type == RPROC_IDR_VDEV) {
- dev_info(&rproc->dev, "vdev intr is not supported yet.\n");
- return IRQ_NONE;
+ rvdev = rsc->rsc_ptr;
+ complete_all(&rvdev->config_wait_complete);
+ return IRQ_HANDLED;
}

dev_err(&rproc->dev, "Unknown rsc type: 0x%x\n", rsc->rsc_type);
--
1.9.1

2017-03-24 19:33:02

by Wendy Liang

[permalink] [raw]
Subject: [RFC LINUX PATCH 05/19] remoteproc: check if remote is running the fw before reload fw

From: Wendy Liang <[email protected]>

Add a function rproc_is_running_fw() to check if it needs to start the
remote betfore it loads firmware and tries to start the remote.

In some cases, when the master restarts, the remote is already running the
expected firmware.
In this case, we don't need to start the remote when the remoteproc driver
starts.

Signed-off-by: Wendy Liang <[email protected]>
Signed-off-by: Michal Simek <[email protected]>
---
drivers/remoteproc/remoteproc_core.c | 99 ++++++++++++++++++++++++++----------
1 file changed, 71 insertions(+), 28 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index dfa2aad..f13f56d 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -898,6 +898,17 @@ static bool rproc_is_running(struct rproc *rproc)
}

/*
+ * check if the remote needs start.
+ */
+static bool rproc_is_running_fw(struct rproc *rproc, const struct firmware *fw)
+{
+ (void)rproc;
+ (void) fw;
+
+ return false;
+}
+
+/*
* take a firmware and boot a remote processor with it.
*/
static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
@@ -906,6 +917,7 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
const char *name = rproc->firmware;
struct resource_table *table, *loaded_table;
int ret, tablesz;
+ bool is_running = false;

ret = rproc_fw_sanity_check(rproc, fw);
if (ret)
@@ -948,6 +960,19 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
/* reset max_notifyid */
rproc->max_notifyid = -1;

+ /* check if the rproc is already running the firmware */
+ /* As it may be required to know if the remote is already running
+ * when handling the resource table, check if the remote is already
+ * running the expected firmware before handling the resource table.
+ */
+ is_running = rproc_is_running_fw(rproc, fw);
+ if (is_running) {
+ rproc->state = RPROC_RUNNING_INDEPENDENT;
+ loaded_table = rproc_find_loaded_rsc_table(rproc, fw);
+ if (loaded_table)
+ rproc->table_ptr = loaded_table;
+ }
+
/* handle fw resources which are required to boot rproc */
ret = rproc_handle_resources(rproc, tablesz, rproc_loading_handlers);
if (ret) {
@@ -955,32 +980,54 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
goto clean_up_resources;
}

- /* load the ELF segments to memory */
- ret = rproc_load_segments(rproc, fw);
- if (ret) {
- dev_err(dev, "Failed to load program segments: %d\n", ret);
- goto clean_up_resources;
- }
+ if (!is_running) {
+ /* If rproc is running, stop it first */
+ if (rproc_is_running(rproc)) {
+ dev_info(dev, "Restarting the remote.\n");
+ ret = rproc->ops->stop(rproc);
+ if (ret) {
+ atomic_inc(&rproc->power);
+ dev_err(dev, "can't stop rproc: %d\n", ret);
+ goto clean_up_resources;
+ }
+ }

- /*
- * The starting device has been given the rproc->cached_table as the
- * resource table. The address of the vring along with the other
- * allocated resources (carveouts etc) is stored in cached_table.
- * In order to pass this information to the remote device we must copy
- * this information to device memory. We also update the table_ptr so
- * that any subsequent changes will be applied to the loaded version.
- */
- loaded_table = rproc_find_loaded_rsc_table(rproc, fw);
- if (loaded_table) {
- memcpy(loaded_table, rproc->cached_table, tablesz);
- rproc->table_ptr = loaded_table;
- }
+ /* load the ELF segments to memory */
+ ret = rproc_load_segments(rproc, fw);
+ if (ret) {
+ dev_err(dev, "Failed to load program segments: %d\n",
+ ret);
+ goto clean_up_resources;
+ }

- /* power up the remote processor */
- ret = rproc->ops->start(rproc);
- if (ret) {
- dev_err(dev, "can't start rproc %s: %d\n", rproc->name, ret);
- goto clean_up_resources;
+ /*
+ * The starting device has been given the rproc->cached_table
+ * as the resource table. The address of the vring along with
+ * the other allocated resources (carveouts etc) is stored in
+ * cached_table. In order to pass this information to the
+ * remote device we must copy this information to device
+ * memory. We also update the table_ptr so that any subsequent
+ * changes will be applied to the loaded version.
+ */
+ loaded_table = rproc_find_loaded_rsc_table(rproc, fw);
+ if (loaded_table) {
+ memcpy(loaded_table, rproc->cached_table, tablesz);
+ rproc->table_ptr = loaded_table;
+ }
+
+ /* power up the remote processor */
+ ret = rproc->ops->start(rproc);
+ if (ret) {
+ dev_err(dev, "can't start rproc %s: %d\n",
+ rproc->name, ret);
+ goto clean_up_resources;
+ }
+
+ rproc->state = RPROC_RUNNING;
+
+ dev_info(dev, "remote processor %s is now up\n", rproc->name);
+ } else {
+ dev_info(dev, "remote is already running. Do not restart\n");
}

/* probe any subdevices for the remote processor */
@@ -991,10 +1038,6 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
goto stop_rproc;
}

- rproc->state = RPROC_RUNNING;
-
- dev_info(dev, "remote processor %s is now up\n", rproc->name);
-
return 0;

stop_rproc:
--
1.9.1

2017-03-24 19:33:16

by Wendy Liang

[permalink] [raw]
Subject: [RFC LINUX PATCH 01/19] remoteproc: Add is_runinng to remoteproc ops

From: Wendy Liang <[email protected]>

Add is_running to remoteproc ops to check if the remote is
running.

Signed-off-by: Wendy Liang <[email protected]>
Signed-off-by: Michal Simek <[email protected]>
---
include/linux/remoteproc.h | 2 ++
1 file changed, 2 insertions(+)

diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 799f041..5eec892 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -352,12 +352,14 @@ struct rproc_mem_entry {
* @stop: power off the device
* @kick: kick a virtqueue (virtqueue id given as a parameter)
* @da_to_va: optional platform hook to perform address translations
+ * @is_running: check if the remote is running
*/
struct rproc_ops {
int (*start)(struct rproc *rproc);
int (*stop)(struct rproc *rproc);
void (*kick)(struct rproc *rproc, int vqid);
void * (*da_to_va)(struct rproc *rproc, u64 da, int len);
+ bool (*is_running)(struct rproc *rproc);
};

/**
--
1.9.1

2017-03-24 19:33:31

by Wendy Liang

[permalink] [raw]
Subject: [RFC LINUX PATCH 03/19] remoteproc: Add a running independent state

From: Wendy Liang <[email protected]>

Add a new RPROC_RUNNING_INDEPENDENT state to indicate
the remote already runs and it is started by the remoteproc
driver.

Signed-off-by: Wendy Liang <[email protected]>
Signed-off-by: Michal Simek <[email protected]>
---
include/linux/remoteproc.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 5eec892..b740b93 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -384,7 +384,8 @@ enum rproc_state {
RPROC_RUNNING = 2,
RPROC_CRASHED = 3,
RPROC_DELETED = 4,
- RPROC_LAST = 5,
+ RPROC_RUNNING_INDEPENDENT = 5,
+ RPROC_LAST = 6,
};

/**
--
1.9.1

2017-03-24 19:33:40

by Wendy Liang

[permalink] [raw]
Subject: [RFC LINUX PATCH 08/19] remoteproc: add a function to set fw checksum rsc

From: Wendy Liang <[email protected]>

Add a function to set the firmware checksum resource.
The function will call the firmware loader to calculate
the firmware checksum and set it to the resource table.

Signed-off-by: Wendy Liang <[email protected]>
Signed-off-by: Michal Simek <[email protected]>
---
drivers/remoteproc/remoteproc_core.c | 54 ++++++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)

diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index f13f56d..447c28b 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -897,6 +897,60 @@ static bool rproc_is_running(struct rproc *rproc)
return (rproc->state == RPROC_RUNNING) ? true : false;
}

+/**
+ * rproc_handle_fw_chksum() - handle firmware checksum resource
+ * @rproc: rproc handle
+ * @fw: firmware
+ * @offset: returns fw_chksum resource offset.
+ *
+ * This function will handle request to set the firmware checksum.
+ */
+static
+struct fw_rsc_fw_chksum *rproc_handle_fw_chksum(struct rproc *rproc,
+ const struct firmware *fw, int *offset)
+{
+ struct fw_rsc_fw_chksum *rsc = NULL;
+ int i, tablesz;
+ struct device *dev = &rproc->dev;
+ struct resource_table *table;
+
+ /* look for the resource table */
+ table = rproc_find_rsc_table(rproc, fw, &tablesz);
+ if (!table) {
+ dev_err(dev, "Failed to find resource table\n");
+ return NULL;
+ }
+
+ for (i = 0; i < rproc->table_ptr->num; i++) {
+ int ret = 0;
+ int tmpoffset = rproc->table_ptr->offset[i];
+ struct fw_rsc_hdr *hdr = (void *)rproc->table_ptr + tmpoffset;
+ int avail = tablesz - tmpoffset - sizeof(*hdr);
+
+ if (hdr->type != RSC_FW_CHKSUM)
+ continue;
+
+ rsc = (struct fw_rsc_fw_chksum *)((void *)hdr + sizeof(*hdr));
+ if (sizeof(*rsc) > avail) {
+ dev_err(dev, "firmware checksum rsc is truncated\n");
+ return NULL;
+ }
+ if (rproc->fw_ops->get_chksum) {
+ ret = rproc->fw_ops->get_chksum(rproc, fw,
+ rsc->algo, rsc->chksum, sizeof(rsc->chksum));
+ if (ret) {
+ dev_err(dev,
+ "failed to get firmware chksum.\n");
+ return NULL;
+ }
+ }
+ *offset = tmpoffset + sizeof(*hdr);
+ return rsc;
+ }
+
+ return NULL;
+}
+
/*
* check if the remote needs start.
*/
--
1.9.1

2017-03-24 19:33:55

by Wendy Liang

[permalink] [raw]
Subject: [RFC LINUX PATCH 02/19] remtoeproc: Add an operation to check if remote is running

From: Wendy Liang <[email protected]>

Add a remoteproc driver operation to check if the remote is running.

Signed-off-by: Wendy Liang <[email protected]>
Signed-off-by: Michal Simek <[email protected]>
---
drivers/remoteproc/remoteproc_core.c | 10 ++++++++++
1 file changed, 10 insertions(+)

diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 9d32737..dfa2aad 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -888,6 +888,16 @@ static void rproc_resource_cleanup(struct rproc *rproc)
}

/*
+ * check if the remote is running
+ */
+static bool rproc_is_running(struct rproc *rproc)
+{
+ if (rproc->ops->is_running)
+ return rproc->ops->is_running(rproc);
+ return (rproc->state == RPROC_RUNNING) ? true : false;
+}
+
+/*
* take a firmware and boot a remote processor with it.
*/
static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
--
1.9.1

2017-03-24 19:34:09

by Wendy Liang

[permalink] [raw]
Subject: [RFC LINUX PATCH 06/19] remoteproc: elf loader: Add get checksum firmware implementation

From: Wendy Liang <[email protected]>

Add get_chksum() implementation to calculate the checksum of
the loadable sections of the firmware.

Signed-off-by: Wendy Liang <[email protected]>
Signed-off-by: Michal Simek <[email protected]>
---
drivers/remoteproc/Kconfig | 1 +
drivers/remoteproc/remoteproc_elf_loader.c | 109 +++++++++++++++++++++++++++++
drivers/remoteproc/remoteproc_internal.h | 3 +
3 files changed, 113 insertions(+)

diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 65f86bc..d832f3b 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -7,6 +7,7 @@ config REMOTEPROC
select FW_LOADER
select VIRTIO
select VIRTUALIZATION
+ select CRYPTO
help
Support for remote processors (such as DSP coprocessors). These
are mainly used on embedded systems.
diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
index c523983..f508083 100644
--- a/drivers/remoteproc/remoteproc_elf_loader.c
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -29,6 +29,7 @@
#include <linux/firmware.h>
#include <linux/remoteproc.h>
#include <linux/elf.h>
+#include <crypto/hash.h>

#include "remoteproc_internal.h"

@@ -328,10 +329,118 @@ u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
}

+/**
+ * rproc_elf_get_chksum() - calcuate checksum of the loadable section
+ * @rproc: the rproc handle
+ * @fw: the ELF firmware image
+ * @algo: name of the checksum algorithm
+ * @chksum: checksum
+ * @output_size: size of the checksum
+ *
+ * This function calculate the checksum of the loadable secitons
+ * of the specified firmware.
+ *
+ * Returns 0 for success, negative value for failure.
+ */
+static int
+rproc_elf_get_chksum(struct rproc *rproc, const struct firmware *fw,
+ char *algo, u8 *chksum, int output_size)
+{
+ int ret, i;
+ struct device *dev = &rproc->dev;
+ struct crypto_shash *tfm;
+ struct shash_desc *desc;
+ int algo_len = 0;
+ struct elf32_hdr *ehdr;
+ struct elf32_phdr *phdr;
+ const u8 *elf_data = fw->data;
+
+ memset(chksum, 0, output_size);
+ /* If no algo is specified, default it to "sha256" */
+ if (!strlen(algo))
+ sprintf(algo, "sha256");
+ ret = crypto_has_alg(algo, 0, 0);
+ if (!ret) {
+ dev_err(dev, "failed to find crypto algo: %s.\n", algo);
+ return -EINVAL;
+ }
+ dev_dbg(dev, "firmware checksum algo: %s.\n", algo);
+ tfm = crypto_alloc_shash(algo, 0, 0);
+ if (!tfm) {
+ dev_err(dev, "failed to allocate shash.\n");
+ return -ENOMEM;
+ }
+ algo_len = crypto_shash_digestsize(tfm);
+ if (algo_len > output_size) {
+ dev_err(dev,
+ "algo digest size %d is larger expected %d.\n",
+ algo_len, output_size);
+ return -EINVAL;
+ }
+ desc = kzalloc(sizeof(*desc) + algo_len, GFP_KERNEL);
+ if (!desc)
+ return -ENOMEM;
+ desc->tfm = tfm;
+ ret = crypto_shash_init(desc);
+ if (ret) {
+ dev_err(dev, "failed crypto %s initialization.\n", algo);
+ return ret;
+ }
+
+ ehdr = (struct elf32_hdr *)elf_data;
+ phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
+
+ /* go through the available ELF segments */
+ for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
+ u32 memsz = phdr->p_memsz;
+ u32 filesz = phdr->p_filesz;
+ u32 offset = phdr->p_offset;
+
+ if (phdr->p_type != PT_LOAD)
+ continue;
+
+ if (filesz > memsz) {
+ dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
+ filesz, memsz);
+ ret = -EINVAL;
+ break;
+ }
+
+ if (offset + filesz > fw->size) {
+ dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
+ offset + filesz, fw->size);
+ ret = -EINVAL;
+ break;
+ }
+
+ /* put the segment where the remote processor expects it */
+ if (phdr->p_filesz) {
+ ret = crypto_shash_update(desc,
+ elf_data + offset, filesz);
+ if (ret) {
+ dev_err(dev,
+ "Failed to update fw crypto digest state at offset 0x%x, size 0x%x.\n",
+ offset, filesz);
+ return ret;
+ }
+ }
+
+ }
+ ret = crypto_shash_final(desc, chksum);
+ crypto_free_shash(tfm);
+ kfree(desc);
+ if (ret) {
+ dev_err(dev, "failed to finalize checksum of firmware.\n");
+ return ret;
+ }
+ return ret;
+}
+
const struct rproc_fw_ops rproc_elf_fw_ops = {
.load = rproc_elf_load_segments,
.find_rsc_table = rproc_elf_find_rsc_table,
.find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table,
.sanity_check = rproc_elf_sanity_check,
+ .get_chksum = rproc_elf_get_chksum,
.get_boot_addr = rproc_elf_get_boot_addr
};
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index 1e9e5b3..f03e07a 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -33,6 +33,7 @@
* expects to find it
* @sanity_check: sanity check the fw image
* @get_boot_addr: get boot address to entry point specified in firmware
+ * @get_chksum: get checksum of the loadable sections of the firmware
*/
struct rproc_fw_ops {
struct resource_table *(*find_rsc_table)(struct rproc *rproc,
@@ -43,6 +44,8 @@ struct rproc_fw_ops {
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);
+ int (*get_chksum)(struct rproc *rproc, const struct firmware *fw,
+ char *algo, u8 *chksum, int output_size);
};

/* from remoteproc_core.c */
--
1.9.1

2017-03-24 19:34:25

by Wendy Liang

[permalink] [raw]
Subject: [RFC LINUX PATCH 15/19] remoteproc: virtio: rename rproc_virtio_notify to rproc_vq_notify

From: Wendy Liang <[email protected]>

rproc_virtio_notify() is to notify about the virtqueue changes but
not the virtio dev and thus rename to rproc_vq_notify().
It will need another API for virtio dev notification.

Signed-off-by: Wendy Liang <[email protected]>
Signed-off-by: Michal Simek <[email protected]>
---
drivers/remoteproc/remoteproc_virtio.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c
index 577344e..cc421f3 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -30,7 +30,7 @@
#include "remoteproc_internal.h"

/* kick the remote processor, and let it know which virtqueue to poke at */
-static bool rproc_virtio_notify(struct virtqueue *vq)
+static bool rproc_vq_notify(struct virtqueue *vq)
{
struct rproc_vring *rvring = vq->priv;
struct rproc *rproc = rvring->rvdev->rproc;
@@ -136,7 +136,7 @@ static struct virtqueue *rp_find_vq(struct virtio_device *vdev,
* the 'weak' smp barriers, since we're talking with a real device.
*/
vq = vring_new_virtqueue(id, len, rvring->align, vdev, false, addr,
- rproc_virtio_notify, callback, name);
+ rproc_vq_notify, callback, name);
if (!vq) {
dev_err(dev, "vring_new_virtqueue %s failed\n", name);
rproc_free_vring(rvring);
--
1.9.1