brcmfmac: change function signatures
[deliverable/linux.git] / drivers / net / wireless / brcm80211 / brcmfmac / dhd_linux.c
CommitLineData
5b435de0
AS
1/*
2 * Copyright (c) 2010 Broadcom Corporation
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
5b435de0 17#include <linux/kernel.h>
5b435de0 18#include <linux/etherdevice.h>
b7a57e76 19#include <linux/module.h>
5b435de0
AS
20#include <net/cfg80211.h>
21#include <net/rtnetlink.h>
5b435de0
AS
22#include <brcmu_utils.h>
23#include <brcmu_wifi.h>
24
25#include "dhd.h"
26#include "dhd_bus.h"
27#include "dhd_proto.h"
28#include "dhd_dbg.h"
7a5c1f64 29#include "fwil_types.h"
9f440b7b 30#include "p2p.h"
5b435de0 31#include "wl_cfg80211.h"
db22ae8c 32#include "fwil.h"
5b435de0
AS
33
34MODULE_AUTHOR("Broadcom Corporation");
b87e2c48
HM
35MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver.");
36MODULE_SUPPORTED_DEVICE("Broadcom 802.11 WLAN fullmac cards");
5b435de0
AS
37MODULE_LICENSE("Dual BSD/GPL");
38
21fff75d 39#define MAX_WAIT_FOR_8021X_TX 50 /* msecs */
5b435de0 40
5b435de0 41/* Error bits */
5e8149f5 42int brcmf_msg_level;
5b435de0
AS
43module_param(brcmf_msg_level, int, 0);
44
5b435de0
AS
45
46char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx)
47{
5b435de0 48 if (ifidx < 0 || ifidx >= BRCMF_MAX_IFS) {
5e8149f5 49 brcmf_err("ifidx %d out of range\n", ifidx);
5b435de0
AS
50 return "<if_bad>";
51 }
52
d08b6a37 53 if (drvr->iflist[ifidx] == NULL) {
5e8149f5 54 brcmf_err("null i/f %d\n", ifidx);
5b435de0
AS
55 return "<if_null>";
56 }
57
d08b6a37
FL
58 if (drvr->iflist[ifidx]->ndev)
59 return drvr->iflist[ifidx]->ndev->name;
5b435de0
AS
60
61 return "<if_none>";
62}
63
64static void _brcmf_set_multicast_list(struct work_struct *work)
65{
db22ae8c 66 struct brcmf_if *ifp;
5b435de0
AS
67 struct net_device *ndev;
68 struct netdev_hw_addr *ha;
db22ae8c 69 u32 cmd_value, cnt;
5b435de0 70 __le32 cnt_le;
5b435de0 71 char *buf, *bufp;
db22ae8c
HM
72 u32 buflen;
73 s32 err;
5b435de0 74
bdf5ff51 75 ifp = container_of(work, struct brcmf_if, multicast_work);
94889b1f 76
2880b868 77 brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
94889b1f 78
db22ae8c 79 ndev = ifp->ndev;
5b435de0
AS
80
81 /* Determine initial value of allmulti flag */
db22ae8c 82 cmd_value = (ndev->flags & IFF_ALLMULTI) ? true : false;
5b435de0
AS
83
84 /* Send down the multicast list first. */
db22ae8c
HM
85 cnt = netdev_mc_count(ndev);
86 buflen = sizeof(cnt) + (cnt * ETH_ALEN);
87 buf = kmalloc(buflen, GFP_ATOMIC);
88 if (!buf)
5b435de0 89 return;
db22ae8c 90 bufp = buf;
5b435de0
AS
91
92 cnt_le = cpu_to_le32(cnt);
db22ae8c 93 memcpy(bufp, &cnt_le, sizeof(cnt_le));
5b435de0
AS
94 bufp += sizeof(cnt_le);
95
96 netdev_for_each_mc_addr(ha, ndev) {
97 if (!cnt)
98 break;
99 memcpy(bufp, ha->addr, ETH_ALEN);
100 bufp += ETH_ALEN;
101 cnt--;
102 }
103
db22ae8c
HM
104 err = brcmf_fil_iovar_data_set(ifp, "mcast_list", buf, buflen);
105 if (err < 0) {
5e8149f5 106 brcmf_err("Setting mcast_list failed, %d\n", err);
db22ae8c 107 cmd_value = cnt ? true : cmd_value;
5b435de0
AS
108 }
109
110 kfree(buf);
111
db22ae8c
HM
112 /*
113 * Now send the allmulti setting. This is based on the setting in the
5b435de0
AS
114 * net_device flags, but might be modified above to be turned on if we
115 * were trying to set some addresses and dongle rejected it...
116 */
db22ae8c
HM
117 err = brcmf_fil_iovar_int_set(ifp, "allmulti", cmd_value);
118 if (err < 0)
5e8149f5 119 brcmf_err("Setting allmulti failed, %d\n", err);
db22ae8c
HM
120
121 /*Finally, pick up the PROMISC flag */
122 cmd_value = (ndev->flags & IFF_PROMISC) ? true : false;
123 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PROMISC, cmd_value);
124 if (err < 0)
5e8149f5 125 brcmf_err("Setting BRCMF_C_SET_PROMISC failed, %d\n",
db22ae8c 126 err);
5b435de0
AS
127}
128
129static void
130_brcmf_set_mac_address(struct work_struct *work)
131{
db22ae8c 132 struct brcmf_if *ifp;
db22ae8c 133 s32 err;
5b435de0 134
bdf5ff51 135 ifp = container_of(work, struct brcmf_if, setmacaddr_work);
94889b1f 136
2880b868 137 brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
94889b1f 138
bdf5ff51 139 err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", ifp->mac_addr,
db22ae8c
HM
140 ETH_ALEN);
141 if (err < 0) {
5e8149f5 142 brcmf_err("Setting cur_etheraddr failed, %d\n", err);
db22ae8c
HM
143 } else {
144 brcmf_dbg(TRACE, "MAC address updated to %pM\n",
bdf5ff51
AS
145 ifp->mac_addr);
146 memcpy(ifp->ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
db22ae8c 147 }
5b435de0
AS
148}
149
150static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr)
151{
e1b83586 152 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0 153 struct sockaddr *sa = (struct sockaddr *)addr;
5b435de0 154
bdf5ff51
AS
155 memcpy(&ifp->mac_addr, sa->sa_data, ETH_ALEN);
156 schedule_work(&ifp->setmacaddr_work);
5b435de0
AS
157 return 0;
158}
159
160static void brcmf_netdev_set_multicast_list(struct net_device *ndev)
161{
e1b83586 162 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0 163
bdf5ff51 164 schedule_work(&ifp->multicast_work);
5b435de0
AS
165}
166
80fd2dbe
HM
167static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
168 struct net_device *ndev)
5b435de0
AS
169{
170 int ret;
e1b83586 171 struct brcmf_if *ifp = netdev_priv(ndev);
d08b6a37 172 struct brcmf_pub *drvr = ifp->drvr;
12b33dac 173 struct ethhdr *eh;
5b435de0 174
2880b868 175 brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
5b435de0 176
80fd2dbe
HM
177 /* Can the device send data? */
178 if (drvr->bus_if->state != BRCMF_BUS_DATA) {
179 brcmf_err("xmit rejected state=%d\n", drvr->bus_if->state);
5b435de0 180 netif_stop_queue(ndev);
80fd2dbe
HM
181 dev_kfree_skb(skb);
182 ret = -ENODEV;
183 goto done;
5b435de0
AS
184 }
185
2880b868
HM
186 if (!drvr->iflist[ifp->bssidx]) {
187 brcmf_err("bad ifidx %d\n", ifp->bssidx);
5b435de0 188 netif_stop_queue(ndev);
80fd2dbe
HM
189 dev_kfree_skb(skb);
190 ret = -ENODEV;
191 goto done;
5b435de0
AS
192 }
193
194 /* Make sure there's enough room for any header */
d08b6a37 195 if (skb_headroom(skb) < drvr->hdrlen) {
5b435de0
AS
196 struct sk_buff *skb2;
197
198 brcmf_dbg(INFO, "%s: insufficient headroom\n",
2880b868 199 brcmf_ifname(drvr, ifp->bssidx));
9c1a043a 200 drvr->bus_if->tx_realloc++;
d08b6a37 201 skb2 = skb_realloc_headroom(skb, drvr->hdrlen);
5b435de0
AS
202 dev_kfree_skb(skb);
203 skb = skb2;
204 if (skb == NULL) {
5e8149f5 205 brcmf_err("%s: skb_realloc_headroom failed\n",
2880b868 206 brcmf_ifname(drvr, ifp->bssidx));
5b435de0
AS
207 ret = -ENOMEM;
208 goto done;
209 }
210 }
211
12b33dac
AS
212 /* validate length for ether packet */
213 if (skb->len < sizeof(*eh)) {
214 ret = -EINVAL;
215 dev_kfree_skb(skb);
216 goto done;
8514fd02
FL
217 }
218
12b33dac
AS
219 /* handle ethernet header */
220 eh = (struct ethhdr *)(skb->data);
221 if (is_multicast_ether_addr(eh->h_dest))
222 drvr->tx_multicast++;
223 if (ntohs(eh->h_proto) == ETH_P_PAE)
10ef7321 224 atomic_inc(&ifp->pend_8021x_cnt);
12b33dac 225
8514fd02 226 /* If the protocol uses a data header, apply it */
2880b868 227 brcmf_proto_hdrpush(drvr, ifp->ifidx, skb);
8514fd02
FL
228
229 /* Use bus module to send data frame */
d9cb2596 230 ret = brcmf_bus_txdata(drvr->bus_if, skb);
5b435de0
AS
231
232done:
b1a2a411
HM
233 if (ret) {
234 ifp->stats.tx_dropped++;
235 } else {
236 ifp->stats.tx_packets++;
237 ifp->stats.tx_bytes += skb->len;
238 }
5b435de0
AS
239
240 /* Return ok: we always eat the packet */
80fd2dbe 241 return NETDEV_TX_OK;
5b435de0
AS
242}
243
90d03ff7 244void brcmf_txflowblock(struct device *dev, bool state)
5b435de0
AS
245{
246 struct net_device *ndev;
2b459056
FL
247 struct brcmf_bus *bus_if = dev_get_drvdata(dev);
248 struct brcmf_pub *drvr = bus_if->drvr;
90d03ff7 249 int i;
5b435de0
AS
250
251 brcmf_dbg(TRACE, "Enter\n");
252
90d03ff7
HM
253 for (i = 0; i < BRCMF_MAX_IFS; i++)
254 if (drvr->iflist[i]) {
255 ndev = drvr->iflist[i]->ndev;
256 if (state)
257 netif_stop_queue(ndev);
258 else
259 netif_wake_queue(ndev);
260 }
5b435de0
AS
261}
262
a43af515 263void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)
5b435de0 264{
5b435de0
AS
265 unsigned char *eth;
266 uint len;
0b45bf74 267 struct sk_buff *skb, *pnext;
5b435de0 268 struct brcmf_if *ifp;
228bb43d
FL
269 struct brcmf_bus *bus_if = dev_get_drvdata(dev);
270 struct brcmf_pub *drvr = bus_if->drvr;
a43af515
AS
271 u8 ifidx;
272 int ret;
5b435de0
AS
273
274 brcmf_dbg(TRACE, "Enter\n");
275
0b45bf74
AS
276 skb_queue_walk_safe(skb_list, skb, pnext) {
277 skb_unlink(skb, skb_list);
5b435de0 278
b1a2a411 279 /* process and remove protocol-specific header */
a43af515 280 ret = brcmf_proto_hdrpull(drvr, &ifidx, skb);
b1a2a411
HM
281 ifp = drvr->iflist[ifidx];
282
283 if (ret || !ifp || !ifp->ndev) {
284 if ((ret != -ENODATA) && ifp)
285 ifp->stats.rx_errors++;
a43af515
AS
286 brcmu_pkt_buf_free_skb(skb);
287 continue;
288 }
289
5b435de0
AS
290 /* Get the protocol, maintain skb around eth_type_trans()
291 * The main reason for this hack is for the limitation of
292 * Linux 2.4 where 'eth_type_trans' uses the
293 * 'net->hard_header_len'
294 * to perform skb_pull inside vs ETH_HLEN. Since to avoid
295 * coping of the packet coming from the network stack to add
296 * BDC, Hardware header etc, during network interface
297 * registration
298 * we set the 'net->hard_header_len' to ETH_HLEN + extra space
299 * required
300 * for BDC, Hardware header etc. and not just the ETH_HLEN
301 */
302 eth = skb->data;
303 len = skb->len;
304
5b435de0
AS
305 skb->dev = ifp->ndev;
306 skb->protocol = eth_type_trans(skb, skb->dev);
307
308 if (skb->pkt_type == PACKET_MULTICAST)
b1a2a411 309 ifp->stats.multicast++;
5b435de0
AS
310
311 skb->data = eth;
312 skb->len = len;
313
314 /* Strip header, count, deliver upward */
315 skb_pull(skb, ETH_HLEN);
316
317 /* Process special event packets and then discard them */
5c36b99a 318 brcmf_fweh_process_skb(drvr, skb, &ifidx);
5b435de0 319
d08b6a37
FL
320 if (drvr->iflist[ifidx]) {
321 ifp = drvr->iflist[ifidx];
5b435de0 322 ifp->ndev->last_rx = jiffies;
d1a5b6fb 323 }
5b435de0 324
b1a2a411
HM
325 if (!(ifp->ndev->flags & IFF_UP)) {
326 brcmu_pkt_buf_free_skb(skb);
327 continue;
328 }
329
330 ifp->stats.rx_bytes += skb->len;
331 ifp->stats.rx_packets++;
5b435de0
AS
332
333 if (in_interrupt())
334 netif_rx(skb);
335 else
336 /* If the receive is not processed inside an ISR,
337 * the softirqd must be woken explicitly to service
338 * the NET_RX_SOFTIRQ. In 2.6 kernels, this is handled
339 * by netif_rx_ni(), but in earlier kernels, we need
340 * to do it manually.
341 */
342 netif_rx_ni(skb);
343 }
344}
345
c995788f 346void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
5b435de0 347{
a43af515 348 u8 ifidx;
5b435de0
AS
349 struct ethhdr *eh;
350 u16 type;
c995788f
FL
351 struct brcmf_bus *bus_if = dev_get_drvdata(dev);
352 struct brcmf_pub *drvr = bus_if->drvr;
10ef7321 353 struct brcmf_if *ifp;
5b435de0 354
a43af515 355 brcmf_proto_hdrpull(drvr, &ifidx, txp);
5b435de0 356
b1a2a411
HM
357 ifp = drvr->iflist[ifidx];
358 if (!ifp)
359 return;
360
5b435de0
AS
361 eh = (struct ethhdr *)(txp->data);
362 type = ntohs(eh->h_proto);
363
21fff75d 364 if (type == ETH_P_PAE) {
10ef7321
HM
365 atomic_dec(&ifp->pend_8021x_cnt);
366 if (waitqueue_active(&ifp->pend_8021x_wait))
367 wake_up(&ifp->pend_8021x_wait);
21fff75d 368 }
b1a2a411
HM
369 if (!success)
370 ifp->stats.tx_errors++;
5b435de0
AS
371}
372
373static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)
374{
e1b83586 375 struct brcmf_if *ifp = netdev_priv(ndev);
5b435de0 376
2880b868 377 brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
5b435de0 378
5b435de0
AS
379 return &ifp->stats;
380}
381
db22ae8c
HM
382/*
383 * Set current toe component enables in toe_ol iovar,
384 * and set toe global enable iovar
385 */
386static int brcmf_toe_set(struct brcmf_if *ifp, u32 toe_ol)
5b435de0 387{
db22ae8c 388 s32 err;
5b435de0 389
db22ae8c
HM
390 err = brcmf_fil_iovar_int_set(ifp, "toe_ol", toe_ol);
391 if (err < 0) {
5e8149f5 392 brcmf_err("Setting toe_ol failed, %d\n", err);
db22ae8c 393 return err;
5b435de0
AS
394 }
395
db22ae8c
HM
396 err = brcmf_fil_iovar_int_set(ifp, "toe", (toe_ol != 0));
397 if (err < 0)
5e8149f5 398 brcmf_err("Setting toe failed, %d\n", err);
5b435de0 399
db22ae8c 400 return err;
5b435de0 401
5b435de0
AS
402}
403
404static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,
405 struct ethtool_drvinfo *info)
406{
e1b83586 407 struct brcmf_if *ifp = netdev_priv(ndev);
d08b6a37 408 struct brcmf_pub *drvr = ifp->drvr;
5b435de0
AS
409
410 sprintf(info->driver, KBUILD_MODNAME);
d08b6a37 411 sprintf(info->version, "%lu", drvr->drv_version);
d9cb2596 412 sprintf(info->bus_info, "%s", dev_name(drvr->bus_if->dev));
5b435de0
AS
413}
414
3eb1fa7e
SH
415static const struct ethtool_ops brcmf_ethtool_ops = {
416 .get_drvinfo = brcmf_ethtool_get_drvinfo,
5b435de0
AS
417};
418
db22ae8c 419static int brcmf_ethtool(struct brcmf_if *ifp, void __user *uaddr)
5b435de0 420{
db22ae8c 421 struct brcmf_pub *drvr = ifp->drvr;
5b435de0
AS
422 struct ethtool_drvinfo info;
423 char drvname[sizeof(info.driver)];
424 u32 cmd;
425 struct ethtool_value edata;
426 u32 toe_cmpnt, csum_dir;
427 int ret;
428
2880b868 429 brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
5b435de0
AS
430
431 /* all ethtool calls start with a cmd word */
432 if (copy_from_user(&cmd, uaddr, sizeof(u32)))
433 return -EFAULT;
434
435 switch (cmd) {
436 case ETHTOOL_GDRVINFO:
437 /* Copy out any request driver name */
438 if (copy_from_user(&info, uaddr, sizeof(info)))
439 return -EFAULT;
440 strncpy(drvname, info.driver, sizeof(info.driver));
441 drvname[sizeof(info.driver) - 1] = '\0';
442
443 /* clear struct for return */
444 memset(&info, 0, sizeof(info));
445 info.cmd = cmd;
446
447 /* if requested, identify ourselves */
448 if (strcmp(drvname, "?dhd") == 0) {
449 sprintf(info.driver, "dhd");
450 strcpy(info.version, BRCMF_VERSION_STR);
451 }
05dde977 452 /* report dongle driver type */
5b435de0 453 else
91917c77 454 sprintf(info.driver, "wl");
5b435de0 455
d08b6a37 456 sprintf(info.version, "%lu", drvr->drv_version);
5b435de0
AS
457 if (copy_to_user(uaddr, &info, sizeof(info)))
458 return -EFAULT;
a6cfb147 459 brcmf_dbg(TRACE, "given %*s, returning %s\n",
5b435de0
AS
460 (int)sizeof(drvname), drvname, info.driver);
461 break;
462
463 /* Get toe offload components from dongle */
464 case ETHTOOL_GRXCSUM:
465 case ETHTOOL_GTXCSUM:
db22ae8c 466 ret = brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_cmpnt);
5b435de0
AS
467 if (ret < 0)
468 return ret;
469
470 csum_dir =
471 (cmd == ETHTOOL_GTXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;
472
473 edata.cmd = cmd;
474 edata.data = (toe_cmpnt & csum_dir) ? 1 : 0;
475
476 if (copy_to_user(uaddr, &edata, sizeof(edata)))
477 return -EFAULT;
478 break;
479
480 /* Set toe offload components in dongle */
481 case ETHTOOL_SRXCSUM:
482 case ETHTOOL_STXCSUM:
483 if (copy_from_user(&edata, uaddr, sizeof(edata)))
484 return -EFAULT;
485
486 /* Read the current settings, update and write back */
db22ae8c 487 ret = brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_cmpnt);
5b435de0
AS
488 if (ret < 0)
489 return ret;
490
491 csum_dir =
492 (cmd == ETHTOOL_STXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;
493
494 if (edata.data != 0)
495 toe_cmpnt |= csum_dir;
496 else
497 toe_cmpnt &= ~csum_dir;
498
db22ae8c 499 ret = brcmf_toe_set(ifp, toe_cmpnt);
5b435de0
AS
500 if (ret < 0)
501 return ret;
502
503 /* If setting TX checksum mode, tell Linux the new mode */
504 if (cmd == ETHTOOL_STXCSUM) {
505 if (edata.data)
db22ae8c 506 ifp->ndev->features |= NETIF_F_IP_CSUM;
5b435de0 507 else
db22ae8c 508 ifp->ndev->features &= ~NETIF_F_IP_CSUM;
5b435de0
AS
509 }
510
511 break;
512
513 default:
514 return -EOPNOTSUPP;
515 }
516
517 return 0;
518}
519
520static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr,
521 int cmd)
522{
e1b83586 523 struct brcmf_if *ifp = netdev_priv(ndev);
d08b6a37 524 struct brcmf_pub *drvr = ifp->drvr;
5b435de0 525
2880b868 526 brcmf_dbg(TRACE, "Enter, idx=%d, cmd=0x%04x\n", ifp->bssidx, cmd);
5b435de0 527
2880b868 528 if (!drvr->iflist[ifp->bssidx])
5b435de0
AS
529 return -1;
530
531 if (cmd == SIOCETHTOOL)
db22ae8c 532 return brcmf_ethtool(ifp, ifr->ifr_data);
5b435de0
AS
533
534 return -EOPNOTSUPP;
535}
536
5b435de0
AS
537static int brcmf_netdev_stop(struct net_device *ndev)
538{
94889b1f
HM
539 struct brcmf_if *ifp = netdev_priv(ndev);
540
2880b868 541 brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
817b178c 542
bdf5ff51 543 brcmf_cfg80211_down(ndev);
817b178c 544
5b435de0 545 /* Set state and stop OS transmissions */
5b435de0
AS
546 netif_stop_queue(ndev);
547
548 return 0;
549}
550
551static int brcmf_netdev_open(struct net_device *ndev)
552{
e1b83586 553 struct brcmf_if *ifp = netdev_priv(ndev);
d08b6a37 554 struct brcmf_pub *drvr = ifp->drvr;
1bb1f384 555 struct brcmf_bus *bus_if = drvr->bus_if;
5b435de0 556 u32 toe_ol;
5b435de0
AS
557 s32 ret = 0;
558
2880b868 559 brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
5b435de0 560
bdf5ff51
AS
561 /* If bus is not ready, can't continue */
562 if (bus_if->state != BRCMF_BUS_DATA) {
5e8149f5 563 brcmf_err("failed bus is not ready\n");
bdf5ff51
AS
564 return -EAGAIN;
565 }
1bb1f384 566
10ef7321 567 atomic_set(&ifp->pend_8021x_cnt, 0);
5b435de0 568
bdf5ff51
AS
569 /* Get current TOE mode from dongle */
570 if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0
571 && (toe_ol & TOE_TX_CSUM_OL) != 0)
40a23296 572 ndev->features |= NETIF_F_IP_CSUM;
bdf5ff51 573 else
40a23296 574 ndev->features &= ~NETIF_F_IP_CSUM;
3338084a 575
5b435de0
AS
576 /* Allow transmit calls */
577 netif_start_queue(ndev);
bdf5ff51 578 if (brcmf_cfg80211_up(ndev)) {
5e8149f5 579 brcmf_err("failed to bring up cfg80211\n");
5b435de0
AS
580 return -1;
581 }
582
583 return ret;
584}
585
dfded557
FL
586static const struct net_device_ops brcmf_netdev_ops_pri = {
587 .ndo_open = brcmf_netdev_open,
588 .ndo_stop = brcmf_netdev_stop,
589 .ndo_get_stats = brcmf_netdev_get_stats,
590 .ndo_do_ioctl = brcmf_netdev_ioctl_entry,
591 .ndo_start_xmit = brcmf_netdev_start_xmit,
592 .ndo_set_mac_address = brcmf_netdev_set_mac_address,
593 .ndo_set_rx_mode = brcmf_netdev_set_multicast_list
594};
595
bdf5ff51
AS
596static const struct net_device_ops brcmf_netdev_ops_virt = {
597 .ndo_open = brcmf_cfg80211_up,
598 .ndo_stop = brcmf_cfg80211_down,
599 .ndo_get_stats = brcmf_netdev_get_stats,
600 .ndo_do_ioctl = brcmf_netdev_ioctl_entry,
601 .ndo_start_xmit = brcmf_netdev_start_xmit,
602 .ndo_set_mac_address = brcmf_netdev_set_mac_address,
603 .ndo_set_rx_mode = brcmf_netdev_set_multicast_list
604};
605
1ed9baf0 606int brcmf_net_attach(struct brcmf_if *ifp)
75c49904 607{
3625c149 608 struct brcmf_pub *drvr = ifp->drvr;
75c49904 609 struct net_device *ndev;
75c49904 610
2880b868 611 brcmf_dbg(TRACE, "Enter, idx=%d mac=%pM\n", ifp->bssidx,
94889b1f 612 ifp->mac_addr);
bdf5ff51 613 ndev = ifp->ndev;
75c49904 614
bdf5ff51 615 /* set appropriate operations */
2880b868 616 if (!ifp->bssidx)
bdf5ff51
AS
617 ndev->netdev_ops = &brcmf_netdev_ops_pri;
618 else
619 ndev->netdev_ops = &brcmf_netdev_ops_virt;
75c49904 620
75c49904
AS
621 ndev->hard_header_len = ETH_HLEN + drvr->hdrlen;
622 ndev->ethtool_ops = &brcmf_ethtool_ops;
623
624 drvr->rxsz = ndev->mtu + ndev->hard_header_len +
625 drvr->hdrlen;
626
0b63cb71
AS
627 /* set the mac address */
628 memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
75c49904 629
75c49904 630 if (register_netdev(ndev) != 0) {
5e8149f5 631 brcmf_err("couldn't register the net device\n");
75c49904
AS
632 goto fail;
633 }
634
635 brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name);
636
637 return 0;
638
639fail:
640 ndev->netdev_ops = NULL;
641 return -EBADE;
642}
643
2880b868
HM
644struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
645 char *name, u8 *mac_addr)
5b435de0
AS
646{
647 struct brcmf_if *ifp;
e1b83586 648 struct net_device *ndev;
5b435de0 649
2880b868 650 brcmf_dbg(TRACE, "Enter, idx=%d, ifidx=%d\n", bssidx, ifidx);
5b435de0 651
2880b868 652 ifp = drvr->iflist[bssidx];
e1b83586
FL
653 /*
654 * Delete the existing interface before overwriting it
655 * in case we missed the BRCMF_E_IF_DEL event.
656 */
657 if (ifp) {
5e8149f5 658 brcmf_err("ERROR: netdev:%s already exists\n",
e1b83586 659 ifp->ndev->name);
2880b868 660 if (bssidx) {
b522dd80
AS
661 netif_stop_queue(ifp->ndev);
662 unregister_netdev(ifp->ndev);
663 free_netdev(ifp->ndev);
2880b868 664 drvr->iflist[bssidx] = NULL;
b522dd80 665 } else {
5e8149f5 666 brcmf_err("ignore IF event\n");
b522dd80
AS
667 return ERR_PTR(-EINVAL);
668 }
15d45b6f 669 }
5b435de0 670
15d45b6f 671 /* Allocate netdev, including space for private structure */
e1b83586
FL
672 ndev = alloc_netdev(sizeof(struct brcmf_if), name, ether_setup);
673 if (!ndev) {
5e8149f5 674 brcmf_err("OOM - alloc_netdev\n");
1ed9baf0 675 return ERR_PTR(-ENOMEM);
15d45b6f 676 }
5b435de0 677
e1b83586
FL
678 ifp = netdev_priv(ndev);
679 ifp->ndev = ndev;
d08b6a37 680 ifp->drvr = drvr;
2880b868
HM
681 drvr->iflist[bssidx] = ifp;
682 ifp->ifidx = ifidx;
1d4fd8d7 683 ifp->bssidx = bssidx;
bdf5ff51
AS
684
685 INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address);
686 INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list);
687
10ef7321
HM
688 init_waitqueue_head(&ifp->pend_8021x_wait);
689
2880b868
HM
690 if (mac_addr != NULL)
691 memcpy(ifp->mac_addr, mac_addr, ETH_ALEN);
5b435de0 692
9bcb74f9
AS
693 brcmf_dbg(TRACE, " ==== pid:%x, if:%s (%pM) created ===\n",
694 current->pid, ifp->ndev->name, ifp->mac_addr);
5b435de0 695
1ed9baf0 696 return ifp;
5b435de0
AS
697}
698
2880b868 699void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx)
5b435de0
AS
700{
701 struct brcmf_if *ifp;
702
2880b868 703 ifp = drvr->iflist[bssidx];
5b435de0 704 if (!ifp) {
2880b868 705 brcmf_err("Null interface, idx=%d\n", bssidx);
5b435de0
AS
706 return;
707 }
2880b868 708 brcmf_dbg(TRACE, "Enter, idx=%d, ifidx=%d\n", bssidx, ifp->ifidx);
dfded557 709 if (ifp->ndev) {
2880b868 710 if (bssidx == 0) {
dfded557
FL
711 if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
712 rtnl_lock();
713 brcmf_netdev_stop(ifp->ndev);
714 rtnl_unlock();
715 }
716 } else {
717 netif_stop_queue(ifp->ndev);
718 }
719
bdf5ff51
AS
720 cancel_work_sync(&ifp->setmacaddr_work);
721 cancel_work_sync(&ifp->multicast_work);
722
5b435de0 723 unregister_netdev(ifp->ndev);
2880b868
HM
724 drvr->iflist[bssidx] = NULL;
725 if (bssidx == 0)
d08b6a37 726 brcmf_cfg80211_detach(drvr->config);
dfded557 727 free_netdev(ifp->ndev);
5b435de0
AS
728 }
729}
730
2447ffb0 731int brcmf_attach(uint bus_hdrlen, struct device *dev)
5b435de0 732{
d08b6a37 733 struct brcmf_pub *drvr = NULL;
712ac5b3 734 int ret = 0;
5b435de0
AS
735
736 brcmf_dbg(TRACE, "Enter\n");
737
5b435de0 738 /* Allocate primary brcmf_info */
d08b6a37
FL
739 drvr = kzalloc(sizeof(struct brcmf_pub), GFP_ATOMIC);
740 if (!drvr)
712ac5b3 741 return -ENOMEM;
5b435de0 742
d08b6a37 743 mutex_init(&drvr->proto_block);
5b435de0
AS
744
745 /* Link to bus module */
d08b6a37
FL
746 drvr->hdrlen = bus_hdrlen;
747 drvr->bus_if = dev_get_drvdata(dev);
55a63bcc 748 drvr->bus_if->drvr = drvr;
5b435de0 749
d319a7cf
AS
750 /* create device debugfs folder */
751 brcmf_debugfs_attach(drvr);
752
5b435de0 753 /* Attach and link in the protocol */
712ac5b3
FL
754 ret = brcmf_proto_attach(drvr);
755 if (ret != 0) {
5e8149f5 756 brcmf_err("brcmf_prot_attach failed\n");
5b435de0
AS
757 goto fail;
758 }
759
5c36b99a
AS
760 /* attach firmware event handler */
761 brcmf_fweh_attach(drvr);
762
135e4c61
FL
763 INIT_LIST_HEAD(&drvr->bus_if->dcmd_list);
764
712ac5b3 765 return ret;
5b435de0
AS
766
767fail:
712ac5b3 768 brcmf_detach(dev);
5b435de0 769
712ac5b3 770 return ret;
5b435de0
AS
771}
772
ed683c98 773int brcmf_bus_start(struct device *dev)
5b435de0
AS
774{
775 int ret = -1;
ed683c98
FL
776 struct brcmf_bus *bus_if = dev_get_drvdata(dev);
777 struct brcmf_pub *drvr = bus_if->drvr;
1ed9baf0 778 struct brcmf_if *ifp;
5b435de0
AS
779
780 brcmf_dbg(TRACE, "\n");
781
782 /* Bring up the bus */
d9cb2596 783 ret = brcmf_bus_init(bus_if);
5b435de0 784 if (ret != 0) {
5e8149f5 785 brcmf_err("brcmf_sdbrcm_bus_init failed %d\n", ret);
5b435de0
AS
786 return ret;
787 }
788
1ed9baf0 789 /* add primary networking interface */
699b5e5b 790 ifp = brcmf_add_if(drvr, 0, 0, "wlan%d", NULL);
1ed9baf0
AS
791 if (IS_ERR(ifp))
792 return PTR_ERR(ifp);
793
0af29bf7
HM
794 /* signal bus ready */
795 bus_if->state = BRCMF_BUS_DATA;
796
797 /* Bus is ready, do any initialization */
798 ret = brcmf_c_preinit_dcmds(ifp);
5b435de0 799 if (ret < 0)
6b028c5e 800 goto fail;
5b435de0 801
d9cb2596 802 drvr->config = brcmf_cfg80211_attach(drvr, bus_if->dev);
6b028c5e
HM
803 if (drvr->config == NULL) {
804 ret = -ENOMEM;
805 goto fail;
806 }
1ed9baf0 807
5c36b99a
AS
808 ret = brcmf_fweh_activate_events(ifp);
809 if (ret < 0)
810 goto fail;
811
1ed9baf0 812 ret = brcmf_net_attach(ifp);
6b028c5e 813fail:
1ed9baf0 814 if (ret < 0) {
5e8149f5 815 brcmf_err("failed: %d\n", ret);
6b028c5e
HM
816 if (drvr->config)
817 brcmf_cfg80211_detach(drvr->config);
2880b868 818 free_netdev(ifp->ndev);
1ed9baf0 819 drvr->iflist[0] = NULL;
474a64c8 820 return ret;
1ed9baf0
AS
821 }
822
5b435de0
AS
823 return 0;
824}
825
5b435de0
AS
826static void brcmf_bus_detach(struct brcmf_pub *drvr)
827{
5b435de0
AS
828 brcmf_dbg(TRACE, "Enter\n");
829
830 if (drvr) {
d08b6a37
FL
831 /* Stop the protocol module */
832 brcmf_proto_stop(drvr);
5b435de0 833
d08b6a37 834 /* Stop the bus module */
d9cb2596 835 brcmf_bus_stop(drvr->bus_if);
5b435de0
AS
836 }
837}
838
81d5f1bb
AS
839void brcmf_dev_reset(struct device *dev)
840{
841 struct brcmf_bus *bus_if = dev_get_drvdata(dev);
842 struct brcmf_pub *drvr = bus_if->drvr;
843
844 if (drvr == NULL)
845 return;
846
643ecaab
HM
847 if (drvr->iflist[0])
848 brcmf_fil_cmd_int_set(drvr->iflist[0], BRCMF_C_TERMINATED, 1);
81d5f1bb
AS
849}
850
5f947ad9 851void brcmf_detach(struct device *dev)
5b435de0 852{
2880b868 853 s32 i;
5f947ad9
FL
854 struct brcmf_bus *bus_if = dev_get_drvdata(dev);
855 struct brcmf_pub *drvr = bus_if->drvr;
5b435de0
AS
856
857 brcmf_dbg(TRACE, "Enter\n");
858
817b178c
HM
859 if (drvr == NULL)
860 return;
5b435de0 861
5c36b99a
AS
862 /* stop firmware event handling */
863 brcmf_fweh_detach(drvr);
864
5f947ad9
FL
865 /* make sure primary interface removed last */
866 for (i = BRCMF_MAX_IFS-1; i > -1; i--)
867 if (drvr->iflist[i])
868 brcmf_del_if(drvr, i);
5b435de0 869
5f947ad9 870 brcmf_bus_detach(drvr);
5b435de0 871
b84e3112 872 if (drvr->prot)
5f947ad9 873 brcmf_proto_detach(drvr);
5b435de0 874
d319a7cf 875 brcmf_debugfs_detach(drvr);
5f947ad9
FL
876 bus_if->drvr = NULL;
877 kfree(drvr);
5b435de0
AS
878}
879
10ef7321 880static int brcmf_get_pend_8021x_cnt(struct brcmf_if *ifp)
5b435de0 881{
10ef7321 882 return atomic_read(&ifp->pend_8021x_cnt);
5b435de0
AS
883}
884
5b435de0
AS
885int brcmf_netdev_wait_pend8021x(struct net_device *ndev)
886{
e1b83586 887 struct brcmf_if *ifp = netdev_priv(ndev);
21fff75d
HM
888 int err;
889
10ef7321
HM
890 err = wait_event_timeout(ifp->pend_8021x_wait,
891 !brcmf_get_pend_8021x_cnt(ifp),
21fff75d
HM
892 msecs_to_jiffies(MAX_WAIT_FOR_8021X_TX));
893
894 WARN_ON(!err);
895
896 return !err;
5b435de0
AS
897}
898
371830ea
AS
899/*
900 * return chip id and rev of the device encoded in u32.
901 */
902u32 brcmf_get_chip_info(struct brcmf_if *ifp)
903{
904 struct brcmf_bus *bus = ifp->drvr->bus_if;
905
906 return bus->chip << 4 | bus->chiprev;
907}
908
e64a4b70 909static void brcmf_driver_init(struct work_struct *work)
f3d7cdc3 910{
d319a7cf
AS
911 brcmf_debugfs_init();
912
f3d7cdc3 913#ifdef CONFIG_BRCMFMAC_SDIO
549040ab 914 brcmf_sdio_init();
f3d7cdc3 915#endif
71bb244b 916#ifdef CONFIG_BRCMFMAC_USB
549040ab 917 brcmf_usb_init();
71bb244b 918#endif
e64a4b70
AS
919}
920static DECLARE_WORK(brcmf_driver_work, brcmf_driver_init);
921
922static int __init brcmfmac_module_init(void)
923{
924 if (!schedule_work(&brcmf_driver_work))
925 return -EBUSY;
926
549040ab 927 return 0;
f3d7cdc3
AS
928}
929
e64a4b70 930static void __exit brcmfmac_module_exit(void)
f3d7cdc3 931{
e64a4b70
AS
932 cancel_work_sync(&brcmf_driver_work);
933
f3d7cdc3
AS
934#ifdef CONFIG_BRCMFMAC_SDIO
935 brcmf_sdio_exit();
936#endif
71bb244b
AS
937#ifdef CONFIG_BRCMFMAC_USB
938 brcmf_usb_exit();
939#endif
d319a7cf 940 brcmf_debugfs_exit();
f3d7cdc3
AS
941}
942
e64a4b70
AS
943module_init(brcmfmac_module_init);
944module_exit(brcmfmac_module_exit);
This page took 0.250479 seconds and 5 git commands to generate.