- refresh, rebase and reorder patches - JH7110 media drivers have been dropped for now - JH7110 E24 and mailbox drivers were added - JH7100 DMA- and errata-patches have been dropped as they were upstreamed Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
196 lines
6.8 KiB
Diff
196 lines
6.8 KiB
Diff
From 356774301b12dbdfe4682e12c57bddb8058014a2 Mon Sep 17 00:00:00 2001
|
|
From: William Qiu <william.qiu@starfivetech.com>
|
|
Date: Sat, 12 Oct 2024 17:56:00 +0800
|
|
Subject: [PATCH 12/55] ipms: CAN: Solve CAN packet leakage problem
|
|
|
|
Improve RX interrupt trigger mechanism, reduce buffer trigger condition,
|
|
and increase polling value to solve the problem of CAN packet leakage.
|
|
|
|
Signed-off-by: William Qiu <william.qiu@starfivetech.com>
|
|
---
|
|
drivers/net/can/ipms_canfd.c | 108 +++++++++++++++++++----------------
|
|
1 file changed, 59 insertions(+), 49 deletions(-)
|
|
|
|
--- a/drivers/net/can/ipms_canfd.c
|
|
+++ b/drivers/net/can/ipms_canfd.c
|
|
@@ -5,28 +5,30 @@
|
|
* Copyright (c) 2022 StarFive Technology Co., Ltd.
|
|
*/
|
|
|
|
+#include <linux/can/dev.h>
|
|
+#include <linux/can/error.h>
|
|
#include <linux/clk.h>
|
|
-#include <linux/reset.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/init.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/io.h>
|
|
+#include <linux/jiffies.h>
|
|
#include <linux/kernel.h>
|
|
+#include <linux/mfd/syscon.h>
|
|
#include <linux/module.h>
|
|
#include <linux/netdevice.h>
|
|
#include <linux/of.h>
|
|
+#include <linux/of_device.h>
|
|
#include <linux/platform_device.h>
|
|
+#include <linux/pm_runtime.h>
|
|
+#include <linux/regmap.h>
|
|
+#include <linux/reset.h>
|
|
#include <linux/skbuff.h>
|
|
#include <linux/string.h>
|
|
#include <linux/types.h>
|
|
-#include <linux/can/dev.h>
|
|
-#include <linux/can/error.h>
|
|
-#include <linux/pm_runtime.h>
|
|
-#include <linux/of_device.h>
|
|
-#include <linux/mfd/syscon.h>
|
|
-#include <linux/regmap.h>
|
|
|
|
#define DRIVER_NAME "ipms_canfd"
|
|
+#define MAX_IRQ 16
|
|
|
|
/* CAN registers set */
|
|
enum canfd_device_reg {
|
|
@@ -124,7 +126,7 @@ enum canfd_reg_bitchange {
|
|
CAN_FD_SET_BEIF_MASK = 0x01,
|
|
CAN_FD_OFF_EPIE_MASK = 0xdf,
|
|
CAN_FD_OFF_BEIE_MASK = 0xfd,
|
|
- CAN_FD_SET_AFWL_MASK = 0x40,
|
|
+ CAN_FD_SET_AFWL_MASK = 0x20,
|
|
CAN_FD_SET_EWL_MASK = 0x0b,
|
|
CAN_FD_SET_KOER_MASK = 0xe0,
|
|
CAN_FD_SET_BIT_ERROR_MASK = 0x20,
|
|
@@ -366,12 +368,8 @@ static int can_rx(struct net_device *nde
|
|
struct can_frame *cf;
|
|
struct sk_buff *skb;
|
|
u32 can_id;
|
|
- u8 dlc, control, rx_status;
|
|
-
|
|
- rx_status = can_ioread8(priv->reg_base + CANFD_RCTRL_OFFSET);
|
|
+ u8 dlc, control;
|
|
|
|
- if (!(rx_status & CAN_FD_RSTAT_NOT_EMPTY_MASK))
|
|
- return 0;
|
|
control = can_ioread8(priv->reg_base + CANFD_RBUF_CTL_OFFSET);
|
|
can_id = priv->read_reg(priv, CANFD_RUBF_ID_OFFSET);
|
|
dlc = can_ioread8(priv->reg_base + CANFD_RBUF_CTL_OFFSET) & CAN_FD_SET_DLC_MASK;
|
|
@@ -403,7 +401,7 @@ static int can_rx(struct net_device *nde
|
|
canfd_reigister_set_bit(priv, CANFD_RCTRL_OFFSET, CAN_FD_SET_RREL_MASK);
|
|
stats->rx_bytes += can_fd_dlc2len(cf->can_dlc);
|
|
stats->rx_packets++;
|
|
- netif_receive_skb(skb);
|
|
+ netif_rx(skb);
|
|
|
|
return 1;
|
|
}
|
|
@@ -419,9 +417,9 @@ static int canfd_rx(struct net_device *n
|
|
int i;
|
|
|
|
rx_status = can_ioread8(priv->reg_base + CANFD_RCTRL_OFFSET);
|
|
-
|
|
if (!(rx_status & CAN_FD_RSTAT_NOT_EMPTY_MASK))
|
|
return 0;
|
|
+
|
|
control = can_ioread8(priv->reg_base + CANFD_RBUF_CTL_OFFSET);
|
|
can_id = priv->read_reg(priv, CANFD_RUBF_ID_OFFSET);
|
|
dlc = can_ioread8(priv->reg_base + CANFD_RBUF_CTL_OFFSET) & CAN_FD_SET_DLC_MASK;
|
|
@@ -557,6 +555,8 @@ static netdev_tx_t canfd_driver_start_xm
|
|
if (can_dropped_invalid_skb(ndev, skb))
|
|
return NETDEV_TX_OK;
|
|
|
|
+ netif_stop_queue(ndev);
|
|
+
|
|
switch (priv->tx_mode) {
|
|
case XMIT_FULL:
|
|
return NETDEV_TX_BUSY;
|
|
@@ -837,46 +837,56 @@ static irqreturn_t canfd_interrupt(int i
|
|
{
|
|
struct net_device *ndev = (struct net_device *)dev_id;
|
|
struct ipms_canfd_priv *priv = netdev_priv(ndev);
|
|
- u8 isr, eir;
|
|
+ u8 isr, eir, rx_status;
|
|
u8 isr_handled = 0, eir_handled = 0;
|
|
+ int num = 0;
|
|
|
|
- /* read the value of interrupt status register */
|
|
- isr = can_ioread8(priv->reg_base + CANFD_RTIF_OFFSET);
|
|
-
|
|
- /* read the value of error interrupt register */
|
|
- eir = can_ioread8(priv->reg_base + CANFD_ERRINT_OFFSET);
|
|
+ while (((isr = can_ioread8(priv->reg_base + CANFD_RTIF_OFFSET)) ||
|
|
+ (eir = can_ioread8(priv->reg_base + CANFD_ERRINT_OFFSET))) &&
|
|
+ num < MAX_IRQ) {
|
|
+ num++;
|
|
+
|
|
+ /* Check for Tx interrupt and Processing it */
|
|
+ if (isr & (CAN_FD_SET_TPIF_MASK | CAN_FD_SET_TSIF_MASK)) {
|
|
+ canfd_tx_interrupt(ndev, isr);
|
|
+ isr_handled |= (CAN_FD_SET_TPIF_MASK | CAN_FD_SET_TSIF_MASK);
|
|
+ break;
|
|
+ }
|
|
|
|
- /* Check for Tx interrupt and Processing it */
|
|
- if (isr & (CAN_FD_SET_TPIF_MASK | CAN_FD_SET_TSIF_MASK)) {
|
|
- canfd_tx_interrupt(ndev, isr);
|
|
- isr_handled |= (CAN_FD_SET_TPIF_MASK | CAN_FD_SET_TSIF_MASK);
|
|
- }
|
|
- if (isr & (CAN_FD_SET_RAFIF_MASK | CAN_FD_SET_RFIF_MASK)) {
|
|
- canfd_rxfull_interrupt(ndev, isr);
|
|
- isr_handled |= (CAN_FD_SET_RAFIF_MASK | CAN_FD_SET_RFIF_MASK);
|
|
- }
|
|
- /* Check Rx interrupt and Processing the receive interrupt routine */
|
|
- if (isr & CAN_FD_SET_RIF_MASK) {
|
|
- canfd_reigister_off_bit(priv, CANFD_RTIE_OFFSET, CAN_FD_OFF_RIE_MASK);
|
|
- canfd_reigister_set_bit(priv, CANFD_RTIF_OFFSET, CAN_FD_SET_RIF_MASK);
|
|
-
|
|
- napi_schedule(&priv->napi);
|
|
- isr_handled |= CAN_FD_SET_RIF_MASK;
|
|
- }
|
|
- if ((isr & CAN_FD_SET_EIF_MASK) | (eir & (CAN_FD_SET_EPIF_MASK | CAN_FD_SET_BEIF_MASK))) {
|
|
- /* reset EPIF and BEIF. Reset EIF */
|
|
- canfd_reigister_set_bit(priv, CANFD_ERRINT_OFFSET,
|
|
- eir & (CAN_FD_SET_EPIF_MASK | CAN_FD_SET_BEIF_MASK));
|
|
- canfd_reigister_set_bit(priv, CANFD_RTIF_OFFSET,
|
|
- isr & CAN_FD_SET_EIF_MASK);
|
|
+ if (unlikely(isr & (CAN_FD_SET_RAFIF_MASK | CAN_FD_SET_RFIF_MASK))) {
|
|
+ canfd_rxfull_interrupt(ndev, isr);
|
|
+ isr_handled |= (CAN_FD_SET_RAFIF_MASK | CAN_FD_SET_RFIF_MASK);
|
|
+ }
|
|
|
|
- canfd_error_interrupt(ndev, isr, eir);
|
|
+ /* Check Rx interrupt and Processing the receive interrupt routine */
|
|
+ if (isr & CAN_FD_SET_RIF_MASK) {
|
|
+ rx_status = can_ioread8(priv->reg_base + CANFD_RCTRL_OFFSET);
|
|
+ while (rx_status & CAN_FD_RSTAT_NOT_EMPTY_MASK) {
|
|
+ can_rx(ndev);
|
|
+ rx_status = can_ioread8(priv->reg_base + CANFD_RCTRL_OFFSET);
|
|
+ }
|
|
+ isr_handled |= CAN_FD_SET_RIF_MASK;
|
|
+ }
|
|
|
|
- isr_handled |= CAN_FD_SET_EIF_MASK;
|
|
- eir_handled |= (CAN_FD_SET_EPIF_MASK | CAN_FD_SET_BEIF_MASK);
|
|
+ if (unlikely((isr & CAN_FD_SET_EIF_MASK) |
|
|
+ (eir & (CAN_FD_SET_EPIF_MASK | CAN_FD_SET_BEIF_MASK)))) {
|
|
+ /* reset EPIF and BEIF. Reset EIF */
|
|
+ canfd_reigister_set_bit(priv, CANFD_ERRINT_OFFSET,
|
|
+ eir & (CAN_FD_SET_EPIF_MASK |
|
|
+ CAN_FD_SET_BEIF_MASK));
|
|
+ canfd_reigister_set_bit(priv, CANFD_RTIF_OFFSET,
|
|
+ isr & CAN_FD_SET_EIF_MASK);
|
|
+ canfd_error_interrupt(ndev, isr, eir);
|
|
+ isr_handled |= CAN_FD_SET_EIF_MASK;
|
|
+ eir_handled |= (CAN_FD_SET_EPIF_MASK | CAN_FD_SET_BEIF_MASK);
|
|
+ }
|
|
+ canfd_reigister_set_bit(priv, CANFD_RTIF_OFFSET, isr);
|
|
}
|
|
- if ((isr_handled == 0) && (eir_handled == 0)) {
|
|
- netdev_err(ndev, "Unhandled interrupt!\n");
|
|
+
|
|
+ if (num == 0) {
|
|
+ isr = can_ioread8(priv->reg_base + CANFD_RTIF_OFFSET);
|
|
+ eir = can_ioread8(priv->reg_base + CANFD_ERRINT_OFFSET);
|
|
+ netdev_err(ndev, "Unhandled interrupt!isr:%x,eir:%x\n", isr, eir);
|
|
return IRQ_NONE;
|
|
}
|
|
|