]> Pileus Git - ~andy/linux/blob - drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[~andy/linux] / drivers / net / wireless / brcm80211 / brcmfmac / dhd_linux.c
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
17 #include <linux/init.h>
18 #include <linux/kernel.h>
19 #include <linux/kthread.h>
20 #include <linux/slab.h>
21 #include <linux/skbuff.h>
22 #include <linux/netdevice.h>
23 #include <linux/etherdevice.h>
24 #include <linux/mmc/sdio_func.h>
25 #include <linux/random.h>
26 #include <linux/spinlock.h>
27 #include <linux/ethtool.h>
28 #include <linux/fcntl.h>
29 #include <linux/fs.h>
30 #include <linux/uaccess.h>
31 #include <linux/hardirq.h>
32 #include <linux/mutex.h>
33 #include <linux/wait.h>
34 #include <linux/module.h>
35 #include <net/cfg80211.h>
36 #include <net/rtnetlink.h>
37 #include <defs.h>
38 #include <brcmu_utils.h>
39 #include <brcmu_wifi.h>
40
41 #include "dhd.h"
42 #include "dhd_bus.h"
43 #include "dhd_proto.h"
44 #include "dhd_dbg.h"
45 #include "wl_cfg80211.h"
46 #include "bcmchip.h"
47
48 MODULE_AUTHOR("Broadcom Corporation");
49 MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN fullmac driver.");
50 MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN fullmac cards");
51 MODULE_LICENSE("Dual BSD/GPL");
52
53
54 /* Interface control information */
55 struct brcmf_if {
56         struct brcmf_info *info;        /* back pointer to brcmf_info */
57         /* OS/stack specifics */
58         struct net_device *ndev;
59         struct net_device_stats stats;
60         int idx;                /* iface idx in dongle */
61         u8 mac_addr[ETH_ALEN];  /* assigned MAC address */
62 };
63
64 /* Local private structure (extension of pub) */
65 struct brcmf_info {
66         struct brcmf_pub pub;
67
68         /* OS/stack specifics */
69         struct brcmf_if *iflist[BRCMF_MAX_IFS];
70
71         struct mutex proto_block;
72
73         struct work_struct setmacaddr_work;
74         struct work_struct multicast_work;
75         u8 macvalue[ETH_ALEN];
76         atomic_t pend_8021x_cnt;
77 };
78
79 /* Error bits */
80 module_param(brcmf_msg_level, int, 0);
81
82 int brcmf_ifname2idx(struct brcmf_info *drvr_priv, char *name)
83 {
84         int i = BRCMF_MAX_IFS;
85         struct brcmf_if *ifp;
86
87         if (name == NULL || *name == '\0')
88                 return 0;
89
90         while (--i > 0) {
91                 ifp = drvr_priv->iflist[i];
92                 if (ifp && !strncmp(ifp->ndev->name, name, IFNAMSIZ))
93                         break;
94         }
95
96         brcmf_dbg(TRACE, "return idx %d for \"%s\"\n", i, name);
97
98         return i;               /* default - the primary interface */
99 }
100
101 char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx)
102 {
103         struct brcmf_info *drvr_priv = drvr->info;
104
105         if (ifidx < 0 || ifidx >= BRCMF_MAX_IFS) {
106                 brcmf_dbg(ERROR, "ifidx %d out of range\n", ifidx);
107                 return "<if_bad>";
108         }
109
110         if (drvr_priv->iflist[ifidx] == NULL) {
111                 brcmf_dbg(ERROR, "null i/f %d\n", ifidx);
112                 return "<if_null>";
113         }
114
115         if (drvr_priv->iflist[ifidx]->ndev)
116                 return drvr_priv->iflist[ifidx]->ndev->name;
117
118         return "<if_none>";
119 }
120
121 static void _brcmf_set_multicast_list(struct work_struct *work)
122 {
123         struct net_device *ndev;
124         struct netdev_hw_addr *ha;
125         u32 dcmd_value, cnt;
126         __le32 cnt_le;
127         __le32 dcmd_le_value;
128
129         struct brcmf_dcmd dcmd;
130         char *buf, *bufp;
131         uint buflen;
132         int ret;
133
134         struct brcmf_info *drvr_priv = container_of(work, struct brcmf_info,
135                                                     multicast_work);
136
137         ndev = drvr_priv->iflist[0]->ndev;
138         cnt = netdev_mc_count(ndev);
139
140         /* Determine initial value of allmulti flag */
141         dcmd_value = (ndev->flags & IFF_ALLMULTI) ? true : false;
142
143         /* Send down the multicast list first. */
144
145         buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETH_ALEN);
146         bufp = buf = kmalloc(buflen, GFP_ATOMIC);
147         if (!bufp)
148                 return;
149
150         strcpy(bufp, "mcast_list");
151         bufp += strlen("mcast_list") + 1;
152
153         cnt_le = cpu_to_le32(cnt);
154         memcpy(bufp, &cnt_le, sizeof(cnt));
155         bufp += sizeof(cnt_le);
156
157         netdev_for_each_mc_addr(ha, ndev) {
158                 if (!cnt)
159                         break;
160                 memcpy(bufp, ha->addr, ETH_ALEN);
161                 bufp += ETH_ALEN;
162                 cnt--;
163         }
164
165         memset(&dcmd, 0, sizeof(dcmd));
166         dcmd.cmd = BRCMF_C_SET_VAR;
167         dcmd.buf = buf;
168         dcmd.len = buflen;
169         dcmd.set = true;
170
171         ret = brcmf_proto_dcmd(&drvr_priv->pub, 0, &dcmd, dcmd.len);
172         if (ret < 0) {
173                 brcmf_dbg(ERROR, "%s: set mcast_list failed, cnt %d\n",
174                           brcmf_ifname(&drvr_priv->pub, 0), cnt);
175                 dcmd_value = cnt ? true : dcmd_value;
176         }
177
178         kfree(buf);
179
180         /* Now send the allmulti setting.  This is based on the setting in the
181          * net_device flags, but might be modified above to be turned on if we
182          * were trying to set some addresses and dongle rejected it...
183          */
184
185         buflen = sizeof("allmulti") + sizeof(dcmd_value);
186         buf = kmalloc(buflen, GFP_ATOMIC);
187         if (!buf)
188                 return;
189
190         dcmd_le_value = cpu_to_le32(dcmd_value);
191
192         if (!brcmf_c_mkiovar
193             ("allmulti", (void *)&dcmd_le_value,
194             sizeof(dcmd_le_value), buf, buflen)) {
195                 brcmf_dbg(ERROR, "%s: mkiovar failed for allmulti, datalen %d buflen %u\n",
196                           brcmf_ifname(&drvr_priv->pub, 0),
197                           (int)sizeof(dcmd_value), buflen);
198                 kfree(buf);
199                 return;
200         }
201
202         memset(&dcmd, 0, sizeof(dcmd));
203         dcmd.cmd = BRCMF_C_SET_VAR;
204         dcmd.buf = buf;
205         dcmd.len = buflen;
206         dcmd.set = true;
207
208         ret = brcmf_proto_dcmd(&drvr_priv->pub, 0, &dcmd, dcmd.len);
209         if (ret < 0) {
210                 brcmf_dbg(ERROR, "%s: set allmulti %d failed\n",
211                           brcmf_ifname(&drvr_priv->pub, 0),
212                           le32_to_cpu(dcmd_le_value));
213         }
214
215         kfree(buf);
216
217         /* Finally, pick up the PROMISC flag as well, like the NIC
218                  driver does */
219
220         dcmd_value = (ndev->flags & IFF_PROMISC) ? true : false;
221         dcmd_le_value = cpu_to_le32(dcmd_value);
222
223         memset(&dcmd, 0, sizeof(dcmd));
224         dcmd.cmd = BRCMF_C_SET_PROMISC;
225         dcmd.buf = &dcmd_le_value;
226         dcmd.len = sizeof(dcmd_le_value);
227         dcmd.set = true;
228
229         ret = brcmf_proto_dcmd(&drvr_priv->pub, 0, &dcmd, dcmd.len);
230         if (ret < 0) {
231                 brcmf_dbg(ERROR, "%s: set promisc %d failed\n",
232                           brcmf_ifname(&drvr_priv->pub, 0),
233                           le32_to_cpu(dcmd_le_value));
234         }
235 }
236
237 static void
238 _brcmf_set_mac_address(struct work_struct *work)
239 {
240         char buf[32];
241         struct brcmf_dcmd dcmd;
242         int ret;
243
244         struct brcmf_info *drvr_priv = container_of(work, struct brcmf_info,
245                                                     setmacaddr_work);
246
247         brcmf_dbg(TRACE, "enter\n");
248         if (!brcmf_c_mkiovar("cur_etheraddr", (char *)drvr_priv->macvalue,
249                            ETH_ALEN, buf, 32)) {
250                 brcmf_dbg(ERROR, "%s: mkiovar failed for cur_etheraddr\n",
251                           brcmf_ifname(&drvr_priv->pub, 0));
252                 return;
253         }
254         memset(&dcmd, 0, sizeof(dcmd));
255         dcmd.cmd = BRCMF_C_SET_VAR;
256         dcmd.buf = buf;
257         dcmd.len = 32;
258         dcmd.set = true;
259
260         ret = brcmf_proto_dcmd(&drvr_priv->pub, 0, &dcmd, dcmd.len);
261         if (ret < 0)
262                 brcmf_dbg(ERROR, "%s: set cur_etheraddr failed\n",
263                           brcmf_ifname(&drvr_priv->pub, 0));
264         else
265                 memcpy(drvr_priv->iflist[0]->ndev->dev_addr,
266                        drvr_priv->macvalue, ETH_ALEN);
267
268         return;
269 }
270
271 static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr)
272 {
273         struct brcmf_if *ifp = netdev_priv(ndev);
274         struct brcmf_info *drvr_priv = ifp->info;
275         struct sockaddr *sa = (struct sockaddr *)addr;
276
277         memcpy(&drvr_priv->macvalue, sa->sa_data, ETH_ALEN);
278         schedule_work(&drvr_priv->setmacaddr_work);
279         return 0;
280 }
281
282 static void brcmf_netdev_set_multicast_list(struct net_device *ndev)
283 {
284         struct brcmf_if *ifp = netdev_priv(ndev);
285         struct brcmf_info *drvr_priv = ifp->info;
286
287         schedule_work(&drvr_priv->multicast_work);
288 }
289
290 int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx, struct sk_buff *pktbuf)
291 {
292         struct brcmf_info *drvr_priv = drvr->info;
293
294         /* Reject if down */
295         if (!drvr->up || (drvr->busstate == BRCMF_BUS_DOWN))
296                 return -ENODEV;
297
298         /* Update multicast statistic */
299         if (pktbuf->len >= ETH_ALEN) {
300                 u8 *pktdata = (u8 *) (pktbuf->data);
301                 struct ethhdr *eh = (struct ethhdr *)pktdata;
302
303                 if (is_multicast_ether_addr(eh->h_dest))
304                         drvr->tx_multicast++;
305                 if (ntohs(eh->h_proto) == ETH_P_PAE)
306                         atomic_inc(&drvr_priv->pend_8021x_cnt);
307         }
308
309         /* If the protocol uses a data header, apply it */
310         brcmf_proto_hdrpush(drvr, ifidx, pktbuf);
311
312         /* Use bus module to send data frame */
313         return brcmf_sdbrcm_bus_txdata(drvr->bus, pktbuf);
314 }
315
316 static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
317 {
318         int ret;
319         struct brcmf_if *ifp = netdev_priv(ndev);
320         struct brcmf_info *drvr_priv = ifp->info;
321
322         brcmf_dbg(TRACE, "Enter\n");
323
324         /* Reject if down */
325         if (!drvr_priv->pub.up || (drvr_priv->pub.busstate == BRCMF_BUS_DOWN)) {
326                 brcmf_dbg(ERROR, "xmit rejected pub.up=%d busstate=%d\n",
327                           drvr_priv->pub.up, drvr_priv->pub.busstate);
328                 netif_stop_queue(ndev);
329                 return -ENODEV;
330         }
331
332         if (!drvr_priv->iflist[ifp->idx]) {
333                 brcmf_dbg(ERROR, "bad ifidx %d\n", ifp->idx);
334                 netif_stop_queue(ndev);
335                 return -ENODEV;
336         }
337
338         /* Make sure there's enough room for any header */
339         if (skb_headroom(skb) < drvr_priv->pub.hdrlen) {
340                 struct sk_buff *skb2;
341
342                 brcmf_dbg(INFO, "%s: insufficient headroom\n",
343                           brcmf_ifname(&drvr_priv->pub, ifp->idx));
344                 drvr_priv->pub.tx_realloc++;
345                 skb2 = skb_realloc_headroom(skb, drvr_priv->pub.hdrlen);
346                 dev_kfree_skb(skb);
347                 skb = skb2;
348                 if (skb == NULL) {
349                         brcmf_dbg(ERROR, "%s: skb_realloc_headroom failed\n",
350                                   brcmf_ifname(&drvr_priv->pub, ifp->idx));
351                         ret = -ENOMEM;
352                         goto done;
353                 }
354         }
355
356         ret = brcmf_sendpkt(&drvr_priv->pub, ifp->idx, skb);
357
358 done:
359         if (ret)
360                 drvr_priv->pub.dstats.tx_dropped++;
361         else
362                 drvr_priv->pub.tx_packets++;
363
364         /* Return ok: we always eat the packet */
365         return 0;
366 }
367
368 void brcmf_txflowcontrol(struct brcmf_pub *drvr, int ifidx, bool state)
369 {
370         struct net_device *ndev;
371         struct brcmf_info *drvr_priv = drvr->info;
372
373         brcmf_dbg(TRACE, "Enter\n");
374
375         drvr->txoff = state;
376         ndev = drvr_priv->iflist[ifidx]->ndev;
377         if (state == ON)
378                 netif_stop_queue(ndev);
379         else
380                 netif_wake_queue(ndev);
381 }
382
383 static int brcmf_host_event(struct brcmf_info *drvr_priv, int *ifidx,
384                             void *pktdata, struct brcmf_event_msg *event,
385                             void **data)
386 {
387         int bcmerror = 0;
388
389         bcmerror = brcmf_c_host_event(drvr_priv, ifidx, pktdata, event, data);
390         if (bcmerror != 0)
391                 return bcmerror;
392
393         if (drvr_priv->iflist[*ifidx]->ndev)
394                 brcmf_cfg80211_event(drvr_priv->iflist[*ifidx]->ndev,
395                                      event, *data);
396
397         return bcmerror;
398 }
399
400 void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, struct sk_buff *skb,
401                   int numpkt)
402 {
403         struct brcmf_info *drvr_priv = drvr->info;
404         unsigned char *eth;
405         uint len;
406         void *data;
407         struct sk_buff *pnext, *save_pktbuf;
408         int i;
409         struct brcmf_if *ifp;
410         struct brcmf_event_msg event;
411
412         brcmf_dbg(TRACE, "Enter\n");
413
414         save_pktbuf = skb;
415
416         for (i = 0; skb && i < numpkt; i++, skb = pnext) {
417
418                 pnext = skb->next;
419                 skb->next = NULL;
420
421                 /* Get the protocol, maintain skb around eth_type_trans()
422                  * The main reason for this hack is for the limitation of
423                  * Linux 2.4 where 'eth_type_trans' uses the
424                  * 'net->hard_header_len'
425                  * to perform skb_pull inside vs ETH_HLEN. Since to avoid
426                  * coping of the packet coming from the network stack to add
427                  * BDC, Hardware header etc, during network interface
428                  * registration
429                  * we set the 'net->hard_header_len' to ETH_HLEN + extra space
430                  * required
431                  * for BDC, Hardware header etc. and not just the ETH_HLEN
432                  */
433                 eth = skb->data;
434                 len = skb->len;
435
436                 ifp = drvr_priv->iflist[ifidx];
437                 if (ifp == NULL)
438                         ifp = drvr_priv->iflist[0];
439
440                 skb->dev = ifp->ndev;
441                 skb->protocol = eth_type_trans(skb, skb->dev);
442
443                 if (skb->pkt_type == PACKET_MULTICAST)
444                         drvr_priv->pub.rx_multicast++;
445
446                 skb->data = eth;
447                 skb->len = len;
448
449                 /* Strip header, count, deliver upward */
450                 skb_pull(skb, ETH_HLEN);
451
452                 /* Process special event packets and then discard them */
453                 if (ntohs(skb->protocol) == ETH_P_LINK_CTL)
454                         brcmf_host_event(drvr_priv, &ifidx,
455                                           skb_mac_header(skb),
456                                           &event, &data);
457
458                 if (drvr_priv->iflist[ifidx]) {
459                         ifp = drvr_priv->iflist[ifidx];
460                         ifp->ndev->last_rx = jiffies;
461                 }
462
463                 drvr->dstats.rx_bytes += skb->len;
464                 drvr->rx_packets++;     /* Local count */
465
466                 if (in_interrupt())
467                         netif_rx(skb);
468                 else
469                         /* If the receive is not processed inside an ISR,
470                          * the softirqd must be woken explicitly to service
471                          * the NET_RX_SOFTIRQ.  In 2.6 kernels, this is handled
472                          * by netif_rx_ni(), but in earlier kernels, we need
473                          * to do it manually.
474                          */
475                         netif_rx_ni(skb);
476         }
477 }
478
479 void brcmf_txcomplete(struct brcmf_pub *drvr, struct sk_buff *txp, bool success)
480 {
481         uint ifidx;
482         struct brcmf_info *drvr_priv = drvr->info;
483         struct ethhdr *eh;
484         u16 type;
485
486         brcmf_proto_hdrpull(drvr, &ifidx, txp);
487
488         eh = (struct ethhdr *)(txp->data);
489         type = ntohs(eh->h_proto);
490
491         if (type == ETH_P_PAE)
492                 atomic_dec(&drvr_priv->pend_8021x_cnt);
493
494 }
495
496 static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)
497 {
498         struct brcmf_if *ifp = netdev_priv(ndev);
499         struct brcmf_info *drvr_priv = ifp->info;
500
501         brcmf_dbg(TRACE, "Enter\n");
502
503         if (drvr_priv->pub.up)
504                 /* Use the protocol to get dongle stats */
505                 brcmf_proto_dstats(&drvr_priv->pub);
506
507         /* Copy dongle stats to net device stats */
508         ifp->stats.rx_packets = drvr_priv->pub.dstats.rx_packets;
509         ifp->stats.tx_packets = drvr_priv->pub.dstats.tx_packets;
510         ifp->stats.rx_bytes = drvr_priv->pub.dstats.rx_bytes;
511         ifp->stats.tx_bytes = drvr_priv->pub.dstats.tx_bytes;
512         ifp->stats.rx_errors = drvr_priv->pub.dstats.rx_errors;
513         ifp->stats.tx_errors = drvr_priv->pub.dstats.tx_errors;
514         ifp->stats.rx_dropped = drvr_priv->pub.dstats.rx_dropped;
515         ifp->stats.tx_dropped = drvr_priv->pub.dstats.tx_dropped;
516         ifp->stats.multicast = drvr_priv->pub.dstats.multicast;
517
518         return &ifp->stats;
519 }
520
521 /* Retrieve current toe component enables, which are kept
522          as a bitmap in toe_ol iovar */
523 static int brcmf_toe_get(struct brcmf_info *drvr_priv, int ifidx, u32 *toe_ol)
524 {
525         struct brcmf_dcmd dcmd;
526         __le32 toe_le;
527         char buf[32];
528         int ret;
529
530         memset(&dcmd, 0, sizeof(dcmd));
531
532         dcmd.cmd = BRCMF_C_GET_VAR;
533         dcmd.buf = buf;
534         dcmd.len = (uint) sizeof(buf);
535         dcmd.set = false;
536
537         strcpy(buf, "toe_ol");
538         ret = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, dcmd.len);
539         if (ret < 0) {
540                 /* Check for older dongle image that doesn't support toe_ol */
541                 if (ret == -EIO) {
542                         brcmf_dbg(ERROR, "%s: toe not supported by device\n",
543                                   brcmf_ifname(&drvr_priv->pub, ifidx));
544                         return -EOPNOTSUPP;
545                 }
546
547                 brcmf_dbg(INFO, "%s: could not get toe_ol: ret=%d\n",
548                           brcmf_ifname(&drvr_priv->pub, ifidx), ret);
549                 return ret;
550         }
551
552         memcpy(&toe_le, buf, sizeof(u32));
553         *toe_ol = le32_to_cpu(toe_le);
554         return 0;
555 }
556
557 /* Set current toe component enables in toe_ol iovar,
558          and set toe global enable iovar */
559 static int brcmf_toe_set(struct brcmf_info *drvr_priv, int ifidx, u32 toe_ol)
560 {
561         struct brcmf_dcmd dcmd;
562         char buf[32];
563         int ret;
564         __le32 toe_le = cpu_to_le32(toe_ol);
565
566         memset(&dcmd, 0, sizeof(dcmd));
567
568         dcmd.cmd = BRCMF_C_SET_VAR;
569         dcmd.buf = buf;
570         dcmd.len = (uint) sizeof(buf);
571         dcmd.set = true;
572
573         /* Set toe_ol as requested */
574         strcpy(buf, "toe_ol");
575         memcpy(&buf[sizeof("toe_ol")], &toe_le, sizeof(u32));
576
577         ret = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, dcmd.len);
578         if (ret < 0) {
579                 brcmf_dbg(ERROR, "%s: could not set toe_ol: ret=%d\n",
580                           brcmf_ifname(&drvr_priv->pub, ifidx), ret);
581                 return ret;
582         }
583
584         /* Enable toe globally only if any components are enabled. */
585         toe_le = cpu_to_le32(toe_ol != 0);
586
587         strcpy(buf, "toe");
588         memcpy(&buf[sizeof("toe")], &toe_le, sizeof(u32));
589
590         ret = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, dcmd.len);
591         if (ret < 0) {
592                 brcmf_dbg(ERROR, "%s: could not set toe: ret=%d\n",
593                           brcmf_ifname(&drvr_priv->pub, ifidx), ret);
594                 return ret;
595         }
596
597         return 0;
598 }
599
600 static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,
601                                     struct ethtool_drvinfo *info)
602 {
603         struct brcmf_if *ifp = netdev_priv(ndev);
604         struct brcmf_info *drvr_priv = ifp->info;
605
606         sprintf(info->driver, KBUILD_MODNAME);
607         sprintf(info->version, "%lu", drvr_priv->pub.drv_version);
608         sprintf(info->fw_version, "%s", BCM4329_FW_NAME);
609         sprintf(info->bus_info, "%s",
610                 dev_name(brcmf_bus_get_device(drvr_priv->pub.bus)));
611 }
612
613 static struct ethtool_ops brcmf_ethtool_ops = {
614         .get_drvinfo = brcmf_ethtool_get_drvinfo
615 };
616
617 static int brcmf_ethtool(struct brcmf_info *drvr_priv, void __user *uaddr)
618 {
619         struct ethtool_drvinfo info;
620         char drvname[sizeof(info.driver)];
621         u32 cmd;
622         struct ethtool_value edata;
623         u32 toe_cmpnt, csum_dir;
624         int ret;
625
626         brcmf_dbg(TRACE, "Enter\n");
627
628         /* all ethtool calls start with a cmd word */
629         if (copy_from_user(&cmd, uaddr, sizeof(u32)))
630                 return -EFAULT;
631
632         switch (cmd) {
633         case ETHTOOL_GDRVINFO:
634                 /* Copy out any request driver name */
635                 if (copy_from_user(&info, uaddr, sizeof(info)))
636                         return -EFAULT;
637                 strncpy(drvname, info.driver, sizeof(info.driver));
638                 drvname[sizeof(info.driver) - 1] = '\0';
639
640                 /* clear struct for return */
641                 memset(&info, 0, sizeof(info));
642                 info.cmd = cmd;
643
644                 /* if requested, identify ourselves */
645                 if (strcmp(drvname, "?dhd") == 0) {
646                         sprintf(info.driver, "dhd");
647                         strcpy(info.version, BRCMF_VERSION_STR);
648                 }
649
650                 /* otherwise, require dongle to be up */
651                 else if (!drvr_priv->pub.up) {
652                         brcmf_dbg(ERROR, "dongle is not up\n");
653                         return -ENODEV;
654                 }
655
656                 /* finally, report dongle driver type */
657                 else if (drvr_priv->pub.iswl)
658                         sprintf(info.driver, "wl");
659                 else
660                         sprintf(info.driver, "xx");
661
662                 sprintf(info.version, "%lu", drvr_priv->pub.drv_version);
663                 if (copy_to_user(uaddr, &info, sizeof(info)))
664                         return -EFAULT;
665                 brcmf_dbg(CTL, "given %*s, returning %s\n",
666                           (int)sizeof(drvname), drvname, info.driver);
667                 break;
668
669                 /* Get toe offload components from dongle */
670         case ETHTOOL_GRXCSUM:
671         case ETHTOOL_GTXCSUM:
672                 ret = brcmf_toe_get(drvr_priv, 0, &toe_cmpnt);
673                 if (ret < 0)
674                         return ret;
675
676                 csum_dir =
677                     (cmd == ETHTOOL_GTXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;
678
679                 edata.cmd = cmd;
680                 edata.data = (toe_cmpnt & csum_dir) ? 1 : 0;
681
682                 if (copy_to_user(uaddr, &edata, sizeof(edata)))
683                         return -EFAULT;
684                 break;
685
686                 /* Set toe offload components in dongle */
687         case ETHTOOL_SRXCSUM:
688         case ETHTOOL_STXCSUM:
689                 if (copy_from_user(&edata, uaddr, sizeof(edata)))
690                         return -EFAULT;
691
692                 /* Read the current settings, update and write back */
693                 ret = brcmf_toe_get(drvr_priv, 0, &toe_cmpnt);
694                 if (ret < 0)
695                         return ret;
696
697                 csum_dir =
698                     (cmd == ETHTOOL_STXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;
699
700                 if (edata.data != 0)
701                         toe_cmpnt |= csum_dir;
702                 else
703                         toe_cmpnt &= ~csum_dir;
704
705                 ret = brcmf_toe_set(drvr_priv, 0, toe_cmpnt);
706                 if (ret < 0)
707                         return ret;
708
709                 /* If setting TX checksum mode, tell Linux the new mode */
710                 if (cmd == ETHTOOL_STXCSUM) {
711                         if (edata.data)
712                                 drvr_priv->iflist[0]->ndev->features |=
713                                     NETIF_F_IP_CSUM;
714                         else
715                                 drvr_priv->iflist[0]->ndev->features &=
716                                     ~NETIF_F_IP_CSUM;
717                 }
718
719                 break;
720
721         default:
722                 return -EOPNOTSUPP;
723         }
724
725         return 0;
726 }
727
728 static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr,
729                                     int cmd)
730 {
731         struct brcmf_if *ifp = netdev_priv(ndev);
732         struct brcmf_info *drvr_priv = ifp->info;
733
734         brcmf_dbg(TRACE, "ifidx %d, cmd 0x%04x\n", ifp->idx, cmd);
735
736         if (!drvr_priv->iflist[ifp->idx])
737                 return -1;
738
739         if (cmd == SIOCETHTOOL)
740                 return brcmf_ethtool(drvr_priv, ifr->ifr_data);
741
742         return -EOPNOTSUPP;
743 }
744
745 /* called only from within this driver. Sends a command to the dongle. */
746 s32 brcmf_exec_dcmd(struct net_device *ndev, u32 cmd, void *arg, u32 len)
747 {
748         struct brcmf_dcmd dcmd;
749         s32 err = 0;
750         int buflen = 0;
751         bool is_set_key_cmd;
752         struct brcmf_if *ifp = netdev_priv(ndev);
753         struct brcmf_info *drvr_priv = ifp->info;
754
755         memset(&dcmd, 0, sizeof(dcmd));
756         dcmd.cmd = cmd;
757         dcmd.buf = arg;
758         dcmd.len = len;
759
760         if (dcmd.buf != NULL)
761                 buflen = min_t(uint, dcmd.len, BRCMF_DCMD_MAXLEN);
762
763         /* send to dongle (must be up, and wl) */
764         if ((drvr_priv->pub.busstate != BRCMF_BUS_DATA)) {
765                 brcmf_dbg(ERROR, "DONGLE_DOWN\n");
766                 err = -EIO;
767                 goto done;
768         }
769
770         if (!drvr_priv->pub.iswl) {
771                 err = -EIO;
772                 goto done;
773         }
774
775         /*
776          * Intercept BRCMF_C_SET_KEY CMD - serialize M4 send and
777          * set key CMD to prevent M4 encryption.
778          */
779         is_set_key_cmd = ((dcmd.cmd == BRCMF_C_SET_KEY) ||
780                           ((dcmd.cmd == BRCMF_C_SET_VAR) &&
781                            !(strncmp("wsec_key", dcmd.buf, 9))) ||
782                           ((dcmd.cmd == BRCMF_C_SET_VAR) &&
783                            !(strncmp("bsscfg:wsec_key", dcmd.buf, 15))));
784         if (is_set_key_cmd)
785                 brcmf_netdev_wait_pend8021x(ndev);
786
787         err = brcmf_proto_dcmd(&drvr_priv->pub, ifp->idx, &dcmd, buflen);
788
789 done:
790         if (err > 0)
791                 err = 0;
792
793         return err;
794 }
795
796 static int brcmf_netdev_stop(struct net_device *ndev)
797 {
798         struct brcmf_if *ifp = netdev_priv(ndev);
799         struct brcmf_pub *drvr = &ifp->info->pub;
800
801         brcmf_dbg(TRACE, "Enter\n");
802         brcmf_cfg80211_down(drvr->config);
803         if (drvr->up == 0)
804                 return 0;
805
806         /* Set state and stop OS transmissions */
807         drvr->up = 0;
808         netif_stop_queue(ndev);
809
810         return 0;
811 }
812
813 static int brcmf_netdev_open(struct net_device *ndev)
814 {
815         struct brcmf_if *ifp = netdev_priv(ndev);
816         struct brcmf_info *drvr_priv = ifp->info;
817         u32 toe_ol;
818         s32 ret = 0;
819
820         brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx);
821
822         if (ifp->idx == 0) {    /* do it only for primary eth0 */
823                 /* try to bring up bus */
824                 ret = brcmf_bus_start(&drvr_priv->pub);
825                 if (ret != 0) {
826                         brcmf_dbg(ERROR, "failed with code %d\n", ret);
827                         return -1;
828                 }
829                 atomic_set(&drvr_priv->pend_8021x_cnt, 0);
830
831                 memcpy(ndev->dev_addr, drvr_priv->pub.mac, ETH_ALEN);
832
833                 /* Get current TOE mode from dongle */
834                 if (brcmf_toe_get(drvr_priv, ifp->idx, &toe_ol) >= 0
835                     && (toe_ol & TOE_TX_CSUM_OL) != 0)
836                         drvr_priv->iflist[ifp->idx]->ndev->features |=
837                                 NETIF_F_IP_CSUM;
838                 else
839                         drvr_priv->iflist[ifp->idx]->ndev->features &=
840                                 ~NETIF_F_IP_CSUM;
841         }
842         /* Allow transmit calls */
843         netif_start_queue(ndev);
844         drvr_priv->pub.up = 1;
845         if (brcmf_cfg80211_up(drvr_priv->pub.config)) {
846                 brcmf_dbg(ERROR, "failed to bring up cfg80211\n");
847                 return -1;
848         }
849
850         return ret;
851 }
852
853 static const struct net_device_ops brcmf_netdev_ops_pri = {
854         .ndo_open = brcmf_netdev_open,
855         .ndo_stop = brcmf_netdev_stop,
856         .ndo_get_stats = brcmf_netdev_get_stats,
857         .ndo_do_ioctl = brcmf_netdev_ioctl_entry,
858         .ndo_start_xmit = brcmf_netdev_start_xmit,
859         .ndo_set_mac_address = brcmf_netdev_set_mac_address,
860         .ndo_set_rx_mode = brcmf_netdev_set_multicast_list
861 };
862
863 int
864 brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx, char *name, u8 *mac_addr)
865 {
866         struct brcmf_if *ifp;
867         struct net_device *ndev;
868
869         brcmf_dbg(TRACE, "idx %d\n", ifidx);
870
871         ifp = drvr_priv->iflist[ifidx];
872         /*
873          * Delete the existing interface before overwriting it
874          * in case we missed the BRCMF_E_IF_DEL event.
875          */
876         if (ifp) {
877                 brcmf_dbg(ERROR, "ERROR: netdev:%s already exists, try free & unregister\n",
878                           ifp->ndev->name);
879                 netif_stop_queue(ifp->ndev);
880                 unregister_netdev(ifp->ndev);
881                 free_netdev(ifp->ndev);
882                 drvr_priv->iflist[ifidx] = NULL;
883         }
884
885         /* Allocate netdev, including space for private structure */
886         ndev = alloc_netdev(sizeof(struct brcmf_if), name, ether_setup);
887         if (!ndev) {
888                 brcmf_dbg(ERROR, "OOM - alloc_netdev\n");
889                 return -ENOMEM;
890         }
891
892         ifp = netdev_priv(ndev);
893         ifp->ndev = ndev;
894         ifp->info = drvr_priv;
895         drvr_priv->iflist[ifidx] = ifp;
896         ifp->idx = ifidx;
897         if (mac_addr != NULL)
898                 memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN);
899
900         if (brcmf_net_attach(&drvr_priv->pub, ifp->idx)) {
901                 brcmf_dbg(ERROR, "brcmf_net_attach failed");
902                 free_netdev(ifp->ndev);
903                 drvr_priv->iflist[ifidx] = NULL;
904                 return -EOPNOTSUPP;
905         }
906
907         brcmf_dbg(TRACE, " ==== pid:%x, net_device for if:%s created ===\n",
908                   current->pid, ifp->ndev->name);
909
910         return 0;
911 }
912
913 void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx)
914 {
915         struct brcmf_if *ifp;
916
917         brcmf_dbg(TRACE, "idx %d\n", ifidx);
918
919         ifp = drvr_priv->iflist[ifidx];
920         if (!ifp) {
921                 brcmf_dbg(ERROR, "Null interface\n");
922                 return;
923         }
924         if (ifp->ndev) {
925                 if (ifidx == 0) {
926                         if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
927                                 rtnl_lock();
928                                 brcmf_netdev_stop(ifp->ndev);
929                                 rtnl_unlock();
930                         }
931                 } else {
932                         netif_stop_queue(ifp->ndev);
933                 }
934
935                 unregister_netdev(ifp->ndev);
936                 drvr_priv->iflist[ifidx] = NULL;
937                 if (ifidx == 0)
938                         brcmf_cfg80211_detach(drvr_priv->pub.config);
939                 free_netdev(ifp->ndev);
940         }
941 }
942
943 struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen)
944 {
945         struct brcmf_info *drvr_priv = NULL;
946
947         brcmf_dbg(TRACE, "Enter\n");
948
949         /* Allocate primary brcmf_info */
950         drvr_priv = kzalloc(sizeof(struct brcmf_info), GFP_ATOMIC);
951         if (!drvr_priv)
952                 goto fail;
953
954         mutex_init(&drvr_priv->proto_block);
955
956         /* Link to info module */
957         drvr_priv->pub.info = drvr_priv;
958
959         /* Link to bus module */
960         drvr_priv->pub.bus = bus;
961         drvr_priv->pub.hdrlen = bus_hdrlen;
962
963         /* Attach and link in the protocol */
964         if (brcmf_proto_attach(&drvr_priv->pub) != 0) {
965                 brcmf_dbg(ERROR, "brcmf_prot_attach failed\n");
966                 goto fail;
967         }
968
969         INIT_WORK(&drvr_priv->setmacaddr_work, _brcmf_set_mac_address);
970         INIT_WORK(&drvr_priv->multicast_work, _brcmf_set_multicast_list);
971
972         return &drvr_priv->pub;
973
974 fail:
975         if (drvr_priv)
976                 brcmf_detach(&drvr_priv->pub);
977
978         return NULL;
979 }
980
981 int brcmf_bus_start(struct brcmf_pub *drvr)
982 {
983         int ret = -1;
984         struct brcmf_info *drvr_priv = drvr->info;
985         /* Room for "event_msgs" + '\0' + bitvec */
986         char iovbuf[BRCMF_EVENTING_MASK_LEN + 12];
987
988         brcmf_dbg(TRACE, "\n");
989
990         /* Bring up the bus */
991         ret = brcmf_sdbrcm_bus_init(&drvr_priv->pub);
992         if (ret != 0) {
993                 brcmf_dbg(ERROR, "brcmf_sdbrcm_bus_init failed %d\n", ret);
994                 return ret;
995         }
996
997         /* If bus is not ready, can't come up */
998         if (drvr_priv->pub.busstate != BRCMF_BUS_DATA) {
999                 brcmf_dbg(ERROR, "failed bus is not ready\n");
1000                 return -ENODEV;
1001         }
1002
1003         brcmf_c_mkiovar("event_msgs", drvr->eventmask, BRCMF_EVENTING_MASK_LEN,
1004                       iovbuf, sizeof(iovbuf));
1005         brcmf_proto_cdc_query_dcmd(drvr, 0, BRCMF_C_GET_VAR, iovbuf,
1006                                     sizeof(iovbuf));
1007         memcpy(drvr->eventmask, iovbuf, BRCMF_EVENTING_MASK_LEN);
1008
1009         setbit(drvr->eventmask, BRCMF_E_SET_SSID);
1010         setbit(drvr->eventmask, BRCMF_E_PRUNE);
1011         setbit(drvr->eventmask, BRCMF_E_AUTH);
1012         setbit(drvr->eventmask, BRCMF_E_REASSOC);
1013         setbit(drvr->eventmask, BRCMF_E_REASSOC_IND);
1014         setbit(drvr->eventmask, BRCMF_E_DEAUTH_IND);
1015         setbit(drvr->eventmask, BRCMF_E_DISASSOC_IND);
1016         setbit(drvr->eventmask, BRCMF_E_DISASSOC);
1017         setbit(drvr->eventmask, BRCMF_E_JOIN);
1018         setbit(drvr->eventmask, BRCMF_E_ASSOC_IND);
1019         setbit(drvr->eventmask, BRCMF_E_PSK_SUP);
1020         setbit(drvr->eventmask, BRCMF_E_LINK);
1021         setbit(drvr->eventmask, BRCMF_E_NDIS_LINK);
1022         setbit(drvr->eventmask, BRCMF_E_MIC_ERROR);
1023         setbit(drvr->eventmask, BRCMF_E_PMKID_CACHE);
1024         setbit(drvr->eventmask, BRCMF_E_TXFAIL);
1025         setbit(drvr->eventmask, BRCMF_E_JOIN_START);
1026         setbit(drvr->eventmask, BRCMF_E_SCAN_COMPLETE);
1027
1028 /* enable dongle roaming event */
1029
1030         drvr->pktfilter_count = 1;
1031         /* Setup filter to allow only unicast */
1032         drvr->pktfilter[0] = "100 0 0 0 0x01 0x00";
1033
1034         /* Bus is ready, do any protocol initialization */
1035         ret = brcmf_proto_init(&drvr_priv->pub);
1036         if (ret < 0)
1037                 return ret;
1038
1039         return 0;
1040 }
1041
1042 int brcmf_net_attach(struct brcmf_pub *drvr, int ifidx)
1043 {
1044         struct brcmf_info *drvr_priv = drvr->info;
1045         struct net_device *ndev;
1046         u8 temp_addr[ETH_ALEN] = {
1047                 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33};
1048
1049         brcmf_dbg(TRACE, "ifidx %d\n", ifidx);
1050
1051         ndev = drvr_priv->iflist[ifidx]->ndev;
1052         ndev->netdev_ops = &brcmf_netdev_ops_pri;
1053
1054         /*
1055          * We have to use the primary MAC for virtual interfaces
1056          */
1057         if (ifidx != 0) {
1058                 /* for virtual interfaces use the primary MAC  */
1059                 memcpy(temp_addr, drvr_priv->pub.mac, ETH_ALEN);
1060
1061         }
1062
1063         if (ifidx == 1) {
1064                 brcmf_dbg(TRACE, "ACCESS POINT MAC:\n");
1065                 /*  ACCESSPOINT INTERFACE CASE */
1066                 temp_addr[0] |= 0X02;   /* set bit 2 ,
1067                          - Locally Administered address  */
1068
1069         }
1070         ndev->hard_header_len = ETH_HLEN + drvr_priv->pub.hdrlen;
1071         ndev->ethtool_ops = &brcmf_ethtool_ops;
1072
1073         drvr_priv->pub.rxsz = ndev->mtu + ndev->hard_header_len +
1074                               drvr_priv->pub.hdrlen;
1075
1076         memcpy(ndev->dev_addr, temp_addr, ETH_ALEN);
1077
1078         /* attach to cfg80211 for primary interface */
1079         if (!ifidx) {
1080                 drvr->config =
1081                         brcmf_cfg80211_attach(ndev,
1082                                               brcmf_bus_get_device(drvr->bus),
1083                                               drvr);
1084                 if (drvr->config == NULL) {
1085                         brcmf_dbg(ERROR, "wl_cfg80211_attach failed\n");
1086                         goto fail;
1087                 }
1088         }
1089
1090         if (register_netdev(ndev) != 0) {
1091                 brcmf_dbg(ERROR, "couldn't register the net device\n");
1092                 goto fail;
1093         }
1094
1095         brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name);
1096
1097         return 0;
1098
1099 fail:
1100         ndev->netdev_ops = NULL;
1101         return -EBADE;
1102 }
1103
1104 static void brcmf_bus_detach(struct brcmf_pub *drvr)
1105 {
1106         struct brcmf_info *drvr_priv;
1107
1108         brcmf_dbg(TRACE, "Enter\n");
1109
1110         if (drvr) {
1111                 drvr_priv = drvr->info;
1112                 if (drvr_priv) {
1113                         /* Stop the protocol module */
1114                         brcmf_proto_stop(&drvr_priv->pub);
1115
1116                         /* Stop the bus module */
1117                         brcmf_sdbrcm_bus_stop(drvr_priv->pub.bus);
1118                 }
1119         }
1120 }
1121
1122 void brcmf_detach(struct brcmf_pub *drvr)
1123 {
1124         struct brcmf_info *drvr_priv;
1125
1126         brcmf_dbg(TRACE, "Enter\n");
1127
1128         if (drvr) {
1129                 drvr_priv = drvr->info;
1130                 if (drvr_priv) {
1131                         int i;
1132
1133                         /* make sure primary interface removed last */
1134                         for (i = BRCMF_MAX_IFS-1; i > -1; i--)
1135                                 if (drvr_priv->iflist[i])
1136                                         brcmf_del_if(drvr_priv, i);
1137
1138                         cancel_work_sync(&drvr_priv->setmacaddr_work);
1139                         cancel_work_sync(&drvr_priv->multicast_work);
1140
1141                         brcmf_bus_detach(drvr);
1142
1143                         if (drvr->prot)
1144                                 brcmf_proto_detach(drvr);
1145
1146                         kfree(drvr_priv);
1147                 }
1148         }
1149 }
1150
1151 static void __exit brcmf_module_cleanup(void)
1152 {
1153         brcmf_dbg(TRACE, "Enter\n");
1154
1155         brcmf_bus_unregister();
1156 }
1157
1158 static int __init brcmf_module_init(void)
1159 {
1160         int error;
1161
1162         brcmf_dbg(TRACE, "Enter\n");
1163
1164         error = brcmf_bus_register();
1165
1166         if (error) {
1167                 brcmf_dbg(ERROR, "brcmf_bus_register failed\n");
1168                 goto failed;
1169         }
1170         return 0;
1171
1172 failed:
1173         return -EINVAL;
1174 }
1175
1176 module_init(brcmf_module_init);
1177 module_exit(brcmf_module_cleanup);
1178
1179 int brcmf_os_proto_block(struct brcmf_pub *drvr)
1180 {
1181         struct brcmf_info *drvr_priv = drvr->info;
1182
1183         if (drvr_priv) {
1184                 mutex_lock(&drvr_priv->proto_block);
1185                 return 1;
1186         }
1187         return 0;
1188 }
1189
1190 int brcmf_os_proto_unblock(struct brcmf_pub *drvr)
1191 {
1192         struct brcmf_info *drvr_priv = drvr->info;
1193
1194         if (drvr_priv) {
1195                 mutex_unlock(&drvr_priv->proto_block);
1196                 return 1;
1197         }
1198
1199         return 0;
1200 }
1201
1202 static int brcmf_get_pend_8021x_cnt(struct brcmf_info *drvr_priv)
1203 {
1204         return atomic_read(&drvr_priv->pend_8021x_cnt);
1205 }
1206
1207 #define MAX_WAIT_FOR_8021X_TX   10
1208
1209 int brcmf_netdev_wait_pend8021x(struct net_device *ndev)
1210 {
1211         struct brcmf_if *ifp = netdev_priv(ndev);
1212         struct brcmf_info *drvr_priv = ifp->info;
1213         int timeout = 10 * HZ / 1000;
1214         int ntimes = MAX_WAIT_FOR_8021X_TX;
1215         int pend = brcmf_get_pend_8021x_cnt(drvr_priv);
1216
1217         while (ntimes && pend) {
1218                 if (pend) {
1219                         set_current_state(TASK_INTERRUPTIBLE);
1220                         schedule_timeout(timeout);
1221                         set_current_state(TASK_RUNNING);
1222                         ntimes--;
1223                 }
1224                 pend = brcmf_get_pend_8021x_cnt(drvr_priv);
1225         }
1226         return pend;
1227 }
1228
1229 #ifdef BCMDBG
1230 int brcmf_write_to_file(struct brcmf_pub *drvr, const u8 *buf, int size)
1231 {
1232         int ret = 0;
1233         struct file *fp;
1234         mm_segment_t old_fs;
1235         loff_t pos = 0;
1236
1237         /* change to KERNEL_DS address limit */
1238         old_fs = get_fs();
1239         set_fs(KERNEL_DS);
1240
1241         /* open file to write */
1242         fp = filp_open("/tmp/mem_dump", O_WRONLY | O_CREAT, 0640);
1243         if (!fp) {
1244                 brcmf_dbg(ERROR, "open file error\n");
1245                 ret = -1;
1246                 goto exit;
1247         }
1248
1249         /* Write buf to file */
1250         fp->f_op->write(fp, (char __user *)buf, size, &pos);
1251
1252 exit:
1253         /* free buf before return */
1254         kfree(buf);
1255         /* close file before return */
1256         if (fp)
1257                 filp_close(fp, current->files);
1258         /* restore previous address limit */
1259         set_fs(old_fs);
1260
1261         return ret;
1262 }
1263 #endif                          /* BCMDBG */