[PATCH v2 3/4] can: flexcan: modify the interrupt register handling

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



in flexcan there are two interrupt mask registers and two interrupt flag
register. all these registers are u32 registers

imask1 and imask2 together provide the interrupt mast for maximum possible
64 Message Buffers (MBs). like

(u64)imask = (u64)imask2 << 32) | imask1;

same is true for iflag1 and iflag2.

Now when the MBs are 64 and we operate flexcan in timestamp mode, the Tx MB
is 63 and Rx MBs are 1-62. Tx MB always lies in imask2/iflag2.Which is why
at present in irq handling for Tx irq, only iflag2 is checked.

However when the MB size grows (for flexcan FD mode) the total MB count
decreases to 14 and Tx MB becomes 13.

in this case only checking iflag2 would cause irq handler to loose Tx
interrupt, which causes flexcan device to stop.

Therefore, modify the imask and iflag handling such that we always
check/set complete 64 bit iflag and imask in timestamp mode.

As FD mode is not supported when FIFO mode is selected, leave the iflag
and imask handling in FIFO mode unchanged.

Signed-off-by: Pankaj Bansal <pankaj.bansal@xxxxxxx>
---

Notes:
    V2:
    - No change

 drivers/net/can/flexcan.c | 42 ++++++++++++++++++++-----------------
 1 file changed, 23 insertions(+), 19 deletions(-)

diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index f093d8a15bb2..26e65d3d1c3a 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -142,7 +142,7 @@
 #define FLEXCAN_TX_MB_RESERVED_OFF_FIFO		8
 #define FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP	0
 #define FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST	(FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP + 1)
-#define FLEXCAN_IFLAG_MB(x)		BIT((x) & 0x1f)
+#define FLEXCAN_IFLAG_MB(x)		BIT((x) & 0x3f)
 #define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW	BIT(7)
 #define FLEXCAN_IFLAG_RX_FIFO_WARN	BIT(6)
 #define FLEXCAN_IFLAG_RX_FIFO_AVAILABLE	BIT(5)
@@ -278,8 +278,7 @@ struct flexcan_priv {
 	u8 clk_src;	/* clock source of CAN Protocol Engine */
 
 	u32 reg_ctrl_default;
-	u32 reg_imask1_default;
-	u32 reg_imask2_default;
+	u64 reg_imask_default;
 
 	struct clk *clk_ipg;
 	struct clk *clk_per;
@@ -844,13 +843,16 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload,
 static inline u64 flexcan_read_reg_iflag_rx(struct flexcan_priv *priv)
 {
 	struct flexcan_regs __iomem *regs = priv->regs;
-	u32 iflag1, iflag2;
+	u64 iflag;
 
-	iflag2 = priv->read(&regs->iflag2) & priv->reg_imask2_default &
-		~FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
-	iflag1 = priv->read(&regs->iflag1) & priv->reg_imask1_default;
+	iflag = ((u64)priv->read(&regs->iflag2) << 32) |
+		 priv->read(&regs->iflag1);
 
-	return (u64)iflag2 << 32 | iflag1;
+	iflag &= priv->reg_imask_default;
+
+	iflag &= ~FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
+
+	return iflag;
 }
 
 static irqreturn_t flexcan_irq(int irq, void *dev_id)
@@ -860,7 +862,8 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
 	struct flexcan_priv *priv = netdev_priv(dev);
 	struct flexcan_regs __iomem *regs = priv->regs;
 	irqreturn_t handled = IRQ_NONE;
-	u32 reg_iflag2, reg_esr;
+	u64 reg_iflag;
+	u32 reg_esr;
 	enum can_state last_state = priv->can.state;
 
 	/* reception interrupt */
@@ -894,10 +897,11 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
 		}
 	}
 
-	reg_iflag2 = priv->read(&regs->iflag2);
+	reg_iflag = ((u64)priv->read(&regs->iflag2) << 32) |
+		     priv->read(&regs->iflag1);
 
 	/* transmission complete interrupt */
-	if (reg_iflag2 & FLEXCAN_IFLAG_MB(priv->tx_mb_idx)) {
+	if (reg_iflag & FLEXCAN_IFLAG_MB(priv->tx_mb_idx)) {
 		u32 reg_ctrl = priv->read(&priv->tx_mb->can_ctrl);
 
 		handled = IRQ_HANDLED;
@@ -909,7 +913,9 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
 		/* after sending a RTR frame MB is in RX mode */
 		priv->write(FLEXCAN_MB_CODE_TX_INACTIVE,
 			    &priv->tx_mb->can_ctrl);
-		priv->write(FLEXCAN_IFLAG_MB(priv->tx_mb_idx), &regs->iflag2);
+		reg_iflag = FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
+		priv->write(reg_iflag >> 32, &regs->iflag2);
+		priv->write((u32)reg_iflag, &regs->iflag1);
 		netif_wake_queue(dev);
 	}
 
@@ -1194,8 +1200,8 @@ static int flexcan_chip_start(struct net_device *dev)
 	/* enable interrupts atomically */
 	disable_irq(dev->irq);
 	priv->write(priv->reg_ctrl_default, &regs->ctrl);
-	priv->write(priv->reg_imask1_default, &regs->imask1);
-	priv->write(priv->reg_imask2_default, &regs->imask2);
+	priv->write(priv->reg_imask_default >> 32, &regs->imask2);
+	priv->write((u32)priv->reg_imask_default, &regs->imask1);
 	enable_irq(dev->irq);
 
 	/* print chip status */
@@ -1264,8 +1270,7 @@ static int flexcan_open(struct net_device *dev)
 	priv->tx_mb_idx = priv->mb_count - 1;
 	priv->tx_mb = flexcan_get_mb(priv, priv->tx_mb_idx);
 
-	priv->reg_imask1_default = 0;
-	priv->reg_imask2_default = FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
+	priv->reg_imask_default = FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
 
 	priv->offload.fd_enable = false;
 	priv->offload.mailbox_read = flexcan_mailbox_read;
@@ -1278,12 +1283,11 @@ static int flexcan_open(struct net_device *dev)
 
 		imask = GENMASK_ULL(priv->offload.mb_last,
 				    priv->offload.mb_first);
-		priv->reg_imask1_default |= imask;
-		priv->reg_imask2_default |= imask >> 32;
+		priv->reg_imask_default |= imask;
 
 		err = can_rx_offload_add_timestamp(dev, &priv->offload);
 	} else {
-		priv->reg_imask1_default |= FLEXCAN_IFLAG_RX_FIFO_OVERFLOW |
+		priv->reg_imask_default |= FLEXCAN_IFLAG_RX_FIFO_OVERFLOW |
 			FLEXCAN_IFLAG_RX_FIFO_AVAILABLE;
 		err = can_rx_offload_add_fifo(dev, &priv->offload,
 					      FLEXCAN_NAPI_WEIGHT);
-- 
2.17.1





[Index of Archives]     [Automotive Discussions]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]     [CAN Bus]

  Powered by Linux