linux-i2c.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Dmitry Osipenko <digetx@gmail.com>
To: Jon Hunter <jonathanh@nvidia.com>,
	Bitan Biswas <bbiswas@nvidia.com>,
	Laxman Dewangan <ldewangan@nvidia.com>,
	Thierry Reding <treding@nvidia.com>,
	linux-i2c@vger.kernel.org, linux-tegra@vger.kernel.org,
	linux-kernel@vger.kernel.org, Peter Rosin <peda@axentia.se>,
	Wolfram Sang <wsa@the-dreams.de>
Cc: Shardar Mohammed <smohammed@nvidia.com>,
	Sowjanya Komatineni <skomatineni@nvidia.com>,
	Mantravadi Karthik <mkarthik@nvidia.com>
Subject: Re: [PATCH V2] i2c: tegra: disable irq in tegra_i2c_xfer_msg
Date: Wed, 19 Jun 2019 12:02:13 +0300	[thread overview]
Message-ID: <698b4903-0580-8a68-88f8-fba3e2cbe6c7@gmail.com> (raw)
In-Reply-To: <d29aa32d-55ef-c98b-00cd-f836bf003662@nvidia.com>

19.06.2019 11:58, Jon Hunter пишет:
> 
> On 18/06/2019 19:26, Dmitry Osipenko wrote:
>> 18.06.2019 11:42, Bitan Biswas пишет:
>>> tegra_i2c_xfer_msg initiates the I2C transfer in DMA
>>> or PIO mode. It involves steps that need FIFO register
>>> access, DMA API calls like dma_sync_single_for_device, etc.
>>> Tegra I2C ISR has calls to tegra_i2c_empty_rx_fifo in PIO mode
>>> and in DMA/PIO mode writes different I2C registers including
>>> I2C interrupt status. ISR cannot start processing
>>> before the preparation step at tegra_i2c_xfer_msg is complete.
>>> Hence, a synchronization between ISR and tegra_i2c_xfer_msg
>>> is in place today using spinlock.
>>
>> Please use full 75 chars per-line, this should make commit message to look better.
>>
>>> Spinlock busy waits and can add avoidable delays.
>>>
>>> In this patch needed synchronization is achieved by disabling
>>> I2C interrupt during preparation step and enabling interrupt
>>> once preparation is over and spinlock is no longer needed.
>>>
>>> Signed-off-by: Bitan Biswas <bbiswas@nvidia.com>
>>> ---
>>>  drivers/i2c/busses/i2c-tegra.c | 17 ++++++++---------
>>>  1 file changed, 8 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
>>> index 6fb545e..ccc7fae 100644
>>> --- a/drivers/i2c/busses/i2c-tegra.c
>>> +++ b/drivers/i2c/busses/i2c-tegra.c
>>> @@ -240,7 +240,6 @@ struct tegra_i2c_hw_feature {
>>>   * @bus_clk_rate: current I2C bus clock rate
>>>   * @clk_divisor_non_hs_mode: clock divider for non-high-speed modes
>>>   * @is_multimaster_mode: track if I2C controller is in multi-master mode
>>> - * @xfer_lock: lock to serialize transfer submission and processing
>>>   * @tx_dma_chan: DMA transmit channel
>>>   * @rx_dma_chan: DMA receive channel
>>>   * @dma_phys: handle to DMA resources
>>> @@ -270,8 +269,6 @@ struct tegra_i2c_dev {
>>>  	u32 bus_clk_rate;
>>>  	u16 clk_divisor_non_hs_mode;
>>>  	bool is_multimaster_mode;
>>> -	/* xfer_lock: lock to serialize transfer submission and processing */
>>> -	spinlock_t xfer_lock;
>>>  	struct dma_chan *tx_dma_chan;
>>>  	struct dma_chan *rx_dma_chan;
>>>  	dma_addr_t dma_phys;
>>> @@ -835,7 +832,6 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
>>>  
>>>  	status = i2c_readl(i2c_dev, I2C_INT_STATUS);
>>>  
>>> -	spin_lock(&i2c_dev->xfer_lock);
>>>  	if (status == 0) {
>>>  		dev_warn(i2c_dev->dev, "irq status 0 %08x %08x %08x\n",
>>>  			 i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS),
>>> @@ -935,7 +931,6 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
>>>  
>>>  	complete(&i2c_dev->msg_complete);
>>>  done:
>>> -	spin_unlock(&i2c_dev->xfer_lock);
>>>  	return IRQ_HANDLED;
>>>  }
>>>  
>>> @@ -1054,7 +1049,6 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
>>>  	u32 packet_header;
>>>  	u32 int_mask;
>>>  	unsigned long time_left;
>>> -	unsigned long flags;
>>>  	size_t xfer_size;
>>>  	u32 *buffer = NULL;
>>>  	int err = 0;
>>> @@ -1085,7 +1079,10 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
>>>  	 */
>>>  	xfer_time += DIV_ROUND_CLOSEST(((xfer_size * 9) + 2) * MSEC_PER_SEC,
>>>  					i2c_dev->bus_clk_rate);
>>> -	spin_lock_irqsave(&i2c_dev->xfer_lock, flags);
>>> +	if (!i2c_dev->irq_disabled) {
>>> +		disable_irq_nosync(i2c_dev->irq);
>>> +		i2c_dev->irq_disabled = true;
>>> +	}
>>
>> 1) Peter correctly pointed out in the other email that the disabling should be synced.
>> But see more below in 3.
>>
>> 2) i2c_dev->irq_disabled == true can't ever be the case here because tegra_i2c_init()
>> re-enables interrupt in a case of error condition. Hence interrupt always enabled at
>> the beginning of the transfer.
>>
>> 3) In my previous answer I was suggesting to request IRQ in a disabled state, this
>> will allow to remove i2c_dev->irq_disabled completely.
>>
>> Then the tegra_i2c_xfer_msg() will have to enable IRQ after completion of the
>> transfer-preparation process and disable IRQ once transfer is done (both success and
>> failure cases). This is actually not a bad additional motivation for this patch, to
>> keep CPU's interrupt disabled while idling and not to only rely on interrupt masking
>> of the I2C hardware.
>>
>> 4) ISR should simply return IRQ_NONE when interrupt status is 0 and allow kernel core
>> to disable the faulty interrupt itself. There will be "unhandled interrupt" error
>> message in KMSG log, following the disabling.
>>
>> 5) In order to request IRQ in a disabled state, the IRQ_NOAUTOEN flag need to be set
>> before the requesting, like this:
>>
>>     irq_set_status_flags(irq, IRQ_NOAUTOEN);
>>
>>     devm_request_irq(&pdev->dev, irq...);
>>
>> In a result of combining 3-5, both i2c_dev->irq_disabled and i2c_dev->irq variables
>> become obsolete and could be removed in addition to xfer_lock. That all is a good
>> cleanup in my opinion.
> 
> I see, so basically you are simplifying the code by waiting to enable
> the interrupt until the transfer is ready and hence you can eliminate
> the need for the spinlock. OK, that would make sense. This really needs
> to be describe better in the changelog.
> 
> Also what about the tegra_i2c_unmask/mask_irq? Can these be eliminated?

Probably, yes.

> Finally, what about tegra_i2c_issue_bus_clear()? This requires
> interrupts as well.

Good points! Bitan, please take this all into account.

  reply	other threads:[~2019-06-19  9:02 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-06-18  8:42 [PATCH V2] i2c: tegra: disable irq in tegra_i2c_xfer_msg Bitan Biswas
2019-06-18  9:13 ` Jon Hunter
2019-06-18 18:34   ` Dmitry Osipenko
2019-06-18  9:41 ` Peter Rosin
2019-06-18 18:26 ` Dmitry Osipenko
2019-06-19  8:58   ` Jon Hunter
2019-06-19  9:02     ` Dmitry Osipenko [this message]
2019-06-19  9:10       ` Dmitry Osipenko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=698b4903-0580-8a68-88f8-fba3e2cbe6c7@gmail.com \
    --to=digetx@gmail.com \
    --cc=bbiswas@nvidia.com \
    --cc=jonathanh@nvidia.com \
    --cc=ldewangan@nvidia.com \
    --cc=linux-i2c@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-tegra@vger.kernel.org \
    --cc=mkarthik@nvidia.com \
    --cc=peda@axentia.se \
    --cc=skomatineni@nvidia.com \
    --cc=smohammed@nvidia.com \
    --cc=treding@nvidia.com \
    --cc=wsa@the-dreams.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).