xref: /linux/drivers/net/can/rockchip/rockchip_canfd-tx.c (revision 58d3cc65a241953d40490329fb7638a93f95dd78) !
1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // Copyright (c) 2023, 2024 Pengutronix,
4 //               Marc Kleine-Budde <kernel@pengutronix.de>
5 //
6 
7 #include <net/netdev_queues.h>
8 
9 #include "rockchip_canfd.h"
10 
11 static void rkcanfd_start_xmit_write_cmd(const struct rkcanfd_priv *priv,
12 					 const u32 reg_cmd)
13 {
14 	rkcanfd_write(priv, RKCANFD_REG_CMD, reg_cmd);
15 }
16 
17 void rkcanfd_xmit_retry(struct rkcanfd_priv *priv)
18 {
19 	const unsigned int tx_head = rkcanfd_get_tx_head(priv);
20 	const u32 reg_cmd = RKCANFD_REG_CMD_TX_REQ(tx_head);
21 
22 	rkcanfd_start_xmit_write_cmd(priv, reg_cmd);
23 }
24 
25 int rkcanfd_start_xmit(struct sk_buff *skb, struct net_device *ndev)
26 {
27 	struct rkcanfd_priv *priv = netdev_priv(ndev);
28 	u32 reg_frameinfo, reg_id, reg_cmd;
29 	unsigned int tx_head, frame_len;
30 	const struct canfd_frame *cfd;
31 	int err;
32 	u8 i;
33 
34 	if (can_dropped_invalid_skb(ndev, skb))
35 		return NETDEV_TX_OK;
36 
37 	if (!netif_subqueue_maybe_stop(priv->ndev, 0,
38 				       rkcanfd_get_tx_free(priv),
39 				       RKCANFD_TX_STOP_THRESHOLD,
40 				       RKCANFD_TX_START_THRESHOLD)) {
41 		if (net_ratelimit())
42 			netdev_info(priv->ndev,
43 				    "Stopping tx-queue (tx_head=0x%08x, tx_tail=0x%08x, tx_pending=%d)\n",
44 				    priv->tx_head, priv->tx_tail,
45 				    rkcanfd_get_tx_pending(priv));
46 
47 		return NETDEV_TX_BUSY;
48 	}
49 
50 	cfd = (struct canfd_frame *)skb->data;
51 
52 	if (cfd->can_id & CAN_EFF_FLAG) {
53 		reg_frameinfo = RKCANFD_REG_FD_FRAMEINFO_FRAME_FORMAT;
54 		reg_id = FIELD_PREP(RKCANFD_REG_FD_ID_EFF, cfd->can_id);
55 	} else {
56 		reg_frameinfo = 0;
57 		reg_id = FIELD_PREP(RKCANFD_REG_FD_ID_SFF, cfd->can_id);
58 	}
59 
60 	if (cfd->can_id & CAN_RTR_FLAG)
61 		reg_frameinfo |= RKCANFD_REG_FD_FRAMEINFO_RTR;
62 
63 	if (can_is_canfd_skb(skb)) {
64 		reg_frameinfo |= RKCANFD_REG_FD_FRAMEINFO_FDF;
65 
66 		if (cfd->flags & CANFD_BRS)
67 			reg_frameinfo |= RKCANFD_REG_FD_FRAMEINFO_BRS;
68 
69 		reg_frameinfo |= FIELD_PREP(RKCANFD_REG_FD_FRAMEINFO_DATA_LENGTH,
70 					    can_fd_len2dlc(cfd->len));
71 	} else {
72 		reg_frameinfo |= FIELD_PREP(RKCANFD_REG_FD_FRAMEINFO_DATA_LENGTH,
73 					    cfd->len);
74 	}
75 
76 	tx_head = rkcanfd_get_tx_head(priv);
77 	reg_cmd = RKCANFD_REG_CMD_TX_REQ(tx_head);
78 
79 	rkcanfd_write(priv, RKCANFD_REG_FD_TXFRAMEINFO, reg_frameinfo);
80 	rkcanfd_write(priv, RKCANFD_REG_FD_TXID, reg_id);
81 	for (i = 0; i < cfd->len; i += 4)
82 		rkcanfd_write(priv, RKCANFD_REG_FD_TXDATA0 + i,
83 			      *(u32 *)(cfd->data + i));
84 
85 	frame_len = can_skb_get_frame_len(skb);
86 	err = can_put_echo_skb(skb, ndev, tx_head, frame_len);
87 	if (!err)
88 		netdev_sent_queue(priv->ndev, frame_len);
89 
90 	WRITE_ONCE(priv->tx_head, priv->tx_head + 1);
91 
92 	rkcanfd_start_xmit_write_cmd(priv, reg_cmd);
93 
94 	netif_subqueue_maybe_stop(priv->ndev, 0,
95 				  rkcanfd_get_tx_free(priv),
96 				  RKCANFD_TX_STOP_THRESHOLD,
97 				  RKCANFD_TX_START_THRESHOLD);
98 
99 	return NETDEV_TX_OK;
100 }
101 
102 void rkcanfd_handle_tx_done_one(struct rkcanfd_priv *priv, const u32 ts,
103 				unsigned int *frame_len_p)
104 {
105 	struct net_device_stats *stats = &priv->ndev->stats;
106 	unsigned int tx_tail;
107 
108 	tx_tail = rkcanfd_get_tx_tail(priv);
109 	stats->tx_bytes +=
110 		can_rx_offload_get_echo_skb_queue_timestamp(&priv->offload,
111 							    tx_tail, ts,
112 							    frame_len_p);
113 	stats->tx_packets++;
114 }
115