diff options
author | Franky Lin <franky.lin@broadcom.com> | 2016-04-11 11:35:25 +0200 |
---|---|---|
committer | Kalle Valo <kvalo@codeaurora.org> | 2016-04-14 15:57:50 +0300 |
commit | c56caa9db8abbbfb9e31325e0897705aa897db37 (patch) | |
tree | 6857c1874dcda08e811232d1e12303f2642c9227 /drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c | |
parent | 2aec2c9d42aa9ac4b31583cf4e1c7774e040e57d (diff) | |
download | op-kernel-dev-c56caa9db8abbbfb9e31325e0897705aa897db37.zip op-kernel-dev-c56caa9db8abbbfb9e31325e0897705aa897db37.tar.gz |
brcmfmac: screening firmware event packet
Firmware uses asynchronized events as a communication method to the
host. The event packets are marked as ETH_P_LINK_CTL protocol type. For
SDIO and PCIe bus, this kind of packets are delivered through virtual
event channel not data channel. This patch adds a screening logic to
make sure the event handler only processes the events coming from the
correct channel.
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
Signed-off-by: Franky Lin <franky.lin@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Diffstat (limited to 'drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c')
-rw-r--r-- | drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c | 46 |
1 files changed, 36 insertions, 10 deletions
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index ff825cd..8a91a517 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -311,16 +311,17 @@ void brcmf_txflowblock(struct device *dev, bool state) brcmf_fws_bus_blocked(drvr, state); } -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 handle_event) { - skb->dev = ifp->ndev; - skb->protocol = eth_type_trans(skb, skb->dev); + skb->protocol = eth_type_trans(skb, ifp->ndev); if (skb->pkt_type == PACKET_MULTICAST) ifp->stats.multicast++; /* Process special event packets */ - brcmf_fweh_process_skb(ifp->drvr, skb); + if (handle_event) + brcmf_fweh_process_skb(ifp->drvr, skb); if (!(ifp->ndev->flags & IFF_UP)) { brcmu_pkt_buf_free_skb(skb); @@ -381,7 +382,7 @@ static void brcmf_rxreorder_process_info(struct brcmf_if *ifp, u8 *reorder_data, /* validate flags and flow id */ if (flags == 0xFF) { brcmf_err("invalid flags...so ignore this packet\n"); - brcmf_netif_rx(ifp, pkt); + brcmf_netif_rx(ifp, pkt, false); return; } @@ -393,7 +394,7 @@ static void brcmf_rxreorder_process_info(struct brcmf_if *ifp, u8 *reorder_data, if (rfi == NULL) { brcmf_dbg(INFO, "received flags to cleanup, but no flow (%d) yet\n", flow_id); - brcmf_netif_rx(ifp, pkt); + brcmf_netif_rx(ifp, pkt, false); return; } @@ -418,7 +419,7 @@ static void brcmf_rxreorder_process_info(struct brcmf_if *ifp, u8 *reorder_data, rfi = kzalloc(buf_size, GFP_ATOMIC); if (rfi == NULL) { brcmf_err("failed to alloc buffer\n"); - brcmf_netif_rx(ifp, pkt); + brcmf_netif_rx(ifp, pkt, false); return; } @@ -532,11 +533,11 @@ static void brcmf_rxreorder_process_info(struct brcmf_if *ifp, u8 *reorder_data, netif_rx: skb_queue_walk_safe(&reorder_list, pkt, pnext) { __skb_unlink(pkt, &reorder_list); - brcmf_netif_rx(ifp, pkt); + brcmf_netif_rx(ifp, pkt, false); } } -void brcmf_rx_frame(struct device *dev, struct sk_buff *skb) +void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_evnt) { struct brcmf_if *ifp; struct brcmf_bus *bus_if = dev_get_drvdata(dev); @@ -560,7 +561,32 @@ void brcmf_rx_frame(struct device *dev, struct sk_buff *skb) if (rd->reorder) brcmf_rxreorder_process_info(ifp, rd->reorder, skb); else - brcmf_netif_rx(ifp, skb); + brcmf_netif_rx(ifp, skb, handle_evnt); +} + +void brcmf_rx_event(struct device *dev, struct sk_buff *skb) +{ + struct brcmf_if *ifp; + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + struct brcmf_pub *drvr = bus_if->drvr; + int ret; + + brcmf_dbg(EVENT, "Enter: %s: rxp=%p\n", dev_name(dev), skb); + + /* process and remove protocol-specific header */ + ret = brcmf_proto_hdrpull(drvr, true, skb, &ifp); + + if (ret || !ifp || !ifp->ndev) { + if (ret != -ENODATA && ifp) + ifp->stats.rx_errors++; + brcmu_pkt_buf_free_skb(skb); + return; + } + + skb->protocol = eth_type_trans(skb, ifp->ndev); + + brcmf_fweh_process_skb(ifp->drvr, skb); + brcmu_pkt_buf_free_skb(skb); } void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success) |