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(®s->iflag2) & priv->reg_imask2_default & - ~FLEXCAN_IFLAG_MB(priv->tx_mb_idx); - iflag1 = priv->read(®s->iflag1) & priv->reg_imask1_default; + iflag = ((u64)priv->read(®s->iflag2) << 32) | + priv->read(®s->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(®s->iflag2); + reg_iflag = ((u64)priv->read(®s->iflag2) << 32) | + priv->read(®s->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), ®s->iflag2); + reg_iflag = FLEXCAN_IFLAG_MB(priv->tx_mb_idx); + priv->write(reg_iflag >> 32, ®s->iflag2); + priv->write((u32)reg_iflag, ®s->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, ®s->ctrl); - priv->write(priv->reg_imask1_default, ®s->imask1); - priv->write(priv->reg_imask2_default, ®s->imask2); + priv->write(priv->reg_imask_default >> 32, ®s->imask2); + priv->write((u32)priv->reg_imask_default, ®s->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