lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Tue, 18 Jun 2019 09:41:55 +0000
From:   Peter Rosin <peda@...ntia.se>
To:     Bitan Biswas <bbiswas@...dia.com>,
        Laxman Dewangan <ldewangan@...dia.com>,
        Thierry Reding <treding@...dia.com>,
        Jonathan Hunter <jonathanh@...dia.com>,
        "linux-i2c@...r.kernel.org" <linux-i2c@...r.kernel.org>,
        "linux-tegra@...r.kernel.org" <linux-tegra@...r.kernel.org>,
        "linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>,
        Wolfram Sang <wsa@...-dreams.de>,
        Dmitry Osipenko <digetx@...il.com>
CC:     Shardar Mohammed <smohammed@...dia.com>,
        Sowjanya Komatineni <skomatineni@...dia.com>,
        Mantravadi Karthik <mkarthik@...dia.com>
Subject: Re: [PATCH V2] i2c: tegra: disable irq in tegra_i2c_xfer_msg

On 2019-06-18 10:42, Bitan Biswas wrote:
> 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.
> 
> 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@...dia.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);

Why do you use ..._nosync in this context? Do you not care about exactly when
the irq is actually disabled? Maybe you must use _nosync, I don't know, but I
get the feeling that you just copied the code from the ISR. Anyway, the
question is if this is still adequate synchronization? Everything might very
well be safe and in order, but this is not clear to me from neither the code,
the (nonexisting) comments nor the patch description.

I'm no IRQ expert, I'm just asking questions...

Cheers,
Peter

> +		i2c_dev->irq_disabled = true;
> +	}
>  
>  	int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
>  	tegra_i2c_unmask_irq(i2c_dev, int_mask);
> @@ -1180,7 +1177,10 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
>  		i2c_readl(i2c_dev, I2C_INT_MASK));
>  
>  unlock:
> -	spin_unlock_irqrestore(&i2c_dev->xfer_lock, flags);
> +	if (i2c_dev->irq_disabled) {
> +		i2c_dev->irq_disabled = false;
> +		enable_irq(i2c_dev->irq);
> +	}
>  
>  	if (dma) {
>  		if (err)
> @@ -1576,7 +1576,6 @@ static int tegra_i2c_probe(struct platform_device *pdev)
>  				I2C_PACKET_HEADER_SIZE;
>  	init_completion(&i2c_dev->msg_complete);
>  	init_completion(&i2c_dev->dma_complete);
> -	spin_lock_init(&i2c_dev->xfer_lock);
>  
>  	if (!i2c_dev->hw->has_single_clk_source) {
>  		fast_clk = devm_clk_get(&pdev->dev, "fast-clk");
> 

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ