Quoting Sandeep Maheswaram (2021-03-23 12:27:32) > This patch adds a shutdown callback to USB DWC core driver to ensure that > it is properly shutdown in reboot/shutdown path. This is required > where SMMU address translation is enabled like on SC7180 > SoC and few others. If the hardware is still accessing memory after > SMMU translation is disabled as part of SMMU shutdown callback in > system reboot or shutdown path, then IOVAs(I/O virtual address) > which it was using will go on the bus as the physical addresses which > might result in unknown crashes (NoC/interconnect errors). > > Previously this was added in dwc3 qcom glue driver. > https://patchwork.kernel.org/project/linux-arm-msm/list/?series=382449 > But observed kernel panic as glue driver shutdown getting called after > iommu shutdown. As we are adding iommu nodes in dwc core node > in device tree adding shutdown callback in core driver seems correct. > > Signed-off-by: Sandeep Maheswaram <sanm@xxxxxxxxxxxxxx> > --- > drivers/usb/dwc3/core.c | 26 +++++++++++++++++++------- > 1 file changed, 19 insertions(+), 7 deletions(-) > > diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c > index 94fdbe5..777b2b5 100644 > --- a/drivers/usb/dwc3/core.c > +++ b/drivers/usb/dwc3/core.c > @@ -1634,11 +1634,9 @@ static int dwc3_probe(struct platform_device *pdev) > return ret; > } > > -static int dwc3_remove(struct platform_device *pdev) > +static void __dwc3_teardown(struct dwc3 *dwc) > { > - struct dwc3 *dwc = platform_get_drvdata(pdev); > - > - pm_runtime_get_sync(&pdev->dev); > + pm_runtime_get_sync(dwc->dev); > > dwc3_debugfs_exit(dwc); > dwc3_core_exit_mode(dwc); > @@ -1646,19 +1644,32 @@ static int dwc3_remove(struct platform_device *pdev) > dwc3_core_exit(dwc); > dwc3_ulpi_exit(dwc); > > - pm_runtime_disable(&pdev->dev); > - pm_runtime_put_noidle(&pdev->dev); > - pm_runtime_set_suspended(&pdev->dev); > + pm_runtime_disable(dwc->dev); > + pm_runtime_put_noidle(dwc->dev); > + pm_runtime_set_suspended(dwc->dev); > > dwc3_free_event_buffers(dwc); > dwc3_free_scratch_buffers(dwc); > > if (dwc->usb_psy) > power_supply_put(dwc->usb_psy); > +} > + > +static int dwc3_remove(struct platform_device *pdev) > +{ > + struct dwc3 *dwc = platform_get_drvdata(pdev); > + > + __dwc3_teardown(dwc); > > return 0; > } > > +static void dwc3_shutdown(struct platform_device *pdev) > +{ > + struct dwc3 *dwc = platform_get_drvdata(pdev); > + > + __dwc3_teardown(dwc); > +} Can't this be static void dwc3_shutdown(struct platform_device *pdev) { dwc3_remove(pdev); } and then there's nothing else to change? Basically ignore return value of dwc3_remove() to make shutdown and remove harmonize. I also wonder if this is more common than we think and a struct driver flag could be set to say "call remove for shutdown" and then have driver core swizzle on that and save some duplicate functions. > #ifdef CONFIG_PM > static int dwc3_core_init_for_resume(struct dwc3 *dwc) > { > @@ -1976,6 +1987,7 @@ MODULE_DEVICE_TABLE(acpi, dwc3_acpi_match); > static struct platform_driver dwc3_driver = { > .probe = dwc3_probe, > .remove = dwc3_remove, > + .shutdown = dwc3_shutdown,