349-0005-brcmfmac-screening-firmware-event-packet.patch 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. From: Franky Lin <franky.lin@broadcom.com>
  2. Date: Mon, 11 Apr 2016 11:35:25 +0200
  3. Subject: [PATCH] brcmfmac: screening firmware event packet
  4. Firmware uses asynchronized events as a communication method to the
  5. host. The event packets are marked as ETH_P_LINK_CTL protocol type. For
  6. SDIO and PCIe bus, this kind of packets are delivered through virtual
  7. event channel not data channel. This patch adds a screening logic to
  8. make sure the event handler only processes the events coming from the
  9. correct channel.
  10. Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
  11. Signed-off-by: Franky Lin <franky.lin@broadcom.com>
  12. Signed-off-by: Arend van Spriel <arend@broadcom.com>
  13. Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
  14. ---
  15. --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
  16. +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
  17. @@ -216,7 +216,9 @@ bool brcmf_c_prec_enq(struct device *dev
  18. int prec);
  19. /* Receive frame for delivery to OS. Callee disposes of rxp. */
  20. -void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp);
  21. +void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp, bool handle_evnt);
  22. +/* Receive async event packet from firmware. Callee disposes of rxp. */
  23. +void brcmf_rx_event(struct device *dev, struct sk_buff *rxp);
  24. /* Indication from bus module regarding presence/insertion of dongle. */
  25. int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings);
  26. --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
  27. +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
  28. @@ -311,16 +311,17 @@ void brcmf_txflowblock(struct device *de
  29. brcmf_fws_bus_blocked(drvr, state);
  30. }
  31. -void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb)
  32. +void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb,
  33. + bool handle_event)
  34. {
  35. - skb->dev = ifp->ndev;
  36. - skb->protocol = eth_type_trans(skb, skb->dev);
  37. + skb->protocol = eth_type_trans(skb, ifp->ndev);
  38. if (skb->pkt_type == PACKET_MULTICAST)
  39. ifp->stats.multicast++;
  40. /* Process special event packets */
  41. - brcmf_fweh_process_skb(ifp->drvr, skb);
  42. + if (handle_event)
  43. + brcmf_fweh_process_skb(ifp->drvr, skb);
  44. if (!(ifp->ndev->flags & IFF_UP)) {
  45. brcmu_pkt_buf_free_skb(skb);
  46. @@ -381,7 +382,7 @@ static void brcmf_rxreorder_process_info
  47. /* validate flags and flow id */
  48. if (flags == 0xFF) {
  49. brcmf_err("invalid flags...so ignore this packet\n");
  50. - brcmf_netif_rx(ifp, pkt);
  51. + brcmf_netif_rx(ifp, pkt, false);
  52. return;
  53. }
  54. @@ -393,7 +394,7 @@ static void brcmf_rxreorder_process_info
  55. if (rfi == NULL) {
  56. brcmf_dbg(INFO, "received flags to cleanup, but no flow (%d) yet\n",
  57. flow_id);
  58. - brcmf_netif_rx(ifp, pkt);
  59. + brcmf_netif_rx(ifp, pkt, false);
  60. return;
  61. }
  62. @@ -418,7 +419,7 @@ static void brcmf_rxreorder_process_info
  63. rfi = kzalloc(buf_size, GFP_ATOMIC);
  64. if (rfi == NULL) {
  65. brcmf_err("failed to alloc buffer\n");
  66. - brcmf_netif_rx(ifp, pkt);
  67. + brcmf_netif_rx(ifp, pkt, false);
  68. return;
  69. }
  70. @@ -532,11 +533,11 @@ static void brcmf_rxreorder_process_info
  71. netif_rx:
  72. skb_queue_walk_safe(&reorder_list, pkt, pnext) {
  73. __skb_unlink(pkt, &reorder_list);
  74. - brcmf_netif_rx(ifp, pkt);
  75. + brcmf_netif_rx(ifp, pkt, false);
  76. }
  77. }
  78. -void brcmf_rx_frame(struct device *dev, struct sk_buff *skb)
  79. +void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_evnt)
  80. {
  81. struct brcmf_if *ifp;
  82. struct brcmf_bus *bus_if = dev_get_drvdata(dev);
  83. @@ -560,7 +561,32 @@ void brcmf_rx_frame(struct device *dev,
  84. if (rd->reorder)
  85. brcmf_rxreorder_process_info(ifp, rd->reorder, skb);
  86. else
  87. - brcmf_netif_rx(ifp, skb);
  88. + brcmf_netif_rx(ifp, skb, handle_evnt);
  89. +}
  90. +
  91. +void brcmf_rx_event(struct device *dev, struct sk_buff *skb)
  92. +{
  93. + struct brcmf_if *ifp;
  94. + struct brcmf_bus *bus_if = dev_get_drvdata(dev);
  95. + struct brcmf_pub *drvr = bus_if->drvr;
  96. + int ret;
  97. +
  98. + brcmf_dbg(EVENT, "Enter: %s: rxp=%p\n", dev_name(dev), skb);
  99. +
  100. + /* process and remove protocol-specific header */
  101. + ret = brcmf_proto_hdrpull(drvr, true, skb, &ifp);
  102. +
  103. + if (ret || !ifp || !ifp->ndev) {
  104. + if (ret != -ENODATA && ifp)
  105. + ifp->stats.rx_errors++;
  106. + brcmu_pkt_buf_free_skb(skb);
  107. + return;
  108. + }
  109. +
  110. + skb->protocol = eth_type_trans(skb, ifp->ndev);
  111. +
  112. + brcmf_fweh_process_skb(ifp->drvr, skb);
  113. + brcmu_pkt_buf_free_skb(skb);
  114. }
  115. void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success)
  116. --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
  117. +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
  118. @@ -225,7 +225,8 @@ int brcmf_get_next_free_bsscfgidx(struct
  119. void brcmf_txflowblock_if(struct brcmf_if *ifp,
  120. enum brcmf_netif_stop_reason reason, bool state);
  121. void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success);
  122. -void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb);
  123. +void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb,
  124. + bool handle_event);
  125. void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on);
  126. int __init brcmf_core_init(void);
  127. void __exit brcmf_core_exit(void);
  128. --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
  129. +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
  130. @@ -20,6 +20,7 @@
  131. #include <linux/types.h>
  132. #include <linux/netdevice.h>
  133. +#include <linux/etherdevice.h>
  134. #include <brcmu_utils.h>
  135. #include <brcmu_wifi.h>
  136. @@ -1075,28 +1076,13 @@ static void brcmf_msgbuf_rxbuf_event_pos
  137. }
  138. -static void
  139. -brcmf_msgbuf_rx_skb(struct brcmf_msgbuf *msgbuf, struct sk_buff *skb,
  140. - u8 ifidx)
  141. -{
  142. - struct brcmf_if *ifp;
  143. -
  144. - ifp = brcmf_get_ifp(msgbuf->drvr, ifidx);
  145. - if (!ifp || !ifp->ndev) {
  146. - brcmf_err("Received pkt for invalid ifidx %d\n", ifidx);
  147. - brcmu_pkt_buf_free_skb(skb);
  148. - return;
  149. - }
  150. - brcmf_netif_rx(ifp, skb);
  151. -}
  152. -
  153. -
  154. static void brcmf_msgbuf_process_event(struct brcmf_msgbuf *msgbuf, void *buf)
  155. {
  156. struct msgbuf_rx_event *event;
  157. u32 idx;
  158. u16 buflen;
  159. struct sk_buff *skb;
  160. + struct brcmf_if *ifp;
  161. event = (struct msgbuf_rx_event *)buf;
  162. idx = le32_to_cpu(event->msg.request_id);
  163. @@ -1116,7 +1102,19 @@ static void brcmf_msgbuf_process_event(s
  164. skb_trim(skb, buflen);
  165. - brcmf_msgbuf_rx_skb(msgbuf, skb, event->msg.ifidx);
  166. + ifp = brcmf_get_ifp(msgbuf->drvr, event->msg.ifidx);
  167. + if (!ifp || !ifp->ndev) {
  168. + brcmf_err("Received pkt for invalid ifidx %d\n",
  169. + event->msg.ifidx);
  170. + goto exit;
  171. + }
  172. +
  173. + skb->protocol = eth_type_trans(skb, ifp->ndev);
  174. +
  175. + brcmf_fweh_process_skb(ifp->drvr, skb);
  176. +
  177. +exit:
  178. + brcmu_pkt_buf_free_skb(skb);
  179. }
  180. @@ -1128,6 +1126,7 @@ brcmf_msgbuf_process_rx_complete(struct
  181. u16 data_offset;
  182. u16 buflen;
  183. u32 idx;
  184. + struct brcmf_if *ifp;
  185. brcmf_msgbuf_update_rxbufpost_count(msgbuf, 1);
  186. @@ -1148,7 +1147,14 @@ brcmf_msgbuf_process_rx_complete(struct
  187. skb_trim(skb, buflen);
  188. - brcmf_msgbuf_rx_skb(msgbuf, skb, rx_complete->msg.ifidx);
  189. + ifp = brcmf_get_ifp(msgbuf->drvr, rx_complete->msg.ifidx);
  190. + if (!ifp || !ifp->ndev) {
  191. + brcmf_err("Received pkt for invalid ifidx %d\n",
  192. + rx_complete->msg.ifidx);
  193. + brcmu_pkt_buf_free_skb(skb);
  194. + return;
  195. + }
  196. + brcmf_netif_rx(ifp, skb, false);
  197. }
  198. --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
  199. +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
  200. @@ -1294,6 +1294,17 @@ static inline u8 brcmf_sdio_getdatoffset
  201. return (u8)((hdrvalue & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT);
  202. }
  203. +static inline bool brcmf_sdio_fromevntchan(u8 *swheader)
  204. +{
  205. + u32 hdrvalue;
  206. + u8 ret;
  207. +
  208. + hdrvalue = *(u32 *)swheader;
  209. + ret = (u8)((hdrvalue & SDPCM_CHANNEL_MASK) >> SDPCM_CHANNEL_SHIFT);
  210. +
  211. + return (ret == SDPCM_EVENT_CHANNEL);
  212. +}
  213. +
  214. static int brcmf_sdio_hdparse(struct brcmf_sdio *bus, u8 *header,
  215. struct brcmf_sdio_hdrinfo *rd,
  216. enum brcmf_sdio_frmtype type)
  217. @@ -1641,7 +1652,11 @@ static u8 brcmf_sdio_rxglom(struct brcmf
  218. pfirst->len, pfirst->next,
  219. pfirst->prev);
  220. skb_unlink(pfirst, &bus->glom);
  221. - brcmf_rx_frame(bus->sdiodev->dev, pfirst);
  222. + if (brcmf_sdio_fromevntchan(pfirst->data))
  223. + brcmf_rx_event(bus->sdiodev->dev, pfirst);
  224. + else
  225. + brcmf_rx_frame(bus->sdiodev->dev, pfirst,
  226. + false);
  227. bus->sdcnt.rxglompkts++;
  228. }
  229. @@ -1967,18 +1982,19 @@ static uint brcmf_sdio_readframes(struct
  230. __skb_trim(pkt, rd->len);
  231. skb_pull(pkt, rd->dat_offset);
  232. + if (pkt->len == 0)
  233. + brcmu_pkt_buf_free_skb(pkt);
  234. + else if (rd->channel == SDPCM_EVENT_CHANNEL)
  235. + brcmf_rx_event(bus->sdiodev->dev, pkt);
  236. + else
  237. + brcmf_rx_frame(bus->sdiodev->dev, pkt,
  238. + false);
  239. +
  240. /* prepare the descriptor for the next read */
  241. rd->len = rd->len_nxtfrm << 4;
  242. rd->len_nxtfrm = 0;
  243. /* treat all packet as event if we don't know */
  244. rd->channel = SDPCM_EVENT_CHANNEL;
  245. -
  246. - if (pkt->len == 0) {
  247. - brcmu_pkt_buf_free_skb(pkt);
  248. - continue;
  249. - }
  250. -
  251. - brcmf_rx_frame(bus->sdiodev->dev, pkt);
  252. }
  253. rxcount = maxframes - rxleft;
  254. --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
  255. +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
  256. @@ -514,7 +514,7 @@ static void brcmf_usb_rx_complete(struct
  257. if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) {
  258. skb_put(skb, urb->actual_length);
  259. - brcmf_rx_frame(devinfo->dev, skb);
  260. + brcmf_rx_frame(devinfo->dev, skb, true);
  261. brcmf_usb_rx_refill(devinfo, req);
  262. } else {
  263. brcmu_pkt_buf_free_skb(skb);