Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1380503 > unrolled thread
| Started by | Shardar Mohammed <smohammed@nvidia.com> |
|---|---|
| First post | 2016-04-16 10:10 +0200 |
| Last post | 2016-04-18 09:40 +0200 |
| Articles | 3 — 2 participants |
Back to article view | Back to linux.kernel
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
RE: [PATCH] i2c: tegra: proper handling of error cases Shardar Mohammed <smohammed@nvidia.com> - 2016-04-16 10:10 +0200
Re: [PATCH] i2c: tegra: proper handling of error cases Thierry Reding <thierry.reding@gmail.com> - 2016-04-18 09:30 +0200
Re: [PATCH] i2c: tegra: proper handling of error cases Thierry Reding <thierry.reding@gmail.com> - 2016-04-18 09:40 +0200
| From | Shardar Mohammed <smohammed@nvidia.com> |
|---|---|
| Date | 2016-04-16 10:10 +0200 |
| Subject | RE: [PATCH] i2c: tegra: proper handling of error cases |
| Message-ID | <rotsJ-p0-3@gated-at.bofh.it> |
Thanks for the review, updated with comments inline with Shardar.
> On Fri, Apr 15, 2016 at 06:51:47PM +0530, Shardar Shariff Md wrote:
> > From: Shardar Shariff Md <smohammed@nvidia.com>
> >
> > To summarize the issue observed in error cases:
> >
> > In SW: For i2c message transfer, packet header and data payload is
> > posted and then required error/packet completion interrupts are
> > enabled later.
> >
> > In HW flow: HW process the packet just after packet header is posted,
> > if ARB lost/NACK error occurs (SW will not handle immediately when
> > error happens as error interrupts are not enabled at this point). HW
> > assumes error is acknowledged and clears current data in FIFO, But SW
> > here posts the remaining data payload which still stays in FIFO as
> > stale data (data without packet header).
> >
> > Now once the interrupts are enabled, SW handles ARB lost/NACK error by
> > clearing the ARB lost/NACK interrupt. Now HW assumes that SW attended
> > the error and will parse/process stale data (data without packet
> > header) present in FIFO which causes invalid NACK errors.
> >
> > Fix: Enable the error interrupts before posting the packet into FIFO
> > which make sure HW to not clear the fifo. Also disable the packet mode
> > before acknowledging errors (ARB lost/NACK error) to not process any
> > stale data.
> >
> > As error interrupts are enabled before posting the packet header use
> > spinlock to avoid preempting.
>
> Please try to use up the full 78 characters per line in the commit message
> (with the exception being the subject line that should be shorter).
[Shardar] Will take care of this.
> > diff --git a/drivers/i2c/busses/i2c-tegra.c
> > b/drivers/i2c/busses/i2c-tegra.c
> [...]
> > @@ -423,12 +424,31 @@ static inline void tegra_i2c_clock_disable(struct
> tegra_i2c_dev *i2c_dev)
> > clk_disable(i2c_dev->fast_clk);
> > }
> >
> > +static int tegra_i2c_wait_for_config_load(struct tegra_i2c_dev
> > +*i2c_dev) {
> > + unsigned long timeout;
> > +
> > + if (i2c_dev->hw->has_config_load_reg) {
> > + i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD,
> I2C_CONFIG_LOAD);
> > + timeout = jiffies + msecs_to_jiffies(1000);
> > + while (i2c_readl(i2c_dev, I2C_CONFIG_LOAD) != 0) {
> > + if (time_after(jiffies, timeout)) {
> > + dev_warn(i2c_dev->dev,
> > + "timeout waiting for config load\n");
>
> Nit: since you're already changing this, perhaps make the arguments on
> subsequent lines align with the first argument on the first line? Like
> so:
>
> dev_warn(i2c_dev->dev,
> "timeout waiting for config load\n");
>
> Note the extra space used for padding.
>
[Shardar] Will take care of this.
> > + return -ETIMEDOUT;
> > + }
> > + msleep(1);
> > + }
> > + }
> > +
> > + return 0;
> > +}
> > +
> > static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) {
> > u32 val;
> > int err = 0;
> > u32 clk_divisor;
> > - unsigned long timeout = jiffies + HZ;
> >
> > err = tegra_i2c_clock_enable(i2c_dev);
> > if (err < 0) {
> > @@ -477,20 +497,13 @@ static int tegra_i2c_init(struct tegra_i2c_dev
> *i2c_dev)
> > if (i2c_dev->is_multimaster_mode && i2c_dev->hw-
> >has_slcg_override_reg)
> > i2c_writel(i2c_dev, I2C_MST_CORE_CLKEN_OVR,
> I2C_CLKEN_OVERRIDE);
> >
> > - if (i2c_dev->hw->has_config_load_reg) {
> > - i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD,
> I2C_CONFIG_LOAD);
> > - while (i2c_readl(i2c_dev, I2C_CONFIG_LOAD) != 0) {
> > - if (time_after(jiffies, timeout)) {
> > - dev_warn(i2c_dev->dev,
> > - "timeout waiting for config load\n");
> > - return -ETIMEDOUT;
> > - }
> > - msleep(1);
> > - }
> > - }
> > + err = tegra_i2c_wait_for_config_load(i2c_dev);
> >
> > tegra_i2c_clock_disable(i2c_dev);
> >
> > + if (err)
> > + return err;
> > +
>
> The behaviour here is now different, though I assume it's really a fix that
> disables the I2C clock in case the timeout happens. Given that I suspect this
> would be better off in a separate patch (factor out the
> tegra_i2c_wait_for_config_load() function and return error after the clocks
> have been disabled).
[Shardar] Will take care of this.
>
> > if (i2c_dev->irq_disabled) {
> > i2c_dev->irq_disabled = 0;
> > enable_irq(i2c_dev->irq);
> > @@ -499,14 +512,28 @@ static int tegra_i2c_init(struct tegra_i2c_dev
> *i2c_dev)
> > return err;
> > }
> >
> > +static int tegra_i2c_disable_packet_mode(struct tegra_i2c_dev
> > +*i2c_dev) {
> > + u32 cnfg;
> > +
> > + cnfg = i2c_readl(i2c_dev, I2C_CNFG);
> > + if (cnfg & I2C_CNFG_PACKET_MODE_EN)
> > + i2c_writel(i2c_dev, cnfg & (~I2C_CNFG_PACKET_MODE_EN),
>
> Parentheses are not necessary here.
>
> > + I2C_CNFG);
>
> If you drop the parentheses above this can be moved into the previous line
> because it will fit within 80 columns.
[Shardar] Will take care of this.
>
> > +
> > + return tegra_i2c_wait_for_config_load(i2c_dev);
> > +}
> > +
> > static irqreturn_t tegra_i2c_isr(int irq, void *dev_id) {
> > u32 status;
> > const u32 status_err = I2C_INT_NO_ACK |
> I2C_INT_ARBITRATION_LOST;
> > struct tegra_i2c_dev *i2c_dev = dev_id;
> > + unsigned long flags;
> >
> > status = i2c_readl(i2c_dev, I2C_INT_STATUS);
> >
> > + spin_lock_irqsave(&i2c_dev->xfer_lock, flags);
> > if (status == 0) {
> > dev_warn(i2c_dev->dev, "irq status 0 %08x %08x %08x\n",
> > i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS),
> @@ -522,6 +549,7
> > @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
> > }
> >
> > if (unlikely(status & status_err)) {
> > + tegra_i2c_disable_packet_mode(i2c_dev);
>
> If you don't care about the return value it'd be better to reflect that by
> making the function return void. I presume ignoring the error here is safe?
[Shardar] Will take care of handling the return valure.
>
> > @@ -583,6 +614,11 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev
> *i2c_dev,
> > i2c_dev->msg_read = (msg->flags & I2C_M_RD);
> > reinit_completion(&i2c_dev->msg_complete);
> >
> > + spin_lock_irqsave(&i2c_dev->xfer_lock, flags);
> > +
> > + int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
> > + tegra_i2c_unmask_irq(i2c_dev, int_mask);
> > +
> > packet_header = (0 << PACKET_HEADER0_HEADER_SIZE_SHIFT) |
> > PACKET_HEADER0_PROTOCOL_I2C |
> > (i2c_dev->cont_id <<
> PACKET_HEADER0_CONT_ID_SHIFT) | @@ -612,14
> > +648,15 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
> > if (!(msg->flags & I2C_M_RD))
> > tegra_i2c_fill_tx_fifo(i2c_dev);
> >
> > - int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
> > if (i2c_dev->hw->has_per_pkt_xfer_complete_irq)
> > int_mask |= I2C_INT_PACKET_XFER_COMPLETE;
> > if (msg->flags & I2C_M_RD)
> > int_mask |= I2C_INT_RX_FIFO_DATA_REQ;
> > else if (i2c_dev->msg_buf_remaining)
> > int_mask |= I2C_INT_TX_FIFO_DATA_REQ;
> > +
> > tegra_i2c_unmask_irq(i2c_dev, int_mask);
>
> Can this line be removed? The NO_ACK and ARBITRATION_LOST interrupts
> are already unmasked earlier.
[Shardar] unmask_irq() here is enabling other interrupts (PACKET_XFER_COMPLETE/TX_FIFO_DATA_REQ/RX_FIFO_DATA_REQ). please let me know if my understanding is wrong from your comment.
>
> Thierry
>
> * Unknown Key
> * 0x7F3EB3A1
[toc] | [next] | [standalone]
| From | Thierry Reding <thierry.reding@gmail.com> |
|---|---|
| Date | 2016-04-18 09:30 +0200 |
| Message-ID | <rpbN7-1wD-1@gated-at.bofh.it> |
| In reply to | #1380503 |
[Multipart message — attachments visible in raw view] — view raw
On Sat, Apr 16, 2016 at 08:08:50AM +0000, Shardar Mohammed wrote: [...] > > > if (!(msg->flags & I2C_M_RD)) > > > tegra_i2c_fill_tx_fifo(i2c_dev); > > > > > > - int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST; > > > if (i2c_dev->hw->has_per_pkt_xfer_complete_irq) > > > int_mask |= I2C_INT_PACKET_XFER_COMPLETE; > > > if (msg->flags & I2C_M_RD) > > > int_mask |= I2C_INT_RX_FIFO_DATA_REQ; > > > else if (i2c_dev->msg_buf_remaining) > > > int_mask |= I2C_INT_TX_FIFO_DATA_REQ; > > > + > > > tegra_i2c_unmask_irq(i2c_dev, int_mask); > > > > Can this line be removed? The NO_ACK and ARBITRATION_LOST interrupts > > are already unmasked earlier. > > [Shardar] unmask_irq() here is enabling other interrupts > (PACKET_XFER_COMPLETE/TX_FIFO_DATA_REQ/RX_FIFO_DATA_REQ). please let > me know if my understanding is wrong from your comment. You're right, I obviously wasn't looking closely enough. Thierry
[toc] | [prev] | [next] | [standalone]
| From | Thierry Reding <thierry.reding@gmail.com> |
|---|---|
| Date | 2016-04-18 09:40 +0200 |
| Message-ID | <rpbWO-1C9-15@gated-at.bofh.it> |
| In reply to | #1380503 |
[Multipart message — attachments visible in raw view] — view raw
On Sat, Apr 16, 2016 at 08:08:50AM +0000, Shardar Mohammed wrote: > Thanks for the review, updated with comments inline with Shardar. > > > On Fri, Apr 15, 2016 at 06:51:47PM +0530, Shardar Shariff Md wrote: > > > From: Shardar Shariff Md <smohammed@nvidia.com> > > > > > > To summarize the issue observed in error cases: > > > > > > In SW: For i2c message transfer, packet header and data payload is > > > posted and then required error/packet completion interrupts are > > > enabled later. > > > > > > In HW flow: HW process the packet just after packet header is posted, > > > if ARB lost/NACK error occurs (SW will not handle immediately when > > > error happens as error interrupts are not enabled at this point). HW > > > assumes error is acknowledged and clears current data in FIFO, But SW > > > here posts the remaining data payload which still stays in FIFO as > > > stale data (data without packet header). > > > > > > Now once the interrupts are enabled, SW handles ARB lost/NACK error by > > > clearing the ARB lost/NACK interrupt. Now HW assumes that SW attended > > > the error and will parse/process stale data (data without packet > > > header) present in FIFO which causes invalid NACK errors. > > > > > > Fix: Enable the error interrupts before posting the packet into FIFO > > > which make sure HW to not clear the fifo. Also disable the packet mode > > > before acknowledging errors (ARB lost/NACK error) to not process any > > > stale data. > > > > > > As error interrupts are enabled before posting the packet header use > > > spinlock to avoid preempting. > > > > Please try to use up the full 78 characters per line in the commit message > > (with the exception being the subject line that should be shorter). > > [Shardar] Will take care of this. I just realized my comment was wrong. The rule is to use 72 characters per line for the commit message. Sorry about that. Thierry
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web