mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 02:50:49 +09:00
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:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user