diff options
Diffstat (limited to 'drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c')
-rw-r--r-- | drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c | 39 |
1 files changed, 21 insertions, 18 deletions
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index f89010a81ffb..3dd28f5fef19 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -395,7 +395,7 @@ void brcmf_txflowblock_if(struct brcmf_if *ifp, spin_unlock_irqrestore(&ifp->netif_stop_lock, flags); } -void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb) +void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb, bool inirq) { /* Most of Broadcom's firmwares send 802.11f ADD frame every time a new * STA connects to the AP interface. This is an obsoleted standard most @@ -418,14 +418,15 @@ void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb) ifp->ndev->stats.rx_packets++; brcmf_dbg(DATA, "rx proto=0x%X\n", ntohs(skb->protocol)); - if (in_interrupt()) + if (inirq) { netif_rx(skb); - else + } else { /* If the receive is not processed inside an ISR, * the softirqd must be woken explicitly to service * the NET_RX_SOFTIRQ. This is handled by netif_rx_ni(). */ netif_rx_ni(skb); + } } void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb) @@ -474,7 +475,7 @@ void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb) skb->pkt_type = PACKET_OTHERHOST; skb->protocol = htons(ETH_P_802_2); - brcmf_netif_rx(ifp, skb); + brcmf_netif_rx(ifp, skb, false); } static int brcmf_rx_hdrpull(struct brcmf_pub *drvr, struct sk_buff *skb, @@ -486,7 +487,7 @@ static int brcmf_rx_hdrpull(struct brcmf_pub *drvr, struct sk_buff *skb, ret = brcmf_proto_hdrpull(drvr, true, skb, ifp); if (ret || !(*ifp) || !(*ifp)->ndev) { - if (ret != -ENODATA && *ifp) + if (ret != -ENODATA && *ifp && (*ifp)->ndev) (*ifp)->ndev->stats.rx_errors++; brcmu_pkt_buf_free_skb(skb); return -ENODATA; @@ -496,7 +497,8 @@ static int brcmf_rx_hdrpull(struct brcmf_pub *drvr, struct sk_buff *skb, return 0; } -void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_event) +void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_event, + bool inirq) { struct brcmf_if *ifp; struct brcmf_bus *bus_if = dev_get_drvdata(dev); @@ -508,14 +510,16 @@ void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_event) return; if (brcmf_proto_is_reorder_skb(skb)) { - brcmf_proto_rxreorder(ifp, skb); + brcmf_proto_rxreorder(ifp, skb, inirq); } else { /* Process special event packets */ - if (handle_event) - brcmf_fweh_process_skb(ifp->drvr, skb, - BCMILCP_SUBTYPE_VENDOR_LONG); + if (handle_event) { + gfp_t gfp = inirq ? GFP_ATOMIC : GFP_KERNEL; - brcmf_netif_rx(ifp, skb); + brcmf_fweh_process_skb(ifp->drvr, skb, + BCMILCP_SUBTYPE_VENDOR_LONG, gfp); + } + brcmf_netif_rx(ifp, skb, inirq); } } @@ -530,7 +534,7 @@ void brcmf_rx_event(struct device *dev, struct sk_buff *skb) if (brcmf_rx_hdrpull(drvr, skb, &ifp)) return; - brcmf_fweh_process_skb(ifp->drvr, skb, 0); + brcmf_fweh_process_skb(ifp->drvr, skb, 0, GFP_KERNEL); brcmu_pkt_buf_free_skb(skb); } @@ -1422,6 +1426,11 @@ void brcmf_detach(struct device *dev) #endif brcmf_bus_change_state(bus_if, BRCMF_BUS_DOWN); + /* make sure primary interface removed last */ + for (i = BRCMF_MAX_IFS - 1; i > -1; i--) { + if (drvr->iflist[i]) + brcmf_remove_interface(drvr->iflist[i], false); + } brcmf_bus_stop(drvr->bus_if); brcmf_fweh_detach(drvr); @@ -1432,12 +1441,6 @@ void brcmf_detach(struct device *dev) drvr->mon_if = NULL; } - /* make sure primary interface removed last */ - for (i = BRCMF_MAX_IFS - 1; i > -1; i--) { - if (drvr->iflist[i]) - brcmf_del_if(drvr, drvr->iflist[i]->bsscfgidx, false); - } - if (drvr->config) { brcmf_p2p_detach(&drvr->config->p2p); brcmf_cfg80211_detach(drvr->config); |