blob: d8a1f67364ce22baf066ac0499e4c3e3ec2420e5 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
2 * Copyright (c) 2015 The Linux Foundation. All rights reserved.
3 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28#include <linux/platform_device.h>
29#include <linux/pci.h>
30#ifdef HIF_PCI
31#ifdef CONFIG_CNSS
32#include <net/cnss.h>
33#endif /* CONFIG_CNSS */
34#else
35#include <soc/qcom/icnss.h>
36#endif /* HIF_PCI */
37#include "cds_api.h"
38#include "cdf_status.h"
39#include "cdf_lock.h"
40#include "cds_sched.h"
41#include "osdep.h"
42#include "hif.h"
43#include "epping_main.h"
44#include "wlan_hdd_main.h"
45#include "wlan_hdd_power.h"
46#include "wlan_logging_sock_svc.h"
47#include "wma_api.h"
48#include "wlan_hdd_napi.h"
49
50#ifdef MODULE
51#define WLAN_MODULE_NAME module_name(THIS_MODULE)
52#else
53#define WLAN_MODULE_NAME "wlan"
54#endif
55
56#ifdef HIF_PCI
57#ifdef CONFIG_CNSS
58#define WLAN_HDD_REGISTER_DRIVER(wlan_drv_ops) \
59 cnss_wlan_register_driver(wlan_drv_ops)
60#define WLAN_HDD_UNREGISTER_DRIVER(wlan_drv_ops) \
61 cnss_wlan_unregister_driver(wlan_drv_ops)
62#else
63#define WLAN_HDD_REGISTER_DRIVER(wlan_drv_ops) \
64 pci_register_driver(wlan_drv_ops)
65#define WLAN_HDD_UNREGISTER_DRIVER(wlan_drv_ops) \
66 pci_unregister_driver(wlan_drv_ops)
67#endif /* CONFIG_CNSS */
68#else
69#define WLAN_HDD_REGISTER_DRIVER(wlan_drv_ops) \
70 icnss_register_driver(wlan_drv_ops)
71#define WLAN_HDD_UNREGISTER_DRIVER(wlan_drv_ops) \
72 icnss_unregister_driver(wlan_drv_ops)
73#endif /* HIF_PCI */
74
75/**
76 * wlan_hdd_probe() - handles probe request
77 *
78 * This function is called to probe the wlan driver
79 *
80 * @dev: wlan device structure
81 * @bdev: bus device structure
82 * @bid: bus identifier for shared busses
83 * @bus_type: underlying bus type
84 * @reinit: true if we are reinitiallizing the driver after a subsystem restart
85 *
86 * Return: 0 on successfull probe
87 */
88static int wlan_hdd_probe(struct device *dev, void *bdev, const hif_bus_id *bid,
89 enum ath_hal_bus_type bus_type, bool reinit)
90{
91 void *hif_ctx;
92 CDF_STATUS status;
93 int ret;
94
95 if (WLAN_IS_EPPING_ENABLED(cds_get_conparam())) {
96 status = epping_open();
97 if (status != CDF_STATUS_SUCCESS)
98 return status;
99 }
100
101 status = hif_open();
102 if (status != CDF_STATUS_SUCCESS) {
103 hddLog(LOGE, FL("hif_open error = %d"), status);
104 return -EFAULT;
105 }
106 hif_ctx = cds_get_context(CDF_MODULE_ID_HIF);
107 if (reinit)
108 hdd_napi_destroy(true);
109 status = hdd_napi_create();
110 if (hdd_napi_enabled(HDD_NAPI_ANY)) {
111 hdd_info("hdd_napi_create returned: %d\n", status);
112 if (status <= 0) {
113 hdd_err("NAPI creation error, rc: 0x%x, reinit = %d",
114 status, reinit);
115 return -EFAULT;
116 }
117 }
118
119 status = hif_enable(hif_ctx, dev, bdev, bid,
120 bus_type, (reinit == true) ?
121 HIF_ENABLE_TYPE_REINIT : HIF_ENABLE_TYPE_PROBE);
122 if (status != CDF_STATUS_SUCCESS) {
123 hdd_err("hif_enable error = %d, reinit = %d",
124 status, reinit);
125 ret = -EIO;
126 goto end;
127 }
128
129 if (reinit)
130 ret = hdd_wlan_re_init(hif_ctx);
131 else
132 ret = hdd_wlan_startup(dev, hif_ctx);
133
134end:
135 if (ret) {
136 if (WLAN_IS_EPPING_ENABLED(cds_get_conparam())) {
137 hif_pktlogmod_exit(hif_ctx);
138 epping_disable();
139 htc_destroy(cds_get_context(CDF_MODULE_ID_HTC));
140 hif_disable(hif_ctx, (reinit == true) ?
141 HIF_ENABLE_TYPE_REINIT : HIF_ENABLE_TYPE_PROBE);
142 cds_free_context(NULL, CDF_MODULE_ID_HTC, NULL);
143 epping_close();
144 } else {
145 hif_pktlogmod_exit(hif_ctx);
146 __hdd_wlan_exit();
147 hif_disable(hif_ctx, HIF_DISABLE_TYPE_REMOVE);
148 }
149 hif_close(hif_ctx);
150 }
151
152 if (reinit)
153 cds_set_logp_in_progress(false);
154
155 return ret;
156}
157
158/**
159 * wlan_hdd_remove() - wlan_hdd_remove
160 *
161 * This function is called by the platform driver to remove the
162 * driver
163 *
164 * Return: void
165 */
166static void wlan_hdd_remove(void)
167{
168 void *hif_ctx;
169 v_CONTEXT_t p_cds_context = NULL;
170
171 /* Get the global cds context */
172 p_cds_context = cds_get_global_context();
173
174 hif_ctx = cds_get_context(CDF_MODULE_ID_HIF);
175
176 if (WLAN_IS_EPPING_ENABLED(cds_get_conparam())) {
177 hif_pktlogmod_exit(hif_ctx);
178 epping_disable();
179 htc_destroy(cds_get_context(CDF_MODULE_ID_HTC));
180 hif_disable(hif_ctx, HIF_DISABLE_TYPE_REMOVE);
181 cds_free_context(NULL, CDF_MODULE_ID_HTC, NULL);
182 epping_close();
183 } else {
184 hif_pktlogmod_exit(hif_ctx);
185 __hdd_wlan_exit();
186 hif_disable(hif_ctx, HIF_DISABLE_TYPE_REMOVE);
187 }
188
189 hdd_napi_destroy(true);
190 hif_close(hif_ctx);
191
192 cds_free_global_context(&p_cds_context);
193
194#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE
195 wlan_logging_sock_deinit_svc();
196#endif
197
198 cdf_wake_lock_destroy(hdd_wlan_get_wake_lock_ptr());
199
200 pr_info("%s: driver unloaded\n", WLAN_MODULE_NAME);
201}
202
203/**
204 * wlan_hdd_shutdown() - wlan_hdd_shutdown
205 *
206 * This is routine is called by platform driver to shutdown the
207 * driver
208 *
209 * Return: void
210 */
211static void wlan_hdd_shutdown(void)
212{
213 void *hif_ctx = cds_get_context(CDF_MODULE_ID_HIF);
214
215 if (cds_is_load_unload_in_progress()) {
216 hddLog(LOGE,
217 FL("Load/unload in progress, ignore SSR shutdown"));
218 return;
219 }
220 /* this is for cases, where shutdown invoked from CNSS */
221 cds_set_logp_in_progress(true);
222
223 if (cds_get_conparam() != CDF_FTM_MODE &&
224 !WLAN_IS_EPPING_ENABLED(cds_get_conparam()))
225 hif_pktlogmod_exit(hif_ctx);
226
227 if (!cds_is_ssr_ready(__func__))
228 hddLog(LOGE,
229 FL("Host is not ready for SSR, attempting anyway"));
230
231 if (!WLAN_IS_EPPING_ENABLED(cds_get_conparam()))
232 hdd_wlan_shutdown();
233
234 hif_disable(hif_ctx, HIF_DISABLE_TYPE_SHUTDOWN);
235 hif_close(hif_ctx);
236}
237
238/**
239 * wlan_hdd_crash_shutdown() - wlan_hdd_crash_shutdown
240 *
241 * HDD crash shutdown funtion: This function is called by
242 * platfrom driver's crash shutdown routine
243 *
244 * Return: void
245 */
246void wlan_hdd_crash_shutdown(void)
247{
248 hif_crash_shutdown(cds_get_context(CDF_MODULE_ID_HIF));
249}
250
251/**
252 * wlan_hdd_notify_handler() - wlan_hdd_notify_handler
253 *
254 * This function is called by the platform driver to notify the
255 * COEX
256 *
257 * @state: state
258 *
259 * Return: void
260 */
261void wlan_hdd_notify_handler(int state)
262{
263 if (!WLAN_IS_EPPING_ENABLED(cds_get_conparam())) {
264 int ret = 0;
265 ret = hdd_wlan_notify_modem_power_state(state);
266 if (ret < 0)
267 hddLog(LOGE, FL("Fail to send notify"));
268 }
269}
270
271/**
272 * __wlan_hdd_bus_suspend() - handles platform supsend
273 * @state: suspend message from the kernel
274 *
275 * Does precondtion validation. Ensures that a subsystem restart isn't in
276 * progress. Ensures that no load or unload is in progress.
277 * Calls ol_txrx_bus_suspend to ensure the layer is ready for a bus suspend.
278 * Calls wma_suspend to configure offloads.
279 * Calls hif_suspend to suspend the bus.
280 *
281 * Return: 0 for success, -EFAULT for null pointers,
282 * -EBUSY or -EAGAIN if another opperation is in progress and
283 * wlan will not be ready to suspend in time.
284 */
285static int __wlan_hdd_bus_suspend(pm_message_t state)
286{
287 void *hdd_ctx = cds_get_context(CDF_MODULE_ID_HDD);
288 int err = wlan_hdd_validate_context(hdd_ctx);
289 int status;
290
291 hdd_info("event %d", state.event);
292
293 if (err)
294 goto done;
295
296 err = cdf_status_to_os_return(
297 ol_txrx_bus_suspend());
298 if (err)
299 goto done;
300
301 err = wma_bus_suspend();
302 if (err)
303 goto resume_oltxrx;
304
305 err = hif_bus_suspend();
306 if (err)
307 goto resume_wma;
308
309 hdd_info("suspend done, status = %d", err);
310 return err;
311
312resume_wma:
313 status = wma_bus_resume();
314 CDF_BUG(!status);
315resume_oltxrx:
316 status = ol_txrx_bus_resume();
317 CDF_BUG(!status);
318done:
319 hdd_err("suspend done, status = %d", err);
320 return err;
321}
322
323/**
324 * wlan_hdd_bus_suspend() - suspend the wlan bus
325 *
326 * This function is called by the platform driver to suspend the
327 * wlan bus
328 *
329 * @state: state
330 *
331 * Return: CDF_STATUS
332 */
333int wlan_hdd_bus_suspend(pm_message_t state)
334{
335 int ret;
336
337 cds_ssr_protect(__func__);
338 ret = __wlan_hdd_bus_suspend(state);
339 cds_ssr_unprotect(__func__);
340
341 return ret;
342}
343
344/**
345 * __wlan_hdd_bus_resume() - handles platform resume
346 *
347 * Does precondtion validation. Ensures that a subsystem restart isn't in
348 * progress. Ensures that no load or unload is in progress. Ensures that
349 * it has valid pointers for the required contexts.
350 * Calls into hif to resume the bus opperation.
351 * Calls into wma to handshake with firmware and notify it that the bus is up.
352 * Calls into ol_txrx for symetry.
353 * Failures are treated as catastrophic.
354 *
355 * return: error code or 0 for success
356 */
357static int __wlan_hdd_bus_resume(void)
358{
359 void *hdd_ctx = cds_get_context(CDF_MODULE_ID_HDD);
360 int status = wlan_hdd_validate_context(hdd_ctx);
361
362 if (0 != status) {
363 hddLog(LOGE, FL("HDD context is not valid"));
364 return status;
365 }
366
367 status = hif_bus_resume();
368 CDF_BUG(!status);
369
370 status = wma_bus_resume();
371 CDF_BUG(!status);
372
373 status = ol_txrx_bus_resume();
374 CDF_BUG(!status);
375
376 hdd_info("resume done");
377 return status;
378}
379
380/**
381 * wlan_hdd_bus_resume(): wake up the bus
382 *
383 * This function is called by the platform driver to resume wlan
384 * bus
385 *
386 * Return: void
387 */
388static int wlan_hdd_bus_resume(void)
389{
390 int ret;
391
392 cds_ssr_protect(__func__);
393 ret = __wlan_hdd_bus_resume();
394 cds_ssr_unprotect(__func__);
395
396 return ret;
397}
398
399#ifdef HIF_PCI
400/**
401 * wlan_hdd_pci_probe() - probe callback for pci platform driver
402 * @pdev: bus dev
403 *
404 * Return: void
405 */
406static int wlan_hdd_pci_probe(struct pci_dev *pdev,
407 const struct pci_device_id *id)
408{
409 return wlan_hdd_probe(&pdev->dev, pdev, (void *)id,
410 HAL_BUS_TYPE_PCI, false);
411}
412
413/**
414 * wlan_hdd_pci_remove() - wlan_hdd_pci_remove
415 *
416 * Return: void
417 */
418void wlan_hdd_pci_remove(struct pci_dev *pdev)
419{
420 wlan_hdd_remove();
421}
422
423/**
424 * wlan_hdd_pci_reinit() - wlan_hdd_pci_reinit
425 * @pdev: bus dev
426 * @id: bus id
427 *
428 * Return: int
429 */
430int wlan_hdd_pci_reinit(struct pci_dev *pdev,
431 const struct pci_device_id *id)
432{
433 return wlan_hdd_probe(&pdev->dev, pdev, id,
434 HAL_BUS_TYPE_PCI, true);
435}
436
437/**
438 * wlan_hdd_pci_shutdown() - wlan_hdd_pci_shutdown
439 * @pdev: pdev
440 *
441 * Return: void
442 */
443void wlan_hdd_pci_shutdown(struct pci_dev *pdev)
444{
445 wlan_hdd_shutdown();
446}
447
448/**
449 * wlan_hdd_pci_crash_shutdown() - wlan_hdd_pci_crash_shutdown
450 * @pdev: pdev
451 *
452 * Return: void
453 */
454void wlan_hdd_pci_crash_shutdown(struct pci_dev *pdev)
455{
456 wlan_hdd_crash_shutdown();
457}
458
459/**
460 * wlan_hdd_pci_notify_handler() - wlan_hdd_pci_notify_handler
461 * @pdev: pdev
462 * @state: state
463 *
464 * Return: void
465 */
466void wlan_hdd_pci_notify_handler(struct pci_dev *pdev, int state)
467{
468 wlan_hdd_notify_handler(state);
469}
470
471/**
472 * wlan_hdd_pci_suspend() - wlan_hdd_pci_suspend
473 * @pdev: pdev
474 * @state: state
475 *
476 * Return: void
477 */
478static int wlan_hdd_pci_suspend(struct pci_dev *pdev, pm_message_t state)
479{
480 return wlan_hdd_bus_suspend(state);
481}
482
483/**
484 * wlan_hdd_pci_resume() - wlan_hdd_pci_resume
485 * @pdev: pdev
486 *
487 * Return: void
488 */
489static int wlan_hdd_pci_resume(struct pci_dev *pdev)
490{
491 return wlan_hdd_bus_resume();
492}
493#else
494/**
495 * wlan_hdd_snoc_probe() - wlan_hdd_snoc_probe
496 * @dev: dev
497 *
498 * Return: int
499 */
500static int wlan_hdd_snoc_probe(struct device *dev)
501{
502 return wlan_hdd_probe(dev, NULL, NULL, HAL_BUS_TYPE_SNOC, false);
503}
504
505/**
506 * wlan_hdd_snoc_remove() - wlan_hdd_snoc_remove
507 * @dev: dev
508 *
509 * Return: void
510 */
511void wlan_hdd_snoc_remove(struct device *dev)
512{
513 wlan_hdd_remove();
514}
515
516/**
517 * wlan_hdd_snoc_shutdown() - wlan_hdd_snoc_shutdown
518 * @dev: dev
519 *
520 * Return: void
521 */
522void wlan_hdd_snoc_shutdown(struct device *dev)
523{
524 wlan_hdd_shutdown();
525}
526
527/**
528 * wlan_hdd_snoc_reinit() - wlan_hdd_snoc_reinit
529 * @dev: dev
530 *
531 * Return: int
532 */
533int wlan_hdd_snoc_reinit(struct device *dev)
534{
535 return wlan_hdd_probe(dev, NULL, NULL, HAL_BUS_TYPE_SNOC, true);
536}
537
538/**
539 * wlan_hdd_snoc_crash_shutdown() - wlan_hdd_snoc_crash_shutdown
540 * @dev: dev
541 *
542 * Return: void
543 */
544void wlan_hdd_snoc_crash_shutdown(void *pdev)
545{
546 wlan_hdd_crash_shutdown();
547}
548
549/**
550 * wlan_hdd_snoc_suspend() - wlan_hdd_snoc_suspend
551 * @dev: dev
552 * @state: state
553 *
554 * Return: int
555 */
556static int wlan_hdd_snoc_suspend(struct device *dev, pm_message_t state)
557{
558 return wlan_hdd_bus_suspend(state);
559}
560
561/**
562 * wlan_hdd_snoc_resume() - wlan_hdd_snoc_resume
563 * @dev: dev
564 *
565 * Return: int
566 */
567static int wlan_hdd_snoc_resume(struct device *dev)
568{
569 return wlan_hdd_bus_resume();
570}
571#endif /* HIF_PCI */
572
573#ifdef HIF_PCI
574static struct pci_device_id wlan_hdd_pci_id_table[] = {
575 { 0x168c, 0x003c, PCI_ANY_ID, PCI_ANY_ID },
576 { 0x168c, 0x003e, PCI_ANY_ID, PCI_ANY_ID },
577 { 0x168c, 0x0041, PCI_ANY_ID, PCI_ANY_ID },
578 { 0x168c, 0xabcd, PCI_ANY_ID, PCI_ANY_ID },
579 { 0x168c, 0x7021, PCI_ANY_ID, PCI_ANY_ID },
580 { 0 }
581};
582
583#ifdef CONFIG_CNSS
584struct cnss_wlan_driver wlan_drv_ops = {
585 .name = "wlan_hdd_pci",
586 .id_table = wlan_hdd_pci_id_table,
587 .probe = wlan_hdd_pci_probe,
588 .remove = wlan_hdd_pci_remove,
589 .reinit = wlan_hdd_pci_reinit,
590 .shutdown = wlan_hdd_pci_shutdown,
591 .crash_shutdown = wlan_hdd_pci_crash_shutdown,
592 .modem_status = wlan_hdd_pci_notify_handler,
593#ifdef ATH_BUS_PM
594 .suspend = wlan_hdd_pci_suspend,
595 .resume = wlan_hdd_pci_resume,
596#endif /* ATH_BUS_PM */
597};
598#else
599MODULE_DEVICE_TABLE(pci, wlan_hdd_pci_id_table);
600struct pci_driver wlan_drv_ops = {
601 .name = "wlan_hdd_pci",
602 .id_table = wlan_hdd_pci_id_table,
603 .probe = wlan_hdd_pci_probe,
604 .remove = wlan_hdd_pci_remove,
605#ifdef ATH_BUS_PM
606 .suspend = wlan_hdd_pci_suspend,
607 .resume = wlan_hdd_pci_resume,
608#endif /* ATH_BUS_PM */
609};
610#endif /* CONFIG_CNSS */
611#else
612struct icnss_driver_ops wlan_drv_ops = {
613 .name = "wlan_hdd_drv",
614 .probe = wlan_hdd_snoc_probe,
615 .remove = wlan_hdd_snoc_remove,
616 .shutdown = wlan_hdd_snoc_shutdown,
617 .reinit = wlan_hdd_snoc_reinit,
618 .crash_shutdown = wlan_hdd_snoc_crash_shutdown,
619 .suspend = wlan_hdd_snoc_suspend,
620 .resume = wlan_hdd_snoc_resume,
621};
622#endif
623
624/**
625 * wlan_hdd_register_driver() - wlan_hdd_register_driver
626 *
627 * Return: int
628 */
629int wlan_hdd_register_driver(void)
630{
631 return WLAN_HDD_REGISTER_DRIVER(&wlan_drv_ops);
632}
633
634/**
635 * wlan_hdd_unregister_driver() - wlan_hdd_unregister_driver
636 *
637 * Return: void
638 */
639void wlan_hdd_unregister_driver(void)
640{
641 WLAN_HDD_UNREGISTER_DRIVER(&wlan_drv_ops);
642}