diff options
Diffstat (limited to 'drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c')
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c | 80 |
1 files changed, 43 insertions, 37 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c index c3e7d76dbf35..699908de314a 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c | |||
@@ -476,6 +476,7 @@ struct brcmf_fws_info { | |||
476 | bool bus_flow_blocked; | 476 | bool bus_flow_blocked; |
477 | bool creditmap_received; | 477 | bool creditmap_received; |
478 | u8 mode; | 478 | u8 mode; |
479 | bool avoid_queueing; | ||
479 | }; | 480 | }; |
480 | 481 | ||
481 | /* | 482 | /* |
@@ -1369,13 +1370,12 @@ done: | |||
1369 | } | 1370 | } |
1370 | 1371 | ||
1371 | static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo, | 1372 | static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo, |
1372 | struct sk_buff *skb, u32 genbit, | 1373 | struct sk_buff *skb, u8 ifidx, |
1373 | u16 seq) | 1374 | u32 genbit, u16 seq) |
1374 | { | 1375 | { |
1375 | struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac; | 1376 | struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac; |
1376 | u32 hslot; | 1377 | u32 hslot; |
1377 | int ret; | 1378 | int ret; |
1378 | u8 ifidx; | ||
1379 | 1379 | ||
1380 | hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT); | 1380 | hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT); |
1381 | 1381 | ||
@@ -1389,29 +1389,21 @@ static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo, | |||
1389 | 1389 | ||
1390 | entry->generation = genbit; | 1390 | entry->generation = genbit; |
1391 | 1391 | ||
1392 | ret = brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb); | 1392 | brcmf_skb_htod_tag_set_field(skb, GENERATION, genbit); |
1393 | if (ret == 0) { | 1393 | brcmf_skbcb(skb)->htod_seq = seq; |
1394 | brcmf_skb_htod_tag_set_field(skb, GENERATION, genbit); | 1394 | if (brcmf_skb_htod_seq_get_field(skb, FROMFW)) { |
1395 | brcmf_skbcb(skb)->htod_seq = seq; | 1395 | brcmf_skb_htod_seq_set_field(skb, FROMDRV, 1); |
1396 | if (brcmf_skb_htod_seq_get_field(skb, FROMFW)) { | 1396 | brcmf_skb_htod_seq_set_field(skb, FROMFW, 0); |
1397 | brcmf_skb_htod_seq_set_field(skb, FROMDRV, 1); | 1397 | } else { |
1398 | brcmf_skb_htod_seq_set_field(skb, FROMFW, 0); | 1398 | 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 | } | 1399 | } |
1400 | ret = brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_SUPPRESSED, fifo, skb); | ||
1405 | 1401 | ||
1406 | if (ret != 0) { | 1402 | if (ret != 0) { |
1407 | /* suppress q is full or hdrpull failed, drop this packet */ | 1403 | /* suppress q is full drop this packet */ |
1408 | brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb, | 1404 | brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb, true); |
1409 | true); | ||
1410 | } else { | 1405 | } else { |
1411 | /* | 1406 | /* 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); | 1407 | brcmf_fws_hanger_mark_suppressed(&fws->hanger, hslot); |
1416 | } | 1408 | } |
1417 | 1409 | ||
@@ -1428,6 +1420,7 @@ brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot, | |||
1428 | struct sk_buff *skb; | 1420 | struct sk_buff *skb; |
1429 | struct brcmf_skbuff_cb *skcb; | 1421 | struct brcmf_skbuff_cb *skcb; |
1430 | struct brcmf_fws_mac_descriptor *entry = NULL; | 1422 | struct brcmf_fws_mac_descriptor *entry = NULL; |
1423 | u8 ifidx; | ||
1431 | 1424 | ||
1432 | brcmf_dbg(DATA, "flags %d\n", flags); | 1425 | brcmf_dbg(DATA, "flags %d\n", flags); |
1433 | 1426 | ||
@@ -1476,12 +1469,15 @@ brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot, | |||
1476 | } | 1469 | } |
1477 | brcmf_fws_macdesc_return_req_credit(skb); | 1470 | brcmf_fws_macdesc_return_req_credit(skb); |
1478 | 1471 | ||
1472 | if (brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb)) { | ||
1473 | brcmu_pkt_buf_free_skb(skb); | ||
1474 | return -EINVAL; | ||
1475 | } | ||
1479 | if (!remove_from_hanger) | 1476 | if (!remove_from_hanger) |
1480 | ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, genbit, | 1477 | ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, ifidx, |
1481 | seq); | 1478 | genbit, seq); |
1482 | |||
1483 | if (remove_from_hanger || ret) | 1479 | if (remove_from_hanger || ret) |
1484 | brcmf_txfinalize(fws->drvr, skb, true); | 1480 | brcmf_txfinalize(fws->drvr, skb, ifidx, true); |
1485 | 1481 | ||
1486 | return 0; | 1482 | return 0; |
1487 | } | 1483 | } |
@@ -1868,7 +1864,7 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) | |||
1868 | struct ethhdr *eh = (struct ethhdr *)(skb->data); | 1864 | struct ethhdr *eh = (struct ethhdr *)(skb->data); |
1869 | int fifo = BRCMF_FWS_FIFO_BCMC; | 1865 | int fifo = BRCMF_FWS_FIFO_BCMC; |
1870 | bool multicast = is_multicast_ether_addr(eh->h_dest); | 1866 | bool multicast = is_multicast_ether_addr(eh->h_dest); |
1871 | bool pae = eh->h_proto == htons(ETH_P_PAE); | 1867 | int rc = 0; |
1872 | 1868 | ||
1873 | brcmf_dbg(DATA, "tx proto=0x%X\n", ntohs(eh->h_proto)); | 1869 | brcmf_dbg(DATA, "tx proto=0x%X\n", ntohs(eh->h_proto)); |
1874 | /* determine the priority */ | 1870 | /* determine the priority */ |
@@ -1876,8 +1872,13 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) | |||
1876 | skb->priority = cfg80211_classify8021d(skb, NULL); | 1872 | skb->priority = cfg80211_classify8021d(skb, NULL); |
1877 | 1873 | ||
1878 | drvr->tx_multicast += !!multicast; | 1874 | drvr->tx_multicast += !!multicast; |
1879 | if (pae) | 1875 | |
1880 | atomic_inc(&ifp->pend_8021x_cnt); | 1876 | if (fws->avoid_queueing) { |
1877 | rc = brcmf_proto_txdata(drvr, ifp->ifidx, 0, skb); | ||
1878 | if (rc < 0) | ||
1879 | brcmf_txfinalize(drvr, skb, ifp->ifidx, false); | ||
1880 | return rc; | ||
1881 | } | ||
1881 | 1882 | ||
1882 | /* set control buffer information */ | 1883 | /* set control buffer information */ |
1883 | skcb->if_flags = 0; | 1884 | skcb->if_flags = 0; |
@@ -1899,15 +1900,12 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) | |||
1899 | brcmf_fws_schedule_deq(fws); | 1900 | brcmf_fws_schedule_deq(fws); |
1900 | } else { | 1901 | } else { |
1901 | brcmf_err("drop skb: no hanger slot\n"); | 1902 | brcmf_err("drop skb: no hanger slot\n"); |
1902 | if (pae) { | 1903 | brcmf_txfinalize(drvr, skb, ifp->ifidx, false); |
1903 | atomic_dec(&ifp->pend_8021x_cnt); | 1904 | rc = -ENOMEM; |
1904 | if (waitqueue_active(&ifp->pend_8021x_wait)) | ||
1905 | wake_up(&ifp->pend_8021x_wait); | ||
1906 | } | ||
1907 | brcmu_pkt_buf_free_skb(skb); | ||
1908 | } | 1905 | } |
1909 | brcmf_fws_unlock(fws); | 1906 | brcmf_fws_unlock(fws); |
1910 | return 0; | 1907 | |
1908 | return rc; | ||
1911 | } | 1909 | } |
1912 | 1910 | ||
1913 | void brcmf_fws_reset_interface(struct brcmf_if *ifp) | 1911 | void brcmf_fws_reset_interface(struct brcmf_if *ifp) |
@@ -1982,7 +1980,8 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker) | |||
1982 | ret = brcmf_proto_txdata(drvr, ifidx, 0, skb); | 1980 | ret = brcmf_proto_txdata(drvr, ifidx, 0, skb); |
1983 | brcmf_fws_lock(fws); | 1981 | brcmf_fws_lock(fws); |
1984 | if (ret < 0) | 1982 | if (ret < 0) |
1985 | brcmf_txfinalize(drvr, skb, false); | 1983 | brcmf_txfinalize(drvr, skb, ifidx, |
1984 | false); | ||
1986 | if (fws->bus_flow_blocked) | 1985 | if (fws->bus_flow_blocked) |
1987 | break; | 1986 | break; |
1988 | } | 1987 | } |
@@ -2039,6 +2038,13 @@ int brcmf_fws_init(struct brcmf_pub *drvr) | |||
2039 | fws->drvr = drvr; | 2038 | fws->drvr = drvr; |
2040 | fws->fcmode = fcmode; | 2039 | fws->fcmode = fcmode; |
2041 | 2040 | ||
2041 | if ((drvr->bus_if->always_use_fws_queue == false) && | ||
2042 | (fcmode == BRCMF_FWS_FCMODE_NONE)) { | ||
2043 | fws->avoid_queueing = true; | ||
2044 | brcmf_dbg(INFO, "FWS queueing will be avoided\n"); | ||
2045 | return 0; | ||
2046 | } | ||
2047 | |||
2042 | fws->fws_wq = create_singlethread_workqueue("brcmf_fws_wq"); | 2048 | fws->fws_wq = create_singlethread_workqueue("brcmf_fws_wq"); |
2043 | if (fws->fws_wq == NULL) { | 2049 | if (fws->fws_wq == NULL) { |
2044 | brcmf_err("workqueue creation failed\n"); | 2050 | brcmf_err("workqueue creation failed\n"); |