Quoting Roja Rani Yarubandi (2021-05-12 01:22:20) > If the hardware is still accessing memory after SMMU translation > is disabled (as part of smmu shutdown callback), then the > IOVAs (I/O virtual address) which it was using will go on the bus > as the physical addresses which will result in unknown crashes > like NoC/interconnect errors. > > So, implement shutdown callback for i2c driver to suspend the bus > during system "reboot" or "shutdown". > > Fixes: 37692de5d523 ("i2c: i2c-qcom-geni: Add bus driver for the Qualcomm GENI I2C controller") > Signed-off-by: Roja Rani Yarubandi <rojay@xxxxxxxxxxxxxx> > --- > Changes in V2: > - As per Stephen's comments added seperate function for stop transfer, > fixed minor nitpicks. > - As per Stephen's comments, changed commit text. > > Changes in V3: > - As per Stephen's comments, squashed patch 1 into patch 2, added Fixes tag. > - As per Akash's comments, included FIFO case in stop_xfer, fixed minor nitpicks. > > Changes in V4: > - As per Stephen's comments cleaned up geni_i2c_stop_xfer function, > added dma_buf in geni_i2c_dev struct to call i2c_put_dma_safe_msg_buf() > from other functions, removed "iova" check in geni_se_rx_dma_unprep() > and geni_se_tx_dma_unprep() functions. > - Added two helper functions geni_i2c_rx_one_msg_done() and > geni_i2c_tx_one_msg_done() to unwrap the things after rx/tx FIFO/DMA > transfers, so that the same can be used in geni_i2c_stop_xfer() function > during shutdown callback. Updated commit text accordingly. > - Checking whether it is tx/rx transfer using I2C_M_RD which is valid for both > FIFO and DMA cases, so dropped DMA_RX_ACTIVE and DMA_TX_ACTIVE bit checking > > Changes in V5: > - As per Stephen's comments, added spin_lock_irqsave & spin_unlock_irqsave in > geni_i2c_stop_xfer() function. > > Changes in V6: > - As per Stephen's comments, taken care of unsafe lock order in > geni_i2c_stop_xfer(). > - Moved spin_lock/unlock to geni_i2c_rx_msg_cleanup() and > geni_i2c_tx_msg_cleanup() functions. > > Changes in V7: > - No changes > > Changes in V8: > - As per Wolfram Sang comment, removed goto and modified geni_i2c_stop_xfer() > accordingly. > > Changes in V9: > - Fixed possbile race by protecting gi2c->cur and calling geni_i2c_abort_xfer() > with adding another parameter to differentiate from which sequence is the > geni_i2c_abort_xfer() called and handle the spin_lock/spin_unlock accordingly > inside geni_i2c_abort_xfer(). For this added two macros ABORT_XFER and > STOP_AND_ABORT_XFER. > - Added a bool variable "stop_xfer" in geni_i2c_dev struct, used to put stop > to upcoming geni_i2c_rx_one_msg() and geni_i2c_tx_one_msg() calls once we > recieve the shutdown call. > - Added gi2c->cur == NULL check in geni_i2c_irq() to not to process the irq > even if any transfer is queued and shutdown to HW received. > > Changes in V10: > - As per Stephen's comments, removed ongoing transfers flush and only > suspending i2c bus in shutdown callback. > - Also removed all other changes which have been made for ongoing transfers > flush, handling race issues etc., during shutdown callback. > - Updated commit text accordingly. > > drivers/i2c/busses/i2c-qcom-geni.c | 9 +++++++++ > 1 file changed, 9 insertions(+) > > diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c > index 214b4c913a13..277ab7e7dd51 100644 > --- a/drivers/i2c/busses/i2c-qcom-geni.c > +++ b/drivers/i2c/busses/i2c-qcom-geni.c > @@ -650,6 +650,14 @@ static int geni_i2c_remove(struct platform_device *pdev) > return 0; > } > > +static void geni_i2c_shutdown(struct platform_device *pdev) > +{ > + struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev); > + > + if (!pm_runtime_status_suspended(gi2c->se.dev)) > + pm_runtime_set_suspended(gi2c->se.dev); What was wrong with my suggested approach of telling i2c core that the bus is suspended? This looks to do a bunch of work right before we're shutting down, when it would be simpler to just mark the bus as suspended and have it block future transactions and spit out a warning. I do see that we should be marking it suspended/resumed during runtime suspend/resume. I'm also confused if during system wide suspend/resume we actually do anything in this driver. Is runtime suspend called for system wide suspend? ----8<---- diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index 214b4c913a13..ca12d348336b 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -656,6 +656,7 @@ static int __maybe_unused geni_i2c_runtime_suspend(struct device *dev) struct geni_i2c_dev *gi2c = dev_get_drvdata(dev); disable_irq(gi2c->irq); + i2c_mark_adapter_suspended(&gi2c->adap); ret = geni_se_resources_off(&gi2c->se); if (ret) { enable_irq(gi2c->irq); @@ -682,6 +683,7 @@ static int __maybe_unused geni_i2c_runtime_resume(struct device *dev) return ret; enable_irq(gi2c->irq); + i2c_mark_adapter_resumed(&gi2c->adap); gi2c->suspended = 0; return 0; }