From: Yanfei Xu
Commit:621e14659f37("can: flexcan: drop repetitive execution
can_rx_offload_add_timestamp") and commit:3713ba3e41db("s32: flexcan:
Remove duplicated code as part of kernel 5.4-rt initial merge") fix the
same flexcan bug in different way, and both of them are contained in
codes, that causes the flexcan_open() always run failed.
Here we remove the commit:621e14659f37 and intergrate codes, and revert
a relevant commit:26f171fbcbe1("s32: flexcan: Remove unused function
flexcan_mailbox_read()")
Signed-off-by: Yanfei Xu
---
drivers/net/can/flexcan.c | 133 ++
1 file changed, 133 insertions(+)
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index 9cf016f7021a..38c6041d3b65 100755
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -1051,6 +1051,117 @@ static inline struct flexcan_priv
*rx_offload_to_priv(struct can_rx_offload *off
return container_of(offload, struct flexcan_priv, offload);
}
+static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload,
+bool drop, struct sk_buff **skb,
+u32 *timestamp, unsigned int n)
+{
+ struct flexcan_priv *priv = rx_offload_to_priv(offload);
+ struct flexcan_regs __iomem *regs = priv->regs;
+ struct flexcan_mb __iomem *mb;
+ struct canfd_frame *cf;
+ u32 reg_ctrl, reg_id, reg_iflag1;
+ int i, j;
+ unsigned long flags;
+
+ mb = flexcan_get_mb(priv, n);
+
+ spin_lock_irqsave(>timer_access, flags);
+ if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
+ u32 code;
+
+ do {
+ reg_ctrl = priv->read(>can_ctrl);
+ } while (reg_ctrl & FLEXCAN_MB_CODE_RX_BUSY_BIT);
+
+ /* is this MB empty? */
+ code = reg_ctrl & FLEXCAN_MB_CODE_MASK;
+ if ((code != FLEXCAN_MB_CODE_RX_FULL) &&
+ (code != FLEXCAN_MB_CODE_RX_OVERRUN)) {
+ spin_unlock_irqrestore(>timer_access, flags);
+ return 0;
+ }
+
+ if (code == FLEXCAN_MB_CODE_RX_OVERRUN) {
+ /* This MB was overrun, we lost data */
+ offload->dev->stats.rx_over_errors++;
+ offload->dev->stats.rx_errors++;
+ }
+ } else {
+ reg_iflag1 = priv->read(>iflag1);
+ if (!(reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE)) {
+ spin_unlock_irqrestore(>timer_access, flags);
+ return 0;
+ }
+
+ reg_ctrl = priv->read(>can_ctrl);
+ }
+
+ if (!drop) {
+ if (reg_ctrl & FLEXCAN_MB_CNT_EDL)
+ *skb = alloc_canfd_skb(offload->dev, );
+ else
+ *skb = alloc_can_skb(offload->dev,
+(struct can_frame **));
+
+ if (!*skb)
+ goto ack_mailbox;
+
+ /* increase timstamp to full 32 bit */
+ *timestamp = reg_ctrl << 16;
+
+ reg_id = priv->read(>can_id);
+ if (reg_ctrl & FLEXCAN_MB_CNT_IDE)
+ cf->can_id = ((reg_id >> 0) & CAN_EFF_MASK) |
+CAN_EFF_FLAG;
+ else
+ cf->can_id = (reg_id >> 18) & CAN_SFF_MASK;
+
+ if (reg_ctrl & FLEXCAN_MB_CNT_EDL) {
+ cf->len = can_dlc2len((reg_ctrl >> 16) & 0x0F);
+
+
+ if (reg_ctrl & FLEXCAN_MB_CNT_BRS)
+ cf->flags |= CANFD_BRS;
+ } else {
+ cf->len = get_can_dlc((reg_ctrl >> 16) & 0x0F);
+
+ if (reg_ctrl & FLEXCAN_MB_CNT_RTR)
+ cf->can_id |= CAN_RTR_FLAG;
+ }
+
+ if (reg_ctrl & FLEXCAN_MB_CNT_ESI) {
+ cf->flags |= CANFD_ESI;
+ netdev_warn(priv->can.dev, "ESI Error\n");
+ }
+
+ for (i = 0, j = 0; i < cf->len; i += sizeof(u32), j++) {
+ __be32 data = cpu_to_be32(priv->read(>data[j]));
+ *(__be32 *)(cf->data + i) = data;
+ }
+ }
+
+ack_mailbox:
+ /* mark as read */
+ if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
+ /* Clear IRQ */
+ if (n < 32)
+ priv->write(BIT(n), >iflag1);
+ else
+ priv->write(BIT(n - 32), >iflag2);
+ } else {
+ priv->write(FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, >iflag1);
+ }
+
+ /* Read the Free Running Timer. It is optional but recommended
+* to unlock Mailbox as soon as possible and make it available