summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/wil6210/txrx.c
diff options
context:
space:
mode:
authorVladimir Kondratiev2014-02-27 15:20:46 +0100
committerJohn W. Linville2014-02-28 20:33:31 +0100
commitfb3cac572657fccf4e4406bd9737a0b3aaf54458 (patch)
tree40055dee9e19e654ab2df92e68d6840c507dd961 /drivers/net/wireless/ath/wil6210/txrx.c
parentwil6210: Find free vring for Tx (diff)
downloadkernel-qcow2-linux-fb3cac572657fccf4e4406bd9737a0b3aaf54458.tar.gz
kernel-qcow2-linux-fb3cac572657fccf4e4406bd9737a0b3aaf54458.tar.xz
kernel-qcow2-linux-fb3cac572657fccf4e4406bd9737a0b3aaf54458.zip
wil6210: broadcast Tx
Hardware do not support "real" broadcast on the air. Use method similar to the Directed Multicast Service (DMS) as described in the 10.23.15.2 "DMS procedures" This service copies frame and delivers unicast for each associated peer Do the following: send original frame to 1-st Tx vring, and send copies to all other active vrings. As currently hardware/firmware don't support A-MSDU, convert broadcast frame to unicast instead of wrapping it in A-MSDU Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/wil6210/txrx.c')
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c65
1 files changed, 55 insertions, 10 deletions
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 48d97156f3db..5ff59ee9c9f6 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -662,6 +662,60 @@ static struct vring *wil_find_tx_vring(struct wil6210_priv *wil,
return NULL;
}
+static void wil_set_da_for_vring(struct wil6210_priv *wil,
+ struct sk_buff *skb, int vring_index)
+{
+ struct ethhdr *eth = (void *)skb->data;
+ int cid = wil->vring2cid_tid[vring_index][0];
+ memcpy(eth->h_dest, wil->sta[cid].addr, ETH_ALEN);
+}
+
+static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
+ struct sk_buff *skb);
+/*
+ * Find 1-st vring and return it; set dest address for this vring in skb
+ * duplicate skb and send it to other active vrings
+ */
+static struct vring *wil_tx_bcast(struct wil6210_priv *wil,
+ struct sk_buff *skb)
+{
+ struct vring *v, *v2;
+ struct sk_buff *skb2;
+ int i;
+
+ /* find 1-st vring */
+ for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
+ v = &wil->vring_tx[i];
+ if (v->va)
+ goto found;
+ }
+
+ wil_err(wil, "Tx while no vrings active?\n");
+
+ return NULL;
+
+found:
+ wil_dbg_txrx(wil, "BCAST -> ring %d\n", i);
+ wil_set_da_for_vring(wil, skb, i);
+
+ /* find other active vrings and duplicate skb for each */
+ for (i++; i < WIL6210_MAX_TX_RINGS; i++) {
+ v2 = &wil->vring_tx[i];
+ if (!v2->va)
+ continue;
+ skb2 = skb_copy(skb, GFP_ATOMIC);
+ if (skb2) {
+ wil_dbg_txrx(wil, "BCAST DUP -> ring %d\n", i);
+ wil_set_da_for_vring(wil, skb2, i);
+ wil_tx_vring(wil, v2, skb2);
+ } else {
+ wil_err(wil, "skb_copy failed\n");
+ }
+ }
+
+ return v;
+}
+
static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len,
int vring_index)
{
@@ -875,16 +929,7 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
if (is_unicast_ether_addr(eth->h_dest)) {
vring = wil_find_tx_vring(wil, skb);
} else {
- int i = 0;
- /* TODO: duplicate for all CID's */
- vring = &wil->vring_tx[i];
- if (vring->va) {
- int cid = wil->vring2cid_tid[i][0];
- /* FIXME FW can accept only unicast frames */
- memcpy(skb->data, wil->sta[cid].addr, ETH_ALEN);
- } else {
- vring = NULL;
- }
+ vring = wil_tx_bcast(wil, skb);
}
if (!vring) {
wil_err(wil, "No Tx VRING found for %pM\n", eth->h_dest);