xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/marvell/libertas/tx.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * This file contains the handling of TX in wlan driver.
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun #include <linux/hardirq.h>
6*4882a593Smuzhiyun #include <linux/netdevice.h>
7*4882a593Smuzhiyun #include <linux/etherdevice.h>
8*4882a593Smuzhiyun #include <linux/sched.h>
9*4882a593Smuzhiyun #include <linux/export.h>
10*4882a593Smuzhiyun #include <net/cfg80211.h>
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include "host.h"
13*4882a593Smuzhiyun #include "radiotap.h"
14*4882a593Smuzhiyun #include "decl.h"
15*4882a593Smuzhiyun #include "defs.h"
16*4882a593Smuzhiyun #include "dev.h"
17*4882a593Smuzhiyun #include "mesh.h"
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun /**
20*4882a593Smuzhiyun  * convert_radiotap_rate_to_mv - converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE
21*4882a593Smuzhiyun  * units (500 Kb/s) into Marvell WLAN format (see Table 8 in Section 3.2.1)
22*4882a593Smuzhiyun  *
23*4882a593Smuzhiyun  * @rate:	Input rate
24*4882a593Smuzhiyun  * returns:	Output Rate (0 if invalid)
25*4882a593Smuzhiyun  */
convert_radiotap_rate_to_mv(u8 rate)26*4882a593Smuzhiyun static u32 convert_radiotap_rate_to_mv(u8 rate)
27*4882a593Smuzhiyun {
28*4882a593Smuzhiyun 	switch (rate) {
29*4882a593Smuzhiyun 	case 2:		/*   1 Mbps */
30*4882a593Smuzhiyun 		return 0 | (1 << 4);
31*4882a593Smuzhiyun 	case 4:		/*   2 Mbps */
32*4882a593Smuzhiyun 		return 1 | (1 << 4);
33*4882a593Smuzhiyun 	case 11:		/* 5.5 Mbps */
34*4882a593Smuzhiyun 		return 2 | (1 << 4);
35*4882a593Smuzhiyun 	case 22:		/*  11 Mbps */
36*4882a593Smuzhiyun 		return 3 | (1 << 4);
37*4882a593Smuzhiyun 	case 12:		/*   6 Mbps */
38*4882a593Smuzhiyun 		return 4 | (1 << 4);
39*4882a593Smuzhiyun 	case 18:		/*   9 Mbps */
40*4882a593Smuzhiyun 		return 5 | (1 << 4);
41*4882a593Smuzhiyun 	case 24:		/*  12 Mbps */
42*4882a593Smuzhiyun 		return 6 | (1 << 4);
43*4882a593Smuzhiyun 	case 36:		/*  18 Mbps */
44*4882a593Smuzhiyun 		return 7 | (1 << 4);
45*4882a593Smuzhiyun 	case 48:		/*  24 Mbps */
46*4882a593Smuzhiyun 		return 8 | (1 << 4);
47*4882a593Smuzhiyun 	case 72:		/*  36 Mbps */
48*4882a593Smuzhiyun 		return 9 | (1 << 4);
49*4882a593Smuzhiyun 	case 96:		/*  48 Mbps */
50*4882a593Smuzhiyun 		return 10 | (1 << 4);
51*4882a593Smuzhiyun 	case 108:		/*  54 Mbps */
52*4882a593Smuzhiyun 		return 11 | (1 << 4);
53*4882a593Smuzhiyun 	}
54*4882a593Smuzhiyun 	return 0;
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun /**
58*4882a593Smuzhiyun  * lbs_hard_start_xmit - checks the conditions and sends packet to IF
59*4882a593Smuzhiyun  * layer if everything is ok
60*4882a593Smuzhiyun  *
61*4882a593Smuzhiyun  * @skb:	A pointer to skb which includes TX packet
62*4882a593Smuzhiyun  * @dev:	A pointer to the &struct net_device
63*4882a593Smuzhiyun  * returns:	0 or -1
64*4882a593Smuzhiyun  */
lbs_hard_start_xmit(struct sk_buff * skb,struct net_device * dev)65*4882a593Smuzhiyun netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun 	unsigned long flags;
68*4882a593Smuzhiyun 	struct lbs_private *priv = dev->ml_priv;
69*4882a593Smuzhiyun 	struct txpd *txpd;
70*4882a593Smuzhiyun 	char *p802x_hdr;
71*4882a593Smuzhiyun 	uint16_t pkt_len;
72*4882a593Smuzhiyun 	netdev_tx_t ret = NETDEV_TX_OK;
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	/* We need to protect against the queues being restarted before
75*4882a593Smuzhiyun 	   we get round to stopping them */
76*4882a593Smuzhiyun 	spin_lock_irqsave(&priv->driver_lock, flags);
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	if (priv->surpriseremoved)
79*4882a593Smuzhiyun 		goto free;
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) {
82*4882a593Smuzhiyun 		lbs_deb_tx("tx err: skb length %d 0 or > %zd\n",
83*4882a593Smuzhiyun 		       skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE);
84*4882a593Smuzhiyun 		/* We'll never manage to send this one; drop it and return 'OK' */
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 		dev->stats.tx_dropped++;
87*4882a593Smuzhiyun 		dev->stats.tx_errors++;
88*4882a593Smuzhiyun 		goto free;
89*4882a593Smuzhiyun 	}
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	netif_stop_queue(priv->dev);
93*4882a593Smuzhiyun 	if (priv->mesh_dev)
94*4882a593Smuzhiyun 		netif_stop_queue(priv->mesh_dev);
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	if (priv->tx_pending_len) {
97*4882a593Smuzhiyun 		/* This can happen if packets come in on the mesh and eth
98*4882a593Smuzhiyun 		   device simultaneously -- there's no mutual exclusion on
99*4882a593Smuzhiyun 		   hard_start_xmit() calls between devices. */
100*4882a593Smuzhiyun 		lbs_deb_tx("Packet on %s while busy\n", dev->name);
101*4882a593Smuzhiyun 		ret = NETDEV_TX_BUSY;
102*4882a593Smuzhiyun 		goto unlock;
103*4882a593Smuzhiyun 	}
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	priv->tx_pending_len = -1;
106*4882a593Smuzhiyun 	spin_unlock_irqrestore(&priv->driver_lock, flags);
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	lbs_deb_hex(LBS_DEB_TX, "TX Data", skb->data, min_t(unsigned int, skb->len, 100));
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	txpd = (void *)priv->tx_pending_buf;
111*4882a593Smuzhiyun 	memset(txpd, 0, sizeof(struct txpd));
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	p802x_hdr = skb->data;
114*4882a593Smuzhiyun 	pkt_len = skb->len;
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
117*4882a593Smuzhiyun 		struct tx_radiotap_hdr *rtap_hdr = (void *)skb->data;
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 		/* set txpd fields from the radiotap header */
120*4882a593Smuzhiyun 		txpd->tx_control = cpu_to_le32(convert_radiotap_rate_to_mv(rtap_hdr->rate));
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 		/* skip the radiotap header */
123*4882a593Smuzhiyun 		p802x_hdr += sizeof(*rtap_hdr);
124*4882a593Smuzhiyun 		pkt_len -= sizeof(*rtap_hdr);
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 		/* copy destination address from 802.11 header */
127*4882a593Smuzhiyun 		memcpy(txpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN);
128*4882a593Smuzhiyun 	} else {
129*4882a593Smuzhiyun 		/* copy destination address from 802.3 header */
130*4882a593Smuzhiyun 		memcpy(txpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN);
131*4882a593Smuzhiyun 	}
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	txpd->tx_packet_length = cpu_to_le16(pkt_len);
134*4882a593Smuzhiyun 	txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd));
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	lbs_mesh_set_txpd(priv, dev, txpd);
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	lbs_deb_hex(LBS_DEB_TX, "txpd", (u8 *) &txpd, sizeof(struct txpd));
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	lbs_deb_hex(LBS_DEB_TX, "Tx Data", (u8 *) p802x_hdr, le16_to_cpu(txpd->tx_packet_length));
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	memcpy(&txpd[1], p802x_hdr, le16_to_cpu(txpd->tx_packet_length));
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	spin_lock_irqsave(&priv->driver_lock, flags);
145*4882a593Smuzhiyun 	priv->tx_pending_len = pkt_len + sizeof(struct txpd);
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	lbs_deb_tx("%s lined up packet\n", __func__);
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	dev->stats.tx_packets++;
150*4882a593Smuzhiyun 	dev->stats.tx_bytes += skb->len;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
153*4882a593Smuzhiyun 		/* Keep the skb to echo it back once Tx feedback is
154*4882a593Smuzhiyun 		   received from FW */
155*4882a593Smuzhiyun 		skb_orphan(skb);
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 		/* Keep the skb around for when we get feedback */
158*4882a593Smuzhiyun 		priv->currenttxskb = skb;
159*4882a593Smuzhiyun 	} else {
160*4882a593Smuzhiyun  free:
161*4882a593Smuzhiyun 		dev_kfree_skb_any(skb);
162*4882a593Smuzhiyun 	}
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun  unlock:
165*4882a593Smuzhiyun 	spin_unlock_irqrestore(&priv->driver_lock, flags);
166*4882a593Smuzhiyun 	wake_up(&priv->waitq);
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	return ret;
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun /**
172*4882a593Smuzhiyun  * lbs_send_tx_feedback - sends to the host the last transmitted packet,
173*4882a593Smuzhiyun  * filling the radiotap headers with transmission information.
174*4882a593Smuzhiyun  *
175*4882a593Smuzhiyun  * @priv:	A pointer to &struct lbs_private structure
176*4882a593Smuzhiyun  * @try_count:	A 32-bit value containing transmission retry status.
177*4882a593Smuzhiyun  *
178*4882a593Smuzhiyun  * returns:	void
179*4882a593Smuzhiyun  */
lbs_send_tx_feedback(struct lbs_private * priv,u32 try_count)180*4882a593Smuzhiyun void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun 	struct tx_radiotap_hdr *radiotap_hdr;
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	if (priv->wdev->iftype != NL80211_IFTYPE_MONITOR ||
185*4882a593Smuzhiyun 	    priv->currenttxskb == NULL)
186*4882a593Smuzhiyun 		return;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	radiotap_hdr = (struct tx_radiotap_hdr *)priv->currenttxskb->data;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	radiotap_hdr->data_retries = try_count ?
191*4882a593Smuzhiyun 		(1 + priv->txretrycount - try_count) : 0;
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	priv->currenttxskb->protocol = eth_type_trans(priv->currenttxskb,
194*4882a593Smuzhiyun 						      priv->dev);
195*4882a593Smuzhiyun 	netif_rx(priv->currenttxskb);
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	priv->currenttxskb = NULL;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	if (priv->connect_status == LBS_CONNECTED)
200*4882a593Smuzhiyun 		netif_wake_queue(priv->dev);
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	if (priv->mesh_dev && netif_running(priv->mesh_dev))
203*4882a593Smuzhiyun 		netif_wake_queue(priv->mesh_dev);
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(lbs_send_tx_feedback);
206