Merge tag 'lsk-android-14.02' into develop-3.10
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / rockchip_wlan / rkwifi / bcmdhd / dhd_linux.c
1 /*
2  * Broadcom Dongle Host Driver (DHD), Linux-specific network interface
3  * Basically selected code segments from usb-cdc.c and usb-rndis.c
4  *
5  * $Copyright Open Broadcom Corporation$
6  *
7  * $Id: dhd_linux.c 419821 2013-08-22 21:43:26Z $
8  */
9
10 #include <typedefs.h>
11 #include <linuxver.h>
12 #include <osl.h>
13
14 #include <linux/init.h>
15 #include <linux/kernel.h>
16 #include <linux/slab.h>
17 #include <linux/skbuff.h>
18 #include <linux/netdevice.h>
19 #include <linux/inetdevice.h>
20 #include <linux/rtnetlink.h>
21 #include <linux/etherdevice.h>
22 #include <linux/random.h>
23 #include <linux/spinlock.h>
24 #include <linux/ethtool.h>
25 #include <linux/fcntl.h>
26 #include <linux/fs.h>
27 #include <linux/ip.h>
28 #include <net/addrconf.h>
29
30 #include <asm/uaccess.h>
31 #include <asm/unaligned.h>
32
33 #include <epivers.h>
34 #include <bcmutils.h>
35 #include <bcmendian.h>
36 #include <bcmdevs.h>
37
38 #include <proto/ethernet.h>
39 #include <proto/bcmip.h>
40 #include <dngl_stats.h>
41 #include <dhd.h>
42 #include <dhd_bus.h>
43 #include <dhd_proto.h>
44 #include <dhd_config.h>
45 #include <dhd_dbg.h>
46 #ifdef CONFIG_HAS_WAKELOCK
47 #include <linux/wakelock.h>
48 #endif
49 #ifdef WL_CFG80211
50 #include <wl_cfg80211.h>
51 #endif
52 #ifdef PNO_SUPPORT
53 #include <dhd_pno.h>
54 #endif
55 #ifdef WLBTAMP
56 #include <proto/802.11_bta.h>
57 #include <proto/bt_amp_hci.h>
58 #include <dhd_bta.h>
59 #endif
60
61 #ifdef WLMEDIA_HTSF
62 #include <linux/time.h>
63 #include <htsf.h>
64
65 #define HTSF_MINLEN 200    /* min. packet length to timestamp */
66 #define HTSF_BUS_DELAY 150 /* assume a fix propagation in us  */
67 #define TSMAX  1000        /* max no. of timing record kept   */
68 #define NUMBIN 34
69
70 static uint32 tsidx = 0;
71 static uint32 htsf_seqnum = 0;
72 uint32 tsfsync;
73 struct timeval tsync;
74 static uint32 tsport = 5010;
75
76 typedef struct histo_ {
77         uint32 bin[NUMBIN];
78 } histo_t;
79
80 #if !ISPOWEROF2(DHD_SDALIGN)
81 #error DHD_SDALIGN is not a power of 2!
82 #endif
83
84 static histo_t vi_d1, vi_d2, vi_d3, vi_d4;
85 #endif /* WLMEDIA_HTSF */
86
87
88 #if defined(SOFTAP)
89 extern bool ap_cfg_running;
90 extern bool ap_fw_loaded;
91 #endif
92
93
94 /* enable HOSTIP cache update from the host side when an eth0:N is up */
95 #define AOE_IP_ALIAS_SUPPORT 1
96
97 #ifdef BCM_FD_AGGR
98 #include <bcm_rpc.h>
99 #include <bcm_rpc_tp.h>
100 #endif
101 #ifdef PROP_TXSTATUS
102 #include <wlfc_proto.h>
103 #include <dhd_wlfc.h>
104 #endif
105
106 #include <wl_android.h>
107
108 #ifdef ARP_OFFLOAD_SUPPORT
109 void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx);
110 static int dhd_device_event(struct notifier_block *this,
111         unsigned long event,
112         void *ptr);
113
114 static struct notifier_block dhd_notifier = {
115         .notifier_call = dhd_device_event
116 };
117 #endif /* ARP_OFFLOAD_SUPPORT */
118 static int dhd_device_ipv6_event(struct notifier_block *this,
119         unsigned long event,
120         void *ptr);
121
122 static struct notifier_block dhd_notifier_ipv6 = {
123         .notifier_call = dhd_device_ipv6_event
124 };
125
126 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
127 #include <linux/suspend.h>
128 volatile bool dhd_mmc_suspend = FALSE;
129 DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait);
130 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
131
132 #if defined(OOB_INTR_ONLY)
133 extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable);
134 #endif 
135 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (1)
136 static void dhd_hang_process(struct work_struct *work);
137 #endif 
138 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
139 MODULE_LICENSE("GPL v2");
140 #endif /* LinuxVer */
141
142 #include <dhd_bus.h>
143
144 #ifdef BCM_FD_AGGR
145 #define DBUS_RX_BUFFER_SIZE_DHD(net)    (BCM_RPC_TP_DNGL_AGG_MAX_BYTE)
146 #else
147 #ifndef PROP_TXSTATUS
148 #define DBUS_RX_BUFFER_SIZE_DHD(net)    (net->mtu + net->hard_header_len + dhd->pub.hdrlen)
149 #else
150 #define DBUS_RX_BUFFER_SIZE_DHD(net)    (net->mtu + net->hard_header_len + dhd->pub.hdrlen + 128)
151 #endif
152 #endif /* BCM_FD_AGGR */
153
154 #ifdef PROP_TXSTATUS
155 extern bool dhd_wlfc_skip_fc(void);
156 extern void dhd_wlfc_plat_enable(void *dhd);
157 extern void dhd_wlfc_plat_deinit(void *dhd);
158 #endif /* PROP_TXSTATUS */
159
160 #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15)
161 const char *
162 print_tainted()
163 {
164         return "";
165 }
166 #endif  /* LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) */
167
168 /* Linux wireless extension support */
169 #if defined(WL_WIRELESS_EXT)
170 #include <wl_iw.h>
171 extern wl_iw_extra_params_t  g_wl_iw_params;
172 #endif /* defined(WL_WIRELESS_EXT) */
173
174 #if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
175 #include <linux/earlysuspend.h>
176 #endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */
177
178 extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd);
179
180 #ifdef PKT_FILTER_SUPPORT
181 extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg);
182 extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode);
183 extern void dhd_pktfilter_offload_delete(dhd_pub_t *dhd, int id);
184 #endif
185
186
187 #ifdef READ_MACADDR
188 extern int dhd_read_macaddr(struct dhd_info *dhd);
189 #else
190 static inline int dhd_read_macaddr(struct dhd_info *dhd) { return 0; }
191 #endif
192 #ifdef WRITE_MACADDR
193 extern int dhd_write_macaddr(struct ether_addr *mac);
194 #else
195 static inline int dhd_write_macaddr(struct ether_addr *mac) { return 0; }
196 #endif
197 struct ipv6_addr {
198         char                    ipv6_addr[IPV6_ADDR_LEN];
199         dhd_ipv6_op_t   ipv6_oper;
200         struct list_head list;
201 };
202
203 /* Interface control information */
204 typedef struct dhd_if {
205         struct dhd_info *info;                  /* back pointer to dhd_info */
206         /* OS/stack specifics */
207         struct net_device *net;
208         struct net_device_stats stats;
209         int                     idx;                    /* iface idx in dongle */
210         dhd_if_state_t  state;                  /* interface state */
211         uint                    subunit;                /* subunit */
212         uint8                   mac_addr[ETHER_ADDR_LEN];       /* assigned MAC address */
213         bool                    attached;               /* Delayed attachment when unset */
214         bool                    txflowcontrol;  /* Per interface flow control indicator */
215         char                    name[IFNAMSIZ+1]; /* linux interface name */
216         uint8                   bssidx;                 /* bsscfg index for the interface */
217         bool                    set_multicast;
218         struct list_head ipv6_list;
219         spinlock_t              ipv6_lock;
220         bool                    event2cfg80211; /* To determine if pass event to cfg80211 */
221 } dhd_if_t;
222
223 #ifdef WLMEDIA_HTSF
224 typedef struct {
225         uint32 low;
226         uint32 high;
227 } tsf_t;
228
229 typedef struct {
230         uint32 last_cycle;
231         uint32 last_sec;
232         uint32 last_tsf;
233         uint32 coef;     /* scaling factor */
234         uint32 coefdec1; /* first decimal  */
235         uint32 coefdec2; /* second decimal */
236 } htsf_t;
237
238 typedef struct {
239         uint32 t1;
240         uint32 t2;
241         uint32 t3;
242         uint32 t4;
243 } tstamp_t;
244
245 static tstamp_t ts[TSMAX];
246 static tstamp_t maxdelayts;
247 static uint32 maxdelay = 0, tspktcnt = 0, maxdelaypktno = 0;
248
249 #endif  /* WLMEDIA_HTSF */
250
251 /* Local private structure (extension of pub) */
252 typedef struct dhd_info {
253 #if defined(WL_WIRELESS_EXT)
254         wl_iw_t         iw;             /* wireless extensions state (must be first) */
255 #endif /* defined(WL_WIRELESS_EXT) */
256
257         dhd_pub_t pub;
258
259         /* For supporting multiple interfaces */
260         dhd_if_t *iflist[DHD_MAX_IFS];
261
262         struct semaphore proto_sem;
263 #ifdef PROP_TXSTATUS
264         spinlock_t      wlfc_spinlock;
265 #endif /* PROP_TXSTATUS */
266 #ifdef WLMEDIA_HTSF
267         htsf_t  htsf;
268 #endif
269         wait_queue_head_t ioctl_resp_wait;
270         uint32  default_wd_interval;
271
272         struct timer_list timer;
273         bool wd_timer_valid;
274         struct tasklet_struct tasklet;
275         spinlock_t      sdlock;
276         spinlock_t      txqlock;
277         spinlock_t      dhd_lock;
278 #ifdef DHDTHREAD
279         /* Thread based operation */
280         bool threads_only;
281         struct semaphore sdsem;
282
283         tsk_ctl_t       thr_dpc_ctl;
284         tsk_ctl_t       thr_wdt_ctl;
285 #ifdef RXFRAME_THREAD
286         tsk_ctl_t       thr_rxf_ctl;
287         spinlock_t      rxf_lock;
288 #endif /* RXFRAME_THREAD */
289 #endif /* DHDTHREAD */
290         bool dhd_tasklet_create;
291         tsk_ctl_t       thr_sysioc_ctl;
292 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
293         struct work_struct work_hang;
294 #endif
295
296         /* Wakelocks */
297 #if defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
298         struct wake_lock wl_wifi;   /* Wifi wakelock */
299         struct wake_lock wl_rxwake; /* Wifi rx wakelock */
300         struct wake_lock wl_ctrlwake; /* Wifi ctrl wakelock */
301         struct wake_lock wl_wdwake; /* Wifi wd wakelock */
302 #endif
303
304 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
305         /* net_device interface lock, prevent race conditions among net_dev interface
306          * calls and wifi_on or wifi_off
307          */
308         struct mutex dhd_net_if_mutex;
309         struct mutex dhd_suspend_mutex;
310 #endif
311         spinlock_t wakelock_spinlock;
312         int wakelock_counter;
313         int wakelock_wd_counter;
314         int wakelock_rx_timeout_enable;
315         int wakelock_ctrl_timeout_enable;
316
317         /* Thread to issue ioctl for multicast */
318         unsigned char set_macaddress;
319         struct ether_addr macvalue;
320         wait_queue_head_t ctrl_wait;
321         atomic_t pend_8021x_cnt;
322         dhd_attach_states_t dhd_state;
323
324 #if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
325         struct early_suspend early_suspend;
326 #endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */
327
328 #ifdef ARP_OFFLOAD_SUPPORT
329         u32 pend_ipaddr;
330 #endif /* ARP_OFFLOAD_SUPPORT */
331 #ifdef BCM_FD_AGGR
332         void *rpc_th;
333         void *rpc_osh;
334         struct timer_list rpcth_timer;
335         bool rpcth_timer_active;
336         bool fdaggr;
337 #endif
338 #ifdef DHDTCPACK_SUPPRESS
339         spinlock_t      tcpack_lock;
340 #endif /* DHDTCPACK_SUPPRESS */
341 } dhd_info_t;
342
343 /* Flag to indicate if we should download firmware on driver load */
344 uint dhd_download_fw_on_driverload = TRUE;
345
346 /* Definitions to provide path to the firmware and nvram
347  * example nvram_path[MOD_PARAM_PATHLEN]="/projects/wlan/nvram.txt"
348  */
349 char firmware_path[MOD_PARAM_PATHLEN];
350 char nvram_path[MOD_PARAM_PATHLEN];
351 char config_path[MOD_PARAM_PATHLEN];
352
353 /* information string to keep firmware, chio, cheip version info visiable from log */
354 char info_string[MOD_PARAM_INFOLEN];
355 module_param_string(info_string, info_string, MOD_PARAM_INFOLEN, 0444);
356 int op_mode = 0;
357 int disable_proptx = 0;
358 module_param(op_mode, int, 0644);
359 extern int wl_control_wl_start(struct net_device *dev);
360 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
361 struct semaphore dhd_registration_sem;
362 struct semaphore dhd_chipup_sem;
363 int dhd_registration_check = FALSE;
364
365 #define DHD_REGISTRATION_TIMEOUT  12000  /* msec : allowed time to finished dhd registration */
366 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
367
368 /* Spawn a thread for system ioctls (set mac, set mcast) */
369 uint dhd_sysioc = TRUE;
370 module_param(dhd_sysioc, uint, 0);
371
372 /* Error bits */
373 module_param(dhd_msg_level, int, 0);
374 #if defined(WL_WIRELESS_EXT)
375 module_param(iw_msg_level, int, 0);
376 #endif
377 #ifdef WL_CFG80211
378 module_param(wl_dbg_level, int, 0);
379 #endif
380 module_param(android_msg_level, int, 0);
381 module_param(config_msg_level, int, 0);
382
383 #ifdef ARP_OFFLOAD_SUPPORT
384 /* ARP offload enable */
385 uint dhd_arp_enable = TRUE;
386 module_param(dhd_arp_enable, uint, 0);
387
388 /* ARP offload agent mode : Enable ARP Host Auto-Reply and ARP Peer Auto-Reply */
389
390 uint dhd_arp_mode = ARP_OL_AGENT | ARP_OL_PEER_AUTO_REPLY;
391
392 module_param(dhd_arp_mode, uint, 0);
393 #endif /* ARP_OFFLOAD_SUPPORT */
394
395
396
397 /* Disable Prop tx */
398 module_param(disable_proptx, int, 0644);
399 /* load firmware and/or nvram values from the filesystem */
400 module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0660);
401 module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0);
402 module_param_string(config_path, config_path, MOD_PARAM_PATHLEN, 0);
403
404 /* Watchdog interval */
405
406 /* extend watchdog expiration to 2 seconds when DPC is running */
407 #define WATCHDOG_EXTEND_INTERVAL (2000)
408
409 uint dhd_watchdog_ms = 10;
410 module_param(dhd_watchdog_ms, uint, 0);
411
412 #if defined(DHD_DEBUG)
413 /* Console poll interval */
414 uint dhd_console_ms = 0;
415 module_param(dhd_console_ms, uint, 0644);
416 #endif /* defined(DHD_DEBUG) */
417
418 uint dhd_slpauto = TRUE;
419 module_param(dhd_slpauto, uint, 0);
420
421 #ifdef PKT_FILTER_SUPPORT
422 /* Global Pkt filter enable control */
423 uint dhd_pkt_filter_enable = TRUE;
424 module_param(dhd_pkt_filter_enable, uint, 0);
425 #endif
426
427 /* Pkt filter init setup */
428 uint dhd_pkt_filter_init = 0;
429 module_param(dhd_pkt_filter_init, uint, 0);
430
431 /* Pkt filter mode control */
432 uint dhd_master_mode = TRUE;
433 module_param(dhd_master_mode, uint, 0);
434
435 #ifdef DHDTHREAD
436 int dhd_watchdog_prio = 0;
437 module_param(dhd_watchdog_prio, int, 0);
438
439 /* DPC thread priority */
440 int dhd_dpc_prio = CUSTOM_DPC_PRIO_SETTING;
441 module_param(dhd_dpc_prio, int, 0);
442
443 #ifdef RXFRAME_THREAD
444 /* RX frame thread priority */
445 int dhd_rxf_prio = CUSTOM_RXF_PRIO_SETTING;
446 module_param(dhd_rxf_prio, int, 0);
447 #endif /* RXFRAME_THREAD */
448
449 /* DPC thread priority, -1 to use tasklet */
450 extern int dhd_dongle_ramsize;
451 module_param(dhd_dongle_ramsize, int, 0);
452 #endif /* DHDTHREAD */
453 /* Control fw roaming */
454 #ifdef BCMCCX
455 uint dhd_roam_disable = 0;
456 #else
457 uint dhd_roam_disable = 0;
458 #endif /* BCMCCX */
459
460 /* Control radio state */
461 uint dhd_radio_up = 1;
462
463 /* Network inteface name */
464 char iface_name[IFNAMSIZ] = {'\0'};
465 module_param_string(iface_name, iface_name, IFNAMSIZ, 0);
466
467 /* The following are specific to the SDIO dongle */
468
469 /* IOCTL response timeout */
470 int dhd_ioctl_timeout_msec = IOCTL_RESP_TIMEOUT;
471
472 /* Idle timeout for backplane clock */
473 int dhd_idletime = DHD_IDLETIME_TICKS;
474 module_param(dhd_idletime, int, 0);
475
476 /* Use polling */
477 uint dhd_poll = FALSE;
478 module_param(dhd_poll, uint, 0);
479
480 /* Use interrupts */
481 uint dhd_intr = TRUE;
482 module_param(dhd_intr, uint, 0);
483
484 /* SDIO Drive Strength (in milliamps) */
485 uint dhd_sdiod_drive_strength = 6;
486 module_param(dhd_sdiod_drive_strength, uint, 0);
487
488 /* Tx/Rx bounds */
489 extern uint dhd_txbound;
490 extern uint dhd_rxbound;
491 module_param(dhd_txbound, uint, 0);
492 module_param(dhd_rxbound, uint, 0);
493
494 /* Deferred transmits */
495 extern uint dhd_deferred_tx;
496 module_param(dhd_deferred_tx, uint, 0);
497
498 #ifdef BCMDBGFS
499 extern void dhd_dbg_init(dhd_pub_t *dhdp);
500 extern void dhd_dbg_remove(void);
501 #endif /* BCMDBGFS */
502
503
504
505 #ifdef SDTEST
506 /* Echo packet generator (pkts/s) */
507 uint dhd_pktgen = 0;
508 module_param(dhd_pktgen, uint, 0);
509
510 /* Echo packet len (0 => sawtooth, max 2040) */
511 uint dhd_pktgen_len = 0;
512 module_param(dhd_pktgen_len, uint, 0);
513 #endif /* SDTEST */
514
515 /* Version string to report */
516 #ifdef DHD_DEBUG
517 #ifndef SRCBASE
518 #define SRCBASE        "drivers/net/wireless/bcmdhd"
519 #endif
520 #define DHD_COMPILED "\nCompiled in " SRCBASE
521 #else
522 #define DHD_COMPILED
523 #endif /* DHD_DEBUG */
524
525 static char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR
526 #ifdef DHD_DEBUG
527 "\nCompiled in " SRCBASE " on " __DATE__ " at " __TIME__
528 #endif
529 ;
530 static void dhd_net_if_lock_local(dhd_info_t *dhd);
531 static void dhd_net_if_unlock_local(dhd_info_t *dhd);
532 static void dhd_suspend_lock(dhd_pub_t *dhdp);
533 static void dhd_suspend_unlock(dhd_pub_t *dhdp);
534
535 #ifdef WLMEDIA_HTSF
536 void htsf_update(dhd_info_t *dhd, void *data);
537 tsf_t prev_tsf, cur_tsf;
538
539 uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx);
540 static int dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx);
541 static void dhd_dump_latency(void);
542 static void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf);
543 static void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf);
544 static void dhd_dump_htsfhisto(histo_t *his, char *s);
545 #endif /* WLMEDIA_HTSF */
546
547 /* Monitor interface */
548 int dhd_monitor_init(void *dhd_pub);
549 int dhd_monitor_uninit(void);
550
551
552
553 #if defined(WL_WIRELESS_EXT)
554 struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev);
555 #endif /* defined(WL_WIRELESS_EXT) */
556
557 static void dhd_dpc(ulong data);
558 /* forward decl */
559 extern int dhd_wait_pend8021x(struct net_device *dev);
560 void dhd_os_wd_timer_extend(void *bus, bool extend);
561
562 #ifdef TOE
563 #ifndef BDC
564 #error TOE requires BDC
565 #endif /* !BDC */
566 static int dhd_toe_get(dhd_info_t *dhd, int idx, uint32 *toe_ol);
567 static int dhd_toe_set(dhd_info_t *dhd, int idx, uint32 toe_ol);
568 #endif /* TOE */
569
570 static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
571                              wl_event_msg_t *event_ptr, void **data_ptr);
572
573 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \
574         KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM_SLEEP)
575 static int dhd_sleep_pm_callback(struct notifier_block *nfb, unsigned long action, void *ignored)
576 {
577         int ret = NOTIFY_DONE;
578
579         switch (action) {
580         case PM_HIBERNATION_PREPARE:
581         case PM_SUSPEND_PREPARE:
582                 dhd_mmc_suspend = TRUE;
583                 ret = NOTIFY_OK;
584                 break;
585         case PM_POST_HIBERNATION:
586         case PM_POST_SUSPEND:
587                 dhd_mmc_suspend = FALSE;
588                 ret = NOTIFY_OK;
589                 break;
590         }
591         smp_mb();
592         return ret;
593 }
594
595 static struct notifier_block dhd_sleep_pm_notifier = {
596         .notifier_call = dhd_sleep_pm_callback,
597         .priority = 10
598 };
599 extern int register_pm_notifier(struct notifier_block *nb);
600 extern int unregister_pm_notifier(struct notifier_block *nb);
601 #endif /* (LINUX_VERSION >= 2.6.27 && LINUX_VERSION <= 2.6.39 && CONFIG_PM_SLEEP */
602
603 #if defined(DHDTHREAD) && defined(RXFRAME_THREAD)
604 /* Request scheduling of the bus rx frame */
605 static void dhd_sched_rxf(dhd_pub_t *dhdp, void *skb);
606 static void dhd_os_rxflock(dhd_pub_t *pub);
607 static void dhd_os_rxfunlock(dhd_pub_t *pub);
608
609 static inline int dhd_rxf_enqueue(dhd_pub_t *dhdp, void* skb)
610 {
611         uint32 store_idx;
612         uint32 sent_idx;
613
614         if (!skb) {
615                 DHD_ERROR(("dhd_rxf_enqueue: NULL skb!!!\n"));
616                 return BCME_ERROR;
617         }
618
619         dhd_os_rxflock(dhdp);
620         store_idx = dhdp->store_idx;
621         sent_idx = dhdp->sent_idx;
622         if (dhdp->skbbuf[store_idx] != NULL) {
623                 /* Make sure the previous packets are processed */
624                 /* Do I need to make this context sleep here? Definitely in Single processor case */
625                 dhd_os_rxfunlock(dhdp);
626                 DHD_ERROR(("dhd_rxf_enqueue: pktbuf not consumed %p, store idx %d sent idx %d\n",
627                         skb, store_idx, sent_idx));
628                 msleep(1);
629                 return BCME_ERROR;
630         }
631         DHD_TRACE(("dhd_rxf_enqueue: Store SKB %p. idx %d -> %d\n",
632                 skb, store_idx, (store_idx + 1) & (MAXSKBPEND - 1)));
633         dhdp->skbbuf[store_idx] = skb;
634         dhdp->store_idx = (store_idx + 1) & (MAXSKBPEND - 1);
635         dhd_os_rxfunlock(dhdp);
636
637         return BCME_OK;
638 }
639
640 static inline void* dhd_rxf_dequeue(dhd_pub_t *dhdp)
641 {
642         uint32 store_idx;
643         uint32 sent_idx;
644         void *skb;
645
646         dhd_os_rxflock(dhdp);
647
648         store_idx = dhdp->store_idx;
649         sent_idx = dhdp->sent_idx;
650         skb = dhdp->skbbuf[sent_idx];
651
652         if (skb == NULL) {
653                 dhd_os_rxfunlock(dhdp);
654                 DHD_ERROR(("dhd_rxf_dequeue: Dequeued packet is NULL, store idx %d sent idx %d\n",
655                         store_idx, sent_idx));
656                 return NULL;
657         }
658
659         dhdp->skbbuf[sent_idx] = NULL;
660         dhdp->sent_idx = (sent_idx + 1) & (MAXSKBPEND - 1);
661
662         DHD_TRACE(("dhd_rxf_dequeue: netif_rx_ni(%p), sent idx %d\n",
663                 skb, sent_idx));
664
665         dhd_os_rxfunlock(dhdp);
666
667         return skb;
668 }
669 #endif /* defined(DHDTHREAD) && defined(RXFRAME_THREAD) */
670
671 static int dhd_process_cid_mac(dhd_pub_t *dhdp, bool prepost)
672 {
673         dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
674
675         if (prepost) { /* pre process */
676                 dhd_read_macaddr(dhd);
677         } else { /* post process */
678                 dhd_write_macaddr(&dhd->pub.mac);
679         }
680
681         return 0;
682 }
683
684 #if defined(PKT_FILTER_SUPPORT) && !defined(GAN_LITE_NAT_KEEPALIVE_FILTER)
685 static bool
686 _turn_on_arp_filter(dhd_pub_t *dhd, int op_mode)
687 {
688         bool _apply = FALSE;
689         /* In case of IBSS mode, apply arp pkt filter */
690         if (op_mode & DHD_FLAG_IBSS_MODE) {
691                 _apply = TRUE;
692                 goto exit;
693         }
694         /* In case of P2P GO or GC, apply pkt filter to pass arp pkt to host */
695         if ((dhd->arp_version == 1) &&
696                 (op_mode & (DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE))) {
697                 _apply = TRUE;
698                 goto exit;
699         }
700
701 exit:
702         return _apply;
703 }
704 #endif /* PKT_FILTER_SUPPORT && !GAN_LITE_NAT_KEEPALIVE_FILTER */
705
706 void dhd_set_packet_filter(dhd_pub_t *dhd)
707 {
708 #ifdef PKT_FILTER_SUPPORT
709         int i;
710
711         DHD_TRACE(("%s: enter\n", __FUNCTION__));
712         if (dhd_pkt_filter_enable) {
713                 for (i = 0; i < dhd->pktfilter_count; i++) {
714                         dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]);
715                 }
716         }
717 #endif /* PKT_FILTER_SUPPORT */
718 }
719
720 void dhd_enable_packet_filter(int value, dhd_pub_t *dhd)
721 {
722 #ifdef PKT_FILTER_SUPPORT
723         int i;
724
725         DHD_TRACE(("%s: enter, value = %d\n", __FUNCTION__, value));
726         /* 1 - Enable packet filter, only allow unicast packet to send up */
727         /* 0 - Disable packet filter */
728         if (dhd_pkt_filter_enable && (!value ||
729             (dhd_support_sta_mode(dhd) && !dhd->dhcp_in_progress)))
730         {
731                 for (i = 0; i < dhd->pktfilter_count; i++) {
732 #ifndef GAN_LITE_NAT_KEEPALIVE_FILTER
733                         if (!dhd->conf->filter_out_all_packets &&
734                                 value && (i == DHD_ARP_FILTER_NUM) &&
735                                 !_turn_on_arp_filter(dhd, dhd->op_mode)) {
736                                 DHD_TRACE(("Do not turn on ARP white list pkt filter:"
737                                         "val %d, cnt %d, op_mode 0x%x\n",
738                                         value, i, dhd->op_mode));
739                                 continue;
740                         }
741 #endif /* !GAN_LITE_NAT_KEEPALIVE_FILTER */
742                         dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i],
743                                 value, dhd_master_mode);
744                 }
745         }
746 #endif /* PKT_FILTER_SUPPORT */
747 }
748
749 static int dhd_set_suspend(int value, dhd_pub_t *dhd)
750 {
751 #ifndef SUPPORT_PM2_ONLY
752         int power_mode = PM_MAX;
753 #endif /* SUPPORT_PM2_ONLY */
754         /* wl_pkt_filter_enable_t       enable_parm; */
755         char iovbuf[32];
756         int bcn_li_dtim = 0; /* Default bcn_li_dtim in resume mode is 0 */
757         uint roamvar = dhd->conf->roam_off_suspend;
758
759         if (!dhd)
760                 return -ENODEV;
761
762         DHD_TRACE(("%s: enter, value = %d in_suspend=%d\n",
763                 __FUNCTION__, value, dhd->in_suspend));
764
765         dhd_suspend_lock(dhd);
766         if (dhd->up) {
767                 if (value && dhd->in_suspend) {
768 #ifdef PKT_FILTER_SUPPORT
769                         dhd->early_suspended = 1;
770 #endif
771                         /* Kernel suspended */
772                         DHD_ERROR(("%s: force extra Suspend setting\n", __FUNCTION__));
773
774 #ifndef SUPPORT_PM2_ONLY
775                         dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
776                                 sizeof(power_mode), TRUE, 0);
777 #endif /* SUPPORT_PM2_ONLY */
778
779                         /* Enable packet filter, only allow unicast packet to send up */
780                         dhd_enable_packet_filter(1, dhd);
781
782                         /* If DTIM skip is set up as default, force it to wake
783                          * each third DTIM for better power savings.  Note that
784                          * one side effect is a chance to miss BC/MC packet.
785                          */
786                         bcn_li_dtim = dhd_get_suspend_bcn_li_dtim(dhd);
787                         bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
788                                 4, iovbuf, sizeof(iovbuf));
789                         if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf),
790                                 TRUE, 0) < 0)
791                                         DHD_ERROR(("%s: set dtim failed\n", __FUNCTION__));
792
793                         /* Disable firmware roaming during suspend */
794                         bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
795                         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
796                 } else {
797 #ifdef PKT_FILTER_SUPPORT
798                         dhd->early_suspended = 0;
799 #endif
800                         /* Kernel resumed  */
801                         DHD_ERROR(("%s: Remove extra suspend setting\n", __FUNCTION__));
802
803 #ifndef SUPPORT_PM2_ONLY
804                         power_mode = PM_FAST;
805                         dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
806                                 sizeof(power_mode), TRUE, 0);
807 #endif /* SUPPORT_PM2_ONLY */
808 #ifdef PKT_FILTER_SUPPORT
809                         /* disable pkt filter */
810                         dhd_enable_packet_filter(0, dhd);
811 #endif /* PKT_FILTER_SUPPORT */
812
813                         /* restore pre-suspend setting for dtim_skip */
814                         bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
815                                 4, iovbuf, sizeof(iovbuf));
816
817                         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
818                         roamvar = dhd_roam_disable;
819                         bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
820                         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
821                 }
822         }
823         dhd_suspend_unlock(dhd);
824
825         return 0;
826 }
827
828 static int dhd_suspend_resume_helper(struct dhd_info *dhd, int val, int force)
829 {
830         dhd_pub_t *dhdp = &dhd->pub;
831         int ret = 0;
832
833         DHD_OS_WAKE_LOCK(dhdp);
834         /* Set flag when early suspend was called */
835         dhdp->in_suspend = val;
836         if ((force || !dhdp->suspend_disable_flag) &&
837                 dhd_support_sta_mode(dhdp))
838         {
839                 ret = dhd_set_suspend(val, dhdp);
840         }
841
842         DHD_OS_WAKE_UNLOCK(dhdp);
843         return ret;
844 }
845
846 #if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
847 static void dhd_early_suspend(struct early_suspend *h)
848 {
849         struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend);
850         DHD_TRACE_HW4(("%s: enter\n", __FUNCTION__));
851
852         if (dhd)
853                 dhd_suspend_resume_helper(dhd, 1, 0);
854 }
855
856 static void dhd_late_resume(struct early_suspend *h)
857 {
858         struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend);
859         DHD_TRACE_HW4(("%s: enter\n", __FUNCTION__));
860
861         if (dhd)
862                 dhd_suspend_resume_helper(dhd, 0, 0);
863 }
864 #endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */
865
866 /*
867  * Generalized timeout mechanism.  Uses spin sleep with exponential back-off until
868  * the sleep time reaches one jiffy, then switches over to task delay.  Usage:
869  *
870  *      dhd_timeout_start(&tmo, usec);
871  *      while (!dhd_timeout_expired(&tmo))
872  *              if (poll_something())
873  *                      break;
874  *      if (dhd_timeout_expired(&tmo))
875  *              fatal();
876  */
877
878 void
879 dhd_timeout_start(dhd_timeout_t *tmo, uint usec)
880 {
881         tmo->limit = usec;
882         tmo->increment = 0;
883         tmo->elapsed = 0;
884         tmo->tick = jiffies_to_usecs(1);
885 }
886
887 int
888 dhd_timeout_expired(dhd_timeout_t *tmo)
889 {
890         /* Does nothing the first call */
891         if (tmo->increment == 0) {
892                 tmo->increment = 1;
893                 return 0;
894         }
895
896         if (tmo->elapsed >= tmo->limit)
897                 return 1;
898
899         /* Add the delay that's about to take place */
900         tmo->elapsed += tmo->increment;
901
902         if (tmo->increment < tmo->tick) {
903                 OSL_DELAY(tmo->increment);
904                 tmo->increment *= 2;
905                 if (tmo->increment > tmo->tick)
906                         tmo->increment = tmo->tick;
907         } else {
908                 wait_queue_head_t delay_wait;
909                 DECLARE_WAITQUEUE(wait, current);
910                 init_waitqueue_head(&delay_wait);
911                 add_wait_queue(&delay_wait, &wait);
912                 set_current_state(TASK_INTERRUPTIBLE);
913                 schedule_timeout(1);
914                 remove_wait_queue(&delay_wait, &wait);
915                 set_current_state(TASK_RUNNING);
916         }
917
918         return 0;
919 }
920
921 int
922 dhd_net2idx(dhd_info_t *dhd, struct net_device *net)
923 {
924         int i = 0;
925
926         ASSERT(dhd);
927         while (i < DHD_MAX_IFS) {
928                 if (dhd->iflist[i] && (dhd->iflist[i]->net == net))
929                         return i;
930                 i++;
931         }
932
933         return DHD_BAD_IF;
934 }
935
936 struct net_device * dhd_idx2net(void *pub, int ifidx)
937 {
938         struct dhd_pub *dhd_pub = (struct dhd_pub *)pub;
939         struct dhd_info *dhd_info;
940
941         if (!dhd_pub || ifidx < 0 || ifidx >= DHD_MAX_IFS)
942                 return NULL;
943         dhd_info = dhd_pub->info;
944         if (dhd_info && dhd_info->iflist[ifidx])
945                 return dhd_info->iflist[ifidx]->net;
946         return NULL;
947 }
948
949 int
950 dhd_ifname2idx(dhd_info_t *dhd, char *name)
951 {
952         int i = DHD_MAX_IFS;
953
954         ASSERT(dhd);
955
956         if (name == NULL || *name == '\0')
957                 return 0;
958
959         while (--i > 0)
960                 if (dhd->iflist[i] && !strncmp(dhd->iflist[i]->name, name, IFNAMSIZ))
961                                 break;
962
963         DHD_TRACE(("%s: return idx %d for \"%s\"\n", __FUNCTION__, i, name));
964
965         return i;       /* default - the primary interface */
966 }
967
968 char *
969 dhd_ifname(dhd_pub_t *dhdp, int ifidx)
970 {
971         dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
972
973         ASSERT(dhd);
974
975         if (ifidx < 0 || ifidx >= DHD_MAX_IFS) {
976                 DHD_ERROR(("%s: ifidx %d out of range\n", __FUNCTION__, ifidx));
977                 return "<if_bad>";
978         }
979
980         if (dhd->iflist[ifidx] == NULL) {
981                 DHD_ERROR(("%s: null i/f %d\n", __FUNCTION__, ifidx));
982                 return "<if_null>";
983         }
984
985         if (dhd->iflist[ifidx]->net)
986                 return dhd->iflist[ifidx]->net->name;
987
988         return "<if_none>";
989 }
990
991 uint8 *
992 dhd_bssidx2bssid(dhd_pub_t *dhdp, int idx)
993 {
994         int i;
995         dhd_info_t *dhd = (dhd_info_t *)dhdp;
996
997         ASSERT(dhd);
998         for (i = 0; i < DHD_MAX_IFS; i++)
999         if (dhd->iflist[i] && dhd->iflist[i]->bssidx == idx)
1000                 return dhd->iflist[i]->mac_addr;
1001
1002         return NULL;
1003 }
1004
1005
1006 static void
1007 _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx)
1008 {
1009         struct net_device *dev;
1010 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
1011         struct netdev_hw_addr *ha;
1012 #else
1013         struct dev_mc_list *mclist;
1014 #endif
1015         uint32 allmulti, cnt;
1016
1017         wl_ioctl_t ioc;
1018         char *buf, *bufp;
1019         uint buflen;
1020         int ret;
1021
1022         ASSERT(dhd && dhd->iflist[ifidx]);
1023         dev = dhd->iflist[ifidx]->net;
1024         if (!dev)
1025                 return;
1026 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
1027         netif_addr_lock_bh(dev);
1028 #endif
1029 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
1030         cnt = netdev_mc_count(dev);
1031 #else
1032         cnt = dev->mc_count;
1033 #endif /* LINUX_VERSION_CODE */
1034
1035 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
1036         netif_addr_unlock_bh(dev);
1037 #endif
1038
1039         /* Determine initial value of allmulti flag */
1040         allmulti = (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE;
1041
1042         /* Send down the multicast list first. */
1043
1044
1045         buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETHER_ADDR_LEN);
1046         if (!(bufp = buf = MALLOC(dhd->pub.osh, buflen))) {
1047                 DHD_ERROR(("%s: out of memory for mcast_list, cnt %d\n",
1048                            dhd_ifname(&dhd->pub, ifidx), cnt));
1049                 return;
1050         }
1051
1052         strncpy(bufp, "mcast_list", buflen - 1);
1053         bufp[buflen - 1] = '\0';
1054         bufp += strlen("mcast_list") + 1;
1055
1056         cnt = htol32(cnt);
1057         memcpy(bufp, &cnt, sizeof(cnt));
1058         bufp += sizeof(cnt);
1059
1060 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
1061         netif_addr_lock_bh(dev);
1062 #endif
1063 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
1064         netdev_for_each_mc_addr(ha, dev) {
1065                 if (!cnt)
1066                         break;
1067                 memcpy(bufp, ha->addr, ETHER_ADDR_LEN);
1068                 bufp += ETHER_ADDR_LEN;
1069                 cnt--;
1070         }
1071 #else
1072         for (mclist = dev->mc_list; (mclist && (cnt > 0));
1073                 cnt--, mclist = mclist->next) {
1074                 memcpy(bufp, (void *)mclist->dmi_addr, ETHER_ADDR_LEN);
1075                 bufp += ETHER_ADDR_LEN;
1076         }
1077 #endif /* LINUX_VERSION_CODE */
1078
1079 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
1080         netif_addr_unlock_bh(dev);
1081 #endif
1082
1083         memset(&ioc, 0, sizeof(ioc));
1084         ioc.cmd = WLC_SET_VAR;
1085         ioc.buf = buf;
1086         ioc.len = buflen;
1087         ioc.set = TRUE;
1088
1089         ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
1090         if (ret < 0) {
1091                 DHD_ERROR(("%s: set mcast_list failed, cnt %d\n",
1092                         dhd_ifname(&dhd->pub, ifidx), cnt));
1093                 allmulti = cnt ? TRUE : allmulti;
1094         }
1095
1096         MFREE(dhd->pub.osh, buf, buflen);
1097
1098         /* Now send the allmulti setting.  This is based on the setting in the
1099          * net_device flags, but might be modified above to be turned on if we
1100          * were trying to set some addresses and dongle rejected it...
1101          */
1102
1103         buflen = sizeof("allmulti") + sizeof(allmulti);
1104         if (!(buf = MALLOC(dhd->pub.osh, buflen))) {
1105                 DHD_ERROR(("%s: out of memory for allmulti\n", dhd_ifname(&dhd->pub, ifidx)));
1106                 return;
1107         }
1108         allmulti = htol32(allmulti);
1109
1110         if (!bcm_mkiovar("allmulti", (void*)&allmulti, sizeof(allmulti), buf, buflen)) {
1111                 DHD_ERROR(("%s: mkiovar failed for allmulti, datalen %d buflen %u\n",
1112                            dhd_ifname(&dhd->pub, ifidx), (int)sizeof(allmulti), buflen));
1113                 MFREE(dhd->pub.osh, buf, buflen);
1114                 return;
1115         }
1116
1117
1118         memset(&ioc, 0, sizeof(ioc));
1119         ioc.cmd = WLC_SET_VAR;
1120         ioc.buf = buf;
1121         ioc.len = buflen;
1122         ioc.set = TRUE;
1123
1124         ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
1125         if (ret < 0) {
1126                 DHD_ERROR(("%s: set allmulti %d failed\n",
1127                            dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti)));
1128         }
1129
1130         MFREE(dhd->pub.osh, buf, buflen);
1131
1132         /* Finally, pick up the PROMISC flag as well, like the NIC driver does */
1133
1134         allmulti = (dev->flags & IFF_PROMISC) ? TRUE : FALSE;
1135         allmulti = htol32(allmulti);
1136
1137         memset(&ioc, 0, sizeof(ioc));
1138         ioc.cmd = WLC_SET_PROMISC;
1139         ioc.buf = &allmulti;
1140         ioc.len = sizeof(allmulti);
1141         ioc.set = TRUE;
1142
1143         ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
1144         if (ret < 0) {
1145                 DHD_ERROR(("%s: set promisc %d failed\n",
1146                            dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti)));
1147         }
1148 }
1149
1150 int
1151 _dhd_set_mac_address(dhd_info_t *dhd, int ifidx, struct ether_addr *addr)
1152 {
1153         char buf[32];
1154         wl_ioctl_t ioc;
1155         int ret;
1156
1157         if (!bcm_mkiovar("cur_etheraddr", (char*)addr, ETHER_ADDR_LEN, buf, 32)) {
1158                 DHD_ERROR(("%s: mkiovar failed for cur_etheraddr\n", dhd_ifname(&dhd->pub, ifidx)));
1159                 return -1;
1160         }
1161         memset(&ioc, 0, sizeof(ioc));
1162         ioc.cmd = WLC_SET_VAR;
1163         ioc.buf = buf;
1164         ioc.len = 32;
1165         ioc.set = TRUE;
1166
1167         ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
1168         if (ret < 0) {
1169                 DHD_ERROR(("%s: set cur_etheraddr failed\n", dhd_ifname(&dhd->pub, ifidx)));
1170         } else {
1171                 memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETHER_ADDR_LEN);
1172                 memcpy(dhd->pub.mac.octet, addr, ETHER_ADDR_LEN);
1173         }
1174
1175         return ret;
1176 }
1177
1178 #ifdef SOFTAP
1179 extern struct net_device *ap_net_dev;
1180 extern tsk_ctl_t ap_eth_ctl; /* ap netdev heper thread ctl */
1181 #endif
1182
1183 static void
1184 dhd_op_if(dhd_if_t *ifp)
1185 {
1186         dhd_info_t      *dhd;
1187         int ret = 0, err = 0;
1188 #ifdef SOFTAP
1189         unsigned long flags;
1190 #endif
1191
1192         if (!ifp || !ifp->info || !ifp->idx)
1193                 return;
1194         ASSERT(ifp && ifp->info && ifp->idx);   /* Virtual interfaces only */
1195         dhd = ifp->info;
1196
1197         DHD_TRACE(("%s: idx %d, state %d\n", __FUNCTION__, ifp->idx, ifp->state));
1198
1199 #ifdef WL_CFG80211
1200         if (wl_cfg80211_is_progress_ifchange())
1201                         return;
1202
1203 #endif
1204         switch (ifp->state) {
1205         case DHD_IF_ADD:
1206                 /*
1207                  * Delete the existing interface before overwriting it
1208                  * in case we missed the WLC_E_IF_DEL event.
1209                  */
1210                 if (ifp->net != NULL) {
1211                         DHD_ERROR(("%s: ERROR: netdev:%s already exists, try free & unregister \n",
1212                          __FUNCTION__, ifp->net->name));
1213                         netif_stop_queue(ifp->net);
1214                         unregister_netdev(ifp->net);
1215                         free_netdev(ifp->net);
1216                 }
1217                 /* Allocate etherdev, including space for private structure */
1218                 if (!(ifp->net = alloc_etherdev(sizeof(dhd)))) {
1219                         DHD_ERROR(("%s: OOM - alloc_etherdev(%d)\n", __FUNCTION__, sizeof(dhd)));
1220                         ret = -ENOMEM;
1221                 }
1222                 if (ret == 0) {
1223                         strncpy(ifp->net->name, ifp->name, IFNAMSIZ);
1224                         ifp->net->name[IFNAMSIZ - 1] = '\0';
1225                         memcpy(netdev_priv(ifp->net), &dhd, sizeof(dhd));
1226 #ifdef WL_CFG80211
1227                         if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)
1228                                 if (!wl_cfg80211_notify_ifadd(ifp->net, ifp->idx, ifp->bssidx,
1229                                         (void*)dhd_net_attach)) {
1230                                         ifp->state = DHD_IF_NONE;
1231                                         ifp->event2cfg80211 = TRUE;
1232                                         return;
1233                                 }
1234 #endif
1235                         if ((err = dhd_net_attach(&dhd->pub, ifp->idx)) != 0) {
1236                                 DHD_ERROR(("%s: dhd_net_attach failed, err %d\n",
1237                                         __FUNCTION__, err));
1238                                 ret = -EOPNOTSUPP;
1239                         } else {
1240 #if defined(SOFTAP)
1241                 if (ap_fw_loaded && !(dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) {
1242                                  /* semaphore that the soft AP CODE waits on */
1243                                 flags = dhd_os_spin_lock(&dhd->pub);
1244
1245                                 /* save ptr to wl0.1 netdev for use in wl_iw.c  */
1246                                 ap_net_dev = ifp->net;
1247                                  /* signal to the SOFTAP 'sleeper' thread, wl0.1 is ready */
1248                                 up(&ap_eth_ctl.sema);
1249                                 dhd_os_spin_unlock(&dhd->pub, flags);
1250                 }
1251 #endif
1252                                 DHD_TRACE(("\n ==== pid:%x, net_device for if:%s created ===\n\n",
1253                                         current->pid, ifp->net->name));
1254                                 ifp->state = DHD_IF_NONE;
1255                         }
1256                 }
1257                 break;
1258         case DHD_IF_DEL:
1259                 /* Make sure that we don't enter again here if .. */
1260                 /* dhd_op_if is called again from some other context */
1261                 ifp->state = DHD_IF_DELETING;
1262                 if (ifp->net != NULL) {
1263                         DHD_TRACE(("\n%s: got 'DHD_IF_DEL' state\n", __FUNCTION__));
1264                         netif_stop_queue(ifp->net);
1265 #ifdef WL_CFG80211
1266                         if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) {
1267                                 wl_cfg80211_ifdel_ops(ifp->net);
1268                         }
1269 #endif
1270                         unregister_netdev(ifp->net);
1271                         ret = DHD_DEL_IF;       /* Make sure the free_netdev() is called */
1272 #ifdef WL_CFG80211
1273                         if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) {
1274                                 wl_cfg80211_notify_ifdel();
1275                         }
1276 #endif
1277                 }
1278                 break;
1279         case DHD_IF_DELETING:
1280                 break;
1281         default:
1282                 DHD_ERROR(("%s: bad op %d\n", __FUNCTION__, ifp->state));
1283                 ASSERT(!ifp->state);
1284                 break;
1285         }
1286
1287         if (ret < 0) {
1288                 ifp->set_multicast = FALSE;
1289                 if (ifp->net) {
1290                         free_netdev(ifp->net);
1291                         ifp->net = NULL;
1292                 }
1293                 dhd->iflist[ifp->idx] = NULL;
1294 #ifdef SOFTAP
1295                 flags = dhd_os_spin_lock(&dhd->pub);
1296                 if (ifp->net == ap_net_dev)
1297                         ap_net_dev = NULL;   /*  NULL  SOFTAP global wl0.1 as well */
1298                 dhd_os_spin_unlock(&dhd->pub, flags);
1299 #endif /*  SOFTAP */
1300                 MFREE(dhd->pub.osh, ifp, sizeof(*ifp));
1301         }
1302 }
1303
1304 #ifdef DHDTCPACK_SUPPRESS
1305 uint dhd_use_tcpack_suppress = TRUE;
1306 module_param(dhd_use_tcpack_suppress, uint, FALSE);
1307 extern bool dhd_tcpack_suppress(dhd_pub_t *dhdp, void *pkt);
1308 #endif /* DHDTCPACK_SUPPRESS */
1309
1310 static int
1311 _dhd_sysioc_thread(void *data)
1312 {
1313         tsk_ctl_t *tsk = (tsk_ctl_t *)data;
1314         dhd_info_t *dhd = (dhd_info_t *)tsk->parent;
1315         struct ipv6_addr *iter, *next;
1316         int i, ret;
1317 #ifdef SOFTAP
1318         bool in_ap = FALSE;
1319         unsigned long flags;
1320 #endif
1321
1322         while (down_interruptible(&tsk->sema) == 0) {
1323
1324                 SMP_RD_BARRIER_DEPENDS();
1325                 if (tsk->terminated) {
1326                         break;
1327                 }
1328
1329                 dhd_net_if_lock_local(dhd);
1330                 DHD_OS_WAKE_LOCK(&dhd->pub);
1331
1332                 for (i = 0; i < DHD_MAX_IFS; i++) {
1333                         if (dhd->iflist[i]) {
1334                                 DHD_TRACE(("%s: interface %d\n", __FUNCTION__, i));
1335 #ifdef SOFTAP
1336                                 flags = dhd_os_spin_lock(&dhd->pub);
1337                                 in_ap = (ap_net_dev != NULL);
1338                                 dhd_os_spin_unlock(&dhd->pub, flags);
1339 #endif /* SOFTAP */
1340                                 if (dhd->iflist[i] && dhd->iflist[i]->state)
1341                                         dhd_op_if(dhd->iflist[i]);
1342
1343                                 if (dhd->iflist[i] == NULL) {
1344                                         DHD_TRACE(("\n\n %s: interface %d just been removed,"
1345                                                 "!\n\n", __FUNCTION__, i));
1346                                         continue;
1347                                 }
1348 #ifdef SOFTAP
1349                                 if (in_ap && dhd->set_macaddress == i+1)  {
1350                                         DHD_TRACE(("attempt to set MAC for %s in AP Mode,"
1351                                                 "blocked. \n", dhd->iflist[i]->net->name));
1352                                         dhd->set_macaddress = 0;
1353                                         continue;
1354                                 }
1355
1356                                 if (in_ap && dhd->iflist[i]->set_multicast)  {
1357                                         DHD_TRACE(("attempt to set MULTICAST list for %s"
1358                                          "in AP Mode, blocked. \n", dhd->iflist[i]->net->name));
1359                                         dhd->iflist[i]->set_multicast = FALSE;
1360                                         continue;
1361                                 }
1362 #endif /* SOFTAP */
1363                                 if (dhd->pub.up == 0)
1364                                         continue;
1365                                 if (dhd->iflist[i]->set_multicast) {
1366                                         dhd->iflist[i]->set_multicast = FALSE;
1367                                         _dhd_set_multicast_list(dhd, i);
1368
1369                                 }
1370                                 list_for_each_entry_safe(iter, next,
1371                                         &dhd->iflist[i]->ipv6_list, list) {
1372                                         spin_lock_bh(&dhd->iflist[i]->ipv6_lock);
1373                                         list_del(&iter->list);
1374                                         spin_unlock_bh(&dhd->iflist[i]->ipv6_lock);
1375                                         if (iter->ipv6_oper == DHD_IPV6_ADDR_ADD) {
1376                                                 ret = dhd_ndo_enable(&dhd->pub, TRUE);
1377                                                 if (ret < 0) {
1378                                                         DHD_ERROR(("%s: Enabling NDO Failed %d\n",
1379                                                                 __FUNCTION__, ret));
1380                                                         continue;
1381                                                 }
1382                                                 ret = dhd_ndo_add_ip(&dhd->pub,
1383                                                         (char*)&iter->ipv6_addr[0], i);
1384                                                 if (ret < 0) {
1385                                                         DHD_ERROR(("%s: Adding host ip fail %d\n",
1386                                                                 __FUNCTION__, ret));
1387                                                         continue;
1388                                                 }
1389                                         } else {
1390                                                 ret = dhd_ndo_remove_ip(&dhd->pub, i);
1391                                                 if (ret < 0) {
1392                                                         DHD_ERROR(("%s: Removing host ip fail %d\n",
1393                                                                 __FUNCTION__, ret));
1394                                                         continue;
1395                                                 }
1396                                         }
1397                                         NATIVE_MFREE(dhd->pub.osh, iter, sizeof(struct ipv6_addr));
1398                                 }
1399                                 if (dhd->set_macaddress == i+1) {
1400                                         dhd->set_macaddress = 0;
1401                                         if (_dhd_set_mac_address(dhd, i, &dhd->macvalue) == 0) {
1402                                                 DHD_INFO(("%s: MACID is overwritten\n", __FUNCTION__));
1403                                         } else {
1404                                                 DHD_ERROR(("%s: _dhd_set_mac_address() failed\n",
1405                                                         __FUNCTION__));
1406                                         }
1407                                 }
1408                         }
1409                 }
1410
1411                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
1412                 dhd_net_if_unlock_local(dhd);
1413         }
1414         DHD_TRACE(("%s: stopped\n", __FUNCTION__));
1415         complete_and_exit(&tsk->completed, 0);
1416 }
1417
1418 static int
1419 dhd_set_mac_address(struct net_device *dev, void *addr)
1420 {
1421         int ret = 0;
1422
1423         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
1424         struct sockaddr *sa = (struct sockaddr *)addr;
1425         int ifidx;
1426
1427         ifidx = dhd_net2idx(dhd, dev);
1428         if (ifidx == DHD_BAD_IF)
1429                 return -1;
1430
1431         ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0);
1432         memcpy(&dhd->macvalue, sa->sa_data, ETHER_ADDR_LEN);
1433         dhd->set_macaddress = ifidx+1;
1434         up(&dhd->thr_sysioc_ctl.sema);
1435
1436         return ret;
1437 }
1438
1439 static void
1440 dhd_set_multicast_list(struct net_device *dev)
1441 {
1442         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
1443         int ifidx;
1444
1445         ifidx = dhd_net2idx(dhd, dev);
1446         if (ifidx == DHD_BAD_IF)
1447                 return;
1448
1449         ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0);
1450         dhd->iflist[ifidx]->set_multicast = TRUE;
1451         up(&dhd->thr_sysioc_ctl.sema);
1452 }
1453
1454 #ifdef PROP_TXSTATUS
1455 int
1456 dhd_os_wlfc_block(dhd_pub_t *pub)
1457 {
1458         dhd_info_t *di = (dhd_info_t *)(pub->info);
1459         ASSERT(di != NULL);
1460         spin_lock_bh(&di->wlfc_spinlock);
1461         return 1;
1462 }
1463
1464 int
1465 dhd_os_wlfc_unblock(dhd_pub_t *pub)
1466 {
1467         dhd_info_t *di = (dhd_info_t *)(pub->info);
1468
1469         ASSERT(di != NULL);
1470         spin_unlock_bh(&di->wlfc_spinlock);
1471         return 1;
1472 }
1473
1474 const uint8 wme_fifo2ac[] = { 0, 1, 2, 3, 1, 1 };
1475 uint8 prio2fifo[8] = { 1, 0, 0, 1, 2, 2, 3, 3 };
1476 #define WME_PRIO2AC(prio)       wme_fifo2ac[prio2fifo[(prio)]]
1477
1478 #endif /* PROP_TXSTATUS */
1479 int
1480 dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf)
1481 {
1482         int ret = BCME_OK;
1483         dhd_info_t *dhd = (dhd_info_t *)(dhdp->info);
1484         struct ether_header *eh = NULL;
1485
1486         /* Reject if down */
1487         if (!dhdp->up || (dhdp->busstate == DHD_BUS_DOWN)) {
1488                 /* free the packet here since the caller won't */
1489                 PKTFREE(dhdp->osh, pktbuf, TRUE);
1490                 return -ENODEV;
1491         }
1492
1493         /* Update multicast statistic */
1494         if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_HDR_LEN) {
1495                 uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf);
1496                 eh = (struct ether_header *)pktdata;
1497
1498                 if (ETHER_ISMULTI(eh->ether_dhost))
1499                         dhdp->tx_multicast++;
1500                 if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X)
1501                         atomic_inc(&dhd->pend_8021x_cnt);
1502         } else {
1503                 PKTFREE(dhd->pub.osh, pktbuf, TRUE);
1504                 return BCME_ERROR;
1505         }
1506
1507         /* Look into the packet and update the packet priority */
1508 #ifndef PKTPRIO_OVERRIDE
1509         if (PKTPRIO(pktbuf) == 0)
1510 #endif 
1511                 pktsetprio(pktbuf, FALSE);
1512
1513 #ifdef PROP_TXSTATUS
1514         if (dhdp->wlfc_state) {
1515                 /* store the interface ID */
1516                 DHD_PKTTAG_SETIF(PKTTAG(pktbuf), ifidx);
1517
1518                 /* store destination MAC in the tag as well */
1519                 DHD_PKTTAG_SETDSTN(PKTTAG(pktbuf), eh->ether_dhost);
1520
1521                 /* decide which FIFO this packet belongs to */
1522                 if (ETHER_ISMULTI(eh->ether_dhost))
1523                         /* one additional queue index (highest AC + 1) is used for bc/mc queue */
1524                         DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), AC_COUNT);
1525                 else
1526                         DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), WME_PRIO2AC(PKTPRIO(pktbuf)));
1527         } else
1528 #endif /* PROP_TXSTATUS */
1529         /* If the protocol uses a data header, apply it */
1530         dhd_prot_hdrpush(dhdp, ifidx, pktbuf);
1531
1532         /* Use bus module to send data frame */
1533 #ifdef WLMEDIA_HTSF
1534         dhd_htsf_addtxts(dhdp, pktbuf);
1535 #endif
1536 #ifdef DHDTCPACK_SUPPRESS
1537         if (dhd_use_tcpack_suppress && dhd_tcpack_suppress(dhdp, pktbuf))
1538                 ret = BCME_OK;
1539         else
1540 #endif /* DHDTCPACK_SUPPRESS */
1541 #ifdef PROP_TXSTATUS
1542         {
1543         dhd_os_wlfc_block(dhdp);
1544         if (dhdp->wlfc_state && ((athost_wl_status_info_t*)dhdp->wlfc_state)->proptxstatus_mode
1545                 != WLFC_FCMODE_NONE) {
1546                 dhd_wlfc_commit_packets(dhdp->wlfc_state,  (f_commitpkt_t)dhd_bus_txdata,
1547                         dhdp->bus, pktbuf);
1548                 if (((athost_wl_status_info_t*)dhdp->wlfc_state)->toggle_host_if) {
1549                         ((athost_wl_status_info_t*)dhdp->wlfc_state)->toggle_host_if = 0;
1550                 }
1551                 dhd_os_wlfc_unblock(dhdp);
1552         }
1553         else {
1554                 dhd_os_wlfc_unblock(dhdp);
1555                 /* non-proptxstatus way */
1556                 ret = dhd_bus_txdata(dhdp->bus, pktbuf);
1557         }
1558         }
1559 #else
1560         ret = dhd_bus_txdata(dhdp->bus, pktbuf);
1561 #endif /* PROP_TXSTATUS */
1562
1563         return ret;
1564 }
1565
1566 int
1567 dhd_start_xmit(struct sk_buff *skb, struct net_device *net)
1568 {
1569         int ret;
1570         uint datalen;
1571         void *pktbuf;
1572         dhd_info_t *dhd  =  *(dhd_info_t **)netdev_priv(net);
1573         dhd_if_t *ifp = NULL;
1574         int ifidx;
1575 #ifdef WLMEDIA_HTSF
1576         uint8 htsfdlystat_sz = dhd->pub.htsfdlystat_sz;
1577 #else
1578         uint8 htsfdlystat_sz = 0;
1579 #endif
1580
1581         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1582
1583         DHD_OS_WAKE_LOCK(&dhd->pub);
1584
1585         /* Reject if down */
1586         if (dhd->pub.busstate == DHD_BUS_DOWN || dhd->pub.hang_was_sent) {
1587                 DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d \n",
1588                         __FUNCTION__, dhd->pub.up, dhd->pub.busstate));
1589                 netif_stop_queue(net);
1590                 /* Send Event when bus down detected during data session */
1591                 if (dhd->pub.up) {
1592                         DHD_ERROR(("%s: Event HANG sent up\n", __FUNCTION__));
1593                         net_os_send_hang_message(net);
1594                 }
1595                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
1596 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20))
1597                 return -ENODEV;
1598 #else
1599                 return NETDEV_TX_BUSY;
1600 #endif
1601         }
1602
1603         ifidx = dhd_net2idx(dhd, net);
1604         if (ifidx == DHD_BAD_IF) {
1605                 DHD_ERROR(("%s: bad ifidx %d\n", __FUNCTION__, ifidx));
1606                 netif_stop_queue(net);
1607                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
1608 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20))
1609                 return -ENODEV;
1610 #else
1611                 return NETDEV_TX_BUSY;
1612 #endif
1613         }
1614
1615         ifp = dhd->iflist[ifidx];
1616         datalen  = PKTLEN(dhdp->osh, skb);
1617
1618         /* Make sure there's enough room for any header */
1619
1620         if (skb_headroom(skb) < dhd->pub.hdrlen + htsfdlystat_sz) {
1621                 struct sk_buff *skb2;
1622
1623                 DHD_INFO(("%s: insufficient headroom\n",
1624                           dhd_ifname(&dhd->pub, ifidx)));
1625                 dhd->pub.tx_realloc++;
1626
1627                 skb2 = skb_realloc_headroom(skb, dhd->pub.hdrlen + htsfdlystat_sz);
1628
1629                 dev_kfree_skb(skb);
1630                 if ((skb = skb2) == NULL) {
1631                         DHD_ERROR(("%s: skb_realloc_headroom failed\n",
1632                                    dhd_ifname(&dhd->pub, ifidx)));
1633                         ret = -ENOMEM;
1634                         goto done;
1635                 }
1636         }
1637
1638         /* Convert to packet */
1639         if (!(pktbuf = PKTFRMNATIVE(dhd->pub.osh, skb))) {
1640                 DHD_ERROR(("%s: PKTFRMNATIVE failed\n",
1641                            dhd_ifname(&dhd->pub, ifidx)));
1642                 dev_kfree_skb_any(skb);
1643                 ret = -ENOMEM;
1644                 goto done;
1645         }
1646 #ifdef WLMEDIA_HTSF
1647         if (htsfdlystat_sz && PKTLEN(dhd->pub.osh, pktbuf) >= ETHER_ADDR_LEN) {
1648                 uint8 *pktdata = (uint8 *)PKTDATA(dhd->pub.osh, pktbuf);
1649                 struct ether_header *eh = (struct ether_header *)pktdata;
1650
1651                 if (!ETHER_ISMULTI(eh->ether_dhost) &&
1652                         (ntoh16(eh->ether_type) == ETHER_TYPE_IP)) {
1653                         eh->ether_type = hton16(ETHER_TYPE_BRCM_PKTDLYSTATS);
1654                 }
1655         }
1656 #endif
1657
1658         ret = dhd_sendpkt(&dhd->pub, ifidx, pktbuf);
1659
1660 done:
1661         if (ret) {
1662                 ifp->stats.tx_dropped++;
1663         }
1664         else {
1665                 dhd->pub.tx_packets++;
1666                 ifp->stats.tx_packets++;
1667                 ifp->stats.tx_bytes += datalen;
1668         }
1669
1670         DHD_OS_WAKE_UNLOCK(&dhd->pub);
1671
1672         /* Return ok: we always eat the packet */
1673 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20))
1674         return 0;
1675 #else
1676         return NETDEV_TX_OK;
1677 #endif
1678 }
1679
1680 void
1681 dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool state)
1682 {
1683         struct net_device *net;
1684         dhd_info_t *dhd = dhdp->info;
1685         int i;
1686
1687         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1688
1689         ASSERT(dhd);
1690
1691         if (ifidx == ALL_INTERFACES) {
1692                 /* Flow control on all active interfaces */
1693                 dhdp->txoff = state;
1694                 for (i = 0; i < DHD_MAX_IFS; i++) {
1695                         if (dhd->iflist[i]) {
1696                                 net = dhd->iflist[i]->net;
1697                                 if (state == ON)
1698                                         netif_stop_queue(net);
1699                                 else
1700                                         netif_wake_queue(net);
1701                         }
1702                 }
1703         }
1704         else {
1705                 if (dhd->iflist[ifidx]) {
1706                         net = dhd->iflist[ifidx]->net;
1707                         if (state == ON)
1708                                 netif_stop_queue(net);
1709                         else
1710                                 netif_wake_queue(net);
1711                 }
1712         }
1713 }
1714
1715 #ifdef DHD_RX_DUMP
1716 typedef struct {
1717         uint16 type;
1718         const char *str;
1719 } PKTTYPE_INFO;
1720
1721 static const PKTTYPE_INFO packet_type_info[] =
1722 {
1723         { ETHER_TYPE_IP, "IP" },
1724         { ETHER_TYPE_ARP, "ARP" },
1725         { ETHER_TYPE_BRCM, "BRCM" },
1726         { ETHER_TYPE_802_1X, "802.1X" },
1727         { ETHER_TYPE_WAI, "WAPI" },
1728         { 0, ""}
1729 };
1730
1731 static const char *_get_packet_type_str(uint16 type)
1732 {
1733         int i;
1734         int n = sizeof(packet_type_info)/sizeof(packet_type_info[1]) - 1;
1735
1736         for (i = 0; i < n; i++) {
1737                 if (packet_type_info[i].type == type)
1738                         return packet_type_info[i].str;
1739         }
1740
1741         return packet_type_info[n].str;
1742 }
1743 #endif /* DHD_RX_DUMP */
1744
1745 void
1746 dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
1747 {
1748         dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
1749         struct sk_buff *skb;
1750         uchar *eth;
1751         uint len;
1752         void *data, *pnext = NULL;
1753         int i;
1754         dhd_if_t *ifp;
1755         wl_event_msg_t event;
1756         int tout_rx = 0;
1757         int tout_ctrl = 0;
1758 #if defined(DHDTHREAD) && defined(RXFRAME_THREAD)
1759         void *skbhead = NULL;
1760         void *skbprev = NULL;
1761 #endif /* defined(DHDTHREAD) && defined(RXFRAME_THREAD) */
1762 #ifdef DHD_RX_DUMP
1763 #ifdef DHD_RX_FULL_DUMP
1764         int k;
1765 #endif /* DHD_RX_FULL_DUMP */
1766         char *dump_data;
1767         uint16 protocol;
1768 #endif /* DHD_RX_DUMP */
1769
1770         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1771
1772         for (i = 0; pktbuf && i < numpkt; i++, pktbuf = pnext) {
1773 #ifdef WLBTAMP
1774                 struct ether_header *eh;
1775                 struct dot11_llc_snap_header *lsh;
1776 #endif
1777
1778                 pnext = PKTNEXT(dhdp->osh, pktbuf);
1779                 PKTSETNEXT(wl->sh.osh, pktbuf, NULL);
1780
1781                 ifp = dhd->iflist[ifidx];
1782                 if (ifp == NULL) {
1783                         DHD_ERROR(("%s: ifp is NULL. drop packet\n",
1784                                 __FUNCTION__));
1785                         PKTFREE(dhdp->osh, pktbuf, TRUE);
1786                         continue;
1787                 }
1788 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
1789                 /* Dropping packets before registering net device to avoid kernel panic */
1790 #ifndef PROP_TXSTATUS_VSDB
1791                 if (!ifp->net || ifp->net->reg_state != NETREG_REGISTERED)
1792 #else
1793                 if (!ifp->net || ifp->net->reg_state != NETREG_REGISTERED || !dhd->pub.up)
1794 #endif /* PROP_TXSTATUS_VSDB */
1795                 {
1796                         DHD_ERROR(("%s: net device is NOT registered yet. drop packet\n",
1797                         __FUNCTION__));
1798                         PKTFREE(dhdp->osh, pktbuf, TRUE);
1799                         continue;
1800                 }
1801 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */
1802
1803 #ifdef WLBTAMP
1804                 eh = (struct ether_header *)PKTDATA(wl->sh.osh, pktbuf);
1805                 lsh = (struct dot11_llc_snap_header *)&eh[1];
1806
1807                 if ((ntoh16(eh->ether_type) < ETHER_TYPE_MIN) &&
1808                     (PKTLEN(wl->sh.osh, pktbuf) >= RFC1042_HDR_LEN) &&
1809                     bcmp(lsh, BT_SIG_SNAP_MPROT, DOT11_LLC_SNAP_HDR_LEN - 2) == 0 &&
1810                     lsh->type == HTON16(BTA_PROT_L2CAP)) {
1811                         amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)
1812                                 ((uint8 *)eh + RFC1042_HDR_LEN);
1813                         ACL_data = NULL;
1814                 }
1815 #endif /* WLBTAMP */
1816
1817 #ifdef PROP_TXSTATUS
1818                 if (dhdp->wlfc_state && PKTLEN(wl->sh.osh, pktbuf) == 0) {
1819                         /* WLFC may send header only packet when
1820                         there is an urgent message but no packet to
1821                         piggy-back on
1822                         */
1823                         ((athost_wl_status_info_t*)dhdp->wlfc_state)->stats.wlfc_header_only_pkt++;
1824                         PKTFREE(dhdp->osh, pktbuf, TRUE);
1825                         continue;
1826                 }
1827 #endif
1828
1829                 skb = PKTTONATIVE(dhdp->osh, pktbuf);
1830
1831                 /* Get the protocol, maintain skb around eth_type_trans()
1832                  * The main reason for this hack is for the limitation of
1833                  * Linux 2.4 where 'eth_type_trans' uses the 'net->hard_header_len'
1834                  * to perform skb_pull inside vs ETH_HLEN. Since to avoid
1835                  * coping of the packet coming from the network stack to add
1836                  * BDC, Hardware header etc, during network interface registration
1837                  * we set the 'net->hard_header_len' to ETH_HLEN + extra space required
1838                  * for BDC, Hardware header etc. and not just the ETH_HLEN
1839                  */
1840                 eth = skb->data;
1841                 len = skb->len;
1842
1843 #ifdef DHD_RX_DUMP
1844                 dump_data = skb->data;
1845                 protocol = (dump_data[12] << 8) | dump_data[13];
1846                 DHD_ERROR(("RX DUMP - %s\n", _get_packet_type_str(protocol)));
1847
1848 #ifdef DHD_RX_FULL_DUMP
1849                 if (protocol != ETHER_TYPE_BRCM) {
1850                         for (k = 0; k < skb->len; k++) {
1851                                 DHD_ERROR(("%02X ", dump_data[k]));
1852                                 if ((k & 15) == 15)
1853                                         DHD_ERROR(("\n"));
1854                         }
1855                         DHD_ERROR(("\n"));
1856                 }
1857 #endif /* DHD_RX_FULL_DUMP */
1858
1859                 if (protocol != ETHER_TYPE_BRCM) {
1860                         if (dump_data[0] == 0xFF) {
1861                                 DHD_ERROR(("%s: BROADCAST\n", __FUNCTION__));
1862
1863                                 if ((dump_data[12] == 8) &&
1864                                         (dump_data[13] == 6)) {
1865                                         DHD_ERROR(("%s: ARP %d\n",
1866                                                 __FUNCTION__, dump_data[0x15]));
1867                                 }
1868                         } else if (dump_data[0] & 1) {
1869                                 DHD_ERROR(("%s: MULTICAST: " MACDBG "\n",
1870                                         __FUNCTION__, MAC2STRDBG(dump_data)));
1871                         }
1872
1873                         if (protocol == ETHER_TYPE_802_1X) {
1874                                 DHD_ERROR(("ETHER_TYPE_802_1X: "
1875                                         "ver %d, type %d, replay %d\n",
1876                                         dump_data[14], dump_data[15],
1877                                         dump_data[30]));
1878                         }
1879                 }
1880
1881 #endif /* DHD_RX_DUMP */
1882
1883                 ifp = dhd->iflist[ifidx];
1884                 if (ifp == NULL)
1885                         ifp = dhd->iflist[0];
1886
1887                 ASSERT(ifp);
1888                 skb->dev = ifp->net;
1889                 skb->protocol = eth_type_trans(skb, skb->dev);
1890
1891                 if (skb->pkt_type == PACKET_MULTICAST) {
1892                         dhd->pub.rx_multicast++;
1893                 }
1894
1895                 skb->data = eth;
1896                 skb->len = len;
1897
1898 #ifdef WLMEDIA_HTSF
1899                 dhd_htsf_addrxts(dhdp, pktbuf);
1900 #endif
1901                 /* Strip header, count, deliver upward */
1902                 skb_pull(skb, ETH_HLEN);
1903
1904                 /* Process special event packets and then discard them */
1905                 memset(&event, 0, sizeof(event));
1906                 if (ntoh16(skb->protocol) == ETHER_TYPE_BRCM) {
1907                         dhd_wl_host_event(dhd, &ifidx,
1908 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
1909                         skb_mac_header(skb),
1910 #else
1911                         skb->mac.raw,
1912 #endif
1913                         &event,
1914                         &data);
1915
1916                         wl_event_to_host_order(&event);
1917                         if (!tout_ctrl)
1918                                 tout_ctrl = DHD_PACKET_TIMEOUT_MS;
1919 #ifdef WLBTAMP
1920                         if (event.event_type == WLC_E_BTA_HCI_EVENT) {
1921                                 dhd_bta_doevt(dhdp, data, event.datalen);
1922                         }
1923 #endif /* WLBTAMP */
1924
1925 #if defined(PNO_SUPPORT)
1926                         if (event.event_type == WLC_E_PFN_NET_FOUND) {
1927                                 /* enforce custom wake lock to garantee that Kernel not suspended */
1928                                 tout_ctrl = CUSTOM_PNO_EVENT_LOCK_xTIME * DHD_PACKET_TIMEOUT_MS;
1929                         }
1930 #endif /* PNO_SUPPORT */
1931
1932 #ifdef DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT
1933                         PKTFREE(dhdp->osh, pktbuf, TRUE);
1934                         continue;
1935 #endif
1936                 } else {
1937                         tout_rx = DHD_PACKET_TIMEOUT_MS;
1938                 }
1939
1940                 ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]);
1941                 if (dhd->iflist[ifidx] && !dhd->iflist[ifidx]->state)
1942                         ifp = dhd->iflist[ifidx];
1943
1944                 if (ifp->net)
1945                         ifp->net->last_rx = jiffies;
1946
1947                 dhdp->dstats.rx_bytes += skb->len;
1948                 dhdp->rx_packets++; /* Local count */
1949                 ifp->stats.rx_bytes += skb->len;
1950                 ifp->stats.rx_packets++;
1951
1952                 if (in_interrupt()) {
1953                         netif_rx(skb);
1954                 } else {
1955                         /* If the receive is not processed inside an ISR,
1956                          * the softirqd must be woken explicitly to service
1957                          * the NET_RX_SOFTIRQ.  In 2.6 kernels, this is handled
1958                          * by netif_rx_ni(), but in earlier kernels, we need
1959                          * to do it manually.
1960                          */
1961 #if defined(DHDTHREAD) && defined(RXFRAME_THREAD)
1962                         if (!skbhead)
1963                                 skbhead = skb;
1964                         else
1965                                 PKTSETNEXT(wl->sh.osh, skbprev, skb);
1966                         skbprev = skb;
1967 #else
1968 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
1969                         netif_rx_ni(skb);
1970 #else
1971                         ulong flags;
1972                         netif_rx(skb);
1973                         local_irq_save(flags);
1974                         RAISE_RX_SOFTIRQ();
1975                         local_irq_restore(flags);
1976 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */
1977 #endif /* defined(DHDTHREAD) && defined(RXFRAME_THREAD) */
1978                 }
1979         }
1980 #if defined(DHDTHREAD) && defined(RXFRAME_THREAD)
1981         if (skbhead)
1982                 dhd_sched_rxf(dhdp, skbhead);
1983 #endif
1984         DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(dhdp, tout_rx);
1985         DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhdp, tout_ctrl);
1986 }
1987
1988 void
1989 dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx)
1990 {
1991         /* Linux version has nothing to do */
1992         return;
1993 }
1994
1995 void
1996 dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success)
1997 {
1998         dhd_info_t *dhd = (dhd_info_t *)(dhdp->info);
1999         struct ether_header *eh;
2000         uint16 type;
2001 #ifdef WLBTAMP
2002         uint len;
2003 #endif
2004
2005         dhd_prot_hdrpull(dhdp, NULL, txp, NULL, NULL);
2006
2007         eh = (struct ether_header *)PKTDATA(dhdp->osh, txp);
2008         type  = ntoh16(eh->ether_type);
2009
2010         if (type == ETHER_TYPE_802_1X)
2011                 atomic_dec(&dhd->pend_8021x_cnt);
2012
2013 #ifdef WLBTAMP
2014         /* Crack open the packet and check to see if it is BT HCI ACL data packet.
2015          * If yes generate packet completion event.
2016          */
2017         len = PKTLEN(dhdp->osh, txp);
2018
2019         /* Generate ACL data tx completion event locally to avoid SDIO bus transaction */
2020         if ((type < ETHER_TYPE_MIN) && (len >= RFC1042_HDR_LEN)) {
2021                 struct dot11_llc_snap_header *lsh = (struct dot11_llc_snap_header *)&eh[1];
2022
2023                 if (bcmp(lsh, BT_SIG_SNAP_MPROT, DOT11_LLC_SNAP_HDR_LEN - 2) == 0 &&
2024                     ntoh16(lsh->type) == BTA_PROT_L2CAP) {
2025
2026                         dhd_bta_tx_hcidata_complete(dhdp, txp, success);
2027                 }
2028         }
2029 #endif /* WLBTAMP */
2030 }
2031
2032 static struct net_device_stats *
2033 dhd_get_stats(struct net_device *net)
2034 {
2035         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
2036         dhd_if_t *ifp;
2037         int ifidx;
2038
2039         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2040
2041         ifidx = dhd_net2idx(dhd, net);
2042         if (ifidx == DHD_BAD_IF) {
2043                 DHD_ERROR(("%s: BAD_IF\n", __FUNCTION__));
2044                 return NULL;
2045         }
2046
2047         ifp = dhd->iflist[ifidx];
2048         ASSERT(dhd && ifp);
2049
2050         if (dhd->pub.up) {
2051                 /* Use the protocol to get dongle stats */
2052                 dhd_prot_dstats(&dhd->pub);
2053         }
2054
2055         /* Copy dongle stats to net device stats */
2056         ifp->stats.rx_packets = dhd->pub.dstats.rx_packets;
2057         ifp->stats.tx_packets = dhd->pub.dstats.tx_packets;
2058         ifp->stats.rx_bytes = dhd->pub.dstats.rx_bytes;
2059         ifp->stats.tx_bytes = dhd->pub.dstats.tx_bytes;
2060         ifp->stats.rx_errors = dhd->pub.dstats.rx_errors;
2061         ifp->stats.tx_errors = dhd->pub.dstats.tx_errors;
2062         ifp->stats.rx_dropped = dhd->pub.dstats.rx_dropped;
2063         ifp->stats.tx_dropped = dhd->pub.dstats.tx_dropped;
2064         ifp->stats.multicast = dhd->pub.dstats.multicast;
2065
2066         return &ifp->stats;
2067 }
2068
2069 #ifdef DHDTHREAD
2070 static int
2071 dhd_watchdog_thread(void *data)
2072 {
2073         tsk_ctl_t *tsk = (tsk_ctl_t *)data;
2074         dhd_info_t *dhd = (dhd_info_t *)tsk->parent;
2075         /* This thread doesn't need any user-level access,
2076          * so get rid of all our resources
2077          */
2078         if (dhd_watchdog_prio > 0) {
2079                 struct sched_param param;
2080                 param.sched_priority = (dhd_watchdog_prio < MAX_RT_PRIO)?
2081                         dhd_watchdog_prio:(MAX_RT_PRIO-1);
2082                 setScheduler(current, SCHED_FIFO, &param);
2083         }
2084
2085         while (1)
2086                 if (down_interruptible (&tsk->sema) == 0) {
2087                         unsigned long flags;
2088                         unsigned long jiffies_at_start = jiffies;
2089                         unsigned long time_lapse;
2090
2091                         SMP_RD_BARRIER_DEPENDS();
2092                         if (tsk->terminated) {
2093                                 break;
2094                         }
2095
2096                         dhd_os_sdlock(&dhd->pub);
2097                         if (dhd->pub.dongle_reset == FALSE) {
2098                                 DHD_TIMER(("%s:\n", __FUNCTION__));
2099
2100                                 /* Call the bus module watchdog */
2101                                 dhd_bus_watchdog(&dhd->pub);
2102
2103                                 flags = dhd_os_spin_lock(&dhd->pub);
2104                                 /* Count the tick for reference */
2105                                 dhd->pub.tickcnt++;
2106                                 time_lapse = jiffies - jiffies_at_start;
2107
2108                                 /* Reschedule the watchdog */
2109                                 if (dhd->wd_timer_valid)
2110                                         mod_timer(&dhd->timer,
2111                                                 jiffies +
2112                                                 msecs_to_jiffies(dhd_watchdog_ms) -
2113                                                 min(msecs_to_jiffies(dhd_watchdog_ms), time_lapse));
2114                                 dhd_os_spin_unlock(&dhd->pub, flags);
2115                         }
2116                         dhd_os_sdunlock(&dhd->pub);
2117                 } else {
2118                         break;
2119         }
2120
2121         complete_and_exit(&tsk->completed, 0);
2122 }
2123 #endif /* DHDTHREAD */
2124
2125 static void dhd_watchdog(ulong data)
2126 {
2127         dhd_info_t *dhd = (dhd_info_t *)data;
2128         unsigned long flags;
2129
2130         if (dhd->pub.dongle_reset) {
2131                 return;
2132         }
2133
2134 #ifdef DHDTHREAD
2135         if (dhd->thr_wdt_ctl.thr_pid >= 0) {
2136                 up(&dhd->thr_wdt_ctl.sema);
2137                 return;
2138         }
2139 #endif /* DHDTHREAD */
2140
2141         dhd_os_sdlock(&dhd->pub);
2142         /* Call the bus module watchdog */
2143         dhd_bus_watchdog(&dhd->pub);
2144
2145         flags = dhd_os_spin_lock(&dhd->pub);
2146         /* Count the tick for reference */
2147         dhd->pub.tickcnt++;
2148
2149         /* Reschedule the watchdog */
2150         if (dhd->wd_timer_valid)
2151                 mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms));
2152         dhd_os_spin_unlock(&dhd->pub, flags);
2153         dhd_os_sdunlock(&dhd->pub);
2154 }
2155
2156 #ifdef DHDTHREAD
2157 static int
2158 dhd_dpc_thread(void *data)
2159 {
2160         tsk_ctl_t *tsk = (tsk_ctl_t *)data;
2161         dhd_info_t *dhd = (dhd_info_t *)tsk->parent;
2162
2163         /* This thread doesn't need any user-level access,
2164          * so get rid of all our resources
2165          */
2166         if (dhd_dpc_prio > 0)
2167         {
2168                 struct sched_param param;
2169                 param.sched_priority = (dhd_dpc_prio < MAX_RT_PRIO)?dhd_dpc_prio:(MAX_RT_PRIO-1);
2170                 setScheduler(current, SCHED_FIFO, &param);
2171         }
2172
2173 #ifdef CUSTOM_DPC_CPUCORE
2174         set_cpus_allowed_ptr(current, cpumask_of(CUSTOM_DPC_CPUCORE));
2175 #endif /* CUSTOM_DPC_CPUCORE */
2176
2177         /* Run until signal received */
2178         while (1) {
2179                 if (!binary_sema_down(tsk)) {
2180
2181                         SMP_RD_BARRIER_DEPENDS();
2182                         if (tsk->terminated) {
2183                                 break;
2184                         }
2185
2186                         /* Call bus dpc unless it indicated down (then clean stop) */
2187                         if (dhd->pub.busstate != DHD_BUS_DOWN) {
2188                                 dhd_os_wd_timer_extend(&dhd->pub, TRUE);
2189                                 while (dhd_bus_dpc(dhd->pub.bus)) {
2190                                         /* process all data */
2191                                 }
2192                                 dhd_os_wd_timer_extend(&dhd->pub, FALSE);
2193                                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
2194                         } else {
2195                                 if (dhd->pub.up)
2196                                         dhd_bus_stop(dhd->pub.bus, TRUE);
2197                                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
2198                         }
2199                 }
2200                 else
2201                         break;
2202         }
2203
2204         complete_and_exit(&tsk->completed, 0);
2205 }
2206
2207 #ifdef RXFRAME_THREAD
2208 static int
2209 dhd_rxf_thread(void *data)
2210 {
2211         tsk_ctl_t *tsk = (tsk_ctl_t *)data;
2212         dhd_info_t *dhd = (dhd_info_t *)tsk->parent;
2213         dhd_pub_t *pub = &dhd->pub;
2214
2215         /* This thread doesn't need any user-level access,
2216          * so get rid of all our resources
2217          */
2218         if (dhd_rxf_prio > 0)
2219         {
2220                 struct sched_param param;
2221                 param.sched_priority = (dhd_rxf_prio < MAX_RT_PRIO)?dhd_rxf_prio:(MAX_RT_PRIO-1);
2222                 setScheduler(current, SCHED_FIFO, &param);
2223         }
2224
2225         DAEMONIZE("dhd_rxf");
2226         /* DHD_OS_WAKE_LOCK is called in dhd_sched_dpc[dhd_linux.c] down below  */
2227
2228         /*  signal: thread has started */
2229         complete(&tsk->completed);
2230
2231         /* Run until signal received */
2232         while (1) {
2233                 if (down_interruptible(&tsk->sema) == 0) {
2234                         void *skb;
2235 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
2236                         ulong flags;
2237 #endif
2238
2239                         SMP_RD_BARRIER_DEPENDS();
2240
2241                         if (tsk->terminated) {
2242                                 break;
2243                         }
2244                         skb = dhd_rxf_dequeue(pub);
2245
2246                         if (skb == NULL) {
2247                                 continue;
2248                         }
2249                         while (skb) {
2250                                 void *skbnext = PKTNEXT(pub->osh, skb);
2251                                 PKTSETNEXT(pub->osh, skb, NULL);
2252
2253 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
2254                                 netif_rx_ni(skb);
2255 #else
2256                                 netif_rx(skb);
2257                                 local_irq_save(flags);
2258                                 RAISE_RX_SOFTIRQ();
2259                                 local_irq_restore(flags);
2260
2261 #endif
2262                                 skb = skbnext;
2263                         }
2264
2265                         DHD_OS_WAKE_UNLOCK(pub);
2266                 }
2267                 else
2268                         break;
2269         }
2270
2271         complete_and_exit(&tsk->completed, 0);
2272 }
2273 #endif /* RXFRAME_THREAD */
2274 #endif /* DHDTHREAD */
2275
2276 static void
2277 dhd_dpc(ulong data)
2278 {
2279         dhd_info_t *dhd;
2280
2281         dhd = (dhd_info_t *)data;
2282
2283         /* this (tasklet) can be scheduled in dhd_sched_dpc[dhd_linux.c]
2284          * down below , wake lock is set,
2285          * the tasklet is initialized in dhd_attach()
2286          */
2287         /* Call bus dpc unless it indicated down (then clean stop) */
2288         if (dhd->pub.busstate != DHD_BUS_DOWN) {
2289                 if (dhd_bus_dpc(dhd->pub.bus))
2290                         tasklet_schedule(&dhd->tasklet);
2291                 else
2292                         DHD_OS_WAKE_UNLOCK(&dhd->pub);
2293         } else {
2294                 dhd_bus_stop(dhd->pub.bus, TRUE);
2295                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
2296         }
2297 }
2298
2299 void
2300 dhd_sched_dpc(dhd_pub_t *dhdp)
2301 {
2302         dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
2303
2304         DHD_OS_WAKE_LOCK(dhdp);
2305 #ifdef DHDTHREAD
2306         if (dhd->thr_dpc_ctl.thr_pid >= 0) {
2307                 /* If the semaphore does not get up,
2308                 * wake unlock should be done here
2309                 */
2310                 if (!binary_sema_up(&dhd->thr_dpc_ctl))
2311                         DHD_OS_WAKE_UNLOCK(dhdp);
2312                 return;
2313         }
2314 #endif /* DHDTHREAD */
2315
2316         if (dhd->dhd_tasklet_create)
2317                 tasklet_schedule(&dhd->tasklet);
2318 }
2319
2320 #if defined(DHDTHREAD) && defined(RXFRAME_THREAD)
2321 static void
2322 dhd_sched_rxf(dhd_pub_t *dhdp, void *skb)
2323 {
2324         dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
2325
2326         DHD_OS_WAKE_LOCK(dhdp);
2327
2328         DHD_TRACE(("dhd_sched_rxf: Enter\n"));
2329
2330         do {
2331                 if (dhd_rxf_enqueue(dhdp, skb) == BCME_OK)
2332                         break;
2333         } while (1);
2334         if (dhd->thr_rxf_ctl.thr_pid >= 0) {
2335                 up(&dhd->thr_rxf_ctl.sema);
2336         }
2337         return;
2338 }
2339 #endif /* defined(DHDTHREAD) && defined(RXFRAME_THREAD) */
2340
2341 #ifdef TOE
2342 /* Retrieve current toe component enables, which are kept as a bitmap in toe_ol iovar */
2343 static int
2344 dhd_toe_get(dhd_info_t *dhd, int ifidx, uint32 *toe_ol)
2345 {
2346         wl_ioctl_t ioc;
2347         char buf[32];
2348         int ret;
2349
2350         memset(&ioc, 0, sizeof(ioc));
2351
2352         ioc.cmd = WLC_GET_VAR;
2353         ioc.buf = buf;
2354         ioc.len = (uint)sizeof(buf);
2355         ioc.set = FALSE;
2356
2357         strncpy(buf, "toe_ol", sizeof(buf) - 1);
2358         buf[sizeof(buf) - 1] = '\0';
2359         if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
2360                 /* Check for older dongle image that doesn't support toe_ol */
2361                 if (ret == -EIO) {
2362                         DHD_ERROR(("%s: toe not supported by device\n",
2363                                 dhd_ifname(&dhd->pub, ifidx)));
2364                         return -EOPNOTSUPP;
2365                 }
2366
2367                 DHD_INFO(("%s: could not get toe_ol: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret));
2368                 return ret;
2369         }
2370
2371         memcpy(toe_ol, buf, sizeof(uint32));
2372         return 0;
2373 }
2374
2375 /* Set current toe component enables in toe_ol iovar, and set toe global enable iovar */
2376 static int
2377 dhd_toe_set(dhd_info_t *dhd, int ifidx, uint32 toe_ol)
2378 {
2379         wl_ioctl_t ioc;
2380         char buf[32];
2381         int toe, ret;
2382
2383         memset(&ioc, 0, sizeof(ioc));
2384
2385         ioc.cmd = WLC_SET_VAR;
2386         ioc.buf = buf;
2387         ioc.len = (uint)sizeof(buf);
2388         ioc.set = TRUE;
2389
2390         /* Set toe_ol as requested */
2391
2392         strncpy(buf, "toe_ol", sizeof(buf) - 1);
2393         buf[sizeof(buf) - 1] = '\0';
2394         memcpy(&buf[sizeof("toe_ol")], &toe_ol, sizeof(uint32));
2395
2396         if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
2397                 DHD_ERROR(("%s: could not set toe_ol: ret=%d\n",
2398                         dhd_ifname(&dhd->pub, ifidx), ret));
2399                 return ret;
2400         }
2401
2402         /* Enable toe globally only if any components are enabled. */
2403
2404         toe = (toe_ol != 0);
2405
2406         strcpy(buf, "toe");
2407         memcpy(&buf[sizeof("toe")], &toe, sizeof(uint32));
2408
2409         if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
2410                 DHD_ERROR(("%s: could not set toe: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret));
2411                 return ret;
2412         }
2413
2414         return 0;
2415 }
2416 #endif /* TOE */
2417
2418 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
2419 static void
2420 dhd_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
2421 {
2422         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
2423
2424         snprintf(info->driver, sizeof(info->driver), "wl");
2425         snprintf(info->version, sizeof(info->version), "%lu", dhd->pub.drv_version);
2426 }
2427
2428 struct ethtool_ops dhd_ethtool_ops = {
2429         .get_drvinfo = dhd_ethtool_get_drvinfo
2430 };
2431 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */
2432
2433
2434 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2)
2435 static int
2436 dhd_ethtool(dhd_info_t *dhd, void *uaddr)
2437 {
2438         struct ethtool_drvinfo info;
2439         char drvname[sizeof(info.driver)];
2440         uint32 cmd;
2441 #ifdef TOE
2442         struct ethtool_value edata;
2443         uint32 toe_cmpnt, csum_dir;
2444         int ret;
2445 #endif
2446
2447         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2448
2449         /* all ethtool calls start with a cmd word */
2450         if (copy_from_user(&cmd, uaddr, sizeof (uint32)))
2451                 return -EFAULT;
2452
2453         switch (cmd) {
2454         case ETHTOOL_GDRVINFO:
2455                 /* Copy out any request driver name */
2456                 if (copy_from_user(&info, uaddr, sizeof(info)))
2457                         return -EFAULT;
2458                 strncpy(drvname, info.driver, sizeof(info.driver));
2459                 drvname[sizeof(info.driver)-1] = '\0';
2460
2461                 /* clear struct for return */
2462                 memset(&info, 0, sizeof(info));
2463                 info.cmd = cmd;
2464
2465                 /* if dhd requested, identify ourselves */
2466                 if (strcmp(drvname, "?dhd") == 0) {
2467                         snprintf(info.driver, sizeof(info.driver), "dhd");
2468                         strncpy(info.version, EPI_VERSION_STR, sizeof(info.version) - 1);
2469                         info.version[sizeof(info.version) - 1] = '\0';
2470                 }
2471
2472                 /* otherwise, require dongle to be up */
2473                 else if (!dhd->pub.up) {
2474                         DHD_ERROR(("%s: dongle is not up\n", __FUNCTION__));
2475                         return -ENODEV;
2476                 }
2477
2478                 /* finally, report dongle driver type */
2479                 else if (dhd->pub.iswl)
2480                         snprintf(info.driver, sizeof(info.driver), "wl");
2481                 else
2482                         snprintf(info.driver, sizeof(info.driver), "xx");
2483
2484                 snprintf(info.version, sizeof(info.version), "%lu", dhd->pub.drv_version);
2485                 if (copy_to_user(uaddr, &info, sizeof(info)))
2486                         return -EFAULT;
2487                 DHD_CTL(("%s: given %*s, returning %s\n", __FUNCTION__,
2488                          (int)sizeof(drvname), drvname, info.driver));
2489                 break;
2490
2491 #ifdef TOE
2492         /* Get toe offload components from dongle */
2493         case ETHTOOL_GRXCSUM:
2494         case ETHTOOL_GTXCSUM:
2495                 if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0)
2496                         return ret;
2497
2498                 csum_dir = (cmd == ETHTOOL_GTXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;
2499
2500                 edata.cmd = cmd;
2501                 edata.data = (toe_cmpnt & csum_dir) ? 1 : 0;
2502
2503                 if (copy_to_user(uaddr, &edata, sizeof(edata)))
2504                         return -EFAULT;
2505                 break;
2506
2507         /* Set toe offload components in dongle */
2508         case ETHTOOL_SRXCSUM:
2509         case ETHTOOL_STXCSUM:
2510                 if (copy_from_user(&edata, uaddr, sizeof(edata)))
2511                         return -EFAULT;
2512
2513                 /* Read the current settings, update and write back */
2514                 if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0)
2515                         return ret;
2516
2517                 csum_dir = (cmd == ETHTOOL_STXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;
2518
2519                 if (edata.data != 0)
2520                         toe_cmpnt |= csum_dir;
2521                 else
2522                         toe_cmpnt &= ~csum_dir;
2523
2524                 if ((ret = dhd_toe_set(dhd, 0, toe_cmpnt)) < 0)
2525                         return ret;
2526
2527                 /* If setting TX checksum mode, tell Linux the new mode */
2528                 if (cmd == ETHTOOL_STXCSUM) {
2529                         if (edata.data)
2530                                 dhd->iflist[0]->net->features |= NETIF_F_IP_CSUM;
2531                         else
2532                                 dhd->iflist[0]->net->features &= ~NETIF_F_IP_CSUM;
2533                 }
2534
2535                 break;
2536 #endif /* TOE */
2537
2538         default:
2539                 return -EOPNOTSUPP;
2540         }
2541
2542         return 0;
2543 }
2544 #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */
2545
2546 static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error)
2547 {
2548         dhd_info_t *dhd;
2549
2550         if (!dhdp) {
2551                 DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__));
2552                 return FALSE;
2553         }
2554
2555         if (!dhdp->up)
2556                 return FALSE;
2557
2558         dhd = (dhd_info_t *)dhdp->info;
2559         if (dhd->thr_sysioc_ctl.thr_pid < 0) {
2560                 DHD_ERROR(("%s : skipped due to negative pid - unloading?\n", __FUNCTION__));
2561                 return FALSE;
2562         }
2563
2564         if ((error == -ETIMEDOUT) || (error == -EREMOTEIO) ||
2565                 ((dhdp->busstate == DHD_BUS_DOWN) && (!dhdp->dongle_reset))) {
2566                 DHD_ERROR(("%s: Event HANG send up due to  re=%d te=%d e=%d s=%d\n", __FUNCTION__,
2567                         dhdp->rxcnt_timeout, dhdp->txcnt_timeout, error, dhdp->busstate));
2568                 net_os_send_hang_message(net);
2569                 return TRUE;
2570         }
2571         return FALSE;
2572 }
2573
2574 int dhd_ioctl_process(dhd_pub_t *pub, int ifidx, dhd_ioctl_t *ioc)
2575 {
2576         int bcmerror = BCME_OK;
2577         int buflen = 0;
2578         void *buf = NULL;
2579         struct net_device *net;
2580
2581         net = dhd_idx2net(pub, ifidx);
2582         if (!net) {
2583                 bcmerror = BCME_BADARG;
2584                 goto done;
2585         }
2586
2587         /* Copy out any buffer passed */
2588         if (ioc->buf) {
2589                 if (ioc->len == 0) {
2590                         DHD_TRACE(("%s: ioc->len=0, returns BCME_BADARG \n", __FUNCTION__));
2591                         bcmerror = BCME_BADARG;
2592                         goto done;
2593                 }
2594                 buflen = MIN(ioc->len, DHD_IOCTL_MAXLEN);
2595                 /* optimization for direct ioctl calls from kernel */
2596                 /*
2597                 if (segment_eq(get_fs(), KERNEL_DS)) {
2598                         buf = ioc->buf;
2599                 } else {
2600                 */
2601                 {
2602                         if (!(buf = MALLOC(pub->osh, buflen + 1))) {
2603                                 bcmerror = BCME_NOMEM;
2604                                 goto done;
2605                         }
2606                         if (copy_from_user(buf, ioc->buf, buflen)) {
2607                                 bcmerror = BCME_BADADDR;
2608                                 goto done;
2609                         }
2610                         *(char *)(buf + buflen) = '\0';
2611                 }
2612         }
2613
2614         /* check for local dhd ioctl and handle it */
2615         if (ioc->driver == DHD_IOCTL_MAGIC) {
2616                 bcmerror = dhd_ioctl((void *)pub, ioc, buf, buflen);
2617                 if (bcmerror)
2618                         pub->bcmerror = bcmerror;
2619                 goto done;
2620         }
2621
2622         /* send to dongle (must be up, and wl). */
2623         if (pub->busstate != DHD_BUS_DATA) {
2624                 bcmerror = BCME_DONGLE_DOWN;
2625                 goto done;
2626         }
2627
2628         if (!pub->iswl) {
2629                 bcmerror = BCME_DONGLE_DOWN;
2630                 goto done;
2631         }
2632
2633         /*
2634          * Flush the TX queue if required for proper message serialization:
2635          * Intercept WLC_SET_KEY IOCTL - serialize M4 send and set key IOCTL to
2636          * prevent M4 encryption and
2637          * intercept WLC_DISASSOC IOCTL - serialize WPS-DONE and WLC_DISASSOC IOCTL to
2638          * prevent disassoc frame being sent before WPS-DONE frame.
2639          */
2640         if (ioc->cmd == WLC_SET_KEY ||
2641             (ioc->cmd == WLC_SET_VAR && ioc->buf != NULL &&
2642              strncmp("wsec_key", ioc->buf, 9) == 0) ||
2643             (ioc->cmd == WLC_SET_VAR && ioc->buf != NULL &&
2644              strncmp("bsscfg:wsec_key", ioc->buf, 15) == 0) ||
2645             ioc->cmd == WLC_DISASSOC)
2646                 dhd_wait_pend8021x(net);
2647
2648 #ifdef WLMEDIA_HTSF
2649         if (ioc->buf) {
2650                 /*  short cut wl ioctl calls here  */
2651                 if (strcmp("htsf", ioc->buf) == 0) {
2652                         dhd_ioctl_htsf_get(dhd, 0);
2653                         return BCME_OK;
2654                 }
2655
2656                 if (strcmp("htsflate", ioc->buf) == 0) {
2657                         if (ioc->set) {
2658                                 memset(ts, 0, sizeof(tstamp_t)*TSMAX);
2659                                 memset(&maxdelayts, 0, sizeof(tstamp_t));
2660                                 maxdelay = 0;
2661                                 tspktcnt = 0;
2662                                 maxdelaypktno = 0;
2663                                 memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN);
2664                                 memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN);
2665                                 memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN);
2666                                 memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN);
2667                         } else {
2668                                 dhd_dump_latency();
2669                         }
2670                         return BCME_OK;
2671                 }
2672                 if (strcmp("htsfclear", ioc->buf) == 0) {
2673                         memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN);
2674                         memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN);
2675                         memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN);
2676                         memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN);
2677                         htsf_seqnum = 0;
2678                         return BCME_OK;
2679                 }
2680                 if (strcmp("htsfhis", ioc->buf) == 0) {
2681                         dhd_dump_htsfhisto(&vi_d1, "H to D");
2682                         dhd_dump_htsfhisto(&vi_d2, "D to D");
2683                         dhd_dump_htsfhisto(&vi_d3, "D to H");
2684                         dhd_dump_htsfhisto(&vi_d4, "H to H");
2685                         return BCME_OK;
2686                 }
2687                 if (strcmp("tsport", ioc->buf) == 0) {
2688                         if (ioc->set) {
2689                                 memcpy(&tsport, ioc->buf + 7, 4);
2690                         } else {
2691                                 DHD_ERROR(("current timestamp port: %d \n", tsport));
2692                         }
2693                         return BCME_OK;
2694                 }
2695         }
2696 #endif /* WLMEDIA_HTSF */
2697
2698         if ((ioc->cmd == WLC_SET_VAR || ioc->cmd == WLC_GET_VAR) &&
2699                 ioc->buf != NULL && strncmp("rpc_", ioc->buf, 4) == 0) {
2700 #ifdef BCM_FD_AGGR
2701                 bcmerror = dhd_fdaggr_ioctl(pub, ifidx, (wl_ioctl_t *)ioc, buf, buflen);
2702 #else
2703                 bcmerror = BCME_UNSUPPORTED;
2704 #endif
2705                 goto done;
2706         }
2707         bcmerror = dhd_wl_ioctl(pub, ifidx, (wl_ioctl_t *)ioc, buf, buflen);
2708
2709 done:
2710         dhd_check_hang(net, pub, bcmerror);
2711
2712         if (!bcmerror && buf && ioc->buf) {
2713                 if (copy_to_user(ioc->buf, buf, buflen))
2714                         bcmerror = -EFAULT;
2715         }
2716
2717         if (buf)
2718                 MFREE(pub->osh, buf, buflen + 1);
2719
2720         return bcmerror;
2721 }
2722
2723 static int
2724 dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
2725 {
2726         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
2727         dhd_ioctl_t ioc;
2728         int bcmerror = 0;
2729         int ifidx;
2730         int ret;
2731
2732         DHD_OS_WAKE_LOCK(&dhd->pub);
2733
2734         /* send to dongle only if we are not waiting for reload already */
2735         if (dhd->pub.hang_was_sent) {
2736                 DHD_ERROR(("%s: HANG was sent up earlier\n", __FUNCTION__));
2737                 DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT_MS);
2738                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
2739                 return OSL_ERROR(BCME_DONGLE_DOWN);
2740         }
2741
2742         ifidx = dhd_net2idx(dhd, net);
2743         DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd));
2744
2745         if (ifidx == DHD_BAD_IF) {
2746                 DHD_ERROR(("%s: BAD IF\n", __FUNCTION__));
2747                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
2748                 return -1;
2749         }
2750
2751 #if defined(WL_WIRELESS_EXT)
2752         /* linux wireless extensions */
2753         if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) {
2754                 /* may recurse, do NOT lock */
2755                 ret = wl_iw_ioctl(net, ifr, cmd);
2756                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
2757                 return ret;
2758         }
2759 #endif /* defined(WL_WIRELESS_EXT) */
2760
2761 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2)
2762         if (cmd == SIOCETHTOOL) {
2763                 ret = dhd_ethtool(dhd, (void*)ifr->ifr_data);
2764                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
2765                 return ret;
2766         }
2767 #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */
2768
2769         if (cmd == SIOCDEVPRIVATE+1) {
2770                 ret = wl_android_priv_cmd(net, ifr, cmd);
2771                 dhd_check_hang(net, &dhd->pub, ret);
2772                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
2773                 return ret;
2774         }
2775
2776         if (cmd != SIOCDEVPRIVATE) {
2777                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
2778                 return -EOPNOTSUPP;
2779         }
2780
2781         memset(&ioc, 0, sizeof(ioc));
2782
2783         /* Copy the ioc control structure part of ioctl request */
2784         if (copy_from_user(&ioc, ifr->ifr_data, sizeof(wl_ioctl_t))) {
2785                 bcmerror = BCME_BADADDR;
2786                 goto done;
2787         }
2788
2789         /* To differentiate between wl and dhd read 4 more byes */
2790         if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(wl_ioctl_t),
2791                 sizeof(uint)) != 0)) {
2792                 bcmerror = BCME_BADADDR;
2793                 goto done;
2794         }
2795
2796         if (!capable(CAP_NET_ADMIN)) {
2797                 bcmerror = BCME_EPERM;
2798                 goto done;
2799         }
2800
2801         bcmerror = dhd_ioctl_process(&dhd->pub, ifidx, &ioc);
2802
2803 done:
2804         DHD_OS_WAKE_UNLOCK(&dhd->pub);
2805
2806         return OSL_ERROR(bcmerror);
2807 }
2808
2809 #ifdef WL_CFG80211
2810 static int
2811 dhd_cleanup_virt_ifaces(dhd_info_t *dhd)
2812 {
2813         int i = 1; /* Leave ifidx 0 [Primary Interface] */
2814 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
2815         int rollback_lock = FALSE;
2816 #endif
2817
2818         DHD_TRACE(("%s: Enter \n", __func__));
2819
2820 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
2821         /* release lock for unregister_netdev */
2822         if (rtnl_is_locked()) {
2823                 rtnl_unlock();
2824                 rollback_lock = TRUE;
2825         }
2826 #endif
2827
2828         for (i = 1; i < DHD_MAX_IFS; i++) {
2829                 dhd_net_if_lock_local(dhd);
2830                 if (dhd->iflist[i]) {
2831                         DHD_TRACE(("Deleting IF: %d \n", i));
2832                         if ((dhd->iflist[i]->state != DHD_IF_DEL) &&
2833                                 (dhd->iflist[i]->state != DHD_IF_DELETING)) {
2834                                 dhd->iflist[i]->state = DHD_IF_DEL;
2835                                 dhd->iflist[i]->idx = i;
2836                                 dhd_op_if(dhd->iflist[i]);
2837                         }
2838                 }
2839                 dhd_net_if_unlock_local(dhd);
2840         }
2841
2842 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
2843         if (rollback_lock)
2844                 rtnl_lock();
2845 #endif
2846
2847         return 0;
2848 }
2849 #endif /* WL_CFG80211 */
2850
2851
2852 static int
2853 dhd_stop(struct net_device *net)
2854 {
2855         int ifidx = 0;
2856         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
2857         DHD_OS_WAKE_LOCK(&dhd->pub);
2858         DHD_TRACE(("%s: Enter %p\n", __FUNCTION__, net));
2859
2860         if (dhd->pub.up == 0) {
2861                 goto exit;
2862         }
2863         ifidx = dhd_net2idx(dhd, net);
2864         BCM_REFERENCE(ifidx);
2865
2866         /* Set state and stop OS transmissions */
2867         netif_stop_queue(net);
2868         dhd->pub.up = 0;
2869
2870 #ifdef WL_CFG80211
2871         if (ifidx == 0) {
2872                 wl_cfg80211_down(NULL);
2873
2874                 /*
2875                  * For CFG80211: Clean up all the left over virtual interfaces
2876                  * when the primary Interface is brought down. [ifconfig wlan0 down]
2877                  */
2878                 if (!dhd_download_fw_on_driverload) {
2879                         if ((dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) &&
2880                                 (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) {
2881                                 dhd_cleanup_virt_ifaces(dhd);
2882                         }
2883                 }
2884         }
2885 #endif
2886
2887 #ifdef PROP_TXSTATUS
2888         dhd_os_wlfc_block(&dhd->pub);
2889         dhd_wlfc_cleanup(&dhd->pub, NULL, 0);
2890         dhd_os_wlfc_unblock(&dhd->pub);
2891 #endif
2892         /* Stop the protocol module */
2893         dhd_prot_stop(&dhd->pub);
2894
2895         OLD_MOD_DEC_USE_COUNT;
2896 exit:
2897 #if defined(WL_CFG80211)
2898         if (ifidx == 0 && !dhd_download_fw_on_driverload)
2899                 wl_android_wifi_off(net);
2900 #endif 
2901         dhd->pub.rxcnt_timeout = 0;
2902         dhd->pub.txcnt_timeout = 0;
2903         dhd->pub.hang_was_sent = 0;
2904
2905         DHD_OS_WAKE_UNLOCK(&dhd->pub);
2906         return 0;
2907 }
2908
2909 /* (USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME) */
2910 static int
2911 dhd_open(struct net_device *net)
2912 {
2913         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
2914 #ifdef TOE
2915         uint32 toe_ol;
2916 #endif
2917         int ifidx;
2918         int32 ret = 0;
2919
2920 #if defined(MULTIPLE_SUPPLICANT)
2921 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 && 1
2922         if (mutex_is_locked(&_dhd_sdio_mutex_lock_) != 0) {
2923                 DHD_ERROR(("%s : dhd_open: call dev open before insmod complete!\n", __FUNCTION__));
2924         }
2925         mutex_lock(&_dhd_sdio_mutex_lock_);
2926 #endif
2927 #endif /* MULTIPLE_SUPPLICANT */
2928
2929         DHD_OS_WAKE_LOCK(&dhd->pub);
2930         /* Update FW path if it was changed */
2931         if (strlen(firmware_path) != 0) {
2932                 if (firmware_path[strlen(firmware_path)-1] == '\n')
2933                         firmware_path[strlen(firmware_path)-1] = '\0';
2934                 dhd_conf_set_fw_name_by_chip(&dhd->pub, fw_path, firmware_path);
2935         }
2936
2937
2938         dhd->pub.dongle_trap_occured = 0;
2939         dhd->pub.hang_was_sent = 0;
2940 #if !defined(WL_CFG80211)
2941         /*
2942          * Force start if ifconfig_up gets called before START command
2943          *  We keep WEXT's wl_control_wl_start to provide backward compatibility
2944          *  This should be removed in the future
2945          */
2946         ret = wl_control_wl_start(net);
2947         if (ret != 0) {
2948                 DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret));
2949                 ret = -1;
2950                 goto exit;
2951         }
2952 #endif
2953
2954         ifidx = dhd_net2idx(dhd, net);
2955         DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx));
2956
2957         if (ifidx < 0) {
2958                 DHD_ERROR(("%s: Error: called with invalid IF\n", __FUNCTION__));
2959                 ret = -1;
2960                 goto exit;
2961         }
2962
2963         if (!dhd->iflist[ifidx] || dhd->iflist[ifidx]->state == DHD_IF_DEL) {
2964                 DHD_ERROR(("%s: Error: called when IF already deleted\n", __FUNCTION__));
2965                 ret = -1;
2966                 goto exit;
2967         }
2968
2969         if (ifidx == 0) {
2970                 atomic_set(&dhd->pend_8021x_cnt, 0);
2971 #if defined(WL_CFG80211)
2972                 DHD_ERROR(("\n%s\n", dhd_version));
2973                 if (!dhd_download_fw_on_driverload) {
2974                         ret = wl_android_wifi_on(net);
2975                         if (ret != 0) {
2976                                 DHD_ERROR(("%s : wl_android_wifi_on failed (%d)\n",
2977                                         __FUNCTION__, ret));
2978                                 ret = -1;
2979                                 goto exit;
2980                         }
2981                 }
2982 #endif 
2983
2984                 if (dhd->pub.busstate != DHD_BUS_DATA) {
2985
2986                         /* try to bring up bus */
2987                         if ((ret = dhd_bus_start(&dhd->pub)) != 0) {
2988                                 DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret));
2989                                 ret = -1;
2990                                 goto exit;
2991                         }
2992
2993                 }
2994
2995                 /* dhd_prot_init has been called in dhd_bus_start or wl_android_wifi_on */
2996                 memcpy(net->dev_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN);
2997
2998 #ifdef TOE
2999                 /* Get current TOE mode from dongle */
3000                 if (dhd_toe_get(dhd, ifidx, &toe_ol) >= 0 && (toe_ol & TOE_TX_CSUM_OL) != 0)
3001                         dhd->iflist[ifidx]->net->features |= NETIF_F_IP_CSUM;
3002                 else
3003                         dhd->iflist[ifidx]->net->features &= ~NETIF_F_IP_CSUM;
3004 #endif /* TOE */
3005
3006 #if defined(WL_CFG80211)
3007                 if (unlikely(wl_cfg80211_up(NULL))) {
3008                         DHD_ERROR(("%s: failed to bring up cfg80211\n", __FUNCTION__));
3009                         ret = -1;
3010                         goto exit;
3011                 }
3012 #endif /* WL_CFG80211 */
3013         }
3014
3015         /* Allow transmit calls */
3016         netif_start_queue(net);
3017         dhd->pub.up = 1;
3018
3019 #ifdef BCMDBGFS
3020         dhd_dbg_init(&dhd->pub);
3021 #endif
3022
3023         OLD_MOD_INC_USE_COUNT;
3024 exit:
3025         if (ret)
3026                 dhd_stop(net);
3027
3028         DHD_OS_WAKE_UNLOCK(&dhd->pub);
3029
3030 #if defined(MULTIPLE_SUPPLICANT)
3031 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 && 1
3032         mutex_unlock(&_dhd_sdio_mutex_lock_);
3033 #endif
3034 #endif /* MULTIPLE_SUPPLICANT */
3035
3036         return ret;
3037 }
3038
3039 int dhd_do_driver_init(struct net_device *net)
3040 {
3041         dhd_info_t *dhd = NULL;
3042
3043         if (!net) {
3044                 DHD_ERROR(("Primary Interface not initialized \n"));
3045                 return -EINVAL;
3046         }
3047
3048 #ifdef MULTIPLE_SUPPLICANT
3049 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 && 1
3050         if (mutex_is_locked(&_dhd_sdio_mutex_lock_) != 0) {
3051                 DHD_ERROR(("%s : dhdsdio_probe is already running!\n", __FUNCTION__));
3052                 return 0;
3053         }
3054 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
3055 #endif /* MULTIPLE_SUPPLICANT */
3056
3057         /*  && defined(OEM_ANDROID) && defined(BCMSDIO) */
3058         dhd = *(dhd_info_t **)netdev_priv(net);
3059
3060         /* If driver is already initialized, do nothing
3061          */
3062         if (dhd->pub.busstate == DHD_BUS_DATA) {
3063                 DHD_TRACE(("Driver already Inititalized. Nothing to do"));
3064                 return 0;
3065         }
3066
3067         if (dhd_open(net) < 0) {
3068                 DHD_ERROR(("Driver Init Failed \n"));
3069                 return -1;
3070         }
3071
3072         return 0;
3073 }
3074
3075 osl_t *
3076 dhd_osl_attach(void *pdev, uint bustype)
3077 {
3078         return osl_attach(pdev, bustype, TRUE);
3079 }
3080
3081 void
3082 dhd_osl_detach(osl_t *osh)
3083 {
3084         if (MALLOCED(osh)) {
3085                 DHD_ERROR(("%s: MEMORY LEAK %d bytes\n", __FUNCTION__, MALLOCED(osh)));
3086         }
3087         osl_detach(osh);
3088 #if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3089         dhd_registration_check = FALSE;
3090         up(&dhd_registration_sem);
3091 #if     defined(BCMLXSDMMC)
3092         up(&dhd_chipup_sem);
3093 #endif
3094 #endif 
3095 }
3096
3097 int
3098 dhd_add_if(dhd_info_t *dhd, int ifidx, void *handle, char *name,
3099         uint8 *mac_addr, uint32 flags, uint8 bssidx)
3100 {
3101         dhd_if_t *ifp;
3102
3103         DHD_TRACE(("%s: idx %d, handle->%p\n", __FUNCTION__, ifidx, handle));
3104
3105         ASSERT(dhd && (ifidx < DHD_MAX_IFS));
3106
3107         ifp = dhd->iflist[ifidx];
3108         if (ifp != NULL) {
3109                 if (ifp->net != NULL) {
3110                         netif_stop_queue(ifp->net);
3111                         unregister_netdev(ifp->net);
3112                         free_netdev(ifp->net);
3113                 }
3114         } else
3115                 if ((ifp = MALLOC(dhd->pub.osh, sizeof(dhd_if_t))) == NULL) {
3116                         DHD_ERROR(("%s: OOM - dhd_if_t(%d)\n", __FUNCTION__, sizeof(dhd_if_t)));
3117                         return -ENOMEM;
3118                 }
3119
3120         memset(ifp, 0, sizeof(dhd_if_t));
3121         ifp->event2cfg80211 = FALSE;
3122         ifp->info = dhd;
3123         dhd->iflist[ifidx] = ifp;
3124         strncpy(ifp->name, name, IFNAMSIZ);
3125         ifp->name[IFNAMSIZ] = '\0';
3126         INIT_LIST_HEAD(&ifp->ipv6_list);
3127         spin_lock_init(&ifp->ipv6_lock);
3128         if (mac_addr != NULL)
3129                 memcpy(&ifp->mac_addr, mac_addr, ETHER_ADDR_LEN);
3130
3131         if (handle == NULL) {
3132                 ifp->state = DHD_IF_ADD;
3133                 ifp->idx = ifidx;
3134                 ifp->bssidx = bssidx;
3135                 ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0);
3136                 up(&dhd->thr_sysioc_ctl.sema);
3137         } else
3138                 ifp->net = (struct net_device *)handle;
3139
3140         if (ifidx == 0) {
3141                 ifp->event2cfg80211 = TRUE;
3142         }
3143
3144         return 0;
3145 }
3146
3147 void
3148 dhd_del_if(dhd_info_t *dhd, int ifidx)
3149 {
3150         dhd_if_t *ifp;
3151
3152         DHD_TRACE(("%s: idx %d\n", __FUNCTION__, ifidx));
3153
3154         ASSERT(dhd && ifidx && (ifidx < DHD_MAX_IFS));
3155         ifp = dhd->iflist[ifidx];
3156         if (!ifp) {
3157                 DHD_ERROR(("%s: Null interface\n", __FUNCTION__));
3158                 return;
3159         }
3160
3161         ifp->state = DHD_IF_DEL;
3162         ifp->idx = ifidx;
3163         ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0);
3164         up(&dhd->thr_sysioc_ctl.sema);
3165 }
3166
3167 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
3168 static struct net_device_ops dhd_ops_pri = {
3169         .ndo_open = dhd_open,
3170         .ndo_stop = dhd_stop,
3171         .ndo_get_stats = dhd_get_stats,
3172         .ndo_do_ioctl = dhd_ioctl_entry,
3173         .ndo_start_xmit = dhd_start_xmit,
3174         .ndo_set_mac_address = dhd_set_mac_address,
3175 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
3176         .ndo_set_rx_mode = dhd_set_multicast_list,
3177 #else
3178         .ndo_set_multicast_list = dhd_set_multicast_list,
3179 #endif
3180 };
3181
3182 static struct net_device_ops dhd_ops_virt = {
3183         .ndo_get_stats = dhd_get_stats,
3184         .ndo_do_ioctl = dhd_ioctl_entry,
3185         .ndo_start_xmit = dhd_start_xmit,
3186         .ndo_set_mac_address = dhd_set_mac_address,
3187 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
3188         .ndo_set_rx_mode = dhd_set_multicast_list,
3189 #else
3190         .ndo_set_multicast_list = dhd_set_multicast_list,
3191 #endif
3192 };
3193 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */
3194
3195 dhd_pub_t *
3196 dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
3197 {
3198         dhd_info_t *dhd = NULL;
3199         struct net_device *net = NULL;
3200
3201         dhd_attach_states_t dhd_state = DHD_ATTACH_STATE_INIT;
3202         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3203
3204         /* updates firmware nvram path if it was provided as module parameters */
3205         if (strlen(nvram_path) != 0) {
3206                 bzero(nv_path, MOD_PARAM_PATHLEN);
3207                 strncpy(nv_path, nvram_path, sizeof(nv_path) -1);
3208         }
3209         if (strlen(config_path) != 0) {
3210                 bzero(conf_path, MOD_PARAM_PATHLEN);
3211                 strncpy(conf_path, config_path, sizeof(conf_path) -1);
3212         }
3213
3214         /* Allocate etherdev, including space for private structure */
3215         if (!(net = alloc_etherdev(sizeof(dhd)))) {
3216                 DHD_ERROR(("%s: OOM - alloc_etherdev\n", __FUNCTION__));
3217                 goto fail;
3218         }
3219         dhd_state |= DHD_ATTACH_STATE_NET_ALLOC;
3220
3221         /* Allocate primary dhd_info */
3222 #if defined(CONFIG_DHD_USE_STATIC_BUF)
3223         dhd = (void *)dhd_os_prealloc(osh, DHD_PREALLOC_DHD_INFO, sizeof(dhd_info_t));
3224         if (!dhd) {
3225                 DHD_INFO(("%s: OOM - Pre-alloc dhd_info\n", __FUNCTION__));
3226 #endif /* CONFIG_DHD_USE_STATIC_BUF */
3227         if (!(dhd = MALLOC(osh, sizeof(dhd_info_t)))) {
3228                 DHD_ERROR(("%s: OOM - alloc dhd_info\n", __FUNCTION__));
3229                 goto fail;
3230         }
3231 #if defined(CONFIG_DHD_USE_STATIC_BUF)
3232         }
3233 #endif /* CONFIG_DHD_USE_STATIC_BUF */
3234         memset(dhd, 0, sizeof(dhd_info_t));
3235
3236 #ifdef DHDTHREAD
3237         dhd->thr_dpc_ctl.thr_pid = DHD_PID_KT_TL_INVALID;
3238         dhd->thr_wdt_ctl.thr_pid = DHD_PID_KT_INVALID;
3239 #endif /* DHDTHREAD */
3240         dhd->dhd_tasklet_create = FALSE;
3241         dhd->thr_sysioc_ctl.thr_pid = DHD_PID_KT_INVALID;
3242         dhd_state |= DHD_ATTACH_STATE_DHD_ALLOC;
3243
3244         /*
3245          * Save the dhd_info into the priv
3246          */
3247         memcpy((void *)netdev_priv(net), &dhd, sizeof(dhd));
3248         dhd->pub.osh = osh;
3249
3250         /* Link to info module */
3251         dhd->pub.info = dhd;
3252         /* Link to bus module */
3253         dhd->pub.bus = bus;
3254         dhd->pub.hdrlen = bus_hdrlen;
3255         if (strlen(firmware_path) != 0)
3256                 dhd_conf_set_fw_name_by_chip(&dhd->pub, fw_path, firmware_path);
3257
3258         /* Set network interface name if it was provided as module parameter */
3259         if (iface_name[0]) {
3260                 int len;
3261                 char ch;
3262                 strncpy(net->name, iface_name, IFNAMSIZ);
3263                 net->name[IFNAMSIZ - 1] = 0;
3264                 len = strlen(net->name);
3265                 ch = net->name[len - 1];
3266                 if ((ch > '9' || ch < '0') && (len < IFNAMSIZ - 2))
3267                         strcat(net->name, "%d");
3268         }
3269
3270         if (dhd_add_if(dhd, 0, (void *)net, net->name, NULL, 0, 0) == DHD_BAD_IF)
3271                 goto fail;
3272         dhd_state |= DHD_ATTACH_STATE_ADD_IF;
3273
3274 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
3275         net->open = NULL;
3276 #else
3277         net->netdev_ops = NULL;
3278 #endif
3279
3280         sema_init(&dhd->proto_sem, 1);
3281
3282 #ifdef PROP_TXSTATUS
3283         spin_lock_init(&dhd->wlfc_spinlock);
3284 #ifdef PROP_TXSTATUS_VSDB
3285         dhd->pub.wlfc_enabled = FALSE;
3286 #else
3287         if (!disable_proptx)
3288                 dhd->pub.wlfc_enabled = TRUE;
3289         else
3290                 dhd->pub.wlfc_enabled = FALSE;
3291 #endif /* PROP_TXSTATUS_VSDB */
3292         dhd->pub.ptx_opt_enabled = FALSE;
3293         dhd->pub.skip_fc = dhd_wlfc_skip_fc;
3294         dhd->pub.plat_enable = dhd_wlfc_plat_enable;
3295         dhd->pub.plat_deinit = dhd_wlfc_plat_deinit;
3296 #endif /* PROP_TXSTATUS */
3297
3298         /* Initialize other structure content */
3299         init_waitqueue_head(&dhd->ioctl_resp_wait);
3300         init_waitqueue_head(&dhd->ctrl_wait);
3301
3302         /* Initialize the spinlocks */
3303         spin_lock_init(&dhd->sdlock);
3304         spin_lock_init(&dhd->txqlock);
3305         spin_lock_init(&dhd->dhd_lock);
3306 #if defined(DHDTHREAD) && defined(RXFRAME_THREAD)
3307         spin_lock_init(&dhd->rxf_lock);
3308 #endif /* defined(DHDTHREAD) && defined(RXFRAME_THREAD) */
3309 #ifdef DHDTCPACK_SUPPRESS
3310         spin_lock_init(&dhd->tcpack_lock);
3311 #endif /* DHDTCPACK_SUPPRESS */
3312
3313         /* Initialize Wakelock stuff */
3314         spin_lock_init(&dhd->wakelock_spinlock);
3315         dhd->wakelock_counter = 0;
3316         dhd->wakelock_wd_counter = 0;
3317         dhd->wakelock_rx_timeout_enable = 0;
3318         dhd->wakelock_ctrl_timeout_enable = 0;
3319 #ifdef CONFIG_HAS_WAKELOCK
3320         wake_lock_init(&dhd->wl_wifi, WAKE_LOCK_SUSPEND, "wlan_wake");
3321         wake_lock_init(&dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake");
3322         wake_lock_init(&dhd->wl_ctrlwake, WAKE_LOCK_SUSPEND, "wlan_ctrl_wake");
3323         wake_lock_init(&dhd->wl_wdwake, WAKE_LOCK_SUSPEND, "wlan_wd_wake");
3324 #endif /* CONFIG_HAS_WAKELOCK */
3325 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
3326         mutex_init(&dhd->dhd_net_if_mutex);
3327         mutex_init(&dhd->dhd_suspend_mutex);
3328 #endif
3329         dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT;
3330
3331         if (dhd_conf_attach(&dhd->pub) != 0) {
3332                 DHD_ERROR(("dhd_conf_attach failed\n"));
3333                 goto fail;
3334         }
3335
3336         /* Attach and link in the protocol */
3337         if (dhd_prot_attach(&dhd->pub) != 0) {
3338                 DHD_ERROR(("dhd_prot_attach failed\n"));
3339                 goto fail;
3340         }
3341         dhd_state |= DHD_ATTACH_STATE_PROT_ATTACH;
3342
3343 #ifdef WL_CFG80211
3344         /* Attach and link in the cfg80211 */
3345         if (unlikely(wl_cfg80211_attach(net, &dhd->pub))) {
3346                 DHD_ERROR(("wl_cfg80211_attach failed\n"));
3347                 goto fail;
3348         }
3349
3350         dhd_monitor_init(&dhd->pub);
3351         dhd_state |= DHD_ATTACH_STATE_CFG80211;
3352 #endif
3353 #if defined(WL_WIRELESS_EXT)
3354         /* Attach and link in the iw */
3355         if (!(dhd_state &  DHD_ATTACH_STATE_CFG80211)) {
3356                 if (wl_iw_attach(net, (void *)&dhd->pub) != 0) {
3357                         DHD_ERROR(("wl_iw_attach failed\n"));
3358                         goto fail;
3359                 }
3360                 dhd_state |= DHD_ATTACH_STATE_WL_ATTACH;
3361         }
3362 #endif /* defined(WL_WIRELESS_EXT) */
3363
3364
3365         /* Set up the watchdog timer */
3366         init_timer(&dhd->timer);
3367         dhd->timer.data = (ulong)dhd;
3368         dhd->timer.function = dhd_watchdog;
3369         dhd->default_wd_interval = dhd_watchdog_ms;
3370
3371 #ifdef DHDTHREAD
3372         /* Initialize thread based operation and lock */
3373         sema_init(&dhd->sdsem, 1);
3374         if ((dhd_watchdog_prio >= 0) && (dhd_dpc_prio >= 0)) {
3375                 dhd->threads_only = TRUE;
3376         }
3377         else {
3378                 dhd->threads_only = FALSE;
3379         }
3380
3381         if (dhd_watchdog_prio >= 0) {
3382                 /* Initialize watchdog thread */
3383                 PROC_START(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0, "dhd_watchdog_thread");
3384
3385         } else {
3386                 dhd->thr_wdt_ctl.thr_pid = -1;
3387         }
3388
3389         /* Set up the bottom half handler */
3390         if (dhd_dpc_prio >= 0) {
3391                 /* Initialize DPC thread */
3392                 PROC_START(dhd_dpc_thread, dhd, &dhd->thr_dpc_ctl, 0, "dhd_dpc");
3393         } else {
3394                 /*  use tasklet for dpc */
3395                 tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd);
3396                 dhd->thr_dpc_ctl.thr_pid = -1;
3397         }
3398 #ifdef RXFRAME_THREAD
3399         bzero(&dhd->pub.skbbuf[0], sizeof(void *) * MAXSKBPEND);
3400         /* Initialize RXF thread */
3401         PROC_START(dhd_rxf_thread, dhd, &dhd->thr_rxf_ctl, 0, "dhd_rxf");
3402 #endif
3403 #else
3404         /* Set up the bottom half handler */
3405         tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd);
3406         dhd->dhd_tasklet_create = TRUE;
3407 #endif /* DHDTHREAD */
3408
3409         if (dhd_sysioc) {
3410                 PROC_START(_dhd_sysioc_thread, dhd, &dhd->thr_sysioc_ctl, 0, "dhd_sysioc");
3411         } else {
3412                 dhd->thr_sysioc_ctl.thr_pid = -1;
3413         }
3414         dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED;
3415
3416 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (1)
3417         INIT_WORK(&dhd->work_hang, dhd_hang_process);
3418 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))  */
3419
3420         /*
3421          * Save the dhd_info into the priv
3422          */
3423         memcpy(netdev_priv(net), &dhd, sizeof(dhd));
3424
3425 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \
3426         KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM_SLEEP)
3427         register_pm_notifier(&dhd_sleep_pm_notifier);
3428 #endif /* (LINUX_VERSION >= 2.6.27 && LINUX_VERSION <= 2.6.39 && CONFIG_PM_SLEEP */
3429
3430 #if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
3431         dhd->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 20;
3432         dhd->early_suspend.suspend = dhd_early_suspend;
3433         dhd->early_suspend.resume = dhd_late_resume;
3434         register_early_suspend(&dhd->early_suspend);
3435         dhd_state |= DHD_ATTACH_STATE_EARLYSUSPEND_DONE;
3436 #endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */
3437
3438 #ifdef ARP_OFFLOAD_SUPPORT
3439         dhd->pend_ipaddr = 0;
3440         register_inetaddr_notifier(&dhd_notifier);
3441 #endif /* ARP_OFFLOAD_SUPPORT */
3442         register_inet6addr_notifier(&dhd_notifier_ipv6);
3443
3444 #ifdef DHDTCPACK_SUPPRESS
3445         dhd->pub.tcp_ack_info_cnt = 0;
3446         bzero(dhd->pub.tcp_ack_info_tbl, sizeof(struct tcp_ack_info)*MAXTCPSTREAMS);
3447 #endif /* DHDTCPACK_SUPPRESS */
3448
3449         dhd_state |= DHD_ATTACH_STATE_DONE;
3450         dhd->dhd_state = dhd_state;
3451         return &dhd->pub;
3452
3453 fail:
3454         if (dhd_state < DHD_ATTACH_STATE_DHD_ALLOC) {
3455                 if (net) free_netdev(net);
3456         } else {
3457                 DHD_TRACE(("%s: Calling dhd_detach dhd_state 0x%x &dhd->pub %p\n",
3458                         __FUNCTION__, dhd_state, &dhd->pub));
3459                 dhd->dhd_state = dhd_state;
3460                 dhd_detach(&dhd->pub);
3461                 dhd_free(&dhd->pub);
3462         }
3463
3464         return NULL;
3465 }
3466
3467 int
3468 dhd_bus_start(dhd_pub_t *dhdp)
3469 {
3470         int ret = -1;
3471         dhd_info_t *dhd = (dhd_info_t*)dhdp->info;
3472         unsigned long flags;
3473
3474         ASSERT(dhd);
3475
3476         DHD_TRACE(("Enter %s:\n", __FUNCTION__));
3477
3478 #ifdef DHDTHREAD
3479         if (dhd->threads_only)
3480                 dhd_os_sdlock(dhdp);
3481 #endif /* DHDTHREAD */
3482
3483
3484         /* try to download image and nvram to the dongle */
3485         if  ((dhd->pub.busstate == DHD_BUS_DOWN) &&
3486                 (fw_path[0] != '\0') && (nv_path[0] != '\0')) {
3487 #ifdef SHOW_NVRAM_TYPE
3488                 {       /* Show nvram type in the kernel log */
3489                         int i;
3490                         for (i = 0; nv_path[i] != '\0'; ++i) {
3491                                 if (nv_path[i] == '.') {
3492                                         ++i;
3493                                         break;
3494                                 }
3495                         }
3496                         DHD_ERROR(("%s: nvram_type = [%s]\n", __FUNCTION__, &nv_path[i]));
3497                 }
3498 #endif /* SHOW_NVRAM_TYPE */
3499                 /* wake lock moved to dhdsdio_download_firmware */
3500                 if (!(dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh,
3501                         fw_path, nv_path, conf_path))) {
3502                         DHD_ERROR(("%s: dhdsdio_probe_download failed. firmware = %s nvram = %s config = %s\n",
3503                                 __FUNCTION__, fw_path, nv_path, conf_path));
3504 #ifdef DHDTHREAD
3505                         if (dhd->threads_only)
3506                                 dhd_os_sdunlock(dhdp);
3507 #endif /* DHDTHREAD */
3508                         return -1;
3509                 }
3510         }
3511         if (dhd->pub.busstate != DHD_BUS_LOAD) {
3512 #ifdef DHDTHREAD
3513                 if (dhd->threads_only)
3514                         dhd_os_sdunlock(dhdp);
3515 #endif /* DHDTHREAD */
3516                 return -ENETDOWN;
3517         }
3518
3519         /* Start the watchdog timer */
3520         dhd->pub.tickcnt = 0;
3521         dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms);
3522
3523         /* Bring up the bus */
3524         if ((ret = dhd_bus_init(&dhd->pub, FALSE)) != 0) {
3525
3526                 DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret));
3527 #ifdef DHDTHREAD
3528                 if (dhd->threads_only)
3529                         dhd_os_sdunlock(dhdp);
3530 #endif /* DHDTHREAD */
3531                 return ret;
3532         }
3533         bcmsdh_set_drvdata(dhdp); // terence 20130427: fix for null pointer issue
3534 #if defined(OOB_INTR_ONLY)
3535         /* Host registration for OOB interrupt */
3536         if (bcmsdh_register_oob_intr(dhdp)) {
3537                 /* deactivate timer and wait for the handler to finish */
3538
3539                 flags = dhd_os_spin_lock(&dhd->pub);
3540                 dhd->wd_timer_valid = FALSE;
3541                 dhd_os_spin_unlock(&dhd->pub, flags);
3542                 del_timer_sync(&dhd->timer);
3543
3544                 DHD_ERROR(("%s Host failed to register for OOB\n", __FUNCTION__));
3545 #ifdef DHDTHREAD
3546                 if (dhd->threads_only)
3547                         dhd_os_sdunlock(dhdp);
3548 #endif /* DHDTHREAD */
3549                 DHD_OS_WD_WAKE_UNLOCK(&dhd->pub);
3550                 return -ENODEV;
3551         }
3552
3553         /* Enable oob at firmware */
3554         dhd_enable_oob_intr(dhd->pub.bus, TRUE);
3555 #endif 
3556
3557         /* If bus is not ready, can't come up */
3558         if (dhd->pub.busstate != DHD_BUS_DATA) {
3559                 flags = dhd_os_spin_lock(&dhd->pub);
3560                 dhd->wd_timer_valid = FALSE;
3561                 dhd_os_spin_unlock(&dhd->pub, flags);
3562                 del_timer_sync(&dhd->timer);
3563                 DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__));
3564 #ifdef DHDTHREAD
3565                 if (dhd->threads_only)
3566                         dhd_os_sdunlock(dhdp);
3567 #endif /* DHDTHREAD */
3568                 DHD_OS_WD_WAKE_UNLOCK(&dhd->pub);
3569                 return -ENODEV;
3570         }
3571
3572 #ifdef DHDTHREAD
3573         if (dhd->threads_only)
3574                 dhd_os_sdunlock(dhdp);
3575 #endif /* DHDTHREAD */
3576
3577         dhd_process_cid_mac(dhdp, TRUE);
3578
3579         /* Bus is ready, do any protocol initialization */
3580         if ((ret = dhd_prot_init(&dhd->pub)) < 0)
3581                 return ret;
3582
3583         dhd_process_cid_mac(dhdp, FALSE);
3584
3585 #ifdef ARP_OFFLOAD_SUPPORT
3586         if (dhd->pend_ipaddr) {
3587 #ifdef AOE_IP_ALIAS_SUPPORT
3588                 aoe_update_host_ipv4_table(&dhd->pub, dhd->pend_ipaddr, TRUE, 0);
3589 #endif /* AOE_IP_ALIAS_SUPPORT */
3590                 dhd->pend_ipaddr = 0;
3591         }
3592 #endif /* ARP_OFFLOAD_SUPPORT */
3593
3594         return 0;
3595 }
3596 #ifdef WLTDLS
3597 int dhd_tdls_enable_disable(dhd_pub_t *dhd, bool flag)
3598 {
3599         char iovbuf[WLC_IOCTL_SMLEN];
3600         uint32 tdls = flag;
3601         int ret;
3602 #ifdef WLTDLS_AUTO_ENABLE
3603         uint32 tdls_auto_op = 1;
3604         uint32 tdls_idle_time = CUSTOM_TDLS_IDLE_MODE_SETTING;
3605 #endif /* WLTDLS_AUTO_ENABLE */
3606         if (!FW_SUPPORTED(dhd, tdls))
3607                 return BCME_ERROR;
3608
3609         bcm_mkiovar("tdls_enable", (char *)&tdls, sizeof(tdls), iovbuf, sizeof(iovbuf));
3610         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
3611                 DHD_ERROR(("%s: tdls %d failed %d\n", __FUNCTION__, tdls, ret));
3612                 goto exit;
3613         }
3614         dhd->tdls_enable = flag;
3615         if (!flag)
3616                 goto exit;
3617 #ifdef WLTDLS_AUTO_ENABLE
3618         bcm_mkiovar("tdls_auto_op", (char *)&tdls_auto_op, sizeof(tdls_auto_op),
3619                 iovbuf, sizeof(iovbuf));
3620         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
3621                 DHD_ERROR(("%s: tdls_auto_op failed %d\n", __FUNCTION__, ret));
3622                 goto exit;
3623         }
3624         bcm_mkiovar("tdls_idle_time", (char *)&tdls_idle_time, sizeof(tdls_idle_time),
3625                 iovbuf, sizeof(iovbuf));
3626         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
3627                 DHD_ERROR(("%s: tdls_idle_time failed %d\n", __FUNCTION__, ret));
3628                 goto exit;
3629         }
3630 #endif /* WLTDLS_AUTO_ENABLE */
3631 exit:
3632         return ret;
3633 }
3634 #endif /* WLTDLS */
3635
3636 bool dhd_is_concurrent_mode(dhd_pub_t *dhd)
3637 {
3638         if (!dhd)
3639                 return FALSE;
3640
3641         if (dhd->op_mode & DHD_FLAG_CONCURR_MULTI_CHAN_MODE)
3642                 return TRUE;
3643         else if ((dhd->op_mode & DHD_FLAG_CONCURR_SINGLE_CHAN_MODE) ==
3644                 DHD_FLAG_CONCURR_SINGLE_CHAN_MODE)
3645                 return TRUE;
3646         else
3647                 return FALSE;
3648 }
3649 #if !defined(AP) && defined(WLP2P)
3650 /* From Android JerryBean release, the concurrent mode is enabled by default and the firmware
3651  * name would be fw_bcmdhd.bin. So we need to determine whether P2P is enabled in the STA
3652  * firmware and accordingly enable concurrent mode (Apply P2P settings). SoftAP firmware
3653  * would still be named as fw_bcmdhd_apsta.
3654  */
3655 uint32
3656 dhd_get_concurrent_capabilites(dhd_pub_t *dhd)
3657 {
3658         int32 ret = 0;
3659         char buf[WLC_IOCTL_SMLEN];
3660         bool mchan_supported = FALSE;
3661         /* if dhd->op_mode is already set for HOSTAP,
3662           * that means we only will use the mode as it is
3663           */
3664         if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE)
3665                 return 0;
3666         if (FW_SUPPORTED(dhd, vsdb)) {
3667                 mchan_supported = TRUE;
3668         }
3669         if (!FW_SUPPORTED(dhd, p2p)) {
3670                 DHD_TRACE(("Chip does not support p2p\n"));
3671                 return 0;
3672         }
3673         else {
3674                 /* Chip supports p2p but ensure that p2p is really implemented in firmware or not */
3675                 memset(buf, 0, sizeof(buf));
3676                 bcm_mkiovar("p2p", 0, 0, buf, sizeof(buf));
3677                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf),
3678                         FALSE, 0)) < 0) {
3679                         DHD_ERROR(("%s: Get P2P failed (error=%d)\n", __FUNCTION__, ret));
3680                         return 0;
3681                 }
3682                 else {
3683                         if (buf[0] == 1) {
3684                                 /* By default, chip supports single chan concurrency,
3685                                 * now lets check for mchan
3686                                 */
3687                                 ret = DHD_FLAG_CONCURR_SINGLE_CHAN_MODE;
3688                                 if (mchan_supported)
3689                                         ret |= DHD_FLAG_CONCURR_MULTI_CHAN_MODE;
3690 #if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF)
3691                                 /* For customer_hw4, although ICS,
3692                                 * we still support concurrent mode
3693                                 */
3694                                 return ret;
3695 #else
3696                                 return 0;
3697 #endif
3698                         }
3699                 }
3700         }
3701         return 0;
3702 }
3703 #endif
3704
3705 int
3706 dhd_preinit_ioctls(dhd_pub_t *dhd)
3707 {
3708         int ret = 0;
3709         char eventmask[WL_EVENTING_MASK_LEN];
3710         char iovbuf[WL_EVENTING_MASK_LEN + 12]; /*  Room for "event_msgs" + '\0' + bitvec  */
3711         uint32 buf_key_b4_m4 = 1;
3712 #if defined(BCMSUP_4WAY_HANDSHAKE) && defined(WLAN_AKM_SUITE_FT_8021X)
3713         uint32 sup_wpa = 0;
3714 #endif
3715 #ifdef CUSTOM_AMPDU_BA_WSIZE
3716         uint32 ampdu_ba_wsize = CUSTOM_AMPDU_BA_WSIZE;
3717 #endif /* CUSTOM_AMPDU_BA_WSIZE */
3718 #ifdef DHD_ENABLE_LPC
3719         uint32 lpc = 1;
3720 #endif /* DHD_ENABLE_LPC */
3721         uint power_mode = PM_FAST;
3722         uint32 dongle_align = DHD_SDALIGN;
3723         uint32 glom = CUSTOM_GLOM_SETTING;
3724         uint bcn_timeout = 4;
3725         uint retry_max = 3;
3726 #if defined(ARP_OFFLOAD_SUPPORT)
3727         int arpoe = 1;
3728 #endif
3729         int scan_assoc_time = DHD_SCAN_ASSOC_ACTIVE_TIME;
3730         int scan_unassoc_time = DHD_SCAN_UNASSOC_ACTIVE_TIME;
3731         int scan_passive_time = DHD_SCAN_PASSIVE_TIME;
3732         char buf[WLC_IOCTL_SMLEN];
3733         char *ptr;
3734         uint32 listen_interval = CUSTOM_LISTEN_INTERVAL; /* Default Listen Interval in Beacons */
3735 #ifdef ROAM_ENABLE
3736         uint roamvar = 0;
3737         int roam_trigger[2] = {CUSTOM_ROAM_TRIGGER_SETTING, WLC_BAND_ALL};
3738         int roam_scan_period[2] = {10, WLC_BAND_ALL};
3739         int roam_delta[2] = {CUSTOM_ROAM_DELTA_SETTING, WLC_BAND_ALL};
3740 #ifdef FULL_ROAMING_SCAN_PERIOD_60_SEC
3741         int roam_fullscan_period = 60;
3742 #else /* FULL_ROAMING_SCAN_PERIOD_60_SEC */
3743         int roam_fullscan_period = 120;
3744 #endif /* FULL_ROAMING_SCAN_PERIOD_60_SEC */
3745 #else
3746 #ifdef DISABLE_BUILTIN_ROAM
3747         uint roamvar = 1;
3748 #endif /* DISABLE_BUILTIN_ROAM */
3749 #endif /* ROAM_ENABLE */
3750
3751 #if defined(SOFTAP)
3752         uint dtim = 1;
3753 #endif
3754 #if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211))
3755         uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */
3756         struct ether_addr p2p_ea;
3757 #endif
3758
3759 #if defined(AP) || defined(WLP2P)
3760         uint32 apsta = 1; /* Enable APSTA mode */
3761 #endif /* defined(AP) || defined(WLP2P) */
3762 #ifdef GET_CUSTOM_MAC_ENABLE
3763         struct ether_addr ea_addr;
3764 #endif /* GET_CUSTOM_MAC_ENABLE */
3765 #ifdef BCMCCX
3766         uint32 ccx = 1;
3767 #endif
3768
3769 #ifdef DISABLE_11N
3770         uint32 nmode = 0;
3771 #endif /* DISABLE_11N */
3772 #ifdef USE_WL_TXBF
3773         uint32 txbf = 1;
3774 #endif /* USE_WL_TXBF */
3775 #ifdef USE_WL_FRAMEBURST
3776         uint32 frameburst = 1;
3777 #endif /* USE_WL_FRAMEBURST */
3778 #ifdef DHD_SET_FW_HIGHSPEED
3779         uint32 ack_ratio = 250;
3780         uint32 ack_ratio_depth = 64;
3781 #endif /* DHD_SET_FW_HIGHSPEED */
3782 #ifdef SUPPORT_2G_VHT
3783         uint32 vht_features = 0x3; /* 2G enable | rates all */
3784 #endif /* SUPPORT_2G_VHT */
3785 #ifdef PROP_TXSTATUS
3786 #ifdef PROP_TXSTATUS_VSDB
3787         /* In case the host does not support proptxstatus, hostreorder in dongle should be off */
3788         uint32 hostreorder = 0;
3789         dhd->wlfc_enabled = FALSE;
3790         /* enable WLFC only if the firmware is VSDB */
3791 #else
3792         if (!disable_proptx)
3793                 dhd->wlfc_enabled = TRUE;
3794         else
3795                 dhd->wlfc_enabled = FALSE;
3796 #endif /* PROP_TXSTATUS_VSDB */
3797 #endif /* PROP_TXSTATUS */
3798
3799         dhd->suspend_bcn_li_dtim = CUSTOM_SUSPEND_BCN_LI_DTIM;
3800         DHD_TRACE(("Enter %s\n", __FUNCTION__));
3801
3802         dhd_conf_set_band(dhd);
3803
3804         dhd->op_mode = 0;
3805 #ifdef GET_CUSTOM_MAC_ENABLE
3806         ret = dhd_custom_get_mac_address(ea_addr.octet);
3807         if (!ret) {
3808                 memset(buf, 0, sizeof(buf));
3809                 bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN, buf, sizeof(buf));
3810                 ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
3811                 if (ret < 0) {
3812                         DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
3813                         return BCME_NOTUP;
3814                 }
3815                 memcpy(dhd->mac.octet, ea_addr.octet, ETHER_ADDR_LEN);
3816         } else {
3817 #endif /* GET_CUSTOM_MAC_ENABLE */
3818                 /* Get the default device MAC address directly from firmware */
3819                 memset(buf, 0, sizeof(buf));
3820                 bcm_mkiovar("cur_etheraddr", 0, 0, buf, sizeof(buf));
3821                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf),
3822                         FALSE, 0)) < 0) {
3823                         DHD_ERROR(("%s: can't get MAC address , error=%d\n", __FUNCTION__, ret));
3824                         return BCME_NOTUP;
3825                 }
3826                 /* Update public MAC address after reading from Firmware */
3827                 memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN);
3828
3829 #ifdef GET_CUSTOM_MAC_ENABLE
3830         }
3831 #endif /* GET_CUSTOM_MAC_ENABLE */
3832
3833         DHD_TRACE(("Firmware = %s\n", fw_path));
3834         /* get a capabilities from firmware */
3835         memset(dhd->fw_capabilities, 0, sizeof(dhd->fw_capabilities));
3836         bcm_mkiovar("cap", 0, 0, dhd->fw_capabilities, sizeof(dhd->fw_capabilities));
3837         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, dhd->fw_capabilities,
3838                 sizeof(dhd->fw_capabilities), FALSE, 0)) < 0) {
3839                 DHD_ERROR(("%s: Get Capability failed (error=%d)\n",
3840                         __FUNCTION__, ret));
3841                 return 0;
3842         }
3843         if ((!op_mode && strstr(fw_path, "_apsta") != NULL) ||
3844                 (op_mode == DHD_FLAG_HOSTAP_MODE)) {
3845 #ifdef SET_RANDOM_MAC_SOFTAP
3846                 uint rand_mac;
3847 #endif
3848                 dhd->op_mode = DHD_FLAG_HOSTAP_MODE;
3849 #if defined(ARP_OFFLOAD_SUPPORT)
3850                         arpoe = 0;
3851 #endif
3852 #ifdef PKT_FILTER_SUPPORT
3853                         dhd_pkt_filter_enable = FALSE;
3854 #endif
3855 #ifdef SET_RANDOM_MAC_SOFTAP
3856                 SRANDOM32((uint)jiffies);
3857                 rand_mac = RANDOM32();
3858                 iovbuf[0] = 0x02;                          /* locally administered bit */
3859                 iovbuf[1] = 0x1A;
3860                 iovbuf[2] = 0x11;
3861                 iovbuf[3] = (unsigned char)(rand_mac & 0x0F) | 0xF0;
3862                 iovbuf[4] = (unsigned char)(rand_mac >> 8);
3863                 iovbuf[5] = (unsigned char)(rand_mac >> 16);
3864
3865                 bcm_mkiovar("cur_etheraddr", (void *)iovbuf, ETHER_ADDR_LEN, buf, sizeof(buf));
3866                 ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
3867                 if (ret < 0) {
3868                         DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
3869                 } else
3870                         memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN);
3871 #endif /* SET_RANDOM_MAC_SOFTAP */
3872 #if !defined(AP) && defined(WL_CFG80211)
3873                 /* Turn off MPC in AP mode */
3874                 bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
3875                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
3876                         sizeof(iovbuf), TRUE, 0)) < 0) {
3877                         DHD_ERROR(("%s mpc for HostAPD failed  %d\n", __FUNCTION__, ret));
3878                 }
3879 #endif
3880         }
3881         else {
3882                 uint32 concurrent_mode = 0;
3883                 if ((!op_mode && strstr(fw_path, "_p2p") != NULL) ||
3884                         (op_mode == DHD_FLAG_P2P_MODE)) {
3885 #if defined(ARP_OFFLOAD_SUPPORT)
3886                         arpoe = 0;
3887 #endif
3888 #ifdef PKT_FILTER_SUPPORT
3889                         dhd_pkt_filter_enable = FALSE;
3890 #endif
3891                         dhd->op_mode = DHD_FLAG_P2P_MODE;
3892                 } else if (op_mode == DHD_FLAG_IBSS_MODE ||
3893                         (!op_mode && strstr(fw_path, "_ibss") != NULL)) {
3894                         dhd->op_mode = DHD_FLAG_IBSS_MODE;
3895                 } else {
3896                         dhd->op_mode = DHD_FLAG_STA_MODE;
3897                 }
3898 #if !defined(AP) && defined(WLP2P)
3899                 if (dhd->op_mode != DHD_FLAG_IBSS_MODE &&
3900                         (concurrent_mode = dhd_get_concurrent_capabilites(dhd))) {
3901 #if defined(ARP_OFFLOAD_SUPPORT)
3902                         arpoe = 1;
3903 #endif
3904                         dhd->op_mode |= concurrent_mode;
3905                 }
3906
3907                 /* Check if we are enabling p2p */
3908                 if (dhd->op_mode & DHD_FLAG_P2P_MODE) {
3909                         bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
3910                         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
3911                                 iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
3912                                 DHD_ERROR(("%s APSTA for P2P failed ret= %d\n", __FUNCTION__, ret));
3913                         }
3914
3915                         memcpy(&p2p_ea, &dhd->mac, ETHER_ADDR_LEN);
3916                         ETHER_SET_LOCALADDR(&p2p_ea);
3917                         bcm_mkiovar("p2p_da_override", (char *)&p2p_ea,
3918                                 ETHER_ADDR_LEN, iovbuf, sizeof(iovbuf));
3919                         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
3920                                 iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
3921                                 DHD_ERROR(("%s p2p_da_override ret= %d\n", __FUNCTION__, ret));
3922                         } else {
3923                                 DHD_INFO(("dhd_preinit_ioctls: p2p_da_override succeeded\n"));
3924                         }
3925                 }
3926 #else
3927         (void)concurrent_mode;
3928 #endif 
3929         }
3930
3931         DHD_ERROR(("Firmware up: op_mode=0x%04x, "
3932                 "Broadcom Dongle Host Driver mac="MACDBG"\n",
3933                 dhd->op_mode,
3934                 MAC2STRDBG(dhd->mac.octet)));
3935         /* Set Country code  */
3936         if (dhd->dhd_cspec.ccode[0] != 0) {
3937                 printf("Set country %s, revision %d\n", dhd->dhd_cspec.ccode, dhd->dhd_cspec.rev);
3938                 bcm_mkiovar("country", (char *)&dhd->dhd_cspec,
3939                         sizeof(wl_country_t), iovbuf, sizeof(iovbuf));
3940                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
3941                         printf("%s: country code setting failed %d\n", __FUNCTION__, ret);
3942         } else
3943                 dhd_conf_set_country(dhd);
3944         dhd_conf_get_country(dhd);
3945
3946         /* Set Listen Interval */
3947         bcm_mkiovar("assoc_listen", (char *)&listen_interval, 4, iovbuf, sizeof(iovbuf));
3948         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
3949                 DHD_ERROR(("%s assoc_listen failed %d\n", __FUNCTION__, ret));
3950
3951 #if defined(ROAM_ENABLE) || defined(DISABLE_BUILTIN_ROAM)
3952         /* Disable built-in roaming to allowed ext supplicant to take care of roaming */
3953         bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
3954         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
3955 #endif /* ROAM_ENABLE || DISABLE_BUILTIN_ROAM */
3956 #if defined(ROAM_ENABLE)
3957         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_TRIGGER, roam_trigger,
3958                 sizeof(roam_trigger), TRUE, 0)) < 0)
3959                 DHD_ERROR(("%s: roam trigger set failed %d\n", __FUNCTION__, ret));
3960         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_SCAN_PERIOD, roam_scan_period,
3961                 sizeof(roam_scan_period), TRUE, 0)) < 0)
3962                 DHD_ERROR(("%s: roam scan period set failed %d\n", __FUNCTION__, ret));
3963         if ((dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_DELTA, roam_delta,
3964                 sizeof(roam_delta), TRUE, 0)) < 0)
3965                 DHD_ERROR(("%s: roam delta set failed %d\n", __FUNCTION__, ret));
3966         bcm_mkiovar("fullroamperiod", (char *)&roam_fullscan_period, 4, iovbuf, sizeof(iovbuf));
3967         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
3968                 DHD_ERROR(("%s: roam fullscan period set failed %d\n", __FUNCTION__, ret));
3969 #endif /* ROAM_ENABLE */
3970         dhd_conf_set_roam(dhd);
3971
3972 #ifdef BCMCCX
3973         bcm_mkiovar("ccx_enable", (char *)&ccx, 4, iovbuf, sizeof(iovbuf));
3974         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
3975 #endif
3976 #ifdef WLTDLS
3977         dhd_tdls_enable_disable(dhd, 1);
3978 #endif /* WLTDLS */
3979
3980 #ifdef DHD_ENABLE_LPC
3981         /* Set lpc 1 */
3982         bcm_mkiovar("lpc", (char *)&lpc, 4, iovbuf, sizeof(iovbuf));
3983         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
3984                 sizeof(iovbuf), TRUE, 0)) < 0) {
3985                 DHD_ERROR(("%s Set lpc failed  %d\n", __FUNCTION__, ret));
3986         }
3987 #endif /* DHD_ENABLE_LPC */
3988
3989         /* Set PowerSave mode */
3990         dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0);
3991
3992         /* Match Host and Dongle rx alignment */
3993         bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf));
3994         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
3995
3996         if (glom != DEFAULT_GLOM_VALUE) {
3997                 DHD_INFO(("%s set glom=0x%X\n", __FUNCTION__, glom));
3998                 bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
3999                 dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
4000         }
4001
4002         /* Setup timeout if Beacons are lost and roam is off to report link down */
4003         bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf));
4004         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
4005         /* Setup assoc_retry_max count to reconnect target AP in dongle */
4006         bcm_mkiovar("assoc_retry_max", (char *)&retry_max, 4, iovbuf, sizeof(iovbuf));
4007         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
4008 #if defined(AP) && !defined(WLP2P)
4009         /* Turn off MPC in AP mode */
4010         bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
4011         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
4012         bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
4013         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
4014 #endif /* defined(AP) && !defined(WLP2P) */
4015         dhd_conf_set_bw(dhd);
4016         dhd_conf_force_wme(dhd);
4017         dhd_conf_set_stbc(dhd);
4018
4019 #if defined(SOFTAP)
4020         if (ap_fw_loaded == TRUE) {
4021                 dhd_wl_ioctl_cmd(dhd, WLC_SET_DTIMPRD, (char *)&dtim, sizeof(dtim), TRUE, 0);
4022         }
4023 #endif 
4024
4025 #if defined(KEEP_ALIVE)
4026         {
4027         /* Set Keep Alive : be sure to use FW with -keepalive */
4028         int res;
4029
4030 #if defined(SOFTAP)
4031         if (ap_fw_loaded == FALSE)
4032 #endif 
4033                 if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) {
4034                         if ((res = dhd_keep_alive_onoff(dhd)) < 0)
4035                                 DHD_ERROR(("%s set keeplive failed %d\n",
4036                                 __FUNCTION__, res));
4037                 }
4038         }
4039 #endif /* defined(KEEP_ALIVE) */
4040 #ifdef USE_WL_TXBF
4041         bcm_mkiovar("txbf", (char *)&txbf, 4, iovbuf, sizeof(iovbuf));
4042         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
4043                 sizeof(iovbuf), TRUE, 0)) < 0) {
4044                 DHD_ERROR(("%s Set txbf failed  %d\n", __FUNCTION__, ret));
4045         }
4046 #endif /* USE_WL_TXBF */
4047 #ifdef USE_WL_FRAMEBURST
4048         /* Set frameburst to value */
4049         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_FAKEFRAG, (char *)&frameburst,
4050                 sizeof(frameburst), TRUE, 0)) < 0) {
4051                 DHD_ERROR(("%s Set frameburst failed  %d\n", __FUNCTION__, ret));
4052         }
4053 #endif /* USE_WL_FRAMEBURST */
4054 #ifdef DHD_SET_FW_HIGHSPEED
4055         /* Set ack_ratio */
4056         bcm_mkiovar("ack_ratio", (char *)&ack_ratio, 4, iovbuf, sizeof(iovbuf));
4057         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
4058                 sizeof(iovbuf), TRUE, 0)) < 0) {
4059                 DHD_ERROR(("%s Set ack_ratio failed  %d\n", __FUNCTION__, ret));
4060         }
4061
4062         /* Set ack_ratio_depth */
4063         bcm_mkiovar("ack_ratio_depth", (char *)&ack_ratio_depth, 4, iovbuf, sizeof(iovbuf));
4064         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
4065                 sizeof(iovbuf), TRUE, 0)) < 0) {
4066                 DHD_ERROR(("%s Set ack_ratio_depth failed  %d\n", __FUNCTION__, ret));
4067         }
4068 #endif /* DHD_SET_FW_HIGHSPEED */
4069 #ifdef CUSTOM_AMPDU_BA_WSIZE
4070         /* Set ampdu ba wsize to 64 */
4071         bcm_mkiovar("ampdu_ba_wsize", (char *)&ampdu_ba_wsize, 4, iovbuf, sizeof(iovbuf));
4072         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
4073                 sizeof(iovbuf), TRUE, 0)) < 0) {
4074                 DHD_ERROR(("%s Set ampdu_ba_wsize to %d failed  %d\n",
4075                         __FUNCTION__, CUSTOM_AMPDU_BA_WSIZE, ret));
4076         }
4077 #endif /* CUSTOM_AMPDU_BA_WSIZE */
4078 #if defined(BCMSUP_4WAY_HANDSHAKE) && defined(WLAN_AKM_SUITE_FT_8021X)
4079         /* Read 4-way handshake requirements. */
4080         bcm_mkiovar("sup_wpa", (char *)&sup_wpa, 4,
4081                 iovbuf, sizeof(iovbuf));
4082         ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0);
4083         if (ret >= 0)
4084                 dhd->fw_4way_handshake = TRUE;
4085         DHD_TRACE(("4-way handshake mode is: %d\n", dhd->fw_4way_handshake));
4086 #endif /* BCMSUP_4WAY_HANDSHAKE && WLAN_AKM_SUITE_FT_8021X */
4087 #ifdef SUPPORT_2G_VHT
4088         bcm_mkiovar("vht_features", (char *)&vht_features, 4, iovbuf, sizeof(iovbuf));
4089         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
4090                 DHD_ERROR(("%s vht_features set failed %d\n", __FUNCTION__, ret));
4091         }
4092 #endif /* SUPPORT_2G_VHT */
4093
4094         bcm_mkiovar("buf_key_b4_m4", (char *)&buf_key_b4_m4, 4, iovbuf, sizeof(iovbuf));
4095         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
4096                 sizeof(iovbuf), TRUE, 0)) < 0) {
4097                 DHD_ERROR(("%s buf_key_b4_m4 set failed %d\n", __FUNCTION__, ret));
4098         }
4099
4100         /* Read event_msgs mask */
4101         bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
4102         if ((ret  = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0)) < 0) {
4103                 DHD_ERROR(("%s read Event mask failed %d\n", __FUNCTION__, ret));
4104                 goto done;
4105         }
4106         bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN);
4107
4108         /* Setup event_msgs */
4109         setbit(eventmask, WLC_E_SET_SSID);
4110         setbit(eventmask, WLC_E_PRUNE);
4111         setbit(eventmask, WLC_E_AUTH);
4112         setbit(eventmask, WLC_E_ASSOC);
4113         setbit(eventmask, WLC_E_REASSOC);
4114         setbit(eventmask, WLC_E_REASSOC_IND);
4115         setbit(eventmask, WLC_E_DEAUTH);
4116         setbit(eventmask, WLC_E_DEAUTH_IND);
4117         setbit(eventmask, WLC_E_DISASSOC_IND);
4118         setbit(eventmask, WLC_E_DISASSOC);
4119         setbit(eventmask, WLC_E_JOIN);
4120         setbit(eventmask, WLC_E_START);
4121         setbit(eventmask, WLC_E_ASSOC_IND);
4122         setbit(eventmask, WLC_E_PSK_SUP);
4123         setbit(eventmask, WLC_E_LINK);
4124         setbit(eventmask, WLC_E_NDIS_LINK);
4125         setbit(eventmask, WLC_E_MIC_ERROR);
4126         setbit(eventmask, WLC_E_ASSOC_REQ_IE);
4127         setbit(eventmask, WLC_E_ASSOC_RESP_IE);
4128 #ifndef WL_CFG80211
4129         setbit(eventmask, WLC_E_PMKID_CACHE);
4130         setbit(eventmask, WLC_E_TXFAIL);
4131 #endif
4132         setbit(eventmask, WLC_E_JOIN_START);
4133         setbit(eventmask, WLC_E_SCAN_COMPLETE);
4134 #ifdef WLMEDIA_HTSF
4135         setbit(eventmask, WLC_E_HTSFSYNC);
4136 #endif /* WLMEDIA_HTSF */
4137 #ifdef PNO_SUPPORT
4138         setbit(eventmask, WLC_E_PFN_NET_FOUND);
4139         setbit(eventmask, WLC_E_PFN_BEST_BATCHING);
4140         setbit(eventmask, WLC_E_PFN_BSSID_NET_FOUND);
4141         setbit(eventmask, WLC_E_PFN_BSSID_NET_LOST);
4142 #endif /* PNO_SUPPORT */
4143         /* enable dongle roaming event */
4144         setbit(eventmask, WLC_E_ROAM);
4145 #ifdef BCMCCX
4146         setbit(eventmask, WLC_E_ADDTS_IND);
4147         setbit(eventmask, WLC_E_DELTS_IND);
4148 #endif /* BCMCCX */
4149 #ifdef WLTDLS
4150         setbit(eventmask, WLC_E_TDLS_PEER_EVENT);
4151 #endif /* WLTDLS */
4152 #ifdef WL_CFG80211
4153         setbit(eventmask, WLC_E_ESCAN_RESULT);
4154         if (dhd->op_mode & DHD_FLAG_P2P_MODE) {
4155                 setbit(eventmask, WLC_E_ACTION_FRAME_RX);
4156                 setbit(eventmask, WLC_E_P2P_DISC_LISTEN_COMPLETE);
4157         }
4158 #endif /* WL_CFG80211 */
4159
4160         /* Write updated Event mask */
4161         bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
4162         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
4163                 DHD_ERROR(("%s Set Event mask failed %d\n", __FUNCTION__, ret));
4164                 goto done;
4165         }
4166
4167         dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_CHANNEL_TIME, (char *)&scan_assoc_time,
4168                 sizeof(scan_assoc_time), TRUE, 0);
4169         dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time,
4170                 sizeof(scan_unassoc_time), TRUE, 0);
4171         dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_PASSIVE_TIME, (char *)&scan_passive_time,
4172                 sizeof(scan_passive_time), TRUE, 0);
4173
4174 #ifdef ARP_OFFLOAD_SUPPORT
4175         /* Set and enable ARP offload feature for STA only  */
4176 #if defined(SOFTAP)
4177         if (arpoe && !ap_fw_loaded)
4178 #else
4179         if (arpoe)
4180 #endif
4181         {
4182                 dhd_arp_offload_enable(dhd, TRUE);
4183                 dhd_arp_offload_set(dhd, dhd_arp_mode);
4184         } else {
4185                 dhd_arp_offload_enable(dhd, FALSE);
4186                 dhd_arp_offload_set(dhd, 0);
4187         }
4188         dhd_arp_enable = arpoe;
4189 #endif /* ARP_OFFLOAD_SUPPORT */
4190
4191 #ifdef PKT_FILTER_SUPPORT
4192         if (dhd->conf->filter_out_all_packets) {
4193                 dhd_master_mode = FALSE;
4194                 dhd->pktfilter_count = 1;
4195                 dhd->pktfilter[0] = "99 0 0 0 0x000000000000 0xFFFFFFFFFFFF";
4196         } else {
4197                 /* Setup default defintions for pktfilter , enable in suspend */
4198                 dhd->pktfilter_count = 6;
4199                 /* Setup filter to allow only unicast */
4200                 dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 0x01 0x00";
4201                 dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = NULL;
4202                 dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = NULL;
4203                 dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = NULL;
4204                 /* Add filter to pass multicastDNS packet and NOT filter out as Broadcast */
4205                 dhd->pktfilter[DHD_MDNS_FILTER_NUM] = "104 0 0 0 0xFFFFFFFFFFFF 0x01005E0000FB";
4206                 /* apply APP pktfilter */
4207                 dhd->pktfilter[DHD_ARP_FILTER_NUM] = "105 0 0 12 0xFFFF 0x0806";
4208         }
4209
4210 #if defined(SOFTAP)
4211         if (ap_fw_loaded) {
4212                 dhd_enable_packet_filter(0, dhd);
4213         }
4214 #endif /* defined(SOFTAP) */
4215         dhd_set_packet_filter(dhd);
4216 #endif /* PKT_FILTER_SUPPORT */
4217 #ifdef DISABLE_11N
4218         bcm_mkiovar("nmode", (char *)&nmode, 4, iovbuf, sizeof(iovbuf));
4219         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
4220                 DHD_ERROR(("%s wl nmode 0 failed %d\n", __FUNCTION__, ret));
4221 #else
4222 #if defined(PROP_TXSTATUS) && defined(PROP_TXSTATUS_VSDB)
4223         bcm_mkiovar("ampdu_hostreorder", (char *)&hostreorder, 4, buf, sizeof(buf));
4224         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
4225 #endif 
4226 #endif /* DISABLE_11N */
4227
4228         /* query for 'ver' to get version info from firmware */
4229         memset(buf, 0, sizeof(buf));
4230         ptr = buf;
4231         bcm_mkiovar("ver", (char *)&buf, 4, buf, sizeof(buf));
4232         if ((ret  = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), FALSE, 0)) < 0)
4233                 DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret));
4234         else {
4235                 bcmstrtok(&ptr, "\n", 0);
4236                 /* Print fw version info */
4237                 DHD_ERROR(("Firmware version = %s\n", buf));
4238                 dhd_set_version_info(dhd, buf);
4239
4240                 /* Check and adjust IOCTL response timeout for Manufactring firmware */
4241                 if (strstr(buf, MANUFACTRING_FW) != NULL) {
4242                         dhd_os_set_ioctl_resp_timeout(20000);
4243                         DHD_ERROR(("%s : adjust IOCTL response time for Manufactring Firmware\n",
4244                         __FUNCTION__));
4245                 }
4246         }
4247
4248 #ifdef BCMSDIOH_TXGLOM
4249         if (bcmsdh_glom_enabled()) {
4250                 dhd_txglom_enable(dhd, TRUE);
4251         }
4252 #endif /* BCMSDIOH_TXGLOM */
4253
4254 #if defined(PROP_TXSTATUS) && !defined(PROP_TXSTATUS_VSDB)
4255         dhd_wlfc_init(dhd);
4256 #endif /* PROP_TXSTATUS && !PROP_TXSTATUS_VSDB */
4257 #ifdef PNO_SUPPORT
4258         if (!dhd->pno_state) {
4259                 dhd_pno_init(dhd);
4260         }
4261 #endif
4262
4263 done:
4264         return ret;
4265 }
4266
4267
4268 int
4269 dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, int set)
4270 {
4271         char buf[strlen(name) + 1 + cmd_len];
4272         int len = sizeof(buf);
4273         wl_ioctl_t ioc;
4274         int ret;
4275
4276         len = bcm_mkiovar(name, cmd_buf, cmd_len, buf, len);
4277
4278         memset(&ioc, 0, sizeof(ioc));
4279
4280         ioc.cmd = set? WLC_SET_VAR : WLC_GET_VAR;
4281         ioc.buf = buf;
4282         ioc.len = len;
4283         ioc.set = set;
4284
4285         ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len);
4286         if (!set && ret >= 0)
4287                 memcpy(cmd_buf, buf, cmd_len);
4288
4289         return ret;
4290 }
4291
4292 int dhd_change_mtu(dhd_pub_t *dhdp, int new_mtu, int ifidx)
4293 {
4294         struct dhd_info *dhd = dhdp->info;
4295         struct net_device *dev = NULL;
4296
4297         ASSERT(dhd && dhd->iflist[ifidx]);
4298         dev = dhd->iflist[ifidx]->net;
4299         ASSERT(dev);
4300
4301         if (netif_running(dev)) {
4302                 DHD_ERROR(("%s: Must be down to change its MTU", dev->name));
4303                 return BCME_NOTDOWN;
4304         }
4305
4306 #define DHD_MIN_MTU 1500
4307 #define DHD_MAX_MTU 1752
4308
4309         if ((new_mtu < DHD_MIN_MTU) || (new_mtu > DHD_MAX_MTU)) {
4310                 DHD_ERROR(("%s: MTU size %d is invalid.\n", __FUNCTION__, new_mtu));
4311                 return BCME_BADARG;
4312         }
4313
4314         dev->mtu = new_mtu;
4315         return 0;
4316 }
4317
4318 #ifdef ARP_OFFLOAD_SUPPORT
4319 /* add or remove AOE host ip(s) (up to 8 IPs on the interface)  */
4320 void
4321 aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx)
4322 {
4323         u32 ipv4_buf[MAX_IPV4_ENTRIES]; /* temp save for AOE host_ip table */
4324         int i;
4325         int ret;
4326
4327         bzero(ipv4_buf, sizeof(ipv4_buf));
4328
4329         /* display what we've got */
4330         ret = dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx);
4331         DHD_ARPOE(("%s: hostip table read from Dongle:\n", __FUNCTION__));
4332 #ifdef AOE_DBG
4333         dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */
4334 #endif
4335         /* now we saved hoste_ip table, clr it in the dongle AOE */
4336         dhd_aoe_hostip_clr(dhd_pub, idx);
4337
4338         if (ret) {
4339                 DHD_ERROR(("%s failed\n", __FUNCTION__));
4340                 return;
4341         }
4342
4343         for (i = 0; i < MAX_IPV4_ENTRIES; i++) {
4344                 if (add && (ipv4_buf[i] == 0)) {
4345                                 ipv4_buf[i] = ipa;
4346                                 add = FALSE; /* added ipa to local table  */
4347                                 DHD_ARPOE(("%s: Saved new IP in temp arp_hostip[%d]\n",
4348                                 __FUNCTION__, i));
4349                 } else if (ipv4_buf[i] == ipa) {
4350                         ipv4_buf[i]     = 0;
4351                         DHD_ARPOE(("%s: removed IP:%x from temp table %d\n",
4352                                 __FUNCTION__, ipa, i));
4353                 }
4354
4355                 if (ipv4_buf[i] != 0) {
4356                         /* add back host_ip entries from our local cache */
4357                         dhd_arp_offload_add_ip(dhd_pub, ipv4_buf[i], idx);
4358                         DHD_ARPOE(("%s: added IP:%x to dongle arp_hostip[%d]\n\n",
4359                                 __FUNCTION__, ipv4_buf[i], i));
4360                 }
4361         }
4362 #ifdef AOE_DBG
4363         /* see the resulting hostip table */
4364         dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx);
4365         DHD_ARPOE(("%s: read back arp_hostip table:\n", __FUNCTION__));
4366         dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */
4367 #endif
4368 }
4369
4370 /*
4371  * Notification mechanism from kernel to our driver. This function is called by the Linux kernel
4372  * whenever there is an event related to an IP address.
4373  * ptr : kernel provided pointer to IP address that has changed
4374  */
4375 static int dhd_device_event(struct notifier_block *this,
4376         unsigned long event,
4377         void *ptr)
4378 {
4379         struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
4380
4381         dhd_info_t *dhd;
4382         dhd_pub_t *dhd_pub;
4383         int idx;
4384
4385         if (!dhd_arp_enable)
4386                 return NOTIFY_DONE;
4387         if (!ifa || !(ifa->ifa_dev->dev))
4388                 return NOTIFY_DONE;
4389
4390 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
4391         /* Filter notifications meant for non Broadcom devices */
4392         if ((ifa->ifa_dev->dev->netdev_ops != &dhd_ops_pri) &&
4393             (ifa->ifa_dev->dev->netdev_ops != &dhd_ops_virt)) {
4394 #if defined(WL_ENABLE_P2P_IF)
4395                 if (!wl_cfgp2p_is_ifops(ifa->ifa_dev->dev->netdev_ops))
4396 #endif /* WL_ENABLE_P2P_IF */
4397                         return NOTIFY_DONE;
4398         }
4399 #endif /* LINUX_VERSION_CODE */
4400
4401         dhd = *(dhd_info_t **)netdev_priv(ifa->ifa_dev->dev);
4402         if (!dhd)
4403                 return NOTIFY_DONE;
4404
4405         dhd_pub = &dhd->pub;
4406
4407         if (dhd_pub->arp_version == 1) {
4408                 idx = 0;
4409         }
4410         else {
4411                 for (idx = 0; idx < DHD_MAX_IFS; idx++) {
4412                         if (dhd->iflist[idx] && dhd->iflist[idx]->net == ifa->ifa_dev->dev)
4413                         break;
4414                 }
4415                 if (idx < DHD_MAX_IFS)
4416                         DHD_TRACE(("ifidx : %p %s %d\n", dhd->iflist[idx]->net,
4417                                 dhd->iflist[idx]->name, dhd->iflist[idx]->idx));
4418                 else {
4419                         DHD_ERROR(("Cannot find ifidx for(%s) set to 0\n", ifa->ifa_label));
4420                         idx = 0;
4421                 }
4422         }
4423
4424         switch (event) {
4425                 case NETDEV_UP:
4426                         DHD_ARPOE(("%s: [%s] Up IP: 0x%x\n",
4427                                 __FUNCTION__, ifa->ifa_label, ifa->ifa_address));
4428
4429                         if (dhd->pub.busstate != DHD_BUS_DATA) {
4430                                 DHD_ERROR(("%s: bus not ready, exit\n", __FUNCTION__));
4431                                 if (dhd->pend_ipaddr) {
4432                                         DHD_ERROR(("%s: overwrite pending ipaddr: 0x%x\n",
4433                                                 __FUNCTION__, dhd->pend_ipaddr));
4434                                 }
4435                                 dhd->pend_ipaddr = ifa->ifa_address;
4436                                 break;
4437                         }
4438
4439 #ifdef AOE_IP_ALIAS_SUPPORT
4440                         DHD_ARPOE(("%s:add aliased IP to AOE hostip cache\n",
4441                                 __FUNCTION__));
4442                         aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE, idx);
4443 #endif /* AOE_IP_ALIAS_SUPPORT */
4444                         break;
4445
4446                 case NETDEV_DOWN:
4447                         DHD_ARPOE(("%s: [%s] Down IP: 0x%x\n",
4448                                 __FUNCTION__, ifa->ifa_label, ifa->ifa_address));
4449                         dhd->pend_ipaddr = 0;
4450 #ifdef AOE_IP_ALIAS_SUPPORT
4451                         DHD_ARPOE(("%s:interface is down, AOE clr all for this if\n",
4452                                 __FUNCTION__));
4453                         aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, FALSE, idx);
4454 #else
4455                         dhd_aoe_hostip_clr(&dhd->pub, idx);
4456                         dhd_aoe_arp_clr(&dhd->pub, idx);
4457 #endif /* AOE_IP_ALIAS_SUPPORT */
4458                         break;
4459
4460                 default:
4461                         DHD_ARPOE(("%s: do noting for [%s] Event: %lu\n",
4462                                 __func__, ifa->ifa_label, event));
4463                         break;
4464         }
4465         return NOTIFY_DONE;
4466 }
4467 #endif /* ARP_OFFLOAD_SUPPORT */
4468
4469 /*
4470  * Neighbor Discovery Offload: Called when an interface
4471  * is assigned with ipv6 address.
4472  * Handles only primary interface
4473  */
4474 static int dhd_device_ipv6_event(struct notifier_block *this,
4475         unsigned long event,
4476         void *ptr)
4477 {
4478         dhd_info_t *dhd;
4479         dhd_pub_t *dhd_pub;
4480         struct ipv6_addr *_ipv6_addr = NULL;
4481         struct inet6_ifaddr *inet6_ifa = ptr;
4482         int idx = 0;
4483 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
4484         /* Filter notifications meant for non Broadcom devices */
4485         if (inet6_ifa->idev->dev->netdev_ops != &dhd_ops_pri) {
4486                         goto exit;
4487         }
4488 #endif /* LINUX_VERSION_CODE */
4489
4490         dhd = *(dhd_info_t **)netdev_priv(inet6_ifa->idev->dev);
4491         if (!dhd)
4492                 goto exit;
4493
4494         idx = dhd_net2idx(dhd, inet6_ifa->idev->dev);
4495         if (idx == DHD_BAD_IF) {
4496                 DHD_ERROR(("Cannot find ifidx"));
4497                 goto exit;
4498         }
4499         dhd_pub = &dhd->pub;
4500         if (!FW_SUPPORTED(dhd_pub, ndoe))
4501                 goto exit;
4502         if (event == NETDEV_UP || event == NETDEV_DOWN) {
4503                 _ipv6_addr = NATIVE_MALLOC(dhd_pub->osh, sizeof(struct ipv6_addr));
4504                 if (_ipv6_addr == NULL) {
4505                         DHD_ERROR(("Failed to allocate ipv6\n"));
4506                         goto exit;
4507                 }
4508                 memcpy(&_ipv6_addr->ipv6_addr[0], &inet6_ifa->addr, IPV6_ADDR_LEN);
4509                 DHD_TRACE(("IPV6 address : %pI6\n", &inet6_ifa->addr));
4510         }
4511         switch (event) {
4512                 case NETDEV_UP:
4513                         DHD_TRACE(("%s: Enable NDO and add ipv6 into table \n ", __FUNCTION__));
4514                         _ipv6_addr->ipv6_oper = DHD_IPV6_ADDR_ADD;
4515                         break;
4516                 case NETDEV_DOWN:
4517                         DHD_TRACE(("%s: clear ipv6 table \n", __FUNCTION__));
4518                         _ipv6_addr->ipv6_oper = DHD_IPV6_ADDR_DELETE;
4519                         break;
4520                 default:
4521                         DHD_ERROR(("%s: unknown notifier event \n", __FUNCTION__));
4522                         goto exit;
4523         }
4524         spin_lock_bh(&dhd->iflist[idx]->ipv6_lock);
4525         list_add_tail(&_ipv6_addr->list, &dhd->iflist[idx]->ipv6_list);
4526         spin_unlock_bh(&dhd->iflist[idx]->ipv6_lock);
4527         up(&dhd->thr_sysioc_ctl.sema);
4528 exit:
4529         return NOTIFY_DONE;
4530 }
4531
4532 int
4533 dhd_net_attach(dhd_pub_t *dhdp, int ifidx)
4534 {
4535         dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
4536         struct net_device *net = NULL;
4537         int err = 0;
4538         uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33 };
4539
4540         DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx));
4541
4542         ASSERT(dhd && dhd->iflist[ifidx]);
4543
4544         net = dhd->iflist[ifidx]->net;
4545         ASSERT(net);
4546
4547 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
4548         ASSERT(!net->open);
4549         net->get_stats = dhd_get_stats;
4550         net->do_ioctl = dhd_ioctl_entry;
4551         net->hard_start_xmit = dhd_start_xmit;
4552         net->set_mac_address = dhd_set_mac_address;
4553         net->set_multicast_list = dhd_set_multicast_list;
4554         net->open = net->stop = NULL;
4555 #else
4556         ASSERT(!net->netdev_ops);
4557         net->netdev_ops = &dhd_ops_virt;
4558 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */
4559
4560         /* Ok, link into the network layer... */
4561         if (ifidx == 0) {
4562                 /*
4563                  * device functions for the primary interface only
4564                  */
4565 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
4566                 net->open = dhd_open;
4567                 net->stop = dhd_stop;
4568 #else
4569                 net->netdev_ops = &dhd_ops_pri;
4570 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */
4571                 if (!ETHER_ISNULLADDR(dhd->pub.mac.octet))
4572                         memcpy(temp_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN);
4573         } else {
4574                 /*
4575                  * We have to use the primary MAC for virtual interfaces
4576                  */
4577                 memcpy(temp_addr, dhd->iflist[ifidx]->mac_addr, ETHER_ADDR_LEN);
4578                 /*
4579                  * Android sets the locally administered bit to indicate that this is a
4580                  * portable hotspot.  This will not work in simultaneous AP/STA mode,
4581                  * nor with P2P.  Need to set the Donlge's MAC address, and then use that.
4582                  */
4583                 if (!memcmp(temp_addr, dhd->iflist[0]->mac_addr,
4584                         ETHER_ADDR_LEN)) {
4585                         DHD_ERROR(("%s interface [%s]: set locally administered bit in MAC\n",
4586                         __func__, net->name));
4587                         temp_addr[0] |= 0x02;
4588                 }
4589         }
4590
4591         net->hard_header_len = ETH_HLEN + dhd->pub.hdrlen;
4592 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
4593         net->ethtool_ops = &dhd_ethtool_ops;
4594 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */
4595
4596 #if defined(WL_WIRELESS_EXT)
4597 #if WIRELESS_EXT < 19
4598         net->get_wireless_stats = dhd_get_wireless_stats;
4599 #endif /* WIRELESS_EXT < 19 */
4600 #if WIRELESS_EXT > 12
4601         net->wireless_handlers = (struct iw_handler_def *)&wl_iw_handler_def;
4602 #endif /* WIRELESS_EXT > 12 */
4603 #endif /* defined(WL_WIRELESS_EXT) */
4604
4605         dhd->pub.rxsz = DBUS_RX_BUFFER_SIZE_DHD(net);
4606
4607         memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN);
4608
4609         net->ifindex = 0;
4610         if ((err = register_netdev(net)) != 0) {
4611                 DHD_ERROR(("couldn't register the net device, err %d\n", err));
4612                 goto fail;
4613         }
4614         printf("Broadcom Dongle Host Driver: register interface [%s]"
4615                 " MAC: "MACDBG"\n",
4616                 net->name,
4617                 MAC2STRDBG(net->dev_addr));
4618
4619 #if defined(SOFTAP) && defined(WL_WIRELESS_EXT) && !defined(WL_CFG80211)
4620                 wl_iw_iscan_set_scan_broadcast_prep(net, 1);
4621 #endif
4622
4623 #if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
4624         if (ifidx == 0) {
4625                 dhd_registration_check = TRUE;
4626                 up(&dhd_registration_sem);
4627         }
4628 #endif 
4629         return 0;
4630
4631 fail:
4632 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
4633         net->open = NULL;
4634 #else
4635         net->netdev_ops = NULL;
4636 #endif
4637         return err;
4638 }
4639
4640 void
4641 dhd_bus_detach(dhd_pub_t *dhdp)
4642 {
4643         dhd_info_t *dhd;
4644
4645         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4646
4647         if (dhdp) {
4648                 dhd = (dhd_info_t *)dhdp->info;
4649                 if (dhd) {
4650
4651                         /*
4652                          * In case of Android cfg80211 driver, the bus is down in dhd_stop,
4653                          *  calling stop again will cuase SD read/write errors.
4654                          */
4655                         if (dhd->pub.busstate != DHD_BUS_DOWN) {
4656                                 /* Stop the protocol module */
4657                                 dhd_prot_stop(&dhd->pub);
4658
4659                                 /* Stop the bus module */
4660                                 dhd_bus_stop(dhd->pub.bus, TRUE);
4661                         }
4662
4663 #if defined(OOB_INTR_ONLY)
4664                         bcmsdh_unregister_oob_intr();
4665 #endif 
4666                 }
4667         }
4668 }
4669
4670
4671 void dhd_detach(dhd_pub_t *dhdp)
4672 {
4673         dhd_info_t *dhd;
4674         unsigned long flags;
4675         int timer_valid = FALSE;
4676
4677         if (!dhdp)
4678                 return;
4679
4680         dhd = (dhd_info_t *)dhdp->info;
4681         if (!dhd)
4682                 return;
4683
4684         DHD_TRACE(("%s: Enter state 0x%x\n", __FUNCTION__, dhd->dhd_state));
4685 #ifdef ARP_OFFLOAD_SUPPORT
4686         unregister_inetaddr_notifier(&dhd_notifier);
4687 #endif /* ARP_OFFLOAD_SUPPORT */
4688         unregister_inet6addr_notifier(&dhd_notifier_ipv6);
4689
4690         dhd->pub.up = 0;
4691         if (!(dhd->dhd_state & DHD_ATTACH_STATE_DONE)) {
4692                 /* Give sufficient time for threads to start running in case
4693                  * dhd_attach() has failed
4694                  */
4695                 OSL_SLEEP(100);
4696         }
4697
4698         if (dhd->dhd_state & DHD_ATTACH_STATE_PROT_ATTACH) {
4699                 dhd_bus_detach(dhdp);
4700
4701                 if (dhdp->prot)
4702                         dhd_prot_detach(dhdp);
4703         }
4704
4705 #if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
4706         if (dhd->dhd_state & DHD_ATTACH_STATE_EARLYSUSPEND_DONE) {
4707                 if (dhd->early_suspend.suspend)
4708                         unregister_early_suspend(&dhd->early_suspend);
4709         }
4710 #endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */
4711
4712 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
4713         cancel_work_sync(&dhd->work_hang);
4714 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))  */
4715
4716 #if defined(WL_WIRELESS_EXT)
4717         if (dhd->dhd_state & DHD_ATTACH_STATE_WL_ATTACH) {
4718                 /* Detatch and unlink in the iw */
4719                 wl_iw_detach();
4720         }
4721 #endif /* defined(WL_WIRELESS_EXT) */
4722
4723         if (dhd->thr_sysioc_ctl.thr_pid >= 0) {
4724                 PROC_STOP(&dhd->thr_sysioc_ctl);
4725         }
4726
4727         /* delete all interfaces, start with virtual  */
4728         if (dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) {
4729                 int i = 1;
4730                 dhd_if_t *ifp;
4731
4732                 /* Cleanup virtual interfaces */
4733                 for (i = 1; i < DHD_MAX_IFS; i++) {
4734                         dhd_net_if_lock_local(dhd);
4735                         if (dhd->iflist[i]) {
4736                                 dhd->iflist[i]->state = DHD_IF_DEL;
4737                                 dhd->iflist[i]->idx = i;
4738                                 dhd_op_if(dhd->iflist[i]);
4739                         }
4740
4741                         dhd_net_if_unlock_local(dhd);
4742                 }
4743                 /*  delete primary interface 0 */
4744                 ifp = dhd->iflist[0];
4745                 ASSERT(ifp);
4746                 ASSERT(ifp->net);
4747                 if (ifp && ifp->net) {
4748 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
4749                         if (ifp->net->open)
4750 #else
4751                         if (ifp->net->netdev_ops == &dhd_ops_pri)
4752 #endif
4753                         {
4754                                 unregister_netdev(ifp->net);
4755                                 free_netdev(ifp->net);
4756                                 ifp->net = NULL;
4757                                 MFREE(dhd->pub.osh, ifp, sizeof(*ifp));
4758                                 dhd->iflist[0] = NULL;
4759                         }
4760                 }
4761         }
4762
4763         /* Clear the watchdog timer */
4764         flags = dhd_os_spin_lock(&dhd->pub);
4765         timer_valid = dhd->wd_timer_valid;
4766         dhd->wd_timer_valid = FALSE;
4767         dhd_os_spin_unlock(&dhd->pub, flags);
4768         if (timer_valid)
4769                 del_timer_sync(&dhd->timer);
4770
4771         if (dhd->dhd_state & DHD_ATTACH_STATE_THREADS_CREATED) {
4772 #ifdef DHDTHREAD
4773                 if (dhd->thr_wdt_ctl.thr_pid >= 0) {
4774                         PROC_STOP(&dhd->thr_wdt_ctl);
4775                 }
4776
4777                 if (dhd->thr_dpc_ctl.thr_pid >= 0) {
4778                         PROC_STOP(&dhd->thr_dpc_ctl);
4779                 }
4780 #ifdef RXFRAME_THREAD
4781                 if (dhd->thr_rxf_ctl.thr_pid >= 0) {
4782                         PROC_STOP(&dhd->thr_rxf_ctl);
4783                 }
4784 #endif
4785                 else
4786 #endif /* DHDTHREAD */
4787                 tasklet_kill(&dhd->tasklet);
4788         }
4789 #ifdef WL_CFG80211
4790         if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) {
4791                 wl_cfg80211_detach(NULL);
4792                 dhd_monitor_uninit();
4793         }
4794 #endif
4795         dhd_conf_detach(dhdp);
4796
4797 #ifdef PNO_SUPPORT
4798         if (dhdp->pno_state)
4799                 dhd_pno_deinit(dhdp);
4800 #endif
4801 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \
4802         KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM_SLEEP)
4803                 unregister_pm_notifier(&dhd_sleep_pm_notifier);
4804 #endif /* (LINUX_VERSION >= 2.6.27 && LINUX_VERSION <= 2.6.39 && CONFIG_PM_SLEEP */
4805
4806         if (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) {
4807                 DHD_TRACE(("wd wakelock count:%d\n", dhd->wakelock_wd_counter));
4808 #ifdef CONFIG_HAS_WAKELOCK
4809                 dhd->wakelock_counter = 0;
4810                 dhd->wakelock_wd_counter = 0;
4811                 dhd->wakelock_rx_timeout_enable = 0;
4812                 dhd->wakelock_ctrl_timeout_enable = 0;
4813                 wake_lock_destroy(&dhd->wl_wifi);
4814                 wake_lock_destroy(&dhd->wl_rxwake);
4815                 wake_lock_destroy(&dhd->wl_ctrlwake);
4816                 wake_lock_destroy(&dhd->wl_wdwake);
4817 #endif /* CONFIG_HAS_WAKELOCK */
4818         }
4819 }
4820
4821
4822 void
4823 dhd_free(dhd_pub_t *dhdp)
4824 {
4825         dhd_info_t *dhd;
4826         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4827
4828         if (dhdp) {
4829                 int i;
4830                 for (i = 0; i < ARRAYSIZE(dhdp->reorder_bufs); i++) {
4831                         if (dhdp->reorder_bufs[i]) {
4832                                 reorder_info_t *ptr;
4833                                 uint32 buf_size = sizeof(struct reorder_info);
4834
4835                                 ptr = dhdp->reorder_bufs[i];
4836
4837                                 buf_size += ((ptr->max_idx + 1) * sizeof(void*));
4838                                 DHD_REORDER(("free flow id buf %d, maxidx is %d, buf_size %d\n",
4839                                         i, ptr->max_idx, buf_size));
4840
4841                                 MFREE(dhdp->osh, dhdp->reorder_bufs[i], buf_size);
4842                                 dhdp->reorder_bufs[i] = NULL;
4843                         }
4844                 }
4845                 dhd = (dhd_info_t *)dhdp->info;
4846 #if defined(CONFIG_DHD_USE_STATIC_BUF)
4847                 /* If pointer is allocated by dhd_os_prealloc then avoid MFREE */
4848                 if (dhd != (dhd_info_t *)dhd_os_prealloc(NULL, DHD_PREALLOC_DHD_INFO, 0)) {
4849 #endif /* CONFIG_DHD_USE_STATIC_BUF */
4850                         if (dhd)
4851                                 MFREE(dhd->pub.osh, dhd, sizeof(*dhd));
4852 #if defined(CONFIG_DHD_USE_STATIC_BUF)
4853                 }
4854                 else {
4855                         if (dhd)
4856                                 dhd = NULL;
4857                 }
4858 #endif /* CONFIG_DHD_USE_STATIC_BUF */
4859         }
4860 }
4861
4862 static void 
4863 dhd_module_cleanup(void)
4864 {
4865         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4866
4867         dhd_bus_unregister();
4868
4869 #if defined(CONFIG_WIFI_CONTROL_FUNC)
4870         wl_android_wifictrl_func_del();
4871 #endif /* CONFIG_WIFI_CONTROL_FUNC */
4872         wl_android_exit();
4873
4874         /* Call customer gpio to turn off power with WL_REG_ON signal */
4875         dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF);
4876 }
4877
4878 #if defined(CONFIG_WIFI_CONTROL_FUNC)
4879 extern bool g_wifi_poweron;
4880 #endif /* CONFIG_WIFI_CONTROL_FUNC */
4881
4882 static int 
4883 dhd_module_init(void)
4884 {
4885         int error = 0;
4886
4887 #if 1 && defined(BCMLXSDMMC) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
4888         int retry = POWERUP_MAX_RETRY;
4889         int chip_up = 0;
4890 #endif 
4891
4892         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4893
4894         wl_android_init();
4895
4896 #if defined(DHDTHREAD)
4897         /* Sanity check on the module parameters */
4898         do {
4899                 /* Both watchdog and DPC as tasklets are ok */
4900                 if ((dhd_watchdog_prio < 0) && (dhd_dpc_prio < 0))
4901                         break;
4902
4903                 /* If both watchdog and DPC are threads, TX must be deferred */
4904                 if ((dhd_watchdog_prio >= 0) && (dhd_dpc_prio >= 0) && dhd_deferred_tx)
4905                         break;
4906
4907                 DHD_ERROR(("Invalid module parameters.\n"));
4908                 error = -EINVAL;
4909         } while (0);
4910 #endif 
4911         if (error)
4912                 goto fail_0;
4913
4914 #if 1 && defined(BCMLXSDMMC) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
4915         do {
4916                 sema_init(&dhd_chipup_sem, 0);
4917                 dhd_bus_reg_sdio_notify(&dhd_chipup_sem);
4918                 dhd_customer_gpio_wlan_ctrl(WLAN_POWER_ON);
4919 #if defined(CONFIG_WIFI_CONTROL_FUNC)
4920                 if (wl_android_wifictrl_func_add() < 0) {
4921                         dhd_bus_unreg_sdio_notify();
4922                         goto fail_1;
4923                 }
4924 #endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */
4925                 if (down_timeout(&dhd_chipup_sem,
4926                         msecs_to_jiffies(POWERUP_WAIT_MS)) == 0) {
4927                         dhd_bus_unreg_sdio_notify();
4928                         chip_up = 1;
4929                         break;
4930                 }
4931                 DHD_ERROR(("\nfailed to power up wifi chip, retry again (%d left) **\n\n",
4932                         retry+1));
4933                 dhd_bus_unreg_sdio_notify();
4934 #if defined(CONFIG_WIFI_CONTROL_FUNC)
4935                 wl_android_wifictrl_func_del();
4936 #endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */
4937                 dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF);
4938         } while (retry-- > 0);
4939
4940         if (!chip_up) {
4941                 DHD_ERROR(("\nfailed to power up wifi chip, max retry reached, exits **\n\n"));
4942                 error = -ENODEV;
4943                 goto fail_0;
4944         }
4945 #else
4946         dhd_customer_gpio_wlan_ctrl(WLAN_POWER_ON);
4947 #if defined(CONFIG_WIFI_CONTROL_FUNC)
4948         if (wl_android_wifictrl_func_add() < 0)
4949                 goto fail_1;
4950 #endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */
4951
4952 #endif 
4953
4954 #if defined(CONFIG_WIFI_CONTROL_FUNC) && defined(BCMLXSDMMC)
4955         /* If the wifi_set_power() is failed,
4956          * we need to jump error handling routines.
4957          */
4958         if (!g_wifi_poweron) {
4959                 printk("%s: wifi_set_power() failed\n", __FUNCTION__);
4960                 error = -ENODEV;
4961                 goto fail_1;
4962         }
4963 #endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */
4964
4965 #if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
4966         sema_init(&dhd_registration_sem, 0);
4967 #endif 
4968
4969
4970         error = dhd_bus_register();
4971
4972         if (!error)
4973                 printf("\n%s\n", dhd_version);
4974         else {
4975                 DHD_ERROR(("%s: sdio_register_driver failed\n", __FUNCTION__));
4976                 goto fail_1;
4977         }
4978
4979 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(BCMLXSDMMC)
4980         /*
4981          * Wait till MMC sdio_register_driver callback called and made driver attach.
4982          * It's needed to make sync up exit from dhd insmod  and
4983          * Kernel MMC sdio device callback registration
4984          */
4985         if ((down_timeout(&dhd_registration_sem,
4986                 msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)) != 0) ||
4987                 (dhd_registration_check != TRUE)) {
4988                 error = -ENODEV;
4989                 DHD_ERROR(("%s: sdio_register_driver timeout or error \n", __FUNCTION__));
4990                 goto fail_2;
4991         }
4992 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
4993 #if defined(WL_CFG80211)
4994         wl_android_post_init();
4995 #endif /* defined(WL_CFG80211) */
4996
4997         return error;
4998
4999 #if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(BCMLXSDMMC)
5000 fail_2:
5001         dhd_bus_unregister();
5002 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
5003
5004 fail_1:
5005
5006 #if defined(CONFIG_WIFI_CONTROL_FUNC)
5007         wl_android_wifictrl_func_del();
5008 #endif 
5009
5010         /* Call customer gpio to turn off power with WL_REG_ON signal */
5011         dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF);
5012
5013 fail_0:
5014
5015         wl_android_exit();
5016
5017         return error;
5018 }
5019
5020 extern char WIFI_MODULE_NAME[];
5021 extern char RKWIFI_DRV_VERSION[];
5022
5023 static int __init rockchip_wifi_init_module(void)
5024 {
5025     printk("=======================================================\n");
5026     printk("==== Launching Wi-Fi driver! (Powered by Rockchip) ====\n");
5027     printk("=======================================================\n");
5028     printk("%s WiFi driver (Powered by Rockchip,Ver %s) init.\n", WIFI_MODULE_NAME, RKWIFI_DRV_VERSION);
5029
5030     return dhd_module_init();
5031 }
5032
5033 static void __exit rockchip_wifi_exit_module(void)
5034 {
5035     printk("=======================================================\n");
5036     printk("== Dis-launching Wi-Fi driver! (Powered by Rockchip) ==\n");
5037     printk("=======================================================\n");
5038     dhd_module_cleanup();
5039 }
5040
5041 late_initcall(rockchip_wifi_init_module);
5042 module_exit(rockchip_wifi_exit_module);
5043 /*
5044 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
5045 #ifdef USE_LATE_INITCALL_SYNC
5046 late_initcall_sync(dhd_module_init);
5047 #else
5048 late_initcall(dhd_module_init);
5049 #endif // USE_LATE_INITCALL_SYNC
5050 #else
5051 module_init(dhd_module_init);
5052 #endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
5053
5054 module_exit(dhd_module_cleanup);
5055 */
5056
5057 /*
5058  * OS specific functions required to implement DHD driver in OS independent way
5059  */
5060 int
5061 dhd_os_proto_block(dhd_pub_t *pub)
5062 {
5063         dhd_info_t * dhd = (dhd_info_t *)(pub->info);
5064
5065         if (dhd) {
5066                 down(&dhd->proto_sem);
5067                 return 1;
5068         }
5069
5070         return 0;
5071 }
5072
5073 int
5074 dhd_os_proto_unblock(dhd_pub_t *pub)
5075 {
5076         dhd_info_t * dhd = (dhd_info_t *)(pub->info);
5077
5078         if (dhd) {
5079                 up(&dhd->proto_sem);
5080                 return 1;
5081         }
5082
5083         return 0;
5084 }
5085
5086 unsigned int
5087 dhd_os_get_ioctl_resp_timeout(void)
5088 {
5089         return ((unsigned int)dhd_ioctl_timeout_msec);
5090 }
5091
5092 void
5093 dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec)
5094 {
5095         dhd_ioctl_timeout_msec = (int)timeout_msec;
5096 }
5097
5098 int
5099 dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending)
5100 {
5101         dhd_info_t * dhd = (dhd_info_t *)(pub->info);
5102         int timeout;
5103
5104         /* Convert timeout in millsecond to jiffies */
5105 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
5106         timeout = msecs_to_jiffies(dhd_ioctl_timeout_msec);
5107 #else
5108         timeout = dhd_ioctl_timeout_msec * HZ / 1000;
5109 #endif
5110
5111         timeout = wait_event_timeout(dhd->ioctl_resp_wait, (*condition), timeout);
5112         return timeout;
5113 }
5114
5115 int
5116 dhd_os_ioctl_resp_wake(dhd_pub_t *pub)
5117 {
5118         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
5119
5120         if (waitqueue_active(&dhd->ioctl_resp_wait)) {
5121                 wake_up(&dhd->ioctl_resp_wait);
5122         }
5123
5124         return 0;
5125 }
5126
5127 void
5128 dhd_os_wd_timer_extend(void *bus, bool extend)
5129 {
5130         dhd_pub_t *pub = bus;
5131         dhd_info_t *dhd = (dhd_info_t *)pub->info;
5132
5133         if (extend)
5134                 dhd_os_wd_timer(bus, WATCHDOG_EXTEND_INTERVAL);
5135         else
5136                 dhd_os_wd_timer(bus, dhd->default_wd_interval);
5137 }
5138
5139
5140 void
5141 dhd_os_wd_timer(void *bus, uint wdtick)
5142 {
5143         dhd_pub_t *pub = bus;
5144         dhd_info_t *dhd = (dhd_info_t *)pub->info;
5145         unsigned long flags;
5146
5147         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5148
5149         if (!dhd) {
5150                 DHD_ERROR(("%s: dhd NULL\n", __FUNCTION__));
5151                 return;
5152         }
5153
5154         flags = dhd_os_spin_lock(pub);
5155
5156         /* don't start the wd until fw is loaded */
5157         if (pub->busstate == DHD_BUS_DOWN) {
5158                 dhd_os_spin_unlock(pub, flags);
5159                 if (!wdtick)
5160                         DHD_OS_WD_WAKE_UNLOCK(pub);
5161                 return;
5162         }
5163
5164         /* Totally stop the timer */
5165         if (!wdtick && dhd->wd_timer_valid == TRUE) {
5166                 dhd->wd_timer_valid = FALSE;
5167                 dhd_os_spin_unlock(pub, flags);
5168 #ifdef DHDTHREAD
5169                 del_timer_sync(&dhd->timer);
5170 #else
5171                 del_timer(&dhd->timer);
5172 #endif /* DHDTHREAD */
5173                 DHD_OS_WD_WAKE_UNLOCK(pub);
5174                 return;
5175         }
5176
5177         if (wdtick) {
5178                 DHD_OS_WD_WAKE_LOCK(pub);
5179                 dhd_watchdog_ms = (uint)wdtick;
5180                 /* Re arm the timer, at last watchdog period */
5181                 mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms));
5182                 dhd->wd_timer_valid = TRUE;
5183         }
5184         dhd_os_spin_unlock(pub, flags);
5185 }
5186
5187 void *
5188 dhd_os_open_image(char *filename)
5189 {
5190         struct file *fp;
5191
5192         fp = filp_open(filename, O_RDONLY, 0);
5193         /*
5194          * 2.6.11 (FC4) supports filp_open() but later revs don't?
5195          * Alternative:
5196          * fp = open_namei(AT_FDCWD, filename, O_RD, 0);
5197          * ???
5198          */
5199          if (IS_ERR(fp))
5200                  fp = NULL;
5201
5202          return fp;
5203 }
5204
5205 int
5206 dhd_os_get_image_block(char *buf, int len, void *image)
5207 {
5208         struct file *fp = (struct file *)image;
5209         int rdlen;
5210
5211         if (!image)
5212                 return 0;
5213
5214         rdlen = kernel_read(fp, fp->f_pos, buf, len);
5215         if (rdlen > 0)
5216                 fp->f_pos += rdlen;
5217
5218         return rdlen;
5219 }
5220
5221 void
5222 dhd_os_close_image(void *image)
5223 {
5224         if (image)
5225                 filp_close((struct file *)image, NULL);
5226 }
5227
5228
5229 void
5230 dhd_os_sdlock(dhd_pub_t *pub)
5231 {
5232         dhd_info_t *dhd;
5233
5234         dhd = (dhd_info_t *)(pub->info);
5235
5236 #ifdef DHDTHREAD
5237         if (dhd->threads_only)
5238                 down(&dhd->sdsem);
5239         else
5240 #endif /* DHDTHREAD */
5241         spin_lock_bh(&dhd->sdlock);
5242 }
5243
5244 void
5245 dhd_os_sdunlock(dhd_pub_t *pub)
5246 {
5247         dhd_info_t *dhd;
5248
5249         dhd = (dhd_info_t *)(pub->info);
5250
5251 #ifdef DHDTHREAD
5252         if (dhd->threads_only)
5253                 up(&dhd->sdsem);
5254         else
5255 #endif /* DHDTHREAD */
5256         spin_unlock_bh(&dhd->sdlock);
5257 }
5258
5259 void
5260 dhd_os_sdlock_txq(dhd_pub_t *pub)
5261 {
5262         dhd_info_t *dhd;
5263
5264         dhd = (dhd_info_t *)(pub->info);
5265         spin_lock_bh(&dhd->txqlock);
5266 }
5267
5268 void
5269 dhd_os_sdunlock_txq(dhd_pub_t *pub)
5270 {
5271         dhd_info_t *dhd;
5272
5273         dhd = (dhd_info_t *)(pub->info);
5274         spin_unlock_bh(&dhd->txqlock);
5275 }
5276
5277 void
5278 dhd_os_sdlock_rxq(dhd_pub_t *pub)
5279 {
5280 }
5281
5282 void
5283 dhd_os_sdunlock_rxq(dhd_pub_t *pub)
5284 {
5285 }
5286
5287 void
5288 dhd_os_sdtxlock(dhd_pub_t *pub)
5289 {
5290         dhd_os_sdlock(pub);
5291 }
5292
5293 void
5294 dhd_os_sdtxunlock(dhd_pub_t *pub)
5295 {
5296         dhd_os_sdunlock(pub);
5297 }
5298
5299 #if defined(DHDTHREAD) && defined(RXFRAME_THREAD)
5300 static void
5301 dhd_os_rxflock(dhd_pub_t *pub)
5302 {
5303         dhd_info_t *dhd;
5304
5305         dhd = (dhd_info_t *)(pub->info);
5306         spin_lock_bh(&dhd->rxf_lock);
5307
5308 }
5309
5310 static void
5311 dhd_os_rxfunlock(dhd_pub_t *pub)
5312 {
5313         dhd_info_t *dhd;
5314
5315         dhd = (dhd_info_t *)(pub->info);
5316         spin_unlock_bh(&dhd->rxf_lock);
5317 }
5318 #endif /* defined(DHDTHREAD) && defined(RXFRAME_THREAD) */
5319
5320 #ifdef DHDTCPACK_SUPPRESS
5321 void
5322 dhd_os_tcpacklock(dhd_pub_t *pub)
5323 {
5324         dhd_info_t *dhd;
5325
5326         dhd = (dhd_info_t *)(pub->info);
5327         spin_lock_bh(&dhd->tcpack_lock);
5328
5329 }
5330
5331 void
5332 dhd_os_tcpackunlock(dhd_pub_t *pub)
5333 {
5334         dhd_info_t *dhd;
5335
5336         dhd = (dhd_info_t *)(pub->info);
5337         spin_unlock_bh(&dhd->tcpack_lock);
5338 }
5339 #endif /* DHDTCPACK_SUPPRESS */
5340
5341 #if defined(CONFIG_DHD_USE_STATIC_BUF)
5342 uint8* dhd_os_prealloc(void *osh, int section, uint size)
5343 {
5344         return (uint8*)wl_android_prealloc(section, size);
5345 }
5346
5347 void dhd_os_prefree(void *osh, void *addr, uint size)
5348 {
5349 }
5350 #endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */
5351
5352 #if defined(WL_WIRELESS_EXT)
5353 struct iw_statistics *
5354 dhd_get_wireless_stats(struct net_device *dev)
5355 {
5356         int res = 0;
5357         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
5358
5359         if (!dhd->pub.up) {
5360                 return NULL;
5361         }
5362
5363         res = wl_iw_get_wireless_stats(dev, &dhd->iw.wstats);
5364
5365         if (res == 0)
5366                 return &dhd->iw.wstats;
5367         else
5368                 return NULL;
5369 }
5370 #endif /* defined(WL_WIRELESS_EXT) */
5371
5372 static int
5373 dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
5374         wl_event_msg_t *event, void **data)
5375 {
5376         int bcmerror = 0;
5377         ASSERT(dhd != NULL);
5378
5379         bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, event, data);
5380         if (bcmerror != BCME_OK)
5381                 return (bcmerror);
5382
5383 #if defined(WL_WIRELESS_EXT)
5384         if (event->bsscfgidx == 0) {
5385                 /*
5386                  * Wireless ext is on primary interface only
5387                  */
5388
5389         ASSERT(dhd->iflist[*ifidx] != NULL);
5390         ASSERT(dhd->iflist[*ifidx]->net != NULL);
5391
5392                 if (dhd->iflist[*ifidx]->net) {
5393                 wl_iw_event(dhd->iflist[*ifidx]->net, event, *data);
5394                 }
5395         }
5396 #endif /* defined(WL_WIRELESS_EXT)  */
5397
5398 #ifdef WL_CFG80211
5399         if ((ntoh32(event->event_type) == WLC_E_IF) &&
5400                 (((dhd_if_event_t *)*data)->action == WLC_E_IF_ADD))
5401                 /* If ADD_IF has been called directly by wl utility then we
5402                  * should not report this. In case if ADD_IF was called from
5403                  * CFG stack, then too this event need not be reported back
5404                  */
5405                 return (BCME_OK);
5406         if ((wl_cfg80211_is_progress_ifchange() ||
5407                 wl_cfg80211_is_progress_ifadd()) && (*ifidx != 0)) {
5408                 /*
5409                  * If IF_ADD/CHANGE operation is going on,
5410                  *  discard any event received on the virtual I/F
5411                  */
5412                 return (BCME_OK);
5413         }
5414
5415         ASSERT(dhd->iflist[*ifidx] != NULL);
5416         ASSERT(dhd->iflist[*ifidx]->net != NULL);
5417         if (dhd->iflist[*ifidx]->event2cfg80211 && dhd->iflist[*ifidx]->net) {
5418                 wl_cfg80211_event(dhd->iflist[*ifidx]->net, event, *data);
5419         }
5420 #endif /* defined(WL_CFG80211) */
5421
5422         return (bcmerror);
5423 }
5424
5425 /* send up locally generated event */
5426 void
5427 dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data)
5428 {
5429         switch (ntoh32(event->event_type)) {
5430 #ifdef WLBTAMP
5431         /* Send up locally generated AMP HCI Events */
5432         case WLC_E_BTA_HCI_EVENT: {
5433                 struct sk_buff *p, *skb;
5434                 bcm_event_t *msg;
5435                 wl_event_msg_t *p_bcm_event;
5436                 char *ptr;
5437                 uint32 len;
5438                 uint32 pktlen;
5439                 dhd_if_t *ifp;
5440                 dhd_info_t *dhd;
5441                 uchar *eth;
5442                 int ifidx;
5443
5444                 len = ntoh32(event->datalen);
5445                 pktlen = sizeof(bcm_event_t) + len + 2;
5446                 dhd = dhdp->info;
5447                 ifidx = dhd_ifname2idx(dhd, event->ifname);
5448
5449                 if ((p = PKTGET(dhdp->osh, pktlen, FALSE))) {
5450                         ASSERT(ISALIGNED((uintptr)PKTDATA(dhdp->osh, p), sizeof(uint32)));
5451
5452                         msg = (bcm_event_t *) PKTDATA(dhdp->osh, p);
5453
5454                         bcopy(&dhdp->mac, &msg->eth.ether_dhost, ETHER_ADDR_LEN);
5455                         bcopy(&dhdp->mac, &msg->eth.ether_shost, ETHER_ADDR_LEN);
5456                         ETHER_TOGGLE_LOCALADDR(&msg->eth.ether_shost);
5457
5458                         msg->eth.ether_type = hton16(ETHER_TYPE_BRCM);
5459
5460                         /* BCM Vendor specific header... */
5461                         msg->bcm_hdr.subtype = hton16(BCMILCP_SUBTYPE_VENDOR_LONG);
5462                         msg->bcm_hdr.version = BCMILCP_BCM_SUBTYPEHDR_VERSION;
5463                         bcopy(BRCM_OUI, &msg->bcm_hdr.oui[0], DOT11_OUI_LEN);
5464
5465                         /* vendor spec header length + pvt data length (private indication
5466                          *  hdr + actual message itself)
5467                          */
5468                         msg->bcm_hdr.length = hton16(BCMILCP_BCM_SUBTYPEHDR_MINLENGTH +
5469                                 BCM_MSG_LEN + sizeof(wl_event_msg_t) + (uint16)len);
5470                         msg->bcm_hdr.usr_subtype = hton16(BCMILCP_BCM_SUBTYPE_EVENT);
5471
5472                         PKTSETLEN(dhdp->osh, p, (sizeof(bcm_event_t) + len + 2));
5473
5474                         /* copy  wl_event_msg_t into sk_buf */
5475
5476                         /* pointer to wl_event_msg_t in sk_buf */
5477                         p_bcm_event = &msg->event;
5478                         bcopy(event, p_bcm_event, sizeof(wl_event_msg_t));
5479
5480                         /* copy hci event into sk_buf */
5481                         bcopy(data, (p_bcm_event + 1), len);
5482
5483                         msg->bcm_hdr.length  = hton16(sizeof(wl_event_msg_t) +
5484                                 ntoh16(msg->bcm_hdr.length));
5485                         PKTSETLEN(dhdp->osh, p, (sizeof(bcm_event_t) + len + 2));
5486
5487                         ptr = (char *)(msg + 1);
5488                         /* Last 2 bytes of the message are 0x00 0x00 to signal that there
5489                          * are no ethertypes which are following this
5490                          */
5491                         ptr[len+0] = 0x00;
5492                         ptr[len+1] = 0x00;
5493
5494                         skb = PKTTONATIVE(dhdp->osh, p);
5495                         eth = skb->data;
5496                         len = skb->len;
5497
5498                         ifp = dhd->iflist[ifidx];
5499                         if (ifp == NULL)
5500                              ifp = dhd->iflist[0];
5501
5502                         ASSERT(ifp);
5503                         skb->dev = ifp->net;
5504                         skb->protocol = eth_type_trans(skb, skb->dev);
5505
5506                         skb->data = eth;
5507                         skb->len = len;
5508
5509                         /* Strip header, count, deliver upward */
5510                         skb_pull(skb, ETH_HLEN);
5511
5512                         /* Send the packet */
5513                         if (in_interrupt()) {
5514                                 netif_rx(skb);
5515                         } else {
5516                                 netif_rx_ni(skb);
5517                         }
5518                 }
5519                 else {
5520                         /* Could not allocate a sk_buf */
5521                         DHD_ERROR(("%s: unable to alloc sk_buf", __FUNCTION__));
5522                 }
5523                 break;
5524         } /* case WLC_E_BTA_HCI_EVENT */
5525 #endif /* WLBTAMP */
5526
5527         default:
5528                 break;
5529         }
5530 }
5531
5532 void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar)
5533 {
5534 #if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
5535         struct dhd_info *dhdinfo =  dhd->info;
5536
5537 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
5538         int timeout = msecs_to_jiffies(IOCTL_RESP_TIMEOUT);
5539 #else
5540         int timeout = (IOCTL_RESP_TIMEOUT / 1000) * HZ;
5541 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
5542
5543         dhd_os_sdunlock(dhd);
5544         wait_event_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), timeout);
5545         dhd_os_sdlock(dhd);
5546 #endif
5547         return;
5548 }
5549
5550 void dhd_wait_event_wakeup(dhd_pub_t *dhd)
5551 {
5552 #if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
5553         struct dhd_info *dhdinfo =  dhd->info;
5554         if (waitqueue_active(&dhdinfo->ctrl_wait))
5555                 wake_up(&dhdinfo->ctrl_wait);
5556 #endif
5557         return;
5558 }
5559
5560 int
5561 dhd_dev_reset(struct net_device *dev, uint8 flag)
5562 {
5563         int ret;
5564
5565         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
5566
5567         if (flag == TRUE) {
5568                 /* Issue wl down command before resetting the chip */
5569                 if (dhd_wl_ioctl_cmd(&dhd->pub, WLC_DOWN, NULL, 0, TRUE, 0) < 0) {
5570                         DHD_TRACE(("%s: wl down failed\n", __FUNCTION__));
5571                 }
5572 #if defined(PROP_TXSTATUS) && !defined(PROP_TXSTATUS_VSDB)
5573         dhd_wlfc_deinit(&dhd->pub);
5574         if (dhd->pub.plat_deinit)
5575                 dhd->pub.plat_deinit((void *)&dhd->pub);
5576 #endif /* PROP_TXSTATUS && !PROP_TXSTATUS_VSDB */
5577         }
5578
5579         ret = dhd_bus_devreset(&dhd->pub, flag);
5580         if (ret) {
5581                 DHD_ERROR(("%s: dhd_bus_devreset: %d\n", __FUNCTION__, ret));
5582                 return ret;
5583         }
5584
5585         return ret;
5586 }
5587
5588 int net_os_set_suspend_disable(struct net_device *dev, int val)
5589 {
5590         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
5591         int ret = 0;
5592
5593         if (dhd) {
5594                 ret = dhd->pub.suspend_disable_flag;
5595                 dhd->pub.suspend_disable_flag = val;
5596         }
5597         return ret;
5598 }
5599
5600 int net_os_set_suspend(struct net_device *dev, int val, int force)
5601 {
5602         int ret = 0;
5603         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
5604
5605         if (dhd) {
5606 #if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
5607                 ret = dhd_set_suspend(val, &dhd->pub);
5608 #else
5609                 ret = dhd_suspend_resume_helper(dhd, val, force);
5610 #endif
5611 #ifdef WL_CFG80211
5612                 wl_cfg80211_update_power_mode(dev);
5613 #endif
5614         }
5615         return ret;
5616 }
5617
5618 int net_os_set_suspend_bcn_li_dtim(struct net_device *dev, int val)
5619 {
5620         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
5621
5622         if (dhd)
5623                 dhd->pub.suspend_bcn_li_dtim = val;
5624
5625         return 0;
5626 }
5627
5628 #ifdef PKT_FILTER_SUPPORT
5629 int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num)
5630 {
5631         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
5632         char *filterp = NULL;
5633         int filter_id = 0;
5634         int ret = 0;
5635
5636         if (dhd->pub.conf->filter_out_all_packets)
5637                 return 0;
5638
5639         if (!dhd || (num == DHD_UNICAST_FILTER_NUM) ||
5640                 (num == DHD_MDNS_FILTER_NUM))
5641                 return ret;
5642         if (num >= dhd->pub.pktfilter_count)
5643                 return -EINVAL;
5644         switch (num) {
5645                 case DHD_BROADCAST_FILTER_NUM:
5646                         filterp = "101 0 0 0 0xFFFFFFFFFFFF 0xFFFFFFFFFFFF";
5647                         filter_id = 101;
5648                         break;
5649                 case DHD_MULTICAST4_FILTER_NUM:
5650                         filterp = "102 0 0 0 0xFFFFFF 0x01005E";
5651                         filter_id = 102;
5652                         break;
5653                 case DHD_MULTICAST6_FILTER_NUM:
5654                         filterp = "103 0 0 0 0xFFFF 0x3333";
5655                         filter_id = 103;
5656                         break;
5657                 default:
5658                         return -EINVAL;
5659         }
5660
5661         /* Add filter */
5662         if (add_remove) {
5663                 dhd->pub.pktfilter[num] = filterp;
5664                 dhd_pktfilter_offload_set(&dhd->pub, dhd->pub.pktfilter[num]);
5665         } else { /* Delete filter */
5666                 dhd_pktfilter_offload_delete(&dhd->pub, filter_id);
5667         }
5668         return ret;
5669 }
5670
5671 int dhd_os_enable_packet_filter(dhd_pub_t *dhdp, int val)
5672 {
5673         int ret = 0;
5674
5675         /* Packet filtering is set only if we still in early-suspend and
5676          * we need either to turn it ON or turn it OFF
5677          * We can always turn it OFF in case of early-suspend, but we turn it
5678          * back ON only if suspend_disable_flag was not set
5679         */
5680         if (dhdp && dhdp->up) {
5681                 if (dhdp->in_suspend) {
5682                         if (!val || (val && !dhdp->suspend_disable_flag))
5683                                 dhd_enable_packet_filter(val, dhdp);
5684                 }
5685         }
5686         return ret;
5687 }
5688
5689 /* function to enable/disable packet for Network device */
5690 int net_os_enable_packet_filter(struct net_device *dev, int val)
5691 {
5692         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
5693
5694         return dhd_os_enable_packet_filter(&dhd->pub, val);
5695 }
5696 #endif /* PKT_FILTER_SUPPORT */
5697
5698 int
5699 dhd_dev_init_ioctl(struct net_device *dev)
5700 {
5701         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
5702         int ret;
5703
5704         dhd_process_cid_mac(&dhd->pub, TRUE);
5705
5706         if ((ret = dhd_preinit_ioctls(&dhd->pub)) < 0)
5707                 goto done;
5708
5709         dhd_process_cid_mac(&dhd->pub, FALSE);
5710
5711 done:
5712         return ret;
5713 }
5714
5715 #ifdef PNO_SUPPORT
5716 /* Linux wrapper to call common dhd_pno_stop_for_ssid */
5717 int
5718 dhd_dev_pno_stop_for_ssid(struct net_device *dev)
5719 {
5720         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
5721
5722         return (dhd_pno_stop_for_ssid(&dhd->pub));
5723 }
5724 /* Linux wrapper to call common dhd_pno_set_for_ssid */
5725 int
5726 dhd_dev_pno_set_for_ssid(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid,
5727         uint16  scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan)
5728 {
5729         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
5730
5731         return (dhd_pno_set_for_ssid(&dhd->pub, ssids_local, nssid, scan_fr,
5732                 pno_repeat, pno_freq_expo_max, channel_list, nchan));
5733 }
5734
5735 /* Linux wrapper to call common dhd_pno_enable */
5736 int
5737 dhd_dev_pno_enable(struct net_device *dev, int enable)
5738 {
5739         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
5740
5741         return (dhd_pno_enable(&dhd->pub, enable));
5742 }
5743
5744 /* Linux wrapper to call common dhd_pno_set_for_hotlist */
5745 int
5746 dhd_dev_pno_set_for_hotlist(struct net_device *dev, wl_pfn_bssid_t *p_pfn_bssid,
5747         struct dhd_pno_hotlist_params *hotlist_params)
5748 {
5749         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
5750         return (dhd_pno_set_for_hotlist(&dhd->pub, p_pfn_bssid, hotlist_params));
5751 }
5752 /* Linux wrapper to call common dhd_dev_pno_stop_for_batch */
5753 int
5754 dhd_dev_pno_stop_for_batch(struct net_device *dev)
5755 {
5756         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
5757         return (dhd_pno_stop_for_batch(&dhd->pub));
5758 }
5759 /* Linux wrapper to call common dhd_dev_pno_set_for_batch */
5760 int
5761 dhd_dev_pno_set_for_batch(struct net_device *dev, struct dhd_pno_batch_params *batch_params)
5762 {
5763         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
5764         return (dhd_pno_set_for_batch(&dhd->pub, batch_params));
5765 }
5766 /* Linux wrapper to call common dhd_dev_pno_get_for_batch */
5767 int
5768 dhd_dev_pno_get_for_batch(struct net_device *dev, char *buf, int bufsize)
5769 {
5770         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
5771         return (dhd_pno_get_for_batch(&dhd->pub, buf, bufsize, PNO_STATUS_NORMAL));
5772 }
5773 #endif /* PNO_SUPPORT */
5774
5775 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (1)
5776 static void dhd_hang_process(struct work_struct *work)
5777 {
5778         dhd_info_t *dhd;
5779         struct net_device *dev;
5780
5781         dhd = (dhd_info_t *)container_of(work, dhd_info_t, work_hang);
5782         dev = dhd->iflist[0]->net;
5783
5784         if (dev) {
5785                 rtnl_lock();
5786                 dev_close(dev);
5787                 rtnl_unlock();
5788 #if defined(WL_WIRELESS_EXT)
5789                 wl_iw_send_priv_event(dev, "HANG");
5790 #endif
5791 #if defined(WL_CFG80211)
5792                 wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED);
5793 #endif
5794         }
5795 }
5796
5797 int dhd_os_send_hang_message(dhd_pub_t *dhdp)
5798 {
5799         int ret = 0;
5800         if (dhdp) {
5801                 if (!dhdp->hang_was_sent) {
5802                         dhdp->hang_was_sent = 1;
5803                         schedule_work(&dhdp->info->work_hang);
5804                 }
5805         }
5806         return ret;
5807 }
5808
5809 int net_os_send_hang_message(struct net_device *dev)
5810 {
5811         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
5812         int ret = 0;
5813
5814         if (dhd) {
5815                 /* Report FW problem when enabled */
5816                 if (dhd->pub.hang_report) {
5817 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
5818                         ret = dhd_os_send_hang_message(&dhd->pub);
5819 #else
5820                         ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED);
5821 #endif
5822                 } else {
5823                         DHD_ERROR(("%s: FW HANG ignored (for testing purpose) and not sent up\n",
5824                                 __FUNCTION__));
5825                         /* Enforce bus down to stop any future traffic */
5826                         dhd->pub.busstate = DHD_BUS_DOWN;
5827                 }
5828         }
5829         return ret;
5830 }
5831 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) && OEM_ANDROID */
5832
5833 void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notify)
5834 {
5835         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
5836         if (dhd && dhd->pub.up) {
5837                 memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t));
5838 #ifdef WL_CFG80211
5839                 wl_update_wiphybands(NULL, notify);
5840 #endif
5841         }
5842 }
5843
5844 void dhd_bus_band_set(struct net_device *dev, uint band)
5845 {
5846         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
5847         if (dhd && dhd->pub.up) {
5848 #ifdef WL_CFG80211
5849                 wl_update_wiphybands(NULL, true);
5850 #endif
5851         }
5852 }
5853
5854 void dhd_net_if_lock(struct net_device *dev)
5855 {
5856         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
5857         dhd_net_if_lock_local(dhd);
5858 }
5859
5860 void dhd_net_if_unlock(struct net_device *dev)
5861 {
5862         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
5863         dhd_net_if_unlock_local(dhd);
5864 }
5865
5866 static void dhd_net_if_lock_local(dhd_info_t *dhd)
5867 {
5868 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
5869         if (dhd)
5870                 mutex_lock(&dhd->dhd_net_if_mutex);
5871 #endif
5872 }
5873
5874 static void dhd_net_if_unlock_local(dhd_info_t *dhd)
5875 {
5876 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
5877         if (dhd)
5878                 mutex_unlock(&dhd->dhd_net_if_mutex);
5879 #endif
5880 }
5881
5882 static void dhd_suspend_lock(dhd_pub_t *pub)
5883 {
5884 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
5885         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
5886         if (dhd)
5887                 mutex_lock(&dhd->dhd_suspend_mutex);
5888 #endif
5889 }
5890
5891 static void dhd_suspend_unlock(dhd_pub_t *pub)
5892 {
5893 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
5894         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
5895         if (dhd)
5896                 mutex_unlock(&dhd->dhd_suspend_mutex);
5897 #endif
5898 }
5899
5900 unsigned long dhd_os_spin_lock(dhd_pub_t *pub)
5901 {
5902         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
5903         unsigned long flags = 0;
5904
5905         if (dhd)
5906                 spin_lock_irqsave(&dhd->dhd_lock, flags);
5907
5908         return flags;
5909 }
5910
5911 void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags)
5912 {
5913         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
5914
5915         if (dhd)
5916                 spin_unlock_irqrestore(&dhd->dhd_lock, flags);
5917 }
5918
5919 static int
5920 dhd_get_pend_8021x_cnt(dhd_info_t *dhd)
5921 {
5922         return (atomic_read(&dhd->pend_8021x_cnt));
5923 }
5924
5925 #define MAX_WAIT_FOR_8021X_TX   50
5926
5927 int
5928 dhd_wait_pend8021x(struct net_device *dev)
5929 {
5930         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
5931         int timeout = msecs_to_jiffies(10);
5932         int ntimes = MAX_WAIT_FOR_8021X_TX;
5933         int pend = dhd_get_pend_8021x_cnt(dhd);
5934
5935         while (ntimes && pend) {
5936                 if (pend) {
5937                         set_current_state(TASK_INTERRUPTIBLE);
5938                         schedule_timeout(timeout);
5939                         set_current_state(TASK_RUNNING);
5940                         ntimes--;
5941                 }
5942                 pend = dhd_get_pend_8021x_cnt(dhd);
5943         }
5944         if (ntimes == 0)
5945         {
5946                 atomic_set(&dhd->pend_8021x_cnt, 0);
5947                 DHD_ERROR(("%s: TIMEOUT\n", __FUNCTION__));
5948         }
5949         return pend;
5950 }
5951
5952 #ifdef DHD_DEBUG
5953 int
5954 write_to_file(dhd_pub_t *dhd, uint8 *buf, int size)
5955 {
5956         int ret = 0;
5957         struct file *fp;
5958         mm_segment_t old_fs;
5959         loff_t pos = 0;
5960
5961         /* change to KERNEL_DS address limit */
5962         old_fs = get_fs();
5963         set_fs(KERNEL_DS);
5964
5965         /* open file to write */
5966         fp = filp_open("/tmp/mem_dump", O_WRONLY|O_CREAT, 0640);
5967         if (!fp) {
5968                 printf("%s: open file error\n", __FUNCTION__);
5969                 ret = -1;
5970                 goto exit;
5971         }
5972
5973         /* Write buf to file */
5974         fp->f_op->write(fp, buf, size, &pos);
5975
5976 exit:
5977         /* free buf before return */
5978         MFREE(dhd->osh, buf, size);
5979         /* close file before return */
5980         if (fp)
5981                 filp_close(fp, current->files);
5982         /* restore previous address limit */
5983         set_fs(old_fs);
5984
5985         return ret;
5986 }
5987 #endif /* DHD_DEBUG */
5988
5989 int dhd_os_wake_lock_timeout(dhd_pub_t *pub)
5990 {
5991         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
5992         unsigned long flags;
5993         int ret = 0;
5994
5995         if (dhd) {
5996                 spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
5997                 ret = dhd->wakelock_rx_timeout_enable > dhd->wakelock_ctrl_timeout_enable ?
5998                         dhd->wakelock_rx_timeout_enable : dhd->wakelock_ctrl_timeout_enable;
5999 #ifdef CONFIG_HAS_WAKELOCK
6000                 if (dhd->wakelock_rx_timeout_enable)
6001                         wake_lock_timeout(&dhd->wl_rxwake,
6002                                 msecs_to_jiffies(dhd->wakelock_rx_timeout_enable));
6003                 if (dhd->wakelock_ctrl_timeout_enable)
6004                         wake_lock_timeout(&dhd->wl_ctrlwake,
6005                                 msecs_to_jiffies(dhd->wakelock_ctrl_timeout_enable));
6006 #endif
6007                 dhd->wakelock_rx_timeout_enable = 0;
6008                 dhd->wakelock_ctrl_timeout_enable = 0;
6009                 spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
6010         }
6011         return ret;
6012 }
6013
6014 int net_os_wake_lock_timeout(struct net_device *dev)
6015 {
6016         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
6017         int ret = 0;
6018
6019         if (dhd)
6020                 ret = dhd_os_wake_lock_timeout(&dhd->pub);
6021         return ret;
6022 }
6023
6024 int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val)
6025 {
6026         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
6027         unsigned long flags;
6028
6029         if (dhd) {
6030                 spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
6031                 if (val > dhd->wakelock_rx_timeout_enable)
6032                         dhd->wakelock_rx_timeout_enable = val;
6033                 spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
6034         }
6035         return 0;
6036 }
6037
6038 int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val)
6039 {
6040         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
6041         unsigned long flags;
6042
6043         if (dhd) {
6044                 spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
6045                 if (val > dhd->wakelock_ctrl_timeout_enable)
6046                         dhd->wakelock_ctrl_timeout_enable = val;
6047                 spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
6048         }
6049         return 0;
6050 }
6051
6052 int net_os_wake_lock_rx_timeout_enable(struct net_device *dev, int val)
6053 {
6054         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
6055         int ret = 0;
6056
6057         if (dhd)
6058                 ret = dhd_os_wake_lock_rx_timeout_enable(&dhd->pub, val);
6059         return ret;
6060 }
6061
6062 int net_os_wake_lock_ctrl_timeout_enable(struct net_device *dev, int val)
6063 {
6064         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
6065         int ret = 0;
6066
6067         if (dhd)
6068                 ret = dhd_os_wake_lock_ctrl_timeout_enable(&dhd->pub, val);
6069         return ret;
6070 }
6071
6072 int dhd_os_wake_lock(dhd_pub_t *pub)
6073 {
6074         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
6075         unsigned long flags;
6076         int ret = 0;
6077
6078         if (dhd) {
6079                 spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
6080 #ifdef CONFIG_HAS_WAKELOCK
6081                 if (!dhd->wakelock_counter)
6082                         wake_lock(&dhd->wl_wifi);
6083 #endif
6084                 dhd->wakelock_counter++;
6085                 ret = dhd->wakelock_counter;
6086                 spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
6087         }
6088         return ret;
6089 }
6090
6091 int net_os_wake_lock(struct net_device *dev)
6092 {
6093         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
6094         int ret = 0;
6095
6096         if (dhd)
6097                 ret = dhd_os_wake_lock(&dhd->pub);
6098         return ret;
6099 }
6100
6101 int dhd_os_wake_unlock(dhd_pub_t *pub)
6102 {
6103         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
6104         unsigned long flags;
6105         int ret = 0;
6106
6107         dhd_os_wake_lock_timeout(pub);
6108         if (dhd) {
6109                 spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
6110                 if (dhd->wakelock_counter) {
6111                         dhd->wakelock_counter--;
6112 #ifdef CONFIG_HAS_WAKELOCK
6113                         if (!dhd->wakelock_counter)
6114                                 wake_unlock(&dhd->wl_wifi);
6115 #endif
6116                         ret = dhd->wakelock_counter;
6117                 }
6118                 spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
6119         }
6120         return ret;
6121 }
6122
6123 int dhd_os_check_wakelock(void *dhdp)
6124 {
6125 #if defined(CONFIG_HAS_WAKELOCK) || (1 && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, \
6126         36)))
6127         dhd_pub_t *pub = (dhd_pub_t *)dhdp;
6128         dhd_info_t *dhd;
6129
6130         if (!pub)
6131                 return 0;
6132         dhd = (dhd_info_t *)(pub->info);
6133 #endif /* CONFIG_HAS_WAKELOCK || BCMSDIO */
6134
6135 #ifdef CONFIG_HAS_WAKELOCK
6136         /* Indicate to the SD Host to avoid going to suspend if internal locks are up */
6137         if (dhd && (wake_lock_active(&dhd->wl_wifi) ||
6138                 (wake_lock_active(&dhd->wl_wdwake))))
6139                 return 1;
6140 #endif
6141         return 0;
6142 }
6143
6144 int net_os_wake_unlock(struct net_device *dev)
6145 {
6146         dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
6147         int ret = 0;
6148
6149         if (dhd)
6150                 ret = dhd_os_wake_unlock(&dhd->pub);
6151         return ret;
6152 }
6153
6154 int dhd_os_wd_wake_lock(dhd_pub_t *pub)
6155 {
6156         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
6157         unsigned long flags;
6158         int ret = 0;
6159
6160         if (dhd) {
6161                 spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
6162 #ifdef CONFIG_HAS_WAKELOCK
6163                 /* if wakelock_wd_counter was never used : lock it at once */
6164                 if (!dhd->wakelock_wd_counter)
6165                         wake_lock(&dhd->wl_wdwake);
6166 #endif
6167                 dhd->wakelock_wd_counter++;
6168                 ret = dhd->wakelock_wd_counter;
6169                 spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
6170         }
6171         return ret;
6172 }
6173
6174 int dhd_os_wd_wake_unlock(dhd_pub_t *pub)
6175 {
6176         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
6177         unsigned long flags;
6178         int ret = 0;
6179
6180         if (dhd) {
6181                 spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
6182                 if (dhd->wakelock_wd_counter) {
6183                         dhd->wakelock_wd_counter = 0;
6184 #ifdef CONFIG_HAS_WAKELOCK
6185                         wake_unlock(&dhd->wl_wdwake);
6186 #endif
6187                 }
6188                 spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
6189         }
6190         return ret;
6191 }
6192
6193 int dhd_os_check_if_up(void *dhdp)
6194 {
6195         dhd_pub_t *pub = (dhd_pub_t *)dhdp;
6196
6197         if (!pub)
6198                 return 0;
6199         return pub->up;
6200 }
6201
6202 /* function to collect firmware, chip id and chip version info */
6203 void dhd_set_version_info(dhd_pub_t *dhdp, char *fw)
6204 {
6205         int i;
6206
6207         i = snprintf(info_string, sizeof(info_string),
6208                 "  Driver: %s\n  Firmware: %s ", EPI_VERSION_STR, fw);
6209         printf("%s\n", info_string);
6210
6211         if (!dhdp)
6212                 return;
6213
6214         i = snprintf(&info_string[i], sizeof(info_string) - i,
6215                 "\n  Chip: %x Rev %x Pkg %x", dhd_bus_chip_id(dhdp),
6216                 dhd_bus_chiprev_id(dhdp), dhd_bus_chippkg_id(dhdp));
6217 }
6218
6219 int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd)
6220 {
6221         int ifidx;
6222         int ret = 0;
6223         dhd_info_t *dhd = NULL;
6224
6225         if (!net || !netdev_priv(net)) {
6226                 DHD_ERROR(("%s invalid parameter\n", __FUNCTION__));
6227                 return -EINVAL;
6228         }
6229
6230         dhd = *(dhd_info_t **)netdev_priv(net);
6231         if (!dhd)
6232                 return -EINVAL;
6233
6234         ifidx = dhd_net2idx(dhd, net);
6235         if (ifidx == DHD_BAD_IF) {
6236                 DHD_ERROR(("%s bad ifidx\n", __FUNCTION__));
6237                 return -ENODEV;
6238         }
6239
6240         DHD_OS_WAKE_LOCK(&dhd->pub);
6241         ret = dhd_wl_ioctl(&dhd->pub, ifidx, ioc, ioc->buf, ioc->len);
6242         dhd_check_hang(net, &dhd->pub, ret);
6243         DHD_OS_WAKE_UNLOCK(&dhd->pub);
6244
6245         return ret;
6246 }
6247
6248 bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret)
6249 {
6250         struct net_device *net;
6251
6252         net = dhd_idx2net(dhdp, ifidx);
6253         return dhd_check_hang(net, dhdp, ret);
6254 }
6255
6256
6257 #ifdef PROP_TXSTATUS
6258 extern int dhd_wlfc_interface_entry_update(void* state, ewlfc_mac_entry_action_t action, uint8 ifid,
6259         uint8 iftype, uint8* ea);
6260 extern int dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits);
6261
6262 int dhd_wlfc_interface_event(struct dhd_info *dhd,
6263         ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea)
6264 {
6265         if (dhd->pub.wlfc_state == NULL)
6266                 return BCME_OK;
6267
6268         return dhd_wlfc_interface_entry_update(dhd->pub.wlfc_state, action, ifid, iftype, ea);
6269 }
6270
6271 int dhd_wlfc_FIFOcreditmap_event(struct dhd_info *dhd, uint8* event_data)
6272 {
6273         if (dhd->pub.wlfc_state == NULL)
6274                 return BCME_OK;
6275
6276         return dhd_wlfc_FIFOcreditmap_update(dhd->pub.wlfc_state, event_data);
6277 }
6278
6279 int dhd_wlfc_event(struct dhd_info *dhd)
6280 {
6281         return dhd_wlfc_enable(&dhd->pub);
6282 }
6283
6284 void dhd_wlfc_plat_enable(void *dhd)
6285 {
6286         return;
6287 }
6288
6289 void dhd_wlfc_plat_deinit(void *dhd)
6290 {
6291         return;
6292 }
6293
6294 bool dhd_wlfc_skip_fc(void)
6295 {
6296
6297 #ifdef WL_CFG80211
6298         extern struct wl_priv *wlcfg_drv_priv;
6299
6300         /* enable flow control in vsdb mode */
6301         return !(wlcfg_drv_priv && wlcfg_drv_priv->vsdb_mode);
6302 #else
6303         return TRUE; /* skip flow control */
6304 #endif /* WL_CFG80211 */
6305 }
6306 #endif /* PROP_TXSTATUS */
6307
6308 #ifdef BCMDBGFS
6309
6310 #include <linux/debugfs.h>
6311
6312 extern uint32 dhd_readregl(void *bp, uint32 addr);
6313 extern uint32 dhd_writeregl(void *bp, uint32 addr, uint32 data);
6314
6315 typedef struct dhd_dbgfs {
6316         struct dentry   *debugfs_dir;
6317         struct dentry   *debugfs_mem;
6318         dhd_pub_t       *dhdp;
6319         uint32          size;
6320 } dhd_dbgfs_t;
6321
6322 dhd_dbgfs_t g_dbgfs;
6323
6324 static int
6325 dhd_dbg_state_open(struct inode *inode, struct file *file)
6326 {
6327         file->private_data = inode->i_private;
6328         return 0;
6329 }
6330
6331 static ssize_t
6332 dhd_dbg_state_read(struct file *file, char __user *ubuf,
6333                        size_t count, loff_t *ppos)
6334 {
6335         ssize_t rval;
6336         uint32 tmp;
6337         loff_t pos = *ppos;
6338         size_t ret;
6339
6340         if (pos < 0)
6341                 return -EINVAL;
6342         if (pos >= g_dbgfs.size || !count)
6343                 return 0;
6344         if (count > g_dbgfs.size - pos)
6345                 count = g_dbgfs.size - pos;
6346
6347         /* Basically enforce aligned 4 byte reads. It's up to the user to work out the details */
6348         tmp = dhd_readregl(g_dbgfs.dhdp->bus, file->f_pos & (~3));
6349
6350         ret = copy_to_user(ubuf, &tmp, 4);
6351         if (ret == count)
6352                 return -EFAULT;
6353
6354         count -= ret;
6355         *ppos = pos + count;
6356         rval = count;
6357
6358         return rval;
6359 }
6360
6361
6362 static ssize_t
6363 dhd_debugfs_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos)
6364 {
6365         loff_t pos = *ppos;
6366         size_t ret;
6367         uint32 buf;
6368
6369         if (pos < 0)
6370                 return -EINVAL;
6371         if (pos >= g_dbgfs.size || !count)
6372                 return 0;
6373         if (count > g_dbgfs.size - pos)
6374                 count = g_dbgfs.size - pos;
6375
6376         ret = copy_from_user(&buf, ubuf, sizeof(uint32));
6377         if (ret == count)
6378                 return -EFAULT;
6379
6380         /* Basically enforce aligned 4 byte writes. It's up to the user to work out the details */
6381         dhd_writeregl(g_dbgfs.dhdp->bus, file->f_pos & (~3), buf);
6382
6383         return count;
6384 }
6385
6386
6387 loff_t
6388 dhd_debugfs_lseek(struct file *file, loff_t off, int whence)
6389 {
6390         loff_t pos = -1;
6391
6392         switch (whence) {
6393                 case 0:
6394                         pos = off;
6395                         break;
6396                 case 1:
6397                         pos = file->f_pos + off;
6398                         break;
6399                 case 2:
6400                         pos = g_dbgfs.size - off;
6401         }
6402         return (pos < 0 || pos > g_dbgfs.size) ? -EINVAL : (file->f_pos = pos);
6403 }
6404
6405 static const struct file_operations dhd_dbg_state_ops = {
6406         .read   = dhd_dbg_state_read,
6407         .write  = dhd_debugfs_write,
6408         .open   = dhd_dbg_state_open,
6409         .llseek = dhd_debugfs_lseek
6410 };
6411
6412 static void dhd_dbg_create(void)
6413 {
6414         if (g_dbgfs.debugfs_dir) {
6415                 g_dbgfs.debugfs_mem = debugfs_create_file("mem", 0644, g_dbgfs.debugfs_dir,
6416                         NULL, &dhd_dbg_state_ops);
6417         }
6418 }
6419
6420 void dhd_dbg_init(dhd_pub_t *dhdp)
6421 {
6422         int err;
6423
6424         g_dbgfs.dhdp = dhdp;
6425         g_dbgfs.size = 0x20000000; /* Allow access to various cores regs */
6426
6427         g_dbgfs.debugfs_dir = debugfs_create_dir("dhd", 0);
6428         if (IS_ERR(g_dbgfs.debugfs_dir)) {
6429                 err = PTR_ERR(g_dbgfs.debugfs_dir);
6430                 g_dbgfs.debugfs_dir = NULL;
6431                 return;
6432         }
6433
6434         dhd_dbg_create();
6435
6436         return;
6437 }
6438
6439 void dhd_dbg_remove(void)
6440 {
6441         debugfs_remove(g_dbgfs.debugfs_mem);
6442         debugfs_remove(g_dbgfs.debugfs_dir);
6443
6444         bzero((unsigned char *) &g_dbgfs, sizeof(g_dbgfs));
6445
6446 }
6447 #endif /* ifdef BCMDBGFS */
6448
6449 #ifdef WLMEDIA_HTSF
6450
6451 static
6452 void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf)
6453 {
6454         dhd_info_t *dhd = (dhd_info_t *)(dhdp->info);
6455         struct sk_buff *skb;
6456         uint32 htsf = 0;
6457         uint16 dport = 0, oldmagic = 0xACAC;
6458         char *p1;
6459         htsfts_t ts;
6460
6461         /*  timestamp packet  */
6462
6463         p1 = (char*) PKTDATA(dhdp->osh, pktbuf);
6464
6465         if (PKTLEN(dhdp->osh, pktbuf) > HTSF_MINLEN) {
6466 /*              memcpy(&proto, p1+26, 4);       */
6467                 memcpy(&dport, p1+40, 2);
6468 /*      proto = ((ntoh32(proto))>> 16) & 0xFF;  */
6469                 dport = ntoh16(dport);
6470         }
6471
6472         /* timestamp only if  icmp or udb iperf with port 5555 */
6473 /*      if (proto == 17 && dport == tsport) { */
6474         if (dport >= tsport && dport <= tsport + 20) {
6475
6476                 skb = (struct sk_buff *) pktbuf;
6477
6478                 htsf = dhd_get_htsf(dhd, 0);
6479                 memset(skb->data + 44, 0, 2); /* clear checksum */
6480                 memcpy(skb->data+82, &oldmagic, 2);
6481                 memcpy(skb->data+84, &htsf, 4);
6482
6483                 memset(&ts, 0, sizeof(htsfts_t));
6484                 ts.magic  = HTSFMAGIC;
6485                 ts.prio   = PKTPRIO(pktbuf);
6486                 ts.seqnum = htsf_seqnum++;
6487                 ts.c10    = get_cycles();
6488                 ts.t10    = htsf;
6489                 ts.endmagic = HTSFENDMAGIC;
6490
6491                 memcpy(skb->data + HTSF_HOSTOFFSET, &ts, sizeof(ts));
6492         }
6493 }
6494
6495 static void dhd_dump_htsfhisto(histo_t *his, char *s)
6496 {
6497         int pktcnt = 0, curval = 0, i;
6498         for (i = 0; i < (NUMBIN-2); i++) {
6499                 curval += 500;
6500                 printf("%d ",  his->bin[i]);
6501                 pktcnt += his->bin[i];
6502         }
6503         printf(" max: %d TotPkt: %d neg: %d [%s]\n", his->bin[NUMBIN-2], pktcnt,
6504                 his->bin[NUMBIN-1], s);
6505 }
6506
6507 static
6508 void sorttobin(int value, histo_t *histo)
6509 {
6510         int i, binval = 0;
6511
6512         if (value < 0) {
6513                 histo->bin[NUMBIN-1]++;
6514                 return;
6515         }
6516         if (value > histo->bin[NUMBIN-2])  /* store the max value  */
6517                 histo->bin[NUMBIN-2] = value;
6518
6519         for (i = 0; i < (NUMBIN-2); i++) {
6520                 binval += 500; /* 500m s bins */
6521                 if (value <= binval) {
6522                         histo->bin[i]++;
6523                         return;
6524                 }
6525         }
6526         histo->bin[NUMBIN-3]++;
6527 }
6528
6529 static
6530 void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf)
6531 {
6532         dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
6533         struct sk_buff *skb;
6534         char *p1;
6535         uint16 old_magic;
6536         int d1, d2, d3, end2end;
6537         htsfts_t *htsf_ts;
6538         uint32 htsf;
6539
6540         skb = PKTTONATIVE(dhdp->osh, pktbuf);
6541         p1 = (char*)PKTDATA(dhdp->osh, pktbuf);
6542
6543         if (PKTLEN(osh, pktbuf) > HTSF_MINLEN) {
6544                 memcpy(&old_magic, p1+78, 2);
6545                 htsf_ts = (htsfts_t*) (p1 + HTSF_HOSTOFFSET - 4);
6546         }
6547         else
6548                 return;
6549
6550         if (htsf_ts->magic == HTSFMAGIC) {
6551                 htsf_ts->tE0 = dhd_get_htsf(dhd, 0);
6552                 htsf_ts->cE0 = get_cycles();
6553         }
6554
6555         if (old_magic == 0xACAC) {
6556
6557                 tspktcnt++;
6558                 htsf = dhd_get_htsf(dhd, 0);
6559                 memcpy(skb->data+92, &htsf, sizeof(uint32));
6560
6561                 memcpy(&ts[tsidx].t1, skb->data+80, 16);
6562
6563                 d1 = ts[tsidx].t2 - ts[tsidx].t1;
6564                 d2 = ts[tsidx].t3 - ts[tsidx].t2;
6565                 d3 = ts[tsidx].t4 - ts[tsidx].t3;
6566                 end2end = ts[tsidx].t4 - ts[tsidx].t1;
6567
6568                 sorttobin(d1, &vi_d1);
6569                 sorttobin(d2, &vi_d2);
6570                 sorttobin(d3, &vi_d3);
6571                 sorttobin(end2end, &vi_d4);
6572
6573                 if (end2end > 0 && end2end >  maxdelay) {
6574                         maxdelay = end2end;
6575                         maxdelaypktno = tspktcnt;
6576                         memcpy(&maxdelayts, &ts[tsidx], 16);
6577                 }
6578                 if (++tsidx >= TSMAX)
6579                         tsidx = 0;
6580         }
6581 }
6582
6583 uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx)
6584 {
6585         uint32 htsf = 0, cur_cycle, delta, delta_us;
6586         uint32    factor, baseval, baseval2;
6587         cycles_t t;
6588
6589         t = get_cycles();
6590         cur_cycle = t;
6591
6592         if (cur_cycle >  dhd->htsf.last_cycle)
6593                 delta = cur_cycle -  dhd->htsf.last_cycle;
6594         else {
6595                 delta = cur_cycle + (0xFFFFFFFF -  dhd->htsf.last_cycle);
6596         }
6597
6598         delta = delta >> 4;
6599
6600         if (dhd->htsf.coef) {
6601                 /* times ten to get the first digit */
6602                 factor = (dhd->htsf.coef*10 + dhd->htsf.coefdec1);
6603                 baseval  = (delta*10)/factor;
6604                 baseval2 = (delta*10)/(factor+1);
6605                 delta_us  = (baseval -  (((baseval - baseval2) * dhd->htsf.coefdec2)) / 10);
6606                 htsf = (delta_us << 4) +  dhd->htsf.last_tsf + HTSF_BUS_DELAY;
6607         }
6608         else {
6609                 DHD_ERROR(("-------dhd->htsf.coef = 0 -------\n"));
6610         }
6611
6612         return htsf;
6613 }
6614
6615 static void dhd_dump_latency(void)
6616 {
6617         int i, max = 0;
6618         int d1, d2, d3, d4, d5;
6619
6620         printf("T1       T2       T3       T4           d1  d2   t4-t1     i    \n");
6621         for (i = 0; i < TSMAX; i++) {
6622                 d1 = ts[i].t2 - ts[i].t1;
6623                 d2 = ts[i].t3 - ts[i].t2;
6624                 d3 = ts[i].t4 - ts[i].t3;
6625                 d4 = ts[i].t4 - ts[i].t1;
6626                 d5 = ts[max].t4-ts[max].t1;
6627                 if (d4 > d5 && d4 > 0)  {
6628                         max = i;
6629                 }
6630                 printf("%08X %08X %08X %08X \t%d %d %d   %d i=%d\n",
6631                         ts[i].t1, ts[i].t2, ts[i].t3, ts[i].t4,
6632                         d1, d2, d3, d4, i);
6633         }
6634
6635         printf("current idx = %d \n", tsidx);
6636
6637         printf("Highest latency %d pkt no.%d total=%d\n", maxdelay, maxdelaypktno, tspktcnt);
6638         printf("%08X %08X %08X %08X \t%d %d %d   %d\n",
6639         maxdelayts.t1, maxdelayts.t2, maxdelayts.t3, maxdelayts.t4,
6640         maxdelayts.t2 - maxdelayts.t1,
6641         maxdelayts.t3 - maxdelayts.t2,
6642         maxdelayts.t4 - maxdelayts.t3,
6643         maxdelayts.t4 - maxdelayts.t1);
6644 }
6645
6646
6647 static int
6648 dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx)
6649 {
6650         wl_ioctl_t ioc;
6651         char buf[32];
6652         int ret;
6653         uint32 s1, s2;
6654
6655         struct tsf {
6656                 uint32 low;
6657                 uint32 high;
6658         } tsf_buf;
6659
6660         memset(&ioc, 0, sizeof(ioc));
6661         memset(&tsf_buf, 0, sizeof(tsf_buf));
6662
6663         ioc.cmd = WLC_GET_VAR;
6664         ioc.buf = buf;
6665         ioc.len = (uint)sizeof(buf);
6666         ioc.set = FALSE;
6667
6668         strncpy(buf, "tsf", sizeof(buf) - 1);
6669         buf[sizeof(buf) - 1] = '\0';
6670         s1 = dhd_get_htsf(dhd, 0);
6671         if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
6672                 if (ret == -EIO) {
6673                         DHD_ERROR(("%s: tsf is not supported by device\n",
6674                                 dhd_ifname(&dhd->pub, ifidx)));
6675                         return -EOPNOTSUPP;
6676                 }
6677                 return ret;
6678         }
6679         s2 = dhd_get_htsf(dhd, 0);
6680
6681         memcpy(&tsf_buf, buf, sizeof(tsf_buf));
6682         printf(" TSF_h=%04X lo=%08X Calc:htsf=%08X, coef=%d.%d%d delta=%d ",
6683                 tsf_buf.high, tsf_buf.low, s2, dhd->htsf.coef, dhd->htsf.coefdec1,
6684                 dhd->htsf.coefdec2, s2-tsf_buf.low);
6685         printf("lasttsf=%08X lastcycle=%08X\n", dhd->htsf.last_tsf, dhd->htsf.last_cycle);
6686         return 0;
6687 }
6688
6689 void htsf_update(dhd_info_t *dhd, void *data)
6690 {
6691         static ulong  cur_cycle = 0, prev_cycle = 0;
6692         uint32 htsf, tsf_delta = 0;
6693         uint32 hfactor = 0, cyc_delta, dec1 = 0, dec2, dec3, tmp;
6694         ulong b, a;
6695         cycles_t t;
6696
6697         /* cycles_t in inlcude/mips/timex.h */
6698
6699         t = get_cycles();
6700
6701         prev_cycle = cur_cycle;
6702         cur_cycle = t;
6703
6704         if (cur_cycle > prev_cycle)
6705                 cyc_delta = cur_cycle - prev_cycle;
6706         else {
6707                 b = cur_cycle;
6708                 a = prev_cycle;
6709                 cyc_delta = cur_cycle + (0xFFFFFFFF - prev_cycle);
6710         }
6711
6712         if (data == NULL)
6713                 printf(" tsf update ata point er is null \n");
6714
6715         memcpy(&prev_tsf, &cur_tsf, sizeof(tsf_t));
6716         memcpy(&cur_tsf, data, sizeof(tsf_t));
6717
6718         if (cur_tsf.low == 0) {
6719                 DHD_INFO((" ---- 0 TSF, do not update, return\n"));
6720                 return;
6721         }
6722
6723         if (cur_tsf.low > prev_tsf.low)
6724                 tsf_delta = (cur_tsf.low - prev_tsf.low);
6725         else {
6726                 DHD_INFO((" ---- tsf low is smaller cur_tsf= %08X, prev_tsf=%08X, \n",
6727                  cur_tsf.low, prev_tsf.low));
6728                 if (cur_tsf.high > prev_tsf.high) {
6729                         tsf_delta = cur_tsf.low + (0xFFFFFFFF - prev_tsf.low);
6730                         DHD_INFO((" ---- Wrap around tsf coutner  adjusted TSF=%08X\n", tsf_delta));
6731                 }
6732                 else
6733                         return; /* do not update */
6734         }
6735
6736         if (tsf_delta)  {
6737                 hfactor = cyc_delta / tsf_delta;
6738                 tmp  =  (cyc_delta - (hfactor * tsf_delta))*10;
6739                 dec1 =  tmp/tsf_delta;
6740                 dec2 =  ((tmp - dec1*tsf_delta)*10) / tsf_delta;
6741                 tmp  =  (tmp   - (dec1*tsf_delta))*10;
6742                 dec3 =  ((tmp - dec2*tsf_delta)*10) / tsf_delta;
6743
6744                 if (dec3 > 4) {
6745                         if (dec2 == 9) {
6746                                 dec2 = 0;
6747                                 if (dec1 == 9) {
6748                                         dec1 = 0;
6749                                         hfactor++;
6750                                 }
6751                                 else {
6752                                         dec1++;
6753                                 }
6754                         }
6755                         else
6756                                 dec2++;
6757                 }
6758         }
6759
6760         if (hfactor) {
6761                 htsf = ((cyc_delta * 10)  / (hfactor*10+dec1)) + prev_tsf.low;
6762                 dhd->htsf.coef = hfactor;
6763                 dhd->htsf.last_cycle = cur_cycle;
6764                 dhd->htsf.last_tsf = cur_tsf.low;
6765                 dhd->htsf.coefdec1 = dec1;
6766                 dhd->htsf.coefdec2 = dec2;
6767         }
6768         else {
6769                 htsf = prev_tsf.low;
6770         }
6771 }
6772
6773 #endif /* WLMEDIA_HTSF */