Merge tag 'lsk-v3.10-15.05-android' 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 505753 2014-10-01 01:40:15Z $
8  */
9
10 #include <typedefs.h>
11 #include <linuxver.h>
12 #include <osl.h>
13 #ifdef SHOW_LOGTRACE
14 #include <linux/syscalls.h>
15 #include <event_log.h>
16 #endif /* SHOW_LOGTRACE */
17
18
19 #include <linux/init.h>
20 #include <linux/kernel.h>
21 #include <linux/slab.h>
22 #include <linux/skbuff.h>
23 #include <linux/netdevice.h>
24 #include <linux/inetdevice.h>
25 #include <linux/rtnetlink.h>
26 #include <linux/etherdevice.h>
27 #include <linux/random.h>
28 #include <linux/spinlock.h>
29 #include <linux/ethtool.h>
30 #include <linux/fcntl.h>
31 #include <linux/fs.h>
32 #include <linux/ip.h>
33 #include <linux/reboot.h>
34 #include <linux/notifier.h>
35 #include <net/addrconf.h>
36 #ifdef ENABLE_ADAPTIVE_SCHED
37 #include <linux/cpufreq.h>
38 #endif /* ENABLE_ADAPTIVE_SCHED */
39
40 #include <asm/uaccess.h>
41 #include <asm/unaligned.h>
42
43 #include <epivers.h>
44 #include <bcmutils.h>
45 #include <bcmendian.h>
46 #include <bcmdevs.h>
47
48 #include <proto/ethernet.h>
49 #include <proto/bcmevent.h>
50 #include <proto/vlan.h>
51 #ifdef DHD_L2_FILTER
52 #include <proto/bcmicmp.h>
53 #endif
54 #include <proto/802.3.h>
55
56 #include <dngl_stats.h>
57 #include <dhd_linux_wq.h>
58 #include <dhd.h>
59 #include <dhd_linux.h>
60 #ifdef PCIE_FULL_DONGLE
61 #include <dhd_flowring.h>
62 #endif
63 #include <dhd_bus.h>
64 #include <dhd_proto.h>
65 #include <dhd_config.h>
66 #include <dhd_dbg.h>
67 #ifdef CONFIG_HAS_WAKELOCK
68 #include <linux/wakelock.h>
69 #endif
70 #ifdef WL_CFG80211
71 #include <wl_cfg80211.h>
72 #endif
73 #ifdef P2PONEINT
74 #include <wl_cfgp2p.h>
75 #endif
76 #ifdef PNO_SUPPORT
77 #include <dhd_pno.h>
78 #endif
79 #ifdef WLBTAMP
80 #include <proto/802.11_bta.h>
81 #include <proto/bt_amp_hci.h>
82 #include <dhd_bta.h>
83 #endif
84
85 #ifdef CONFIG_COMPAT
86 #include <linux/compat.h>
87 #endif
88
89 #ifdef DHD_WMF
90 #include <dhd_wmf_linux.h>
91 #endif /* DHD_WMF */
92
93 #ifdef AMPDU_VO_ENABLE
94 #include <proto/802.1d.h>
95 #endif /* AMPDU_VO_ENABLE */
96 #ifdef DHDTCPACK_SUPPRESS
97 #include <dhd_ip.h>
98 #endif /* DHDTCPACK_SUPPRESS */
99
100 #if defined(DHD_TCP_WINSIZE_ADJUST)
101 #include <linux/tcp.h>
102 #include <net/tcp.h>
103 #endif /* DHD_TCP_WINSIZE_ADJUST */
104
105 #ifdef WLMEDIA_HTSF
106 #include <linux/time.h>
107 #include <htsf.h>
108
109 #define HTSF_MINLEN 200    /* min. packet length to timestamp */
110 #define HTSF_BUS_DELAY 150 /* assume a fix propagation in us  */
111 #define TSMAX  1000        /* max no. of timing record kept   */
112 #define NUMBIN 34
113
114 static uint32 tsidx = 0;
115 static uint32 htsf_seqnum = 0;
116 uint32 tsfsync;
117 struct timeval tsync;
118 static uint32 tsport = 5010;
119
120 typedef struct histo_ {
121         uint32 bin[NUMBIN];
122 } histo_t;
123
124 #if !ISPOWEROF2(DHD_SDALIGN)
125 #error DHD_SDALIGN is not a power of 2!
126 #endif
127
128 static histo_t vi_d1, vi_d2, vi_d3, vi_d4;
129 #endif /* WLMEDIA_HTSF */
130
131 #if defined(DHD_TCP_WINSIZE_ADJUST)
132 #define MIN_TCP_WIN_SIZE 18000
133 #define WIN_SIZE_SCALE_FACTOR 2
134 #define MAX_TARGET_PORTS 5
135
136 static uint target_ports[MAX_TARGET_PORTS] = {20, 0, 0, 0, 0};
137 static uint dhd_use_tcp_window_size_adjust = FALSE;
138 static void dhd_adjust_tcp_winsize(int op_mode, struct sk_buff *skb);
139 #endif /* DHD_TCP_WINSIZE_ADJUST */
140
141
142 #if defined(SOFTAP)
143 extern bool ap_cfg_running;
144 extern bool ap_fw_loaded;
145 #endif
146
147
148 #ifdef ENABLE_ADAPTIVE_SCHED
149 #define DEFAULT_CPUFREQ_THRESH          1000000 /* threshold frequency : 1000000 = 1GHz */
150 #ifndef CUSTOM_CPUFREQ_THRESH
151 #define CUSTOM_CPUFREQ_THRESH   DEFAULT_CPUFREQ_THRESH
152 #endif /* CUSTOM_CPUFREQ_THRESH */
153 #endif /* ENABLE_ADAPTIVE_SCHED */
154
155 /* enable HOSTIP cache update from the host side when an eth0:N is up */
156 #define AOE_IP_ALIAS_SUPPORT 1
157
158 #ifdef BCM_FD_AGGR
159 #include <bcm_rpc.h>
160 #include <bcm_rpc_tp.h>
161 #endif
162 #ifdef PROP_TXSTATUS
163 #include <wlfc_proto.h>
164 #include <dhd_wlfc.h>
165 #endif
166
167 #include <wl_android.h>
168
169 #if defined(CUSTOMER_HW20) && defined(WLANAUDIO)
170 #include <sdaudio.h>
171 #endif /* CUSTOMER_HW20 && WLANAUDIO */
172
173 /* Maximum STA per radio */
174 #define DHD_MAX_STA     32
175
176
177 const uint8 wme_fifo2ac[] = { 0, 1, 2, 3, 1, 1 };
178 const uint8 prio2fifo[8] = { 1, 0, 0, 1, 2, 2, 3, 3 };
179 #define WME_PRIO2AC(prio)  wme_fifo2ac[prio2fifo[(prio)]]
180
181 #ifdef ARP_OFFLOAD_SUPPORT
182 void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx);
183 static int dhd_inetaddr_notifier_call(struct notifier_block *this,
184         unsigned long event, void *ptr);
185 static struct notifier_block dhd_inetaddr_notifier = {
186         .notifier_call = dhd_inetaddr_notifier_call
187 };
188 /* to make sure we won't register the same notifier twice, otherwise a loop is likely to be
189  * created in kernel notifier link list (with 'next' pointing to itself)
190  */
191 static bool dhd_inetaddr_notifier_registered = FALSE;
192 #endif /* ARP_OFFLOAD_SUPPORT */
193
194 #ifdef CONFIG_IPV6
195 static int dhd_inet6addr_notifier_call(struct notifier_block *this,
196         unsigned long event, void *ptr);
197 static struct notifier_block dhd_inet6addr_notifier = {
198         .notifier_call = dhd_inet6addr_notifier_call
199 };
200 /* to make sure we won't register the same notifier twice, otherwise a loop is likely to be
201  * created in kernel notifier link list (with 'next' pointing to itself)
202  */
203 static bool dhd_inet6addr_notifier_registered = FALSE;
204 #endif
205
206 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
207 #include <linux/suspend.h>
208 volatile bool dhd_mmc_suspend = FALSE;
209 DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait);
210 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
211
212 #if defined(OOB_INTR_ONLY)
213 extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable);
214 #endif 
215 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (1)
216 static void dhd_hang_process(void *dhd_info, void *event_data, u8 event);
217 #endif 
218 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
219 MODULE_LICENSE("GPL v2");
220 #endif /* LinuxVer */
221
222 #include <dhd_bus.h>
223
224 #ifdef BCM_FD_AGGR
225 #define DBUS_RX_BUFFER_SIZE_DHD(net)    (BCM_RPC_TP_DNGL_AGG_MAX_BYTE)
226 #else
227 #ifndef PROP_TXSTATUS
228 #define DBUS_RX_BUFFER_SIZE_DHD(net)    (net->mtu + net->hard_header_len + dhd->pub.hdrlen)
229 #else
230 #define DBUS_RX_BUFFER_SIZE_DHD(net)    (net->mtu + net->hard_header_len + dhd->pub.hdrlen + 128)
231 #endif
232 #endif /* BCM_FD_AGGR */
233
234 #ifdef PROP_TXSTATUS
235 extern bool dhd_wlfc_skip_fc(void);
236 extern void dhd_wlfc_plat_init(void *dhd);
237 extern void dhd_wlfc_plat_deinit(void *dhd);
238 #endif /* PROP_TXSTATUS */
239
240 #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15)
241 const char *
242 print_tainted()
243 {
244         return "";
245 }
246 #endif  /* LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) */
247
248 /* Linux wireless extension support */
249 #if defined(WL_WIRELESS_EXT)
250 #include <wl_iw.h>
251 extern wl_iw_extra_params_t  g_wl_iw_params;
252 #endif /* defined(WL_WIRELESS_EXT) */
253
254 #if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
255 #include <linux/earlysuspend.h>
256 #endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */
257
258 extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd);
259
260 #ifdef PKT_FILTER_SUPPORT
261 extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg);
262 extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode);
263 extern void dhd_pktfilter_offload_delete(dhd_pub_t *dhd, int id);
264 #endif
265
266
267 #ifdef READ_MACADDR
268 extern int dhd_read_macaddr(struct dhd_info *dhd);
269 #else
270 static inline int dhd_read_macaddr(struct dhd_info *dhd) { return 0; }
271 #endif
272 #ifdef WRITE_MACADDR
273 extern int dhd_write_macaddr(struct ether_addr *mac);
274 #else
275 static inline int dhd_write_macaddr(struct ether_addr *mac) { return 0; }
276 #endif
277
278
279 #if defined(SOFTAP_TPUT_ENHANCE)
280 extern void dhd_bus_setidletime(dhd_pub_t *dhdp, int idle_time);
281 extern void dhd_bus_getidletime(dhd_pub_t *dhdp, int* idle_time);
282 #endif /* SOFTAP_TPUT_ENHANCE */
283
284
285 #ifdef SET_RPS_CPUS
286 int custom_rps_map_set(struct netdev_rx_queue *queue, char *buf, size_t len);
287 void custom_rps_map_clear(struct netdev_rx_queue *queue);
288 #ifdef CONFIG_MACH_UNIVERSAL5433
289 #define RPS_CPUS_MASK "10"
290 #else
291 #define RPS_CPUS_MASK "6"
292 #endif /* CONFIG_MACH_UNIVERSAL5433 */
293 #endif /* SET_RPS_CPUS */
294
295 static int dhd_reboot_callback(struct notifier_block *this, unsigned long code, void *unused);
296 static struct notifier_block dhd_reboot_notifier = {
297                 .notifier_call = dhd_reboot_callback,
298                 .priority = 1,
299 };
300
301
302 typedef struct dhd_if_event {
303         struct list_head        list;
304         wl_event_data_if_t      event;
305         char                    name[IFNAMSIZ+1];
306         uint8                   mac[ETHER_ADDR_LEN];
307 } dhd_if_event_t;
308
309 /* Interface control information */
310 typedef struct dhd_if {
311         struct dhd_info *info;                  /* back pointer to dhd_info */
312         /* OS/stack specifics */
313         struct net_device *net;
314         int                             idx;                    /* iface idx in dongle */
315         uint                    subunit;                /* subunit */
316         uint8                   mac_addr[ETHER_ADDR_LEN];       /* assigned MAC address */
317         bool                    set_macaddress;
318         bool                    set_multicast;
319         uint8                   bssidx;                 /* bsscfg index for the interface */
320         bool                    attached;               /* Delayed attachment when unset */
321         bool                    txflowcontrol;  /* Per interface flow control indicator */
322         char                    name[IFNAMSIZ+1]; /* linux interface name */
323         struct net_device_stats stats;
324 #ifdef DHD_WMF
325         dhd_wmf_t               wmf;            /* per bsscfg wmf setting */
326 #endif /* DHD_WMF */
327 #ifdef PCIE_FULL_DONGLE
328         struct list_head sta_list;              /* sll of associated stations */
329 #if !defined(BCM_GMAC3)
330         spinlock_t      sta_list_lock;          /* lock for manipulating sll */
331 #endif /* ! BCM_GMAC3 */
332 #endif /* PCIE_FULL_DONGLE */
333         uint32  ap_isolate;                     /* ap-isolation settings */
334 } dhd_if_t;
335
336 #ifdef WLMEDIA_HTSF
337 typedef struct {
338         uint32 low;
339         uint32 high;
340 } tsf_t;
341
342 typedef struct {
343         uint32 last_cycle;
344         uint32 last_sec;
345         uint32 last_tsf;
346         uint32 coef;     /* scaling factor */
347         uint32 coefdec1; /* first decimal  */
348         uint32 coefdec2; /* second decimal */
349 } htsf_t;
350
351 typedef struct {
352         uint32 t1;
353         uint32 t2;
354         uint32 t3;
355         uint32 t4;
356 } tstamp_t;
357
358 static tstamp_t ts[TSMAX];
359 static tstamp_t maxdelayts;
360 static uint32 maxdelay = 0, tspktcnt = 0, maxdelaypktno = 0;
361
362 #endif  /* WLMEDIA_HTSF */
363
364 struct ipv6_work_info_t {
365         uint8                   if_idx;
366         char                    ipv6_addr[16];
367         unsigned long           event;
368 };
369
370 #if defined(CUSTOMER_HW20) && defined(WLANAUDIO)
371 #define MAX_WLANAUDIO_BLACKLIST 4
372
373 struct wlanaudio_blacklist {
374         bool is_blacklist;
375         uint32 cnt;
376         ulong txfail_jiffies;
377         struct ether_addr blacklist_addr;
378 };
379 #endif /* CUSTOMER_HW20 && WLANAUDIO */
380
381 /* When Perimeter locks are deployed, any blocking calls must be preceeded
382  * with a PERIM UNLOCK and followed by a PERIM LOCK.
383  * Examples of blocking calls are: schedule_timeout(), down_interruptible(),
384  * wait_event_timeout().
385  */
386
387 /* Local private structure (extension of pub) */
388 typedef struct dhd_info {
389 #if defined(WL_WIRELESS_EXT)
390         wl_iw_t         iw;             /* wireless extensions state (must be first) */
391 #endif /* defined(WL_WIRELESS_EXT) */
392         dhd_pub_t pub;
393         dhd_if_t *iflist[DHD_MAX_IFS]; /* for supporting multiple interfaces */
394
395         void *adapter;                  /* adapter information, interrupt, fw path etc. */
396         char fw_path[PATH_MAX];         /* path to firmware image */
397         char nv_path[PATH_MAX];         /* path to nvram vars file */
398         char conf_path[PATH_MAX];       /* path to config vars file */
399
400         struct semaphore proto_sem;
401 #ifdef PROP_TXSTATUS
402         spinlock_t      wlfc_spinlock;
403
404 #endif /* PROP_TXSTATUS */
405 #ifdef WLMEDIA_HTSF
406         htsf_t  htsf;
407 #endif
408         wait_queue_head_t ioctl_resp_wait;
409         uint32  default_wd_interval;
410
411         struct timer_list timer;
412         bool wd_timer_valid;
413         struct tasklet_struct tasklet;
414         spinlock_t      sdlock;
415         spinlock_t      txqlock;
416         spinlock_t      dhd_lock;
417
418         struct semaphore sdsem;
419         tsk_ctl_t       thr_dpc_ctl;
420         tsk_ctl_t       thr_wdt_ctl;
421
422         tsk_ctl_t       thr_rxf_ctl;
423         spinlock_t      rxf_lock;
424         bool            rxthread_enabled;
425
426         /* Wakelocks */
427 #if defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
428         struct wake_lock wl_wifi;   /* Wifi wakelock */
429         struct wake_lock wl_rxwake; /* Wifi rx wakelock */
430         struct wake_lock wl_ctrlwake; /* Wifi ctrl wakelock */
431         struct wake_lock wl_wdwake; /* Wifi wd wakelock */
432 #ifdef BCMPCIE_OOB_HOST_WAKE
433         struct wake_lock wl_intrwake; /* Host wakeup wakelock */
434 #endif /* BCMPCIE_OOB_HOST_WAKE */
435 #endif /* CONFIG_HAS_WAKELOCK && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */
436
437 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
438         /* net_device interface lock, prevent race conditions among net_dev interface
439          * calls and wifi_on or wifi_off
440          */
441         struct mutex dhd_net_if_mutex;
442         struct mutex dhd_suspend_mutex;
443 #endif
444         spinlock_t wakelock_spinlock;
445         uint32 wakelock_counter;
446         int wakelock_wd_counter;
447         int wakelock_rx_timeout_enable;
448         int wakelock_ctrl_timeout_enable;
449         bool waive_wakelock;
450         uint32 wakelock_before_waive;
451
452         /* Thread to issue ioctl for multicast */
453         wait_queue_head_t ctrl_wait;
454         atomic_t pend_8021x_cnt;
455         dhd_attach_states_t dhd_state;
456 #ifdef SHOW_LOGTRACE
457         dhd_event_log_t event_data;
458 #endif /* SHOW_LOGTRACE */
459
460 #if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
461         struct early_suspend early_suspend;
462 #endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */
463
464 #ifdef ARP_OFFLOAD_SUPPORT
465         u32 pend_ipaddr;
466 #endif /* ARP_OFFLOAD_SUPPORT */
467 #ifdef BCM_FD_AGGR
468         void *rpc_th;
469         void *rpc_osh;
470         struct timer_list rpcth_timer;
471         bool rpcth_timer_active;
472         bool fdaggr;
473 #endif
474 #ifdef DHDTCPACK_SUPPRESS
475         spinlock_t      tcpack_lock;
476 #endif /* DHDTCPACK_SUPPRESS */
477         void                    *dhd_deferred_wq;
478 #ifdef DEBUG_CPU_FREQ
479         struct notifier_block freq_trans;
480         int __percpu *new_freq;
481 #endif
482         unsigned int unit;
483         struct notifier_block pm_notifier;
484 #if defined(CUSTOMER_HW20) && defined(WLANAUDIO)
485         struct wlanaudio_blacklist wlanaudio_blist[MAX_WLANAUDIO_BLACKLIST];
486         bool is_wlanaudio_blist;
487 #endif /* CUSTOMER_HW20 && WLANAUDIO */
488 } dhd_info_t;
489
490 #define DHDIF_FWDER(dhdif)      FALSE
491
492 /* Flag to indicate if we should download firmware on driver load */
493 uint dhd_download_fw_on_driverload = TRUE;
494
495 /* Definitions to provide path to the firmware and nvram
496  * example nvram_path[MOD_PARAM_PATHLEN]="/projects/wlan/nvram.txt"
497  */
498 char firmware_path[MOD_PARAM_PATHLEN];
499 char nvram_path[MOD_PARAM_PATHLEN];
500 char config_path[MOD_PARAM_PATHLEN];
501
502 /* backup buffer for firmware and nvram path */
503 char fw_bak_path[MOD_PARAM_PATHLEN];
504 char nv_bak_path[MOD_PARAM_PATHLEN];
505
506 /* information string to keep firmware, chio, cheip version info visiable from log */
507 char info_string[MOD_PARAM_INFOLEN];
508 module_param_string(info_string, info_string, MOD_PARAM_INFOLEN, 0444);
509 int op_mode = 0;
510 int disable_proptx = 0;
511 module_param(op_mode, int, 0644);
512 extern int wl_control_wl_start(struct net_device *dev);
513 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(BCMLXSDMMC)
514 struct semaphore dhd_registration_sem;
515 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
516
517 /* deferred handlers */
518 static void dhd_ifadd_event_handler(void *handle, void *event_info, u8 event);
519 static void dhd_ifdel_event_handler(void *handle, void *event_info, u8 event);
520 static void dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event);
521 static void dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event);
522 #ifdef CONFIG_IPV6
523 static void dhd_inet6_work_handler(void *dhd_info, void *event_data, u8 event);
524 #endif
525
526 #ifdef WL_CFG80211
527 extern void dhd_netdev_free(struct net_device *ndev);
528 #endif /* WL_CFG80211 */
529
530 /* Error bits */
531 module_param(dhd_msg_level, int, 0);
532 #if defined(WL_WIRELESS_EXT)
533 module_param(iw_msg_level, int, 0);
534 #endif
535 #ifdef WL_CFG80211
536 module_param(wl_dbg_level, int, 0);
537 #endif
538 module_param(android_msg_level, int, 0);
539 module_param(config_msg_level, int, 0);
540
541 #ifdef ARP_OFFLOAD_SUPPORT
542 /* ARP offload enable */
543 uint dhd_arp_enable = TRUE;
544 module_param(dhd_arp_enable, uint, 0);
545
546 /* ARP offload agent mode : Enable ARP Host Auto-Reply and ARP Peer Auto-Reply */
547
548 uint dhd_arp_mode = ARP_OL_AGENT | ARP_OL_PEER_AUTO_REPLY;
549
550 module_param(dhd_arp_mode, uint, 0);
551 #endif /* ARP_OFFLOAD_SUPPORT */
552
553 /* Disable Prop tx */
554 module_param(disable_proptx, int, 0644);
555 /* load firmware and/or nvram values from the filesystem */
556 module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0660);
557 module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0660);
558 module_param_string(config_path, config_path, MOD_PARAM_PATHLEN, 0);
559
560 /* Watchdog interval */
561
562 /* extend watchdog expiration to 2 seconds when DPC is running */
563 #define WATCHDOG_EXTEND_INTERVAL (2000)
564
565 uint dhd_watchdog_ms = CUSTOM_DHD_WATCHDOG_MS;
566 module_param(dhd_watchdog_ms, uint, 0);
567
568 #if defined(DHD_DEBUG)
569 /* Console poll interval */
570 uint dhd_console_ms = 0;
571 module_param(dhd_console_ms, uint, 0644);
572 #endif /* defined(DHD_DEBUG) */
573
574
575 uint dhd_slpauto = TRUE;
576 module_param(dhd_slpauto, uint, 0);
577
578 #ifdef PKT_FILTER_SUPPORT
579 /* Global Pkt filter enable control */
580 uint dhd_pkt_filter_enable = TRUE;
581 module_param(dhd_pkt_filter_enable, uint, 0);
582 #endif
583
584 /* Pkt filter init setup */
585 uint dhd_pkt_filter_init = 0;
586 module_param(dhd_pkt_filter_init, uint, 0);
587
588 /* Pkt filter mode control */
589 uint dhd_master_mode = FALSE;
590 module_param(dhd_master_mode, uint, 0);
591
592 int dhd_watchdog_prio = 0;
593 module_param(dhd_watchdog_prio, int, 0);
594
595 /* DPC thread priority */
596 int dhd_dpc_prio = CUSTOM_DPC_PRIO_SETTING;
597 module_param(dhd_dpc_prio, int, 0);
598
599 /* RX frame thread priority */
600 int dhd_rxf_prio = CUSTOM_RXF_PRIO_SETTING;
601 module_param(dhd_rxf_prio, int, 0);
602
603 int passive_channel_skip = 0;
604 module_param(passive_channel_skip, int, (S_IRUSR|S_IWUSR));
605
606 #if !defined(BCMDHDUSB)
607 extern int dhd_dongle_ramsize;
608 module_param(dhd_dongle_ramsize, int, 0);
609 #endif /* BCMDHDUSB */
610
611 /* Keep track of number of instances */
612 static int dhd_found = 0;
613 static int instance_base = 0; /* Starting instance number */
614 module_param(instance_base, int, 0644);
615
616 #if defined(CUSTOMER_HW20) && defined(WLANAUDIO)
617 dhd_info_t *dhd_global = NULL;
618 #endif /* CUSTOMER_HW20 && WLANAUDIO */
619
620
621
622 /* DHD Perimiter lock only used in router with bypass forwarding. */
623 #define DHD_PERIM_RADIO_INIT()              do { /* noop */ } while (0)
624 #define DHD_PERIM_LOCK_TRY(unit, flag)      do { /* noop */ } while (0)
625 #define DHD_PERIM_UNLOCK_TRY(unit, flag)    do { /* noop */ } while (0)
626 #define DHD_PERIM_LOCK_ALL()                do { /* noop */ } while (0)
627 #define DHD_PERIM_UNLOCK_ALL()              do { /* noop */ } while (0)
628
629 #ifdef PCIE_FULL_DONGLE
630 #if defined(BCM_GMAC3)
631 #define DHD_IF_STA_LIST_LOCK_INIT(ifp)      do { /* noop */ } while (0)
632 #define DHD_IF_STA_LIST_LOCK(ifp, flags)    ({ BCM_REFERENCE(flags); })
633 #define DHD_IF_STA_LIST_UNLOCK(ifp, flags)  ({ BCM_REFERENCE(flags); })
634 #else /* ! BCM_GMAC3 */
635 #define DHD_IF_STA_LIST_LOCK_INIT(ifp) spin_lock_init(&(ifp)->sta_list_lock)
636 #define DHD_IF_STA_LIST_LOCK(ifp, flags) \
637         spin_lock_irqsave(&(ifp)->sta_list_lock, (flags))
638 #define DHD_IF_STA_LIST_UNLOCK(ifp, flags) \
639         spin_unlock_irqrestore(&(ifp)->sta_list_lock, (flags))
640 #endif /* ! BCM_GMAC3 */
641 #endif /* PCIE_FULL_DONGLE */
642
643 /* Control fw roaming */
644 #ifdef BCMCCX
645 uint dhd_roam_disable = 0;
646 #else
647 uint dhd_roam_disable = 0;
648 #endif /* BCMCCX */
649
650 /* Control radio state */
651 uint dhd_radio_up = 1;
652
653 /* Network inteface name */
654 char iface_name[IFNAMSIZ] = {'\0'};
655 module_param_string(iface_name, iface_name, IFNAMSIZ, 0);
656
657 /* The following are specific to the SDIO dongle */
658
659 /* IOCTL response timeout */
660 int dhd_ioctl_timeout_msec = IOCTL_RESP_TIMEOUT;
661
662 /* Idle timeout for backplane clock */
663 int dhd_idletime = DHD_IDLETIME_TICKS;
664 module_param(dhd_idletime, int, 0);
665
666 /* Use polling */
667 uint dhd_poll = FALSE;
668 module_param(dhd_poll, uint, 0);
669
670 /* Use interrupts */
671 uint dhd_intr = TRUE;
672 module_param(dhd_intr, uint, 0);
673
674 /* SDIO Drive Strength (in milliamps) */
675 uint dhd_sdiod_drive_strength = 6;
676 module_param(dhd_sdiod_drive_strength, uint, 0);
677
678 #ifdef BCMSDIO
679 /* Tx/Rx bounds */
680 extern uint dhd_txbound;
681 extern uint dhd_rxbound;
682 module_param(dhd_txbound, uint, 0);
683 module_param(dhd_rxbound, uint, 0);
684
685 /* Deferred transmits */
686 extern uint dhd_deferred_tx;
687 module_param(dhd_deferred_tx, uint, 0);
688
689 #ifdef BCMDBGFS
690 extern void dhd_dbg_init(dhd_pub_t *dhdp);
691 extern void dhd_dbg_remove(void);
692 #endif /* BCMDBGFS */
693
694 #endif /* BCMSDIO */
695
696
697 #ifdef SDTEST
698 /* Echo packet generator (pkts/s) */
699 uint dhd_pktgen = 0;
700 module_param(dhd_pktgen, uint, 0);
701
702 /* Echo packet len (0 => sawtooth, max 2040) */
703 uint dhd_pktgen_len = 0;
704 module_param(dhd_pktgen_len, uint, 0);
705 #endif /* SDTEST */
706
707 #if defined(BCMSUP_4WAY_HANDSHAKE)
708 /* Use in dongle supplicant for 4-way handshake */
709 uint dhd_use_idsup = 0;
710 module_param(dhd_use_idsup, uint, 0);
711 #endif /* BCMSUP_4WAY_HANDSHAKE */
712
713 extern char dhd_version[];
714
715 int dhd_net_bus_devreset(struct net_device *dev, uint8 flag);
716 static void dhd_net_if_lock_local(dhd_info_t *dhd);
717 static void dhd_net_if_unlock_local(dhd_info_t *dhd);
718 static void dhd_suspend_lock(dhd_pub_t *dhdp);
719 static void dhd_suspend_unlock(dhd_pub_t *dhdp);
720
721 #ifdef WLMEDIA_HTSF
722 void htsf_update(dhd_info_t *dhd, void *data);
723 tsf_t prev_tsf, cur_tsf;
724
725 uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx);
726 static int dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx);
727 static void dhd_dump_latency(void);
728 static void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf);
729 static void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf);
730 static void dhd_dump_htsfhisto(histo_t *his, char *s);
731 #endif /* WLMEDIA_HTSF */
732
733 /* Monitor interface */
734 int dhd_monitor_init(void *dhd_pub);
735 int dhd_monitor_uninit(void);
736
737
738 #if defined(WL_WIRELESS_EXT)
739 struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev);
740 #endif /* defined(WL_WIRELESS_EXT) */
741
742 static void dhd_dpc(ulong data);
743 /* forward decl */
744 extern int dhd_wait_pend8021x(struct net_device *dev);
745 void dhd_os_wd_timer_extend(void *bus, bool extend);
746
747 #ifdef TOE
748 #ifndef BDC
749 #error TOE requires BDC
750 #endif /* !BDC */
751 static int dhd_toe_get(dhd_info_t *dhd, int idx, uint32 *toe_ol);
752 static int dhd_toe_set(dhd_info_t *dhd, int idx, uint32 toe_ol);
753 #endif /* TOE */
754
755 static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
756                              wl_event_msg_t *event_ptr, void **data_ptr);
757 #ifdef DHD_UNICAST_DHCP
758 static const uint8 llc_snap_hdr[SNAP_HDR_LEN] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
759 static int dhd_get_pkt_ip_type(dhd_pub_t *dhd, void *skb, uint8 **data_ptr,
760         int *len_ptr, uint8 *prot_ptr);
761 static int dhd_get_pkt_ether_type(dhd_pub_t *dhd, void *skb, uint8 **data_ptr,
762         int *len_ptr, uint16 *et_ptr, bool *snap_ptr);
763
764 static int dhd_convert_dhcp_broadcast_ack_to_unicast(dhd_pub_t *pub, void *pktbuf, int ifidx);
765 #endif /* DHD_UNICAST_DHCP */
766 #ifdef DHD_L2_FILTER
767 static int dhd_l2_filter_block_ping(dhd_pub_t *pub, void *pktbuf, int ifidx);
768 #endif
769 #if defined(CONFIG_PM_SLEEP)
770 static int dhd_pm_callback(struct notifier_block *nfb, unsigned long action, void *ignored)
771 {
772         int ret = NOTIFY_DONE;
773         bool suspend = FALSE;
774         dhd_info_t *dhdinfo = (dhd_info_t*)container_of(nfb, struct dhd_info, pm_notifier);
775
776         BCM_REFERENCE(dhdinfo);
777         switch (action) {
778         case PM_HIBERNATION_PREPARE:
779         case PM_SUSPEND_PREPARE:
780                 suspend = TRUE;
781                 break;
782         case PM_POST_HIBERNATION:
783         case PM_POST_SUSPEND:
784                 suspend = FALSE;
785                 break;
786         }
787
788 #if defined(SUPPORT_P2P_GO_PS)
789 #ifdef PROP_TXSTATUS
790         if (suspend) {
791                 DHD_OS_WAKE_LOCK_WAIVE(&dhdinfo->pub);
792                 dhd_wlfc_suspend(&dhdinfo->pub);
793                 DHD_OS_WAKE_LOCK_RESTORE(&dhdinfo->pub);
794         } else
795                 dhd_wlfc_resume(&dhdinfo->pub);
796 #endif
797 #endif /* defined(SUPPORT_P2P_GO_PS) */
798
799 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \
800         KERNEL_VERSION(2, 6, 39))
801         dhd_mmc_suspend = suspend;
802         smp_mb();
803 #endif
804
805         return ret;
806 }
807
808 static struct notifier_block dhd_pm_notifier = {
809         .notifier_call = dhd_pm_callback,
810         .priority = 10
811 };
812 /* to make sure we won't register the same notifier twice, otherwise a loop is likely to be
813  * created in kernel notifier link list (with 'next' pointing to itself)
814  */
815 static bool dhd_pm_notifier_registered = FALSE;
816
817 extern int register_pm_notifier(struct notifier_block *nb);
818 extern int unregister_pm_notifier(struct notifier_block *nb);
819 #endif /* CONFIG_PM_SLEEP */
820
821 /* Request scheduling of the bus rx frame */
822 static void dhd_sched_rxf(dhd_pub_t *dhdp, void *skb);
823 static void dhd_os_rxflock(dhd_pub_t *pub);
824 static void dhd_os_rxfunlock(dhd_pub_t *pub);
825
826 /** priv_link is the link between netdev and the dhdif and dhd_info structs. */
827 typedef struct dhd_dev_priv {
828         dhd_info_t * dhd; /* cached pointer to dhd_info in netdevice priv */
829         dhd_if_t   * ifp; /* cached pointer to dhd_if in netdevice priv */
830         int          ifidx; /* interface index */
831 } dhd_dev_priv_t;
832
833 #define DHD_DEV_PRIV_SIZE       (sizeof(dhd_dev_priv_t))
834 #define DHD_DEV_PRIV(dev)       ((dhd_dev_priv_t *)DEV_PRIV(dev))
835 #define DHD_DEV_INFO(dev)       (((dhd_dev_priv_t *)DEV_PRIV(dev))->dhd)
836 #define DHD_DEV_IFP(dev)        (((dhd_dev_priv_t *)DEV_PRIV(dev))->ifp)
837 #define DHD_DEV_IFIDX(dev)      (((dhd_dev_priv_t *)DEV_PRIV(dev))->ifidx)
838
839 /** Clear the dhd net_device's private structure. */
840 static inline void
841 dhd_dev_priv_clear(struct net_device * dev)
842 {
843         dhd_dev_priv_t * dev_priv;
844         ASSERT(dev != (struct net_device *)NULL);
845         dev_priv = DHD_DEV_PRIV(dev);
846         dev_priv->dhd = (dhd_info_t *)NULL;
847         dev_priv->ifp = (dhd_if_t *)NULL;
848         dev_priv->ifidx = DHD_BAD_IF;
849 }
850
851 /** Setup the dhd net_device's private structure. */
852 static inline void
853 dhd_dev_priv_save(struct net_device * dev, dhd_info_t * dhd, dhd_if_t * ifp,
854                   int ifidx)
855 {
856         dhd_dev_priv_t * dev_priv;
857         ASSERT(dev != (struct net_device *)NULL);
858         dev_priv = DHD_DEV_PRIV(dev);
859         dev_priv->dhd = dhd;
860         dev_priv->ifp = ifp;
861         dev_priv->ifidx = ifidx;
862 }
863
864 #ifdef PCIE_FULL_DONGLE
865
866 /** Dummy objects are defined with state representing bad|down.
867  * Performance gains from reducing branch conditionals, instruction parallelism,
868  * dual issue, reducing load shadows, avail of larger pipelines.
869  * Use DHD_XXX_NULL instead of (dhd_xxx_t *)NULL, whenever an object pointer
870  * is accessed via the dhd_sta_t.
871  */
872
873 /* Dummy dhd_info object */
874 dhd_info_t dhd_info_null = {
875 #if defined(BCM_GMAC3)
876         .fwdh = FWDER_NULL,
877 #endif
878         .pub = {
879                  .info = &dhd_info_null,
880 #ifdef DHDTCPACK_SUPPRESS
881                  .tcpack_sup_mode = TCPACK_SUP_REPLACE,
882 #endif /* DHDTCPACK_SUPPRESS */
883                  .up = FALSE, .busstate = DHD_BUS_DOWN
884         }
885 };
886 #define DHD_INFO_NULL (&dhd_info_null)
887 #define DHD_PUB_NULL  (&dhd_info_null.pub)
888
889 /* Dummy netdevice object */
890 struct net_device dhd_net_dev_null = {
891         .reg_state = NETREG_UNREGISTERED
892 };
893 #define DHD_NET_DEV_NULL (&dhd_net_dev_null)
894
895 /* Dummy dhd_if object */
896 dhd_if_t dhd_if_null = {
897 #if defined(BCM_GMAC3)
898         .fwdh = FWDER_NULL,
899 #endif
900 #ifdef WMF
901         .wmf = { .wmf_enable = TRUE },
902 #endif
903         .info = DHD_INFO_NULL,
904         .net = DHD_NET_DEV_NULL,
905         .idx = DHD_BAD_IF
906 };
907 #define DHD_IF_NULL  (&dhd_if_null)
908
909 #define DHD_STA_NULL ((dhd_sta_t *)NULL)
910
911 /** Interface STA list management. */
912
913 /** Fetch the dhd_if object, given the interface index in the dhd. */
914 static inline dhd_if_t *dhd_get_ifp(dhd_pub_t *dhdp, uint32 ifidx);
915
916 /** Alloc/Free a dhd_sta object from the dhd instances' sta_pool. */
917 static void dhd_sta_free(dhd_pub_t *pub, dhd_sta_t *sta);
918 static dhd_sta_t * dhd_sta_alloc(dhd_pub_t * dhdp);
919
920 /* Delete a dhd_sta or flush all dhd_sta in an interface's sta_list. */
921 static void dhd_if_del_sta_list(dhd_if_t * ifp);
922 static void     dhd_if_flush_sta(dhd_if_t * ifp);
923
924 /* Construct/Destruct a sta pool. */
925 static int dhd_sta_pool_init(dhd_pub_t *dhdp, int max_sta);
926 static void dhd_sta_pool_fini(dhd_pub_t *dhdp, int max_sta);
927 static void dhd_sta_pool_clear(dhd_pub_t *dhdp, int max_sta);
928
929
930 /* Return interface pointer */
931 static inline dhd_if_t *dhd_get_ifp(dhd_pub_t *dhdp, uint32 ifidx)
932 {
933         ASSERT(ifidx < DHD_MAX_IFS);
934
935         if (ifidx >= DHD_MAX_IFS)
936                 return NULL;
937
938         return dhdp->info->iflist[ifidx];
939 }
940
941 /** Reset a dhd_sta object and free into the dhd pool. */
942 static void
943 dhd_sta_free(dhd_pub_t * dhdp, dhd_sta_t * sta)
944 {
945         int prio;
946
947         ASSERT((sta != DHD_STA_NULL) && (sta->idx != ID16_INVALID));
948
949         ASSERT((dhdp->staid_allocator != NULL) && (dhdp->sta_pool != NULL));
950         id16_map_free(dhdp->staid_allocator, sta->idx);
951         for (prio = 0; prio < (int)NUMPRIO; prio++)
952                 sta->flowid[prio] = FLOWID_INVALID;
953         sta->ifp = DHD_IF_NULL; /* dummy dhd_if object */
954         sta->ifidx = DHD_BAD_IF;
955         bzero(sta->ea.octet, ETHER_ADDR_LEN);
956         INIT_LIST_HEAD(&sta->list);
957         sta->idx = ID16_INVALID; /* implying free */
958 }
959
960 /** Allocate a dhd_sta object from the dhd pool. */
961 static dhd_sta_t *
962 dhd_sta_alloc(dhd_pub_t * dhdp)
963 {
964         uint16 idx;
965         dhd_sta_t * sta;
966         dhd_sta_pool_t * sta_pool;
967
968         ASSERT((dhdp->staid_allocator != NULL) && (dhdp->sta_pool != NULL));
969
970         idx = id16_map_alloc(dhdp->staid_allocator);
971         if (idx == ID16_INVALID) {
972                 DHD_ERROR(("%s: cannot get free staid\n", __FUNCTION__));
973                 return DHD_STA_NULL;
974         }
975
976         sta_pool = (dhd_sta_pool_t *)(dhdp->sta_pool);
977         sta = &sta_pool[idx];
978
979         ASSERT((sta->idx == ID16_INVALID) &&
980                (sta->ifp == DHD_IF_NULL) && (sta->ifidx == DHD_BAD_IF));
981         sta->idx = idx; /* implying allocated */
982
983         return sta;
984 }
985
986 /** Delete all STAs in an interface's STA list. */
987 static void
988 dhd_if_del_sta_list(dhd_if_t *ifp)
989 {
990         dhd_sta_t *sta, *next;
991         unsigned long flags;
992
993         DHD_IF_STA_LIST_LOCK(ifp, flags);
994
995         list_for_each_entry_safe(sta, next, &ifp->sta_list, list) {
996 #if defined(BCM_GMAC3)
997                 if (ifp->fwdh) {
998                         /* Remove sta from WOFA forwarder. */
999                         fwder_deassoc(ifp->fwdh, (uint16 *)(sta->ea.octet), (wofa_t)sta);
1000                 }
1001 #endif /* BCM_GMAC3 */
1002                 list_del(&sta->list);
1003                 dhd_sta_free(&ifp->info->pub, sta);
1004         }
1005
1006         DHD_IF_STA_LIST_UNLOCK(ifp, flags);
1007
1008         return;
1009 }
1010
1011 /** Router/GMAC3: Flush all station entries in the forwarder's WOFA database. */
1012 static void
1013 dhd_if_flush_sta(dhd_if_t * ifp)
1014 {
1015 #if defined(BCM_GMAC3)
1016
1017         if (ifp && (ifp->fwdh != FWDER_NULL)) {
1018                 dhd_sta_t *sta, *next;
1019                 unsigned long flags;
1020
1021                 DHD_IF_STA_LIST_LOCK(ifp, flags);
1022
1023                 list_for_each_entry_safe(sta, next, &ifp->sta_list, list) {
1024                         /* Remove any sta entry from WOFA forwarder. */
1025                         fwder_flush(ifp->fwdh, (wofa_t)sta);
1026                 }
1027
1028                 DHD_IF_STA_LIST_UNLOCK(ifp, flags);
1029         }
1030 #endif /* BCM_GMAC3 */
1031 }
1032
1033 /** Construct a pool of dhd_sta_t objects to be used by interfaces. */
1034 static int
1035 dhd_sta_pool_init(dhd_pub_t *dhdp, int max_sta)
1036 {
1037         int idx, sta_pool_memsz;
1038         dhd_sta_t * sta;
1039         dhd_sta_pool_t * sta_pool;
1040         void * staid_allocator;
1041
1042         ASSERT(dhdp != (dhd_pub_t *)NULL);
1043         ASSERT((dhdp->staid_allocator == NULL) && (dhdp->sta_pool == NULL));
1044
1045         /* dhd_sta objects per radio are managed in a table. id#0 reserved. */
1046         staid_allocator = id16_map_init(dhdp->osh, max_sta, 1);
1047         if (staid_allocator == NULL) {
1048                 DHD_ERROR(("%s: sta id allocator init failure\n", __FUNCTION__));
1049                 return BCME_ERROR;
1050         }
1051
1052         /* Pre allocate a pool of dhd_sta objects (one extra). */
1053         sta_pool_memsz = ((max_sta + 1) * sizeof(dhd_sta_t)); /* skip idx 0 */
1054         sta_pool = (dhd_sta_pool_t *)MALLOC(dhdp->osh, sta_pool_memsz);
1055         if (sta_pool == NULL) {
1056                 DHD_ERROR(("%s: sta table alloc failure\n", __FUNCTION__));
1057                 id16_map_fini(dhdp->osh, staid_allocator);
1058                 return BCME_ERROR;
1059         }
1060
1061         dhdp->sta_pool = sta_pool;
1062         dhdp->staid_allocator = staid_allocator;
1063
1064         /* Initialize all sta(s) for the pre-allocated free pool. */
1065         bzero((uchar *)sta_pool, sta_pool_memsz);
1066         for (idx = max_sta; idx >= 1; idx--) { /* skip sta_pool[0] */
1067                 sta = &sta_pool[idx];
1068                 sta->idx = id16_map_alloc(staid_allocator);
1069                 ASSERT(sta->idx <= max_sta);
1070         }
1071         /* Now place them into the pre-allocated free pool. */
1072         for (idx = 1; idx <= max_sta; idx++) {
1073                 sta = &sta_pool[idx];
1074                 dhd_sta_free(dhdp, sta);
1075         }
1076
1077         return BCME_OK;
1078 }
1079
1080 /** Destruct the pool of dhd_sta_t objects.
1081  * Caller must ensure that no STA objects are currently associated with an if.
1082  */
1083 static void
1084 dhd_sta_pool_fini(dhd_pub_t *dhdp, int max_sta)
1085 {
1086         dhd_sta_pool_t * sta_pool = (dhd_sta_pool_t *)dhdp->sta_pool;
1087
1088         if (sta_pool) {
1089                 int idx;
1090                 int sta_pool_memsz = ((max_sta + 1) * sizeof(dhd_sta_t));
1091                 for (idx = 1; idx <= max_sta; idx++) {
1092                         ASSERT(sta_pool[idx].ifp == DHD_IF_NULL);
1093                         ASSERT(sta_pool[idx].idx == ID16_INVALID);
1094                 }
1095                 MFREE(dhdp->osh, dhdp->sta_pool, sta_pool_memsz);
1096                 dhdp->sta_pool = NULL;
1097         }
1098
1099         id16_map_fini(dhdp->osh, dhdp->staid_allocator);
1100         dhdp->staid_allocator = NULL;
1101 }
1102
1103 /* Clear the pool of dhd_sta_t objects for built-in type driver */
1104 static void
1105 dhd_sta_pool_clear(dhd_pub_t *dhdp, int max_sta)
1106 {
1107         int idx, sta_pool_memsz;
1108         dhd_sta_t * sta;
1109         dhd_sta_pool_t * sta_pool;
1110         void *staid_allocator;
1111
1112         if (!dhdp) {
1113                 DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__));
1114                 return;
1115         }
1116
1117         sta_pool = (dhd_sta_pool_t *)dhdp->sta_pool;
1118         staid_allocator = dhdp->staid_allocator;
1119
1120         if (!sta_pool) {
1121                 DHD_ERROR(("%s: sta_pool is NULL\n", __FUNCTION__));
1122                 return;
1123         }
1124
1125         if (!staid_allocator) {
1126                 DHD_ERROR(("%s: staid_allocator is NULL\n", __FUNCTION__));
1127                 return;
1128         }
1129
1130         /* clear free pool */
1131         sta_pool_memsz = ((max_sta + 1) * sizeof(dhd_sta_t));
1132         bzero((uchar *)sta_pool, sta_pool_memsz);
1133
1134         /* dhd_sta objects per radio are managed in a table. id#0 reserved. */
1135         id16_map_clear(staid_allocator, max_sta, 1);
1136
1137         /* Initialize all sta(s) for the pre-allocated free pool. */
1138         for (idx = max_sta; idx >= 1; idx--) { /* skip sta_pool[0] */
1139                 sta = &sta_pool[idx];
1140                 sta->idx = id16_map_alloc(staid_allocator);
1141                 ASSERT(sta->idx <= max_sta);
1142         }
1143         /* Now place them into the pre-allocated free pool. */
1144         for (idx = 1; idx <= max_sta; idx++) {
1145                 sta = &sta_pool[idx];
1146                 dhd_sta_free(dhdp, sta);
1147         }
1148 }
1149
1150 /** Find STA with MAC address ea in an interface's STA list. */
1151 dhd_sta_t *
1152 dhd_find_sta(void *pub, int ifidx, void *ea)
1153 {
1154         dhd_sta_t *sta;
1155         dhd_if_t *ifp;
1156         unsigned long flags;
1157
1158         ASSERT(ea != NULL);
1159         ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx);
1160         if (ifp == NULL)
1161                 return DHD_STA_NULL;
1162
1163         DHD_IF_STA_LIST_LOCK(ifp, flags);
1164
1165         list_for_each_entry(sta, &ifp->sta_list, list) {
1166                 if (!memcmp(sta->ea.octet, ea, ETHER_ADDR_LEN)) {
1167                         DHD_IF_STA_LIST_UNLOCK(ifp, flags);
1168                         return sta;
1169                 }
1170         }
1171
1172         DHD_IF_STA_LIST_UNLOCK(ifp, flags);
1173
1174         return DHD_STA_NULL;
1175 }
1176
1177 /** Add STA into the interface's STA list. */
1178 dhd_sta_t *
1179 dhd_add_sta(void *pub, int ifidx, void *ea)
1180 {
1181         dhd_sta_t *sta;
1182         dhd_if_t *ifp;
1183         unsigned long flags;
1184
1185         ASSERT(ea != NULL);
1186         ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx);
1187         if (ifp == NULL)
1188                 return DHD_STA_NULL;
1189
1190         sta = dhd_sta_alloc((dhd_pub_t *)pub);
1191         if (sta == DHD_STA_NULL) {
1192                 DHD_ERROR(("%s: Alloc failed\n", __FUNCTION__));
1193                 return DHD_STA_NULL;
1194         }
1195
1196         memcpy(sta->ea.octet, ea, ETHER_ADDR_LEN);
1197
1198         /* link the sta and the dhd interface */
1199         sta->ifp = ifp;
1200         sta->ifidx = ifidx;
1201         INIT_LIST_HEAD(&sta->list);
1202
1203         DHD_IF_STA_LIST_LOCK(ifp, flags);
1204
1205         list_add_tail(&sta->list, &ifp->sta_list);
1206
1207 #if defined(BCM_GMAC3)
1208         if (ifp->fwdh) {
1209                 ASSERT(ISALIGNED(ea, 2));
1210                 /* Add sta to WOFA forwarder. */
1211                 fwder_reassoc(ifp->fwdh, (uint16 *)ea, (wofa_t)sta);
1212         }
1213 #endif /* BCM_GMAC3 */
1214
1215         DHD_IF_STA_LIST_UNLOCK(ifp, flags);
1216
1217         return sta;
1218 }
1219
1220 /** Delete STA from the interface's STA list. */
1221 void
1222 dhd_del_sta(void *pub, int ifidx, void *ea)
1223 {
1224         dhd_sta_t *sta, *next;
1225         dhd_if_t *ifp;
1226         unsigned long flags;
1227
1228         ASSERT(ea != NULL);
1229         ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx);
1230         if (ifp == NULL)
1231                 return;
1232
1233         DHD_IF_STA_LIST_LOCK(ifp, flags);
1234
1235         list_for_each_entry_safe(sta, next, &ifp->sta_list, list) {
1236                 if (!memcmp(sta->ea.octet, ea, ETHER_ADDR_LEN)) {
1237 #if defined(BCM_GMAC3)
1238                         if (ifp->fwdh) { /* Found a sta, remove from WOFA forwarder. */
1239                                 ASSERT(ISALIGNED(ea, 2));
1240                                 fwder_deassoc(ifp->fwdh, (uint16 *)ea, (wofa_t)sta);
1241                         }
1242 #endif /* BCM_GMAC3 */
1243                         list_del(&sta->list);
1244                         dhd_sta_free(&ifp->info->pub, sta);
1245                 }
1246         }
1247
1248         DHD_IF_STA_LIST_UNLOCK(ifp, flags);
1249
1250         return;
1251 }
1252
1253 /** Add STA if it doesn't exist. Not reentrant. */
1254 dhd_sta_t*
1255 dhd_findadd_sta(void *pub, int ifidx, void *ea)
1256 {
1257         dhd_sta_t *sta;
1258
1259         sta = dhd_find_sta(pub, ifidx, ea);
1260
1261         if (!sta) {
1262                 /* Add entry */
1263                 sta = dhd_add_sta(pub, ifidx, ea);
1264         }
1265
1266         return sta;
1267 }
1268 #else
1269 static inline void dhd_if_flush_sta(dhd_if_t * ifp) { }
1270 static inline void dhd_if_del_sta_list(dhd_if_t *ifp) {}
1271 static inline int dhd_sta_pool_init(dhd_pub_t *dhdp, int max_sta) { return BCME_OK; }
1272 static inline void dhd_sta_pool_fini(dhd_pub_t *dhdp, int max_sta) {}
1273 static inline void dhd_sta_pool_clear(dhd_pub_t *dhdp, int max_sta) {}
1274 dhd_sta_t *dhd_findadd_sta(void *pub, int ifidx, void *ea) { return NULL; }
1275 void dhd_del_sta(void *pub, int ifidx, void *ea) {}
1276 #endif /* PCIE_FULL_DONGLE */
1277
1278
1279 /* Returns dhd iflist index correspondig the the bssidx provided by apps */
1280 int dhd_bssidx2idx(dhd_pub_t *dhdp, uint32 bssidx)
1281 {
1282         dhd_if_t *ifp;
1283         dhd_info_t *dhd = dhdp->info;
1284         int i;
1285
1286         ASSERT(bssidx < DHD_MAX_IFS);
1287         ASSERT(dhdp);
1288
1289         for (i = 0; i < DHD_MAX_IFS; i++) {
1290                 ifp = dhd->iflist[i];
1291                 if (ifp && (ifp->bssidx == bssidx)) {
1292                         DHD_TRACE(("Index manipulated for %s from %d to %d\n",
1293                                 ifp->name, bssidx, i));
1294                         break;
1295                 }
1296         }
1297         return i;
1298 }
1299
1300 static inline int dhd_rxf_enqueue(dhd_pub_t *dhdp, void* skb)
1301 {
1302         uint32 store_idx;
1303         uint32 sent_idx;
1304
1305         if (!skb) {
1306                 DHD_ERROR(("dhd_rxf_enqueue: NULL skb!!!\n"));
1307                 return BCME_ERROR;
1308         }
1309
1310         dhd_os_rxflock(dhdp);
1311         store_idx = dhdp->store_idx;
1312         sent_idx = dhdp->sent_idx;
1313         if (dhdp->skbbuf[store_idx] != NULL) {
1314                 /* Make sure the previous packets are processed */
1315                 dhd_os_rxfunlock(dhdp);
1316 #ifdef RXF_DEQUEUE_ON_BUSY
1317                 DHD_TRACE(("dhd_rxf_enqueue: pktbuf not consumed %p, store idx %d sent idx %d\n",
1318                         skb, store_idx, sent_idx));
1319                 return BCME_BUSY;
1320 #else /* RXF_DEQUEUE_ON_BUSY */
1321                 DHD_ERROR(("dhd_rxf_enqueue: pktbuf not consumed %p, store idx %d sent idx %d\n",
1322                         skb, store_idx, sent_idx));
1323                 /* removed msleep here, should use wait_event_timeout if we
1324                  * want to give rx frame thread a chance to run
1325                  */
1326 #if defined(WAIT_DEQUEUE)
1327                 OSL_SLEEP(1);
1328 #endif
1329                 return BCME_ERROR;
1330 #endif /* RXF_DEQUEUE_ON_BUSY */
1331         }
1332         DHD_TRACE(("dhd_rxf_enqueue: Store SKB %p. idx %d -> %d\n",
1333                 skb, store_idx, (store_idx + 1) & (MAXSKBPEND - 1)));
1334         dhdp->skbbuf[store_idx] = skb;
1335         dhdp->store_idx = (store_idx + 1) & (MAXSKBPEND - 1);
1336         dhd_os_rxfunlock(dhdp);
1337
1338         return BCME_OK;
1339 }
1340
1341 static inline void* dhd_rxf_dequeue(dhd_pub_t *dhdp)
1342 {
1343         uint32 store_idx;
1344         uint32 sent_idx;
1345         void *skb;
1346
1347         dhd_os_rxflock(dhdp);
1348
1349         store_idx = dhdp->store_idx;
1350         sent_idx = dhdp->sent_idx;
1351         skb = dhdp->skbbuf[sent_idx];
1352
1353         if (skb == NULL) {
1354                 dhd_os_rxfunlock(dhdp);
1355                 DHD_ERROR(("dhd_rxf_dequeue: Dequeued packet is NULL, store idx %d sent idx %d\n",
1356                         store_idx, sent_idx));
1357                 return NULL;
1358         }
1359
1360         dhdp->skbbuf[sent_idx] = NULL;
1361         dhdp->sent_idx = (sent_idx + 1) & (MAXSKBPEND - 1);
1362
1363         DHD_TRACE(("dhd_rxf_dequeue: netif_rx_ni(%p), sent idx %d\n",
1364                 skb, sent_idx));
1365
1366         dhd_os_rxfunlock(dhdp);
1367
1368         return skb;
1369 }
1370
1371 int dhd_process_cid_mac(dhd_pub_t *dhdp, bool prepost)
1372 {
1373 #ifndef CUSTOMER_HW10
1374         dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
1375 #endif /* !CUSTOMER_HW10 */
1376
1377         if (prepost) { /* pre process */
1378                 dhd_read_macaddr(dhd);
1379         } else { /* post process */
1380                 dhd_write_macaddr(&dhd->pub.mac);
1381         }
1382
1383         return 0;
1384 }
1385
1386 #if defined(PKT_FILTER_SUPPORT) && !defined(GAN_LITE_NAT_KEEPALIVE_FILTER)
1387 static bool
1388 _turn_on_arp_filter(dhd_pub_t *dhd, int op_mode)
1389 {
1390         bool _apply = FALSE;
1391         /* In case of IBSS mode, apply arp pkt filter */
1392         if (op_mode & DHD_FLAG_IBSS_MODE) {
1393                 _apply = TRUE;
1394                 goto exit;
1395         }
1396         /* In case of P2P GO or GC, apply pkt filter to pass arp pkt to host */
1397         if ((dhd->arp_version == 1) &&
1398                 (op_mode & (DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE))) {
1399                 _apply = TRUE;
1400                 goto exit;
1401         }
1402
1403 exit:
1404         return _apply;
1405 }
1406 #endif /* PKT_FILTER_SUPPORT && !GAN_LITE_NAT_KEEPALIVE_FILTER */
1407
1408 #if defined(CUSTOM_PLATFORM_NV_TEGRA)
1409 #ifdef PKT_FILTER_SUPPORT
1410 void
1411 dhd_set_packet_filter_mode(struct net_device *dev, char *command)
1412 {
1413         dhd_info_t *dhdi = *(dhd_info_t **)netdev_priv(dev);
1414
1415         dhdi->pub.pkt_filter_mode = bcm_strtoul(command, &command, 0);
1416 }
1417
1418 int
1419 dhd_set_packet_filter_ports(struct net_device *dev, char *command)
1420 {
1421         int i = 0, error = BCME_OK, count = 0, get_count = 0, action = 0;
1422         uint16 portnum = 0, *ports = NULL, get_ports[WL_PKT_FILTER_PORTS_MAX];
1423         dhd_info_t *dhdi = *(dhd_info_t **)netdev_priv(dev);
1424         dhd_pub_t *dhdp = &dhdi->pub;
1425         char iovbuf[WLC_IOCTL_SMLEN];
1426
1427         /* get action */
1428         action = bcm_strtoul(command, &command, 0);
1429         if (action > PKT_FILTER_PORTS_MAX)
1430                 return BCME_BADARG;
1431
1432         if (action == PKT_FILTER_PORTS_LOOPBACK) {
1433                 /* echo the loopback value if port filter is supported else error */
1434                 bcm_mkiovar("cap", NULL, 0, iovbuf, sizeof(iovbuf));
1435                 error = dhd_wl_ioctl_cmd(dhdp, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0);
1436                 if (error < 0) {
1437                         DHD_ERROR(("%s: Get Capability failed (error=%d)\n", __FUNCTION__, error));
1438                         return error;
1439                 }
1440
1441                 if (strstr(iovbuf, "pktfltr2"))
1442                         return bcm_strtoul(command, &command, 0);
1443                 else {
1444                         DHD_ERROR(("%s: pktfltr2 is not supported\n", __FUNCTION__));
1445                         return BCME_UNSUPPORTED;
1446                 }
1447         }
1448
1449         if (action == PKT_FILTER_PORTS_CLEAR) {
1450                 /* action 0 is clear all ports */
1451                 dhdp->pkt_filter_ports_count = 0;
1452                 bzero(dhdp->pkt_filter_ports, sizeof(dhdp->pkt_filter_ports));
1453         }
1454         else {
1455                 portnum = bcm_strtoul(command, &command, 0);
1456                 if (portnum == 0) {
1457                         /* no ports to add or remove */
1458                         return BCME_BADARG;
1459                 }
1460
1461                 /* get configured ports */
1462                 count = dhdp->pkt_filter_ports_count;
1463                 ports = dhdp->pkt_filter_ports;
1464
1465                 if (action == PKT_FILTER_PORTS_ADD) {
1466                         /* action 1 is add ports */
1467
1468                         /* copy new ports */
1469                         while ((portnum != 0) && (count < WL_PKT_FILTER_PORTS_MAX)) {
1470                                 for (i = 0; i < count; i++) {
1471                                         /* duplicate port */
1472                                         if (portnum == ports[i])
1473                                                 break;
1474                                 }
1475                                 if (portnum != ports[i])
1476                                         ports[count++] = portnum;
1477                                 portnum = bcm_strtoul(command, &command, 0);
1478                         }
1479                 } else if ((action == PKT_FILTER_PORTS_DEL) && (count > 0)) {
1480                         /* action 2 is remove ports */
1481                         bcopy(dhdp->pkt_filter_ports, get_ports, count * sizeof(uint16));
1482                         get_count = count;
1483
1484                         while (portnum != 0) {
1485                                 count = 0;
1486                                 for (i = 0; i < get_count; i++) {
1487                                         if (portnum != get_ports[i])
1488                                                 ports[count++] = get_ports[i];
1489                                 }
1490                                 get_count = count;
1491                                 bcopy(ports, get_ports, count * sizeof(uint16));
1492                                 portnum = bcm_strtoul(command, &command, 0);
1493                         }
1494                 }
1495                 dhdp->pkt_filter_ports_count = count;
1496         }
1497         return error;
1498 }
1499
1500 static void
1501 dhd_enable_packet_filter_ports(dhd_pub_t *dhd, bool enable)
1502 {
1503         int error = 0;
1504         wl_pkt_filter_ports_t *portlist = NULL;
1505         const uint pkt_filter_ports_buf_len = sizeof("pkt_filter_ports")
1506                 + WL_PKT_FILTER_PORTS_FIXED_LEN + (WL_PKT_FILTER_PORTS_MAX * sizeof(uint16));
1507         char pkt_filter_ports_buf[pkt_filter_ports_buf_len];
1508         char iovbuf[pkt_filter_ports_buf_len];
1509
1510         DHD_TRACE(("%s: enable %d, in_suspend %d, mode %d, port count %d\n", __FUNCTION__,
1511                 enable, dhd->in_suspend, dhd->pkt_filter_mode,
1512                 dhd->pkt_filter_ports_count));
1513
1514         bzero(pkt_filter_ports_buf, sizeof(pkt_filter_ports_buf));
1515         portlist = (wl_pkt_filter_ports_t*)pkt_filter_ports_buf;
1516         portlist->version = WL_PKT_FILTER_PORTS_VERSION;
1517         portlist->reserved = 0;
1518
1519         if (enable) {
1520                 if (!(dhd->pkt_filter_mode & PKT_FILTER_MODE_PORTS_ONLY))
1521                         return;
1522
1523                 /* enable port filter */
1524                 dhd_master_mode |= PKT_FILTER_MODE_PORTS_ONLY;
1525                 if (dhd->pkt_filter_mode & PKT_FILTER_MODE_FORWARD_ON_MATCH)
1526                         /* whitelist mode: FORWARD_ON_MATCH */
1527                         dhd_master_mode |= PKT_FILTER_MODE_FORWARD_ON_MATCH;
1528                 else
1529                         /* blacklist mode: DISCARD_ON_MATCH */
1530                         dhd_master_mode &= ~PKT_FILTER_MODE_FORWARD_ON_MATCH;
1531
1532                 portlist->count = dhd->pkt_filter_ports_count;
1533                 bcopy(dhd->pkt_filter_ports, portlist->ports,
1534                         dhd->pkt_filter_ports_count * sizeof(uint16));
1535         } else {
1536                 /* disable port filter */
1537                 portlist->count = 0;
1538                 dhd_master_mode &= ~PKT_FILTER_MODE_PORTS_ONLY;
1539                 dhd_master_mode |= PKT_FILTER_MODE_FORWARD_ON_MATCH;
1540         }
1541
1542         DHD_INFO(("%s: update: mode %d, port count %d\n", __FUNCTION__, dhd_master_mode,
1543                 portlist->count));
1544
1545         /* update ports */
1546         bcm_mkiovar("pkt_filter_ports",
1547                 (char*)portlist,
1548                 (WL_PKT_FILTER_PORTS_FIXED_LEN + (portlist->count * sizeof(uint16))),
1549                 iovbuf, sizeof(iovbuf));
1550         error = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
1551         if (error < 0)
1552                 DHD_ERROR(("%s: set pkt_filter_ports failed %d\n", __FUNCTION__, error));
1553
1554         /* update mode */
1555         bcm_mkiovar("pkt_filter_mode", (char*)&dhd_master_mode,
1556                 sizeof(dhd_master_mode), iovbuf, sizeof(iovbuf));
1557         error = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
1558         if (error < 0)
1559                 DHD_ERROR(("%s: set pkt_filter_mode failed %d\n", __FUNCTION__, error));
1560
1561         return;
1562 }
1563 #endif /* PKT_FILTER_SUPPORT */
1564 #endif /* defined(CUSTOM_PLATFORM_NV_TEGRA) */
1565
1566 void dhd_set_packet_filter(dhd_pub_t *dhd)
1567 {
1568 #ifdef PKT_FILTER_SUPPORT
1569         int i;
1570
1571         DHD_TRACE(("%s: enter\n", __FUNCTION__));
1572         if (dhd_pkt_filter_enable) {
1573                 for (i = 0; i < dhd->pktfilter_count; i++) {
1574                         dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]);
1575                 }
1576         }
1577 #endif /* PKT_FILTER_SUPPORT */
1578 }
1579
1580 void dhd_enable_packet_filter(int value, dhd_pub_t *dhd)
1581 {
1582 #ifdef PKT_FILTER_SUPPORT
1583         int i;
1584
1585         DHD_TRACE(("%s: enter, value = %d\n", __FUNCTION__, value));
1586
1587 #if defined(CUSTOM_PLATFORM_NV_TEGRA)
1588         dhd_enable_packet_filter_ports(dhd, value);
1589 #endif /* defined(CUSTOM_PLATFORM_NV_TEGRA) */
1590
1591         /* 1 - Enable packet filter, only allow unicast packet to send up */
1592         /* 0 - Disable packet filter */
1593         if (dhd_pkt_filter_enable && (!value ||
1594             (dhd_support_sta_mode(dhd) && !dhd->dhcp_in_progress)))
1595         {
1596                 for (i = 0; i < dhd->pktfilter_count; i++) {
1597 #ifndef GAN_LITE_NAT_KEEPALIVE_FILTER
1598                         if (value && (i == DHD_ARP_FILTER_NUM) &&
1599                                 !_turn_on_arp_filter(dhd, dhd->op_mode)) {
1600                                 DHD_TRACE(("Do not turn on ARP white list pkt filter:"
1601                                         "val %d, cnt %d, op_mode 0x%x\n",
1602                                         value, i, dhd->op_mode));
1603                                 continue;
1604                         }
1605 #endif /* !GAN_LITE_NAT_KEEPALIVE_FILTER */
1606                         dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i],
1607                                 value, dhd_master_mode);
1608                 }
1609         }
1610 #endif /* PKT_FILTER_SUPPORT */
1611 }
1612
1613 static int dhd_set_suspend(int value, dhd_pub_t *dhd)
1614 {
1615 #ifndef SUPPORT_PM2_ONLY
1616         int power_mode = PM_MAX;
1617 #endif /* SUPPORT_PM2_ONLY */
1618         /* wl_pkt_filter_enable_t       enable_parm; */
1619         char iovbuf[32];
1620         int bcn_li_dtim = 0; /* Default bcn_li_dtim in resume mode is 0 */
1621         uint roamvar = dhd->conf->roam_off_suspend;
1622         uint nd_ra_filter = 0;
1623         int ret = 0;
1624
1625         if (!dhd)
1626                 return -ENODEV;
1627
1628         DHD_TRACE(("%s: enter, value = %d in_suspend=%d\n",
1629                 __FUNCTION__, value, dhd->in_suspend));
1630
1631         dhd_suspend_lock(dhd);
1632
1633 #ifdef CUSTOM_SET_CPUCORE
1634         DHD_TRACE(("%s set cpucore(suspend%d)\n", __FUNCTION__, value));
1635         /* set specific cpucore */
1636         dhd_set_cpucore(dhd, TRUE);
1637 #endif /* CUSTOM_SET_CPUCORE */
1638 #ifndef SUPPORT_PM2_ONLY
1639         if (dhd->conf->pm >= 0)
1640                 power_mode = dhd->conf->pm;
1641 #endif /* SUPPORT_PM2_ONLY */
1642         if (dhd->up) {
1643                 if (value && dhd->in_suspend) {
1644 #ifdef PKT_FILTER_SUPPORT
1645                         dhd->early_suspended = 1;
1646 #endif
1647                         /* Kernel suspended */
1648                         DHD_ERROR(("%s: force extra Suspend setting\n", __FUNCTION__));
1649
1650 #ifndef SUPPORT_PM2_ONLY
1651                         dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
1652                                 sizeof(power_mode), TRUE, 0);
1653 #endif /* SUPPORT_PM2_ONLY */
1654
1655                         /* Enable packet filter, only allow unicast packet to send up */
1656                         dhd_enable_packet_filter(1, dhd);
1657
1658                         /* If DTIM skip is set up as default, force it to wake
1659                          * each third DTIM for better power savings.  Note that
1660                          * one side effect is a chance to miss BC/MC packet.
1661                          */
1662                         bcn_li_dtim = dhd_get_suspend_bcn_li_dtim(dhd);
1663                         bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
1664                                 4, iovbuf, sizeof(iovbuf));
1665                         if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf),
1666                                 TRUE, 0) < 0)
1667                                         DHD_ERROR(("%s: set dtim failed\n", __FUNCTION__));
1668
1669                         /* Disable firmware roaming during suspend */
1670                         bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
1671                         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
1672                         if (FW_SUPPORTED(dhd, ndoe)) {
1673                                 /* enable IPv6 RA filter in  firmware during suspend */
1674                                 nd_ra_filter = 1;
1675                                 bcm_mkiovar("nd_ra_filter_enable", (char *)&nd_ra_filter, 4,
1676                                         iovbuf, sizeof(iovbuf));
1677                                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
1678                                         sizeof(iovbuf), TRUE, 0)) < 0)
1679                                         DHD_ERROR(("failed to set nd_ra_filter (%d)\n",
1680                                                 ret));
1681                         }
1682                 } else {
1683 #ifdef PKT_FILTER_SUPPORT
1684                         dhd->early_suspended = 0;
1685 #endif
1686                         /* Kernel resumed  */
1687                         DHD_ERROR(("%s: Remove extra suspend setting\n", __FUNCTION__));
1688
1689 #ifndef SUPPORT_PM2_ONLY
1690                         power_mode = PM_FAST;
1691                         dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
1692                                 sizeof(power_mode), TRUE, 0);
1693 #endif /* SUPPORT_PM2_ONLY */
1694 #ifdef PKT_FILTER_SUPPORT
1695                         /* disable pkt filter */
1696                         dhd_enable_packet_filter(0, dhd);
1697 #endif /* PKT_FILTER_SUPPORT */
1698
1699                         /* restore pre-suspend setting for dtim_skip */
1700                         bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
1701                                 4, iovbuf, sizeof(iovbuf));
1702
1703                         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
1704                         roamvar = dhd_roam_disable;
1705                         bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
1706                         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
1707                         if (FW_SUPPORTED(dhd, ndoe)) {
1708                                 /* disable IPv6 RA filter in  firmware during suspend */
1709                                 nd_ra_filter = 0;
1710                                 bcm_mkiovar("nd_ra_filter_enable", (char *)&nd_ra_filter, 4,
1711                                         iovbuf, sizeof(iovbuf));
1712                                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
1713                                         sizeof(iovbuf), TRUE, 0)) < 0)
1714                                         DHD_ERROR(("failed to set nd_ra_filter (%d)\n",
1715                                                 ret));
1716                         }
1717                 }
1718         }
1719         dhd_suspend_unlock(dhd);
1720
1721         return 0;
1722 }
1723
1724 static int dhd_suspend_resume_helper(struct dhd_info *dhd, int val, int force)
1725 {
1726         dhd_pub_t *dhdp = &dhd->pub;
1727         int ret = 0;
1728
1729         DHD_OS_WAKE_LOCK(dhdp);
1730         DHD_PERIM_LOCK(dhdp);
1731
1732         /* Set flag when early suspend was called */
1733         dhdp->in_suspend = val;
1734         if ((force || !dhdp->suspend_disable_flag) &&
1735                 dhd_support_sta_mode(dhdp))
1736         {
1737                 ret = dhd_set_suspend(val, dhdp);
1738         }
1739
1740         DHD_PERIM_UNLOCK(dhdp);
1741         DHD_OS_WAKE_UNLOCK(dhdp);
1742         return ret;
1743 }
1744
1745 #if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
1746 static void dhd_early_suspend(struct early_suspend *h)
1747 {
1748         struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend);
1749         DHD_TRACE_HW4(("%s: enter\n", __FUNCTION__));
1750
1751         if (dhd)
1752                 dhd_suspend_resume_helper(dhd, 1, 0);
1753 }
1754
1755 static void dhd_late_resume(struct early_suspend *h)
1756 {
1757         struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend);
1758         DHD_TRACE_HW4(("%s: enter\n", __FUNCTION__));
1759
1760         if (dhd)
1761                 dhd_suspend_resume_helper(dhd, 0, 0);
1762 }
1763 #endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */
1764
1765 /*
1766  * Generalized timeout mechanism.  Uses spin sleep with exponential back-off until
1767  * the sleep time reaches one jiffy, then switches over to task delay.  Usage:
1768  *
1769  *      dhd_timeout_start(&tmo, usec);
1770  *      while (!dhd_timeout_expired(&tmo))
1771  *              if (poll_something())
1772  *                      break;
1773  *      if (dhd_timeout_expired(&tmo))
1774  *              fatal();
1775  */
1776
1777 void
1778 dhd_timeout_start(dhd_timeout_t *tmo, uint usec)
1779 {
1780         tmo->limit = usec;
1781         tmo->increment = 0;
1782         tmo->elapsed = 0;
1783         tmo->tick = jiffies_to_usecs(1);
1784 }
1785
1786 int
1787 dhd_timeout_expired(dhd_timeout_t *tmo)
1788 {
1789         /* Does nothing the first call */
1790         if (tmo->increment == 0) {
1791                 tmo->increment = 1;
1792                 return 0;
1793         }
1794
1795         if (tmo->elapsed >= tmo->limit)
1796                 return 1;
1797
1798         /* Add the delay that's about to take place */
1799         tmo->elapsed += tmo->increment;
1800
1801         if ((!CAN_SLEEP()) || tmo->increment < tmo->tick) {
1802                 OSL_DELAY(tmo->increment);
1803                 tmo->increment *= 2;
1804                 if (tmo->increment > tmo->tick)
1805                         tmo->increment = tmo->tick;
1806         } else {
1807                 wait_queue_head_t delay_wait;
1808                 DECLARE_WAITQUEUE(wait, current);
1809                 init_waitqueue_head(&delay_wait);
1810                 add_wait_queue(&delay_wait, &wait);
1811                 set_current_state(TASK_INTERRUPTIBLE);
1812                 (void)schedule_timeout(1);
1813                 remove_wait_queue(&delay_wait, &wait);
1814                 set_current_state(TASK_RUNNING);
1815         }
1816
1817         return 0;
1818 }
1819
1820 int
1821 dhd_net2idx(dhd_info_t *dhd, struct net_device *net)
1822 {
1823         int i = 0;
1824
1825         if (!dhd) {
1826                 DHD_ERROR(("%s : DHD_BAD_IF return\n", __FUNCTION__));
1827                 return DHD_BAD_IF;
1828         }
1829         while (i < DHD_MAX_IFS) {
1830                 if (dhd->iflist[i] && dhd->iflist[i]->net && (dhd->iflist[i]->net == net))
1831                         return i;
1832                 i++;
1833         }
1834
1835         return DHD_BAD_IF;
1836 }
1837
1838 struct net_device * dhd_idx2net(void *pub, int ifidx)
1839 {
1840         struct dhd_pub *dhd_pub = (struct dhd_pub *)pub;
1841         struct dhd_info *dhd_info;
1842
1843         if (!dhd_pub || ifidx < 0 || ifidx >= DHD_MAX_IFS)
1844                 return NULL;
1845         dhd_info = dhd_pub->info;
1846         if (dhd_info && dhd_info->iflist[ifidx])
1847                 return dhd_info->iflist[ifidx]->net;
1848         return NULL;
1849 }
1850
1851 int
1852 dhd_ifname2idx(dhd_info_t *dhd, char *name)
1853 {
1854         int i = DHD_MAX_IFS;
1855
1856         ASSERT(dhd);
1857
1858         if (name == NULL || *name == '\0')
1859                 return 0;
1860
1861         while (--i > 0)
1862                 if (dhd->iflist[i] && !strncmp(dhd->iflist[i]->name, name, IFNAMSIZ))
1863                                 break;
1864
1865         DHD_TRACE(("%s: return idx %d for \"%s\"\n", __FUNCTION__, i, name));
1866
1867         return i;       /* default - the primary interface */
1868 }
1869
1870 int
1871 dhd_ifidx2hostidx(dhd_info_t *dhd, int ifidx)
1872 {
1873         int i = DHD_MAX_IFS;
1874
1875         ASSERT(dhd);
1876
1877         while (--i > 0)
1878                 if (dhd->iflist[i] && (dhd->iflist[i]->idx == ifidx))
1879                                 break;
1880
1881         DHD_TRACE(("%s: return hostidx %d for ifidx %d\n", __FUNCTION__, i, ifidx));
1882
1883         return i;       /* default - the primary interface */
1884 }
1885
1886 char *
1887 dhd_ifname(dhd_pub_t *dhdp, int ifidx)
1888 {
1889         dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
1890
1891         ASSERT(dhd);
1892
1893         if (ifidx < 0 || ifidx >= DHD_MAX_IFS) {
1894                 DHD_ERROR(("%s: ifidx %d out of range\n", __FUNCTION__, ifidx));
1895                 return "<if_bad>";
1896         }
1897
1898         if (dhd->iflist[ifidx] == NULL) {
1899                 DHD_ERROR(("%s: null i/f %d\n", __FUNCTION__, ifidx));
1900                 return "<if_null>";
1901         }
1902
1903         if (dhd->iflist[ifidx]->net)
1904                 return dhd->iflist[ifidx]->net->name;
1905
1906         return "<if_none>";
1907 }
1908
1909 uint8 *
1910 dhd_bssidx2bssid(dhd_pub_t *dhdp, int idx)
1911 {
1912         int i;
1913         dhd_info_t *dhd = (dhd_info_t *)dhdp;
1914
1915         ASSERT(dhd);
1916         for (i = 0; i < DHD_MAX_IFS; i++)
1917         if (dhd->iflist[i] && dhd->iflist[i]->bssidx == idx)
1918                 return dhd->iflist[i]->mac_addr;
1919
1920         return NULL;
1921 }
1922
1923
1924 static void
1925 _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx)
1926 {
1927         struct net_device *dev;
1928 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
1929         struct netdev_hw_addr *ha;
1930 #else
1931         struct dev_mc_list *mclist;
1932 #endif
1933         uint32 allmulti, cnt;
1934
1935         wl_ioctl_t ioc;
1936         char *buf, *bufp;
1937         uint buflen;
1938         int ret;
1939
1940         ASSERT(dhd && dhd->iflist[ifidx]);
1941         dev = dhd->iflist[ifidx]->net;
1942         if (!dev)
1943                 return;
1944 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
1945         netif_addr_lock_bh(dev);
1946 #endif
1947 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
1948         cnt = netdev_mc_count(dev);
1949 #else
1950         cnt = dev->mc_count;
1951 #endif /* LINUX_VERSION_CODE */
1952
1953 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
1954         netif_addr_unlock_bh(dev);
1955 #endif
1956
1957         /* Determine initial value of allmulti flag */
1958         allmulti = (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE;
1959
1960         /* Send down the multicast list first. */
1961
1962
1963         buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETHER_ADDR_LEN);
1964         if (!(bufp = buf = MALLOC(dhd->pub.osh, buflen))) {
1965                 DHD_ERROR(("%s: out of memory for mcast_list, cnt %d\n",
1966                         dhd_ifname(&dhd->pub, ifidx), cnt));
1967                 return;
1968         }
1969
1970         strncpy(bufp, "mcast_list", buflen - 1);
1971         bufp[buflen - 1] = '\0';
1972         bufp += strlen("mcast_list") + 1;
1973
1974         cnt = htol32(cnt);
1975         memcpy(bufp, &cnt, sizeof(cnt));
1976         bufp += sizeof(cnt);
1977
1978
1979 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
1980         netif_addr_lock_bh(dev);
1981 #endif
1982 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
1983         netdev_for_each_mc_addr(ha, dev) {
1984                 if (!cnt)
1985                         break;
1986                 memcpy(bufp, ha->addr, ETHER_ADDR_LEN);
1987                 bufp += ETHER_ADDR_LEN;
1988                 cnt--;
1989         }
1990 #else
1991         for (mclist = dev->mc_list; (mclist && (cnt > 0));
1992                         cnt--, mclist = mclist->next) {
1993                 memcpy(bufp, (void *)mclist->dmi_addr, ETHER_ADDR_LEN);
1994                 bufp += ETHER_ADDR_LEN;
1995         }
1996 #endif /* LINUX_VERSION_CODE */
1997
1998 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
1999         netif_addr_unlock_bh(dev);
2000 #endif
2001
2002         memset(&ioc, 0, sizeof(ioc));
2003         ioc.cmd = WLC_SET_VAR;
2004         ioc.buf = buf;
2005         ioc.len = buflen;
2006         ioc.set = TRUE;
2007
2008         ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
2009         if (ret < 0) {
2010                 DHD_ERROR(("%s: set mcast_list failed, cnt %d\n",
2011                         dhd_ifname(&dhd->pub, ifidx), cnt));
2012                 allmulti = cnt ? TRUE : allmulti;
2013         }
2014
2015         MFREE(dhd->pub.osh, buf, buflen);
2016
2017         /* Now send the allmulti setting.  This is based on the setting in the
2018          * net_device flags, but might be modified above to be turned on if we
2019          * were trying to set some addresses and dongle rejected it...
2020          */
2021
2022         buflen = sizeof("allmulti") + sizeof(allmulti);
2023         if (!(buf = MALLOC(dhd->pub.osh, buflen))) {
2024                 DHD_ERROR(("%s: out of memory for allmulti\n", dhd_ifname(&dhd->pub, ifidx)));
2025                 return;
2026         }
2027         allmulti = htol32(allmulti);
2028
2029         if (!bcm_mkiovar("allmulti", (void*)&allmulti, sizeof(allmulti), buf, buflen)) {
2030                 DHD_ERROR(("%s: mkiovar failed for allmulti, datalen %d buflen %u\n",
2031                            dhd_ifname(&dhd->pub, ifidx), (int)sizeof(allmulti), buflen));
2032                 MFREE(dhd->pub.osh, buf, buflen);
2033                 return;
2034         }
2035
2036
2037         memset(&ioc, 0, sizeof(ioc));
2038         ioc.cmd = WLC_SET_VAR;
2039         ioc.buf = buf;
2040         ioc.len = buflen;
2041         ioc.set = TRUE;
2042
2043         ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
2044         if (ret < 0) {
2045                 DHD_ERROR(("%s: set allmulti %d failed\n",
2046                            dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti)));
2047         }
2048
2049         MFREE(dhd->pub.osh, buf, buflen);
2050
2051         /* Finally, pick up the PROMISC flag as well, like the NIC driver does */
2052
2053         allmulti = (dev->flags & IFF_PROMISC) ? TRUE : FALSE;
2054
2055         allmulti = htol32(allmulti);
2056
2057         memset(&ioc, 0, sizeof(ioc));
2058         ioc.cmd = WLC_SET_PROMISC;
2059         ioc.buf = &allmulti;
2060         ioc.len = sizeof(allmulti);
2061         ioc.set = TRUE;
2062
2063         ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
2064         if (ret < 0) {
2065                 DHD_ERROR(("%s: set promisc %d failed\n",
2066                            dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti)));
2067         }
2068 }
2069
2070 int
2071 _dhd_set_mac_address(dhd_info_t *dhd, int ifidx, uint8 *addr)
2072 {
2073         char buf[32];
2074         wl_ioctl_t ioc;
2075         int ret;
2076
2077         if (!bcm_mkiovar("cur_etheraddr", (char*)addr, ETHER_ADDR_LEN, buf, 32)) {
2078                 DHD_ERROR(("%s: mkiovar failed for cur_etheraddr\n", dhd_ifname(&dhd->pub, ifidx)));
2079                 return -1;
2080         }
2081         memset(&ioc, 0, sizeof(ioc));
2082         ioc.cmd = WLC_SET_VAR;
2083         ioc.buf = buf;
2084         ioc.len = 32;
2085         ioc.set = TRUE;
2086
2087         ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
2088         if (ret < 0) {
2089                 DHD_ERROR(("%s: set cur_etheraddr failed\n", dhd_ifname(&dhd->pub, ifidx)));
2090         } else {
2091                 memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETHER_ADDR_LEN);
2092                 if (ifidx == 0)
2093                         memcpy(dhd->pub.mac.octet, addr, ETHER_ADDR_LEN);
2094         }
2095
2096         return ret;
2097 }
2098
2099 #ifdef SOFTAP
2100 extern struct net_device *ap_net_dev;
2101 extern tsk_ctl_t ap_eth_ctl; /* ap netdev heper thread ctl */
2102 #endif
2103
2104 static void
2105 dhd_ifadd_event_handler(void *handle, void *event_info, u8 event)
2106 {
2107         dhd_info_t *dhd = handle;
2108         dhd_if_event_t *if_event = event_info;
2109         struct net_device *ndev;
2110         int ifidx, bssidx;
2111         int ret;
2112 #if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
2113         struct wireless_dev *vwdev, *primary_wdev;
2114         struct net_device *primary_ndev;
2115 #endif /* OEM_ANDROID && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */
2116
2117         if (event != DHD_WQ_WORK_IF_ADD) {
2118                 DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
2119                 return;
2120         }
2121
2122         if (!dhd) {
2123                 DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__));
2124                 return;
2125         }
2126
2127         if (!if_event) {
2128                 DHD_ERROR(("%s: event data is null \n", __FUNCTION__));
2129                 return;
2130         }
2131
2132         dhd_net_if_lock_local(dhd);
2133         DHD_OS_WAKE_LOCK(&dhd->pub);
2134         DHD_PERIM_LOCK(&dhd->pub);
2135
2136         ifidx = if_event->event.ifidx;
2137         bssidx = if_event->event.bssidx;
2138         DHD_TRACE(("%s: registering if with ifidx %d\n", __FUNCTION__, ifidx));
2139
2140         ndev = dhd_allocate_if(&dhd->pub, ifidx, if_event->name,
2141                 if_event->mac, bssidx, TRUE);
2142         if (!ndev) {
2143                 DHD_ERROR(("%s: net device alloc failed  \n", __FUNCTION__));
2144                 goto done;
2145         }
2146
2147 #if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
2148         vwdev = kzalloc(sizeof(*vwdev), GFP_KERNEL);
2149         if (unlikely(!vwdev)) {
2150                 WL_ERR(("Could not allocate wireless device\n"));
2151                 goto done;
2152         }
2153         primary_ndev = dhd->pub.info->iflist[0]->net;
2154         primary_wdev = ndev_to_wdev(primary_ndev);
2155         vwdev->wiphy = primary_wdev->wiphy;
2156         vwdev->iftype = if_event->event.role;
2157         vwdev->netdev = ndev;
2158         ndev->ieee80211_ptr = vwdev;
2159         SET_NETDEV_DEV(ndev, wiphy_dev(vwdev->wiphy));
2160         DHD_ERROR(("virtual interface(%s) is created\n", if_event->name));
2161 #endif /* OEM_ANDROID && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */
2162
2163         DHD_PERIM_UNLOCK(&dhd->pub);
2164         ret = dhd_register_if(&dhd->pub, ifidx, TRUE);
2165         DHD_PERIM_LOCK(&dhd->pub);
2166         if (ret != BCME_OK) {
2167                 DHD_ERROR(("%s: dhd_register_if failed\n", __FUNCTION__));
2168                 dhd_remove_if(&dhd->pub, ifidx, TRUE);
2169                 goto done;
2170         }
2171 #ifdef PCIE_FULL_DONGLE
2172         /* Turn on AP isolation in the firmware for interfaces operating in AP mode */
2173         if (FW_SUPPORTED((&dhd->pub), ap) && !(DHD_IF_ROLE_STA(if_event->event.role))) {
2174                 char iovbuf[WLC_IOCTL_SMLEN];
2175                 uint32 var_int =  1;
2176
2177                 memset(iovbuf, 0, sizeof(iovbuf));
2178                 bcm_mkiovar("ap_isolate", (char *)&var_int, 4, iovbuf, sizeof(iovbuf));
2179                 ret = dhd_wl_ioctl_cmd(&dhd->pub, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, ifidx);
2180
2181                 if (ret != BCME_OK) {
2182                         DHD_ERROR(("%s: Failed to set ap_isolate to dongle\n", __FUNCTION__));
2183                         dhd_remove_if(&dhd->pub, ifidx, TRUE);
2184                 }
2185         }
2186 #endif /* PCIE_FULL_DONGLE */
2187 done:
2188         MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t));
2189
2190         DHD_PERIM_UNLOCK(&dhd->pub);
2191         DHD_OS_WAKE_UNLOCK(&dhd->pub);
2192         dhd_net_if_unlock_local(dhd);
2193 }
2194
2195 static void
2196 dhd_ifdel_event_handler(void *handle, void *event_info, u8 event)
2197 {
2198         dhd_info_t *dhd = handle;
2199         int ifidx;
2200         dhd_if_event_t *if_event = event_info;
2201
2202
2203         if (event != DHD_WQ_WORK_IF_DEL) {
2204                 DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
2205                 return;
2206         }
2207
2208         if (!dhd) {
2209                 DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__));
2210                 return;
2211         }
2212
2213         if (!if_event) {
2214                 DHD_ERROR(("%s: event data is null \n", __FUNCTION__));
2215                 return;
2216         }
2217
2218         dhd_net_if_lock_local(dhd);
2219         DHD_OS_WAKE_LOCK(&dhd->pub);
2220         DHD_PERIM_LOCK(&dhd->pub);
2221
2222         ifidx = if_event->event.ifidx;
2223         DHD_TRACE(("Removing interface with idx %d\n", ifidx));
2224
2225         dhd_remove_if(&dhd->pub, ifidx, TRUE);
2226
2227         MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t));
2228
2229         DHD_PERIM_UNLOCK(&dhd->pub);
2230         DHD_OS_WAKE_UNLOCK(&dhd->pub);
2231         dhd_net_if_unlock_local(dhd);
2232 }
2233
2234 static void
2235 dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event)
2236 {
2237         dhd_info_t *dhd = handle;
2238         dhd_if_t *ifp = event_info;
2239
2240         if (event != DHD_WQ_WORK_SET_MAC) {
2241                 DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
2242         }
2243
2244         if (!dhd) {
2245                 DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__));
2246                 return;
2247         }
2248
2249         dhd_net_if_lock_local(dhd);
2250         DHD_OS_WAKE_LOCK(&dhd->pub);
2251         DHD_PERIM_LOCK(&dhd->pub);
2252
2253 #ifdef SOFTAP
2254         {
2255                 unsigned long flags;
2256                 bool in_ap = FALSE;
2257                 DHD_GENERAL_LOCK(&dhd->pub, flags);
2258                 in_ap = (ap_net_dev != NULL);
2259                 DHD_GENERAL_UNLOCK(&dhd->pub, flags);
2260
2261                 if (in_ap)  {
2262                         DHD_ERROR(("attempt to set MAC for %s in AP Mode, blocked. \n",
2263                                    ifp->net->name));
2264                         goto done;
2265                 }
2266         }
2267 #endif /* SOFTAP */
2268
2269         if (ifp == NULL || !dhd->pub.up) {
2270                 DHD_ERROR(("%s: interface info not available/down \n", __FUNCTION__));
2271                 goto done;
2272         }
2273
2274         DHD_ERROR(("%s: MACID is overwritten\n", __FUNCTION__));
2275         ifp->set_macaddress = FALSE;
2276         if (_dhd_set_mac_address(dhd, ifp->idx, ifp->mac_addr) == 0)
2277                 DHD_INFO(("%s: MACID is overwritten\n", __FUNCTION__));
2278         else
2279                 DHD_ERROR(("%s: _dhd_set_mac_address() failed\n", __FUNCTION__));
2280
2281 done:
2282         DHD_PERIM_UNLOCK(&dhd->pub);
2283         DHD_OS_WAKE_UNLOCK(&dhd->pub);
2284         dhd_net_if_unlock_local(dhd);
2285 }
2286
2287 static void
2288 dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event)
2289 {
2290         dhd_info_t *dhd = handle;
2291         dhd_if_t *ifp = event_info;
2292         int ifidx;
2293
2294         if (event != DHD_WQ_WORK_SET_MCAST_LIST) {
2295                 DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
2296                 return;
2297         }
2298
2299         if (!dhd) {
2300                 DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__));
2301                 return;
2302         }
2303
2304         dhd_net_if_lock_local(dhd);
2305         DHD_OS_WAKE_LOCK(&dhd->pub);
2306         DHD_PERIM_LOCK(&dhd->pub);
2307
2308 #ifdef SOFTAP
2309         {
2310                 bool in_ap = FALSE;
2311                 unsigned long flags;
2312                 DHD_GENERAL_LOCK(&dhd->pub, flags);
2313                 in_ap = (ap_net_dev != NULL);
2314                 DHD_GENERAL_UNLOCK(&dhd->pub, flags);
2315
2316                 if (in_ap)  {
2317                         DHD_ERROR(("set MULTICAST list for %s in AP Mode, blocked. \n",
2318                                    ifp->net->name));
2319                         ifp->set_multicast = FALSE;
2320                         goto done;
2321                 }
2322         }
2323 #endif /* SOFTAP */
2324
2325         if (ifp == NULL || !dhd->pub.up) {
2326                 DHD_ERROR(("%s: interface info not available/down \n", __FUNCTION__));
2327                 goto done;
2328         }
2329
2330         ifidx = ifp->idx;
2331
2332
2333         _dhd_set_multicast_list(dhd, ifidx);
2334         DHD_INFO(("%s: set multicast list for if %d\n", __FUNCTION__, ifidx));
2335
2336 done:
2337         DHD_PERIM_UNLOCK(&dhd->pub);
2338         DHD_OS_WAKE_UNLOCK(&dhd->pub);
2339         dhd_net_if_unlock_local(dhd);
2340 }
2341
2342 static int
2343 dhd_set_mac_address(struct net_device *dev, void *addr)
2344 {
2345         int ret = 0;
2346
2347         dhd_info_t *dhd = DHD_DEV_INFO(dev);
2348         struct sockaddr *sa = (struct sockaddr *)addr;
2349         int ifidx;
2350         dhd_if_t *dhdif;
2351
2352         ifidx = dhd_net2idx(dhd, dev);
2353         if (ifidx == DHD_BAD_IF)
2354                 return -1;
2355
2356         dhdif = dhd->iflist[ifidx];
2357
2358         dhd_net_if_lock_local(dhd);
2359         memcpy(dhdif->mac_addr, sa->sa_data, ETHER_ADDR_LEN);
2360         dhdif->set_macaddress = TRUE;
2361         dhd_net_if_unlock_local(dhd);
2362         dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)dhdif, DHD_WQ_WORK_SET_MAC,
2363                 dhd_set_mac_addr_handler, DHD_WORK_PRIORITY_LOW);
2364         return ret;
2365 }
2366
2367 static void
2368 dhd_set_multicast_list(struct net_device *dev)
2369 {
2370         dhd_info_t *dhd = DHD_DEV_INFO(dev);
2371         int ifidx;
2372
2373         ifidx = dhd_net2idx(dhd, dev);
2374         if (ifidx == DHD_BAD_IF)
2375                 return;
2376
2377         dhd->iflist[ifidx]->set_multicast = TRUE;
2378         dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)dhd->iflist[ifidx],
2379                 DHD_WQ_WORK_SET_MCAST_LIST, dhd_set_mcast_list_handler, DHD_WORK_PRIORITY_LOW);
2380 }
2381
2382 #ifdef PROP_TXSTATUS
2383 int
2384 dhd_os_wlfc_block(dhd_pub_t *pub)
2385 {
2386         dhd_info_t *di = (dhd_info_t *)(pub->info);
2387         ASSERT(di != NULL);
2388         spin_lock_bh(&di->wlfc_spinlock);
2389         return 1;
2390 }
2391
2392 int
2393 dhd_os_wlfc_unblock(dhd_pub_t *pub)
2394 {
2395         dhd_info_t *di = (dhd_info_t *)(pub->info);
2396
2397         ASSERT(di != NULL);
2398         spin_unlock_bh(&di->wlfc_spinlock);
2399         return 1;
2400 }
2401
2402 #endif /* PROP_TXSTATUS */
2403
2404 #if defined(DHD_RX_DUMP) || defined(DHD_TX_DUMP)
2405 typedef struct {
2406         uint16 type;
2407         const char *str;
2408 } PKTTYPE_INFO;
2409
2410 static const PKTTYPE_INFO packet_type_info[] =
2411 {
2412         { ETHER_TYPE_IP, "IP" },
2413         { ETHER_TYPE_ARP, "ARP" },
2414         { ETHER_TYPE_BRCM, "BRCM" },
2415         { ETHER_TYPE_802_1X, "802.1X" },
2416         { ETHER_TYPE_WAI, "WAPI" },
2417         { 0, ""}
2418 };
2419
2420 static const char *_get_packet_type_str(uint16 type)
2421 {
2422         int i;
2423         int n = sizeof(packet_type_info)/sizeof(packet_type_info[1]) - 1;
2424
2425         for (i = 0; i < n; i++) {
2426                 if (packet_type_info[i].type == type)
2427                         return packet_type_info[i].str;
2428         }
2429
2430         return packet_type_info[n].str;
2431 }
2432 #endif /* DHD_RX_DUMP || DHD_TX_DUMP */
2433
2434 #if defined(DHD_TX_DUMP)
2435 void
2436 dhd_tx_dump(osl_t *osh, void *pkt)
2437 {
2438         uint8 *dump_data;
2439         uint16 protocol;
2440         struct ether_header *eh;
2441
2442         dump_data = PKTDATA(osh, pkt);
2443         eh = (struct ether_header *) dump_data;
2444         protocol = ntoh16(eh->ether_type);
2445         
2446         DHD_ERROR(("TX DUMP - %s\n", _get_packet_type_str(protocol)));
2447
2448         if (protocol == ETHER_TYPE_802_1X) {
2449                 DHD_ERROR(("ETHER_TYPE_802_1X [TX]: ver %d, type %d, replay %d\n",
2450                         dump_data[14], dump_data[15], dump_data[30]));
2451         }
2452
2453 #if defined(DHD_TX_FULL_DUMP)
2454         {
2455                 int i;
2456                 uint datalen;
2457                 datalen = PKTLEN(osh, pkt);
2458
2459                 for (i = 0; i < datalen; i++) {
2460                         DHD_ERROR(("%02X ", dump_data[i]));
2461                         if ((i & 15) == 15)
2462                                 printk("\n");
2463                 }
2464                 DHD_ERROR(("\n"));
2465         }
2466 #endif /* DHD_TX_FULL_DUMP */
2467 }
2468 #endif /* DHD_TX_DUMP */
2469
2470 int BCMFASTPATH
2471 dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf)
2472 {
2473         int ret = BCME_OK;
2474         dhd_info_t *dhd = (dhd_info_t *)(dhdp->info);
2475         struct ether_header *eh = NULL;
2476
2477         /* Reject if down */
2478         if (!dhdp->up || (dhdp->busstate == DHD_BUS_DOWN)) {
2479                 /* free the packet here since the caller won't */
2480                 PKTFREE(dhdp->osh, pktbuf, TRUE);
2481                 return -ENODEV;
2482         }
2483
2484 #ifdef PCIE_FULL_DONGLE
2485         if (dhdp->busstate == DHD_BUS_SUSPEND) {
2486                 DHD_ERROR(("%s : pcie is still in suspend state!!\n", __FUNCTION__));
2487                 PKTFREE(dhdp->osh, pktbuf, TRUE);
2488                 return -EBUSY;
2489         }
2490 #endif /* PCIE_FULL_DONGLE */
2491
2492 #ifdef DHD_UNICAST_DHCP
2493         /* if dhcp_unicast is enabled, we need to convert the */
2494         /* broadcast DHCP ACK/REPLY packets to Unicast. */
2495         if (dhdp->dhcp_unicast) {
2496             dhd_convert_dhcp_broadcast_ack_to_unicast(dhdp, pktbuf, ifidx);
2497         }
2498 #endif /* DHD_UNICAST_DHCP */
2499         /* Update multicast statistic */
2500         if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_HDR_LEN) {
2501                 uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf);
2502                 eh = (struct ether_header *)pktdata;
2503
2504                 if (ETHER_ISMULTI(eh->ether_dhost))
2505                         dhdp->tx_multicast++;
2506                 if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X)
2507                         atomic_inc(&dhd->pend_8021x_cnt);
2508         } else {
2509                         PKTFREE(dhd->pub.osh, pktbuf, TRUE);
2510                         return BCME_ERROR;
2511         }
2512
2513         /* Look into the packet and update the packet priority */
2514 #ifndef PKTPRIO_OVERRIDE
2515         if (PKTPRIO(pktbuf) == 0)
2516 #endif 
2517                 pktsetprio(pktbuf, FALSE);
2518
2519
2520 #if defined(PCIE_FULL_DONGLE) && !defined(PCIE_TX_DEFERRAL)
2521         /*
2522          * Lkup the per interface hash table, for a matching flowring. If one is not
2523          * available, allocate a unique flowid and add a flowring entry.
2524          * The found or newly created flowid is placed into the pktbuf's tag.
2525          */
2526         ret = dhd_flowid_update(dhdp, ifidx, dhdp->flow_prio_map[(PKTPRIO(pktbuf))], pktbuf);
2527         if (ret != BCME_OK) {
2528                 PKTCFREE(dhd->pub.osh, pktbuf, TRUE);
2529                 return ret;
2530         }
2531 #endif
2532 #if defined(DHD_TX_DUMP)
2533         dhd_tx_dump(dhdp->osh, pktbuf);
2534 #endif
2535
2536 #ifdef PROP_TXSTATUS
2537         if (dhd_wlfc_is_supported(dhdp)) {
2538                 /* store the interface ID */
2539                 DHD_PKTTAG_SETIF(PKTTAG(pktbuf), ifidx);
2540
2541                 /* store destination MAC in the tag as well */
2542                 DHD_PKTTAG_SETDSTN(PKTTAG(pktbuf), eh->ether_dhost);
2543
2544                 /* decide which FIFO this packet belongs to */
2545                 if (ETHER_ISMULTI(eh->ether_dhost))
2546                         /* one additional queue index (highest AC + 1) is used for bc/mc queue */
2547                         DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), AC_COUNT);
2548                 else
2549                         DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), WME_PRIO2AC(PKTPRIO(pktbuf)));
2550         } else
2551 #endif /* PROP_TXSTATUS */
2552         /* If the protocol uses a data header, apply it */
2553         dhd_prot_hdrpush(dhdp, ifidx, pktbuf);
2554
2555         /* Use bus module to send data frame */
2556 #ifdef WLMEDIA_HTSF
2557         dhd_htsf_addtxts(dhdp, pktbuf);
2558 #endif
2559
2560 #ifdef PROP_TXSTATUS
2561         {
2562                 if (dhd_wlfc_commit_packets(dhdp, (f_commitpkt_t)dhd_bus_txdata,
2563                         dhdp->bus, pktbuf, TRUE) == WLFC_UNSUPPORTED) {
2564                         /* non-proptxstatus way */
2565 #ifdef BCMPCIE
2566                         ret = dhd_bus_txdata(dhdp->bus, pktbuf, (uint8)ifidx);
2567 #else
2568                         ret = dhd_bus_txdata(dhdp->bus, pktbuf);
2569 #endif /* BCMPCIE */
2570                 }
2571         }
2572 #else
2573 #ifdef BCMPCIE
2574         ret = dhd_bus_txdata(dhdp->bus, pktbuf, (uint8)ifidx);
2575 #else
2576         ret = dhd_bus_txdata(dhdp->bus, pktbuf);
2577 #endif /* BCMPCIE */
2578 #endif /* PROP_TXSTATUS */
2579
2580         return ret;
2581 }
2582
2583 int BCMFASTPATH
2584 dhd_start_xmit(struct sk_buff *skb, struct net_device *net)
2585 {
2586         int ret;
2587         uint datalen;
2588         void *pktbuf;
2589         dhd_info_t *dhd = DHD_DEV_INFO(net);
2590         dhd_if_t *ifp = NULL;
2591         int ifidx;
2592 #ifdef WLMEDIA_HTSF
2593         uint8 htsfdlystat_sz = dhd->pub.htsfdlystat_sz;
2594 #else
2595         uint8 htsfdlystat_sz = 0;
2596 #endif
2597 #ifdef DHD_WMF
2598         struct ether_header *eh;
2599         uint8 *iph;
2600 #endif /* DHD_WMF */
2601
2602         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2603
2604         DHD_OS_WAKE_LOCK(&dhd->pub);
2605         DHD_PERIM_LOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
2606
2607         /* Reject if down */
2608         if (dhd->pub.busstate == DHD_BUS_DOWN || dhd->pub.hang_was_sent) {
2609                 DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d \n",
2610                         __FUNCTION__, dhd->pub.up, dhd->pub.busstate));
2611                 netif_stop_queue(net);
2612                 /* Send Event when bus down detected during data session */
2613                 if (dhd->pub.up) {
2614                         DHD_ERROR(("%s: Event HANG sent up\n", __FUNCTION__));
2615                         net_os_send_hang_message(net);
2616                 }
2617                 DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
2618                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
2619 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20))
2620                 return -ENODEV;
2621 #else
2622                 return NETDEV_TX_BUSY;
2623 #endif
2624         }
2625
2626         ifp = DHD_DEV_IFP(net);
2627         ifidx = DHD_DEV_IFIDX(net);
2628
2629         ASSERT(ifidx == dhd_net2idx(dhd, net));
2630         ASSERT((ifp != NULL) && (ifp == dhd->iflist[ifidx]));
2631
2632         if (ifidx == DHD_BAD_IF) {
2633                 DHD_ERROR(("%s: bad ifidx %d\n", __FUNCTION__, ifidx));
2634                 netif_stop_queue(net);
2635                 DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
2636                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
2637 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20))
2638                 return -ENODEV;
2639 #else
2640                 return NETDEV_TX_BUSY;
2641 #endif
2642         }
2643
2644         /* re-align socket buffer if "skb->data" is odd address */
2645         if (((unsigned long)(skb->data)) & 0x1) {
2646                 unsigned char *data = skb->data;
2647                 uint32 length = skb->len;
2648                 PKTPUSH(dhd->pub.osh, skb, 1);
2649                 memmove(skb->data, data, length);
2650                 PKTSETLEN(dhd->pub.osh, skb, length);
2651         }
2652
2653         datalen  = PKTLEN(dhd->pub.osh, skb);
2654
2655         /* Make sure there's enough room for any header */
2656
2657         if (skb_headroom(skb) < dhd->pub.hdrlen + htsfdlystat_sz) {
2658                 struct sk_buff *skb2;
2659
2660                 DHD_INFO(("%s: insufficient headroom\n",
2661                           dhd_ifname(&dhd->pub, ifidx)));
2662                 dhd->pub.tx_realloc++;
2663
2664                 skb2 = skb_realloc_headroom(skb, dhd->pub.hdrlen + htsfdlystat_sz);
2665
2666                 dev_kfree_skb(skb);
2667                 if ((skb = skb2) == NULL) {
2668                         DHD_ERROR(("%s: skb_realloc_headroom failed\n",
2669                                    dhd_ifname(&dhd->pub, ifidx)));
2670                         ret = -ENOMEM;
2671                         goto done;
2672                 }
2673         }
2674
2675         /* Convert to packet */
2676         if (!(pktbuf = PKTFRMNATIVE(dhd->pub.osh, skb))) {
2677                 DHD_ERROR(("%s: PKTFRMNATIVE failed\n",
2678                            dhd_ifname(&dhd->pub, ifidx)));
2679                 dev_kfree_skb_any(skb);
2680                 ret = -ENOMEM;
2681                 goto done;
2682         }
2683 #ifdef WLMEDIA_HTSF
2684         if (htsfdlystat_sz && PKTLEN(dhd->pub.osh, pktbuf) >= ETHER_ADDR_LEN) {
2685                 uint8 *pktdata = (uint8 *)PKTDATA(dhd->pub.osh, pktbuf);
2686                 struct ether_header *eh = (struct ether_header *)pktdata;
2687
2688                 if (!ETHER_ISMULTI(eh->ether_dhost) &&
2689                         (ntoh16(eh->ether_type) == ETHER_TYPE_IP)) {
2690                         eh->ether_type = hton16(ETHER_TYPE_BRCM_PKTDLYSTATS);
2691                 }
2692         }
2693 #endif
2694 #ifdef DHD_WMF
2695         eh = (struct ether_header *)PKTDATA(dhd->pub.osh, pktbuf);
2696         iph = (uint8 *)eh + ETHER_HDR_LEN;
2697
2698         /* WMF processing for multicast packets
2699          * Only IPv4 packets are handled
2700          */
2701         if (ifp->wmf.wmf_enable && (ntoh16(eh->ether_type) == ETHER_TYPE_IP) &&
2702                 (IP_VER(iph) == IP_VER_4) && (ETHER_ISMULTI(eh->ether_dhost) ||
2703                 ((IPV4_PROT(iph) == IP_PROT_IGMP) && dhd->pub.wmf_ucast_igmp))) {
2704 #if defined(DHD_IGMP_UCQUERY) || defined(DHD_UCAST_UPNP)
2705                 void *sdu_clone;
2706                 bool ucast_convert = FALSE;
2707 #ifdef DHD_UCAST_UPNP
2708                 uint32 dest_ip;
2709
2710                 dest_ip = ntoh32(*((uint32 *)(iph + IPV4_DEST_IP_OFFSET)));
2711                 ucast_convert = dhd->pub.wmf_ucast_upnp && MCAST_ADDR_UPNP_SSDP(dest_ip);
2712 #endif /* DHD_UCAST_UPNP */
2713 #ifdef DHD_IGMP_UCQUERY
2714                 ucast_convert |= dhd->pub.wmf_ucast_igmp_query &&
2715                         (IPV4_PROT(iph) == IP_PROT_IGMP) &&
2716                         (*(iph + IPV4_HLEN(iph)) == IGMPV2_HOST_MEMBERSHIP_QUERY);
2717 #endif /* DHD_IGMP_UCQUERY */
2718                 if (ucast_convert) {
2719                         dhd_sta_t *sta;
2720                         unsigned long flags;
2721
2722                         DHD_IF_STA_LIST_LOCK(ifp, flags);
2723
2724                         /* Convert upnp/igmp query to unicast for each assoc STA */
2725                         list_for_each_entry(sta, &ifp->sta_list, list) {
2726                                 if ((sdu_clone = PKTDUP(dhd->pub.osh, pktbuf)) == NULL) {
2727                                         DHD_IF_STA_LIST_UNLOCK(ifp, flags);
2728                                         DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
2729                                         DHD_OS_WAKE_UNLOCK(&dhd->pub);
2730                                         return (WMF_NOP);
2731                                 }
2732                                 dhd_wmf_forward(ifp->wmf.wmfh, sdu_clone, 0, sta, 1);
2733                         }
2734
2735                         DHD_IF_STA_LIST_UNLOCK(ifp, flags);
2736                         DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
2737                         DHD_OS_WAKE_UNLOCK(&dhd->pub);
2738
2739                         PKTFREE(dhd->pub.osh, pktbuf, TRUE);
2740                         return NETDEV_TX_OK;
2741                 } else
2742 #endif /* defined(DHD_IGMP_UCQUERY) || defined(DHD_UCAST_UPNP) */
2743                 {
2744                         /* There will be no STA info if the packet is coming from LAN host
2745                          * Pass as NULL
2746                          */
2747                         ret = dhd_wmf_packets_handle(&dhd->pub, pktbuf, NULL, ifidx, 0);
2748                         switch (ret) {
2749                         case WMF_TAKEN:
2750                         case WMF_DROP:
2751                                 /* Either taken by WMF or we should drop it.
2752                                  * Exiting send path
2753                                  */
2754                                 DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
2755                                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
2756                                 return NETDEV_TX_OK;
2757                         default:
2758                                 /* Continue the transmit path */
2759                                 break;
2760                         }
2761                 }
2762         }
2763 #endif /* DHD_WMF */
2764
2765 #ifdef DHDTCPACK_SUPPRESS
2766         if (dhd->pub.tcpack_sup_mode == TCPACK_SUP_HOLD) {
2767                 /* If this packet has been hold or got freed, just return */
2768                 if (dhd_tcpack_hold(&dhd->pub, pktbuf, ifidx))
2769                         return 0;
2770         } else {
2771                 /* If this packet has replaced another packet and got freed, just return */
2772                 if (dhd_tcpack_suppress(&dhd->pub, pktbuf))
2773                         return 0;
2774         }
2775 #endif /* DHDTCPACK_SUPPRESS */
2776
2777         ret = dhd_sendpkt(&dhd->pub, ifidx, pktbuf);
2778
2779 done:
2780         if (ret) {
2781                 ifp->stats.tx_dropped++;
2782                 dhd->pub.tx_dropped++;
2783         }
2784         else {
2785
2786 #ifdef PROP_TXSTATUS
2787                 /* tx_packets counter can counted only when wlfc is disabled */
2788                 if (!dhd_wlfc_is_supported(&dhd->pub))
2789 #endif
2790                 {
2791                         dhd->pub.tx_packets++;
2792                         ifp->stats.tx_packets++;
2793                         ifp->stats.tx_bytes += datalen;
2794                 }
2795         }
2796
2797         DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
2798         DHD_OS_WAKE_UNLOCK(&dhd->pub);
2799
2800         /* Return ok: we always eat the packet */
2801 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20))
2802         return 0;
2803 #else
2804         return NETDEV_TX_OK;
2805 #endif
2806 }
2807
2808
2809 void
2810 dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool state)
2811 {
2812         struct net_device *net;
2813         dhd_info_t *dhd = dhdp->info;
2814         int i;
2815
2816         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2817
2818         ASSERT(dhd);
2819
2820         if (ifidx == ALL_INTERFACES) {
2821                 /* Flow control on all active interfaces */
2822                 dhdp->txoff = state;
2823                 for (i = 0; i < DHD_MAX_IFS; i++) {
2824                         if (dhd->iflist[i]) {
2825                                 net = dhd->iflist[i]->net;
2826                                 if (state == ON)
2827                                         netif_stop_queue(net);
2828                                 else
2829                                         netif_wake_queue(net);
2830                         }
2831                 }
2832         }
2833         else {
2834                 if (dhd->iflist[ifidx]) {
2835                         net = dhd->iflist[ifidx]->net;
2836                         if (state == ON)
2837                                 netif_stop_queue(net);
2838                         else
2839                                 netif_wake_queue(net);
2840                 }
2841         }
2842 }
2843
2844
2845 #ifdef DHD_WMF
2846 bool
2847 dhd_is_rxthread_enabled(dhd_pub_t *dhdp)
2848 {
2849         dhd_info_t *dhd = dhdp->info;
2850
2851         return dhd->rxthread_enabled;
2852 }
2853 #endif /* DHD_WMF */
2854
2855 void
2856 dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
2857 {
2858         dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
2859         struct sk_buff *skb;
2860         uchar *eth;
2861         uint len;
2862         void *data, *pnext = NULL;
2863         int i;
2864         dhd_if_t *ifp;
2865         wl_event_msg_t event;
2866         int tout_rx = 0;
2867         int tout_ctrl = 0;
2868         void *skbhead = NULL;
2869         void *skbprev = NULL;
2870 #if defined(DHD_RX_DUMP) || defined(DHD_8021X_DUMP)
2871         char *dump_data;
2872         uint16 protocol;
2873 #endif /* DHD_RX_DUMP || DHD_8021X_DUMP */
2874
2875         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2876
2877         for (i = 0; pktbuf && i < numpkt; i++, pktbuf = pnext) {
2878                 struct ether_header *eh;
2879 #ifdef WLBTAMP
2880                 struct dot11_llc_snap_header *lsh;
2881 #endif
2882
2883                 pnext = PKTNEXT(dhdp->osh, pktbuf);
2884                 PKTSETNEXT(dhdp->osh, pktbuf, NULL);
2885
2886                 ifp = dhd->iflist[ifidx];
2887                 if (ifp == NULL) {
2888                         DHD_ERROR(("%s: ifp is NULL. drop packet\n",
2889                                 __FUNCTION__));
2890                         PKTCFREE(dhdp->osh, pktbuf, FALSE);
2891                         continue;
2892                 }
2893
2894                 eh = (struct ether_header *)PKTDATA(dhdp->osh, pktbuf);
2895
2896                 /* Dropping only data packets before registering net device to avoid kernel panic */
2897 #ifndef PROP_TXSTATUS_VSDB
2898                 if ((!ifp->net || ifp->net->reg_state != NETREG_REGISTERED) &&
2899                         (ntoh16(eh->ether_type) != ETHER_TYPE_BRCM))
2900 #else
2901                 if ((!ifp->net || ifp->net->reg_state != NETREG_REGISTERED || !dhd->pub.up) &&
2902                         (ntoh16(eh->ether_type) != ETHER_TYPE_BRCM))
2903 #endif /* PROP_TXSTATUS_VSDB */
2904                 {
2905                         DHD_ERROR(("%s: net device is NOT registered yet. drop packet\n",
2906                         __FUNCTION__));
2907                         PKTCFREE(dhdp->osh, pktbuf, FALSE);
2908                         continue;
2909                 }
2910
2911 #ifdef WLBTAMP
2912                 lsh = (struct dot11_llc_snap_header *)&eh[1];
2913
2914                 if ((ntoh16(eh->ether_type) < ETHER_TYPE_MIN) &&
2915                     (PKTLEN(dhdp->osh, pktbuf) >= RFC1042_HDR_LEN) &&
2916                     bcmp(lsh, BT_SIG_SNAP_MPROT, DOT11_LLC_SNAP_HDR_LEN - 2) == 0 &&
2917                     lsh->type == HTON16(BTA_PROT_L2CAP)) {
2918                         amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)
2919                                 ((uint8 *)eh + RFC1042_HDR_LEN);
2920                         ACL_data = NULL;
2921                 }
2922 #endif /* WLBTAMP */
2923
2924 #ifdef PROP_TXSTATUS
2925                 if (dhd_wlfc_is_header_only_pkt(dhdp, pktbuf)) {
2926                         /* WLFC may send header only packet when
2927                         there is an urgent message but no packet to
2928                         piggy-back on
2929                         */
2930                         PKTCFREE(dhdp->osh, pktbuf, FALSE);
2931                         continue;
2932                 }
2933 #endif
2934 #ifdef DHD_L2_FILTER
2935                 /* If block_ping is enabled drop the ping packet */
2936                 if (dhdp->block_ping) {
2937                         if (dhd_l2_filter_block_ping(dhdp, pktbuf, ifidx) == BCME_OK) {
2938                                 PKTFREE(dhdp->osh, pktbuf, FALSE);
2939                                 continue;
2940                         }
2941                 }
2942 #endif
2943 #ifdef DHD_WMF
2944                 /* WMF processing for multicast packets */
2945                 if (ifp->wmf.wmf_enable && (ETHER_ISMULTI(eh->ether_dhost))) {
2946                         dhd_sta_t *sta;
2947                         int ret;
2948
2949                         sta = dhd_find_sta(dhdp, ifidx, (void *)eh->ether_shost);
2950                         ret = dhd_wmf_packets_handle(dhdp, pktbuf, sta, ifidx, 1);
2951                         switch (ret) {
2952                                 case WMF_TAKEN:
2953                                         /* The packet is taken by WMF. Continue to next iteration */
2954                                         continue;
2955                                 case WMF_DROP:
2956                                         /* Packet DROP decision by WMF. Toss it */
2957                                         DHD_ERROR(("%s: WMF decides to drop packet\n",
2958                                                 __FUNCTION__));
2959                                         PKTCFREE(dhdp->osh, pktbuf, FALSE);
2960                                         continue;
2961                                 default:
2962                                         /* Continue the transmit path */
2963                                         break;
2964                         }
2965                 }
2966 #endif /* DHD_WMF */
2967 #ifdef DHDTCPACK_SUPPRESS
2968                 dhd_tcpdata_info_get(dhdp, pktbuf);
2969 #endif
2970                 skb = PKTTONATIVE(dhdp->osh, pktbuf);
2971
2972                 ifp = dhd->iflist[ifidx];
2973                 if (ifp == NULL)
2974                         ifp = dhd->iflist[0];
2975
2976                 ASSERT(ifp);
2977                 skb->dev = ifp->net;
2978
2979 #ifdef PCIE_FULL_DONGLE
2980                 if ((DHD_IF_ROLE_AP(dhdp, ifidx) || DHD_IF_ROLE_P2PGO(dhdp, ifidx)) &&
2981                         (!ifp->ap_isolate)) {
2982                         eh = (struct ether_header *)PKTDATA(dhdp->osh, pktbuf);
2983                         if (ETHER_ISUCAST(eh->ether_dhost)) {
2984                                 if (dhd_find_sta(dhdp, ifidx, (void *)eh->ether_dhost)) {
2985                                         dhd_sendpkt(dhdp, ifidx, pktbuf);
2986                                         continue;
2987                                 }
2988                         } else {
2989                                 void *npktbuf = PKTDUP(dhdp->osh, pktbuf);
2990                                 dhd_sendpkt(dhdp, ifidx, npktbuf);
2991                         }
2992                 }
2993 #endif /* PCIE_FULL_DONGLE */
2994
2995                 /* Get the protocol, maintain skb around eth_type_trans()
2996                  * The main reason for this hack is for the limitation of
2997                  * Linux 2.4 where 'eth_type_trans' uses the 'net->hard_header_len'
2998                  * to perform skb_pull inside vs ETH_HLEN. Since to avoid
2999                  * coping of the packet coming from the network stack to add
3000                  * BDC, Hardware header etc, during network interface registration
3001                  * we set the 'net->hard_header_len' to ETH_HLEN + extra space required
3002                  * for BDC, Hardware header etc. and not just the ETH_HLEN
3003                  */
3004                 eth = skb->data;
3005                 len = skb->len;
3006
3007 #if defined(DHD_RX_DUMP) || defined(DHD_8021X_DUMP)
3008                 dump_data = skb->data;
3009                 protocol = (dump_data[12] << 8) | dump_data[13];
3010
3011                 if (protocol == ETHER_TYPE_802_1X) {
3012                         DHD_ERROR(("ETHER_TYPE_802_1X [RX]: "
3013                                 "ver %d, type %d, replay %d\n",
3014                                 dump_data[14], dump_data[15],
3015                                 dump_data[30]));
3016                 }
3017 #endif /* DHD_RX_DUMP || DHD_8021X_DUMP */
3018 #if defined(DHD_RX_DUMP)
3019                 DHD_ERROR(("RX DUMP - %s\n", _get_packet_type_str(protocol)));
3020                 if (protocol != ETHER_TYPE_BRCM) {
3021                         if (dump_data[0] == 0xFF) {
3022                                 DHD_ERROR(("%s: BROADCAST\n", __FUNCTION__));
3023
3024                                 if ((dump_data[12] == 8) &&
3025                                         (dump_data[13] == 6)) {
3026                                         DHD_ERROR(("%s: ARP %d\n",
3027                                                 __FUNCTION__, dump_data[0x15]));
3028                                 }
3029                         } else if (dump_data[0] & 1) {
3030                                 DHD_ERROR(("%s: MULTICAST: " MACDBG "\n",
3031                                         __FUNCTION__, MAC2STRDBG(dump_data)));
3032                         }
3033 #ifdef DHD_RX_FULL_DUMP
3034                         {
3035                                 int k;
3036                                 for (k = 0; k < skb->len; k++) {
3037                                         DHD_ERROR(("%02X ", dump_data[k]));
3038                                         if ((k & 15) == 15)
3039                                                 DHD_ERROR(("\n"));
3040                                 }
3041                                 DHD_ERROR(("\n"));
3042                         }
3043 #endif /* DHD_RX_FULL_DUMP */
3044                 }
3045 #endif /* DHD_RX_DUMP */
3046
3047                 skb->protocol = eth_type_trans(skb, skb->dev);
3048
3049                 if (skb->pkt_type == PACKET_MULTICAST) {
3050                         dhd->pub.rx_multicast++;
3051                         ifp->stats.multicast++;
3052                 }
3053
3054                 skb->data = eth;
3055                 skb->len = len;
3056
3057 #ifdef WLMEDIA_HTSF
3058                 dhd_htsf_addrxts(dhdp, pktbuf);
3059 #endif
3060                 /* Strip header, count, deliver upward */
3061                 skb_pull(skb, ETH_HLEN);
3062
3063                 /* Process special event packets and then discard them */
3064                 memset(&event, 0, sizeof(event));
3065                 if (ntoh16(skb->protocol) == ETHER_TYPE_BRCM) {
3066                         dhd_wl_host_event(dhd, &ifidx,
3067 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
3068                         skb_mac_header(skb),
3069 #else
3070                         skb->mac.raw,
3071 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) */
3072                         &event,
3073                         &data);
3074
3075                         wl_event_to_host_order(&event);
3076                         if (!tout_ctrl)
3077                                 tout_ctrl = DHD_PACKET_TIMEOUT_MS;
3078 #ifdef WLBTAMP
3079                         if (event.event_type == WLC_E_BTA_HCI_EVENT) {
3080                                 dhd_bta_doevt(dhdp, data, event.datalen);
3081                         }
3082 #endif /* WLBTAMP */
3083
3084 #if defined(PNO_SUPPORT)
3085                         if (event.event_type == WLC_E_PFN_NET_FOUND) {
3086                                 /* enforce custom wake lock to garantee that Kernel not suspended */
3087                                 tout_ctrl = CUSTOM_PNO_EVENT_LOCK_xTIME * DHD_PACKET_TIMEOUT_MS;
3088                         }
3089 #endif /* PNO_SUPPORT */
3090
3091 #ifdef DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT
3092                         PKTFREE(dhdp->osh, pktbuf, FALSE);
3093                         continue;
3094 #endif /* DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT */
3095                 } else {
3096                         tout_rx = DHD_PACKET_TIMEOUT_MS;
3097
3098 #ifdef PROP_TXSTATUS
3099                         dhd_wlfc_save_rxpath_ac_time(dhdp, (uint8)PKTPRIO(skb));
3100 #endif /* PROP_TXSTATUS */
3101                 }
3102
3103                 ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]);
3104                 ifp = dhd->iflist[ifidx];
3105
3106                 if (ifp->net)
3107                         ifp->net->last_rx = jiffies;
3108
3109                 if (ntoh16(skb->protocol) != ETHER_TYPE_BRCM) {
3110                         dhdp->dstats.rx_bytes += skb->len;
3111                         dhdp->rx_packets++; /* Local count */
3112                         ifp->stats.rx_bytes += skb->len;
3113                         ifp->stats.rx_packets++;
3114                 }
3115 #if defined(DHD_TCP_WINSIZE_ADJUST)
3116                 if (dhd_use_tcp_window_size_adjust) {
3117                         if (ifidx == 0 && ntoh16(skb->protocol) == ETHER_TYPE_IP) {
3118                                 dhd_adjust_tcp_winsize(dhdp->op_mode, skb);
3119                         }
3120                 }
3121 #endif /* DHD_TCP_WINSIZE_ADJUST */
3122
3123                 if (in_interrupt()) {
3124                         netif_rx(skb);
3125                 } else {
3126                         if (dhd->rxthread_enabled) {
3127                                 if (!skbhead)
3128                                         skbhead = skb;
3129                                 else
3130                                         PKTSETNEXT(dhdp->osh, skbprev, skb);
3131                                 skbprev = skb;
3132                         } else {
3133
3134                                 /* If the receive is not processed inside an ISR,
3135                                  * the softirqd must be woken explicitly to service
3136                                  * the NET_RX_SOFTIRQ.  In 2.6 kernels, this is handled
3137                                  * by netif_rx_ni(), but in earlier kernels, we need
3138                                  * to do it manually.
3139                                  */
3140 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
3141                                 netif_rx_ni(skb);
3142 #else
3143                                 ulong flags;
3144                                 netif_rx(skb);
3145                                 local_irq_save(flags);
3146                                 RAISE_RX_SOFTIRQ();
3147                                 local_irq_restore(flags);
3148 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */
3149                         }
3150                 }
3151         }
3152
3153         if (dhd->rxthread_enabled && skbhead)
3154                 dhd_sched_rxf(dhdp, skbhead);
3155
3156         DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(dhdp, tout_rx);
3157         DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhdp, tout_ctrl);
3158 }
3159
3160 void
3161 dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx)
3162 {
3163         /* Linux version has nothing to do */
3164         return;
3165 }
3166
3167 void
3168 dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success)
3169 {
3170         dhd_info_t *dhd = (dhd_info_t *)(dhdp->info);
3171         struct ether_header *eh;
3172         uint16 type;
3173 #ifdef WLBTAMP
3174         uint len;
3175 #endif
3176
3177         dhd_prot_hdrpull(dhdp, NULL, txp, NULL, NULL);
3178
3179         eh = (struct ether_header *)PKTDATA(dhdp->osh, txp);
3180         type  = ntoh16(eh->ether_type);
3181
3182         if (type == ETHER_TYPE_802_1X)
3183                 atomic_dec(&dhd->pend_8021x_cnt);
3184
3185 #ifdef WLBTAMP
3186         /* Crack open the packet and check to see if it is BT HCI ACL data packet.
3187          * If yes generate packet completion event.
3188          */
3189         len = PKTLEN(dhdp->osh, txp);
3190
3191         /* Generate ACL data tx completion event locally to avoid SDIO bus transaction */
3192         if ((type < ETHER_TYPE_MIN) && (len >= RFC1042_HDR_LEN)) {
3193                 struct dot11_llc_snap_header *lsh = (struct dot11_llc_snap_header *)&eh[1];
3194
3195                 if (bcmp(lsh, BT_SIG_SNAP_MPROT, DOT11_LLC_SNAP_HDR_LEN - 2) == 0 &&
3196                     ntoh16(lsh->type) == BTA_PROT_L2CAP) {
3197
3198                         dhd_bta_tx_hcidata_complete(dhdp, txp, success);
3199                 }
3200         }
3201 #endif /* WLBTAMP */
3202 #ifdef PROP_TXSTATUS
3203         if (dhdp->wlfc_state && (dhdp->proptxstatus_mode != WLFC_FCMODE_NONE)) {
3204                 dhd_if_t *ifp = dhd->iflist[DHD_PKTTAG_IF(PKTTAG(txp))];
3205                 uint datalen  = PKTLEN(dhd->pub.osh, txp);
3206
3207                 if (success) {
3208                         dhd->pub.tx_packets++;
3209                         ifp->stats.tx_packets++;
3210                         ifp->stats.tx_bytes += datalen;
3211                 } else {
3212                         ifp->stats.tx_dropped++;
3213                 }
3214         }
3215 #endif
3216 }
3217
3218 static struct net_device_stats *
3219 dhd_get_stats(struct net_device *net)
3220 {
3221         dhd_info_t *dhd = DHD_DEV_INFO(net);
3222         dhd_if_t *ifp;
3223         int ifidx;
3224
3225         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3226
3227         ifidx = dhd_net2idx(dhd, net);
3228         if (ifidx == DHD_BAD_IF) {
3229                 DHD_ERROR(("%s: BAD_IF\n", __FUNCTION__));
3230
3231                 memset(&net->stats, 0, sizeof(net->stats));
3232                 return &net->stats;
3233         }
3234
3235         ifp = dhd->iflist[ifidx];
3236         ASSERT(dhd && ifp);
3237
3238         if (dhd->pub.up) {
3239                 /* Use the protocol to get dongle stats */
3240                 dhd_prot_dstats(&dhd->pub);
3241         }
3242         return &ifp->stats;
3243 }
3244
3245 static int
3246 dhd_watchdog_thread(void *data)
3247 {
3248         tsk_ctl_t *tsk = (tsk_ctl_t *)data;
3249         dhd_info_t *dhd = (dhd_info_t *)tsk->parent;
3250         /* This thread doesn't need any user-level access,
3251          * so get rid of all our resources
3252          */
3253         if (dhd_watchdog_prio > 0) {
3254                 struct sched_param param;
3255                 param.sched_priority = (dhd_watchdog_prio < MAX_RT_PRIO)?
3256                         dhd_watchdog_prio:(MAX_RT_PRIO-1);
3257                 setScheduler(current, SCHED_FIFO, &param);
3258         }
3259
3260         while (1)
3261                 if (down_interruptible (&tsk->sema) == 0) {
3262                         unsigned long flags;
3263                         unsigned long jiffies_at_start = jiffies;
3264                         unsigned long time_lapse;
3265
3266                         SMP_RD_BARRIER_DEPENDS();
3267                         if (tsk->terminated) {
3268                                 break;
3269                         }
3270
3271                         if (dhd->pub.dongle_reset == FALSE) {
3272                                 DHD_TIMER(("%s:\n", __FUNCTION__));
3273
3274                                 /* Call the bus module watchdog */
3275                                 dhd_bus_watchdog(&dhd->pub);
3276
3277
3278                                 DHD_GENERAL_LOCK(&dhd->pub, flags);
3279                                 /* Count the tick for reference */
3280                                 dhd->pub.tickcnt++;
3281                                 time_lapse = jiffies - jiffies_at_start;
3282
3283                                 /* Reschedule the watchdog */
3284                                 if (dhd->wd_timer_valid)
3285                                         mod_timer(&dhd->timer,
3286                                             jiffies +
3287                                             msecs_to_jiffies(dhd_watchdog_ms) -
3288                                             min(msecs_to_jiffies(dhd_watchdog_ms), time_lapse));
3289                                         DHD_GENERAL_UNLOCK(&dhd->pub, flags);
3290                                 }
3291                 } else {
3292                         break;
3293         }
3294
3295         complete_and_exit(&tsk->completed, 0);
3296 }
3297
3298 static void dhd_watchdog(ulong data)
3299 {
3300         dhd_info_t *dhd = (dhd_info_t *)data;
3301         unsigned long flags;
3302
3303         if (dhd->pub.dongle_reset) {
3304                 return;
3305         }
3306
3307         if (dhd->thr_wdt_ctl.thr_pid >= 0) {
3308                 up(&dhd->thr_wdt_ctl.sema);
3309                 return;
3310         }
3311
3312         /* Call the bus module watchdog */
3313         dhd_bus_watchdog(&dhd->pub);
3314
3315         DHD_GENERAL_LOCK(&dhd->pub, flags);
3316         /* Count the tick for reference */
3317         dhd->pub.tickcnt++;
3318
3319         /* Reschedule the watchdog */
3320         if (dhd->wd_timer_valid)
3321                 mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms));
3322         DHD_GENERAL_UNLOCK(&dhd->pub, flags);
3323
3324 }
3325
3326 #ifdef ENABLE_ADAPTIVE_SCHED
3327 static void
3328 dhd_sched_policy(int prio)
3329 {
3330         struct sched_param param;
3331         if (cpufreq_quick_get(0) <= CUSTOM_CPUFREQ_THRESH) {
3332                 param.sched_priority = 0;
3333                 setScheduler(current, SCHED_NORMAL, &param);
3334         } else {
3335                 if (get_scheduler_policy(current) != SCHED_FIFO) {
3336                         param.sched_priority = (prio < MAX_RT_PRIO)? prio : (MAX_RT_PRIO-1);
3337                         setScheduler(current, SCHED_FIFO, &param);
3338                 }
3339         }
3340 }
3341 #endif /* ENABLE_ADAPTIVE_SCHED */
3342 #ifdef DEBUG_CPU_FREQ
3343 static int dhd_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data)
3344 {
3345         dhd_info_t *dhd = container_of(nb, struct dhd_info, freq_trans);
3346         struct cpufreq_freqs *freq = data;
3347         if (dhd) {
3348                 if (!dhd->new_freq)
3349                         goto exit;
3350                 if (val == CPUFREQ_POSTCHANGE) {
3351                         DHD_ERROR(("cpu freq is changed to %u kHZ on CPU %d\n",
3352                                 freq->new, freq->cpu));
3353                         *per_cpu_ptr(dhd->new_freq, freq->cpu) = freq->new;
3354                 }
3355         }
3356 exit:
3357         return 0;
3358 }
3359 #endif /* DEBUG_CPU_FREQ */
3360 static int
3361 dhd_dpc_thread(void *data)
3362 {
3363         tsk_ctl_t *tsk = (tsk_ctl_t *)data;
3364         dhd_info_t *dhd = (dhd_info_t *)tsk->parent;
3365
3366         /* This thread doesn't need any user-level access,
3367          * so get rid of all our resources
3368          */
3369         if (dhd_dpc_prio > 0)
3370         {
3371                 struct sched_param param;
3372                 param.sched_priority = (dhd_dpc_prio < MAX_RT_PRIO)?dhd_dpc_prio:(MAX_RT_PRIO-1);
3373                 setScheduler(current, SCHED_FIFO, &param);
3374         }
3375
3376 #ifdef CUSTOM_DPC_CPUCORE
3377         set_cpus_allowed_ptr(current, cpumask_of(CUSTOM_DPC_CPUCORE));
3378 #else
3379         if (dhd->pub.conf->dpc_cpucore >= 0) {
3380                 printf("%s: set dpc_cpucore %d from config.txt\n", __FUNCTION__, dhd->pub.conf->dpc_cpucore);
3381                 set_cpus_allowed_ptr(current, cpumask_of(dhd->pub.conf->dpc_cpucore));
3382         }
3383 #endif
3384 #ifdef CUSTOM_SET_CPUCORE
3385         dhd->pub.current_dpc = current;
3386 #endif /* CUSTOM_SET_CPUCORE */
3387         /* Run until signal received */
3388         while (1) {
3389                 if (!binary_sema_down(tsk)) {
3390 #ifdef ENABLE_ADAPTIVE_SCHED
3391                         dhd_sched_policy(dhd_dpc_prio);
3392 #endif /* ENABLE_ADAPTIVE_SCHED */
3393                         SMP_RD_BARRIER_DEPENDS();
3394                         if (tsk->terminated) {
3395                                 break;
3396                         }
3397
3398                         /* Call bus dpc unless it indicated down (then clean stop) */
3399                         if (dhd->pub.busstate != DHD_BUS_DOWN) {
3400                                 dhd_os_wd_timer_extend(&dhd->pub, TRUE);
3401                                 while (dhd_bus_dpc(dhd->pub.bus)) {
3402                                         /* process all data */
3403                                 }
3404                                 dhd_os_wd_timer_extend(&dhd->pub, FALSE);
3405                                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
3406
3407                         } else {
3408                                 if (dhd->pub.up)
3409                                         dhd_bus_stop(dhd->pub.bus, TRUE);
3410                                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
3411                         }
3412                 }
3413                 else
3414                         break;
3415         }
3416         complete_and_exit(&tsk->completed, 0);
3417 }
3418
3419 static int
3420 dhd_rxf_thread(void *data)
3421 {
3422         tsk_ctl_t *tsk = (tsk_ctl_t *)data;
3423         dhd_info_t *dhd = (dhd_info_t *)tsk->parent;
3424 #if defined(WAIT_DEQUEUE)
3425 #define RXF_WATCHDOG_TIME 250 /* BARK_TIME(1000) /  */
3426         ulong watchdogTime = OSL_SYSUPTIME(); /* msec */
3427 #endif
3428         dhd_pub_t *pub = &dhd->pub;
3429
3430         /* This thread doesn't need any user-level access,
3431          * so get rid of all our resources
3432          */
3433         if (dhd_rxf_prio > 0)
3434         {
3435                 struct sched_param param;
3436                 param.sched_priority = (dhd_rxf_prio < MAX_RT_PRIO)?dhd_rxf_prio:(MAX_RT_PRIO-1);
3437                 setScheduler(current, SCHED_FIFO, &param);
3438         }
3439
3440         DAEMONIZE("dhd_rxf");
3441         /* DHD_OS_WAKE_LOCK is called in dhd_sched_dpc[dhd_linux.c] down below  */
3442
3443         /*  signal: thread has started */
3444         complete(&tsk->completed);
3445 #ifdef CUSTOM_SET_CPUCORE
3446         dhd->pub.current_rxf = current;
3447 #endif /* CUSTOM_SET_CPUCORE */
3448         /* Run until signal received */
3449         while (1) {
3450                 if (down_interruptible(&tsk->sema) == 0) {
3451                         void *skb;
3452 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
3453                         ulong flags;
3454 #endif
3455 #ifdef ENABLE_ADAPTIVE_SCHED
3456                         dhd_sched_policy(dhd_rxf_prio);
3457 #endif /* ENABLE_ADAPTIVE_SCHED */
3458
3459                         SMP_RD_BARRIER_DEPENDS();
3460
3461                         if (tsk->terminated) {
3462                                 break;
3463                         }
3464                         skb = dhd_rxf_dequeue(pub);
3465
3466                         if (skb == NULL) {
3467                                 continue;
3468                         }
3469                         while (skb) {
3470                                 void *skbnext = PKTNEXT(pub->osh, skb);
3471                                 PKTSETNEXT(pub->osh, skb, NULL);
3472
3473 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
3474                                 netif_rx_ni(skb);
3475 #else
3476                                 netif_rx(skb);
3477                                 local_irq_save(flags);
3478                                 RAISE_RX_SOFTIRQ();
3479                                 local_irq_restore(flags);
3480
3481 #endif
3482                                 skb = skbnext;
3483                         }
3484 #if defined(WAIT_DEQUEUE)
3485                         if (OSL_SYSUPTIME() - watchdogTime > RXF_WATCHDOG_TIME) {
3486                                 OSL_SLEEP(1);
3487                                 watchdogTime = OSL_SYSUPTIME();
3488                         }
3489 #endif
3490
3491                         DHD_OS_WAKE_UNLOCK(pub);
3492                 }
3493                 else
3494                         break;
3495         }
3496         complete_and_exit(&tsk->completed, 0);
3497 }
3498
3499 #ifdef BCMPCIE
3500 void dhd_dpc_kill(dhd_pub_t *dhdp)
3501 {
3502         dhd_info_t *dhd;
3503
3504         if (!dhdp)
3505                 return;
3506
3507         dhd = dhdp->info;
3508
3509         if (!dhd)
3510                 return;
3511
3512         tasklet_kill(&dhd->tasklet);
3513         DHD_ERROR(("%s: tasklet disabled\n", __FUNCTION__));
3514 }
3515 #endif /* BCMPCIE */
3516
3517 static void
3518 dhd_dpc(ulong data)
3519 {
3520         dhd_info_t *dhd;
3521
3522         dhd = (dhd_info_t *)data;
3523
3524         /* this (tasklet) can be scheduled in dhd_sched_dpc[dhd_linux.c]
3525          * down below , wake lock is set,
3526          * the tasklet is initialized in dhd_attach()
3527          */
3528         /* Call bus dpc unless it indicated down (then clean stop) */
3529         if (dhd->pub.busstate != DHD_BUS_DOWN) {
3530                 if (dhd_bus_dpc(dhd->pub.bus))
3531                         tasklet_schedule(&dhd->tasklet);
3532                 else
3533                         DHD_OS_WAKE_UNLOCK(&dhd->pub);
3534         } else {
3535                 dhd_bus_stop(dhd->pub.bus, TRUE);
3536                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
3537         }
3538 }
3539
3540 void
3541 dhd_sched_dpc(dhd_pub_t *dhdp)
3542 {
3543         dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
3544
3545         DHD_OS_WAKE_LOCK(dhdp);
3546         if (dhd->thr_dpc_ctl.thr_pid >= 0) {
3547                 /* If the semaphore does not get up,
3548                 * wake unlock should be done here
3549                 */
3550                 if (!binary_sema_up(&dhd->thr_dpc_ctl))
3551                         DHD_OS_WAKE_UNLOCK(dhdp);
3552                 return;
3553         } else {
3554                 tasklet_schedule(&dhd->tasklet);
3555         }
3556 }
3557
3558 static void
3559 dhd_sched_rxf(dhd_pub_t *dhdp, void *skb)
3560 {
3561         dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
3562 #ifdef RXF_DEQUEUE_ON_BUSY
3563         int ret = BCME_OK;
3564         int retry = 2;
3565 #endif /* RXF_DEQUEUE_ON_BUSY */
3566
3567         DHD_OS_WAKE_LOCK(dhdp);
3568
3569         DHD_TRACE(("dhd_sched_rxf: Enter\n"));
3570 #ifdef RXF_DEQUEUE_ON_BUSY
3571         do {
3572                 ret = dhd_rxf_enqueue(dhdp, skb);
3573                 if (ret == BCME_OK || ret == BCME_ERROR)
3574                         break;
3575                 else
3576                         OSL_SLEEP(50); /* waiting for dequeueing */
3577         } while (retry-- > 0);
3578
3579         if (retry <= 0 && ret == BCME_BUSY) {
3580                 void *skbp = skb;
3581
3582                 while (skbp) {
3583                         void *skbnext = PKTNEXT(dhdp->osh, skbp);
3584                         PKTSETNEXT(dhdp->osh, skbp, NULL);
3585                         netif_rx_ni(skbp);
3586                         skbp = skbnext;
3587                 }
3588                 DHD_ERROR(("send skb to kernel backlog without rxf_thread\n"));
3589         }
3590         else {
3591                 if (dhd->thr_rxf_ctl.thr_pid >= 0) {
3592                         up(&dhd->thr_rxf_ctl.sema);
3593                 }
3594         }
3595 #else /* RXF_DEQUEUE_ON_BUSY */
3596         do {
3597                 if (dhd_rxf_enqueue(dhdp, skb) == BCME_OK)
3598                         break;
3599         } while (1);
3600         if (dhd->thr_rxf_ctl.thr_pid >= 0) {
3601                 up(&dhd->thr_rxf_ctl.sema);
3602         }
3603         return;
3604 #endif /* RXF_DEQUEUE_ON_BUSY */
3605 }
3606
3607 #ifdef TOE
3608 /* Retrieve current toe component enables, which are kept as a bitmap in toe_ol iovar */
3609 static int
3610 dhd_toe_get(dhd_info_t *dhd, int ifidx, uint32 *toe_ol)
3611 {
3612         wl_ioctl_t ioc;
3613         char buf[32];
3614         int ret;
3615
3616         memset(&ioc, 0, sizeof(ioc));
3617
3618         ioc.cmd = WLC_GET_VAR;
3619         ioc.buf = buf;
3620         ioc.len = (uint)sizeof(buf);
3621         ioc.set = FALSE;
3622
3623         strncpy(buf, "toe_ol", sizeof(buf) - 1);
3624         buf[sizeof(buf) - 1] = '\0';
3625         if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
3626                 /* Check for older dongle image that doesn't support toe_ol */
3627                 if (ret == -EIO) {
3628                         DHD_ERROR(("%s: toe not supported by device\n",
3629                                 dhd_ifname(&dhd->pub, ifidx)));
3630                         return -EOPNOTSUPP;
3631                 }
3632
3633                 DHD_INFO(("%s: could not get toe_ol: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret));
3634                 return ret;
3635         }
3636
3637         memcpy(toe_ol, buf, sizeof(uint32));
3638         return 0;
3639 }
3640
3641 /* Set current toe component enables in toe_ol iovar, and set toe global enable iovar */
3642 static int
3643 dhd_toe_set(dhd_info_t *dhd, int ifidx, uint32 toe_ol)
3644 {
3645         wl_ioctl_t ioc;
3646         char buf[32];
3647         int toe, ret;
3648
3649         memset(&ioc, 0, sizeof(ioc));
3650
3651         ioc.cmd = WLC_SET_VAR;
3652         ioc.buf = buf;
3653         ioc.len = (uint)sizeof(buf);
3654         ioc.set = TRUE;
3655
3656         /* Set toe_ol as requested */
3657
3658         strncpy(buf, "toe_ol", sizeof(buf) - 1);
3659         buf[sizeof(buf) - 1] = '\0';
3660         memcpy(&buf[sizeof("toe_ol")], &toe_ol, sizeof(uint32));
3661
3662         if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
3663                 DHD_ERROR(("%s: could not set toe_ol: ret=%d\n",
3664                         dhd_ifname(&dhd->pub, ifidx), ret));
3665                 return ret;
3666         }
3667
3668         /* Enable toe globally only if any components are enabled. */
3669
3670         toe = (toe_ol != 0);
3671
3672         strcpy(buf, "toe");
3673         memcpy(&buf[sizeof("toe")], &toe, sizeof(uint32));
3674
3675         if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
3676                 DHD_ERROR(("%s: could not set toe: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret));
3677                 return ret;
3678         }
3679
3680         return 0;
3681 }
3682 #endif /* TOE */
3683
3684 #if defined(WL_CFG80211)
3685 void dhd_set_scb_probe(dhd_pub_t *dhd)
3686 {
3687 #define NUM_SCB_MAX_PROBE 3
3688         int ret = 0;
3689         wl_scb_probe_t scb_probe;
3690         char iovbuf[WL_EVENTING_MASK_LEN + 12];
3691
3692         memset(&scb_probe, 0, sizeof(wl_scb_probe_t));
3693
3694         if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE)
3695                 return;
3696
3697         bcm_mkiovar("scb_probe", NULL, 0, iovbuf, sizeof(iovbuf));
3698
3699         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
3700                 DHD_ERROR(("%s: GET max_scb_probe failed\n", __FUNCTION__));
3701
3702         memcpy(&scb_probe, iovbuf, sizeof(wl_scb_probe_t));
3703
3704         scb_probe.scb_max_probe = NUM_SCB_MAX_PROBE;
3705
3706         bcm_mkiovar("scb_probe", (char *)&scb_probe,
3707                 sizeof(wl_scb_probe_t), iovbuf, sizeof(iovbuf));
3708         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
3709                 DHD_ERROR(("%s: max_scb_probe setting failed\n", __FUNCTION__));
3710 #undef NUM_SCB_MAX_PROBE
3711         return;
3712 }
3713 #endif /* WL_CFG80211 */
3714
3715 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
3716 static void
3717 dhd_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
3718 {
3719         dhd_info_t *dhd = DHD_DEV_INFO(net);
3720
3721         snprintf(info->driver, sizeof(info->driver), "wl");
3722         snprintf(info->version, sizeof(info->version), "%lu", dhd->pub.drv_version);
3723 }
3724
3725 struct ethtool_ops dhd_ethtool_ops = {
3726         .get_drvinfo = dhd_ethtool_get_drvinfo
3727 };
3728 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */
3729
3730
3731 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2)
3732 static int
3733 dhd_ethtool(dhd_info_t *dhd, void *uaddr)
3734 {
3735         struct ethtool_drvinfo info;
3736         char drvname[sizeof(info.driver)];
3737         uint32 cmd;
3738 #ifdef TOE
3739         struct ethtool_value edata;
3740         uint32 toe_cmpnt, csum_dir;
3741         int ret;
3742 #endif
3743
3744         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3745
3746         /* all ethtool calls start with a cmd word */
3747         if (copy_from_user(&cmd, uaddr, sizeof (uint32)))
3748                 return -EFAULT;
3749
3750         switch (cmd) {
3751         case ETHTOOL_GDRVINFO:
3752                 /* Copy out any request driver name */
3753                 if (copy_from_user(&info, uaddr, sizeof(info)))
3754                         return -EFAULT;
3755                 strncpy(drvname, info.driver, sizeof(info.driver));
3756                 drvname[sizeof(info.driver)-1] = '\0';
3757
3758                 /* clear struct for return */
3759                 memset(&info, 0, sizeof(info));
3760                 info.cmd = cmd;
3761
3762                 /* if dhd requested, identify ourselves */
3763                 if (strcmp(drvname, "?dhd") == 0) {
3764                         snprintf(info.driver, sizeof(info.driver), "dhd");
3765                         strncpy(info.version, EPI_VERSION_STR, sizeof(info.version) - 1);
3766                         info.version[sizeof(info.version) - 1] = '\0';
3767                 }
3768
3769                 /* otherwise, require dongle to be up */
3770                 else if (!dhd->pub.up) {
3771                         DHD_ERROR(("%s: dongle is not up\n", __FUNCTION__));
3772                         return -ENODEV;
3773                 }
3774
3775                 /* finally, report dongle driver type */
3776                 else if (dhd->pub.iswl)
3777                         snprintf(info.driver, sizeof(info.driver), "wl");
3778                 else
3779                         snprintf(info.driver, sizeof(info.driver), "xx");
3780
3781                 snprintf(info.version, sizeof(info.version), "%lu", dhd->pub.drv_version);
3782                 if (copy_to_user(uaddr, &info, sizeof(info)))
3783                         return -EFAULT;
3784                 DHD_CTL(("%s: given %*s, returning %s\n", __FUNCTION__,
3785                          (int)sizeof(drvname), drvname, info.driver));
3786                 break;
3787
3788 #ifdef TOE
3789         /* Get toe offload components from dongle */
3790         case ETHTOOL_GRXCSUM:
3791         case ETHTOOL_GTXCSUM:
3792                 if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0)
3793                         return ret;
3794
3795                 csum_dir = (cmd == ETHTOOL_GTXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;
3796
3797                 edata.cmd = cmd;
3798                 edata.data = (toe_cmpnt & csum_dir) ? 1 : 0;
3799
3800                 if (copy_to_user(uaddr, &edata, sizeof(edata)))
3801                         return -EFAULT;
3802                 break;
3803
3804         /* Set toe offload components in dongle */
3805         case ETHTOOL_SRXCSUM:
3806         case ETHTOOL_STXCSUM:
3807                 if (copy_from_user(&edata, uaddr, sizeof(edata)))
3808                         return -EFAULT;
3809
3810                 /* Read the current settings, update and write back */
3811                 if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0)
3812                         return ret;
3813
3814                 csum_dir = (cmd == ETHTOOL_STXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;
3815
3816                 if (edata.data != 0)
3817                         toe_cmpnt |= csum_dir;
3818                 else
3819                         toe_cmpnt &= ~csum_dir;
3820
3821                 if ((ret = dhd_toe_set(dhd, 0, toe_cmpnt)) < 0)
3822                         return ret;
3823
3824                 /* If setting TX checksum mode, tell Linux the new mode */
3825                 if (cmd == ETHTOOL_STXCSUM) {
3826                         if (edata.data)
3827                                 dhd->iflist[0]->net->features |= NETIF_F_IP_CSUM;
3828                         else
3829                                 dhd->iflist[0]->net->features &= ~NETIF_F_IP_CSUM;
3830                 }
3831
3832                 break;
3833 #endif /* TOE */
3834
3835         default:
3836                 return -EOPNOTSUPP;
3837         }
3838
3839         return 0;
3840 }
3841 #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */
3842
3843 static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error)
3844 {
3845         dhd_info_t *dhd;
3846
3847         if (!dhdp) {
3848                 DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__));
3849                 return FALSE;
3850         }
3851
3852         if (!dhdp->up)
3853                 return FALSE;
3854
3855         dhd = (dhd_info_t *)dhdp->info;
3856 #if !defined(BCMPCIE)
3857         if (dhd->thr_dpc_ctl.thr_pid < 0) {
3858                 DHD_ERROR(("%s : skipped due to negative pid - unloading?\n", __FUNCTION__));
3859                 return FALSE;
3860         }
3861 #endif 
3862
3863 #ifdef CONFIG_MACH_UNIVERSAL5433
3864         /* old revision does not send hang message */
3865         if ((check_rev() && (error == -ETIMEDOUT)) || (error == -EREMOTEIO) ||
3866 #else
3867         if ((error == -ETIMEDOUT) || (error == -EREMOTEIO) ||
3868 #endif /* CONFIG_MACH_UNIVERSAL5433 */
3869                 ((dhdp->busstate == DHD_BUS_DOWN) && (!dhdp->dongle_reset))) {
3870                 DHD_ERROR(("%s: Event HANG send up due to  re=%d te=%d e=%d s=%d\n", __FUNCTION__,
3871                         dhdp->rxcnt_timeout, dhdp->txcnt_timeout, error, dhdp->busstate));
3872                 net_os_send_hang_message(net);
3873                 return TRUE;
3874         }
3875         return FALSE;
3876 }
3877
3878 int dhd_ioctl_process(dhd_pub_t *pub, int ifidx, dhd_ioctl_t *ioc, void *data_buf)
3879 {
3880         int bcmerror = BCME_OK;
3881         int buflen = 0;
3882         struct net_device *net;
3883
3884         net = dhd_idx2net(pub, ifidx);
3885         if (!net) {
3886                 bcmerror = BCME_BADARG;
3887                 goto done;
3888         }
3889
3890         if (data_buf)
3891                 buflen = MIN(ioc->len, DHD_IOCTL_MAXLEN);
3892
3893         /* check for local dhd ioctl and handle it */
3894         if (ioc->driver == DHD_IOCTL_MAGIC) {
3895                 bcmerror = dhd_ioctl((void *)pub, ioc, data_buf, buflen);
3896                 if (bcmerror)
3897                         pub->bcmerror = bcmerror;
3898                 goto done;
3899         }
3900
3901         /* send to dongle (must be up, and wl). */
3902         if (pub->busstate != DHD_BUS_DATA) {
3903                 bcmerror = BCME_DONGLE_DOWN;
3904                 goto done;
3905         }
3906
3907         if (!pub->iswl) {
3908                 bcmerror = BCME_DONGLE_DOWN;
3909                 goto done;
3910         }
3911
3912         /*
3913          * Flush the TX queue if required for proper message serialization:
3914          * Intercept WLC_SET_KEY IOCTL - serialize M4 send and set key IOCTL to
3915          * prevent M4 encryption and
3916          * intercept WLC_DISASSOC IOCTL - serialize WPS-DONE and WLC_DISASSOC IOCTL to
3917          * prevent disassoc frame being sent before WPS-DONE frame.
3918          */
3919         if (ioc->cmd == WLC_SET_KEY ||
3920             (ioc->cmd == WLC_SET_VAR && data_buf != NULL &&
3921              strncmp("wsec_key", data_buf, 9) == 0) ||
3922             (ioc->cmd == WLC_SET_VAR && data_buf != NULL &&
3923              strncmp("bsscfg:wsec_key", data_buf, 15) == 0) ||
3924             ioc->cmd == WLC_DISASSOC)
3925                 dhd_wait_pend8021x(net);
3926
3927 #ifdef WLMEDIA_HTSF
3928         if (data_buf) {
3929                 /*  short cut wl ioctl calls here  */
3930                 if (strcmp("htsf", data_buf) == 0) {
3931                         dhd_ioctl_htsf_get(dhd, 0);
3932                         return BCME_OK;
3933                 }
3934
3935                 if (strcmp("htsflate", data_buf) == 0) {
3936                         if (ioc->set) {
3937                                 memset(ts, 0, sizeof(tstamp_t)*TSMAX);
3938                                 memset(&maxdelayts, 0, sizeof(tstamp_t));
3939                                 maxdelay = 0;
3940                                 tspktcnt = 0;
3941                                 maxdelaypktno = 0;
3942                                 memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN);
3943                                 memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN);
3944                                 memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN);
3945                                 memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN);
3946                         } else {
3947                                 dhd_dump_latency();
3948                         }
3949                         return BCME_OK;
3950                 }
3951                 if (strcmp("htsfclear", data_buf) == 0) {
3952                         memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN);
3953                         memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN);
3954                         memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN);
3955                         memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN);
3956                         htsf_seqnum = 0;
3957                         return BCME_OK;
3958                 }
3959                 if (strcmp("htsfhis", data_buf) == 0) {
3960                         dhd_dump_htsfhisto(&vi_d1, "H to D");
3961                         dhd_dump_htsfhisto(&vi_d2, "D to D");
3962                         dhd_dump_htsfhisto(&vi_d3, "D to H");
3963                         dhd_dump_htsfhisto(&vi_d4, "H to H");
3964                         return BCME_OK;
3965                 }
3966                 if (strcmp("tsport", data_buf) == 0) {
3967                         if (ioc->set) {
3968                                 memcpy(&tsport, data_buf + 7, 4);
3969                         } else {
3970                                 DHD_ERROR(("current timestamp port: %d \n", tsport));
3971                         }
3972                         return BCME_OK;
3973                 }
3974         }
3975 #endif /* WLMEDIA_HTSF */
3976
3977         if ((ioc->cmd == WLC_SET_VAR || ioc->cmd == WLC_GET_VAR) &&
3978                 data_buf != NULL && strncmp("rpc_", data_buf, 4) == 0) {
3979 #ifdef BCM_FD_AGGR
3980                 bcmerror = dhd_fdaggr_ioctl(pub, ifidx, (wl_ioctl_t *)ioc, data_buf, buflen);
3981 #else
3982                 bcmerror = BCME_UNSUPPORTED;
3983 #endif
3984                 goto done;
3985         }
3986         bcmerror = dhd_wl_ioctl(pub, ifidx, (wl_ioctl_t *)ioc, data_buf, buflen);
3987
3988 done:
3989         dhd_check_hang(net, pub, bcmerror);
3990
3991         return bcmerror;
3992 }
3993
3994 static int
3995 dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
3996 {
3997         dhd_info_t *dhd = DHD_DEV_INFO(net);
3998         dhd_ioctl_t ioc;
3999         int bcmerror = 0;
4000         int ifidx;
4001         int ret;
4002         void *local_buf = NULL;
4003         u16 buflen = 0;
4004
4005         DHD_OS_WAKE_LOCK(&dhd->pub);
4006         DHD_PERIM_LOCK(&dhd->pub);
4007
4008         /* Interface up check for built-in type */
4009         if (!dhd_download_fw_on_driverload && dhd->pub.up == 0) {
4010                 DHD_ERROR(("%s: Interface is down \n", __FUNCTION__));
4011                 DHD_PERIM_UNLOCK(&dhd->pub);
4012                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
4013                 return BCME_NOTUP;
4014         }
4015
4016         /* send to dongle only if we are not waiting for reload already */
4017         if (dhd->pub.hang_was_sent) {
4018                 DHD_ERROR(("%s: HANG was sent up earlier\n", __FUNCTION__));
4019                 DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT_MS);
4020                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
4021                 return OSL_ERROR(BCME_DONGLE_DOWN);
4022         }
4023
4024         ifidx = dhd_net2idx(dhd, net);
4025         DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd));
4026
4027         if (ifidx == DHD_BAD_IF) {
4028                 DHD_ERROR(("%s: BAD IF\n", __FUNCTION__));
4029                 DHD_PERIM_UNLOCK(&dhd->pub);
4030                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
4031                 return -1;
4032         }
4033
4034 #if defined(WL_WIRELESS_EXT)
4035         /* linux wireless extensions */
4036         if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) {
4037                 /* may recurse, do NOT lock */
4038                 ret = wl_iw_ioctl(net, ifr, cmd);
4039                 DHD_PERIM_UNLOCK(&dhd->pub);
4040                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
4041                 return ret;
4042         }
4043 #endif /* defined(WL_WIRELESS_EXT) */
4044
4045 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2)
4046         if (cmd == SIOCETHTOOL) {
4047                 ret = dhd_ethtool(dhd, (void*)ifr->ifr_data);
4048                 DHD_PERIM_UNLOCK(&dhd->pub);
4049                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
4050                 return ret;
4051         }
4052 #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */
4053
4054         if (cmd == SIOCDEVPRIVATE+1) {
4055                 ret = wl_android_priv_cmd(net, ifr, cmd);
4056                 dhd_check_hang(net, &dhd->pub, ret);
4057                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
4058                 return ret;
4059         }
4060
4061         if (cmd != SIOCDEVPRIVATE) {
4062                 DHD_PERIM_UNLOCK(&dhd->pub);
4063                 DHD_OS_WAKE_UNLOCK(&dhd->pub);
4064                 return -EOPNOTSUPP;
4065         }
4066
4067         memset(&ioc, 0, sizeof(ioc));
4068
4069 #ifdef CONFIG_COMPAT
4070         if (is_compat_task()) {
4071                 compat_wl_ioctl_t compat_ioc;
4072                 if (copy_from_user(&compat_ioc, ifr->ifr_data, sizeof(compat_wl_ioctl_t))) {
4073                         bcmerror = BCME_BADADDR;
4074                         goto done;
4075                 }
4076                 ioc.cmd = compat_ioc.cmd;
4077                 ioc.buf = compat_ptr(compat_ioc.buf);
4078                 ioc.len = compat_ioc.len;
4079                 ioc.set = compat_ioc.set;
4080                 ioc.used = compat_ioc.used;
4081                 ioc.needed = compat_ioc.needed;
4082                 /* To differentiate between wl and dhd read 4 more byes */
4083                 if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(compat_wl_ioctl_t),
4084                         sizeof(uint)) != 0)) {
4085                         bcmerror = BCME_BADADDR;
4086                         goto done;
4087                 }
4088         } else
4089 #endif /* CONFIG_COMPAT */
4090         {
4091                 /* Copy the ioc control structure part of ioctl request */
4092                 if (copy_from_user(&ioc, ifr->ifr_data, sizeof(wl_ioctl_t))) {
4093                         bcmerror = BCME_BADADDR;
4094                         goto done;
4095                 }
4096
4097                 /* To differentiate between wl and dhd read 4 more byes */
4098                 if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(wl_ioctl_t),
4099                         sizeof(uint)) != 0)) {
4100                         bcmerror = BCME_BADADDR;
4101                         goto done;
4102                 }
4103         }
4104
4105         if (!capable(CAP_NET_ADMIN)) {
4106                 bcmerror = BCME_EPERM;
4107                 goto done;
4108         }
4109
4110         if (ioc.len > 0) {
4111                 buflen = MIN(ioc.len, DHD_IOCTL_MAXLEN);
4112                 if (!(local_buf = MALLOC(dhd->pub.osh, buflen+1))) {
4113                         bcmerror = BCME_NOMEM;
4114                         goto done;
4115                 }
4116
4117                 DHD_PERIM_UNLOCK(&dhd->pub);
4118                 if (copy_from_user(local_buf, ioc.buf, buflen)) {
4119                         DHD_PERIM_LOCK(&dhd->pub);
4120                         bcmerror = BCME_BADADDR;
4121                         goto done;
4122                 }
4123                 DHD_PERIM_LOCK(&dhd->pub);
4124
4125                 *(char *)(local_buf + buflen) = '\0';
4126         }
4127
4128         bcmerror = dhd_ioctl_process(&dhd->pub, ifidx, &ioc, local_buf);
4129
4130         if (!bcmerror && buflen && local_buf && ioc.buf) {
4131                 DHD_PERIM_UNLOCK(&dhd->pub);
4132                 if (copy_to_user(ioc.buf, local_buf, buflen))
4133                         bcmerror = -EFAULT;
4134                 DHD_PERIM_LOCK(&dhd->pub);
4135         }
4136
4137 done:
4138         if (local_buf)
4139                 MFREE(dhd->pub.osh, local_buf, buflen+1);
4140
4141         DHD_PERIM_UNLOCK(&dhd->pub);
4142         DHD_OS_WAKE_UNLOCK(&dhd->pub);
4143
4144         return OSL_ERROR(bcmerror);
4145 }
4146
4147 #define MAX_TRY_CNT             5 /* Number of tries to disable deepsleep */
4148 int dhd_deepsleep(dhd_info_t *dhd, int flag)
4149 {
4150         char iovbuf[20];
4151         uint powervar = 0;
4152         dhd_pub_t *dhdp;
4153         int cnt = 0;
4154         int ret = 0;
4155
4156         dhdp = &dhd->pub;
4157
4158         switch (flag) {
4159                 case 1 :  /* Deepsleep on */
4160                         DHD_ERROR(("dhd_deepsleep: ON\n"));
4161                         /* give some time to sysioc_work before deepsleep */
4162                         OSL_SLEEP(200);
4163 #ifdef PKT_FILTER_SUPPORT
4164                         /* disable pkt filter */
4165                         dhd_enable_packet_filter(0, dhdp);
4166 #endif /* PKT_FILTER_SUPPORT */
4167                         /* Disable MPC */
4168                         powervar = 0;
4169                         memset(iovbuf, 0, sizeof(iovbuf));
4170                         bcm_mkiovar("mpc", (char *)&powervar, 4, iovbuf, sizeof(iovbuf));
4171                         dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
4172
4173                         /* Enable Deepsleep */
4174                         powervar = 1;
4175                         memset(iovbuf, 0, sizeof(iovbuf));
4176                         bcm_mkiovar("deepsleep", (char *)&powervar, 4, iovbuf, sizeof(iovbuf));
4177                         dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
4178                         break;
4179
4180                 case 0: /* Deepsleep Off */
4181                         DHD_ERROR(("dhd_deepsleep: OFF\n"));
4182
4183                         /* Disable Deepsleep */
4184                         for (cnt = 0; cnt < MAX_TRY_CNT; cnt++) {
4185                                 powervar = 0;
4186                                 memset(iovbuf, 0, sizeof(iovbuf));
4187                                 bcm_mkiovar("deepsleep", (char *)&powervar, 4,
4188                                         iovbuf, sizeof(iovbuf));
4189                                 dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf,
4190                                         sizeof(iovbuf), TRUE, 0);
4191
4192                                 memset(iovbuf, 0, sizeof(iovbuf));
4193                                 bcm_mkiovar("deepsleep", (char *)&powervar, 4,
4194                                         iovbuf, sizeof(iovbuf));
4195                                 if ((ret = dhd_wl_ioctl_cmd(dhdp, WLC_GET_VAR, iovbuf,
4196                                         sizeof(iovbuf), FALSE, 0)) < 0) {
4197                                         DHD_ERROR(("the error of dhd deepsleep status"
4198                                                 " ret value :%d\n", ret));
4199                                 } else {
4200                                         if (!(*(int *)iovbuf)) {
4201                                                 DHD_ERROR(("deepsleep mode is 0,"
4202                                                         " count: %d\n", cnt));
4203                                                 break;
4204                                         }
4205                                 }
4206                         }
4207
4208                         /* Enable MPC */
4209                         powervar = 1;
4210                         memset(iovbuf, 0, sizeof(iovbuf));
4211                         bcm_mkiovar("mpc", (char *)&powervar, 4, iovbuf, sizeof(iovbuf));
4212                         dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
4213                         break;
4214         }
4215
4216         return 0;
4217 }
4218
4219 static int
4220 dhd_stop(struct net_device *net)
4221 {
4222         int ifidx = 0;
4223         dhd_info_t *dhd = DHD_DEV_INFO(net);
4224         DHD_OS_WAKE_LOCK(&dhd->pub);
4225         DHD_PERIM_LOCK(&dhd->pub);
4226         printk("%s: Enter %p\n", __FUNCTION__, net);
4227         if (dhd->pub.up == 0) {
4228                 goto exit;
4229         }
4230
4231         dhd_if_flush_sta(DHD_DEV_IFP(net));
4232
4233
4234         ifidx = dhd_net2idx(dhd, net);
4235         BCM_REFERENCE(ifidx);
4236
4237         /* Set state and stop OS transmissions */
4238         netif_stop_queue(net);
4239         dhd->pub.up = 0;
4240
4241 #ifdef WL_CFG80211
4242         if (ifidx == 0) {
4243                 wl_cfg80211_down(NULL);
4244
4245                 /*
4246                  * For CFG80211: Clean up all the left over virtual interfaces
4247                  * when the primary Interface is brought down. [ifconfig wlan0 down]
4248                  */
4249                 if (!dhd_download_fw_on_driverload) {
4250                         if ((dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) &&
4251                                 (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) {
4252                                 int i;
4253
4254                                 dhd_net_if_lock_local(dhd);
4255                                 for (i = 1; i < DHD_MAX_IFS; i++)
4256                                         dhd_remove_if(&dhd->pub, i, FALSE);
4257                                 dhd_net_if_unlock_local(dhd);
4258                         }
4259                 }
4260         }
4261 #endif /* WL_CFG80211 */
4262
4263 #ifdef PROP_TXSTATUS
4264         dhd_wlfc_cleanup(&dhd->pub, NULL, 0);
4265 #endif
4266         /* Stop the protocol module */
4267         dhd_prot_stop(&dhd->pub);
4268
4269         OLD_MOD_DEC_USE_COUNT;
4270 exit:
4271         if (ifidx == 0 && !dhd_download_fw_on_driverload)
4272                 wl_android_wifi_off(net);
4273         else {
4274                 if (dhd->pub.conf->deepsleep)
4275                         dhd_deepsleep(dhd, 1);
4276         }
4277         dhd->pub.rxcnt_timeout = 0;
4278         dhd->pub.txcnt_timeout = 0;
4279
4280         dhd->pub.hang_was_sent = 0;
4281
4282         /* Clear country spec for for built-in type driver */
4283         if (!dhd_download_fw_on_driverload) {
4284                 dhd->pub.dhd_cspec.country_abbrev[0] = 0x00;
4285                 dhd->pub.dhd_cspec.rev = 0;
4286                 dhd->pub.dhd_cspec.ccode[0] = 0x00;
4287         }
4288
4289         printk("%s: Exit\n", __FUNCTION__);
4290         DHD_PERIM_UNLOCK(&dhd->pub);
4291         DHD_OS_WAKE_UNLOCK(&dhd->pub);
4292         return 0;
4293 }
4294
4295 #if defined(WL_CFG80211) && defined(USE_INITIAL_SHORT_DWELL_TIME)
4296 extern bool g_first_broadcast_scan;
4297 #endif 
4298
4299 #ifdef WL11U
4300 static int dhd_interworking_enable(dhd_pub_t *dhd)
4301 {
4302         char iovbuf[WLC_IOCTL_SMLEN];
4303         uint32 enable = true;
4304         int ret = BCME_OK;
4305
4306         bcm_mkiovar("interworking", (char *)&enable, sizeof(enable), iovbuf, sizeof(iovbuf));
4307         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
4308                 DHD_ERROR(("%s: enableing interworking failed, ret=%d\n", __FUNCTION__, ret));
4309         }
4310
4311         if (ret == BCME_OK) {
4312                 /* basic capabilities for HS20 REL2 */
4313                 uint32 cap = WL_WNM_BSSTRANS | WL_WNM_NOTIF;
4314                 bcm_mkiovar("wnm", (char *)&cap, sizeof(cap), iovbuf, sizeof(iovbuf));
4315                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
4316                         iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
4317                         DHD_ERROR(("%s: failed to set WNM info, ret=%d\n", __FUNCTION__, ret));
4318                 }
4319         }
4320
4321         return ret;
4322 }
4323 #endif /* WL11u */
4324
4325 static int
4326 dhd_open(struct net_device *net)
4327 {
4328         dhd_info_t *dhd = DHD_DEV_INFO(net);
4329 #ifdef TOE
4330         uint32 toe_ol;
4331 #endif
4332         int ifidx;
4333         int32 ret = 0;
4334
4335         printk("%s: Enter %p\n", __FUNCTION__, net);
4336 #if defined(MULTIPLE_SUPPLICANT)
4337 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
4338         if (mutex_is_locked(&_dhd_sdio_mutex_lock_) != 0) {
4339                 DHD_ERROR(("%s : dhd_open: call dev open before insmod complete!\n", __FUNCTION__));
4340         }
4341         mutex_lock(&_dhd_sdio_mutex_lock_);
4342 #endif
4343 #endif /* MULTIPLE_SUPPLICANT */
4344
4345         DHD_OS_WAKE_LOCK(&dhd->pub);
4346         DHD_PERIM_LOCK(&dhd->pub);
4347         dhd->pub.dongle_trap_occured = 0;
4348         dhd->pub.hang_was_sent = 0;
4349
4350 #if 0
4351         /*
4352          * Force start if ifconfig_up gets called before START command
4353          *  We keep WEXT's wl_control_wl_start to provide backward compatibility
4354          *  This should be removed in the future
4355          */
4356         ret = wl_control_wl_start(net);
4357         if (ret != 0) {
4358                 DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret));
4359                 ret = -1;
4360                 goto exit;
4361         }
4362 #endif
4363
4364         ifidx = dhd_net2idx(dhd, net);
4365         DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx));
4366
4367         if (ifidx < 0) {
4368                 DHD_ERROR(("%s: Error: called with invalid IF\n", __FUNCTION__));
4369                 ret = -1;
4370                 goto exit;
4371         }
4372
4373         if (!dhd->iflist[ifidx]) {
4374                 DHD_ERROR(("%s: Error: called when IF already deleted\n", __FUNCTION__));
4375                 ret = -1;
4376                 goto exit;
4377         }
4378
4379         if (ifidx == 0) {
4380                 atomic_set(&dhd->pend_8021x_cnt, 0);
4381                 if (!dhd_download_fw_on_driverload) {
4382                         DHD_ERROR(("\n%s\n", dhd_version));
4383 #if defined(USE_INITIAL_SHORT_DWELL_TIME)
4384                         g_first_broadcast_scan = TRUE;
4385 #endif 
4386                         ret = wl_android_wifi_on(net);
4387                         if (ret != 0) {
4388                                 DHD_ERROR(("%s : wl_android_wifi_on failed (%d)\n",
4389                                         __FUNCTION__, ret));
4390                                 ret = -1;
4391                                 goto exit;
4392                         }
4393                 }
4394
4395                 if (dhd->pub.busstate != DHD_BUS_DATA) {
4396
4397                         /* try to bring up bus */
4398                         DHD_PERIM_UNLOCK(&dhd->pub);
4399                         ret = dhd_bus_start(&dhd->pub);
4400                         DHD_PERIM_LOCK(&dhd->pub);
4401                         if (ret) {
4402                                 DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret));
4403                                 ret = -1;
4404                                 goto exit;
4405                         }
4406
4407                 }
4408                 if (dhd_download_fw_on_driverload) {
4409                         if (dhd->pub.conf->deepsleep)
4410                                 dhd_deepsleep(dhd, 0);
4411                 }
4412
4413                 /* dhd_sync_with_dongle has been called in dhd_bus_start or wl_android_wifi_on */
4414                 memcpy(net->dev_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN);
4415
4416 #ifdef TOE
4417                 /* Get current TOE mode from dongle */
4418                 if (dhd_toe_get(dhd, ifidx, &toe_ol) >= 0 && (toe_ol & TOE_TX_CSUM_OL) != 0)
4419                         dhd->iflist[ifidx]->net->features |= NETIF_F_IP_CSUM;
4420                 else
4421                         dhd->iflist[ifidx]->net->features &= ~NETIF_F_IP_CSUM;
4422 #endif /* TOE */
4423
4424 #if defined(WL_CFG80211)
4425                 if (unlikely(wl_cfg80211_up(NULL))) {
4426                         DHD_ERROR(("%s: failed to bring up cfg80211\n", __FUNCTION__));
4427                         ret = -1;
4428                         goto exit;
4429                 }
4430                 dhd_set_scb_probe(&dhd->pub);
4431 #endif /* WL_CFG80211 */
4432         }
4433
4434         /* Allow transmit calls */
4435         netif_start_queue(net);
4436         dhd->pub.up = 1;
4437
4438 #ifdef BCMDBGFS
4439         dhd_dbg_init(&dhd->pub);
4440 #endif
4441
4442         OLD_MOD_INC_USE_COUNT;
4443 exit:
4444         if (ret)
4445                 dhd_stop(net);
4446
4447         DHD_PERIM_UNLOCK(&dhd->pub);
4448         DHD_OS_WAKE_UNLOCK(&dhd->pub);
4449
4450 #if defined(MULTIPLE_SUPPLICANT)
4451 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
4452         mutex_unlock(&_dhd_sdio_mutex_lock_);
4453 #endif
4454 #endif /* MULTIPLE_SUPPLICANT */
4455
4456         printk("%s: Exit ret=%d\n", __FUNCTION__, ret);
4457         return ret;
4458 }
4459
4460 int dhd_do_driver_init(struct net_device *net)
4461 {
4462         dhd_info_t *dhd = NULL;
4463
4464         if (!net) {
4465                 DHD_ERROR(("Primary Interface not initialized \n"));
4466                 return -EINVAL;
4467         }
4468
4469 #ifdef MULTIPLE_SUPPLICANT
4470 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 && defined(BCMSDIO)
4471         if (mutex_is_locked(&_dhd_sdio_mutex_lock_) != 0) {
4472                 DHD_ERROR(("%s : dhdsdio_probe is already running!\n", __FUNCTION__));
4473                 return 0;
4474         }
4475 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
4476 #endif /* MULTIPLE_SUPPLICANT */
4477
4478         /*  && defined(OEM_ANDROID) && defined(BCMSDIO) */
4479         dhd = DHD_DEV_INFO(net);
4480
4481         /* If driver is already initialized, do nothing
4482          */
4483         if (dhd->pub.busstate == DHD_BUS_DATA) {
4484                 DHD_TRACE(("Driver already Inititalized. Nothing to do"));
4485                 return 0;
4486         }
4487
4488         if (dhd_open(net) < 0) {
4489                 DHD_ERROR(("Driver Init Failed \n"));
4490                 return -1;
4491         }
4492
4493         return 0;
4494 }
4495
4496 int
4497 dhd_event_ifadd(dhd_info_t *dhdinfo, wl_event_data_if_t *ifevent, char *name, uint8 *mac)
4498 {
4499
4500 #ifdef WL_CFG80211
4501         if (wl_cfg80211_notify_ifadd(ifevent->ifidx, name, mac, ifevent->bssidx) == BCME_OK)
4502                 return BCME_OK;
4503 #endif
4504
4505         /* handle IF event caused by wl commands, SoftAP, WEXT and
4506          * anything else. This has to be done asynchronously otherwise
4507          * DPC will be blocked (and iovars will timeout as DPC has no chance
4508          * to read the response back)
4509          */
4510         if (ifevent->ifidx > 0) {
4511                 dhd_if_event_t *if_event = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_event_t));
4512
4513                 memcpy(&if_event->event, ifevent, sizeof(if_event->event));
4514                 memcpy(if_event->mac, mac, ETHER_ADDR_LEN);
4515                 strncpy(if_event->name, name, IFNAMSIZ);
4516                 if_event->name[IFNAMSIZ - 1] = '\0';
4517                 dhd_deferred_schedule_work(dhdinfo->dhd_deferred_wq, (void *)if_event,
4518                         DHD_WQ_WORK_IF_ADD, dhd_ifadd_event_handler, DHD_WORK_PRIORITY_LOW);
4519         }
4520
4521         return BCME_OK;
4522 }
4523
4524 int
4525 dhd_event_ifdel(dhd_info_t *dhdinfo, wl_event_data_if_t *ifevent, char *name, uint8 *mac)
4526 {
4527         dhd_if_event_t *if_event;
4528
4529 #if defined(WL_CFG80211) && !defined(P2PONEINT)
4530         if (wl_cfg80211_notify_ifdel(ifevent->ifidx, name, mac, ifevent->bssidx) == BCME_OK)
4531                 return BCME_OK;
4532 #endif /* WL_CFG80211 */
4533
4534         /* handle IF event caused by wl commands, SoftAP, WEXT and
4535          * anything else
4536          */
4537         if_event = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_event_t));
4538         memcpy(&if_event->event, ifevent, sizeof(if_event->event));
4539         memcpy(if_event->mac, mac, ETHER_ADDR_LEN);
4540         strncpy(if_event->name, name, IFNAMSIZ);
4541         if_event->name[IFNAMSIZ - 1] = '\0';
4542         dhd_deferred_schedule_work(dhdinfo->dhd_deferred_wq, (void *)if_event, DHD_WQ_WORK_IF_DEL,
4543                 dhd_ifdel_event_handler, DHD_WORK_PRIORITY_LOW);
4544
4545         return BCME_OK;
4546 }
4547
4548 /* unregister and free the existing net_device interface (if any) in iflist and
4549  * allocate a new one. the slot is reused. this function does NOT register the
4550  * new interface to linux kernel. dhd_register_if does the job
4551  */
4552 struct net_device*
4553 dhd_allocate_if(dhd_pub_t *dhdpub, int ifidx, char *name,
4554         uint8 *mac, uint8 bssidx, bool need_rtnl_lock)
4555 {
4556         dhd_info_t *dhdinfo = (dhd_info_t *)dhdpub->info;
4557         dhd_if_t *ifp;
4558
4559         ASSERT(dhdinfo && (ifidx < DHD_MAX_IFS));
4560         ifp = dhdinfo->iflist[ifidx];
4561
4562         if (ifp != NULL) {
4563                 if (ifp->net != NULL) {
4564                         DHD_ERROR(("%s: free existing IF %s\n", __FUNCTION__, ifp->net->name));
4565
4566                         dhd_dev_priv_clear(ifp->net); /* clear net_device private */
4567
4568                         /* in unregister_netdev case, the interface gets freed by net->destructor
4569                          * (which is set to free_netdev)
4570                          */
4571                         if (ifp->net->reg_state == NETREG_UNINITIALIZED) {
4572                                 free_netdev(ifp->net);
4573                         } else {
4574                                 netif_stop_queue(ifp->net);
4575                                 if (need_rtnl_lock)
4576                                         unregister_netdev(ifp->net);
4577                                 else
4578                                         unregister_netdevice(ifp->net);
4579                         }
4580                         ifp->net = NULL;
4581                 }
4582         } else {
4583                 ifp = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_t));
4584                 if (ifp == NULL) {
4585                         DHD_ERROR(("%s: OOM - dhd_if_t(%zu)\n", __FUNCTION__, sizeof(dhd_if_t)));
4586                         return NULL;
4587                 }
4588         }
4589
4590         memset(ifp, 0, sizeof(dhd_if_t));
4591         ifp->info = dhdinfo;
4592         ifp->idx = ifidx;
4593         ifp->bssidx = bssidx;
4594         if (mac != NULL)
4595                 memcpy(&ifp->mac_addr, mac, ETHER_ADDR_LEN);
4596
4597         /* Allocate etherdev, including space for private structure */
4598         ifp->net = alloc_etherdev(DHD_DEV_PRIV_SIZE);
4599         if (ifp->net == NULL) {
4600                 DHD_ERROR(("%s: OOM - alloc_etherdev(%zu)\n", __FUNCTION__, sizeof(dhdinfo)));
4601                 goto fail;
4602         }
4603
4604         /* Setup the dhd interface's netdevice private structure. */
4605         dhd_dev_priv_save(ifp->net, dhdinfo, ifp, ifidx);
4606
4607         if (name && name[0]) {
4608                 strncpy(ifp->net->name, name, IFNAMSIZ);
4609                 ifp->net->name[IFNAMSIZ - 1] = '\0';
4610         }
4611 #ifdef WL_CFG80211
4612         if (ifidx == 0)
4613                 ifp->net->destructor = free_netdev;
4614         else
4615                 ifp->net->destructor = dhd_netdev_free;
4616 #else
4617         ifp->net->destructor = free_netdev;
4618 #endif /* WL_CFG80211 */
4619         strncpy(ifp->name, ifp->net->name, IFNAMSIZ);
4620         ifp->name[IFNAMSIZ - 1] = '\0';
4621         dhdinfo->iflist[ifidx] = ifp;
4622
4623 #ifdef PCIE_FULL_DONGLE
4624         /* Initialize STA info list */
4625         INIT_LIST_HEAD(&ifp->sta_list);
4626         DHD_IF_STA_LIST_LOCK_INIT(ifp);
4627 #endif /* PCIE_FULL_DONGLE */
4628
4629         return ifp->net;
4630
4631 fail:
4632         if (ifp != NULL) {
4633                 if (ifp->net != NULL) {
4634                         dhd_dev_priv_clear(ifp->net);
4635                         free_netdev(ifp->net);
4636                         ifp->net = NULL;
4637                 }
4638                 MFREE(dhdinfo->pub.osh, ifp, sizeof(*ifp));
4639                 ifp = NULL;
4640         }
4641         dhdinfo->iflist[ifidx] = NULL;
4642         return NULL;
4643 }
4644
4645 /* unregister and free the the net_device interface associated with the indexed
4646  * slot, also free the slot memory and set the slot pointer to NULL
4647  */
4648 int
4649 dhd_remove_if(dhd_pub_t *dhdpub, int ifidx, bool need_rtnl_lock)
4650 {
4651         dhd_info_t *dhdinfo = (dhd_info_t *)dhdpub->info;
4652         dhd_if_t *ifp;
4653
4654         ifp = dhdinfo->iflist[ifidx];
4655         if (ifp != NULL) {
4656                 if (ifp->net != NULL) {
4657                         DHD_ERROR(("deleting interface '%s' idx %d\n", ifp->net->name, ifp->idx));
4658
4659                         /* in unregister_netdev case, the interface gets freed by net->destructor
4660                          * (which is set to free_netdev)
4661                          */
4662                         if (ifp->net->reg_state == NETREG_UNINITIALIZED) {
4663                                 free_netdev(ifp->net);
4664                         } else {
4665                                 netif_stop_queue(ifp->net);
4666
4667
4668
4669 #ifdef SET_RPS_CPUS
4670                                 custom_rps_map_clear(ifp->net->_rx);
4671 #endif /* SET_RPS_CPUS */
4672                                 if (need_rtnl_lock)
4673                                         unregister_netdev(ifp->net);
4674                                 else
4675                                         unregister_netdevice(ifp->net);
4676                         }
4677                         ifp->net = NULL;
4678                 }
4679 #ifdef DHD_WMF
4680                 dhd_wmf_cleanup(dhdpub, ifidx);
4681 #endif /* DHD_WMF */
4682
4683                 dhd_if_del_sta_list(ifp);
4684
4685                 dhdinfo->iflist[ifidx] = NULL;
4686                 MFREE(dhdinfo->pub.osh, ifp, sizeof(*ifp));
4687
4688         }
4689
4690         return BCME_OK;
4691 }
4692
4693 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
4694 static struct net_device_ops dhd_ops_pri = {
4695         .ndo_open = dhd_open,
4696         .ndo_stop = dhd_stop,
4697         .ndo_get_stats = dhd_get_stats,
4698         .ndo_do_ioctl = dhd_ioctl_entry,
4699         .ndo_start_xmit = dhd_start_xmit,
4700         .ndo_set_mac_address = dhd_set_mac_address,
4701 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
4702         .ndo_set_rx_mode = dhd_set_multicast_list,
4703 #else
4704         .ndo_set_multicast_list = dhd_set_multicast_list,
4705 #endif
4706 };
4707
4708 static struct net_device_ops dhd_ops_virt = {
4709         .ndo_get_stats = dhd_get_stats,
4710         .ndo_do_ioctl = dhd_ioctl_entry,
4711         .ndo_start_xmit = dhd_start_xmit,
4712         .ndo_set_mac_address = dhd_set_mac_address,
4713 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
4714         .ndo_set_rx_mode = dhd_set_multicast_list,
4715 #else
4716         .ndo_set_multicast_list = dhd_set_multicast_list,
4717 #endif
4718 };
4719
4720 #ifdef P2PONEINT
4721 extern int wl_cfgp2p_if_open(struct net_device *net);
4722 extern int wl_cfgp2p_if_stop(struct net_device *net);
4723
4724 static struct net_device_ops dhd_cfgp2p_ops_virt = {
4725         .ndo_open = wl_cfgp2p_if_open,
4726         .ndo_stop = wl_cfgp2p_if_stop,
4727         .ndo_get_stats = dhd_get_stats,
4728         .ndo_do_ioctl = dhd_ioctl_entry,
4729         .ndo_start_xmit = dhd_start_xmit,
4730         .ndo_set_mac_address = dhd_set_mac_address,
4731 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
4732         .ndo_set_rx_mode = dhd_set_multicast_list,
4733 #else
4734         .ndo_set_multicast_list = dhd_set_multicast_list,
4735 #endif
4736 };
4737 #endif /* P2PONEINT */
4738 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */
4739
4740 #ifdef DEBUGGER
4741 extern void debugger_init(void *bus_handle);
4742 #endif
4743
4744
4745 #ifdef SHOW_LOGTRACE
4746 static char *logstrs_path = "/root/logstrs.bin";
4747 module_param(logstrs_path, charp, S_IRUGO);
4748
4749 int
4750 dhd_init_logstrs_array(dhd_event_log_t *temp)
4751 {
4752         struct file *filep = NULL;
4753         struct kstat stat;
4754         mm_segment_t fs;
4755         char *raw_fmts =  NULL;
4756         int logstrs_size = 0;
4757
4758         logstr_header_t *hdr = NULL;
4759         uint32 *lognums = NULL;
4760         char *logstrs = NULL;
4761         int ram_index = 0;
4762         char **fmts;
4763         int num_fmts = 0;
4764         uint32 i = 0;
4765         int error = 0;
4766         set_fs(KERNEL_DS);
4767         fs = get_fs();
4768         filep = filp_open(logstrs_path, O_RDONLY, 0);
4769         if (IS_ERR(filep)) {
4770                 DHD_ERROR(("Failed to open the file logstrs.bin in %s\n",  __FUNCTION__));
4771                 goto fail;
4772         }
4773         error = vfs_stat(logstrs_path, &stat);
4774         if (error) {
4775                 DHD_ERROR(("Failed in %s to find file stat\n", __FUNCTION__));
4776                 goto fail;
4777         }
4778         logstrs_size = (int) stat.size;
4779
4780         raw_fmts = kmalloc(logstrs_size, GFP_KERNEL);
4781         if (raw_fmts == NULL) {
4782                 DHD_ERROR(("Failed to allocate raw_fmts memory\n"));
4783                 goto fail;
4784         }
4785         if (vfs_read(filep, raw_fmts, logstrs_size, &filep->f_pos) !=   logstrs_size) {
4786                 DHD_ERROR(("Error: Log strings file read failed\n"));
4787                 goto fail;
4788         }
4789
4790         /* Remember header from the logstrs.bin file */
4791         hdr = (logstr_header_t *) (raw_fmts + logstrs_size -
4792                 sizeof(logstr_header_t));
4793
4794         if (hdr->log_magic == LOGSTRS_MAGIC) {
4795                 /*
4796                 * logstrs.bin start with header.
4797                 */
4798                 num_fmts =      hdr->rom_logstrs_offset / sizeof(uint32);
4799                 ram_index = (hdr->ram_lognums_offset -
4800                         hdr->rom_lognums_offset) / sizeof(uint32);
4801                 lognums = (uint32 *) &raw_fmts[hdr->rom_lognums_offset];
4802                 logstrs = (char *)       &raw_fmts[hdr->rom_logstrs_offset];
4803         } else {
4804                 /*
4805                  * Legacy logstrs.bin format without header.
4806                  */
4807                 num_fmts = *((uint32 *) (raw_fmts)) / sizeof(uint32);
4808                 if (num_fmts == 0) {
4809                         /* Legacy ROM/RAM logstrs.bin format:
4810                           *  - ROM 'lognums' section
4811                           *   - RAM 'lognums' section
4812                           *   - ROM 'logstrs' section.
4813                           *   - RAM 'logstrs' section.
4814                           *
4815                           * 'lognums' is an array of indexes for the strings in the
4816                           * 'logstrs' section. The first uint32 is 0 (index of first
4817                           * string in ROM 'logstrs' section).
4818                           *
4819                           * The 4324b5 is the only ROM that uses this legacy format. Use the
4820                           * fixed number of ROM fmtnums to find the start of the RAM
4821                           * 'lognums' section. Use the fixed first ROM string ("Con\n") to
4822                           * find the ROM 'logstrs' section.
4823                           */
4824                         #define NUM_4324B5_ROM_FMTS     186
4825                         #define FIRST_4324B5_ROM_LOGSTR "Con\n"
4826                         ram_index = NUM_4324B5_ROM_FMTS;
4827                         lognums = (uint32 *) raw_fmts;
4828                         num_fmts =      ram_index;
4829                         logstrs = (char *) &raw_fmts[num_fmts << 2];
4830                         while (strncmp(FIRST_4324B5_ROM_LOGSTR, logstrs, 4)) {
4831                                 num_fmts++;
4832                                 logstrs = (char *) &raw_fmts[num_fmts << 2];
4833                         }
4834                 } else {
4835                                 /* Legacy RAM-only logstrs.bin format:
4836                                  *        - RAM 'lognums' section
4837                                  *        - RAM 'logstrs' section.
4838                                  *
4839                                  * 'lognums' is an array of indexes for the strings in the
4840                                  * 'logstrs' section. The first uint32 is an index to the
4841                                  * start of 'logstrs'. Therefore, if this index is divided
4842                                  * by 'sizeof(uint32)' it provides the number of logstr
4843                                  *      entries.
4844                                  */
4845                                 ram_index = 0;
4846                                 lognums = (uint32 *) raw_fmts;
4847                                 logstrs = (char *)      &raw_fmts[num_fmts << 2];
4848                         }
4849         }
4850         fmts = kmalloc(num_fmts  * sizeof(char *), GFP_KERNEL);
4851         if (fmts == NULL) {
4852                 DHD_ERROR(("Failed to allocate fmts memory\n"));
4853                 goto fail;
4854         }
4855
4856         for (i = 0; i < num_fmts; i++) {
4857                 /* ROM lognums index into logstrs using 'rom_logstrs_offset' as a base
4858                 * (they are 0-indexed relative to 'rom_logstrs_offset').
4859                 *
4860                 * RAM lognums are already indexed to point to the correct RAM logstrs (they
4861                 * are 0-indexed relative to the start of the logstrs.bin file).
4862                 */
4863                 if (i == ram_index) {
4864                         logstrs = raw_fmts;
4865                 }
4866                 fmts[i] = &logstrs[lognums[i]];
4867         }
4868         temp->fmts = fmts;
4869         temp->raw_fmts = raw_fmts;
4870         temp->num_fmts = num_fmts;
4871         filp_close(filep, NULL);
4872         set_fs(fs);
4873         return 0;
4874 fail:
4875         if (raw_fmts) {
4876                 kfree(raw_fmts);
4877                 raw_fmts = NULL;
4878         }
4879         if (!IS_ERR(filep))
4880                 filp_close(filep, NULL);
4881         set_fs(fs);
4882         temp->fmts = NULL;
4883         return -1;
4884 }
4885 #endif /* SHOW_LOGTRACE */
4886
4887
4888 dhd_pub_t *
4889 dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
4890 {
4891         dhd_info_t *dhd = NULL;
4892         struct net_device *net = NULL;
4893         char if_name[IFNAMSIZ] = {'\0'};
4894         uint32 bus_type = -1;
4895         uint32 bus_num = -1;
4896         uint32 slot_num = -1;
4897         wifi_adapter_info_t *adapter = NULL;
4898
4899         dhd_attach_states_t dhd_state = DHD_ATTACH_STATE_INIT;
4900         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4901
4902         /* will implement get_ids for DBUS later */
4903 #if defined(BCMSDIO)
4904         dhd_bus_get_ids(bus, &bus_type, &bus_num, &slot_num);
4905 #endif 
4906         adapter = dhd_wifi_platform_get_adapter(bus_type, bus_num, slot_num);
4907
4908         /* Allocate primary dhd_info */
4909         dhd = wifi_platform_prealloc(adapter, DHD_PREALLOC_DHD_INFO, sizeof(dhd_info_t));
4910         if (dhd == NULL) {
4911                 dhd = MALLOC(osh, sizeof(dhd_info_t));
4912                 if (dhd == NULL) {
4913                         DHD_ERROR(("%s: OOM - alloc dhd_info\n", __FUNCTION__));
4914                         goto fail;
4915                 }
4916         }
4917         memset(dhd, 0, sizeof(dhd_info_t));
4918         dhd_state |= DHD_ATTACH_STATE_DHD_ALLOC;
4919
4920         dhd->unit = dhd_found + instance_base; /* do not increment dhd_found, yet */
4921
4922         dhd->pub.osh = osh;
4923         dhd->adapter = adapter;
4924
4925 #ifdef GET_CUSTOM_MAC_ENABLE
4926         wifi_platform_get_mac_addr(dhd->adapter, dhd->pub.mac.octet);
4927 #endif /* GET_CUSTOM_MAC_ENABLE */
4928         dhd->thr_dpc_ctl.thr_pid = DHD_PID_KT_TL_INVALID;
4929         dhd->thr_wdt_ctl.thr_pid = DHD_PID_KT_INVALID;
4930
4931         /* Initialize thread based operation and lock */
4932         sema_init(&dhd->sdsem, 1);
4933
4934         /* Link to info module */
4935         dhd->pub.info = dhd;
4936
4937
4938         /* Link to bus module */
4939         dhd->pub.bus = bus;
4940         dhd->pub.hdrlen = bus_hdrlen;
4941
4942         /* dhd_conf must be attached after linking dhd to dhd->pub.info,
4943          * because dhd_detech will check .info is NULL or not.
4944         */
4945         if (dhd_conf_attach(&dhd->pub) != 0) {
4946                 DHD_ERROR(("dhd_conf_attach failed\n"));
4947                 goto fail;
4948         }
4949         dhd_conf_reset(&dhd->pub);
4950         dhd_conf_set_chiprev(&dhd->pub, dhd_bus_chip(bus), dhd_bus_chiprev(bus));
4951         dhd_conf_preinit(&dhd->pub);
4952
4953         /* Some DHD modules (e.g. cfg80211) configures operation mode based on firmware name.
4954          * This is indeed a hack but we have to make it work properly before we have a better
4955          * solution
4956          */
4957         dhd_update_fw_nv_path(dhd);
4958 #ifndef BUILD_IN_KERNEL
4959         dhd_conf_read_config(&dhd->pub, dhd->conf_path);
4960 #endif
4961
4962         /* Set network interface name if it was provided as module parameter */
4963         if (iface_name[0]) {
4964                 int len;
4965                 char ch;
4966                 strncpy(if_name, iface_name, IFNAMSIZ);
4967                 if_name[IFNAMSIZ - 1] = 0;
4968                 len = strlen(if_name);
4969                 ch = if_name[len - 1];
4970                 if ((ch > '9' || ch < '0') && (len < IFNAMSIZ - 2))
4971                         strcat(if_name, "%d");
4972         }
4973         net = dhd_allocate_if(&dhd->pub, 0, if_name, NULL, 0, TRUE);
4974         if (net == NULL)
4975                 goto fail;
4976         dhd_state |= DHD_ATTACH_STATE_ADD_IF;
4977
4978 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
4979         net->open = NULL;
4980 #else
4981         net->netdev_ops = NULL;
4982 #endif
4983
4984         sema_init(&dhd->proto_sem, 1);
4985
4986 #ifdef PROP_TXSTATUS
4987         spin_lock_init(&dhd->wlfc_spinlock);
4988
4989         dhd->pub.skip_fc = dhd_wlfc_skip_fc;
4990         dhd->pub.plat_init = dhd_wlfc_plat_init;
4991         dhd->pub.plat_deinit = dhd_wlfc_plat_deinit;
4992 #endif /* PROP_TXSTATUS */
4993
4994         /* Initialize other structure content */
4995         init_waitqueue_head(&dhd->ioctl_resp_wait);
4996         init_waitqueue_head(&dhd->ctrl_wait);
4997
4998         /* Initialize the spinlocks */
4999         spin_lock_init(&dhd->sdlock);
5000         spin_lock_init(&dhd->txqlock);
5001         spin_lock_init(&dhd->dhd_lock);
5002         spin_lock_init(&dhd->rxf_lock);
5003 #if defined(RXFRAME_THREAD)
5004         dhd->rxthread_enabled = TRUE;
5005 #endif /* defined(RXFRAME_THREAD) */
5006
5007 #ifdef DHDTCPACK_SUPPRESS
5008         spin_lock_init(&dhd->tcpack_lock);
5009 #endif /* DHDTCPACK_SUPPRESS */
5010
5011         /* Initialize Wakelock stuff */
5012         spin_lock_init(&dhd->wakelock_spinlock);
5013         dhd->wakelock_counter = 0;
5014         dhd->wakelock_wd_counter = 0;
5015         dhd->wakelock_rx_timeout_enable = 0;
5016         dhd->wakelock_ctrl_timeout_enable = 0;
5017 #ifdef CONFIG_HAS_WAKELOCK
5018         wake_lock_init(&dhd->wl_wifi, WAKE_LOCK_SUSPEND, "wlan_wake");
5019         wake_lock_init(&dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake");
5020         wake_lock_init(&dhd->wl_ctrlwake, WAKE_LOCK_SUSPEND, "wlan_ctrl_wake");
5021         wake_lock_init(&dhd->wl_wdwake, WAKE_LOCK_SUSPEND, "wlan_wd_wake");
5022 #ifdef BCMPCIE_OOB_HOST_WAKE
5023         wake_lock_init(&dhd->wl_intrwake, WAKE_LOCK_SUSPEND, "wlan_oob_irq_wake");
5024 #endif /* BCMPCIE_OOB_HOST_WAKE */
5025 #endif /* CONFIG_HAS_WAKELOCK */
5026 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
5027         mutex_init(&dhd->dhd_net_if_mutex);
5028         mutex_init(&dhd->dhd_suspend_mutex);
5029 #endif
5030         dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT;
5031
5032         /* Attach and link in the protocol */
5033         if (dhd_prot_attach(&dhd->pub) != 0) {
5034                 DHD_ERROR(("dhd_prot_attach failed\n"));
5035                 goto fail;
5036         }
5037         dhd_state |= DHD_ATTACH_STATE_PROT_ATTACH;
5038
5039 #ifdef WL_CFG80211
5040         /* Attach and link in the cfg80211 */
5041         if (unlikely(wl_cfg80211_attach(net, &dhd->pub))) {
5042                 DHD_ERROR(("wl_cfg80211_attach failed\n"));
5043                 goto fail;
5044         }
5045
5046         dhd_monitor_init(&dhd->pub);
5047         dhd_state |= DHD_ATTACH_STATE_CFG80211;
5048 #endif
5049 #if defined(WL_WIRELESS_EXT)
5050         /* Attach and link in the iw */
5051         if (!(dhd_state &  DHD_ATTACH_STATE_CFG80211)) {
5052                 if (wl_iw_attach(net, (void *)&dhd->pub) != 0) {
5053                         DHD_ERROR(("wl_iw_attach failed\n"));
5054                         goto fail;
5055                 }
5056                 dhd_state |= DHD_ATTACH_STATE_WL_ATTACH;
5057         }
5058 #endif /* defined(WL_WIRELESS_EXT) */
5059
5060 #ifdef SHOW_LOGTRACE
5061         dhd_init_logstrs_array(&dhd->event_data);
5062 #endif /* SHOW_LOGTRACE */
5063
5064         if (dhd_sta_pool_init(&dhd->pub, DHD_MAX_STA) != BCME_OK) {
5065                 DHD_ERROR(("%s: Initializing %u sta\n", __FUNCTION__, DHD_MAX_STA));
5066                 goto fail;
5067         }
5068
5069
5070         /* Set up the watchdog timer */
5071         init_timer(&dhd->timer);
5072         dhd->timer.data = (ulong)dhd;
5073         dhd->timer.function = dhd_watchdog;
5074         dhd->default_wd_interval = dhd_watchdog_ms;
5075
5076         if (dhd_watchdog_prio >= 0) {
5077                 /* Initialize watchdog thread */
5078                 PROC_START(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0, "dhd_watchdog_thread");
5079
5080         } else {
5081                 dhd->thr_wdt_ctl.thr_pid = -1;
5082         }
5083
5084 #ifdef DEBUGGER
5085         debugger_init((void *) bus);
5086 #endif
5087
5088         /* Set up the bottom half handler */
5089         if (dhd_dpc_prio >= 0) {
5090                 /* Initialize DPC thread */
5091                 PROC_START(dhd_dpc_thread, dhd, &dhd->thr_dpc_ctl, 0, "dhd_dpc");
5092         } else {
5093                 /*  use tasklet for dpc */
5094                 tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd);
5095                 dhd->thr_dpc_ctl.thr_pid = -1;
5096         }
5097
5098         if (dhd->rxthread_enabled) {
5099                 bzero(&dhd->pub.skbbuf[0], sizeof(void *) * MAXSKBPEND);
5100                 /* Initialize RXF thread */
5101                 PROC_START(dhd_rxf_thread, dhd, &dhd->thr_rxf_ctl, 0, "dhd_rxf");
5102         }
5103
5104         dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED;
5105
5106 #if defined(CONFIG_PM_SLEEP)
5107         if (!dhd_pm_notifier_registered) {
5108                 dhd_pm_notifier_registered = TRUE;
5109                 register_pm_notifier(&dhd_pm_notifier);
5110         }
5111 #endif /* CONFIG_PM_SLEEP */
5112
5113 #if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
5114         dhd->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 20;
5115         dhd->early_suspend.suspend = dhd_early_suspend;
5116         dhd->early_suspend.resume = dhd_late_resume;
5117         register_early_suspend(&dhd->early_suspend);
5118         dhd_state |= DHD_ATTACH_STATE_EARLYSUSPEND_DONE;
5119 #endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */
5120
5121 #ifdef ARP_OFFLOAD_SUPPORT
5122         dhd->pend_ipaddr = 0;
5123         if (!dhd_inetaddr_notifier_registered) {
5124                 dhd_inetaddr_notifier_registered = TRUE;
5125                 register_inetaddr_notifier(&dhd_inetaddr_notifier);
5126         }
5127 #endif /* ARP_OFFLOAD_SUPPORT */
5128 #ifdef CONFIG_IPV6
5129         if (!dhd_inet6addr_notifier_registered) {
5130                 dhd_inet6addr_notifier_registered = TRUE;
5131                 register_inet6addr_notifier(&dhd_inet6addr_notifier);
5132         }
5133 #endif
5134         dhd->dhd_deferred_wq = dhd_deferred_work_init((void *)dhd);
5135 #ifdef DEBUG_CPU_FREQ
5136         dhd->new_freq = alloc_percpu(int);
5137         dhd->freq_trans.notifier_call = dhd_cpufreq_notifier;
5138         cpufreq_register_notifier(&dhd->freq_trans, CPUFREQ_TRANSITION_NOTIFIER);
5139 #endif
5140 #ifdef DHDTCPACK_SUPPRESS
5141 #ifdef BCMSDIO
5142         dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_DELAYTX);
5143 #elif defined(BCMPCIE)
5144         dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_HOLD);
5145 #else
5146         dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_OFF);
5147 #endif /* BCMSDIO */
5148 #endif /* DHDTCPACK_SUPPRESS */
5149
5150         dhd_state |= DHD_ATTACH_STATE_DONE;
5151         dhd->dhd_state = dhd_state;
5152
5153         dhd_found++;
5154 #if defined(CUSTOMER_HW20) && defined(WLANAUDIO)
5155         dhd_global = dhd;
5156 #endif /* CUSTOMER_HW20 && WLANAUDIO */
5157         return &dhd->pub;
5158
5159 fail:
5160         if (dhd_state >= DHD_ATTACH_STATE_DHD_ALLOC) {
5161                 DHD_TRACE(("%s: Calling dhd_detach dhd_state 0x%x &dhd->pub %p\n",
5162                         __FUNCTION__, dhd_state, &dhd->pub));
5163                 dhd->dhd_state = dhd_state;
5164                 dhd_detach(&dhd->pub);
5165                 dhd_free(&dhd->pub);
5166         }
5167
5168         return NULL;
5169 }
5170
5171 int dhd_get_fw_mode(dhd_info_t *dhdinfo)
5172 {
5173         if (strstr(dhdinfo->fw_path, "_apsta") != NULL)
5174                 return DHD_FLAG_HOSTAP_MODE;
5175         if (strstr(dhdinfo->fw_path, "_p2p") != NULL)
5176                 return DHD_FLAG_P2P_MODE;
5177         if (strstr(dhdinfo->fw_path, "_ibss") != NULL)
5178                 return DHD_FLAG_IBSS_MODE;
5179         if (strstr(dhdinfo->fw_path, "_mfg") != NULL)
5180                 return DHD_FLAG_MFG_MODE;
5181
5182         return DHD_FLAG_STA_MODE;
5183 }
5184
5185 extern int rkwifi_set_firmware(char *fw, char *nvram);
5186
5187 bool dhd_update_fw_nv_path(dhd_info_t *dhdinfo)
5188 {
5189         int fw_len;
5190         int nv_len;
5191         int conf_len;
5192         const char *fw = NULL;
5193         const char *nv = NULL;
5194         const char *conf = NULL;
5195         char firmware[100] = {0};
5196         char nvram[100] = {0};
5197         wifi_adapter_info_t *adapter = dhdinfo->adapter;
5198
5199
5200         /* Update firmware and nvram path. The path may be from adapter info or module parameter
5201          * The path from adapter info is used for initialization only (as it won't change).
5202          *
5203          * The firmware_path/nvram_path module parameter may be changed by the system at run
5204          * time. When it changes we need to copy it to dhdinfo->fw_path. Also Android private
5205          * command may change dhdinfo->fw_path. As such we need to clear the path info in
5206          * module parameter after it is copied. We won't update the path until the module parameter
5207          * is changed again (first character is not '\0')
5208          */
5209
5210         /* set default firmware and nvram path for built-in type driver */
5211 //      if (!dhd_download_fw_on_driverload) {
5212                 rkwifi_set_firmware(firmware, nvram);
5213 #ifdef CONFIG_BCMDHD_FW_PATH
5214                 fw = CONFIG_BCMDHD_FW_PATH;
5215 #else
5216                 fw = firmware;
5217 #endif /* CONFIG_BCMDHD_FW_PATH */
5218 #ifdef CONFIG_BCMDHD_NVRAM_PATH
5219                 nv = CONFIG_BCMDHD_NVRAM_PATH;
5220 #else
5221                 nv = nvram;
5222 #endif /* CONFIG_BCMDHD_NVRAM_PATH */
5223 //      }
5224
5225         /* check if we need to initialize the path */
5226         if (dhdinfo->fw_path[0] == '\0') {
5227                 if (adapter && adapter->fw_path && adapter->fw_path[0] != '\0')
5228                         fw = adapter->fw_path;
5229
5230         }
5231         if (dhdinfo->nv_path[0] == '\0') {
5232                 if (adapter && adapter->nv_path && adapter->nv_path[0] != '\0')
5233                         nv = adapter->nv_path;
5234         }
5235         if (dhdinfo->conf_path[0] == '\0') {
5236                 if (adapter && adapter->conf_path && adapter->conf_path[0] != '\0')
5237                         conf = adapter->conf_path;
5238         }
5239
5240         /* Use module parameter if it is valid, EVEN IF the path has not been initialized
5241          *
5242          * TODO: need a solution for multi-chip, can't use the same firmware for all chips
5243          */
5244         if (firmware_path[0] != '\0')
5245                 fw = firmware_path;
5246         if (nvram_path[0] != '\0')
5247                 nv = nvram_path;
5248         if (config_path[0] != '\0')
5249                 conf = config_path;
5250
5251         if (fw && fw[0] != '\0') {
5252                 fw_len = strlen(fw);
5253                 if (fw_len >= sizeof(dhdinfo->fw_path)) {
5254                         DHD_ERROR(("fw path len exceeds max len of dhdinfo->fw_path\n"));
5255                         return FALSE;
5256                 }
5257                 strncpy(dhdinfo->fw_path, fw, sizeof(dhdinfo->fw_path));
5258                 if (dhdinfo->fw_path[fw_len-1] == '\n')
5259                        dhdinfo->fw_path[fw_len-1] = '\0';
5260         }
5261         if (nv && nv[0] != '\0') {
5262                 nv_len = strlen(nv);
5263                 if (nv_len >= sizeof(dhdinfo->nv_path)) {
5264                         DHD_ERROR(("nvram path len exceeds max len of dhdinfo->nv_path\n"));
5265                         return FALSE;
5266                 }
5267                 strncpy(dhdinfo->nv_path, nv, sizeof(dhdinfo->nv_path));
5268                 if (dhdinfo->nv_path[nv_len-1] == '\n')
5269                        dhdinfo->nv_path[nv_len-1] = '\0';
5270         }
5271         if (conf && conf[0] != '\0') {
5272                 conf_len = strlen(conf);
5273                 if (conf_len >= sizeof(dhdinfo->conf_path)) {
5274                         DHD_ERROR(("config path len exceeds max len of dhdinfo->conf_path\n"));
5275                         return FALSE;
5276                 }
5277                 strncpy(dhdinfo->conf_path, conf, sizeof(dhdinfo->conf_path));
5278                 if (dhdinfo->conf_path[conf_len-1] == '\n')
5279                        dhdinfo->conf_path[conf_len-1] = '\0';
5280         }
5281
5282 #if 0
5283         /* clear the path in module parameter */
5284         firmware_path[0] = '\0';
5285         nvram_path[0] = '\0';
5286         config_path[0] = '\0';
5287 #endif
5288
5289 #ifndef BCMEMBEDIMAGE
5290         /* fw_path and nv_path are not mandatory for BCMEMBEDIMAGE */
5291         if (dhdinfo->fw_path[0] == '\0') {
5292                 DHD_ERROR(("firmware path not found\n"));
5293                 return FALSE;
5294         }
5295         if (dhdinfo->nv_path[0] == '\0') {
5296                 DHD_ERROR(("nvram path not found\n"));
5297                 return FALSE;
5298         }
5299         if (dhdinfo->conf_path[0] == '\0') {
5300                 dhd_conf_set_conf_path_by_nv_path(&dhdinfo->pub, dhdinfo->conf_path, dhdinfo->nv_path);
5301         }
5302 #endif /* BCMEMBEDIMAGE */
5303
5304         return TRUE;
5305 }
5306
5307
5308 int
5309 dhd_bus_start(dhd_pub_t *dhdp)
5310 {
5311         int ret = -1;
5312         dhd_info_t *dhd = (dhd_info_t*)dhdp->info;
5313         unsigned long flags;
5314
5315         ASSERT(dhd);
5316
5317         DHD_TRACE(("Enter %s:\n", __FUNCTION__));
5318
5319         DHD_PERIM_LOCK(dhdp);
5320
5321         /* try to download image and nvram to the dongle */
5322         if  (dhd->pub.busstate == DHD_BUS_DOWN && dhd_update_fw_nv_path(dhd)) {
5323                 DHD_INFO(("%s download fw %s, nv %s, conf %s\n",
5324                         __FUNCTION__, dhd->fw_path, dhd->nv_path, dhd->conf_path));
5325                 ret = dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh,
5326                         dhd->fw_path, dhd->nv_path, dhd->conf_path);
5327                 if (ret < 0) {
5328                         DHD_ERROR(("%s: failed to download firmware %s\n",
5329                                 __FUNCTION__, dhd->fw_path));
5330                         DHD_PERIM_UNLOCK(dhdp);
5331                         return ret;
5332                 }
5333         }
5334         if (dhd->pub.busstate != DHD_BUS_LOAD) {
5335                 DHD_PERIM_UNLOCK(dhdp);
5336                 return -ENETDOWN;
5337         }
5338
5339         dhd_os_sdlock(dhdp);
5340
5341         /* Start the watchdog timer */
5342         dhd->pub.tickcnt = 0;
5343         dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms);
5344
5345         /* Bring up the bus */
5346         if ((ret = dhd_bus_init(&dhd->pub, FALSE)) != 0) {
5347
5348                 DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret));
5349                 dhd_os_sdunlock(dhdp);
5350                 DHD_PERIM_UNLOCK(dhdp);
5351                 return ret;
5352         }
5353 #if defined(OOB_INTR_ONLY) || defined(BCMPCIE_OOB_HOST_WAKE)
5354 #if defined(BCMPCIE_OOB_HOST_WAKE)
5355         dhd_os_sdunlock(dhdp);
5356 #endif /* BCMPCIE_OOB_HOST_WAKE */
5357         /* Host registration for OOB interrupt */
5358         if (dhd_bus_oob_intr_register(dhdp)) {
5359                 /* deactivate timer and wait for the handler to finish */
5360 #if !defined(BCMPCIE_OOB_HOST_WAKE)
5361                 DHD_GENERAL_LOCK(&dhd->pub, flags);
5362                 dhd->wd_timer_valid = FALSE;
5363                 DHD_GENERAL_UNLOCK(&dhd->pub, flags);
5364                 del_timer_sync(&dhd->timer);
5365
5366                 dhd_os_sdunlock(dhdp);
5367 #endif /* BCMPCIE_OOB_HOST_WAKE */
5368                 DHD_PERIM_UNLOCK(dhdp);
5369                 DHD_OS_WD_WAKE_UNLOCK(&dhd->pub);
5370                 DHD_ERROR(("%s Host failed to register for OOB\n", __FUNCTION__));
5371                 return -ENODEV;
5372         }
5373
5374 #if defined(BCMPCIE_OOB_HOST_WAKE)
5375         dhd_os_sdlock(dhdp);
5376         dhd_bus_oob_intr_set(dhdp, TRUE);
5377 #else
5378         /* Enable oob at firmware */
5379         dhd_enable_oob_intr(dhd->pub.bus, TRUE);
5380 #endif /* BCMPCIE_OOB_HOST_WAKE */
5381 #endif 
5382 #ifdef PCIE_FULL_DONGLE
5383         {
5384                 uint8 txpush = 0;
5385                 uint32 num_flowrings; /* includes H2D common rings */
5386                 num_flowrings = dhd_bus_max_h2d_queues(dhd->pub.bus, &txpush);
5387                 DHD_ERROR(("%s: Initializing %u flowrings\n", __FUNCTION__,
5388                         num_flowrings));
5389                 if ((ret = dhd_flow_rings_init(&dhd->pub, num_flowrings)) != BCME_OK) {
5390                         dhd_os_sdunlock(dhdp);
5391                         DHD_PERIM_UNLOCK(dhdp);
5392                         return ret;
5393                 }
5394         }
5395 #endif /* PCIE_FULL_DONGLE */
5396
5397         /* Do protocol initialization necessary for IOCTL/IOVAR */
5398         dhd_prot_init(&dhd->pub);
5399
5400         /* If bus is not ready, can't come up */
5401         if (dhd->pub.busstate != DHD_BUS_DATA) {
5402                 DHD_GENERAL_LOCK(&dhd->pub, flags);
5403                 dhd->wd_timer_valid = FALSE;
5404                 DHD_GENERAL_UNLOCK(&dhd->pub, flags);
5405                 del_timer_sync(&dhd->timer);
5406                 DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__));
5407                 dhd_os_sdunlock(dhdp);
5408                 DHD_PERIM_UNLOCK(dhdp);
5409                 DHD_OS_WD_WAKE_UNLOCK(&dhd->pub);
5410                 return -ENODEV;
5411         }
5412
5413         dhd_os_sdunlock(dhdp);
5414
5415         /* Bus is ready, query any dongle information */
5416         if ((ret = dhd_sync_with_dongle(&dhd->pub)) < 0) {
5417                 DHD_PERIM_UNLOCK(dhdp);
5418                 return ret;
5419         }
5420
5421 #ifdef ARP_OFFLOAD_SUPPORT
5422         if (dhd->pend_ipaddr) {
5423 #ifdef AOE_IP_ALIAS_SUPPORT
5424                 aoe_update_host_ipv4_table(&dhd->pub, dhd->pend_ipaddr, TRUE, 0);
5425 #endif /* AOE_IP_ALIAS_SUPPORT */
5426                 dhd->pend_ipaddr = 0;
5427         }
5428 #endif /* ARP_OFFLOAD_SUPPORT */
5429
5430         DHD_PERIM_UNLOCK(dhdp);
5431         return 0;
5432 }
5433
5434 #ifdef WLTDLS
5435 int _dhd_tdls_enable(dhd_pub_t *dhd, bool tdls_on, bool auto_on, struct ether_addr *mac)
5436 {
5437         char iovbuf[WLC_IOCTL_SMLEN];
5438         uint32 tdls = tdls_on;
5439         int ret = 0;
5440         uint32 tdls_auto_op = 0;
5441         uint32 tdls_idle_time = CUSTOM_TDLS_IDLE_MODE_SETTING;
5442         int32 tdls_rssi_high = CUSTOM_TDLS_RSSI_THRESHOLD_HIGH;
5443         int32 tdls_rssi_low = CUSTOM_TDLS_RSSI_THRESHOLD_LOW;
5444         BCM_REFERENCE(mac);
5445         if (!FW_SUPPORTED(dhd, tdls))
5446                 return BCME_ERROR;
5447
5448         if (dhd->tdls_enable == tdls_on)
5449                 goto auto_mode;
5450         bcm_mkiovar("tdls_enable", (char *)&tdls, sizeof(tdls), iovbuf, sizeof(iovbuf));
5451         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
5452                 DHD_ERROR(("%s: tdls %d failed %d\n", __FUNCTION__, tdls, ret));
5453                 goto exit;
5454         }
5455         dhd->tdls_enable = tdls_on;
5456 auto_mode:
5457
5458         tdls_auto_op = auto_on;
5459         bcm_mkiovar("tdls_auto_op", (char *)&tdls_auto_op, sizeof(tdls_auto_op),
5460                 iovbuf, sizeof(iovbuf));
5461         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
5462                 sizeof(iovbuf), TRUE, 0)) < 0) {
5463                 DHD_ERROR(("%s: tdls_auto_op failed %d\n", __FUNCTION__, ret));
5464                 goto exit;
5465         }
5466
5467         if (tdls_auto_op) {
5468                 bcm_mkiovar("tdls_idle_time", (char *)&tdls_idle_time,
5469                         sizeof(tdls_idle_time), iovbuf, sizeof(iovbuf));
5470                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
5471                         sizeof(iovbuf), TRUE, 0)) < 0) {
5472                         DHD_ERROR(("%s: tdls_idle_time failed %d\n", __FUNCTION__, ret));
5473                         goto exit;
5474                 }
5475                 bcm_mkiovar("tdls_rssi_high", (char *)&tdls_rssi_high, 4, iovbuf, sizeof(iovbuf));
5476                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
5477                         sizeof(iovbuf), TRUE, 0)) < 0) {
5478                         DHD_ERROR(("%s: tdls_rssi_high failed %d\n", __FUNCTION__, ret));
5479                         goto exit;
5480                 }
5481                 bcm_mkiovar("tdls_rssi_low", (char *)&tdls_rssi_low, 4, iovbuf, sizeof(iovbuf));
5482                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
5483                         sizeof(iovbuf), TRUE, 0)) < 0) {
5484                         DHD_ERROR(("%s: tdls_rssi_low failed %d\n", __FUNCTION__, ret));
5485                         goto exit;
5486                 }
5487         }
5488
5489 exit:
5490         return ret;
5491 }
5492
5493 int dhd_tdls_enable(struct net_device *dev, bool tdls_on, bool auto_on, struct ether_addr *mac)
5494 {
5495         dhd_info_t *dhd = DHD_DEV_INFO(dev);
5496         int ret = 0;
5497         if (dhd)
5498                 ret = _dhd_tdls_enable(&dhd->pub, tdls_on, auto_on, mac);
5499         else
5500                 ret = BCME_ERROR;
5501         return ret;
5502 }
5503 #ifdef PCIE_FULL_DONGLE
5504 void dhd_tdls_update_peer_info(struct net_device *dev, bool connect, uint8 *da)
5505 {
5506         dhd_info_t *dhd = DHD_DEV_INFO(dev);
5507         dhd_pub_t *dhdp =  (dhd_pub_t *)&dhd->pub;
5508         tdls_peer_node_t *cur = dhdp->peer_tbl.node;
5509         tdls_peer_node_t *new = NULL, *prev = NULL;
5510         dhd_if_t *dhdif;
5511         uint8 sa[ETHER_ADDR_LEN];
5512         int ifidx = dhd_net2idx(dhd, dev);
5513
5514         if (ifidx == DHD_BAD_IF)
5515                 return;
5516
5517         dhdif = dhd->iflist[ifidx];
5518         memcpy(sa, dhdif->mac_addr, ETHER_ADDR_LEN);
5519
5520         if (connect) {
5521                 while (cur != NULL) {
5522                         if (!memcmp(da, cur->addr, ETHER_ADDR_LEN)) {
5523                                 DHD_ERROR(("%s: TDLS Peer exist already %d\n",
5524                                         __FUNCTION__, __LINE__));
5525                                 return;
5526                         }
5527                         cur = cur->next;
5528                 }
5529
5530                 new = MALLOC(dhdp->osh, sizeof(tdls_peer_node_t));
5531                 if (new == NULL) {
5532                         DHD_ERROR(("%s: Failed to allocate memory\n", __FUNCTION__));
5533                         return;
5534                 }
5535                 memcpy(new->addr, da, ETHER_ADDR_LEN);
5536                 new->next = dhdp->peer_tbl.node;
5537                 dhdp->peer_tbl.node = new;
5538                 dhdp->peer_tbl.tdls_peer_count++;
5539
5540         } else {
5541                 while (cur != NULL) {
5542                         if (!memcmp(da, cur->addr, ETHER_ADDR_LEN)) {
5543                                 dhd_flow_rings_delete_for_peer(dhdp, ifidx, da);
5544                                 if (prev)
5545                                         prev->next = cur->next;
5546                                 else
5547                                         dhdp->peer_tbl.node = cur->next;
5548                                 MFREE(dhdp->osh, cur, sizeof(tdls_peer_node_t));
5549                                 dhdp->peer_tbl.tdls_peer_count--;
5550                                 return;
5551                         }
5552                         prev = cur;
5553                         cur = cur->next;
5554                 }
5555                 DHD_ERROR(("%s: TDLS Peer Entry Not found\n", __FUNCTION__));
5556         }
5557 }
5558 #endif /* PCIE_FULL_DONGLE */
5559 #endif 
5560
5561 bool dhd_is_concurrent_mode(dhd_pub_t *dhd)
5562 {
5563         if (!dhd)
5564                 return FALSE;
5565
5566         if (dhd->op_mode & DHD_FLAG_CONCURR_MULTI_CHAN_MODE)
5567                 return TRUE;
5568         else if ((dhd->op_mode & DHD_FLAG_CONCURR_SINGLE_CHAN_MODE) ==
5569                 DHD_FLAG_CONCURR_SINGLE_CHAN_MODE)
5570                 return TRUE;
5571         else
5572                 return FALSE;
5573 }
5574 #if !defined(AP) && defined(WLP2P)
5575 /* From Android JerryBean release, the concurrent mode is enabled by default and the firmware
5576  * name would be fw_bcmdhd.bin. So we need to determine whether P2P is enabled in the STA
5577  * firmware and accordingly enable concurrent mode (Apply P2P settings). SoftAP firmware
5578  * would still be named as fw_bcmdhd_apsta.
5579  */
5580 uint32
5581 dhd_get_concurrent_capabilites(dhd_pub_t *dhd)
5582 {
5583         int32 ret = 0;
5584         char buf[WLC_IOCTL_SMLEN];
5585         bool mchan_supported = FALSE;
5586         /* if dhd->op_mode is already set for HOSTAP and Manufacturing
5587          * test mode, that means we only will use the mode as it is
5588          */
5589         if (dhd->op_mode & (DHD_FLAG_HOSTAP_MODE | DHD_FLAG_MFG_MODE))
5590                 return 0;
5591         if (FW_SUPPORTED(dhd, vsdb)) {
5592                 mchan_supported = TRUE;
5593         }
5594         if (!FW_SUPPORTED(dhd, p2p)) {
5595                 DHD_TRACE(("Chip does not support p2p\n"));
5596                 return 0;
5597         }
5598         else {
5599                 /* Chip supports p2p but ensure that p2p is really implemented in firmware or not */
5600                 memset(buf, 0, sizeof(buf));
5601                 bcm_mkiovar("p2p", 0, 0, buf, sizeof(buf));
5602                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf),
5603                         FALSE, 0)) < 0) {
5604                         DHD_ERROR(("%s: Get P2P failed (error=%d)\n", __FUNCTION__, ret));
5605                         return 0;
5606                 }
5607                 else {
5608                         if (buf[0] == 1) {
5609                                 /* By default, chip supports single chan concurrency,
5610                                 * now lets check for mchan
5611                                 */
5612                                 ret = DHD_FLAG_CONCURR_SINGLE_CHAN_MODE;
5613                                 if (mchan_supported)
5614                                         ret |= DHD_FLAG_CONCURR_MULTI_CHAN_MODE;
5615 #if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF)
5616                                 /* For customer_hw4, although ICS,
5617                                 * we still support concurrent mode
5618                                 */
5619                                 return ret;
5620 #else
5621                                 return 0;
5622 #endif
5623                         }
5624                 }
5625         }
5626         return 0;
5627 }
5628 #endif
5629
5630 #ifdef SUPPORT_AP_POWERSAVE
5631 #define RXCHAIN_PWRSAVE_PPS                     10
5632 #define RXCHAIN_PWRSAVE_QUIET_TIME              10
5633 #define RXCHAIN_PWRSAVE_STAS_ASSOC_CHECK        0
5634 int dhd_set_ap_powersave(dhd_pub_t *dhdp, int ifidx, int enable)
5635 {
5636         char iovbuf[128];
5637         int32 pps = RXCHAIN_PWRSAVE_PPS;
5638         int32 quiet_time = RXCHAIN_PWRSAVE_QUIET_TIME;
5639         int32 stas_assoc_check = RXCHAIN_PWRSAVE_STAS_ASSOC_CHECK;
5640
5641         if (enable) {
5642                 bcm_mkiovar("rxchain_pwrsave_enable", (char *)&enable, 4, iovbuf, sizeof(iovbuf));
5643                 if (dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR,
5644                     iovbuf, sizeof(iovbuf), TRUE, 0) != BCME_OK) {
5645                         DHD_ERROR(("Failed to enable AP power save\n"));
5646                 }
5647                 bcm_mkiovar("rxchain_pwrsave_pps", (char *)&pps, 4, iovbuf, sizeof(iovbuf));
5648                 if (dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR,
5649                     iovbuf, sizeof(iovbuf), TRUE, 0) != BCME_OK) {
5650                         DHD_ERROR(("Failed to set pps\n"));
5651                 }
5652                 bcm_mkiovar("rxchain_pwrsave_quiet_time", (char *)&quiet_time,
5653                 4, iovbuf, sizeof(iovbuf));
5654                 if (dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR,
5655                     iovbuf, sizeof(iovbuf), TRUE, 0) != BCME_OK) {
5656                         DHD_ERROR(("Failed to set quiet time\n"));
5657                 }
5658                 bcm_mkiovar("rxchain_pwrsave_stas_assoc_check", (char *)&stas_assoc_check,
5659                 4, iovbuf, sizeof(iovbuf));
5660                 if (dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR,
5661                     iovbuf, sizeof(iovbuf), TRUE, 0) != BCME_OK) {
5662                         DHD_ERROR(("Failed to set stas assoc check\n"));
5663                 }
5664         } else {
5665                 bcm_mkiovar("rxchain_pwrsave_enable", (char *)&enable, 4, iovbuf, sizeof(iovbuf));
5666                 if (dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR,
5667                     iovbuf, sizeof(iovbuf), TRUE, 0) != BCME_OK) {
5668                         DHD_ERROR(("Failed to disable AP power save\n"));
5669                 }
5670         }
5671
5672         return 0;
5673 }
5674 #endif /* SUPPORT_AP_POWERSAVE */
5675
5676
5677 #if defined(READ_CONFIG_FROM_FILE)
5678 #include <linux/fs.h>
5679 #include <linux/ctype.h>
5680
5681 #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
5682 bool PM_control = TRUE;
5683
5684 static int dhd_preinit_proc(dhd_pub_t *dhd, int ifidx, char *name, char *value)
5685 {
5686         int var_int;
5687         wl_country_t cspec = {{0}, -1, {0}};
5688         char *revstr;
5689         char *endptr = NULL;
5690         int iolen;
5691         char smbuf[WLC_IOCTL_SMLEN*2];
5692
5693         if (!strcmp(name, "country")) {
5694                 revstr = strchr(value, '/');
5695                 if (revstr) {
5696                         cspec.rev = strtoul(revstr + 1, &endptr, 10);
5697                         memcpy(cspec.country_abbrev, value, WLC_CNTRY_BUF_SZ);
5698                         cspec.country_abbrev[2] = '\0';
5699                         memcpy(cspec.ccode, cspec.country_abbrev, WLC_CNTRY_BUF_SZ);
5700                 } else {
5701                         cspec.rev = -1;
5702                         memcpy(cspec.country_abbrev, value, WLC_CNTRY_BUF_SZ);
5703                         memcpy(cspec.ccode, value, WLC_CNTRY_BUF_SZ);
5704                         get_customized_country_code(dhd->info->adapter,
5705                                 (char *)&cspec.country_abbrev, &cspec);
5706                 }
5707                 memset(smbuf, 0, sizeof(smbuf));
5708                 DHD_ERROR(("config country code is country : %s, rev : %d !!\n",
5709                         cspec.country_abbrev, cspec.rev));
5710                 iolen = bcm_mkiovar("country", (char*)&cspec, sizeof(cspec),
5711                         smbuf, sizeof(smbuf));
5712                 return dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
5713                         smbuf, iolen, TRUE, 0);
5714         } else if (!strcmp(name, "roam_scan_period")) {
5715                 var_int = (int)simple_strtol(value, NULL, 0);
5716                 return dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_SCAN_PERIOD,
5717                         &var_int, sizeof(var_int), TRUE, 0);
5718         } else if (!strcmp(name, "roam_delta")) {
5719                 struct {
5720                         int val;
5721                         int band;
5722                 } x;
5723                 x.val = (int)simple_strtol(value, NULL, 0);
5724                 /* x.band = WLC_BAND_AUTO; */
5725                 x.band = WLC_BAND_ALL;
5726                 return dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_DELTA, &x, sizeof(x), TRUE, 0);
5727         } else if (!strcmp(name, "roam_trigger")) {
5728                 int ret = 0;
5729
5730                 roam_trigger[0] = (int)simple_strtol(value, NULL, 0);
5731                 roam_trigger[1] = WLC_BAND_ALL;
5732                 ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_TRIGGER, &roam_trigger,
5733                         sizeof(roam_trigger), TRUE, 0);
5734
5735                 return ret;
5736         } else if (!strcmp(name, "PM")) {
5737                 int ret = 0;
5738                 var_int = (int)simple_strtol(value, NULL, 0);
5739
5740                 ret =  dhd_wl_ioctl_cmd(dhd, WLC_SET_PM,
5741                         &var_int, sizeof(var_int), TRUE, 0);
5742
5743 #if defined(CONFIG_PM_LOCK)
5744                 if (var_int == 0) {
5745                         g_pm_control = TRUE;
5746                         printk("%s var_int=%d don't control PM\n", __func__, var_int);
5747                 } else {
5748                         g_pm_control = FALSE;
5749                         printk("%s var_int=%d do control PM\n", __func__, var_int);
5750                 }
5751 #endif
5752
5753                 return ret;
5754         }
5755 #ifdef WLBTAMP
5756         else if (!strcmp(name, "btamp_chan")) {
5757                 int btamp_chan;
5758                 int iov_len = 0;
5759                 char iovbuf[128];
5760                 int ret;
5761
5762                 btamp_chan = (int)simple_strtol(value, NULL, 0);
5763                 iov_len = bcm_mkiovar("btamp_chan", (char *)&btamp_chan, 4, iovbuf, sizeof(iovbuf));
5764                 if ((ret  = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0) < 0))
5765                         DHD_ERROR(("%s btamp_chan=%d set failed code %d\n",
5766                                 __FUNCTION__, btamp_chan, ret));
5767                 else
5768                         DHD_ERROR(("%s btamp_chan %d set success\n",
5769                                 __FUNCTION__, btamp_chan));
5770         }
5771 #endif /* WLBTAMP */
5772         else if (!strcmp(name, "band")) {
5773                 int ret;
5774                 if (!strcmp(value, "auto"))
5775                         var_int = WLC_BAND_AUTO;
5776                 else if (!strcmp(value, "a"))
5777                         var_int = WLC_BAND_5G;
5778                 else if (!strcmp(value, "b"))
5779                         var_int = WLC_BAND_2G;
5780                 else if (!strcmp(value, "all"))
5781                         var_int = WLC_BAND_ALL;
5782                 else {
5783                         printk(" set band value should be one of the a or b or all\n");
5784                         var_int = WLC_BAND_AUTO;
5785                 }
5786                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_BAND, &var_int,
5787                         sizeof(var_int), TRUE, 0)) < 0)
5788                         printk(" set band err=%d\n", ret);
5789                 return ret;
5790         } else if (!strcmp(name, "cur_etheraddr")) {
5791                 struct ether_addr ea;
5792                 char buf[32];
5793                 uint iovlen;
5794                 int ret;
5795
5796                 bcm_ether_atoe(value, &ea);
5797
5798                 ret = memcmp(&ea.octet, dhd->mac.octet, ETHER_ADDR_LEN);
5799                 if (ret == 0) {
5800                         DHD_ERROR(("%s: Same Macaddr\n", __FUNCTION__));
5801                         return 0;
5802                 }
5803
5804                 DHD_ERROR(("%s: Change Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n", __FUNCTION__,
5805                         ea.octet[0], ea.octet[1], ea.octet[2],
5806                         ea.octet[3], ea.octet[4], ea.octet[5]));
5807
5808                 iovlen = bcm_mkiovar("cur_etheraddr", (char*)&ea, ETHER_ADDR_LEN, buf, 32);
5809
5810                 ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, iovlen, TRUE, 0);
5811                 if (ret < 0) {
5812                         DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
5813                         return ret;
5814                 }
5815                 else {
5816                         memcpy(dhd->mac.octet, (void *)&ea, ETHER_ADDR_LEN);
5817                         return ret;
5818                 }
5819         } else if (!strcmp(name, "lpc")) {
5820                 int ret = 0;
5821                 char buf[32];
5822                 uint iovlen;
5823                 var_int = (int)simple_strtol(value, NULL, 0);
5824                 if (dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, 0) < 0) {
5825                         DHD_ERROR(("%s: wl down failed\n", __FUNCTION__));
5826                 }
5827                 iovlen = bcm_mkiovar("lpc", (char *)&var_int, 4, buf, sizeof(buf));
5828                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, iovlen, TRUE, 0)) < 0) {
5829                         DHD_ERROR(("%s Set lpc failed  %d\n", __FUNCTION__, ret));
5830                 }
5831                 if (dhd_wl_ioctl_cmd(dhd, WLC_UP, NULL, 0, TRUE, 0) < 0) {
5832                         DHD_ERROR(("%s: wl up failed\n", __FUNCTION__));
5833                 }
5834                 return ret;
5835         } else if (!strcmp(name, "vht_features")) {
5836                 int ret = 0;
5837                 char buf[32];
5838                 uint iovlen;
5839                 var_int = (int)simple_strtol(value, NULL, 0);
5840
5841                 if (dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, 0) < 0) {
5842                         DHD_ERROR(("%s: wl down failed\n", __FUNCTION__));
5843                 }
5844                 iovlen = bcm_mkiovar("vht_features", (char *)&var_int, 4, buf, sizeof(buf));
5845                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, iovlen, TRUE, 0)) < 0) {
5846                         DHD_ERROR(("%s Set vht_features failed  %d\n", __FUNCTION__, ret));
5847                 }
5848                 if (dhd_wl_ioctl_cmd(dhd, WLC_UP, NULL, 0, TRUE, 0) < 0) {
5849                         DHD_ERROR(("%s: wl up failed\n", __FUNCTION__));
5850                 }
5851                 return ret;
5852         } else {
5853                 uint iovlen;
5854                 char iovbuf[WLC_IOCTL_SMLEN];
5855
5856                 /* wlu_iovar_setint */
5857                 var_int = (int)simple_strtol(value, NULL, 0);
5858
5859                 /* Setup timeout bcn_timeout from dhd driver 4.217.48 */
5860                 if (!strcmp(name, "roam_off")) {
5861                         /* Setup timeout if Beacons are lost to report link down */
5862                         if (var_int) {
5863                                 uint bcn_timeout = 2;
5864                                 bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4,
5865                                         iovbuf, sizeof(iovbuf));
5866                                 dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
5867                         }
5868                 }
5869                 /* Setup timeout bcm_timeout from dhd driver 4.217.48 */
5870
5871                 DHD_INFO(("%s:[%s]=[%d]\n", __FUNCTION__, name, var_int));
5872
5873                 iovlen = bcm_mkiovar(name, (char *)&var_int, sizeof(var_int),
5874                         iovbuf, sizeof(iovbuf));
5875                 return dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
5876                         iovbuf, iovlen, TRUE, 0);
5877         }
5878
5879         return 0;
5880 }
5881
5882 static int dhd_preinit_config(dhd_pub_t *dhd, int ifidx)
5883 {
5884         mm_segment_t old_fs;
5885         struct kstat stat;
5886         struct file *fp = NULL;
5887         unsigned int len;
5888         char *buf = NULL, *p, *name, *value;
5889         int ret = 0;
5890         char *config_path;
5891
5892         config_path = CONFIG_BCMDHD_CONFIG_PATH;
5893
5894         if (!config_path)
5895         {
5896                 printk(KERN_ERR "config_path can't read. \n");
5897                 return 0;
5898         }
5899
5900         old_fs = get_fs();
5901         set_fs(get_ds());
5902         if ((ret = vfs_stat(config_path, &stat))) {
5903                 set_fs(old_fs);
5904                 printk(KERN_ERR "%s: Failed to get information (%d)\n",
5905                         config_path, ret);
5906                 return ret;
5907         }
5908         set_fs(old_fs);
5909
5910         if (!(buf = MALLOC(dhd->osh, stat.size + 1))) {
5911                 printk(KERN_ERR "Failed to allocate memory %llu bytes\n", stat.size);
5912                 return -ENOMEM;
5913         }
5914
5915         printk("dhd_preinit_config : config path : %s \n", config_path);
5916
5917         if (!(fp = dhd_os_open_image(config_path)) ||
5918                 (len = dhd_os_get_image_block(buf, stat.size, fp)) < 0)
5919                 goto err;
5920
5921         buf[stat.size] = '\0';
5922         for (p = buf; *p; p++) {
5923                 if (isspace(*p))
5924                         continue;
5925                 for (name = p++; *p && !isspace(*p); p++) {
5926                         if (*p == '=') {
5927                                 *p = '\0';
5928                                 p++;
5929                                 for (value = p; *p && !isspace(*p); p++);
5930                                 *p = '\0';
5931                                 if ((ret = dhd_preinit_proc(dhd, ifidx, name, value)) < 0) {
5932                                         printk(KERN_ERR "%s: %s=%s\n",
5933                                                 bcmerrorstr(ret), name, value);
5934                                 }
5935                                 break;
5936                         }
5937                 }
5938         }
5939         ret = 0;
5940
5941 out:
5942         if (fp)
5943                 dhd_os_close_image(fp);
5944         if (buf)
5945                 MFREE(dhd->osh, buf, stat.size+1);
5946         return ret;
5947
5948 err:
5949         ret = -1;
5950         goto out;
5951 }
5952 #endif /* READ_CONFIG_FROM_FILE */
5953
5954 int
5955 dhd_preinit_ioctls(dhd_pub_t *dhd)
5956 {
5957         int ret = 0;
5958         char eventmask[WL_EVENTING_MASK_LEN];
5959         char iovbuf[WL_EVENTING_MASK_LEN + 12]; /*  Room for "event_msgs" + '\0' + bitvec  */
5960         uint32 buf_key_b4_m4 = 1;
5961 #ifndef WL_CFG80211
5962         u32 up = 0;
5963 #endif
5964         uint8 msglen;
5965         eventmsgs_ext_t *eventmask_msg = NULL;
5966         char* iov_buf = NULL;
5967         int ret2 = 0;
5968 #ifdef WLAIBSS
5969         aibss_bcn_force_config_t bcn_config;
5970         uint32 aibss;
5971 #ifdef WLAIBSS_PS
5972         uint32 aibss_ps;
5973 #endif /* WLAIBSS_PS */
5974 #endif /* WLAIBSS */
5975 #if defined(BCMSUP_4WAY_HANDSHAKE) && defined(WLAN_AKM_SUITE_FT_8021X)
5976         uint32 sup_wpa = 0;
5977 #endif
5978 #if defined(CUSTOM_AMPDU_BA_WSIZE) || (defined(WLAIBSS) && \
5979         defined(CUSTOM_IBSS_AMPDU_BA_WSIZE))
5980         uint32 ampdu_ba_wsize = 0;
5981 #endif /* CUSTOM_AMPDU_BA_WSIZE ||(WLAIBSS && CUSTOM_IBSS_AMPDU_BA_WSIZE) */
5982 #if defined(CUSTOM_AMPDU_MPDU)
5983         int32 ampdu_mpdu = 0;
5984 #endif
5985 #if defined(CUSTOM_AMPDU_RELEASE)
5986         int32 ampdu_release = 0;
5987 #endif
5988 #if defined(CUSTOM_AMSDU_AGGSF)
5989         int32 amsdu_aggsf = 0;
5990 #endif
5991
5992 #if defined(BCMSDIO)
5993 #ifdef PROP_TXSTATUS
5994         int wlfc_enable = TRUE;
5995 #ifndef DISABLE_11N
5996         uint32 hostreorder = 1;
5997         uint wl_down = 1;
5998 #endif /* DISABLE_11N */
5999 #endif /* PROP_TXSTATUS */
6000 #endif 
6001 #ifdef PCIE_FULL_DONGLE
6002         uint32 wl_ap_isolate;
6003 #endif /* PCIE_FULL_DONGLE */
6004
6005 #ifdef DHD_ENABLE_LPC
6006         uint32 lpc = 1;
6007 #endif /* DHD_ENABLE_LPC */
6008         uint power_mode = PM_FAST;
6009         uint32 dongle_align = DHD_SDALIGN;
6010 #if defined(BCMSDIO)
6011         uint32 glom = CUSTOM_GLOM_SETTING;
6012 #endif /* defined(BCMSDIO) */
6013 #if defined(CUSTOMER_HW2) && defined(USE_WL_CREDALL)
6014         uint32 credall = 1;
6015 #endif
6016         uint bcn_timeout = dhd->conf->bcn_timeout;
6017         uint retry_max = 3;
6018 #if defined(ARP_OFFLOAD_SUPPORT)
6019         int arpoe = 1;
6020 #endif
6021         int scan_assoc_time = DHD_SCAN_ASSOC_ACTIVE_TIME;
6022         int scan_unassoc_time = DHD_SCAN_UNASSOC_ACTIVE_TIME;
6023         int scan_passive_time = DHD_SCAN_PASSIVE_TIME;
6024         char buf[WLC_IOCTL_SMLEN];
6025         char *ptr;
6026         uint32 listen_interval = CUSTOM_LISTEN_INTERVAL; /* Default Listen Interval in Beacons */
6027 #ifdef ROAM_ENABLE
6028         uint roamvar = 0;
6029         int roam_trigger[2] = {CUSTOM_ROAM_TRIGGER_SETTING, WLC_BAND_ALL};
6030         int roam_scan_period[2] = {10, WLC_BAND_ALL};
6031         int roam_delta[2] = {CUSTOM_ROAM_DELTA_SETTING, WLC_BAND_ALL};
6032 #ifdef FULL_ROAMING_SCAN_PERIOD_60_SEC
6033         int roam_fullscan_period = 60;
6034 #else /* FULL_ROAMING_SCAN_PERIOD_60_SEC */
6035         int roam_fullscan_period = 120;
6036 #endif /* FULL_ROAMING_SCAN_PERIOD_60_SEC */
6037 #else
6038 #ifdef DISABLE_BUILTIN_ROAM
6039         uint roamvar = 1;
6040 #endif /* DISABLE_BUILTIN_ROAM */
6041 #endif /* ROAM_ENABLE */
6042
6043 #if defined(SOFTAP)
6044         uint dtim = 1;
6045 #endif
6046 #if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211))
6047         uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */
6048         struct ether_addr p2p_ea;
6049 #endif
6050 #ifdef BCMCCX
6051         uint32 ccx = 1;
6052 #endif
6053 #ifdef SOFTAP_UAPSD_OFF
6054         uint32 wme_apsd = 0;
6055 #endif /* SOFTAP_UAPSD_OFF */
6056 #if (defined(AP) || defined(WLP2P)) && !defined(SOFTAP_AND_GC)
6057         uint32 apsta = 1; /* Enable APSTA mode */
6058 #elif defined(SOFTAP_AND_GC)
6059         uint32 apsta = 0;
6060         int ap_mode = 1;
6061 #endif /* (defined(AP) || defined(WLP2P)) && !defined(SOFTAP_AND_GC) */
6062 #ifdef GET_CUSTOM_MAC_ENABLE
6063         struct ether_addr ea_addr;
6064 #endif /* GET_CUSTOM_MAC_ENABLE */
6065
6066 #ifdef DISABLE_11N
6067         uint32 nmode = 0;
6068 #endif /* DISABLE_11N */
6069
6070 #if defined(DISABLE_11AC)
6071         uint32 vhtmode = 0;
6072 #endif /* DISABLE_11AC */
6073 #ifdef USE_WL_TXBF
6074         uint32 txbf = 1;
6075 #endif /* USE_WL_TXBF */
6076 #ifdef AMPDU_VO_ENABLE
6077         struct ampdu_tid_control tid;
6078 #endif
6079 #ifdef USE_WL_FRAMEBURST
6080         uint32 frameburst = 1;
6081 #endif /* USE_WL_FRAMEBURST */
6082 #ifdef DHD_SET_FW_HIGHSPEED
6083         uint32 ack_ratio = 250;
6084         uint32 ack_ratio_depth = 64;
6085 #endif /* DHD_SET_FW_HIGHSPEED */
6086 #ifdef SUPPORT_2G_VHT
6087         uint32 vht_features = 0x3; /* 2G enable | rates all */
6088 #endif /* SUPPORT_2G_VHT */
6089 #ifdef CUSTOM_PSPRETEND_THR
6090         uint32 pspretend_thr = CUSTOM_PSPRETEND_THR;
6091 #endif
6092 #ifdef PKT_FILTER_SUPPORT
6093         dhd_pkt_filter_enable = TRUE;
6094 #endif /* PKT_FILTER_SUPPORT */
6095 #ifdef WLTDLS
6096         dhd->tdls_enable = FALSE;
6097 #endif /* WLTDLS */
6098         dhd->suspend_bcn_li_dtim = CUSTOM_SUSPEND_BCN_LI_DTIM;
6099         DHD_TRACE(("Enter %s\n", __FUNCTION__));
6100
6101         dhd_conf_set_band(dhd);
6102
6103         dhd->op_mode = 0;
6104         if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_MFG_MODE) ||
6105                 (op_mode == DHD_FLAG_MFG_MODE)) {
6106                 /* Check and adjust IOCTL response timeout for Manufactring firmware */
6107                 dhd_os_set_ioctl_resp_timeout(MFG_IOCTL_RESP_TIMEOUT);
6108                 DHD_ERROR(("%s : Set IOCTL response time for Manufactring Firmware\n",
6109                         __FUNCTION__));
6110         }
6111         else {
6112                 dhd_os_set_ioctl_resp_timeout(IOCTL_RESP_TIMEOUT);
6113                 DHD_INFO(("%s : Set IOCTL response time.\n", __FUNCTION__));
6114         }
6115 #ifdef GET_CUSTOM_MAC_ENABLE
6116         ret = wifi_platform_get_mac_addr(dhd->info->adapter, ea_addr.octet);
6117         if (!ret) {
6118                 memset(buf, 0, sizeof(buf));
6119                 bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN, buf, sizeof(buf));
6120                 ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
6121                 if (ret < 0) {
6122                         DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
6123                         ret = BCME_NOTUP;
6124                         goto done;
6125                 }
6126                 memcpy(dhd->mac.octet, ea_addr.octet, ETHER_ADDR_LEN);
6127         } else {
6128 #endif /* GET_CUSTOM_MAC_ENABLE */
6129                 /* Get the default device MAC address directly from firmware */
6130                 memset(buf, 0, sizeof(buf));
6131                 bcm_mkiovar("cur_etheraddr", 0, 0, buf, sizeof(buf));
6132                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf),
6133                         FALSE, 0)) < 0) {
6134                         DHD_ERROR(("%s: can't get MAC address , error=%d\n", __FUNCTION__, ret));
6135                         ret = BCME_NOTUP;
6136                         goto done;
6137                 }
6138                 /* Update public MAC address after reading from Firmware */
6139                 memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN);
6140
6141 #ifdef GET_CUSTOM_MAC_ENABLE
6142         }
6143 #endif /* GET_CUSTOM_MAC_ENABLE */
6144
6145         /* get a capabilities from firmware */
6146         memset(dhd->fw_capabilities, 0, sizeof(dhd->fw_capabilities));
6147         bcm_mkiovar("cap", 0, 0, dhd->fw_capabilities, sizeof(dhd->fw_capabilities));
6148         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, dhd->fw_capabilities,
6149                 sizeof(dhd->fw_capabilities), FALSE, 0)) < 0) {
6150                 DHD_ERROR(("%s: Get Capability failed (error=%d)\n",
6151                         __FUNCTION__, ret));
6152                 goto done;
6153         }
6154         if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_HOSTAP_MODE) ||
6155                 (op_mode == DHD_FLAG_HOSTAP_MODE)) {
6156 #ifdef SET_RANDOM_MAC_SOFTAP
6157                 uint rand_mac;
6158 #endif
6159                 dhd->op_mode = DHD_FLAG_HOSTAP_MODE;
6160 #if defined(ARP_OFFLOAD_SUPPORT)
6161                         arpoe = 0;
6162 #endif
6163 #ifdef PKT_FILTER_SUPPORT
6164                         dhd_pkt_filter_enable = FALSE;
6165 #endif
6166 #ifdef SET_RANDOM_MAC_SOFTAP
6167                 SRANDOM32((uint)jiffies);
6168                 rand_mac = RANDOM32();
6169                 iovbuf[0] = 0x02;                          /* locally administered bit */
6170                 iovbuf[1] = 0x1A;
6171                 iovbuf[2] = 0x11;
6172                 iovbuf[3] = (unsigned char)(rand_mac & 0x0F) | 0xF0;
6173                 iovbuf[4] = (unsigned char)(rand_mac >> 8);
6174                 iovbuf[5] = (unsigned char)(rand_mac >> 16);
6175
6176                 bcm_mkiovar("cur_etheraddr", (void *)iovbuf, ETHER_ADDR_LEN, buf, sizeof(buf));
6177                 ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
6178                 if (ret < 0) {
6179                         DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
6180                 } else
6181                         memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN);
6182 #endif /* SET_RANDOM_MAC_SOFTAP */
6183 #if !defined(AP) && defined(WL_CFG80211)
6184                 /* Turn off MPC in AP mode */
6185                 bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
6186                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
6187                         sizeof(iovbuf), TRUE, 0)) < 0) {
6188                         DHD_ERROR(("%s mpc for HostAPD failed  %d\n", __FUNCTION__, ret));
6189                 }
6190 #endif
6191 #ifdef SUPPORT_AP_POWERSAVE
6192                 dhd_set_ap_powersave(dhd, 0, TRUE);
6193 #endif
6194 #ifdef SOFTAP_UAPSD_OFF
6195                 bcm_mkiovar("wme_apsd", (char *)&wme_apsd, 4, iovbuf, sizeof(iovbuf));
6196                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
6197                         DHD_ERROR(("%s: set wme_apsd 0 fail (error=%d)\n", __FUNCTION__, ret));
6198 #endif /* SOFTAP_UAPSD_OFF */
6199         } else if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_MFG_MODE) ||
6200                 (op_mode == DHD_FLAG_MFG_MODE)) {
6201 #if defined(ARP_OFFLOAD_SUPPORT)
6202                 arpoe = 0;
6203 #endif /* ARP_OFFLOAD_SUPPORT */
6204 #ifdef PKT_FILTER_SUPPORT
6205                 dhd_pkt_filter_enable = FALSE;
6206 #endif /* PKT_FILTER_SUPPORT */
6207                 dhd->op_mode = DHD_FLAG_MFG_MODE;
6208         } else {
6209                 uint32 concurrent_mode = 0;
6210                 if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_P2P_MODE) ||
6211                         (op_mode == DHD_FLAG_P2P_MODE)) {
6212 #if defined(ARP_OFFLOAD_SUPPORT)
6213                         arpoe = 0;
6214 #endif
6215 #ifdef PKT_FILTER_SUPPORT
6216                         dhd_pkt_filter_enable = FALSE;
6217 #endif
6218                         dhd->op_mode = DHD_FLAG_P2P_MODE;
6219                 } else if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_IBSS_MODE) ||
6220                         (op_mode == DHD_FLAG_IBSS_MODE)) {
6221                         dhd->op_mode = DHD_FLAG_IBSS_MODE;
6222                 } else
6223                         dhd->op_mode = DHD_FLAG_STA_MODE;
6224 #if !defined(AP) && defined(WLP2P)
6225                 if (dhd->op_mode != DHD_FLAG_IBSS_MODE &&
6226                         (concurrent_mode = dhd_get_concurrent_capabilites(dhd))) {
6227 #if defined(ARP_OFFLOAD_SUPPORT)
6228                         arpoe = 1;
6229 #endif
6230                         dhd->op_mode |= concurrent_mode;
6231                 }
6232
6233                 /* Check if we are enabling p2p */
6234                 if (dhd->op_mode & DHD_FLAG_P2P_MODE) {
6235                         bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
6236                         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
6237                                 iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
6238                                 DHD_ERROR(("%s APSTA for P2P failed ret= %d\n", __FUNCTION__, ret));
6239                         }
6240
6241 #if defined(SOFTAP_AND_GC)
6242                         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_AP,
6243                                 (char *)&ap_mode, sizeof(ap_mode), TRUE, 0)) < 0) {
6244                                         DHD_ERROR(("%s WLC_SET_AP failed %d\n", __FUNCTION__, ret));
6245                         }
6246 #endif
6247                         memcpy(&p2p_ea, &dhd->mac, ETHER_ADDR_LEN);
6248                         ETHER_SET_LOCALADDR(&p2p_ea);
6249                         bcm_mkiovar("p2p_da_override", (char *)&p2p_ea,
6250                                 ETHER_ADDR_LEN, iovbuf, sizeof(iovbuf));
6251                         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
6252                                 iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
6253                                 DHD_ERROR(("%s p2p_da_override ret= %d\n", __FUNCTION__, ret));
6254                         } else {
6255                                 DHD_INFO(("dhd_preinit_ioctls: p2p_da_override succeeded\n"));
6256                         }
6257                 }
6258 #else
6259                 (void)concurrent_mode;
6260 #endif 
6261         }
6262
6263         DHD_ERROR(("Firmware up: op_mode=0x%04x, MAC="MACDBG"\n",
6264                 dhd->op_mode, MAC2STRDBG(dhd->mac.octet)));
6265         /* Set Country code  */
6266         if (dhd->dhd_cspec.ccode[0] != 0) {
6267                 printf("Set country %s, revision %d\n", dhd->dhd_cspec.ccode, dhd->dhd_cspec.rev);
6268                 bcm_mkiovar("country", (char *)&dhd->dhd_cspec,
6269                         sizeof(wl_country_t), iovbuf, sizeof(iovbuf));
6270                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
6271                         printf("%s: country code setting failed %d\n", __FUNCTION__, ret);
6272         } else {
6273                 dhd_conf_set_country(dhd);
6274                 dhd_conf_fix_country(dhd);
6275         }
6276         dhd_conf_get_country(dhd, &dhd->dhd_cspec);
6277
6278 #if defined(DISABLE_11AC)
6279         bcm_mkiovar("vhtmode", (char *)&vhtmode, 4, iovbuf, sizeof(iovbuf));
6280         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
6281                 DHD_ERROR(("%s wl vhtmode 0 failed %d\n", __FUNCTION__, ret));
6282 #endif /* DISABLE_11AC */
6283
6284         /* Set Listen Interval */
6285         bcm_mkiovar("assoc_listen", (char *)&listen_interval, 4, iovbuf, sizeof(iovbuf));
6286         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
6287                 DHD_ERROR(("%s assoc_listen failed %d\n", __FUNCTION__, ret));
6288
6289 #if defined(ROAM_ENABLE) || defined(DISABLE_BUILTIN_ROAM)
6290         /* Disable built-in roaming to allowed ext supplicant to take care of roaming */
6291         bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
6292         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
6293 #endif /* ROAM_ENABLE || DISABLE_BUILTIN_ROAM */
6294 #if defined(ROAM_ENABLE)
6295         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_TRIGGER, roam_trigger,
6296                 sizeof(roam_trigger), TRUE, 0)) < 0)
6297                 DHD_ERROR(("%s: roam trigger set failed %d\n", __FUNCTION__, ret));
6298         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_SCAN_PERIOD, roam_scan_period,
6299                 sizeof(roam_scan_period), TRUE, 0)) < 0)
6300                 DHD_ERROR(("%s: roam scan period set failed %d\n", __FUNCTION__, ret));
6301         if ((dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_DELTA, roam_delta,
6302                 sizeof(roam_delta), TRUE, 0)) < 0)
6303                 DHD_ERROR(("%s: roam delta set failed %d\n", __FUNCTION__, ret));
6304         bcm_mkiovar("fullroamperiod", (char *)&roam_fullscan_period, 4, iovbuf, sizeof(iovbuf));
6305         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
6306                 DHD_ERROR(("%s: roam fullscan period set failed %d\n", __FUNCTION__, ret));
6307 #endif /* ROAM_ENABLE */
6308         dhd_conf_set_roam(dhd);
6309
6310 #ifdef BCMCCX
6311         bcm_mkiovar("ccx_enable", (char *)&ccx, 4, iovbuf, sizeof(iovbuf));
6312         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
6313 #endif /* BCMCCX */
6314 #ifdef WLTDLS
6315         /* by default TDLS on and auto mode off */
6316         _dhd_tdls_enable(dhd, true, false, NULL);
6317 #endif /* WLTDLS */
6318
6319 #ifdef DHD_ENABLE_LPC
6320         /* Set lpc 1 */
6321         bcm_mkiovar("lpc", (char *)&lpc, 4, iovbuf, sizeof(iovbuf));
6322         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
6323                 sizeof(iovbuf), TRUE, 0)) < 0) {
6324                 DHD_ERROR(("%s Set lpc failed  %d\n", __FUNCTION__, ret));
6325         }
6326 #endif /* DHD_ENABLE_LPC */
6327         dhd_conf_set_lpc(dhd);
6328
6329         /* Set PowerSave mode */
6330         if (dhd->conf->pm >= 0)
6331                 power_mode = dhd->conf->pm;
6332         dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0);
6333
6334         /* Match Host and Dongle rx alignment */
6335         bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf));
6336         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
6337
6338 #if defined(CUSTOMER_HW2) && defined(USE_WL_CREDALL)
6339         /* enable credall to reduce the chance of no bus credit happened. */
6340         bcm_mkiovar("bus:credall", (char *)&credall, 4, iovbuf, sizeof(iovbuf));
6341         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
6342 #endif
6343
6344 #if defined(BCMSDIO)
6345         if (glom != DEFAULT_GLOM_VALUE) {
6346                 DHD_INFO(("%s set glom=0x%X\n", __FUNCTION__, glom));
6347                 bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
6348                 dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
6349         }
6350 #endif /* defined(BCMSDIO) */
6351         dhd_conf_set_bus_txglom(dhd);
6352
6353         /* Setup timeout if Beacons are lost and roam is off to report link down */
6354         bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf));
6355         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
6356         /* Setup assoc_retry_max count to reconnect target AP in dongle */
6357         bcm_mkiovar("assoc_retry_max", (char *)&retry_max, 4, iovbuf, sizeof(iovbuf));
6358         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
6359 #if defined(AP) && !defined(WLP2P)
6360         /* Turn off MPC in AP mode */
6361         bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
6362         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
6363         bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
6364         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
6365 #endif /* defined(AP) && !defined(WLP2P) */
6366         dhd_conf_set_mimo_bw_cap(dhd);
6367         dhd_conf_force_wme(dhd);
6368         dhd_conf_set_stbc(dhd);
6369         dhd_conf_set_srl(dhd);
6370         dhd_conf_set_lrl(dhd);
6371         dhd_conf_set_spect(dhd);
6372
6373 #if defined(SOFTAP)
6374         if (ap_fw_loaded == TRUE) {
6375                 dhd_wl_ioctl_cmd(dhd, WLC_SET_DTIMPRD, (char *)&dtim, sizeof(dtim), TRUE, 0);
6376         }
6377 #endif 
6378
6379 #if defined(KEEP_ALIVE)
6380         {
6381         /* Set Keep Alive : be sure to use FW with -keepalive */
6382         int res;
6383
6384 #if defined(SOFTAP)
6385         if (ap_fw_loaded == FALSE)
6386 #endif 
6387                 if (!(dhd->op_mode &
6388                         (DHD_FLAG_HOSTAP_MODE | DHD_FLAG_MFG_MODE))) {
6389                         if ((res = dhd_keep_alive_onoff(dhd)) < 0)
6390                                 DHD_ERROR(("%s set keeplive failed %d\n",
6391                                 __FUNCTION__, res));
6392                 }
6393         }
6394 #endif /* defined(KEEP_ALIVE) */
6395
6396 #ifdef USE_WL_TXBF
6397         bcm_mkiovar("txbf", (char *)&txbf, 4, iovbuf, sizeof(iovbuf));
6398         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
6399                 sizeof(iovbuf), TRUE, 0)) < 0) {
6400                 DHD_ERROR(("%s Set txbf failed  %d\n", __FUNCTION__, ret));
6401         }
6402 #endif /* USE_WL_TXBF */
6403         dhd_conf_set_txbf(dhd);
6404 #ifdef USE_WL_FRAMEBURST
6405         /* Set frameburst to value */
6406         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_FAKEFRAG, (char *)&frameburst,
6407                 sizeof(frameburst), TRUE, 0)) < 0) {
6408                 DHD_ERROR(("%s Set frameburst failed  %d\n", __FUNCTION__, ret));
6409         }
6410 #endif /* USE_WL_FRAMEBURST */
6411         dhd_conf_set_frameburst(dhd);
6412 #ifdef DHD_SET_FW_HIGHSPEED
6413         /* Set ack_ratio */
6414         bcm_mkiovar("ack_ratio", (char *)&ack_ratio, 4, iovbuf, sizeof(iovbuf));
6415         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
6416                 sizeof(iovbuf), TRUE, 0)) < 0) {
6417                 DHD_ERROR(("%s Set ack_ratio failed  %d\n", __FUNCTION__, ret));
6418         }
6419
6420         /* Set ack_ratio_depth */
6421         bcm_mkiovar("ack_ratio_depth", (char *)&ack_ratio_depth, 4, iovbuf, sizeof(iovbuf));
6422         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
6423                 sizeof(iovbuf), TRUE, 0)) < 0) {
6424                 DHD_ERROR(("%s Set ack_ratio_depth failed  %d\n", __FUNCTION__, ret));
6425         }
6426 #endif /* DHD_SET_FW_HIGHSPEED */
6427 #if defined(CUSTOM_AMPDU_BA_WSIZE) || (defined(WLAIBSS) && \
6428         defined(CUSTOM_IBSS_AMPDU_BA_WSIZE))
6429         /* Set ampdu ba wsize to 64 or 16 */
6430 #ifdef CUSTOM_AMPDU_BA_WSIZE
6431         ampdu_ba_wsize = CUSTOM_AMPDU_BA_WSIZE;
6432 #endif
6433 #if defined(WLAIBSS) && defined(CUSTOM_IBSS_AMPDU_BA_WSIZE)
6434         if (dhd->op_mode == DHD_FLAG_IBSS_MODE)
6435                 ampdu_ba_wsize = CUSTOM_IBSS_AMPDU_BA_WSIZE;
6436 #endif /* WLAIBSS && CUSTOM_IBSS_AMPDU_BA_WSIZE */
6437         if (ampdu_ba_wsize != 0) {
6438                 bcm_mkiovar("ampdu_ba_wsize", (char *)&ampdu_ba_wsize, 4, iovbuf, sizeof(iovbuf));
6439                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
6440                         sizeof(iovbuf), TRUE, 0)) < 0) {
6441                         DHD_ERROR(("%s Set ampdu_ba_wsize to %d failed  %d\n",
6442                                 __FUNCTION__, ampdu_ba_wsize, ret));
6443                 }
6444         }
6445 #endif /* CUSTOM_AMPDU_BA_WSIZE || (WLAIBSS && CUSTOM_IBSS_AMPDU_BA_WSIZE) */
6446         dhd_conf_set_ampdu_ba_wsize(dhd);
6447
6448         iov_buf = (char*)kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL);
6449         if (iov_buf == NULL) {
6450                 DHD_ERROR(("failed to allocate %d bytes for iov_buf\n", WLC_IOCTL_SMLEN));
6451                 ret = BCME_NOMEM;
6452                 goto done;
6453         }
6454 #ifdef WLAIBSS
6455         /* Configure custom IBSS beacon transmission */
6456         if (dhd->op_mode & DHD_FLAG_IBSS_MODE)
6457         {
6458                 aibss = 1;
6459                 bcm_mkiovar("aibss", (char *)&aibss, 4, iovbuf, sizeof(iovbuf));
6460                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
6461                         sizeof(iovbuf), TRUE, 0)) < 0) {
6462                         DHD_ERROR(("%s Set aibss to %d failed  %d\n",
6463                                 __FUNCTION__, aibss, ret));
6464                 }
6465 #ifdef WLAIBSS_PS
6466                 aibss_ps = 1;
6467                 bcm_mkiovar("aibss_ps", (char *)&aibss_ps, 4, iovbuf, sizeof(iovbuf));
6468                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
6469                         sizeof(iovbuf), TRUE, 0)) < 0) {
6470                         DHD_ERROR(("%s Set aibss PS to %d failed  %d\n",
6471                                 __FUNCTION__, aibss, ret));
6472                 }
6473 #endif /* WLAIBSS_PS */
6474         }
6475         memset(&bcn_config, 0, sizeof(bcn_config));
6476         bcn_config.initial_min_bcn_dur = AIBSS_INITIAL_MIN_BCN_DUR;
6477         bcn_config.min_bcn_dur = AIBSS_MIN_BCN_DUR;
6478         bcn_config.bcn_flood_dur = AIBSS_BCN_FLOOD_DUR;
6479         bcn_config.version = AIBSS_BCN_FORCE_CONFIG_VER_0;
6480         bcn_config.len = sizeof(bcn_config);
6481
6482         bcm_mkiovar("aibss_bcn_force_config", (char *)&bcn_config,
6483                 sizeof(aibss_bcn_force_config_t), iov_buf, WLC_IOCTL_SMLEN);
6484         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iov_buf,
6485                 WLC_IOCTL_SMLEN, TRUE, 0)) < 0) {
6486                 DHD_ERROR(("%s Set aibss_bcn_force_config to %d, %d, %d failed %d\n",
6487                         __FUNCTION__, AIBSS_INITIAL_MIN_BCN_DUR, AIBSS_MIN_BCN_DUR,
6488                         AIBSS_BCN_FLOOD_DUR, ret));
6489         }
6490 #endif /* WLAIBSS */
6491
6492 #if defined(CUSTOM_AMPDU_MPDU)
6493         ampdu_mpdu = CUSTOM_AMPDU_MPDU;
6494         if (ampdu_mpdu != 0 && (ampdu_mpdu <= ampdu_ba_wsize)) {
6495                 bcm_mkiovar("ampdu_mpdu", (char *)&ampdu_mpdu, 4, iovbuf, sizeof(iovbuf));
6496                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
6497                         sizeof(iovbuf), TRUE, 0)) < 0) {
6498                         DHD_ERROR(("%s Set ampdu_mpdu to %d failed  %d\n",
6499                                 __FUNCTION__, CUSTOM_AMPDU_MPDU, ret));
6500                 }
6501         }
6502 #endif /* CUSTOM_AMPDU_MPDU */
6503
6504 #if defined(CUSTOM_AMPDU_RELEASE)
6505         ampdu_release = CUSTOM_AMPDU_RELEASE;
6506         if (ampdu_release != 0 && (ampdu_release <= ampdu_ba_wsize)) {
6507                 bcm_mkiovar("ampdu_release", (char *)&ampdu_release, 4, iovbuf, sizeof(iovbuf));
6508                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
6509                         sizeof(iovbuf), TRUE, 0)) < 0) {
6510                         DHD_ERROR(("%s Set ampdu_release to %d failed  %d\n",
6511                                 __FUNCTION__, CUSTOM_AMPDU_RELEASE, ret));
6512                 }
6513         }
6514 #endif /* CUSTOM_AMPDU_RELEASE */
6515
6516 #if defined(CUSTOM_AMSDU_AGGSF)
6517         amsdu_aggsf = CUSTOM_AMSDU_AGGSF;
6518         if (amsdu_aggsf != 0) {
6519                 bcm_mkiovar("amsdu_aggsf", (char *)&amsdu_aggsf, 4, iovbuf, sizeof(iovbuf));
6520                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
6521                         sizeof(iovbuf), TRUE, 0)) < 0) {
6522                         DHD_ERROR(("%s Set amsdu_aggsf to %d failed  %d\n",
6523                                 __FUNCTION__, CUSTOM_AMSDU_AGGSF, ret));
6524                 }
6525         }
6526 #endif /* CUSTOM_AMSDU_AGGSF */
6527
6528 #if defined(BCMSUP_4WAY_HANDSHAKE) && defined(WLAN_AKM_SUITE_FT_8021X)
6529         /* Read 4-way handshake requirements */
6530         if (dhd_use_idsup == 1) {
6531                 bcm_mkiovar("sup_wpa", (char *)&sup_wpa, 4, iovbuf, sizeof(iovbuf));
6532                 ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0);
6533                 /* sup_wpa iovar returns NOTREADY status on some platforms using modularized
6534                  * in-dongle supplicant.
6535                  */
6536                 if (ret >= 0 || ret == BCME_NOTREADY)
6537                         dhd->fw_4way_handshake = TRUE;
6538                 DHD_TRACE(("4-way handshake mode is: %d\n", dhd->fw_4way_handshake));
6539         }
6540 #endif /* BCMSUP_4WAY_HANDSHAKE && WLAN_AKM_SUITE_FT_8021X */
6541 #ifdef SUPPORT_2G_VHT
6542         bcm_mkiovar("vht_features", (char *)&vht_features, 4, iovbuf, sizeof(iovbuf));
6543         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
6544                 DHD_ERROR(("%s vht_features set failed %d\n", __FUNCTION__, ret));
6545         }
6546 #endif /* SUPPORT_2G_VHT */
6547 #ifdef CUSTOM_PSPRETEND_THR
6548         /* Turn off MPC in AP mode */
6549         bcm_mkiovar("pspretend_threshold", (char *)&pspretend_thr, 4,
6550                 iovbuf, sizeof(iovbuf));
6551         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
6552                 sizeof(iovbuf), TRUE, 0)) < 0) {
6553                 DHD_ERROR(("%s pspretend_threshold for HostAPD failed  %d\n",
6554                         __FUNCTION__, ret));
6555         }
6556 #endif
6557
6558         bcm_mkiovar("buf_key_b4_m4", (char *)&buf_key_b4_m4, 4, iovbuf, sizeof(iovbuf));
6559         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
6560                 sizeof(iovbuf), TRUE, 0)) < 0) {
6561                 DHD_ERROR(("%s buf_key_b4_m4 set failed %d\n", __FUNCTION__, ret));
6562         }
6563
6564         /* Read event_msgs mask */
6565         bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
6566         if ((ret  = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0)) < 0) {
6567                 DHD_ERROR(("%s read Event mask failed %d\n", __FUNCTION__, ret));
6568                 goto done;
6569         }
6570         bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN);
6571
6572         /* Setup event_msgs */
6573         setbit(eventmask, WLC_E_SET_SSID);
6574         setbit(eventmask, WLC_E_PRUNE);
6575         setbit(eventmask, WLC_E_AUTH);
6576         setbit(eventmask, WLC_E_AUTH_IND);
6577         setbit(eventmask, WLC_E_ASSOC);
6578         setbit(eventmask, WLC_E_REASSOC);
6579         setbit(eventmask, WLC_E_REASSOC_IND);
6580         setbit(eventmask, WLC_E_DEAUTH);
6581         setbit(eventmask, WLC_E_DEAUTH_IND);
6582         setbit(eventmask, WLC_E_DISASSOC_IND);
6583         setbit(eventmask, WLC_E_DISASSOC);
6584         setbit(eventmask, WLC_E_JOIN);
6585         setbit(eventmask, WLC_E_START);
6586         setbit(eventmask, WLC_E_ASSOC_IND);
6587         setbit(eventmask, WLC_E_PSK_SUP);
6588         setbit(eventmask, WLC_E_LINK);
6589         setbit(eventmask, WLC_E_NDIS_LINK);
6590         setbit(eventmask, WLC_E_MIC_ERROR);
6591         setbit(eventmask, WLC_E_ASSOC_REQ_IE);
6592         setbit(eventmask, WLC_E_ASSOC_RESP_IE);
6593 #ifndef WL_CFG80211
6594         setbit(eventmask, WLC_E_PMKID_CACHE);
6595         setbit(eventmask, WLC_E_TXFAIL);
6596 #endif
6597         setbit(eventmask, WLC_E_JOIN_START);
6598         setbit(eventmask, WLC_E_SCAN_COMPLETE);
6599 #ifdef WLMEDIA_HTSF
6600         setbit(eventmask, WLC_E_HTSFSYNC);
6601 #endif /* WLMEDIA_HTSF */
6602 #ifdef PNO_SUPPORT
6603         setbit(eventmask, WLC_E_PFN_NET_FOUND);
6604         setbit(eventmask, WLC_E_PFN_BEST_BATCHING);
6605         setbit(eventmask, WLC_E_PFN_BSSID_NET_FOUND);
6606         setbit(eventmask, WLC_E_PFN_BSSID_NET_LOST);
6607 #endif /* PNO_SUPPORT */
6608         /* enable dongle roaming event */
6609         setbit(eventmask, WLC_E_ROAM);
6610         setbit(eventmask, WLC_E_BSSID);
6611 #ifdef BCMCCX
6612         setbit(eventmask, WLC_E_ADDTS_IND);
6613         setbit(eventmask, WLC_E_DELTS_IND);
6614 #endif /* BCMCCX */
6615 #ifdef WLTDLS
6616         setbit(eventmask, WLC_E_TDLS_PEER_EVENT);
6617 #endif /* WLTDLS */
6618 #ifdef WL_CFG80211
6619         setbit(eventmask, WLC_E_ESCAN_RESULT);
6620         if (dhd->op_mode & DHD_FLAG_P2P_MODE) {
6621                 setbit(eventmask, WLC_E_ACTION_FRAME_RX);
6622                 setbit(eventmask, WLC_E_P2P_DISC_LISTEN_COMPLETE);
6623         }
6624 #endif /* WL_CFG80211 */
6625 #ifdef WLAIBSS
6626         setbit(eventmask, WLC_E_AIBSS_TXFAIL);
6627 #endif /* WLAIBSS */
6628 #ifdef CUSTOMER_HW10
6629         clrbit(eventmask, WLC_E_TRACE);
6630 #else
6631         setbit(eventmask, WLC_E_TRACE);
6632 #endif
6633         /* Write updated Event mask */
6634         bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
6635         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
6636                 DHD_ERROR(("%s Set Event mask failed %d\n", __FUNCTION__, ret));
6637                 goto done;
6638         }
6639
6640         /* make up event mask ext message iovar for event larger than 128 */
6641         msglen = ROUNDUP(WLC_E_LAST, NBBY)/NBBY + EVENTMSGS_EXT_STRUCT_SIZE;
6642         eventmask_msg = (eventmsgs_ext_t*)kmalloc(msglen, GFP_KERNEL);
6643         if (eventmask_msg == NULL) {
6644                 DHD_ERROR(("failed to allocate %d bytes for event_msg_ext\n", msglen));
6645                 ret = BCME_NOMEM;
6646                 goto done;
6647         }
6648         bzero(eventmask_msg, msglen);
6649         eventmask_msg->ver = EVENTMSGS_VER;
6650         eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY;
6651
6652         /* Read event_msgs_ext mask */
6653         bcm_mkiovar("event_msgs_ext", (char *)eventmask_msg, msglen, iov_buf, WLC_IOCTL_SMLEN);
6654         ret2  = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iov_buf, WLC_IOCTL_SMLEN, FALSE, 0);
6655         if (ret2 != BCME_UNSUPPORTED)
6656                 ret = ret2;
6657         if (ret2 == 0) { /* event_msgs_ext must be supported */
6658                 bcopy(iov_buf, eventmask_msg, msglen);
6659
6660 #ifdef BT_WIFI_HANDOVER
6661                 setbit(eventmask_msg->mask, WLC_E_BT_WIFI_HANDOVER_REQ);
6662 #endif /* BT_WIFI_HANDOVER */
6663
6664                 /* Write updated Event mask */
6665                 eventmask_msg->ver = EVENTMSGS_VER;
6666                 eventmask_msg->command = EVENTMSGS_SET_MASK;
6667                 eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY;
6668                 bcm_mkiovar("event_msgs_ext", (char *)eventmask_msg,
6669                         msglen, iov_buf, WLC_IOCTL_SMLEN);
6670                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
6671                         iov_buf, WLC_IOCTL_SMLEN, TRUE, 0)) < 0) {
6672                         DHD_ERROR(("%s write event mask ext failed %d\n", __FUNCTION__, ret));
6673                         goto done;
6674                 }
6675         } else if (ret2 < 0 && ret2 != BCME_UNSUPPORTED) {
6676                 DHD_ERROR(("%s read event mask ext failed %d\n", __FUNCTION__, ret2));
6677                 goto done;
6678         } /* unsupported is ok */
6679
6680         dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_CHANNEL_TIME, (char *)&scan_assoc_time,
6681                 sizeof(scan_assoc_time), TRUE, 0);
6682         dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time,
6683                 sizeof(scan_unassoc_time), TRUE, 0);
6684         dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_PASSIVE_TIME, (char *)&scan_passive_time,
6685                 sizeof(scan_passive_time), TRUE, 0);
6686
6687 #ifdef ARP_OFFLOAD_SUPPORT
6688         /* Set and enable ARP offload feature for STA only  */
6689 #if defined(SOFTAP)
6690         if (arpoe && !ap_fw_loaded)
6691 #else
6692         if (arpoe)
6693 #endif
6694         {
6695                 dhd_arp_offload_enable(dhd, TRUE);
6696                 dhd_arp_offload_set(dhd, dhd_arp_mode);
6697         } else {
6698                 dhd_arp_offload_enable(dhd, FALSE);
6699                 dhd_arp_offload_set(dhd, 0);
6700         }
6701         dhd_arp_enable = arpoe;
6702 #endif /* ARP_OFFLOAD_SUPPORT */
6703
6704 #ifdef PKT_FILTER_SUPPORT
6705         /* Setup default defintions for pktfilter , enable in suspend */
6706         dhd->pktfilter_count = 6;
6707         /* Setup filter to allow only unicast */
6708         if (dhd_master_mode) {
6709                 dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 0x01 0x00";
6710                 dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = NULL;
6711                 dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = NULL;
6712                 dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = NULL;
6713                 /* Add filter to pass multicastDNS packet and NOT filter out as Broadcast */
6714                 dhd->pktfilter[DHD_MDNS_FILTER_NUM] = "104 0 0 0 0xFFFFFFFFFFFF 0x01005E0000FB";
6715                 /* apply APP pktfilter */
6716                 dhd->pktfilter[DHD_ARP_FILTER_NUM] = "105 0 0 12 0xFFFF 0x0806";
6717         } else
6718                 dhd_conf_discard_pkt_filter(dhd);
6719         dhd_conf_add_pkt_filter(dhd);
6720
6721 #if defined(SOFTAP)
6722         if (ap_fw_loaded) {
6723                 dhd_enable_packet_filter(0, dhd);
6724         }
6725 #endif /* defined(SOFTAP) */
6726         dhd_set_packet_filter(dhd);
6727 #endif /* PKT_FILTER_SUPPORT */
6728 #ifdef DISABLE_11N
6729         bcm_mkiovar("nmode", (char *)&nmode, 4, iovbuf, sizeof(iovbuf));
6730         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
6731                 DHD_ERROR(("%s wl nmode 0 failed %d\n", __FUNCTION__, ret));
6732 #endif /* DISABLE_11N */
6733
6734 #ifdef AMPDU_VO_ENABLE
6735         tid.tid = PRIO_8021D_VO; /* Enable TID(6) for voice */
6736         tid.enable = TRUE;
6737         bcm_mkiovar("ampdu_tid", (char *)&tid, sizeof(tid), iovbuf, sizeof(iovbuf));
6738         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
6739
6740         tid.tid = PRIO_8021D_NC; /* Enable TID(7) for voice */
6741         tid.enable = TRUE;
6742         bcm_mkiovar("ampdu_tid", (char *)&tid, sizeof(tid), iovbuf, sizeof(iovbuf));
6743         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
6744 #endif
6745 #if defined(SOFTAP_TPUT_ENHANCE)
6746         if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
6747                 dhd_bus_setidletime(dhd, (int)100);
6748 #ifdef DHDTCPACK_SUPPRESS
6749                 dhd->tcpack_sup_enabled = FALSE;
6750 #endif
6751 #if defined(DHD_TCP_WINSIZE_ADJUST)
6752                 dhd_use_tcp_window_size_adjust = TRUE;
6753 #endif
6754
6755                 memset(buf, 0, sizeof(buf));
6756                 bcm_mkiovar("bus:txglom_auto_control", 0, 0, buf, sizeof(buf));
6757                 if ((ret  = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), FALSE, 0)) < 0) {
6758                         glom = 0;
6759                         bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
6760                         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
6761                 }
6762                 else {
6763                         if (buf[0] == 0) {
6764                                 glom = 1;
6765                                 bcm_mkiovar("bus:txglom_auto_control", (char *)&glom, 4, iovbuf,
6766                                 sizeof(iovbuf));
6767                                 dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
6768                         }
6769                 }
6770         }
6771 #endif /* SOFTAP_TPUT_ENHANCE */
6772
6773         /* query for 'ver' to get version info from firmware */
6774         memset(buf, 0, sizeof(buf));
6775         ptr = buf;
6776         bcm_mkiovar("ver", (char *)&buf, 4, buf, sizeof(buf));
6777         if ((ret  = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), FALSE, 0)) < 0)
6778                 DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret));
6779         else {
6780                 bcmstrtok(&ptr, "\n", 0);
6781                 /* Print fw version info */
6782                 DHD_ERROR(("Firmware version = %s\n", buf));
6783                 dhd_set_version_info(dhd, buf);
6784         }
6785
6786 #if defined(BCMSDIO)
6787         dhd_txglom_enable(dhd, dhd->conf->bus_rxglom);
6788 #endif /* defined(BCMSDIO) */
6789
6790         dhd_conf_set_disable_proptx(dhd);
6791 #if defined(BCMSDIO)
6792 #ifdef PROP_TXSTATUS
6793         if (disable_proptx ||
6794 #ifdef PROP_TXSTATUS_VSDB
6795                 /* enable WLFC only if the firmware is VSDB when it is in STA mode */
6796                 (dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
6797                  dhd->op_mode != DHD_FLAG_IBSS_MODE) ||
6798 #endif /* PROP_TXSTATUS_VSDB */
6799                 FALSE) {
6800                 wlfc_enable = FALSE;
6801         }
6802
6803 #ifndef DISABLE_11N
6804         ret = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, (char *)&wl_down, sizeof(wl_down), TRUE, 0);
6805         bcm_mkiovar("ampdu_hostreorder", (char *)&hostreorder, 4, iovbuf, sizeof(iovbuf));
6806         if ((ret2 = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
6807                 DHD_ERROR(("%s wl ampdu_hostreorder failed %d\n", __FUNCTION__, ret2));
6808                 if (ret2 != BCME_UNSUPPORTED)
6809                         ret = ret2;
6810                 if (ret2 != BCME_OK)
6811                         hostreorder = 0;
6812         }
6813 #endif /* DISABLE_11N */
6814
6815 #ifdef READ_CONFIG_FROM_FILE
6816         dhd_preinit_config(dhd, 0);
6817 #endif /* READ_CONFIG_FROM_FILE */
6818
6819         if (wlfc_enable)
6820                 dhd_wlfc_init(dhd);
6821 #ifndef DISABLE_11N
6822         else if (hostreorder)
6823                 dhd_wlfc_hostreorder_init(dhd);
6824 #endif /* DISABLE_11N */
6825
6826 #endif /* PROP_TXSTATUS */
6827 #endif /* BCMSDIO || BCMBUS */
6828 #ifdef PCIE_FULL_DONGLE
6829         /* For FD we need all the packets at DHD to handle intra-BSS forwarding */
6830         if (FW_SUPPORTED(dhd, ap)) {
6831                 wl_ap_isolate = AP_ISOLATE_SENDUP_ALL;
6832                 bcm_mkiovar("ap_isolate", (char *)&wl_ap_isolate, 4, iovbuf, sizeof(iovbuf));
6833                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
6834                         DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret));
6835         }
6836 #endif /* PCIE_FULL_DONGLE */
6837 #ifdef PNO_SUPPORT
6838         if (!dhd->pno_state) {
6839                 dhd_pno_init(dhd);
6840         }
6841 #endif
6842 #ifdef WL11U
6843         dhd_interworking_enable(dhd);
6844 #endif /* WL11U */
6845 #ifndef WL_CFG80211
6846         dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0);
6847 #endif
6848
6849 done:
6850
6851         if (eventmask_msg)
6852                 kfree(eventmask_msg);
6853         if (iov_buf)
6854                 kfree(iov_buf);
6855
6856         return ret;
6857 }
6858
6859
6860 int
6861 dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, int set)
6862 {
6863         char buf[strlen(name) + 1 + cmd_len];
6864         int len = sizeof(buf);
6865         wl_ioctl_t ioc;
6866         int ret;
6867
6868         len = bcm_mkiovar(name, cmd_buf, cmd_len, buf, len);
6869
6870         memset(&ioc, 0, sizeof(ioc));
6871
6872         ioc.cmd = set? WLC_SET_VAR : WLC_GET_VAR;
6873         ioc.buf = buf;
6874         ioc.len = len;
6875         ioc.set = set;
6876
6877         ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len);
6878         if (!set && ret >= 0)
6879                 memcpy(cmd_buf, buf, cmd_len);
6880
6881         return ret;
6882 }
6883
6884 int dhd_change_mtu(dhd_pub_t *dhdp, int new_mtu, int ifidx)
6885 {
6886         struct dhd_info *dhd = dhdp->info;
6887         struct net_device *dev = NULL;
6888
6889         ASSERT(dhd && dhd->iflist[ifidx]);
6890         dev = dhd->iflist[ifidx]->net;
6891         ASSERT(dev);
6892
6893         if (netif_running(dev)) {
6894                 DHD_ERROR(("%s: Must be down to change its MTU\n", dev->name));
6895                 return BCME_NOTDOWN;
6896         }
6897
6898 #define DHD_MIN_MTU 1500
6899 #define DHD_MAX_MTU 1752
6900
6901         if ((new_mtu < DHD_MIN_MTU) || (new_mtu > DHD_MAX_MTU)) {
6902                 DHD_ERROR(("%s: MTU size %d is invalid.\n", __FUNCTION__, new_mtu));
6903                 return BCME_BADARG;
6904         }
6905
6906         dev->mtu = new_mtu;
6907         return 0;
6908 }
6909
6910 #ifdef ARP_OFFLOAD_SUPPORT
6911 /* add or remove AOE host ip(s) (up to 8 IPs on the interface)  */
6912 void
6913 aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx)
6914 {
6915         u32 ipv4_buf[MAX_IPV4_ENTRIES]; /* temp save for AOE host_ip table */
6916         int i;
6917         int ret;
6918
6919         bzero(ipv4_buf, sizeof(ipv4_buf));
6920
6921         /* display what we've got */
6922         ret = dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx);
6923         DHD_ARPOE(("%s: hostip table read from Dongle:\n", __FUNCTION__));
6924 #ifdef AOE_DBG
6925         dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */
6926 #endif
6927         /* now we saved hoste_ip table, clr it in the dongle AOE */
6928         dhd_aoe_hostip_clr(dhd_pub, idx);
6929
6930         if (ret) {
6931                 DHD_ERROR(("%s failed\n", __FUNCTION__));
6932                 return;
6933         }
6934
6935         for (i = 0; i < MAX_IPV4_ENTRIES; i++) {
6936                 if (add && (ipv4_buf[i] == 0)) {
6937                                 ipv4_buf[i] = ipa;
6938                                 add = FALSE; /* added ipa to local table  */
6939                                 DHD_ARPOE(("%s: Saved new IP in temp arp_hostip[%d]\n",
6940                                 __FUNCTION__, i));
6941                 } else if (ipv4_buf[i] == ipa) {
6942                         ipv4_buf[i]     = 0;
6943                         DHD_ARPOE(("%s: removed IP:%x from temp table %d\n",
6944                                 __FUNCTION__, ipa, i));
6945                 }
6946
6947                 if (ipv4_buf[i] != 0) {
6948                         /* add back host_ip entries from our local cache */
6949                         dhd_arp_offload_add_ip(dhd_pub, ipv4_buf[i], idx);
6950                         DHD_ARPOE(("%s: added IP:%x to dongle arp_hostip[%d]\n\n",
6951                                 __FUNCTION__, ipv4_buf[i], i));
6952                 }
6953         }
6954 #ifdef AOE_DBG
6955         /* see the resulting hostip table */
6956         dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx);
6957         DHD_ARPOE(("%s: read back arp_hostip table:\n", __FUNCTION__));
6958         dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */
6959 #endif
6960 }
6961
6962 /*
6963  * Notification mechanism from kernel to our driver. This function is called by the Linux kernel
6964  * whenever there is an event related to an IP address.
6965  * ptr : kernel provided pointer to IP address that has changed
6966  */
6967 static int dhd_inetaddr_notifier_call(struct notifier_block *this,
6968         unsigned long event,
6969         void *ptr)
6970 {
6971         struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
6972
6973         dhd_info_t *dhd;
6974         dhd_pub_t *dhd_pub;
6975         int idx;
6976
6977         if (!dhd_arp_enable)
6978                 return NOTIFY_DONE;
6979         if (!ifa || !(ifa->ifa_dev->dev))
6980                 return NOTIFY_DONE;
6981
6982 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
6983         /* Filter notifications meant for non Broadcom devices */
6984         if ((ifa->ifa_dev->dev->netdev_ops != &dhd_ops_pri) &&
6985             (ifa->ifa_dev->dev->netdev_ops != &dhd_ops_virt)) {
6986 #if defined(WL_ENABLE_P2P_IF)
6987                 if (!wl_cfgp2p_is_ifops(ifa->ifa_dev->dev->netdev_ops))
6988 #endif /* WL_ENABLE_P2P_IF */
6989                         return NOTIFY_DONE;
6990         }
6991 #endif /* LINUX_VERSION_CODE */
6992
6993         dhd = DHD_DEV_INFO(ifa->ifa_dev->dev);
6994         if (!dhd)
6995                 return NOTIFY_DONE;
6996
6997         dhd_pub = &dhd->pub;
6998
6999         if (dhd_pub->arp_version == 1) {
7000                 idx = 0;
7001         }
7002         else {
7003                 for (idx = 0; idx < DHD_MAX_IFS; idx++) {
7004                         if (dhd->iflist[idx] && dhd->iflist[idx]->net == ifa->ifa_dev->dev)
7005                         break;
7006                 }
7007                 if (idx < DHD_MAX_IFS)
7008                         DHD_TRACE(("ifidx : %p %s %d\n", dhd->iflist[idx]->net,
7009                                 dhd->iflist[idx]->name, dhd->iflist[idx]->idx));
7010                 else {
7011                         DHD_ERROR(("Cannot find ifidx for(%s) set to 0\n", ifa->ifa_label));
7012                         idx = 0;
7013                 }
7014         }
7015
7016         switch (event) {
7017                 case NETDEV_UP:
7018                         DHD_ARPOE(("%s: [%s] Up IP: 0x%x\n",
7019                                 __FUNCTION__, ifa->ifa_label, ifa->ifa_address));
7020
7021                         if (dhd->pub.busstate != DHD_BUS_DATA) {
7022                                 DHD_ERROR(("%s: bus not ready, exit\n", __FUNCTION__));
7023                                 if (dhd->pend_ipaddr) {
7024                                         DHD_ERROR(("%s: overwrite pending ipaddr: 0x%x\n",
7025                                                 __FUNCTION__, dhd->pend_ipaddr));
7026                                 }
7027                                 dhd->pend_ipaddr = ifa->ifa_address;
7028                                 break;
7029                         }
7030
7031 #ifdef AOE_IP_ALIAS_SUPPORT
7032                         DHD_ARPOE(("%s:add aliased IP to AOE hostip cache\n",
7033                                 __FUNCTION__));
7034                         aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE, idx);
7035 #endif /* AOE_IP_ALIAS_SUPPORT */
7036                         break;
7037
7038                 case NETDEV_DOWN:
7039                         DHD_ARPOE(("%s: [%s] Down IP: 0x%x\n",
7040                                 __FUNCTION__, ifa->ifa_label, ifa->ifa_address));
7041                         dhd->pend_ipaddr = 0;
7042 #ifdef AOE_IP_ALIAS_SUPPORT
7043                         DHD_ARPOE(("%s:interface is down, AOE clr all for this if\n",
7044                                 __FUNCTION__));
7045                         aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, FALSE, idx);
7046 #else
7047                         dhd_aoe_hostip_clr(&dhd->pub, idx);
7048                         dhd_aoe_arp_clr(&dhd->pub, idx);
7049 #endif /* AOE_IP_ALIAS_SUPPORT */
7050                         break;
7051
7052                 default:
7053                         DHD_ARPOE(("%s: do noting for [%s] Event: %lu\n",
7054                                 __func__, ifa->ifa_label, event));
7055                         break;
7056         }
7057         return NOTIFY_DONE;
7058 }
7059 #endif /* ARP_OFFLOAD_SUPPORT */
7060
7061 #ifdef CONFIG_IPV6
7062 /* Neighbor Discovery Offload: defered handler */
7063 static void
7064 dhd_inet6_work_handler(void *dhd_info, void *event_data, u8 event)
7065 {
7066         struct ipv6_work_info_t *ndo_work = (struct ipv6_work_info_t *)event_data;
7067         dhd_pub_t       *pub = &((dhd_info_t *)dhd_info)->pub;
7068         int             ret;
7069
7070         if (event != DHD_WQ_WORK_IPV6_NDO) {
7071                 DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
7072                 return;
7073         }
7074
7075         if (!ndo_work) {
7076                 DHD_ERROR(("%s: ipv6 work info is not initialized \n", __FUNCTION__));
7077                 return;
7078         }
7079
7080         if (!pub) {
7081                 DHD_ERROR(("%s: dhd pub is not initialized \n", __FUNCTION__));
7082                 return;
7083         }
7084
7085         if (ndo_work->if_idx) {
7086                 DHD_ERROR(("%s: idx %d \n", __FUNCTION__, ndo_work->if_idx));
7087                 return;
7088         }
7089
7090         switch (ndo_work->event) {
7091                 case NETDEV_UP:
7092                         DHD_TRACE(("%s: Enable NDO and add ipv6 into table \n", __FUNCTION__));
7093                         ret = dhd_ndo_enable(pub, TRUE);
7094                         if (ret < 0) {
7095                                 DHD_ERROR(("%s: Enabling NDO Failed %d\n", __FUNCTION__, ret));
7096                         }
7097
7098                         ret = dhd_ndo_add_ip(pub, &ndo_work->ipv6_addr[0], ndo_work->if_idx);
7099                         if (ret < 0) {
7100                                 DHD_ERROR(("%s: Adding host ip for NDO failed %d\n",
7101                                         __FUNCTION__, ret));
7102                         }
7103                         break;
7104                 case NETDEV_DOWN:
7105                         DHD_TRACE(("%s: clear ipv6 table \n", __FUNCTION__));
7106                         ret = dhd_ndo_remove_ip(pub, ndo_work->if_idx);
7107                         if (ret < 0) {
7108                                 DHD_ERROR(("%s: Removing host ip for NDO failed %d\n",
7109                                         __FUNCTION__, ret));
7110                                 goto done;
7111                         }
7112
7113                         ret = dhd_ndo_enable(pub, FALSE);
7114                         if (ret < 0) {
7115                                 DHD_ERROR(("%s: disabling NDO Failed %d\n", __FUNCTION__, ret));
7116                                 goto done;
7117                         }
7118                         break;
7119                 default:
7120                         DHD_ERROR(("%s: unknown notifier event \n", __FUNCTION__));
7121                         break;
7122         }
7123 done:
7124         /* free ndo_work. alloced while scheduling the work */
7125         kfree(ndo_work);
7126
7127         return;
7128 }
7129
7130 /*
7131  * Neighbor Discovery Offload: Called when an interface
7132  * is assigned with ipv6 address.
7133  * Handles only primary interface
7134  */
7135 static int dhd_inet6addr_notifier_call(struct notifier_block *this,
7136         unsigned long event,
7137         void *ptr)
7138 {
7139         dhd_info_t *dhd;
7140         dhd_pub_t *dhd_pub;
7141         struct inet6_ifaddr *inet6_ifa = ptr;
7142         struct in6_addr *ipv6_addr = &inet6_ifa->addr;
7143         struct ipv6_work_info_t *ndo_info;
7144         int idx = 0; /* REVISIT */
7145
7146 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
7147         /* Filter notifications meant for non Broadcom devices */
7148         if (inet6_ifa->idev->dev->netdev_ops != &dhd_ops_pri) {
7149                         return NOTIFY_DONE;
7150         }
7151 #endif /* LINUX_VERSION_CODE */
7152
7153         dhd = DHD_DEV_INFO(inet6_ifa->idev->dev);
7154         if (!dhd)
7155                 return NOTIFY_DONE;
7156
7157         if (dhd->iflist[idx] && dhd->iflist[idx]->net != inet6_ifa->idev->dev)
7158                 return NOTIFY_DONE;
7159         dhd_pub = &dhd->pub;
7160         if (!FW_SUPPORTED(dhd_pub, ndoe))
7161                 return NOTIFY_DONE;
7162
7163         ndo_info = (struct ipv6_work_info_t *)kzalloc(sizeof(struct ipv6_work_info_t), GFP_ATOMIC);
7164         if (!ndo_info) {
7165                 DHD_ERROR(("%s: ipv6 work alloc failed\n", __FUNCTION__));
7166                 return NOTIFY_DONE;
7167         }
7168
7169         ndo_info->event = event;
7170         ndo_info->if_idx = idx;
7171         memcpy(&ndo_info->ipv6_addr[0], ipv6_addr, IPV6_ADDR_LEN);
7172
7173         /* defer the work to thread as it may block kernel */
7174         dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)ndo_info, DHD_WQ_WORK_IPV6_NDO,
7175                 dhd_inet6_work_handler, DHD_WORK_PRIORITY_LOW);
7176         return NOTIFY_DONE;
7177 }
7178 #endif /* #ifdef CONFIG_IPV6 */
7179
7180 int
7181 dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock)
7182 {
7183         dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
7184         dhd_if_t *ifp;
7185         struct net_device *net = NULL;
7186         int err = 0;
7187         uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33 };
7188
7189         DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx));
7190
7191         ASSERT(dhd && dhd->iflist[ifidx]);
7192         ifp = dhd->iflist[ifidx];
7193         net = ifp->net;
7194         ASSERT(net && (ifp->idx == ifidx));
7195
7196 #ifndef  P2PONEINT
7197 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
7198         ASSERT(!net->open);
7199         net->get_stats = dhd_get_stats;
7200         net->do_ioctl = dhd_ioctl_entry;
7201         net->hard_start_xmit = dhd_start_xmit;
7202         net->set_mac_address = dhd_set_mac_address;
7203         net->set_multicast_list = dhd_set_multicast_list;
7204         net->open = net->stop = NULL;
7205 #else
7206         ASSERT(!net->netdev_ops);
7207         net->netdev_ops = &dhd_ops_virt;
7208 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */
7209 #else
7210         net->netdev_ops = &dhd_cfgp2p_ops_virt;
7211 #endif /* P2PONEINT */
7212
7213         /* Ok, link into the network layer... */
7214         if (ifidx == 0) {
7215                 /*
7216                  * device functions for the primary interface only
7217                  */
7218 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
7219                 net->open = dhd_open;
7220                 net->stop = dhd_stop;
7221 #else
7222                 net->netdev_ops = &dhd_ops_pri;
7223 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */
7224                 if (!ETHER_ISNULLADDR(dhd->pub.mac.octet))
7225                         memcpy(temp_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN);
7226         } else {
7227                 /*
7228                  * We have to use the primary MAC for virtual interfaces
7229                  */
7230                 memcpy(temp_addr, ifp->mac_addr, ETHER_ADDR_LEN);
7231                 /*
7232                  * Android sets the locally administered bit to indicate that this is a
7233                  * portable hotspot.  This will not work in simultaneous AP/STA mode,
7234                  * nor with P2P.  Need to set the Donlge's MAC address, and then use that.
7235                  */
7236                 if (!memcmp(temp_addr, dhd->iflist[0]->mac_addr,
7237                         ETHER_ADDR_LEN)) {
7238                         DHD_ERROR(("%s interface [%s]: set locally administered bit in MAC\n",
7239                         __func__, net->name));
7240                         temp_addr[0] |= 0x02;
7241                 }
7242         }
7243
7244         net->hard_header_len = ETH_HLEN + dhd->pub.hdrlen;
7245 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
7246         net->ethtool_ops = &dhd_ethtool_ops;
7247 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */
7248
7249 #if defined(WL_WIRELESS_EXT)
7250 #if WIRELESS_EXT < 19
7251         net->get_wireless_stats = dhd_get_wireless_stats;
7252 #endif /* WIRELESS_EXT < 19 */
7253 #if WIRELESS_EXT > 12
7254         net->wireless_handlers = (struct iw_handler_def *)&wl_iw_handler_def;
7255 #endif /* WIRELESS_EXT > 12 */
7256 #endif /* defined(WL_WIRELESS_EXT) */
7257
7258         dhd->pub.rxsz = DBUS_RX_BUFFER_SIZE_DHD(net);
7259
7260         memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN);
7261
7262         if (ifidx == 0)
7263                 printf("%s\n", dhd_version);
7264
7265         if (need_rtnl_lock)
7266                 err = register_netdev(net);
7267         else
7268                 err = register_netdevice(net);
7269
7270         if (err != 0) {
7271                 DHD_ERROR(("couldn't register the net device [%s], err %d\n", net->name, err));
7272                 goto fail;
7273         }
7274
7275 #ifdef SET_RPS_CPUS
7276         err = custom_rps_map_set(net->_rx, RPS_CPUS_MASK, strlen(RPS_CPUS_MASK));
7277         if (err < 0)
7278                 DHD_ERROR(("%s : custom_rps_map_set done. error : %d\n", __FUNCTION__, err));
7279 #endif /* SET_RPS_CPUS */
7280
7281
7282
7283         printf("Register interface [%s]  MAC: "MACDBG"\n\n", net->name,
7284                 MAC2STRDBG(net->dev_addr));
7285
7286 #if defined(SOFTAP) && defined(WL_WIRELESS_EXT) && !defined(WL_CFG80211)
7287 //              wl_iw_iscan_set_scan_broadcast_prep(net, 1);
7288 #endif
7289
7290 #if 1 && (defined(BCMPCIE) || (defined(BCMLXSDMMC) && (LINUX_VERSION_CODE >= \
7291         KERNEL_VERSION(2, 6, 27))))
7292         if (ifidx == 0) {
7293 #ifdef BCMLXSDMMC
7294                 up(&dhd_registration_sem);
7295 #endif
7296                 if (!dhd_download_fw_on_driverload) {
7297                         dhd_net_bus_devreset(net, TRUE);
7298 #ifdef BCMLXSDMMC
7299                         dhd_net_bus_suspend(net);
7300 #endif /* BCMLXSDMMC */
7301                         wifi_platform_set_power(dhdp->info->adapter, FALSE, WIFI_TURNOFF_DELAY);
7302                 }
7303         }
7304 #endif /* OEM_ANDROID && (BCMPCIE || (BCMLXSDMMC && KERNEL_VERSION >= 2.6.27)) */
7305         return 0;
7306
7307 fail:
7308 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
7309         net->open = NULL;
7310 #else
7311         net->netdev_ops = NULL;
7312 #endif
7313         return err;
7314 }
7315
7316 void
7317 dhd_bus_detach(dhd_pub_t *dhdp)
7318 {
7319         dhd_info_t *dhd;
7320
7321         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7322
7323         if (dhdp) {
7324                 dhd = (dhd_info_t *)dhdp->info;
7325                 if (dhd) {
7326
7327                         /*
7328                          * In case of Android cfg80211 driver, the bus is down in dhd_stop,
7329                          *  calling stop again will cuase SD read/write errors.
7330                          */
7331                         if (dhd->pub.busstate != DHD_BUS_DOWN) {
7332                                 /* Stop the protocol module */
7333                                 dhd_prot_stop(&dhd->pub);
7334
7335                                 /* Stop the bus module */
7336                                 dhd_bus_stop(dhd->pub.bus, TRUE);
7337                         }
7338
7339 #if defined(OOB_INTR_ONLY) || defined(BCMPCIE_OOB_HOST_WAKE)
7340                         dhd_bus_oob_intr_unregister(dhdp);
7341 #endif 
7342                 }
7343         }
7344 }
7345
7346
7347 void dhd_detach(dhd_pub_t *dhdp)
7348 {
7349         dhd_info_t *dhd;
7350         unsigned long flags;
7351         int timer_valid = FALSE;
7352
7353         if (!dhdp)
7354                 return;
7355
7356         dhd = (dhd_info_t *)dhdp->info;
7357         if (!dhd)
7358                 return;
7359
7360 #if defined(CUSTOMER_HW20) && defined(WLANAUDIO)
7361         dhd_global = NULL;
7362 #endif /* CUSTOMER_HW20 && WLANAUDIO */
7363
7364         DHD_TRACE(("%s: Enter state 0x%x\n", __FUNCTION__, dhd->dhd_state));
7365
7366         dhd->pub.up = 0;
7367         if (!(dhd->dhd_state & DHD_ATTACH_STATE_DONE)) {
7368                 /* Give sufficient time for threads to start running in case
7369                  * dhd_attach() has failed
7370                  */
7371                 OSL_SLEEP(100);
7372         }
7373
7374         if (dhd->dhd_state & DHD_ATTACH_STATE_PROT_ATTACH) {
7375                 dhd_bus_detach(dhdp);
7376 #ifdef PCIE_FULL_DONGLE
7377                 dhd_flow_rings_deinit(dhdp);
7378 #endif
7379
7380                 if (dhdp->prot)
7381                         dhd_prot_detach(dhdp);
7382         }
7383
7384 #ifdef ARP_OFFLOAD_SUPPORT
7385         if (dhd_inetaddr_notifier_registered) {
7386                 dhd_inetaddr_notifier_registered = FALSE;
7387                 unregister_inetaddr_notifier(&dhd_inetaddr_notifier);
7388         }
7389 #endif /* ARP_OFFLOAD_SUPPORT */
7390 #ifdef CONFIG_IPV6
7391         if (dhd_inet6addr_notifier_registered) {
7392                 dhd_inet6addr_notifier_registered = FALSE;
7393                 unregister_inet6addr_notifier(&dhd_inet6addr_notifier);
7394         }
7395 #endif
7396
7397 #if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
7398         if (dhd->dhd_state & DHD_ATTACH_STATE_EARLYSUSPEND_DONE) {
7399                 if (dhd->early_suspend.suspend)
7400                         unregister_early_suspend(&dhd->early_suspend);
7401         }
7402 #endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */
7403
7404 #if defined(WL_WIRELESS_EXT)
7405         if (dhd->dhd_state & DHD_ATTACH_STATE_WL_ATTACH) {
7406                 /* Detatch and unlink in the iw */
7407                 wl_iw_detach();
7408         }
7409 #endif /* defined(WL_WIRELESS_EXT) */
7410
7411         /* delete all interfaces, start with virtual  */
7412         if (dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) {
7413                 int i = 1;
7414                 dhd_if_t *ifp;
7415
7416                 /* Cleanup virtual interfaces */
7417                 dhd_net_if_lock_local(dhd);
7418                 for (i = 1; i < DHD_MAX_IFS; i++) {
7419                         if (dhd->iflist[i])
7420                                 dhd_remove_if(&dhd->pub, i, TRUE);
7421                 }
7422                 dhd_net_if_unlock_local(dhd);
7423
7424                 /*  delete primary interface 0 */
7425                 ifp = dhd->iflist[0];
7426                 ASSERT(ifp);
7427                 ASSERT(ifp->net);
7428                 if (ifp && ifp->net) {
7429
7430
7431
7432                         /* in unregister_netdev case, the interface gets freed by net->destructor
7433                          * (which is set to free_netdev)
7434                          */
7435                         if (ifp->net->reg_state == NETREG_UNINITIALIZED)
7436                                 free_netdev(ifp->net);
7437                         else {
7438 #ifdef SET_RPS_CPUS
7439                                 custom_rps_map_clear(ifp->net->_rx);
7440 #endif /* SET_RPS_CPUS */
7441                                 unregister_netdev(ifp->net);
7442                         }
7443                         ifp->net = NULL;
7444 #ifdef DHD_WMF
7445                         dhd_wmf_cleanup(dhdp, 0);
7446 #endif /* DHD_WMF */
7447
7448                         dhd_if_del_sta_list(ifp);
7449
7450                         MFREE(dhd->pub.osh, ifp, sizeof(*ifp));
7451                         dhd->iflist[0] = NULL;
7452                 }
7453         }
7454
7455         /* Clear the watchdog timer */
7456         DHD_GENERAL_LOCK(&dhd->pub, flags);
7457         timer_valid = dhd->wd_timer_valid;
7458         dhd->wd_timer_valid = FALSE;
7459         DHD_GENERAL_UNLOCK(&dhd->pub, flags);
7460         if (timer_valid)
7461                 del_timer_sync(&dhd->timer);
7462
7463         if (dhd->dhd_state & DHD_ATTACH_STATE_THREADS_CREATED) {
7464                 if (dhd->thr_wdt_ctl.thr_pid >= 0) {
7465                         PROC_STOP(&dhd->thr_wdt_ctl);
7466                 }
7467
7468                 if (dhd->rxthread_enabled && dhd->thr_rxf_ctl.thr_pid >= 0) {
7469                         PROC_STOP(&dhd->thr_rxf_ctl);
7470                 }
7471
7472                 if (dhd->thr_dpc_ctl.thr_pid >= 0) {
7473                         PROC_STOP(&dhd->thr_dpc_ctl);
7474                 } else
7475                         tasklet_kill(&dhd->tasklet);
7476         }
7477 #ifdef WL_CFG80211
7478         if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) {
7479                 wl_cfg80211_detach(NULL);
7480                 dhd_monitor_uninit();
7481         }
7482 #endif
7483         /* free deferred work queue */
7484         dhd_deferred_work_deinit(dhd->dhd_deferred_wq);
7485         dhd->dhd_deferred_wq = NULL;
7486
7487 #ifdef SHOW_LOGTRACE
7488         if (dhd->event_data.fmts)
7489                 kfree(dhd->event_data.fmts);
7490         if (dhd->event_data.raw_fmts)
7491                 kfree(dhd->event_data.raw_fmts);
7492 #endif /* SHOW_LOGTRACE */
7493
7494 #ifdef PNO_SUPPORT
7495         if (dhdp->pno_state)
7496                 dhd_pno_deinit(dhdp);
7497 #endif
7498 #if defined(CONFIG_PM_SLEEP)
7499         if (dhd_pm_notifier_registered) {
7500                 unregister_pm_notifier(&dhd_pm_notifier);
7501                 dhd_pm_notifier_registered = FALSE;
7502         }
7503 #endif /* CONFIG_PM_SLEEP */
7504 #ifdef DEBUG_CPU_FREQ
7505                 if (dhd->new_freq)
7506                         free_percpu(dhd->new_freq);
7507                 dhd->new_freq = NULL;
7508                 cpufreq_unregister_notifier(&dhd->freq_trans, CPUFREQ_TRANSITION_NOTIFIER);
7509 #endif
7510         if (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) {
7511                 DHD_TRACE(("wd wakelock count:%d\n", dhd->wakelock_wd_counter));
7512 #ifdef CONFIG_HAS_WAKELOCK
7513                 dhd->wakelock_counter = 0;
7514                 dhd->wakelock_wd_counter = 0;
7515                 dhd->wakelock_rx_timeout_enable = 0;
7516                 dhd->wakelock_ctrl_timeout_enable = 0;
7517                 wake_lock_destroy(&dhd->wl_wifi);
7518                 wake_lock_destroy(&dhd->wl_rxwake);
7519                 wake_lock_destroy(&dhd->wl_ctrlwake);
7520                 wake_lock_destroy(&dhd->wl_wdwake);
7521 #ifdef BCMPCIE_OOB_HOST_WAKE
7522                 wake_lock_destroy(&dhd->wl_intrwake);
7523 #endif /* BCMPCIE_OOB_HOST_WAKE */
7524 #endif /* CONFIG_HAS_WAKELOCK */
7525         }
7526
7527
7528
7529
7530 #ifdef DHDTCPACK_SUPPRESS
7531         /* This will free all MEM allocated for TCPACK SUPPRESS */
7532         dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_OFF);
7533 #endif /* DHDTCPACK_SUPPRESS */
7534         dhd_conf_detach(dhdp);
7535 }
7536
7537
7538 void
7539 dhd_free(dhd_pub_t *dhdp)
7540 {
7541         dhd_info_t *dhd;
7542         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7543
7544         if (dhdp) {
7545                 int i;
7546                 for (i = 0; i < ARRAYSIZE(dhdp->reorder_bufs); i++) {
7547                         if (dhdp->reorder_bufs[i]) {
7548                                 reorder_info_t *ptr;
7549                                 uint32 buf_size = sizeof(struct reorder_info);
7550
7551                                 ptr = dhdp->reorder_bufs[i];
7552
7553                                 buf_size += ((ptr->max_idx + 1) * sizeof(void*));
7554                                 DHD_REORDER(("free flow id buf %d, maxidx is %d, buf_size %d\n",
7555                                         i, ptr->max_idx, buf_size));
7556
7557                                 MFREE(dhdp->osh, dhdp->reorder_bufs[i], buf_size);
7558                                 dhdp->reorder_bufs[i] = NULL;
7559                         }
7560                 }
7561
7562                 dhd_sta_pool_fini(dhdp, DHD_MAX_STA);
7563
7564                 dhd = (dhd_info_t *)dhdp->info;
7565                 /* If pointer is allocated by dhd_os_prealloc then avoid MFREE */
7566                 if (dhd &&
7567                         dhd != (dhd_info_t *)dhd_os_prealloc(dhdp, DHD_PREALLOC_DHD_INFO, 0, FALSE))
7568                         MFREE(dhd->pub.osh, dhd, sizeof(*dhd));
7569                 dhd = NULL;
7570         }
7571 }
7572
7573 void
7574 dhd_clear(dhd_pub_t *dhdp)
7575 {
7576         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7577
7578         if (dhdp) {
7579                 int i;
7580                 for (i = 0; i < ARRAYSIZE(dhdp->reorder_bufs); i++) {
7581                         if (dhdp->reorder_bufs[i]) {
7582                                 reorder_info_t *ptr;
7583                                 uint32 buf_size = sizeof(struct reorder_info);
7584
7585                                 ptr = dhdp->reorder_bufs[i];
7586
7587                                 buf_size += ((ptr->max_idx + 1) * sizeof(void*));
7588                                 DHD_REORDER(("free flow id buf %d, maxidx is %d, buf_size %d\n",
7589                                         i, ptr->max_idx, buf_size));
7590
7591                                 MFREE(dhdp->osh, dhdp->reorder_bufs[i], buf_size);
7592                                 dhdp->reorder_bufs[i] = NULL;
7593                         }
7594                 }
7595
7596                 dhd_sta_pool_clear(dhdp, DHD_MAX_STA);
7597         }
7598 }
7599
7600 static void
7601 dhd_module_cleanup(void)
7602 {
7603         printk("%s: Enter\n", __FUNCTION__);
7604
7605         dhd_bus_unregister();
7606
7607         wl_android_exit();
7608
7609         dhd_wifi_platform_unregister_drv();
7610         printk("%s: Exit\n", __FUNCTION__);
7611 }
7612
7613 static void 
7614 dhd_module_exit(void)
7615 {
7616         dhd_module_cleanup();
7617         unregister_reboot_notifier(&dhd_reboot_notifier);
7618 }
7619
7620 static int 
7621 dhd_module_init(void)
7622 {
7623         int err;
7624         int retry = POWERUP_MAX_RETRY;
7625
7626         printk("%s: in\n", __FUNCTION__);
7627
7628         DHD_PERIM_RADIO_INIT();
7629
7630         if (firmware_path[0] != '\0') {
7631                 strncpy(fw_bak_path, firmware_path, MOD_PARAM_PATHLEN);
7632                 fw_bak_path[MOD_PARAM_PATHLEN-1] = '\0';
7633         }
7634
7635         if (nvram_path[0] != '\0') {
7636                 strncpy(nv_bak_path, nvram_path, MOD_PARAM_PATHLEN);
7637                 nv_bak_path[MOD_PARAM_PATHLEN-1] = '\0';
7638         }
7639
7640         do {
7641                 err = dhd_wifi_platform_register_drv();
7642                 if (!err) {
7643                         register_reboot_notifier(&dhd_reboot_notifier);
7644                         break;
7645                 }
7646                 else {
7647                         DHD_ERROR(("%s: Failed to load the driver, try cnt %d\n",
7648                                 __FUNCTION__, retry));
7649                         strncpy(firmware_path, fw_bak_path, MOD_PARAM_PATHLEN);
7650                         firmware_path[MOD_PARAM_PATHLEN-1] = '\0';
7651                         strncpy(nvram_path, nv_bak_path, MOD_PARAM_PATHLEN);
7652                         nvram_path[MOD_PARAM_PATHLEN-1] = '\0';
7653                 }
7654         } while (retry--);
7655
7656         if (err)
7657                 DHD_ERROR(("%s: Failed to load driver max retry reached**\n", __FUNCTION__));
7658
7659         printk("%s: Exit err=%d\n", __FUNCTION__, err);
7660         return err;
7661 }
7662
7663 static int
7664 dhd_reboot_callback(struct notifier_block *this, unsigned long code, void *unused)
7665 {
7666         DHD_TRACE(("%s: code = %ld\n", __FUNCTION__, code));
7667         if (code == SYS_RESTART) {
7668         }
7669
7670         return NOTIFY_DONE;
7671 }
7672
7673 #include <linux/rfkill-wlan.h>
7674 extern int get_wifi_chip_type(void);
7675 extern char WIFI_MODULE_NAME[];
7676 extern char RKWIFI_DRV_VERSION[];
7677
7678 #ifdef CONFIG_WIFI_LOAD_DRIVER_WHEN_KERNEL_BOOTUP
7679 static int wifi_init_thread(void *data)
7680 {
7681     dhd_module_init();
7682     return 0;
7683 }
7684 #endif
7685
7686 int rockchip_wifi_init_module_rkwifi(void)
7687 {
7688 #ifdef CONFIG_WIFI_LOAD_DRIVER_WHEN_KERNEL_BOOTUP
7689     int type = get_wifi_chip_type();
7690     if (type > WIFI_AP6XXX_SERIES) return 0;
7691 #endif
7692     printk("=======================================================\n");
7693     printk("==== Launching Wi-Fi driver! (Powered by Rockchip) ====\n");
7694     printk("=======================================================\n");
7695     printk("%s WiFi driver (Powered by Rockchip,Ver %s) init.\n", WIFI_MODULE_NAME, RKWIFI_DRV_VERSION);
7696
7697 #ifdef CONFIG_WIFI_LOAD_DRIVER_WHEN_KERNEL_BOOTUP
7698 {
7699     struct task_struct *kthread = kthread_run(wifi_init_thread, NULL, "wifi_init_thread");
7700     if (kthread->pid < 0)
7701         printk("create wifi_init_thread failed.\n");
7702     return 0; 
7703 }
7704 #else
7705     return dhd_module_init();
7706 #endif
7707 }
7708
7709 void rockchip_wifi_exit_module_rkwifi(void)
7710 {
7711 #ifdef CONFIG_WIFI_LOAD_DRIVER_WHEN_KERNEL_BOOTUP
7712     int type = get_wifi_chip_type();    
7713     if (type > WIFI_AP6XXX_SERIES) return;
7714 #endif
7715     printk("=======================================================\n");
7716     printk("== Dis-launching Wi-Fi driver! (Powered by Rockchip) ==\n");
7717     printk("=======================================================\n");
7718     dhd_module_exit();
7719 }
7720
7721 #ifdef CONFIG_WIFI_LOAD_DRIVER_WHEN_KERNEL_BOOTUP
7722 late_initcall(rockchip_wifi_init_module_rkwifi);
7723 module_exit(rockchip_wifi_exit_module_rkwifi);
7724 #else
7725 EXPORT_SYMBOL(rockchip_wifi_init_module_rkwifi);
7726 EXPORT_SYMBOL(rockchip_wifi_exit_module_rkwifi);
7727 #endif
7728 //#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
7729 //#if defined(CONFIG_DEFERRED_INITCALLS)
7730 //deferred_module_init(dhd_module_init);
7731 //#elif defined(USE_LATE_INITCALL_SYNC)
7732 //late_initcall_sync(dhd_module_init);
7733 //#else
7734 //late_initcall(dhd_module_init);
7735 //#endif /* USE_LATE_INITCALL_SYNC */
7736 //#else
7737 //module_init(dhd_module_init);
7738 //#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */
7739 //
7740 //module_exit(dhd_module_exit);
7741
7742 /*
7743  * OS specific functions required to implement DHD driver in OS independent way
7744  */
7745 int
7746 dhd_os_proto_block(dhd_pub_t *pub)
7747 {
7748         dhd_info_t * dhd = (dhd_info_t *)(pub->info);
7749
7750         if (dhd) {
7751                 DHD_PERIM_UNLOCK(pub);
7752
7753                 down(&dhd->proto_sem);
7754
7755                 DHD_PERIM_LOCK(pub);
7756                 return 1;
7757         }
7758
7759         return 0;
7760 }
7761
7762 int
7763 dhd_os_proto_unblock(dhd_pub_t *pub)
7764 {
7765         dhd_info_t * dhd = (dhd_info_t *)(pub->info);
7766
7767         if (dhd) {
7768                 up(&dhd->proto_sem);
7769                 return 1;
7770         }
7771
7772         return 0;
7773 }
7774
7775 unsigned int
7776 dhd_os_get_ioctl_resp_timeout(void)
7777 {
7778         return ((unsigned int)dhd_ioctl_timeout_msec);
7779 }
7780
7781 void
7782 dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec)
7783 {
7784         dhd_ioctl_timeout_msec = (int)timeout_msec;
7785 }
7786
7787 int
7788 dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending)
7789 {
7790         dhd_info_t * dhd = (dhd_info_t *)(pub->info);
7791         int timeout;
7792
7793         /* Convert timeout in millsecond to jiffies */
7794 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
7795         timeout = msecs_to_jiffies(dhd_ioctl_timeout_msec);
7796 #else
7797         timeout = dhd_ioctl_timeout_msec * HZ / 1000;
7798 #endif
7799
7800         DHD_PERIM_UNLOCK(pub);
7801
7802         timeout = wait_event_timeout(dhd->ioctl_resp_wait, (*condition), timeout);
7803
7804         DHD_PERIM_LOCK(pub);
7805
7806         return timeout;
7807 }
7808
7809 int
7810 dhd_os_ioctl_resp_wake(dhd_pub_t *pub)
7811 {
7812         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
7813
7814         wake_up(&dhd->ioctl_resp_wait);
7815         return 0;
7816 }
7817
7818 void
7819 dhd_os_wd_timer_extend(void *bus, bool extend)
7820 {
7821         dhd_pub_t *pub = bus;
7822         dhd_info_t *dhd = (dhd_info_t *)pub->info;
7823
7824         if (extend)
7825                 dhd_os_wd_timer(bus, WATCHDOG_EXTEND_INTERVAL);
7826         else
7827                 dhd_os_wd_timer(bus, dhd->default_wd_interval);
7828 }
7829
7830
7831 void
7832 dhd_os_wd_timer(void *bus, uint wdtick)
7833 {
7834         dhd_pub_t *pub = bus;
7835         dhd_info_t *dhd = (dhd_info_t *)pub->info;
7836         unsigned long flags;
7837
7838         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7839
7840         if (!dhd) {
7841                 DHD_ERROR(("%s: dhd NULL\n", __FUNCTION__));
7842                 return;
7843         }
7844
7845         DHD_GENERAL_LOCK(pub, flags);
7846
7847         /* don't start the wd until fw is loaded */
7848         if (pub->busstate == DHD_BUS_DOWN) {
7849                 DHD_GENERAL_UNLOCK(pub, flags);
7850                 if (!wdtick)
7851                         DHD_OS_WD_WAKE_UNLOCK(pub);
7852                 return;
7853         }
7854
7855         /* Totally stop the timer */
7856         if (!wdtick && dhd->wd_timer_valid == TRUE) {
7857                 dhd->wd_timer_valid = FALSE;
7858                 DHD_GENERAL_UNLOCK(pub, flags);
7859                 del_timer_sync(&dhd->timer);
7860                 DHD_OS_WD_WAKE_UNLOCK(pub);
7861                 return;
7862         }
7863
7864         if (wdtick) {
7865                 DHD_OS_WD_WAKE_LOCK(pub);
7866                 dhd_watchdog_ms = (uint)wdtick;
7867                 /* Re arm the timer, at last watchdog period */
7868                 mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms));
7869                 dhd->wd_timer_valid = TRUE;
7870         }
7871         DHD_GENERAL_UNLOCK(pub, flags);
7872 }
7873
7874 void *
7875 dhd_os_open_image(char *filename)
7876 {
7877         struct file *fp;
7878
7879         fp = filp_open(filename, O_RDONLY, 0);
7880         /*
7881          * 2.6.11 (FC4) supports filp_open() but later revs don't?
7882          * Alternative:
7883          * fp = open_namei(AT_FDCWD, filename, O_RD, 0);
7884          * ???
7885          */
7886          if (IS_ERR(fp))
7887                  fp = NULL;
7888
7889          return fp;
7890 }
7891
7892 int
7893 dhd_os_get_image_block(char *buf, int len, void *image)
7894 {
7895         struct file *fp = (struct file *)image;
7896         int rdlen;
7897
7898         if (!image)
7899                 return 0;
7900
7901         rdlen = kernel_read(fp, fp->f_pos, buf, len);
7902         if (rdlen > 0)
7903                 fp->f_pos += rdlen;
7904
7905         return rdlen;
7906 }
7907
7908 void
7909 dhd_os_close_image(void *image)
7910 {
7911         if (image)
7912                 filp_close((struct file *)image, NULL);
7913 }
7914
7915 void
7916 dhd_os_sdlock(dhd_pub_t *pub)
7917 {
7918         dhd_info_t *dhd;
7919
7920         dhd = (dhd_info_t *)(pub->info);
7921
7922         if (dhd_dpc_prio >= 0)
7923                 down(&dhd->sdsem);
7924         else
7925                 spin_lock_bh(&dhd->sdlock);
7926 }
7927
7928 void
7929 dhd_os_sdunlock(dhd_pub_t *pub)
7930 {
7931         dhd_info_t *dhd;
7932
7933         dhd = (dhd_info_t *)(pub->info);
7934
7935         if (dhd_dpc_prio >= 0)
7936                 up(&dhd->sdsem);
7937         else
7938                 spin_unlock_bh(&dhd->sdlock);
7939 }
7940
7941 void
7942 dhd_os_sdlock_txq(dhd_pub_t *pub)
7943 {
7944         dhd_info_t *dhd;
7945
7946         dhd = (dhd_info_t *)(pub->info);
7947         spin_lock_bh(&dhd->txqlock);
7948 }
7949
7950 void
7951 dhd_os_sdunlock_txq(dhd_pub_t *pub)
7952 {
7953         dhd_info_t *dhd;
7954
7955         dhd = (dhd_info_t *)(pub->info);
7956         spin_unlock_bh(&dhd->txqlock);
7957 }
7958
7959 void
7960 dhd_os_sdlock_rxq(dhd_pub_t *pub)
7961 {
7962 }
7963
7964 void
7965 dhd_os_sdunlock_rxq(dhd_pub_t *pub)
7966 {
7967 }
7968
7969 static void
7970 dhd_os_rxflock(dhd_pub_t *pub)
7971 {
7972         dhd_info_t *dhd;
7973
7974         dhd = (dhd_info_t *)(pub->info);
7975         spin_lock_bh(&dhd->rxf_lock);
7976
7977 }
7978
7979 static void
7980 dhd_os_rxfunlock(dhd_pub_t *pub)
7981 {
7982         dhd_info_t *dhd;
7983
7984         dhd = (dhd_info_t *)(pub->info);
7985         spin_unlock_bh(&dhd->rxf_lock);
7986 }
7987
7988 #ifdef DHDTCPACK_SUPPRESS
7989 void
7990 dhd_os_tcpacklock(dhd_pub_t *pub)
7991 {
7992         dhd_info_t *dhd;
7993
7994         dhd = (dhd_info_t *)(pub->info);
7995         spin_lock_bh(&dhd->tcpack_lock);
7996
7997 }
7998
7999 void
8000 dhd_os_tcpackunlock(dhd_pub_t *pub)
8001 {
8002         dhd_info_t *dhd;
8003
8004         dhd = (dhd_info_t *)(pub->info);
8005         spin_unlock_bh(&dhd->tcpack_lock);
8006 }
8007 #endif /* DHDTCPACK_SUPPRESS */
8008
8009 uint8* dhd_os_prealloc(dhd_pub_t *dhdpub, int section, uint size, bool kmalloc_if_fail)
8010 {
8011         uint8* buf;
8012         gfp_t flags = CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC;
8013
8014         buf = (uint8*)wifi_platform_prealloc(dhdpub->info->adapter, section, size);
8015         if (buf == NULL) {
8016                 DHD_ERROR(("%s: failed to alloc memory, section: %d,"
8017                         " size: %dbytes\n", __FUNCTION__, section, size));
8018                 if (kmalloc_if_fail)
8019                         buf = kmalloc(size, flags);
8020         }
8021
8022         return buf;
8023 }
8024
8025 void dhd_os_prefree(dhd_pub_t *dhdpub, void *addr, uint size)
8026 {
8027 }
8028
8029 #if defined(WL_WIRELESS_EXT)
8030 struct iw_statistics *
8031 dhd_get_wireless_stats(struct net_device *dev)
8032 {
8033         int res = 0;
8034         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8035
8036         if (!dhd->pub.up) {
8037                 return NULL;
8038         }
8039
8040         res = wl_iw_get_wireless_stats(dev, &dhd->iw.wstats);
8041
8042         if (res == 0)
8043                 return &dhd->iw.wstats;
8044         else
8045                 return NULL;
8046 }
8047 #endif /* defined(WL_WIRELESS_EXT) */
8048
8049 #if defined(CUSTOMER_HW20) && defined(WLANAUDIO)
8050 static int
8051 dhd_wlanaudio_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
8052                     wl_event_msg_t *event, void **data)
8053 {
8054         int cnt;
8055         char eabuf[ETHER_ADDR_STR_LEN];
8056         struct ether_addr *addr = &event->addr;
8057         uint32 type = ntoh32_ua((void *)&event->event_type);
8058
8059         switch (type) {
8060         case WLC_E_TXFAIL:
8061                 if (addr != NULL)
8062                         bcm_ether_ntoa(addr, eabuf);
8063                 else
8064                         return (BCME_ERROR);
8065
8066                 for (cnt = 0; cnt < MAX_WLANAUDIO_BLACKLIST; cnt++) {
8067                         if (dhd->wlanaudio_blist[cnt].is_blacklist)
8068                                 break;
8069
8070                         if (!bcmp(&dhd->wlanaudio_blist[cnt].blacklist_addr,
8071                                   addr, ETHER_ADDR_LEN)) {
8072                                 /* Mac address is Same */
8073                                 dhd->wlanaudio_blist[cnt].cnt++;
8074
8075                                 if (dhd->wlanaudio_blist[cnt].cnt < 15) {
8076                                         /* black list is false */
8077                                         if ((dhd->wlanaudio_blist[cnt].cnt > 10) &&
8078                                             (jiffies - dhd->wlanaudio_blist[cnt].txfail_jiffies
8079                                              < 100)) {
8080                                                 dhd->wlanaudio_blist[cnt].is_blacklist = true;
8081                                                 dhd->is_wlanaudio_blist = true;
8082                                         }
8083                                 } else {
8084                                         if ((!dhd->wlanaudio_blist[cnt].is_blacklist) &&
8085                                            (jiffies - dhd->wlanaudio_blist[cnt].txfail_jiffies
8086                                             > 100)) {
8087
8088                                                 bzero(&dhd->wlanaudio_blist[cnt],
8089                                                       sizeof(struct wlanaudio_blacklist));
8090                                         }
8091                                 }
8092                                 break;
8093                         } else if ((!dhd->wlanaudio_blist[cnt].is_blacklist) &&
8094                                    (!dhd->wlanaudio_blist[cnt].cnt)) {
8095                                 bcopy(addr,
8096                                       (char*)&dhd->wlanaudio_blist[cnt].blacklist_addr,
8097                                       ETHER_ADDR_LEN);
8098                                 dhd->wlanaudio_blist[cnt].cnt++;
8099                                 dhd->wlanaudio_blist[cnt].txfail_jiffies = jiffies;
8100
8101                                 bcm_ether_ntoa(&dhd->wlanaudio_blist[cnt].blacklist_addr, eabuf);
8102                                 break;
8103                         }
8104                 }
8105                 break;
8106         case WLC_E_AUTH  :
8107         case WLC_E_AUTH_IND :
8108         case WLC_E_DEAUTH :
8109         case WLC_E_DEAUTH_IND :
8110         case WLC_E_ASSOC:
8111         case WLC_E_ASSOC_IND:
8112         case WLC_E_REASSOC:
8113         case WLC_E_REASSOC_IND:
8114         case WLC_E_DISASSOC:
8115         case WLC_E_DISASSOC_IND:
8116                 {
8117                         int bl_cnt = 0;
8118
8119                         if (addr != NULL)
8120                                 bcm_ether_ntoa(addr, eabuf);
8121                         else
8122                                 return (BCME_ERROR);
8123
8124                         for (cnt = 0; cnt < MAX_WLANAUDIO_BLACKLIST; cnt++) {
8125                                 if (!bcmp(&dhd->wlanaudio_blist[cnt].blacklist_addr,
8126                                           addr, ETHER_ADDR_LEN)) {
8127                                         /* Mac address is Same */
8128                                         if (dhd->wlanaudio_blist[cnt].is_blacklist) {
8129                                                 /* black list is true */
8130                                                 bzero(&dhd->wlanaudio_blist[cnt],
8131                                                       sizeof(struct wlanaudio_blacklist));
8132                                         }
8133                                 }
8134                         }
8135
8136                         for (cnt = 0; cnt < MAX_WLANAUDIO_BLACKLIST; cnt++) {
8137                                 if (dhd->wlanaudio_blist[cnt].is_blacklist)
8138                                         bl_cnt++;
8139                         }
8140
8141                         if (!bl_cnt)
8142                         {
8143                                 dhd->is_wlanaudio_blist = false;
8144                         }
8145
8146                         break;
8147                 }
8148         }
8149         return BCME_OK;
8150 }
8151 #endif /* CUSTOMER_HW20 && WLANAUDIO */
8152 static int
8153 dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
8154         wl_event_msg_t *event, void **data)
8155 {
8156         int bcmerror = 0;
8157
8158         ASSERT(dhd != NULL);
8159
8160 #if defined(CUSTOMER_HW20) && defined(WLANAUDIO)
8161         bcmerror = dhd_wlanaudio_event(dhd, ifidx, pktdata, event, data);
8162
8163         if (bcmerror != BCME_OK)
8164                 return (bcmerror);
8165 #endif /* CUSTOMER_HW20 && WLANAUDIO */
8166
8167 #ifdef SHOW_LOGTRACE
8168         bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, event, data, &dhd->event_data);
8169 #else
8170         bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, event, data, NULL);
8171 #endif /* SHOW_LOGTRACE */
8172
8173         if (bcmerror != BCME_OK)
8174                 return (bcmerror);
8175
8176 #if defined(WL_WIRELESS_EXT)
8177         if (event->bsscfgidx == 0) {
8178                 /*
8179                  * Wireless ext is on primary interface only
8180                  */
8181
8182         ASSERT(dhd->iflist[*ifidx] != NULL);
8183         ASSERT(dhd->iflist[*ifidx]->net != NULL);
8184
8185                 if (dhd->iflist[*ifidx]->net) {
8186                 wl_iw_event(dhd->iflist[*ifidx]->net, event, *data);
8187                 }
8188         }
8189 #endif /* defined(WL_WIRELESS_EXT)  */
8190
8191 #ifdef WL_CFG80211
8192         ASSERT(dhd->iflist[*ifidx] != NULL);
8193         ASSERT(dhd->iflist[*ifidx]->net != NULL);
8194         if (dhd->iflist[*ifidx]->net)
8195                 wl_cfg80211_event(dhd->iflist[*ifidx]->net, event, *data);
8196 #endif /* defined(WL_CFG80211) */
8197
8198         return (bcmerror);
8199 }
8200
8201 /* send up locally generated event */
8202 void
8203 dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data)
8204 {
8205         switch (ntoh32(event->event_type)) {
8206 #ifdef WLBTAMP
8207         /* Send up locally generated AMP HCI Events */
8208         case WLC_E_BTA_HCI_EVENT: {
8209                 struct sk_buff *p, *skb;
8210                 bcm_event_t *msg;
8211                 wl_event_msg_t *p_bcm_event;
8212                 char *ptr;
8213                 uint32 len;
8214                 uint32 pktlen;
8215                 dhd_if_t *ifp;
8216                 dhd_info_t *dhd;
8217                 uchar *eth;
8218                 int ifidx;
8219
8220                 len = ntoh32(event->datalen);
8221                 pktlen = sizeof(bcm_event_t) + len + 2;
8222                 dhd = dhdp->info;
8223                 ifidx = dhd_ifname2idx(dhd, event->ifname);
8224
8225                 if ((p = PKTGET(dhdp->osh, pktlen, FALSE))) {
8226                         ASSERT(ISALIGNED((uintptr)PKTDATA(dhdp->osh, p), sizeof(uint32)));
8227
8228                         msg = (bcm_event_t *) PKTDATA(dhdp->osh, p);
8229
8230                         bcopy(&dhdp->mac, &msg->eth.ether_dhost, ETHER_ADDR_LEN);
8231                         bcopy(&dhdp->mac, &msg->eth.ether_shost, ETHER_ADDR_LEN);
8232                         ETHER_TOGGLE_LOCALADDR(&msg->eth.ether_shost);
8233
8234                         msg->eth.ether_type = hton16(ETHER_TYPE_BRCM);
8235
8236                         /* BCM Vendor specific header... */
8237                         msg->bcm_hdr.subtype = hton16(BCMILCP_SUBTYPE_VENDOR_LONG);
8238                         msg->bcm_hdr.version = BCMILCP_BCM_SUBTYPEHDR_VERSION;
8239                         bcopy(BRCM_OUI, &msg->bcm_hdr.oui[0], DOT11_OUI_LEN);
8240
8241                         /* vendor spec header length + pvt data length (private indication
8242                          *  hdr + actual message itself)
8243                          */
8244                         msg->bcm_hdr.length = hton16(BCMILCP_BCM_SUBTYPEHDR_MINLENGTH +
8245                                 BCM_MSG_LEN + sizeof(wl_event_msg_t) + (uint16)len);
8246                         msg->bcm_hdr.usr_subtype = hton16(BCMILCP_BCM_SUBTYPE_EVENT);
8247
8248                         PKTSETLEN(dhdp->osh, p, (sizeof(bcm_event_t) + len + 2));
8249
8250                         /* copy  wl_event_msg_t into sk_buf */
8251
8252                         /* pointer to wl_event_msg_t in sk_buf */
8253                         p_bcm_event = &msg->event;
8254                         bcopy(event, p_bcm_event, sizeof(wl_event_msg_t));
8255
8256                         /* copy hci event into sk_buf */
8257                         bcopy(data, (p_bcm_event + 1), len);
8258
8259                         msg->bcm_hdr.length  = hton16(sizeof(wl_event_msg_t) +
8260                                 ntoh16(msg->bcm_hdr.length));
8261                         PKTSETLEN(dhdp->osh, p, (sizeof(bcm_event_t) + len + 2));
8262
8263                         ptr = (char *)(msg + 1);
8264                         /* Last 2 bytes of the message are 0x00 0x00 to signal that there
8265                          * are no ethertypes which are following this
8266                          */
8267                         ptr[len+0] = 0x00;
8268                         ptr[len+1] = 0x00;
8269
8270                         skb = PKTTONATIVE(dhdp->osh, p);
8271                         eth = skb->data;
8272                         len = skb->len;
8273
8274                         ifp = dhd->iflist[ifidx];
8275                         if (ifp == NULL)
8276                              ifp = dhd->iflist[0];
8277
8278                         ASSERT(ifp);
8279                         skb->dev = ifp->net;
8280                         skb->protocol = eth_type_trans(skb, skb->dev);
8281
8282                         skb->data = eth;
8283                         skb->len = len;
8284
8285                         /* Strip header, count, deliver upward */
8286                         skb_pull(skb, ETH_HLEN);
8287
8288                         /* Send the packet */
8289                         if (in_interrupt()) {
8290                                 netif_rx(skb);
8291                         } else {
8292                                 netif_rx_ni(skb);
8293                         }
8294                 }
8295                 else {
8296                         /* Could not allocate a sk_buf */
8297                         DHD_ERROR(("%s: unable to alloc sk_buf\n", __FUNCTION__));
8298                 }
8299                 break;
8300         } /* case WLC_E_BTA_HCI_EVENT */
8301 #endif /* WLBTAMP */
8302
8303         default:
8304                 break;
8305         }
8306 }
8307
8308 #ifdef LOG_INTO_TCPDUMP
8309 void
8310 dhd_sendup_log(dhd_pub_t *dhdp, void *data, int data_len)
8311 {
8312         struct sk_buff *p, *skb;
8313         uint32 pktlen;
8314         int len;
8315         dhd_if_t *ifp;
8316         dhd_info_t *dhd;
8317         uchar *skb_data;
8318         int ifidx = 0;
8319         struct ether_header eth;
8320
8321         pktlen = sizeof(eth) + data_len;
8322         dhd = dhdp->info;
8323
8324         if ((p = PKTGET(dhdp->osh, pktlen, FALSE))) {
8325                 ASSERT(ISALIGNED((uintptr)PKTDATA(dhdp->osh, p), sizeof(uint32)));
8326
8327                 bcopy(&dhdp->mac, &eth.ether_dhost, ETHER_ADDR_LEN);
8328                 bcopy(&dhdp->mac, &eth.ether_shost, ETHER_ADDR_LEN);
8329                 ETHER_TOGGLE_LOCALADDR(&eth.ether_shost);
8330                 eth.ether_type = hton16(ETHER_TYPE_BRCM);
8331
8332                 bcopy((void *)&eth, PKTDATA(dhdp->osh, p), sizeof(eth));
8333                 bcopy(data, PKTDATA(dhdp->osh, p) + sizeof(eth), data_len);
8334                 skb = PKTTONATIVE(dhdp->osh, p);
8335                 skb_data = skb->data;
8336                 len = skb->len;
8337
8338                 ifidx = dhd_ifname2idx(dhd, "wlan0");
8339                 ifp = dhd->iflist[ifidx];
8340                 if (ifp == NULL)
8341                          ifp = dhd->iflist[0];
8342
8343                 ASSERT(ifp);
8344                 skb->dev = ifp->net;
8345                 skb->protocol = eth_type_trans(skb, skb->dev);
8346                 skb->data = skb_data;
8347                 skb->len = len;
8348
8349                 /* Strip header, count, deliver upward */
8350                 skb_pull(skb, ETH_HLEN);
8351
8352                 /* Send the packet */
8353                 if (in_interrupt()) {
8354                         netif_rx(skb);
8355                 } else {
8356                         netif_rx_ni(skb);
8357                 }
8358         }
8359         else {
8360                 /* Could not allocate a sk_buf */
8361                 DHD_ERROR(("%s: unable to alloc sk_buf\n", __FUNCTION__));
8362         }
8363 }
8364 #endif /* LOG_INTO_TCPDUMP */
8365
8366 void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar)
8367 {
8368 #if defined(BCMSDIO) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
8369         struct dhd_info *dhdinfo =  dhd->info;
8370
8371 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
8372         int timeout = msecs_to_jiffies(IOCTL_RESP_TIMEOUT);
8373 #else
8374         int timeout = (IOCTL_RESP_TIMEOUT / 1000) * HZ;
8375 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
8376
8377         dhd_os_sdunlock(dhd);
8378         wait_event_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), timeout);
8379         dhd_os_sdlock(dhd);
8380 #endif /* defined(BCMSDIO) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) */
8381         return;
8382 }
8383
8384 void dhd_wait_event_wakeup(dhd_pub_t *dhd)
8385 {
8386 #if defined(BCMSDIO) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
8387         struct dhd_info *dhdinfo =  dhd->info;
8388         if (waitqueue_active(&dhdinfo->ctrl_wait))
8389                 wake_up(&dhdinfo->ctrl_wait);
8390 #endif
8391         return;
8392 }
8393
8394 #if defined(BCMSDIO) || defined(BCMPCIE)
8395 int
8396 dhd_net_bus_devreset(struct net_device *dev, uint8 flag)
8397 {
8398         int ret = 0;
8399         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8400
8401         if (flag == TRUE) {
8402                 /* Issue wl down command before resetting the chip */
8403                 if (dhd_wl_ioctl_cmd(&dhd->pub, WLC_DOWN, NULL, 0, TRUE, 0) < 0) {
8404                         DHD_TRACE(("%s: wl down failed\n", __FUNCTION__));
8405                 }
8406 #ifdef PROP_TXSTATUS
8407                 if (dhd->pub.wlfc_enabled)
8408                         dhd_wlfc_deinit(&dhd->pub);
8409 #endif /* PROP_TXSTATUS */
8410 #ifdef PNO_SUPPORT
8411         if (dhd->pub.pno_state)
8412                 dhd_pno_deinit(&dhd->pub);
8413 #endif
8414         }
8415
8416 #ifdef BCMSDIO
8417         if (!flag) {
8418                 dhd_update_fw_nv_path(dhd);
8419                 /* update firmware and nvram path to sdio bus */
8420                 dhd_bus_update_fw_nv_path(dhd->pub.bus,
8421                         dhd->fw_path, dhd->nv_path, dhd->conf_path);
8422         }
8423 #endif /* BCMSDIO */
8424
8425         ret = dhd_bus_devreset(&dhd->pub, flag);
8426         if (ret) {
8427                 DHD_ERROR(("%s: dhd_bus_devreset: %d\n", __FUNCTION__, ret));
8428                 return ret;
8429         }
8430
8431         return ret;
8432 }
8433
8434 #ifdef BCMSDIO
8435 int
8436 dhd_net_bus_suspend(struct net_device *dev)
8437 {
8438         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8439         return dhd_bus_suspend(&dhd->pub);
8440 }
8441
8442 int
8443 dhd_net_bus_resume(struct net_device *dev, uint8 stage)
8444 {
8445         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8446         return dhd_bus_resume(&dhd->pub, stage);
8447 }
8448
8449 #endif /* BCMSDIO */
8450 #endif /* BCMSDIO || BCMPCIE */
8451
8452 int net_os_set_suspend_disable(struct net_device *dev, int val)
8453 {
8454         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8455         int ret = 0;
8456
8457         if (dhd) {
8458                 ret = dhd->pub.suspend_disable_flag;
8459                 dhd->pub.suspend_disable_flag = val;
8460         }
8461         return ret;
8462 }
8463
8464 int net_os_set_suspend(struct net_device *dev, int val, int force)
8465 {
8466         int ret = 0;
8467         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8468
8469         if (dhd) {
8470 #if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
8471                 ret = dhd_set_suspend(val, &dhd->pub);
8472 #else
8473                 ret = dhd_suspend_resume_helper(dhd, val, force);
8474 #endif
8475 #ifdef WL_CFG80211
8476                 wl_cfg80211_update_power_mode(dev);
8477 #endif
8478         }
8479         return ret;
8480 }
8481
8482 int net_os_set_suspend_bcn_li_dtim(struct net_device *dev, int val)
8483 {
8484         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8485
8486         if (dhd)
8487                 dhd->pub.suspend_bcn_li_dtim = val;
8488
8489         return 0;
8490 }
8491
8492 #ifdef PKT_FILTER_SUPPORT
8493 int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num)
8494 {
8495         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8496         char *filterp = NULL;
8497         int filter_id = 0;
8498         int ret = 0;
8499
8500         if (!dhd_master_mode)
8501                 add_remove = !add_remove;
8502
8503         if (!dhd || (num == DHD_UNICAST_FILTER_NUM) ||
8504                 (num == DHD_MDNS_FILTER_NUM))
8505                 return ret;
8506         if (num >= dhd->pub.pktfilter_count)
8507                 return -EINVAL;
8508         switch (num) {
8509                 case DHD_BROADCAST_FILTER_NUM:
8510                         filterp = "101 0 0 0 0xFFFFFFFFFFFF 0xFFFFFFFFFFFF";
8511                         filter_id = 101;
8512                         break;
8513                 case DHD_MULTICAST4_FILTER_NUM:
8514                         filterp = "102 0 0 0 0xFFFFFF 0x01005E";
8515                         filter_id = 102;
8516                         break;
8517                 case DHD_MULTICAST6_FILTER_NUM:
8518                         filterp = "103 0 0 0 0xFFFF 0x3333";
8519                         filter_id = 103;
8520                         break;
8521                 default:
8522                         return -EINVAL;
8523         }
8524
8525         /* Add filter */
8526         if (add_remove) {
8527                 dhd->pub.pktfilter[num] = filterp;
8528                 dhd_pktfilter_offload_set(&dhd->pub, dhd->pub.pktfilter[num]);
8529         } else { /* Delete filter */
8530                 if (dhd->pub.pktfilter[num] != NULL) {
8531                         dhd_pktfilter_offload_delete(&dhd->pub, filter_id);
8532                         dhd->pub.pktfilter[num] = NULL;
8533                 }
8534         }
8535         return ret;
8536 }
8537
8538 int dhd_os_enable_packet_filter(dhd_pub_t *dhdp, int val)
8539
8540 {
8541         int ret = 0;
8542
8543         /* Packet filtering is set only if we still in early-suspend and
8544          * we need either to turn it ON or turn it OFF
8545          * We can always turn it OFF in case of early-suspend, but we turn it
8546          * back ON only if suspend_disable_flag was not set
8547         */
8548         if (dhdp && dhdp->up) {
8549                 if (dhdp->in_suspend) {
8550                         if (!val || (val && !dhdp->suspend_disable_flag))
8551                                 dhd_enable_packet_filter(val, dhdp);
8552                 }
8553         }
8554         return ret;
8555 }
8556
8557 /* function to enable/disable packet for Network device */
8558 int net_os_enable_packet_filter(struct net_device *dev, int val)
8559 {
8560         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8561
8562         return dhd_os_enable_packet_filter(&dhd->pub, val);
8563 }
8564 #endif /* PKT_FILTER_SUPPORT */
8565
8566 int
8567 dhd_dev_init_ioctl(struct net_device *dev)
8568 {
8569         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8570         int ret;
8571
8572         if ((ret = dhd_sync_with_dongle(&dhd->pub)) < 0)
8573                 goto done;
8574
8575 done:
8576         return ret;
8577 }
8578
8579 #ifdef PNO_SUPPORT
8580 /* Linux wrapper to call common dhd_pno_stop_for_ssid */
8581 int
8582 dhd_dev_pno_stop_for_ssid(struct net_device *dev)
8583 {
8584         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8585
8586         return (dhd_pno_stop_for_ssid(&dhd->pub));
8587 }
8588 /* Linux wrapper to call common dhd_pno_set_for_ssid */
8589 int
8590 dhd_dev_pno_set_for_ssid(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid,
8591         uint16  scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan)
8592 {
8593         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8594
8595         return (dhd_pno_set_for_ssid(&dhd->pub, ssids_local, nssid, scan_fr,
8596                 pno_repeat, pno_freq_expo_max, channel_list, nchan));
8597 }
8598
8599 /* Linux wrapper to call common dhd_pno_enable */
8600 int
8601 dhd_dev_pno_enable(struct net_device *dev, int enable)
8602 {
8603         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8604
8605         return (dhd_pno_enable(&dhd->pub, enable));
8606 }
8607
8608 /* Linux wrapper to call common dhd_pno_set_for_hotlist */
8609 int
8610 dhd_dev_pno_set_for_hotlist(struct net_device *dev, wl_pfn_bssid_t *p_pfn_bssid,
8611         struct dhd_pno_hotlist_params *hotlist_params)
8612 {
8613         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8614         return (dhd_pno_set_for_hotlist(&dhd->pub, p_pfn_bssid, hotlist_params));
8615 }
8616 /* Linux wrapper to call common dhd_dev_pno_stop_for_batch */
8617 int
8618 dhd_dev_pno_stop_for_batch(struct net_device *dev)
8619 {
8620         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8621         return (dhd_pno_stop_for_batch(&dhd->pub));
8622 }
8623 /* Linux wrapper to call common dhd_dev_pno_set_for_batch */
8624 int
8625 dhd_dev_pno_set_for_batch(struct net_device *dev, struct dhd_pno_batch_params *batch_params)
8626 {
8627         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8628         return (dhd_pno_set_for_batch(&dhd->pub, batch_params));
8629 }
8630 /* Linux wrapper to call common dhd_dev_pno_get_for_batch */
8631 int
8632 dhd_dev_pno_get_for_batch(struct net_device *dev, char *buf, int bufsize)
8633 {
8634         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8635         return (dhd_pno_get_for_batch(&dhd->pub, buf, bufsize, PNO_STATUS_NORMAL));
8636 }
8637 #endif /* PNO_SUPPORT */
8638
8639 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (1)
8640 static void dhd_hang_process(void *dhd_info, void *event_info, u8 event)
8641 {
8642         dhd_info_t *dhd;
8643         struct net_device *dev;
8644
8645         dhd = (dhd_info_t *)dhd_info;
8646         dev = dhd->iflist[0]->net;
8647
8648         if (dev) {
8649                 rtnl_lock();
8650                 dev_close(dev);
8651                 rtnl_unlock();
8652 #if defined(WL_WIRELESS_EXT)
8653                 wl_iw_send_priv_event(dev, "HANG");
8654 #endif
8655 #if defined(WL_CFG80211)
8656                 wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED);
8657 #endif
8658         }
8659 }
8660
8661
8662 int dhd_os_send_hang_message(dhd_pub_t *dhdp)
8663 {
8664         int ret = 0;
8665         if (dhdp) {
8666                 if (!dhdp->hang_was_sent) {
8667                         dhdp->hang_was_sent = 1;
8668                         dhd_deferred_schedule_work(dhdp->info->dhd_deferred_wq, (void *)dhdp,
8669                                 DHD_WQ_WORK_HANG_MSG, dhd_hang_process, DHD_WORK_PRIORITY_HIGH);
8670                 }
8671         }
8672         return ret;
8673 }
8674
8675 int net_os_send_hang_message(struct net_device *dev)
8676 {
8677         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8678         int ret = 0;
8679
8680         if (dhd) {
8681                 /* Report FW problem when enabled */
8682                 if (dhd->pub.hang_report) {
8683 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
8684                         ret = dhd_os_send_hang_message(&dhd->pub);
8685 #else
8686                         ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED);
8687 #endif
8688                 } else {
8689                         DHD_ERROR(("%s: FW HANG ignored (for testing purpose) and not sent up\n",
8690                                 __FUNCTION__));
8691                         /* Enforce bus down to stop any future traffic */
8692                         dhd->pub.busstate = DHD_BUS_DOWN;
8693                 }
8694         }
8695         return ret;
8696 }
8697 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) && OEM_ANDROID */
8698
8699
8700 int dhd_net_wifi_platform_set_power(struct net_device *dev, bool on, unsigned long delay_msec)
8701 {
8702         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8703         return wifi_platform_set_power(dhd->adapter, on, delay_msec);
8704 }
8705
8706 void dhd_get_customized_country_code(struct net_device *dev, char *country_iso_code,
8707         wl_country_t *cspec)
8708 {
8709         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8710         get_customized_country_code(dhd->adapter, country_iso_code, cspec);
8711 }
8712 void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notify)
8713 {
8714         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8715         if (dhd && dhd->pub.up) {
8716                 memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t));
8717 #ifdef WL_CFG80211
8718                 wl_update_wiphybands(NULL, notify);
8719 #endif
8720         }
8721 }
8722
8723 void dhd_bus_band_set(struct net_device *dev, uint band)
8724 {
8725         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8726         if (dhd && dhd->pub.up) {
8727 #ifdef WL_CFG80211
8728                 wl_update_wiphybands(NULL, true);
8729 #endif
8730         }
8731 }
8732
8733 int dhd_net_set_fw_path(struct net_device *dev, char *fw)
8734 {
8735         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8736
8737         if (!fw || fw[0] == '\0')
8738                 return -EINVAL;
8739
8740         strncpy(dhd->fw_path, fw, sizeof(dhd->fw_path) - 1);
8741         dhd->fw_path[sizeof(dhd->fw_path)-1] = '\0';
8742
8743 #if defined(SOFTAP)
8744         if (strstr(fw, "apsta") != NULL) {
8745                 DHD_INFO(("GOT APSTA FIRMWARE\n"));
8746                 ap_fw_loaded = TRUE;
8747         } else {
8748                 DHD_INFO(("GOT STA FIRMWARE\n"));
8749                 ap_fw_loaded = FALSE;
8750         }
8751 #endif 
8752         return 0;
8753 }
8754
8755 void dhd_net_if_lock(struct net_device *dev)
8756 {
8757         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8758         dhd_net_if_lock_local(dhd);
8759 }
8760
8761 void dhd_net_if_unlock(struct net_device *dev)
8762 {
8763         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8764         dhd_net_if_unlock_local(dhd);
8765 }
8766
8767 static void dhd_net_if_lock_local(dhd_info_t *dhd)
8768 {
8769 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
8770         if (dhd)
8771                 mutex_lock(&dhd->dhd_net_if_mutex);
8772 #endif
8773 }
8774
8775 static void dhd_net_if_unlock_local(dhd_info_t *dhd)
8776 {
8777 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
8778         if (dhd)
8779                 mutex_unlock(&dhd->dhd_net_if_mutex);
8780 #endif
8781 }
8782
8783 static void dhd_suspend_lock(dhd_pub_t *pub)
8784 {
8785 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
8786         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
8787         if (dhd)
8788                 mutex_lock(&dhd->dhd_suspend_mutex);
8789 #endif
8790 }
8791
8792 static void dhd_suspend_unlock(dhd_pub_t *pub)
8793 {
8794 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
8795         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
8796         if (dhd)
8797                 mutex_unlock(&dhd->dhd_suspend_mutex);
8798 #endif
8799 }
8800
8801 unsigned long dhd_os_general_spin_lock(dhd_pub_t *pub)
8802 {
8803         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
8804         unsigned long flags = 0;
8805
8806         if (dhd)
8807                 spin_lock_irqsave(&dhd->dhd_lock, flags);
8808
8809         return flags;
8810 }
8811
8812 void dhd_os_general_spin_unlock(dhd_pub_t *pub, unsigned long flags)
8813 {
8814         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
8815
8816         if (dhd)
8817                 spin_unlock_irqrestore(&dhd->dhd_lock, flags);
8818 }
8819
8820 /* Linux specific multipurpose spinlock API */
8821 void *
8822 dhd_os_spin_lock_init(osl_t *osh)
8823 {
8824         /* Adding 4 bytes since the sizeof(spinlock_t) could be 0 */
8825         /* if CONFIG_SMP and CONFIG_DEBUG_SPINLOCK are not defined */
8826         /* and this results in kernel asserts in internal builds */
8827         spinlock_t * lock = MALLOC(osh, sizeof(spinlock_t) + 4);
8828         if (lock)
8829                 spin_lock_init(lock);
8830         return ((void *)lock);
8831 }
8832 void
8833 dhd_os_spin_lock_deinit(osl_t *osh, void *lock)
8834 {
8835         MFREE(osh, lock, sizeof(spinlock_t) + 4);
8836 }
8837 unsigned long
8838 dhd_os_spin_lock(void *lock)
8839 {
8840         unsigned long flags = 0;
8841
8842         if (lock)
8843                 spin_lock_irqsave((spinlock_t *)lock, flags);
8844
8845         return flags;
8846 }
8847 void
8848 dhd_os_spin_unlock(void *lock, unsigned long flags)
8849 {
8850         if (lock)
8851                 spin_unlock_irqrestore((spinlock_t *)lock, flags);
8852 }
8853
8854 static int
8855 dhd_get_pend_8021x_cnt(dhd_info_t *dhd)
8856 {
8857         return (atomic_read(&dhd->pend_8021x_cnt));
8858 }
8859
8860 #define MAX_WAIT_FOR_8021X_TX   100
8861
8862 int
8863 dhd_wait_pend8021x(struct net_device *dev)
8864 {
8865         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8866         int timeout = msecs_to_jiffies(10);
8867         int ntimes = MAX_WAIT_FOR_8021X_TX;
8868         int pend = dhd_get_pend_8021x_cnt(dhd);
8869
8870         while (ntimes && pend) {
8871                 if (pend) {
8872                         set_current_state(TASK_INTERRUPTIBLE);
8873                         DHD_PERIM_UNLOCK(&dhd->pub);
8874                         schedule_timeout(timeout);
8875                         DHD_PERIM_LOCK(&dhd->pub);
8876                         set_current_state(TASK_RUNNING);
8877                         ntimes--;
8878                 }
8879                 pend = dhd_get_pend_8021x_cnt(dhd);
8880         }
8881         if (ntimes == 0)
8882         {
8883                 atomic_set(&dhd->pend_8021x_cnt, 0);
8884                 DHD_ERROR(("%s: TIMEOUT\n", __FUNCTION__));
8885         }
8886         return pend;
8887 }
8888
8889 #ifdef DHD_DEBUG
8890 int
8891 write_to_file(dhd_pub_t *dhd, uint8 *buf, int size)
8892 {
8893         int ret = 0;
8894         struct file *fp;
8895         mm_segment_t old_fs;
8896         loff_t pos = 0;
8897
8898         /* change to KERNEL_DS address limit */
8899         old_fs = get_fs();
8900         set_fs(KERNEL_DS);
8901
8902         /* open file to write */
8903         fp = filp_open("/tmp/mem_dump", O_WRONLY|O_CREAT, 0640);
8904         if (!fp) {
8905                 printf("%s: open file error\n", __FUNCTION__);
8906                 ret = -1;
8907                 goto exit;
8908         }
8909
8910         /* Write buf to file */
8911         fp->f_op->write(fp, buf, size, &pos);
8912
8913 exit:
8914         /* free buf before return */
8915         MFREE(dhd->osh, buf, size);
8916         /* close file before return */
8917         if (fp)
8918                 filp_close(fp, current->files);
8919         /* restore previous address limit */
8920         set_fs(old_fs);
8921
8922         return ret;
8923 }
8924 #endif /* DHD_DEBUG */
8925
8926 int dhd_os_wake_lock_timeout(dhd_pub_t *pub)
8927 {
8928         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
8929         unsigned long flags;
8930         int ret = 0;
8931
8932         if (dhd) {
8933                 spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
8934                 ret = dhd->wakelock_rx_timeout_enable > dhd->wakelock_ctrl_timeout_enable ?
8935                         dhd->wakelock_rx_timeout_enable : dhd->wakelock_ctrl_timeout_enable;
8936 #ifdef CONFIG_HAS_WAKELOCK
8937                 if (dhd->wakelock_rx_timeout_enable)
8938                         wake_lock_timeout(&dhd->wl_rxwake,
8939                                 msecs_to_jiffies(dhd->wakelock_rx_timeout_enable));
8940                 if (dhd->wakelock_ctrl_timeout_enable)
8941                         wake_lock_timeout(&dhd->wl_ctrlwake,
8942                                 msecs_to_jiffies(dhd->wakelock_ctrl_timeout_enable));
8943 #endif
8944                 dhd->wakelock_rx_timeout_enable = 0;
8945                 dhd->wakelock_ctrl_timeout_enable = 0;
8946                 spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
8947         }
8948         return ret;
8949 }
8950
8951 int net_os_wake_lock_timeout(struct net_device *dev)
8952 {
8953         dhd_info_t *dhd = DHD_DEV_INFO(dev);
8954         int ret = 0;
8955
8956         if (dhd)
8957                 ret = dhd_os_wake_lock_timeout(&dhd->pub);
8958         return ret;
8959 }
8960
8961 int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val)
8962 {
8963         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
8964         unsigned long flags;
8965
8966         if (dhd) {
8967                 spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
8968                 if (val > dhd->wakelock_rx_timeout_enable)
8969                         dhd->wakelock_rx_timeout_enable = val;
8970                 spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
8971         }
8972         return 0;
8973 }
8974
8975 int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val)
8976 {
8977         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
8978         unsigned long flags;
8979
8980         if (dhd) {
8981                 spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
8982                 if (val > dhd->wakelock_ctrl_timeout_enable)
8983                         dhd->wakelock_ctrl_timeout_enable = val;
8984                 spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
8985         }
8986         return 0;
8987 }
8988
8989 int dhd_os_wake_lock_ctrl_timeout_cancel(dhd_pub_t *pub)
8990 {
8991         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
8992         unsigned long flags;
8993
8994         if (dhd) {
8995                 spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
8996                 dhd->wakelock_ctrl_timeout_enable = 0;
8997 #ifdef CONFIG_HAS_WAKELOCK
8998                 if (wake_lock_active(&dhd->wl_ctrlwake))
8999                         wake_unlock(&dhd->wl_ctrlwake);
9000 #endif
9001                 spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
9002         }
9003         return 0;
9004 }
9005
9006 int net_os_wake_lock_rx_timeout_enable(struct net_device *dev, int val)
9007 {
9008         dhd_info_t *dhd = DHD_DEV_INFO(dev);
9009         int ret = 0;
9010
9011         if (dhd)
9012                 ret = dhd_os_wake_lock_rx_timeout_enable(&dhd->pub, val);
9013         return ret;
9014 }
9015
9016 int net_os_wake_lock_ctrl_timeout_enable(struct net_device *dev, int val)
9017 {
9018         dhd_info_t *dhd = DHD_DEV_INFO(dev);
9019         int ret = 0;
9020
9021         if (dhd)
9022                 ret = dhd_os_wake_lock_ctrl_timeout_enable(&dhd->pub, val);
9023         return ret;
9024 }
9025
9026 int dhd_os_wake_lock(dhd_pub_t *pub)
9027 {
9028         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
9029         unsigned long flags;
9030         int ret = 0;
9031
9032         if (dhd) {
9033                 spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
9034
9035                 if (dhd->wakelock_counter == 0 && !dhd->waive_wakelock) {
9036 #ifdef CONFIG_HAS_WAKELOCK
9037                         wake_lock(&dhd->wl_wifi);
9038 #elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
9039                         dhd_bus_dev_pm_stay_awake(pub);
9040 #endif
9041                 }
9042                 dhd->wakelock_counter++;
9043                 ret = dhd->wakelock_counter;
9044                 spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
9045         }
9046         return ret;
9047 }
9048
9049 int net_os_wake_lock(struct net_device *dev)
9050 {
9051         dhd_info_t *dhd = DHD_DEV_INFO(dev);
9052         int ret = 0;
9053
9054         if (dhd)
9055                 ret = dhd_os_wake_lock(&dhd->pub);
9056         return ret;
9057 }
9058
9059 int dhd_os_wake_unlock(dhd_pub_t *pub)
9060 {
9061         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
9062         unsigned long flags;
9063         int ret = 0;
9064
9065         dhd_os_wake_lock_timeout(pub);
9066         if (dhd) {
9067                 spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
9068                 if (dhd->wakelock_counter > 0) {
9069                         dhd->wakelock_counter--;
9070                         if (dhd->wakelock_counter == 0 && !dhd->waive_wakelock) {
9071 #ifdef CONFIG_HAS_WAKELOCK
9072                                 wake_unlock(&dhd->wl_wifi);
9073 #elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
9074                                 dhd_bus_dev_pm_relax(pub);
9075 #endif
9076                         }
9077                         ret = dhd->wakelock_counter;
9078                 }
9079                 spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
9080         }
9081         return ret;
9082 }
9083
9084 int dhd_os_check_wakelock(dhd_pub_t *pub)
9085 {
9086 #if defined(CONFIG_HAS_WAKELOCK) || (defined(BCMSDIO) && (LINUX_VERSION_CODE > \
9087         KERNEL_VERSION(2, 6, 36)))
9088         dhd_info_t *dhd;
9089
9090         if (!pub)
9091                 return 0;
9092         dhd = (dhd_info_t *)(pub->info);
9093 #endif /* CONFIG_HAS_WAKELOCK || BCMSDIO */
9094
9095 #ifdef CONFIG_HAS_WAKELOCK
9096         /* Indicate to the SD Host to avoid going to suspend if internal locks are up */
9097         if (dhd && (wake_lock_active(&dhd->wl_wifi) ||
9098                 (wake_lock_active(&dhd->wl_wdwake))))
9099                 return 1;
9100 #elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
9101         if (dhd && (dhd->wakelock_counter > 0) && dhd_bus_dev_pm_enabled(pub))
9102                 return 1;
9103 #endif
9104         return 0;
9105 }
9106
9107 int dhd_os_check_wakelock_all(dhd_pub_t *pub)
9108 {
9109 #if defined(CONFIG_HAS_WAKELOCK) || (defined(BCMSDIO) && (LINUX_VERSION_CODE > \
9110         KERNEL_VERSION(2, 6, 36)))
9111         dhd_info_t *dhd;
9112
9113         if (!pub)
9114                 return 0;
9115         dhd = (dhd_info_t *)(pub->info);
9116 #endif /* CONFIG_HAS_WAKELOCK || BCMSDIO */
9117
9118 #ifdef CONFIG_HAS_WAKELOCK
9119         /* Indicate to the SD Host to avoid going to suspend if internal locks are up */
9120         if (dhd && (wake_lock_active(&dhd->wl_wifi) ||
9121                 wake_lock_active(&dhd->wl_wdwake) ||
9122                 wake_lock_active(&dhd->wl_rxwake) ||
9123                 wake_lock_active(&dhd->wl_ctrlwake))) {
9124                 return 1;
9125         }
9126 #elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
9127         if (dhd && (dhd->wakelock_counter > 0) && dhd_bus_dev_pm_enabled(pub))
9128                 return 1;
9129 #endif
9130         return 0;
9131 }
9132
9133 int net_os_wake_unlock(struct net_device *dev)
9134 {
9135         dhd_info_t *dhd = DHD_DEV_INFO(dev);
9136         int ret = 0;
9137
9138         if (dhd)
9139                 ret = dhd_os_wake_unlock(&dhd->pub);
9140         return ret;
9141 }
9142
9143 int dhd_os_wd_wake_lock(dhd_pub_t *pub)
9144 {
9145         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
9146         unsigned long flags;
9147         int ret = 0;
9148
9149         if (dhd) {
9150                 spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
9151 #ifdef CONFIG_HAS_WAKELOCK
9152                 /* if wakelock_wd_counter was never used : lock it at once */
9153                 if (!dhd->wakelock_wd_counter)
9154                         wake_lock(&dhd->wl_wdwake);
9155 #endif
9156                 dhd->wakelock_wd_counter++;
9157                 ret = dhd->wakelock_wd_counter;
9158                 spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
9159         }
9160         return ret;
9161 }
9162
9163 int dhd_os_wd_wake_unlock(dhd_pub_t *pub)
9164 {
9165         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
9166         unsigned long flags;
9167         int ret = 0;
9168
9169         if (dhd) {
9170                 spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
9171                 if (dhd->wakelock_wd_counter) {
9172                         dhd->wakelock_wd_counter = 0;
9173 #ifdef CONFIG_HAS_WAKELOCK
9174                         wake_unlock(&dhd->wl_wdwake);
9175 #endif
9176                 }
9177                 spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
9178         }
9179         return ret;
9180 }
9181
9182 #ifdef BCMPCIE_OOB_HOST_WAKE
9183 int dhd_os_oob_irq_wake_lock_timeout(dhd_pub_t *pub, int val)
9184 {
9185         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
9186         int ret = 0;
9187
9188         if (dhd) {
9189 #ifdef CONFIG_HAS_WAKELOCK
9190                 wake_lock_timeout(&dhd->wl_intrwake, msecs_to_jiffies(val));
9191 #endif
9192         }
9193         return ret;
9194 }
9195
9196 int dhd_os_oob_irq_wake_unlock(dhd_pub_t *pub)
9197 {
9198         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
9199         int ret = 0;
9200
9201         if (dhd) {
9202 #ifdef CONFIG_HAS_WAKELOCK
9203                 /* if wl_intrwake is active, unlock it */
9204                 if (wake_lock_active(&dhd->wl_intrwake)) {
9205                         wake_unlock(&dhd->wl_intrwake);
9206                 }
9207 #endif
9208         }
9209         return ret;
9210 }
9211 #endif /* BCMPCIE_OOB_HOST_WAKE */
9212
9213 /* waive wakelocks for operations such as IOVARs in suspend function, must be closed
9214  * by a paired function call to dhd_wakelock_restore. returns current wakelock counter
9215  */
9216 int dhd_os_wake_lock_waive(dhd_pub_t *pub)
9217 {
9218         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
9219         unsigned long flags;
9220         int ret = 0;
9221
9222         if (dhd) {
9223                 spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
9224                 /* dhd_wakelock_waive/dhd_wakelock_restore must be paired */
9225                 if (dhd->waive_wakelock == FALSE) {
9226                         /* record current lock status */
9227                         dhd->wakelock_before_waive = dhd->wakelock_counter;
9228                         dhd->waive_wakelock = TRUE;
9229                 }
9230                 ret = dhd->wakelock_wd_counter;
9231                 spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
9232         }
9233         return ret;
9234 }
9235
9236 int dhd_os_wake_lock_restore(dhd_pub_t *pub)
9237 {
9238         dhd_info_t *dhd = (dhd_info_t *)(pub->info);
9239         unsigned long flags;
9240         int ret = 0;
9241
9242         if (!dhd)
9243                 return 0;
9244
9245         spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
9246         /* dhd_wakelock_waive/dhd_wakelock_restore must be paired */
9247         if (!dhd->waive_wakelock)
9248                 goto exit;
9249
9250         dhd->waive_wakelock = FALSE;
9251         /* if somebody else acquires wakelock between dhd_wakelock_waive/dhd_wakelock_restore,
9252          * we need to make it up by calling wake_lock or pm_stay_awake. or if somebody releases
9253          * the lock in between, do the same by calling wake_unlock or pm_relax
9254          */
9255         if (dhd->wakelock_before_waive == 0 && dhd->wakelock_counter > 0) {
9256 #ifdef CONFIG_HAS_WAKELOCK
9257                 wake_lock(&dhd->wl_wifi);
9258 #elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
9259                 dhd_bus_dev_pm_stay_awake(&dhd->pub);
9260 #endif
9261         } else if (dhd->wakelock_before_waive > 0 && dhd->wakelock_counter == 0) {
9262 #ifdef CONFIG_HAS_WAKELOCK
9263                 wake_unlock(&dhd->wl_wifi);
9264 #elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
9265                 dhd_bus_dev_pm_relax(&dhd->pub);
9266 #endif
9267         }
9268         dhd->wakelock_before_waive = 0;
9269 exit:
9270         ret = dhd->wakelock_wd_counter;
9271         spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
9272         return ret;
9273 }
9274
9275 bool dhd_os_check_if_up(dhd_pub_t *pub)
9276 {
9277         if (!pub)
9278                 return FALSE;
9279         return pub->up;
9280 }
9281
9282 /* function to collect firmware, chip id and chip version info */
9283 void dhd_set_version_info(dhd_pub_t *dhdp, char *fw)
9284 {
9285         int i;
9286
9287         i = snprintf(info_string, sizeof(info_string),
9288                 "  Driver: %s\n  Firmware: %s ", EPI_VERSION_STR, fw);
9289         printf("%s\n", info_string);
9290
9291         if (!dhdp)
9292                 return;
9293
9294         i = snprintf(&info_string[i], sizeof(info_string) - i,
9295                 "\n  Chip: %x Rev %x Pkg %x", dhd_bus_chip_id(dhdp),
9296                 dhd_bus_chiprev_id(dhdp), dhd_bus_chippkg_id(dhdp));
9297 }
9298
9299 int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd)
9300 {
9301         int ifidx;
9302         int ret = 0;
9303         dhd_info_t *dhd = NULL;
9304
9305         if (!net || !DEV_PRIV(net)) {
9306                 DHD_ERROR(("%s invalid parameter\n", __FUNCTION__));
9307                 return -EINVAL;
9308         }
9309
9310         dhd = DHD_DEV_INFO(net);
9311         if (!dhd)
9312                 return -EINVAL;
9313
9314         ifidx = dhd_net2idx(dhd, net);
9315         if (ifidx == DHD_BAD_IF) {
9316                 DHD_ERROR(("%s bad ifidx\n", __FUNCTION__));
9317                 return -ENODEV;
9318         }
9319
9320         DHD_OS_WAKE_LOCK(&dhd->pub);
9321         DHD_PERIM_LOCK(&dhd->pub);
9322
9323         ret = dhd_wl_ioctl(&dhd->pub, ifidx, ioc, ioc->buf, ioc->len);
9324         dhd_check_hang(net, &dhd->pub, ret);
9325
9326         DHD_PERIM_UNLOCK(&dhd->pub);
9327         DHD_OS_WAKE_UNLOCK(&dhd->pub);
9328
9329         return ret;
9330 }
9331
9332 bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret)
9333 {
9334         struct net_device *net;
9335
9336         net = dhd_idx2net(dhdp, ifidx);
9337         if (!net) {
9338                 DHD_ERROR(("%s : Invalid index : %d\n", __FUNCTION__, ifidx));
9339                 return -EINVAL;
9340         }
9341
9342         return dhd_check_hang(net, dhdp, ret);
9343 }
9344
9345 /* Return instance */
9346 int dhd_get_instance(dhd_pub_t *dhdp)
9347 {
9348         return dhdp->info->unit;
9349 }
9350
9351
9352 #ifdef PROP_TXSTATUS
9353
9354 void dhd_wlfc_plat_init(void *dhd)
9355 {
9356         return;
9357 }
9358
9359 void dhd_wlfc_plat_deinit(void *dhd)
9360 {
9361         return;
9362 }
9363
9364 bool dhd_wlfc_skip_fc(void)
9365 {
9366         return FALSE;
9367 }
9368 #endif /* PROP_TXSTATUS */
9369
9370 #ifdef BCMDBGFS
9371
9372 #include <linux/debugfs.h>
9373
9374 extern uint32 dhd_readregl(void *bp, uint32 addr);
9375 extern uint32 dhd_writeregl(void *bp, uint32 addr, uint32 data);
9376
9377 typedef struct dhd_dbgfs {
9378         struct dentry   *debugfs_dir;
9379         struct dentry   *debugfs_mem;
9380         dhd_pub_t       *dhdp;
9381         uint32          size;
9382 } dhd_dbgfs_t;
9383
9384 dhd_dbgfs_t g_dbgfs;
9385
9386 static int
9387 dhd_dbg_state_open(struct inode *inode, struct file *file)
9388 {
9389         file->private_data = inode->i_private;
9390         return 0;
9391 }
9392
9393 static ssize_t
9394 dhd_dbg_state_read(struct file *file, char __user *ubuf,
9395                        size_t count, loff_t *ppos)
9396 {
9397         ssize_t rval;
9398         uint32 tmp;
9399         loff_t pos = *ppos;
9400         size_t ret;
9401
9402         if (pos < 0)
9403                 return -EINVAL;
9404         if (pos >= g_dbgfs.size || !count)
9405                 return 0;
9406         if (count > g_dbgfs.size - pos)
9407                 count = g_dbgfs.size - pos;
9408
9409         /* Basically enforce aligned 4 byte reads. It's up to the user to work out the details */
9410         tmp = dhd_readregl(g_dbgfs.dhdp->bus, file->f_pos & (~3));
9411
9412         ret = copy_to_user(ubuf, &tmp, 4);
9413         if (ret == count)
9414                 return -EFAULT;
9415
9416         count -= ret;
9417         *ppos = pos + count;
9418         rval = count;
9419
9420         return rval;
9421 }
9422
9423
9424 static ssize_t
9425 dhd_debugfs_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos)
9426 {
9427         loff_t pos = *ppos;
9428         size_t ret;
9429         uint32 buf;
9430
9431         if (pos < 0)
9432                 return -EINVAL;
9433         if (pos >= g_dbgfs.size || !count)
9434                 return 0;
9435         if (count > g_dbgfs.size - pos)
9436                 count = g_dbgfs.size - pos;
9437
9438         ret = copy_from_user(&buf, ubuf, sizeof(uint32));
9439         if (ret == count)
9440                 return -EFAULT;
9441
9442         /* Basically enforce aligned 4 byte writes. It's up to the user to work out the details */
9443         dhd_writeregl(g_dbgfs.dhdp->bus, file->f_pos & (~3), buf);
9444
9445         return count;
9446 }
9447
9448
9449 loff_t
9450 dhd_debugfs_lseek(struct file *file, loff_t off, int whence)
9451 {
9452         loff_t pos = -1;
9453
9454         switch (whence) {
9455                 case 0:
9456                         pos = off;
9457                         break;
9458                 case 1:
9459                         pos = file->f_pos + off;
9460                         break;
9461                 case 2:
9462                         pos = g_dbgfs.size - off;
9463         }
9464         return (pos < 0 || pos > g_dbgfs.size) ? -EINVAL : (file->f_pos = pos);
9465 }
9466
9467 static const struct file_operations dhd_dbg_state_ops = {
9468         .read   = dhd_dbg_state_read,
9469         .write  = dhd_debugfs_write,
9470         .open   = dhd_dbg_state_open,
9471         .llseek = dhd_debugfs_lseek
9472 };
9473
9474 static void dhd_dbg_create(void)
9475 {
9476         if (g_dbgfs.debugfs_dir) {
9477                 g_dbgfs.debugfs_mem = debugfs_create_file("mem", 0644, g_dbgfs.debugfs_dir,
9478                         NULL, &dhd_dbg_state_ops);
9479         }
9480 }
9481
9482 void dhd_dbg_init(dhd_pub_t *dhdp)
9483 {
9484         int err;
9485
9486         g_dbgfs.dhdp = dhdp;
9487         g_dbgfs.size = 0x20000000; /* Allow access to various cores regs */
9488
9489         g_dbgfs.debugfs_dir = debugfs_create_dir("dhd", 0);
9490         if (IS_ERR(g_dbgfs.debugfs_dir)) {
9491                 err = PTR_ERR(g_dbgfs.debugfs_dir);
9492                 g_dbgfs.debugfs_dir = NULL;
9493                 return;
9494         }
9495
9496         dhd_dbg_create();
9497
9498         return;
9499 }
9500
9501 void dhd_dbg_remove(void)
9502 {
9503         debugfs_remove(g_dbgfs.debugfs_mem);
9504         debugfs_remove(g_dbgfs.debugfs_dir);
9505
9506         bzero((unsigned char *) &g_dbgfs, sizeof(g_dbgfs));
9507
9508 }
9509 #endif /* ifdef BCMDBGFS */
9510
9511 #ifdef WLMEDIA_HTSF
9512
9513 static
9514 void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf)
9515 {
9516         dhd_info_t *dhd = (dhd_info_t *)(dhdp->info);
9517         struct sk_buff *skb;
9518         uint32 htsf = 0;
9519         uint16 dport = 0, oldmagic = 0xACAC;
9520         char *p1;
9521         htsfts_t ts;
9522
9523         /*  timestamp packet  */
9524
9525         p1 = (char*) PKTDATA(dhdp->osh, pktbuf);
9526
9527         if (PKTLEN(dhdp->osh, pktbuf) > HTSF_MINLEN) {
9528 /*              memcpy(&proto, p1+26, 4);       */
9529                 memcpy(&dport, p1+40, 2);
9530 /*      proto = ((ntoh32(proto))>> 16) & 0xFF;  */
9531                 dport = ntoh16(dport);
9532         }
9533
9534         /* timestamp only if  icmp or udb iperf with port 5555 */
9535 /*      if (proto == 17 && dport == tsport) { */
9536         if (dport >= tsport && dport <= tsport + 20) {
9537
9538                 skb = (struct sk_buff *) pktbuf;
9539
9540                 htsf = dhd_get_htsf(dhd, 0);
9541                 memset(skb->data + 44, 0, 2); /* clear checksum */
9542                 memcpy(skb->data+82, &oldmagic, 2);
9543                 memcpy(skb->data+84, &htsf, 4);
9544
9545                 memset(&ts, 0, sizeof(htsfts_t));
9546                 ts.magic  = HTSFMAGIC;
9547                 ts.prio   = PKTPRIO(pktbuf);
9548                 ts.seqnum = htsf_seqnum++;
9549                 ts.c10    = get_cycles();
9550                 ts.t10    = htsf;
9551                 ts.endmagic = HTSFENDMAGIC;
9552
9553                 memcpy(skb->data + HTSF_HOSTOFFSET, &ts, sizeof(ts));
9554         }
9555 }
9556
9557 static void dhd_dump_htsfhisto(histo_t *his, char *s)
9558 {
9559         int pktcnt = 0, curval = 0, i;
9560         for (i = 0; i < (NUMBIN-2); i++) {
9561                 curval += 500;
9562                 printf("%d ",  his->bin[i]);
9563                 pktcnt += his->bin[i];
9564         }
9565         printf(" max: %d TotPkt: %d neg: %d [%s]\n", his->bin[NUMBIN-2], pktcnt,
9566                 his->bin[NUMBIN-1], s);
9567 }
9568
9569 static
9570 void sorttobin(int value, histo_t *histo)
9571 {
9572         int i, binval = 0;
9573
9574         if (value < 0) {
9575                 histo->bin[NUMBIN-1]++;
9576                 return;
9577         }
9578         if (value > histo->bin[NUMBIN-2])  /* store the max value  */
9579                 histo->bin[NUMBIN-2] = value;
9580
9581         for (i = 0; i < (NUMBIN-2); i++) {
9582                 binval += 500; /* 500m s bins */
9583                 if (value <= binval) {
9584                         histo->bin[i]++;
9585                         return;
9586                 }
9587         }
9588         histo->bin[NUMBIN-3]++;
9589 }
9590
9591 static
9592 void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf)
9593 {
9594         dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
9595         struct sk_buff *skb;
9596         char *p1;
9597         uint16 old_magic;
9598         int d1, d2, d3, end2end;
9599         htsfts_t *htsf_ts;
9600         uint32 htsf;
9601
9602         skb = PKTTONATIVE(dhdp->osh, pktbuf);
9603         p1 = (char*)PKTDATA(dhdp->osh, pktbuf);
9604
9605         if (PKTLEN(osh, pktbuf) > HTSF_MINLEN) {
9606                 memcpy(&old_magic, p1+78, 2);
9607                 htsf_ts = (htsfts_t*) (p1 + HTSF_HOSTOFFSET - 4);
9608         }
9609         else
9610                 return;
9611
9612         if (htsf_ts->magic == HTSFMAGIC) {
9613                 htsf_ts->tE0 = dhd_get_htsf(dhd, 0);
9614                 htsf_ts->cE0 = get_cycles();
9615         }
9616
9617         if (old_magic == 0xACAC) {
9618
9619                 tspktcnt++;
9620                 htsf = dhd_get_htsf(dhd, 0);
9621                 memcpy(skb->data+92, &htsf, sizeof(uint32));
9622
9623                 memcpy(&ts[tsidx].t1, skb->data+80, 16);
9624
9625                 d1 = ts[tsidx].t2 - ts[tsidx].t1;
9626                 d2 = ts[tsidx].t3 - ts[tsidx].t2;
9627                 d3 = ts[tsidx].t4 - ts[tsidx].t3;
9628                 end2end = ts[tsidx].t4 - ts[tsidx].t1;
9629
9630                 sorttobin(d1, &vi_d1);
9631                 sorttobin(d2, &vi_d2);
9632                 sorttobin(d3, &vi_d3);
9633                 sorttobin(end2end, &vi_d4);
9634
9635                 if (end2end > 0 && end2end >  maxdelay) {
9636                         maxdelay = end2end;
9637                         maxdelaypktno = tspktcnt;
9638                         memcpy(&maxdelayts, &ts[tsidx], 16);
9639                 }
9640                 if (++tsidx >= TSMAX)
9641                         tsidx = 0;
9642         }
9643 }
9644
9645 uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx)
9646 {
9647         uint32 htsf = 0, cur_cycle, delta, delta_us;
9648         uint32    factor, baseval, baseval2;
9649         cycles_t t;
9650
9651         t = get_cycles();
9652         cur_cycle = t;
9653
9654         if (cur_cycle >  dhd->htsf.last_cycle)
9655                 delta = cur_cycle -  dhd->htsf.last_cycle;
9656         else {
9657                 delta = cur_cycle + (0xFFFFFFFF -  dhd->htsf.last_cycle);
9658         }
9659
9660         delta = delta >> 4;
9661
9662         if (dhd->htsf.coef) {
9663                 /* times ten to get the first digit */
9664                 factor = (dhd->htsf.coef*10 + dhd->htsf.coefdec1);
9665                 baseval  = (delta*10)/factor;
9666                 baseval2 = (delta*10)/(factor+1);
9667                 delta_us  = (baseval -  (((baseval - baseval2) * dhd->htsf.coefdec2)) / 10);
9668                 htsf = (delta_us << 4) +  dhd->htsf.last_tsf + HTSF_BUS_DELAY;
9669         }
9670         else {
9671                 DHD_ERROR(("-------dhd->htsf.coef = 0 -------\n"));
9672         }
9673
9674         return htsf;
9675 }
9676
9677 static void dhd_dump_latency(void)
9678 {
9679         int i, max = 0;
9680         int d1, d2, d3, d4, d5;
9681
9682         printf("T1       T2       T3       T4           d1  d2   t4-t1     i    \n");
9683         for (i = 0; i < TSMAX; i++) {
9684                 d1 = ts[i].t2 - ts[i].t1;
9685                 d2 = ts[i].t3 - ts[i].t2;
9686                 d3 = ts[i].t4 - ts[i].t3;
9687                 d4 = ts[i].t4 - ts[i].t1;
9688                 d5 = ts[max].t4-ts[max].t1;
9689                 if (d4 > d5 && d4 > 0)  {
9690                         max = i;
9691                 }
9692                 printf("%08X %08X %08X %08X \t%d %d %d   %d i=%d\n",
9693                         ts[i].t1, ts[i].t2, ts[i].t3, ts[i].t4,
9694                         d1, d2, d3, d4, i);
9695         }
9696
9697         printf("current idx = %d \n", tsidx);
9698
9699         printf("Highest latency %d pkt no.%d total=%d\n", maxdelay, maxdelaypktno, tspktcnt);
9700         printf("%08X %08X %08X %08X \t%d %d %d   %d\n",
9701         maxdelayts.t1, maxdelayts.t2, maxdelayts.t3, maxdelayts.t4,
9702         maxdelayts.t2 - maxdelayts.t1,
9703         maxdelayts.t3 - maxdelayts.t2,
9704         maxdelayts.t4 - maxdelayts.t3,
9705         maxdelayts.t4 - maxdelayts.t1);
9706 }
9707
9708
9709 static int
9710 dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx)
9711 {
9712         wl_ioctl_t ioc;
9713         char buf[32];
9714         int ret;
9715         uint32 s1, s2;
9716
9717         struct tsf {
9718                 uint32 low;
9719                 uint32 high;
9720         } tsf_buf;
9721
9722         memset(&ioc, 0, sizeof(ioc));
9723         memset(&tsf_buf, 0, sizeof(tsf_buf));
9724
9725         ioc.cmd = WLC_GET_VAR;
9726         ioc.buf = buf;
9727         ioc.len = (uint)sizeof(buf);
9728         ioc.set = FALSE;
9729
9730         strncpy(buf, "tsf", sizeof(buf) - 1);
9731         buf[sizeof(buf) - 1] = '\0';
9732         s1 = dhd_get_htsf(dhd, 0);
9733         if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
9734                 if (ret == -EIO) {
9735                         DHD_ERROR(("%s: tsf is not supported by device\n",
9736                                 dhd_ifname(&dhd->pub, ifidx)));
9737                         return -EOPNOTSUPP;
9738                 }
9739                 return ret;
9740         }
9741         s2 = dhd_get_htsf(dhd, 0);
9742
9743         memcpy(&tsf_buf, buf, sizeof(tsf_buf));
9744         printf(" TSF_h=%04X lo=%08X Calc:htsf=%08X, coef=%d.%d%d delta=%d ",
9745                 tsf_buf.high, tsf_buf.low, s2, dhd->htsf.coef, dhd->htsf.coefdec1,
9746                 dhd->htsf.coefdec2, s2-tsf_buf.low);
9747         printf("lasttsf=%08X lastcycle=%08X\n", dhd->htsf.last_tsf, dhd->htsf.last_cycle);
9748         return 0;
9749 }
9750
9751 void htsf_update(dhd_info_t *dhd, void *data)
9752 {
9753         static ulong  cur_cycle = 0, prev_cycle = 0;
9754         uint32 htsf, tsf_delta = 0;
9755         uint32 hfactor = 0, cyc_delta, dec1 = 0, dec2, dec3, tmp;
9756         ulong b, a;
9757         cycles_t t;
9758
9759         /* cycles_t in inlcude/mips/timex.h */
9760
9761         t = get_cycles();
9762
9763         prev_cycle = cur_cycle;
9764         cur_cycle = t;
9765
9766         if (cur_cycle > prev_cycle)
9767                 cyc_delta = cur_cycle - prev_cycle;
9768         else {
9769                 b = cur_cycle;
9770                 a = prev_cycle;
9771                 cyc_delta = cur_cycle + (0xFFFFFFFF - prev_cycle);
9772         }
9773
9774         if (data == NULL)
9775                 printf(" tsf update ata point er is null \n");
9776
9777         memcpy(&prev_tsf, &cur_tsf, sizeof(tsf_t));
9778         memcpy(&cur_tsf, data, sizeof(tsf_t));
9779
9780         if (cur_tsf.low == 0) {
9781                 DHD_INFO((" ---- 0 TSF, do not update, return\n"));
9782                 return;
9783         }
9784
9785         if (cur_tsf.low > prev_tsf.low)
9786                 tsf_delta = (cur_tsf.low - prev_tsf.low);
9787         else {
9788                 DHD_INFO((" ---- tsf low is smaller cur_tsf= %08X, prev_tsf=%08X, \n",
9789                  cur_tsf.low, prev_tsf.low));
9790                 if (cur_tsf.high > prev_tsf.high) {
9791                         tsf_delta = cur_tsf.low + (0xFFFFFFFF - prev_tsf.low);
9792                         DHD_INFO((" ---- Wrap around tsf coutner  adjusted TSF=%08X\n", tsf_delta));
9793                 }
9794                 else
9795                         return; /* do not update */
9796         }
9797
9798         if (tsf_delta)  {
9799                 hfactor = cyc_delta / tsf_delta;
9800                 tmp  =  (cyc_delta - (hfactor * tsf_delta))*10;
9801                 dec1 =  tmp/tsf_delta;
9802                 dec2 =  ((tmp - dec1*tsf_delta)*10) / tsf_delta;
9803                 tmp  =  (tmp   - (dec1*tsf_delta))*10;
9804                 dec3 =  ((tmp - dec2*tsf_delta)*10) / tsf_delta;
9805
9806                 if (dec3 > 4) {
9807                         if (dec2 == 9) {
9808                                 dec2 = 0;
9809                                 if (dec1 == 9) {
9810                                         dec1 = 0;
9811                                         hfactor++;
9812                                 }
9813                                 else {
9814                                         dec1++;
9815                                 }
9816                         }
9817                         else
9818                                 dec2++;
9819                 }
9820         }
9821
9822         if (hfactor) {
9823                 htsf = ((cyc_delta * 10)  / (hfactor*10+dec1)) + prev_tsf.low;
9824                 dhd->htsf.coef = hfactor;
9825                 dhd->htsf.last_cycle = cur_cycle;
9826                 dhd->htsf.last_tsf = cur_tsf.low;
9827                 dhd->htsf.coefdec1 = dec1;
9828                 dhd->htsf.coefdec2 = dec2;
9829         }
9830         else {
9831                 htsf = prev_tsf.low;
9832         }
9833 }
9834
9835 #endif /* WLMEDIA_HTSF */
9836
9837 #ifdef CUSTOM_SET_CPUCORE
9838 void dhd_set_cpucore(dhd_pub_t *dhd, int set)
9839 {
9840         int e_dpc = 0, e_rxf = 0, retry_set = 0;
9841
9842         if (!(dhd->chan_isvht80)) {
9843                 DHD_ERROR(("%s: chan_status(%d) cpucore!!!\n", __FUNCTION__, dhd->chan_isvht80));
9844                 return;
9845         }
9846
9847         if (DPC_CPUCORE) {
9848                 do {
9849                         if (set == TRUE) {
9850                                 e_dpc = set_cpus_allowed_ptr(dhd->current_dpc,
9851                                         cpumask_of(DPC_CPUCORE));
9852                         } else {
9853                                 e_dpc = set_cpus_allowed_ptr(dhd->current_dpc,
9854                                         cpumask_of(PRIMARY_CPUCORE));
9855                         }
9856                         if (retry_set++ > MAX_RETRY_SET_CPUCORE) {
9857                                 DHD_ERROR(("%s: dpc(%d) invalid cpu!\n", __FUNCTION__, e_dpc));
9858                                 return;
9859                         }
9860                         if (e_dpc < 0)
9861                                 OSL_SLEEP(1);
9862                 } while (e_dpc < 0);
9863         }
9864         if (RXF_CPUCORE) {
9865                 do {
9866                         if (set == TRUE) {
9867                                 e_rxf = set_cpus_allowed_ptr(dhd->current_rxf,
9868                                         cpumask_of(RXF_CPUCORE));
9869                         } else {
9870                                 e_rxf = set_cpus_allowed_ptr(dhd->current_rxf,
9871                                         cpumask_of(PRIMARY_CPUCORE));
9872                         }
9873                         if (retry_set++ > MAX_RETRY_SET_CPUCORE) {
9874                                 DHD_ERROR(("%s: rxf(%d) invalid cpu!\n", __FUNCTION__, e_rxf));
9875                                 return;
9876                         }
9877                         if (e_rxf < 0)
9878                                 OSL_SLEEP(1);
9879                 } while (e_rxf < 0);
9880         }
9881 #ifdef DHD_OF_SUPPORT
9882         interrupt_set_cpucore(set);
9883 #endif /* DHD_OF_SUPPORT */
9884         DHD_TRACE(("%s: set(%d) cpucore success!\n", __FUNCTION__, set));
9885
9886         return;
9887 }
9888 #endif /* CUSTOM_SET_CPUCORE */
9889 #if defined(DHD_TCP_WINSIZE_ADJUST)
9890 static int dhd_port_list_match(int port)
9891 {
9892         int i;
9893         for (i = 0; i < MAX_TARGET_PORTS; i++) {
9894                 if (target_ports[i] == port)
9895                         return 1;
9896         }
9897         return 0;
9898 }
9899 static void dhd_adjust_tcp_winsize(int op_mode, struct sk_buff *skb)
9900 {
9901         struct iphdr *ipheader;
9902         struct tcphdr *tcpheader;
9903         uint16 win_size;
9904         int32 incremental_checksum;
9905
9906         if (!(op_mode & DHD_FLAG_HOSTAP_MODE))
9907                 return;
9908         if (skb == NULL || skb->data == NULL)
9909                 return;
9910
9911         ipheader = (struct iphdr*)(skb->data);
9912
9913         if (ipheader->protocol == IPPROTO_TCP) {
9914                 tcpheader = (struct tcphdr*) skb_pull(skb, (ipheader->ihl)<<2);
9915                 if (tcpheader) {
9916                         win_size = ntoh16(tcpheader->window);
9917                         if (win_size < MIN_TCP_WIN_SIZE &&
9918                                 dhd_port_list_match(ntoh16(tcpheader->dest))) {
9919                                 incremental_checksum = ntoh16(tcpheader->check);
9920                                 incremental_checksum += win_size - win_size*WIN_SIZE_SCALE_FACTOR;
9921                                 if (incremental_checksum < 0)
9922                                         --incremental_checksum;
9923                                 tcpheader->window = hton16(win_size*WIN_SIZE_SCALE_FACTOR);
9924                                 tcpheader->check = hton16((unsigned short)incremental_checksum);
9925                         }
9926                 }
9927                 skb_push(skb, (ipheader->ihl)<<2);
9928         }
9929 }
9930 #endif /* DHD_TCP_WINSIZE_ADJUST */
9931
9932 /* Get interface specific ap_isolate configuration */
9933 int dhd_get_ap_isolate(dhd_pub_t *dhdp, uint32 idx)
9934 {
9935         dhd_info_t *dhd = dhdp->info;
9936         dhd_if_t *ifp;
9937
9938         ASSERT(idx < DHD_MAX_IFS);
9939
9940         ifp = dhd->iflist[idx];
9941
9942         return ifp->ap_isolate;
9943 }
9944
9945 /* Set interface specific ap_isolate configuration */
9946 int dhd_set_ap_isolate(dhd_pub_t *dhdp, uint32 idx, int val)
9947 {
9948         dhd_info_t *dhd = dhdp->info;
9949         dhd_if_t *ifp;
9950
9951         ASSERT(idx < DHD_MAX_IFS);
9952
9953         ifp = dhd->iflist[idx];
9954
9955         ifp->ap_isolate = val;
9956
9957         return 0;
9958 }
9959
9960 #ifdef DHD_WMF
9961 /* Returns interface specific WMF configuration */
9962 dhd_wmf_t* dhd_wmf_conf(dhd_pub_t *dhdp, uint32 idx)
9963 {
9964         dhd_info_t *dhd = dhdp->info;
9965         dhd_if_t *ifp;
9966
9967         ASSERT(idx < DHD_MAX_IFS);
9968
9969         ifp = dhd->iflist[idx];
9970         return &ifp->wmf;
9971 }
9972 #endif /* DHD_WMF */
9973
9974
9975 #ifdef DHD_UNICAST_DHCP
9976 static int
9977 dhd_get_pkt_ether_type(dhd_pub_t *pub, void *pktbuf,
9978         uint8 **data_ptr, int *len_ptr, uint16 *et_ptr, bool *snap_ptr)
9979 {
9980         uint8 *frame = PKTDATA(pub->osh, pktbuf);
9981         int length = PKTLEN(pub->osh, pktbuf);
9982         uint8 *pt;                      /* Pointer to type field */
9983         uint16 ethertype;
9984         bool snap = FALSE;
9985         /* Process Ethernet II or SNAP-encapsulated 802.3 frames */
9986         if (length < ETHER_HDR_LEN) {
9987                 DHD_ERROR(("dhd: %s: short eth frame (%d)\n",
9988                            __FUNCTION__, length));
9989                 return BCME_ERROR;
9990         } else if (ntoh16_ua(frame + ETHER_TYPE_OFFSET) >= ETHER_TYPE_MIN) {
9991                 /* Frame is Ethernet II */
9992                 pt = frame + ETHER_TYPE_OFFSET;
9993         } else if (length >= ETHER_HDR_LEN + SNAP_HDR_LEN + ETHER_TYPE_LEN &&
9994                    !bcmp(llc_snap_hdr, frame + ETHER_HDR_LEN, SNAP_HDR_LEN)) {
9995                 pt = frame + ETHER_HDR_LEN + SNAP_HDR_LEN;
9996                 snap = TRUE;
9997         } else {
9998                 DHD_INFO(("DHD: %s: non-SNAP 802.3 frame\n",
9999                            __FUNCTION__));
10000                 return BCME_ERROR;
10001         }
10002
10003         ethertype = ntoh16_ua(pt);
10004
10005         /* Skip VLAN tag, if any */
10006         if (ethertype == ETHER_TYPE_8021Q) {
10007                 pt += VLAN_TAG_LEN;
10008
10009                 if ((pt + ETHER_TYPE_LEN) > (frame + length)) {
10010                         DHD_ERROR(("dhd: %s: short VLAN frame (%d)\n",
10011                                   __FUNCTION__, length));
10012                         return BCME_ERROR;
10013                 }
10014
10015                 ethertype = ntoh16_ua(pt);
10016         }
10017
10018         *data_ptr = pt + ETHER_TYPE_LEN;
10019         *len_ptr = length - (pt + ETHER_TYPE_LEN - frame);
10020         *et_ptr = ethertype;
10021         *snap_ptr = snap;
10022         return BCME_OK;
10023 }
10024
10025 static int
10026 dhd_get_pkt_ip_type(dhd_pub_t *pub, void *pktbuf,
10027         uint8 **data_ptr, int *len_ptr, uint8 *prot_ptr)
10028 {
10029         struct ipv4_hdr *iph;           /* IP frame pointer */
10030         int iplen;                      /* IP frame length */
10031         uint16 ethertype, iphdrlen, ippktlen;
10032         uint16 iph_frag;
10033         uint8 prot;
10034         bool snap;
10035
10036         if (dhd_get_pkt_ether_type(pub, pktbuf, (uint8 **)&iph,
10037             &iplen, &ethertype, &snap) != 0)
10038                 return BCME_ERROR;
10039
10040         if (ethertype != ETHER_TYPE_IP) {
10041                 return BCME_ERROR;
10042         }
10043
10044         /* We support IPv4 only */
10045         if (iplen < IPV4_OPTIONS_OFFSET || (IP_VER(iph) != IP_VER_4)) {
10046                 return BCME_ERROR;
10047         }
10048
10049         /* Header length sanity */
10050         iphdrlen = IPV4_HLEN(iph);
10051
10052         /*
10053          * Packet length sanity; sometimes we receive eth-frame size bigger
10054          * than the IP content, which results in a bad tcp chksum
10055          */
10056         ippktlen = ntoh16(iph->tot_len);
10057         if (ippktlen < iplen) {
10058
10059                 DHD_INFO(("%s: extra frame length ignored\n",
10060                           __FUNCTION__));
10061                 iplen = ippktlen;
10062         } else if (ippktlen > iplen) {
10063                 DHD_ERROR(("dhd: %s: truncated IP packet (%d)\n",
10064                            __FUNCTION__, ippktlen - iplen));
10065                 return BCME_ERROR;
10066         }
10067
10068         if (iphdrlen < IPV4_OPTIONS_OFFSET || iphdrlen > iplen) {
10069                 DHD_ERROR(("DHD: %s: IP-header-len (%d) out of range (%d-%d)\n",
10070                            __FUNCTION__, iphdrlen, IPV4_OPTIONS_OFFSET, iplen));
10071                 return BCME_ERROR;
10072         }
10073
10074         /*
10075          * We don't handle fragmented IP packets.  A first frag is indicated by the MF
10076          * (more frag) bit and a subsequent frag is indicated by a non-zero frag offset.
10077          */
10078         iph_frag = ntoh16(iph->frag);
10079
10080         if ((iph_frag & IPV4_FRAG_MORE) || (iph_frag & IPV4_FRAG_OFFSET_MASK) != 0) {
10081                 DHD_INFO(("DHD:%s: IP fragment not handled\n",
10082                            __FUNCTION__));
10083                 return BCME_ERROR;
10084         }
10085
10086         prot = IPV4_PROT(iph);
10087
10088         *data_ptr = (((uint8 *)iph) + iphdrlen);
10089         *len_ptr = iplen - iphdrlen;
10090         *prot_ptr = prot;
10091         return BCME_OK;
10092 }
10093
10094 /** check the packet type, if it is DHCP ACK/REPLY, convert into unicast packet */
10095 static
10096 int dhd_convert_dhcp_broadcast_ack_to_unicast(dhd_pub_t *pub, void *pktbuf, int ifidx)
10097 {
10098         dhd_sta_t* stainfo;
10099         uint8 *eh = PKTDATA(pub->osh, pktbuf);
10100         uint8 *udph;
10101         uint8 *dhcp;
10102         uint8 *chaddr;
10103         int udpl;
10104         int dhcpl;
10105         uint16 port;
10106         uint8 prot;
10107
10108         if (!ETHER_ISMULTI(eh + ETHER_DEST_OFFSET))
10109             return BCME_ERROR;
10110         if (dhd_get_pkt_ip_type(pub, pktbuf, &udph, &udpl, &prot) != 0)
10111                 return BCME_ERROR;
10112         if (prot != IP_PROT_UDP)
10113                 return BCME_ERROR;
10114         /* check frame length, at least UDP_HDR_LEN */
10115         if (udpl < UDP_HDR_LEN) {
10116                 DHD_ERROR(("DHD: %s: short UDP frame, ignored\n",
10117                     __FUNCTION__));
10118                 return BCME_ERROR;
10119         }
10120         port = ntoh16_ua(udph + UDP_DEST_PORT_OFFSET);
10121         /* only process DHCP packets from server to client */
10122         if (port != DHCP_PORT_CLIENT)
10123                 return BCME_ERROR;
10124
10125         dhcp = udph + UDP_HDR_LEN;
10126         dhcpl = udpl - UDP_HDR_LEN;
10127
10128         if (dhcpl < DHCP_CHADDR_OFFSET + ETHER_ADDR_LEN) {
10129                 DHD_ERROR(("DHD: %s: short DHCP frame, ignored\n",
10130                     __FUNCTION__));
10131                 return BCME_ERROR;
10132         }
10133         /* only process DHCP reply(offer/ack) packets */
10134         if (*(dhcp + DHCP_TYPE_OFFSET) != DHCP_TYPE_REPLY)
10135                 return BCME_ERROR;
10136         chaddr = dhcp + DHCP_CHADDR_OFFSET;
10137         stainfo = dhd_find_sta(pub, ifidx, chaddr);
10138         if (stainfo) {
10139                 bcopy(chaddr, eh + ETHER_DEST_OFFSET, ETHER_ADDR_LEN);
10140                 return BCME_OK;
10141         }
10142         return BCME_ERROR;
10143 }
10144 #endif /* DHD_UNICAST_DHD */
10145 #ifdef DHD_L2_FILTER
10146 /* Check if packet type is ICMP ECHO */
10147 static
10148 int dhd_l2_filter_block_ping(dhd_pub_t *pub, void *pktbuf, int ifidx)
10149 {
10150         struct bcmicmp_hdr *icmph;
10151         int udpl;
10152         uint8 prot;
10153
10154         if (dhd_get_pkt_ip_type(pub, pktbuf, (uint8 **)&icmph, &udpl, &prot) != 0)
10155                 return BCME_ERROR;
10156         if (prot == IP_PROT_ICMP) {
10157                 if (icmph->type == ICMP_TYPE_ECHO_REQUEST)
10158                         return BCME_OK;
10159         }
10160         return BCME_ERROR;
10161 }
10162 #endif /* DHD_L2_FILTER */
10163
10164 #ifdef SET_RPS_CPUS
10165 int custom_rps_map_set(struct netdev_rx_queue *queue, char *buf, size_t len)
10166 {
10167         struct rps_map *old_map, *map;
10168         cpumask_var_t mask;
10169         int err, cpu, i;
10170         static DEFINE_SPINLOCK(rps_map_lock);
10171
10172         DHD_INFO(("%s : Entered.\n", __FUNCTION__));
10173
10174         if (!alloc_cpumask_var(&mask, GFP_KERNEL)) {
10175                 DHD_ERROR(("%s : alloc_cpumask_var fail.\n", __FUNCTION__));
10176                 return -ENOMEM;
10177         }
10178
10179         err = bitmap_parse(buf, len, cpumask_bits(mask), nr_cpumask_bits);
10180         if (err) {
10181                 free_cpumask_var(mask);
10182                 DHD_ERROR(("%s : bitmap_parse fail.\n", __FUNCTION__));
10183                 return err;
10184         }
10185
10186         map = kzalloc(max_t(unsigned int,
10187                 RPS_MAP_SIZE(cpumask_weight(mask)), L1_CACHE_BYTES),
10188                 GFP_KERNEL);
10189         if (!map) {
10190                 free_cpumask_var(mask);
10191                 DHD_ERROR(("%s : map malloc fail.\n", __FUNCTION__));
10192                 return -ENOMEM;
10193         }
10194
10195         i = 0;
10196         for_each_cpu(cpu, mask)
10197                 map->cpus[i++] = cpu;
10198
10199         if (i)
10200                 map->len = i;
10201         else {
10202                 kfree(map);
10203                 DHD_ERROR(("%s : mapping cpu fail.\n", __FUNCTION__));
10204                 map = NULL;
10205         }
10206
10207         spin_lock(&rps_map_lock);
10208         old_map = rcu_dereference_protected(queue->rps_map,
10209                 lockdep_is_held(&rps_map_lock));
10210         rcu_assign_pointer(queue->rps_map, map);
10211         spin_unlock(&rps_map_lock);
10212
10213         if (map)
10214                 static_key_slow_inc(&rps_needed);
10215         if (old_map) {
10216                 kfree_rcu(old_map, rcu);
10217                 static_key_slow_dec(&rps_needed);
10218         }
10219         free_cpumask_var(mask);
10220
10221         DHD_INFO(("%s : Done. mapping cpu nummber : %d\n", __FUNCTION__, map->len));
10222         return map->len;
10223 }
10224
10225 void custom_rps_map_clear(struct netdev_rx_queue *queue)
10226 {
10227         struct rps_map *map;
10228
10229         DHD_INFO(("%s : Entered.\n", __FUNCTION__));
10230
10231         map = rcu_dereference_protected(queue->rps_map, 1);
10232         if (map) {
10233                 RCU_INIT_POINTER(queue->rps_map, NULL);
10234                 kfree_rcu(map, rcu);
10235                 DHD_INFO(("%s : rps_cpus map clear.\n", __FUNCTION__));
10236         }
10237 }
10238 #endif /* SET_RPS_CPUS */
10239
10240 #if defined(CUSTOMER_HW20) && defined(WLANAUDIO)
10241 void
10242 SDA_setSharedMemory4Send(unsigned int buffer_id,
10243                          unsigned char *buffer, unsigned int buffer_size,
10244                          unsigned int packet_size, unsigned int headroom_size)
10245 {
10246         dhd_info_t *dhd = dhd_global;
10247
10248         sda_packet_length = packet_size;
10249
10250         ASSERT(dhd);
10251         if (dhd == NULL)
10252                 return;
10253 }
10254
10255 void
10256 SDA_registerCallback4SendDone(SDA_SendDoneCallBack packet_cb)
10257 {
10258         dhd_info_t *dhd = dhd_global;
10259
10260         ASSERT(dhd);
10261         if (dhd == NULL)
10262                 return;
10263 }
10264
10265
10266 unsigned long long
10267 SDA_getTsf(unsigned char vif_id)
10268 {
10269         dhd_info_t *dhd = dhd_global;
10270         uint64 tsf_val;
10271         char buf[WLC_IOCTL_SMLEN];
10272         int ifidx = 0;
10273
10274         struct tsf {
10275                 uint32 low;
10276                 uint32 high;
10277         } tsf_buf;
10278
10279         memset(buf, 0, sizeof(buf));
10280
10281         if (vif_id == 0) /* wlan0 tsf */
10282                 ifidx = dhd_ifname2idx(dhd, "wlan0");
10283         else if (vif_id == 1) /* p2p0 tsf */
10284                 ifidx = dhd_ifname2idx(dhd, "p2p0");
10285
10286         bcm_mkiovar("tsf_bss", 0, 0, buf, sizeof(buf));
10287
10288         if (dhd_wl_ioctl_cmd(&dhd->pub, WLC_GET_VAR, buf, sizeof(buf), FALSE, ifidx) < 0) {
10289                 DHD_ERROR(("%s wl ioctl error\n", __FUNCTION__));
10290                 return 0;
10291         }
10292
10293         memcpy(&tsf_buf, buf, sizeof(tsf_buf));
10294         tsf_val = (uint64)tsf_buf.high;
10295         DHD_TRACE(("%s tsf high 0x%08x, low 0x%08x\n",
10296                    __FUNCTION__, tsf_buf.high, tsf_buf.low));
10297
10298         return ((tsf_val << 32) | tsf_buf.low);
10299 }
10300 EXPORT_SYMBOL(SDA_getTsf);
10301
10302 unsigned int
10303 SDA_syncTsf(void)
10304 {
10305         dhd_info_t *dhd = dhd_global;
10306         int tsf_sync = 1;
10307         char iovbuf[WLC_IOCTL_SMLEN];
10308
10309         bcm_mkiovar("wa_tsf_sync", (char *)&tsf_sync, 4, iovbuf, sizeof(iovbuf));
10310         dhd_wl_ioctl_cmd(&dhd->pub, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
10311
10312         DHD_TRACE(("%s\n", __FUNCTION__));
10313         return 0;
10314 }
10315
10316 extern struct net_device *wl0dot1_dev;
10317
10318 void
10319 BCMFASTPATH SDA_function4Send(uint buffer_id, void *packet, uint packet_size)
10320 {
10321         struct sk_buff *skb;
10322         sda_packet_t *shm_packet = packet;
10323         dhd_info_t *dhd = dhd_global;
10324         int cnt;
10325
10326         static unsigned int cnt_t = 1;
10327
10328         ASSERT(dhd);
10329         if (dhd == NULL)
10330                 return;
10331
10332         if (dhd->is_wlanaudio_blist) {
10333                 for (cnt = 0; cnt < MAX_WLANAUDIO_BLACKLIST; cnt++) {
10334                         if (dhd->wlanaudio_blist[cnt].is_blacklist == true) {
10335                                 if (!bcmp(dhd->wlanaudio_blist[cnt].blacklist_addr.octet,
10336                                           shm_packet->headroom.ether_dhost, ETHER_ADDR_LEN))
10337                                         return;
10338                         }
10339                 }
10340         }
10341
10342         if ((cnt_t % 10000) == 0)
10343                 cnt_t = 0;
10344
10345         cnt_t++;
10346
10347         /* packet_size may be smaller than SDA_SHM_PKT_SIZE, remaining will be garbage */
10348 #define TXOFF 26
10349         skb = __dev_alloc_skb(TXOFF + sda_packet_length - SDA_PKT_HEADER_SIZE, GFP_ATOMIC);
10350
10351         skb_reserve(skb, TXOFF - SDA_HEADROOM_SIZE);
10352         skb_put(skb, sda_packet_length - SDA_PKT_HEADER_SIZE + SDA_HEADROOM_SIZE);
10353         skb->priority = PRIO_8021D_VO; /* PRIO_8021D_VO or PRIO_8021D_VI */
10354
10355         /* p2p_net  */
10356         skb->dev = wl0dot1_dev;
10357         shm_packet->txTsf = 0x0;
10358         shm_packet->rxTsf = 0x0;
10359         memcpy(skb->data, &shm_packet->headroom,
10360                sda_packet_length - OFFSETOF(sda_packet_t, headroom));
10361         shm_packet->desc.ready_to_copy = 0;
10362
10363         dhd_start_xmit(skb, skb->dev);
10364 }
10365
10366 void
10367 SDA_registerCallback4Recv(unsigned char *pBufferTotal,
10368                           unsigned int BufferTotalSize)
10369 {
10370         dhd_info_t *dhd = dhd_global;
10371
10372         ASSERT(dhd);
10373         if (dhd == NULL)
10374                 return;
10375 }
10376
10377
10378 void
10379 SDA_setSharedMemory4Recv(unsigned char *pBufferTotal,
10380                          unsigned int BufferTotalSize,
10381                          unsigned int BufferUnitSize,
10382                          unsigned int Headroomsize)
10383 {
10384         dhd_info_t *dhd = dhd_global;
10385
10386         ASSERT(dhd);
10387         if (dhd == NULL)
10388                 return;
10389 }
10390
10391
10392 void
10393 SDA_function4RecvDone(unsigned char * pBuffer, unsigned int BufferSize)
10394 {
10395         dhd_info_t *dhd = dhd_global;
10396
10397         ASSERT(dhd);
10398         if (dhd == NULL)
10399                 return;
10400 }
10401
10402 EXPORT_SYMBOL(SDA_setSharedMemory4Send);
10403 EXPORT_SYMBOL(SDA_registerCallback4SendDone);
10404 EXPORT_SYMBOL(SDA_syncTsf);
10405 EXPORT_SYMBOL(SDA_function4Send);
10406 EXPORT_SYMBOL(SDA_registerCallback4Recv);
10407 EXPORT_SYMBOL(SDA_setSharedMemory4Recv);
10408 EXPORT_SYMBOL(SDA_function4RecvDone);
10409
10410 #endif /* CUSTOMER_HW20 && WLANAUDIO */
10411
10412 void *dhd_get_pub(struct net_device *dev)
10413 {
10414         dhd_info_t *dhdinfo = *(dhd_info_t **)netdev_priv(dev);
10415         if (dhdinfo)
10416                 return (void *)&dhdinfo->pub;
10417         else
10418                 return NULL;
10419 }