123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596 |
- From b763cdabc4c54e897400dc3fbfb3f9a795c41a48 Mon Sep 17 00:00:00 2001
- From: Suman Anna <s-anna@ti.com>
- Date: Wed, 7 Apr 2021 10:56:41 -0500
- Subject: [PATCH] remoteproc: pru: Fix and cleanup firmware interrupt mapping
- logic
- The PRU firmware interrupt mappings are configured and unconfigured in
- .start() and .stop() callbacks respectively using the variables 'evt_count'
- and a 'mapped_irq' pointer. These variables are modified only during these
- callbacks but are not re-initialized/reset properly during unwind or
- failure paths. These stale values caused a kernel crash while stopping a
- PRU remoteproc running a different firmware with no events on a subsequent
- run after a previous run that was running a firmware with events.
- Fix this crash by ensuring that the evt_count is 0 and the mapped_irq
- pointer is set to NULL in pru_dispose_irq_mapping(). Also, reset these
- variables properly during any failures in the .start() callback. While
- at this, the pru_dispose_irq_mapping() callsites are all made to look
- the same, moving any conditional logic to inside the function.
- Reviewed-by: Mathieu Poirier <mathieu.poirier@linaro.org>
- Fixes: c75c9fdac66e ("remoteproc: pru: Add support for PRU specific interrupt configuration")
- Reported-by: Vignesh Raghavendra <vigneshr@ti.com>
- Signed-off-by: Suman Anna <s-anna@ti.com>
- Link: https://lore.kernel.org/r/20210407155641.5501-4-s-anna@ti.com
- Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
- ---
- drivers/remoteproc/pru_rproc.c | 22 +++++++++++++++++-----
- 1 file changed, 17 insertions(+), 5 deletions(-)
- diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c
- index e0c5fce8bccd..d8597027a93e 100644
- --- a/drivers/remoteproc/pru_rproc.c
- +++ b/drivers/remoteproc/pru_rproc.c
- @@ -266,12 +266,17 @@ static void pru_rproc_create_debug_entries(struct rproc *rproc)
-
- static void pru_dispose_irq_mapping(struct pru_rproc *pru)
- {
- - while (pru->evt_count--) {
- + if (!pru->mapped_irq)
- + return;
- +
- + while (pru->evt_count) {
- + pru->evt_count--;
- if (pru->mapped_irq[pru->evt_count] > 0)
- irq_dispose_mapping(pru->mapped_irq[pru->evt_count]);
- }
-
- kfree(pru->mapped_irq);
- + pru->mapped_irq = NULL;
- }
-
- /*
- @@ -307,8 +312,10 @@ static int pru_handle_intrmap(struct rproc *rproc)
- pru->evt_count = rsc->num_evts;
- pru->mapped_irq = kcalloc(pru->evt_count, sizeof(unsigned int),
- GFP_KERNEL);
- - if (!pru->mapped_irq)
- + if (!pru->mapped_irq) {
- + pru->evt_count = 0;
- return -ENOMEM;
- + }
-
- /*
- * parse and fill in system event to interrupt channel and
- @@ -317,13 +324,19 @@ static int pru_handle_intrmap(struct rproc *rproc)
- * corresponding sibling PRUSS INTC node.
- */
- parent = of_get_parent(dev_of_node(pru->dev));
- - if (!parent)
- + if (!parent) {
- + kfree(pru->mapped_irq);
- + pru->mapped_irq = NULL;
- + pru->evt_count = 0;
- return -ENODEV;
- + }
-
- irq_parent = of_get_child_by_name(parent, "interrupt-controller");
- of_node_put(parent);
- if (!irq_parent) {
- kfree(pru->mapped_irq);
- + pru->mapped_irq = NULL;
- + pru->evt_count = 0;
- return -ENODEV;
- }
-
- @@ -398,8 +411,7 @@ static int pru_rproc_stop(struct rproc *rproc)
- pru_control_write_reg(pru, PRU_CTRL_CTRL, val);
-
- /* dispose irq mapping - new firmware can provide new mapping */
- - if (pru->mapped_irq)
- - pru_dispose_irq_mapping(pru);
- + pru_dispose_irq_mapping(pru);
-
- return 0;
- }
|