123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297 |
- From: Franky Lin <franky.lin@broadcom.com>
- Date: Mon, 11 Apr 2016 11:35:25 +0200
- Subject: [PATCH] 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>
- ---
- --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
- +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
- @@ -216,7 +216,9 @@ bool brcmf_c_prec_enq(struct device *dev
- int prec);
-
- /* Receive frame for delivery to OS. Callee disposes of rxp. */
- -void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp);
- +void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp, bool handle_evnt);
- +/* Receive async event packet from firmware. Callee disposes of rxp. */
- +void brcmf_rx_event(struct device *dev, struct sk_buff *rxp);
-
- /* Indication from bus module regarding presence/insertion of dongle. */
- int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings);
- --- 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 *de
- 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
- /* 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
- 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
- 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
- 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,
- 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)
- --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
- +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
- @@ -225,7 +225,8 @@ int brcmf_get_next_free_bsscfgidx(struct
- void brcmf_txflowblock_if(struct brcmf_if *ifp,
- enum brcmf_netif_stop_reason reason, bool state);
- void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success);
- -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);
- void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on);
- int __init brcmf_core_init(void);
- void __exit brcmf_core_exit(void);
- --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
- +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
- @@ -20,6 +20,7 @@
-
- #include <linux/types.h>
- #include <linux/netdevice.h>
- +#include <linux/etherdevice.h>
-
- #include <brcmu_utils.h>
- #include <brcmu_wifi.h>
- @@ -1075,28 +1076,13 @@ static void brcmf_msgbuf_rxbuf_event_pos
- }
-
-
- -static void
- -brcmf_msgbuf_rx_skb(struct brcmf_msgbuf *msgbuf, struct sk_buff *skb,
- - u8 ifidx)
- -{
- - struct brcmf_if *ifp;
- -
- - ifp = brcmf_get_ifp(msgbuf->drvr, ifidx);
- - if (!ifp || !ifp->ndev) {
- - brcmf_err("Received pkt for invalid ifidx %d\n", ifidx);
- - brcmu_pkt_buf_free_skb(skb);
- - return;
- - }
- - brcmf_netif_rx(ifp, skb);
- -}
- -
- -
- static void brcmf_msgbuf_process_event(struct brcmf_msgbuf *msgbuf, void *buf)
- {
- struct msgbuf_rx_event *event;
- u32 idx;
- u16 buflen;
- struct sk_buff *skb;
- + struct brcmf_if *ifp;
-
- event = (struct msgbuf_rx_event *)buf;
- idx = le32_to_cpu(event->msg.request_id);
- @@ -1116,7 +1102,19 @@ static void brcmf_msgbuf_process_event(s
-
- skb_trim(skb, buflen);
-
- - brcmf_msgbuf_rx_skb(msgbuf, skb, event->msg.ifidx);
- + ifp = brcmf_get_ifp(msgbuf->drvr, event->msg.ifidx);
- + if (!ifp || !ifp->ndev) {
- + brcmf_err("Received pkt for invalid ifidx %d\n",
- + event->msg.ifidx);
- + goto exit;
- + }
- +
- + skb->protocol = eth_type_trans(skb, ifp->ndev);
- +
- + brcmf_fweh_process_skb(ifp->drvr, skb);
- +
- +exit:
- + brcmu_pkt_buf_free_skb(skb);
- }
-
-
- @@ -1128,6 +1126,7 @@ brcmf_msgbuf_process_rx_complete(struct
- u16 data_offset;
- u16 buflen;
- u32 idx;
- + struct brcmf_if *ifp;
-
- brcmf_msgbuf_update_rxbufpost_count(msgbuf, 1);
-
- @@ -1148,7 +1147,14 @@ brcmf_msgbuf_process_rx_complete(struct
-
- skb_trim(skb, buflen);
-
- - brcmf_msgbuf_rx_skb(msgbuf, skb, rx_complete->msg.ifidx);
- + ifp = brcmf_get_ifp(msgbuf->drvr, rx_complete->msg.ifidx);
- + if (!ifp || !ifp->ndev) {
- + brcmf_err("Received pkt for invalid ifidx %d\n",
- + rx_complete->msg.ifidx);
- + brcmu_pkt_buf_free_skb(skb);
- + return;
- + }
- + brcmf_netif_rx(ifp, skb, false);
- }
-
-
- --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
- +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
- @@ -1294,6 +1294,17 @@ static inline u8 brcmf_sdio_getdatoffset
- return (u8)((hdrvalue & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT);
- }
-
- +static inline bool brcmf_sdio_fromevntchan(u8 *swheader)
- +{
- + u32 hdrvalue;
- + u8 ret;
- +
- + hdrvalue = *(u32 *)swheader;
- + ret = (u8)((hdrvalue & SDPCM_CHANNEL_MASK) >> SDPCM_CHANNEL_SHIFT);
- +
- + return (ret == SDPCM_EVENT_CHANNEL);
- +}
- +
- static int brcmf_sdio_hdparse(struct brcmf_sdio *bus, u8 *header,
- struct brcmf_sdio_hdrinfo *rd,
- enum brcmf_sdio_frmtype type)
- @@ -1641,7 +1652,11 @@ static u8 brcmf_sdio_rxglom(struct brcmf
- pfirst->len, pfirst->next,
- pfirst->prev);
- skb_unlink(pfirst, &bus->glom);
- - brcmf_rx_frame(bus->sdiodev->dev, pfirst);
- + if (brcmf_sdio_fromevntchan(pfirst->data))
- + brcmf_rx_event(bus->sdiodev->dev, pfirst);
- + else
- + brcmf_rx_frame(bus->sdiodev->dev, pfirst,
- + false);
- bus->sdcnt.rxglompkts++;
- }
-
- @@ -1967,18 +1982,19 @@ static uint brcmf_sdio_readframes(struct
- __skb_trim(pkt, rd->len);
- skb_pull(pkt, rd->dat_offset);
-
- + if (pkt->len == 0)
- + brcmu_pkt_buf_free_skb(pkt);
- + else if (rd->channel == SDPCM_EVENT_CHANNEL)
- + brcmf_rx_event(bus->sdiodev->dev, pkt);
- + else
- + brcmf_rx_frame(bus->sdiodev->dev, pkt,
- + false);
- +
- /* prepare the descriptor for the next read */
- rd->len = rd->len_nxtfrm << 4;
- rd->len_nxtfrm = 0;
- /* treat all packet as event if we don't know */
- rd->channel = SDPCM_EVENT_CHANNEL;
- -
- - if (pkt->len == 0) {
- - brcmu_pkt_buf_free_skb(pkt);
- - continue;
- - }
- -
- - brcmf_rx_frame(bus->sdiodev->dev, pkt);
- }
-
- rxcount = maxframes - rxleft;
- --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
- +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
- @@ -514,7 +514,7 @@ static void brcmf_usb_rx_complete(struct
-
- if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) {
- skb_put(skb, urb->actual_length);
- - brcmf_rx_frame(devinfo->dev, skb);
- + brcmf_rx_frame(devinfo->dev, skb, true);
- brcmf_usb_rx_refill(devinfo, req);
- } else {
- brcmu_pkt_buf_free_skb(skb);
|