-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdhd_pcie.c
23021 lines (20207 loc) · 675 KB
/
dhd_pcie.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* DHD Bus Module for PCIE
*
* Copyright (C) 2023, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
*
* <<Broadcom-WL-IPTag/Dual:>>
*/
/* include files */
#include <typedefs.h>
#include <bcmutils.h>
#include <bcmrand.h>
#include <bcmdevs.h>
#include <bcmdevs_legacy.h> /* need to still support chips no longer in trunk firmware */
#include <siutils.h>
#include <sbgci.h>
#include <hndoobr.h>
#include <hndsoc.h>
#include <hndpmu_dhd.h>
#include <etd.h>
#include <hnd_debug.h>
#include <sbchipc.h>
#include <sbhndarm.h>
#include <sbsysmem.h>
#include <sbsreng.h>
#include <hnd_armtrap.h>
#if defined(DHD_DEBUG)
#include <hnd_cons.h>
#endif /* defined(DHD_DEBUG) */
#include <dngl_stats.h>
#include <pcie_core.h>
#include <dhd.h>
#include <dhd_bus.h>
#include <dhd_flowring.h>
#include <dhd_proto.h>
#include <dhd_dbg.h>
#include <dhd_debug.h>
#if defined(__linux__)
#include <dhd_daemon.h>
#include <dhd_plat.h>
#endif /* __linux__ */
#include <dhdioctl.h>
#include <sdiovar.h>
#include <bcmmsgbuf.h>
#include <pcicfg.h>
#include <dhd_pcie.h>
#include <bcmpcie.h>
#include <bcmutils.h>
#include <bcmendian.h>
#include <bcmstdlib_s.h>
#ifdef DHDTCPACK_SUPPRESS
#include <dhd_ip.h>
#endif /* DHDTCPACK_SUPPRESS */
#include <bcmevent.h>
#ifdef DHD_TIMESYNC
#include <dhd_timesync.h>
#endif /* DHD_TIMESYNC */
#ifdef EWP_DACS
#include <dhd_log_dump.h>
#endif
#include <hnddap.h>
#ifdef BCM_ROUTER_DHD
#include <bcmnvram.h>
#define STR_END "END\0\0"
#define BOARDREV_PROMOTABLE_STR "0xff"
#endif
#ifdef DHD_PCIE_NATIVE_RUNTIMEPM
#include <linux/pm_runtime.h>
#endif /* DHD_PCIE_NATIVE_RUNTIMEPM */
#if defined(DEBUGGER) || defined (DHD_DSCOPE)
#include <debugger.h>
#endif /* DEBUGGER || DHD_DSCOPE */
#if defined(FW_SIGNATURE)
#include <dngl_rtlv.h>
#include <bootrommem.h>
#include <fwpkg_utils.h>
#endif /* FW_SIGNATURE */
#ifdef COEX_CPU
#include <coex_shared_memfile.h>
#endif /* COEX_CPU */
#ifdef DNGL_AXI_ERROR_LOGGING
#include <dhd_linux_wq.h>
#include <dhd_linux.h>
#endif /* DNGL_AXI_ERROR_LOGGING */
#ifdef DHD_PKT_LOGGING
#include <dhd_pktlog.h>
#endif /* DHD_PKT_LOGGING */
#define EXTENDED_PCIE_DEBUG_DUMP 1 /* Enable Extended pcie registers dump */
#define MEMBLOCK 2048 /* Block size used for downloading of dongle image */
#if defined(__linux__)
#define MAX_WKLK_IDLE_CHECK 3 /* times dhd_wake_lock checked before deciding not to suspend */
#endif /* __linux__ */
#define DHD_MAX_ITEMS_HPP_TXCPL_RING 512
#define DHD_MAX_ITEMS_HPP_RXCPL_RING 512
#define MAX_HP2P_CMPL_RINGS 2u
#define DHD_MAX_ITEMS_MESH_RXCPL_RING 512
/* defines for 4378 */
#define ARMCR4REG_CORECAP (0x4/sizeof(uint32))
#define ARMCR4REG_MPUCTRL (0x90/sizeof(uint32))
#define ACC_MPU_SHIFT 25
#define ACC_MPU_MASK (0x1u << ACC_MPU_SHIFT)
/* Offset for 4375 work around register */
#define REG_WORK_AROUND (0x1e4/sizeof(uint32))
/* defines for 43602a0 workaround JIRA CRWLARMCR4-53 */
#define ARMCR4REG_BANKIDX (0x40/sizeof(uint32))
#define ARMCR4REG_BANKPDA (0x4C/sizeof(uint32))
/* Temporary war to fix precommit till sync issue between trunk & precommit branch is resolved */
/* CTO Prevention Recovery */
#define CTO_TO_CLEAR_WAIT_MS 50
#define CTO_TO_CLEAR_WAIT_MAX_CNT 200
/* FLR setting */
#define PCIE_FLR_CAPAB_BIT 28
#define PCIE_FUNCTION_LEVEL_RESET_BIT 15
#ifdef BCMQT_HW
int cc_wd_reset = TRUE;
int db7trap_in_detach = FALSE;
#else
int db7trap_in_detach = TRUE;
int cc_wd_reset = FALSE;
#endif /* BCMQT_HW */
#ifdef BCMQT_HW
/* FLR takes longer on QT Z boards so increasing the delay by 30% */
#define DHD_FUNCTION_LEVEL_RESET_DELAY 70u
#define DHD_SSRESET_STATUS_RETRY_DELAY 55u
#else
#define DHD_FUNCTION_LEVEL_RESET_DELAY 70u /* 70 msec delay */
#define DHD_SSRESET_STATUS_RETRY_DELAY 40u
#endif /* BCMQT_HW */
/*
* Increase SSReset de-assert time to 8ms.
* since it takes longer time if re-scan time on 4378B0.
*/
#define DHD_SSRESET_STATUS_RETRIES 200u
/* Fetch address of a member in the pciedev_shared structure in dongle memory */
#define DHD_PCIE_SHARED_MEMBER_ADDR(bus, member) \
(bus)->shared_addr + OFFSETOF(pciedev_shared_t, member)
/* Fetch address of a member in rings_info_ptr structure in dongle memory */
#define DHD_RING_INFO_MEMBER_ADDR(bus, member) \
(bus)->pcie_sh->rings_info_ptr + OFFSETOF(ring_info_t, member)
/* Fetch address of a member in the ring_mem structure in dongle memory */
#define DHD_RING_MEM_MEMBER_ADDR(bus, ringid, member) \
(bus)->ring_sh[ringid].ring_mem_addr + OFFSETOF(ring_mem_t, member)
/* Mpu conntrol */
#define MPU_REG(regs, reg) (&((sysmemregs_t *)regs)->reg)
#define BUS_MPU_ENABLE_MASK 0x1u
#define BUS_MPU_ROM_PR_MASK 0x2u
#define BUS_MPU_VEC_PR_MASK 0x4u
#define BUS_MPU_LOCK_MASK 0x8u
#if defined(SUPPORT_MULTIPLE_BOARD_REV)
extern unsigned int system_rev;
#endif /* SUPPORT_MULTIPLE_BOARD_REV */
#ifdef BCMQT_HW
extern int qt_dngl_timeout;
#endif /* BCMQT_HW */
/* This can be overwritten by module parameter(dma_ring_indices) defined in dhd_linux.c */
uint dma_ring_indices = 0;
#ifdef DHD_AGGR_WI
uint aggr_wi_enab = DHD_AGGR_WI_EN;
#endif /* DHD_AGGR_WI */
/* This can be overwritten by module parameter(h2d_phase) defined in dhd_linux.c */
bool h2d_phase = 0;
/* This can be overwritten by module parameter(force_trap_bad_h2d_phase)
* defined in dhd_linux.c
*/
bool force_trap_bad_h2d_phase = 0;
/* This can be overwritten by module parameter ptm_sync_periodic */
int ptm_sync_periodic = TRUE;
#ifdef DHD_PCIE_WRAPPER_DUMP
typedef struct pcie_wrapper {
char *core;
uint32 base;
} pcie_wrapper_t;
typedef struct pcie_wrapper_offset {
uint32 offset;
uint32 len;
} pcie_wrapper_offset_t;
const pcie_wrapper_t wrapper_base_4388[] = {
{"chipcommon_mwrapper", 0x18100000},
{"pcie_mwrapper", 0x18101000},
{"pcie_swrapper", 0x18102000},
{"chipcommon_swrapper_for_sflash", 0x18103000},
{"default_swrapper", 0x18104000},
{"enumeration_rom_swrapper", 0x18105000},
{"apb_bridge_cb0_swrapper_apb_2", 0x18106000},
{"apb_bridge_cb1_swrapper_apb_aaon", 0x18107000},
{"adb400_swrapper_shared_bridge_s", 0x1810a000},
{"adb400_mwrapper_shared_bridge1_m", 0x1810b000},
{"adb400_mwrapper_shared_bridge2_m", 0x1810c000},
{"armca7_mwrapper", 0x18120000},
{"dot11mac_2x2_bw80_mwrapper", 0x18121000},
{"dot11mac_2x2_bw20_mwrapper", 0x18122000},
{"dot11mac_1x1_scan_mwrapper", 0x18123000},
{"sysmem_swrapper", 0x18124000},
{"dot11mac_2x2_bw80_i1_mwrapper", 0x18125000},
{"dot11mac_2x2_bw80_i2_mwrapper", 0x18126000},
{"dot11mac_2x2_bw80_swrapper", 0x18127000},
{"dot11mac_2x2_bw20_i1_mwrapper", 0x18128000},
{"dot11mac_2x2_bw20_i2_mwrapper", 0x18129000},
{"dot11mac_2x2_bw20_swrapper", 0x1812a000},
{"dot11mac_1x1_scan_swrapper", 0x1812b000},
{"aximem_wl_swrapper", 0x1812c000},
{"adb400_swrapper_wl_bridge1_s", 0x1812d000},
{"adb400_swrapper_wl_bridge2_s", 0x1812e000},
{"default_swrapper", 0x1812f000},
{"enumeration_rom_swrapper", 0x18130000},
{"adb400_mwrapper_wl_bridge_m", 0x18131000},
{"adb0_bridge_wlb0_swrapper", 0x18132000}
};
const pcie_wrapper_offset_t wrapper_offset_4388[] = {
{0x408, 4},
{0x500, 4},
{0x800, 16},
{0x900, 32},
{0xe00, 4}
};
#endif /* DHD_PCIE_WRAPPER_DUMP */
uint32 ltr_latency_scale_ns[6] = {1, 32, 1024, 32768, 1048576, 33554432}; //ns
int dhd_dongle_ramsize;
struct dhd_bus *g_dhd_bus = NULL;
#ifdef DNGL_AXI_ERROR_LOGGING
static void dhd_log_dump_axi_error(uint8 *axi_err);
#endif /* DNGL_AXI_ERROR_LOGGING */
static int dhdpcie_checkdied(dhd_bus_t *bus, char *data, uint size);
static int dhdpcie_bus_readconsole(dhd_bus_t *bus);
#if defined(DHD_FW_COREDUMP)
static int dhdpcie_mem_dump(dhd_bus_t *bus);
static int dhdpcie_get_mem_dump(dhd_bus_t *bus);
#endif /* DHD_FW_COREDUMP */
static int dhdpcie_bus_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid,
const char *name, void *params,
uint plen, void *arg, uint len, int val_size);
static int dhdpcie_bus_lpback_req(struct dhd_bus *bus, uint32 intval);
static int dhdpcie_bus_dmaxfer_req(struct dhd_bus *bus,
uint32 len, uint32 srcdelay, uint32 destdelay,
uint32 d11_lpbk, uint32 core_num, uint32 wait,
uint32 mem_addr);
static int dhdpcie_bus_download_state(dhd_bus_t *bus, bool enter);
static int _dhdpcie_download_firmware(struct dhd_bus *bus);
static int dhdpcie_download_firmware(dhd_bus_t *bus, osl_t *osh);
#ifndef DHD_LINUX_STD_FW_API
static int dhdpcie_download_file(dhd_bus_t *bus, void *filep, uint32 fsize,
uint32 addr, char *path);
#endif
#if defined(FW_SIGNATURE)
static int dhdpcie_bus_download_fw_signature(dhd_bus_t *bus, bool *do_write);
static int dhdpcie_bus_write_fw_signature(dhd_bus_t *bus);
static int dhdpcie_bus_download_ram_bootloader(dhd_bus_t *bus);
static int dhdpcie_bus_write_fws_status(dhd_bus_t *bus);
static int dhdpcie_bus_write_fws_mem_info(dhd_bus_t *bus);
static int dhdpcie_bus_write_fwsig(dhd_bus_t *bus, char *fwsig_path, char *nvsig_path);
static int dhdpcie_download_rtlv_end(dhd_bus_t *bus);
static int dhdpcie_read_fwstatus(dhd_bus_t *bus, bl_verif_status_t *status);
#endif /* FW_SIGNATURE */
static int dhdpcie_bus_save_download_info(dhd_bus_t *bus, uint32 download_addr,
uint32 download_size, const char *signature_fname,
const char *bloader_fname, uint32 bloader_download_addr, const char *fw_path);
static int dhdpcie_bus_write_vars(dhd_bus_t *bus);
static bool dhdpcie_bus_process_mailbox_intr(dhd_bus_t *bus, uint32 intstatus);
static bool dhdpci_bus_read_frames(dhd_bus_t *bus);
static int dhdpcie_readshared(dhd_bus_t *bus);
static void dhdpcie_init_shared_addr(dhd_bus_t *bus);
static bool dhdpcie_dongle_attach(dhd_bus_t *bus);
static void dhdpcie_bus_dongle_setmemsize(dhd_bus_t *bus, int mem_size);
static void dhdpcie_bus_release_dongle(dhd_bus_t *bus, osl_t *osh,
bool dongle_isolation, bool reset_flag);
static void dhdpcie_bus_release_malloc(dhd_bus_t *bus, osl_t *osh);
static int dhdpcie_downloadvars(dhd_bus_t *bus, void *arg, int len);
static void dhdpcie_setbar1win(dhd_bus_t *bus, uint32 addr);
static void dhd_deinit_bar1_switch_lock(dhd_bus_t *bus);
static void dhd_init_bar2_switch_lock(dhd_bus_t *bus);
static void dhd_deinit_bar2_switch_lock(dhd_bus_t *bus);
static void dhd_init_pwr_req_lock(dhd_bus_t *bus);
static void dhd_deinit_pwr_req_lock(dhd_bus_t *bus);
static void dhd_init_bus_lp_state_lock(dhd_bus_t *bus);
static void dhd_deinit_bus_lp_state_lock(dhd_bus_t *bus);
static void dhd_init_backplane_access_lock(dhd_bus_t *bus);
static void dhd_deinit_backplane_access_lock(dhd_bus_t *bus);
static uint8 dhdpcie_bus_rtcm8(dhd_bus_t *bus, dhd_pcie_mem_region_t region, ulong offset);
static void dhdpcie_bus_wtcm8(dhd_bus_t *bus, dhd_pcie_mem_region_t region, ulong offset,
uint8 data);
static void dhdpcie_bus_wtcm16(dhd_bus_t *bus, dhd_pcie_mem_region_t region, ulong offset,
uint16 data);
static uint16 dhdpcie_bus_rtcm16(dhd_bus_t *bus, dhd_pcie_mem_region_t region, ulong offset);
static void dhdpcie_bus_wtcm32(dhd_bus_t *bus, dhd_pcie_mem_region_t region, ulong offset,
uint32 data);
static uint32 dhdpcie_bus_rtcm32(dhd_bus_t *bus, dhd_pcie_mem_region_t region, ulong offset);
#ifdef DHD_SUPPORT_64BIT
static void dhdpcie_bus_wtcm64(dhd_bus_t *bus, dhd_pcie_mem_region_t region, ulong offset,
uint64 data) __attribute__ ((used));
static uint64 dhdpcie_bus_rtcm64(dhd_bus_t *bus, dhd_pcie_mem_region_t region,
ulong offset) __attribute__ ((used));
#endif /* DHD_SUPPORT_64BIT */
static void dhdpcie_bus_cfg_set_bar0_win(dhd_bus_t *bus, uint32 data);
static void dhdpcie_bus_reg_unmap(osl_t *osh, volatile char *addr, int size);
static int dhdpcie_cc_nvmshadow(dhd_bus_t *bus, struct bcmstrbuf *b);
static void dhd_bus_dump_rxlat_info(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf);
static void dhd_bus_dump_rxlat_histo(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf);
static void dhd_bus_dump_txcpl_info(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf);
static void dhd_bus_dump_mdring_info(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf);
static bool dhd_bus_support_dar_sec_status(dhd_bus_t *bus);
static int dhd_bus_security_info(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf);
static int dhd_bus_sboot_disable(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf);
static int dhd_bus_get_security_status(dhd_bus_t *bus, uint32 *status);
static void dhdpcie_fw_trap(dhd_bus_t *bus);
static void dhd_fillup_ring_sharedptr_info(dhd_bus_t *bus, ring_info_t *ring_info);
static void dhdpcie_handle_mb_data(dhd_bus_t *bus);
extern void dhd_dpc_enable(dhd_pub_t *dhdp);
#ifdef PCIE_INB_DW
static void dhd_bus_ds_trace(dhd_bus_t *bus, uint32 dsval,
bool d2h, enum dhd_bus_ds_state inbstate, const char *context);
#else
static void dhd_bus_ds_trace(dhd_bus_t *bus, uint32 dsval, bool d2h);
#endif /* PCIE_INB_DW */
#ifdef DHD_MMIO_TRACE
static void dhd_bus_mmio_trace(dhd_bus_t *bus, uint32 addr, uint32 value, bool set);
#endif /* defined(DHD_MMIO_TRACE) */
#if defined(__linux__)
extern void dhd_update_fw_path(dhd_pub_t *dhdp, const char *fw_path);
#endif /* __linux__ */
#ifdef IDLE_TX_FLOW_MGMT
static void dhd_bus_check_idle_scan(dhd_bus_t *bus);
static void dhd_bus_idle_scan(dhd_bus_t *bus);
#endif /* IDLE_TX_FLOW_MGMT */
#ifdef DHD_SSSR_DUMP
static bool dhdpcie_fis_fw_triggered_check(struct dhd_bus *bus);
#endif /* DHD_SSSR_DUMP */
#ifdef BCM_ROUTER_DHD
extern char * nvram_get(const char *name);
#endif
#ifdef BCM_ROUTER_DHD
int dbushost_initvars_flash(si_t *sih, osl_t *osh, char **base, uint len);
#endif
#if defined(DHD_H2D_LOG_TIME_SYNC)
static void dhdpci_bus_rte_log_time_sync_poll(dhd_bus_t *bus);
#endif /* DHD_H2D_LOG_TIME_SYNC */
#define PCI_VENDOR_ID_BROADCOM 0x14e4
#ifdef DHD_PCIE_NATIVE_RUNTIMEPM
#define MAX_D3_ACK_TIMEOUT 100
#endif /* DHD_PCIE_NATIVE_RUNTIMEPM */
#ifdef BCMQT
#define DHD_DEFAULT_DOORBELL_TIMEOUT 40 /* ms */
#else
#define DHD_DEFAULT_DOORBELL_TIMEOUT 200 /* ms */
#endif
#if defined(PCIE_OOB) || defined(PCIE_INB_DW)
static uint dhd_doorbell_timeout = DHD_DEFAULT_DOORBELL_TIMEOUT;
#endif /* PCIE_OOB || PCIE_INB_DW */
static bool dhdpcie_check_firmware_compatible(uint32 f_api_version, uint32 h_api_version);
static int dhdpcie_cto_error_recovery(struct dhd_bus *bus);
static int dhdpcie_init_d11status(struct dhd_bus *bus);
static int dhdpcie_wrt_rnd(struct dhd_bus *bus);
static void dhdpcie_set_host_init_hw_exit_latency(dhd_bus_t *bus, uint32 val);
static void dhdpcie_flush_bl_status(dhd_bus_t *bus);
#ifdef DHD_HP2P
extern enum hrtimer_restart dhd_hp2p_write(struct hrtimer *timer);
static uint16 dhd_bus_set_hp2p_ring_max_size(struct dhd_bus *bus, bool tx, uint16 val);
#endif
#ifdef DHD_MESH
static uint16 dhd_bus_set_mesh_ring_max_size(struct dhd_bus *bus, bool tx, uint16 val);
#endif
#if defined(__linux__)
#if !defined(DHD_FW_MEM_CORRUPTION) && defined(BCM4375_CHIP)
#define NUM_PATTERNS 6
#else
#define NUM_PATTERNS 2
#endif /* !DHD_FW_MEM_CORRUPTION && BCM4375_CHIP */
static bool dhd_bus_tcm_test(struct dhd_bus *bus);
#endif /* __linux__ */
#if defined(FW_SIGNATURE)
static int dhd_bus_dump_fws(dhd_bus_t *bus, struct bcmstrbuf *strbuf);
#endif
static void dhdpcie_pme_stat_clear(dhd_bus_t *bus);
#if defined(SUPPORT_MULTIPLE_BOARD_REVISION)
extern void concate_custom_board_revision(char *nv_path);
#endif /* SUPPORT_MULTIPLE_BOARD_REVISION */
#if defined(EWP_DACS) || defined(DHD_SDTC_ETB_DUMP)
static int dhd_bus_get_etb_dump_cmn(dhd_bus_t *bus, uint8 *buf, uint bufsize,
uint32 etb_config_info_addr);
#endif /* EWP_DACS || DHD_SDTC_ETB_DUMP */
static void dhdpcie_dump_sreng_regs(dhd_bus_t *bus);
/* IOVar table */
enum {
IOV_INTR = 1,
#ifdef DHD_BUS_MEM_ACCESS
IOV_MEMBYTES,
#endif /* DHD_BUS_MEM_ACCESS */
IOV_MEMSIZE,
IOV_SET_DOWNLOAD_STATE,
IOV_SET_DOWNLOAD_INFO,
IOV_DEVRESET,
IOV_VARS,
IOV_MSI_SIM,
IOV_PCIE_LPBK,
IOV_CC_NVMSHADOW,
IOV_RAMSIZE,
IOV_RAMSTART,
#ifdef COEX_CPU
IOV_COEX_ITCMBASE,
IOV_COEX_ITCMSIZE,
IOV_COEX_DTCMBASE,
IOV_COEX_DTCMSIZE,
#endif /* COEX_CPU */
IOV_SLEEP_ALLOWED,
IOV_PCIE_DMAXFER,
IOV_PCIE_SUSPEND,
#ifdef DHD_PCIE_REG_ACCESS
IOV_PCIEREG,
IOV_PCIECFGREG,
IOV_PCIECOREREG,
IOV_PCIESERDESREG,
IOV_PCIEASPM,
IOV_BAR0_SECWIN_REG,
IOV_SBREG,
#endif /* DHD_PCIE_REG_ACCESS */
IOV_DONGLEISOLATION,
IOV_LTRSLEEPON_UNLOOAD,
IOV_METADATA_DBG,
IOV_RX_METADATALEN,
IOV_TX_METADATALEN,
IOV_TXP_THRESHOLD,
IOV_BUZZZ_DUMP,
IOV_DUMP_RINGUPD_BLOCK,
IOV_DMA_RINGINDICES,
IOV_FORCE_FW_TRAP,
IOV_DB1_FOR_MB,
IOV_FLOW_PRIO_MAP,
#ifdef DHD_PCIE_RUNTIMEPM
IOV_IDLETIME,
#endif /* DHD_PCIE_RUNTIMEPM */
IOV_RX_CPL_POST_BOUND,
IOV_TX_CPL_BOUND,
IOV_CTRL_CPL_POST_BOUND,
IOV_TX_POST_BOUND,
IOV_HANGREPORT,
IOV_H2D_MAILBOXDATA,
IOV_INFORINGS,
IOV_H2D_PHASE,
IOV_H2D_ENABLE_TRAP_BADPHASE,
IOV_RING_SIZE_VER,
IOV_H2D_TXPOST_MAX_ITEM,
IOV_H2D_HTPUT_TXPOST_MAX_ITEM,
IOV_D2H_TXCPL_MAX_ITEM,
IOV_H2D_RXPOST_MAX_ITEM,
IOV_D2H_RXCPL_MAX_ITEM,
IOV_H2D_CTRLPOST_MAX_ITEM,
IOV_D2H_CTRLCPL_MAX_ITEM,
IOV_RX_BUF_BURST,
IOV_RX_BUFPOST_THRESHOLD,
IOV_TRAPDATA,
IOV_TRAPDATA_RAW,
IOV_CTO_PREVENTION,
#ifdef PCIE_OOB
IOV_OOB_BT_REG_ON,
IOV_OOB_ENABLE,
#endif /* PCIE_OOB */
#ifdef DEVICE_TX_STUCK_DETECT
IOV_DEVICE_TX_STUCK_DETECT,
#endif /* DEVICE_TX_STUCK_DETECT */
IOV_PCIE_WD_RESET,
IOV_DUMP_DONGLE,
#ifdef DHD_EFI
IOV_WIFI_PROPERTIES,
IOV_CONTROL_SIGNAL,
IOV_OTP_DUMP,
#ifdef BT_OVER_PCIE
IOV_BTOP_TEST,
#endif
#endif /* DHD_EFI */
IOV_IDMA_ENABLE,
IOV_IFRM_ENABLE,
IOV_CLEAR_RING,
IOV_DAR_ENABLE,
IOV_DHD_CAPS, /**< returns string with dhd capabilities */
#if defined(DEBUGGER) || defined(DHD_DSCOPE)
IOV_GDB_SERVER, /**< starts gdb server on given interface */
#endif /* DEBUGGER || DHD_DSCOPE */
#if defined(GDB_PROXY)
IOV_GDB_PROXY_PROBE, /**< gdb proxy support presence check */
IOV_GDB_PROXY_STOP_COUNT, /**< gdb proxy firmware stop count */
#endif /* GDB_PROXY */
IOV_INB_DW_ENABLE,
#if defined(PCIE_OOB) || defined(PCIE_INB_DW)
IOV_DEEP_SLEEP,
#endif /* PCIE_OOB || PCIE_INB_DW */
IOV_CTO_THRESHOLD,
#ifdef D2H_MINIDUMP
IOV_MINIDUMP_OVERRIDE,
#endif /* D2H_MINIDUMP */
IOV_HSCBSIZE, /* get HSCB buffer size */
#ifdef DHD_BUS_MEM_ACCESS
IOV_HSCBBYTES, /* copy HSCB buffer */
#endif
IOV_HP2P_ENABLE,
IOV_HP2P_PKT_THRESHOLD,
IOV_HP2P_TIME_THRESHOLD,
IOV_HP2P_PKT_EXPIRY,
IOV_HP2P_TXCPL_MAXITEMS,
IOV_HP2P_RXCPL_MAXITEMS,
IOV_HP2P_SCALE_FACTOR,
IOV_TXDUR_SCALE_FACTOR,
IOV_RXDUR_SCALE_FACTOR,
IOV_EXTDTXS_IN_TXCPL,
IOV_HOSTRDY_AFTER_INIT,
IOV_MESH_RXCPL_MAXITEMS,
IOV_HP2P_MF_ENABLE,
IOV_DONGLE_RXLAT_INFO,
IOV_DONGLE_RXLAT_HISTO,
IOV_LPM_MODE,
IOV_DONGLE_TXCPL_INFO,
#ifdef DHD_AGGR_WI
IOV_AGGR_WI_ENAB,
#endif /* DHD_AGGR_WI */
IOV_DONGLE_SEC_INFO,
IOV_DONGLE_SBOOT_DIS,
IOV_MDRING_LINK,
IOV_MDRING_UNLINK,
IOV_MDRING_DUMP,
IOV_FLOWRING_BKP_QSIZE,
IOV_MAX_HOST_RXBUFS,
IOV_PTM_ENABLE,
IOV_PCIE_DMAXFER_PTRN,
IOV_HOST_INIT_HW_EXIT_LATENCY,
IOV_PCIE_LAST /**< unused IOVAR */
};
const bcm_iovar_t dhdpcie_iovars[] = {
{"intr", IOV_INTR, 0, 0, IOVT_BOOL, 0 },
#ifdef DHD_BUS_MEM_ACCESS
{"membytes", IOV_MEMBYTES, 0, 0, IOVT_BUFFER, 2 * sizeof(int) },
#endif /* DHD_BUS_MEM_ACCESS */
{"memsize", IOV_MEMSIZE, 0, 0, IOVT_UINT32, 0 },
{"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, 0, IOVT_BOOL, 0 },
{"dwnldinfo", IOV_SET_DOWNLOAD_INFO, 0, 0, IOVT_BUFFER,
sizeof(fw_download_info_t) },
{"vars", IOV_VARS, 0, 0, IOVT_BUFFER, 0 },
{"devreset", IOV_DEVRESET, 0, 0, IOVT_UINT8, 0 },
{"pcie_device_trap", IOV_FORCE_FW_TRAP, 0, 0, 0, 0 },
{"pcie_lpbk", IOV_PCIE_LPBK, 0, 0, IOVT_UINT32, 0 },
{"cc_nvmshadow", IOV_CC_NVMSHADOW, 0, 0, IOVT_BUFFER, 0 },
{"ramsize", IOV_RAMSIZE, 0, 0, IOVT_UINT32, 0 },
{"ramstart", IOV_RAMSTART, 0, 0, IOVT_UINT32, 0 },
#ifdef COEX_CPU
{"coex_itcmbase", IOV_COEX_ITCMBASE, 0, 0, IOVT_UINT32, 0 },
{"coex_itcmsize", IOV_COEX_ITCMSIZE, 0, 0, IOVT_UINT32, 0 },
{"coex_dtcmbase", IOV_COEX_DTCMBASE, 0, 0, IOVT_UINT32, 0 },
{"coex_dtcmsize", IOV_COEX_DTCMSIZE, 0, 0, IOVT_UINT32, 0 },
#endif /* COEX_CPU */
#ifdef DHD_PCIE_REG_ACCESS
{"pciereg", IOV_PCIEREG, 0, 0, IOVT_BUFFER, 2 * sizeof(int32) },
{"pciecfgreg", IOV_PCIECFGREG, DHD_IOVF_PWRREQ_BYPASS, 0, IOVT_BUFFER, 2 * sizeof(int32) },
{"pciecorereg", IOV_PCIECOREREG, 0, 0, IOVT_BUFFER, 2 * sizeof(int32) },
{"pcieserdesreg", IOV_PCIESERDESREG, 0, 0, IOVT_BUFFER, 3 * sizeof(int32) },
{"bar0secwinreg", IOV_BAR0_SECWIN_REG, 0, 0, IOVT_BUFFER, sizeof(sdreg_t) },
{"sbreg", IOV_SBREG, 0, 0, IOVT_BUFFER, sizeof(uint8) },
#endif /* DHD_PCIE_REG_ACCESS */
{"pcie_dmaxfer", IOV_PCIE_DMAXFER, 0, 0, IOVT_BUFFER, sizeof(dma_xfer_info_t)},
{"lpbk_dmaxfer_data_pattern", IOV_PCIE_DMAXFER_PTRN, 0, 0, IOVT_UINT32, 0},
{"pcie_suspend", IOV_PCIE_SUSPEND, DHD_IOVF_PWRREQ_BYPASS, 0, IOVT_UINT32, 0 },
#ifdef PCIE_OOB
{"oob_bt_reg_on", IOV_OOB_BT_REG_ON, 0, 0, IOVT_UINT32, 0 },
{"oob_enable", IOV_OOB_ENABLE, 0, 0, IOVT_UINT32, 0 },
#endif /* PCIE_OOB */
{"sleep_allowed", IOV_SLEEP_ALLOWED, 0, 0, IOVT_BOOL, 0 },
{"dngl_isolation", IOV_DONGLEISOLATION, 0, 0, IOVT_UINT32, 0 },
{"ltrsleep_on_unload", IOV_LTRSLEEPON_UNLOOAD, 0, 0, IOVT_UINT32, 0 },
{"dump_ringupdblk", IOV_DUMP_RINGUPD_BLOCK, 0, 0, IOVT_BUFFER, 0 },
{"dma_ring_indices", IOV_DMA_RINGINDICES, 0, 0, IOVT_UINT32, 0},
{"metadata_dbg", IOV_METADATA_DBG, 0, 0, IOVT_BOOL, 0 },
{"rx_metadata_len", IOV_RX_METADATALEN, 0, 0, IOVT_UINT32, 0 },
{"tx_metadata_len", IOV_TX_METADATALEN, 0, 0, IOVT_UINT32, 0 },
{"db1_for_mb", IOV_DB1_FOR_MB, 0, 0, IOVT_UINT32, 0 },
{"txp_thresh", IOV_TXP_THRESHOLD, 0, 0, IOVT_UINT32, 0 },
{"buzzz_dump", IOV_BUZZZ_DUMP, 0, 0, IOVT_UINT32, 0 },
{"flow_prio_map", IOV_FLOW_PRIO_MAP, 0, 0, IOVT_UINT32, 0 },
#ifdef DHD_PCIE_RUNTIMEPM
{"idletime", IOV_IDLETIME, 0, 0, IOVT_INT32, 0 },
#endif /* DHD_PCIE_RUNTIMEPM */
{"rx_cpl_post_bound", IOV_RX_CPL_POST_BOUND, 0, 0, IOVT_UINT32, 0 },
{"tx_cpl_bound", IOV_TX_CPL_BOUND, 0, 0, IOVT_UINT32, 0 },
{"ctrl_cpl_post_bound", IOV_CTRL_CPL_POST_BOUND, 0, 0, IOVT_UINT32, 0 },
{"tx_post_bound", IOV_TX_POST_BOUND, 0, 0, IOVT_UINT32, 0 },
#ifdef DHD_PCIE_REG_ACCESS
{"aspm", IOV_PCIEASPM, 0, 0, IOVT_INT32, 0 },
#endif /* DHD_PCIE_REG_ACCESS */
{"fw_hang_report", IOV_HANGREPORT, 0, 0, IOVT_BOOL, 0 },
{"h2d_mb_data", IOV_H2D_MAILBOXDATA, 0, 0, IOVT_UINT32, 0 },
{"inforings", IOV_INFORINGS, 0, 0, IOVT_UINT32, 0 },
{"h2d_phase", IOV_H2D_PHASE, 0, 0, IOVT_UINT32, 0 },
{"force_trap_bad_h2d_phase", IOV_H2D_ENABLE_TRAP_BADPHASE, 0, 0,
IOVT_UINT32, 0 },
{"ring_size_ver", IOV_RING_SIZE_VER, 0, 0, IOVT_UINT32, 0 },
{"h2d_max_txpost", IOV_H2D_TXPOST_MAX_ITEM, 0, 0, IOVT_UINT32, 0 },
{"h2d_htput_max_txpost", IOV_H2D_HTPUT_TXPOST_MAX_ITEM, 0, 0, IOVT_UINT32, 0 },
{"d2h_max_txcpl", IOV_D2H_TXCPL_MAX_ITEM, 0, 0, IOVT_UINT32, 0 },
{"h2d_max_rxpost", IOV_H2D_RXPOST_MAX_ITEM, 0, 0, IOVT_UINT32, 0 },
{"d2h_max_rxcpl", IOV_D2H_RXCPL_MAX_ITEM, 0, 0, IOVT_UINT32, 0 },
{"h2d_max_ctrlpost", IOV_H2D_CTRLPOST_MAX_ITEM, 0, 0, IOVT_UINT32, 0 },
{"d2h_max_ctrlcpl", IOV_D2H_CTRLCPL_MAX_ITEM, 0, 0, IOVT_UINT32, 0 },
{"rx_buf_burst", IOV_RX_BUF_BURST, 0, 0, IOVT_UINT32, 0 },
{"rx_bufpost_threshold", IOV_RX_BUFPOST_THRESHOLD, 0, 0, IOVT_UINT32, 0 },
{"trap_data", IOV_TRAPDATA, 0, 0, IOVT_BUFFER, 0 },
{"trap_data_raw", IOV_TRAPDATA_RAW, 0, 0, IOVT_BUFFER, 0 },
{"cto_prevention", IOV_CTO_PREVENTION, 0, 0, IOVT_UINT32, 0 },
{"pcie_wd_reset", IOV_PCIE_WD_RESET, 0, 0, IOVT_BOOL, 0 },
#ifdef DEVICE_TX_STUCK_DETECT
{"dev_tx_stuck_monitor", IOV_DEVICE_TX_STUCK_DETECT, 0, 0, IOVT_UINT32, 0 },
#endif /* DEVICE_TX_STUCK_DETECT */
{"dump_dongle", IOV_DUMP_DONGLE, 0, 0, IOVT_BUFFER,
MAX(sizeof(dump_dongle_in_t), sizeof(dump_dongle_out_t))},
{"clear_ring", IOV_CLEAR_RING, 0, 0, IOVT_UINT32, 0 },
#ifdef DHD_EFI
{"properties", IOV_WIFI_PROPERTIES, 0, 0, IOVT_BUFFER, 0},
{"otp_dump", IOV_OTP_DUMP, 0, 0, IOVT_BUFFER, 0},
{"control_signal", IOV_CONTROL_SIGNAL, 0, 0, IOVT_UINT32, 0},
#ifdef BT_OVER_PCIE
{"btop_test", IOV_BTOP_TEST, 0, 0, IOVT_UINT32, 0},
#endif
#endif /* DHD_EFI */
{"idma_enable", IOV_IDMA_ENABLE, 0, 0, IOVT_UINT32, 0 },
{"ifrm_enable", IOV_IFRM_ENABLE, 0, 0, IOVT_UINT32, 0 },
{"dar_enable", IOV_DAR_ENABLE, 0, 0, IOVT_UINT32, 0 },
{"cap", IOV_DHD_CAPS, 0, 0, IOVT_BUFFER, 0},
#if defined(DEBUGGER) || defined(DHD_DSCOPE)
{"gdb_server", IOV_GDB_SERVER, 0, 0, IOVT_UINT32, 0 },
#endif /* DEBUGGER || DHD_DSCOPE */
#if defined(GDB_PROXY)
{"gdb_proxy_probe", IOV_GDB_PROXY_PROBE, 0, 0, IOVT_BUFFER, 2 * sizeof(int32) },
{"gdb_proxy_stop_count", IOV_GDB_PROXY_STOP_COUNT, 0, 0, IOVT_UINT32, 0 },
#endif /* GDB_PROXY */
{"inb_dw_enable", IOV_INB_DW_ENABLE, 0, 0, IOVT_UINT32, 0 },
#if defined(PCIE_OOB) || defined(PCIE_INB_DW)
{"deep_sleep", IOV_DEEP_SLEEP, 0, 0, IOVT_UINT32, 0},
#endif /* PCIE_OOB || PCIE_INB_DW */
{"cto_threshold", IOV_CTO_THRESHOLD, 0, 0, IOVT_UINT32, 0 },
#ifdef D2H_MINIDUMP
{"minidump_override", IOV_MINIDUMP_OVERRIDE, 0, 0, IOVT_UINT32, 0 },
#endif /* D2H_MINIDUMP */
{"hscbsize", IOV_HSCBSIZE, 0, 0, IOVT_UINT32, 0 },
#ifdef DHD_BUS_MEM_ACCESS
{"hscbbytes", IOV_HSCBBYTES, 0, 0, IOVT_BUFFER, 2 * sizeof(int32) },
#endif
#ifdef DHD_HP2P
{"hp2p_enable", IOV_HP2P_ENABLE, 0, 0, IOVT_UINT32, 0 },
{"hp2p_pkt_thresh", IOV_HP2P_PKT_THRESHOLD, 0, 0, IOVT_UINT32, 0 },
{"hp2p_time_thresh", IOV_HP2P_TIME_THRESHOLD, 0, 0, IOVT_UINT32, 0 },
{"hp2p_pkt_expiry", IOV_HP2P_PKT_EXPIRY, 0, 0, IOVT_UINT32, 0 },
{"hp2p_txcpl_maxitems", IOV_HP2P_TXCPL_MAXITEMS, 0, 0, IOVT_UINT32, 0 },
{"hp2p_rxcpl_maxitems", IOV_HP2P_RXCPL_MAXITEMS, 0, 0, IOVT_UINT32, 0 },
{"hp2p_scale_factor", IOV_HP2P_SCALE_FACTOR, 0, 0, IOVT_UINT32, 0 },
{"tx_duration_scale", IOV_TXDUR_SCALE_FACTOR, 0, 0, IOVT_UINT32, 0 },
{"rx_duration_scale", IOV_RXDUR_SCALE_FACTOR, 0, 0, IOVT_UINT32, 0 },
#endif /* DHD_HP2P */
#ifdef DHD_MESH
{"mesh_rxcpl_maxitems", IOV_MESH_RXCPL_MAXITEMS, 0, 0, IOVT_UINT32, 0 },
#endif /* DHD_HP2P */
{"extdtxs_in_txcpl", IOV_EXTDTXS_IN_TXCPL, 0, 0, IOVT_UINT32, 0 },
{"hostrdy_after_init", IOV_HOSTRDY_AFTER_INIT, 0, 0, IOVT_UINT32, 0 },
{"hp2p_mf_enable", IOV_HP2P_MF_ENABLE, 0, 0, IOVT_UINT32, 0 },
{"dump_rxlat", IOV_DONGLE_RXLAT_INFO, 0, 0, IOVT_BUFFER,
sizeof(rx_cpl_history_t) * MAX_RXCPL_HISTORY + 128 },
{"dump_rxlat_hist", IOV_DONGLE_RXLAT_HISTO, 0, 0, IOVT_BUFFER,
(MAX_RX_LAT_PRIO * MAX_RX_LAT_HIST_BIN * 2) + 128 },
{"lpm_mode", IOV_LPM_MODE, 0, 0, IOVT_UINT32, 0 },
{"dump_txcpl", IOV_DONGLE_TXCPL_INFO, 0, 0, IOVT_BUFFER,
sizeof(tx_cpl_history_t) * MAX_TXCPL_HISTORY + 128 },
#ifdef DHD_AGGR_WI
{"aggr_wi_enab", IOV_AGGR_WI_ENAB, 0, 0, IOVT_UINT32, 0},
#endif /* DHD_AGGR_WI */
{"security_status", IOV_DONGLE_SEC_INFO, 0, 0, IOVT_BUFFER,
sizeof(tx_cpl_history_t) * MAX_TXCPL_HISTORY + 128 },
{"sboot_disable", IOV_DONGLE_SBOOT_DIS, 0, 0, IOVT_BUFFER,
sizeof(tx_cpl_history_t) * MAX_TXCPL_HISTORY + 128 },
{"mdring_link", IOV_MDRING_LINK, 0, 0, IOVT_UINT32, 0 },
{"mdring_unlink", IOV_MDRING_UNLINK, 0, 0, IOVT_UINT32, 0 },
{"dump_mdring", IOV_MDRING_DUMP, 0, 0, IOVT_BUFFER,
MAX_MDRING_ITEM_DUMP * D2HRING_MDCMPLT_ITEMSIZE },
{"flowring_bkp_qsize", IOV_FLOWRING_BKP_QSIZE, 0, 0, IOVT_UINT32, 0},
{"max_host_rxbufs", IOV_MAX_HOST_RXBUFS, 0, 0, IOVT_UINT32, 0},
{"ptm_enable", IOV_PTM_ENABLE, 0, 0, IOVT_UINT32, 0 },
{"host_init_hw_exit_latency", IOV_HOST_INIT_HW_EXIT_LATENCY, 0, 0,
IOVT_UINT32, 0 },
{NULL, 0, 0, 0, 0, 0 }
};
#ifdef BCMQT_HW
#define MAX_READ_TIMEOUT 200 * 1000 /* 200 ms in dongle time */
#elif defined(NDIS)
#define MAX_READ_TIMEOUT 5 * 1000 * 1000
#else
#define MAX_READ_TIMEOUT 2 * 1000 * 1000
#endif
#define DHD_INFORING_BOUND 32
#define DHD_BTLOGRING_BOUND 32
#if defined(DEBUGGER) || defined(DHD_DSCOPE)
static uint16
dhdpcie_gdb_bus_rtcm16(dhd_bus_t *bus, ulong offset)
{
return dhdpcie_bus_rtcm16(bus, DHD_PCIE_MEM_BAR1, offset);
}
static uint32
dhdpcie_gdb_bus_rtcm32(dhd_bus_t *bus, ulong offset)
{
return dhdpcie_bus_rtcm32(bus, DHD_PCIE_MEM_BAR1, offset);
}
static void
dhdpcie_gdb_bus_wtcm32(dhd_bus_t *bus, ulong offset, uint32 data)
{
dhdpcie_bus_wtcm32(bus, DHD_PCIE_MEM_BAR1, offset, data);
}
/** the GDB debugger layer will call back into this (bus) layer to read/write dongle memory */
static struct dhd_gdb_bus_ops_s bus_ops = {
.read_u16 = dhdpcie_gdb_bus_rtcm16,
.read_u32 = dhdpcie_gdb_bus_rtcm32,
.write_u32 = dhdpcie_gdb_bus_wtcm32,
};
#endif /* DEBUGGER || DHD_DSCOPE */
bool
dhd_bus_get_flr_force_fail(struct dhd_bus *bus)
{
return bus->flr_force_fail;
}
/**
* Register/Unregister functions are called by the main DHD entry point (eg module insertion) to
* link with the bus driver, in order to look for or await the device.
*/
int
dhd_bus_register(void)
{
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
return dhdpcie_bus_register();
}
void
dhd_bus_unregister(void)
{
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
dhdpcie_bus_unregister();
return;
}
/** returns a host virtual address */
uint32 *
dhdpcie_bus_reg_map(osl_t *osh, ulong addr, int size)
{
return (uint32 *)REG_MAP(addr, size);
}
void
dhdpcie_bus_reg_unmap(osl_t *osh, volatile char *addr, int size)
{
REG_UNMAP(addr);
return;
}
/**
* retrun H2D Doorbell registers address
* use DAR registers instead of enum register for corerev >= 23 (4347B0)
*/
static INLINE uint
dhd_bus_db0_addr_get(struct dhd_bus *bus)
{
uint addr = PCIE_REG_OFF(hosttodev0doorbell0);
uint dar_addr = DAR_PCIH2D_DB0_0(bus->sih->buscorerev);
/* Note: For DAR doorbell registers, the values is invalid. */
return ((DAR_ACTIVE(bus->dhd)) ? dar_addr : addr);
}
static INLINE uint
dhd_bus_db0_addr_2_get(struct dhd_bus *bus)
{
/* Note: For DAR doorbell registers, the values is invalid. */
return ((DAR_ACTIVE(bus->dhd)) ? DAR_PCIH2D_DB2_0(bus->sih->buscorerev) :
PCIE_REG_OFF(hosttodev2doorbell0));
}
static INLINE uint
dhd_bus_db1_addr_get(struct dhd_bus *bus)
{
/* Note: For DB1, don't use DAR register */
return PCIE_REG_OFF(hosttodev0doorbell1);
}
static INLINE uint
dhd_bus_db1_addr_3_get(struct dhd_bus *bus)
{
/* Note: For DB7, don't use DAR register */
return PCIE_REG_OFF(hosttodev3doorbell1);
}
static void
dhd_init_pwr_req_lock(dhd_bus_t *bus)
{
if (!bus->pwr_req_lock) {
bus->pwr_req_lock = osl_spin_lock_init(bus->osh);
}
}
static void
dhd_deinit_pwr_req_lock(dhd_bus_t *bus)
{
if (bus->pwr_req_lock) {
osl_spin_lock_deinit(bus->osh, bus->pwr_req_lock);
bus->pwr_req_lock = NULL;
}
}
#ifdef PCIE_INB_DW
void
dhdpcie_set_dongle_deepsleep(dhd_bus_t *bus, bool val)
{
ulong flags_ds;
if (INBAND_DW_ENAB(bus)) {
DHD_BUS_DONGLE_DS_LOCK(bus->dongle_ds_lock, flags_ds);
bus->dongle_in_deepsleep = val;
DHD_BUS_DONGLE_DS_UNLOCK(bus->dongle_ds_lock, flags_ds);
}
}
void
dhd_init_dongle_ds_lock(dhd_bus_t *bus)
{
if (!bus->dongle_ds_lock) {
bus->dongle_ds_lock = osl_spin_lock_init(bus->osh);
}
}
void
dhd_deinit_dongle_ds_lock(dhd_bus_t *bus)
{
if (bus->dongle_ds_lock) {
osl_spin_lock_deinit(bus->osh, bus->dongle_ds_lock);
bus->dongle_ds_lock = NULL;
}
}
#endif /* PCIE_INB_DW */
/*
* WAR for SWWLAN-215055 - [4378B0] ARM fails to boot without DAR WL domain request
*/
static INLINE void
dhd_bus_pcie_pwr_req_wl_domain(struct dhd_bus *bus, uint offset, bool enable)
{
if (enable) {
si_corereg(bus->sih, bus->sih->buscoreidx, offset,
SRPWR_DMN1_ARMBPSD_MASK << SRPWR_REQON_SHIFT,
SRPWR_DMN1_ARMBPSD_MASK << SRPWR_REQON_SHIFT);
} else {
si_corereg(bus->sih, bus->sih->buscoreidx, offset,
SRPWR_DMN1_ARMBPSD_MASK << SRPWR_REQON_SHIFT, 0);
}
}
static INLINE void
_dhd_bus_pcie_pwr_req_clear_cmn(struct dhd_bus *bus)
{
uint mask;
/*
* If multiple de-asserts, decrement ref and return
* Clear power request when only one pending
* so initial request is not removed unexpectedly
*/
if (bus->pwr_req_ref > 1) {
bus->pwr_req_ref--;
return;
}
ASSERT(bus->pwr_req_ref == 1);
if (MULTIBP_ENAB(bus->sih)) {
/* Common BP controlled by HW so only need to toggle WL/ARM backplane */
mask = SRPWR_DMN1_ARMBPSD_MASK;
} else {
mask = SRPWR_DMN0_PCIE_MASK | SRPWR_DMN1_ARMBPSD_MASK;
}
si_srpwr_request(bus->sih, mask, 0);
bus->pwr_req_ref = 0;
}
static INLINE void
dhd_bus_pcie_pwr_req_clear(struct dhd_bus *bus)
{
unsigned long flags = 0;
DHD_BUS_PWR_REQ_LOCK(bus->pwr_req_lock, flags);