aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShardar Shariff Md <smohammed@nvidia.com>2016-08-31 09:28:44 -0400
committerWolfram Sang <wsa@the-dreams.de>2016-09-08 16:34:58 -0400
commit77821b4678f93b0b45870c04b7c06c364ed090de (patch)
treecff0edbebba4d9c52617e7e37f7f1d879e526e20
parent2bc445e2253f963412083c3eb1fc92a276086389 (diff)
i2c: tegra: proper handling of error cases
To summarize the issue observed in error cases: SW Flow: For i2c message transfer, packet header and data payload is posted and then required error/packet completion interrupts are enabled later. 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. Signed-off-by: Shardar Shariff Md <smohammed@nvidia.com> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
-rw-r--r--drivers/i2c/busses/i2c-tegra.c29
1 files changed, 27 insertions, 2 deletions
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 243753564110..c15d5755bccc 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -196,6 +196,7 @@ struct tegra_i2c_dev {
196 u16 clk_divisor_non_hs_mode; 196 u16 clk_divisor_non_hs_mode;
197 bool is_suspended; 197 bool is_suspended;
198 bool is_multimaster_mode; 198 bool is_multimaster_mode;
199 spinlock_t xfer_lock;
199}; 200};
200 201
201static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val, 202static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
@@ -542,14 +543,27 @@ err:
542 return err; 543 return err;
543} 544}
544 545
546static int tegra_i2c_disable_packet_mode(struct tegra_i2c_dev *i2c_dev)
547{
548 u32 cnfg;
549
550 cnfg = i2c_readl(i2c_dev, I2C_CNFG);
551 if (cnfg & I2C_CNFG_PACKET_MODE_EN)
552 i2c_writel(i2c_dev, cnfg & ~I2C_CNFG_PACKET_MODE_EN, I2C_CNFG);
553
554 return tegra_i2c_wait_for_config_load(i2c_dev);
555}
556
545static irqreturn_t tegra_i2c_isr(int irq, void *dev_id) 557static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
546{ 558{
547 u32 status; 559 u32 status;
548 const u32 status_err = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST; 560 const u32 status_err = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
549 struct tegra_i2c_dev *i2c_dev = dev_id; 561 struct tegra_i2c_dev *i2c_dev = dev_id;
562 unsigned long flags;
550 563
551 status = i2c_readl(i2c_dev, I2C_INT_STATUS); 564 status = i2c_readl(i2c_dev, I2C_INT_STATUS);
552 565
566 spin_lock_irqsave(&i2c_dev->xfer_lock, flags);
553 if (status == 0) { 567 if (status == 0) {
554 dev_warn(i2c_dev->dev, "irq status 0 %08x %08x %08x\n", 568 dev_warn(i2c_dev->dev, "irq status 0 %08x %08x %08x\n",
555 i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS), 569 i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS),
@@ -565,6 +579,7 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
565 } 579 }
566 580
567 if (unlikely(status & status_err)) { 581 if (unlikely(status & status_err)) {
582 tegra_i2c_disable_packet_mode(i2c_dev);
568 if (status & I2C_INT_NO_ACK) 583 if (status & I2C_INT_NO_ACK)
569 i2c_dev->msg_err |= I2C_ERR_NO_ACK; 584 i2c_dev->msg_err |= I2C_ERR_NO_ACK;
570 if (status & I2C_INT_ARBITRATION_LOST) 585 if (status & I2C_INT_ARBITRATION_LOST)
@@ -594,7 +609,7 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
594 BUG_ON(i2c_dev->msg_buf_remaining); 609 BUG_ON(i2c_dev->msg_buf_remaining);
595 complete(&i2c_dev->msg_complete); 610 complete(&i2c_dev->msg_complete);
596 } 611 }
597 return IRQ_HANDLED; 612 goto done;
598err: 613err:
599 /* An error occurred, mask all interrupts */ 614 /* An error occurred, mask all interrupts */
600 tegra_i2c_mask_irq(i2c_dev, I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST | 615 tegra_i2c_mask_irq(i2c_dev, I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST |
@@ -605,6 +620,8 @@ err:
605 dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS); 620 dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
606 621
607 complete(&i2c_dev->msg_complete); 622 complete(&i2c_dev->msg_complete);
623done:
624 spin_unlock_irqrestore(&i2c_dev->xfer_lock, flags);
608 return IRQ_HANDLED; 625 return IRQ_HANDLED;
609} 626}
610 627
@@ -614,6 +631,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
614 u32 packet_header; 631 u32 packet_header;
615 u32 int_mask; 632 u32 int_mask;
616 unsigned long time_left; 633 unsigned long time_left;
634 unsigned long flags;
617 635
618 tegra_i2c_flush_fifos(i2c_dev); 636 tegra_i2c_flush_fifos(i2c_dev);
619 637
@@ -626,6 +644,11 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
626 i2c_dev->msg_read = (msg->flags & I2C_M_RD); 644 i2c_dev->msg_read = (msg->flags & I2C_M_RD);
627 reinit_completion(&i2c_dev->msg_complete); 645 reinit_completion(&i2c_dev->msg_complete);
628 646
647 spin_lock_irqsave(&i2c_dev->xfer_lock, flags);
648
649 int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
650 tegra_i2c_unmask_irq(i2c_dev, int_mask);
651
629 packet_header = (0 << PACKET_HEADER0_HEADER_SIZE_SHIFT) | 652 packet_header = (0 << PACKET_HEADER0_HEADER_SIZE_SHIFT) |
630 PACKET_HEADER0_PROTOCOL_I2C | 653 PACKET_HEADER0_PROTOCOL_I2C |
631 (i2c_dev->cont_id << PACKET_HEADER0_CONT_ID_SHIFT) | 654 (i2c_dev->cont_id << PACKET_HEADER0_CONT_ID_SHIFT) |
@@ -655,14 +678,15 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
655 if (!(msg->flags & I2C_M_RD)) 678 if (!(msg->flags & I2C_M_RD))
656 tegra_i2c_fill_tx_fifo(i2c_dev); 679 tegra_i2c_fill_tx_fifo(i2c_dev);
657 680
658 int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
659 if (i2c_dev->hw->has_per_pkt_xfer_complete_irq) 681 if (i2c_dev->hw->has_per_pkt_xfer_complete_irq)
660 int_mask |= I2C_INT_PACKET_XFER_COMPLETE; 682 int_mask |= I2C_INT_PACKET_XFER_COMPLETE;
661 if (msg->flags & I2C_M_RD) 683 if (msg->flags & I2C_M_RD)
662 int_mask |= I2C_INT_RX_FIFO_DATA_REQ; 684 int_mask |= I2C_INT_RX_FIFO_DATA_REQ;
663 else if (i2c_dev->msg_buf_remaining) 685 else if (i2c_dev->msg_buf_remaining)
664 int_mask |= I2C_INT_TX_FIFO_DATA_REQ; 686 int_mask |= I2C_INT_TX_FIFO_DATA_REQ;
687
665 tegra_i2c_unmask_irq(i2c_dev, int_mask); 688 tegra_i2c_unmask_irq(i2c_dev, int_mask);
689 spin_unlock_irqrestore(&i2c_dev->xfer_lock, flags);
666 dev_dbg(i2c_dev->dev, "unmasked irq: %02x\n", 690 dev_dbg(i2c_dev->dev, "unmasked irq: %02x\n",
667 i2c_readl(i2c_dev, I2C_INT_MASK)); 691 i2c_readl(i2c_dev, I2C_INT_MASK));
668 692
@@ -899,6 +923,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
899 i2c_dev->is_dvc = of_device_is_compatible(pdev->dev.of_node, 923 i2c_dev->is_dvc = of_device_is_compatible(pdev->dev.of_node,
900 "nvidia,tegra20-i2c-dvc"); 924 "nvidia,tegra20-i2c-dvc");
901 init_completion(&i2c_dev->msg_complete); 925 init_completion(&i2c_dev->msg_complete);
926 spin_lock_init(&i2c_dev->xfer_lock);
902 927
903 if (!i2c_dev->hw->has_single_clk_source) { 928 if (!i2c_dev->hw->has_single_clk_source) {
904 fast_clk = devm_clk_get(&pdev->dev, "fast-clk"); 929 fast_clk = devm_clk_get(&pdev->dev, "fast-clk");