1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include <linux/kernel.h>
18#include <linux/etherdevice.h>
19#include <linux/module.h>
20#include <linux/inetdevice.h>
21#include <net/cfg80211.h>
22#include <net/rtnetlink.h>
23#include <net/addrconf.h>
24#include <net/ieee80211_radiotap.h>
25#include <net/ipv6.h>
26#include <brcmu_utils.h>
27#include <brcmu_wifi.h>
28
29#include "core.h"
30#include "bus.h"
31#include "debug.h"
32#include "fwil_types.h"
33#include "p2p.h"
34#include "pno.h"
35#include "cfg80211.h"
36#include "fwil.h"
37#include "feature.h"
38#include "proto.h"
39#include "pcie.h"
40#include "common.h"
41
42#define MAX_WAIT_FOR_8021X_TX msecs_to_jiffies(950)
43
44#define BRCMF_BSSIDX_INVALID -1
45
46#define RXS_PBPRES BIT(2)
47
48#define D11_PHY_HDR_LEN 6
49
50struct d11rxhdr_le {
51 __le16 RxFrameSize;
52 u16 PAD;
53 __le16 PhyRxStatus_0;
54 __le16 PhyRxStatus_1;
55 __le16 PhyRxStatus_2;
56 __le16 PhyRxStatus_3;
57 __le16 PhyRxStatus_4;
58 __le16 PhyRxStatus_5;
59 __le16 RxStatus1;
60 __le16 RxStatus2;
61 __le16 RxTSFTime;
62 __le16 RxChan;
63 u8 unknown[12];
64} __packed;
65
66struct wlc_d11rxhdr {
67 struct d11rxhdr_le rxhdr;
68 __le32 tsf_l;
69 s8 rssi;
70 s8 rxpwr0;
71 s8 rxpwr1;
72 s8 do_rssi_ma;
73 s8 rxpwr[4];
74} __packed;
75
76char *brcmf_ifname(struct brcmf_if *ifp)
77{
78 if (!ifp)
79 return "<if_null>";
80
81 if (ifp->ndev)
82 return ifp->ndev->name;
83
84 return "<if_none>";
85}
86
87struct brcmf_if *brcmf_get_ifp(struct brcmf_pub *drvr, int ifidx)
88{
89 struct brcmf_if *ifp;
90 s32 bsscfgidx;
91
92 if (ifidx < 0 || ifidx >= BRCMF_MAX_IFS) {
93 bphy_err(drvr, "ifidx %d out of range\n", ifidx);
94 return NULL;
95 }
96
97 ifp = NULL;
98 bsscfgidx = drvr->if2bss[ifidx];
99 if (bsscfgidx >= 0)
100 ifp = drvr->iflist[bsscfgidx];
101
102 return ifp;
103}
104
105void brcmf_configure_arp_nd_offload(struct brcmf_if *ifp, bool enable)
106{
107 s32 err;
108 u32 mode;
109
110 if (enable)
111 mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY;
112 else
113 mode = 0;
114
115
116
117 err = brcmf_fil_iovar_int_set(ifp, "arp_ol", mode);
118 if (err) {
119 brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
120 mode, err);
121 } else {
122 err = brcmf_fil_iovar_int_set(ifp, "arpoe", enable);
123 if (err) {
124 brcmf_dbg(TRACE, "failed to configure (%d) ARP offload err = %d\n",
125 enable, err);
126 } else {
127 brcmf_dbg(TRACE, "successfully configured (%d) ARP offload to 0x%x\n",
128 enable, mode);
129 }
130 }
131
132 err = brcmf_fil_iovar_int_set(ifp, "ndoe", enable);
133 if (err) {
134 brcmf_dbg(TRACE, "failed to configure (%d) ND offload err = %d\n",
135 enable, err);
136 } else {
137 brcmf_dbg(TRACE, "successfully configured (%d) ND offload to 0x%x\n",
138 enable, mode);
139 }
140}
141
142static void _brcmf_set_multicast_list(struct work_struct *work)
143{
144 struct brcmf_if *ifp = container_of(work, struct brcmf_if,
145 multicast_work);
146 struct brcmf_pub *drvr = ifp->drvr;
147 struct net_device *ndev;
148 struct netdev_hw_addr *ha;
149 u32 cmd_value, cnt;
150 __le32 cnt_le;
151 char *buf, *bufp;
152 u32 buflen;
153 s32 err;
154
155 brcmf_dbg(TRACE, "Enter, bsscfgidx=%d\n", ifp->bsscfgidx);
156
157 ndev = ifp->ndev;
158
159
160 cmd_value = (ndev->flags & IFF_ALLMULTI) ? true : false;
161
162
163 cnt = netdev_mc_count(ndev);
164 buflen = sizeof(cnt) + (cnt * ETH_ALEN);
165 buf = kmalloc(buflen, GFP_ATOMIC);
166 if (!buf)
167 return;
168 bufp = buf;
169
170 cnt_le = cpu_to_le32(cnt);
171 memcpy(bufp, &cnt_le, sizeof(cnt_le));
172 bufp += sizeof(cnt_le);
173
174 netdev_for_each_mc_addr(ha, ndev) {
175 if (!cnt)
176 break;
177 memcpy(bufp, ha->addr, ETH_ALEN);
178 bufp += ETH_ALEN;
179 cnt--;
180 }
181
182 err = brcmf_fil_iovar_data_set(ifp, "mcast_list", buf, buflen);
183 if (err < 0) {
184 bphy_err(drvr, "Setting mcast_list failed, %d\n", err);
185 cmd_value = cnt ? true : cmd_value;
186 }
187
188 kfree(buf);
189
190
191
192
193
194
195 err = brcmf_fil_iovar_int_set(ifp, "allmulti", cmd_value);
196 if (err < 0)
197 bphy_err(drvr, "Setting allmulti failed, %d\n", err);
198
199
200 cmd_value = (ndev->flags & IFF_PROMISC) ? true : false;
201 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PROMISC, cmd_value);
202 if (err < 0)
203 bphy_err(drvr, "Setting BRCMF_C_SET_PROMISC failed, %d\n",
204 err);
205 brcmf_configure_arp_nd_offload(ifp, !cmd_value);
206}
207
208#if IS_ENABLED(CONFIG_IPV6)
209static void _brcmf_update_ndtable(struct work_struct *work)
210{
211 struct brcmf_if *ifp = container_of(work, struct brcmf_if,
212 ndoffload_work);
213 struct brcmf_pub *drvr = ifp->drvr;
214 int i, ret;
215
216
217 ret = brcmf_fil_iovar_data_set(ifp, "nd_hostip_clear", NULL, 0);
218 if (ret) {
219 brcmf_dbg(TRACE, "fail to clear nd ip table err:%d\n", ret);
220 return;
221 }
222
223 for (i = 0; i < ifp->ipv6addr_idx; i++) {
224 ret = brcmf_fil_iovar_data_set(ifp, "nd_hostip",
225 &ifp->ipv6_addr_tbl[i],
226 sizeof(struct in6_addr));
227 if (ret)
228 bphy_err(drvr, "add nd ip err %d\n", ret);
229 }
230}
231#else
232static void _brcmf_update_ndtable(struct work_struct *work)
233{
234}
235#endif
236
237static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr)
238{
239 struct brcmf_if *ifp = netdev_priv(ndev);
240 struct sockaddr *sa = (struct sockaddr *)addr;
241 struct brcmf_pub *drvr = ifp->drvr;
242 int err;
243
244 brcmf_dbg(TRACE, "Enter, bsscfgidx=%d\n", ifp->bsscfgidx);
245
246 err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", sa->sa_data,
247 ETH_ALEN);
248 if (err < 0) {
249 bphy_err(drvr, "Setting cur_etheraddr failed, %d\n", err);
250 } else {
251 brcmf_dbg(TRACE, "updated to %pM\n", sa->sa_data);
252 memcpy(ifp->mac_addr, sa->sa_data, ETH_ALEN);
253 memcpy(ifp->ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
254 }
255 return err;
256}
257
258static void brcmf_netdev_set_multicast_list(struct net_device *ndev)
259{
260 struct brcmf_if *ifp = netdev_priv(ndev);
261
262 schedule_work(&ifp->multicast_work);
263}
264
265
266
267
268
269
270static bool brcmf_skb_is_iapp(struct sk_buff *skb)
271{
272 static const u8 iapp_l2_update_packet[6] __aligned(2) = {
273 0x00, 0x01, 0xaf, 0x81, 0x01, 0x00,
274 };
275 unsigned char *eth_data;
276#if !defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
277 const u16 *a, *b;
278#endif
279
280 if (skb->len - skb->mac_len != 6 ||
281 !is_multicast_ether_addr(eth_hdr(skb)->h_dest))
282 return false;
283
284 eth_data = skb_mac_header(skb) + ETH_HLEN;
285#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
286 return !(((*(const u32 *)eth_data) ^ (*(const u32 *)iapp_l2_update_packet)) |
287 ((*(const u16 *)(eth_data + 4)) ^ (*(const u16 *)(iapp_l2_update_packet + 4))));
288#else
289 a = (const u16 *)eth_data;
290 b = (const u16 *)iapp_l2_update_packet;
291
292 return !((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2]));
293#endif
294}
295
296static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
297 struct net_device *ndev)
298{
299 int ret;
300 struct brcmf_if *ifp = netdev_priv(ndev);
301 struct brcmf_pub *drvr = ifp->drvr;
302 struct ethhdr *eh;
303 int head_delta;
304
305 brcmf_dbg(DATA, "Enter, bsscfgidx=%d\n", ifp->bsscfgidx);
306
307
308 if (drvr->bus_if->state != BRCMF_BUS_UP) {
309 bphy_err(drvr, "xmit rejected state=%d\n", drvr->bus_if->state);
310 netif_stop_queue(ndev);
311 dev_kfree_skb(skb);
312 ret = -ENODEV;
313 goto done;
314 }
315
316
317
318
319
320
321
322
323
324
325
326
327 if (!drvr->settings->iapp && brcmf_skb_is_iapp(skb)) {
328 dev_kfree_skb(skb);
329 ret = -EINVAL;
330 goto done;
331 }
332
333
334 if (skb_headroom(skb) < drvr->hdrlen || skb_header_cloned(skb)) {
335 head_delta = max_t(int, drvr->hdrlen - skb_headroom(skb), 0);
336
337 brcmf_dbg(INFO, "%s: insufficient headroom (%d)\n",
338 brcmf_ifname(ifp), head_delta);
339 atomic_inc(&drvr->bus_if->stats.pktcowed);
340 ret = pskb_expand_head(skb, ALIGN(head_delta, NET_SKB_PAD), 0,
341 GFP_ATOMIC);
342 if (ret < 0) {
343 bphy_err(drvr, "%s: failed to expand headroom\n",
344 brcmf_ifname(ifp));
345 atomic_inc(&drvr->bus_if->stats.pktcow_failed);
346 goto done;
347 }
348 }
349
350
351 if (skb->len < sizeof(*eh)) {
352 ret = -EINVAL;
353 dev_kfree_skb(skb);
354 goto done;
355 }
356
357 eh = (struct ethhdr *)(skb->data);
358
359 if (eh->h_proto == htons(ETH_P_PAE))
360 atomic_inc(&ifp->pend_8021x_cnt);
361
362
363 if ((skb->priority == 0) || (skb->priority > 7))
364 skb->priority = cfg80211_classify8021d(skb, NULL);
365
366 ret = brcmf_proto_tx_queue_data(drvr, ifp->ifidx, skb);
367 if (ret < 0)
368 brcmf_txfinalize(ifp, skb, false);
369
370done:
371 if (ret) {
372 ndev->stats.tx_dropped++;
373 } else {
374 ndev->stats.tx_packets++;
375 ndev->stats.tx_bytes += skb->len;
376 }
377
378
379 return NETDEV_TX_OK;
380}
381
382void brcmf_txflowblock_if(struct brcmf_if *ifp,
383 enum brcmf_netif_stop_reason reason, bool state)
384{
385 unsigned long flags;
386
387 if (!ifp || !ifp->ndev)
388 return;
389
390 brcmf_dbg(TRACE, "enter: bsscfgidx=%d stop=0x%X reason=%d state=%d\n",
391 ifp->bsscfgidx, ifp->netif_stop, reason, state);
392
393 spin_lock_irqsave(&ifp->netif_stop_lock, flags);
394 if (state) {
395 if (!ifp->netif_stop)
396 netif_stop_queue(ifp->ndev);
397 ifp->netif_stop |= reason;
398 } else {
399 ifp->netif_stop &= ~reason;
400 if (!ifp->netif_stop)
401 netif_wake_queue(ifp->ndev);
402 }
403 spin_unlock_irqrestore(&ifp->netif_stop_lock, flags);
404}
405
406void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb)
407{
408
409
410
411
412 if (!ifp->drvr->settings->iapp && brcmf_skb_is_iapp(skb)) {
413 brcmu_pkt_buf_free_skb(skb);
414 return;
415 }
416
417 if (skb->pkt_type == PACKET_MULTICAST)
418 ifp->ndev->stats.multicast++;
419
420 if (!(ifp->ndev->flags & IFF_UP)) {
421 brcmu_pkt_buf_free_skb(skb);
422 return;
423 }
424
425 ifp->ndev->stats.rx_bytes += skb->len;
426 ifp->ndev->stats.rx_packets++;
427
428 brcmf_dbg(DATA, "rx proto=0x%X\n", ntohs(skb->protocol));
429 if (in_interrupt())
430 netif_rx(skb);
431 else
432
433
434
435
436 netif_rx_ni(skb);
437}
438
439void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb)
440{
441 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MONITOR_FMT_RADIOTAP)) {
442
443 } else if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MONITOR_FMT_HW_RX_HDR)) {
444 struct wlc_d11rxhdr *wlc_rxhdr = (struct wlc_d11rxhdr *)skb->data;
445 struct ieee80211_radiotap_header *radiotap;
446 unsigned int offset;
447 u16 RxStatus1;
448
449 RxStatus1 = le16_to_cpu(wlc_rxhdr->rxhdr.RxStatus1);
450
451 offset = sizeof(struct wlc_d11rxhdr);
452
453
454
455 if (RxStatus1 & RXS_PBPRES)
456 offset += 2;
457 offset += D11_PHY_HDR_LEN;
458
459 skb_pull(skb, offset);
460
461
462 radiotap = skb_push(skb, sizeof(*radiotap));
463 memset(radiotap, 0, sizeof(*radiotap));
464 radiotap->it_len = cpu_to_le16(sizeof(*radiotap));
465
466
467 skb->len -= 4;
468 } else {
469 struct ieee80211_radiotap_header *radiotap;
470
471
472 radiotap = skb_push(skb, sizeof(*radiotap));
473 memset(radiotap, 0, sizeof(*radiotap));
474 radiotap->it_len = cpu_to_le16(sizeof(*radiotap));
475
476
477 skb->len -= 4;
478 }
479
480 skb->dev = ifp->ndev;
481 skb_reset_mac_header(skb);
482 skb->pkt_type = PACKET_OTHERHOST;
483 skb->protocol = htons(ETH_P_802_2);
484
485 brcmf_netif_rx(ifp, skb);
486}
487
488static int brcmf_rx_hdrpull(struct brcmf_pub *drvr, struct sk_buff *skb,
489 struct brcmf_if **ifp)
490{
491 int ret;
492
493
494 ret = brcmf_proto_hdrpull(drvr, true, skb, ifp);
495
496 if (ret || !(*ifp) || !(*ifp)->ndev) {
497 if (ret != -ENODATA && *ifp)
498 (*ifp)->ndev->stats.rx_errors++;
499 brcmu_pkt_buf_free_skb(skb);
500 return -ENODATA;
501 }
502
503 skb->protocol = eth_type_trans(skb, (*ifp)->ndev);
504 return 0;
505}
506
507void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_event)
508{
509 struct brcmf_if *ifp;
510 struct brcmf_bus *bus_if = dev_get_drvdata(dev);
511 struct brcmf_pub *drvr = bus_if->drvr;
512
513 brcmf_dbg(DATA, "Enter: %s: rxp=%p\n", dev_name(dev), skb);
514
515 if (brcmf_rx_hdrpull(drvr, skb, &ifp))
516 return;
517
518 if (brcmf_proto_is_reorder_skb(skb)) {
519 brcmf_proto_rxreorder(ifp, skb);
520 } else {
521
522 if (handle_event)
523 brcmf_fweh_process_skb(ifp->drvr, skb,
524 BCMILCP_SUBTYPE_VENDOR_LONG);
525
526 brcmf_netif_rx(ifp, skb);
527 }
528}
529
530void brcmf_rx_event(struct device *dev, struct sk_buff *skb)
531{
532 struct brcmf_if *ifp;
533 struct brcmf_bus *bus_if = dev_get_drvdata(dev);
534 struct brcmf_pub *drvr = bus_if->drvr;
535
536 brcmf_dbg(EVENT, "Enter: %s: rxp=%p\n", dev_name(dev), skb);
537
538 if (brcmf_rx_hdrpull(drvr, skb, &ifp))
539 return;
540
541 brcmf_fweh_process_skb(ifp->drvr, skb, 0);
542 brcmu_pkt_buf_free_skb(skb);
543}
544
545void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success)
546{
547 struct ethhdr *eh;
548 u16 type;
549
550 eh = (struct ethhdr *)(txp->data);
551 type = ntohs(eh->h_proto);
552
553 if (type == ETH_P_PAE) {
554 atomic_dec(&ifp->pend_8021x_cnt);
555 if (waitqueue_active(&ifp->pend_8021x_wait))
556 wake_up(&ifp->pend_8021x_wait);
557 }
558
559 if (!success)
560 ifp->ndev->stats.tx_errors++;
561
562 brcmu_pkt_buf_free_skb(txp);
563}
564
565static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,
566 struct ethtool_drvinfo *info)
567{
568 struct brcmf_if *ifp = netdev_priv(ndev);
569 struct brcmf_pub *drvr = ifp->drvr;
570 char drev[BRCMU_DOTREV_LEN] = "n/a";
571
572 if (drvr->revinfo.result == 0)
573 brcmu_dotrev_str(drvr->revinfo.driverrev, drev);
574 strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
575 strlcpy(info->version, drev, sizeof(info->version));
576 strlcpy(info->fw_version, drvr->fwver, sizeof(info->fw_version));
577 strlcpy(info->bus_info, dev_name(drvr->bus_if->dev),
578 sizeof(info->bus_info));
579}
580
581static const struct ethtool_ops brcmf_ethtool_ops = {
582 .get_drvinfo = brcmf_ethtool_get_drvinfo,
583};
584
585static int brcmf_netdev_stop(struct net_device *ndev)
586{
587 struct brcmf_if *ifp = netdev_priv(ndev);
588
589 brcmf_dbg(TRACE, "Enter, bsscfgidx=%d\n", ifp->bsscfgidx);
590
591 brcmf_cfg80211_down(ndev);
592
593 brcmf_fil_iovar_data_set(ifp, "arp_hostip_clear", NULL, 0);
594
595 brcmf_net_setcarrier(ifp, false);
596
597 return 0;
598}
599
600static int brcmf_netdev_open(struct net_device *ndev)
601{
602 struct brcmf_if *ifp = netdev_priv(ndev);
603 struct brcmf_pub *drvr = ifp->drvr;
604 struct brcmf_bus *bus_if = drvr->bus_if;
605 u32 toe_ol;
606
607 brcmf_dbg(TRACE, "Enter, bsscfgidx=%d\n", ifp->bsscfgidx);
608
609
610 if (bus_if->state != BRCMF_BUS_UP) {
611 bphy_err(drvr, "failed bus is not ready\n");
612 return -EAGAIN;
613 }
614
615 atomic_set(&ifp->pend_8021x_cnt, 0);
616
617
618 if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0
619 && (toe_ol & TOE_TX_CSUM_OL) != 0)
620 ndev->features |= NETIF_F_IP_CSUM;
621 else
622 ndev->features &= ~NETIF_F_IP_CSUM;
623
624 if (brcmf_cfg80211_up(ndev)) {
625 bphy_err(drvr, "failed to bring up cfg80211\n");
626 return -EIO;
627 }
628
629
630 netif_carrier_off(ndev);
631 return 0;
632}
633
634static const struct net_device_ops brcmf_netdev_ops_pri = {
635 .ndo_open = brcmf_netdev_open,
636 .ndo_stop = brcmf_netdev_stop,
637 .ndo_start_xmit = brcmf_netdev_start_xmit,
638 .ndo_set_mac_address = brcmf_netdev_set_mac_address,
639 .ndo_set_rx_mode = brcmf_netdev_set_multicast_list
640};
641
642int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked)
643{
644 struct brcmf_pub *drvr = ifp->drvr;
645 struct net_device *ndev;
646 s32 err;
647
648 brcmf_dbg(TRACE, "Enter, bsscfgidx=%d mac=%pM\n", ifp->bsscfgidx,
649 ifp->mac_addr);
650 ndev = ifp->ndev;
651
652
653 ndev->netdev_ops = &brcmf_netdev_ops_pri;
654
655 ndev->needed_headroom += drvr->hdrlen;
656 ndev->ethtool_ops = &brcmf_ethtool_ops;
657
658
659 memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
660 dev_net_set(ndev, wiphy_net(cfg_to_wiphy(drvr->config)));
661
662 INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list);
663 INIT_WORK(&ifp->ndoffload_work, _brcmf_update_ndtable);
664
665 if (rtnl_locked)
666 err = register_netdevice(ndev);
667 else
668 err = register_netdev(ndev);
669 if (err != 0) {
670 bphy_err(drvr, "couldn't register the net device\n");
671 goto fail;
672 }
673
674 ndev->priv_destructor = brcmf_cfg80211_free_netdev;
675 brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name);
676 return 0;
677
678fail:
679 drvr->iflist[ifp->bsscfgidx] = NULL;
680 ndev->netdev_ops = NULL;
681 return -EBADE;
682}
683
684static void brcmf_net_detach(struct net_device *ndev, bool rtnl_locked)
685{
686 if (ndev->reg_state == NETREG_REGISTERED) {
687 if (rtnl_locked)
688 unregister_netdevice(ndev);
689 else
690 unregister_netdev(ndev);
691 } else {
692 brcmf_cfg80211_free_netdev(ndev);
693 free_netdev(ndev);
694 }
695}
696
697void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on)
698{
699 struct net_device *ndev;
700
701 brcmf_dbg(TRACE, "Enter, bsscfgidx=%d carrier=%d\n", ifp->bsscfgidx,
702 on);
703
704 ndev = ifp->ndev;
705 brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_DISCONNECTED, !on);
706 if (on) {
707 if (!netif_carrier_ok(ndev))
708 netif_carrier_on(ndev);
709
710 } else {
711 if (netif_carrier_ok(ndev))
712 netif_carrier_off(ndev);
713 }
714}
715
716static int brcmf_net_p2p_open(struct net_device *ndev)
717{
718 brcmf_dbg(TRACE, "Enter\n");
719
720 return brcmf_cfg80211_up(ndev);
721}
722
723static int brcmf_net_p2p_stop(struct net_device *ndev)
724{
725 brcmf_dbg(TRACE, "Enter\n");
726
727 return brcmf_cfg80211_down(ndev);
728}
729
730static netdev_tx_t brcmf_net_p2p_start_xmit(struct sk_buff *skb,
731 struct net_device *ndev)
732{
733 if (skb)
734 dev_kfree_skb_any(skb);
735
736 return NETDEV_TX_OK;
737}
738
739static const struct net_device_ops brcmf_netdev_ops_p2p = {
740 .ndo_open = brcmf_net_p2p_open,
741 .ndo_stop = brcmf_net_p2p_stop,
742 .ndo_start_xmit = brcmf_net_p2p_start_xmit
743};
744
745static int brcmf_net_p2p_attach(struct brcmf_if *ifp)
746{
747 struct brcmf_pub *drvr = ifp->drvr;
748 struct net_device *ndev;
749
750 brcmf_dbg(TRACE, "Enter, bsscfgidx=%d mac=%pM\n", ifp->bsscfgidx,
751 ifp->mac_addr);
752 ndev = ifp->ndev;
753
754 ndev->netdev_ops = &brcmf_netdev_ops_p2p;
755
756
757 memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
758
759 if (register_netdev(ndev) != 0) {
760 bphy_err(drvr, "couldn't register the p2p net device\n");
761 goto fail;
762 }
763
764 brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name);
765
766 return 0;
767
768fail:
769 ifp->drvr->iflist[ifp->bsscfgidx] = NULL;
770 ndev->netdev_ops = NULL;
771 return -EBADE;
772}
773
774struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx,
775 bool is_p2pdev, const char *name, u8 *mac_addr)
776{
777 struct brcmf_if *ifp;
778 struct net_device *ndev;
779
780 brcmf_dbg(TRACE, "Enter, bsscfgidx=%d, ifidx=%d\n", bsscfgidx, ifidx);
781
782 ifp = drvr->iflist[bsscfgidx];
783
784
785
786
787 if (ifp) {
788 if (ifidx) {
789 bphy_err(drvr, "ERROR: netdev:%s already exists\n",
790 ifp->ndev->name);
791 netif_stop_queue(ifp->ndev);
792 brcmf_net_detach(ifp->ndev, false);
793 drvr->iflist[bsscfgidx] = NULL;
794 } else {
795 brcmf_dbg(INFO, "netdev:%s ignore IF event\n",
796 ifp->ndev->name);
797 return ERR_PTR(-EINVAL);
798 }
799 }
800
801 if (!drvr->settings->p2p_enable && is_p2pdev) {
802
803 brcmf_dbg(INFO, "allocate non-netdev interface\n");
804 ifp = kzalloc(sizeof(*ifp), GFP_KERNEL);
805 if (!ifp)
806 return ERR_PTR(-ENOMEM);
807 } else {
808 brcmf_dbg(INFO, "allocate netdev interface\n");
809
810 ndev = alloc_netdev(sizeof(*ifp), is_p2pdev ? "p2p%d" : name,
811 NET_NAME_UNKNOWN, ether_setup);
812 if (!ndev)
813 return ERR_PTR(-ENOMEM);
814
815 ndev->needs_free_netdev = true;
816 ifp = netdev_priv(ndev);
817 ifp->ndev = ndev;
818
819 if (drvr->if2bss[ifidx] == BRCMF_BSSIDX_INVALID)
820 drvr->if2bss[ifidx] = bsscfgidx;
821 }
822
823 ifp->drvr = drvr;
824 drvr->iflist[bsscfgidx] = ifp;
825 ifp->ifidx = ifidx;
826 ifp->bsscfgidx = bsscfgidx;
827
828 init_waitqueue_head(&ifp->pend_8021x_wait);
829 spin_lock_init(&ifp->netif_stop_lock);
830
831 if (mac_addr != NULL)
832 memcpy(ifp->mac_addr, mac_addr, ETH_ALEN);
833
834 brcmf_dbg(TRACE, " ==== pid:%x, if:%s (%pM) created ===\n",
835 current->pid, name, ifp->mac_addr);
836
837 return ifp;
838}
839
840static void brcmf_del_if(struct brcmf_pub *drvr, s32 bsscfgidx,
841 bool rtnl_locked)
842{
843 struct brcmf_if *ifp;
844 int ifidx;
845
846 ifp = drvr->iflist[bsscfgidx];
847 if (!ifp) {
848 bphy_err(drvr, "Null interface, bsscfgidx=%d\n", bsscfgidx);
849 return;
850 }
851 brcmf_dbg(TRACE, "Enter, bsscfgidx=%d, ifidx=%d\n", bsscfgidx,
852 ifp->ifidx);
853 ifidx = ifp->ifidx;
854
855 if (ifp->ndev) {
856 if (bsscfgidx == 0) {
857 if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
858 rtnl_lock();
859 brcmf_netdev_stop(ifp->ndev);
860 rtnl_unlock();
861 }
862 } else {
863 netif_stop_queue(ifp->ndev);
864 }
865
866 if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
867 cancel_work_sync(&ifp->multicast_work);
868 cancel_work_sync(&ifp->ndoffload_work);
869 }
870 brcmf_net_detach(ifp->ndev, rtnl_locked);
871 } else {
872
873
874
875
876
877
878
879 brcmf_p2p_ifp_removed(ifp, rtnl_locked);
880 kfree(ifp);
881 }
882
883 drvr->iflist[bsscfgidx] = NULL;
884 if (drvr->if2bss[ifidx] == bsscfgidx)
885 drvr->if2bss[ifidx] = BRCMF_BSSIDX_INVALID;
886}
887
888void brcmf_remove_interface(struct brcmf_if *ifp, bool rtnl_locked)
889{
890 if (!ifp || WARN_ON(ifp->drvr->iflist[ifp->bsscfgidx] != ifp))
891 return;
892 brcmf_dbg(TRACE, "Enter, bsscfgidx=%d, ifidx=%d\n", ifp->bsscfgidx,
893 ifp->ifidx);
894 brcmf_proto_del_if(ifp->drvr, ifp);
895 brcmf_del_if(ifp->drvr, ifp->bsscfgidx, rtnl_locked);
896}
897
898static int brcmf_psm_watchdog_notify(struct brcmf_if *ifp,
899 const struct brcmf_event_msg *evtmsg,
900 void *data)
901{
902 struct brcmf_pub *drvr = ifp->drvr;
903 int err;
904
905 brcmf_dbg(TRACE, "enter: bsscfgidx=%d\n", ifp->bsscfgidx);
906
907 bphy_err(drvr, "PSM's watchdog has fired!\n");
908
909 err = brcmf_debug_create_memdump(ifp->drvr->bus_if, data,
910 evtmsg->datalen);
911 if (err)
912 bphy_err(drvr, "Failed to get memory dump, %d\n", err);
913
914 return err;
915}
916
917#ifdef CONFIG_INET
918#define ARPOL_MAX_ENTRIES 8
919static int brcmf_inetaddr_changed(struct notifier_block *nb,
920 unsigned long action, void *data)
921{
922 struct brcmf_pub *drvr = container_of(nb, struct brcmf_pub,
923 inetaddr_notifier);
924 struct in_ifaddr *ifa = data;
925 struct net_device *ndev = ifa->ifa_dev->dev;
926 struct brcmf_if *ifp;
927 int idx, i, ret;
928 u32 val;
929 __be32 addr_table[ARPOL_MAX_ENTRIES] = {0};
930
931
932 for (idx = 0; idx < BRCMF_MAX_IFS; idx++) {
933 ifp = drvr->iflist[idx];
934 if (ifp && ifp->ndev == ndev)
935 break;
936 if (idx == BRCMF_MAX_IFS - 1)
937 return NOTIFY_DONE;
938 }
939
940
941 ret = brcmf_fil_iovar_int_get(ifp, "arpoe", &val);
942 if (ret)
943 return NOTIFY_OK;
944
945
946 ret = brcmf_fil_iovar_int_get(ifp, "arp_version", &val);
947 if (ret)
948 val = 1;
949 if (val == 1)
950 ifp = drvr->iflist[0];
951
952
953 ret = brcmf_fil_iovar_data_get(ifp, "arp_hostip", addr_table,
954 sizeof(addr_table));
955 if (ret) {
956 bphy_err(drvr, "fail to get arp ip table err:%d\n", ret);
957 return NOTIFY_OK;
958 }
959
960 for (i = 0; i < ARPOL_MAX_ENTRIES; i++)
961 if (ifa->ifa_address == addr_table[i])
962 break;
963
964 switch (action) {
965 case NETDEV_UP:
966 if (i == ARPOL_MAX_ENTRIES) {
967 brcmf_dbg(TRACE, "add %pI4 to arp table\n",
968 &ifa->ifa_address);
969
970 ret = brcmf_fil_iovar_data_set(ifp, "arp_hostip",
971 &ifa->ifa_address, sizeof(ifa->ifa_address));
972 if (ret)
973 bphy_err(drvr, "add arp ip err %d\n", ret);
974 }
975 break;
976 case NETDEV_DOWN:
977 if (i < ARPOL_MAX_ENTRIES) {
978 addr_table[i] = 0;
979 brcmf_dbg(TRACE, "remove %pI4 from arp table\n",
980 &ifa->ifa_address);
981
982 ret = brcmf_fil_iovar_data_set(ifp, "arp_hostip_clear",
983 NULL, 0);
984 if (ret) {
985 bphy_err(drvr, "fail to clear arp ip table err:%d\n",
986 ret);
987 return NOTIFY_OK;
988 }
989 for (i = 0; i < ARPOL_MAX_ENTRIES; i++) {
990 if (addr_table[i] == 0)
991 continue;
992 ret = brcmf_fil_iovar_data_set(ifp, "arp_hostip",
993 &addr_table[i],
994 sizeof(addr_table[i]));
995 if (ret)
996 bphy_err(drvr, "add arp ip err %d\n",
997 ret);
998 }
999 }
1000 break;
1001 default:
1002 break;
1003 }
1004
1005 return NOTIFY_OK;
1006}
1007#endif
1008
1009#if IS_ENABLED(CONFIG_IPV6)
1010static int brcmf_inet6addr_changed(struct notifier_block *nb,
1011 unsigned long action, void *data)
1012{
1013 struct brcmf_pub *drvr = container_of(nb, struct brcmf_pub,
1014 inet6addr_notifier);
1015 struct inet6_ifaddr *ifa = data;
1016 struct brcmf_if *ifp;
1017 int i;
1018 struct in6_addr *table;
1019
1020
1021 ifp = drvr->iflist[0];
1022 if (!ifp)
1023 return NOTIFY_DONE;
1024 if (ifp->ndev != ifa->idev->dev)
1025 return NOTIFY_DONE;
1026
1027 table = ifp->ipv6_addr_tbl;
1028 for (i = 0; i < NDOL_MAX_ENTRIES; i++)
1029 if (ipv6_addr_equal(&ifa->addr, &table[i]))
1030 break;
1031
1032 switch (action) {
1033 case NETDEV_UP:
1034 if (i == NDOL_MAX_ENTRIES) {
1035 if (ifp->ipv6addr_idx < NDOL_MAX_ENTRIES) {
1036 table[ifp->ipv6addr_idx++] = ifa->addr;
1037 } else {
1038 for (i = 0; i < NDOL_MAX_ENTRIES - 1; i++)
1039 table[i] = table[i + 1];
1040 table[NDOL_MAX_ENTRIES - 1] = ifa->addr;
1041 }
1042 }
1043 break;
1044 case NETDEV_DOWN:
1045 if (i < NDOL_MAX_ENTRIES) {
1046 for (; i < ifp->ipv6addr_idx - 1; i++)
1047 table[i] = table[i + 1];
1048 memset(&table[i], 0, sizeof(table[i]));
1049 ifp->ipv6addr_idx--;
1050 }
1051 break;
1052 default:
1053 break;
1054 }
1055
1056 schedule_work(&ifp->ndoffload_work);
1057
1058 return NOTIFY_OK;
1059}
1060#endif
1061
1062static int brcmf_revinfo_read(struct seq_file *s, void *data)
1063{
1064 struct brcmf_bus *bus_if = dev_get_drvdata(s->private);
1065 struct brcmf_rev_info *ri = &bus_if->drvr->revinfo;
1066 char drev[BRCMU_DOTREV_LEN];
1067 char brev[BRCMU_BOARDREV_LEN];
1068
1069 seq_printf(s, "vendorid: 0x%04x\n", ri->vendorid);
1070 seq_printf(s, "deviceid: 0x%04x\n", ri->deviceid);
1071 seq_printf(s, "radiorev: %s\n", brcmu_dotrev_str(ri->radiorev, drev));
1072 seq_printf(s, "chip: %s\n", ri->chipname);
1073 seq_printf(s, "chippkg: %u\n", ri->chippkg);
1074 seq_printf(s, "corerev: %u\n", ri->corerev);
1075 seq_printf(s, "boardid: 0x%04x\n", ri->boardid);
1076 seq_printf(s, "boardvendor: 0x%04x\n", ri->boardvendor);
1077 seq_printf(s, "boardrev: %s\n", brcmu_boardrev_str(ri->boardrev, brev));
1078 seq_printf(s, "driverrev: %s\n", brcmu_dotrev_str(ri->driverrev, drev));
1079 seq_printf(s, "ucoderev: %u\n", ri->ucoderev);
1080 seq_printf(s, "bus: %u\n", ri->bus);
1081 seq_printf(s, "phytype: %u\n", ri->phytype);
1082 seq_printf(s, "phyrev: %u\n", ri->phyrev);
1083 seq_printf(s, "anarev: %u\n", ri->anarev);
1084 seq_printf(s, "nvramrev: %08x\n", ri->nvramrev);
1085
1086 seq_printf(s, "clmver: %s\n", bus_if->drvr->clmver);
1087
1088 return 0;
1089}
1090
1091static void brcmf_core_bus_reset(struct work_struct *work)
1092{
1093 struct brcmf_pub *drvr = container_of(work, struct brcmf_pub,
1094 bus_reset);
1095
1096 brcmf_bus_reset(drvr->bus_if);
1097}
1098
1099static int brcmf_bus_started(struct brcmf_pub *drvr, struct cfg80211_ops *ops)
1100{
1101 int ret = -1;
1102 struct brcmf_bus *bus_if = drvr->bus_if;
1103 struct brcmf_if *ifp;
1104 struct brcmf_if *p2p_ifp;
1105
1106 brcmf_dbg(TRACE, "\n");
1107
1108
1109 ifp = brcmf_add_if(drvr, 0, 0, false, "wlan%d", NULL);
1110 if (IS_ERR(ifp))
1111 return PTR_ERR(ifp);
1112
1113 p2p_ifp = NULL;
1114
1115
1116 brcmf_bus_change_state(bus_if, BRCMF_BUS_UP);
1117
1118
1119 ret = brcmf_bus_preinit(bus_if);
1120 if (ret < 0)
1121 goto fail;
1122
1123
1124 ret = brcmf_c_preinit_dcmds(ifp);
1125 if (ret < 0)
1126 goto fail;
1127
1128 brcmf_feat_attach(drvr);
1129
1130 ret = brcmf_proto_init_done(drvr);
1131 if (ret < 0)
1132 goto fail;
1133
1134 brcmf_proto_add_if(drvr, ifp);
1135
1136 drvr->config = brcmf_cfg80211_attach(drvr, ops,
1137 drvr->settings->p2p_enable);
1138 if (drvr->config == NULL) {
1139 ret = -ENOMEM;
1140 goto fail;
1141 }
1142
1143 ret = brcmf_net_attach(ifp, false);
1144
1145 if ((!ret) && (drvr->settings->p2p_enable)) {
1146 p2p_ifp = drvr->iflist[1];
1147 if (p2p_ifp)
1148 ret = brcmf_net_p2p_attach(p2p_ifp);
1149 }
1150
1151 if (ret)
1152 goto fail;
1153
1154#ifdef CONFIG_INET
1155 drvr->inetaddr_notifier.notifier_call = brcmf_inetaddr_changed;
1156 ret = register_inetaddr_notifier(&drvr->inetaddr_notifier);
1157 if (ret)
1158 goto fail;
1159
1160#if IS_ENABLED(CONFIG_IPV6)
1161 drvr->inet6addr_notifier.notifier_call = brcmf_inet6addr_changed;
1162 ret = register_inet6addr_notifier(&drvr->inet6addr_notifier);
1163 if (ret) {
1164 unregister_inetaddr_notifier(&drvr->inetaddr_notifier);
1165 goto fail;
1166 }
1167#endif
1168#endif
1169
1170 INIT_WORK(&drvr->bus_reset, brcmf_core_bus_reset);
1171
1172
1173 brcmf_debugfs_add_entry(drvr, "revinfo", brcmf_revinfo_read);
1174 brcmf_feat_debugfs_create(drvr);
1175 brcmf_proto_debugfs_create(drvr);
1176 brcmf_bus_debugfs_create(bus_if);
1177
1178 return 0;
1179
1180fail:
1181 bphy_err(drvr, "failed: %d\n", ret);
1182 if (drvr->config) {
1183 brcmf_cfg80211_detach(drvr->config);
1184 drvr->config = NULL;
1185 }
1186 brcmf_net_detach(ifp->ndev, false);
1187 if (p2p_ifp)
1188 brcmf_net_detach(p2p_ifp->ndev, false);
1189 drvr->iflist[0] = NULL;
1190 drvr->iflist[1] = NULL;
1191 if (drvr->settings->ignore_probe_fail)
1192 ret = 0;
1193
1194 return ret;
1195}
1196
1197int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings)
1198{
1199 struct wiphy *wiphy;
1200 struct cfg80211_ops *ops;
1201 struct brcmf_pub *drvr = NULL;
1202 int ret = 0;
1203 int i;
1204
1205 brcmf_dbg(TRACE, "Enter\n");
1206
1207 ops = brcmf_cfg80211_get_ops(settings);
1208 if (!ops)
1209 return -ENOMEM;
1210
1211 wiphy = wiphy_new(ops, sizeof(*drvr));
1212 if (!wiphy)
1213 return -ENOMEM;
1214
1215 set_wiphy_dev(wiphy, dev);
1216 drvr = wiphy_priv(wiphy);
1217 drvr->wiphy = wiphy;
1218
1219 for (i = 0; i < ARRAY_SIZE(drvr->if2bss); i++)
1220 drvr->if2bss[i] = BRCMF_BSSIDX_INVALID;
1221
1222 mutex_init(&drvr->proto_block);
1223
1224
1225 drvr->hdrlen = 0;
1226 drvr->bus_if = dev_get_drvdata(dev);
1227 drvr->bus_if->drvr = drvr;
1228 drvr->settings = settings;
1229
1230
1231 ret = brcmf_proto_attach(drvr);
1232 if (ret != 0) {
1233 bphy_err(drvr, "brcmf_prot_attach failed\n");
1234 goto fail;
1235 }
1236
1237
1238 brcmf_fweh_register(drvr, BRCMF_E_PSM_WATCHDOG,
1239 brcmf_psm_watchdog_notify);
1240
1241
1242 brcmf_fweh_attach(drvr);
1243
1244 ret = brcmf_bus_started(drvr, ops);
1245 if (ret != 0) {
1246 bphy_err(drvr, "dongle is not responding: err=%d\n", ret);
1247 goto fail;
1248 }
1249
1250 drvr->config->ops = ops;
1251 return 0;
1252
1253fail:
1254 brcmf_detach(dev);
1255 kfree(ops);
1256
1257 return ret;
1258}
1259
1260void brcmf_bus_add_txhdrlen(struct device *dev, uint len)
1261{
1262 struct brcmf_bus *bus_if = dev_get_drvdata(dev);
1263 struct brcmf_pub *drvr = bus_if->drvr;
1264
1265 if (drvr) {
1266 drvr->hdrlen += len;
1267 }
1268}
1269
1270void brcmf_dev_reset(struct device *dev)
1271{
1272 struct brcmf_bus *bus_if = dev_get_drvdata(dev);
1273 struct brcmf_pub *drvr = bus_if->drvr;
1274
1275 if (drvr == NULL)
1276 return;
1277
1278 if (drvr->iflist[0])
1279 brcmf_fil_cmd_int_set(drvr->iflist[0], BRCMF_C_TERMINATED, 1);
1280}
1281
1282void brcmf_dev_coredump(struct device *dev)
1283{
1284 struct brcmf_bus *bus_if = dev_get_drvdata(dev);
1285
1286 if (brcmf_debug_create_memdump(bus_if, NULL, 0) < 0)
1287 brcmf_dbg(TRACE, "failed to create coredump\n");
1288}
1289
1290void brcmf_fw_crashed(struct device *dev)
1291{
1292 struct brcmf_bus *bus_if = dev_get_drvdata(dev);
1293 struct brcmf_pub *drvr = bus_if->drvr;
1294
1295 bphy_err(drvr, "Firmware has halted or crashed\n");
1296
1297 brcmf_dev_coredump(dev);
1298
1299 schedule_work(&drvr->bus_reset);
1300}
1301
1302void brcmf_detach(struct device *dev)
1303{
1304 s32 i;
1305 struct brcmf_bus *bus_if = dev_get_drvdata(dev);
1306 struct brcmf_pub *drvr = bus_if->drvr;
1307
1308 brcmf_dbg(TRACE, "Enter\n");
1309
1310 if (drvr == NULL)
1311 return;
1312
1313#ifdef CONFIG_INET
1314 unregister_inetaddr_notifier(&drvr->inetaddr_notifier);
1315#endif
1316
1317#if IS_ENABLED(CONFIG_IPV6)
1318 unregister_inet6addr_notifier(&drvr->inet6addr_notifier);
1319#endif
1320
1321
1322 brcmf_fweh_detach(drvr);
1323 if (drvr->config)
1324 brcmf_p2p_detach(&drvr->config->p2p);
1325
1326 brcmf_bus_change_state(bus_if, BRCMF_BUS_DOWN);
1327
1328 brcmf_proto_detach_pre_delif(drvr);
1329
1330
1331 for (i = BRCMF_MAX_IFS-1; i > -1; i--)
1332 brcmf_remove_interface(drvr->iflist[i], false);
1333
1334 brcmf_cfg80211_detach(drvr->config);
1335 drvr->config = NULL;
1336
1337 brcmf_bus_stop(drvr->bus_if);
1338
1339 brcmf_proto_detach_post_delif(drvr);
1340
1341 bus_if->drvr = NULL;
1342 wiphy_free(drvr->wiphy);
1343}
1344
1345s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data, u32 len)
1346{
1347 struct brcmf_bus *bus_if = dev_get_drvdata(dev);
1348 struct brcmf_if *ifp = bus_if->drvr->iflist[0];
1349
1350 return brcmf_fil_iovar_data_set(ifp, name, data, len);
1351}
1352
1353static int brcmf_get_pend_8021x_cnt(struct brcmf_if *ifp)
1354{
1355 return atomic_read(&ifp->pend_8021x_cnt);
1356}
1357
1358int brcmf_netdev_wait_pend8021x(struct brcmf_if *ifp)
1359{
1360 struct brcmf_pub *drvr = ifp->drvr;
1361 int err;
1362
1363 err = wait_event_timeout(ifp->pend_8021x_wait,
1364 !brcmf_get_pend_8021x_cnt(ifp),
1365 MAX_WAIT_FOR_8021X_TX);
1366
1367 if (!err)
1368 bphy_err(drvr, "Timed out waiting for no pending 802.1x packets\n");
1369
1370 return !err;
1371}
1372
1373void brcmf_bus_change_state(struct brcmf_bus *bus, enum brcmf_bus_state state)
1374{
1375 struct brcmf_pub *drvr = bus->drvr;
1376 struct net_device *ndev;
1377 int ifidx;
1378
1379 brcmf_dbg(TRACE, "%d -> %d\n", bus->state, state);
1380
1381 if (!drvr) {
1382 brcmf_dbg(INFO, "ignoring transition, bus not attached yet\n");
1383 return;
1384 }
1385
1386 bus->state = state;
1387
1388 if (state == BRCMF_BUS_UP) {
1389 for (ifidx = 0; ifidx < BRCMF_MAX_IFS; ifidx++) {
1390 if ((drvr->iflist[ifidx]) &&
1391 (drvr->iflist[ifidx]->ndev)) {
1392 ndev = drvr->iflist[ifidx]->ndev;
1393 if (netif_queue_stopped(ndev))
1394 netif_wake_queue(ndev);
1395 }
1396 }
1397 }
1398}
1399
1400static void brcmf_driver_register(struct work_struct *work)
1401{
1402#ifdef CONFIG_BRCMFMAC_SDIO
1403 brcmf_sdio_register();
1404#endif
1405#ifdef CONFIG_BRCMFMAC_USB
1406 brcmf_usb_register();
1407#endif
1408#ifdef CONFIG_BRCMFMAC_PCIE
1409 brcmf_pcie_register();
1410#endif
1411}
1412static DECLARE_WORK(brcmf_driver_work, brcmf_driver_register);
1413
1414int __init brcmf_core_init(void)
1415{
1416 if (!schedule_work(&brcmf_driver_work))
1417 return -EBUSY;
1418
1419 return 0;
1420}
1421
1422void __exit brcmf_core_exit(void)
1423{
1424 cancel_work_sync(&brcmf_driver_work);
1425
1426#ifdef CONFIG_BRCMFMAC_SDIO
1427 brcmf_sdio_exit();
1428#endif
1429#ifdef CONFIG_BRCMFMAC_USB
1430 brcmf_usb_exit();
1431#endif
1432#ifdef CONFIG_BRCMFMAC_PCIE
1433 brcmf_pcie_exit();
1434#endif
1435}
1436
1437