net: can: rockchip: fix tx error in special application

add wait tx req cmd.
fix warning: "BUG! echo_skb %d is occupied!"
disable space_rx_mode when tx req to fix extended frame probability
change standard frame.

Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
Change-Id: I0b11d985224682700f43cb155f357b28622dc4be
This commit is contained in:
Elaine Zhang
2023-10-13 10:21:20 +08:00
committed by Tao Huang
parent ecd2f7a8a0
commit 4314dcc88f

View File

@@ -214,6 +214,7 @@ enum {
#define CAN_RXFRD_OFFSET(n) (CAN_RXFRD + CAN_RF_SIZE * (n))
#define CAN_RX_FILTER_MASK 0x1fffffff
#define NOACK_ERR_FLAG 0xc200800
#define DRV_NAME "rockchip_canfd"
@@ -234,6 +235,7 @@ struct rockchip_canfd {
bool txtorx;
u32 tx_invalid[4];
struct delayed_work tx_err_work;
u32 delay_time_ms;
};
static inline u32 rockchip_canfd_read(const struct rockchip_canfd *priv,
@@ -357,6 +359,12 @@ static int rockchip_canfd_set_bittiming(struct net_device *ndev)
rockchip_canfd_write(rcan, CAN_DBTP, reg_btp);
}
if (bt->bitrate > 200000)
rcan->delay_time_ms = 1;
else if (bt->bitrate > 50000)
rcan->delay_time_ms = 5;
else
rcan->delay_time_ms = 20;
netdev_dbg(ndev, "%s NBTP=0x%08x, DBTP=0x%08x, TDCR=0x%08x\n", __func__,
rockchip_canfd_read(rcan, CAN_NBTP),
@@ -487,13 +495,27 @@ static void rockchip_canfd_tx_err_delay_work(struct work_struct *work)
{
struct rockchip_canfd *rcan =
container_of(work, struct rockchip_canfd, tx_err_work.work);
u32 mode;
u32 mode, err_code;
mode = rockchip_canfd_read(rcan, CAN_MODE);
rockchip_canfd_write(rcan, CAN_MODE, 0);
rockchip_canfd_write(rcan, CAN_MODE, mode);
rockchip_canfd_write(rcan, CAN_CMD, CAN_TX0_REQ);
schedule_delayed_work(&rcan->tx_err_work, 1);
err_code = rockchip_canfd_read(rcan, CAN_ERR_CODE);
if ((err_code & NOACK_ERR_FLAG) == NOACK_ERR_FLAG) {
rockchip_canfd_write(rcan, CAN_MODE,
rockchip_canfd_read(rcan, CAN_MODE) | MODE_SPACE_RX);
rockchip_canfd_write(rcan, CAN_CMD, CAN_TX0_REQ);
rockchip_canfd_write(rcan, CAN_MODE,
rockchip_canfd_read(rcan, CAN_MODE) & (~MODE_SPACE_RX));
schedule_delayed_work(&rcan->tx_err_work, msecs_to_jiffies(rcan->delay_time_ms));
} else {
rockchip_canfd_write(rcan, CAN_MODE, 0);
rockchip_canfd_write(rcan, CAN_MODE, mode);
rockchip_canfd_write(rcan, CAN_MODE,
rockchip_canfd_read(rcan, CAN_MODE) | MODE_SPACE_RX);
rockchip_canfd_write(rcan, CAN_CMD, CAN_TX0_REQ);
rockchip_canfd_write(rcan, CAN_MODE,
rockchip_canfd_read(rcan, CAN_MODE) & (~MODE_SPACE_RX));
schedule_delayed_work(&rcan->tx_err_work, msecs_to_jiffies(rcan->delay_time_ms));
}
}
/* transmit a CAN message
@@ -569,10 +591,9 @@ static int rockchip_canfd_start_xmit(struct sk_buff *skb,
for (i = 0; i < cf->len; i += 4)
rockchip_canfd_write(rcan, CAN_TXDAT0 + i,
*(u32 *)(cf->data + i));
can_put_echo_skb(skb, ndev, 0);
rockchip_canfd_write(rcan, CAN_CMD, CAN_TX1_REQ);
local_irq_restore(flags);
can_put_echo_skb(skb, ndev, 0);
return NETDEV_TX_OK;
}
@@ -583,12 +604,13 @@ static int rockchip_canfd_start_xmit(struct sk_buff *skb,
rockchip_canfd_write(rcan, CAN_TXDAT0 + i,
*(u32 *)(cf->data + i));
rockchip_canfd_write(rcan, CAN_CMD, cmd);
schedule_delayed_work(&rcan->tx_err_work, 1);
can_put_echo_skb(skb, ndev, 0);
rockchip_canfd_write(rcan, CAN_MODE,
rockchip_canfd_read(rcan, CAN_MODE) | MODE_SPACE_RX);
rockchip_canfd_write(rcan, CAN_CMD, cmd);
rockchip_canfd_write(rcan, CAN_MODE,
rockchip_canfd_read(rcan, CAN_MODE) & (~MODE_SPACE_RX));
schedule_delayed_work(&rcan->tx_err_work, msecs_to_jiffies(rcan->delay_time_ms));
return NETDEV_TX_OK;
}
@@ -740,9 +762,6 @@ static int rockchip_canfd_err(struct net_device *ndev, u32 isr)
cf->data[7] = rxerr;
}
if (isr & TX_LOSTARB_INT)
schedule_delayed_work(&rcan->tx_err_work, 1);
if (isr & BUS_OFF_INT) {
rcan->can.state = CAN_STATE_BUS_OFF;
rcan->can.can_stats.bus_off++;
@@ -788,13 +807,14 @@ static irqreturn_t rockchip_canfd_interrupt(int irq, void *dev_id)
struct rockchip_canfd *rcan = netdev_priv(ndev);
struct net_device_stats *stats = &ndev->stats;
u32 err_int = ERR_WARN_INT | RX_BUF_OV_INT | PASSIVE_ERR_INT |
TX_LOSTARB_INT | BUS_ERR_INT | BUS_OFF_INT;
BUS_ERR_INT | BUS_OFF_INT;
u32 isr;
u32 dlc = 0;
u32 quota, work_done = 0;
isr = rockchip_canfd_read(rcan, CAN_INT);
if (isr & TX_FINISH_INT) {
cancel_delayed_work(&rcan->tx_err_work);
dlc = rockchip_canfd_read(rcan, CAN_TXFIC);
/* transmission complete interrupt */
if (dlc & FDF_MASK)
@@ -802,7 +822,6 @@ static irqreturn_t rockchip_canfd_interrupt(int irq, void *dev_id)
else
stats->tx_bytes += (dlc & DLC_MASK);
stats->tx_packets++;
cancel_delayed_work(&rcan->tx_err_work);
if (rcan->txtorx && rcan->mode <= ROCKCHIP_RK3568_CAN_MODE && dlc & FORMAT_MASK) {
rockchip_canfd_write(rcan, CAN_TX_CHECK_FIC, FORMAT_MASK);
quota = rockchip_canfd_get_rx_fifo_cnt(ndev);
@@ -814,6 +833,10 @@ static irqreturn_t rockchip_canfd_interrupt(int irq, void *dev_id)
rockchip_canfd_write(rcan, CAN_CMD, CAN_TX1_REQ);
rockchip_canfd_write(rcan, CAN_TX_CHECK_FIC, 0);
}
if (read_poll_timeout_atomic(rockchip_canfd_read, quota,
!(quota & 0x3),
0, 5000000, false, rcan, CAN_CMD))
netdev_err(ndev, "Warning: wait tx req timeout!\n");
rockchip_canfd_write(rcan, CAN_CMD, 0);
can_get_echo_skb(ndev, 0);
netif_wake_queue(ndev);