| .. | .. |
|---|
| 214 | 214 | #define CAN_RXFRD_OFFSET(n) (CAN_RXFRD + CAN_RF_SIZE * (n)) |
|---|
| 215 | 215 | |
|---|
| 216 | 216 | #define CAN_RX_FILTER_MASK 0x1fffffff |
|---|
| 217 | +#define NOACK_ERR_FLAG 0xc200800 |
|---|
| 218 | +#define CAN_BUSOFF_FLAG 0x20 |
|---|
| 217 | 219 | |
|---|
| 218 | 220 | #define DRV_NAME "rockchip_canfd" |
|---|
| 219 | 221 | |
|---|
| .. | .. |
|---|
| 234 | 236 | bool txtorx; |
|---|
| 235 | 237 | u32 tx_invalid[4]; |
|---|
| 236 | 238 | struct delayed_work tx_err_work; |
|---|
| 239 | + u32 delay_time_ms; |
|---|
| 237 | 240 | }; |
|---|
| 238 | 241 | |
|---|
| 239 | 242 | static inline u32 rockchip_canfd_read(const struct rockchip_canfd *priv, |
|---|
| .. | .. |
|---|
| 357 | 360 | |
|---|
| 358 | 361 | rockchip_canfd_write(rcan, CAN_DBTP, reg_btp); |
|---|
| 359 | 362 | } |
|---|
| 363 | + if (bt->bitrate > 200000) |
|---|
| 364 | + rcan->delay_time_ms = 1; |
|---|
| 365 | + else if (bt->bitrate > 50000) |
|---|
| 366 | + rcan->delay_time_ms = 5; |
|---|
| 367 | + else |
|---|
| 368 | + rcan->delay_time_ms = 20; |
|---|
| 360 | 369 | |
|---|
| 361 | 370 | netdev_dbg(ndev, "%s NBTP=0x%08x, DBTP=0x%08x, TDCR=0x%08x\n", __func__, |
|---|
| 362 | 371 | rockchip_canfd_read(rcan, CAN_NBTP), |
|---|
| .. | .. |
|---|
| 428 | 437 | if (rcan->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) |
|---|
| 429 | 438 | val |= MODE_SELF_TEST | MODE_LBACK; |
|---|
| 430 | 439 | |
|---|
| 440 | + /* Listen-only mode */ |
|---|
| 441 | + if (rcan->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) |
|---|
| 442 | + val |= MODE_SILENT; |
|---|
| 443 | + |
|---|
| 431 | 444 | rockchip_canfd_write(rcan, CAN_MODE, val); |
|---|
| 432 | 445 | |
|---|
| 433 | 446 | rockchip_canfd_set_bittiming(ndev); |
|---|
| .. | .. |
|---|
| 487 | 500 | { |
|---|
| 488 | 501 | struct rockchip_canfd *rcan = |
|---|
| 489 | 502 | container_of(work, struct rockchip_canfd, tx_err_work.work); |
|---|
| 490 | | - u32 mode; |
|---|
| 503 | + u32 mode, err_code; |
|---|
| 491 | 504 | |
|---|
| 492 | 505 | mode = rockchip_canfd_read(rcan, CAN_MODE); |
|---|
| 493 | | - rockchip_canfd_write(rcan, CAN_MODE, 0); |
|---|
| 494 | | - rockchip_canfd_write(rcan, CAN_MODE, mode); |
|---|
| 495 | | - rockchip_canfd_write(rcan, CAN_CMD, CAN_TX0_REQ); |
|---|
| 496 | | - schedule_delayed_work(&rcan->tx_err_work, 1); |
|---|
| 506 | + err_code = rockchip_canfd_read(rcan, CAN_ERR_CODE); |
|---|
| 507 | + if ((err_code & NOACK_ERR_FLAG) == NOACK_ERR_FLAG) { |
|---|
| 508 | + rockchip_canfd_write(rcan, CAN_MODE, |
|---|
| 509 | + rockchip_canfd_read(rcan, CAN_MODE) | MODE_SPACE_RX); |
|---|
| 510 | + rockchip_canfd_write(rcan, CAN_CMD, CAN_TX0_REQ); |
|---|
| 511 | + rockchip_canfd_write(rcan, CAN_MODE, |
|---|
| 512 | + rockchip_canfd_read(rcan, CAN_MODE) & (~MODE_SPACE_RX)); |
|---|
| 513 | + schedule_delayed_work(&rcan->tx_err_work, msecs_to_jiffies(rcan->delay_time_ms)); |
|---|
| 514 | + } else { |
|---|
| 515 | + rockchip_canfd_write(rcan, CAN_MODE, 0); |
|---|
| 516 | + rockchip_canfd_write(rcan, CAN_MODE, mode); |
|---|
| 517 | + rockchip_canfd_write(rcan, CAN_MODE, |
|---|
| 518 | + rockchip_canfd_read(rcan, CAN_MODE) | MODE_SPACE_RX); |
|---|
| 519 | + rockchip_canfd_write(rcan, CAN_CMD, CAN_TX0_REQ); |
|---|
| 520 | + rockchip_canfd_write(rcan, CAN_MODE, |
|---|
| 521 | + rockchip_canfd_read(rcan, CAN_MODE) & (~MODE_SPACE_RX)); |
|---|
| 522 | + schedule_delayed_work(&rcan->tx_err_work, msecs_to_jiffies(rcan->delay_time_ms)); |
|---|
| 523 | + } |
|---|
| 497 | 524 | } |
|---|
| 498 | 525 | |
|---|
| 499 | 526 | /* transmit a CAN message |
|---|
| .. | .. |
|---|
| 569 | 596 | for (i = 0; i < cf->len; i += 4) |
|---|
| 570 | 597 | rockchip_canfd_write(rcan, CAN_TXDAT0 + i, |
|---|
| 571 | 598 | *(u32 *)(cf->data + i)); |
|---|
| 599 | + can_put_echo_skb(skb, ndev, 0); |
|---|
| 572 | 600 | rockchip_canfd_write(rcan, CAN_CMD, CAN_TX1_REQ); |
|---|
| 573 | 601 | local_irq_restore(flags); |
|---|
| 574 | | - can_put_echo_skb(skb, ndev, 0); |
|---|
| 575 | | - |
|---|
| 576 | 602 | return NETDEV_TX_OK; |
|---|
| 577 | 603 | } |
|---|
| 578 | 604 | |
|---|
| .. | .. |
|---|
| 583 | 609 | rockchip_canfd_write(rcan, CAN_TXDAT0 + i, |
|---|
| 584 | 610 | *(u32 *)(cf->data + i)); |
|---|
| 585 | 611 | |
|---|
| 586 | | - rockchip_canfd_write(rcan, CAN_CMD, cmd); |
|---|
| 587 | | - |
|---|
| 588 | | - schedule_delayed_work(&rcan->tx_err_work, 1); |
|---|
| 589 | | - |
|---|
| 590 | 612 | can_put_echo_skb(skb, ndev, 0); |
|---|
| 591 | | - |
|---|
| 613 | + rockchip_canfd_write(rcan, CAN_MODE, |
|---|
| 614 | + rockchip_canfd_read(rcan, CAN_MODE) | MODE_SPACE_RX); |
|---|
| 615 | + rockchip_canfd_write(rcan, CAN_CMD, cmd); |
|---|
| 616 | + rockchip_canfd_write(rcan, CAN_MODE, |
|---|
| 617 | + rockchip_canfd_read(rcan, CAN_MODE) & (~MODE_SPACE_RX)); |
|---|
| 618 | + schedule_delayed_work(&rcan->tx_err_work, msecs_to_jiffies(rcan->delay_time_ms)); |
|---|
| 592 | 619 | return NETDEV_TX_OK; |
|---|
| 593 | 620 | } |
|---|
| 594 | 621 | |
|---|
| .. | .. |
|---|
| 740 | 767 | cf->data[7] = rxerr; |
|---|
| 741 | 768 | } |
|---|
| 742 | 769 | |
|---|
| 743 | | - if (isr & TX_LOSTARB_INT) |
|---|
| 744 | | - schedule_delayed_work(&rcan->tx_err_work, 1); |
|---|
| 745 | | - |
|---|
| 746 | 770 | if (isr & BUS_OFF_INT) { |
|---|
| 747 | 771 | rcan->can.state = CAN_STATE_BUS_OFF; |
|---|
| 748 | 772 | rcan->can.can_stats.bus_off++; |
|---|
| .. | .. |
|---|
| 772 | 796 | } |
|---|
| 773 | 797 | |
|---|
| 774 | 798 | if (rcan->can.state >= CAN_STATE_BUS_OFF || |
|---|
| 775 | | - ((sta_reg & 0x20) == 0x20)) |
|---|
| 776 | | - can_bus_off(ndev); |
|---|
| 799 | + ((sta_reg & CAN_BUSOFF_FLAG) == CAN_BUSOFF_FLAG)) { |
|---|
| 800 | + cancel_delayed_work(&rcan->tx_err_work); |
|---|
| 801 | + netif_stop_queue(ndev); |
|---|
| 802 | + rockchip_canfd_stop(ndev); |
|---|
| 803 | + can_free_echo_skb(ndev, 0); |
|---|
| 804 | + rockchip_canfd_start(ndev); |
|---|
| 805 | + netif_start_queue(ndev); |
|---|
| 806 | + } |
|---|
| 777 | 807 | |
|---|
| 778 | 808 | stats->rx_packets++; |
|---|
| 779 | 809 | stats->rx_bytes += cf->can_dlc; |
|---|
| .. | .. |
|---|
| 788 | 818 | struct rockchip_canfd *rcan = netdev_priv(ndev); |
|---|
| 789 | 819 | struct net_device_stats *stats = &ndev->stats; |
|---|
| 790 | 820 | u32 err_int = ERR_WARN_INT | RX_BUF_OV_INT | PASSIVE_ERR_INT | |
|---|
| 791 | | - TX_LOSTARB_INT | BUS_ERR_INT | BUS_OFF_INT; |
|---|
| 821 | + BUS_ERR_INT | BUS_OFF_INT; |
|---|
| 792 | 822 | u32 isr; |
|---|
| 793 | 823 | u32 dlc = 0; |
|---|
| 794 | 824 | u32 quota, work_done = 0; |
|---|
| 795 | 825 | |
|---|
| 796 | 826 | isr = rockchip_canfd_read(rcan, CAN_INT); |
|---|
| 797 | 827 | if (isr & TX_FINISH_INT) { |
|---|
| 828 | + cancel_delayed_work(&rcan->tx_err_work); |
|---|
| 798 | 829 | dlc = rockchip_canfd_read(rcan, CAN_TXFIC); |
|---|
| 799 | 830 | /* transmission complete interrupt */ |
|---|
| 800 | 831 | if (dlc & FDF_MASK) |
|---|
| .. | .. |
|---|
| 802 | 833 | else |
|---|
| 803 | 834 | stats->tx_bytes += (dlc & DLC_MASK); |
|---|
| 804 | 835 | stats->tx_packets++; |
|---|
| 805 | | - cancel_delayed_work(&rcan->tx_err_work); |
|---|
| 806 | 836 | if (rcan->txtorx && rcan->mode <= ROCKCHIP_RK3568_CAN_MODE && dlc & FORMAT_MASK) { |
|---|
| 807 | 837 | rockchip_canfd_write(rcan, CAN_TX_CHECK_FIC, FORMAT_MASK); |
|---|
| 808 | 838 | quota = rockchip_canfd_get_rx_fifo_cnt(ndev); |
|---|
| .. | .. |
|---|
| 814 | 844 | rockchip_canfd_write(rcan, CAN_CMD, CAN_TX1_REQ); |
|---|
| 815 | 845 | rockchip_canfd_write(rcan, CAN_TX_CHECK_FIC, 0); |
|---|
| 816 | 846 | } |
|---|
| 847 | + if (read_poll_timeout_atomic(rockchip_canfd_read, quota, |
|---|
| 848 | + !(quota & 0x3), |
|---|
| 849 | + 0, 5000000, false, rcan, CAN_CMD)) |
|---|
| 850 | + netdev_err(ndev, "Warning: wait tx req timeout!\n"); |
|---|
| 817 | 851 | rockchip_canfd_write(rcan, CAN_CMD, 0); |
|---|
| 818 | 852 | can_get_echo_skb(ndev, 0); |
|---|
| 819 | 853 | netif_wake_queue(ndev); |
|---|
| .. | .. |
|---|
| 825 | 859 | rockchip_canfd_write(rcan, CAN_INT_MASK, 0x1); |
|---|
| 826 | 860 | napi_schedule(&rcan->napi); |
|---|
| 827 | 861 | } else { |
|---|
| 828 | | - quota = rockchip_canfd_get_rx_fifo_cnt(ndev); |
|---|
| 862 | + work_done = 0; |
|---|
| 863 | + quota = (rockchip_canfd_read(rcan, CAN_RXFC) & |
|---|
| 864 | + rcan->rx_fifo_mask) >> |
|---|
| 865 | + rcan->rx_fifo_shift; |
|---|
| 829 | 866 | if (quota) { |
|---|
| 830 | 867 | while (work_done < quota) |
|---|
| 831 | 868 | work_done += rockchip_canfd_rx(ndev); |
|---|