PageRenderTime 90ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 1ms

/drivers/net/wireless/bcmdhd/dhd_linux.c

https://bitbucket.org/wisechild/galaxy-nexus
C | 5041 lines | 3804 code | 837 blank | 400 comment | 685 complexity | fe4e4f51f9d74a59db8f79ca55e59935 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
  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 (C) 1999-2011, Broadcom Corporation
  6. *
  7. * Unless you and Broadcom execute a separate written software license
  8. * agreement governing use of this software, this software is licensed to you
  9. * under the terms of the GNU General Public License version 2 (the "GPL"),
  10. * available at http://www.broadcom.com/licenses/GPLv2.php, with the
  11. * following added to such license:
  12. *
  13. * As a special exception, the copyright holders of this software give you
  14. * permission to link this software with independent modules, and to copy and
  15. * distribute the resulting executable under terms of your choice, provided that
  16. * you also meet, for each linked independent module, the terms and conditions of
  17. * the license of that module. An independent module is a module which is not
  18. * derived from this software. The special exception does not apply to any
  19. * modifications of the software.
  20. *
  21. * Notwithstanding the above, under no circumstances may you combine this
  22. * software in any way with any other Broadcom software provided under a license
  23. * other than the GPL, without Broadcom's express prior written consent.
  24. *
  25. * $Id: dhd_linux.c 287541 2011-10-03 23:48:17Z $
  26. */
  27. #include <typedefs.h>
  28. #include <linuxver.h>
  29. #include <osl.h>
  30. #include <linux/init.h>
  31. #include <linux/kernel.h>
  32. #include <linux/slab.h>
  33. #include <linux/skbuff.h>
  34. #include <linux/netdevice.h>
  35. #include <linux/inetdevice.h>
  36. #include <linux/rtnetlink.h>
  37. #include <linux/etherdevice.h>
  38. #include <linux/random.h>
  39. #include <linux/spinlock.h>
  40. #include <linux/ethtool.h>
  41. #include <linux/fcntl.h>
  42. #include <linux/fs.h>
  43. #include <asm/uaccess.h>
  44. #include <asm/unaligned.h>
  45. #include <epivers.h>
  46. #include <bcmutils.h>
  47. #include <bcmendian.h>
  48. #include <proto/ethernet.h>
  49. #include <dngl_stats.h>
  50. #include <dhd.h>
  51. #include <dhd_bus.h>
  52. #include <dhd_proto.h>
  53. #include <dhd_dbg.h>
  54. #ifdef CONFIG_HAS_WAKELOCK
  55. #include <linux/wakelock.h>
  56. #endif
  57. #ifdef WL_CFG80211
  58. #include <wl_cfg80211.h>
  59. #endif
  60. #include <proto/802.11_bta.h>
  61. #include <proto/bt_amp_hci.h>
  62. #include <dhd_bta.h>
  63. #ifdef WLMEDIA_HTSF
  64. #include <linux/time.h>
  65. #include <htsf.h>
  66. #define HTSF_MINLEN 200 /* min. packet length to timestamp */
  67. #define HTSF_BUS_DELAY 150 /* assume a fix propagation in us */
  68. #define TSMAX 1000 /* max no. of timing record kept */
  69. #define NUMBIN 34
  70. static uint32 tsidx = 0;
  71. static uint32 htsf_seqnum = 0;
  72. uint32 tsfsync;
  73. struct timeval tsync;
  74. static uint32 tsport = 5010;
  75. typedef struct histo_ {
  76. uint32 bin[NUMBIN];
  77. } histo_t;
  78. #if !ISPOWEROF2(DHD_SDALIGN)
  79. #error DHD_SDALIGN is not a power of 2!
  80. #endif
  81. static histo_t vi_d1, vi_d2, vi_d3, vi_d4;
  82. #endif /* WLMEDIA_HTSF */
  83. #if defined(SOFTAP)
  84. extern bool ap_cfg_running;
  85. extern bool ap_fw_loaded;
  86. #endif
  87. /* enable HOSTIP cache update from the host side when an eth0:N is up */
  88. #define AOE_IP_ALIAS_SUPPORT 1
  89. #ifdef PROP_TXSTATUS
  90. #include <wlfc_proto.h>
  91. #include <dhd_wlfc.h>
  92. #endif
  93. #include <wl_android.h>
  94. #ifdef ARP_OFFLOAD_SUPPORT
  95. static int dhd_device_event(struct notifier_block *this,
  96. unsigned long event,
  97. void *ptr);
  98. static struct notifier_block dhd_notifier = {
  99. .notifier_call = dhd_device_event
  100. };
  101. #endif /* ARP_OFFLOAD_SUPPORT */
  102. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
  103. #include <linux/suspend.h>
  104. volatile bool dhd_mmc_suspend = FALSE;
  105. DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait);
  106. #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
  107. #if defined(OOB_INTR_ONLY)
  108. extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable);
  109. #endif /* defined(OOB_INTR_ONLY) */
  110. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
  111. MODULE_LICENSE("GPL v2");
  112. #endif /* LinuxVer */
  113. #include <dhd_bus.h>
  114. #ifndef PROP_TXSTATUS
  115. #define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen)
  116. #else
  117. #define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen + 128)
  118. #endif
  119. #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15)
  120. const char *
  121. print_tainted()
  122. {
  123. return "";
  124. }
  125. #endif /* LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) */
  126. /* Linux wireless extension support */
  127. #if defined(CONFIG_WIRELESS_EXT)
  128. #include <wl_iw.h>
  129. extern wl_iw_extra_params_t g_wl_iw_params;
  130. #endif /* defined(CONFIG_WIRELESS_EXT) */
  131. #if defined(CONFIG_HAS_EARLYSUSPEND)
  132. #include <linux/earlysuspend.h>
  133. extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len);
  134. extern int dhd_get_dtim_skip(dhd_pub_t *dhd);
  135. #endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
  136. #ifdef PKT_FILTER_SUPPORT
  137. extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg);
  138. extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode);
  139. #endif
  140. /* Interface control information */
  141. typedef struct dhd_if {
  142. struct dhd_info *info; /* back pointer to dhd_info */
  143. /* OS/stack specifics */
  144. struct net_device *net;
  145. struct net_device_stats stats;
  146. int idx; /* iface idx in dongle */
  147. int state; /* interface state */
  148. uint subunit; /* subunit */
  149. uint8 mac_addr[ETHER_ADDR_LEN]; /* assigned MAC address */
  150. bool attached; /* Delayed attachment when unset */
  151. bool txflowcontrol; /* Per interface flow control indicator */
  152. char name[IFNAMSIZ+1]; /* linux interface name */
  153. uint8 bssidx; /* bsscfg index for the interface */
  154. bool set_multicast;
  155. } dhd_if_t;
  156. #ifdef WLMEDIA_HTSF
  157. typedef struct {
  158. uint32 low;
  159. uint32 high;
  160. } tsf_t;
  161. typedef struct {
  162. uint32 last_cycle;
  163. uint32 last_sec;
  164. uint32 last_tsf;
  165. uint32 coef; /* scaling factor */
  166. uint32 coefdec1; /* first decimal */
  167. uint32 coefdec2; /* second decimal */
  168. } htsf_t;
  169. typedef struct {
  170. uint32 t1;
  171. uint32 t2;
  172. uint32 t3;
  173. uint32 t4;
  174. } tstamp_t;
  175. static tstamp_t ts[TSMAX];
  176. static tstamp_t maxdelayts;
  177. static uint32 maxdelay = 0, tspktcnt = 0, maxdelaypktno = 0;
  178. #endif /* WLMEDIA_HTSF */
  179. /* Local private structure (extension of pub) */
  180. typedef struct dhd_info {
  181. #if defined(CONFIG_WIRELESS_EXT)
  182. wl_iw_t iw; /* wireless extensions state (must be first) */
  183. #endif /* defined(CONFIG_WIRELESS_EXT) */
  184. dhd_pub_t pub;
  185. /* For supporting multiple interfaces */
  186. dhd_if_t *iflist[DHD_MAX_IFS];
  187. struct semaphore proto_sem;
  188. #ifdef PROP_TXSTATUS
  189. spinlock_t wlfc_spinlock;
  190. #endif /* PROP_TXSTATUS */
  191. #ifdef WLMEDIA_HTSF
  192. htsf_t htsf;
  193. #endif
  194. wait_queue_head_t ioctl_resp_wait;
  195. struct timer_list timer;
  196. bool wd_timer_valid;
  197. struct tasklet_struct tasklet;
  198. spinlock_t sdlock;
  199. spinlock_t txqlock;
  200. spinlock_t dhd_lock;
  201. #ifdef DHDTHREAD
  202. /* Thread based operation */
  203. bool threads_only;
  204. struct semaphore sdsem;
  205. tsk_ctl_t thr_dpc_ctl;
  206. tsk_ctl_t thr_wdt_ctl;
  207. #else
  208. bool dhd_tasklet_create;
  209. #endif /* DHDTHREAD */
  210. tsk_ctl_t thr_sysioc_ctl;
  211. /* Wakelocks */
  212. #if defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
  213. struct wake_lock wl_wifi; /* Wifi wakelock */
  214. struct wake_lock wl_rxwake; /* Wifi rx wakelock */
  215. #endif
  216. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
  217. /* net_device interface lock, prevent race conditions among net_dev interface
  218. * calls and wifi_on or wifi_off
  219. */
  220. struct mutex dhd_net_if_mutex;
  221. #endif
  222. spinlock_t wakelock_spinlock;
  223. int wakelock_counter;
  224. int wakelock_timeout_enable;
  225. /* Thread to issue ioctl for multicast */
  226. bool set_macaddress;
  227. struct ether_addr macvalue;
  228. wait_queue_head_t ctrl_wait;
  229. atomic_t pend_8021x_cnt;
  230. dhd_attach_states_t dhd_state;
  231. #ifdef CONFIG_HAS_EARLYSUSPEND
  232. struct early_suspend early_suspend;
  233. #endif /* CONFIG_HAS_EARLYSUSPEND */
  234. } dhd_info_t;
  235. /* Definitions to provide path to the firmware and nvram
  236. * example nvram_path[MOD_PARAM_PATHLEN]="/projects/wlan/nvram.txt"
  237. */
  238. char firmware_path[MOD_PARAM_PATHLEN];
  239. char nvram_path[MOD_PARAM_PATHLEN];
  240. extern int wl_control_wl_start(struct net_device *dev);
  241. extern int net_os_send_hang_message(struct net_device *dev);
  242. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
  243. struct semaphore dhd_registration_sem;
  244. #define DHD_REGISTRATION_TIMEOUT 12000 /* msec : allowed time to finished dhd registration */
  245. #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
  246. /* Spawn a thread for system ioctls (set mac, set mcast) */
  247. uint dhd_sysioc = TRUE;
  248. module_param(dhd_sysioc, uint, 0);
  249. /* Error bits */
  250. module_param(dhd_msg_level, int, 0);
  251. /* load firmware and/or nvram values from the filesystem */
  252. module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0660);
  253. module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0);
  254. /* Watchdog interval */
  255. uint dhd_watchdog_ms = 10;
  256. module_param(dhd_watchdog_ms, uint, 0);
  257. #if defined(DHD_DEBUG)
  258. /* Console poll interval */
  259. uint dhd_console_ms = 0;
  260. module_param(dhd_console_ms, uint, 0);
  261. #endif /* defined(DHD_DEBUG) */
  262. /* ARP offload agent mode : Enable ARP Host Auto-Reply and ARP Peer Auto-Reply */
  263. uint dhd_arp_mode = 0xb;
  264. module_param(dhd_arp_mode, uint, 0);
  265. /* ARP offload enable */
  266. uint dhd_arp_enable = TRUE;
  267. module_param(dhd_arp_enable, uint, 0);
  268. /* Global Pkt filter enable control */
  269. uint dhd_pkt_filter_enable = TRUE;
  270. module_param(dhd_pkt_filter_enable, uint, 0);
  271. /* Pkt filter init setup */
  272. uint dhd_pkt_filter_init = 0;
  273. module_param(dhd_pkt_filter_init, uint, 0);
  274. /* Pkt filter mode control */
  275. uint dhd_master_mode = TRUE;
  276. module_param(dhd_master_mode, uint, 1);
  277. #ifdef DHDTHREAD
  278. /* Watchdog thread priority, -1 to use kernel timer */
  279. int dhd_watchdog_prio = 97;
  280. module_param(dhd_watchdog_prio, int, 0);
  281. /* DPC thread priority, -1 to use tasklet */
  282. int dhd_dpc_prio = 98;
  283. module_param(dhd_dpc_prio, int, 0);
  284. /* DPC thread priority, -1 to use tasklet */
  285. extern int dhd_dongle_memsize;
  286. module_param(dhd_dongle_memsize, int, 0);
  287. #endif /* DHDTHREAD */
  288. /* Control fw roaming */
  289. uint dhd_roam_disable = 0;
  290. /* Control radio state */
  291. uint dhd_radio_up = 1;
  292. /* Network inteface name */
  293. char iface_name[IFNAMSIZ];
  294. module_param_string(iface_name, iface_name, IFNAMSIZ, 0);
  295. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
  296. #define DAEMONIZE(a) daemonize(a); \
  297. allow_signal(SIGKILL); \
  298. allow_signal(SIGTERM);
  299. #else /* Linux 2.4 (w/o preemption patch) */
  300. #define RAISE_RX_SOFTIRQ() \
  301. cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ)
  302. #define DAEMONIZE(a) daemonize(); \
  303. do { if (a) \
  304. strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a) + 1))); \
  305. } while (0);
  306. #endif /* LINUX_VERSION_CODE */
  307. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
  308. #define BLOCKABLE() (!in_atomic())
  309. #else
  310. #define BLOCKABLE() (!in_interrupt())
  311. #endif
  312. /* The following are specific to the SDIO dongle */
  313. /* IOCTL response timeout */
  314. int dhd_ioctl_timeout_msec = IOCTL_RESP_TIMEOUT;
  315. /* Idle timeout for backplane clock */
  316. int dhd_idletime = DHD_IDLETIME_TICKS;
  317. module_param(dhd_idletime, int, 0);
  318. /* Use polling */
  319. uint dhd_poll = FALSE;
  320. module_param(dhd_poll, uint, 0);
  321. /* Use interrupts */
  322. uint dhd_intr = TRUE;
  323. module_param(dhd_intr, uint, 0);
  324. /* SDIO Drive Strength (in milliamps) */
  325. uint dhd_sdiod_drive_strength = 6;
  326. module_param(dhd_sdiod_drive_strength, uint, 0);
  327. /* Tx/Rx bounds */
  328. extern uint dhd_txbound;
  329. extern uint dhd_rxbound;
  330. module_param(dhd_txbound, uint, 0);
  331. module_param(dhd_rxbound, uint, 0);
  332. /* Deferred transmits */
  333. extern uint dhd_deferred_tx;
  334. module_param(dhd_deferred_tx, uint, 0);
  335. #ifdef BCMDBGFS
  336. extern void dhd_dbg_init(dhd_pub_t *dhdp);
  337. extern void dhd_dbg_remove(void);
  338. #endif /* BCMDBGFS */
  339. #ifdef SDTEST
  340. /* Echo packet generator (pkts/s) */
  341. uint dhd_pktgen = 0;
  342. module_param(dhd_pktgen, uint, 0);
  343. /* Echo packet len (0 => sawtooth, max 2040) */
  344. uint dhd_pktgen_len = 0;
  345. module_param(dhd_pktgen_len, uint, 0);
  346. #endif /* SDTEST */
  347. /* Version string to report */
  348. #ifdef DHD_DEBUG
  349. #ifndef SRCBASE
  350. #define SRCBASE "drivers/net/wireless/bcmdhd"
  351. #endif
  352. #define DHD_COMPILED "\nCompiled in " SRCBASE
  353. #else
  354. #define DHD_COMPILED
  355. #endif /* DHD_DEBUG */
  356. static char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR
  357. #ifdef DHD_DEBUG
  358. "\nCompiled in " SRCBASE " on " __DATE__ " at " __TIME__
  359. #endif
  360. ;
  361. static void dhd_net_if_lock_local(dhd_info_t *dhd);
  362. static void dhd_net_if_unlock_local(dhd_info_t *dhd);
  363. #ifdef WLMEDIA_HTSF
  364. void htsf_update(dhd_info_t *dhd, void *data);
  365. tsf_t prev_tsf, cur_tsf;
  366. uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx);
  367. static int dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx);
  368. static void dhd_dump_latency(void);
  369. static void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf);
  370. static void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf);
  371. static void dhd_dump_htsfhisto(histo_t *his, char *s);
  372. #endif /* WLMEDIA_HTSF */
  373. /* Monitor interface */
  374. int dhd_monitor_init(void *dhd_pub);
  375. int dhd_monitor_uninit(void);
  376. #if defined(CONFIG_WIRELESS_EXT)
  377. struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev);
  378. #endif /* defined(CONFIG_WIRELESS_EXT) */
  379. static void dhd_dpc(ulong data);
  380. /* forward decl */
  381. extern int dhd_wait_pend8021x(struct net_device *dev);
  382. #ifdef TOE
  383. #ifndef BDC
  384. #error TOE requires BDC
  385. #endif /* !BDC */
  386. static int dhd_toe_get(dhd_info_t *dhd, int idx, uint32 *toe_ol);
  387. static int dhd_toe_set(dhd_info_t *dhd, int idx, uint32 toe_ol);
  388. #endif /* TOE */
  389. static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
  390. wl_event_msg_t *event_ptr, void **data_ptr);
  391. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
  392. static int dhd_sleep_pm_callback(struct notifier_block *nfb, unsigned long action, void *ignored)
  393. {
  394. int ret = NOTIFY_DONE;
  395. switch (action) {
  396. case PM_HIBERNATION_PREPARE:
  397. case PM_SUSPEND_PREPARE:
  398. dhd_mmc_suspend = TRUE;
  399. ret = NOTIFY_OK;
  400. break;
  401. case PM_POST_HIBERNATION:
  402. case PM_POST_SUSPEND:
  403. dhd_mmc_suspend = FALSE;
  404. ret = NOTIFY_OK;
  405. break;
  406. }
  407. smp_mb();
  408. return ret;
  409. }
  410. static struct notifier_block dhd_sleep_pm_notifier = {
  411. .notifier_call = dhd_sleep_pm_callback,
  412. .priority = 0
  413. };
  414. extern int register_pm_notifier(struct notifier_block *nb);
  415. extern int unregister_pm_notifier(struct notifier_block *nb);
  416. #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
  417. static void dhd_set_packet_filter(int value, dhd_pub_t *dhd)
  418. {
  419. #ifdef PKT_FILTER_SUPPORT
  420. DHD_TRACE(("%s: %d\n", __FUNCTION__, value));
  421. /* 1 - Enable packet filter, only allow unicast packet to send up */
  422. /* 0 - Disable packet filter */
  423. if (dhd_pkt_filter_enable) {
  424. int i;
  425. for (i = 0; i < dhd->pktfilter_count; i++) {
  426. dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]);
  427. dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i],
  428. value, dhd_master_mode);
  429. }
  430. }
  431. #endif
  432. }
  433. #if defined(CONFIG_HAS_EARLYSUSPEND)
  434. static int dhd_set_suspend(int value, dhd_pub_t *dhd)
  435. {
  436. int power_mode = PM_FAST;
  437. /* wl_pkt_filter_enable_t enable_parm; */
  438. char iovbuf[32];
  439. int bcn_li_dtim = 3;
  440. uint roamvar = 1;
  441. DHD_TRACE(("%s: enter, value = %d in_suspend=%d\n",
  442. __FUNCTION__, value, dhd->in_suspend));
  443. if (dhd && dhd->up) {
  444. if (value && dhd->in_suspend) {
  445. /* Kernel suspended */
  446. DHD_ERROR(("%s: force extra Suspend setting \n", __FUNCTION__));
  447. dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
  448. sizeof(power_mode), TRUE, 0);
  449. /* Enable packet filter, only allow unicast packet to send up */
  450. dhd_set_packet_filter(1, dhd);
  451. /* If DTIM skip is set up as default, force it to wake
  452. * each third DTIM for better power savings. Note that
  453. * one side effect is a chance to miss BC/MC packet.
  454. */
  455. bcn_li_dtim = dhd_get_dtim_skip(dhd);
  456. bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
  457. 4, iovbuf, sizeof(iovbuf));
  458. dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
  459. /* Disable firmware roaming during suspend */
  460. bcm_mkiovar("roam_off", (char *)&roamvar, 4,
  461. iovbuf, sizeof(iovbuf));
  462. dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
  463. } else {
  464. /* Kernel resumed */
  465. DHD_TRACE(("%s: Remove extra suspend setting \n", __FUNCTION__));
  466. power_mode = PM_FAST;
  467. dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
  468. sizeof(power_mode), TRUE, 0);
  469. /* disable pkt filter */
  470. dhd_set_packet_filter(0, dhd);
  471. /* restore pre-suspend setting for dtim_skip */
  472. bcm_mkiovar("bcn_li_dtim", (char *)&dhd->dtim_skip,
  473. 4, iovbuf, sizeof(iovbuf));
  474. dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
  475. roamvar = dhd_roam_disable;
  476. bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf,
  477. sizeof(iovbuf));
  478. dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
  479. }
  480. }
  481. return 0;
  482. }
  483. static void dhd_suspend_resume_helper(struct dhd_info *dhd, int val)
  484. {
  485. dhd_pub_t *dhdp = &dhd->pub;
  486. DHD_OS_WAKE_LOCK(dhdp);
  487. /* Set flag when early suspend was called */
  488. dhdp->in_suspend = val;
  489. if (!dhdp->suspend_disable_flag)
  490. dhd_set_suspend(val, dhdp);
  491. DHD_OS_WAKE_UNLOCK(dhdp);
  492. }
  493. static void dhd_early_suspend(struct early_suspend *h)
  494. {
  495. struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend);
  496. DHD_TRACE(("%s: enter\n", __FUNCTION__));
  497. if (dhd)
  498. dhd_suspend_resume_helper(dhd, 1);
  499. }
  500. static void dhd_late_resume(struct early_suspend *h)
  501. {
  502. struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend);
  503. DHD_TRACE(("%s: enter\n", __FUNCTION__));
  504. if (dhd)
  505. dhd_suspend_resume_helper(dhd, 0);
  506. }
  507. #endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
  508. /*
  509. * Generalized timeout mechanism. Uses spin sleep with exponential back-off until
  510. * the sleep time reaches one jiffy, then switches over to task delay. Usage:
  511. *
  512. * dhd_timeout_start(&tmo, usec);
  513. * while (!dhd_timeout_expired(&tmo))
  514. * if (poll_something())
  515. * break;
  516. * if (dhd_timeout_expired(&tmo))
  517. * fatal();
  518. */
  519. void
  520. dhd_timeout_start(dhd_timeout_t *tmo, uint usec)
  521. {
  522. tmo->limit = usec;
  523. tmo->increment = 0;
  524. tmo->elapsed = 0;
  525. tmo->tick = 1000000 / HZ;
  526. }
  527. int
  528. dhd_timeout_expired(dhd_timeout_t *tmo)
  529. {
  530. /* Does nothing the first call */
  531. if (tmo->increment == 0) {
  532. tmo->increment = 1;
  533. return 0;
  534. }
  535. if (tmo->elapsed >= tmo->limit)
  536. return 1;
  537. /* Add the delay that's about to take place */
  538. tmo->elapsed += tmo->increment;
  539. if (tmo->increment < tmo->tick) {
  540. OSL_DELAY(tmo->increment);
  541. tmo->increment *= 2;
  542. if (tmo->increment > tmo->tick)
  543. tmo->increment = tmo->tick;
  544. } else {
  545. wait_queue_head_t delay_wait;
  546. DECLARE_WAITQUEUE(wait, current);
  547. int pending;
  548. init_waitqueue_head(&delay_wait);
  549. add_wait_queue(&delay_wait, &wait);
  550. set_current_state(TASK_INTERRUPTIBLE);
  551. schedule_timeout(1);
  552. pending = signal_pending(current);
  553. remove_wait_queue(&delay_wait, &wait);
  554. set_current_state(TASK_RUNNING);
  555. if (pending)
  556. return 1; /* Interrupted */
  557. }
  558. return 0;
  559. }
  560. int
  561. dhd_net2idx(dhd_info_t *dhd, struct net_device *net)
  562. {
  563. int i = 0;
  564. ASSERT(dhd);
  565. while (i < DHD_MAX_IFS) {
  566. if (dhd->iflist[i] && (dhd->iflist[i]->net == net))
  567. return i;
  568. i++;
  569. }
  570. return DHD_BAD_IF;
  571. }
  572. struct net_device * dhd_idx2net(struct dhd_pub *dhd_pub, int ifidx)
  573. {
  574. struct dhd_info *dhd_info;
  575. if (!dhd_pub || ifidx < 0 || ifidx >= DHD_MAX_IFS)
  576. return NULL;
  577. dhd_info = dhd_pub->info;
  578. if (dhd_info && dhd_info->iflist[ifidx])
  579. return dhd_info->iflist[ifidx]->net;
  580. return NULL;
  581. }
  582. int
  583. dhd_ifname2idx(dhd_info_t *dhd, char *name)
  584. {
  585. int i = DHD_MAX_IFS;
  586. ASSERT(dhd);
  587. if (name == NULL || *name == '\0')
  588. return 0;
  589. while (--i > 0)
  590. if (dhd->iflist[i] && !strncmp(dhd->iflist[i]->name, name, IFNAMSIZ))
  591. break;
  592. DHD_TRACE(("%s: return idx %d for \"%s\"\n", __FUNCTION__, i, name));
  593. return i; /* default - the primary interface */
  594. }
  595. char *
  596. dhd_ifname(dhd_pub_t *dhdp, int ifidx)
  597. {
  598. dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
  599. ASSERT(dhd);
  600. if (ifidx < 0 || ifidx >= DHD_MAX_IFS) {
  601. DHD_ERROR(("%s: ifidx %d out of range\n", __FUNCTION__, ifidx));
  602. return "<if_bad>";
  603. }
  604. if (dhd->iflist[ifidx] == NULL) {
  605. DHD_ERROR(("%s: null i/f %d\n", __FUNCTION__, ifidx));
  606. return "<if_null>";
  607. }
  608. if (dhd->iflist[ifidx]->net)
  609. return dhd->iflist[ifidx]->net->name;
  610. return "<if_none>";
  611. }
  612. uint8 *
  613. dhd_bssidx2bssid(dhd_pub_t *dhdp, int idx)
  614. {
  615. int i;
  616. dhd_info_t *dhd = (dhd_info_t *)dhdp;
  617. ASSERT(dhd);
  618. for (i = 0; i < DHD_MAX_IFS; i++)
  619. if (dhd->iflist[i] && dhd->iflist[i]->bssidx == idx)
  620. return dhd->iflist[i]->mac_addr;
  621. return NULL;
  622. }
  623. static void
  624. _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx)
  625. {
  626. struct net_device *dev;
  627. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
  628. struct netdev_hw_addr *ha;
  629. #else
  630. struct dev_mc_list *mclist;
  631. #endif
  632. uint32 allmulti, cnt;
  633. wl_ioctl_t ioc;
  634. char *buf, *bufp;
  635. uint buflen;
  636. int ret;
  637. ASSERT(dhd && dhd->iflist[ifidx]);
  638. dev = dhd->iflist[ifidx]->net;
  639. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
  640. netif_addr_lock_bh(dev);
  641. #endif
  642. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
  643. cnt = netdev_mc_count(dev);
  644. #else
  645. cnt = dev->mc_count;
  646. #endif
  647. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
  648. netif_addr_unlock_bh(dev);
  649. #endif
  650. /* Determine initial value of allmulti flag */
  651. allmulti = (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE;
  652. /* Send down the multicast list first. */
  653. buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETHER_ADDR_LEN);
  654. if (!(bufp = buf = MALLOC(dhd->pub.osh, buflen))) {
  655. DHD_ERROR(("%s: out of memory for mcast_list, cnt %d\n",
  656. dhd_ifname(&dhd->pub, ifidx), cnt));
  657. return;
  658. }
  659. strcpy(bufp, "mcast_list");
  660. bufp += strlen("mcast_list") + 1;
  661. cnt = htol32(cnt);
  662. memcpy(bufp, &cnt, sizeof(cnt));
  663. bufp += sizeof(cnt);
  664. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
  665. netif_addr_lock_bh(dev);
  666. #endif
  667. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
  668. netdev_for_each_mc_addr(ha, dev) {
  669. if (!cnt)
  670. break;
  671. memcpy(bufp, ha->addr, ETHER_ADDR_LEN);
  672. bufp += ETHER_ADDR_LEN;
  673. cnt--;
  674. }
  675. #else
  676. for (mclist = dev->mc_list; (mclist && (cnt > 0)); cnt--, mclist = mclist->next) {
  677. memcpy(bufp, (void *)mclist->dmi_addr, ETHER_ADDR_LEN);
  678. bufp += ETHER_ADDR_LEN;
  679. }
  680. #endif
  681. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
  682. netif_addr_unlock_bh(dev);
  683. #endif
  684. memset(&ioc, 0, sizeof(ioc));
  685. ioc.cmd = WLC_SET_VAR;
  686. ioc.buf = buf;
  687. ioc.len = buflen;
  688. ioc.set = TRUE;
  689. ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
  690. if (ret < 0) {
  691. DHD_ERROR(("%s: set mcast_list failed, cnt %d\n",
  692. dhd_ifname(&dhd->pub, ifidx), cnt));
  693. allmulti = cnt ? TRUE : allmulti;
  694. }
  695. MFREE(dhd->pub.osh, buf, buflen);
  696. /* Now send the allmulti setting. This is based on the setting in the
  697. * net_device flags, but might be modified above to be turned on if we
  698. * were trying to set some addresses and dongle rejected it...
  699. */
  700. buflen = sizeof("allmulti") + sizeof(allmulti);
  701. if (!(buf = MALLOC(dhd->pub.osh, buflen))) {
  702. DHD_ERROR(("%s: out of memory for allmulti\n", dhd_ifname(&dhd->pub, ifidx)));
  703. return;
  704. }
  705. allmulti = htol32(allmulti);
  706. if (!bcm_mkiovar("allmulti", (void*)&allmulti, sizeof(allmulti), buf, buflen)) {
  707. DHD_ERROR(("%s: mkiovar failed for allmulti, datalen %d buflen %u\n",
  708. dhd_ifname(&dhd->pub, ifidx), (int)sizeof(allmulti), buflen));
  709. MFREE(dhd->pub.osh, buf, buflen);
  710. return;
  711. }
  712. memset(&ioc, 0, sizeof(ioc));
  713. ioc.cmd = WLC_SET_VAR;
  714. ioc.buf = buf;
  715. ioc.len = buflen;
  716. ioc.set = TRUE;
  717. ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
  718. if (ret < 0) {
  719. DHD_ERROR(("%s: set allmulti %d failed\n",
  720. dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti)));
  721. }
  722. MFREE(dhd->pub.osh, buf, buflen);
  723. /* Finally, pick up the PROMISC flag as well, like the NIC driver does */
  724. allmulti = (dev->flags & IFF_PROMISC) ? TRUE : FALSE;
  725. allmulti = htol32(allmulti);
  726. memset(&ioc, 0, sizeof(ioc));
  727. ioc.cmd = WLC_SET_PROMISC;
  728. ioc.buf = &allmulti;
  729. ioc.len = sizeof(allmulti);
  730. ioc.set = TRUE;
  731. ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
  732. if (ret < 0) {
  733. DHD_ERROR(("%s: set promisc %d failed\n",
  734. dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti)));
  735. }
  736. }
  737. static int
  738. _dhd_set_mac_address(dhd_info_t *dhd, int ifidx, struct ether_addr *addr)
  739. {
  740. char buf[32];
  741. wl_ioctl_t ioc;
  742. int ret;
  743. if (!bcm_mkiovar("cur_etheraddr", (char*)addr, ETHER_ADDR_LEN, buf, 32)) {
  744. DHD_ERROR(("%s: mkiovar failed for cur_etheraddr\n", dhd_ifname(&dhd->pub, ifidx)));
  745. return -1;
  746. }
  747. memset(&ioc, 0, sizeof(ioc));
  748. ioc.cmd = WLC_SET_VAR;
  749. ioc.buf = buf;
  750. ioc.len = 32;
  751. ioc.set = TRUE;
  752. ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
  753. if (ret < 0) {
  754. DHD_ERROR(("%s: set cur_etheraddr failed\n", dhd_ifname(&dhd->pub, ifidx)));
  755. } else {
  756. memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETHER_ADDR_LEN);
  757. }
  758. return ret;
  759. }
  760. #ifdef SOFTAP
  761. extern struct net_device *ap_net_dev;
  762. extern tsk_ctl_t ap_eth_ctl; /* ap netdev heper thread ctl */
  763. #endif
  764. static void
  765. dhd_op_if(dhd_if_t *ifp)
  766. {
  767. dhd_info_t *dhd;
  768. int ret = 0, err = 0;
  769. #ifdef SOFTAP
  770. unsigned long flags;
  771. #endif
  772. ASSERT(ifp && ifp->info && ifp->idx); /* Virtual interfaces only */
  773. dhd = ifp->info;
  774. DHD_TRACE(("%s: idx %d, state %d\n", __FUNCTION__, ifp->idx, ifp->state));
  775. #ifdef WL_CFG80211
  776. if (wl_cfg80211_is_progress_ifchange())
  777. return;
  778. #endif
  779. switch (ifp->state) {
  780. case WLC_E_IF_ADD:
  781. /*
  782. * Delete the existing interface before overwriting it
  783. * in case we missed the WLC_E_IF_DEL event.
  784. */
  785. if (ifp->net != NULL) {
  786. DHD_ERROR(("%s: ERROR: netdev:%s already exists, try free & unregister \n",
  787. __FUNCTION__, ifp->net->name));
  788. netif_stop_queue(ifp->net);
  789. unregister_netdev(ifp->net);
  790. free_netdev(ifp->net);
  791. }
  792. /* Allocate etherdev, including space for private structure */
  793. if (!(ifp->net = alloc_etherdev(sizeof(dhd)))) {
  794. DHD_ERROR(("%s: OOM - alloc_etherdev\n", __FUNCTION__));
  795. ret = -ENOMEM;
  796. }
  797. if (ret == 0) {
  798. strncpy(ifp->net->name, ifp->name, IFNAMSIZ);
  799. ifp->net->name[IFNAMSIZ - 1] = '\0';
  800. memcpy(netdev_priv(ifp->net), &dhd, sizeof(dhd));
  801. #ifdef WL_CFG80211
  802. if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)
  803. if (!wl_cfg80211_notify_ifadd(ifp->net, ifp->idx, ifp->bssidx,
  804. dhd_net_attach)) {
  805. ifp->state = 0;
  806. return;
  807. }
  808. #endif
  809. if ((err = dhd_net_attach(&dhd->pub, ifp->idx)) != 0) {
  810. DHD_ERROR(("%s: dhd_net_attach failed, err %d\n",
  811. __FUNCTION__, err));
  812. ret = -EOPNOTSUPP;
  813. } else {
  814. #if defined(SOFTAP)
  815. if (ap_fw_loaded && !(dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) {
  816. /* semaphore that the soft AP CODE waits on */
  817. flags = dhd_os_spin_lock(&dhd->pub);
  818. /* save ptr to wl0.1 netdev for use in wl_iw.c */
  819. ap_net_dev = ifp->net;
  820. /* signal to the SOFTAP 'sleeper' thread, wl0.1 is ready */
  821. up(&ap_eth_ctl.sema);
  822. dhd_os_spin_unlock(&dhd->pub, flags);
  823. }
  824. #endif
  825. DHD_TRACE(("\n ==== pid:%x, net_device for if:%s created ===\n\n",
  826. current->pid, ifp->net->name));
  827. ifp->state = 0;
  828. }
  829. }
  830. break;
  831. case WLC_E_IF_DEL:
  832. if (ifp->net != NULL) {
  833. DHD_TRACE(("\n%s: got 'WLC_E_IF_DEL' state\n", __FUNCTION__));
  834. #ifdef WL_CFG80211
  835. wl_cfg80211_ifdel_ops(ifp->net);
  836. #endif
  837. netif_stop_queue(ifp->net);
  838. unregister_netdev(ifp->net);
  839. ret = DHD_DEL_IF; /* Make sure the free_netdev() is called */
  840. }
  841. break;
  842. default:
  843. DHD_ERROR(("%s: bad op %d\n", __FUNCTION__, ifp->state));
  844. ASSERT(!ifp->state);
  845. break;
  846. }
  847. if (ret < 0) {
  848. ifp->set_multicast = FALSE;
  849. if (ifp->net) {
  850. free_netdev(ifp->net);
  851. }
  852. dhd->iflist[ifp->idx] = NULL;
  853. #ifdef WL_CFG80211
  854. if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) {
  855. wl_cfg80211_notify_ifdel(ifp->net);
  856. }
  857. #endif
  858. #ifdef SOFTAP
  859. flags = dhd_os_spin_lock(&dhd->pub);
  860. if (ifp->net == ap_net_dev)
  861. ap_net_dev = NULL; /* NULL SOFTAP global wl0.1 as well */
  862. dhd_os_spin_unlock(&dhd->pub, flags);
  863. #endif /* SOFTAP */
  864. MFREE(dhd->pub.osh, ifp, sizeof(*ifp));
  865. }
  866. }
  867. static int
  868. _dhd_sysioc_thread(void *data)
  869. {
  870. tsk_ctl_t *tsk = (tsk_ctl_t *)data;
  871. dhd_info_t *dhd = (dhd_info_t *)tsk->parent;
  872. int i;
  873. #ifdef SOFTAP
  874. bool in_ap = FALSE;
  875. unsigned long flags;
  876. #endif
  877. DAEMONIZE("dhd_sysioc");
  878. complete(&tsk->completed);
  879. while (down_interruptible(&tsk->sema) == 0) {
  880. SMP_RD_BARRIER_DEPENDS();
  881. if (tsk->terminated) {
  882. break;
  883. }
  884. dhd_net_if_lock_local(dhd);
  885. DHD_OS_WAKE_LOCK(&dhd->pub);
  886. for (i = 0; i < DHD_MAX_IFS; i++) {
  887. if (dhd->iflist[i]) {
  888. DHD_TRACE(("%s: interface %d\n", __FUNCTION__, i));
  889. #ifdef SOFTAP
  890. flags = dhd_os_spin_lock(&dhd->pub);
  891. in_ap = (ap_net_dev != NULL);
  892. dhd_os_spin_unlock(&dhd->pub, flags);
  893. #endif /* SOFTAP */
  894. if (dhd->iflist[i] && dhd->iflist[i]->state)
  895. dhd_op_if(dhd->iflist[i]);
  896. if (dhd->iflist[i] == NULL) {
  897. DHD_TRACE(("\n\n %s: interface %d just been removed,"
  898. "!\n\n", __FUNCTION__, i));
  899. continue;
  900. }
  901. #ifdef SOFTAP
  902. if (in_ap && dhd->set_macaddress) {
  903. DHD_TRACE(("attempt to set MAC for %s in AP Mode,"
  904. "blocked. \n", dhd->iflist[i]->net->name));
  905. dhd->set_macaddress = FALSE;
  906. continue;
  907. }
  908. if (in_ap && dhd->iflist[i]->set_multicast) {
  909. DHD_TRACE(("attempt to set MULTICAST list for %s"
  910. "in AP Mode, blocked. \n", dhd->iflist[i]->net->name));
  911. dhd->iflist[i]->set_multicast = FALSE;
  912. continue;
  913. }
  914. #endif /* SOFTAP */
  915. if (dhd->iflist[i]->set_multicast) {
  916. dhd->iflist[i]->set_multicast = FALSE;
  917. _dhd_set_multicast_list(dhd, i);
  918. }
  919. if (dhd->set_macaddress) {
  920. dhd->set_macaddress = FALSE;
  921. _dhd_set_mac_address(dhd, i, &dhd->macvalue);
  922. }
  923. }
  924. }
  925. DHD_OS_WAKE_UNLOCK(&dhd->pub);
  926. dhd_net_if_unlock_local(dhd);
  927. }
  928. DHD_TRACE(("%s: stopped\n", __FUNCTION__));
  929. complete_and_exit(&tsk->completed, 0);
  930. }
  931. static int
  932. dhd_set_mac_address(struct net_device *dev, void *addr)
  933. {
  934. int ret = 0;
  935. dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
  936. struct sockaddr *sa = (struct sockaddr *)addr;
  937. int ifidx;
  938. ifidx = dhd_net2idx(dhd, dev);
  939. if (ifidx == DHD_BAD_IF)
  940. return -1;
  941. ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0);
  942. memcpy(&dhd->macvalue, sa->sa_data, ETHER_ADDR_LEN);
  943. dhd->set_macaddress = TRUE;
  944. up(&dhd->thr_sysioc_ctl.sema);
  945. return ret;
  946. }
  947. static void
  948. dhd_set_multicast_list(struct net_device *dev)
  949. {
  950. dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
  951. int ifidx;
  952. ifidx = dhd_net2idx(dhd, dev);
  953. if (ifidx == DHD_BAD_IF)
  954. return;
  955. ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0);
  956. dhd->iflist[ifidx]->set_multicast = TRUE;
  957. up(&dhd->thr_sysioc_ctl.sema);
  958. }
  959. #ifdef PROP_TXSTATUS
  960. int
  961. dhd_os_wlfc_block(dhd_pub_t *pub)
  962. {
  963. dhd_info_t *di = (dhd_info_t *)(pub->info);
  964. ASSERT(di != NULL);
  965. spin_lock_bh(&di->wlfc_spinlock);
  966. return 1;
  967. }
  968. int
  969. dhd_os_wlfc_unblock(dhd_pub_t *pub)
  970. {
  971. dhd_info_t *di = (dhd_info_t *)(pub->info);
  972. ASSERT(di != NULL);
  973. spin_unlock_bh(&di->wlfc_spinlock);
  974. return 1;
  975. }
  976. const uint8 wme_fifo2ac[] = { 0, 1, 2, 3, 1, 1 };
  977. uint8 prio2fifo[8] = { 1, 0, 0, 1, 2, 2, 3, 3 };
  978. #define WME_PRIO2AC(prio) wme_fifo2ac[prio2fifo[(prio)]]
  979. #endif /* PROP_TXSTATUS */
  980. int
  981. dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf)
  982. {
  983. int ret;
  984. dhd_info_t *dhd = (dhd_info_t *)(dhdp->info);
  985. struct ether_header *eh = NULL;
  986. /* Reject if down */
  987. if (!dhdp->up || (dhdp->busstate == DHD_BUS_DOWN)) {
  988. /* free the packet here since the caller won't */
  989. PKTFREE(dhdp->osh, pktbuf, TRUE);
  990. return -ENODEV;
  991. }
  992. /* Update multicast statistic */
  993. if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_ADDR_LEN) {
  994. uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf);
  995. eh = (struct ether_header *)pktdata;
  996. if (ETHER_ISMULTI(eh->ether_dhost))
  997. dhdp->tx_multicast++;
  998. if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X)
  999. atomic_inc(&dhd->pend_8021x_cnt);
  1000. }
  1001. /* Look into the packet and update the packet priority */
  1002. if (PKTPRIO(pktbuf) == 0)
  1003. pktsetprio(pktbuf, FALSE);
  1004. #ifdef PROP_TXSTATUS
  1005. if (dhdp->wlfc_state) {
  1006. /* store the interface ID */
  1007. DHD_PKTTAG_SETIF(PKTTAG(pktbuf), ifidx);
  1008. /* store destination MAC in the tag as well */
  1009. DHD_PKTTAG_SETDSTN(PKTTAG(pktbuf), eh->ether_dhost);
  1010. /* decide which FIFO this packet belongs to */
  1011. if (ETHER_ISMULTI(eh->ether_dhost))
  1012. /* one additional queue index (highest AC + 1) is used for bc/mc queue */
  1013. DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), AC_COUNT);
  1014. else
  1015. DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), WME_PRIO2AC(PKTPRIO(pktbuf)));
  1016. } else
  1017. #endif /* PROP_TXSTATUS */
  1018. /* If the protocol uses a data header, apply it */
  1019. dhd_prot_hdrpush(dhdp, ifidx, pktbuf);
  1020. /* Use bus module to send data frame */
  1021. #ifdef WLMEDIA_HTSF
  1022. dhd_htsf_addtxts(dhdp, pktbuf);
  1023. #endif
  1024. #ifdef PROP_TXSTATUS
  1025. if (dhdp->wlfc_state && ((athost_wl_status_info_t*)dhdp->wlfc_state)->proptxstatus_mode
  1026. != WLFC_FCMODE_NONE) {
  1027. dhd_os_wlfc_block(dhdp);
  1028. ret = dhd_wlfc_enque_sendq(dhdp->wlfc_state, DHD_PKTTAG_FIFO(PKTTAG(pktbuf)),
  1029. pktbuf);
  1030. dhd_wlfc_commit_packets(dhdp->wlfc_state, (f_commitpkt_t)dhd_bus_txdata,
  1031. dhdp->bus);
  1032. if (((athost_wl_status_info_t*)dhdp->wlfc_state)->toggle_host_if) {
  1033. ((athost_wl_status_info_t*)dhdp->wlfc_state)->toggle_host_if = 0;
  1034. }
  1035. dhd_os_wlfc_unblock(dhdp);
  1036. }
  1037. else
  1038. /* non-proptxstatus way */
  1039. ret = dhd_bus_txdata(dhdp->bus, pktbuf);
  1040. #else
  1041. ret = dhd_bus_txdata(dhdp->bus, pktbuf);
  1042. #endif /* PROP_TXSTATUS */
  1043. return ret;
  1044. }
  1045. int
  1046. dhd_start_xmit(struct sk_buff *skb, struct net_device *net)
  1047. {
  1048. int ret;
  1049. void *pktbuf;
  1050. dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
  1051. int ifidx;
  1052. #ifdef WLMEDIA_HTSF
  1053. uint8 htsfdlystat_sz = dhd->pub.htsfdlystat_sz;
  1054. #else
  1055. uint8 htsfdlystat_sz = 0;
  1056. #endif
  1057. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  1058. DHD_OS_WAKE_LOCK(&dhd->pub);
  1059. /* Reject if down */
  1060. if (!dhd->pub.up || (dhd->pub.busstate == DHD_BUS_DOWN)) {
  1061. DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d \n",
  1062. __FUNCTION__, dhd->pub.up, dhd->pub.busstate));
  1063. netif_stop_queue(net);
  1064. /* Send Event when bus down detected during data session */
  1065. if (dhd->pub.busstate == DHD_BUS_DOWN) {
  1066. DHD_ERROR(("%s: Event HANG sent up\n", __FUNCTION__));
  1067. net_os_send_hang_message(net);
  1068. }
  1069. DHD_OS_WAKE_UNLOCK(&dhd->pub);
  1070. return -ENODEV;
  1071. }
  1072. ifidx = dhd_net2idx(dhd, net);
  1073. if (ifidx == DHD_BAD_IF) {
  1074. DHD_ERROR(("%s: bad ifidx %d\n", __FUNCTION__, ifidx));
  1075. netif_stop_queue(net);
  1076. DHD_OS_WAKE_UNLOCK(&dhd->pub);
  1077. return -ENODEV;
  1078. }
  1079. /* Make sure there's enough room for any header */
  1080. if (skb_headroom(skb) < dhd->pub.hdrlen + htsfdlystat_sz) {
  1081. struct sk_buff *skb2;
  1082. DHD_INFO(("%s: insufficient headroom\n",
  1083. dhd_ifname(&dhd->pub, ifidx)));
  1084. dhd->pub.tx_realloc++;
  1085. skb2 = skb_realloc_headroom(skb, dhd->pub.hdrlen + htsfdlystat_sz);
  1086. dev_kfree_skb(skb);
  1087. if ((skb = skb2) == NULL) {
  1088. DHD_ERROR(("%s: skb_realloc_headroom failed\n",
  1089. dhd_ifname(&dhd->pub, ifidx)));
  1090. ret = -ENOMEM;
  1091. goto done;
  1092. }
  1093. }
  1094. /* Convert to packet */
  1095. if (!(pktbuf = PKTFRMNATIVE(dhd->pub.osh, skb))) {
  1096. DHD_ERROR(("%s: PKTFRMNATIVE failed\n",
  1097. dhd_ifname(&dhd->pub, ifidx)));
  1098. dev_kfree_skb_any(skb);
  1099. ret = -ENOMEM;
  1100. goto done;
  1101. }
  1102. #ifdef WLMEDIA_HTSF
  1103. if (htsfdlystat_sz && PKTLEN(dhd->pub.osh, pktbuf) >= ETHER_ADDR_LEN) {
  1104. uint8 *pktdata = (uint8 *)PKTDATA(dhd->pub.osh, pktbuf);
  1105. struct ether_header *eh = (struct ether_header *)pktdata;
  1106. if (!ETHER_ISMULTI(eh->ether_dhost) &&
  1107. (ntoh16(eh->ether_type) == ETHER_TYPE_IP)) {
  1108. eh->ether_type = hton16(ETHER_TYPE_BRCM_PKTDLYSTATS);
  1109. }
  1110. }
  1111. #endif
  1112. ret = dhd_sendpkt(&dhd->pub, ifidx, pktbuf);
  1113. done:
  1114. if (ret)
  1115. dhd->pub.dstats.tx_dropped++;
  1116. else
  1117. dhd->pub.tx_packets++;
  1118. DHD_OS_WAKE_UNLOCK(&dhd->pub);
  1119. /* Return ok: we always eat the packet */
  1120. return 0;
  1121. }
  1122. void
  1123. dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool state)
  1124. {
  1125. struct net_device *net;
  1126. dhd_info_t *dhd = dhdp->info;
  1127. int i;
  1128. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  1129. dhdp->txoff = state;
  1130. ASSERT(dhd);
  1131. if (ifidx == ALL_INTERFACES) {
  1132. /* Flow control on all active interfaces */
  1133. for (i = 0; i < DHD_MAX_IFS; i++) {
  1134. if (dhd->iflist[i]) {
  1135. net = dhd->iflist[i]->net;
  1136. if (state == ON)
  1137. netif_stop_queue(net);
  1138. else
  1139. netif_wake_queue(net);
  1140. }
  1141. }
  1142. }
  1143. else {
  1144. if (dhd->iflist[ifidx]) {
  1145. net = dhd->iflist[ifidx]->net;
  1146. if (state == ON)
  1147. netif_stop_queue(net);
  1148. else
  1149. netif_wake_queue(net);
  1150. }
  1151. }
  1152. }
  1153. void
  1154. dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
  1155. {
  1156. dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
  1157. struct sk_buff *skb;
  1158. uchar *eth;
  1159. uint len;
  1160. void *data, *pnext = NULL, *save_pktbuf;
  1161. int i;
  1162. dhd_if_t *ifp;
  1163. wl_event_msg_t event;
  1164. int tout = DHD_PACKET_TIMEOUT;
  1165. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  1166. save_pktbuf = pktbuf;
  1167. for (i = 0; pktbuf && i < numpkt; i++, pktbuf = pnext) {
  1168. struct ether_header *eh;
  1169. struct dot11_llc_snap_header *lsh;
  1170. ifp = dhd->iflist[ifidx];
  1171. if (ifp == NULL) {
  1172. DHD_ERROR(("%s: ifp is NULL. drop packet\n",
  1173. __FUNCTION__));
  1174. PKTFREE(dhdp->osh, pktbuf, TRUE);
  1175. continue;
  1176. }
  1177. /* Dropping packets before registering net device to avoid kernel panic */
  1178. if (!ifp->net || ifp->net->reg_state != NETREG_REGISTERED ||
  1179. !dhd->pub.up) {
  1180. DHD_ERROR(("%s: net device is NOT registered yet. drop packet\n",
  1181. __FUNCTION__));
  1182. PKTFREE(dhdp->osh, pktbuf, TRUE);
  1183. continue;
  1184. }
  1185. pnext = PKTNEXT(dhdp->osh, pktbuf);
  1186. PKTSETNEXT(wl->sh.osh, pktbuf, NULL);
  1187. eh = (struct ether_header *)PKTDATA(wl->sh.osh, pktbuf);
  1188. lsh = (struct dot11_llc_snap_header *)&eh[1];
  1189. if ((ntoh16(eh->ether_type) < ETHER_TYPE_MIN) &&
  1190. (PKTLEN(wl->sh.osh, pktbuf) >= RFC1042_HDR_LEN) &&
  1191. bcmp(lsh, BT_SIG_SNAP_MPROT, DOT11_LLC_SNAP_HDR_LEN - 2) == 0 &&
  1192. lsh->type == HTON16(BTA_PROT_L2CAP)) {
  1193. amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)
  1194. ((uint8 *)eh + RFC1042_HDR_LEN);
  1195. ACL_data = NULL;
  1196. }
  1197. #ifdef PROP_TXSTATUS
  1198. if (dhdp->wlfc_state && PKTLEN(wl->sh.osh, pktbuf) == 0) {
  1199. /* WLFC may send header only packet when
  1200. there is an urgent message but no packet to
  1201. piggy-back on
  1202. */
  1203. ((athost_wl_status_info_t*)dhdp->wlfc_state)->stats.wlfc_header_only_pkt++;
  1204. PKTFREE(dhdp->osh, pktbuf, TRUE);
  1205. continue;
  1206. }
  1207. #endif
  1208. skb = PKTTONATIVE(dhdp->osh, pktbuf);
  1209. /* Get the protocol, maintain skb around eth_type_trans()
  1210. * The main reason for this hack is for the limitation of
  1211. * Linux 2.4 where 'eth_type_trans' uses the 'net->hard_header_len'
  1212. * to perform skb_pull inside vs ETH_HLEN. Since to avoid
  1213. * coping of the packet coming from the network stack to add
  1214. * BDC, Hardware header etc, during network interface registration
  1215. * we set the 'net->hard_header_len' to ETH_HLEN + extra space required
  1216. * for BDC, Hardware header etc. and not just the ETH_HLEN
  1217. */
  1218. eth = skb->data;
  1219. len = skb->len;
  1220. ifp = dhd->iflist[ifidx];
  1221. if (ifp == NULL)
  1222. ifp = dhd->iflist[0];
  1223. ASSERT(ifp);
  1224. skb->dev = ifp->net;
  1225. skb->protocol = eth_type_trans(skb, skb->dev);
  1226. if (skb->pkt_type == PACKET_MULTICAST) {
  1227. dhd->pub.rx_multicast++;
  1228. }
  1229. skb->data = eth;
  1230. skb->len = len;
  1231. #ifdef WLMEDIA_HTSF
  1232. dhd_htsf_addrxts(dhdp, pktbuf);
  1233. #endif
  1234. /* Strip header, count, deliver upward */
  1235. skb_pull(skb, ETH_HLEN);
  1236. /* Process special event packets and then discard them */
  1237. if (ntoh16(skb->protocol) == ETHER_TYPE_BRCM) {
  1238. dhd_wl_host_event(dhd, &ifidx,
  1239. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
  1240. skb->mac_header,
  1241. #else
  1242. skb->mac.raw,
  1243. #endif
  1244. &event,
  1245. &data);
  1246. wl_event_to_host_order(&event);
  1247. if (event.event_type == WLC_E_BTA_HCI_EVENT) {
  1248. dhd_bta_doevt(dhdp, data, event.datalen);
  1249. }
  1250. tout = DHD_EVENT_TIMEOUT;
  1251. }
  1252. ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]);
  1253. if (dhd->iflist[ifidx] && !dhd->iflist[ifidx]->state)
  1254. ifp = dhd->iflist[ifidx];
  1255. if (ifp->net)
  1256. ifp->net->last_rx = jiffies;
  1257. dhdp->dstats.rx_bytes += skb->len;
  1258. dhdp->rx_packets++; /* Local count */
  1259. if (in_interrupt()) {
  1260. netif_rx(skb);
  1261. } else {
  1262. /* If the receive is not processed inside an ISR,
  1263. * the softirqd must be woken explicitly to service
  1264. * the NET_RX_SOFTIRQ. In 2.6 kernels, this is handled
  1265. * by netif_rx_ni(), but in earlier kernels, we need
  1266. * to do it manually.
  1267. */
  1268. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
  1269. netif_rx_ni(skb);
  1270. #else
  1271. ulong flags;
  1272. netif_rx(skb);
  1273. local_irq_save(flags);
  1274. RAISE_RX_SOFTIRQ();
  1275. local_irq_restore(flags);
  1276. #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */
  1277. }
  1278. }
  1279. DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(dhdp, tout);
  1280. }
  1281. void
  1282. dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx)
  1283. {
  1284. /* Linux version has nothing to do */
  1285. return;
  1286. }
  1287. void
  1288. dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success)
  1289. {
  1290. uint ifidx;
  1291. dhd_info_t *dhd = (dhd_info_t *)(dhdp->info);
  1292. struct ether_header *eh;
  1293. uint16 type;
  1294. uint len;
  1295. dhd_prot_hdrpull(dhdp, &ifidx, txp);
  1296. eh = (struct ether_header *)PKTDATA(dhdp->osh, txp);
  1297. type = ntoh16(eh->ether_type);
  1298. if (type == ETHER_TYPE_802_1X)
  1299. atomic_dec(&dhd->pend_8021x_cnt);
  1300. /* Crack open the packet and check to see if it is BT HCI ACL data packet.
  1301. * If yes generate packet completion event.
  1302. */
  1303. len = PKTLEN(dhdp->osh, txp);
  1304. /* Generate ACL data tx completion event locally to avoid SDIO bus transaction */
  1305. if ((type < ETHER_TYPE_MIN) && (len >= RFC1042_HDR_LEN)) {
  1306. struct dot11_llc_snap_header *lsh = (struct dot11_llc_snap_header *)&eh[1];
  1307. if (bcmp(lsh, BT_SIG_SNAP_MPROT, DOT11_LLC_SNAP_HDR_LEN - 2) == 0 &&
  1308. ntoh16(lsh->type) == BTA_PROT_L2CAP) {
  1309. dhd_bta_tx_hcidata_complete(dhdp, txp, success);
  1310. }
  1311. }
  1312. }
  1313. static struct net_device_stats *
  1314. dhd_get_stats(struct net_device *net)
  1315. {
  1316. dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
  1317. dhd_if_t *ifp;
  1318. int ifidx;
  1319. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  1320. ifidx = dhd_net2idx(dhd, net);
  1321. if (ifidx == DHD_BAD_IF)
  1322. return NULL;
  1323. ifp = dhd->iflist[ifidx];
  1324. ASSERT(dhd && ifp);
  1325. if (dhd->pub.up) {
  1326. /* Use the protocol to get dongle stats */
  1327. dhd_prot_dstats(&dhd->pub);
  1328. }
  1329. /* Copy dongle stats to net device stats */
  1330. ifp->stats.rx_packets = dhd->pub.dstats.rx_packets;
  1331. ifp->stats.tx_packets = dhd->pub.dstats.tx_packets;
  1332. ifp->stats.rx_bytes = dhd->pub.dstats.rx_bytes;
  1333. ifp->stats.tx_bytes = dhd->pub.dstats.tx_bytes;
  1334. ifp->stats.rx_errors = dhd->pub.dstats.rx_errors;
  1335. ifp->stats.tx_errors = dhd->pub.dstats.tx_errors;
  1336. ifp->stats.rx_dropped = dhd->pub.dstats.rx_dropped;
  1337. ifp->stats.tx_dropped = dhd->pub.dstats.tx_dropped;
  1338. ifp->stats.multicast = dhd->pub.dstats.multicast;
  1339. return &ifp->stats;
  1340. }
  1341. #ifdef DHDTHREAD
  1342. static int
  1343. dhd_watchdog_thread(void *data)
  1344. {
  1345. tsk_ctl_t *tsk = (tsk_ctl_t *)data;
  1346. dhd_info_t *dhd = (dhd_info_t *)tsk->parent;
  1347. /* This thread doesn't need any user-level access,
  1348. * so get rid of all our resources
  1349. */
  1350. if (dhd_watchdog_prio > 0) {
  1351. struct sched_param param;
  1352. param.sched_priority = (dhd_watchdog_prio < MAX_RT_PRIO)?
  1353. dhd_watchdog_prio:(MAX_RT_PRIO-1);
  1354. setScheduler(current, SCHED_FIFO, &param);
  1355. }
  1356. DAEMONIZE("dhd_watchdog");
  1357. /* Run until signal received */
  1358. complete(&tsk->completed);
  1359. while (1)
  1360. if (down_interruptible (&tsk->sema) == 0) {
  1361. unsigned long flags;
  1362. SMP_RD_BARRIER_DEPENDS();
  1363. if (tsk->terminated) {
  1364. break;
  1365. }
  1366. dhd_os_sdlock(&dhd->pub);
  1367. if (dhd->pub.dongle_reset == FALSE) {
  1368. DHD_TIMER(("%s:\n", __FUNCTION__));
  1369. /* Call the bus module watchdog */
  1370. dhd_bus_watchdog(&dhd->pub);
  1371. flags = dhd_os_spin_lock(&dhd->pub);
  1372. /* Count the tick for reference */
  1373. dhd->pub.tickcnt++;
  1374. /* Reschedule the watchdog */
  1375. if (dhd->wd_timer_valid)
  1376. mod_timer(&dhd->timer,
  1377. jiffies + dhd_watchdog_ms * HZ / 1000);
  1378. dhd_os_spin_unlock(&dhd->pub, flags);
  1379. }
  1380. dhd_os_sdunlock(&dhd->pub);
  1381. DHD_OS_WAKE_UNLOCK(&dhd->pub);
  1382. } else {
  1383. break;
  1384. }
  1385. complete_and_exit(&tsk->completed, 0);
  1386. }
  1387. #endif /* DHDTHREAD */
  1388. static void dhd_watchdog(ulong data)
  1389. {
  1390. dhd_info_t *dhd = (dhd_info_t *)data;
  1391. unsigned long flags;
  1392. DHD_OS_WAKE_LOCK(&dhd->pub);
  1393. if (dhd->pub.dongle_reset) {
  1394. DHD_OS_WAKE_UNLOCK(&dhd->pub);
  1395. return;
  1396. }
  1397. #ifdef DHDTHREAD
  1398. if (dhd->thr_wdt_ctl.thr_pid >= 0) {
  1399. up(&dhd->thr_wdt_ctl.sema);
  1400. return;
  1401. }
  1402. #endif /* DHDTHREAD */
  1403. dhd_os_sdlock(&dhd->pub);
  1404. /* Call the bus module watchdog */
  1405. dhd_bus_watchdog(&dhd->pub);
  1406. flags = dhd_os_spin_lock(&dhd->pub);
  1407. /* Count the tick for reference */
  1408. dhd->pub.tickcnt++;
  1409. /* Reschedule the watchdog */
  1410. if (dhd->wd_timer_valid)
  1411. mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000);
  1412. dhd_os_spin_unlock(&dhd->pub, flags);
  1413. dhd_os_sdunlock(&dhd->pub);
  1414. DHD_OS_WAKE_UNLOCK(&dhd->pub);
  1415. }
  1416. #ifdef DHDTHREAD
  1417. static int
  1418. dhd_dpc_thread(void *data)
  1419. {
  1420. tsk_ctl_t *tsk = (tsk_ctl_t *)data;
  1421. dhd_info_t *dhd = (dhd_info_t *)tsk->parent;
  1422. /* This thread doesn't need any user-level access,
  1423. * so get rid of all our resources
  1424. */
  1425. if (dhd_dpc_prio > 0)
  1426. {
  1427. struct sched_param param;
  1428. param.sched_priority = (dhd_dpc_prio < MAX_RT_PRIO)?dhd_dpc_prio:(MAX_RT_PRIO-1);
  1429. setScheduler(current, SCHED_FIFO, &param);
  1430. }
  1431. DAEMONIZE("dhd_dpc");
  1432. /* DHD_OS_WAKE_LOCK is called in dhd_sched_dpc[dhd_linux.c] down below */
  1433. /* signal: thread has started */
  1434. complete(&tsk->completed);
  1435. /* Run until signal received */
  1436. while (1) {
  1437. if (down_interruptible(&tsk->sema) == 0) {
  1438. SMP_RD_BARRIER_DEPENDS();
  1439. if (tsk->terminated) {
  1440. break;
  1441. }
  1442. /* Call bus dpc unless it indicated down (then clean stop) */
  1443. if (dhd->pub.busstate != DHD_BUS_DOWN) {
  1444. if (dhd_bus_dpc(dhd->pub.bus)) {
  1445. up(&tsk->sema);
  1446. }
  1447. else {
  1448. DHD_OS_WAKE_UNLOCK(&dhd->pub);
  1449. }
  1450. } else {
  1451. dhd_bus_stop(dhd->pub.bus, TRUE);
  1452. DHD_OS_WAKE_UNLOCK(&dhd->pub);
  1453. }
  1454. }
  1455. else
  1456. break;
  1457. }
  1458. complete_and_exit(&tsk->completed, 0);
  1459. }
  1460. #endif /* DHDTHREAD */
  1461. static void
  1462. dhd_dpc(ulong data)
  1463. {
  1464. dhd_info_t *dhd;
  1465. dhd = (dhd_info_t *)data;
  1466. /* this (tasklet) can be scheduled in dhd_sched_dpc[dhd_linux.c]
  1467. * down below , wake lock is set,
  1468. * the tasklet is initialized in dhd_attach()
  1469. */
  1470. /* Call bus dpc unless it indicated down (then clean stop) */
  1471. if (dhd->pub.busstate != DHD_BUS_DOWN) {
  1472. if (dhd_bus_dpc(dhd->pub.bus))
  1473. tasklet_schedule(&dhd->tasklet);
  1474. else
  1475. DHD_OS_WAKE_UNLOCK(&dhd->pub);
  1476. } else {
  1477. dhd_bus_stop(dhd->pub.bus, TRUE);
  1478. DHD_OS_WAKE_UNLOCK(&dhd->pub);
  1479. }
  1480. }
  1481. void
  1482. dhd_sched_dpc(dhd_pub_t *dhdp)
  1483. {
  1484. dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
  1485. DHD_OS_WAKE_LOCK(dhdp);
  1486. #ifdef DHDTHREAD
  1487. if (dhd->thr_dpc_ctl.thr_pid >= 0) {
  1488. up(&dhd->thr_dpc_ctl.sema);
  1489. return;
  1490. }
  1491. #endif /* DHDTHREAD */
  1492. tasklet_schedule(&dhd->tasklet);
  1493. }
  1494. #ifdef TOE
  1495. /* Retrieve current toe component enables, which are kept as a bitmap in toe_ol iovar */
  1496. static int
  1497. dhd_toe_get(dhd_info_t *dhd, int ifidx, uint32 *toe_ol)
  1498. {
  1499. wl_ioctl_t ioc;
  1500. char buf[32];
  1501. int ret;
  1502. memset(&ioc, 0, sizeof(ioc));
  1503. ioc.cmd = WLC_GET_VAR;
  1504. ioc.buf = buf;
  1505. ioc.len = (uint)sizeof(buf);
  1506. ioc.set = FALSE;
  1507. strcpy(buf, "toe_ol");
  1508. if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
  1509. /* Check for older dongle image that doesn't support toe_ol */
  1510. if (ret == -EIO) {
  1511. DHD_ERROR(("%s: toe not supported by device\n",
  1512. dhd_ifname(&dhd->pub, ifidx)));
  1513. return -EOPNOTSUPP;
  1514. }
  1515. DHD_INFO(("%s: could not get toe_ol: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret));
  1516. return ret;
  1517. }
  1518. memcpy(toe_ol, buf, sizeof(uint32));
  1519. return 0;
  1520. }
  1521. /* Set current toe component enables in toe_ol iovar, and set toe global enable iovar */
  1522. static int
  1523. dhd_toe_set(dhd_info_t *dhd, int ifidx, uint32 toe_ol)
  1524. {
  1525. wl_ioctl_t ioc;
  1526. char buf[32];
  1527. int toe, ret;
  1528. memset(&ioc, 0, sizeof(ioc));
  1529. ioc.cmd = WLC_SET_VAR;
  1530. ioc.buf = buf;
  1531. ioc.len = (uint)sizeof(buf);
  1532. ioc.set = TRUE;
  1533. /* Set toe_ol as requested */
  1534. strcpy(buf, "toe_ol");
  1535. memcpy(&buf[sizeof("toe_ol")], &toe_ol, sizeof(uint32));
  1536. if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
  1537. DHD_ERROR(("%s: could not set toe_ol: ret=%d\n",
  1538. dhd_ifname(&dhd->pub, ifidx), ret));
  1539. return ret;
  1540. }
  1541. /* Enable toe globally only if any components are enabled. */
  1542. toe = (toe_ol != 0);
  1543. strcpy(buf, "toe");
  1544. memcpy(&buf[sizeof("toe")], &toe, sizeof(uint32));
  1545. if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
  1546. DHD_ERROR(("%s: could not set toe: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret));
  1547. return ret;
  1548. }
  1549. return 0;
  1550. }
  1551. #endif /* TOE */
  1552. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
  1553. static void
  1554. dhd_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
  1555. {
  1556. dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
  1557. sprintf(info->driver, "wl");
  1558. sprintf(info->version, "%lu", dhd->pub.drv_version);
  1559. }
  1560. struct ethtool_ops dhd_ethtool_ops = {
  1561. .get_drvinfo = dhd_ethtool_get_drvinfo
  1562. };
  1563. #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */
  1564. #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2)
  1565. static int
  1566. dhd_ethtool(dhd_info_t *dhd, void *uaddr)
  1567. {
  1568. struct ethtool_drvinfo info;
  1569. char drvname[sizeof(info.driver)];
  1570. uint32 cmd;
  1571. #ifdef TOE
  1572. struct ethtool_value edata;
  1573. uint32 toe_cmpnt, csum_dir;
  1574. int ret;
  1575. #endif
  1576. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  1577. /* all ethtool calls start with a cmd word */
  1578. if (copy_from_user(&cmd, uaddr, sizeof (uint32)))
  1579. return -EFAULT;
  1580. switch (cmd) {
  1581. case ETHTOOL_GDRVINFO:
  1582. /* Copy out any request driver name */
  1583. if (copy_from_user(&info, uaddr, sizeof(info)))
  1584. return -EFAULT;
  1585. strncpy(drvname, info.driver, sizeof(info.driver));
  1586. drvname[sizeof(info.driver)-1] = '\0';
  1587. /* clear struct for return */
  1588. memset(&info, 0, sizeof(info));
  1589. info.cmd = cmd;
  1590. /* if dhd requested, identify ourselves */
  1591. if (strcmp(drvname, "?dhd") == 0) {
  1592. sprintf(info.driver, "dhd");
  1593. strcpy(info.version, EPI_VERSION_STR);
  1594. }
  1595. /* otherwise, require dongle to be up */
  1596. else if (!dhd->pub.up) {
  1597. DHD_ERROR(("%s: dongle is not up\n", __FUNCTION__));
  1598. return -ENODEV;
  1599. }
  1600. /* finally, report dongle driver type */
  1601. else if (dhd->pub.iswl)
  1602. sprintf(info.driver, "wl");
  1603. else
  1604. sprintf(info.driver, "xx");
  1605. sprintf(info.version, "%lu", dhd->pub.drv_version);
  1606. if (copy_to_user(uaddr, &info, sizeof(info)))
  1607. return -EFAULT;
  1608. DHD_CTL(("%s: given %*s, returning %s\n", __FUNCTION__,
  1609. (int)sizeof(drvname), drvname, info.driver));
  1610. break;
  1611. #ifdef TOE
  1612. /* Get toe offload components from dongle */
  1613. case ETHTOOL_GRXCSUM:
  1614. case ETHTOOL_GTXCSUM:
  1615. if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0)
  1616. return ret;
  1617. csum_dir = (cmd == ETHTOOL_GTXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;
  1618. edata.cmd = cmd;
  1619. edata.data = (toe_cmpnt & csum_dir) ? 1 : 0;
  1620. if (copy_to_user(uaddr, &edata, sizeof(edata)))
  1621. return -EFAULT;
  1622. break;
  1623. /* Set toe offload components in dongle */
  1624. case ETHTOOL_SRXCSUM:
  1625. case ETHTOOL_STXCSUM:
  1626. if (copy_from_user(&edata, uaddr, sizeof(edata)))
  1627. return -EFAULT;
  1628. /* Read the current settings, update and write back */
  1629. if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0)
  1630. return ret;
  1631. csum_dir = (cmd == ETHTOOL_STXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;
  1632. if (edata.data != 0)
  1633. toe_cmpnt |= csum_dir;
  1634. else
  1635. toe_cmpnt &= ~csum_dir;
  1636. if ((ret = dhd_toe_set(dhd, 0, toe_cmpnt)) < 0)
  1637. return ret;
  1638. /* If setting TX checksum mode, tell Linux the new mode */
  1639. if (cmd == ETHTOOL_STXCSUM) {
  1640. if (edata.data)
  1641. dhd->iflist[0]->net->features |= NETIF_F_IP_CSUM;
  1642. else
  1643. dhd->iflist[0]->net->features &= ~NETIF_F_IP_CSUM;
  1644. }
  1645. break;
  1646. #endif /* TOE */
  1647. default:
  1648. return -EOPNOTSUPP;
  1649. }
  1650. return 0;
  1651. }
  1652. #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */
  1653. static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error)
  1654. {
  1655. if (!dhdp)
  1656. return FALSE;
  1657. if ((error == -ETIMEDOUT) || ((dhdp->busstate == DHD_BUS_DOWN) &&
  1658. (!dhdp->dongle_reset))) {
  1659. DHD_ERROR(("%s: Event HANG send up due to re=%d te=%d e=%d s=%d\n", __FUNCTION__,
  1660. dhdp->rxcnt_timeout, dhdp->txcnt_timeout, error, dhdp->busstate));
  1661. net_os_send_hang_message(net);
  1662. return TRUE;
  1663. }
  1664. return FALSE;
  1665. }
  1666. static int
  1667. dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
  1668. {
  1669. dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
  1670. dhd_ioctl_t ioc;
  1671. int bcmerror = 0;
  1672. int buflen = 0;
  1673. void *buf = NULL;
  1674. uint driver = 0;
  1675. int ifidx;
  1676. int ret;
  1677. DHD_OS_WAKE_LOCK(&dhd->pub);
  1678. /* send to dongle only if we are not waiting for reload already */
  1679. if (dhd->pub.hang_was_sent) {
  1680. DHD_ERROR(("%s: HANG was sent up earlier\n", __FUNCTION__));
  1681. DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT);
  1682. DHD_OS_WAKE_UNLOCK(&dhd->pub);
  1683. return OSL_ERROR(BCME_DONGLE_DOWN);
  1684. }
  1685. ifidx = dhd_net2idx(dhd, net);
  1686. DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd));
  1687. if (ifidx == DHD_BAD_IF) {
  1688. DHD_OS_WAKE_UNLOCK(&dhd->pub);
  1689. return -1;
  1690. }
  1691. #if defined(CONFIG_WIRELESS_EXT)
  1692. /* linux wireless extensions */
  1693. if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) {
  1694. /* may recurse, do NOT lock */
  1695. ret = wl_iw_ioctl(net, ifr, cmd);
  1696. DHD_OS_WAKE_UNLOCK(&dhd->pub);
  1697. return ret;
  1698. }
  1699. #endif /* defined(CONFIG_WIRELESS_EXT) */
  1700. #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2)
  1701. if (cmd == SIOCETHTOOL) {
  1702. ret = dhd_ethtool(dhd, (void*)ifr->ifr_data);
  1703. DHD_OS_WAKE_UNLOCK(&dhd->pub);
  1704. return ret;
  1705. }
  1706. #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */
  1707. if (cmd == SIOCDEVPRIVATE+1) {
  1708. ret = wl_android_priv_cmd(net, ifr, cmd);
  1709. dhd_check_hang(net, &dhd->pub, ret);
  1710. DHD_OS_WAKE_UNLOCK(&dhd->pub);
  1711. return ret;
  1712. }
  1713. if (cmd != SIOCDEVPRIVATE) {
  1714. DHD_OS_WAKE_UNLOCK(&dhd->pub);
  1715. return -EOPNOTSUPP;
  1716. }
  1717. memset(&ioc, 0, sizeof(ioc));
  1718. /* Copy the ioc control structure part of ioctl request */
  1719. if (copy_from_user(&ioc, ifr->ifr_data, sizeof(wl_ioctl_t))) {
  1720. bcmerror = -BCME_BADADDR;
  1721. goto done;
  1722. }
  1723. /* Copy out any buffer passed */
  1724. if (ioc.buf) {
  1725. buflen = MIN(ioc.len, DHD_IOCTL_MAXLEN);
  1726. /* optimization for direct ioctl calls from kernel */
  1727. /*
  1728. if (segment_eq(get_fs(), KERNEL_DS)) {
  1729. buf = ioc.buf;
  1730. } else {
  1731. */
  1732. {
  1733. if (!(buf = (char*)MALLOC(dhd->pub.osh, buflen))) {
  1734. bcmerror = -BCME_NOMEM;
  1735. goto done;
  1736. }
  1737. if (copy_from_user(buf, ioc.buf, buflen)) {
  1738. bcmerror = -BCME_BADADDR;
  1739. goto done;
  1740. }
  1741. }
  1742. }
  1743. /* To differentiate between wl and dhd read 4 more byes */
  1744. if ((copy_from_user(&driver, (char *)ifr->ifr_data + sizeof(wl_ioctl_t),
  1745. sizeof(uint)) != 0)) {
  1746. bcmerror = -BCME_BADADDR;
  1747. goto done;
  1748. }
  1749. if (!capable(CAP_NET_ADMIN)) {
  1750. bcmerror = -BCME_EPERM;
  1751. goto done;
  1752. }
  1753. /* check for local dhd ioctl and handle it */
  1754. if (driver == DHD_IOCTL_MAGIC) {
  1755. bcmerror = dhd_ioctl((void *)&dhd->pub, &ioc, buf, buflen);
  1756. if (bcmerror)
  1757. dhd->pub.bcmerror = bcmerror;
  1758. goto done;
  1759. }
  1760. /* send to dongle (must be up, and wl). */
  1761. if (dhd->pub.busstate != DHD_BUS_DATA) {
  1762. bcmerror = BCME_DONGLE_DOWN;
  1763. goto done;
  1764. }
  1765. if (!dhd->pub.iswl) {
  1766. bcmerror = BCME_DONGLE_DOWN;
  1767. goto done;
  1768. }
  1769. /*
  1770. * Flush the TX queue if required for proper message serialization:
  1771. * Intercept WLC_SET_KEY IOCTL - serialize M4 send and set key IOCTL to
  1772. * prevent M4 encryption and
  1773. * intercept WLC_DISASSOC IOCTL - serialize WPS-DONE and WLC_DISASSOC IOCTL to
  1774. * prevent disassoc frame being sent before WPS-DONE frame.
  1775. */
  1776. if (ioc.cmd == WLC_SET_KEY ||
  1777. (ioc.cmd == WLC_SET_VAR && ioc.buf != NULL &&
  1778. strncmp("wsec_key", ioc.buf, 9) == 0) ||
  1779. (ioc.cmd == WLC_SET_VAR && ioc.buf != NULL &&
  1780. strncmp("bsscfg:wsec_key", ioc.buf, 15) == 0) ||
  1781. ioc.cmd == WLC_DISASSOC)
  1782. dhd_wait_pend8021x(net);
  1783. #ifdef WLMEDIA_HTSF
  1784. if (ioc.buf) {
  1785. /* short cut wl ioctl calls here */
  1786. if (strcmp("htsf", ioc.buf) == 0) {
  1787. dhd_ioctl_htsf_get(dhd, 0);
  1788. return BCME_OK;
  1789. }
  1790. if (strcmp("htsflate", ioc.buf) == 0) {
  1791. if (ioc.set) {
  1792. memset(ts, 0, sizeof(tstamp_t)*TSMAX);
  1793. memset(&maxdelayts, 0, sizeof(tstamp_t));
  1794. maxdelay = 0;
  1795. tspktcnt = 0;
  1796. maxdelaypktno = 0;
  1797. memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN);
  1798. memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN);
  1799. memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN);
  1800. memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN);
  1801. } else {
  1802. dhd_dump_latency();
  1803. }
  1804. return BCME_OK;
  1805. }
  1806. if (strcmp("htsfclear", ioc.buf) == 0) {
  1807. memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN);
  1808. memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN);
  1809. memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN);
  1810. memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN);
  1811. htsf_seqnum = 0;
  1812. return BCME_OK;
  1813. }
  1814. if (strcmp("htsfhis", ioc.buf) == 0) {
  1815. dhd_dump_htsfhisto(&vi_d1, "H to D");
  1816. dhd_dump_htsfhisto(&vi_d2, "D to D");
  1817. dhd_dump_htsfhisto(&vi_d3, "D to H");
  1818. dhd_dump_htsfhisto(&vi_d4, "H to H");
  1819. return BCME_OK;
  1820. }
  1821. if (strcmp("tsport", ioc.buf) == 0) {
  1822. if (ioc.set) {
  1823. memcpy(&tsport, ioc.buf + 7, 4);
  1824. } else {
  1825. DHD_ERROR(("current timestamp port: %d \n", tsport));
  1826. }
  1827. return BCME_OK;
  1828. }
  1829. }
  1830. #endif /* WLMEDIA_HTSF */
  1831. bcmerror = dhd_wl_ioctl(&dhd->pub, ifidx, (wl_ioctl_t *)&ioc, buf, buflen);
  1832. done:
  1833. dhd_check_hang(net, &dhd->pub, bcmerror);
  1834. if (!bcmerror && buf && ioc.buf) {
  1835. if (copy_to_user(ioc.buf, buf, buflen))
  1836. bcmerror = -EFAULT;
  1837. }
  1838. if (buf)
  1839. MFREE(dhd->pub.osh, buf, buflen);
  1840. DHD_OS_WAKE_UNLOCK(&dhd->pub);
  1841. return OSL_ERROR(bcmerror);
  1842. }
  1843. #ifdef WL_CFG80211
  1844. static int
  1845. dhd_cleanup_virt_ifaces(dhd_info_t *dhd)
  1846. {
  1847. int i = 1; /* Leave ifidx 0 [Primary Interface] */
  1848. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
  1849. int rollback_lock = FALSE;
  1850. #endif
  1851. DHD_TRACE(("%s: Enter \n", __func__));
  1852. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
  1853. /* release lock for unregister_netdev */
  1854. if (rtnl_is_locked()) {
  1855. rtnl_unlock();
  1856. rollback_lock = TRUE;
  1857. }
  1858. #endif
  1859. for (i = 1; i < DHD_MAX_IFS; i++) {
  1860. if (dhd->iflist[i]) {
  1861. DHD_TRACE(("Deleting IF: %d \n", i));
  1862. if (dhd->iflist[i]->state != WLC_E_IF_DEL) {
  1863. dhd->iflist[i]->state = WLC_E_IF_DEL;
  1864. dhd->iflist[i]->idx = i;
  1865. dhd_op_if(dhd->iflist[i]);
  1866. }
  1867. }
  1868. }
  1869. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
  1870. if (rollback_lock)
  1871. rtnl_lock();
  1872. #endif
  1873. return 0;
  1874. }
  1875. #endif /* WL_CFG80211 */
  1876. static int
  1877. dhd_stop(struct net_device *net)
  1878. {
  1879. int ifidx;
  1880. dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
  1881. DHD_OS_WAKE_LOCK(&dhd->pub);
  1882. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  1883. if (dhd->pub.up == 0) {
  1884. goto exit;
  1885. }
  1886. ifidx = dhd_net2idx(dhd, net);
  1887. #ifdef WL_CFG80211
  1888. if (ifidx == 0) {
  1889. wl_cfg80211_down();
  1890. /** For CFG80211: Clean up all the left over virtual interfaces
  1891. * when the primary Interface is brought down. [ifconfig wlan0 down]
  1892. */
  1893. if ((dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) &&
  1894. (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) {
  1895. dhd_cleanup_virt_ifaces(dhd);
  1896. }
  1897. }
  1898. #endif
  1899. #ifdef PROP_TXSTATUS
  1900. dhd_wlfc_cleanup(&dhd->pub);
  1901. #endif
  1902. /* Set state and stop OS transmissions */
  1903. dhd->pub.up = 0;
  1904. netif_stop_queue(net);
  1905. /* Stop the protocol module */
  1906. dhd_prot_stop(&dhd->pub);
  1907. #if defined(WL_CFG80211)
  1908. if (ifidx == 0 && !dhd_download_fw_on_driverload)
  1909. wl_android_wifi_off(net);
  1910. #endif
  1911. dhd->pub.hang_was_sent = 0;
  1912. dhd->pub.rxcnt_timeout = 0;
  1913. dhd->pub.txcnt_timeout = 0;
  1914. OLD_MOD_DEC_USE_COUNT;
  1915. exit:
  1916. DHD_OS_WAKE_UNLOCK(&dhd->pub);
  1917. return 0;
  1918. }
  1919. static int
  1920. dhd_open(struct net_device *net)
  1921. {
  1922. dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
  1923. #ifdef TOE
  1924. uint32 toe_ol;
  1925. #endif
  1926. int ifidx;
  1927. int32 ret = 0;
  1928. DHD_OS_WAKE_LOCK(&dhd->pub);
  1929. /* Update FW path if it was changed */
  1930. if ((firmware_path != NULL) && (firmware_path[0] != '\0')) {
  1931. if (firmware_path[strlen(firmware_path)-1] == '\n')
  1932. firmware_path[strlen(firmware_path)-1] = '\0';
  1933. strcpy(fw_path, firmware_path);
  1934. firmware_path[0] = '\0';
  1935. }
  1936. #if !defined(WL_CFG80211)
  1937. /** Force start if ifconfig_up gets called before START command
  1938. * We keep WEXT's wl_control_wl_start to provide backward compatibility
  1939. * This should be removed in the future
  1940. */
  1941. wl_control_wl_start(net);
  1942. #endif
  1943. ifidx = dhd_net2idx(dhd, net);
  1944. DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx));
  1945. if (ifidx < 0) {
  1946. DHD_ERROR(("%s: Error: called with invalid IF\n", __FUNCTION__));
  1947. ret = -1;
  1948. goto exit;
  1949. }
  1950. if (!dhd->iflist[ifidx] || dhd->iflist[ifidx]->state == WLC_E_IF_DEL) {
  1951. DHD_ERROR(("%s: Error: called when IF already deleted\n", __FUNCTION__));
  1952. ret = -1;
  1953. goto exit;
  1954. }
  1955. if (ifidx == 0) {
  1956. atomic_set(&dhd->pend_8021x_cnt, 0);
  1957. #if defined(WL_CFG80211)
  1958. DHD_ERROR(("\n%s\n", dhd_version));
  1959. if (!dhd_download_fw_on_driverload)
  1960. wl_android_wifi_on(net);
  1961. #endif /* defined(WL_CFG80211) */
  1962. if (dhd->pub.busstate != DHD_BUS_DATA) {
  1963. int ret;
  1964. /* try to bring up bus */
  1965. if ((ret = dhd_bus_start(&dhd->pub)) != 0) {
  1966. DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret));
  1967. ret = -1;
  1968. goto exit;
  1969. }
  1970. }
  1971. /* dhd_prot_init has been called in dhd_bus_start or wl_android_wifi_on */
  1972. memcpy(net->dev_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN);
  1973. #ifdef TOE
  1974. /* Get current TOE mode from dongle */
  1975. if (dhd_toe_get(dhd, ifidx, &toe_ol) >= 0 && (toe_ol & TOE_TX_CSUM_OL) != 0)
  1976. dhd->iflist[ifidx]->net->features |= NETIF_F_IP_CSUM;
  1977. else
  1978. dhd->iflist[ifidx]->net->features &= ~NETIF_F_IP_CSUM;
  1979. #endif /* TOE */
  1980. #if defined(WL_CFG80211)
  1981. if (unlikely(wl_cfg80211_up())) {
  1982. DHD_ERROR(("%s: failed to bring up cfg80211\n", __FUNCTION__));
  1983. ret = -1;
  1984. goto exit;
  1985. }
  1986. #endif /* WL_CFG80211 */
  1987. }
  1988. /* Allow transmit calls */
  1989. netif_start_queue(net);
  1990. dhd->pub.up = 1;
  1991. #ifdef BCMDBGFS
  1992. dhd_dbg_init(&dhd->pub);
  1993. #endif
  1994. OLD_MOD_INC_USE_COUNT;
  1995. exit:
  1996. DHD_OS_WAKE_UNLOCK(&dhd->pub);
  1997. return ret;
  1998. }
  1999. osl_t *
  2000. dhd_osl_attach(void *pdev, uint bustype)
  2001. {
  2002. return osl_attach(pdev, bustype, TRUE);
  2003. }
  2004. void
  2005. dhd_osl_detach(osl_t *osh)
  2006. {
  2007. if (MALLOCED(osh)) {
  2008. DHD_ERROR(("%s: MEMORY LEAK %d bytes\n", __FUNCTION__, MALLOCED(osh)));
  2009. }
  2010. osl_detach(osh);
  2011. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
  2012. up(&dhd_registration_sem);
  2013. #endif
  2014. }
  2015. int
  2016. dhd_add_if(dhd_info_t *dhd, int ifidx, void *handle, char *name,
  2017. uint8 *mac_addr, uint32 flags, uint8 bssidx)
  2018. {
  2019. dhd_if_t *ifp;
  2020. DHD_TRACE(("%s: idx %d, handle->%p\n", __FUNCTION__, ifidx, handle));
  2021. ASSERT(dhd && (ifidx < DHD_MAX_IFS));
  2022. ifp = dhd->iflist[ifidx];
  2023. if (ifp != NULL) {
  2024. if (ifp->net != NULL) {
  2025. netif_stop_queue(ifp->net);
  2026. unregister_netdev(ifp->net);
  2027. free_netdev(ifp->net);
  2028. }
  2029. } else
  2030. if ((ifp = MALLOC(dhd->pub.osh, sizeof(dhd_if_t))) == NULL) {
  2031. DHD_ERROR(("%s: OOM - dhd_if_t\n", __FUNCTION__));
  2032. return -ENOMEM;
  2033. }
  2034. memset(ifp, 0, sizeof(dhd_if_t));
  2035. ifp->info = dhd;
  2036. dhd->iflist[ifidx] = ifp;
  2037. strncpy(ifp->name, name, IFNAMSIZ);
  2038. ifp->name[IFNAMSIZ] = '\0';
  2039. if (mac_addr != NULL)
  2040. memcpy(&ifp->mac_addr, mac_addr, ETHER_ADDR_LEN);
  2041. if (handle == NULL) {
  2042. ifp->state = WLC_E_IF_ADD;
  2043. ifp->idx = ifidx;
  2044. ifp->bssidx = bssidx;
  2045. ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0);
  2046. up(&dhd->thr_sysioc_ctl.sema);
  2047. } else
  2048. ifp->net = (struct net_device *)handle;
  2049. return 0;
  2050. }
  2051. void
  2052. dhd_del_if(dhd_info_t *dhd, int ifidx)
  2053. {
  2054. dhd_if_t *ifp;
  2055. DHD_TRACE(("%s: idx %d\n", __FUNCTION__, ifidx));
  2056. ASSERT(dhd && ifidx && (ifidx < DHD_MAX_IFS));
  2057. ifp = dhd->iflist[ifidx];
  2058. if (!ifp) {
  2059. DHD_ERROR(("%s: Null interface\n", __FUNCTION__));
  2060. return;
  2061. }
  2062. ifp->state = WLC_E_IF_DEL;
  2063. ifp->idx = ifidx;
  2064. ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0);
  2065. up(&dhd->thr_sysioc_ctl.sema);
  2066. }
  2067. dhd_pub_t *
  2068. dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
  2069. {
  2070. dhd_info_t *dhd = NULL;
  2071. struct net_device *net = NULL;
  2072. dhd_attach_states_t dhd_state = DHD_ATTACH_STATE_INIT;
  2073. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  2074. /* updates firmware nvram path if it was provided as module parameters */
  2075. if ((firmware_path != NULL) && (firmware_path[0] != '\0'))
  2076. strcpy(fw_path, firmware_path);
  2077. if ((nvram_path != NULL) && (nvram_path[0] != '\0'))
  2078. strcpy(nv_path, nvram_path);
  2079. /* Allocate etherdev, including space for private structure */
  2080. if (!(net = alloc_etherdev(sizeof(dhd)))) {
  2081. DHD_ERROR(("%s: OOM - alloc_etherdev\n", __FUNCTION__));
  2082. goto fail;
  2083. }
  2084. dhd_state |= DHD_ATTACH_STATE_NET_ALLOC;
  2085. /* Allocate primary dhd_info */
  2086. if (!(dhd = MALLOC(osh, sizeof(dhd_info_t)))) {
  2087. DHD_ERROR(("%s: OOM - alloc dhd_info\n", __FUNCTION__));
  2088. goto fail;
  2089. }
  2090. memset(dhd, 0, sizeof(dhd_info_t));
  2091. #ifdef DHDTHREAD
  2092. dhd->thr_dpc_ctl.thr_pid = DHD_PID_KT_TL_INVALID;
  2093. dhd->thr_wdt_ctl.thr_pid = DHD_PID_KT_INVALID;
  2094. #else
  2095. dhd->dhd_tasklet_create = FALSE;
  2096. #endif /* DHDTHREAD */
  2097. dhd->thr_sysioc_ctl.thr_pid = DHD_PID_KT_INVALID;
  2098. dhd_state |= DHD_ATTACH_STATE_DHD_ALLOC;
  2099. /*
  2100. * Save the dhd_info into the priv
  2101. */
  2102. memcpy((void *)netdev_priv(net), &dhd, sizeof(dhd));
  2103. dhd->pub.osh = osh;
  2104. /* Link to info module */
  2105. dhd->pub.info = dhd;
  2106. /* Link to bus module */
  2107. dhd->pub.bus = bus;
  2108. dhd->pub.hdrlen = bus_hdrlen;
  2109. /* Set network interface name if it was provided as module parameter */
  2110. if (iface_name[0]) {
  2111. int len;
  2112. char ch;
  2113. strncpy(net->name, iface_name, IFNAMSIZ);
  2114. net->name[IFNAMSIZ - 1] = 0;
  2115. len = strlen(net->name);
  2116. ch = net->name[len - 1];
  2117. if ((ch > '9' || ch < '0') && (len < IFNAMSIZ - 2))
  2118. strcat(net->name, "%d");
  2119. }
  2120. if (dhd_add_if(dhd, 0, (void *)net, net->name, NULL, 0, 0) == DHD_BAD_IF)
  2121. goto fail;
  2122. dhd_state |= DHD_ATTACH_STATE_ADD_IF;
  2123. #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
  2124. net->open = NULL;
  2125. #else
  2126. net->netdev_ops = NULL;
  2127. #endif
  2128. sema_init(&dhd->proto_sem, 1);
  2129. #ifdef PROP_TXSTATUS
  2130. spin_lock_init(&dhd->wlfc_spinlock);
  2131. dhd->pub.wlfc_enabled = TRUE;
  2132. #endif /* PROP_TXSTATUS */
  2133. /* Initialize other structure content */
  2134. init_waitqueue_head(&dhd->ioctl_resp_wait);
  2135. init_waitqueue_head(&dhd->ctrl_wait);
  2136. /* Initialize the spinlocks */
  2137. spin_lock_init(&dhd->sdlock);
  2138. spin_lock_init(&dhd->txqlock);
  2139. spin_lock_init(&dhd->dhd_lock);
  2140. /* Initialize Wakelock stuff */
  2141. spin_lock_init(&dhd->wakelock_spinlock);
  2142. dhd->wakelock_counter = 0;
  2143. dhd->wakelock_timeout_enable = 0;
  2144. #ifdef CONFIG_HAS_WAKELOCK
  2145. wake_lock_init(&dhd->wl_wifi, WAKE_LOCK_SUSPEND, "wlan_wake");
  2146. wake_lock_init(&dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake");
  2147. #endif
  2148. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
  2149. mutex_init(&dhd->dhd_net_if_mutex);
  2150. #endif
  2151. dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT;
  2152. /* Attach and link in the protocol */
  2153. if (dhd_prot_attach(&dhd->pub) != 0) {
  2154. DHD_ERROR(("dhd_prot_attach failed\n"));
  2155. goto fail;
  2156. }
  2157. dhd_state |= DHD_ATTACH_STATE_PROT_ATTACH;
  2158. #ifdef WL_CFG80211
  2159. /* Attach and link in the cfg80211 */
  2160. if (unlikely(wl_cfg80211_attach(net, &dhd->pub))) {
  2161. DHD_ERROR(("wl_cfg80211_attach failed\n"));
  2162. goto fail;
  2163. }
  2164. dhd_monitor_init(&dhd->pub);
  2165. dhd_state |= DHD_ATTACH_STATE_CFG80211;
  2166. #endif
  2167. #if defined(CONFIG_WIRELESS_EXT)
  2168. /* Attach and link in the iw */
  2169. if (!(dhd_state & DHD_ATTACH_STATE_CFG80211)) {
  2170. if (wl_iw_attach(net, (void *)&dhd->pub) != 0) {
  2171. DHD_ERROR(("wl_iw_attach failed\n"));
  2172. goto fail;
  2173. }
  2174. dhd_state |= DHD_ATTACH_STATE_WL_ATTACH;
  2175. }
  2176. #endif /* defined(CONFIG_WIRELESS_EXT) */
  2177. /* Set up the watchdog timer */
  2178. init_timer(&dhd->timer);
  2179. dhd->timer.data = (ulong)dhd;
  2180. dhd->timer.function = dhd_watchdog;
  2181. #ifdef DHDTHREAD
  2182. /* Initialize thread based operation and lock */
  2183. sema_init(&dhd->sdsem, 1);
  2184. if ((dhd_watchdog_prio >= 0) && (dhd_dpc_prio >= 0)) {
  2185. dhd->threads_only = TRUE;
  2186. }
  2187. else {
  2188. dhd->threads_only = FALSE;
  2189. }
  2190. if (dhd_dpc_prio >= 0) {
  2191. /* Initialize watchdog thread */
  2192. PROC_START(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0);
  2193. } else {
  2194. dhd->thr_wdt_ctl.thr_pid = -1;
  2195. }
  2196. /* Set up the bottom half handler */
  2197. if (dhd_dpc_prio >= 0) {
  2198. /* Initialize DPC thread */
  2199. PROC_START(dhd_dpc_thread, dhd, &dhd->thr_dpc_ctl, 0);
  2200. } else {
  2201. /* use tasklet for dpc */
  2202. tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd);
  2203. dhd->thr_dpc_ctl.thr_pid = -1;
  2204. }
  2205. #else
  2206. /* Set up the bottom half handler */
  2207. tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd);
  2208. dhd->dhd_tasklet_create = TRUE;
  2209. #endif /* DHDTHREAD */
  2210. if (dhd_sysioc) {
  2211. PROC_START(_dhd_sysioc_thread, dhd, &dhd->thr_sysioc_ctl, 0);
  2212. } else {
  2213. dhd->thr_sysioc_ctl.thr_pid = -1;
  2214. }
  2215. dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED;
  2216. /*
  2217. * Save the dhd_info into the priv
  2218. */
  2219. memcpy(netdev_priv(net), &dhd, sizeof(dhd));
  2220. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
  2221. register_pm_notifier(&dhd_sleep_pm_notifier);
  2222. #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
  2223. #ifdef CONFIG_HAS_EARLYSUSPEND
  2224. dhd->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 20;
  2225. dhd->early_suspend.suspend = dhd_early_suspend;
  2226. dhd->early_suspend.resume = dhd_late_resume;
  2227. register_early_suspend(&dhd->early_suspend);
  2228. dhd_state |= DHD_ATTACH_STATE_EARLYSUSPEND_DONE;
  2229. #endif
  2230. #ifdef ARP_OFFLOAD_SUPPORT
  2231. register_inetaddr_notifier(&dhd_notifier);
  2232. #endif /* ARP_OFFLOAD_SUPPORT */
  2233. dhd_state |= DHD_ATTACH_STATE_DONE;
  2234. dhd->dhd_state = dhd_state;
  2235. return &dhd->pub;
  2236. fail:
  2237. if (dhd_state < DHD_ATTACH_STATE_DHD_ALLOC) {
  2238. if (net) free_netdev(net);
  2239. } else {
  2240. DHD_TRACE(("%s: Calling dhd_detach dhd_state 0x%x &dhd->pub %p\n",
  2241. __FUNCTION__, dhd_state, &dhd->pub));
  2242. dhd->dhd_state = dhd_state;
  2243. dhd_detach(&dhd->pub);
  2244. dhd_free(&dhd->pub);
  2245. }
  2246. return NULL;
  2247. }
  2248. int
  2249. dhd_bus_start(dhd_pub_t *dhdp)
  2250. {
  2251. int ret = -1;
  2252. dhd_info_t *dhd = (dhd_info_t*)dhdp->info;
  2253. unsigned long flags;
  2254. ASSERT(dhd);
  2255. DHD_TRACE(("Enter %s:\n", __FUNCTION__));
  2256. #ifdef DHDTHREAD
  2257. dhd_os_sdlock(dhdp);
  2258. #endif /* DHDTHREAD */
  2259. /* try to download image and nvram to the dongle */
  2260. if ((dhd->pub.busstate == DHD_BUS_DOWN) &&
  2261. (fw_path != NULL) && (fw_path[0] != '\0') &&
  2262. (nv_path != NULL) && (nv_path[0] != '\0')) {
  2263. /* wake lock moved to dhdsdio_download_firmware */
  2264. if (!(dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh,
  2265. fw_path, nv_path))) {
  2266. DHD_ERROR(("%s: dhdsdio_probe_download failed. firmware = %s nvram = %s\n",
  2267. __FUNCTION__, fw_path, nv_path));
  2268. #ifdef DHDTHREAD
  2269. dhd_os_sdunlock(dhdp);
  2270. #endif /* DHDTHREAD */
  2271. return -1;
  2272. }
  2273. }
  2274. if (dhd->pub.busstate != DHD_BUS_LOAD) {
  2275. #ifdef DHDTHREAD
  2276. dhd_os_sdunlock(dhdp);
  2277. #endif /* DHDTHREAD */
  2278. return -ENETDOWN;
  2279. }
  2280. /* Start the watchdog timer */
  2281. dhd->pub.tickcnt = 0;
  2282. dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms);
  2283. /* Bring up the bus */
  2284. if ((ret = dhd_bus_init(&dhd->pub, FALSE)) != 0) {
  2285. DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret));
  2286. #ifdef DHDTHREAD
  2287. dhd_os_sdunlock(dhdp);
  2288. #endif /* DHDTHREAD */
  2289. return ret;
  2290. }
  2291. #if defined(OOB_INTR_ONLY)
  2292. /* Host registration for OOB interrupt */
  2293. if (bcmsdh_register_oob_intr(dhdp)) {
  2294. /* deactivate timer and wait for the handler to finish */
  2295. flags = dhd_os_spin_lock(&dhd->pub);
  2296. dhd->wd_timer_valid = FALSE;
  2297. dhd_os_spin_unlock(&dhd->pub, flags);
  2298. del_timer_sync(&dhd->timer);
  2299. DHD_ERROR(("%s Host failed to register for OOB\n", __FUNCTION__));
  2300. #ifdef DHDTHREAD
  2301. dhd_os_sdunlock(dhdp);
  2302. #endif /* DHDTHREAD */
  2303. return -ENODEV;
  2304. }
  2305. /* Enable oob at firmware */
  2306. dhd_enable_oob_intr(dhd->pub.bus, TRUE);
  2307. #endif /* defined(OOB_INTR_ONLY) */
  2308. /* If bus is not ready, can't come up */
  2309. if (dhd->pub.busstate != DHD_BUS_DATA) {
  2310. flags = dhd_os_spin_lock(&dhd->pub);
  2311. dhd->wd_timer_valid = FALSE;
  2312. dhd_os_spin_unlock(&dhd->pub, flags);
  2313. del_timer_sync(&dhd->timer);
  2314. DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__));
  2315. #ifdef DHDTHREAD
  2316. dhd_os_sdunlock(dhdp);
  2317. #endif /* DHDTHREAD */
  2318. return -ENODEV;
  2319. }
  2320. #ifdef DHDTHREAD
  2321. dhd_os_sdunlock(dhdp);
  2322. #endif /* DHDTHREAD */
  2323. #ifdef READ_MACADDR
  2324. dhd_read_macaddr(dhd);
  2325. #endif
  2326. /* Bus is ready, do any protocol initialization */
  2327. if ((ret = dhd_prot_init(&dhd->pub)) < 0)
  2328. return ret;
  2329. #ifdef WRITE_MACADDR
  2330. dhd_write_macaddr(dhd->pub.mac.octet);
  2331. #endif
  2332. return 0;
  2333. }
  2334. int
  2335. dhd_preinit_ioctls(dhd_pub_t *dhd)
  2336. {
  2337. int ret = 0;
  2338. char eventmask[WL_EVENTING_MASK_LEN];
  2339. char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
  2340. uint up = 0;
  2341. uint power_mode = PM_FAST;
  2342. uint32 dongle_align = DHD_SDALIGN;
  2343. uint32 glom = 0;
  2344. uint bcn_timeout = 4;
  2345. uint retry_max = 3;
  2346. #if defined(ARP_OFFLOAD_SUPPORT)
  2347. int arpoe = 1;
  2348. #endif
  2349. int scan_assoc_time = 40;
  2350. int scan_unassoc_time = 40;
  2351. int scan_passive_time = 130;
  2352. char buf[WLC_IOCTL_SMLEN];
  2353. char *ptr;
  2354. uint32 listen_interval = LISTEN_INTERVAL; /* Default Listen Interval in Beacons */
  2355. #if defined(SOFTAP)
  2356. uint dtim = 1;
  2357. #endif
  2358. #if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211))
  2359. uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */
  2360. #endif
  2361. #if defined(AP) || defined(WLP2P)
  2362. uint32 apsta = 1; /* Enable APSTA mode */
  2363. #endif /* defined(AP) || defined(WLP2P) */
  2364. #ifdef GET_CUSTOM_MAC_ENABLE
  2365. struct ether_addr ea_addr;
  2366. #endif /* GET_CUSTOM_MAC_ENABLE */
  2367. DHD_TRACE(("Enter %s\n", __FUNCTION__));
  2368. dhd->op_mode = 0;
  2369. #ifdef GET_CUSTOM_MAC_ENABLE
  2370. ret = dhd_custom_get_mac_address(ea_addr.octet);
  2371. if (!ret) {
  2372. memset(buf, 0, sizeof(buf));
  2373. bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN, buf, sizeof(buf));
  2374. ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
  2375. if (ret < 0) {
  2376. DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
  2377. return BCME_NOTUP;
  2378. }
  2379. } else {
  2380. #endif /* GET_CUSTOM_MAC_ENABLE */
  2381. /* Get the default device MAC address directly from firmware */
  2382. memset(buf, 0, sizeof(buf));
  2383. bcm_mkiovar("cur_etheraddr", 0, 0, buf, sizeof(buf));
  2384. if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf),
  2385. FALSE, 0)) < 0) {
  2386. DHD_ERROR(("%s: can't get MAC address , error=%d\n", __FUNCTION__, ret));
  2387. return BCME_NOTUP;
  2388. }
  2389. /* Update public MAC address after reading from Firmware */
  2390. memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN);
  2391. #ifdef GET_CUSTOM_MAC_ENABLE
  2392. }
  2393. #endif /* GET_CUSTOM_MAC_ENABLE */
  2394. #ifdef SET_RANDOM_MAC_SOFTAP
  2395. if (strstr(fw_path, "_apsta") != NULL) {
  2396. uint rand_mac;
  2397. srandom32((uint)jiffies);
  2398. rand_mac = random32();
  2399. iovbuf[0] = 0x02; /* locally administered bit */
  2400. iovbuf[1] = 0x1A;
  2401. iovbuf[2] = 0x11;
  2402. iovbuf[3] = (unsigned char)(rand_mac & 0x0F) | 0xF0;
  2403. iovbuf[4] = (unsigned char)(rand_mac >> 8);
  2404. iovbuf[5] = (unsigned char)(rand_mac >> 16);
  2405. bcm_mkiovar("cur_etheraddr", (void *)iovbuf, ETHER_ADDR_LEN, buf, sizeof(buf));
  2406. ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
  2407. if (ret < 0) {
  2408. DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
  2409. } else
  2410. memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN);
  2411. }
  2412. #endif /* SET_RANDOM_MAC_SOFTAP */
  2413. DHD_TRACE(("Firmware = %s\n", fw_path));
  2414. #if !defined(AP) && defined(WLP2P)
  2415. /* Check if firmware with WFD support used */
  2416. if (strstr(fw_path, "_p2p") != NULL) {
  2417. bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
  2418. if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
  2419. iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
  2420. DHD_ERROR(("%s APSTA for WFD failed ret= %d\n", __FUNCTION__, ret));
  2421. } else {
  2422. dhd->op_mode |= WFD_MASK;
  2423. #if defined(ARP_OFFLOAD_SUPPORT)
  2424. arpoe = 0;
  2425. #endif /* (ARP_OFFLOAD_SUPPORT) */
  2426. dhd_pkt_filter_enable = FALSE;
  2427. }
  2428. }
  2429. #endif
  2430. #if !defined(AP) && defined(WL_CFG80211)
  2431. /* Check if firmware with HostAPD support used */
  2432. if (strstr(fw_path, "_apsta") != NULL) {
  2433. /* Turn off MPC in AP mode */
  2434. bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
  2435. if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
  2436. sizeof(iovbuf), TRUE, 0)) < 0) {
  2437. DHD_ERROR(("%s mpc for HostAPD failed %d\n", __FUNCTION__, ret));
  2438. } else {
  2439. dhd->op_mode |= HOSTAPD_MASK;
  2440. #if defined(ARP_OFFLOAD_SUPPORT)
  2441. arpoe = 0;
  2442. #endif /* (ARP_OFFLOAD_SUPPORT) */
  2443. dhd_pkt_filter_enable = FALSE;
  2444. }
  2445. }
  2446. #endif
  2447. if ((dhd->op_mode != WFD_MASK) && (dhd->op_mode != HOSTAPD_MASK)) {
  2448. /* STA only operation mode */
  2449. dhd->op_mode |= STA_MASK;
  2450. dhd_pkt_filter_enable = TRUE;
  2451. }
  2452. DHD_ERROR(("Firmware up: op_mode=%d, "
  2453. "Broadcom Dongle Host Driver mac=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
  2454. dhd->op_mode,
  2455. dhd->mac.octet[0], dhd->mac.octet[1], dhd->mac.octet[2],
  2456. dhd->mac.octet[3], dhd->mac.octet[4], dhd->mac.octet[5]));
  2457. /* Set Country code */
  2458. if (dhd->dhd_cspec.ccode[0] != 0) {
  2459. bcm_mkiovar("country", (char *)&dhd->dhd_cspec,
  2460. sizeof(wl_country_t), iovbuf, sizeof(iovbuf));
  2461. if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
  2462. DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__));
  2463. }
  2464. /* Set Listen Interval */
  2465. bcm_mkiovar("assoc_listen", (char *)&listen_interval, 4, iovbuf, sizeof(iovbuf));
  2466. if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
  2467. DHD_ERROR(("%s assoc_listen failed %d\n", __FUNCTION__, ret));
  2468. /* Set PowerSave mode */
  2469. dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0);
  2470. /* Match Host and Dongle rx alignment */
  2471. bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf));
  2472. dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
  2473. /* disable glom option per default */
  2474. bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
  2475. dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
  2476. /* Setup timeout if Beacons are lost and roam is off to report link down */
  2477. bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf));
  2478. dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
  2479. /* Setup assoc_retry_max count to reconnect target AP in dongle */
  2480. bcm_mkiovar("assoc_retry_max", (char *)&retry_max, 4, iovbuf, sizeof(iovbuf));
  2481. dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
  2482. #if defined(AP) && !defined(WLP2P)
  2483. /* Turn off MPC in AP mode */
  2484. bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
  2485. dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
  2486. bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
  2487. dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
  2488. #endif /* defined(AP) && !defined(WLP2P) */
  2489. #if defined(SOFTAP)
  2490. if (ap_fw_loaded == TRUE) {
  2491. dhd_wl_ioctl_cmd(dhd, WLC_SET_DTIMPRD, (char *)&dtim, sizeof(dtim), TRUE, 0);
  2492. }
  2493. #endif
  2494. #if defined(KEEP_ALIVE)
  2495. {
  2496. /* Set Keep Alive : be sure to use FW with -keepalive */
  2497. int res;
  2498. #if defined(SOFTAP)
  2499. if (ap_fw_loaded == FALSE)
  2500. #endif
  2501. if ((res = dhd_keep_alive_onoff(dhd)) < 0)
  2502. DHD_ERROR(("%s set keeplive failed %d\n",
  2503. __FUNCTION__, res));
  2504. }
  2505. #endif /* defined(KEEP_ALIVE) */
  2506. /* Read event_msgs mask */
  2507. bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
  2508. if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0)) < 0) {
  2509. DHD_ERROR(("%s read Event mask failed %d\n", __FUNCTION__, ret));
  2510. goto done;
  2511. }
  2512. bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN);
  2513. /* Setup event_msgs */
  2514. setbit(eventmask, WLC_E_SET_SSID);
  2515. setbit(eventmask, WLC_E_PRUNE);
  2516. setbit(eventmask, WLC_E_AUTH);
  2517. setbit(eventmask, WLC_E_REASSOC);
  2518. setbit(eventmask, WLC_E_REASSOC_IND);
  2519. setbit(eventmask, WLC_E_DEAUTH);
  2520. setbit(eventmask, WLC_E_DEAUTH_IND);
  2521. setbit(eventmask, WLC_E_DISASSOC_IND);
  2522. setbit(eventmask, WLC_E_DISASSOC);
  2523. setbit(eventmask, WLC_E_JOIN);
  2524. setbit(eventmask, WLC_E_ASSOC_IND);
  2525. setbit(eventmask, WLC_E_PSK_SUP);
  2526. setbit(eventmask, WLC_E_LINK);
  2527. setbit(eventmask, WLC_E_NDIS_LINK);
  2528. setbit(eventmask, WLC_E_MIC_ERROR);
  2529. setbit(eventmask, WLC_E_PMKID_CACHE);
  2530. setbit(eventmask, WLC_E_TXFAIL);
  2531. setbit(eventmask, WLC_E_JOIN_START);
  2532. setbit(eventmask, WLC_E_SCAN_COMPLETE);
  2533. #ifdef WLMEDIA_HTSF
  2534. setbit(eventmask, WLC_E_HTSFSYNC);
  2535. #endif /* WLMEDIA_HTSF */
  2536. #ifdef PNO_SUPPORT
  2537. setbit(eventmask, WLC_E_PFN_NET_FOUND);
  2538. #endif /* PNO_SUPPORT */
  2539. /* enable dongle roaming event */
  2540. setbit(eventmask, WLC_E_ROAM);
  2541. #ifdef WL_CFG80211
  2542. setbit(eventmask, WLC_E_ESCAN_RESULT);
  2543. if ((dhd->op_mode & WFD_MASK) == WFD_MASK) {
  2544. setbit(eventmask, WLC_E_ACTION_FRAME_RX);
  2545. setbit(eventmask, WLC_E_ACTION_FRAME_COMPLETE);
  2546. setbit(eventmask, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE);
  2547. setbit(eventmask, WLC_E_P2P_PROBREQ_MSG);
  2548. setbit(eventmask, WLC_E_P2P_DISC_LISTEN_COMPLETE);
  2549. }
  2550. #endif /* WL_CFG80211 */
  2551. /* Write updated Event mask */
  2552. bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
  2553. if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
  2554. DHD_ERROR(("%s Set Event mask failed %d\n", __FUNCTION__, ret));
  2555. goto done;
  2556. }
  2557. dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_CHANNEL_TIME, (char *)&scan_assoc_time,
  2558. sizeof(scan_assoc_time), TRUE, 0);
  2559. dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time,
  2560. sizeof(scan_unassoc_time), TRUE, 0);
  2561. dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_PASSIVE_TIME, (char *)&scan_passive_time,
  2562. sizeof(scan_passive_time), TRUE, 0);
  2563. #ifdef ARP_OFFLOAD_SUPPORT
  2564. /* Set and enable ARP offload feature for STA only */
  2565. #if defined(SOFTAP)
  2566. if (arpoe && !ap_fw_loaded) {
  2567. #else
  2568. if (arpoe) {
  2569. #endif
  2570. dhd_arp_offload_set(dhd, dhd_arp_mode);
  2571. dhd_arp_offload_enable(dhd, arpoe);
  2572. } else {
  2573. dhd_arp_offload_set(dhd, 0);
  2574. dhd_arp_offload_enable(dhd, FALSE);
  2575. }
  2576. #endif /* ARP_OFFLOAD_SUPPORT */
  2577. #ifdef PKT_FILTER_SUPPORT
  2578. /* Setup defintions for pktfilter , enable in suspend */
  2579. dhd->pktfilter_count = 4;
  2580. /* Setup filter to allow only unicast */
  2581. dhd->pktfilter[0] = "100 0 0 0 0x01 0x00";
  2582. dhd->pktfilter[1] = NULL;
  2583. dhd->pktfilter[2] = NULL;
  2584. dhd->pktfilter[3] = NULL;
  2585. #if defined(SOFTAP)
  2586. if (ap_fw_loaded) {
  2587. int i;
  2588. for (i = 0; i < dhd->pktfilter_count; i++) {
  2589. dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i],
  2590. 0, dhd_master_mode);
  2591. }
  2592. }
  2593. #endif /* defined(SOFTAP) */
  2594. #endif /* PKT_FILTER_SUPPORT */
  2595. /* Force STA UP */
  2596. if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0)) < 0) {
  2597. DHD_ERROR(("%s Setting WL UP failed %d\n", __FUNCTION__, ret));
  2598. goto done;
  2599. }
  2600. /* query for 'ver' to get version info from firmware */
  2601. memset(buf, 0, sizeof(buf));
  2602. ptr = buf;
  2603. bcm_mkiovar("ver", (char *)&buf, 4, buf, sizeof(buf));
  2604. if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), FALSE, 0)) < 0)
  2605. DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret));
  2606. else {
  2607. bcmstrtok(&ptr, "\n", 0);
  2608. /* Print fw version info */
  2609. DHD_ERROR(("Firmware version = %s\n", buf));
  2610. DHD_BLOG(buf, strlen(buf) + 1);
  2611. DHD_BLOG(dhd_version, strlen(dhd_version) + 1);
  2612. }
  2613. done:
  2614. return ret;
  2615. }
  2616. int
  2617. dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, int set)
  2618. {
  2619. char buf[strlen(name) + 1 + cmd_len];
  2620. int len = sizeof(buf);
  2621. wl_ioctl_t ioc;
  2622. int ret;
  2623. len = bcm_mkiovar(name, cmd_buf, cmd_len, buf, len);
  2624. memset(&ioc, 0, sizeof(ioc));
  2625. ioc.cmd = set? WLC_SET_VAR : WLC_GET_VAR;
  2626. ioc.buf = buf;
  2627. ioc.len = len;
  2628. ioc.set = TRUE;
  2629. ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len);
  2630. if (!set && ret >= 0)
  2631. memcpy(cmd_buf, buf, cmd_len);
  2632. return ret;
  2633. }
  2634. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
  2635. static struct net_device_ops dhd_ops_pri = {
  2636. .ndo_open = dhd_open,
  2637. .ndo_stop = dhd_stop,
  2638. .ndo_get_stats = dhd_get_stats,
  2639. .ndo_do_ioctl = dhd_ioctl_entry,
  2640. .ndo_start_xmit = dhd_start_xmit,
  2641. .ndo_set_mac_address = dhd_set_mac_address,
  2642. .ndo_set_multicast_list = dhd_set_multicast_list,
  2643. };
  2644. static struct net_device_ops dhd_ops_virt = {
  2645. .ndo_get_stats = dhd_get_stats,
  2646. .ndo_do_ioctl = dhd_ioctl_entry,
  2647. .ndo_start_xmit = dhd_start_xmit,
  2648. .ndo_set_mac_address = dhd_set_mac_address,
  2649. .ndo_set_multicast_list = dhd_set_multicast_list,
  2650. };
  2651. #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */
  2652. int dhd_change_mtu(dhd_pub_t *dhdp, int new_mtu, int ifidx)
  2653. {
  2654. struct dhd_info *dhd = dhdp->info;
  2655. struct net_device *dev = NULL;
  2656. ASSERT(dhd && dhd->iflist[ifidx]);
  2657. dev = dhd->iflist[ifidx]->net;
  2658. ASSERT(dev);
  2659. if (netif_running(dev)) {
  2660. DHD_ERROR(("%s: Must be down to change its MTU", dev->name));
  2661. return BCME_NOTDOWN;
  2662. }
  2663. #define DHD_MIN_MTU 1500
  2664. #define DHD_MAX_MTU 1752
  2665. if ((new_mtu < DHD_MIN_MTU) || (new_mtu > DHD_MAX_MTU)) {
  2666. DHD_ERROR(("%s: MTU size %d is invalid.\n", __FUNCTION__, new_mtu));
  2667. return BCME_BADARG;
  2668. }
  2669. dev->mtu = new_mtu;
  2670. return 0;
  2671. }
  2672. #ifdef ARP_OFFLOAD_SUPPORT
  2673. /* add or remove AOE host ip(s) (up to 8 IPs on the interface) */
  2674. void
  2675. aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add)
  2676. {
  2677. u32 ipv4_buf[MAX_IPV4_ENTRIES]; /* temp save for AOE host_ip table */
  2678. int i;
  2679. int ret;
  2680. bzero(ipv4_buf, sizeof(ipv4_buf));
  2681. /* display what we've got */
  2682. ret = dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf));
  2683. DHD_ARPOE(("%s: hostip table read from Dongle:\n", __FUNCTION__));
  2684. #ifdef AOE_DBG
  2685. dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */
  2686. #endif
  2687. /* now we saved hoste_ip table, clr it in the dongle AOE */
  2688. dhd_aoe_hostip_clr(dhd_pub);
  2689. if (ret) {
  2690. DHD_ERROR(("%s failed\n", __FUNCTION__));
  2691. return;
  2692. }
  2693. for (i = 0; i < MAX_IPV4_ENTRIES; i++) {
  2694. if (add && (ipv4_buf[i] == 0)) {
  2695. ipv4_buf[i] = ipa;
  2696. add = FALSE; /* added ipa to local table */
  2697. DHD_ARPOE(("%s: Saved new IP in temp arp_hostip[%d]\n",
  2698. __FUNCTION__, i));
  2699. } else if (ipv4_buf[i] == ipa) {
  2700. ipv4_buf[i] = 0;
  2701. DHD_ARPOE(("%s: removed IP:%x from temp table %d\n",
  2702. __FUNCTION__, ipa, i));
  2703. }
  2704. if (ipv4_buf[i] != 0) {
  2705. /* add back host_ip entries from our local cache */
  2706. dhd_arp_offload_add_ip(dhd_pub, ipv4_buf[i]);
  2707. DHD_ARPOE(("%s: added IP:%x to dongle arp_hostip[%d]\n\n",
  2708. __FUNCTION__, ipv4_buf[i], i));
  2709. }
  2710. }
  2711. #ifdef AOE_DBG
  2712. /* see the resulting hostip table */
  2713. dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf));
  2714. DHD_ARPOE(("%s: read back arp_hostip table:\n", __FUNCTION__));
  2715. dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */
  2716. #endif
  2717. }
  2718. static int dhd_device_event(struct notifier_block *this,
  2719. unsigned long event,
  2720. void *ptr)
  2721. {
  2722. struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
  2723. dhd_info_t *dhd;
  2724. dhd_pub_t *dhd_pub;
  2725. if (!ifa)
  2726. return NOTIFY_DONE;
  2727. dhd = *(dhd_info_t **)netdev_priv(ifa->ifa_dev->dev);
  2728. dhd_pub = &dhd->pub;
  2729. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
  2730. if (ifa->ifa_dev->dev->netdev_ops == &dhd_ops_pri) {
  2731. #else
  2732. if (ifa->ifa_dev->dev) {
  2733. #endif
  2734. switch (event) {
  2735. case NETDEV_UP:
  2736. DHD_ARPOE(("%s: [%s] Up IP: 0x%x\n",
  2737. __FUNCTION__, ifa->ifa_label, ifa->ifa_address));
  2738. /* firmware not downloaded, do nothing */
  2739. if (dhd->pub.busstate == DHD_BUS_DOWN) {
  2740. DHD_ERROR(("%s: bus is down, exit\n", __FUNCTION__));
  2741. break;
  2742. }
  2743. #ifdef AOE_IP_ALIAS_SUPPORT
  2744. if (ifa->ifa_label[strlen(ifa->ifa_label)-2] == 0x3a) {
  2745. DHD_ARPOE(("%s:add aliased IP to AOE hostip cache\n",
  2746. __FUNCTION__));
  2747. aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE);
  2748. }
  2749. else
  2750. aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE);
  2751. #endif
  2752. break;
  2753. case NETDEV_DOWN:
  2754. DHD_ARPOE(("%s: [%s] Down IP: 0x%x\n",
  2755. __FUNCTION__, ifa->ifa_label, ifa->ifa_address));
  2756. #ifdef AOE_IP_ALIAS_SUPPORT
  2757. if (!(ifa->ifa_label[strlen(ifa->ifa_label)-2] == 0x3a)) {
  2758. DHD_ARPOE(("%s: primary interface is down, AOE clr all\n",
  2759. __FUNCTION__));
  2760. dhd_aoe_hostip_clr(&dhd->pub);
  2761. dhd_aoe_arp_clr(&dhd->pub);
  2762. } else
  2763. aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, FALSE);
  2764. #else
  2765. dhd_aoe_hostip_clr(&dhd->pub);
  2766. dhd_aoe_arp_clr(&dhd->pub);
  2767. #endif
  2768. break;
  2769. default:
  2770. DHD_ARPOE(("%s: do noting for [%s] Event: %lu\n",
  2771. __func__, ifa->ifa_label, event));
  2772. break;
  2773. }
  2774. }
  2775. return NOTIFY_DONE;
  2776. }
  2777. #endif /* ARP_OFFLOAD_SUPPORT */
  2778. int
  2779. dhd_net_attach(dhd_pub_t *dhdp, int ifidx)
  2780. {
  2781. dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
  2782. struct net_device *net = NULL;
  2783. int err = 0;
  2784. uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33 };
  2785. DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx));
  2786. ASSERT(dhd && dhd->iflist[ifidx]);
  2787. net = dhd->iflist[ifidx]->net;
  2788. ASSERT(net);
  2789. #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
  2790. ASSERT(!net->open);
  2791. net->get_stats = dhd_get_stats;
  2792. net->do_ioctl = dhd_ioctl_entry;
  2793. net->hard_start_xmit = dhd_start_xmit;
  2794. net->set_mac_address = dhd_set_mac_address;
  2795. net->set_multicast_list = dhd_set_multicast_list;
  2796. net->open = net->stop = NULL;
  2797. #else
  2798. ASSERT(!net->netdev_ops);
  2799. net->netdev_ops = &dhd_ops_virt;
  2800. #endif
  2801. /* Ok, link into the network layer... */
  2802. if (ifidx == 0) {
  2803. /*
  2804. * device functions for the primary interface only
  2805. */
  2806. #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
  2807. net->open = dhd_open;
  2808. net->stop = dhd_stop;
  2809. #else
  2810. net->netdev_ops = &dhd_ops_pri;
  2811. #endif
  2812. } else {
  2813. /*
  2814. * We have to use the primary MAC for virtual interfaces
  2815. */
  2816. memcpy(temp_addr, dhd->iflist[ifidx]->mac_addr, ETHER_ADDR_LEN);
  2817. /*
  2818. * Android sets the locally administered bit to indicate that this is a
  2819. * portable hotspot. This will not work in simultaneous AP/STA mode,
  2820. * nor with P2P. Need to set the Donlge's MAC address, and then use that.
  2821. */
  2822. if (ifidx > 0) {
  2823. DHD_ERROR(("%s interface [%s]: set locally administered bit in MAC\n",
  2824. __func__, net->name));
  2825. temp_addr[0] |= 0x02;
  2826. }
  2827. }
  2828. net->hard_header_len = ETH_HLEN + dhd->pub.hdrlen;
  2829. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
  2830. net->ethtool_ops = &dhd_ethtool_ops;
  2831. #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */
  2832. #if defined(CONFIG_WIRELESS_EXT)
  2833. #if WIRELESS_EXT < 19
  2834. net->get_wireless_stats = dhd_get_wireless_stats;
  2835. #endif /* WIRELESS_EXT < 19 */
  2836. #if WIRELESS_EXT > 12
  2837. net->wireless_handlers = (struct iw_handler_def *)&wl_iw_handler_def;
  2838. #endif /* WIRELESS_EXT > 12 */
  2839. #endif /* defined(CONFIG_WIRELESS_EXT) */
  2840. dhd->pub.rxsz = DBUS_RX_BUFFER_SIZE_DHD(net);
  2841. memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN);
  2842. if ((err = register_netdev(net)) != 0) {
  2843. DHD_ERROR(("couldn't register the net device, err %d\n", err));
  2844. goto fail;
  2845. }
  2846. printf("Broadcom Dongle Host Driver: register interface [%s]"
  2847. " MAC: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
  2848. net->name,
  2849. net->dev_addr[0], net->dev_addr[1], net->dev_addr[2],
  2850. net->dev_addr[3], net->dev_addr[4], net->dev_addr[5]);
  2851. #if defined(SOFTAP) && defined(CONFIG_WIRELESS_EXT) && !defined(WL_CFG80211)
  2852. wl_iw_iscan_set_scan_broadcast_prep(net, 1);
  2853. #endif
  2854. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
  2855. if (ifidx == 0) {
  2856. up(&dhd_registration_sem);
  2857. }
  2858. #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
  2859. return 0;
  2860. fail:
  2861. #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
  2862. net->open = NULL;
  2863. #else
  2864. net->netdev_ops = NULL;
  2865. #endif
  2866. return err;
  2867. }
  2868. void
  2869. dhd_bus_detach(dhd_pub_t *dhdp)
  2870. {
  2871. dhd_info_t *dhd;
  2872. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  2873. if (dhdp) {
  2874. dhd = (dhd_info_t *)dhdp->info;
  2875. if (dhd) {
  2876. /** In case of Android cfg80211 driver, the bus is down in dhd_stop,
  2877. * calling stop again will cuase SD read/write errors.
  2878. */
  2879. if (dhd->pub.busstate != DHD_BUS_DOWN) {
  2880. /* Stop the protocol module */
  2881. dhd_prot_stop(&dhd->pub);
  2882. /* Stop the bus module */
  2883. dhd_bus_stop(dhd->pub.bus, TRUE);
  2884. }
  2885. #if defined(OOB_INTR_ONLY)
  2886. bcmsdh_unregister_oob_intr();
  2887. #endif /* defined(OOB_INTR_ONLY) */
  2888. }
  2889. }
  2890. }
  2891. void dhd_detach(dhd_pub_t *dhdp)
  2892. {
  2893. dhd_info_t *dhd;
  2894. unsigned long flags;
  2895. int timer_valid = FALSE;
  2896. if (!dhdp)
  2897. return;
  2898. dhd = (dhd_info_t *)dhdp->info;
  2899. if (!dhd)
  2900. return;
  2901. DHD_TRACE(("%s: Enter state 0x%x\n", __FUNCTION__, dhd->dhd_state));
  2902. if (!(dhd->dhd_state & DHD_ATTACH_STATE_DONE)) {
  2903. /* Give sufficient time for threads to start running in case
  2904. * dhd_attach() has failed
  2905. */
  2906. osl_delay(1000*100);
  2907. }
  2908. #ifdef ARP_OFFLOAD_SUPPORT
  2909. unregister_inetaddr_notifier(&dhd_notifier);
  2910. #endif /* ARP_OFFLOAD_SUPPORT */
  2911. #if defined(CONFIG_HAS_EARLYSUSPEND)
  2912. if (dhd->dhd_state & DHD_ATTACH_STATE_EARLYSUSPEND_DONE) {
  2913. if (dhd->early_suspend.suspend)
  2914. unregister_early_suspend(&dhd->early_suspend);
  2915. }
  2916. #endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
  2917. #if defined(CONFIG_WIRELESS_EXT)
  2918. if (dhd->dhd_state & DHD_ATTACH_STATE_WL_ATTACH) {
  2919. /* Detatch and unlink in the iw */
  2920. wl_iw_detach();
  2921. }
  2922. #endif /* defined(CONFIG_WIRELESS_EXT) */
  2923. if (&dhd->thr_sysioc_ctl.thr_pid >= 0) {
  2924. PROC_STOP(&dhd->thr_sysioc_ctl);
  2925. }
  2926. /* delete all interfaces, start with virtual */
  2927. if (dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) {
  2928. int i = 1;
  2929. dhd_if_t *ifp;
  2930. /* Cleanup virtual interfaces */
  2931. for (i = 1; i < DHD_MAX_IFS; i++)
  2932. if (dhd->iflist[i]) {
  2933. dhd->iflist[i]->state = WLC_E_IF_DEL;
  2934. dhd->iflist[i]->idx = i;
  2935. dhd_op_if(dhd->iflist[i]);
  2936. }
  2937. /* delete primary interface 0 */
  2938. ifp = dhd->iflist[0];
  2939. ASSERT(ifp);
  2940. #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
  2941. if (ifp->net->open)
  2942. #else
  2943. if (ifp->net->netdev_ops == &dhd_ops_pri)
  2944. #endif
  2945. {
  2946. if (ifp->net) {
  2947. unregister_netdev(ifp->net);
  2948. free_netdev(ifp->net);
  2949. ifp->net = NULL;
  2950. }
  2951. MFREE(dhd->pub.osh, ifp, sizeof(*ifp));
  2952. dhd->iflist[0] = NULL;
  2953. }
  2954. }
  2955. /* Clear the watchdog timer */
  2956. flags = dhd_os_spin_lock(&dhd->pub);
  2957. timer_valid = dhd->wd_timer_valid;
  2958. dhd->wd_timer_valid = FALSE;
  2959. dhd_os_spin_unlock(&dhd->pub, flags);
  2960. if (timer_valid)
  2961. del_timer_sync(&dhd->timer);
  2962. if (dhd->dhd_state & DHD_ATTACH_STATE_THREADS_CREATED) {
  2963. #ifdef DHDTHREAD
  2964. if (dhd->thr_wdt_ctl.thr_pid >= 0) {
  2965. PROC_STOP(&dhd->thr_wdt_ctl);
  2966. }
  2967. if (dhd->thr_dpc_ctl.thr_pid >= 0) {
  2968. PROC_STOP(&dhd->thr_dpc_ctl);
  2969. }
  2970. else
  2971. #endif /* DHDTHREAD */
  2972. tasklet_kill(&dhd->tasklet);
  2973. }
  2974. if (dhd->dhd_state & DHD_ATTACH_STATE_PROT_ATTACH) {
  2975. dhd_bus_detach(dhdp);
  2976. if (dhdp->prot)
  2977. dhd_prot_detach(dhdp);
  2978. }
  2979. #ifdef WL_CFG80211
  2980. if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) {
  2981. wl_cfg80211_detach();
  2982. dhd_monitor_uninit();
  2983. }
  2984. #endif
  2985. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
  2986. unregister_pm_notifier(&dhd_sleep_pm_notifier);
  2987. #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
  2988. if (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) {
  2989. #ifdef CONFIG_HAS_WAKELOCK
  2990. wake_lock_destroy(&dhd->wl_wifi);
  2991. wake_lock_destroy(&dhd->wl_rxwake);
  2992. #endif
  2993. }
  2994. }
  2995. void
  2996. dhd_free(dhd_pub_t *dhdp)
  2997. {
  2998. dhd_info_t *dhd;
  2999. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  3000. if (dhdp) {
  3001. dhd = (dhd_info_t *)dhdp->info;
  3002. if (dhd)
  3003. MFREE(dhd->pub.osh, dhd, sizeof(*dhd));
  3004. }
  3005. }
  3006. static void __exit
  3007. dhd_module_cleanup(void)
  3008. {
  3009. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  3010. dhd_bus_unregister();
  3011. #if defined(CONFIG_WIFI_CONTROL_FUNC)
  3012. wl_android_wifictrl_func_del();
  3013. #endif /* CONFIG_WIFI_CONTROL_FUNC */
  3014. wl_android_exit();
  3015. /* Call customer gpio to turn off power with WL_REG_ON signal */
  3016. dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF);
  3017. }
  3018. static int __init
  3019. dhd_module_init(void)
  3020. {
  3021. int error = 0;
  3022. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  3023. wl_android_init();
  3024. #ifdef DHDTHREAD
  3025. /* Sanity check on the module parameters */
  3026. do {
  3027. /* Both watchdog and DPC as tasklets are ok */
  3028. if ((dhd_watchdog_prio < 0) && (dhd_dpc_prio < 0))
  3029. break;
  3030. /* If both watchdog and DPC are threads, TX must be deferred */
  3031. if ((dhd_watchdog_prio >= 0) && (dhd_dpc_prio >= 0) && dhd_deferred_tx)
  3032. break;
  3033. DHD_ERROR(("Invalid module parameters.\n"));
  3034. return -EINVAL;
  3035. } while (0);
  3036. #endif /* DHDTHREAD */
  3037. /* Call customer gpio to turn on power with WL_REG_ON signal */
  3038. dhd_customer_gpio_wlan_ctrl(WLAN_POWER_ON);
  3039. #if defined(CONFIG_WIFI_CONTROL_FUNC)
  3040. if (wl_android_wifictrl_func_add() < 0)
  3041. goto fail_1;
  3042. #endif
  3043. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
  3044. sema_init(&dhd_registration_sem, 0);
  3045. #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
  3046. error = dhd_bus_register();
  3047. if (!error)
  3048. printf("\n%s\n", dhd_version);
  3049. else {
  3050. DHD_ERROR(("%s: sdio_register_driver failed\n", __FUNCTION__));
  3051. goto fail_1;
  3052. }
  3053. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
  3054. /*
  3055. * Wait till MMC sdio_register_driver callback called and made driver attach.
  3056. * It's needed to make sync up exit from dhd insmod and
  3057. * Kernel MMC sdio device callback registration
  3058. */
  3059. if (down_timeout(&dhd_registration_sem, msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)) != 0) {
  3060. error = -EINVAL;
  3061. DHD_ERROR(("%s: sdio_register_driver timeout\n", __FUNCTION__));
  3062. goto fail_2;
  3063. }
  3064. #endif
  3065. #if defined(WL_CFG80211)
  3066. error = wl_android_post_init();
  3067. #endif
  3068. return error;
  3069. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1
  3070. fail_2:
  3071. dhd_bus_unregister();
  3072. #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
  3073. fail_1:
  3074. #if defined(CONFIG_WIFI_CONTROL_FUNC)
  3075. wl_android_wifictrl_func_del();
  3076. #endif
  3077. /* Call customer gpio to turn off power with WL_REG_ON signal */
  3078. dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF);
  3079. return error;
  3080. }
  3081. late_initcall(dhd_module_init);
  3082. module_exit(dhd_module_cleanup);
  3083. /*
  3084. * OS specific functions required to implement DHD driver in OS independent way
  3085. */
  3086. int
  3087. dhd_os_proto_block(dhd_pub_t *pub)
  3088. {
  3089. dhd_info_t * dhd = (dhd_info_t *)(pub->info);
  3090. if (dhd) {
  3091. down(&dhd->proto_sem);
  3092. return 1;
  3093. }
  3094. return 0;
  3095. }
  3096. int
  3097. dhd_os_proto_unblock(dhd_pub_t *pub)
  3098. {
  3099. dhd_info_t * dhd = (dhd_info_t *)(pub->info);
  3100. if (dhd) {
  3101. up(&dhd->proto_sem);
  3102. return 1;
  3103. }
  3104. return 0;
  3105. }
  3106. unsigned int
  3107. dhd_os_get_ioctl_resp_timeout(void)
  3108. {
  3109. return ((unsigned int)dhd_ioctl_timeout_msec);
  3110. }
  3111. void
  3112. dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec)
  3113. {
  3114. dhd_ioctl_timeout_msec = (int)timeout_msec;
  3115. }
  3116. int
  3117. dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending)
  3118. {
  3119. dhd_info_t * dhd = (dhd_info_t *)(pub->info);
  3120. DECLARE_WAITQUEUE(wait, current);
  3121. int timeout = dhd_ioctl_timeout_msec;
  3122. /* Convert timeout in millsecond to jiffies */
  3123. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
  3124. timeout = msecs_to_jiffies(timeout);
  3125. #else
  3126. timeout = timeout * HZ / 1000;
  3127. #endif
  3128. /* Wait until control frame is available */
  3129. add_wait_queue(&dhd->ioctl_resp_wait, &wait);
  3130. set_current_state(TASK_INTERRUPTIBLE);
  3131. /* Memory barrier to support multi-processing
  3132. * As the variable "condition", which points to dhd->rxlen (dhd_bus_rxctl[dhd_sdio.c])
  3133. * Can be changed by another processor.
  3134. */
  3135. smp_mb();
  3136. while (!(*condition) && (!signal_pending(current) && timeout)) {
  3137. timeout = schedule_timeout(timeout);
  3138. smp_mb();
  3139. }
  3140. if (signal_pending(current))
  3141. *pending = TRUE;
  3142. set_current_state(TASK_RUNNING);
  3143. remove_wait_queue(&dhd->ioctl_resp_wait, &wait);
  3144. return timeout;
  3145. }
  3146. int
  3147. dhd_os_ioctl_resp_wake(dhd_pub_t *pub)
  3148. {
  3149. dhd_info_t *dhd = (dhd_info_t *)(pub->info);
  3150. if (waitqueue_active(&dhd->ioctl_resp_wait)) {
  3151. wake_up_interruptible(&dhd->ioctl_resp_wait);
  3152. }
  3153. return 0;
  3154. }
  3155. void
  3156. dhd_os_wd_timer(void *bus, uint wdtick)
  3157. {
  3158. dhd_pub_t *pub = bus;
  3159. dhd_info_t *dhd = (dhd_info_t *)pub->info;
  3160. unsigned long flags;
  3161. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  3162. flags = dhd_os_spin_lock(pub);
  3163. /* don't start the wd until fw is loaded */
  3164. if (pub->busstate == DHD_BUS_DOWN) {
  3165. dhd_os_spin_unlock(pub, flags);
  3166. return;
  3167. }
  3168. /* Totally stop the timer */
  3169. if (!wdtick && dhd->wd_timer_valid == TRUE) {
  3170. dhd->wd_timer_valid = FALSE;
  3171. dhd_os_spin_unlock(pub, flags);
  3172. #ifdef DHDTHREAD
  3173. del_timer_sync(&dhd->timer);
  3174. #else
  3175. del_timer(&dhd->timer);
  3176. #endif /* DHDTHREAD */
  3177. return;
  3178. }
  3179. if (wdtick) {
  3180. dhd_watchdog_ms = (uint)wdtick;
  3181. /* Re arm the timer, at last watchdog period */
  3182. mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000);
  3183. dhd->wd_timer_valid = TRUE;
  3184. }
  3185. dhd_os_spin_unlock(pub, flags);
  3186. }
  3187. void *
  3188. dhd_os_open_image(char *filename)
  3189. {
  3190. struct file *fp;
  3191. /* wl_cfg80211_request_fw(filename); */
  3192. fp = filp_open(filename, O_RDONLY, 0);
  3193. /*
  3194. * 2.6.11 (FC4) supports filp_open() but later revs don't?
  3195. * Alternative:
  3196. * fp = open_namei(AT_FDCWD, filename, O_RD, 0);
  3197. * ???
  3198. */
  3199. if (IS_ERR(fp))
  3200. fp = NULL;
  3201. return fp;
  3202. }
  3203. int
  3204. dhd_os_get_image_block(char *buf, int len, void *image)
  3205. {
  3206. struct file *fp = (struct file *)image;
  3207. int rdlen;
  3208. /* wl_cfg80211_read_fw(buf, len); */
  3209. if (!image)
  3210. return 0;
  3211. rdlen = kernel_read(fp, fp->f_pos, buf, len);
  3212. if (rdlen > 0)
  3213. fp->f_pos += rdlen;
  3214. return rdlen;
  3215. }
  3216. void
  3217. dhd_os_close_image(void *image)
  3218. {
  3219. /* wl_cfg80211_release_fw(); */
  3220. if (image)
  3221. filp_close((struct file *)image, NULL);
  3222. }
  3223. void
  3224. dhd_os_sdlock(dhd_pub_t *pub)
  3225. {
  3226. dhd_info_t *dhd;
  3227. dhd = (dhd_info_t *)(pub->info);
  3228. #ifdef DHDTHREAD
  3229. if (dhd->threads_only)
  3230. down(&dhd->sdsem);
  3231. else
  3232. #endif /* DHDTHREAD */
  3233. spin_lock_bh(&dhd->sdlock);
  3234. }
  3235. void
  3236. dhd_os_sdunlock(dhd_pub_t *pub)
  3237. {
  3238. dhd_info_t *dhd;
  3239. dhd = (dhd_info_t *)(pub->info);
  3240. #ifdef DHDTHREAD
  3241. if (dhd->threads_only)
  3242. up(&dhd->sdsem);
  3243. else
  3244. #endif /* DHDTHREAD */
  3245. spin_unlock_bh(&dhd->sdlock);
  3246. }
  3247. void
  3248. dhd_os_sdlock_txq(dhd_pub_t *pub)
  3249. {
  3250. dhd_info_t *dhd;
  3251. dhd = (dhd_info_t *)(pub->info);
  3252. spin_lock_bh(&dhd->txqlock);
  3253. }
  3254. void
  3255. dhd_os_sdunlock_txq(dhd_pub_t *pub)
  3256. {
  3257. dhd_info_t *dhd;
  3258. dhd = (dhd_info_t *)(pub->info);
  3259. spin_unlock_bh(&dhd->txqlock);
  3260. }
  3261. void
  3262. dhd_os_sdlock_rxq(dhd_pub_t *pub)
  3263. {
  3264. }
  3265. void
  3266. dhd_os_sdunlock_rxq(dhd_pub_t *pub)
  3267. {
  3268. }
  3269. void
  3270. dhd_os_sdtxlock(dhd_pub_t *pub)
  3271. {
  3272. dhd_os_sdlock(pub);
  3273. }
  3274. void
  3275. dhd_os_sdtxunlock(dhd_pub_t *pub)
  3276. {
  3277. dhd_os_sdunlock(pub);
  3278. }
  3279. #if defined(DHD_USE_STATIC_BUF)
  3280. uint8* dhd_os_prealloc(void *osh, int section, uint size)
  3281. {
  3282. return (uint8*)wl_android_prealloc(section, size);
  3283. }
  3284. void dhd_os_prefree(void *osh, void *addr, uint size)
  3285. {
  3286. }
  3287. #endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */
  3288. #if defined(CONFIG_WIRELESS_EXT)
  3289. struct iw_statistics *
  3290. dhd_get_wireless_stats(struct net_device *dev)
  3291. {
  3292. int res = 0;
  3293. dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
  3294. if (!dhd->pub.up) {
  3295. return NULL;
  3296. }
  3297. res = wl_iw_get_wireless_stats(dev, &dhd->iw.wstats);
  3298. if (res == 0)
  3299. return &dhd->iw.wstats;
  3300. else
  3301. return NULL;
  3302. }
  3303. #endif /* defined(CONFIG_WIRELESS_EXT) */
  3304. static int
  3305. dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
  3306. wl_event_msg_t *event, void **data)
  3307. {
  3308. int bcmerror = 0;
  3309. ASSERT(dhd != NULL);
  3310. bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, event, data);
  3311. if (bcmerror != BCME_OK)
  3312. return (bcmerror);
  3313. #if defined(CONFIG_WIRELESS_EXT)
  3314. if (event->bsscfgidx == 0) {
  3315. /*
  3316. * Wireless ext is on primary interface only
  3317. */
  3318. ASSERT(dhd->iflist[*ifidx] != NULL);
  3319. ASSERT(dhd->iflist[*ifidx]->net != NULL);
  3320. if (dhd->iflist[*ifidx]->net) {
  3321. wl_iw_event(dhd->iflist[*ifidx]->net, event, *data);
  3322. }
  3323. }
  3324. #endif /* defined(CONFIG_WIRELESS_EXT) */
  3325. #ifdef WL_CFG80211
  3326. if ((wl_cfg80211_is_progress_ifchange() ||
  3327. wl_cfg80211_is_progress_ifadd()) && (*ifidx != 0)) {
  3328. /*
  3329. * If IF_ADD/CHANGE operation is going on,
  3330. * discard any event received on the virtual I/F
  3331. */
  3332. return (BCME_OK);
  3333. }
  3334. ASSERT(dhd->iflist[*ifidx] != NULL);
  3335. ASSERT(dhd->iflist[*ifidx]->net != NULL);
  3336. if (dhd->iflist[*ifidx]->net) {
  3337. wl_cfg80211_event(dhd->iflist[*ifidx]->net, event, *data);
  3338. }
  3339. #endif /* defined(WL_CFG80211) */
  3340. return (bcmerror);
  3341. }
  3342. /* send up locally generated event */
  3343. void
  3344. dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data)
  3345. {
  3346. switch (ntoh32(event->event_type)) {
  3347. /* Send up locally generated AMP HCI Events */
  3348. case WLC_E_BTA_HCI_EVENT: {
  3349. struct sk_buff *p, *skb;
  3350. bcm_event_t *msg;
  3351. wl_event_msg_t *p_bcm_event;
  3352. char *ptr;
  3353. uint32 len;
  3354. uint32 pktlen;
  3355. dhd_if_t *ifp;
  3356. dhd_info_t *dhd;
  3357. uchar *eth;
  3358. int ifidx;
  3359. len = ntoh32(event->datalen);
  3360. pktlen = sizeof(bcm_event_t) + len + 2;
  3361. dhd = dhdp->info;
  3362. ifidx = dhd_ifname2idx(dhd, event->ifname);
  3363. if ((p = PKTGET(dhdp->osh, pktlen, FALSE))) {
  3364. ASSERT(ISALIGNED((uintptr)PKTDATA(dhdp->osh, p), sizeof(uint32)));
  3365. msg = (bcm_event_t *) PKTDATA(dhdp->osh, p);
  3366. bcopy(&dhdp->mac, &msg->eth.ether_dhost, ETHER_ADDR_LEN);
  3367. bcopy(&dhdp->mac, &msg->eth.ether_shost, ETHER_ADDR_LEN);
  3368. ETHER_TOGGLE_LOCALADDR(&msg->eth.ether_shost);
  3369. msg->eth.ether_type = hton16(ETHER_TYPE_BRCM);
  3370. /* BCM Vendor specific header... */
  3371. msg->bcm_hdr.subtype = hton16(BCMILCP_SUBTYPE_VENDOR_LONG);
  3372. msg->bcm_hdr.version = BCMILCP_BCM_SUBTYPEHDR_VERSION;
  3373. bcopy(BRCM_OUI, &msg->bcm_hdr.oui[0], DOT11_OUI_LEN);
  3374. /* vendor spec header length + pvt data length (private indication
  3375. * hdr + actual message itself)
  3376. */
  3377. msg->bcm_hdr.length = hton16(BCMILCP_BCM_SUBTYPEHDR_MINLENGTH +
  3378. BCM_MSG_LEN + sizeof(wl_event_msg_t) + (uint16)len);
  3379. msg->bcm_hdr.usr_subtype = hton16(BCMILCP_BCM_SUBTYPE_EVENT);
  3380. PKTSETLEN(dhdp->osh, p, (sizeof(bcm_event_t) + len + 2));
  3381. /* copy wl_event_msg_t into sk_buf */
  3382. /* pointer to wl_event_msg_t in sk_buf */
  3383. p_bcm_event = &msg->event;
  3384. bcopy(event, p_bcm_event, sizeof(wl_event_msg_t));
  3385. /* copy hci event into sk_buf */
  3386. bcopy(data, (p_bcm_event + 1), len);
  3387. msg->bcm_hdr.length = hton16(sizeof(wl_event_msg_t) +
  3388. ntoh16(msg->bcm_hdr.length));
  3389. PKTSETLEN(dhdp->osh, p, (sizeof(bcm_event_t) + len + 2));
  3390. ptr = (char *)(msg + 1);
  3391. /* Last 2 bytes of the message are 0x00 0x00 to signal that there
  3392. * are no ethertypes which are following this
  3393. */
  3394. ptr[len+0] = 0x00;
  3395. ptr[len+1] = 0x00;
  3396. skb = PKTTONATIVE(dhdp->osh, p);
  3397. eth = skb->data;
  3398. len = skb->len;
  3399. ifp = dhd->iflist[ifidx];
  3400. if (ifp == NULL)
  3401. ifp = dhd->iflist[0];
  3402. ASSERT(ifp);
  3403. skb->dev = ifp->net;
  3404. skb->protocol = eth_type_trans(skb, skb->dev);
  3405. skb->data = eth;
  3406. skb->len = len;
  3407. /* Strip header, count, deliver upward */
  3408. skb_pull(skb, ETH_HLEN);
  3409. /* Send the packet */
  3410. if (in_interrupt()) {
  3411. netif_rx(skb);
  3412. } else {
  3413. netif_rx_ni(skb);
  3414. }
  3415. }
  3416. else {
  3417. /* Could not allocate a sk_buf */
  3418. DHD_ERROR(("%s: unable to alloc sk_buf", __FUNCTION__));
  3419. }
  3420. break;
  3421. } /* case WLC_E_BTA_HCI_EVENT */
  3422. default:
  3423. break;
  3424. }
  3425. }
  3426. void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar)
  3427. {
  3428. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
  3429. struct dhd_info *dhdinfo = dhd->info;
  3430. dhd_os_sdunlock(dhd);
  3431. wait_event_interruptible_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), HZ * 2);
  3432. dhd_os_sdlock(dhd);
  3433. #endif
  3434. return;
  3435. }
  3436. void dhd_wait_event_wakeup(dhd_pub_t *dhd)
  3437. {
  3438. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
  3439. struct dhd_info *dhdinfo = dhd->info;
  3440. if (waitqueue_active(&dhdinfo->ctrl_wait))
  3441. wake_up_interruptible(&dhdinfo->ctrl_wait);
  3442. #endif
  3443. return;
  3444. }
  3445. int
  3446. dhd_dev_reset(struct net_device *dev, uint8 flag)
  3447. {
  3448. int ret;
  3449. dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
  3450. ret = dhd_bus_devreset(&dhd->pub, flag);
  3451. if (ret) {
  3452. DHD_ERROR(("%s: dhd_bus_devreset: %d\n", __FUNCTION__, ret));
  3453. return ret;
  3454. }
  3455. return ret;
  3456. }
  3457. int net_os_set_suspend_disable(struct net_device *dev, int val)
  3458. {
  3459. dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
  3460. int ret = 0;
  3461. if (dhd) {
  3462. ret = dhd->pub.suspend_disable_flag;
  3463. dhd->pub.suspend_disable_flag = val;
  3464. }
  3465. return ret;
  3466. }
  3467. int net_os_set_suspend(struct net_device *dev, int val)
  3468. {
  3469. int ret = 0;
  3470. #if defined(CONFIG_HAS_EARLYSUSPEND)
  3471. dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
  3472. if (dhd) {
  3473. ret = dhd_set_suspend(val, &dhd->pub);
  3474. }
  3475. #endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
  3476. return ret;
  3477. }
  3478. int net_os_set_dtim_skip(struct net_device *dev, int val)
  3479. {
  3480. dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
  3481. if (dhd)
  3482. dhd->pub.dtim_skip = val;
  3483. return 0;
  3484. }
  3485. int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num)
  3486. {
  3487. dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
  3488. char *filterp = NULL;
  3489. int ret = 0;
  3490. if (!dhd || (num == DHD_UNICAST_FILTER_NUM))
  3491. return ret;
  3492. if (num >= dhd->pub.pktfilter_count)
  3493. return -EINVAL;
  3494. if (add_remove) {
  3495. switch (num) {
  3496. case DHD_BROADCAST_FILTER_NUM:
  3497. filterp = "101 0 0 0 0xFFFFFFFFFFFF 0xFFFFFFFFFFFF";
  3498. break;
  3499. case DHD_MULTICAST4_FILTER_NUM:
  3500. filterp = "102 0 0 0 0xFFFFFF 0x01005E";
  3501. break;
  3502. case DHD_MULTICAST6_FILTER_NUM:
  3503. filterp = "103 0 0 0 0xFFFF 0x3333";
  3504. break;
  3505. default:
  3506. return -EINVAL;
  3507. }
  3508. }
  3509. dhd->pub.pktfilter[num] = filterp;
  3510. return ret;
  3511. }
  3512. int net_os_set_packet_filter(struct net_device *dev, int val)
  3513. {
  3514. dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
  3515. int ret = 0;
  3516. /* Packet filtering is set only if we still in early-suspend and
  3517. * we need either to turn it ON or turn it OFF
  3518. * We can always turn it OFF in case of early-suspend, but we turn it
  3519. * back ON only if suspend_disable_flag was not set
  3520. */
  3521. if (dhd && dhd->pub.up) {
  3522. if (dhd->pub.in_suspend) {
  3523. if (!val || (val && !dhd->pub.suspend_disable_flag))
  3524. dhd_set_packet_filter(val, &dhd->pub);
  3525. }
  3526. }
  3527. return ret;
  3528. }
  3529. void
  3530. dhd_dev_init_ioctl(struct net_device *dev)
  3531. {
  3532. dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
  3533. dhd_preinit_ioctls(&dhd->pub);
  3534. }
  3535. #ifdef PNO_SUPPORT
  3536. /* Linux wrapper to call common dhd_pno_clean */
  3537. int
  3538. dhd_dev_pno_reset(struct net_device *dev)
  3539. {
  3540. dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
  3541. return (dhd_pno_clean(&dhd->pub));
  3542. }
  3543. /* Linux wrapper to call common dhd_pno_enable */
  3544. int
  3545. dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled)
  3546. {
  3547. dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
  3548. return (dhd_pno_enable(&dhd->pub, pfn_enabled));
  3549. }
  3550. /* Linux wrapper to call common dhd_pno_set */
  3551. int
  3552. dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid,
  3553. ushort scan_fr, int pno_repeat, int pno_freq_expo_max)
  3554. {
  3555. dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
  3556. return (dhd_pno_set(&dhd->pub, ssids_local, nssid, scan_fr, pno_repeat, pno_freq_expo_max));
  3557. }
  3558. /* Linux wrapper to get pno status */
  3559. int
  3560. dhd_dev_get_pno_status(struct net_device *dev)
  3561. {
  3562. dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
  3563. return (dhd_pno_get_status(&dhd->pub));
  3564. }
  3565. #endif /* PNO_SUPPORT */
  3566. int net_os_send_hang_message(struct net_device *dev)
  3567. {
  3568. dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
  3569. int ret = 0;
  3570. if (dhd) {
  3571. if (!dhd->pub.hang_was_sent) {
  3572. dhd->pub.hang_was_sent = 1;
  3573. #if defined(CONFIG_WIRELESS_EXT)
  3574. ret = wl_iw_send_priv_event(dev, "HANG");
  3575. #endif
  3576. #if defined(WL_CFG80211)
  3577. ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED);
  3578. #endif
  3579. }
  3580. }
  3581. return ret;
  3582. }
  3583. void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec)
  3584. {
  3585. dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
  3586. if (dhd && dhd->pub.up)
  3587. memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t));
  3588. }
  3589. void dhd_net_if_lock(struct net_device *dev)
  3590. {
  3591. dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
  3592. dhd_net_if_lock_local(dhd);
  3593. }
  3594. void dhd_net_if_unlock(struct net_device *dev)
  3595. {
  3596. dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
  3597. dhd_net_if_unlock_local(dhd);
  3598. }
  3599. static void dhd_net_if_lock_local(dhd_info_t *dhd)
  3600. {
  3601. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
  3602. if (dhd)
  3603. mutex_lock(&dhd->dhd_net_if_mutex);
  3604. #endif
  3605. }
  3606. static void dhd_net_if_unlock_local(dhd_info_t *dhd)
  3607. {
  3608. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
  3609. if (dhd)
  3610. mutex_unlock(&dhd->dhd_net_if_mutex);
  3611. #endif
  3612. }
  3613. unsigned long dhd_os_spin_lock(dhd_pub_t *pub)
  3614. {
  3615. dhd_info_t *dhd = (dhd_info_t *)(pub->info);
  3616. unsigned long flags = 0;
  3617. if (dhd)
  3618. spin_lock_irqsave(&dhd->dhd_lock, flags);
  3619. return flags;
  3620. }
  3621. void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags)
  3622. {
  3623. dhd_info_t *dhd = (dhd_info_t *)(pub->info);
  3624. if (dhd)
  3625. spin_unlock_irqrestore(&dhd->dhd_lock, flags);
  3626. }
  3627. static int
  3628. dhd_get_pend_8021x_cnt(dhd_info_t *dhd)
  3629. {
  3630. return (atomic_read(&dhd->pend_8021x_cnt));
  3631. }
  3632. #define MAX_WAIT_FOR_8021X_TX 10
  3633. int
  3634. dhd_wait_pend8021x(struct net_device *dev)
  3635. {
  3636. dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
  3637. int timeout = 10 * HZ / 1000;
  3638. int ntimes = MAX_WAIT_FOR_8021X_TX;
  3639. int pend = dhd_get_pend_8021x_cnt(dhd);
  3640. while (ntimes && pend) {
  3641. if (pend) {
  3642. set_current_state(TASK_INTERRUPTIBLE);
  3643. schedule_timeout(timeout);
  3644. set_current_state(TASK_RUNNING);
  3645. ntimes--;
  3646. }
  3647. pend = dhd_get_pend_8021x_cnt(dhd);
  3648. }
  3649. return pend;
  3650. }
  3651. #ifdef DHD_DEBUG
  3652. int
  3653. write_to_file(dhd_pub_t *dhd, uint8 *buf, int size)
  3654. {
  3655. int ret = 0;
  3656. struct file *fp;
  3657. mm_segment_t old_fs;
  3658. loff_t pos = 0;
  3659. /* change to KERNEL_DS address limit */
  3660. old_fs = get_fs();
  3661. set_fs(KERNEL_DS);
  3662. /* open file to write */
  3663. fp = filp_open("/tmp/mem_dump", O_WRONLY|O_CREAT, 0640);
  3664. if (!fp) {
  3665. printf("%s: open file error\n", __FUNCTION__);
  3666. ret = -1;
  3667. goto exit;
  3668. }
  3669. /* Write buf to file */
  3670. fp->f_op->write(fp, buf, size, &pos);
  3671. exit:
  3672. /* free buf before return */
  3673. MFREE(dhd->osh, buf, size);
  3674. /* close file before return */
  3675. if (fp)
  3676. filp_close(fp, current->files);
  3677. /* restore previous address limit */
  3678. set_fs(old_fs);
  3679. return ret;
  3680. }
  3681. #endif /* DHD_DEBUG */
  3682. int dhd_os_wake_lock_timeout(dhd_pub_t *pub)
  3683. {
  3684. dhd_info_t *dhd = (dhd_info_t *)(pub->info);
  3685. unsigned long flags;
  3686. int ret = 0;
  3687. if (dhd) {
  3688. spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
  3689. ret = dhd->wakelock_timeout_enable;
  3690. #ifdef CONFIG_HAS_WAKELOCK
  3691. if (dhd->wakelock_timeout_enable)
  3692. wake_lock_timeout(&dhd->wl_rxwake,
  3693. dhd->wakelock_timeout_enable * HZ);
  3694. #endif
  3695. dhd->wakelock_timeout_enable = 0;
  3696. spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
  3697. }
  3698. return ret;
  3699. }
  3700. int net_os_wake_lock_timeout(struct net_device *dev)
  3701. {
  3702. dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
  3703. int ret = 0;
  3704. if (dhd)
  3705. ret = dhd_os_wake_lock_timeout(&dhd->pub);
  3706. return ret;
  3707. }
  3708. int dhd_os_wake_lock_timeout_enable(dhd_pub_t *pub, int val)
  3709. {
  3710. dhd_info_t *dhd = (dhd_info_t *)(pub->info);
  3711. unsigned long flags;
  3712. if (dhd) {
  3713. spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
  3714. if (val > dhd->wakelock_timeout_enable)
  3715. dhd->wakelock_timeout_enable = val;
  3716. spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
  3717. }
  3718. return 0;
  3719. }
  3720. int net_os_wake_lock_timeout_enable(struct net_device *dev, int val)
  3721. {
  3722. dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
  3723. int ret = 0;
  3724. if (dhd)
  3725. ret = dhd_os_wake_lock_timeout_enable(&dhd->pub, val);
  3726. return ret;
  3727. }
  3728. int dhd_os_wake_lock(dhd_pub_t *pub)
  3729. {
  3730. dhd_info_t *dhd = (dhd_info_t *)(pub->info);
  3731. unsigned long flags;
  3732. int ret = 0;
  3733. if (dhd) {
  3734. spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
  3735. #ifdef CONFIG_HAS_WAKELOCK
  3736. if (!dhd->wakelock_counter)
  3737. wake_lock(&dhd->wl_wifi);
  3738. #endif
  3739. dhd->wakelock_counter++;
  3740. ret = dhd->wakelock_counter;
  3741. spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
  3742. }
  3743. return ret;
  3744. }
  3745. int net_os_wake_lock(struct net_device *dev)
  3746. {
  3747. dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
  3748. int ret = 0;
  3749. if (dhd)
  3750. ret = dhd_os_wake_lock(&dhd->pub);
  3751. return ret;
  3752. }
  3753. int dhd_os_wake_unlock(dhd_pub_t *pub)
  3754. {
  3755. dhd_info_t *dhd = (dhd_info_t *)(pub->info);
  3756. unsigned long flags;
  3757. int ret = 0;
  3758. dhd_os_wake_lock_timeout(pub);
  3759. if (dhd) {
  3760. spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
  3761. if (dhd->wakelock_counter) {
  3762. dhd->wakelock_counter--;
  3763. #ifdef CONFIG_HAS_WAKELOCK
  3764. if (!dhd->wakelock_counter)
  3765. wake_unlock(&dhd->wl_wifi);
  3766. #endif
  3767. ret = dhd->wakelock_counter;
  3768. }
  3769. spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
  3770. }
  3771. return ret;
  3772. }
  3773. int net_os_wake_unlock(struct net_device *dev)
  3774. {
  3775. dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
  3776. int ret = 0;
  3777. if (dhd)
  3778. ret = dhd_os_wake_unlock(&dhd->pub);
  3779. return ret;
  3780. }
  3781. int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd)
  3782. {
  3783. int ifidx;
  3784. int ret = 0;
  3785. dhd_info_t *dhd = NULL;
  3786. if (!net || !netdev_priv(net)) {
  3787. DHD_ERROR(("%s invalid parameter\n", __FUNCTION__));
  3788. return -EINVAL;
  3789. }
  3790. dhd = *(dhd_info_t **)netdev_priv(net);
  3791. ifidx = dhd_net2idx(dhd, net);
  3792. if (ifidx == DHD_BAD_IF) {
  3793. DHD_ERROR(("%s bad ifidx\n", __FUNCTION__));
  3794. return -ENODEV;
  3795. }
  3796. DHD_OS_WAKE_LOCK(&dhd->pub);
  3797. ret = dhd_wl_ioctl(&dhd->pub, ifidx, ioc, ioc->buf, ioc->len);
  3798. dhd_check_hang(net, &dhd->pub, ret);
  3799. DHD_OS_WAKE_UNLOCK(&dhd->pub);
  3800. return ret;
  3801. }
  3802. #ifdef PROP_TXSTATUS
  3803. extern int dhd_wlfc_interface_entry_update(void* state, ewlfc_mac_entry_action_t action, uint8 ifid,
  3804. uint8 iftype, uint8* ea);
  3805. extern int dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits);
  3806. int dhd_wlfc_interface_event(struct dhd_info *dhd, uint8 action, uint8 ifid, uint8 iftype,
  3807. uint8* ea)
  3808. {
  3809. if (dhd->pub.wlfc_state == NULL)
  3810. return BCME_OK;
  3811. return dhd_wlfc_interface_entry_update(dhd->pub.wlfc_state, action, ifid, iftype, ea);
  3812. }
  3813. int dhd_wlfc_FIFOcreditmap_event(struct dhd_info *dhd, uint8* event_data)
  3814. {
  3815. if (dhd->pub.wlfc_state == NULL)
  3816. return BCME_OK;
  3817. return dhd_wlfc_FIFOcreditmap_update(dhd->pub.wlfc_state, event_data);
  3818. }
  3819. int dhd_wlfc_event(struct dhd_info *dhd)
  3820. {
  3821. return dhd_wlfc_enable(&dhd->pub);
  3822. }
  3823. #endif /* PROP_TXSTATUS */
  3824. #ifdef BCMDBGFS
  3825. #include <linux/debugfs.h>
  3826. extern uint32 dhd_readregl(void *bp, uint32 addr);
  3827. extern uint32 dhd_writeregl(void *bp, uint32 addr, uint32 data);
  3828. typedef struct dhd_dbgfs {
  3829. struct dentry *debugfs_dir;
  3830. struct dentry *debugfs_mem;
  3831. dhd_pub_t *dhdp;
  3832. uint32 size;
  3833. } dhd_dbgfs_t;
  3834. dhd_dbgfs_t g_dbgfs;
  3835. static int
  3836. dhd_dbg_state_open(struct inode *inode, struct file *file)
  3837. {
  3838. file->private_data = inode->i_private;
  3839. return 0;
  3840. }
  3841. static ssize_t
  3842. dhd_dbg_state_read(struct file *file, char __user *ubuf,
  3843. size_t count, loff_t *ppos)
  3844. {
  3845. ssize_t rval;
  3846. uint32 tmp;
  3847. loff_t pos = *ppos;
  3848. size_t ret;
  3849. if (pos < 0)
  3850. return -EINVAL;
  3851. if (pos >= g_dbgfs.size || !count)
  3852. return 0;
  3853. if (count > g_dbgfs.size - pos)
  3854. count = g_dbgfs.size - pos;
  3855. /* Basically enforce aligned 4 byte reads. It's up to the user to work out the details */
  3856. tmp = dhd_readregl(g_dbgfs.dhdp->bus, file->f_pos & (~3));
  3857. ret = copy_to_user(ubuf, &tmp, 4);
  3858. if (ret == count)
  3859. return -EFAULT;
  3860. count -= ret;
  3861. *ppos = pos + count;
  3862. rval = count;
  3863. return rval;
  3864. }
  3865. static ssize_t
  3866. dhd_debugfs_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos)
  3867. {
  3868. loff_t pos = *ppos;
  3869. size_t ret;
  3870. uint32 buf;
  3871. if (pos < 0)
  3872. return -EINVAL;
  3873. if (pos >= g_dbgfs.size || !count)
  3874. return 0;
  3875. if (count > g_dbgfs.size - pos)
  3876. count = g_dbgfs.size - pos;
  3877. ret = copy_from_user(&buf, ubuf, sizeof(uint32));
  3878. if (ret == count)
  3879. return -EFAULT;
  3880. /* Basically enforce aligned 4 byte writes. It's up to the user to work out the details */
  3881. dhd_writeregl(g_dbgfs.dhdp->bus, file->f_pos & (~3), buf);
  3882. return count;
  3883. }
  3884. loff_t
  3885. dhd_debugfs_lseek(struct file *file, loff_t off, int whence)
  3886. {
  3887. loff_t pos = -1;
  3888. switch (whence) {
  3889. case 0:
  3890. pos = off;
  3891. break;
  3892. case 1:
  3893. pos = file->f_pos + off;
  3894. break;
  3895. case 2:
  3896. pos = g_dbgfs.size - off;
  3897. }
  3898. return (pos < 0 || pos > g_dbgfs.size) ? -EINVAL : (file->f_pos = pos);
  3899. }
  3900. static const struct file_operations dhd_dbg_state_ops = {
  3901. .read = dhd_dbg_state_read,
  3902. .write = dhd_debugfs_write,
  3903. .open = dhd_dbg_state_open,
  3904. .llseek = dhd_debugfs_lseek
  3905. };
  3906. static void dhd_dbg_create(void)
  3907. {
  3908. if (g_dbgfs.debugfs_dir) {
  3909. g_dbgfs.debugfs_mem = debugfs_create_file("mem", 0644, g_dbgfs.debugfs_dir,
  3910. NULL, &dhd_dbg_state_ops);
  3911. }
  3912. }
  3913. void dhd_dbg_init(dhd_pub_t *dhdp)
  3914. {
  3915. int err;
  3916. g_dbgfs.dhdp = dhdp;
  3917. g_dbgfs.size = 0x20000000; /* Allow access to various cores regs */
  3918. g_dbgfs.debugfs_dir = debugfs_create_dir("dhd", 0);
  3919. if (IS_ERR(g_dbgfs.debugfs_dir)) {
  3920. err = PTR_ERR(g_dbgfs.debugfs_dir);
  3921. g_dbgfs.debugfs_dir = NULL;
  3922. return;
  3923. }
  3924. dhd_dbg_create();
  3925. return;
  3926. }
  3927. void dhd_dbg_remove(void)
  3928. {
  3929. debugfs_remove(g_dbgfs.debugfs_mem);
  3930. debugfs_remove(g_dbgfs.debugfs_dir);
  3931. bzero((unsigned char *) &g_dbgfs, sizeof(g_dbgfs));
  3932. }
  3933. #endif /* ifdef BCMDBGFS */
  3934. #ifdef WLMEDIA_HTSF
  3935. static
  3936. void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf)
  3937. {
  3938. dhd_info_t *dhd = (dhd_info_t *)(dhdp->info);
  3939. struct sk_buff *skb;
  3940. uint32 htsf = 0;
  3941. uint16 dport = 0, oldmagic = 0xACAC;
  3942. char *p1;
  3943. htsfts_t ts;
  3944. /* timestamp packet */
  3945. p1 = (char*) PKTDATA(dhdp->osh, pktbuf);
  3946. if (PKTLEN(dhdp->osh, pktbuf) > HTSF_MINLEN) {
  3947. /* memcpy(&proto, p1+26, 4); */
  3948. memcpy(&dport, p1+40, 2);
  3949. /* proto = ((ntoh32(proto))>> 16) & 0xFF; */
  3950. dport = ntoh16(dport);
  3951. }
  3952. /* timestamp only if icmp or udb iperf with port 5555 */
  3953. /* if (proto == 17 && dport == tsport) { */
  3954. if (dport >= tsport && dport <= tsport + 20) {
  3955. skb = (struct sk_buff *) pktbuf;
  3956. htsf = dhd_get_htsf(dhd, 0);
  3957. memset(skb->data + 44, 0, 2); /* clear checksum */
  3958. memcpy(skb->data+82, &oldmagic, 2);
  3959. memcpy(skb->data+84, &htsf, 4);
  3960. memset(&ts, 0, sizeof(htsfts_t));
  3961. ts.magic = HTSFMAGIC;
  3962. ts.prio = PKTPRIO(pktbuf);
  3963. ts.seqnum = htsf_seqnum++;
  3964. ts.c10 = get_cycles();
  3965. ts.t10 = htsf;
  3966. ts.endmagic = HTSFENDMAGIC;
  3967. memcpy(skb->data + HTSF_HOSTOFFSET, &ts, sizeof(ts));
  3968. }
  3969. }
  3970. static void dhd_dump_htsfhisto(histo_t *his, char *s)
  3971. {
  3972. int pktcnt = 0, curval = 0, i;
  3973. for (i = 0; i < (NUMBIN-2); i++) {
  3974. curval += 500;
  3975. printf("%d ", his->bin[i]);
  3976. pktcnt += his->bin[i];
  3977. }
  3978. printf(" max: %d TotPkt: %d neg: %d [%s]\n", his->bin[NUMBIN-2], pktcnt,
  3979. his->bin[NUMBIN-1], s);
  3980. }
  3981. static
  3982. void sorttobin(int value, histo_t *histo)
  3983. {
  3984. int i, binval = 0;
  3985. if (value < 0) {
  3986. histo->bin[NUMBIN-1]++;
  3987. return;
  3988. }
  3989. if (value > histo->bin[NUMBIN-2]) /* store the max value */
  3990. histo->bin[NUMBIN-2] = value;
  3991. for (i = 0; i < (NUMBIN-2); i++) {
  3992. binval += 500; /* 500m s bins */
  3993. if (value <= binval) {
  3994. histo->bin[i]++;
  3995. return;
  3996. }
  3997. }
  3998. histo->bin[NUMBIN-3]++;
  3999. }
  4000. static
  4001. void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf)
  4002. {
  4003. dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
  4004. struct sk_buff *skb;
  4005. char *p1;
  4006. uint16 old_magic;
  4007. int d1, d2, d3, end2end;
  4008. htsfts_t *htsf_ts;
  4009. uint32 htsf;
  4010. skb = PKTTONATIVE(dhdp->osh, pktbuf);
  4011. p1 = (char*)PKTDATA(dhdp->osh, pktbuf);
  4012. if (PKTLEN(osh, pktbuf) > HTSF_MINLEN) {
  4013. memcpy(&old_magic, p1+78, 2);
  4014. htsf_ts = (htsfts_t*) (p1 + HTSF_HOSTOFFSET - 4);
  4015. }
  4016. else
  4017. return;
  4018. if (htsf_ts->magic == HTSFMAGIC) {
  4019. htsf_ts->tE0 = dhd_get_htsf(dhd, 0);
  4020. htsf_ts->cE0 = get_cycles();
  4021. }
  4022. if (old_magic == 0xACAC) {
  4023. tspktcnt++;
  4024. htsf = dhd_get_htsf(dhd, 0);
  4025. memcpy(skb->data+92, &htsf, sizeof(uint32));
  4026. memcpy(&ts[tsidx].t1, skb->data+80, 16);
  4027. d1 = ts[tsidx].t2 - ts[tsidx].t1;
  4028. d2 = ts[tsidx].t3 - ts[tsidx].t2;
  4029. d3 = ts[tsidx].t4 - ts[tsidx].t3;
  4030. end2end = ts[tsidx].t4 - ts[tsidx].t1;
  4031. sorttobin(d1, &vi_d1);
  4032. sorttobin(d2, &vi_d2);
  4033. sorttobin(d3, &vi_d3);
  4034. sorttobin(end2end, &vi_d4);
  4035. if (end2end > 0 && end2end > maxdelay) {
  4036. maxdelay = end2end;
  4037. maxdelaypktno = tspktcnt;
  4038. memcpy(&maxdelayts, &ts[tsidx], 16);
  4039. }
  4040. if (++tsidx >= TSMAX)
  4041. tsidx = 0;
  4042. }
  4043. }
  4044. uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx)
  4045. {
  4046. uint32 htsf = 0, cur_cycle, delta, delta_us;
  4047. uint32 factor, baseval, baseval2;
  4048. cycles_t t;
  4049. t = get_cycles();
  4050. cur_cycle = t;
  4051. if (cur_cycle > dhd->htsf.last_cycle)
  4052. delta = cur_cycle - dhd->htsf.last_cycle;
  4053. else {
  4054. delta = cur_cycle + (0xFFFFFFFF - dhd->htsf.last_cycle);
  4055. }
  4056. delta = delta >> 4;
  4057. if (dhd->htsf.coef) {
  4058. /* times ten to get the first digit */
  4059. factor = (dhd->htsf.coef*10 + dhd->htsf.coefdec1);
  4060. baseval = (delta*10)/factor;
  4061. baseval2 = (delta*10)/(factor+1);
  4062. delta_us = (baseval - (((baseval - baseval2) * dhd->htsf.coefdec2)) / 10);
  4063. htsf = (delta_us << 4) + dhd->htsf.last_tsf + HTSF_BUS_DELAY;
  4064. }
  4065. else {
  4066. DHD_ERROR(("-------dhd->htsf.coef = 0 -------\n"));
  4067. }
  4068. return htsf;
  4069. }
  4070. static void dhd_dump_latency(void)
  4071. {
  4072. int i, max = 0;
  4073. int d1, d2, d3, d4, d5;
  4074. printf("T1 T2 T3 T4 d1 d2 t4-t1 i \n");
  4075. for (i = 0; i < TSMAX; i++) {
  4076. d1 = ts[i].t2 - ts[i].t1;
  4077. d2 = ts[i].t3 - ts[i].t2;
  4078. d3 = ts[i].t4 - ts[i].t3;
  4079. d4 = ts[i].t4 - ts[i].t1;
  4080. d5 = ts[max].t4-ts[max].t1;
  4081. if (d4 > d5 && d4 > 0) {
  4082. max = i;
  4083. }
  4084. printf("%08X %08X %08X %08X \t%d %d %d %d i=%d\n",
  4085. ts[i].t1, ts[i].t2, ts[i].t3, ts[i].t4,
  4086. d1, d2, d3, d4, i);
  4087. }
  4088. printf("current idx = %d \n", tsidx);
  4089. printf("Highest latency %d pkt no.%d total=%d\n", maxdelay, maxdelaypktno, tspktcnt);
  4090. printf("%08X %08X %08X %08X \t%d %d %d %d\n",
  4091. maxdelayts.t1, maxdelayts.t2, maxdelayts.t3, maxdelayts.t4,
  4092. maxdelayts.t2 - maxdelayts.t1,
  4093. maxdelayts.t3 - maxdelayts.t2,
  4094. maxdelayts.t4 - maxdelayts.t3,
  4095. maxdelayts.t4 - maxdelayts.t1);
  4096. }
  4097. static int
  4098. dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx)
  4099. {
  4100. wl_ioctl_t ioc;
  4101. char buf[32];
  4102. int ret;
  4103. uint32 s1, s2;
  4104. struct tsf {
  4105. uint32 low;
  4106. uint32 high;
  4107. } tsf_buf;
  4108. memset(&ioc, 0, sizeof(ioc));
  4109. memset(&tsf_buf, 0, sizeof(tsf_buf));
  4110. ioc.cmd = WLC_GET_VAR;
  4111. ioc.buf = buf;
  4112. ioc.len = (uint)sizeof(buf);
  4113. ioc.set = FALSE;
  4114. strcpy(buf, "tsf");
  4115. s1 = dhd_get_htsf(dhd, 0);
  4116. if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
  4117. if (ret == -EIO) {
  4118. DHD_ERROR(("%s: tsf is not supported by device\n",
  4119. dhd_ifname(&dhd->pub, ifidx)));
  4120. return -EOPNOTSUPP;
  4121. }
  4122. return ret;
  4123. }
  4124. s2 = dhd_get_htsf(dhd, 0);
  4125. memcpy(&tsf_buf, buf, sizeof(tsf_buf));
  4126. printf(" TSF_h=%04X lo=%08X Calc:htsf=%08X, coef=%d.%d%d delta=%d ",
  4127. tsf_buf.high, tsf_buf.low, s2, dhd->htsf.coef, dhd->htsf.coefdec1,
  4128. dhd->htsf.coefdec2, s2-tsf_buf.low);
  4129. printf("lasttsf=%08X lastcycle=%08X\n", dhd->htsf.last_tsf, dhd->htsf.last_cycle);
  4130. return 0;
  4131. }
  4132. void htsf_update(dhd_info_t *dhd, void *data)
  4133. {
  4134. static ulong cur_cycle = 0, prev_cycle = 0;
  4135. uint32 htsf, tsf_delta = 0;
  4136. uint32 hfactor = 0, cyc_delta, dec1 = 0, dec2, dec3, tmp;
  4137. ulong b, a;
  4138. cycles_t t;
  4139. /* cycles_t in inlcude/mips/timex.h */
  4140. t = get_cycles();
  4141. prev_cycle = cur_cycle;
  4142. cur_cycle = t;
  4143. if (cur_cycle > prev_cycle)
  4144. cyc_delta = cur_cycle - prev_cycle;
  4145. else {
  4146. b = cur_cycle;
  4147. a = prev_cycle;
  4148. cyc_delta = cur_cycle + (0xFFFFFFFF - prev_cycle);
  4149. }
  4150. if (data == NULL)
  4151. printf(" tsf update ata point er is null \n");
  4152. memcpy(&prev_tsf, &cur_tsf, sizeof(tsf_t));
  4153. memcpy(&cur_tsf, data, sizeof(tsf_t));
  4154. if (cur_tsf.low == 0) {
  4155. DHD_INFO((" ---- 0 TSF, do not update, return\n"));
  4156. return;
  4157. }
  4158. if (cur_tsf.low > prev_tsf.low)
  4159. tsf_delta = (cur_tsf.low - prev_tsf.low);
  4160. else {
  4161. DHD_INFO((" ---- tsf low is smaller cur_tsf= %08X, prev_tsf=%08X, \n",
  4162. cur_tsf.low, prev_tsf.low));
  4163. if (cur_tsf.high > prev_tsf.high) {
  4164. tsf_delta = cur_tsf.low + (0xFFFFFFFF - prev_tsf.low);
  4165. DHD_INFO((" ---- Wrap around tsf coutner adjusted TSF=%08X\n", tsf_delta));
  4166. }
  4167. else
  4168. return; /* do not update */
  4169. }
  4170. if (tsf_delta) {
  4171. hfactor = cyc_delta / tsf_delta;
  4172. tmp = (cyc_delta - (hfactor * tsf_delta))*10;
  4173. dec1 = tmp/tsf_delta;
  4174. dec2 = ((tmp - dec1*tsf_delta)*10) / tsf_delta;
  4175. tmp = (tmp - (dec1*tsf_delta))*10;
  4176. dec3 = ((tmp - dec2*tsf_delta)*10) / tsf_delta;
  4177. if (dec3 > 4) {
  4178. if (dec2 == 9) {
  4179. dec2 = 0;
  4180. if (dec1 == 9) {
  4181. dec1 = 0;
  4182. hfactor++;
  4183. }
  4184. else {
  4185. dec1++;
  4186. }
  4187. }
  4188. else
  4189. dec2++;
  4190. }
  4191. }
  4192. if (hfactor) {
  4193. htsf = ((cyc_delta * 10) / (hfactor*10+dec1)) + prev_tsf.low;
  4194. dhd->htsf.coef = hfactor;
  4195. dhd->htsf.last_cycle = cur_cycle;
  4196. dhd->htsf.last_tsf = cur_tsf.low;
  4197. dhd->htsf.coefdec1 = dec1;
  4198. dhd->htsf.coefdec2 = dec2;
  4199. }
  4200. else {
  4201. htsf = prev_tsf.low;
  4202. }
  4203. }
  4204. #endif /* WLMEDIA_HTSF */