1 /*
2 * Linux DHD Bus Module for PCIE
3 *
4 * Copyright (C) 1999-2017, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 *
25 * <<Broadcom-WL-IPTag/Open:>>
26 *
27 * $Id: dhd_pcie_linux.c 707536 2017-06-28 04:23:48Z $
28 */
29
30
31 /* include files */
32 #include <typedefs.h>
33 #include <bcmutils.h>
34 #include <bcmdevs.h>
35 #include <siutils.h>
36 #include <hndsoc.h>
37 #include <hndpmu.h>
38 #include <sbchipc.h>
39 #if defined(DHD_DEBUG)
40 #include <hnd_armtrap.h>
41 #include <hnd_cons.h>
42 #endif /* defined(DHD_DEBUG) */
43 #include <dngl_stats.h>
44 #include <pcie_core.h>
45 #include <dhd.h>
46 #include <dhd_bus.h>
47 #include <dhd_proto.h>
48 #include <dhd_dbg.h>
49 #include <dhdioctl.h>
50 #include <bcmmsgbuf.h>
51 #include <pcicfg.h>
52 #include <dhd_pcie.h>
53 #include <dhd_linux.h>
54 #ifdef CONFIG_ARCH_MSM
55 #if defined(CONFIG_PCI_MSM) || defined(CONFIG_ARCH_MSM8996)
56 #include <linux/msm_pcie.h>
57 #else
58 #include <mach/msm_pcie.h>
59 #endif /* CONFIG_PCI_MSM */
60 #endif /* CONFIG_ARCH_MSM */
61 #ifdef PCIE_OOB
62 #include "ftdi_sio_external.h"
63 #endif /* PCIE_OOB */
64 #include <linux/irq.h>
65 #ifdef USE_SMMU_ARCH_MSM
66 #include <asm/dma-iommu.h>
67 #include <linux/iommu.h>
68 #include <linux/of.h>
69 #include <linux/platform_device.h>
70 #endif /* USE_SMMU_ARCH_MSM */
71
72 #define PCI_CFG_RETRY 10
73 #define OS_HANDLE_MAGIC 0x1234abcd /* Magic # to recognize osh */
74 #define BCM_MEM_FILENAME_LEN 24 /* Mem. filename length */
75
76 #define OSL_PKTTAG_CLEAR(p) \
77 do { \
78 struct sk_buff *s = (struct sk_buff *)(p); \
79 ASSERT(OSL_PKTTAG_SZ == 32); \
80 *(uint32 *)(&s->cb[0]) = 0; *(uint32 *)(&s->cb[4]) = 0; \
81 *(uint32 *)(&s->cb[8]) = 0; *(uint32 *)(&s->cb[12]) = 0; \
82 *(uint32 *)(&s->cb[16]) = 0; *(uint32 *)(&s->cb[20]) = 0; \
83 *(uint32 *)(&s->cb[24]) = 0; *(uint32 *)(&s->cb[28]) = 0; \
84 } while (0)
85
86 #ifdef PCIE_OOB
87 #define HOST_WAKE 4 /* GPIO_0 (HOST_WAKE) - Output from WLAN */
88 #define DEVICE_WAKE 5 /* GPIO_1 (DEVICE_WAKE) - Input to WLAN */
89 #define BIT_WL_REG_ON 6
90 #define BIT_BT_REG_ON 7
91
92 int gpio_handle_val = 0;
93 unsigned char gpio_port = 0;
94 unsigned char gpio_direction = 0;
95 #define OOB_PORT "ttyUSB0"
96 #endif /* PCIE_OOB */
97
98 /* user defined data structures */
99
100 typedef struct dhd_pc_res {
101 uint32 bar0_size;
102 void* bar0_addr;
103 uint32 bar1_size;
104 void* bar1_addr;
105 } pci_config_res, *pPci_config_res;
106
107 typedef bool (*dhdpcie_cb_fn_t)(void *);
108
109 typedef struct dhdpcie_info
110 {
111 dhd_bus_t *bus;
112 osl_t *osh;
113 struct pci_dev *dev; /* pci device handle */
114 volatile char *regs; /* pci device memory va */
115 volatile char *tcm; /* pci device memory va */
116 uint32 tcm_size; /* pci device memory size */
117 struct pcos_info *pcos_info;
118 uint16 last_intrstatus; /* to cache intrstatus */
119 int irq;
120 char pciname[32];
121 struct pci_saved_state* default_state;
122 struct pci_saved_state* state;
123 #ifdef BCMPCIE_OOB_HOST_WAKE
124 void *os_cxt; /* Pointer to per-OS private data */
125 #endif /* BCMPCIE_OOB_HOST_WAKE */
126 #ifdef DHD_WAKE_STATUS
127 spinlock_t pcie_lock;
128 unsigned int total_wake_count;
129 int pkt_wake;
130 int wake_irq;
131 #endif /* DHD_WAKE_STATUS */
132 #ifdef USE_SMMU_ARCH_MSM
133 void *smmu_cxt;
134 #endif /* USE_SMMU_ARCH_MSM */
135 } dhdpcie_info_t;
136
137
138 struct pcos_info {
139 dhdpcie_info_t *pc;
140 spinlock_t lock;
141 wait_queue_head_t intr_wait_queue;
142 struct timer_list tuning_timer;
143 int tuning_timer_exp;
144 atomic_t timer_enab;
145 struct tasklet_struct tuning_tasklet;
146 };
147
148 #ifdef BCMPCIE_OOB_HOST_WAKE
149 typedef struct dhdpcie_os_info {
150 int oob_irq_num; /* valid when hardware or software oob in use */
151 unsigned long oob_irq_flags; /* valid when hardware or software oob in use */
152 bool oob_irq_registered;
153 bool oob_irq_enabled;
154 bool oob_irq_wake_enabled;
155 spinlock_t oob_irq_spinlock;
156 void *dev; /* handle to the underlying device */
157 } dhdpcie_os_info_t;
158 static irqreturn_t wlan_oob_irq(int irq, void *data);
159 #if defined(CUSTOMER_HW2) && defined(CONFIG_ARCH_APQ8084)
160 extern struct brcm_pcie_wake brcm_pcie_wake;
161 #endif /* CUSTOMER_HW2 && CONFIG_ARCH_APQ8084 */
162 #endif /* BCMPCIE_OOB_HOST_WAKE */
163
164 #ifdef USE_SMMU_ARCH_MSM
165 typedef struct dhdpcie_smmu_info {
166 struct dma_iommu_mapping *smmu_mapping;
167 dma_addr_t smmu_iova_start;
168 size_t smmu_iova_len;
169 } dhdpcie_smmu_info_t;
170 #endif /* USE_SMMU_ARCH_MSM */
171
172 /* function declarations */
173 static int __devinit
174 dhdpcie_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
175 static void __devexit
176 dhdpcie_pci_remove(struct pci_dev *pdev);
177 static int dhdpcie_init(struct pci_dev *pdev);
178 static irqreturn_t dhdpcie_isr(int irq, void *arg);
179 /* OS Routine functions for PCI suspend/resume */
180
181 static int dhdpcie_set_suspend_resume(dhd_bus_t *bus, bool state);
182 static int dhdpcie_resume_host_dev(dhd_bus_t *bus);
183 static int dhdpcie_suspend_host_dev(dhd_bus_t *bus);
184 static int dhdpcie_resume_dev(struct pci_dev *dev);
185 static int dhdpcie_suspend_dev(struct pci_dev *dev);
186 #ifdef DHD_PCIE_RUNTIMEPM
187 static int dhdpcie_pm_suspend(struct device *dev);
188 static int dhdpcie_pm_prepare(struct device *dev);
189 static int dhdpcie_pm_resume(struct device *dev);
190 static void dhdpcie_pm_complete(struct device *dev);
191 #else
192 static int dhdpcie_pci_suspend(struct pci_dev *dev, pm_message_t state);
193 static int dhdpcie_pci_resume(struct pci_dev *dev);
194 #endif /* DHD_PCIE_RUNTIMEPM */
195
196 static struct pci_device_id dhdpcie_pci_devid[] __devinitdata = {
197 { vendor: 0x14e4,
198 device: PCI_ANY_ID,
199 subvendor: PCI_ANY_ID,
200 subdevice: PCI_ANY_ID,
201 class: PCI_CLASS_NETWORK_OTHER << 8,
202 class_mask: 0xffff00,
203 driver_data: 0,
204 },
205 { 0, 0, 0, 0, 0, 0, 0}
206 };
207 MODULE_DEVICE_TABLE(pci, dhdpcie_pci_devid);
208
209 /* Power Management Hooks */
210 #ifdef DHD_PCIE_RUNTIMEPM
211 static const struct dev_pm_ops dhd_pcie_pm_ops = {
212 .prepare = dhdpcie_pm_prepare,
213 .suspend = dhdpcie_pm_suspend,
214 .resume = dhdpcie_pm_resume,
215 .complete = dhdpcie_pm_complete,
216 };
217 #endif /* DHD_PCIE_RUNTIMEPM */
218
219 static struct pci_driver dhdpcie_driver = {
220 node: {&dhdpcie_driver.node, &dhdpcie_driver.node},
221 name: "pcieh",
222 id_table: dhdpcie_pci_devid,
223 probe: dhdpcie_pci_probe,
224 remove: dhdpcie_pci_remove,
225 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
226 save_state: NULL,
227 #endif
228 #ifdef DHD_PCIE_RUNTIMEPM
229 .driver.pm = &dhd_pcie_pm_ops,
230 #else
231 suspend: dhdpcie_pci_suspend,
232 resume: dhdpcie_pci_resume,
233 #endif /* DHD_PCIE_RUNTIMEPM */
234 };
235
236 int dhdpcie_init_succeeded = FALSE;
237
238 #ifdef USE_SMMU_ARCH_MSM
dhdpcie_smmu_init(struct pci_dev * pdev,void * smmu_cxt)239 static int dhdpcie_smmu_init(struct pci_dev *pdev, void *smmu_cxt)
240 {
241 struct dma_iommu_mapping *mapping;
242 struct device_node *root_node = NULL;
243 dhdpcie_smmu_info_t *smmu_info = (dhdpcie_smmu_info_t *)smmu_cxt;
244 int smmu_iova_address[2];
245 char *wlan_node = "android,bcmdhd_wlan";
246 char *wlan_smmu_node = "wlan-smmu-iova-address";
247 int atomic_ctx = 1;
248 int s1_bypass = 1;
249 int ret = 0;
250
251 DHD_ERROR(("%s: SMMU initialize\n", __FUNCTION__));
252
253 root_node = of_find_compatible_node(NULL, NULL, wlan_node);
254 if (!root_node) {
255 WARN(1, "failed to get device node of BRCM WLAN\n");
256 return -ENODEV;
257 }
258
259 if (of_property_read_u32_array(root_node, wlan_smmu_node,
260 smmu_iova_address, 2) == 0) {
261 DHD_ERROR(("%s : get SMMU start address 0x%x, size 0x%x\n",
262 __FUNCTION__, smmu_iova_address[0], smmu_iova_address[1]));
263 smmu_info->smmu_iova_start = smmu_iova_address[0];
264 smmu_info->smmu_iova_len = smmu_iova_address[1];
265 } else {
266 printf("%s : can't get smmu iova address property\n",
267 __FUNCTION__);
268 return -ENODEV;
269 }
270
271 if (smmu_info->smmu_iova_len <= 0) {
272 DHD_ERROR(("%s: Invalid smmu iova len %d\n",
273 __FUNCTION__, (int)smmu_info->smmu_iova_len));
274 return -EINVAL;
275 }
276
277 DHD_ERROR(("%s : SMMU init start\n", __FUNCTION__));
278 mapping = arm_iommu_create_mapping(&platform_bus_type,
279 smmu_info->smmu_iova_start, smmu_info->smmu_iova_len);
280 if (IS_ERR(mapping)) {
281 DHD_ERROR(("%s: create mapping failed, err = %d\n",
282 __FUNCTION__, ret));
283 ret = PTR_ERR(mapping);
284 goto map_fail;
285 }
286
287 ret = iommu_domain_set_attr(mapping->domain,
288 DOMAIN_ATTR_ATOMIC, &atomic_ctx);
289 if (ret) {
290 DHD_ERROR(("%s: set atomic_ctx attribute failed, err = %d\n",
291 __FUNCTION__, ret));
292 goto set_attr_fail;
293 }
294
295 ret = iommu_domain_set_attr(mapping->domain,
296 DOMAIN_ATTR_S1_BYPASS, &s1_bypass);
297 if (ret < 0) {
298 DHD_ERROR(("%s: set s1_bypass attribute failed, err = %d\n",
299 __FUNCTION__, ret));
300 goto set_attr_fail;
301 }
302
303 ret = arm_iommu_attach_device(&pdev->dev, mapping);
304 if (ret) {
305 DHD_ERROR(("%s: attach device failed, err = %d\n",
306 __FUNCTION__, ret));
307 goto attach_fail;
308 }
309
310 smmu_info->smmu_mapping = mapping;
311
312 return ret;
313
314 attach_fail:
315 set_attr_fail:
316 arm_iommu_release_mapping(mapping);
317 map_fail:
318 return ret;
319 }
320
dhdpcie_smmu_remove(struct pci_dev * pdev,void * smmu_cxt)321 static void dhdpcie_smmu_remove(struct pci_dev *pdev, void *smmu_cxt)
322 {
323 dhdpcie_smmu_info_t *smmu_info;
324
325 if (!smmu_cxt) {
326 return;
327 }
328
329 smmu_info = (dhdpcie_smmu_info_t *)smmu_cxt;
330 if (smmu_info->smmu_mapping) {
331 arm_iommu_detach_device(&pdev->dev);
332 arm_iommu_release_mapping(smmu_info->smmu_mapping);
333 smmu_info->smmu_mapping = NULL;
334 }
335 }
336 #endif /* USE_SMMU_ARCH_MSM */
337
338 #ifdef DHD_PCIE_RUNTIMEPM
dhdpcie_pm_suspend(struct device * dev)339 static int dhdpcie_pm_suspend(struct device *dev)
340 {
341 int ret = 0;
342 struct pci_dev *pdev = to_pci_dev(dev);
343 dhdpcie_info_t *pch = pci_get_drvdata(pdev);
344 dhd_bus_t *bus = NULL;
345 unsigned long flags;
346
347 if (pch) {
348 bus = pch->bus;
349 }
350 if (!bus) {
351 return ret;
352 }
353
354 DHD_GENERAL_LOCK(bus->dhd, flags);
355 if (!DHD_BUS_BUSY_CHECK_IDLE(bus->dhd)) {
356 DHD_ERROR(("%s: Bus not IDLE!! dhd_bus_busy_state = 0x%x\n",
357 __FUNCTION__, bus->dhd->dhd_bus_busy_state));
358 DHD_GENERAL_UNLOCK(bus->dhd, flags);
359 return -EBUSY;
360 }
361 DHD_BUS_BUSY_SET_SUSPEND_IN_PROGRESS(bus->dhd);
362 DHD_GENERAL_UNLOCK(bus->dhd, flags);
363
364 if (!bus->dhd->dongle_reset)
365 ret = dhdpcie_set_suspend_resume(bus, TRUE);
366
367 DHD_GENERAL_LOCK(bus->dhd, flags);
368 DHD_BUS_BUSY_CLEAR_SUSPEND_IN_PROGRESS(bus->dhd);
369 dhd_os_busbusy_wake(bus->dhd);
370 DHD_GENERAL_UNLOCK(bus->dhd, flags);
371
372 return ret;
373 }
374
dhdpcie_pm_prepare(struct device * dev)375 static int dhdpcie_pm_prepare(struct device *dev)
376 {
377 struct pci_dev *pdev = to_pci_dev(dev);
378 dhdpcie_info_t *pch = pci_get_drvdata(pdev);
379 dhd_bus_t *bus = NULL;
380
381 if (pch) {
382 bus = pch->bus;
383 DHD_DISABLE_RUNTIME_PM(bus->dhd);
384 }
385
386 bus->chk_pm = TRUE;
387 return 0;
388 }
389
dhdpcie_pm_resume(struct device * dev)390 static int dhdpcie_pm_resume(struct device *dev)
391 {
392 int ret = 0;
393 struct pci_dev *pdev = to_pci_dev(dev);
394 dhdpcie_info_t *pch = pci_get_drvdata(pdev);
395 dhd_bus_t *bus = NULL;
396 unsigned long flags;
397
398 if (pch) {
399 bus = pch->bus;
400 }
401 if (!bus) {
402 return ret;
403 }
404
405 DHD_GENERAL_LOCK(bus->dhd, flags);
406 DHD_BUS_BUSY_SET_RESUME_IN_PROGRESS(bus->dhd);
407 DHD_GENERAL_UNLOCK(bus->dhd, flags);
408
409 if (!bus->dhd->dongle_reset) {
410 ret = dhdpcie_set_suspend_resume(bus, FALSE);
411 bus->chk_pm = FALSE;
412 }
413
414 DHD_GENERAL_LOCK(bus->dhd, flags);
415 DHD_BUS_BUSY_CLEAR_RESUME_IN_PROGRESS(bus->dhd);
416 dhd_os_busbusy_wake(bus->dhd);
417 DHD_GENERAL_UNLOCK(bus->dhd, flags);
418
419 return ret;
420 }
421
dhdpcie_pm_complete(struct device * dev)422 static void dhdpcie_pm_complete(struct device *dev)
423 {
424 struct pci_dev *pdev = to_pci_dev(dev);
425 dhdpcie_info_t *pch = pci_get_drvdata(pdev);
426 dhd_bus_t *bus = NULL;
427
428 if (pch) {
429 bus = pch->bus;
430 DHD_ENABLE_RUNTIME_PM(bus->dhd);
431 }
432
433 return;
434 }
435 #else
dhdpcie_pci_suspend(struct pci_dev * pdev,pm_message_t state)436 static int dhdpcie_pci_suspend(struct pci_dev * pdev, pm_message_t state)
437 {
438 int ret = 0;
439 dhdpcie_info_t *pch = pci_get_drvdata(pdev);
440 dhd_bus_t *bus = NULL;
441 unsigned long flags;
442
443 if (pch) {
444 bus = pch->bus;
445 }
446 if (!bus) {
447 return ret;
448 }
449
450 BCM_REFERENCE(state);
451
452 DHD_GENERAL_LOCK(bus->dhd, flags);
453 if (!DHD_BUS_BUSY_CHECK_IDLE(bus->dhd)) {
454 DHD_ERROR(("%s: Bus not IDLE!! dhd_bus_busy_state = 0x%x\n",
455 __FUNCTION__, bus->dhd->dhd_bus_busy_state));
456 DHD_GENERAL_UNLOCK(bus->dhd, flags);
457 return -EBUSY;
458 }
459 DHD_BUS_BUSY_SET_SUSPEND_IN_PROGRESS(bus->dhd);
460 DHD_GENERAL_UNLOCK(bus->dhd, flags);
461
462 if (!bus->dhd->dongle_reset)
463 ret = dhdpcie_set_suspend_resume(bus, TRUE);
464
465 DHD_GENERAL_LOCK(bus->dhd, flags);
466 DHD_BUS_BUSY_CLEAR_SUSPEND_IN_PROGRESS(bus->dhd);
467 dhd_os_busbusy_wake(bus->dhd);
468 DHD_GENERAL_UNLOCK(bus->dhd, flags);
469
470 return ret;
471 }
472
dhdpcie_pci_resume(struct pci_dev * pdev)473 static int dhdpcie_pci_resume(struct pci_dev *pdev)
474 {
475 int ret = 0;
476 dhdpcie_info_t *pch = pci_get_drvdata(pdev);
477 dhd_bus_t *bus = NULL;
478 unsigned long flags;
479
480 if (pch) {
481 bus = pch->bus;
482 }
483 if (!bus) {
484 return ret;
485 }
486
487 DHD_GENERAL_LOCK(bus->dhd, flags);
488 DHD_BUS_BUSY_SET_RESUME_IN_PROGRESS(bus->dhd);
489 DHD_GENERAL_UNLOCK(bus->dhd, flags);
490
491 if (!bus->dhd->dongle_reset)
492 ret = dhdpcie_set_suspend_resume(bus, FALSE);
493
494 DHD_GENERAL_LOCK(bus->dhd, flags);
495 DHD_BUS_BUSY_CLEAR_RESUME_IN_PROGRESS(bus->dhd);
496 dhd_os_busbusy_wake(bus->dhd);
497 DHD_GENERAL_UNLOCK(bus->dhd, flags);
498
499 return ret;
500 }
501
502 #endif /* DHD_PCIE_RUNTIMEPM */
503
dhdpcie_set_suspend_resume(dhd_bus_t * bus,bool state)504 static int dhdpcie_set_suspend_resume(dhd_bus_t *bus, bool state)
505 {
506 int ret = 0;
507
508 ASSERT(bus && !bus->dhd->dongle_reset);
509
510 #ifdef DHD_PCIE_RUNTIMEPM
511 /* if wakelock is held during suspend, return failed */
512 if (state == TRUE && dhd_os_check_wakelock_all(bus->dhd)) {
513 return -EBUSY;
514 }
515 mutex_lock(&bus->pm_lock);
516 #endif /* DHD_PCIE_RUNTIMEPM */
517
518 /* When firmware is not loaded do the PCI bus */
519 /* suspend/resume only */
520 if (bus->dhd->busstate == DHD_BUS_DOWN) {
521 ret = dhdpcie_pci_suspend_resume(bus, state);
522 #ifdef DHD_PCIE_RUNTIMEPM
523 mutex_unlock(&bus->pm_lock);
524 #endif /* DHD_PCIE_RUNTIMEPM */
525 return ret;
526 }
527
528 ret = dhdpcie_bus_suspend(bus, state);
529
530 #ifdef DHD_PCIE_RUNTIMEPM
531 mutex_unlock(&bus->pm_lock);
532 #endif /* DHD_PCIE_RUNTIMEPM */
533
534 return ret;
535 }
536
537 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
538 extern void dhd_dpc_tasklet_kill(dhd_pub_t *dhdp);
539 #endif /* OEM_ANDROID && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */
540
dhdpcie_suspend_dev(struct pci_dev * dev)541 static int dhdpcie_suspend_dev(struct pci_dev *dev)
542 {
543 int ret;
544 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
545 dhdpcie_info_t *pch = pci_get_drvdata(dev);
546 dhd_bus_t *bus = pch->bus;
547
548 if (bus->is_linkdown) {
549 DHD_ERROR(("%s: PCIe link is down\n", __FUNCTION__));
550 return BCME_ERROR;
551 }
552 #endif /* OEM_ANDROID && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */
553 DHD_TRACE_HW4(("%s: Enter\n", __FUNCTION__));
554 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
555 dhd_dpc_tasklet_kill(bus->dhd);
556 #endif /* OEM_ANDROID && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */
557 pci_save_state(dev);
558 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
559 pch->state = pci_store_saved_state(dev);
560 #endif /* OEM_ANDROID && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */
561 pci_enable_wake(dev, PCI_D0, TRUE);
562 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
563 if (pci_is_enabled(dev))
564 #endif
565 pci_disable_device(dev);
566
567 ret = pci_set_power_state(dev, PCI_D3hot);
568 if (ret) {
569 DHD_ERROR(("%s: pci_set_power_state error %d\n",
570 __FUNCTION__, ret));
571 }
572 dev->state_saved = FALSE;
573 return ret;
574 }
575
576 #ifdef DHD_WAKE_STATUS
bcmpcie_get_total_wake(struct dhd_bus * bus)577 int bcmpcie_get_total_wake(struct dhd_bus *bus)
578 {
579 dhdpcie_info_t *pch = pci_get_drvdata(bus->dev);
580
581 return pch->total_wake_count;
582 }
583
bcmpcie_set_get_wake(struct dhd_bus * bus,int flag)584 int bcmpcie_set_get_wake(struct dhd_bus *bus, int flag)
585 {
586 dhdpcie_info_t *pch = pci_get_drvdata(bus->dev);
587 unsigned long flags;
588 int ret;
589
590 spin_lock_irqsave(&pch->pcie_lock, flags);
591
592 ret = pch->pkt_wake;
593 pch->total_wake_count += flag;
594 pch->pkt_wake = flag;
595
596 spin_unlock_irqrestore(&pch->pcie_lock, flags);
597 return ret;
598 }
599 #endif /* DHD_WAKE_STATUS */
600
dhdpcie_resume_dev(struct pci_dev * dev)601 static int dhdpcie_resume_dev(struct pci_dev *dev)
602 {
603 int err = 0;
604 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
605 dhdpcie_info_t *pch = pci_get_drvdata(dev);
606 pci_load_and_free_saved_state(dev, &pch->state);
607 #endif /* OEM_ANDROID && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */
608 DHD_TRACE_HW4(("%s: Enter\n", __FUNCTION__));
609 dev->state_saved = TRUE;
610 pci_restore_state(dev);
611 err = pci_enable_device(dev);
612 if (err) {
613 printf("%s:pci_enable_device error %d \n", __FUNCTION__, err);
614 goto out;
615 }
616 pci_set_master(dev);
617 err = pci_set_power_state(dev, PCI_D0);
618 if (err) {
619 printf("%s:pci_set_power_state error %d \n", __FUNCTION__, err);
620 goto out;
621 }
622
623 out:
624 return err;
625 }
626
dhdpcie_resume_host_dev(dhd_bus_t * bus)627 static int dhdpcie_resume_host_dev(dhd_bus_t *bus)
628 {
629 int bcmerror = 0;
630 #ifdef USE_EXYNOS_PCIE_RC_PMPATCH
631 bcmerror = exynos_pcie_pm_resume(SAMSUNG_PCIE_CH_NUM);
632 #endif /* USE_EXYNOS_PCIE_RC_PMPATCH */
633 #ifdef CONFIG_ARCH_MSM
634 bcmerror = dhdpcie_start_host_pcieclock(bus);
635 #endif /* CONFIG_ARCH_MSM */
636 #ifdef CONFIG_ARCH_TEGRA
637 bcmerror = tegra_pcie_pm_resume();
638 #endif /* CONFIG_ARCH_TEGRA */
639 if (bcmerror < 0) {
640 DHD_ERROR(("%s: PCIe RC resume failed!!! (%d)\n",
641 __FUNCTION__, bcmerror));
642 bus->is_linkdown = 1;
643 #ifdef SUPPORT_LINKDOWN_RECOVERY
644 #ifdef CONFIG_ARCH_MSM
645 bus->no_cfg_restore = 1;
646 #endif /* CONFIG_ARCH_MSM */
647 #endif /* SUPPORT_LINKDOWN_RECOVERY */
648 }
649
650 return bcmerror;
651 }
652
dhdpcie_suspend_host_dev(dhd_bus_t * bus)653 static int dhdpcie_suspend_host_dev(dhd_bus_t *bus)
654 {
655 int bcmerror = 0;
656 #ifdef USE_EXYNOS_PCIE_RC_PMPATCH
657 if (bus->rc_dev) {
658 pci_save_state(bus->rc_dev);
659 } else {
660 DHD_ERROR(("%s: RC %x:%x handle is NULL\n",
661 __FUNCTION__, PCIE_RC_VENDOR_ID, PCIE_RC_DEVICE_ID));
662 }
663 exynos_pcie_pm_suspend(SAMSUNG_PCIE_CH_NUM);
664 #endif /* USE_EXYNOS_PCIE_RC_PMPATCH */
665 #ifdef CONFIG_ARCH_MSM
666 bcmerror = dhdpcie_stop_host_pcieclock(bus);
667 #endif /* CONFIG_ARCH_MSM */
668 #ifdef CONFIG_ARCH_TEGRA
669 bcmerror = tegra_pcie_pm_suspend();
670 #endif /* CONFIG_ARCH_TEGRA */
671 return bcmerror;
672 }
673
674 #if defined(PCIE_RC_VENDOR_ID) && defined(PCIE_RC_DEVICE_ID)
675 uint32
dhdpcie_rc_config_read(dhd_bus_t * bus,uint offset)676 dhdpcie_rc_config_read(dhd_bus_t *bus, uint offset)
677 {
678 uint val = -1; /* Initialise to 0xfffffff */
679 if (bus->rc_dev) {
680 pci_read_config_dword(bus->rc_dev, offset, &val);
681 OSL_DELAY(100);
682 } else {
683 DHD_ERROR(("%s: RC %x:%x handle is NULL\n",
684 __FUNCTION__, PCIE_RC_VENDOR_ID, PCIE_RC_DEVICE_ID));
685 }
686 DHD_ERROR(("%s: RC %x:%x offset 0x%x val 0x%x\n",
687 __FUNCTION__, PCIE_RC_VENDOR_ID, PCIE_RC_DEVICE_ID, offset, val));
688 return (val);
689 }
690
691 /*
692 * Reads/ Writes the value of capability register
693 * from the given CAP_ID section of PCI Root Port
694 *
695 * Arguements
696 * @bus current dhd_bus_t pointer
697 * @cap Capability or Extended Capability ID to get
698 * @offset offset of Register to Read
699 * @is_ext TRUE if @cap is given for Extended Capability
700 * @is_write is set to TRUE to indicate write
701 * @val value to write
702 *
703 * Return Value
704 * Returns 0xffffffff on error
705 * on write success returns BCME_OK (0)
706 * on Read Success returns the value of register requested
707 * Note: caller shoud ensure valid capability ID and Ext. Capability ID.
708 */
709
710 uint32
dhdpcie_rc_access_cap(dhd_bus_t * bus,int cap,uint offset,bool is_ext,bool is_write,uint32 writeval)711 dhdpcie_rc_access_cap(dhd_bus_t *bus, int cap, uint offset, bool is_ext, bool is_write,
712 uint32 writeval)
713 {
714 int cap_ptr = 0;
715 uint32 ret = -1;
716 uint32 readval;
717
718 if (!(bus->rc_dev)) {
719 DHD_ERROR(("%s: RC %x:%x handle is NULL\n",
720 __FUNCTION__, PCIE_RC_VENDOR_ID, PCIE_RC_DEVICE_ID));
721 return ret;
722 }
723
724 /* Find Capability offset */
725 if (is_ext) {
726 /* removing max EXT_CAP_ID check as
727 * linux kernel definition's max value is not upadted yet as per spec
728 */
729 cap_ptr = pci_find_ext_capability(bus->rc_dev, cap);
730 } else {
731 /* removing max PCI_CAP_ID_MAX check as
732 * pervious kernel versions dont have this definition
733 */
734 cap_ptr = pci_find_capability(bus->rc_dev, cap);
735 }
736
737 /* Return if capability with given ID not found */
738 if (cap_ptr == 0) {
739 DHD_ERROR(("%s: RC %x:%x PCI Cap(0x%02x) not supported.\n",
740 __FUNCTION__, PCIE_RC_VENDOR_ID, PCIE_RC_DEVICE_ID, cap));
741 return BCME_ERROR;
742 }
743
744 if (is_write) {
745 ret = pci_write_config_dword(bus->rc_dev, (cap_ptr + offset), writeval);
746 if (ret) {
747 DHD_ERROR(("%s: pci_write_config_dword failed. cap=%d offset=%d\n",
748 __FUNCTION__, cap, offset));
749 return BCME_ERROR;
750 }
751 ret = BCME_OK;
752 } else {
753 ret = pci_read_config_dword(bus->rc_dev, (cap_ptr + offset), &readval);
754
755 if (ret) {
756 DHD_ERROR(("%s: pci_read_config_dword failed. cap=%d offset=%d\n",
757 __FUNCTION__, cap, offset));
758 return BCME_ERROR;
759 }
760 ret = readval;
761 }
762
763 return ret;
764 }
765
766 /* API wrapper to read Root Port link capability
767 * Returns 2 = GEN2 1 = GEN1 BCME_ERR on linkcap not found
768 */
769
dhd_debug_get_rc_linkcap(dhd_bus_t * bus)770 uint32 dhd_debug_get_rc_linkcap(dhd_bus_t *bus)
771 {
772 uint32 linkcap = -1;
773 linkcap = dhdpcie_rc_access_cap(bus, PCIE_CAP_ID_EXP,
774 PCIE_CAP_LINKCAP_OFFSET, FALSE, FALSE, 0);
775 linkcap &= PCIE_CAP_LINKCAP_LNKSPEED_MASK;
776 return linkcap;
777 }
778 #endif
779
dhdpcie_pci_suspend_resume(dhd_bus_t * bus,bool state)780 int dhdpcie_pci_suspend_resume(dhd_bus_t *bus, bool state)
781 {
782 int rc;
783
784 struct pci_dev *dev = bus->dev;
785
786 if (state) {
787 #ifndef BCMPCIE_OOB_HOST_WAKE
788 dhdpcie_pme_active(bus->osh, state);
789 #endif /* !BCMPCIE_OOB_HOST_WAKE */
790 rc = dhdpcie_suspend_dev(dev);
791 if (!rc) {
792 dhdpcie_suspend_host_dev(bus);
793 }
794 } else {
795 dhdpcie_resume_host_dev(bus);
796 rc = dhdpcie_resume_dev(dev);
797 #ifndef BCMPCIE_OOB_HOST_WAKE
798 dhdpcie_pme_active(bus->osh, state);
799 #endif /* !BCMPCIE_OOB_HOST_WAKE */
800 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
801 #if defined(DHD_HANG_SEND_UP_TEST)
802 if (bus->is_linkdown ||
803 bus->dhd->req_hang_type == HANG_REASON_PCIE_RC_LINK_UP_FAIL)
804 #else /* DHD_HANG_SEND_UP_TEST */
805 if (bus->is_linkdown)
806 #endif /* DHD_HANG_SEND_UP_TEST */
807 {
808 bus->dhd->hang_reason = HANG_REASON_PCIE_RC_LINK_UP_FAIL;
809 dhd_os_send_hang_message(bus->dhd);
810 }
811 #endif
812 }
813 return rc;
814 }
815
816 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
dhdpcie_device_scan(struct device * dev,void * data)817 static int dhdpcie_device_scan(struct device *dev, void *data)
818 {
819 struct pci_dev *pcidev;
820 int *cnt = data;
821
822 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
823 #pragma GCC diagnostic push
824 #pragma GCC diagnostic ignored "-Wcast-qual"
825 #endif
826 pcidev = container_of(dev, struct pci_dev, dev);
827 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
828 #pragma GCC diagnostic pop
829 #endif
830 if (pcidev->vendor != 0x14e4)
831 return 0;
832
833 DHD_INFO(("Found Broadcom PCI device 0x%04x\n", pcidev->device));
834 *cnt += 1;
835 if (pcidev->driver && strcmp(pcidev->driver->name, dhdpcie_driver.name))
836 DHD_ERROR(("Broadcom PCI Device 0x%04x has allocated with driver %s\n",
837 pcidev->device, pcidev->driver->name));
838
839 return 0;
840 }
841 #endif /* LINUX_VERSION >= 2.6.0 */
842
843 int
dhdpcie_bus_register(void)844 dhdpcie_bus_register(void)
845 {
846 int error = 0;
847
848
849 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
850 if (!(error = pci_module_init(&dhdpcie_driver)))
851 return 0;
852
853 DHD_ERROR(("%s: pci_module_init failed 0x%x\n", __FUNCTION__, error));
854 #else
855 if (!(error = pci_register_driver(&dhdpcie_driver))) {
856 bus_for_each_dev(dhdpcie_driver.driver.bus, NULL, &error, dhdpcie_device_scan);
857 if (!error) {
858 DHD_ERROR(("No Broadcom PCI device enumerated!\n"));
859 } else if (!dhdpcie_init_succeeded) {
860 DHD_ERROR(("%s: dhdpcie initialize failed.\n", __FUNCTION__));
861 } else {
862 return 0;
863 }
864
865 pci_unregister_driver(&dhdpcie_driver);
866 error = BCME_ERROR;
867 }
868 #endif /* LINUX_VERSION < 2.6.0 */
869
870 return error;
871 }
872
873
874 void
dhdpcie_bus_unregister(void)875 dhdpcie_bus_unregister(void)
876 {
877 pci_unregister_driver(&dhdpcie_driver);
878 }
879
880 int __devinit
dhdpcie_pci_probe(struct pci_dev * pdev,const struct pci_device_id * ent)881 dhdpcie_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
882 {
883 DHD_MUTEX_LOCK();
884
885 if (dhdpcie_chipmatch (pdev->vendor, pdev->device)) {
886 DHD_ERROR(("%s: chipmatch failed!!\n", __FUNCTION__));
887 DHD_MUTEX_UNLOCK();
888 return -ENODEV;
889 }
890 printf("PCI_PROBE: bus %X, slot %X,vendor %X, device %X"
891 "(good PCI location)\n", pdev->bus->number,
892 PCI_SLOT(pdev->devfn), pdev->vendor, pdev->device);
893
894 if (dhdpcie_init (pdev)) {
895 DHD_ERROR(("%s: PCIe Enumeration failed\n", __FUNCTION__));
896 DHD_MUTEX_UNLOCK();
897 return -ENODEV;
898 }
899
900 #ifdef BCMPCIE_DISABLE_ASYNC_SUSPEND
901 /* disable async suspend */
902 device_disable_async_suspend(&pdev->dev);
903 #endif /* BCMPCIE_DISABLE_ASYNC_SUSPEND */
904
905 DHD_TRACE(("%s: PCIe Enumeration done!!\n", __FUNCTION__));
906 DHD_MUTEX_UNLOCK();
907 return 0;
908 }
909
910 int
dhdpcie_detach(dhdpcie_info_t * pch)911 dhdpcie_detach(dhdpcie_info_t *pch)
912 {
913 if (pch) {
914 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
915 if (!dhd_download_fw_on_driverload) {
916 pci_load_and_free_saved_state(pch->dev, &pch->default_state);
917 }
918 #endif /* OEM_ANDROID && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */
919 MFREE(pch->osh, pch, sizeof(dhdpcie_info_t));
920 }
921 return 0;
922 }
923
924
925 void __devexit
dhdpcie_pci_remove(struct pci_dev * pdev)926 dhdpcie_pci_remove(struct pci_dev *pdev)
927 {
928 osl_t *osh = NULL;
929 dhdpcie_info_t *pch = NULL;
930 dhd_bus_t *bus = NULL;
931
932 DHD_TRACE(("%s Enter\n", __FUNCTION__));
933
934 DHD_MUTEX_LOCK();
935
936 pch = pci_get_drvdata(pdev);
937 bus = pch->bus;
938 osh = pch->osh;
939
940 #ifdef SUPPORT_LINKDOWN_RECOVERY
941 if (bus) {
942 #ifdef CONFIG_ARCH_MSM
943 msm_pcie_deregister_event(&bus->pcie_event);
944 #endif /* CONFIG_ARCH_MSM */
945 #ifdef EXYNOS_PCIE_LINKDOWN_RECOVERY
946 #ifdef CONFIG_SOC_EXYNOS8890
947 exynos_pcie_deregister_event(&bus->pcie_event);
948 #endif /* CONFIG_SOC_EXYNOS8890 */
949 #endif /* EXYNOS_PCIE_LINKDOWN_RECOVERY */
950 }
951 #endif /* SUPPORT_LINKDOWN_RECOVERY */
952
953 bus->rc_dev = NULL;
954
955 dhdpcie_bus_release(bus);
956 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
957 if (pci_is_enabled(pdev))
958 #endif
959 pci_disable_device(pdev);
960 #ifdef BCMPCIE_OOB_HOST_WAKE
961 /* pcie os info detach */
962 MFREE(osh, pch->os_cxt, sizeof(dhdpcie_os_info_t));
963 #endif /* BCMPCIE_OOB_HOST_WAKE */
964 #ifdef USE_SMMU_ARCH_MSM
965 /* smmu info detach */
966 dhdpcie_smmu_remove(pdev, pch->smmu_cxt);
967 MFREE(osh, pch->smmu_cxt, sizeof(dhdpcie_smmu_info_t));
968 #endif /* USE_SMMU_ARCH_MSM */
969 /* pcie info detach */
970 dhdpcie_detach(pch);
971 /* osl detach */
972 osl_detach(osh);
973
974 #if defined(BCMPCIE_OOB_HOST_WAKE) && defined(CUSTOMER_HW2) && \
975 defined(CONFIG_ARCH_APQ8084)
976 brcm_pcie_wake.wake_irq = NULL;
977 brcm_pcie_wake.data = NULL;
978 #endif /* BCMPCIE_OOB_HOST_WAKE && CUSTOMR_HW2 && CONFIG_ARCH_APQ8084 */
979
980 dhdpcie_init_succeeded = FALSE;
981
982 DHD_MUTEX_UNLOCK();
983
984 DHD_TRACE(("%s Exit\n", __FUNCTION__));
985
986 return;
987 }
988
989 /* Free Linux irq */
990 int
dhdpcie_request_irq(dhdpcie_info_t * dhdpcie_info)991 dhdpcie_request_irq(dhdpcie_info_t *dhdpcie_info)
992 {
993 dhd_bus_t *bus = dhdpcie_info->bus;
994 struct pci_dev *pdev = dhdpcie_info->bus->dev;
995 int err = 0;
996
997 if (!bus->irq_registered) {
998 snprintf(dhdpcie_info->pciname, sizeof(dhdpcie_info->pciname),
999 "dhdpcie:%s", pci_name(pdev));
1000 #ifdef DHD_USE_MSI
1001 printf("%s: MSI enabled\n", __FUNCTION__);
1002 err = pci_enable_msi(pdev);
1003 if (err < 0) {
1004 DHD_ERROR(("%s: pci_enable_msi() failed, %d, fall back to INTx\n", __FUNCTION__, err));
1005 }
1006 #else
1007 printf("%s: MSI not enabled\n", __FUNCTION__);
1008 #endif /* DHD_USE_MSI */
1009 err = request_irq(pdev->irq, dhdpcie_isr, IRQF_SHARED,
1010 dhdpcie_info->pciname, bus);
1011 if (err) {
1012 DHD_ERROR(("%s: request_irq() failed\n", __FUNCTION__));
1013 #ifdef DHD_USE_MSI
1014 pci_disable_msi(pdev);
1015 #endif /* DHD_USE_MSI */
1016 return -1;
1017 } else {
1018 bus->irq_registered = TRUE;
1019 }
1020 } else {
1021 DHD_ERROR(("%s: PCI IRQ is already registered\n", __FUNCTION__));
1022 }
1023
1024 if (!dhdpcie_irq_enabled(bus)) {
1025 DHD_ERROR(("%s: PCIe IRQ was disabled, so, enabled it again\n", __FUNCTION__));
1026 dhdpcie_enable_irq(bus);
1027 }
1028
1029 DHD_TRACE(("%s %s\n", __FUNCTION__, dhdpcie_info->pciname));
1030
1031
1032 return 0; /* SUCCESS */
1033 }
1034
1035 /**
1036 * dhdpcie_get_pcieirq - return pcie irq number to linux-dhd
1037 */
1038 int
dhdpcie_get_pcieirq(struct dhd_bus * bus,unsigned int * irq)1039 dhdpcie_get_pcieirq(struct dhd_bus *bus, unsigned int *irq)
1040 {
1041 struct pci_dev *pdev = bus->dev;
1042
1043 if (!pdev) {
1044 DHD_ERROR(("%s : bus->dev is NULL\n", __FUNCTION__));
1045 return -ENODEV;
1046 }
1047
1048 *irq = pdev->irq;
1049
1050 return 0; /* SUCCESS */
1051 }
1052
1053 #ifdef CONFIG_PHYS_ADDR_T_64BIT
1054 #define PRINTF_RESOURCE "0x%016llx"
1055 #else
1056 #define PRINTF_RESOURCE "0x%08x"
1057 #endif
1058
1059 /*
1060
1061 Name: osl_pci_get_resource
1062
1063 Parametrs:
1064
1065 1: struct pci_dev *pdev -- pci device structure
1066 2: pci_res -- structure containing pci configuration space values
1067
1068
1069 Return value:
1070
1071 int - Status (TRUE or FALSE)
1072
1073 Description:
1074 Access PCI configuration space, retrieve PCI allocated resources , updates in resource structure.
1075
1076 */
dhdpcie_get_resource(dhdpcie_info_t * dhdpcie_info)1077 int dhdpcie_get_resource(dhdpcie_info_t *dhdpcie_info)
1078 {
1079 phys_addr_t bar0_addr, bar1_addr;
1080 ulong bar1_size;
1081 struct pci_dev *pdev = NULL;
1082 pdev = dhdpcie_info->dev;
1083 #ifdef EXYNOS_PCIE_MODULE_PATCH
1084 pci_restore_state(pdev);
1085 #endif /* EXYNOS_MODULE_PATCH */
1086 do {
1087 if (pci_enable_device(pdev)) {
1088 printf("%s: Cannot enable PCI device\n", __FUNCTION__);
1089 break;
1090 }
1091 pci_set_master(pdev);
1092 bar0_addr = pci_resource_start(pdev, 0); /* Bar-0 mapped address */
1093 bar1_addr = pci_resource_start(pdev, 2); /* Bar-1 mapped address */
1094
1095 /* read Bar-1 mapped memory range */
1096 bar1_size = pci_resource_len(pdev, 2);
1097
1098 if ((bar1_size == 0) || (bar1_addr == 0)) {
1099 printf("%s: BAR1 Not enabled for this device size(%ld),"
1100 " addr(0x"PRINTF_RESOURCE")\n",
1101 __FUNCTION__, bar1_size, bar1_addr);
1102 goto err;
1103 }
1104
1105 dhdpcie_info->regs = (volatile char *) REG_MAP(bar0_addr, DONGLE_REG_MAP_SIZE);
1106 dhdpcie_info->tcm_size =
1107 (bar1_size > DONGLE_TCM_MAP_SIZE) ? bar1_size : DONGLE_TCM_MAP_SIZE;
1108 dhdpcie_info->tcm = (volatile char *) REG_MAP(bar1_addr, dhdpcie_info->tcm_size);
1109
1110 if (!dhdpcie_info->regs || !dhdpcie_info->tcm) {
1111 DHD_ERROR(("%s:ioremap() failed\n", __FUNCTION__));
1112 break;
1113 }
1114
1115 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
1116 if (!dhd_download_fw_on_driverload) {
1117 /* Backup PCIe configuration so as to use Wi-Fi on/off process
1118 * in case of built in driver
1119 */
1120 pci_save_state(pdev);
1121 dhdpcie_info->default_state = pci_store_saved_state(pdev);
1122
1123 if (dhdpcie_info->default_state == NULL) {
1124 DHD_ERROR(("%s pci_store_saved_state returns NULL\n",
1125 __FUNCTION__));
1126 REG_UNMAP(dhdpcie_info->regs);
1127 REG_UNMAP(dhdpcie_info->tcm);
1128 pci_disable_device(pdev);
1129 break;
1130 }
1131 }
1132 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */
1133
1134 #ifdef EXYNOS_PCIE_MODULE_PATCH
1135 pci_save_state(pdev);
1136 #endif /* EXYNOS_MODULE_PATCH */
1137
1138 DHD_TRACE(("%s:Phys addr : reg space = %p base addr 0x"PRINTF_RESOURCE" \n",
1139 __FUNCTION__, dhdpcie_info->regs, bar0_addr));
1140 DHD_TRACE(("%s:Phys addr : tcm_space = %p base addr 0x"PRINTF_RESOURCE" \n",
1141 __FUNCTION__, dhdpcie_info->tcm, bar1_addr));
1142
1143 return 0; /* SUCCESS */
1144 } while (0);
1145 err:
1146 return -1; /* FAILURE */
1147 }
1148
dhdpcie_scan_resource(dhdpcie_info_t * dhdpcie_info)1149 int dhdpcie_scan_resource(dhdpcie_info_t *dhdpcie_info)
1150 {
1151 DHD_TRACE(("%s: ENTER\n", __FUNCTION__));
1152
1153 do {
1154 /* define it here only!! */
1155 if (dhdpcie_get_resource (dhdpcie_info)) {
1156 DHD_ERROR(("%s: Failed to get PCI resources\n", __FUNCTION__));
1157 break;
1158 }
1159 DHD_TRACE(("%s:Exit - SUCCESS \n",
1160 __FUNCTION__));
1161
1162 return 0; /* SUCCESS */
1163 } while (0);
1164
1165 DHD_TRACE(("%s:Exit - FAILURE \n", __FUNCTION__));
1166
1167 return -1; /* FAILURE */
1168 }
1169
1170 #ifdef SUPPORT_LINKDOWN_RECOVERY
1171 #if defined(CONFIG_ARCH_MSM) || (defined(EXYNOS_PCIE_LINKDOWN_RECOVERY) && \
1172 (defined(CONFIG_SOC_EXYNOS8890) || defined(CONFIG_SOC_EXYNOS8895)))
dhdpcie_linkdown_cb(struct_pcie_notify * noti)1173 void dhdpcie_linkdown_cb(struct_pcie_notify *noti)
1174 {
1175 struct pci_dev *pdev = (struct pci_dev *)noti->user;
1176 dhdpcie_info_t *pch = NULL;
1177
1178 if (pdev) {
1179 pch = pci_get_drvdata(pdev);
1180 if (pch) {
1181 dhd_bus_t *bus = pch->bus;
1182 if (bus) {
1183 dhd_pub_t *dhd = bus->dhd;
1184 if (dhd) {
1185 DHD_ERROR(("%s: Event HANG send up "
1186 "due to PCIe linkdown\n",
1187 __FUNCTION__));
1188 #ifdef CONFIG_ARCH_MSM
1189 bus->no_cfg_restore = 1;
1190 #endif /* CONFIG_ARCH_MSM */
1191 bus->is_linkdown = 1;
1192 DHD_OS_WAKE_LOCK(dhd);
1193 dhd->hang_reason = HANG_REASON_PCIE_LINK_DOWN;
1194 dhd_os_send_hang_message(dhd);
1195 }
1196 }
1197 }
1198 }
1199 }
1200 #endif /* CONFIG_ARCH_MSM || (EXYNOS_PCIE_LINKDOWN_RECOVERY &&
1201 * (CONFIG_SOC_EXYNOS8890 || CONFIG_SOC_EXYNOS8895))
1202 */
1203 #endif /* SUPPORT_LINKDOWN_RECOVERY */
1204
dhdpcie_init(struct pci_dev * pdev)1205 int dhdpcie_init(struct pci_dev *pdev)
1206 {
1207 osl_t *osh = NULL;
1208 dhd_bus_t *bus = NULL;
1209 dhdpcie_info_t *dhdpcie_info = NULL;
1210 wifi_adapter_info_t *adapter = NULL;
1211 #ifdef BCMPCIE_OOB_HOST_WAKE
1212 dhdpcie_os_info_t *dhdpcie_osinfo = NULL;
1213 #endif /* BCMPCIE_OOB_HOST_WAKE */
1214 #ifdef USE_SMMU_ARCH_MSM
1215 dhdpcie_smmu_info_t *dhdpcie_smmu_info = NULL;
1216 #endif /* USE_SMMU_ARCH_MSM */
1217
1218 do {
1219 /* osl attach */
1220 if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) {
1221 DHD_ERROR(("%s: osl_attach failed\n", __FUNCTION__));
1222 break;
1223 }
1224
1225 /* initialize static buffer */
1226 adapter = dhd_wifi_platform_get_adapter(PCI_BUS, pdev->bus->number,
1227 PCI_SLOT(pdev->devfn));
1228 if (adapter != NULL) {
1229 DHD_ERROR(("%s: found adapter info '%s'\n", __FUNCTION__, adapter->name));
1230 #ifdef BUS_POWER_RESTORE
1231 adapter->pci_dev = pdev;
1232 #endif
1233 } else
1234 DHD_ERROR(("%s: can't find adapter info for this chip\n", __FUNCTION__));
1235 osl_static_mem_init(osh, adapter);
1236
1237 /* Set ACP coherence flag */
1238 if (OSL_ACP_WAR_ENAB() || OSL_ARCH_IS_COHERENT())
1239 osl_flag_set(osh, OSL_ACP_COHERENCE);
1240
1241 /* allocate linux spcific pcie structure here */
1242 if (!(dhdpcie_info = MALLOC(osh, sizeof(dhdpcie_info_t)))) {
1243 DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__));
1244 break;
1245 }
1246 bzero(dhdpcie_info, sizeof(dhdpcie_info_t));
1247 dhdpcie_info->osh = osh;
1248 dhdpcie_info->dev = pdev;
1249
1250 #ifdef BCMPCIE_OOB_HOST_WAKE
1251 /* allocate OS speicific structure */
1252 dhdpcie_osinfo = MALLOC(osh, sizeof(dhdpcie_os_info_t));
1253 if (dhdpcie_osinfo == NULL) {
1254 DHD_ERROR(("%s: MALLOC of dhdpcie_os_info_t failed\n",
1255 __FUNCTION__));
1256 break;
1257 }
1258 bzero(dhdpcie_osinfo, sizeof(dhdpcie_os_info_t));
1259 dhdpcie_info->os_cxt = (void *)dhdpcie_osinfo;
1260
1261 /* Initialize host wake IRQ */
1262 spin_lock_init(&dhdpcie_osinfo->oob_irq_spinlock);
1263 /* Get customer specific host wake IRQ parametres: IRQ number as IRQ type */
1264 dhdpcie_osinfo->oob_irq_num = wifi_platform_get_irq_number(adapter,
1265 &dhdpcie_osinfo->oob_irq_flags);
1266 if (dhdpcie_osinfo->oob_irq_num < 0) {
1267 DHD_ERROR(("%s: Host OOB irq is not defined\n", __FUNCTION__));
1268 }
1269 #endif /* BCMPCIE_OOB_HOST_WAKE */
1270
1271 #ifdef USE_SMMU_ARCH_MSM
1272 /* allocate private structure for using SMMU */
1273 dhdpcie_smmu_info = MALLOC(osh, sizeof(dhdpcie_smmu_info_t));
1274 if (dhdpcie_smmu_info == NULL) {
1275 DHD_ERROR(("%s: MALLOC of dhdpcie_smmu_info_t failed\n",
1276 __FUNCTION__));
1277 break;
1278 }
1279 bzero(dhdpcie_smmu_info, sizeof(dhdpcie_smmu_info_t));
1280 dhdpcie_info->smmu_cxt = (void *)dhdpcie_smmu_info;
1281
1282 /* Initialize smmu structure */
1283 if (dhdpcie_smmu_init(pdev, dhdpcie_info->smmu_cxt) < 0) {
1284 DHD_ERROR(("%s: Failed to initialize SMMU\n",
1285 __FUNCTION__));
1286 break;
1287 }
1288 #endif /* USE_SMMU_ARCH_MSM */
1289
1290 #ifdef DHD_WAKE_STATUS
1291 /* Initialize pcie_lock */
1292 spin_lock_init(&dhdpcie_info->pcie_lock);
1293 #endif /* DHD_WAKE_STATUS */
1294
1295 /* Find the PCI resources, verify the */
1296 /* vendor and device ID, map BAR regions and irq, update in structures */
1297 if (dhdpcie_scan_resource(dhdpcie_info)) {
1298 DHD_ERROR(("%s: dhd_Scan_PCI_Res failed\n", __FUNCTION__));
1299
1300 break;
1301 }
1302
1303 /* Bus initialization */
1304 bus = dhdpcie_bus_attach(osh, dhdpcie_info->regs, dhdpcie_info->tcm, pdev);
1305 if (!bus) {
1306 DHD_ERROR(("%s:dhdpcie_bus_attach() failed\n", __FUNCTION__));
1307 break;
1308 }
1309
1310 dhdpcie_info->bus = bus;
1311 bus->is_linkdown = 0;
1312
1313 /* Get RC Device Handle */
1314 #if defined(PCIE_RC_VENDOR_ID) && defined(PCIE_RC_DEVICE_ID)
1315 bus->rc_dev = pci_get_device(PCIE_RC_VENDOR_ID, PCIE_RC_DEVICE_ID, NULL);
1316 #else
1317 bus->rc_dev = NULL;
1318 #endif
1319
1320 #if defined(BCMPCIE_OOB_HOST_WAKE) && defined(CUSTOMER_HW2) && \
1321 defined(CONFIG_ARCH_APQ8084)
1322 brcm_pcie_wake.wake_irq = wlan_oob_irq;
1323 brcm_pcie_wake.data = bus;
1324 #endif /* BCMPCIE_OOB_HOST_WAKE && CUSTOMR_HW2 && CONFIG_ARCH_APQ8084 */
1325
1326 #ifdef DONGLE_ENABLE_ISOLATION
1327 bus->dhd->dongle_isolation = TRUE;
1328 #endif /* DONGLE_ENABLE_ISOLATION */
1329 #ifdef SUPPORT_LINKDOWN_RECOVERY
1330 #ifdef CONFIG_ARCH_MSM
1331 bus->pcie_event.events = MSM_PCIE_EVENT_LINKDOWN;
1332 bus->pcie_event.user = pdev;
1333 bus->pcie_event.mode = MSM_PCIE_TRIGGER_CALLBACK;
1334 bus->pcie_event.callback = dhdpcie_linkdown_cb;
1335 bus->pcie_event.options = MSM_PCIE_CONFIG_NO_RECOVERY;
1336 msm_pcie_register_event(&bus->pcie_event);
1337 bus->no_cfg_restore = 0;
1338 #endif /* CONFIG_ARCH_MSM */
1339 #ifdef EXYNOS_PCIE_LINKDOWN_RECOVERY
1340 #if defined(CONFIG_SOC_EXYNOS8890) || defined(CONFIG_SOC_EXYNOS8895)
1341 bus->pcie_event.events = EXYNOS_PCIE_EVENT_LINKDOWN;
1342 bus->pcie_event.user = pdev;
1343 bus->pcie_event.mode = EXYNOS_PCIE_TRIGGER_CALLBACK;
1344 bus->pcie_event.callback = dhdpcie_linkdown_cb;
1345 exynos_pcie_register_event(&bus->pcie_event);
1346 #endif /* CONFIG_SOC_EXYNOS8890 || CONFIG_SOC_EXYNOS8895 */
1347 #endif /* EXYNOS_PCIE_LINKDOWN_RECOVERY */
1348 bus->read_shm_fail = FALSE;
1349 #endif /* SUPPORT_LINKDOWN_RECOVERY */
1350
1351 if (bus->intr) {
1352 /* Register interrupt callback, but mask it (not operational yet). */
1353 DHD_INTR(("%s: Registering and masking interrupts\n", __FUNCTION__));
1354 dhdpcie_bus_intr_disable(bus);
1355
1356 if (dhdpcie_request_irq(dhdpcie_info)) {
1357 DHD_ERROR(("%s: request_irq() failed\n", __FUNCTION__));
1358 break;
1359 }
1360 } else {
1361 bus->pollrate = 1;
1362 DHD_INFO(("%s: PCIe interrupt function is NOT registered "
1363 "due to polling mode\n", __FUNCTION__));
1364 }
1365
1366 #if defined(BCM_REQUEST_FW)
1367 if (dhd_bus_download_firmware(bus, osh, NULL, NULL) < 0) {
1368 DHD_ERROR(("%s: failed to download firmware\n", __FUNCTION__));
1369 }
1370 bus->nv_path = NULL;
1371 bus->fw_path = NULL;
1372 #endif /* BCM_REQUEST_FW */
1373
1374 /* set private data for pci_dev */
1375 pci_set_drvdata(pdev, dhdpcie_info);
1376
1377 if (dhd_download_fw_on_driverload) {
1378 if (dhd_bus_start(bus->dhd)) {
1379 DHD_ERROR(("%s: dhd_bud_start() failed\n", __FUNCTION__));
1380 if (!allow_delay_fwdl)
1381 break;
1382 }
1383 } else {
1384 /* Set ramdom MAC address during boot time */
1385 get_random_bytes(&bus->dhd->mac.octet[3], 3);
1386 /* Adding BRCM OUI */
1387 bus->dhd->mac.octet[0] = 0;
1388 bus->dhd->mac.octet[1] = 0x90;
1389 bus->dhd->mac.octet[2] = 0x4C;
1390 }
1391
1392 /* Attach to the OS network interface */
1393 DHD_TRACE(("%s(): Calling dhd_register_if() \n", __FUNCTION__));
1394 if (dhd_register_if(bus->dhd, 0, TRUE)) {
1395 DHD_ERROR(("%s(): ERROR.. dhd_register_if() failed\n", __FUNCTION__));
1396 break;
1397 }
1398
1399 dhdpcie_init_succeeded = TRUE;
1400
1401 #if defined(MULTIPLE_SUPPLICANT)
1402 wl_android_post_init(); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe
1403 #endif /* MULTIPLE_SUPPLICANT */
1404
1405 DHD_TRACE(("%s:Exit - SUCCESS \n", __FUNCTION__));
1406 return 0; /* return SUCCESS */
1407
1408 } while (0);
1409 /* reverse the initialization in order in case of error */
1410
1411 if (bus)
1412 dhdpcie_bus_release(bus);
1413
1414 #ifdef BCMPCIE_OOB_HOST_WAKE
1415 if (dhdpcie_osinfo) {
1416 MFREE(osh, dhdpcie_osinfo, sizeof(dhdpcie_os_info_t));
1417 }
1418 #endif /* BCMPCIE_OOB_HOST_WAKE */
1419
1420 #ifdef USE_SMMU_ARCH_MSM
1421 if (dhdpcie_smmu_info) {
1422 MFREE(osh, dhdpcie_smmu_info, sizeof(dhdpcie_smmu_info_t));
1423 dhdpcie_info->smmu_cxt = NULL;
1424 }
1425 #endif /* USE_SMMU_ARCH_MSM */
1426
1427 if (dhdpcie_info)
1428 dhdpcie_detach(dhdpcie_info);
1429 pci_disable_device(pdev);
1430 if (osh)
1431 osl_detach(osh);
1432
1433 dhdpcie_init_succeeded = FALSE;
1434
1435 DHD_TRACE(("%s:Exit - FAILURE \n", __FUNCTION__));
1436
1437 return -1; /* return FAILURE */
1438 }
1439
1440 /* Free Linux irq */
1441 void
dhdpcie_free_irq(dhd_bus_t * bus)1442 dhdpcie_free_irq(dhd_bus_t *bus)
1443 {
1444 struct pci_dev *pdev = NULL;
1445
1446 DHD_TRACE(("%s: freeing up the IRQ\n", __FUNCTION__));
1447 if (bus) {
1448 pdev = bus->dev;
1449 if (bus->irq_registered) {
1450 free_irq(pdev->irq, bus);
1451 bus->irq_registered = FALSE;
1452 #ifdef DHD_USE_MSI
1453 pci_disable_msi(pdev);
1454 #endif /* DHD_USE_MSI */
1455 } else {
1456 DHD_ERROR(("%s: PCIe IRQ is not registered\n", __FUNCTION__));
1457 }
1458 }
1459 DHD_TRACE(("%s: Exit\n", __FUNCTION__));
1460 return;
1461 }
1462
1463 /*
1464
1465 Name: dhdpcie_isr
1466
1467 Parametrs:
1468
1469 1: IN int irq -- interrupt vector
1470 2: IN void *arg -- handle to private data structure
1471
1472 Return value:
1473
1474 Status (TRUE or FALSE)
1475
1476 Description:
1477 Interrupt Service routine checks for the status register,
1478 disable interrupt and queue DPC if mail box interrupts are raised.
1479 */
1480
1481
1482 irqreturn_t
dhdpcie_isr(int irq,void * arg)1483 dhdpcie_isr(int irq, void *arg)
1484 {
1485 dhd_bus_t *bus = (dhd_bus_t*)arg;
1486 if (dhdpcie_bus_isr(bus))
1487 return TRUE;
1488 else
1489 return FALSE;
1490 }
1491
1492 int
dhdpcie_disable_irq_nosync(dhd_bus_t * bus)1493 dhdpcie_disable_irq_nosync(dhd_bus_t *bus)
1494 {
1495 struct pci_dev *dev;
1496 if ((bus == NULL) || (bus->dev == NULL)) {
1497 DHD_ERROR(("%s: bus or bus->dev is NULL\n", __FUNCTION__));
1498 return BCME_ERROR;
1499 }
1500
1501 dev = bus->dev;
1502 disable_irq_nosync(dev->irq);
1503 return BCME_OK;
1504 }
1505
1506 int
dhdpcie_disable_irq(dhd_bus_t * bus)1507 dhdpcie_disable_irq(dhd_bus_t *bus)
1508 {
1509 struct pci_dev *dev;
1510 if ((bus == NULL) || (bus->dev == NULL)) {
1511 DHD_ERROR(("%s: bus or bus->dev is NULL\n", __FUNCTION__));
1512 return BCME_ERROR;
1513 }
1514
1515 dev = bus->dev;
1516 disable_irq(dev->irq);
1517 return BCME_OK;
1518 }
1519
1520 int
dhdpcie_enable_irq(dhd_bus_t * bus)1521 dhdpcie_enable_irq(dhd_bus_t *bus)
1522 {
1523 struct pci_dev *dev;
1524 if ((bus == NULL) || (bus->dev == NULL)) {
1525 DHD_ERROR(("%s: bus or bus->dev is NULL\n", __FUNCTION__));
1526 return BCME_ERROR;
1527 }
1528
1529 dev = bus->dev;
1530 enable_irq(dev->irq);
1531 return BCME_OK;
1532 }
1533
1534 bool
dhdpcie_irq_enabled(dhd_bus_t * bus)1535 dhdpcie_irq_enabled(dhd_bus_t *bus)
1536 {
1537 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
1538 struct irq_desc *desc = irq_to_desc(bus->dev->irq);
1539 /* depth will be zero, if enabled */
1540 if (!desc->depth) {
1541 DHD_ERROR(("%s: depth:%d\n", __FUNCTION__, desc->depth));
1542 }
1543 return desc->depth ? FALSE : TRUE;
1544 #else
1545 /* return TRUE by default as there is no support for lower versions */
1546 return TRUE;
1547 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */
1548 }
1549
1550 int
dhdpcie_start_host_pcieclock(dhd_bus_t * bus)1551 dhdpcie_start_host_pcieclock(dhd_bus_t *bus)
1552 {
1553 int ret = 0;
1554 #ifdef CONFIG_ARCH_MSM
1555 #ifdef SUPPORT_LINKDOWN_RECOVERY
1556 int options = 0;
1557 #endif /* SUPPORT_LINKDOWN_RECOVERY */
1558 #endif /* CONFIG_ARCH_MSM */
1559 DHD_TRACE(("%s Enter:\n", __FUNCTION__));
1560
1561 if (bus == NULL) {
1562 return BCME_ERROR;
1563 }
1564
1565 if (bus->dev == NULL) {
1566 return BCME_ERROR;
1567 }
1568
1569 #ifdef CONFIG_ARCH_MSM
1570 #ifdef SUPPORT_LINKDOWN_RECOVERY
1571 if (bus->no_cfg_restore) {
1572 options = MSM_PCIE_CONFIG_NO_CFG_RESTORE;
1573 }
1574 ret = msm_pcie_pm_control(MSM_PCIE_RESUME, bus->dev->bus->number,
1575 bus->dev, NULL, options);
1576 if (bus->no_cfg_restore && !ret) {
1577 msm_pcie_recover_config(bus->dev);
1578 bus->no_cfg_restore = 0;
1579 }
1580 #else
1581 ret = msm_pcie_pm_control(MSM_PCIE_RESUME, bus->dev->bus->number,
1582 bus->dev, NULL, 0);
1583 #endif /* SUPPORT_LINKDOWN_RECOVERY */
1584 if (ret) {
1585 DHD_ERROR(("%s Failed to bring up PCIe link\n", __FUNCTION__));
1586 goto done;
1587 }
1588
1589 done:
1590 #endif /* CONFIG_ARCH_MSM */
1591 DHD_TRACE(("%s Exit:\n", __FUNCTION__));
1592 return ret;
1593 }
1594
1595 int
dhdpcie_stop_host_pcieclock(dhd_bus_t * bus)1596 dhdpcie_stop_host_pcieclock(dhd_bus_t *bus)
1597 {
1598 int ret = 0;
1599 #ifdef CONFIG_ARCH_MSM
1600 #ifdef SUPPORT_LINKDOWN_RECOVERY
1601 int options = 0;
1602 #endif /* SUPPORT_LINKDOWN_RECOVERY */
1603 #endif /* CONFIG_ARCH_MSM */
1604
1605 DHD_TRACE(("%s Enter:\n", __FUNCTION__));
1606
1607 if (bus == NULL) {
1608 return BCME_ERROR;
1609 }
1610
1611 if (bus->dev == NULL) {
1612 return BCME_ERROR;
1613 }
1614
1615 #ifdef CONFIG_ARCH_MSM
1616 #ifdef SUPPORT_LINKDOWN_RECOVERY
1617 /* Always reset the PCIe host when wifi off */
1618 bus->no_cfg_restore = 1;
1619
1620 if (bus->no_cfg_restore) {
1621 options = MSM_PCIE_CONFIG_NO_CFG_RESTORE | MSM_PCIE_CONFIG_LINKDOWN;
1622 }
1623
1624 ret = msm_pcie_pm_control(MSM_PCIE_SUSPEND, bus->dev->bus->number,
1625 bus->dev, NULL, options);
1626 #else
1627 ret = msm_pcie_pm_control(MSM_PCIE_SUSPEND, bus->dev->bus->number,
1628 bus->dev, NULL, 0);
1629 #endif /* SUPPORT_LINKDOWN_RECOVERY */
1630 if (ret) {
1631 DHD_ERROR(("Failed to stop PCIe link\n"));
1632 goto done;
1633 }
1634 done:
1635 #endif /* CONFIG_ARCH_MSM */
1636 DHD_TRACE(("%s Exit:\n", __FUNCTION__));
1637 return ret;
1638 }
1639
1640 int
dhdpcie_disable_device(dhd_bus_t * bus)1641 dhdpcie_disable_device(dhd_bus_t *bus)
1642 {
1643 DHD_TRACE(("%s Enter:\n", __FUNCTION__));
1644
1645 if (bus == NULL) {
1646 return BCME_ERROR;
1647 }
1648
1649 if (bus->dev == NULL) {
1650 return BCME_ERROR;
1651 }
1652
1653 pci_disable_device(bus->dev);
1654
1655 return 0;
1656 }
1657
1658 int
dhdpcie_enable_device(dhd_bus_t * bus)1659 dhdpcie_enable_device(dhd_bus_t *bus)
1660 {
1661 int ret = BCME_ERROR;
1662 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
1663 dhdpcie_info_t *pch;
1664 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */
1665
1666 DHD_TRACE(("%s Enter:\n", __FUNCTION__));
1667
1668 if (bus == NULL) {
1669 return BCME_ERROR;
1670 }
1671
1672 if (bus->dev == NULL) {
1673 return BCME_ERROR;
1674 }
1675
1676 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
1677 pch = pci_get_drvdata(bus->dev);
1678 if (pch == NULL) {
1679 return BCME_ERROR;
1680 }
1681
1682 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) && (LINUX_VERSION_CODE < \
1683 KERNEL_VERSION(3, 19, 0)) && !defined(CONFIG_SOC_EXYNOS8890)
1684 /* Updated with pci_load_and_free_saved_state to compatible
1685 * with Kernel version 3.14.0 to 3.18.41.
1686 */
1687 pci_load_and_free_saved_state(bus->dev, &pch->default_state);
1688 pch->default_state = pci_store_saved_state(bus->dev);
1689 #else
1690 pci_load_saved_state(bus->dev, pch->default_state);
1691 #endif /* LINUX_VERSION >= 3.14.0 && LINUX_VERSION < 3.19.0 && !CONFIG_SOC_EXYNOS8890 */
1692
1693 pci_restore_state(bus->dev);
1694 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) */
1695
1696 ret = pci_enable_device(bus->dev);
1697 if (ret) {
1698 pci_disable_device(bus->dev);
1699 } else {
1700 pci_set_master(bus->dev);
1701 }
1702
1703 return ret;
1704 }
1705
1706 int
dhdpcie_alloc_resource(dhd_bus_t * bus)1707 dhdpcie_alloc_resource(dhd_bus_t *bus)
1708 {
1709 dhdpcie_info_t *dhdpcie_info;
1710 phys_addr_t bar0_addr, bar1_addr;
1711 ulong bar1_size;
1712
1713 do {
1714 if (bus == NULL) {
1715 DHD_ERROR(("%s: bus is NULL\n", __FUNCTION__));
1716 break;
1717 }
1718
1719 if (bus->dev == NULL) {
1720 DHD_ERROR(("%s: bus->dev is NULL\n", __FUNCTION__));
1721 break;
1722 }
1723
1724 dhdpcie_info = pci_get_drvdata(bus->dev);
1725 if (dhdpcie_info == NULL) {
1726 DHD_ERROR(("%s: dhdpcie_info is NULL\n", __FUNCTION__));
1727 break;
1728 }
1729
1730 bar0_addr = pci_resource_start(bus->dev, 0); /* Bar-0 mapped address */
1731 bar1_addr = pci_resource_start(bus->dev, 2); /* Bar-1 mapped address */
1732
1733 /* read Bar-1 mapped memory range */
1734 bar1_size = pci_resource_len(bus->dev, 2);
1735
1736 if ((bar1_size == 0) || (bar1_addr == 0)) {
1737 printf("%s: BAR1 Not enabled for this device size(%ld),"
1738 " addr(0x"PRINTF_RESOURCE")\n",
1739 __FUNCTION__, bar1_size, bar1_addr);
1740 break;
1741 }
1742
1743 dhdpcie_info->regs = (volatile char *) REG_MAP(bar0_addr, DONGLE_REG_MAP_SIZE);
1744 if (!dhdpcie_info->regs) {
1745 DHD_ERROR(("%s: ioremap() for regs is failed\n", __FUNCTION__));
1746 break;
1747 }
1748
1749 bus->regs = dhdpcie_info->regs;
1750 dhdpcie_info->tcm_size =
1751 (bar1_size > DONGLE_TCM_MAP_SIZE) ? bar1_size : DONGLE_TCM_MAP_SIZE;
1752 dhdpcie_info->tcm = (volatile char *) REG_MAP(bar1_addr, dhdpcie_info->tcm_size);
1753 if (!dhdpcie_info->tcm) {
1754 DHD_ERROR(("%s: ioremap() for regs is failed\n", __FUNCTION__));
1755 REG_UNMAP(dhdpcie_info->regs);
1756 bus->regs = NULL;
1757 break;
1758 }
1759
1760 bus->tcm = dhdpcie_info->tcm;
1761
1762 DHD_TRACE(("%s:Phys addr : reg space = %p base addr 0x"PRINTF_RESOURCE" \n",
1763 __FUNCTION__, dhdpcie_info->regs, bar0_addr));
1764 DHD_TRACE(("%s:Phys addr : tcm_space = %p base addr 0x"PRINTF_RESOURCE" \n",
1765 __FUNCTION__, dhdpcie_info->tcm, bar1_addr));
1766
1767 return 0;
1768 } while (0);
1769
1770 return BCME_ERROR;
1771 }
1772
1773 void
dhdpcie_free_resource(dhd_bus_t * bus)1774 dhdpcie_free_resource(dhd_bus_t *bus)
1775 {
1776 dhdpcie_info_t *dhdpcie_info;
1777
1778 if (bus == NULL) {
1779 DHD_ERROR(("%s: bus is NULL\n", __FUNCTION__));
1780 return;
1781 }
1782
1783 if (bus->dev == NULL) {
1784 DHD_ERROR(("%s: bus->dev is NULL\n", __FUNCTION__));
1785 return;
1786 }
1787
1788 dhdpcie_info = pci_get_drvdata(bus->dev);
1789 if (dhdpcie_info == NULL) {
1790 DHD_ERROR(("%s: dhdpcie_info is NULL\n", __FUNCTION__));
1791 return;
1792 }
1793
1794 if (bus->regs) {
1795 REG_UNMAP(dhdpcie_info->regs);
1796 bus->regs = NULL;
1797 }
1798
1799 if (bus->tcm) {
1800 REG_UNMAP(dhdpcie_info->tcm);
1801 bus->tcm = NULL;
1802 }
1803 }
1804
1805 int
dhdpcie_bus_request_irq(struct dhd_bus * bus)1806 dhdpcie_bus_request_irq(struct dhd_bus *bus)
1807 {
1808 dhdpcie_info_t *dhdpcie_info;
1809 int ret = 0;
1810
1811 if (bus == NULL) {
1812 DHD_ERROR(("%s: bus is NULL\n", __FUNCTION__));
1813 return BCME_ERROR;
1814 }
1815
1816 if (bus->dev == NULL) {
1817 DHD_ERROR(("%s: bus->dev is NULL\n", __FUNCTION__));
1818 return BCME_ERROR;
1819 }
1820
1821 dhdpcie_info = pci_get_drvdata(bus->dev);
1822 if (dhdpcie_info == NULL) {
1823 DHD_ERROR(("%s: dhdpcie_info is NULL\n", __FUNCTION__));
1824 return BCME_ERROR;
1825 }
1826
1827 if (bus->intr) {
1828 /* Register interrupt callback, but mask it (not operational yet). */
1829 DHD_INTR(("%s: Registering and masking interrupts\n", __FUNCTION__));
1830 dhdpcie_bus_intr_disable(bus);
1831 ret = dhdpcie_request_irq(dhdpcie_info);
1832 if (ret) {
1833 DHD_ERROR(("%s: request_irq() failed, ret=%d\n",
1834 __FUNCTION__, ret));
1835 return ret;
1836 }
1837 }
1838
1839 return ret;
1840 }
1841
1842 #ifdef BCMPCIE_OOB_HOST_WAKE
dhdpcie_oob_intr_set(dhd_bus_t * bus,bool enable)1843 void dhdpcie_oob_intr_set(dhd_bus_t *bus, bool enable)
1844 {
1845 unsigned long flags;
1846 dhdpcie_info_t *pch;
1847 dhdpcie_os_info_t *dhdpcie_osinfo;
1848
1849 if (bus == NULL) {
1850 DHD_ERROR(("%s: bus is NULL\n", __FUNCTION__));
1851 return;
1852 }
1853
1854 if (bus->dev == NULL) {
1855 DHD_ERROR(("%s: bus->dev is NULL\n", __FUNCTION__));
1856 return;
1857 }
1858
1859 pch = pci_get_drvdata(bus->dev);
1860 if (pch == NULL) {
1861 DHD_ERROR(("%s: pch is NULL\n", __FUNCTION__));
1862 return;
1863 }
1864
1865 dhdpcie_osinfo = (dhdpcie_os_info_t *)pch->os_cxt;
1866 spin_lock_irqsave(&dhdpcie_osinfo->oob_irq_spinlock, flags);
1867 if ((dhdpcie_osinfo->oob_irq_enabled != enable) &&
1868 (dhdpcie_osinfo->oob_irq_num > 0)) {
1869 if (enable) {
1870 enable_irq(dhdpcie_osinfo->oob_irq_num);
1871 } else {
1872 disable_irq_nosync(dhdpcie_osinfo->oob_irq_num);
1873 }
1874 dhdpcie_osinfo->oob_irq_enabled = enable;
1875 }
1876 spin_unlock_irqrestore(&dhdpcie_osinfo->oob_irq_spinlock, flags);
1877 }
1878
wlan_oob_irq(int irq,void * data)1879 static irqreturn_t wlan_oob_irq(int irq, void *data)
1880 {
1881 dhd_bus_t *bus;
1882 DHD_TRACE(("%s: IRQ Triggered\n", __FUNCTION__));
1883 bus = (dhd_bus_t *)data;
1884 dhdpcie_oob_intr_set(bus, FALSE);
1885 #ifdef DHD_WAKE_STATUS
1886 #ifdef DHD_PCIE_RUNTIMEPM
1887 /* This condition is for avoiding counting of wake up from Runtime PM */
1888 if (bus->chk_pm)
1889 #endif /* DHD_PCIE_RUNTIMPM */
1890 {
1891 bcmpcie_set_get_wake(bus, 1);
1892 }
1893 #endif /* DHD_WAKE_STATUS */
1894 #ifdef DHD_PCIE_RUNTIMEPM
1895 dhdpcie_runtime_bus_wake(bus->dhd, FALSE, wlan_oob_irq);
1896 #endif /* DHD_PCIE_RUNTIMPM */
1897 if (bus->dhd->up && bus->oob_presuspend) {
1898 DHD_OS_OOB_IRQ_WAKE_LOCK_TIMEOUT(bus->dhd, OOB_WAKE_LOCK_TIMEOUT);
1899 }
1900 return IRQ_HANDLED;
1901 }
1902
dhdpcie_oob_intr_register(dhd_bus_t * bus)1903 int dhdpcie_oob_intr_register(dhd_bus_t *bus)
1904 {
1905 int err = 0;
1906 dhdpcie_info_t *pch;
1907 dhdpcie_os_info_t *dhdpcie_osinfo;
1908
1909 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1910 if (bus == NULL) {
1911 DHD_ERROR(("%s: bus is NULL\n", __FUNCTION__));
1912 return -EINVAL;
1913 }
1914
1915 if (bus->dev == NULL) {
1916 DHD_ERROR(("%s: bus->dev is NULL\n", __FUNCTION__));
1917 return -EINVAL;
1918 }
1919
1920 pch = pci_get_drvdata(bus->dev);
1921 if (pch == NULL) {
1922 DHD_ERROR(("%s: pch is NULL\n", __FUNCTION__));
1923 return -EINVAL;
1924 }
1925
1926 dhdpcie_osinfo = (dhdpcie_os_info_t *)pch->os_cxt;
1927 if (dhdpcie_osinfo->oob_irq_registered) {
1928 DHD_ERROR(("%s: irq is already registered\n", __FUNCTION__));
1929 return -EBUSY;
1930 }
1931
1932 if (dhdpcie_osinfo->oob_irq_num > 0) {
1933 printf("%s OOB irq=%d flags=0x%X\n", __FUNCTION__,
1934 (int)dhdpcie_osinfo->oob_irq_num,
1935 (int)dhdpcie_osinfo->oob_irq_flags);
1936 err = request_irq(dhdpcie_osinfo->oob_irq_num, wlan_oob_irq,
1937 dhdpcie_osinfo->oob_irq_flags, "dhdpcie_host_wake",
1938 bus);
1939 if (err) {
1940 DHD_ERROR(("%s: request_irq failed with %d\n",
1941 __FUNCTION__, err));
1942 return err;
1943 }
1944 #if defined(DISABLE_WOWLAN)
1945 printf("%s: disable_irq_wake\n", __FUNCTION__);
1946 dhdpcie_osinfo->oob_irq_wake_enabled = FALSE;
1947 #else
1948 printf("%s: enable_irq_wake\n", __FUNCTION__);
1949 err = enable_irq_wake(dhdpcie_osinfo->oob_irq_num);
1950 if (!err) {
1951 dhdpcie_osinfo->oob_irq_wake_enabled = TRUE;
1952 } else
1953 printf("%s: enable_irq_wake failed with %d\n", __FUNCTION__, err);
1954 #endif
1955 dhdpcie_osinfo->oob_irq_enabled = TRUE;
1956 }
1957
1958 dhdpcie_osinfo->oob_irq_registered = TRUE;
1959
1960 return err;
1961 }
1962
dhdpcie_oob_intr_unregister(dhd_bus_t * bus)1963 void dhdpcie_oob_intr_unregister(dhd_bus_t *bus)
1964 {
1965 int err = 0;
1966 dhdpcie_info_t *pch;
1967 dhdpcie_os_info_t *dhdpcie_osinfo;
1968
1969 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1970 if (bus == NULL) {
1971 DHD_ERROR(("%s: bus is NULL\n", __FUNCTION__));
1972 return;
1973 }
1974
1975 if (bus->dev == NULL) {
1976 DHD_ERROR(("%s: bus->dev is NULL\n", __FUNCTION__));
1977 return;
1978 }
1979
1980 pch = pci_get_drvdata(bus->dev);
1981 if (pch == NULL) {
1982 DHD_ERROR(("%s: pch is NULL\n", __FUNCTION__));
1983 return;
1984 }
1985
1986 dhdpcie_osinfo = (dhdpcie_os_info_t *)pch->os_cxt;
1987 if (!dhdpcie_osinfo->oob_irq_registered) {
1988 DHD_ERROR(("%s: irq is not registered\n", __FUNCTION__));
1989 return;
1990 }
1991 if (dhdpcie_osinfo->oob_irq_num > 0) {
1992 if (dhdpcie_osinfo->oob_irq_wake_enabled) {
1993 err = disable_irq_wake(dhdpcie_osinfo->oob_irq_num);
1994 if (!err) {
1995 dhdpcie_osinfo->oob_irq_wake_enabled = FALSE;
1996 }
1997 }
1998 if (dhdpcie_osinfo->oob_irq_enabled) {
1999 disable_irq(dhdpcie_osinfo->oob_irq_num);
2000 dhdpcie_osinfo->oob_irq_enabled = FALSE;
2001 }
2002 free_irq(dhdpcie_osinfo->oob_irq_num, bus);
2003 }
2004 dhdpcie_osinfo->oob_irq_registered = FALSE;
2005 }
2006 #endif /* BCMPCIE_OOB_HOST_WAKE */
2007
2008 #ifdef PCIE_OOB
dhdpcie_oob_init(dhd_bus_t * bus)2009 void dhdpcie_oob_init(dhd_bus_t *bus)
2010 {
2011 gpio_handle_val = get_handle(OOB_PORT);
2012 if (gpio_handle_val < 0)
2013 {
2014 DHD_ERROR(("%s: Could not get GPIO handle.\n", __FUNCTION__));
2015 ASSERT(FALSE);
2016 }
2017
2018 gpio_direction = 0;
2019 ftdi_set_bitmode(gpio_handle_val, 0, BITMODE_BITBANG);
2020
2021 /* Note BT core is also enabled here */
2022 gpio_port = 1 << BIT_WL_REG_ON | 1 << BIT_BT_REG_ON | 1 << DEVICE_WAKE;
2023 gpio_write_port(gpio_handle_val, gpio_port);
2024
2025 gpio_direction = 1 << BIT_WL_REG_ON | 1 << BIT_BT_REG_ON | 1 << DEVICE_WAKE;
2026 ftdi_set_bitmode(gpio_handle_val, gpio_direction, BITMODE_BITBANG);
2027
2028 bus->oob_enabled = TRUE;
2029 bus->oob_presuspend = FALSE;
2030
2031 /* drive the Device_Wake GPIO low on startup */
2032 bus->device_wake_state = TRUE;
2033 dhd_bus_set_device_wake(bus, FALSE);
2034 dhd_bus_doorbell_timeout_reset(bus);
2035 }
2036
2037 void
dhd_oob_set_bt_reg_on(struct dhd_bus * bus,bool val)2038 dhd_oob_set_bt_reg_on(struct dhd_bus *bus, bool val)
2039 {
2040 DHD_INFO(("Set Device_Wake to %d\n", val));
2041 if (val)
2042 {
2043 gpio_port = gpio_port | (1 << BIT_BT_REG_ON);
2044 gpio_write_port(gpio_handle_val, gpio_port);
2045 } else {
2046 gpio_port = gpio_port & (0xff ^ (1 << BIT_BT_REG_ON));
2047 gpio_write_port(gpio_handle_val, gpio_port);
2048 }
2049 }
2050
2051 int
dhd_oob_get_bt_reg_on(struct dhd_bus * bus)2052 dhd_oob_get_bt_reg_on(struct dhd_bus *bus)
2053 {
2054 int ret;
2055 uint8 val;
2056 ret = gpio_read_port(gpio_handle_val, &val);
2057
2058 if (ret < 0) {
2059 DHD_ERROR(("gpio_read_port returns %d\n", ret));
2060 return ret;
2061 }
2062
2063 if (val & (1 << BIT_BT_REG_ON))
2064 {
2065 ret = 1;
2066 } else {
2067 ret = 0;
2068 }
2069
2070 return ret;
2071 }
2072
2073 int
dhd_os_oob_set_device_wake(struct dhd_bus * bus,bool val)2074 dhd_os_oob_set_device_wake(struct dhd_bus *bus, bool val)
2075 {
2076 if (bus->device_wake_state != val)
2077 {
2078 DHD_INFO(("Set Device_Wake to %d\n", val));
2079
2080 if (bus->oob_enabled && !bus->oob_presuspend)
2081 {
2082 if (val)
2083 {
2084 gpio_port = gpio_port | (1 << DEVICE_WAKE);
2085 gpio_write_port_non_block(gpio_handle_val, gpio_port);
2086 } else {
2087 gpio_port = gpio_port & (0xff ^ (1 << DEVICE_WAKE));
2088 gpio_write_port_non_block(gpio_handle_val, gpio_port);
2089 }
2090 }
2091
2092 bus->device_wake_state = val;
2093 }
2094 return BCME_OK;
2095 }
2096
2097 INLINE void
dhd_os_ib_set_device_wake(struct dhd_bus * bus,bool val)2098 dhd_os_ib_set_device_wake(struct dhd_bus *bus, bool val)
2099 {
2100 /* TODO: Currently Inband implementation of Device_Wake is not supported,
2101 * so this function is left empty later this can be used to support the same.
2102 */
2103 }
2104 #endif /* PCIE_OOB */
2105
2106 #ifdef DHD_PCIE_RUNTIMEPM
dhd_runtimepm_state(dhd_pub_t * dhd)2107 bool dhd_runtimepm_state(dhd_pub_t *dhd)
2108 {
2109 dhd_bus_t *bus;
2110 unsigned long flags;
2111 bus = dhd->bus;
2112
2113 DHD_GENERAL_LOCK(dhd, flags);
2114
2115 bus->idlecount++;
2116
2117 DHD_TRACE(("%s : Enter \n", __FUNCTION__));
2118 if ((bus->idletime > 0) && (bus->idlecount >= bus->idletime)) {
2119 bus->idlecount = 0;
2120 if (DHD_BUS_BUSY_CHECK_IDLE(dhd) && !DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhd)) {
2121 bus->bus_wake = 0;
2122 DHD_BUS_BUSY_SET_RPM_SUSPEND_IN_PROGRESS(dhd);
2123 bus->runtime_resume_done = FALSE;
2124 /* stop all interface network queue. */
2125 dhd_bus_stop_queue(bus);
2126 DHD_GENERAL_UNLOCK(dhd, flags);
2127 DHD_ERROR(("%s: DHD Idle state!! - idletime :%d, wdtick :%d \n",
2128 __FUNCTION__, bus->idletime, dhd_runtimepm_ms));
2129 /* RPM suspend is failed, return FALSE then re-trying */
2130 if (dhdpcie_set_suspend_resume(bus, TRUE)) {
2131 DHD_ERROR(("%s: exit with wakelock \n", __FUNCTION__));
2132 DHD_GENERAL_LOCK(dhd, flags);
2133 DHD_BUS_BUSY_CLEAR_RPM_SUSPEND_IN_PROGRESS(dhd);
2134 dhd_os_busbusy_wake(bus->dhd);
2135 bus->runtime_resume_done = TRUE;
2136 /* It can make stuck NET TX Queue without below */
2137 dhd_bus_start_queue(bus);
2138 DHD_GENERAL_UNLOCK(dhd, flags);
2139 smp_wmb();
2140 wake_up_interruptible(&bus->rpm_queue);
2141 return FALSE;
2142 }
2143
2144 DHD_GENERAL_LOCK(dhd, flags);
2145 DHD_BUS_BUSY_CLEAR_RPM_SUSPEND_IN_PROGRESS(dhd);
2146 DHD_BUS_BUSY_SET_RPM_SUSPEND_DONE(dhd);
2147 /* For making sure NET TX Queue active */
2148 dhd_bus_start_queue(bus);
2149 DHD_GENERAL_UNLOCK(dhd, flags);
2150
2151 wait_event_interruptible(bus->rpm_queue, bus->bus_wake);
2152
2153 DHD_GENERAL_LOCK(dhd, flags);
2154 DHD_BUS_BUSY_CLEAR_RPM_SUSPEND_DONE(dhd);
2155 DHD_BUS_BUSY_SET_RPM_RESUME_IN_PROGRESS(dhd);
2156 DHD_GENERAL_UNLOCK(dhd, flags);
2157
2158 dhdpcie_set_suspend_resume(bus, FALSE);
2159
2160 DHD_GENERAL_LOCK(dhd, flags);
2161 DHD_BUS_BUSY_CLEAR_RPM_RESUME_IN_PROGRESS(dhd);
2162 dhd_os_busbusy_wake(bus->dhd);
2163 /* Inform the wake up context that Resume is over */
2164 bus->runtime_resume_done = TRUE;
2165 /* For making sure NET TX Queue active */
2166 dhd_bus_start_queue(bus);
2167 DHD_GENERAL_UNLOCK(dhd, flags);
2168
2169 smp_wmb();
2170 wake_up_interruptible(&bus->rpm_queue);
2171 DHD_ERROR(("%s : runtime resume ended \n", __FUNCTION__));
2172 return TRUE;
2173 } else {
2174 DHD_GENERAL_UNLOCK(dhd, flags);
2175 /* Since one of the contexts are busy (TX, IOVAR or RX)
2176 * we should not suspend
2177 */
2178 DHD_ERROR(("%s : bus is active with dhd_bus_busy_state = 0x%x\n",
2179 __FUNCTION__, dhd->dhd_bus_busy_state));
2180 return FALSE;
2181 }
2182 }
2183
2184 DHD_GENERAL_UNLOCK(dhd, flags);
2185 return FALSE;
2186 } /* dhd_runtimepm_state */
2187
2188 /*
2189 * dhd_runtime_bus_wake
2190 * TRUE - related with runtime pm context
2191 * FALSE - It isn't invloved in runtime pm context
2192 */
dhd_runtime_bus_wake(dhd_bus_t * bus,bool wait,void * func_addr)2193 bool dhd_runtime_bus_wake(dhd_bus_t *bus, bool wait, void *func_addr)
2194 {
2195 unsigned long flags;
2196 bus->idlecount = 0;
2197 DHD_TRACE(("%s : enter\n", __FUNCTION__));
2198 if (bus->dhd->up == FALSE) {
2199 DHD_INFO(("%s : dhd is not up\n", __FUNCTION__));
2200 return FALSE;
2201 }
2202
2203 DHD_GENERAL_LOCK(bus->dhd, flags);
2204 if (DHD_BUS_BUSY_CHECK_RPM_ALL(bus->dhd)) {
2205 /* Wake up RPM state thread if it is suspend in progress or suspended */
2206 if (DHD_BUS_BUSY_CHECK_RPM_SUSPEND_IN_PROGRESS(bus->dhd) ||
2207 DHD_BUS_BUSY_CHECK_RPM_SUSPEND_DONE(bus->dhd)) {
2208 bus->bus_wake = 1;
2209
2210 DHD_GENERAL_UNLOCK(bus->dhd, flags);
2211
2212 DHD_ERROR(("Runtime Resume is called in %pf\n", func_addr));
2213 smp_wmb();
2214 wake_up_interruptible(&bus->rpm_queue);
2215 /* No need to wake up the RPM state thread */
2216 } else if (DHD_BUS_BUSY_CHECK_RPM_RESUME_IN_PROGRESS(bus->dhd)) {
2217 DHD_GENERAL_UNLOCK(bus->dhd, flags);
2218 }
2219
2220 /* If wait is TRUE, function with wait = TRUE will be wait in here */
2221 if (wait) {
2222 wait_event_interruptible(bus->rpm_queue, bus->runtime_resume_done);
2223 } else {
2224 DHD_INFO(("%s: bus wakeup but no wait until resume done\n", __FUNCTION__));
2225 }
2226 /* If it is called from RPM context, it returns TRUE */
2227 return TRUE;
2228 }
2229
2230 DHD_GENERAL_UNLOCK(bus->dhd, flags);
2231
2232 return FALSE;
2233 }
2234
dhdpcie_runtime_bus_wake(dhd_pub_t * dhdp,bool wait,void * func_addr)2235 bool dhdpcie_runtime_bus_wake(dhd_pub_t *dhdp, bool wait, void* func_addr)
2236 {
2237 dhd_bus_t *bus = dhdp->bus;
2238 return dhd_runtime_bus_wake(bus, wait, func_addr);
2239 }
2240
dhdpcie_block_runtime_pm(dhd_pub_t * dhdp)2241 void dhdpcie_block_runtime_pm(dhd_pub_t *dhdp)
2242 {
2243 dhd_bus_t *bus = dhdp->bus;
2244 bus->idletime = 0;
2245 }
2246
dhdpcie_is_resume_done(dhd_pub_t * dhdp)2247 bool dhdpcie_is_resume_done(dhd_pub_t *dhdp)
2248 {
2249 dhd_bus_t *bus = dhdp->bus;
2250 return bus->runtime_resume_done;
2251 }
2252 #endif /* DHD_PCIE_RUNTIMEPM */
2253
dhd_bus_to_dev(dhd_bus_t * bus)2254 struct device *dhd_bus_to_dev(dhd_bus_t *bus)
2255 {
2256 struct pci_dev *pdev;
2257 pdev = bus->dev;
2258
2259 if (pdev)
2260 return &pdev->dev;
2261 else
2262 return NULL;
2263 }
2264
2265 #ifdef HOFFLOAD_MODULES
2266 void
dhd_free_module_memory(struct dhd_bus * bus,struct module_metadata * hmem)2267 dhd_free_module_memory(struct dhd_bus *bus, struct module_metadata *hmem)
2268 {
2269 struct device *dev = &bus->dev->dev;
2270 if (hmem) {
2271 dma_unmap_single(dev, (dma_addr_t) hmem->data_addr, hmem->size, DMA_TO_DEVICE);
2272 kfree(hmem->data);
2273 hmem->data = NULL;
2274 hmem->size = 0;
2275 } else {
2276 DHD_ERROR(("dev:%p pci unmapping error\n", dev));
2277 }
2278 }
2279
2280 void *
dhd_alloc_module_memory(struct dhd_bus * bus,uint32_t size,struct module_metadata * hmem)2281 dhd_alloc_module_memory(struct dhd_bus *bus, uint32_t size, struct module_metadata *hmem)
2282 {
2283 struct device *dev = &bus->dev->dev;
2284 if (!hmem->data) {
2285 hmem->data = kzalloc(size, GFP_KERNEL);
2286 if (!hmem->data) {
2287 DHD_ERROR(("dev:%p mem alloc failure\n", dev));
2288 return NULL;
2289 }
2290 }
2291 hmem->size = size;
2292 DHD_INFO(("module size: 0x%x \n", hmem->size));
2293 hmem->data_addr = (u64) dma_map_single(dev, hmem->data, hmem->size, DMA_TO_DEVICE);
2294 if (dma_mapping_error(dev, hmem->data_addr)) {
2295 DHD_ERROR(("dev:%p dma mapping error\n", dev));
2296 kfree(hmem->data);
2297 hmem->data = NULL;
2298 return hmem->data;
2299 }
2300 return hmem->data;
2301 }
2302 #endif /* HOFFLOAD_MODULES */
2303