aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd.h2
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c27
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c50
3 files changed, 37 insertions, 42 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
index 939d6b132922..16f9ab2568a8 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
@@ -186,7 +186,7 @@ void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx);
186void brcmf_txflowblock_if(struct brcmf_if *ifp, 186void brcmf_txflowblock_if(struct brcmf_if *ifp,
187 enum brcmf_netif_stop_reason reason, bool state); 187 enum brcmf_netif_stop_reason reason, bool state);
188u32 brcmf_get_chip_info(struct brcmf_if *ifp); 188u32 brcmf_get_chip_info(struct brcmf_if *ifp);
189void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, 189void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, u8 ifidx,
190 bool success); 190 bool success);
191 191
192/* Sets dongle media info (drv_version, mac address). */ 192/* Sets dongle media info (drv_version, mac address). */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
index 7d28cd385092..6056efd02fcd 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
@@ -538,31 +538,26 @@ void brcmf_rx_frame(struct device *dev, struct sk_buff *skb)
538 brcmf_netif_rx(ifp, skb); 538 brcmf_netif_rx(ifp, skb);
539} 539}
540 540
541void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, 541void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, u8 ifidx,
542 bool success) 542 bool success)
543{ 543{
544 struct brcmf_if *ifp; 544 struct brcmf_if *ifp;
545 struct ethhdr *eh; 545 struct ethhdr *eh;
546 u8 ifidx;
547 u16 type; 546 u16 type;
548 int res;
549
550 res = brcmf_proto_hdrpull(drvr, false, &ifidx, txp);
551 547
552 ifp = drvr->iflist[ifidx]; 548 ifp = drvr->iflist[ifidx];
553 if (!ifp) 549 if (!ifp)
554 goto done; 550 goto done;
555 551
556 if (res == 0) { 552 eh = (struct ethhdr *)(txp->data);
557 eh = (struct ethhdr *)(txp->data); 553 type = ntohs(eh->h_proto);
558 type = ntohs(eh->h_proto);
559 554
560 if (type == ETH_P_PAE) { 555 if (type == ETH_P_PAE) {
561 atomic_dec(&ifp->pend_8021x_cnt); 556 atomic_dec(&ifp->pend_8021x_cnt);
562 if (waitqueue_active(&ifp->pend_8021x_wait)) 557 if (waitqueue_active(&ifp->pend_8021x_wait))
563 wake_up(&ifp->pend_8021x_wait); 558 wake_up(&ifp->pend_8021x_wait);
564 }
565 } 559 }
560
566 if (!success) 561 if (!success)
567 ifp->stats.tx_errors++; 562 ifp->stats.tx_errors++;
568done: 563done:
@@ -573,13 +568,17 @@ void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
573{ 568{
574 struct brcmf_bus *bus_if = dev_get_drvdata(dev); 569 struct brcmf_bus *bus_if = dev_get_drvdata(dev);
575 struct brcmf_pub *drvr = bus_if->drvr; 570 struct brcmf_pub *drvr = bus_if->drvr;
571 u8 ifidx;
576 572
577 /* await txstatus signal for firmware if active */ 573 /* await txstatus signal for firmware if active */
578 if (brcmf_fws_fc_active(drvr->fws)) { 574 if (brcmf_fws_fc_active(drvr->fws)) {
579 if (!success) 575 if (!success)
580 brcmf_fws_bustxfail(drvr->fws, txp); 576 brcmf_fws_bustxfail(drvr->fws, txp);
581 } else { 577 } else {
582 brcmf_txfinalize(drvr, txp, success); 578 if (brcmf_proto_hdrpull(drvr, false, &ifidx, txp))
579 brcmu_pkt_buf_free_skb(txp);
580 else
581 brcmf_txfinalize(drvr, txp, ifidx, success);
583 } 582 }
584} 583}
585 584
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
index c3e7d76dbf35..bfe7c9aab65c 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
@@ -1369,13 +1369,12 @@ done:
1369} 1369}
1370 1370
1371static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo, 1371static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo,
1372 struct sk_buff *skb, u32 genbit, 1372 struct sk_buff *skb, u8 ifidx,
1373 u16 seq) 1373 u32 genbit, u16 seq)
1374{ 1374{
1375 struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac; 1375 struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
1376 u32 hslot; 1376 u32 hslot;
1377 int ret; 1377 int ret;
1378 u8 ifidx;
1379 1378
1380 hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT); 1379 hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
1381 1380
@@ -1389,29 +1388,21 @@ static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo,
1389 1388
1390 entry->generation = genbit; 1389 entry->generation = genbit;
1391 1390
1392 ret = brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb); 1391 brcmf_skb_htod_tag_set_field(skb, GENERATION, genbit);
1393 if (ret == 0) { 1392 brcmf_skbcb(skb)->htod_seq = seq;
1394 brcmf_skb_htod_tag_set_field(skb, GENERATION, genbit); 1393 if (brcmf_skb_htod_seq_get_field(skb, FROMFW)) {
1395 brcmf_skbcb(skb)->htod_seq = seq; 1394 brcmf_skb_htod_seq_set_field(skb, FROMDRV, 1);
1396 if (brcmf_skb_htod_seq_get_field(skb, FROMFW)) { 1395 brcmf_skb_htod_seq_set_field(skb, FROMFW, 0);
1397 brcmf_skb_htod_seq_set_field(skb, FROMDRV, 1); 1396 } else {
1398 brcmf_skb_htod_seq_set_field(skb, FROMFW, 0); 1397 brcmf_skb_htod_seq_set_field(skb, FROMDRV, 0);
1399 } else {
1400 brcmf_skb_htod_seq_set_field(skb, FROMDRV, 0);
1401 }
1402 ret = brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_SUPPRESSED, fifo,
1403 skb);
1404 } 1398 }
1399 ret = brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_SUPPRESSED, fifo, skb);
1405 1400
1406 if (ret != 0) { 1401 if (ret != 0) {
1407 /* suppress q is full or hdrpull failed, drop this packet */ 1402 /* suppress q is full drop this packet */
1408 brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb, 1403 brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb, true);
1409 true);
1410 } else { 1404 } else {
1411 /* 1405 /* Mark suppressed to avoid a double free during wlfc cleanup */
1412 * Mark suppressed to avoid a double free during
1413 * wlfc cleanup
1414 */
1415 brcmf_fws_hanger_mark_suppressed(&fws->hanger, hslot); 1406 brcmf_fws_hanger_mark_suppressed(&fws->hanger, hslot);
1416 } 1407 }
1417 1408
@@ -1428,6 +1419,7 @@ brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,
1428 struct sk_buff *skb; 1419 struct sk_buff *skb;
1429 struct brcmf_skbuff_cb *skcb; 1420 struct brcmf_skbuff_cb *skcb;
1430 struct brcmf_fws_mac_descriptor *entry = NULL; 1421 struct brcmf_fws_mac_descriptor *entry = NULL;
1422 u8 ifidx;
1431 1423
1432 brcmf_dbg(DATA, "flags %d\n", flags); 1424 brcmf_dbg(DATA, "flags %d\n", flags);
1433 1425
@@ -1476,12 +1468,15 @@ brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,
1476 } 1468 }
1477 brcmf_fws_macdesc_return_req_credit(skb); 1469 brcmf_fws_macdesc_return_req_credit(skb);
1478 1470
1471 if (brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb)) {
1472 brcmu_pkt_buf_free_skb(skb);
1473 return -EINVAL;
1474 }
1479 if (!remove_from_hanger) 1475 if (!remove_from_hanger)
1480 ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, genbit, 1476 ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, ifidx,
1481 seq); 1477 genbit, seq);
1482
1483 if (remove_from_hanger || ret) 1478 if (remove_from_hanger || ret)
1484 brcmf_txfinalize(fws->drvr, skb, true); 1479 brcmf_txfinalize(fws->drvr, skb, ifidx, true);
1485 1480
1486 return 0; 1481 return 0;
1487} 1482}
@@ -1982,7 +1977,8 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker)
1982 ret = brcmf_proto_txdata(drvr, ifidx, 0, skb); 1977 ret = brcmf_proto_txdata(drvr, ifidx, 0, skb);
1983 brcmf_fws_lock(fws); 1978 brcmf_fws_lock(fws);
1984 if (ret < 0) 1979 if (ret < 0)
1985 brcmf_txfinalize(drvr, skb, false); 1980 brcmf_txfinalize(drvr, skb, ifidx,
1981 false);
1986 if (fws->bus_flow_blocked) 1982 if (fws->bus_flow_blocked)
1987 break; 1983 break;
1988 } 1984 }