Following the work done here [1], this set provides support for the
remoteproc core to release resources associated with a remote processor
without having to switch it off. That way a platform driver can be removed
or the application processor power cycled while the remote processor is
still operating.
Modifications for this revision are detailed in the changelog of each patch but
the main enhancement is the setup of a clean resource table when a remote
processor is detached from.
I have tested scenarios where the processor is detached and re-attached when
booted from an external entity and the remoteproc core. I was also able
to confirm that removing the platform driver of a detached remote processor
works. Re-attaching the remote processor after re-inserting the platorm driver
also works properly.
Applies cleanly on rproc-next (43d3f2c715ce).
Thanks,
Mathieu
Arnaud POULIQUEN (1):
remoteproc: stm32: Move memory parsing to rproc_ops
Mathieu Poirier (18):
dt-bindings: remoteproc: Add bindind to support autonomous processors
remoteproc: Re-check state in rproc_shutdown()
remoteproc: Remove useless check in rproc_del()
remoteproc: Rename function rproc_actuate()
remoteproc: Add new RPROC_ATTACHED state
remoteproc: Properly represent the attached state
remoteproc: Add new get_loaded_rsc_table() to rproc_ops
remoteproc: stm32: Move resource table setup to rproc_ops
remoteproc: Add new detach() remoteproc operation
remoteproc: Introduce function __rproc_detach()
remoteproc: Introduce function rproc_detach()
remoteproc: Properly deal with the resource table
remoteproc: Add return value to function rproc_shutdown()
remoteproc: Properly deal with a kernel panic when attached
remoteproc: Properly deal with a stop request when attached
remoteproc: Properly deal with a start request when attached
remoteproc: Properly deal with detach request
remoteproc: Refactor rproc delete and cdev release path
.../bindings/remoteproc/remoteproc-core.yaml | 27 ++
drivers/remoteproc/remoteproc_cdev.c | 32 +-
drivers/remoteproc/remoteproc_core.c | 307 ++++++++++++++++--
drivers/remoteproc/remoteproc_elf_loader.c | 24 +-
drivers/remoteproc/remoteproc_internal.h | 10 +
drivers/remoteproc/remoteproc_sysfs.c | 20 +-
drivers/remoteproc/stm32_rproc.c | 168 +++++-----
include/linux/remoteproc.h | 27 +-
8 files changed, 465 insertions(+), 150 deletions(-)
create mode 100644 Documentation/devicetree/bindings/remoteproc/remoteproc-core.yaml
--
2.25.1
This patch adds a binding to guide the remoteproc core on how to deal with
remote processors in two cases:
1) When an application holding a reference to a remote processor character
device interface crashes.
2) when the platform driver for a remote processor is removed.
In both cases if "autonomous-on-core-reboot" is specified in the remote
processor DT node, the remoteproc core will detach the remote processor
rather than switching it off.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Reviewed-by: Rob Herring <robh@kernel.org>
---
.../bindings/remoteproc/remoteproc-core.yaml | 27 +++++++++++++++++++
1 file changed, 27 insertions(+)
create mode 100644 Documentation/devicetree/bindings/remoteproc/remoteproc-core.yaml
@@ -0,0 +1,27 @@+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)+%YAML1.2+---+$id:http://devicetree.org/schemas/remoteproc/remoteproc-core.yaml#+$schema:http://devicetree.org/meta-schemas/core.yaml#++title:Binding(s) for a primary processor applicable to all ancillary+processors++maintainers:+-Bjorn Andersson <bjorn.andersson@linaro.org>+-Mathieu Poirier <mathieu.poirier@linaro.org>++description:+This document defines the bindings used by a primary processor to determine+the state it should leave an ancillary processor when the former is no longer+functioning.++properties:+autonomous-on-core-reboot:+$ref:/schemas/types.yaml#/definitions/flag+description:+When specified the ancillary processor should be left operational when+the primary processor is no longer available. Otherwise the ancillary+processor should be made inoperative.++additionalProperties:true
The state of the remote processor may have changed between the
time a call to rproc_shutdown() was made and the time it is
executed. To avoid moving forward with an operation that may
have been cancelled, recheck while holding the mutex.
Cc: <redacted>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Reviewed-by: Peng Fan <peng.fan@nxp.com>
Reviewed-by: Arnaud Pouliquen <redacted>
---
drivers/remoteproc/remoteproc_core.c | 3 +++
1 file changed, 3 insertions(+)
@@ -1857,6 +1857,9 @@ void rproc_shutdown(struct rproc *rproc)return;}+if(rproc->state!=RPROC_RUNNING)+gotoout;+/* if the remote proc is still needed, bail out */if(!atomic_dec_and_test(&rproc->power))gotoout;
Rename function rproc_actuate() to rproc_attach(). That way it is
easy to understand that it does the opposite of rproc_detach().
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Reviewed-by: Peng Fan <peng.fan@nxp.com>
Reviewed-by: Arnaud Pouliquen <redacted>
---
drivers/remoteproc/remoteproc_core.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
@@ -1581,7 +1581,7 @@ static int rproc_actuate(struct rproc *rproc)gotoclean_up_resources;}-ret=rproc_attach(rproc);+ret=__rproc_attach(rproc);if(ret)gotoclean_up_resources;
@@ -1802,7 +1802,7 @@ int rproc_boot(struct rproc *rproc)if(rproc->state==RPROC_DETACHED){dev_info(dev,"attaching to %s\n",rproc->name);-ret=rproc_actuate(rproc);+ret=rproc_attach(rproc);}else{dev_info(dev,"powering up %s\n",rproc->name);
Whether started at probe() time or thereafter from the command
line, a remote processor needs to be shutdown before the final
cleanup phases can happen. Otherwise the system may be left in
an unpredictable state where the remote processor is expecting
the remoteproc core to be providing services when in fact it
no longer exist.
Invariably calling rproc_shutdown() is fine since it will return
immediately if the remote processor has already been switched
off.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Reviewed-by: Peng Fan <peng.fan@nxp.com>
Reviewed-by: Arnaud Pouliquen <redacted>
---
drivers/remoteproc/remoteproc_core.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
@@ -2350,10 +2350,8 @@ int rproc_del(struct rproc *rproc)if(!rproc)return-EINVAL;-/* if rproc is marked always-on, rproc_add() booted it *//* TODO: make sure this works with rproc->power > 1 */-if(rproc->auto_boot)-rproc_shutdown(rproc);+rproc_shutdown(rproc);mutex_lock(&rproc->lock);rproc->state=RPROC_DELETED;
There is a need to know when a remote processor has been attached
to rather than booted by the remoteproc core. In order to avoid
manipulating two variables, i.e rproc::autonomous and
rproc::state, get rid of the former and simply use the newly
introduced RPROC_ATTACHED state.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Reviewed-by: Peng Fan <peng.fan@nxp.com>
Reviewed-by: Arnaud Pouliquen <redacted>
---
drivers/remoteproc/remoteproc_core.c | 20 +-------------------
drivers/remoteproc/remoteproc_sysfs.c | 5 +----
include/linux/remoteproc.h | 2 --
3 files changed, 2 insertions(+), 25 deletions(-)
@@ -1444,7 +1444,7 @@ static int __rproc_attach(struct rproc *rproc)gotostop_rproc;}-rproc->state=RPROC_RUNNING;+rproc->state=RPROC_ATTACHED;dev_info(dev,"remote processor %s is now attached\n",rproc->name);
@@ -2080,16 +2072,6 @@ int rproc_add(struct rproc *rproc)if(ret<0)returnret;-/*-*Remindourselvestheremoteprocessorhasbeenattachedtorather-*thanbootedbytheremoteproccore.Thisisimportantbecausethe-*RPROC_DETACHEDstatewillbelostassoonastheremoteprocessor-*hasbeenattachedto.Usedinfirmware_show()andresetin-*rproc_stop().-*/-if(rproc->state==RPROC_DETACHED)-rproc->autonomous=true;-/* if rproc is marked always-on, request it to boot */if(rproc->auto_boot){ret=rproc_trigger_auto_boot(rproc);
Add a new get_loaded_rsc_table() operation in order to support
scenarios where the remoteproc core has booted a remote processor
and detaches from it. When re-attaching to the remote processor,
the core needs to know where the resource table has been placed
in memory.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
New for V5:
- Added function rproc_set_loaded_rsc_table() to keep rproc_attach() clean.
- Setting ->cached_table, ->table_ptr and ->table_sz in the remoteproc core
rather than the platform drivers.
---
drivers/remoteproc/remoteproc_core.c | 35 ++++++++++++++++++++++++
drivers/remoteproc/remoteproc_internal.h | 10 +++++++
include/linux/remoteproc.h | 6 +++-
3 files changed, 50 insertions(+), 1 deletion(-)
Add a new RPROC_ATTACHED state to take into account scenarios
where the remoteproc core needs to attach to a remote processor
that is booted by another entity.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Reviewed-by: Peng Fan <peng.fan@nxp.com>
Reviewed-by: Arnaud Pouliquen <redacted>
---
drivers/remoteproc/remoteproc_sysfs.c | 1 +
include/linux/remoteproc.h | 7 +++++--
2 files changed, 6 insertions(+), 2 deletions(-)
Move the setting of the resource table installed by an external
entity to rproc_ops::get_loaded_rsc_table(). This is to support
scenarios where a remote processor has been started by the core
but is detached at a later stage. To re-attach the remote
processor, the address of the resource table needs to be available
at a later time than the platform driver's probe() function.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
New for V5:
- stm32_rproc_get_loaded_rsc_table() now returns a resource table pointer.
---
drivers/remoteproc/stm32_rproc.c | 141 +++++++++++++++----------------
1 file changed, 68 insertions(+), 73 deletions(-)
@@ -541,6 +541,73 @@ static void stm32_rproc_kick(struct rproc *rproc, int vqid)}}+staticintstm32_rproc_da_to_pa(structrproc*rproc,+u64da,phys_addr_t*pa)+{+structstm32_rproc*ddata=rproc->priv;+structdevice*dev=rproc->dev.parent;+structstm32_rproc_mem*p_mem;+unsignedinti;++for(i=0;i<ddata->nb_rmems;i++){+p_mem=&ddata->rmems[i];++if(da<p_mem->dev_addr||+da>=p_mem->dev_addr+p_mem->size)+continue;++*pa=da-p_mem->dev_addr+p_mem->bus_addr;+dev_dbg(dev,"da %llx to pa %#x\n",da,*pa);++return0;+}++dev_err(dev,"can't translate da %llx\n",da);++return-EINVAL;+}++staticstructresource_table*+stm32_rproc_get_loaded_rsc_table(structrproc*rproc,size_t*table_sz)+{+structstm32_rproc*ddata=rproc->priv;+structdevice*dev=rproc->dev.parent;+phys_addr_trsc_pa;+u32rsc_da;+interr;++/* The resource table has already been mapped, nothing to do */+if(ddata->rsc_va)+gotodone;++err=regmap_read(ddata->rsctbl.map,ddata->rsctbl.reg,&rsc_da);+if(err){+dev_err(dev,"failed to read rsc tbl addr\n");+returnERR_PTR(-EINVAL);+}++if(!rsc_da)+/* no rsc table */+returnERR_PTR(-ENOENT);++err=stm32_rproc_da_to_pa(rproc,rsc_da,&rsc_pa);+if(err)+returnERR_PTR(err);++ddata->rsc_va=devm_ioremap_wc(dev,rsc_pa,RSC_TBL_SIZE);+if(IS_ERR_OR_NULL(ddata->rsc_va)){+dev_err(dev,"Unable to map memory region: %pa+%zx\n",+&rsc_pa,RSC_TBL_SIZE);+ddata->rsc_va=NULL;+returnERR_PTR(-ENOMEM);+}++done:+/* Assuming the resource table fits in 1kB is fair */+*table_sz=RSC_TBL_SIZE;+return(structresource_table*)ddata->rsc_va;+}+staticconststructrproc_opsst_rproc_ops={.start=stm32_rproc_start,.stop=stm32_rproc_stop,
@@ -692,75 +760,6 @@ static int stm32_rproc_get_m4_status(struct stm32_rproc *ddata,returnregmap_read(ddata->m4_state.map,ddata->m4_state.reg,state);}-staticintstm32_rproc_da_to_pa(structplatform_device*pdev,-structstm32_rproc*ddata,-u64da,phys_addr_t*pa)-{-structdevice*dev=&pdev->dev;-structstm32_rproc_mem*p_mem;-unsignedinti;--for(i=0;i<ddata->nb_rmems;i++){-p_mem=&ddata->rmems[i];--if(da<p_mem->dev_addr||-da>=p_mem->dev_addr+p_mem->size)-continue;--*pa=da-p_mem->dev_addr+p_mem->bus_addr;-dev_dbg(dev,"da %llx to pa %#x\n",da,*pa);--return0;-}--dev_err(dev,"can't translate da %llx\n",da);--return-EINVAL;-}--staticintstm32_rproc_get_loaded_rsc_table(structplatform_device*pdev,-structrproc*rproc,-structstm32_rproc*ddata)-{-structdevice*dev=&pdev->dev;-phys_addr_trsc_pa;-u32rsc_da;-interr;--err=regmap_read(ddata->rsctbl.map,ddata->rsctbl.reg,&rsc_da);-if(err){-dev_err(dev,"failed to read rsc tbl addr\n");-returnerr;-}--if(!rsc_da)-/* no rsc table */-return0;--err=stm32_rproc_da_to_pa(pdev,ddata,rsc_da,&rsc_pa);-if(err)-returnerr;--ddata->rsc_va=devm_ioremap_wc(dev,rsc_pa,RSC_TBL_SIZE);-if(IS_ERR_OR_NULL(ddata->rsc_va)){-dev_err(dev,"Unable to map memory region: %pa+%zx\n",-&rsc_pa,RSC_TBL_SIZE);-ddata->rsc_va=NULL;-return-ENOMEM;-}--/*-*Theresourcetableisalreadyloadedindevicememory,noneed-*toworkwithacachedtable.-*/-rproc->cached_table=NULL;-/* Assuming the resource table fits in 1kB is fair */-rproc->table_sz=RSC_TBL_SIZE;-rproc->table_ptr=(structresource_table*)ddata->rsc_va;--return0;-}-staticintstm32_rproc_probe(structplatform_device*pdev){structdevice*dev=&pdev->dev;
@@ -800,10 +799,6 @@ static int stm32_rproc_probe(struct platform_device *pdev)ret=stm32_rproc_parse_memory_regions(rproc);if(ret)gotofree_resources;--ret=stm32_rproc_get_loaded_rsc_table(pdev,rproc,ddata);-if(ret)-gotofree_resources;}rproc->has_iommu=false;
From: Arnaud POULIQUEN <arnaud.pouliquen@foss.st.com>
Some actions such as memory resources reallocation are needed when
trying to reattach a co-processor. Use the prepare() operation for
these actions.
Co-developed-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Arnaud POULIQUEN <arnaud.pouliquen@foss.st.com>
---
drivers/remoteproc/remoteproc_core.c | 14 ++++++++++++--
drivers/remoteproc/stm32_rproc.c | 27 ++++++---------------------
2 files changed, 18 insertions(+), 23 deletions(-)
@@ -1585,10 +1585,17 @@ static int rproc_attach(struct rproc *rproc)returnret;}+/* Do anything that is needed to boot the remote processor */+ret=rproc_prepare_device(rproc);+if(ret){+dev_err(dev,"can't prepare rproc %s: %d\n",rproc->name,ret);+gotodisable_iommu;+}+ret=rproc_set_loaded_rsc_table(rproc);if(ret){dev_err(dev,"can't load resource table: %d\n",ret);-gotodisable_iommu;+gotounprepare_device;}/* reset max_notifyid */
@@ -1605,7 +1612,7 @@ static int rproc_attach(struct rproc *rproc)ret=rproc_handle_resources(rproc,rproc_loading_handlers);if(ret){dev_err(dev,"Failed to process resources: %d\n",ret);-gotodisable_iommu;+gotounprepare_device;}/* Allocate carveout resources associated to rproc */
@@ -1624,6 +1631,9 @@ static int rproc_attach(struct rproc *rproc)clean_up_resources:rproc_resource_cleanup(rproc);+unprepare_device:+/* release HW resources if needed */+rproc_unprepare_device(rproc);disable_iommu:rproc_disable_iommu(rproc);returnret;
@@ -207,16 +207,7 @@ static int stm32_rproc_mbox_idx(struct rproc *rproc, const unsigned char *name)return-EINVAL;}-staticintstm32_rproc_elf_load_rsc_table(structrproc*rproc,-conststructfirmware*fw)-{-if(rproc_elf_load_rsc_table(rproc,fw))-dev_warn(&rproc->dev,"no resource table found for this firmware\n");--return0;-}--staticintstm32_rproc_parse_memory_regions(structrproc*rproc)+staticintstm32_rproc_prepare(structrproc*rproc){structdevice*dev=rproc->dev.parent;structdevice_node*np=dev->of_node;
@@ -274,12 +265,10 @@ static int stm32_rproc_parse_memory_regions(struct rproc *rproc)staticintstm32_rproc_parse_fw(structrproc*rproc,conststructfirmware*fw){-intret=stm32_rproc_parse_memory_regions(rproc);--if(ret)-returnret;+if(rproc_elf_load_rsc_table(rproc,fw))+dev_warn(&rproc->dev,"no resource table found for this firmware\n");-returnstm32_rproc_elf_load_rsc_table(rproc,fw);+return0;}staticirqreturn_tstm32_rproc_wdg(intirq,void*data)
Add an new detach() operation in order to support scenarios where
the remoteproc core is going away but the remote processor is
kept operating. This could be the case when the system is
rebooted or when the platform driver is removed.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Reviewed-by: Peng Fan <peng.fan@nxp.com>
Reviewed-by: Arnaud Pouliquen <redacted>
---
include/linux/remoteproc.h | 2 ++
1 file changed, 2 insertions(+)
Introduce function __rproc_detach() to perform the same kind of
operation as rproc_stop(), but instead of switching off the
remote processor using rproc->ops->stop(), it uses
rproc->ops->detach(). That way it is possible for the core
to release the resources associated with a remote processor while
the latter is kept operating.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Reviewed-by: Peng Fan <peng.fan@nxp.com>
---
New for V5:
- Removed fancy error recovery when ops->detach() fails to replicate what is
done in rproc->stop().
---
drivers/remoteproc/remoteproc_core.c | 30 ++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
@@ -1709,6 +1709,36 @@ static int rproc_stop(struct rproc *rproc, bool crashed)return0;}+/*+*__rproc_detach():Doestheoppositeof__rproc_attach()+*/+staticint__maybe_unused__rproc_detach(structrproc*rproc)+{+structdevice*dev=&rproc->dev;+intret;++/* No need to continue if a detach() operation has not been provided */+if(!rproc->ops->detach)+return-EINVAL;++/* Stop any subdevices for the remote processor */+rproc_stop_subdevices(rproc,false);++/* Tell the remote processor the core isn't available anymore */+ret=rproc->ops->detach(rproc);+if(ret){+dev_err(dev,"can't detach from rproc: %d\n",ret);+returnret;+}++rproc_unprepare_subdevices(rproc);++rproc->state=RPROC_DETACHED;++dev_info(dev,"detached remote processor %s\n",rproc->name);++return0;+}/***rproc_trigger_recovery()-recoveraremoteproc
Introduce function rproc_detach() to enable the remoteproc
core to release the resources associated with a remote processor
without stopping its operation.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
New for V5:
- Fixed comment about rproc_actuate() that no longer exists.
- Added call to rproc_unprepare_device() to balance rproc_prepare_device() in
function rproc_attach().
- Removed RB from Peng and Arnaud because of the above.
---
drivers/remoteproc/remoteproc_core.c | 66 +++++++++++++++++++++++++++-
include/linux/remoteproc.h | 1 +
2 files changed, 66 insertions(+), 1 deletion(-)
@@ -1954,6 +1954,70 @@ void rproc_shutdown(struct rproc *rproc)}EXPORT_SYMBOL(rproc_shutdown);+/**+*rproc_detach()-Detachtheremoteprocessorfromthe+*remoteproccore+*+*@rproc:theremoteprocessor+*+*Detacharemoteprocessor(previouslyattachedtowithrproc_attach()).+*+*Incase@rprocisstillbeingusedbyanadditionaluser(s),then+*thisfunctionwilljustdecrementthepowerrefcountandexit,+*withoutdisconnectingthedevice.+*+*Functionrproc_detach()calls__rproc_detach()inordertoletaremote+*processorknowthatservicesprovidedbytheapplicationprocessorare+*nolongeravailable.Fromthereitshouldbepossibletoremovethe+*platformdriverandevenpowercycletheapplicationprocessor(iftheHW+*supportsit)withoutneedingtoswitchofftheremoteprocessor.+*/+intrproc_detach(structrproc*rproc)+{+structdevice*dev=&rproc->dev;+intret;++ret=mutex_lock_interruptible(&rproc->lock);+if(ret){+dev_err(dev,"can't lock rproc %s: %d\n",rproc->name,ret);+returnret;+}++if(rproc->state!=RPROC_RUNNING&&rproc->state!=RPROC_ATTACHED){+ret=-EPERM;+gotoout;+}++/* if the remote proc is still needed, bail out */+if(!atomic_dec_and_test(&rproc->power)){+ret=-EBUSY;+gotoout;+}++ret=__rproc_detach(rproc);+if(ret){+atomic_inc(&rproc->power);+gotoout;+}++/* clean up all acquired resources */+rproc_resource_cleanup(rproc);++/* release HW resources if needed */+rproc_unprepare_device(rproc);++rproc_disable_iommu(rproc);++/* Follow the same sequence as in rproc_shutdown() */+kfree(rproc->cached_table);+rproc->cached_table=NULL;+rproc->table_ptr=NULL;+out:+mutex_unlock(&rproc->lock);+returnret;+}+EXPORT_SYMBOL(rproc_detach);+/***rproc_get_by_phandle()-findaremoteprocessorbyphandle*@phandle:phandletotherproc
Add a return value to function rproc_shutdown() in order to
properly deal with error conditions that may occur.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Reviewed-by: Peng Fan <peng.fan@nxp.com>
Reviewed-by: Arnaud Pouliquen <redacted>
---
drivers/remoteproc/remoteproc_core.c | 19 ++++++++++++++-----
include/linux/remoteproc.h | 2 +-
2 files changed, 15 insertions(+), 6 deletions(-)
@@ -1974,15 +1974,19 @@ void rproc_shutdown(struct rproc *rproc)ret=mutex_lock_interruptible(&rproc->lock);if(ret){dev_err(dev,"can't lock rproc %s: %d\n",rproc->name,ret);-return;+returnret;}-if(rproc->state!=RPROC_RUNNING)+if(rproc->state!=RPROC_RUNNING){+ret=-EPERM;gotoout;+}/* if the remote proc is still needed, bail out */-if(!atomic_dec_and_test(&rproc->power))+if(!atomic_dec_and_test(&rproc->power)){+ret=-EBUSY;gotoout;+}ret=rproc_stop(rproc,false);if(ret){
If it is possible to detach the remote processor, keep an untouched
copy of the resource table. That way we can start from the same
resource table without having to worry about original values or what
elements the startup code has changed when re-attaching to the remote
processor.
Reported-by: Arnaud POULIQUEN <arnaud.pouliquen@foss.st.com>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
drivers/remoteproc/remoteproc_core.c | 70 ++++++++++++++++++++++
drivers/remoteproc/remoteproc_elf_loader.c | 24 +++++++-
include/linux/remoteproc.h | 3 +
3 files changed, 95 insertions(+), 2 deletions(-)
@@ -1527,7 +1527,9 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)clean_up_resources:rproc_resource_cleanup(rproc);kfree(rproc->cached_table);+kfree(rproc->clean_table);rproc->cached_table=NULL;+rproc->clean_table=NULL;rproc->table_ptr=NULL;unprepare_rproc:/* release HW resources if needed */
@@ -1555,6 +1557,23 @@ static int rproc_set_loaded_rsc_table(struct rproc *rproc)returnret;}+/*+*Ifitispossibletodetachtheremoteprocessor,keepanuntouched+*copyoftheresourcetable.Thatwaywecanstartfreshagainwhen+*theremoteprocessorisre-attached,thatis:+*+*DETACHED->ATTACHED->DETACHED->ATTACHED+*+*Acleancopyofthetableisalsotakeninrproc_elf_load_rsc_table()+*forcaseswheretheremoteprocessorisbootedbytheremoteproc+*coreandlaterdetachedfrom.+*/+if(rproc->ops->detach){+rproc->clean_table=kmemdup(table_ptr,table_sz,GFP_KERNEL);+if(!rproc->clean_table)+return-ENOMEM;+}+/**Theresourcetableisalreadyloadedindevicememory,noneed*toworkwithacachedtable.
@@ -1566,6 +1585,40 @@ static int rproc_set_loaded_rsc_table(struct rproc *rproc)return0;}+staticintrproc_reset_loaded_rsc_table(structrproc*rproc)+{+/*+*Inordertodetach()fromaremoteprocessoracleanresourcetable+*_must_havebeenallocatedatboottime,eitherfromrproc_fw_boot()+*orfromrproc_attach().Ifoneisn'tpresentsomethingwentreally+*wrongandwemustcomplain.+*/+if(WARN_ON(!rproc->clean_table))+return-EINVAL;++/*+*Installthecleanresourcetablewherethefirmware,i.e+*rproc_get_loaded_rsc_table(),expectsit.+*/+memcpy(rproc->table_ptr,rproc->clean_table,rproc->table_sz);++/*+*Iftheremoteprocessorswasstartedbythecorethenacached_table+*ispresentandwemustfollowthesamecleanupsequenceaswewould+*forashutdown().Asitisinrproc_stop(),usethecachedresource+*tablefortherestofthedetachprocesssince->table_ptrwill+*becomeinvalidassoonascarveoutsarereleasedin+*rproc_resource_cleanup().+*+*Iftheremoteprocessorwasstartedbyanexternalentitythe+*cached_tableisNULLandtherestofthecleanupcodein+*rproc_free_vring()candealwiththat.+*/+rproc->table_ptr=rproc->cached_table;++return0;+}+/**Attachtoremoteprocessor-similartorproc_fw_boot()butwithout*thestepsthatdealwiththefirmwareimage.
@@ -1947,7 +2000,10 @@ void rproc_shutdown(struct rproc *rproc)/* Free the copy of the resource table */kfree(rproc->cached_table);+/* Free the clean resource table */+kfree(rproc->clean_table);rproc->cached_table=NULL;+rproc->clean_table=NULL;rproc->table_ptr=NULL;out:mutex_unlock(&rproc->lock);
@@ -2000,6 +2056,16 @@ int rproc_detach(struct rproc *rproc)gotoout;}+/*+*Installacleanresourcetableforre-attachwhile+*rproc->table_ptrisstillvalid.+*/+ret=rproc_reset_loaded_rsc_table(rproc);+if(ret){+atomic_inc(&rproc->power);+gotoout;+}+/* clean up all acquired resources */rproc_resource_cleanup(rproc);
@@ -2008,10 +2074,14 @@ int rproc_detach(struct rproc *rproc)rproc_disable_iommu(rproc);+/* Free the copy of the resource table */+kfree(rproc->cached_table);/* Follow the same sequence as in rproc_shutdown() */kfree(rproc->cached_table);rproc->cached_table=NULL;+rproc->clean_table=NULL;rproc->table_ptr=NULL;+out:mutex_unlock(&rproc->lock);returnret;
The panic handler operation of registered remote processors
should also be called when remote processors have been
attached to.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Reviewed-by: Peng Fan <peng.fan@nxp.com>
Reviewed-by: Arnaud Pouliquen <redacted>
---
drivers/remoteproc/remoteproc_core.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
This patch takes into account scenarios where a remote processor
has been attached to when receiving a "start" command from sysfs.
As with the "running" case, the command can't be carried out if the
remote processor is already in operation.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Reviewed-by: Arnaud Pouliquen <redacted>
---
drivers/remoteproc/remoteproc_cdev.c | 3 ++-
drivers/remoteproc/remoteproc_sysfs.c | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
This patch introduces the capability to stop a remote processor
that has been attached to by the remoteproc core. For that to
happen a rproc::ops::stop() operation need to be available.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Reviewed-by: Peng Fan <peng.fan@nxp.com>
Reviewed-by: Arnaud Pouliquen <redacted>
---
drivers/remoteproc/remoteproc_cdev.c | 5 +++--
drivers/remoteproc/remoteproc_core.c | 6 +++++-
drivers/remoteproc/remoteproc_sysfs.c | 5 +++--
3 files changed, 11 insertions(+), 5 deletions(-)
@@ -1740,6 +1740,10 @@ static int rproc_stop(struct rproc *rproc, bool crashed)structdevice*dev=&rproc->dev;intret;+/* No need to continue if a stop() operation has not been provided */+if(!rproc->ops->stop)+return-EINVAL;+/* Stop any subdevices for the remote processor */rproc_stop_subdevices(rproc,crashed);
@@ -1977,7 +1981,7 @@ int rproc_shutdown(struct rproc *rproc)returnret;}-if(rproc->state!=RPROC_RUNNING){+if(rproc->state!=RPROC_RUNNING&&rproc->state!=RPROC_ATTACHED){ret=-EPERM;gotoout;}
@@ -2413,6 +2413,22 @@ static int rproc_alloc_ops(struct rproc *rproc, const struct rproc_ops *ops)return0;}+staticvoidrproc_set_automation_flags(structrproc*rproc)+{+structdevice*dev=rproc->dev.parent;+structdevice_node*np=dev->of_node;+boolcore_shutdown;++/*+*Whenfunctionrproc_cdev_release()orrproc_del()arecalledand+*theremoteprocessorhasbeenattachedto,itwillbedetachedfrom+*(ratherthanturnedoff)if"autonomous-on-core-shutdown is specified+*intheDT.+*/+core_shutdown=of_property_read_bool(np,"autonomous-on-core-shutdown");+rproc->autonomous_on_core_shutdown=core_shutdown;+}+/***rproc_alloc()-allocatearemoteprocessorhandle*@dev:theunderlyingdevice
@@ -2471,6 +2487,8 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,if(rproc_alloc_ops(rproc,ops))gotoput_device;+rproc_set_automation_flags(rproc);+/* Assign a unique device index and name */rproc->index=ida_simple_get(&rproc_dev_index,0,0,GFP_KERNEL);if(rproc->index<0){
@@ -2547,15 +2565,25 @@ EXPORT_SYMBOL(rproc_put);*oftheoutstandingreferencecreatedbyrproc_alloc.Todecrementthat*onelastrefcount,onestillneedstocallrproc_free().*-*Returns0onsuccessand-EINVALif@rprocisn'tvalid.+*Returns0onsuccessandanegativeerrorcodeonfailure.*/intrproc_del(structrproc*rproc){+intret;+if(!rproc)return-EINVAL;-/* TODO: make sure this works with rproc->power > 1 */-rproc_shutdown(rproc);+/*+*TODO:makesurethisworkswithrproc->power>1+*+*Noneedtocheckrproc->staterightaway,itwillbedoneineither+*rproc_detach()orrproc_shutdown().+*/+if(rproc->autonomous_on_core_shutdown)+ret=rproc_detach(rproc);+else+ret=rproc_shutdown(rproc);mutex_lock(&rproc->lock);rproc->state=RPROC_DELETED;
@@ -2574,7 +2602,7 @@ int rproc_del(struct rproc *rproc)device_del(&rproc->dev);-return0;+returnret;}EXPORT_SYMBOL(rproc_del);
This patch introduces the capability to detach a remote processor
that has been attached to or booted by the remoteproc core. For
that to happen a rproc::ops::detach() operation need to be
available.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Reviewed-by: Peng Fan <peng.fan@nxp.com>
Reviewed-by: Arnaud Pouliquen <redacted>
---
drivers/remoteproc/remoteproc_cdev.c | 6 ++++++
drivers/remoteproc/remoteproc_sysfs.c | 6 ++++++
2 files changed, 12 insertions(+)
Hi Mathieu,
On 2/12/21 12:46 AM, Mathieu Poirier wrote:
quoted hunk
Add a new get_loaded_rsc_table() operation in order to support
scenarios where the remoteproc core has booted a remote processor
and detaches from it. When re-attaching to the remote processor,
the core needs to know where the resource table has been placed
in memory.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
New for V5:
- Added function rproc_set_loaded_rsc_table() to keep rproc_attach() clean.
- Setting ->cached_table, ->table_ptr and ->table_sz in the remoteproc core
rather than the platform drivers.
---
drivers/remoteproc/remoteproc_core.c | 35 ++++++++++++++++++++++++
drivers/remoteproc/remoteproc_internal.h | 10 +++++++
include/linux/remoteproc.h | 6 +++-
3 files changed, 50 insertions(+), 1 deletion(-)
I did few tests on this showing that this approach does not cover all use cases.
The first one is a firmware without resource table. In this case table_ptr
should be null, or we have to consider the -ENOENT error as a non error usecase.
The second one, more tricky, is a firmware started by the remoteproc framework.
In this case the resource table address is retrieved from the ELF file by the
core part.
So if we detach and reattach rproc_get_loaded_rsc_table cannot return the
address. Look to me that we should have also an alocation of the clean_table in
rproc_start and then to keep the memory allocated until a shutdown.
That said regarding the complexity to re-attach, I wonder if it would not be
better to focus first on a simple detach, and address the reattachment in a
separate series, to move forward in stages.
Regards,
Arnaud
quoted hunk
+ else
+ ret = PTR_ERR(table_ptr);
+
+ dev_err(dev, "can't load resource table: %d\n", ret);
+ return ret;
+ }
+
+ /*
+ * The resource table is already loaded in device memory, no need
+ * to work with a cached table.
+ */
+ rproc->cached_table = NULL;
+ rproc->table_ptr = table_ptr;
+ rproc->table_sz = table_sz;
+
+ return 0;
+}
+
/*
* Attach to remote processor - similar to rproc_fw_boot() but without
* the steps that deal with the firmware image.
If it is possible to detach the remote processor, keep an untouched
copy of the resource table. That way we can start from the same
resource table without having to worry about original values or what
elements the startup code has changed when re-attaching to the remote
processor.
Reported-by: Arnaud POULIQUEN <arnaud.pouliquen@foss.st.com>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
drivers/remoteproc/remoteproc_core.c | 70 ++++++++++++++++++++++
drivers/remoteproc/remoteproc_elf_loader.c | 24 +++++++-
include/linux/remoteproc.h | 3 +
3 files changed, 95 insertions(+), 2 deletions(-)
@@ -1527,7 +1527,9 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)clean_up_resources:rproc_resource_cleanup(rproc);kfree(rproc->cached_table);+kfree(rproc->clean_table);rproc->cached_table=NULL;+rproc->clean_table=NULL;rproc->table_ptr=NULL;unprepare_rproc:/* release HW resources if needed */
@@ -1555,6 +1557,23 @@ static int rproc_set_loaded_rsc_table(struct rproc *rproc)returnret;}+/*+*Ifitispossibletodetachtheremoteprocessor,keepanuntouched+*copyoftheresourcetable.Thatwaywecanstartfreshagainwhen+*theremoteprocessorisre-attached,thatis:+*+*DETACHED->ATTACHED->DETACHED->ATTACHED+*+*Acleancopyofthetableisalsotakeninrproc_elf_load_rsc_table()+*forcaseswheretheremoteprocessorisbootedbytheremoteproc+*coreandlaterdetachedfrom.+*/+if(rproc->ops->detach){+rproc->clean_table=kmemdup(table_ptr,table_sz,GFP_KERNEL);+if(!rproc->clean_table)+return-ENOMEM;+}+/**Theresourcetableisalreadyloadedindevicememory,noneed*toworkwithacachedtable.
@@ -1566,6 +1585,40 @@ static int rproc_set_loaded_rsc_table(struct rproc *rproc)return0;}+staticintrproc_reset_loaded_rsc_table(structrproc*rproc)+{+/*+*Inordertodetach()fromaremoteprocessoracleanresourcetable+*_must_havebeenallocatedatboottime,eitherfromrproc_fw_boot()+*orfromrproc_attach().Ifoneisn'tpresentsomethingwentreally+*wrongandwemustcomplain.+*/+if(WARN_ON(!rproc->clean_table))+return-EINVAL;++/*+*Installthecleanresourcetablewherethefirmware,i.e+*rproc_get_loaded_rsc_table(),expectsit.+*/+memcpy(rproc->table_ptr,rproc->clean_table,rproc->table_sz);++/*+*Iftheremoteprocessorswasstartedbythecorethenacached_table+*ispresentandwemustfollowthesamecleanupsequenceaswewould+*forashutdown().Asitisinrproc_stop(),usethecachedresource+*tablefortherestofthedetachprocesssince->table_ptrwill+*becomeinvalidassoonascarveoutsarereleasedin+*rproc_resource_cleanup().+*+*Iftheremoteprocessorwasstartedbyanexternalentitythe+*cached_tableisNULLandtherestofthecleanupcodein+*rproc_free_vring()candealwiththat.+*/+rproc->table_ptr=rproc->cached_table;++return0;+}+/**Attachtoremoteprocessor-similartorproc_fw_boot()butwithout*thestepsthatdealwiththefirmwareimage.
@@ -1947,7 +2000,10 @@ void rproc_shutdown(struct rproc *rproc)/* Free the copy of the resource table */kfree(rproc->cached_table);+/* Free the clean resource table */+kfree(rproc->clean_table);rproc->cached_table=NULL;+rproc->clean_table=NULL;rproc->table_ptr=NULL;out:mutex_unlock(&rproc->lock);
@@ -2000,6 +2056,16 @@ int rproc_detach(struct rproc *rproc)gotoout;}+/*+*Installacleanresourcetableforre-attachwhile+*rproc->table_ptrisstillvalid.+*/+ret=rproc_reset_loaded_rsc_table(rproc);+if(ret){+atomic_inc(&rproc->power);+gotoout;+}+
Here you rewrite the initial values in the loaded resource table but then
rproc_resource_cleanup will clean up the resource table.
That can lead to an overwrite, and perhaps to unexpected memory access, as
DA and PA addresses are reinitialized.
(e.g call of rproc_vdev_release that will overwrite the resource table)
And because the vdev release is asynchronous, probably better to reinitialize
the resource table on attach or in rproc_handle_resources.
Regards,
Arnaud
quoted hunk
/* clean up all acquired resources */
rproc_resource_cleanup(rproc);
@@ -2008,10 +2074,14 @@ int rproc_detach(struct rproc *rproc) rproc_disable_iommu(rproc);+ /* Free the copy of the resource table */+ kfree(rproc->cached_table); /* Follow the same sequence as in rproc_shutdown() */ kfree(rproc->cached_table); rproc->cached_table = NULL;+ rproc->clean_table = NULL; rproc->table_ptr = NULL;+ out: mutex_unlock(&rproc->lock); return ret;
On Mon, Feb 15, 2021 at 02:10:10PM +0100, Arnaud POULIQUEN wrote:
Hi Mathieu,
On 2/12/21 12:46 AM, Mathieu Poirier wrote:
quoted
Add a new get_loaded_rsc_table() operation in order to support
scenarios where the remoteproc core has booted a remote processor
and detaches from it. When re-attaching to the remote processor,
the core needs to know where the resource table has been placed
in memory.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
New for V5:
- Added function rproc_set_loaded_rsc_table() to keep rproc_attach() clean.
- Setting ->cached_table, ->table_ptr and ->table_sz in the remoteproc core
rather than the platform drivers.
---
drivers/remoteproc/remoteproc_core.c | 35 ++++++++++++++++++++++++
drivers/remoteproc/remoteproc_internal.h | 10 +++++++
include/linux/remoteproc.h | 6 +++-
3 files changed, 50 insertions(+), 1 deletion(-)
I did few tests on this showing that this approach does not cover all use cases.
The first one is a firmware without resource table. In this case table_ptr
should be null, or we have to consider the -ENOENT error as a non error usecase.
Right, I'll provision for those cases.
The second one, more tricky, is a firmware started by the remoteproc framework.
In this case the resource table address is retrieved from the ELF file by the
core part.
Correct.
So if we detach and reattach rproc_get_loaded_rsc_table cannot return the
address. Look to me that we should have also an alocation of the clean_table in
rproc_start and then to keep the memory allocated until a shutdown.
I assumed the address of the resource table found in the ELF image was the same
as the one known by the platform driver. In hindsight I realise the platform
driver may not know that address.
That said regarding the complexity to re-attach, I wonder if it would not be
better to focus first on a simple detach, and address the reattachment in a
separate series, to move forward in stages.
I agree that OFFLINE -> RUNNING -> DETACHED -> ATTACHED is introducing some
complexity related to the management of the resource table that where not
expected. We could concentrate on a simple detach and see where that takes us.
It would also mean to get rid of the "autonomous-on-core-shutdown" DT binding.
Thanks,
Mathieu
Regards,
Arnaud
quoted
+ else
+ ret = PTR_ERR(table_ptr);
+
+ dev_err(dev, "can't load resource table: %d\n", ret);
+ return ret;
+ }
+
+ /*
+ * The resource table is already loaded in device memory, no need
+ * to work with a cached table.
+ */
+ rproc->cached_table = NULL;
+ rproc->table_ptr = table_ptr;
+ rproc->table_sz = table_sz;
+
+ return 0;
+}
+
/*
* Attach to remote processor - similar to rproc_fw_boot() but without
* the steps that deal with the firmware image.