brintos

brintos / linux-shallow public Read only

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