• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * DHD Bus Module for SDIO
3  *
4  * Copyright (C) 1999-2019, Broadcom.
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
16  * of the license of that module.  An independent module is a module which is
17  * not 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_sdio.c 825481 2019-06-14 10:06:03Z $
28  */
29 
30 #include <typedefs.h>
31 #include <osl.h>
32 #include <bcmsdh.h>
33 
34 #include <bcmdefs.h>
35 #include <bcmutils.h>
36 #include <bcmendian.h>
37 #include <bcmdevs.h>
38 
39 #include <siutils.h>
40 #include <hndpmu.h>
41 #include <hndsoc.h>
42 #include <bcmsdpcm.h>
43 #include <hnd_armtrap.h>
44 #include <hnd_cons.h>
45 #include <sbchipc.h>
46 #include <sbhnddma.h>
47 
48 #include <sdio.h>
49 #ifdef BCMSPI
50 #include <spid.h>
51 #endif /* BCMSPI */
52 #include <sbsdio.h>
53 #include <sbsdpcmdev.h>
54 #include <bcmsdpcm.h>
55 #include <bcmsdbus.h>
56 
57 #include <ethernet.h>
58 #include <802.1d.h>
59 #include <802.11.h>
60 
61 #include <dngl_stats.h>
62 #include <dhd.h>
63 #include <dhd_bus.h>
64 #include <dhd_proto.h>
65 #include <dhd_dbg.h>
66 #include <dhdioctl.h>
67 #include <sdiovar.h>
68 #include <dhd_config.h>
69 #ifdef DHD_PKTDUMP_TOFW
70 #include <dhd_linux_pktdump.h>
71 #endif
72 #include <linux/mmc/sdio_func.h>
73 #include <dhd_linux.h>
74 
75 #ifdef PROP_TXSTATUS
76 #include <dhd_wlfc.h>
77 #endif // endif
78 #ifdef DHDTCPACK_SUPPRESS
79 #include <dhd_ip.h>
80 #endif /* DHDTCPACK_SUPPRESS */
81 
82 #ifdef BT_OVER_SDIO
83 #include <dhd_bt_interface.h>
84 #endif /* BT_OVER_SDIO */
85 
86 #if defined(DEBUGGER) || defined(DHD_DSCOPE)
87 #include <debugger.h>
88 #endif /* DEBUGGER || DHD_DSCOPE */
89 
90 bool dhd_mp_halting(dhd_pub_t *dhdp);
91 extern void bcmsdh_waitfor_iodrain(void *sdh);
92 extern void bcmsdh_reject_ioreqs(void *sdh, bool reject);
93 extern bool bcmsdh_fatal_error(void *sdh);
94 static int dhdsdio_suspend(void *context);
95 static int dhdsdio_resume(void *context);
96 
97 #ifndef DHDSDIO_MEM_DUMP_FNAME
98 #define DHDSDIO_MEM_DUMP_FNAME "mem_dump"
99 #endif // endif
100 
101 #define QLEN (1024) /* bulk rx and tx queue lengths */
102 #define FCHI (QLEN - 10)
103 #define FCLOW (FCHI / 2)
104 #define PRIOMASK 0x7
105 
106 #define F0_BLOCK_SIZE 32
107 #define TXRETRIES 2 /* # of retries for tx frames */
108 #define READ_FRM_CNT_RETRIES 3
109 #ifndef DHD_RXBOUND
110 #define DHD_RXBOUND 50 /* Default for max rx frames in one scheduling */
111 #endif                 // endif
112 
113 #ifndef DHD_TXBOUND
114 #define DHD_TXBOUND 20 /* Default for max tx frames in one scheduling */
115 #endif                 // endif
116 
117 #define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */
118 
119 #define MEMBLOCK 2048 /* Block size used for downloading of dongle image */
120 #define MAX_MEMBLOCK                                                           \
121     (32 * 1024) /* Block size used for downloading of dongle image */
122 
123 #define MAX_DATA_BUF                                                           \
124     (0x40 * 1024) /* Must be large enough to hold biggest possible glom */
125 #define MAX_MEM_BUF 4096
126 
127 #ifndef DHD_FIRSTREAD
128 #define DHD_FIRSTREAD 32
129 #endif // endif
130 #if !ISPOWEROF2(DHD_FIRSTREAD)
131 #error DHD_FIRSTREAD is not a power of 2!
132 #endif // endif
133 
134 /* Total length of frame header for dongle protocol */
135 #define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
136 #define SDPCM_HDRLEN_TXGLOM (SDPCM_HDRLEN + SDPCM_HWEXT_LEN)
137 #define MAX_TX_PKTCHAIN_CNT SDPCM_MAXGLOM_SIZE
138 
139 #ifdef SDTEST
140 #define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN)
141 #else
142 #define SDPCM_RESERVE (SDPCM_HDRLEN + DHD_SDALIGN)
143 #endif // endif
144 
145 /* Space for header read, limit for data packets */
146 #ifndef MAX_HDR_READ
147 #define MAX_HDR_READ 32
148 #endif // endif
149 #if !ISPOWEROF2(MAX_HDR_READ)
150 #error MAX_HDR_READ is not a power of 2!
151 #endif // endif
152 
153 #define MAX_RX_DATASZ 2048
154 
155 /* Maximum milliseconds to wait for F2 to come up */
156 #define DHD_WAIT_F2RDY 3000
157 
158 /* Maximum usec to wait for HTAVAIL to come up */
159 #define DHD_WAIT_HTAVAIL 10000
160 
161 /* Bump up limit on waiting for HT to account for first startup;
162  * if the image is doing a CRC calculation before programming the PMU
163  * for HT availability, it could take a couple hundred ms more, so
164  * max out at a 1 second (1000000us).
165  */
166 #if (PMU_MAX_TRANSITION_DLY <= 1000000)
167 #undef PMU_MAX_TRANSITION_DLY
168 #ifdef NO_EXT32K
169 #define PMU_MAX_TRANSITION_DLY (1000000 * 5)
170 #else
171 #define PMU_MAX_TRANSITION_DLY 1000000
172 #endif
173 #endif // endif
174 
175 /* hooks for limiting threshold custom tx num in rx processing */
176 #define DEFAULT_TXINRX_THRES 0
177 #ifndef CUSTOM_TXINRX_THRES
178 #define CUSTOM_TXINRX_THRES DEFAULT_TXINRX_THRES
179 #endif // endif
180 
181 /* Value for ChipClockCSR during initial setup */
182 #define DHD_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ)
183 #define DHD_INIT_CLKCTL2 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP)
184 
185 /* Flags for SDH calls */
186 #define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
187 
188 /* Packet free applicable unconditionally for sdio and sdspi.  Conditional if
189  * bufpool was present for gspi bus.
190  */
191 #define PKTFREE2()                                                             \
192     if ((bus->bus != SPI_BUS) || bus->usebufpool)                              \
193         PKTFREE(bus->dhd->osh, pkt, FALSE);
194 DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep);
195 
196 #ifdef SUPPORT_MULTIPLE_BOARD_REV_FROM_HW
197 extern unsigned int system_hw_rev;
198 #endif /* SUPPORT_MULTIPLE_BOARD_REV_FROM_HW */
199 
200 /* Device console log buffer state */
201 #define CONSOLE_LINE_MAX 192
202 #define CONSOLE_BUFFER_MAX 8192
203 typedef struct dhd_console {
204     uint count;    /* Poll interval msec counter */
205     uint log_addr; /* Log struct address (fixed) */
206     hnd_log_t log; /* Log struct (host copy) */
207     uint bufsize;  /* Size of log buffer */
208     uint8 *buf;    /* Log buffer (host copy) */
209     uint last;     /* Last buffer read index */
210 } dhd_console_t;
211 
212 #define REMAP_ENAB(bus) ((bus)->remap)
213 #define REMAP_ISADDR(bus, a)                                                   \
214     (((a) >= ((bus)->orig_ramsize)) && ((a) < ((bus)->ramsize)))
215 #define KSO_ENAB(bus) ((bus)->kso)
216 #define SR_ENAB(bus) ((bus)->_srenab)
217 #define SLPAUTO_ENAB(bus) ((SR_ENAB(bus)) && ((bus)->_slpauto))
218 
219 #define MIN_RSRC_SR 0x3
220 #define CORE_CAPEXT_ADDR_OFFSET (0x64c)
221 #define CORE_CAPEXT_SR_SUPPORTED_MASK (1 << 1)
222 #define RCTL_MACPHY_DISABLE_MASK (1 << 26)
223 #define RCTL_LOGIC_DISABLE_MASK (1 << 27)
224 
225 #define OOB_WAKEUP_ENAB(bus) ((bus)->_oobwakeup)
226 #define GPIO_DEV_SRSTATE 16 /* Host gpio17 mapped to device gpio0 SR state */
227 #define GPIO_DEV_SRSTATE_TIMEOUT 320000 /* 320ms */
228 #define GPIO_DEV_WAKEUP 17 /* Host gpio17 mapped to device gpio1 wakeup */
229 #define CC_CHIPCTRL2_GPIO1_WAKEUP (1 << 0)
230 #define CC_CHIPCTRL3_SR_ENG_ENABLE (1 << 2)
231 #define OVERFLOW_BLKSZ512_WM 96
232 #define OVERFLOW_BLKSZ512_MES 80
233 
234 #define CC_PMUCC3 (0x3)
235 
236 #ifdef DHD_UCODE_DOWNLOAD
237 /* Ucode host download related macros */
238 #define UCODE_DOWNLOAD_REQUEST 0xCAFECAFE
239 #define UCODE_DOWNLOAD_COMPLETE 0xABCDABCD
240 #endif /* DHD_UCODE_DOWNLOAD */
241 
242 #if defined(BT_OVER_SDIO)
243 #define BTMEM_OFFSET 0x19000000
244 /* BIT0 => WLAN Power UP and BIT1=> WLAN Wake */
245 #define BT2WLAN_PWRUP_WAKE 0x03
246 #define BT2WLAN_PWRUP_ADDR 0x640894 /* This address is specific to 43012B0 */
247 
248 #define BTFW_MAX_STR_LEN 600
249 #define BTFW_DOWNLOAD_BLK_SIZE (BTFW_MAX_STR_LEN / 2 + 0x8)
250 
251 #define BTFW_ADDR_MODE_UNKNOWN 0
252 #define BTFW_ADDR_MODE_EXTENDED 1
253 #define BTFW_ADDR_MODE_SEGMENT 2
254 #define BTFW_ADDR_MODE_LINEAR32 3
255 
256 #define BTFW_HEX_LINE_TYPE_DATA 0
257 #define BTFW_HEX_LINE_TYPE_END_OF_DATA 1
258 #define BTFW_HEX_LINE_TYPE_EXTENDED_SEGMENT_ADDRESS 2
259 #define BTFW_HEX_LINE_TYPE_EXTENDED_ADDRESS 4
260 #define BTFW_HEX_LINE_TYPE_ABSOLUTE_32BIT_ADDRESS 5
261 
262 #endif /* defined (BT_OVER_SDIO) */
263 
264 /* Private data for SDIO bus interaction */
265 typedef struct dhd_bus {
266     dhd_pub_t *dhd;
267 
268     bcmsdh_info_t *sdh; /* Handle for BCMSDH calls */
269     si_t *sih;          /* Handle for SI calls */
270     char *vars;         /* Variables (from CIS and/or other) */
271     uint varsz;         /* Size of variables buffer */
272     uint32 sbaddr;      /* Current SB window pointer (-1, invalid) */
273 
274     sdpcmd_regs_t *regs; /* Registers for SDIO core */
275     uint sdpcmrev;       /* SDIO core revision */
276     uint armrev;         /* CPU core revision */
277     uint ramrev;         /* SOCRAM core revision */
278     uint32 ramsize;      /* Size of RAM in SOCRAM (bytes) */
279     uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */
280     uint32 srmemsize;    /* Size of SRMEM */
281 
282     uint32 bus;         /* gSPI or SDIO bus */
283     uint32 bus_num;     /* bus number */
284     uint32 slot_num;    /* slot ID */
285     uint32 hostintmask; /* Copy of Host Interrupt Mask */
286     uint32 intstatus;   /* Intstatus bits (events) pending */
287     bool dpc_sched;     /* Indicates DPC schedule (intrpt rcvd) */
288     bool fcstate;       /* State of dongle flow-control */
289 
290     uint16 cl_devid; /* cached devid for dhdsdio_probe_attach() */
291     char *fw_path;   /* module_param: path to firmware image */
292     char *nv_path;   /* module_param: path to nvram vars file */
293 
294     uint blocksize; /* Block size of SDIO transfers */
295     uint roundup;   /* Max roundup limit */
296 
297     struct pktq txq;   /* Queue length used for flow-control */
298     uint8 flowcontrol; /* per prio flow control bitmask */
299     uint8 tx_seq;      /* Transmit sequence number (next) */
300     uint8 tx_max;      /* Maximum transmit sequence allowed */
301 
302 #ifdef DYNAMIC_MAX_HDR_READ
303     uint8 *hdrbufp;
304 #else
305     uint8 hdrbuf[MAX_HDR_READ + DHD_SDALIGN];
306 #endif
307     uint8 *rxhdr;   /* Header of current rx frame (in hdrbuf) */
308     uint16 nextlen; /* Next Read Len from last header */
309     uint8 rx_seq;   /* Receive sequence number (expected) */
310     bool rxskip;    /* Skip receive (awaiting NAK ACK) */
311 
312     void *glomd;  /* Packet containing glomming descriptor */
313     void *glom;   /* Packet chain for glommed superframe */
314     uint glomerr; /* Glom packet read errors */
315 
316     uint8 *rxbuf;   /* Buffer for receiving control packets */
317     uint rxblen;    /* Allocated length of rxbuf */
318     uint8 *rxctl;   /* Aligned pointer into rxbuf */
319     uint8 *databuf; /* Buffer for receiving big glom packet */
320     uint8 *dataptr; /* Aligned pointer into databuf */
321     uint rxlen;     /* Length of valid data in buffer */
322 
323     uint8 sdpcm_ver; /* Bus protocol reported by dongle */
324 
325     bool intr;      /* Use interrupts */
326     bool poll;      /* Use polling */
327     bool ipend;     /* Device interrupt is pending */
328     bool intdis;    /* Interrupts disabled by isr */
329     uint intrcount; /* Count of device interrupt callbacks */
330     uint lastintrs; /* Count as of last watchdog timer */
331     uint spurious;  /* Count of spurious interrupts */
332     uint pollrate;  /* Ticks between device polls */
333     uint polltick;  /* Tick counter */
334     uint pollcnt;   /* Count of active polls */
335 
336     dhd_console_t console; /* Console output polling support */
337     uint console_addr;     /* Console address from shared struct */
338 
339     uint regfails; /* Count of R_REG/W_REG failures */
340 
341     uint clkstate;    /* State of sd and backplane clock(s) */
342     bool activity;    /* Activity flag for clock down */
343     int32 idletime;   /* Control for activity timeout */
344     int32 idlecount;  /* Activity timeout counter */
345     int32 idleclock;  /* How to set bus driver when idle */
346     int32 sd_divisor; /* Speed control to bus driver */
347     int32 sd_mode;    /* Mode control to bus driver */
348     int32 sd_rxchain; /* If bcmsdh api accepts PKT chains */
349     bool use_rxchain; /* If dhd should use PKT chains */
350     bool sleeping;    /* Is SDIO bus sleeping? */
351 #if defined(SUPPORT_P2P_GO_PS)
352     wait_queue_head_t bus_sleep;
353 #endif /* LINUX && SUPPORT_P2P_GO_PS */
354     bool ctrl_wait;
355     wait_queue_head_t ctrl_tx_wait;
356     uint rxflow_mode;    /* Rx flow control mode */
357     bool rxflow;         /* Is rx flow control on */
358     uint prev_rxlim_hit; /* Is prev rx limit exceeded (per dpc schedule) */
359     bool alp_only;       /* Don't use HT clock (ALP only) */
360     /* Field to decide if rx of control frames happen in rxbuf or lb-pool */
361     bool usebufpool;
362     int32 txinrx_thres; /* num of in-queued pkts */
363     int32 dotxinrx;     /* tx first in dhdsdio_readframes */
364 #ifdef BCMSDIO_RXLIM_POST
365     bool rxlim_en;
366     uint32 rxlim_addr;
367 #endif /* BCMSDIO_RXLIM_POST */
368 #ifdef SDTEST
369     /* external loopback */
370     bool ext_loop;
371     uint8 loopid;
372 
373     /* pktgen configuration */
374     uint pktgen_freq;   /* Ticks between bursts */
375     uint pktgen_count;  /* Packets to send each burst */
376     uint pktgen_print;  /* Bursts between count displays */
377     uint pktgen_total;  /* Stop after this many */
378     uint pktgen_minlen; /* Minimum packet data len */
379     uint pktgen_maxlen; /* Maximum packet data len */
380     uint pktgen_mode;   /* Configured mode: tx, rx, or echo */
381     uint pktgen_stop;   /* Number of tx failures causing stop */
382 
383     /* active pktgen fields */
384     uint pktgen_tick;      /* Tick counter for bursts */
385     uint pktgen_ptick;     /* Burst counter for printing */
386     uint pktgen_sent;      /* Number of test packets generated */
387     uint pktgen_rcvd;      /* Number of test packets received */
388     uint pktgen_prev_time; /* Time at which previous stats where printed */
389     uint pktgen_prev_sent; /* Number of test packets generated when
390                             * previous stats were printed
391                             */
392     uint pktgen_prev_rcvd; /* Number of test packets received when
393                             * previous stats were printed
394                             */
395     uint pktgen_fail;      /* Number of failed send attempts */
396     uint16 pktgen_len;     /* Length of next packet to send */
397 #define PKTGEN_RCV_IDLE (0)
398 #define PKTGEN_RCV_ONGOING (1)
399     uint16 pktgen_rcv_state;     /* receive state */
400     uint pktgen_rcvd_rcvsession; /* test pkts rcvd per rcv session. */
401 #endif                           /* SDTEST */
402 
403     /* Some additional counters */
404     uint tx_sderrs;            /* Count of tx attempts with sd errors */
405     uint fcqueued;             /* Tx packets that got queued */
406     uint rxrtx;                /* Count of rtx requests (NAK to dongle) */
407     uint rx_toolong;           /* Receive frames too long to receive */
408     uint rxc_errors;           /* SDIO errors when reading control frames */
409     uint rx_hdrfail;           /* SDIO errors on header reads */
410     uint rx_badhdr;            /* Bad received headers (roosync?) */
411     uint rx_badseq;            /* Mismatched rx sequence number */
412     uint fc_rcvd;              /* Number of flow-control events received */
413     uint fc_xoff;              /* Number which turned on flow-control */
414     uint fc_xon;               /* Number which turned off flow-control */
415     uint rxglomfail;           /* Failed deglom attempts */
416     uint rxglomframes;         /* Number of glom frames (superframes) */
417     uint rxglompkts;           /* Number of packets from glom frames */
418     uint f2rxhdrs;             /* Number of header reads */
419     uint f2rxdata;             /* Number of frame data reads */
420     uint f2txdata;             /* Number of f2 frame writes */
421     uint f1regdata;            /* Number of f1 register accesses */
422     wake_counts_t wake_counts; /* Wake up counter */
423 #ifdef BCMSPI
424     bool dwordmode;
425 #endif /* BCMSPI */
426 #ifdef DHDENABLE_TAILPAD
427     uint tx_tailpad_chain;  /* Number of tail padding by chaining pad_pkt */
428     uint tx_tailpad_pktget; /* Number of tail padding by new PKTGET */
429 #endif                      /* DHDENABLE_TAILPAD */
430     uint8 *ctrl_frame_buf;
431     uint32 ctrl_frame_len;
432     bool ctrl_frame_stat;
433 #ifndef BCMSPI
434     uint32 rxint_mode; /* rx interrupt mode */
435 #endif                 /* BCMSPI */
436     bool remap;        /* Contiguous 1MB RAM: 512K socram + 512K devram
437                         * Available with socram rev 16
438                         * Remap region not DMA-able
439                         */
440     bool kso;
441     bool _slpauto;
442     bool _oobwakeup;
443     bool _srenab;
444     bool readframes;
445     bool reqbussleep;
446     uint32 resetinstr;
447     uint32 dongle_ram_base;
448 
449     void *glom_pkt_arr[SDPCM_MAXGLOM_SIZE]; /* Array of pkts for glomming */
450     uint32 txglom_cnt;       /* Number of pkts in the glom array */
451     uint32 txglom_total_len; /* Total length of pkts in glom array */
452     bool txglom_enable; /* Flag to indicate whether tx glom is enabled/disabled
453                          */
454     uint32 txglomsize;  /* Glom size limitation */
455 #ifdef DHDENABLE_TAILPAD
456     void *pad_pkt;
457 #endif                       /* DHDENABLE_TAILPAD */
458     uint32 dongle_trap_addr; /* device trap addr location in device memory */
459 #if defined(BT_OVER_SDIO)
460     char *btfw_path;     /* module_param: path to BT firmware image */
461     uint32 bt_use_count; /* Counter that tracks whether BT is using the bus */
462 #endif                   /* defined (BT_OVER_SDIO) */
463     uint txglomframes;   /* Number of tx glom frames (superframes) */
464     uint txglompkts;     /* Number of packets from tx glom frames */
465 #ifdef PKT_STATICS
466     struct pkt_statics tx_statics;
467 #endif
468     uint8 *membuf; /* Buffer for dhdsdio_membytes */
469 #ifdef CONSOLE_DPC
470     char cons_cmd[0x10];
471 #endif
472 } dhd_bus_t;
473 
474 /*
475  * Whenever DHD_IDLE_IMMEDIATE condition is handled, we have to now check if
476  * BT is active too. Instead of adding #ifdef code in all the places, we thought
477  * of adding one macro check as part of the if condition that checks for
478  * DHD_IDLE_IMMEDIATE In case of non BT over SDIO builds, this macro will always
479  * return TRUE. In case of the builds where BT_OVER_SDIO is enabled, it will
480  * expand to a condition check that checks if bt_use_count is zero. So this
481  * macro will return equate to 1 if bt_use_count is 0, indicating that there are
482  * no active users and if bt_use_count is non zero it would return 0 there by
483  * preventing the caller from executing the sleep calls.
484  */
485 #ifdef BT_OVER_SDIO
486 #define NO_OTHER_ACTIVE_BUS_USER(bus) (bus->bt_use_count == 0)
487 #else
488 #define NO_OTHER_ACTIVE_BUS_USER(bus) (1)
489 #endif /* BT_OVER_SDIO */
490 
491 /* clkstate */
492 #define CLK_NONE 0
493 #define CLK_SDONLY 1
494 #define CLK_PENDING 2 /* Not used yet */
495 #define CLK_AVAIL 3
496 
497 #define DHD_NOPMU(dhd) (FALSE)
498 
499 #if defined(BCMSDIOH_STD)
500 #define BLK_64_MAXTXGLOM 20
501 #endif /* BCMSDIOH_STD */
502 
503 #ifdef DHD_DEBUG
504 static int qcount[NUMPRIO];
505 static int tx_packets[NUMPRIO];
506 #endif /* DHD_DEBUG */
507 
508 /* Deferred transmit */
509 const uint dhd_deferred_tx = 1;
510 
511 extern uint dhd_watchdog_ms;
512 extern uint sd_f1_blocksize;
513 
514 #ifdef BCMSPI_ANDROID
515 extern uint *dhd_spi_lockcount;
516 #endif /* BCMSPI_ANDROID */
517 
518 extern void dhd_os_wd_timer(void *bus, uint wdtick);
519 int dhd_enableOOB(dhd_pub_t *dhd, bool sleep);
520 
521 #ifdef DHD_PM_CONTROL_FROM_FILE
522 extern bool g_pm_control;
523 #endif /* DHD_PM_CONTROL_FROM_FILE */
524 
525 /* Tx/Rx bounds */
526 uint dhd_txbound;
527 uint dhd_rxbound;
528 uint dhd_txminmax = DHD_TXMINMAX;
529 
530 /* override the RAM size if possible */
531 #define DONGLE_MIN_RAMSIZE (128 * 1024)
532 int dhd_dongle_ramsize;
533 
534 uint dhd_doflow = TRUE;
535 uint dhd_dpcpoll = FALSE;
536 
537 module_param(dhd_doflow, uint, 0644);
538 module_param(dhd_dpcpoll, uint, 0644);
539 
540 static bool dhd_alignctl;
541 
542 static bool sd1idle;
543 
544 static bool retrydata;
545 #define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata)
546 
547 #ifdef BCMSPI
548 /* At a watermark around 8 the spid hits underflow error. */
549 static uint watermark = 32;
550 static uint mesbusyctrl = 0;
551 #else
552 static uint watermark = 8;
553 static uint mesbusyctrl = 0;
554 #endif /* BCMSPI */
555 #ifdef DYNAMIC_MAX_HDR_READ
556 uint firstread = DHD_FIRSTREAD;
557 #else
558 static const uint firstread = DHD_FIRSTREAD;
559 #endif
560 
561 /* Retry count for register access failures */
562 static const uint retry_limit = 2;
563 
564 /* Force even SD lengths (some host controllers mess up on odd bytes) */
565 static bool forcealign;
566 
567 #if defined(DEBUGGER)
568 static uint32 dhd_sdio_reg_read(struct dhd_bus *bus, ulong addr);
569 static void dhd_sdio_reg_write(struct dhd_bus *bus, ulong addr, uint32 val);
570 
571 /** the debugger layer will call back into this (bus) layer to read/write dongle
572  * memory */
573 static struct dhd_dbg_bus_ops_s bus_ops = {
574     .read_u16 = NULL,
575     .read_u32 = dhd_sdio_reg_read,
576     .write_u32 = dhd_sdio_reg_write,
577 };
578 #endif /* DEBUGGER */
579 
580 #define ALIGNMENT 4
581 
582 #if (defined(OOB_INTR_ONLY) && defined(HW_OOB)) || defined(FORCE_WOWLAN)
583 extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable);
584 #endif // endif
585 
586 #if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD)
587 #error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD
588 #endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */
589 #define PKTALIGN(osh, p, len, align)                                           \
590     do {                                                                       \
591         uintptr datalign;                                                      \
592         datalign = (uintptr)PKTDATA((osh), (p));                               \
593         datalign = ROUNDUP(datalign, (align)) - datalign;                      \
594         ASSERT(datalign < (align));                                            \
595         ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign));                      \
596         if (datalign)                                                          \
597             PKTPULL((osh), (p), (uint)datalign);                               \
598         PKTSETLEN((osh), (p), (len));                                          \
599     } while (0)
600 
601 /* Limit on rounding up frames */
602 static const uint max_roundup = 512;
603 
604 /* Try doing readahead */
605 static bool dhd_readahead;
606 
607 #if defined(BCMSDIOH_TXGLOM_EXT)
dhdsdio_is_dataok(dhd_bus_t * bus)608 bool dhdsdio_is_dataok(dhd_bus_t *bus)
609 {
610     return (
611         ((uint8)(bus->tx_max - bus->tx_seq) - bus->dhd->conf->tx_max_offset >
612          1) &&
613         (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0));
614 }
615 
dhdsdio_get_databufcnt(dhd_bus_t * bus)616 uint8 dhdsdio_get_databufcnt(dhd_bus_t *bus)
617 {
618     return ((uint8)(bus->tx_max - bus->tx_seq) - 1 -
619             bus->dhd->conf->tx_max_offset);
620 }
621 #endif
622 
623 /* To check if there's window offered */
624 #if defined(BCMSDIOH_TXGLOM_EXT)
625 #define DATAOK(bus) dhdsdio_is_dataok(bus)
626 #else
627 #define DATAOK(bus)                                                            \
628     (((uint8)(bus->tx_max - bus->tx_seq) > 1) &&                               \
629      (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
630 #endif
631 
632 /* To check if there's window offered for ctrl frame */
633 #define TXCTLOK(bus)                                                           \
634     (((uint8)(bus->tx_max - bus->tx_seq) != 0) &&                              \
635      (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
636 
637 /* Number of pkts available in dongle for data RX */
638 #if defined(BCMSDIOH_TXGLOM_EXT)
639 #define DATABUFCNT(bus) dhdsdio_get_databufcnt(bus)
640 #else
641 #define DATABUFCNT(bus) ((uint8)(bus->tx_max - bus->tx_seq) - 1)
642 #endif
643 
644 /* Macros to get register read/write status */
645 /* NOTE: these assume a local dhdsdio_bus_t *bus! */
646 #define R_SDREG(regvar, regaddr, retryvar)                                     \
647     do {                                                                       \
648         retryvar = 0;                                                          \
649         do {                                                                   \
650             regvar = R_REG(bus->dhd->osh, regaddr);                            \
651         } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit));     \
652         if (retryvar) {                                                        \
653             bus->regfails += (retryvar - 1);                                   \
654             if (retryvar > retry_limit) {                                      \
655                 DHD_ERROR(("%s: FAILED" #regvar "READ, LINE %d\n",             \
656                            __FUNCTION__, __LINE__));                           \
657                 regvar = 0;                                                    \
658             }                                                                  \
659         }                                                                      \
660     } while (0)
661 
662 #define W_SDREG(regval, regaddr, retryvar)                                     \
663     do {                                                                       \
664         retryvar = 0;                                                          \
665         do {                                                                   \
666             W_REG(bus->dhd->osh, regaddr, regval);                             \
667         } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit));     \
668         if (retryvar) {                                                        \
669             bus->regfails += (retryvar - 1);                                   \
670             if (retryvar > retry_limit)                                        \
671                 DHD_ERROR(("%s: FAILED REGISTER WRITE, LINE %d\n",             \
672                            __FUNCTION__, __LINE__));                           \
673         }                                                                      \
674     } while (0)
675 
676 #define BUS_WAKE(bus)                                                          \
677     do {                                                                       \
678         bus->idlecount = 0;                                                    \
679         if ((bus)->sleeping)                                                   \
680             dhdsdio_bussleep((bus), FALSE);                                    \
681     } while (0);
682 
683 /*
684  * pktavail interrupts from dongle to host can be managed in 3 different ways
685  * whenever there is a packet available in dongle to transmit to host.
686  *
687  * Mode 0:	Dongle writes the software host mailbox and host is interrupted.
688  * Mode 1:	(sdiod core rev >= 4)
689  *		Device sets a new bit in the intstatus whenever there is a packet
690  *		available in fifo.  Host can't clear this specific status bit until all
691  * the packets are read from the FIFO.  No need to ack dongle intstatus. Mode 2:
692  * (sdiod core rev >= 4) Device sets a bit in the intstatus, and host acks this
693  * by writing one to this bit.  Dongle won't generate anymore packet interrupts
694  *		until host reads all the packets from the dongle and reads a zero to
695  *		figure that there are no more packets.  No need to disable host ints.
696  *		Need to ack the intstatus.
697  */
698 
699 #define SDIO_DEVICE_HMB_RXINT 0        /* default old way */
700 #define SDIO_DEVICE_RXDATAINT_MODE_0 1 /* from sdiod rev 4 */
701 #define SDIO_DEVICE_RXDATAINT_MODE_1 2 /* from sdiod rev 4 */
702 
703 #ifdef BCMSPI
704 
705 #define FRAME_AVAIL_MASK(bus) I_HMB_FRAME_IND
706 
707 #define DHD_BUS SPI_BUS
708 
709 /* check packet-available-interrupt in piggybacked dstatus */
710 #define PKT_AVAILABLE(bus, intstatus)                                          \
711     (bcmsdh_get_dstatus(bus->sdh) & STATUS_F2_PKT_AVAILABLE)
712 
713 #define HOSTINTMASK (I_HMB_FC_CHANGE | I_HMB_HOST_INT)
714 
715 #define GSPI_PR55150_BAILOUT                                                   \
716     do {                                                                       \
717         uint32 dstatussw = bcmsdh_get_dstatus((void *)bus->sdh);               \
718         uint32 dstatushw = bcmsdh_cfg_read_word(bus->sdh, SDIO_FUNC_0,         \
719                                                 SPID_STATUS_REG, NULL);        \
720         uint32 intstatuserr = 0;                                               \
721         uint retries = 0;                                                      \
722                                                                                \
723         R_SDREG(intstatuserr, &bus->regs->intstatus, retries);                 \
724         printf("dstatussw = 0x%x, dstatushw = 0x%x, intstatus = 0x%x\n",       \
725                dstatussw, dstatushw, intstatuserr);                            \
726                                                                                \
727         bus->nextlen = 0;                                                      \
728         *finished = TRUE;                                                      \
729     } while (0)
730 
731 #else /* BCMSDIO */
732 
733 #define FRAME_AVAIL_MASK(bus)                                                  \
734     ((bus->rxint_mode == SDIO_DEVICE_HMB_RXINT) ? I_HMB_FRAME_IND              \
735                                                 : I_XMTDATA_AVAIL)
736 
737 #define DHD_BUS SDIO_BUS
738 
739 #define PKT_AVAILABLE(bus, intstatus) ((intstatus) & (FRAME_AVAIL_MASK(bus)))
740 
741 #define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE)
742 
743 #define GSPI_PR55150_BAILOUT
744 
745 #endif /* BCMSPI */
746 
747 #ifdef SDTEST
748 static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq);
749 static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint count);
750 #endif // endif
751 
752 static int dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size);
753 #ifdef DHD_DEBUG
754 static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable,
755                              int *bcmerror);
756 #endif /* DHD_DEBUG */
757 
758 #if defined(DHD_FW_COREDUMP)
759 static int dhdsdio_mem_dump(dhd_bus_t *bus);
760 static int dhdsdio_get_mem_dump(dhd_bus_t *bus);
761 #endif /* DHD_FW_COREDUMP */
762 static int dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap);
763 static int dhdsdio_download_state(dhd_bus_t *bus, bool enter);
764 
765 static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh);
766 static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh);
767 static void dhdsdio_disconnect(void *ptr);
768 static bool dhdsdio_chipmatch(uint16 chipid);
769 static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh,
770                                  void *regsva, uint16 devid);
771 static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh);
772 static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh);
773 static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh,
774                                    bool dongle_isolation, bool reset_flag);
775 
776 static void dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size);
777 static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
778                                uint8 *buf, uint nbytes, void *pkt,
779                                bcmsdh_cmplt_fn_t complete, void *handle);
780 static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
781                                uint8 *buf, uint nbytes, void *pkt,
782                                bcmsdh_cmplt_fn_t complete, void *handle,
783                                int max_retry);
784 static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void **pkts, int num_pkt,
785                          bool free_pkt);
786 static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan,
787                                     int txseq, int prev_chain_total_len,
788                                     bool last_chained_pkt, int *pad_pkt_len,
789                                     void **new_pkt
790 #if defined(BCMSDIOH_TXGLOM_EXT)
791                                     ,
792                                     int first_frame
793 #endif
794 );
795 static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt);
796 
797 static int dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh);
798 static int _dhdsdio_download_firmware(dhd_bus_t *bus);
799 
800 #ifdef DHD_UCODE_DOWNLOAD
801 static int dhdsdio_download_ucode_file(struct dhd_bus *bus, char *ucode_path);
802 #endif /* DHD_UCODE_DOWNLOAD */
803 static int dhdsdio_download_code_file(dhd_bus_t *bus, char *image_path);
804 static int dhdsdio_download_nvram(dhd_bus_t *bus);
805 static int dhdsdio_bussleep(dhd_bus_t *bus, bool sleep);
806 static int dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok);
807 static uint8 dhdsdio_sleepcsr_get(dhd_bus_t *bus);
808 static bool dhdsdio_dpc(dhd_bus_t *bus);
809 static int dhd_bcmsdh_send_buffer(void *bus, uint8 *frame, uint16 len);
810 static int dhdsdio_set_sdmode(dhd_bus_t *bus, int32 sd_mode);
811 static int dhdsdio_sdclk(dhd_bus_t *bus, bool on);
812 static void dhdsdio_advertise_bus_cleanup(dhd_pub_t *dhdp);
813 static void dhdsdio_advertise_bus_remove(dhd_pub_t *dhdp);
814 
815 #if defined(BT_OVER_SDIO)
816 static int extract_hex_field(char *line, uint16 start_pos, uint16 num_chars,
817                              uint16 *value);
818 static int read_more_btbytes(struct dhd_bus *bus, void *file, char *line,
819                              int *addr_mode, uint16 *hi_addr, uint32 *dest_addr,
820                              uint8 *data_bytes, uint32 *num_bytes);
821 static int dhdsdio_download_btfw(struct dhd_bus *bus, osl_t *osh, void *sdh);
822 static int _dhdsdio_download_btfw(struct dhd_bus *bus);
823 #endif /* defined (BT_OVER_SDIO) */
824 
825 #ifdef DHD_ULP
826 #include <dhd_ulp.h>
827 static int dhd_bus_ulp_reinit_fw(dhd_bus_t *bus);
828 #endif /* DHD_ULP */
829 
830 #ifdef DHD_WAKE_STATUS
831 int bcmsdh_get_total_wake(bcmsdh_info_t *bcmsdh);
832 int bcmsdh_set_get_wake(bcmsdh_info_t *bcmsdh, int flag);
833 #endif /* DHD_WAKE_STATUS */
834 
dhdsdio_tune_fifoparam(struct dhd_bus * bus)835 static void dhdsdio_tune_fifoparam(struct dhd_bus *bus)
836 {
837     int err;
838     uint8 devctl, wm, mes;
839 
840     if (bus->sih->buscorerev >= 0xF) {
841         /* See .ppt in PR for these recommended values */
842         if (bus->blocksize == 0x200) {
843             wm = OVERFLOW_BLKSZ512_WM;
844             mes = OVERFLOW_BLKSZ512_MES;
845         } else {
846             mes = bus->blocksize / 0x4;
847             wm = bus->blocksize / 0x4;
848         }
849 
850         watermark = wm;
851         mesbusyctrl = mes;
852     } else {
853         DHD_INFO(
854             ("skip fifotune: SdioRev(%d) is lower than minimal requested ver\n",
855              bus->sih->buscorerev));
856         return;
857     }
858 
859     /* Update watermark */
860     if (wm > 0) {
861         bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, wm, &err);
862 
863         devctl =
864             bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
865         devctl |= SBSDIO_DEVCTL_F2WM_ENAB;
866         bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl,
867                          &err);
868     }
869 
870     /* Update MES */
871     if (mes > 0) {
872         bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
873                          (mes | SBSDIO_MESBUSYCTRL_ENAB), &err);
874     }
875 
876     DHD_INFO(("Apply overflow WAR: 0x%02x 0x%02x 0x%02x\n",
877               bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err),
878               bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, &err),
879               bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
880                               &err)));
881 }
882 
dhd_dongle_setramsize(struct dhd_bus * bus,int mem_size)883 static void dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size)
884 {
885     int32 min_size = DONGLE_MIN_RAMSIZE;
886     /* Restrict the ramsize to user specified limit */
887     DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n",
888                dhd_dongle_ramsize, min_size));
889     if ((dhd_dongle_ramsize > min_size) &&
890         (dhd_dongle_ramsize < (int32)bus->orig_ramsize)) {
891         bus->ramsize = dhd_dongle_ramsize;
892     }
893 }
894 
dhdsdio_set_siaddr_window(dhd_bus_t * bus,uint32 address)895 static int dhdsdio_set_siaddr_window(dhd_bus_t *bus, uint32 address)
896 {
897     int err = 0;
898     bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
899                      (address >> 0x8) & SBSDIO_SBADDRLOW_MASK, &err);
900     if (!err) {
901         bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID,
902                          (address >> 0x10) & SBSDIO_SBADDRMID_MASK, &err);
903     }
904     if (!err) {
905         bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH,
906                          (address >> 0x18) & SBSDIO_SBADDRHIGH_MASK, &err);
907     }
908     return err;
909 }
910 
911 #ifdef BCMSPI
dhdsdio_wkwlan(dhd_bus_t * bus,bool on)912 static void dhdsdio_wkwlan(dhd_bus_t *bus, bool on)
913 {
914     int err;
915     uint32 regdata;
916     bcmsdh_info_t *sdh = bus->sdh;
917 
918     if (bus->sih->buscoretype == SDIOD_CORE_ID) {
919         /* wake up wlan function :WAKE_UP goes as ht_avail_request and
920          * alp_avail_request */
921         regdata = bcmsdh_cfg_read_word(sdh, SDIO_FUNC_0, SPID_CONFIG, NULL);
922         DHD_INFO(("F0 REG0 rd = 0x%x\n", regdata));
923 
924         if (on == TRUE) {
925             regdata |= WAKE_UP;
926         } else {
927             regdata &= ~WAKE_UP;
928         }
929 
930         bcmsdh_cfg_write_word(sdh, SDIO_FUNC_0, SPID_CONFIG, regdata, &err);
931     }
932 }
933 #endif /* BCMSPI */
934 
935 #ifdef USE_OOB_GPIO1
dhdsdio_oobwakeup_init(dhd_bus_t * bus)936 static int dhdsdio_oobwakeup_init(dhd_bus_t *bus)
937 {
938     uint32 val, addr, data;
939 
940     bcmsdh_gpioouten(bus->sdh, GPIO_DEV_WAKEUP);
941 
942     addr = SI_ENUM_BASE(bus->sih) + OFFSETOF(chipcregs_t, chipcontrol_addr);
943     data = SI_ENUM_BASE(bus->sih) + OFFSETOF(chipcregs_t, chipcontrol_data);
944 
945     /* Set device for gpio1 wakeup */
946     bcmsdh_reg_write(bus->sdh, addr, 0x4, 0x2);
947     val = bcmsdh_reg_read(bus->sdh, data, 0x4);
948     val |= CC_CHIPCTRL2_GPIO1_WAKEUP;
949     bcmsdh_reg_write(bus->sdh, data, 0x4, val);
950 
951     bus->_oobwakeup = TRUE;
952 
953     return 0;
954 }
955 #endif /* USE_OOB_GPIO1 */
956 
957 #ifndef BCMSPI
958 /*
959  * Query if FW is in SR mode
960  */
dhdsdio_sr_cap(dhd_bus_t * bus)961 static bool dhdsdio_sr_cap(dhd_bus_t *bus)
962 {
963     bool cap = FALSE;
964     uint32 core_capext, addr, data;
965 
966     if (bus->sih->chip == BCM43430_CHIP_ID ||
967         bus->sih->chip == BCM43018_CHIP_ID) {
968         /* check if fw initialized sr engine */
969         addr = SI_ENUM_BASE(bus->sih) + OFFSETOF(chipcregs_t, sr_control1);
970         if (bcmsdh_reg_read(bus->sdh, addr, 0x4) != 0) {
971             cap = TRUE;
972         }
973 
974         return cap;
975     }
976     if (0) {
977         core_capext = FALSE;
978     } else if ((bus->sih->chip == BCM4330_CHIP_ID) ||
979                (bus->sih->chip == BCM43362_CHIP_ID) ||
980                (BCM4347_CHIP(bus->sih->chip))) {
981         core_capext = FALSE;
982     } else if ((bus->sih->chip == BCM4335_CHIP_ID) ||
983                (bus->sih->chip == BCM4339_CHIP_ID) ||
984                BCM4345_CHIP(bus->sih->chip) ||
985                (bus->sih->chip == BCM4354_CHIP_ID) ||
986                (bus->sih->chip == BCM4358_CHIP_ID) ||
987                (bus->sih->chip == BCM43569_CHIP_ID) ||
988                (bus->sih->chip == BCM4371_CHIP_ID) ||
989                (BCM4349_CHIP(bus->sih->chip)) ||
990                (bus->sih->chip == BCM4350_CHIP_ID) ||
991                (bus->sih->chip == BCM4362_CHIP_ID) ||
992                (bus->sih->chip == BCM43012_CHIP_ID) ||
993                (bus->sih->chip == BCM43014_CHIP_ID) ||
994                (bus->sih->chip == BCM43751_CHIP_ID) ||
995                (bus->sih->chip == BCM43752_CHIP_ID)) {
996         core_capext = TRUE;
997     } else {
998         core_capext = bcmsdh_reg_read(
999             bus->sdh,
1000             si_get_pmu_reg_addr(bus->sih, OFFSETOF(chipcregs_t, core_cap_ext)),
1001             0x4);
1002         core_capext = (core_capext & CORE_CAPEXT_SR_SUPPORTED_MASK);
1003     }
1004     if (!(core_capext)) {
1005         return FALSE;
1006     }
1007 
1008     if ((bus->sih->chip == BCM4335_CHIP_ID) ||
1009         (bus->sih->chip == BCM4339_CHIP_ID) || BCM4345_CHIP(bus->sih->chip) ||
1010         (bus->sih->chip == BCM4354_CHIP_ID) ||
1011         (bus->sih->chip == BCM4358_CHIP_ID) ||
1012         (bus->sih->chip == BCM43569_CHIP_ID) ||
1013         (bus->sih->chip == BCM4371_CHIP_ID) ||
1014         (bus->sih->chip == BCM4350_CHIP_ID)) {
1015         uint32 enabval = 0;
1016         addr = SI_ENUM_BASE(bus->sih) + OFFSETOF(chipcregs_t, chipcontrol_addr);
1017         data = SI_ENUM_BASE(bus->sih) + OFFSETOF(chipcregs_t, chipcontrol_data);
1018         bcmsdh_reg_write(bus->sdh, addr, 0x4, CC_PMUCC3);
1019         enabval = bcmsdh_reg_read(bus->sdh, data, 0x4);
1020 
1021         if ((bus->sih->chip == BCM4350_CHIP_ID) ||
1022             BCM4345_CHIP(bus->sih->chip) ||
1023             (bus->sih->chip == BCM4354_CHIP_ID) ||
1024             (bus->sih->chip == BCM4358_CHIP_ID) ||
1025             (bus->sih->chip == BCM43569_CHIP_ID) ||
1026             (bus->sih->chip == BCM4371_CHIP_ID)) {
1027             enabval &= CC_CHIPCTRL3_SR_ENG_ENABLE;
1028         }
1029 
1030         if (enabval) {
1031             cap = TRUE;
1032         }
1033     } else {
1034         data = bcmsdh_reg_read(
1035             bus->sdh,
1036             si_get_pmu_reg_addr(bus->sih, OFFSETOF(chipcregs_t, retention_ctl)),
1037             0x4);
1038         if ((data & (RCTL_MACPHY_DISABLE_MASK | RCTL_LOGIC_DISABLE_MASK)) ==
1039             0) {
1040             cap = TRUE;
1041         }
1042     }
1043 
1044     return cap;
1045 }
1046 
dhdsdio_sr_init(dhd_bus_t * bus)1047 static int dhdsdio_sr_init(dhd_bus_t *bus)
1048 {
1049     uint8 val;
1050     int err = 0;
1051 
1052     if (bus->sih->chip == BCM43012_CHIP_ID) {
1053         val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL,
1054                               NULL);
1055         val |= 1 << SBSDIO_FUNC1_WCTRL_ALPWAIT_SHIFT;
1056         bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL,
1057                          1 << SBSDIO_FUNC1_WCTRL_ALPWAIT_SHIFT, &err);
1058         val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL,
1059                               NULL);
1060     } else {
1061         val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL,
1062                               NULL);
1063         val |= 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT;
1064         bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL,
1065                          1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT, &err);
1066         val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL,
1067                               NULL);
1068     }
1069 
1070 #ifdef USE_CMD14
1071     /* Add CMD14 Support */
1072     dhdsdio_devcap_set(bus, (SDIOD_CCCR_BRCM_CARDCAP_CMD14_SUPPORT |
1073                              SDIOD_CCCR_BRCM_CARDCAP_CMD14_EXT));
1074 #endif /* USE_CMD14 */
1075 
1076     if (CHIPID(bus->sih->chip) == BCM43430_CHIP_ID ||
1077         CHIPID(bus->sih->chip) == BCM43018_CHIP_ID ||
1078         CHIPID(bus->sih->chip) == BCM4339_CHIP_ID ||
1079         CHIPID(bus->sih->chip) == BCM43012_CHIP_ID ||
1080         CHIPID(bus->sih->chip) == BCM4362_CHIP_ID ||
1081         CHIPID(bus->sih->chip) == BCM43014_CHIP_ID ||
1082         CHIPID(bus->sih->chip) == BCM43751_CHIP_ID ||
1083         CHIPID(bus->sih->chip) == BCM43752_CHIP_ID) {
1084         dhdsdio_devcap_set(bus, SDIOD_CCCR_BRCM_CARDCAP_CMD_NODEC);
1085     }
1086 
1087     if (bus->sih->chip == BCM43012_CHIP_ID) {
1088         bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
1089                          SBSDIO_HT_AVAIL_REQ, &err);
1090     } else {
1091         bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
1092                          SBSDIO_FORCE_HT, &err);
1093     }
1094     bus->_slpauto = dhd_slpauto ? TRUE : FALSE;
1095 
1096     bus->_srenab = TRUE;
1097 
1098     return 0;
1099 }
1100 #endif /* BCMSPI */
1101 
1102 /*
1103  * FIX: Be sure KSO bit is enabled
1104  * Currently, it's defaulting to 0 which should be 1.
1105  */
dhdsdio_clk_kso_init(dhd_bus_t * bus)1106 static int dhdsdio_clk_kso_init(dhd_bus_t *bus)
1107 {
1108     uint8 val;
1109     int err = 0;
1110 
1111     /* set flag */
1112     bus->kso = TRUE;
1113 
1114     /*
1115      * Enable KeepSdioOn (KSO) bit for normal operation
1116      * Default is 0 (4334A0) so set it. Fixed in B0.
1117      */
1118     val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, NULL);
1119     if (!(val & SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) {
1120         val |=
1121             (SBSDIO_FUNC1_SLEEPCSR_KSO_EN << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
1122         bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, val,
1123                          &err);
1124         if (err) {
1125             DHD_ERROR(
1126                 ("%s: SBSDIO_FUNC1_SLEEPCSR err: 0x%x\n", __FUNCTION__, err));
1127         }
1128     }
1129 
1130     return 0;
1131 }
1132 
1133 #define KSO_DBG(x)
1134 #define KSO_WAIT_US 50
1135 #define KSO_WAIT_MS 1
1136 #define KSO_SLEEP_RETRY_COUNT 20
1137 #define KSO_WAKE_RETRY_COUNT 100
1138 #define ERROR_BCME_NODEVICE_MAX 1
1139 
1140 #define DEFAULT_MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY / KSO_WAIT_US)
1141 #ifndef CUSTOM_MAX_KSO_ATTEMPTS
1142 #define CUSTOM_MAX_KSO_ATTEMPTS DEFAULT_MAX_KSO_ATTEMPTS
1143 #endif // endif
1144 
dhdsdio_clk_kso_enab(dhd_bus_t * bus,bool on)1145 static int dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on)
1146 {
1147     uint8 wr_val = 0, rd_val, cmp_val, bmask;
1148     int err = 0;
1149     int try_cnt = 0, try_max = CUSTOM_MAX_KSO_ATTEMPTS;
1150     struct dhd_conf *conf = bus->dhd->conf;
1151 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0))
1152     wifi_adapter_info_t *adapter = NULL;
1153     uint32 bus_type = -1, bus_num = -1, slot_num = -1;
1154 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) */
1155 
1156     KSO_DBG(("%s> op:%s\n", __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR")));
1157 
1158 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0))
1159     dhd_bus_get_ids(bus, &bus_type, &bus_num, &slot_num);
1160     adapter = dhd_wifi_platform_get_adapter(bus_type, bus_num, slot_num);
1161     sdio_retune_crc_disable(adapter->sdio_func);
1162     if (on) {
1163         sdio_retune_hold_now(adapter->sdio_func);
1164     }
1165 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) */
1166 
1167     wr_val |= (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
1168 
1169     bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val,
1170                      &err);
1171 
1172     /* In case of 43012 chip, the chip could go down immediately after KSO bit
1173      * is cleared. So the further reads of KSO register could fail. Thereby just
1174      * bailing out immediately after clearing KSO bit, to avoid polling of KSO
1175      * bit.
1176      */
1177     if ((!on) && (bus->sih->chip == BCM43012_CHIP_ID)) {
1178         goto exit;
1179     }
1180 
1181     if (on) {
1182         cmp_val =
1183             SBSDIO_FUNC1_SLEEPCSR_KSO_MASK | SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK;
1184         bmask = cmp_val;
1185 
1186         OSL_SLEEP(0x3);
1187     } else {
1188         /* Put device to sleep, turn off  KSO  */
1189         cmp_val = 0;
1190         bmask = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK;
1191     }
1192 
1193     if (conf->kso_try_max) {
1194         try_max = conf->kso_try_max;
1195     }
1196     do {
1197         rd_val =
1198             bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err);
1199         if (((rd_val & bmask) == cmp_val) && !err) {
1200             break;
1201         }
1202 
1203         KSO_DBG(
1204             ("%s> KSO wr/rd retry:%d, ERR:%x \n", __FUNCTION__, try_cnt, err));
1205 
1206         if (((try_cnt + 1) % KSO_SLEEP_RETRY_COUNT) == 0) {
1207             OSL_SLEEP(KSO_WAIT_MS);
1208         } else {
1209             OSL_DELAY(KSO_WAIT_US);
1210         }
1211 
1212         bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val,
1213                          &err);
1214     } while (try_cnt++ < try_max);
1215 
1216 #ifdef KSO_DEBUG
1217     if (try_cnt > 0 && try_cnt <= 0xA) {
1218         conf->kso_try_array[0] += 1;
1219     } else if (try_cnt <= 0x32) {
1220         conf->kso_try_array[1] += 1;
1221     } else if (try_cnt <= 0x64) {
1222         conf->kso_try_array[0x2] += 1;
1223     } else if (try_cnt <= 0xC8) {
1224         conf->kso_try_array[0x3] += 1;
1225     } else if (try_cnt <= 0x1F4) {
1226         conf->kso_try_array[0x4] += 1;
1227     } else if (try_cnt <= 0x3E8) {
1228         conf->kso_try_array[0x5] += 1;
1229     } else if (try_cnt <= 0x7D0) {
1230         conf->kso_try_array[0x6] += 1;
1231     } else if (try_cnt <= 0x1388) {
1232         conf->kso_try_array[0x7] += 1;
1233     } else if (try_cnt <= 0x2710) {
1234         conf->kso_try_array[0x8] += 1;
1235     } else {
1236         conf->kso_try_array[0x9] += 1;
1237     }
1238 #endif
1239     if (try_cnt > 0x2) {
1240         KSO_DBG(("%s> op:%s, try_cnt:%d, rd_val:%x, ERR:%x \n", __FUNCTION__,
1241                  (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err));
1242     }
1243 
1244     if (try_cnt > try_max) {
1245         DHD_ERROR(("%s> op:%s, ERROR: try_cnt:%d, rd_val:%x, ERR:%x \n",
1246                    __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val,
1247                    err));
1248 #ifdef KSO_DEBUG
1249         {
1250             int i;
1251             printk(KERN_CONT DHD_LOG_PREFIXS);
1252             for (i = 0; i < 0xA; i++) {
1253                 printk(KERN_CONT "[%d]: %d, ", i, conf->kso_try_array[i]);
1254             }
1255             printk("\n");
1256         }
1257 #endif
1258     }
1259 
1260 exit:
1261 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0))
1262     if (on) {
1263         sdio_retune_release(adapter->sdio_func);
1264     }
1265     sdio_retune_crc_enable(adapter->sdio_func);
1266 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) */
1267 
1268     return err;
1269 }
1270 
dhdsdio_clk_kso_iovar(dhd_bus_t * bus,bool on)1271 static int dhdsdio_clk_kso_iovar(dhd_bus_t *bus, bool on)
1272 {
1273     int err = 0;
1274 
1275     if (on == FALSE) {
1276         BUS_WAKE(bus);
1277         dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1278 
1279         DHD_ERROR(("%s: KSO disable clk: 0x%x\n", __FUNCTION__,
1280                    bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
1281                                    SBSDIO_FUNC1_CHIPCLKCSR, &err)));
1282         dhdsdio_clk_kso_enab(bus, FALSE);
1283     } else {
1284         DHD_ERROR(("%s: KSO enable\n", __FUNCTION__));
1285 
1286         /* Make sure we have SD bus access */
1287         if (bus->clkstate == CLK_NONE) {
1288             DHD_ERROR(("%s: Request SD clk\n", __FUNCTION__));
1289             dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1290         }
1291 
1292         dhdsdio_clk_kso_enab(bus, TRUE);
1293 
1294         DHD_ERROR(
1295             ("%s: sleepcsr: 0x%x\n", __FUNCTION__, dhdsdio_sleepcsr_get(bus)));
1296     }
1297 
1298     bus->kso = on;
1299     BCM_REFERENCE(err);
1300 
1301     return 0;
1302 }
1303 
dhdsdio_sleepcsr_get(dhd_bus_t * bus)1304 static uint8 dhdsdio_sleepcsr_get(dhd_bus_t *bus)
1305 {
1306     int err = 0;
1307     uint8 val = 0;
1308 
1309     val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err);
1310     if (err) {
1311         DHD_TRACE(("Failed to read SLEEPCSR: %d\n", err));
1312     }
1313 
1314     return val;
1315 }
1316 
dhdsdio_devcap_get(dhd_bus_t * bus)1317 uint8 dhdsdio_devcap_get(dhd_bus_t *bus)
1318 {
1319     return bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP,
1320                            NULL);
1321 }
1322 
dhdsdio_devcap_set(dhd_bus_t * bus,uint8 cap)1323 static int dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap)
1324 {
1325     int err = 0;
1326 
1327     bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, cap, &err);
1328     if (err) {
1329         DHD_ERROR(("%s: devcap set err: 0x%x\n", __FUNCTION__, err));
1330     }
1331 
1332     return 0;
1333 }
1334 
dhdsdio_clk_devsleep_iovar(dhd_bus_t * bus,bool on)1335 static int dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on)
1336 {
1337     int err = 0, retry;
1338     uint8 val;
1339 
1340     retry = 0;
1341     if (on == TRUE) {
1342         /* Enter Sleep */
1343 
1344         /* Be sure we request clk before going to sleep
1345          * so we can wake-up with clk request already set
1346          * else device can go back to sleep immediately
1347          */
1348         if (!SLPAUTO_ENAB(bus)) {
1349             dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1350         } else {
1351             val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
1352                                   SBSDIO_FUNC1_CHIPCLKCSR, &err);
1353             if ((val & SBSDIO_CSR_MASK) == 0) {
1354                 DHD_ERROR(("%s: No clock before enter sleep:0x%x\n",
1355                            __FUNCTION__, val));
1356 
1357                 /* Reset clock request */
1358                 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
1359                                  SBSDIO_ALP_AVAIL_REQ, &err);
1360                 DHD_ERROR(("%s: clock before sleep:0x%x\n", __FUNCTION__,
1361                            bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
1362                                            SBSDIO_FUNC1_CHIPCLKCSR, &err)));
1363             }
1364         }
1365 
1366         DHD_TRACE(("%s: clk before sleep: 0x%x\n", __FUNCTION__,
1367                    bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
1368                                    SBSDIO_FUNC1_CHIPCLKCSR, &err)));
1369 #ifdef USE_CMD14
1370         err = bcmsdh_sleep(bus->sdh, TRUE);
1371 #else
1372         if ((SLPAUTO_ENAB(bus)) && (bus->idleclock == DHD_IDLE_STOP)) {
1373             if (sd1idle) {
1374                 /* Change to SD1 mode */
1375                 dhdsdio_set_sdmode(bus, 1);
1376             }
1377         }
1378 
1379         err = dhdsdio_clk_kso_enab(bus, FALSE);
1380         if (OOB_WAKEUP_ENAB(bus)) {
1381             err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP,
1382                                  FALSE); /* GPIO_1 is off */
1383         }
1384 #endif /* USE_CMD14 */
1385 
1386         if ((SLPAUTO_ENAB(bus)) && (bus->idleclock != DHD_IDLE_ACTIVE)) {
1387             DHD_TRACE(("%s: Turnoff SD clk\n", __FUNCTION__));
1388             /* Now remove the SD clock */
1389             err = dhdsdio_sdclk(bus, FALSE);
1390         }
1391     } else {
1392         /* Exit Sleep */
1393         /* Make sure we have SD bus access */
1394         if (bus->clkstate == CLK_NONE) {
1395             DHD_TRACE(("%s: Request SD clk\n", __FUNCTION__));
1396             dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1397         }
1398 #ifdef USE_CMD14
1399         err = bcmsdh_sleep(bus->sdh, FALSE);
1400         if (SLPAUTO_ENAB(bus) && (err != 0)) {
1401             OSL_DELAY(0x2710);
1402             DHD_TRACE(("%s: Resync device sleep\n", __FUNCTION__));
1403 
1404             /* Toggle sleep to resync with host and device */
1405             err = bcmsdh_sleep(bus->sdh, TRUE);
1406             OSL_DELAY(0x2710);
1407             err = bcmsdh_sleep(bus->sdh, FALSE);
1408             if (err) {
1409                 OSL_DELAY(0x2710);
1410                 DHD_ERROR(("%s: CMD14 exit failed again!\n", __FUNCTION__));
1411 
1412                 /* Toggle sleep to resync with host and device */
1413                 err = bcmsdh_sleep(bus->sdh, TRUE);
1414                 OSL_DELAY(0x2710);
1415                 err = bcmsdh_sleep(bus->sdh, FALSE);
1416                 if (err) {
1417                     DHD_ERROR(("%s: CMD14 exit failed twice!\n", __FUNCTION__));
1418                     DHD_ERROR(
1419                         ("%s: FATAL: Device non-response!\n", __FUNCTION__));
1420                     err = 0;
1421                 }
1422             }
1423         }
1424 #else
1425         if (OOB_WAKEUP_ENAB(bus)) {
1426             err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP,
1427                                  TRUE); /* GPIO_1 is on */
1428         }
1429         do {
1430             err = dhdsdio_clk_kso_enab(bus, TRUE);
1431             if (err) {
1432                 OSL_SLEEP(0xA);
1433             }
1434         } while ((err != 0) && (++retry < 0x3));
1435 
1436         if (err != 0) {
1437             DHD_ERROR(("ERROR: kso set failed retry: %d\n", retry));
1438 #ifndef BT_OVER_SDIO
1439             err = 0; /* continue anyway */
1440 #endif /* BT_OVER_SDIO */
1441         }
1442 
1443         if ((SLPAUTO_ENAB(bus)) && (bus->idleclock == DHD_IDLE_STOP)) {
1444             dhdsdio_set_sdmode(bus, bus->sd_mode);
1445         }
1446 #endif /* !USE_CMD14 */
1447 
1448         if (err == 0) {
1449             uint8 csr;
1450 
1451             /* Wait for device ready during transition to wake-up */
1452             SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1453                            (((csr = dhdsdio_sleepcsr_get(bus)) &
1454                              SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK) !=
1455                             (SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)),
1456                            (0x4E20));
1457 
1458             DHD_TRACE(("%s: ExitSleep sleepcsr: 0x%x\n", __FUNCTION__, csr));
1459 
1460             if (!(csr & SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)) {
1461                 DHD_ERROR(("%s:ERROR: ExitSleep device NOT Ready! 0x%x\n",
1462                            __FUNCTION__, csr));
1463                 err = BCME_NODEVICE;
1464             }
1465 
1466             SPINWAIT_SLEEP(
1467                 sdioh_spinwait_sleep,
1468                 (((csr = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
1469                                          SBSDIO_FUNC1_CHIPCLKCSR, &err)) &
1470                   SBSDIO_HT_AVAIL) != (SBSDIO_HT_AVAIL)),
1471                 (DHD_WAIT_HTAVAIL));
1472 
1473             DHD_TRACE(
1474                 ("%s: SBSDIO_FUNC1_CHIPCLKCSR : 0x%x\n", __FUNCTION__, csr));
1475             if (!err && ((csr & SBSDIO_HT_AVAIL) != SBSDIO_HT_AVAIL)) {
1476                 DHD_ERROR(
1477                     ("%s:ERROR: device NOT Ready! 0x%x\n", __FUNCTION__, csr));
1478                 err = BCME_NODEVICE;
1479             }
1480         }
1481     }
1482 
1483     /* Update if successful */
1484     if (err == 0) {
1485         bus->kso = on ? FALSE : TRUE;
1486     } else {
1487         DHD_ERROR(("%s: Sleep request failed: kso:%d on:%d err:%d\n",
1488                    __FUNCTION__, bus->kso, on, err));
1489         if (!on && retry > 0x2) {
1490             bus->kso = FALSE;
1491         }
1492     }
1493 
1494     return err;
1495 }
1496 
1497 /* Turn backplane clock on or off */
dhdsdio_htclk(dhd_bus_t * bus,bool on,bool pendok)1498 static int dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok)
1499 {
1500 #define HT_AVAIL_ERROR_MAX 0xA
1501     static int ht_avail_error = 0;
1502     int err;
1503     uint8 clkctl, clkreq, devctl;
1504     bcmsdh_info_t *sdh;
1505 
1506     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1507 
1508     clkctl = 0;
1509     sdh = bus->sdh;
1510 
1511     if (!KSO_ENAB(bus)) {
1512         return BCME_OK;
1513     }
1514 
1515     if (SLPAUTO_ENAB(bus)) {
1516         bus->clkstate = (on ? CLK_AVAIL : CLK_SDONLY);
1517         return BCME_OK;
1518     }
1519 
1520     if (on) {
1521         /* Request HT Avail */
1522         clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
1523 
1524 #ifdef BCMSPI
1525         dhdsdio_wkwlan(bus, TRUE);
1526 #endif /* BCMSPI */
1527 
1528         bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq,
1529                          &err);
1530         if (err) {
1531             ht_avail_error++;
1532             if (ht_avail_error < HT_AVAIL_ERROR_MAX) {
1533                 DHD_ERROR(
1534                     ("%s: HT Avail request error: %d\n", __FUNCTION__, err));
1535             } else if (ht_avail_error == HT_AVAIL_ERROR_MAX) {
1536                 bus->dhd->hang_reason = HANG_REASON_HT_AVAIL_ERROR;
1537                 dhd_os_send_hang_message(bus->dhd);
1538             }
1539             return BCME_ERROR;
1540         } else {
1541             ht_avail_error = 0;
1542         }
1543 
1544         /* Check current status */
1545         clkctl =
1546             bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
1547         if (err) {
1548             DHD_ERROR(("%s: HT Avail read error: %d\n", __FUNCTION__, err));
1549             return BCME_ERROR;
1550         }
1551 
1552 #if !defined(OOB_INTR_ONLY)
1553         /* Go to pending and await interrupt if appropriate */
1554         if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
1555             /* Allow only clock-available interrupt */
1556             devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1557             if (err) {
1558                 DHD_ERROR(("%s: Devctl access error setting CA: %d\n",
1559                            __FUNCTION__, err));
1560                 return BCME_ERROR;
1561             }
1562 
1563             devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
1564             bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1565             DHD_INFO(("CLKCTL: set PENDING\n"));
1566             bus->clkstate = CLK_PENDING;
1567             return BCME_OK;
1568         } else
1569 #endif /* !defined (OOB_INTR_ONLY) */
1570         {
1571             if (bus->clkstate == CLK_PENDING) {
1572                 /* Cancel CA-only interrupt filter */
1573                 devctl =
1574                     bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1575                 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
1576                 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl,
1577                                  &err);
1578             }
1579         }
1580 #ifndef BCMSDIOLITE
1581         /* Otherwise, wait here (polling) for HT Avail */
1582         if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
1583             SPINWAIT_SLEEP(
1584                 sdioh_spinwait_sleep,
1585                 ((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1586                                            SBSDIO_FUNC1_CHIPCLKCSR, &err)),
1587                  !SBSDIO_CLKAV(clkctl, bus->alp_only)),
1588                 PMU_MAX_TRANSITION_DLY);
1589         }
1590         if (err) {
1591             DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
1592             return BCME_ERROR;
1593         }
1594         if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
1595             DHD_ERROR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n",
1596                        __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl));
1597             return BCME_ERROR;
1598         }
1599 #endif /* BCMSDIOLITE */
1600         /* Mark clock available */
1601         bus->clkstate = CLK_AVAIL;
1602         DHD_INFO(("CLKCTL: turned ON\n"));
1603 
1604 #if defined(DHD_DEBUG)
1605         if (bus->alp_only == TRUE) {
1606 #if !defined(BCMLXSDMMC)
1607             if (!SBSDIO_ALPONLY(clkctl)) {
1608                 DHD_ERROR(("%s: HT Clock, when ALP Only\n", __FUNCTION__));
1609             }
1610 #endif /* !defined(BCMLXSDMMC) */
1611         } else {
1612             if (SBSDIO_ALPONLY(clkctl)) {
1613                 DHD_ERROR(("%s: HT Clock should be on.\n", __FUNCTION__));
1614             }
1615         }
1616 #endif /* defined (DHD_DEBUG) */
1617 
1618         bus->activity = TRUE;
1619 #ifdef DHD_USE_IDLECOUNT
1620         bus->idlecount = 0;
1621 #endif /* DHD_USE_IDLECOUNT */
1622     } else {
1623         clkreq = 0;
1624 
1625         if (bus->clkstate == CLK_PENDING) {
1626             /* Cancel CA-only interrupt filter */
1627             devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1628             devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
1629             bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1630         }
1631 
1632         bus->clkstate = CLK_SDONLY;
1633         if (!SR_ENAB(bus)) {
1634             bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq,
1635                              &err);
1636             DHD_INFO(("CLKCTL: turned OFF\n"));
1637             if (err) {
1638                 DHD_ERROR(("%s: Failed access turning clock off: %d\n",
1639                            __FUNCTION__, err));
1640                 return BCME_ERROR;
1641             }
1642         }
1643 #ifdef BCMSPI
1644         dhdsdio_wkwlan(bus, FALSE);
1645 #endif /* BCMSPI */
1646     }
1647     return BCME_OK;
1648 }
1649 
1650 /* Change SD1/SD4 bus mode */
dhdsdio_set_sdmode(dhd_bus_t * bus,int32 sd_mode)1651 static int dhdsdio_set_sdmode(dhd_bus_t *bus, int32 sd_mode)
1652 {
1653     int err;
1654 
1655     err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0, &sd_mode,
1656                           sizeof(sd_mode), TRUE);
1657     if (err) {
1658         DHD_ERROR(("%s: error changing sd_mode: %d\n", __FUNCTION__, err));
1659         return BCME_ERROR;
1660     }
1661     return BCME_OK;
1662 }
1663 
1664 /* Change idle/active SD state */
dhdsdio_sdclk(dhd_bus_t * bus,bool on)1665 static int dhdsdio_sdclk(dhd_bus_t *bus, bool on)
1666 {
1667 #ifndef BCMSPI
1668     int err;
1669     int32 iovalue;
1670 
1671     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1672 
1673     if (on) {
1674         if (bus->idleclock == DHD_IDLE_STOP) {
1675             /* Turn on clock and restore mode */
1676             iovalue = 1;
1677             err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0, &iovalue,
1678                                   sizeof(iovalue), TRUE);
1679             if (err) {
1680                 DHD_ERROR(
1681                     ("%s: error enabling sd_clock: %d\n", __FUNCTION__, err));
1682                 return BCME_ERROR;
1683             }
1684         } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
1685             /* Restore clock speed */
1686             iovalue = bus->sd_divisor;
1687             err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, &iovalue,
1688                                   sizeof(iovalue), TRUE);
1689             if (err) {
1690                 DHD_ERROR(("%s: error restoring sd_divisor: %d\n", __FUNCTION__,
1691                            err));
1692                 return BCME_ERROR;
1693             }
1694         }
1695         bus->clkstate = CLK_SDONLY;
1696     } else {
1697         /* Stop or slow the SD clock itself */
1698         if ((bus->sd_divisor == -1) || (bus->sd_mode == -1)) {
1699             DHD_TRACE(("%s: can't idle clock, divisor %d mode %d\n",
1700                        __FUNCTION__, bus->sd_divisor, bus->sd_mode));
1701             return BCME_ERROR;
1702         }
1703         if (bus->idleclock == DHD_IDLE_STOP) {
1704             iovalue = 0;
1705             err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0, &iovalue,
1706                                   sizeof(iovalue), TRUE);
1707             if (err) {
1708                 DHD_ERROR(
1709                     ("%s: error disabling sd_clock: %d\n", __FUNCTION__, err));
1710                 return BCME_ERROR;
1711             }
1712         } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
1713             /* Set divisor to idle value */
1714             iovalue = bus->idleclock;
1715             err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, &iovalue,
1716                                   sizeof(iovalue), TRUE);
1717             if (err) {
1718                 DHD_ERROR(
1719                     ("%s: error changing sd_divisor: %d\n", __FUNCTION__, err));
1720                 return BCME_ERROR;
1721             }
1722         }
1723         bus->clkstate = CLK_NONE;
1724     }
1725 #endif /* BCMSPI */
1726 
1727     return BCME_OK;
1728 }
1729 
1730 /* Transition SD and backplane clock readiness */
dhdsdio_clkctl(dhd_bus_t * bus,uint target,bool pendok)1731 static int dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok)
1732 {
1733     int ret = BCME_OK;
1734 #ifdef DHD_DEBUG
1735     uint oldstate = bus->clkstate;
1736 #endif /* DHD_DEBUG */
1737 
1738     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1739 
1740     /* Early exit if we're already there */
1741     if (bus->clkstate == target) {
1742         if (target == CLK_AVAIL) {
1743             dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1744             bus->activity = TRUE;
1745 #ifdef DHD_USE_IDLECOUNT
1746             bus->idlecount = 0;
1747 #endif /* DHD_USE_IDLECOUNT */
1748         }
1749         return ret;
1750     }
1751 
1752     switch (target) {
1753         case CLK_AVAIL:
1754             /* Make sure SD clock is available */
1755             if (bus->clkstate == CLK_NONE) {
1756                 dhdsdio_sdclk(bus, TRUE);
1757             }
1758             /* Now request HT Avail on the backplane */
1759             ret = dhdsdio_htclk(bus, TRUE, pendok);
1760             if (ret == BCME_OK) {
1761                 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1762                 bus->activity = TRUE;
1763 #ifdef DHD_USE_IDLECOUNT
1764                 bus->idlecount = 0;
1765 #endif /* DHD_USE_IDLECOUNT */
1766             }
1767             break;
1768 
1769         case CLK_SDONLY:
1770 
1771 #ifdef BT_OVER_SDIO
1772             /*
1773              * If the request is to switch off Back plane clock,
1774              * confirm that BT is inactive before doing so.
1775              * If this call had come from Non Watchdog context any way
1776              * the Watchdog would switch off the clock again when
1777              * nothing is to be done & Bt has finished using the bus.
1778              */
1779             if (bus->bt_use_count != 0) {
1780                 DHD_INFO(("%s(): Req CLK_SDONLY, BT is active %d not switching "
1781                           "off \r\n",
1782                           __FUNCTION__, bus->bt_use_count));
1783                 ret = BCME_OK;
1784                 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1785                 break;
1786             }
1787 
1788             DHD_INFO(
1789                 ("%s(): Request CLK_NONE BT is NOT active switching off \r\n",
1790                  __FUNCTION__));
1791 #endif /* BT_OVER_SDIO */
1792 
1793             /* Remove HT request, or bring up SD clock */
1794             if (bus->clkstate == CLK_NONE) {
1795                 ret = dhdsdio_sdclk(bus, TRUE);
1796             } else if (bus->clkstate == CLK_AVAIL) {
1797                 ret = dhdsdio_htclk(bus, FALSE, FALSE);
1798             } else {
1799                 DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n",
1800                            bus->clkstate, target));
1801             }
1802             if (ret == BCME_OK) {
1803                 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1804             }
1805             break;
1806 
1807         case CLK_NONE:
1808 
1809 #ifdef BT_OVER_SDIO
1810             /*
1811              * If the request is to switch off Back plane clock,
1812              * confirm that BT is inactive before doing so.
1813              * If this call had come from Non Watchdog context any way
1814              * the Watchdog would switch off the clock again when
1815              * nothing is to be done & Bt has finished using the bus.
1816              */
1817             if (bus->bt_use_count != 0) {
1818                 DHD_INFO(("%s(): Request CLK_NONE BT is active %d not "
1819                           "switching off \r\n",
1820                           __FUNCTION__, bus->bt_use_count));
1821                 ret = BCME_OK;
1822                 break;
1823             }
1824 
1825             DHD_INFO(
1826                 ("%s(): Request CLK_NONE BT is NOT active switching off \r\n",
1827                  __FUNCTION__));
1828 #endif /* BT_OVER_SDIO */
1829 
1830             /* Make sure to remove HT request */
1831             if (bus->clkstate == CLK_AVAIL) {
1832                 ret = dhdsdio_htclk(bus, FALSE, FALSE);
1833             }
1834             /* Now remove the SD clock */
1835             ret = dhdsdio_sdclk(bus, FALSE);
1836 #ifdef DHD_DEBUG
1837             if (bus->dhd->dhd_console_ms == 0)
1838 #endif /* DHD_DEBUG */
1839                 if (bus->poll == 0) {
1840                     dhd_os_wd_timer(bus->dhd, 0);
1841                 }
1842             break;
1843     }
1844 #ifdef DHD_DEBUG
1845     DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate));
1846 #endif /* DHD_DEBUG */
1847 
1848     return ret;
1849 }
1850 
dhdsdio_bussleep(dhd_bus_t * bus,bool sleep)1851 static int dhdsdio_bussleep(dhd_bus_t *bus, bool sleep)
1852 {
1853     int err = 0;
1854     bcmsdh_info_t *sdh = bus->sdh;
1855     sdpcmd_regs_t *regs = bus->regs;
1856     uint retries = 0;
1857 #if defined(BCMSDIOH_STD)
1858     uint32 sd3_tuning_disable = FALSE;
1859 #endif /* BCMSDIOH_STD */
1860 
1861     DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n",
1862               (sleep ? "SLEEP" : "WAKE"), (bus->sleeping ? "SLEEP" : "WAKE")));
1863 
1864     if (bus->dhd->hang_was_sent) {
1865         return BCME_ERROR;
1866     }
1867 
1868     /* Done if we're already in the requested state */
1869     if (sleep == bus->sleeping) {
1870         return BCME_OK;
1871     }
1872 
1873     /* Going to sleep: set the alarm and turn off the lights... */
1874     if (sleep) {
1875         /* Don't sleep if something is pending */
1876 #ifdef DHD_USE_IDLECOUNT
1877         if (bus->dpc_sched || bus->rxskip || pktq_n_pkts_tot(&bus->txq) ||
1878             bus->readframes || bus->ctrl_frame_stat)
1879 #else
1880         if (bus->dpc_sched || bus->rxskip || pktq_n_pkts_tot(&bus->txq))
1881 #endif /* DHD_USE_IDLECOUNT */
1882             return BCME_BUSY;
1883 
1884 #ifdef BT_OVER_SDIO
1885         /*
1886          * The following is the assumption based on which the hook is placed.
1887          * From WLAN driver, either from the active contexts OR from the
1888          * Watchdog contexts we will be attempting to Go to Sleep. AT that
1889          * moment if we see that BT is still actively using the bus, we will
1890          * return BCME_BUSY from here, but the bus->sleeping state would not
1891          * have changed. So the caller can then schedule the Watchdog again
1892          * which will come and attempt to sleep at a later point.
1893          *
1894          * In case if BT is the only one and is the last user, we don't switch
1895          * off the clock immediately, we allow the WLAN to decide when to sleep
1896          * i.e from the watchdog. Now if the watchdog becomes active and
1897          * attempts to switch off the clock and if another WLAN context is
1898          * active they are any way serialized with sdlock.
1899          */
1900         if (bus->bt_use_count != 0) {
1901             DHD_INFO(("%s(): Cannot sleep BT is active \r\n", __FUNCTION__));
1902             return BCME_BUSY;
1903         }
1904 #endif /* !BT_OVER_SDIO */
1905 
1906         if (!SLPAUTO_ENAB(bus)) {
1907             /* Disable SDIO interrupts (no longer interested) */
1908             bcmsdh_intr_disable(bus->sdh);
1909 
1910             /* Make sure the controller has the bus up */
1911             dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1912 
1913             /* Tell device to start using OOB wakeup */
1914             W_SDREG(SMB_USE_OOB, &regs->tosbmailbox, retries);
1915             if (retries > retry_limit) {
1916                 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
1917             }
1918 
1919             /* Turn off our contribution to the HT clock request */
1920             dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1921 
1922             bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
1923                              SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
1924 
1925             /* Isolate the bus */
1926             bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
1927                              SBSDIO_DEVCTL_PADS_ISO, NULL);
1928         } else {
1929 #ifdef FORCE_SWOOB_ENABLE
1930             /* Tell device to start using OOB wakeup */
1931             W_SDREG(SMB_USE_OOB, &regs->tosbmailbox, retries);
1932             if (retries > retry_limit) {
1933                 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
1934             }
1935 #endif
1936             /* Leave interrupts enabled since device can exit sleep and
1937              * interrupt host
1938              */
1939             err = dhdsdio_clk_devsleep_iovar(bus, TRUE /* sleep */);
1940         }
1941 
1942         /* Change state */
1943         bus->sleeping = TRUE;
1944 #if defined(BCMSDIOH_STD)
1945         sd3_tuning_disable = TRUE;
1946         err = bcmsdh_iovar_op(bus->sdh, "sd3_tuning_disable", NULL, 0,
1947                               &sd3_tuning_disable, sizeof(sd3_tuning_disable),
1948                               TRUE);
1949 #endif /* BCMSDIOH_STD */
1950 #if defined(SUPPORT_P2P_GO_PS)
1951         wake_up(&bus->bus_sleep);
1952 #endif /* LINUX && SUPPORT_P2P_GO_PS */
1953     } else {
1954         /* Waking up: bus power up is ok, set local state */
1955 
1956         if (!SLPAUTO_ENAB(bus)) {
1957             bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0,
1958                              &err);
1959 
1960             /* Force pad isolation off if possible (in case power never toggled)
1961              */
1962             bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL);
1963 
1964             /* Make sure the controller has the bus up */
1965             dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1966 
1967             /* Send misc interrupt to indicate OOB not needed */
1968             W_SDREG(0, &regs->tosbmailboxdata, retries);
1969             if (retries <= retry_limit) {
1970                 W_SDREG(SMB_DEV_INT, &regs->tosbmailbox, retries);
1971             }
1972 
1973             if (retries > retry_limit) {
1974                 DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
1975             }
1976 
1977             /* Make sure we have SD bus access */
1978             dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1979 
1980             /* Enable interrupts again */
1981             if (bus->intr && (bus->dhd->busstate == DHD_BUS_DATA)) {
1982                 bus->intdis = FALSE;
1983                 bcmsdh_intr_enable(bus->sdh);
1984             }
1985         } else {
1986             err = dhdsdio_clk_devsleep_iovar(bus, FALSE /* wake */);
1987 #ifdef FORCE_SWOOB_ENABLE
1988             /* Send misc interrupt to indicate OOB not needed */
1989             W_SDREG(0, &regs->tosbmailboxdata, retries);
1990             if (retries <= retry_limit) {
1991                 W_SDREG(SMB_DEV_INT, &regs->tosbmailbox, retries);
1992             }
1993 #endif
1994 #ifdef BT_OVER_SDIO
1995             if (err < 0) {
1996                 struct net_device *net = NULL;
1997                 dhd_pub_t *dhd = bus->dhd;
1998                 net = dhd_idx2net(dhd, 0);
1999                 if (net != NULL) {
2000                     DHD_ERROR(("<< WIFI HANG by KSO Enabled failure\n"));
2001                     dhd_os_sdunlock(dhd);
2002                     net_os_send_hang_message(net);
2003                     dhd_os_sdlock(dhd);
2004                 } else {
2005                     DHD_ERROR(("<< WIFI HANG Fail because net is NULL\n"));
2006                 }
2007             }
2008 #endif /* BT_OVER_SDIO */
2009         }
2010 
2011         if (err == 0) {
2012             /* Change state */
2013             bus->sleeping = FALSE;
2014 #if defined(BCMSDIOH_STD)
2015             sd3_tuning_disable = FALSE;
2016             err = bcmsdh_iovar_op(bus->sdh, "sd3_tuning_disable", NULL, 0,
2017                                   &sd3_tuning_disable,
2018                                   sizeof(sd3_tuning_disable), TRUE);
2019 #endif /* BCMSDIOH_STD */
2020         }
2021     }
2022 
2023     return err;
2024 }
2025 
2026 #ifdef BT_OVER_SDIO
2027 /*
2028  * Call this function to Get the Clock running.
2029  * Assumes that the caller holds the sdlock.
2030  * bus - Pointer to the dhd_bus handle
2031  * can_wait - TRUE if the caller can wait until the clock becomes ready
2032  *            FALSE if the caller cannot wait
2033  */
__dhdsdio_clk_enable(struct dhd_bus * bus,bus_owner_t owner,int can_wait)2034 int __dhdsdio_clk_enable(struct dhd_bus *bus, bus_owner_t owner, int can_wait)
2035 {
2036     int ret = BCME_ERROR;
2037 
2038     BCM_REFERENCE(owner);
2039 
2040     bus->bt_use_count++;
2041 
2042     /*
2043      * We can call BUS_WAKE, clkctl multiple times, both of the items
2044      * have states and if its already ON, no new configuration is done
2045      */
2046 
2047     /* Wake up the Dongle FW from SR */
2048     BUS_WAKE(bus);
2049 
2050     /*
2051      * Make sure back plane ht clk is on
2052      * CLK_AVAIL - Turn On both SD & HT clock
2053      */
2054     ret = dhdsdio_clkctl(bus, CLK_AVAIL, can_wait);
2055 
2056     DHD_INFO(("%s():bt_use_count %d \r\n", __FUNCTION__, bus->bt_use_count));
2057     return ret;
2058 }
2059 
2060 /*
2061  * Call this function to relinquish the Clock.
2062  * Assumes that the caller holds the sdlock.
2063  * bus - Pointer to the dhd_bus handle
2064  * can_wait - TRUE if the caller can wait until the clock becomes ready
2065  *            FALSE if the caller cannot wait
2066  */
__dhdsdio_clk_disable(struct dhd_bus * bus,bus_owner_t owner,int can_wait)2067 int __dhdsdio_clk_disable(struct dhd_bus *bus, bus_owner_t owner, int can_wait)
2068 {
2069     int ret = BCME_ERROR;
2070 
2071     BCM_REFERENCE(owner);
2072     BCM_REFERENCE(can_wait);
2073 
2074     if (bus->bt_use_count == 0) {
2075         DHD_ERROR(("%s(): Clocks are already turned off \r\n", __FUNCTION__));
2076         return ret;
2077     }
2078 
2079     bus->bt_use_count--;
2080 
2081     /*
2082      * When the SDIO Bus is shared between BT & WLAN, we turn Off the clock
2083      * once the last user has relinqushed the same. But there are two schemes
2084      * in that too. We consider WLAN as the  bus master (even if its not
2085      * active). Even when the WLAN is OFF the DHD Watchdog is active.
2086      * So this Bus Watchdog is the context whill put the Bus to sleep.
2087      * Refer dhd_bus_watchdog function
2088      */
2089 
2090     ret = BCME_OK;
2091     DHD_INFO(("%s():bt_use_count %d \r\n", __FUNCTION__, bus->bt_use_count));
2092     return ret;
2093 }
2094 
dhdsdio_reset_bt_use_count(struct dhd_bus * bus)2095 void dhdsdio_reset_bt_use_count(struct dhd_bus *bus)
2096 {
2097     /* reset bt use count */
2098     bus->bt_use_count = 0;
2099 }
2100 #endif /* BT_OVER_SDIO */
2101 
2102 #ifdef USE_DYNAMIC_F2_BLKSIZE
dhdsdio_func_blocksize(dhd_pub_t * dhd,int function_num,int block_size)2103 int dhdsdio_func_blocksize(dhd_pub_t *dhd, int function_num, int block_size)
2104 {
2105     int func_blk_size = function_num;
2106     int bcmerr = 0;
2107     int result;
2108 
2109     bcmerr = dhd_bus_iovar_op(dhd, "sd_blocksize", &func_blk_size, sizeof(int),
2110                               &result, sizeof(int), IOV_GET);
2111     if (bcmerr != BCME_OK) {
2112         DHD_ERROR(
2113             ("%s: Get F%d Block size error\n", __FUNCTION__, function_num));
2114         return BCME_ERROR;
2115     }
2116 
2117     if (result != block_size) {
2118         DHD_ERROR(("%s: F%d Block size set from %d to %d\n", __FUNCTION__,
2119                    function_num, result, block_size));
2120         func_blk_size = function_num << 0x10 | block_size;
2121         bcmerr = dhd_bus_iovar_op(dhd, "sd_blocksize", NULL, 0, &func_blk_size,
2122                                   sizeof(int32), IOV_SET);
2123         if (bcmerr != BCME_OK) {
2124             DHD_ERROR(
2125                 ("%s: Set F%d Block size error\n", __FUNCTION__, function_num));
2126             return BCME_ERROR;
2127         }
2128     }
2129 
2130     return BCME_OK;
2131 }
2132 #endif /* USE_DYNAMIC_F2_BLKSIZE */
2133 
2134 #if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) || defined(FORCE_WOWLAN)
dhd_enable_oob_intr(struct dhd_bus * bus,bool enable)2135 void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable)
2136 {
2137 #if defined(BCMSPI_ANDROID)
2138     bcmsdh_intr_enable(bus->sdh);
2139 #elif defined(HW_OOB) || defined(FORCE_WOWLAN)
2140     bcmsdh_enable_hw_oob_intr(bus->sdh, enable);
2141 #else
2142     sdpcmd_regs_t *regs = bus->regs;
2143     uint retries = 0;
2144 
2145     dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
2146     if (enable == TRUE) {
2147         /* Tell device to start using OOB wakeup */
2148         W_SDREG(SMB_USE_OOB, &regs->tosbmailbox, retries);
2149         if (retries > retry_limit) {
2150             DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
2151         }
2152     } else {
2153         /* Send misc interrupt to indicate OOB not needed */
2154         W_SDREG(0, &regs->tosbmailboxdata, retries);
2155         if (retries <= retry_limit) {
2156             W_SDREG(SMB_DEV_INT, &regs->tosbmailbox, retries);
2157         }
2158     }
2159 
2160     /* Turn off our contribution to the HT clock request */
2161     dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
2162 #endif /* !defined(HW_OOB) */
2163 }
2164 #endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
2165 
dhd_bus_txdata(struct dhd_bus * bus,void * pkt)2166 int dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
2167 {
2168     int ret = BCME_ERROR;
2169     osl_t *osh;
2170     uint datalen, prec;
2171 
2172     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2173 
2174     osh = bus->dhd->osh;
2175     datalen = PKTLEN(osh, pkt);
2176 
2177 #ifdef SDTEST
2178     /* Push the test header if doing loopback */
2179     if (bus->ext_loop) {
2180         uint8 *data;
2181         PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN);
2182         data = PKTDATA(osh, pkt);
2183         *data++ = SDPCM_TEST_ECHOREQ;
2184         *data++ = (uint8)bus->loopid++;
2185         *data++ = (datalen >> 0);
2186         *data++ = (datalen >> 0x8);
2187         datalen += SDPCM_TEST_HDRLEN;
2188     }
2189 #else  /* SDTEST */
2190     BCM_REFERENCE(datalen);
2191 #endif /* SDTEST */
2192 
2193 #ifdef DHD_ULP
2194     dhd_ulp_set_path(bus->dhd, DHD_ULP_TX_DATA);
2195 #endif /* DHD_ULP */
2196 
2197     prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK));
2198 
2199     /* move from dhdsdio_sendfromq(), try to orphan skb early */
2200     if (bus->dhd->conf->orphan_move == 1) {
2201         PKTORPHAN(pkt, bus->dhd->conf->tsq);
2202     }
2203 
2204     /* Check for existing queue, current flow-control, pending event, or pending
2205      * clock */
2206     if (dhd_deferred_tx || bus->fcstate || pktq_n_pkts_tot(&bus->txq) ||
2207         bus->dpc_sched || (!DATAOK(bus)) ||
2208         (bus->flowcontrol & NBITVAL(prec)) || (bus->clkstate != CLK_AVAIL)) {
2209         bool deq_ret;
2210         int pkq_len = 0;
2211 
2212         DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__,
2213                    pktq_n_pkts_tot(&bus->txq)));
2214         bus->fcqueued++;
2215 
2216         /* Priority based enq */
2217         dhd_os_sdlock_txq(bus->dhd);
2218         deq_ret = dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec);
2219         dhd_os_sdunlock_txq(bus->dhd);
2220 
2221         if (!deq_ret) {
2222 #ifdef PROP_TXSTATUS
2223             if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt)) == 0)
2224 #endif /* PROP_TXSTATUS */
2225             {
2226 #ifdef DHDTCPACK_SUPPRESS
2227                 if (dhd_tcpack_check_xmit(bus->dhd, pkt) == BCME_ERROR) {
2228                     DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using\n",
2229                                __FUNCTION__, __LINE__));
2230                     dhd_tcpack_suppress_set(bus->dhd, TCPACK_SUP_OFF);
2231                 }
2232 #endif /* DHDTCPACK_SUPPRESS */
2233                 dhd_txcomplete(bus->dhd, pkt, FALSE);
2234                 PKTFREE(osh, pkt, TRUE);
2235             }
2236             ret = BCME_NORESOURCE;
2237         } else {
2238             ret = BCME_OK;
2239         }
2240 
2241         if (dhd_doflow) {
2242             dhd_os_sdlock_txq(bus->dhd);
2243             pkq_len = pktq_n_pkts_tot(&bus->txq);
2244             dhd_os_sdunlock_txq(bus->dhd);
2245         }
2246         if (dhd_doflow && pkq_len >= FCHI) {
2247             bool wlfc_enabled = FALSE;
2248 #ifdef PROP_TXSTATUS
2249             wlfc_enabled =
2250                 (dhd_wlfc_flowcontrol(bus->dhd, ON, FALSE) != WLFC_UNSUPPORTED);
2251 #endif // endif
2252             if (!wlfc_enabled && dhd_doflow) {
2253                 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
2254             }
2255         }
2256 
2257 #ifdef DHD_DEBUG
2258         dhd_os_sdlock_txq(bus->dhd);
2259         if (pktqprec_n_pkts(&bus->txq, prec) > qcount[prec]) {
2260             qcount[prec] = pktqprec_n_pkts(&bus->txq, prec);
2261         }
2262         dhd_os_sdunlock_txq(bus->dhd);
2263 #endif // endif
2264 
2265         /* Schedule DPC if needed to send queued packet(s) */
2266         if (dhd_deferred_tx && !bus->dpc_sched) {
2267             if (bus->dhd->conf->deferred_tx_len) {
2268                 if (dhd_os_wd_timer_enabled(bus->dhd) == FALSE) {
2269                     bus->dpc_sched = TRUE;
2270                     dhd_sched_dpc(bus->dhd);
2271                 }
2272                 if (pktq_n_pkts_tot(&bus->txq) >=
2273                         bus->dhd->conf->deferred_tx_len &&
2274                     dhd_os_wd_timer_enabled(bus->dhd) == FALSE) {
2275                     bus->dpc_sched = TRUE;
2276                     dhd_sched_dpc(bus->dhd);
2277                 }
2278             } else {
2279                 bus->dpc_sched = TRUE;
2280                 dhd_sched_dpc(bus->dhd);
2281             }
2282         }
2283     } else {
2284         int chan = SDPCM_DATA_CHANNEL;
2285 
2286 #ifdef SDTEST
2287         chan = (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL);
2288 #endif // endif
2289         /* Lock: we're about to use shared data/code (and SDIO) */
2290         dhd_os_sdlock(bus->dhd);
2291 
2292         /* Otherwise, send it now */
2293         BUS_WAKE(bus);
2294         /* Make sure back plane ht clk is on, no pending allowed */
2295         dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
2296 
2297         ret = dhdsdio_txpkt(bus, chan, &pkt, 1, TRUE);
2298         if (ret != BCME_OK) {
2299             bus->dhd->tx_errors++;
2300         } else {
2301             bus->dhd->dstats.tx_bytes += datalen;
2302         }
2303         if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched &&
2304             NO_OTHER_ACTIVE_BUS_USER(bus)) {
2305             bus->activity = FALSE;
2306             dhdsdio_bussleep(bus, TRUE);
2307             dhdsdio_clkctl(bus, CLK_NONE, FALSE);
2308         }
2309 
2310         dhd_os_sdunlock(bus->dhd);
2311     }
2312 
2313     return ret;
2314 }
2315 
2316 /* align packet data pointer and packet length to n-byte boundary, process
2317  * packet headers, a new packet may be allocated if there is not enough head
2318  * and/or tail from for padding. the caller is responsible for updating the glom
2319  * size in the head packet (when glom is used)
2320  *
2321  * pad_pkt_len: returns the length of extra padding needed from the padding
2322  * packet, this parameter is taken in tx glom mode only
2323  *
2324  * new_pkt: out, pointer of the new packet allocated due to insufficient head
2325  * room for alignment padding, NULL if not needed, the caller is responsible for
2326  * freeing the new packet
2327  *
2328  * return: positive value - length of the packet, including head and tail
2329  * padding negative value - errors
2330  */
dhdsdio_txpkt_preprocess(dhd_bus_t * bus,void * pkt,int chan,int txseq,int prev_chain_total_len,bool last_chained_pkt,int * pad_pkt_len,void ** new_pkt,int first_frame)2331 static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan,
2332                                     int txseq, int prev_chain_total_len,
2333                                     bool last_chained_pkt, int *pad_pkt_len,
2334                                     void **new_pkt
2335 #if defined(BCMSDIOH_TXGLOM_EXT)
2336                                     ,
2337                                     int first_frame
2338 #endif
2339 )
2340 {
2341     osl_t *osh;
2342     uint8 *frame;
2343     int pkt_len;
2344     int modulo;
2345     int head_padding;
2346     int tail_padding = 0;
2347     uint32 swheader;
2348     uint32 swhdr_offset;
2349     bool alloc_new_pkt = FALSE;
2350     uint8 sdpcm_hdrlen =
2351         bus->txglom_enable ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN;
2352 #ifdef PKT_STATICS
2353     uint16 len;
2354 #endif
2355 
2356     *new_pkt = NULL;
2357     osh = bus->dhd->osh;
2358 
2359 #ifdef DHDTCPACK_SUPPRESS
2360     if (dhd_tcpack_check_xmit(bus->dhd, pkt) == BCME_ERROR) {
2361         DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n",
2362                    __FUNCTION__, __LINE__));
2363         dhd_tcpack_suppress_set(bus->dhd, TCPACK_SUP_OFF);
2364     }
2365 #endif /* DHDTCPACK_SUPPRESS */
2366 
2367     /* Add space for the SDPCM hardware/software headers */
2368     PKTPUSH(osh, pkt, sdpcm_hdrlen);
2369     ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 0x2));
2370 
2371     frame = (uint8 *)PKTDATA(osh, pkt);
2372     pkt_len = (uint16)PKTLEN(osh, pkt);
2373 
2374 #ifdef PKT_STATICS
2375     len = (uint16)PKTLEN(osh, pkt);
2376     switch (chan) {
2377         case SDPCM_CONTROL_CHANNEL:
2378             bus->tx_statics.ctrl_count++;
2379             bus->tx_statics.ctrl_size += len;
2380             break;
2381         case SDPCM_DATA_CHANNEL:
2382             bus->tx_statics.data_count++;
2383             bus->tx_statics.data_size += len;
2384             break;
2385         case SDPCM_GLOM_CHANNEL:
2386             bus->tx_statics.glom_count++;
2387             bus->tx_statics.glom_size += len;
2388             break;
2389         case SDPCM_EVENT_CHANNEL:
2390             bus->tx_statics.event_count++;
2391             bus->tx_statics.event_size += len;
2392             break;
2393         case SDPCM_TEST_CHANNEL:
2394             bus->tx_statics.test_count++;
2395             bus->tx_statics.test_size += len;
2396             break;
2397 
2398         default:
2399             break;
2400     }
2401 #endif /* PKT_STATICS */
2402 #ifdef DHD_DEBUG
2403     if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets)) {
2404         tx_packets[PKTPRIO(pkt)]++;
2405     }
2406 #endif /* DHD_DEBUG */
2407 
2408     /* align the data pointer, allocate a new packet if there is not enough
2409      * space (new packet data pointer will be aligned thus no padding will be
2410      * needed)
2411      */
2412     head_padding = (uintptr)frame % DHD_SDALIGN;
2413     if (PKTHEADROOM(osh, pkt) < head_padding) {
2414         head_padding = 0;
2415         alloc_new_pkt = TRUE;
2416     } else {
2417         uint cur_chain_total_len;
2418         int chain_tail_padding = 0;
2419 
2420         /* All packets need to be aligned by DHD_SDALIGN */
2421         modulo = (pkt_len + head_padding) % DHD_SDALIGN;
2422         tail_padding = modulo > 0 ? (DHD_SDALIGN - modulo) : 0;
2423 
2424         /* Total pkt chain length needs to be aligned by block size,
2425          * unless it is a single pkt chain with total length less than one block
2426          * size, which we prefer sending by byte mode.
2427          *
2428          * Do the chain alignment here if
2429          * 1. This is the last pkt of the chain of multiple pkts or a single
2430          * pkt. 2-1. This chain is of multiple pkts, or 2-2. This is a single
2431          * pkt whose size is longer than one block size.
2432          */
2433         cur_chain_total_len =
2434             prev_chain_total_len + (head_padding + pkt_len + tail_padding);
2435         if (last_chained_pkt && bus->blocksize != 0 &&
2436             (cur_chain_total_len > (int)bus->blocksize ||
2437              prev_chain_total_len > 0)) {
2438             modulo = cur_chain_total_len % bus->blocksize;
2439             chain_tail_padding = modulo > 0 ? (bus->blocksize - modulo) : 0;
2440         }
2441 
2442 #ifdef DHDENABLE_TAILPAD
2443         if (PKTTAILROOM(osh, pkt) < tail_padding) {
2444             /* We don't have tail room to align by DHD_SDALIGN */
2445             alloc_new_pkt = TRUE;
2446             bus->tx_tailpad_pktget++;
2447         } else if (PKTTAILROOM(osh, pkt) < tail_padding + chain_tail_padding) {
2448             /* We have tail room for tail_padding of this pkt itself, but not
2449              * for total pkt chain alignment by block size. Use the padding
2450              * packet to avoid memory copy if applicable, otherwise, just
2451              * allocate a new pkt.
2452              */
2453             if (bus->pad_pkt) {
2454                 *pad_pkt_len = chain_tail_padding;
2455                 bus->tx_tailpad_chain++;
2456             } else {
2457                 alloc_new_pkt = TRUE;
2458                 bus->tx_tailpad_pktget++;
2459             }
2460         } else
2461         /* This last pkt's tailroom is sufficient to hold both tail_padding
2462          * of the pkt itself and chain_tail_padding of total pkt chain
2463          */
2464 #endif /* DHDENABLE_TAILPAD */
2465             tail_padding += chain_tail_padding;
2466     }
2467 
2468     DHD_INFO(
2469         ("%s sdhdr len + orig_pkt_len %d h_pad %d t_pad %d pad_pkt_len %d\n",
2470          __FUNCTION__, pkt_len, head_padding, tail_padding, *pad_pkt_len));
2471 
2472     if (alloc_new_pkt) {
2473         void *tmp_pkt;
2474         int newpkt_size;
2475         int cur_total_len;
2476 
2477         ASSERT(*pad_pkt_len == 0);
2478 
2479         DHD_INFO(("%s allocating new packet for padding\n", __FUNCTION__));
2480 
2481         /* head pointer is aligned now, no padding needed */
2482         head_padding = 0;
2483 
2484         /* update the tail padding as it depends on the head padding, since a
2485          * new packet is allocated, the head padding is non longer needed and
2486          * packet length is chagned
2487          */
2488 
2489         cur_total_len = prev_chain_total_len + pkt_len;
2490         if (last_chained_pkt && bus->blocksize != 0 &&
2491             (cur_total_len > (int)bus->blocksize || prev_chain_total_len > 0)) {
2492             modulo = cur_total_len % bus->blocksize;
2493             tail_padding = modulo > 0 ? (bus->blocksize - modulo) : 0;
2494         } else {
2495             modulo = pkt_len % DHD_SDALIGN;
2496             tail_padding = modulo > 0 ? (DHD_SDALIGN - modulo) : 0;
2497         }
2498 
2499         newpkt_size = PKTLEN(osh, pkt) + bus->blocksize + DHD_SDALIGN;
2500         bus->dhd->tx_realloc++;
2501         tmp_pkt = PKTGET(osh, newpkt_size, TRUE);
2502         if (tmp_pkt == NULL) {
2503             DHD_ERROR(("failed to alloc new %d byte packet\n", newpkt_size));
2504             return BCME_NOMEM;
2505         }
2506         PKTALIGN(osh, tmp_pkt, PKTLEN(osh, pkt), DHD_SDALIGN);
2507         bcopy(PKTDATA(osh, pkt), PKTDATA(osh, tmp_pkt), PKTLEN(osh, pkt));
2508         *new_pkt = tmp_pkt;
2509         pkt = tmp_pkt;
2510     }
2511 
2512     if (head_padding) {
2513         PKTPUSH(osh, pkt, head_padding);
2514     }
2515 
2516     frame = (uint8 *)PKTDATA(osh, pkt);
2517     bzero(frame, head_padding + sdpcm_hdrlen);
2518     pkt_len = (uint16)PKTLEN(osh, pkt);
2519 
2520     /* the header has the followming format
2521      * 4-byte HW frame tag: length, ~length (for glom this is the total length)
2522      *
2523      * 8-byte HW extesion flags (glom mode only) as the following:
2524      *			2-byte packet length, excluding HW tag and padding
2525      *			2-byte frame channel and frame flags (e.g. next frame following)
2526      *			2-byte header length
2527      *			2-byte tail padding size
2528      *
2529      * 8-byte SW frame tags as the following
2530      *			4-byte flags: host tx seq, channel, data offset
2531      */
2532 
2533     swhdr_offset = SDPCM_FRAMETAG_LEN;
2534 
2535     /* hardware frame tag:
2536      *
2537      * in tx-glom mode, dongle only checks the hardware frame tag in the first
2538      * packet and sees it as the total lenght of the glom (including tail
2539      * padding), for each packet in the glom, the packet length needs to be
2540      * updated, (see below PKTSETLEN)
2541      *
2542      * in non tx-glom mode, PKTLEN still need to include tail padding as to be
2543      * referred to in sdioh_request_buffer(). The tail length will be excluded
2544      * in dhdsdio_txpkt_postprocess().
2545      */
2546 #if defined(BCMSDIOH_TXGLOM_EXT)
2547     if (bus->dhd->conf->txglom_bucket_size) {
2548         tail_padding = 0;
2549     }
2550 #endif
2551     *(uint16 *)frame = (uint16)htol16(pkt_len);
2552     *(((uint16 *)frame) + 1) = (uint16)htol16(~pkt_len);
2553     pkt_len += tail_padding;
2554 
2555     /* hardware extesion flags */
2556     if (bus->txglom_enable) {
2557         uint32 hwheader1;
2558         uint32 hwheader2;
2559 #ifdef BCMSDIOH_TXGLOM_EXT
2560         uint32 act_len = pkt_len - tail_padding;
2561         uint32 real_pad = 0;
2562         if (bus->dhd->conf->txglom_ext && !last_chained_pkt) {
2563             tail_padding = 0;
2564             if (first_frame == 0) {
2565                 // first pkt, add pad to bucket size - recv offset
2566                 pkt_len =
2567                     bus->dhd->conf->txglom_bucket_size - TXGLOM_RECV_OFFSET;
2568             } else {
2569                 // add pad to bucket size
2570                 pkt_len = bus->dhd->conf->txglom_bucket_size;
2571             }
2572             swhdr_offset += SDPCM_HWEXT_LEN;
2573             hwheader1 =
2574                 (act_len - SDPCM_FRAMETAG_LEN) | (last_chained_pkt << 0x18);
2575             hwheader2 = (pkt_len - act_len) << 0x10;
2576             htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
2577             htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 0x4);
2578             real_pad = pkt_len - act_len;
2579 
2580             if (PKTTAILROOM(osh, pkt) < real_pad) {
2581                 DHD_INFO(("%s : insufficient tailroom %d for %d real_pad\n",
2582                           __func__, (int)PKTTAILROOM(osh, pkt), real_pad));
2583                 if (PKTPADTAILROOM(osh, pkt, real_pad)) {
2584                     DHD_ERROR(("CHK1: padding error size %d\n", real_pad));
2585                 } else {
2586                     frame = (uint8 *)PKTDATA(osh, pkt);
2587                 }
2588             }
2589         } else
2590 #endif
2591         {
2592             swhdr_offset += SDPCM_HWEXT_LEN;
2593             hwheader1 = (pkt_len - SDPCM_FRAMETAG_LEN - tail_padding) |
2594                         (last_chained_pkt << 0x18);
2595             hwheader2 = (tail_padding) << 0x10;
2596             htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
2597             htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 0x4);
2598         }
2599     }
2600     PKTSETLEN((osh), (pkt), (pkt_len));
2601 
2602     /* software frame tags */
2603     swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) |
2604                (txseq % SDPCM_SEQUENCE_WRAP) |
2605                (((head_padding + sdpcm_hdrlen) << SDPCM_DOFFSET_SHIFT) &
2606                 SDPCM_DOFFSET_MASK);
2607     htol32_ua_store(swheader, frame + swhdr_offset);
2608     htol32_ua_store(0, frame + swhdr_offset + sizeof(swheader));
2609 
2610     return pkt_len;
2611 }
2612 
dhdsdio_txpkt_postprocess(dhd_bus_t * bus,void * pkt)2613 static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt)
2614 {
2615     osl_t *osh;
2616     uint8 *frame;
2617     int data_offset;
2618     int tail_padding;
2619     int swhdr_offset =
2620         SDPCM_FRAMETAG_LEN + (bus->txglom_enable ? SDPCM_HWEXT_LEN : 0);
2621 
2622     (void)osh;
2623     osh = bus->dhd->osh;
2624 
2625     /* restore pkt buffer pointer, but keeps the header pushed by
2626      * dhd_prot_hdrpush */
2627     frame = (uint8 *)PKTDATA(osh, pkt);
2628 
2629     DHD_INFO(
2630         ("%s PKTLEN before postprocess %d", __FUNCTION__, PKTLEN(osh, pkt)));
2631 
2632     /* PKTLEN still includes tail_padding, so exclude it.
2633      * We shall have head_padding + original pkt_len for PKTLEN afterwards.
2634      */
2635     if (bus->txglom_enable) {
2636         /* txglom pkts have tail_padding length in HW ext header */
2637         tail_padding = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + 0x4) >> 0x10;
2638         PKTSETLEN(osh, pkt, PKTLEN(osh, pkt) - tail_padding);
2639         DHD_INFO((" txglom pkt: tail_padding %d PKTLEN %d\n", tail_padding,
2640                   PKTLEN(osh, pkt)));
2641     } else {
2642         /* non-txglom pkts have head_padding + original pkt length in HW frame
2643          * tag. We cannot refer to this field for txglom pkts as the first pkt
2644          * of the chain will have the field for the total length of the chain.
2645          */
2646         PKTSETLEN(osh, pkt, *(uint16 *)frame);
2647         DHD_INFO((" non-txglom pkt: HW frame tag len %d after PKTLEN %d\n",
2648                   *(uint16 *)frame, PKTLEN(osh, pkt)));
2649     }
2650 
2651     data_offset = ltoh32_ua(frame + swhdr_offset);
2652     data_offset = (data_offset & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT;
2653     /* Get rid of sdpcm header + head_padding */
2654     PKTPULL(osh, pkt, data_offset);
2655 
2656     DHD_INFO(("%s data_offset %d, PKTLEN %d\n", __FUNCTION__, data_offset,
2657               PKTLEN(osh, pkt)));
2658 
2659     return BCME_OK;
2660 }
2661 
dhdsdio_txpkt(dhd_bus_t * bus,uint chan,void ** pkts,int num_pkt,bool free_pkt)2662 static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void **pkts, int num_pkt,
2663                          bool free_pkt)
2664 {
2665     int i;
2666     int ret = 0;
2667     osl_t *osh;
2668     bcmsdh_info_t *sdh;
2669     void *pkt = NULL;
2670     void *pkt_chain;
2671     int total_len = 0;
2672     void *head_pkt = NULL;
2673     void *prev_pkt = NULL;
2674     int pad_pkt_len = 0;
2675     int new_pkt_num = 0;
2676     void *new_pkts[MAX_TX_PKTCHAIN_CNT];
2677     bool wlfc_enabled = FALSE;
2678 
2679     if (bus->dhd->dongle_reset) {
2680         return BCME_NOTREADY;
2681     }
2682 
2683     if (num_pkt <= 0) {
2684         return BCME_BADARG;
2685     }
2686 
2687     sdh = bus->sdh;
2688     osh = bus->dhd->osh;
2689     /* init new_pkts[0] to make some compiler happy, not necessary as we check
2690      * new_pkt_num */
2691     new_pkts[0] = NULL;
2692 
2693     for (i = 0; i < num_pkt; i++) {
2694         int pkt_len;
2695         bool last_pkt;
2696         void *new_pkt = NULL;
2697 
2698         pkt = pkts[i];
2699         ASSERT(pkt);
2700         last_pkt = (i == num_pkt - 1);
2701         pkt_len =
2702             dhdsdio_txpkt_preprocess(bus, pkt, chan, bus->tx_seq + i, total_len,
2703                                      last_pkt, &pad_pkt_len, &new_pkt
2704 #if defined(BCMSDIOH_TXGLOM_EXT)
2705                                      ,
2706                                      i
2707 #endif
2708             );
2709         if (pkt_len <= 0) {
2710             goto done;
2711         }
2712         if (new_pkt) {
2713             pkt = new_pkt;
2714             new_pkts[new_pkt_num++] = new_pkt;
2715         }
2716         total_len += pkt_len;
2717 
2718         PKTSETNEXT(osh, pkt, NULL);
2719         /* insert the packet into the list */
2720         head_pkt ? PKTSETNEXT(osh, prev_pkt, pkt) : (head_pkt = pkt);
2721         prev_pkt = pkt;
2722     }
2723 
2724     /* Update the HW frame tag (total length) in the first pkt of the glom */
2725     if (bus->txglom_enable) {
2726         uint8 *frame;
2727 
2728         total_len += pad_pkt_len;
2729         frame = (uint8 *)PKTDATA(osh, head_pkt);
2730         *(uint16 *)frame = (uint16)htol16(total_len);
2731         *(((uint16 *)frame) + 1) = (uint16)htol16(~total_len);
2732     }
2733 
2734 #ifdef DHDENABLE_TAILPAD
2735     /* if a padding packet if needed, insert it to the end of the link list */
2736     if (pad_pkt_len) {
2737         PKTSETLEN(osh, bus->pad_pkt, pad_pkt_len);
2738         PKTSETNEXT(osh, pkt, bus->pad_pkt);
2739     }
2740 #endif /* DHDENABLE_TAILPAD */
2741 
2742     /* dhd_bcmsdh_send_buf ignores the buffer pointer if he packet
2743      * parameter is not NULL, for non packet chian we pass NULL pkt pointer
2744      * so it will take the aligned length and buffer pointer.
2745      */
2746     pkt_chain = PKTNEXT(osh, head_pkt) ? head_pkt : NULL;
2747 #ifdef TPUT_MONITOR
2748     if ((bus->dhd->conf->data_drop_mode == TXPKT_DROP) && (total_len > 0x1F4)) {
2749         ret = BCME_OK;
2750     } else
2751 #endif
2752         ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2,
2753                                   F2SYNC, PKTDATA(osh, head_pkt), total_len,
2754                                   pkt_chain, NULL, NULL, TXRETRIES);
2755     if (ret == BCME_OK) {
2756         bus->tx_seq = (bus->tx_seq + num_pkt) % SDPCM_SEQUENCE_WRAP;
2757     }
2758 
2759     /* if a padding packet was needed, remove it from the link list as it not a
2760      * data pkt */
2761     if (pad_pkt_len && pkt) {
2762         PKTSETNEXT(osh, pkt, NULL);
2763     }
2764 
2765 done:
2766     pkt = head_pkt;
2767     while (pkt) {
2768         void *pkt_next = PKTNEXT(osh, pkt);
2769         PKTSETNEXT(osh, pkt, NULL);
2770         dhdsdio_txpkt_postprocess(bus, pkt);
2771         pkt = pkt_next;
2772     }
2773 
2774     /* new packets might be allocated due to insufficient room for padding, but
2775      * we still have to indicate the original packets to upper layer
2776      */
2777     for (i = 0; i < num_pkt; i++) {
2778         pkt = pkts[i];
2779         wlfc_enabled = FALSE;
2780 #ifdef PROP_TXSTATUS
2781         if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt))) {
2782             wlfc_enabled = (dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0) !=
2783                             WLFC_UNSUPPORTED);
2784         }
2785 #endif /* PROP_TXSTATUS */
2786         if (!wlfc_enabled) {
2787             PKTSETNEXT(osh, pkt, NULL);
2788             dhd_txcomplete(bus->dhd, pkt, ret != 0);
2789             if (free_pkt) {
2790                 PKTFREE(osh, pkt, TRUE);
2791             }
2792         }
2793     }
2794 
2795     for (i = 0; i < new_pkt_num; i++) {
2796         PKTFREE(osh, new_pkts[i], TRUE);
2797     }
2798 
2799     return ret;
2800 }
2801 
dhdsdio_sendfromq(dhd_bus_t * bus,uint maxframes)2802 static uint dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
2803 {
2804     uint cnt = 0;
2805     uint8 tx_prec_map;
2806     uint16 txpktqlen = 0;
2807     uint32 intstatus = 0;
2808     uint retries = 0;
2809     osl_t *osh;
2810     dhd_pub_t *dhd = bus->dhd;
2811     sdpcmd_regs_t *regs = bus->regs;
2812 #if defined(DHD_LOSSLESS_ROAMING) || defined(DHD_PKTDUMP_TOFW)
2813     uint8 *pktdata;
2814     struct ether_header *eh;
2815 #ifdef BDC
2816     struct bdc_header *bdc_header;
2817     uint8 data_offset;
2818 #endif // endif
2819 #endif /* DHD_LOSSLESS_ROAMING */
2820 
2821     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2822 
2823     if (!KSO_ENAB(bus)) {
2824         DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
2825         return BCME_NODEVICE;
2826     }
2827 
2828     osh = dhd->osh;
2829     tx_prec_map = ~bus->flowcontrol;
2830 #ifdef DHD_LOSSLESS_ROAMING
2831     tx_prec_map &= dhd->dequeue_prec_map;
2832 #endif /* DHD_LOSSLESS_ROAMING */
2833     for (cnt = 0; (cnt < maxframes) && DATAOK(bus);) {
2834         int i;
2835         int num_pkt = 1;
2836         void *pkts[MAX_TX_PKTCHAIN_CNT];
2837         int prec_out;
2838         uint datalen = 0;
2839 
2840         dhd_os_sdlock_txq(bus->dhd);
2841         if (bus->txglom_enable) {
2842             uint32 glomlimit = (uint32)bus->txglomsize;
2843 #if defined(BCMSDIOH_STD)
2844             if (bus->blocksize == 0x40) {
2845                 glomlimit = MIN((uint32)bus->txglomsize, BLK_64_MAXTXGLOM);
2846             }
2847 #endif /* BCMSDIOH_STD */
2848             num_pkt = MIN((uint32)DATABUFCNT(bus), glomlimit);
2849             num_pkt = MIN(num_pkt, ARRAYSIZE(pkts));
2850         }
2851         num_pkt = MIN(num_pkt, pktq_mlen(&bus->txq, tx_prec_map));
2852         for (i = 0; i < num_pkt; i++) {
2853             pkts[i] = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out);
2854             if (!pkts[i]) {
2855                 DHD_ERROR(
2856                     ("%s: pktq_mlen non-zero when no pkt\n", __FUNCTION__));
2857                 ASSERT(0);
2858                 break;
2859             }
2860 #if defined(DHD_LOSSLESS_ROAMING) || defined(DHD_PKTDUMP_TOFW)
2861             pktdata = (uint8 *)PKTDATA(osh, pkts[i]);
2862 #ifdef BDC
2863             /* Skip BDC header */
2864             bdc_header = (struct bdc_header *)pktdata;
2865             data_offset = bdc_header->dataOffset;
2866             pktdata += BDC_HEADER_LEN + (data_offset << 0x2);
2867 #endif // endif
2868             eh = (struct ether_header *)pktdata;
2869 #ifdef DHD_LOSSLESS_ROAMING
2870             if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) {
2871                 uint8 prio = (uint8)PKTPRIO(pkts[i]);
2872                 /* Restore to original priority for 802.1X packet */
2873                 if (prio == PRIO_8021D_NC) {
2874                     PKTSETPRIO(pkts[i], dhd->prio_8021x);
2875 #ifdef BDC
2876                     /* Restore to original priority in BDC header */
2877                     bdc_header->priority =
2878                         (dhd->prio_8021x & BDC_PRIORITY_MASK);
2879 #endif // endif
2880                 }
2881             }
2882 #endif /* DHD_LOSSLESS_ROAMING */
2883 #ifdef DHD_PKTDUMP_TOFW
2884             dhd_dump_pkt(bus->dhd, BDC_GET_IF_IDX(bdc_header), pktdata,
2885                          (uint32)PKTLEN(bus->dhd->osh, pkts[i]), TRUE, NULL,
2886                          NULL);
2887 #endif
2888 #endif /* DHD_LOSSLESS_ROAMING || DHD_8021X_DUMP */
2889             if (!bus->dhd->conf->orphan_move) {
2890                 PKTORPHAN(pkts[i], bus->dhd->conf->tsq);
2891             }
2892             datalen += PKTLEN(osh, pkts[i]);
2893         }
2894         dhd_os_sdunlock_txq(bus->dhd);
2895 
2896         if (i == 0) {
2897             break;
2898         }
2899         if (dhdsdio_txpkt(bus, SDPCM_DATA_CHANNEL, pkts, i, TRUE) != BCME_OK) {
2900             dhd->tx_errors++;
2901         } else {
2902             dhd->dstats.tx_bytes += datalen;
2903             bus->txglomframes++;
2904             bus->txglompkts += num_pkt;
2905 #ifdef PKT_STATICS
2906             bus->tx_statics.glom_cnt_us[num_pkt - 1] =
2907                 (bus->tx_statics.glom_cnt[num_pkt - 1] *
2908                      bus->tx_statics.glom_cnt_us[num_pkt - 1] +
2909                  bcmsdh_get_spend_time(bus->sdh)) /
2910                 (bus->tx_statics.glom_cnt[num_pkt - 1] + 1);
2911 #endif
2912         }
2913         cnt += i;
2914 #ifdef PKT_STATICS
2915         if (num_pkt) {
2916             bus->tx_statics.glom_cnt[num_pkt - 1]++;
2917             if (num_pkt > bus->tx_statics.glom_max) {
2918                 bus->tx_statics.glom_max = num_pkt;
2919             }
2920         }
2921 #endif
2922 
2923         /* In poll mode, need to check for other events */
2924         if (!bus->intr && cnt) {
2925             /* Check device status, signal pending interrupt */
2926             R_SDREG(intstatus, &regs->intstatus, retries);
2927             bus->f2txdata++;
2928             if (bcmsdh_regfail(bus->sdh)) {
2929                 break;
2930             }
2931             if (intstatus & bus->hostintmask) {
2932                 bus->ipend = TRUE;
2933             }
2934         }
2935     }
2936 
2937     if (dhd_doflow) {
2938         dhd_os_sdlock_txq(bus->dhd);
2939         txpktqlen = pktq_n_pkts_tot(&bus->txq);
2940         dhd_os_sdunlock_txq(bus->dhd);
2941     }
2942 
2943     /* Do flow-control if needed */
2944     if (dhd->up && (dhd->busstate == DHD_BUS_DATA) && (txpktqlen < FCLOW)) {
2945         bool wlfc_enabled = FALSE;
2946 #ifdef PROP_TXSTATUS
2947         wlfc_enabled =
2948             (dhd_wlfc_flowcontrol(dhd, OFF, TRUE) != WLFC_UNSUPPORTED);
2949 #endif // endif
2950         if (!wlfc_enabled && dhd_doflow && dhd->txoff) {
2951             dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
2952         }
2953     }
2954 
2955     return cnt;
2956 }
2957 
dhdsdio_sendpendctl(dhd_bus_t * bus)2958 static void dhdsdio_sendpendctl(dhd_bus_t *bus)
2959 {
2960     bcmsdh_info_t *sdh = bus->sdh;
2961     int ret;
2962     uint8 *frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN;
2963 
2964     if (bus->txglom_enable) {
2965         frame_seq += SDPCM_HWEXT_LEN;
2966     }
2967 
2968     if (*frame_seq != bus->tx_seq) {
2969         DHD_INFO(("%s IOCTL frame seq lag detected!"
2970                   " frm_seq:%d != bus->tx_seq:%d, corrected\n",
2971                   __FUNCTION__, *frame_seq, bus->tx_seq));
2972         *frame_seq = bus->tx_seq;
2973     }
2974 
2975     ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
2976                               (uint8 *)bus->ctrl_frame_buf,
2977                               (uint32)bus->ctrl_frame_len, NULL, NULL, NULL, 1);
2978     if (ret == BCME_OK) {
2979         bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
2980     }
2981 
2982     bus->ctrl_frame_stat = FALSE;
2983     dhd_wait_event_wakeup(bus->dhd);
2984 }
2985 
dhd_bus_txctl(struct dhd_bus * bus,uchar * msg,uint msglen)2986 int dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
2987 {
2988     static int err_nodevice = 0;
2989     uint8 *frame;
2990     uint16 len;
2991     uint32 swheader;
2992     uint8 doff = 0;
2993     int ret = -1;
2994     uint8 sdpcm_hdrlen =
2995         bus->txglom_enable ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN;
2996 
2997     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2998 
2999     if (bus->dhd->dongle_reset) {
3000         return -EIO;
3001     }
3002 
3003     /* Back the pointer to make a room for bus header */
3004     frame = msg - sdpcm_hdrlen;
3005     len = (msglen += sdpcm_hdrlen);
3006 
3007     /* Add alignment padding (optional for ctl frames) */
3008     if (dhd_alignctl) {
3009         if ((doff = ((uintptr)frame % DHD_SDALIGN))) {
3010             frame -= doff;
3011             len += doff;
3012             msglen += doff;
3013             bzero(frame, doff + sdpcm_hdrlen);
3014         }
3015         ASSERT(doff < DHD_SDALIGN);
3016     }
3017     doff += sdpcm_hdrlen;
3018 
3019 #ifndef BCMSPI
3020     /* Round send length to next SDIO block */
3021     if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
3022         uint16 pad = bus->blocksize - (len % bus->blocksize);
3023         if ((pad <= bus->roundup) && (pad < bus->blocksize)) {
3024             len += pad;
3025         }
3026     } else if (len % DHD_SDALIGN) {
3027         len += DHD_SDALIGN - (len % DHD_SDALIGN);
3028     }
3029 #endif /* BCMSPI */
3030 
3031     /* Satisfy length-alignment requirements */
3032     if (forcealign && (len & (ALIGNMENT - 1))) {
3033         len = ROUNDUP(len, ALIGNMENT);
3034     }
3035 
3036     ASSERT(ISALIGNED((uintptr)frame, 0x2));
3037 
3038     /* Need to lock here to protect txseq and SDIO tx calls */
3039     dhd_os_sdlock(bus->dhd);
3040     if (bus->dhd->conf->txctl_tmo_fix > 0 && !TXCTLOK(bus)) {
3041         bus->ctrl_wait = TRUE;
3042         dhd_os_sdunlock(bus->dhd);
3043         wait_event_interruptible_timeout(
3044             bus->ctrl_tx_wait, TXCTLOK(bus),
3045             msecs_to_jiffies(bus->dhd->conf->txctl_tmo_fix));
3046         dhd_os_sdlock(bus->dhd);
3047         bus->ctrl_wait = FALSE;
3048     }
3049 
3050     BUS_WAKE(bus);
3051 
3052     /* Make sure backplane clock is on */
3053     dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
3054 
3055     /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
3056     *(uint16 *)frame = htol16((uint16)msglen);
3057     *(((uint16 *)frame) + 1) = htol16(~msglen);
3058 
3059     if (bus->txglom_enable) {
3060         uint32 hwheader1, hwheader2;
3061         /* Software tag: channel, sequence number, data offset */
3062         swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) &
3063                     SDPCM_CHANNEL_MASK) |
3064                    bus->tx_seq |
3065                    ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
3066         htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN);
3067         htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN +
3068                                sizeof(swheader));
3069 
3070         hwheader1 = (msglen - SDPCM_FRAMETAG_LEN) | (1 << 0x18);
3071         hwheader2 = (len - (msglen)) << 0x10;
3072         htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
3073         htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 0x4);
3074 
3075         *(uint16 *)frame = htol16(len);
3076         *(((uint16 *)frame) + 1) = htol16(~(len));
3077     } else {
3078         /* Software tag: channel, sequence number, data offset */
3079         swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) &
3080                     SDPCM_CHANNEL_MASK) |
3081                    bus->tx_seq |
3082                    ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
3083         htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
3084         htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
3085     }
3086 
3087 #ifdef DHD_ULP
3088     dhd_ulp_set_path(bus->dhd, DHD_ULP_TX_CTRL);
3089 
3090     if (!TXCTLOK(bus) || !dhd_ulp_f2_ready(bus->dhd, bus->sdh))
3091 #else
3092     if (!TXCTLOK(bus))
3093 #endif // endif
3094     {
3095         DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n",
3096                   __FUNCTION__, bus->tx_max, bus->tx_seq));
3097         bus->ctrl_frame_stat = TRUE;
3098         /* Send from dpc */
3099         bus->ctrl_frame_buf = frame;
3100         bus->ctrl_frame_len = len;
3101 
3102         if (!bus->dpc_sched) {
3103             bus->dpc_sched = TRUE;
3104             dhd_sched_dpc(bus->dhd);
3105         }
3106         if (bus->ctrl_frame_stat) {
3107             dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat);
3108         }
3109 
3110         if (bus->ctrl_frame_stat == FALSE) {
3111             DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__));
3112             ret = 0;
3113         } else {
3114             bus->dhd->txcnt_timeout++;
3115             if (!bus->dhd->hang_was_sent) {
3116                 DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n",
3117                            __FUNCTION__, bus->dhd->txcnt_timeout));
3118 #ifdef BCMSDIO_RXLIM_POST
3119                 DHD_ERROR(("%s: rxlim_en=%d, rxlim enable=%d, rxlim_addr=%d\n",
3120                            __FUNCTION__, bus->dhd->conf->rxlim_en,
3121                            bus->rxlim_en, bus->rxlim_addr));
3122 #endif /* BCMSDIO_RXLIM_POST */
3123             }
3124 #ifdef DHD_FW_COREDUMP
3125             /* Collect socram dump */
3126             if ((bus->dhd->memdump_enabled) &&
3127                 (bus->dhd->txcnt_timeout >= MAX_CNTL_TX_TIMEOUT)) {
3128                 /* collect core dump */
3129                 bus->dhd->memdump_type = DUMP_TYPE_RESUMED_ON_TIMEOUT_TX;
3130                 dhd_os_sdunlock(bus->dhd);
3131                 dhd_bus_mem_dump(bus->dhd);
3132                 dhd_os_sdlock(bus->dhd);
3133             }
3134 #endif /* DHD_FW_COREDUMP */
3135             ret = -1;
3136             bus->ctrl_frame_stat = FALSE;
3137             goto done;
3138         }
3139     }
3140 
3141     bus->dhd->txcnt_timeout = 0;
3142     bus->ctrl_frame_stat = TRUE;
3143 
3144     if (ret == -1) {
3145 #ifdef DHD_DEBUG
3146         if (DHD_BYTES_ON() && DHD_CTL_ON()) {
3147             prhex("Tx Frame", frame, len);
3148         } else if (DHD_HDRS_ON()) {
3149             prhex("TxHdr", frame, MIN(len, 0x10));
3150         }
3151 #endif // endif
3152 #ifdef PKT_STATICS
3153         bus->tx_statics.ctrl_count++;
3154         bus->tx_statics.ctrl_size += len;
3155 #endif
3156         ret = dhd_bcmsdh_send_buffer(bus, frame, len);
3157     }
3158     bus->ctrl_frame_stat = FALSE;
3159 #ifdef DHD_ULP
3160     dhd_ulp_enable_cached_sbwad(bus->dhd, bus->sdh);
3161 #endif /* DHD_ULP */
3162 
3163 done:
3164     if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched &&
3165         NO_OTHER_ACTIVE_BUS_USER(bus)) {
3166         bus->activity = FALSE;
3167         dhdsdio_bussleep(bus, TRUE);
3168         dhdsdio_clkctl(bus, CLK_NONE, FALSE);
3169     }
3170 
3171     dhd_os_sdunlock(bus->dhd);
3172 
3173     if (ret) {
3174         bus->dhd->tx_ctlerrs++;
3175     } else {
3176         bus->dhd->tx_ctlpkts++;
3177     }
3178 
3179     if (bus->dhd->txcnt_timeout >= MAX_CNTL_TX_TIMEOUT) {
3180 #ifdef DHD_PM_CONTROL_FROM_FILE
3181         if (g_pm_control == TRUE) {
3182             return -BCME_ERROR;
3183         } else {
3184             return -ETIMEDOUT;
3185         }
3186 #else
3187         return -ETIMEDOUT;
3188 #endif /* DHD_PM_CONTROL_FROM_FILE */
3189     }
3190     if (ret == BCME_NODEVICE) {
3191         err_nodevice++;
3192     } else {
3193         err_nodevice = 0;
3194     }
3195 
3196     return ret ? err_nodevice >= ERROR_BCME_NODEVICE_MAX ? -ETIMEDOUT : -EIO
3197                : 0;
3198 }
3199 
dhd_bus_rxctl(struct dhd_bus * bus,uchar * msg,uint msglen)3200 int dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
3201 {
3202     int timeleft;
3203     uint rxlen = 0;
3204     static uint cnt = 0;
3205     uint max_rxcnt;
3206 
3207     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3208 
3209     if (bus->dhd->dongle_reset) {
3210         return -EIO;
3211     }
3212 
3213     /* Wait until control frame is available */
3214     timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen);
3215 
3216     dhd_os_sdlock(bus->dhd);
3217     rxlen = bus->rxlen;
3218     bcopy(bus->rxctl, msg, MIN(msglen, rxlen));
3219     bus->rxlen = 0;
3220     dhd_os_sdunlock(bus->dhd);
3221 
3222     if (bus->dhd->conf->ctrl_resched > 0 && !rxlen && timeleft == 0) {
3223         cnt++;
3224         if (cnt <= bus->dhd->conf->ctrl_resched) {
3225             uint32 status, retry = 0;
3226             R_SDREG(status, &bus->regs->intstatus, retry);
3227             if ((status & I_HMB_HOST_INT) || PKT_AVAILABLE(bus, status)) {
3228                 DHD_ERROR(("%s: reschedule dhd_dpc, cnt=%d, status=0x%x\n",
3229                            __FUNCTION__, cnt, status));
3230                 bus->ipend = TRUE;
3231                 bus->dpc_sched = TRUE;
3232                 dhd_sched_dpc(bus->dhd);
3233 
3234                 /* Wait until control frame is available */
3235                 timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen);
3236 
3237                 dhd_os_sdlock(bus->dhd);
3238                 rxlen = bus->rxlen;
3239                 bcopy(bus->rxctl, msg, MIN(msglen, rxlen));
3240                 bus->rxlen = 0;
3241                 dhd_os_sdunlock(bus->dhd);
3242             }
3243         }
3244     } else {
3245         cnt = 0;
3246     }
3247 
3248     if (rxlen) {
3249         DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n",
3250                  __FUNCTION__, rxlen, msglen));
3251     } else {
3252         if (timeleft == 0) {
3253 #ifdef DHD_DEBUG
3254             uint32 status, retry = 0;
3255             R_SDREG(status, &bus->regs->intstatus, retry);
3256             DHD_ERROR(("%s: resumed on timeout, INT status=0x%08X\n",
3257                        __FUNCTION__, status));
3258 #else
3259             DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__));
3260 #endif /* DHD_DEBUG */
3261             if (!bus->dhd->dongle_trap_occured) {
3262 #ifdef DHD_FW_COREDUMP
3263                 bus->dhd->memdump_type = DUMP_TYPE_RESUMED_ON_TIMEOUT;
3264 #endif /* DHD_FW_COREDUMP */
3265                 dhd_os_sdlock(bus->dhd);
3266                 dhdsdio_checkdied(bus, NULL, 0);
3267                 dhd_os_sdunlock(bus->dhd);
3268             }
3269         } else {
3270             DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__));
3271             if (!bus->dhd->dongle_trap_occured) {
3272 #ifdef DHD_FW_COREDUMP
3273                 bus->dhd->memdump_type = DUMP_TYPE_RESUMED_UNKNOWN;
3274 #endif /* DHD_FW_COREDUMP */
3275                 dhd_os_sdlock(bus->dhd);
3276                 dhdsdio_checkdied(bus, NULL, 0);
3277                 dhd_os_sdunlock(bus->dhd);
3278             }
3279         }
3280 #ifdef DHD_FW_COREDUMP
3281         /* Dump the ram image */
3282         if (bus->dhd->memdump_enabled && !bus->dhd->dongle_trap_occured) {
3283             dhdsdio_mem_dump(bus);
3284         }
3285 #endif /* DHD_FW_COREDUMP */
3286     }
3287     if (timeleft == 0) {
3288         if (rxlen == 0) {
3289             bus->dhd->rxcnt_timeout++;
3290         }
3291         DHD_ERROR(("%s: rxcnt_timeout=%d, rxlen=%d\n", __FUNCTION__,
3292                    bus->dhd->rxcnt_timeout, rxlen));
3293 #ifdef DHD_FW_COREDUMP
3294         /* collect socram dump */
3295         if (bus->dhd->memdump_enabled) {
3296             bus->dhd->memdump_type = DUMP_TYPE_RESUMED_ON_TIMEOUT_RX;
3297             dhd_bus_mem_dump(bus->dhd);
3298         }
3299 #endif /* DHD_FW_COREDUMP */
3300     } else {
3301         bus->dhd->rxcnt_timeout = 0;
3302     }
3303 
3304     if (rxlen) {
3305         bus->dhd->rx_ctlpkts++;
3306     } else {
3307         bus->dhd->rx_ctlerrs++;
3308     }
3309 
3310     if (bus->dhd->conf->rxcnt_timeout) {
3311         max_rxcnt = bus->dhd->conf->rxcnt_timeout;
3312     } else {
3313         max_rxcnt = MAX_CNTL_RX_TIMEOUT;
3314     }
3315     if (bus->dhd->rxcnt_timeout >= max_rxcnt) {
3316 #ifdef DHD_PM_CONTROL_FROM_FILE
3317         if (g_pm_control == TRUE) {
3318             return -BCME_ERROR;
3319         } else {
3320             return -ETIMEDOUT;
3321         }
3322 #else
3323         return -ETIMEDOUT;
3324 #endif /* DHD_PM_CONTROL_FROM_FILE */
3325     }
3326     if (bus->dhd->dongle_trap_occured) {
3327         return -EREMOTEIO;
3328     }
3329 
3330     return rxlen ? (int)rxlen : -EIO;
3331 }
3332 
3333 /* IOVar table */
3334 enum {
3335     IOV_INTR = 1,
3336     IOV_POLLRATE,
3337     IOV_SDREG,
3338     IOV_SBREG,
3339     IOV_SDCIS,
3340     IOV_RAMSIZE,
3341     IOV_RAMSTART,
3342 #ifdef DHD_DEBUG
3343     IOV_CHECKDIED,
3344     IOV_SERIALCONS,
3345 #endif /* DHD_DEBUG */
3346     IOV_SET_DOWNLOAD_STATE,
3347     IOV_SOCRAM_STATE,
3348     IOV_FORCEEVEN,
3349     IOV_SDIOD_DRIVE,
3350     IOV_READAHEAD,
3351     IOV_SDRXCHAIN,
3352     IOV_ALIGNCTL,
3353     IOV_SDALIGN,
3354     IOV_DEVRESET,
3355     IOV_CPU,
3356 #if defined(USE_SDIOFIFO_IOVAR)
3357     IOV_WATERMARK,
3358     IOV_MESBUSYCTRL,
3359 #endif /* USE_SDIOFIFO_IOVAR */
3360 #ifdef SDTEST
3361     IOV_PKTGEN,
3362     IOV_EXTLOOP,
3363 #endif /* SDTEST */
3364     IOV_SPROM,
3365     IOV_TXBOUND,
3366     IOV_RXBOUND,
3367     IOV_TXMINMAX,
3368     IOV_IDLETIME,
3369     IOV_IDLECLOCK,
3370     IOV_SD1IDLE,
3371     IOV_SLEEP,
3372     IOV_DONGLEISOLATION,
3373     IOV_KSO,
3374     IOV_DEVSLEEP,
3375     IOV_DEVCAP,
3376     IOV_VARS,
3377 #ifdef SOFTAP
3378     IOV_FWPATH,
3379 #endif // endif
3380     IOV_TXGLOMSIZE,
3381     IOV_TXGLOMMODE,
3382     IOV_HANGREPORT,
3383     IOV_TXINRX_THRES,
3384     IOV_SDIO_SUSPEND
3385 #if defined(DEBUGGER) || defined(DHD_DSCOPE)
3386         IOV_GDB_SERVER, /**< starts gdb server on given interface */
3387 #endif                  /* DEBUGGER || DHD_DSCOPE */
3388 };
3389 
3390 const bcm_iovar_t dhdsdio_iovars[] = {
3391     {"intr", IOV_INTR, 0, 0, IOVT_BOOL, 0},
3392     {"sleep", IOV_SLEEP, 0, 0, IOVT_BOOL, 0},
3393     {"pollrate", IOV_POLLRATE, 0, 0, IOVT_UINT32, 0},
3394     {"idletime", IOV_IDLETIME, 0, 0, IOVT_INT32, 0},
3395     {"idleclock", IOV_IDLECLOCK, 0, 0, IOVT_INT32, 0},
3396     {"sd1idle", IOV_SD1IDLE, 0, 0, IOVT_BOOL, 0},
3397     {"ramsize", IOV_RAMSIZE, 0, 0, IOVT_UINT32, 0},
3398     {"ramstart", IOV_RAMSTART, 0, 0, IOVT_UINT32, 0},
3399     {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, 0, IOVT_BOOL, 0},
3400     {"socram_state", IOV_SOCRAM_STATE, 0, 0, IOVT_BOOL, 0},
3401     {"vars", IOV_VARS, 0, 0, IOVT_BUFFER, 0},
3402     {"sdiod_drive", IOV_SDIOD_DRIVE, 0, 0, IOVT_UINT32, 0},
3403     {"readahead", IOV_READAHEAD, 0, 0, IOVT_BOOL, 0},
3404     {"sdrxchain", IOV_SDRXCHAIN, 0, 0, IOVT_BOOL, 0},
3405     {"alignctl", IOV_ALIGNCTL, 0, 0, IOVT_BOOL, 0},
3406     {"sdalign", IOV_SDALIGN, 0, 0, IOVT_BOOL, 0},
3407     {"devreset", IOV_DEVRESET, 0, 0, IOVT_BOOL, 0},
3408 #ifdef DHD_DEBUG
3409     {"sdreg", IOV_SDREG, 0, 0, IOVT_BUFFER, sizeof(sdreg_t)},
3410     {"sbreg", IOV_SBREG, 0, 0, IOVT_BUFFER, sizeof(sdreg_t)},
3411     {"sd_cis", IOV_SDCIS, 0, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN},
3412     {"forcealign", IOV_FORCEEVEN, 0, 0, IOVT_BOOL, 0},
3413     {"txbound", IOV_TXBOUND, 0, 0, IOVT_UINT32, 0},
3414     {"rxbound", IOV_RXBOUND, 0, 0, IOVT_UINT32, 0},
3415     {"txminmax", IOV_TXMINMAX, 0, 0, IOVT_UINT32, 0},
3416     {"cpu", IOV_CPU, 0, 0, IOVT_BOOL, 0},
3417 #ifdef DHD_DEBUG
3418     {"checkdied", IOV_CHECKDIED, 0, 0, IOVT_BUFFER, 0},
3419     {"serial", IOV_SERIALCONS, 0, 0, IOVT_UINT32, 0},
3420 #endif /* DHD_DEBUG  */
3421 #endif /* DHD_DEBUG */
3422 #ifdef SDTEST
3423     {"extloop", IOV_EXTLOOP, 0, 0, IOVT_BOOL, 0},
3424     {"pktgen", IOV_PKTGEN, 0, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t)},
3425 #endif /* SDTEST */
3426 #if defined(USE_SDIOFIFO_IOVAR)
3427     {"watermark", IOV_WATERMARK, 0, 0, IOVT_UINT32, 0},
3428     {"mesbusyctrl", IOV_MESBUSYCTRL, 0, 0, IOVT_UINT32, 0},
3429 #endif /* USE_SDIOFIFO_IOVAR */
3430     {"devcap", IOV_DEVCAP, 0, 0, IOVT_UINT32, 0},
3431     {"dngl_isolation", IOV_DONGLEISOLATION, 0, 0, IOVT_UINT32, 0},
3432     {"kso", IOV_KSO, 0, 0, IOVT_UINT32, 0},
3433     {"devsleep", IOV_DEVSLEEP, 0, 0, IOVT_UINT32, 0},
3434 #ifdef SOFTAP
3435     {"fwpath", IOV_FWPATH, 0, 0, IOVT_BUFFER, 0},
3436 #endif // endif
3437     {"txglomsize", IOV_TXGLOMSIZE, 0, 0, IOVT_UINT32, 0},
3438     {"fw_hang_report", IOV_HANGREPORT, 0, 0, IOVT_BOOL, 0},
3439     {"txinrx_thres", IOV_TXINRX_THRES, 0, 0, IOVT_INT32, 0},
3440     {"sdio_suspend", IOV_SDIO_SUSPEND, 0, 0, IOVT_UINT32, 0},
3441 #if defined(DEBUGGER) || defined(DHD_DSCOPE)
3442     {"gdb_server", IOV_GDB_SERVER, 0, 0, IOVT_UINT32, 0},
3443 #endif /* DEBUGGER || DHD_DSCOPE */
3444     {NULL, 0, 0, 0, 0, 0}};
3445 
dhd_dump_pct(struct bcmstrbuf * strbuf,char * desc,uint num,uint div)3446 static void dhd_dump_pct(struct bcmstrbuf *strbuf, char *desc, uint num,
3447                          uint div)
3448 {
3449     uint q1, q2;
3450 
3451     if (!div) {
3452         bcm_bprintf(strbuf, "%s N/A", desc);
3453     } else {
3454         q1 = num / div;
3455         q2 = (0x64 * (num - (q1 * div))) / div;
3456         bcm_bprintf(strbuf, "%s %d.%02d", desc, q1, q2);
3457     }
3458 }
3459 
dhd_bus_dump(dhd_pub_t * dhdp,struct bcmstrbuf * strbuf)3460 void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
3461 {
3462     dhd_bus_t *bus = dhdp->bus;
3463 #if defined(DHD_WAKE_STATUS) && defined(DHD_WAKE_EVENT_STATUS)
3464     int i;
3465 #endif // endif
3466 
3467     bcm_bprintf(strbuf, "Bus SDIO structure:\n");
3468     bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n",
3469                 bus->hostintmask, bus->intstatus, bus->sdpcm_ver);
3470     bcm_bprintf(
3471         strbuf,
3472         "fcstate %d qlen %u tx_seq %d, max %d, rxskip %d rxlen %u rx_seq %d\n",
3473         bus->fcstate, pktq_n_pkts_tot(&bus->txq), bus->tx_seq, bus->tx_max,
3474         bus->rxskip, bus->rxlen, bus->rx_seq);
3475     bcm_bprintf(strbuf, "intr %d intrcount %u lastintrs %u spurious %u\n",
3476                 bus->intr, bus->intrcount, bus->lastintrs, bus->spurious);
3477 
3478 #ifdef DHD_WAKE_STATUS
3479     bcm_bprintf(strbuf, "wake %u rxwake %u readctrlwake %u\n",
3480                 bcmsdh_get_total_wake(bus->sdh), bus->wake_counts.rxwake,
3481                 bus->wake_counts.rcwake);
3482 #ifdef DHD_WAKE_RX_STATUS
3483     bcm_bprintf(strbuf, " unicast %u multicast %u broadcast %u arp %u\n",
3484                 bus->wake_counts.rx_ucast, bus->wake_counts.rx_mcast,
3485                 bus->wake_counts.rx_bcast, bus->wake_counts.rx_arp);
3486     bcm_bprintf(strbuf, " multi4 %u multi6 %u icmp6 %u multiother %u\n",
3487                 bus->wake_counts.rx_multi_ipv4, bus->wake_counts.rx_multi_ipv6,
3488                 bus->wake_counts.rx_icmpv6, bus->wake_counts.rx_multi_other);
3489     bcm_bprintf(strbuf, " icmp6_ra %u, icmp6_na %u, icmp6_ns %u\n",
3490                 bus->wake_counts.rx_icmpv6_ra, bus->wake_counts.rx_icmpv6_na,
3491                 bus->wake_counts.rx_icmpv6_ns);
3492 #endif /* DHD_WAKE_RX_STATUS */
3493 #ifdef DHD_WAKE_EVENT_STATUS
3494     for (i = 0; i < WLC_E_LAST; i++) {
3495         if (bus->wake_counts.rc_event[i] != 0) {
3496             bcm_bprintf(strbuf, " %s = %u\n", bcmevent_get_name(i),
3497                         bus->wake_counts.rc_event[i]);
3498         }
3499     }
3500     bcm_bprintf(strbuf, "\n");
3501 #endif /* DHD_WAKE_EVENT_STATUS */
3502 #endif /* DHD_WAKE_STATUS */
3503 
3504     bcm_bprintf(strbuf, "pollrate %u pollcnt %u regfails %u\n", bus->pollrate,
3505                 bus->pollcnt, bus->regfails);
3506 
3507     bcm_bprintf(strbuf, "\nAdditional counters:\n");
3508 #ifdef DHDENABLE_TAILPAD
3509     bcm_bprintf(strbuf, "tx_tailpad_chain %u tx_tailpad_pktget %u\n",
3510                 bus->tx_tailpad_chain, bus->tx_tailpad_pktget);
3511 #endif /* DHDENABLE_TAILPAD */
3512     bcm_bprintf(
3513         strbuf,
3514         "tx_sderrs %u fcqueued %u rxrtx %u rx_toolong %u rxc_errors %u\n",
3515         bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong,
3516         bus->rxc_errors);
3517     bcm_bprintf(strbuf, "rx_hdrfail %u badhdr %u badseq %u\n", bus->rx_hdrfail,
3518                 bus->rx_badhdr, bus->rx_badseq);
3519     bcm_bprintf(strbuf, "fc_rcvd %u, fc_xoff %u, fc_xon %u\n", bus->fc_rcvd,
3520                 bus->fc_xoff, bus->fc_xon);
3521     bcm_bprintf(strbuf, "rxglomfail %u, rxglomframes %u, rxglompkts %u\n",
3522                 bus->rxglomfail, bus->rxglomframes, bus->rxglompkts);
3523     bcm_bprintf(strbuf, "f2rx (hdrs/data) %u (%u/%u), f2tx %u f1regs %u\n",
3524                 (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata,
3525                 bus->f2txdata, bus->f1regdata);
3526     {
3527         dhd_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->dhd->rx_packets,
3528                      (bus->f2rxhdrs + bus->f2rxdata));
3529         dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->rx_packets,
3530                      bus->f1regdata);
3531         dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->rx_packets,
3532                      (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
3533         dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->rx_packets,
3534                      bus->intrcount);
3535         bcm_bprintf(strbuf, "\n");
3536 
3537         dhd_dump_pct(strbuf, "Rx: glom pct", (0x64 * bus->rxglompkts),
3538                      bus->dhd->rx_packets);
3539         dhd_dump_pct(strbuf, ", pkts/glom", bus->rxglompkts, bus->rxglomframes);
3540         bcm_bprintf(strbuf, "\n");
3541 
3542         dhd_dump_pct(strbuf, "Tx: pkts/f2wr", bus->dhd->tx_packets,
3543                      bus->f2txdata);
3544         dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->tx_packets,
3545                      bus->f1regdata);
3546         dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->tx_packets,
3547                      (bus->f2txdata + bus->f1regdata));
3548         dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->tx_packets,
3549                      bus->intrcount);
3550         bcm_bprintf(strbuf, "\n");
3551 
3552         dhd_dump_pct(strbuf, "Total: pkts/f2rw",
3553                      (bus->dhd->tx_packets + bus->dhd->rx_packets),
3554                      (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata));
3555         dhd_dump_pct(strbuf, ", pkts/f1sd",
3556                      (bus->dhd->tx_packets + bus->dhd->rx_packets),
3557                      bus->f1regdata);
3558         dhd_dump_pct(
3559             strbuf, ", pkts/sd", (bus->dhd->tx_packets + bus->dhd->rx_packets),
3560             (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
3561         dhd_dump_pct(strbuf, ", pkts/int",
3562                      (bus->dhd->tx_packets + bus->dhd->rx_packets),
3563                      bus->intrcount);
3564         bcm_bprintf(strbuf, "\n\n");
3565     }
3566 
3567 #ifdef SDTEST
3568     if (bus->pktgen_count) {
3569         bcm_bprintf(strbuf, "pktgen config and count:\n");
3570         bcm_bprintf(strbuf,
3571                     "freq %u count %u print %u total %u min %u len %u\n",
3572                     bus->pktgen_freq, bus->pktgen_count, bus->pktgen_print,
3573                     bus->pktgen_total, bus->pktgen_minlen, bus->pktgen_maxlen);
3574         bcm_bprintf(strbuf, "send attempts %u rcvd %u fail %u\n",
3575                     bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
3576     }
3577 #endif /* SDTEST */
3578 #ifdef DHD_DEBUG
3579     bcm_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n",
3580                 bus->dpc_sched,
3581                 (bcmsdh_intr_pending(bus->sdh) ? " " : " not "));
3582     bcm_bprintf(strbuf, "blocksize %u roundup %u\n", bus->blocksize,
3583                 bus->roundup);
3584 #endif /* DHD_DEBUG */
3585     bcm_bprintf(
3586         strbuf,
3587         "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n",
3588         bus->clkstate, bus->activity, bus->idletime, bus->idlecount,
3589         bus->sleeping);
3590     dhd_dump_pct(strbuf, "Tx: glom pct", (0x64 * bus->txglompkts),
3591                  bus->dhd->tx_packets);
3592     dhd_dump_pct(strbuf, ", pkts/glom", bus->txglompkts, bus->txglomframes);
3593     bcm_bprintf(strbuf, "\n");
3594     bcm_bprintf(strbuf, "txglomframes %u, txglompkts %u\n", bus->txglomframes,
3595                 bus->txglompkts);
3596     bcm_bprintf(strbuf, "\n");
3597 }
3598 
dhd_bus_clearcounts(dhd_pub_t * dhdp)3599 void dhd_bus_clearcounts(dhd_pub_t *dhdp)
3600 {
3601     dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus;
3602 
3603     bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0;
3604     bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0;
3605     bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0;
3606 #ifdef DHDENABLE_TAILPAD
3607     bus->tx_tailpad_chain = bus->tx_tailpad_pktget = 0;
3608 #endif /* DHDENABLE_TAILPAD */
3609     bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0;
3610     bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0;
3611     bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0;
3612     bus->txglomframes = bus->txglompkts = 0;
3613 }
3614 
3615 #ifdef SDTEST
dhdsdio_pktgen_get(dhd_bus_t * bus,uint8 * arg)3616 static int dhdsdio_pktgen_get(dhd_bus_t *bus, uint8 *arg)
3617 {
3618     dhd_pktgen_t pktgen;
3619 
3620     pktgen.version = DHD_PKTGEN_VERSION;
3621     pktgen.freq = bus->pktgen_freq;
3622     pktgen.count = bus->pktgen_count;
3623     pktgen.print = bus->pktgen_print;
3624     pktgen.total = bus->pktgen_total;
3625     pktgen.minlen = bus->pktgen_minlen;
3626     pktgen.maxlen = bus->pktgen_maxlen;
3627     pktgen.numsent = bus->pktgen_sent;
3628     pktgen.numrcvd = bus->pktgen_rcvd;
3629     pktgen.numfail = bus->pktgen_fail;
3630     pktgen.mode = bus->pktgen_mode;
3631     pktgen.stop = bus->pktgen_stop;
3632 
3633     bcopy(&pktgen, arg, sizeof(pktgen));
3634 
3635     return 0;
3636 }
3637 
dhdsdio_pktgen_set(dhd_bus_t * bus,uint8 * arg)3638 static int dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg)
3639 {
3640     dhd_pktgen_t pktgen;
3641     uint oldcnt, oldmode;
3642 
3643     bcopy(arg, &pktgen, sizeof(pktgen));
3644     if (pktgen.version != DHD_PKTGEN_VERSION) {
3645         return BCME_BADARG;
3646     }
3647 
3648     oldcnt = bus->pktgen_count;
3649     oldmode = bus->pktgen_mode;
3650 
3651     bus->pktgen_freq = pktgen.freq;
3652     bus->pktgen_count = pktgen.count;
3653     bus->pktgen_print = pktgen.print;
3654     bus->pktgen_total = pktgen.total;
3655     bus->pktgen_minlen = pktgen.minlen;
3656     bus->pktgen_maxlen = pktgen.maxlen;
3657     bus->pktgen_mode = pktgen.mode;
3658     bus->pktgen_stop = pktgen.stop;
3659 
3660     bus->pktgen_tick = bus->pktgen_ptick = 0;
3661     bus->pktgen_prev_time = jiffies;
3662     bus->pktgen_len = MAX(bus->pktgen_len, bus->pktgen_minlen);
3663     bus->pktgen_len = MIN(bus->pktgen_len, bus->pktgen_maxlen);
3664 
3665     /* Clear counts for a new pktgen (mode change, or was stopped) */
3666     if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode)) {
3667         bus->pktgen_sent = bus->pktgen_prev_sent = bus->pktgen_rcvd = 0;
3668         bus->pktgen_prev_rcvd = bus->pktgen_fail = 0;
3669     }
3670 
3671     return 0;
3672 }
3673 #endif /* SDTEST */
3674 
dhdsdio_devram_remap(dhd_bus_t * bus,bool val)3675 static void dhdsdio_devram_remap(dhd_bus_t *bus, bool val)
3676 {
3677     uint8 enable, protect, remap;
3678 
3679     si_socdevram(bus->sih, FALSE, &enable, &protect, &remap);
3680     remap = val ? TRUE : FALSE;
3681     si_socdevram(bus->sih, TRUE, &enable, &protect, &remap);
3682 }
3683 
dhdsdio_membytes(dhd_bus_t * bus,bool write,uint32 address,uint8 * data,uint size)3684 static int dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address,
3685                             uint8 *data, uint size)
3686 {
3687     int bcmerror = 0;
3688     uint32 sdaddr;
3689     uint dsize;
3690     uint8 *pdata;
3691 
3692     /* In remap mode, adjust address beyond socram and redirect
3693      * to devram at SOCDEVRAM_BP_ADDR since remap address > orig_ramsize
3694      * is not backplane accessible
3695      */
3696     if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address)) {
3697         address -= bus->orig_ramsize;
3698         address += SOCDEVRAM_BP_ADDR;
3699     }
3700 
3701     /* Determine initial transfer parameters */
3702     sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
3703     if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK) {
3704         dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
3705     } else {
3706         dsize = size;
3707     }
3708 
3709     /* Set the backplane window to include the start address */
3710     if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
3711         DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
3712         goto xfer_done;
3713     }
3714 
3715     /* Do the transfer(s) */
3716     while (size) {
3717         DHD_INFO(("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n",
3718                   __FUNCTION__, (write ? "write" : "read"), dsize, sdaddr,
3719                   (address & SBSDIO_SBWINDOW_MASK)));
3720         if (dsize <= MAX_MEM_BUF) {
3721             pdata = bus->membuf;
3722             if (write) {
3723                 memcpy(bus->membuf, data, dsize);
3724             }
3725         } else {
3726             pdata = data;
3727         }
3728         if ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, pdata, dsize))) {
3729             DHD_ERROR(("%s: membytes transfer failed\n", __FUNCTION__));
3730             break;
3731         }
3732         if (dsize <= MAX_MEM_BUF && !write) {
3733             memcpy(data, bus->membuf, dsize);
3734         }
3735 
3736         /* Adjust for next transfer (if any) */
3737         if ((size -= dsize)) {
3738             data += dsize;
3739             address += dsize;
3740             if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
3741                 DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
3742                 break;
3743             }
3744             sdaddr = 0;
3745             dsize = MIN(SBSDIO_SB_OFT_ADDR_LIMIT, size);
3746         }
3747     }
3748 
3749 xfer_done:
3750     /* Return the window to backplane enumeration space for core access */
3751     if (dhdsdio_set_siaddr_window(bus, bcmsdh_cur_sbwad(bus->sdh))) {
3752         DHD_ERROR(("%s: FAILED to set window back to 0x%x\n", __FUNCTION__,
3753                    bcmsdh_cur_sbwad(bus->sdh)));
3754     }
3755 
3756     return bcmerror;
3757 }
3758 
dhdsdio_readshared(dhd_bus_t * bus,sdpcm_shared_t * sh)3759 static int dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
3760 {
3761     uint32 addr;
3762     int rv, i;
3763     uint32 shaddr = 0;
3764 
3765     if (bus->sih == NULL) {
3766         if (bus->dhd && bus->dhd->dongle_reset) {
3767             DHD_ERROR(("%s: Dongle is in reset state\n", __FUNCTION__));
3768             return BCME_NOTREADY;
3769         } else {
3770             ASSERT(bus->dhd);
3771             ASSERT(bus->sih);
3772             DHD_ERROR(("%s: The address of sih is invalid\n", __FUNCTION__));
3773             return BCME_ERROR;
3774         }
3775     }
3776     if ((CHIPID(bus->sih->chip) == BCM43430_CHIP_ID ||
3777          CHIPID(bus->sih->chip) == BCM43018_CHIP_ID) &&
3778         !dhdsdio_sr_cap(bus)) {
3779         bus->srmemsize = 0;
3780     }
3781 
3782     shaddr = bus->dongle_ram_base + bus->ramsize - 0x4;
3783     i = 0;
3784     do {
3785         /* Read last word in memory to determine address of sdpcm_shared
3786          * structure */
3787         if ((rv = dhdsdio_membytes(bus, FALSE, shaddr, (uint8 *)&addr, 0x4)) <
3788             0) {
3789             return rv;
3790         }
3791 
3792         addr = ltoh32(addr);
3793 
3794         DHD_INFO(("sdpcm_shared address 0x%08X\n", addr));
3795 
3796         /*
3797          * Check if addr is valid.
3798          * NVRAM length at the end of memory should have been overwritten.
3799          */
3800         if (addr == 0 || ((~addr >> 0x10) & 0xffff) == (addr & 0xffff)) {
3801             if ((bus->srmemsize > 0) && (i++ == 0)) {
3802                 shaddr -= bus->srmemsize;
3803             } else {
3804                 DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n",
3805                            __FUNCTION__, addr));
3806                 return BCME_ERROR;
3807             }
3808         } else {
3809             break;
3810         }
3811     } while (i < 0x2);
3812 
3813     /* Read hndrte_shared structure */
3814     if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)sh,
3815                                sizeof(sdpcm_shared_t))) < 0) {
3816         return rv;
3817     }
3818 
3819     /* Endianness */
3820     sh->flags = ltoh32(sh->flags);
3821     sh->trap_addr = ltoh32(sh->trap_addr);
3822     sh->assert_exp_addr = ltoh32(sh->assert_exp_addr);
3823     sh->assert_file_addr = ltoh32(sh->assert_file_addr);
3824     sh->assert_line = ltoh32(sh->assert_line);
3825     sh->console_addr = ltoh32(sh->console_addr);
3826     sh->msgtrace_addr = ltoh32(sh->msgtrace_addr);
3827 
3828 #ifdef BCMSDIO_RXLIM_POST
3829     if (sh->flags & SDPCM_SHARED_RXLIM_POST) {
3830         if (bus->dhd->conf->rxlim_en) {
3831             bus->rxlim_en = !!sh->msgtrace_addr;
3832         }
3833         bus->rxlim_addr = sh->msgtrace_addr;
3834         DHD_INFO(("%s: rxlim_en=%d, rxlim enable=%d, rxlim_addr=%d\n",
3835                   __FUNCTION__, bus->dhd->conf->rxlim_en, bus->rxlim_en,
3836                   bus->rxlim_addr));
3837         sh->flags &= ~SDPCM_SHARED_RXLIM_POST;
3838     } else {
3839         bus->rxlim_en = 0;
3840         DHD_INFO(("%s: FW has no rx limit post support\n", __FUNCTION__));
3841     }
3842 #endif /* BCMSDIO_RXLIM_POST */
3843 
3844 #ifdef BCMSDIO_TXSEQ_SYNC
3845     if (bus->dhd->conf->txseq_sync) {
3846         sh->txseq_sync_addr = ltoh32(sh->txseq_sync_addr);
3847         if (sh->flags & SDPCM_SHARED_TXSEQ_SYNC) {
3848             uint8 val = 0;
3849             DHD_INFO(("%s: TXSEQ_SYNC enabled in fw\n", __FUNCTION__));
3850             if (0 == dhdsdio_membytes(bus, FALSE, sh->txseq_sync_addr,
3851                                       (uint8 *)&val, 1)) {
3852                 if (bus->tx_seq != val) {
3853                     DHD_INFO(("%s: Sync tx_seq from %d to %d\n", __FUNCTION__,
3854                               bus->tx_seq, val));
3855                     bus->tx_seq = val;
3856                     bus->tx_max = bus->tx_seq + 0x4;
3857                 }
3858             }
3859             sh->flags &= ~SDPCM_SHARED_TXSEQ_SYNC;
3860         } else {
3861             bus->dhd->conf->txseq_sync = FALSE;
3862         }
3863     }
3864 #endif /* BCMSDIO_TXSEQ_SYNC */
3865 
3866     if ((sh->flags & SDPCM_SHARED_VERSION_MASK) == 0x3 &&
3867         SDPCM_SHARED_VERSION == 1) {
3868         return BCME_OK;
3869     }
3870 
3871     if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
3872         DHD_ERROR(("%s: sdpcm_shared version %d in dhd "
3873                    "is different than sdpcm_shared version %d in dongle\n",
3874                    __FUNCTION__, SDPCM_SHARED_VERSION,
3875                    sh->flags & SDPCM_SHARED_VERSION_MASK));
3876         return BCME_ERROR;
3877     }
3878 
3879     return BCME_OK;
3880 }
3881 
3882 #define CONSOLE_LINE_MAX 192
3883 
3884 #ifdef DHD_DEBUG
dhdsdio_readconsole(dhd_bus_t * bus)3885 static int dhdsdio_readconsole(dhd_bus_t *bus)
3886 {
3887     dhd_console_t *c = &bus->console;
3888     uint8 line[CONSOLE_LINE_MAX], ch;
3889     uint32 n, idx, addr;
3890     int rv;
3891 
3892     /* Don't do anything until FWREADY updates console address */
3893     if (bus->console_addr == 0) {
3894         return 0;
3895     }
3896 
3897     if (!KSO_ENAB(bus)) {
3898         return 0;
3899     }
3900 
3901     /* Read console log struct */
3902     addr = bus->console_addr + OFFSETOF(hnd_cons_t, log);
3903     if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log,
3904                                sizeof(c->log))) < 0) {
3905         return rv;
3906     }
3907 
3908     /* Allocate console buffer (one time only) */
3909     if (c->buf == NULL) {
3910         c->bufsize = ltoh32(c->log.buf_size);
3911         if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL) {
3912             return BCME_NOMEM;
3913         }
3914     }
3915 
3916     idx = ltoh32(c->log.idx);
3917     /* Protect against corrupt value */
3918     if (idx > c->bufsize) {
3919         return BCME_ERROR;
3920     }
3921     /* Skip reading the console buffer if the index pointer has not moved */
3922     if (idx == c->last) {
3923         return BCME_OK;
3924     }
3925 
3926     /* Read the console buffer */
3927     addr = ltoh32(c->log.buf);
3928     if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 0) {
3929         return rv;
3930     }
3931 
3932     while (c->last != idx) {
3933         for (n = 0; n < CONSOLE_LINE_MAX - 0x2; n++) {
3934             if (c->last == idx) {
3935                 /* This would output a partial line.  Instead, back up
3936                  * the buffer pointer and output this line next time around.
3937                  */
3938                 if (c->last >= n) {
3939                     c->last -= n;
3940                 } else {
3941                     c->last = c->bufsize - n;
3942                 }
3943                 goto break2;
3944             }
3945             ch = c->buf[c->last];
3946             c->last = (c->last + 1) % c->bufsize;
3947             if (ch == '\n') {
3948                 break;
3949             }
3950             line[n] = ch;
3951         }
3952 
3953         if (n > 0) {
3954             if (line[n - 1] == '\r') {
3955                 n--;
3956             }
3957             line[n] = 0;
3958             printf("CONSOLE: %s\n", line);
3959 #ifdef LOG_INTO_TCPDUMP
3960             dhd_sendup_log(bus->dhd, line, n);
3961 #endif /* LOG_INTO_TCPDUMP */
3962         }
3963     }
3964 break2:
3965 
3966     return BCME_OK;
3967 }
3968 #endif /* DHD_DEBUG */
3969 
dhdsdio_checkdied(dhd_bus_t * bus,char * data,uint size)3970 static int dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size)
3971 {
3972     int bcmerror = 0;
3973     uint msize = 512;
3974     char *mbuffer = NULL;
3975     char *console_buffer = NULL;
3976     uint maxstrlen = 256;
3977     char *str = NULL;
3978     sdpcm_shared_t l_sdpcm_shared;
3979     struct bcmstrbuf strbuf;
3980     uint32 console_ptr, console_size, console_index;
3981     uint8 line[CONSOLE_LINE_MAX], ch;
3982     uint32 n, i, addr;
3983     int rv;
3984 
3985     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3986 
3987     if (DHD_NOCHECKDIED_ON()) {
3988         return 0;
3989     }
3990 
3991     if (data == NULL) {
3992         /*
3993          * Called after a rx ctrl timeout. "data" is NULL.
3994          * allocate memory to trace the trap or assert.
3995          */
3996         size = msize;
3997         mbuffer = data = MALLOC(bus->dhd->osh, msize);
3998         if (mbuffer == NULL) {
3999             DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, msize));
4000             bcmerror = BCME_NOMEM;
4001             goto done;
4002         }
4003     }
4004 
4005     if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) {
4006         DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen));
4007         bcmerror = BCME_NOMEM;
4008         goto done;
4009     }
4010 
4011     if ((bcmerror = dhdsdio_readshared(bus, &l_sdpcm_shared)) < 0) {
4012         goto done;
4013     }
4014 
4015     bcm_binit(&strbuf, data, size);
4016 
4017     bcm_bprintf(&strbuf,
4018                 "msgtrace address : 0x%08X\nconsole address  : 0x%08X\n",
4019                 l_sdpcm_shared.msgtrace_addr, l_sdpcm_shared.console_addr);
4020 
4021     if ((l_sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) {
4022         /* NOTE: Misspelled assert is intentional - DO NOT FIX.
4023          * (Avoids conflict with real asserts for programmatic parsing of
4024          * output.)
4025          */
4026         bcm_bprintf(&strbuf, "Assrt not built in dongle\n");
4027     }
4028 
4029     if ((l_sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) ==
4030         0) {
4031         /* NOTE: Misspelled assert is intentional - DO NOT FIX.
4032          * (Avoids conflict with real asserts for programmatic parsing of
4033          * output.)
4034          */
4035         bcm_bprintf(
4036             &strbuf, "No trap%s in dongle",
4037             (l_sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) ? "/assrt" : "");
4038     } else {
4039         if (l_sdpcm_shared.flags & SDPCM_SHARED_ASSERT) {
4040             /* Download assert */
4041             bcm_bprintf(&strbuf, "Dongle assert");
4042             if (l_sdpcm_shared.assert_exp_addr != 0) {
4043                 str[0] = '\0';
4044                 if ((bcmerror = dhdsdio_membytes(
4045                          bus, FALSE, l_sdpcm_shared.assert_exp_addr,
4046                          (uint8 *)str, maxstrlen)) < 0) {
4047                     goto done;
4048                 }
4049 
4050                 str[maxstrlen - 1] = '\0';
4051                 bcm_bprintf(&strbuf, " expr \"%s\"", str);
4052             }
4053 
4054             if (l_sdpcm_shared.assert_file_addr != 0) {
4055                 str[0] = '\0';
4056                 if ((bcmerror = dhdsdio_membytes(
4057                          bus, FALSE, l_sdpcm_shared.assert_file_addr,
4058                          (uint8 *)str, maxstrlen)) < 0) {
4059                     goto done;
4060                 }
4061 
4062                 str[maxstrlen - 1] = '\0';
4063                 bcm_bprintf(&strbuf, " file \"%s\"", str);
4064             }
4065 
4066             bcm_bprintf(&strbuf, " line %d ", l_sdpcm_shared.assert_line);
4067         }
4068 
4069         if (l_sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
4070             trap_t *tr = &bus->dhd->last_trap_info;
4071             bus->dhd->dongle_trap_occured = TRUE;
4072             if ((bcmerror =
4073                      dhdsdio_membytes(bus, FALSE, l_sdpcm_shared.trap_addr,
4074                                       (uint8 *)tr, sizeof(trap_t))) < 0) {
4075                 goto done;
4076             }
4077 
4078             bus->dongle_trap_addr = ltoh32(l_sdpcm_shared.trap_addr);
4079 
4080             dhd_bus_dump_trap_info(bus, &strbuf);
4081 
4082             addr = l_sdpcm_shared.console_addr + OFFSETOF(hnd_cons_t, log);
4083             if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&console_ptr,
4084                                        sizeof(console_ptr))) < 0) {
4085                 goto printbuf;
4086             }
4087 
4088             addr = l_sdpcm_shared.console_addr +
4089                    OFFSETOF(hnd_cons_t, log.buf_size);
4090             if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&console_size,
4091                                        sizeof(console_size))) < 0) {
4092                 goto printbuf;
4093             }
4094 
4095             addr = l_sdpcm_shared.console_addr + OFFSETOF(hnd_cons_t, log.idx);
4096             if ((rv =
4097                      dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&console_index,
4098                                       sizeof(console_index))) < 0) {
4099                 goto printbuf;
4100             }
4101 
4102             console_ptr = ltoh32(console_ptr);
4103             console_size = ltoh32(console_size);
4104             console_index = ltoh32(console_index);
4105 
4106             if (console_size > CONSOLE_BUFFER_MAX ||
4107                 !(console_buffer = MALLOC(bus->dhd->osh, console_size))) {
4108                 goto printbuf;
4109             }
4110 
4111             if ((rv = dhdsdio_membytes(bus, FALSE, console_ptr,
4112                                        (uint8 *)console_buffer, console_size)) <
4113                 0) {
4114                 goto printbuf;
4115             }
4116 
4117             for (i = 0, n = 0; i < console_size; i += n + 1) {
4118                 for (n = 0; n < CONSOLE_LINE_MAX - 0x2; n++) {
4119                     ch = console_buffer[(console_index + i + n) % console_size];
4120                     if (ch == '\n') {
4121                         break;
4122                     }
4123                     line[n] = ch;
4124                 }
4125 
4126                 if (n > 0) {
4127                     if (line[n - 1] == '\r') {
4128                         n--;
4129                     }
4130                     line[n] = 0;
4131                     /* Don't use DHD_ERROR macro since we print
4132                      * a lot of information quickly. The macro
4133                      * will truncate a lot of the printfs
4134                      */
4135 
4136                     if (dhd_msg_level & DHD_ERROR_VAL) {
4137                         printf("CONSOLE: %s\n", line);
4138                     }
4139                 }
4140             }
4141         }
4142     }
4143 
4144 printbuf:
4145     if (l_sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) {
4146         DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf));
4147     }
4148 
4149 #if defined(DHD_FW_COREDUMP)
4150     if (bus->dhd->memdump_enabled &&
4151         (l_sdpcm_shared.flags & SDPCM_SHARED_TRAP)) {
4152         /* Mem dump to a file on device */
4153         bus->dhd->memdump_type = DUMP_TYPE_DONGLE_TRAP;
4154         dhd_os_sdunlock(bus->dhd);
4155         dhdsdio_mem_dump(bus);
4156         dhd_os_sdlock(bus->dhd);
4157     }
4158 #endif /* #if defined(DHD_FW_COREDUMP) */
4159 
4160 done:
4161     if (mbuffer) {
4162         MFREE(bus->dhd->osh, mbuffer, msize);
4163     }
4164     if (str) {
4165         MFREE(bus->dhd->osh, str, maxstrlen);
4166     }
4167     if (console_buffer) {
4168         MFREE(bus->dhd->osh, console_buffer, console_size);
4169     }
4170 
4171     return bcmerror;
4172 }
4173 
4174 #if defined(DHD_FW_COREDUMP)
dhd_bus_mem_dump(dhd_pub_t * dhdp)4175 int dhd_bus_mem_dump(dhd_pub_t *dhdp)
4176 {
4177     dhd_bus_t *bus = dhdp->bus;
4178     if (dhdp->busstate == DHD_BUS_SUSPEND) {
4179         DHD_ERROR(("%s: Bus is suspend so skip\n", __FUNCTION__));
4180         return 0;
4181     }
4182     return dhdsdio_mem_dump(bus);
4183 }
4184 
dhd_bus_get_mem_dump(dhd_pub_t * dhdp)4185 int dhd_bus_get_mem_dump(dhd_pub_t *dhdp)
4186 {
4187     if (!dhdp) {
4188         DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__));
4189         return BCME_ERROR;
4190     }
4191 
4192     return dhdsdio_get_mem_dump(dhdp->bus);
4193 }
4194 
dhdsdio_get_mem_dump(dhd_bus_t * bus)4195 static int dhdsdio_get_mem_dump(dhd_bus_t *bus)
4196 {
4197     int ret = BCME_ERROR;
4198     int size = bus->ramsize;             /* Full mem size */
4199     uint32 start = bus->dongle_ram_base; /* Start address */
4200     uint read_size = 0;                  /* Read size of each iteration */
4201     uint8 *p_buf = NULL, *databuf = NULL;
4202 
4203     /* Get full mem size */
4204     p_buf = dhd_get_fwdump_buf(bus->dhd, size);
4205     if (!p_buf) {
4206         DHD_ERROR(("%s: Out of memory (%d bytes)\n", __FUNCTION__, size));
4207         return BCME_ERROR;
4208     }
4209 
4210     dhd_os_sdlock(bus->dhd);
4211     BUS_WAKE(bus);
4212     dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4213 
4214     /* Read mem content */
4215     DHD_ERROR(("Dump dongle memory\n"));
4216     databuf = p_buf;
4217     while (size) {
4218         read_size = MIN(MEMBLOCK, size);
4219         ret = dhdsdio_membytes(bus, FALSE, start, databuf, read_size);
4220         if (ret) {
4221             DHD_ERROR(("%s: Error membytes %d\n", __FUNCTION__, ret));
4222             ret = BCME_ERROR;
4223             break;
4224         }
4225         /* Decrement size and increment start address */
4226         size -= read_size;
4227         start += read_size;
4228         databuf += read_size;
4229     }
4230 
4231     if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched &&
4232         NO_OTHER_ACTIVE_BUS_USER(bus)) {
4233         bus->activity = FALSE;
4234         dhdsdio_clkctl(bus, CLK_NONE, TRUE);
4235     }
4236 
4237     dhd_os_sdunlock(bus->dhd);
4238 
4239     return ret;
4240 }
4241 
dhdsdio_mem_dump(dhd_bus_t * bus)4242 static int dhdsdio_mem_dump(dhd_bus_t *bus)
4243 {
4244     dhd_pub_t *dhdp;
4245     int ret = BCME_ERROR;
4246 
4247     dhdp = bus->dhd;
4248     if (!dhdp) {
4249         DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__));
4250         return ret;
4251     }
4252 
4253     ret = dhdsdio_get_mem_dump(bus);
4254     if (ret) {
4255         DHD_ERROR(("%s: failed to get mem dump, err=%d\n", __FUNCTION__, ret));
4256     } else {
4257         /* schedule a work queue to perform actual memdump.
4258          * dhd_mem_dump() performs the job
4259          */
4260         dhd_schedule_memdump(dhdp, dhdp->soc_ram, dhdp->soc_ram_length);
4261         /* soc_ram free handled in dhd_{free,clear} */
4262     }
4263 
4264     return ret;
4265 }
4266 #endif /* DHD_FW_COREDUMP */
4267 
dhd_socram_dump(dhd_bus_t * bus)4268 int dhd_socram_dump(dhd_bus_t *bus)
4269 {
4270 #if defined(DHD_FW_COREDUMP)
4271     return (dhdsdio_mem_dump(bus));
4272 #else
4273     return -1;
4274 #endif // endif
4275 }
4276 
dhdsdio_downloadvars(dhd_bus_t * bus,void * arg,int len)4277 int dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len)
4278 {
4279     int bcmerror = BCME_OK;
4280 
4281     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4282 
4283     if (bus->dhd->up &&
4284 #ifdef DHD_ULP
4285         (DHD_ULP_DISABLED == dhd_ulp_get_ulp_state(bus->dhd)) &&
4286 #endif /* DHD_ULP */
4287         1) {
4288         bcmerror = BCME_NOTDOWN;
4289         goto err;
4290     }
4291     if (!len) {
4292         bcmerror = BCME_BUFTOOSHORT;
4293         goto err;
4294     }
4295 
4296     /* Free the old ones and replace with passed variables */
4297     if (bus->vars) {
4298         MFREE(bus->dhd->osh, bus->vars, bus->varsz);
4299     }
4300 
4301     bus->vars = MALLOC(bus->dhd->osh, len);
4302     bus->varsz = bus->vars ? len : 0;
4303     if (bus->vars == NULL) {
4304         bcmerror = BCME_NOMEM;
4305         goto err;
4306     }
4307 
4308     /* Copy the passed variables, which should include the terminating
4309      * double-null */
4310     bcopy(arg, bus->vars, bus->varsz);
4311 err:
4312     return bcmerror;
4313 }
4314 
4315 #ifdef DHD_DEBUG
dhd_serialconsole(dhd_bus_t * bus,bool set,bool enable,int * bcmerror)4316 static int dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable,
4317                              int *bcmerror)
4318 {
4319     int int_val;
4320     uint32 addr, data, uart_enab = 0;
4321 
4322     addr = SI_ENUM_BASE(bus->sih) + OFFSETOF(chipcregs_t, chipcontrol_addr);
4323     data = SI_ENUM_BASE(bus->sih) + OFFSETOF(chipcregs_t, chipcontrol_data);
4324     *bcmerror = 0;
4325 
4326     bcmsdh_reg_write(bus->sdh, addr, 0x4, 1);
4327     if (bcmsdh_regfail(bus->sdh)) {
4328         *bcmerror = BCME_SDIO_ERROR;
4329         return -1;
4330     }
4331     int_val = bcmsdh_reg_read(bus->sdh, data, 0x4);
4332     if (bcmsdh_regfail(bus->sdh)) {
4333         *bcmerror = BCME_SDIO_ERROR;
4334         return -1;
4335     }
4336 
4337     if (!set) {
4338         return (int_val & uart_enab);
4339     }
4340     if (enable) {
4341         int_val |= uart_enab;
4342     } else {
4343         int_val &= ~uart_enab;
4344     }
4345     bcmsdh_reg_write(bus->sdh, data, 0x4, int_val);
4346     if (bcmsdh_regfail(bus->sdh)) {
4347         *bcmerror = BCME_SDIO_ERROR;
4348         return -1;
4349     }
4350 
4351     return (int_val & uart_enab);
4352 }
4353 #endif // endif
4354 
dhdsdio_doiovar(dhd_bus_t * bus,const bcm_iovar_t * vi,uint32 actionid,const char * name,void * params,int plen,void * arg,int len,int val_size)4355 static int dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi,
4356                            uint32 actionid, const char *name, void *params,
4357                            int plen, void *arg, int len, int val_size)
4358 {
4359     int bcmerror = 0;
4360     int32 int_val = 0;
4361     bool bool_val = 0;
4362 
4363     DHD_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d "
4364                "val_size %d\n",
4365                __FUNCTION__, actionid, name, params, plen, arg, len, val_size));
4366 
4367     if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) !=
4368         0) {
4369         goto exit;
4370     }
4371 
4372     if (plen >= (int)sizeof(int_val)) {
4373         bcopy(params, &int_val, sizeof(int_val));
4374     }
4375 
4376     bool_val = (int_val != 0) ? TRUE : FALSE;
4377 
4378     /* Some ioctls use the bus */
4379     dhd_os_sdlock(bus->dhd);
4380 
4381     /* Check if dongle is in reset. If so, only allow DEVRESET iovars */
4382     if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) ||
4383                                     actionid == IOV_GVAL(IOV_DEVRESET))) {
4384         bcmerror = BCME_NOTREADY;
4385         goto exit;
4386     }
4387 
4388     /*
4389      * Special handling for keepSdioOn: New SDIO Wake-up Mechanism
4390      */
4391     if ((vi->varid == IOV_KSO) && (IOV_ISSET(actionid))) {
4392         dhdsdio_clk_kso_iovar(bus, bool_val);
4393         goto exit;
4394     } else if ((vi->varid == IOV_DEVSLEEP) && (IOV_ISSET(actionid))) {
4395         {
4396             dhdsdio_clk_devsleep_iovar(bus, bool_val);
4397             if (!SLPAUTO_ENAB(bus) && (bool_val == FALSE) && (bus->ipend)) {
4398                 DHD_ERROR(("INT pending in devsleep 1, dpc_sched: %d\n",
4399                            bus->dpc_sched));
4400                 if (!bus->dpc_sched) {
4401                     bus->dpc_sched = TRUE;
4402                     dhd_sched_dpc(bus->dhd);
4403                 }
4404             }
4405         }
4406         goto exit;
4407     }
4408 
4409     /* Handle sleep stuff before any clock mucking */
4410     if (vi->varid == IOV_SLEEP) {
4411         if (IOV_ISSET(actionid)) {
4412             bcmerror = dhdsdio_bussleep(bus, bool_val);
4413         } else {
4414             int_val = (int32)bus->sleeping;
4415             bcopy(&int_val, arg, val_size);
4416         }
4417         goto exit;
4418     }
4419 
4420     /* Request clock to allow SDIO accesses */
4421     if (!bus->dhd->dongle_reset) {
4422         BUS_WAKE(bus);
4423         dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4424     }
4425 
4426     switch (actionid) {
4427         case IOV_GVAL(IOV_INTR):
4428             int_val = (int32)bus->intr;
4429             bcopy(&int_val, arg, val_size);
4430             break;
4431 
4432         case IOV_SVAL(IOV_INTR):
4433             bus->intr = bool_val;
4434             bus->intdis = FALSE;
4435             if (bus->dhd->up) {
4436                 if (bus->intr) {
4437                     DHD_INTR(
4438                         ("%s: enable SDIO device interrupts\n", __FUNCTION__));
4439                     // terence 20141207: enbale intdis
4440                     bus->intdis = TRUE;
4441                     bcmsdh_intr_enable(bus->sdh);
4442                 } else {
4443                     DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
4444                     bcmsdh_intr_disable(bus->sdh);
4445                 }
4446             }
4447             break;
4448 
4449         case IOV_GVAL(IOV_POLLRATE):
4450             int_val = (int32)bus->pollrate;
4451             bcopy(&int_val, arg, val_size);
4452             break;
4453 
4454         case IOV_SVAL(IOV_POLLRATE):
4455             bus->pollrate = (uint)int_val;
4456             bus->poll = (bus->pollrate != 0);
4457             break;
4458 
4459         case IOV_GVAL(IOV_IDLETIME):
4460             int_val = bus->idletime;
4461             bcopy(&int_val, arg, val_size);
4462             break;
4463 
4464         case IOV_SVAL(IOV_IDLETIME):
4465             if ((int_val < 0) && (int_val != DHD_IDLE_IMMEDIATE)) {
4466                 bcmerror = BCME_BADARG;
4467             } else {
4468                 bus->idletime = int_val;
4469             }
4470             break;
4471 
4472         case IOV_GVAL(IOV_IDLECLOCK):
4473             int_val = (int32)bus->idleclock;
4474             bcopy(&int_val, arg, val_size);
4475             break;
4476 
4477         case IOV_SVAL(IOV_IDLECLOCK):
4478             bus->idleclock = int_val;
4479             break;
4480 
4481         case IOV_GVAL(IOV_SD1IDLE):
4482             int_val = (int32)sd1idle;
4483             bcopy(&int_val, arg, val_size);
4484             break;
4485 
4486         case IOV_SVAL(IOV_SD1IDLE):
4487             sd1idle = bool_val;
4488             break;
4489 
4490 #ifdef DHD_DEBUG
4491         case IOV_GVAL(IOV_CHECKDIED):
4492             bcmerror = dhdsdio_checkdied(bus, arg, len);
4493             break;
4494 #endif /* DHD_DEBUG */
4495 
4496         case IOV_GVAL(IOV_RAMSIZE):
4497             int_val = (int32)bus->ramsize;
4498             bcopy(&int_val, arg, val_size);
4499             break;
4500 
4501         case IOV_GVAL(IOV_RAMSTART):
4502             int_val = (int32)bus->dongle_ram_base;
4503             bcopy(&int_val, arg, val_size);
4504             break;
4505 
4506         case IOV_GVAL(IOV_SDIOD_DRIVE):
4507             int_val = (int32)dhd_sdiod_drive_strength;
4508             bcopy(&int_val, arg, val_size);
4509             break;
4510 
4511         case IOV_SVAL(IOV_SDIOD_DRIVE):
4512             dhd_sdiod_drive_strength = int_val;
4513             si_sdiod_drive_strength_init(bus->sih, bus->dhd->osh,
4514                                          dhd_sdiod_drive_strength);
4515             break;
4516 
4517         case IOV_SVAL(IOV_SET_DOWNLOAD_STATE):
4518             bcmerror = dhdsdio_download_state(bus, bool_val);
4519             break;
4520 
4521         case IOV_SVAL(IOV_SOCRAM_STATE):
4522             bcmerror = dhdsdio_download_state(bus, bool_val);
4523             break;
4524 
4525         case IOV_SVAL(IOV_VARS):
4526             bcmerror = dhdsdio_downloadvars(bus, arg, len);
4527             break;
4528 
4529         case IOV_GVAL(IOV_READAHEAD):
4530             int_val = (int32)dhd_readahead;
4531             bcopy(&int_val, arg, val_size);
4532             break;
4533 
4534         case IOV_SVAL(IOV_READAHEAD):
4535             if (bool_val && !dhd_readahead) {
4536                 bus->nextlen = 0;
4537             }
4538             dhd_readahead = bool_val;
4539             break;
4540 
4541         case IOV_GVAL(IOV_SDRXCHAIN):
4542             int_val = (int32)bus->use_rxchain;
4543             bcopy(&int_val, arg, val_size);
4544             break;
4545 
4546         case IOV_SVAL(IOV_SDRXCHAIN):
4547             if (bool_val && !bus->sd_rxchain) {
4548                 bcmerror = BCME_UNSUPPORTED;
4549             } else {
4550                 bus->use_rxchain = bool_val;
4551             }
4552             break;
4553 #ifndef BCMSPI
4554         case IOV_GVAL(IOV_ALIGNCTL):
4555             int_val = (int32)dhd_alignctl;
4556             bcopy(&int_val, arg, val_size);
4557             break;
4558 
4559         case IOV_SVAL(IOV_ALIGNCTL):
4560             dhd_alignctl = bool_val;
4561             break;
4562 #endif /* BCMSPI */
4563 
4564         case IOV_GVAL(IOV_SDALIGN):
4565             int_val = DHD_SDALIGN;
4566             bcopy(&int_val, arg, val_size);
4567             break;
4568 
4569 #ifdef DHD_DEBUG
4570         case IOV_GVAL(IOV_VARS):
4571             if (bus->varsz < (uint)len) {
4572                 bcopy(bus->vars, arg, bus->varsz);
4573             } else {
4574                 bcmerror = BCME_BUFTOOSHORT;
4575             }
4576             break;
4577 #endif /* DHD_DEBUG */
4578 
4579 #ifdef DHD_DEBUG
4580         case IOV_GVAL(IOV_SDREG): {
4581             sdreg_t *sd_ptr;
4582             uintptr addr;
4583             uint size;
4584 
4585             sd_ptr = (sdreg_t *)params;
4586 
4587             addr = ((uintptr)bus->regs + sd_ptr->offset);
4588             size = sd_ptr->func;
4589             int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
4590             if (bcmsdh_regfail(bus->sdh)) {
4591                 bcmerror = BCME_SDIO_ERROR;
4592             }
4593             bcopy(&int_val, arg, sizeof(int32));
4594             break;
4595         }
4596 
4597         case IOV_SVAL(IOV_SDREG): {
4598             sdreg_t *sd_ptr;
4599             uintptr addr;
4600             uint size;
4601 
4602             sd_ptr = (sdreg_t *)params;
4603 
4604             addr = ((uintptr)bus->regs + sd_ptr->offset);
4605             size = sd_ptr->func;
4606             bcmsdh_reg_write(bus->sdh, addr, size, sd_ptr->value);
4607             if (bcmsdh_regfail(bus->sdh)) {
4608                 bcmerror = BCME_SDIO_ERROR;
4609             }
4610             break;
4611         }
4612 
4613         /* Same as above, but offset is not backplane (not SDIO core) */
4614         case IOV_GVAL(IOV_SBREG): {
4615             sdreg_t sdreg;
4616             uint32 addr, size;
4617 
4618             bcopy(params, &sdreg, sizeof(sdreg));
4619 
4620             addr = SI_ENUM_BASE(bus->sih) + sdreg.offset;
4621             size = sdreg.func;
4622             int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
4623             if (bcmsdh_regfail(bus->sdh)) {
4624                 bcmerror = BCME_SDIO_ERROR;
4625             }
4626             bcopy(&int_val, arg, sizeof(int32));
4627             break;
4628         }
4629 
4630         case IOV_SVAL(IOV_SBREG): {
4631             sdreg_t sdreg;
4632             uint32 addr, size;
4633 
4634             bcopy(params, &sdreg, sizeof(sdreg));
4635 
4636             addr = SI_ENUM_BASE(bus->sih) + sdreg.offset;
4637             size = sdreg.func;
4638             bcmsdh_reg_write(bus->sdh, addr, size, sdreg.value);
4639             if (bcmsdh_regfail(bus->sdh)) {
4640                 bcmerror = BCME_SDIO_ERROR;
4641             }
4642             break;
4643         }
4644 
4645         case IOV_GVAL(IOV_SDCIS): {
4646             *(char *)arg = 0;
4647 
4648             bcmstrcat(arg, "\nFunc 0\n");
4649             bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg),
4650                             SBSDIO_CIS_SIZE_LIMIT);
4651             bcmstrcat(arg, "\nFunc 1\n");
4652             bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg),
4653                             SBSDIO_CIS_SIZE_LIMIT);
4654             bcmstrcat(arg, "\nFunc 2\n");
4655             bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg),
4656                             SBSDIO_CIS_SIZE_LIMIT);
4657             break;
4658         }
4659 
4660         case IOV_GVAL(IOV_FORCEEVEN):
4661             int_val = (int32)forcealign;
4662             bcopy(&int_val, arg, val_size);
4663             break;
4664 
4665         case IOV_SVAL(IOV_FORCEEVEN):
4666             forcealign = bool_val;
4667             break;
4668 
4669         case IOV_GVAL(IOV_TXBOUND):
4670             int_val = (int32)dhd_txbound;
4671             bcopy(&int_val, arg, val_size);
4672             break;
4673 
4674         case IOV_SVAL(IOV_TXBOUND):
4675             dhd_txbound = (uint)int_val;
4676             break;
4677 
4678         case IOV_GVAL(IOV_RXBOUND):
4679             int_val = (int32)dhd_rxbound;
4680             bcopy(&int_val, arg, val_size);
4681             break;
4682 
4683         case IOV_SVAL(IOV_RXBOUND):
4684             dhd_rxbound = (uint)int_val;
4685             break;
4686 
4687         case IOV_GVAL(IOV_TXMINMAX):
4688             int_val = (int32)dhd_txminmax;
4689             bcopy(&int_val, arg, val_size);
4690             break;
4691 
4692         case IOV_SVAL(IOV_TXMINMAX):
4693             dhd_txminmax = (uint)int_val;
4694             break;
4695 
4696 #ifdef DHD_DEBUG
4697         case IOV_GVAL(IOV_SERIALCONS):
4698             int_val = dhd_serialconsole(bus, FALSE, 0, &bcmerror);
4699             if (bcmerror != 0) {
4700                 break;
4701             }
4702 
4703             bcopy(&int_val, arg, val_size);
4704             break;
4705 
4706         case IOV_SVAL(IOV_SERIALCONS):
4707             dhd_serialconsole(bus, TRUE, bool_val, &bcmerror);
4708             break;
4709 #endif /* DHD_DEBUG */
4710 
4711 #endif /* DHD_DEBUG */
4712 
4713 #ifdef SDTEST
4714         case IOV_GVAL(IOV_EXTLOOP):
4715             int_val = (int32)bus->ext_loop;
4716             bcopy(&int_val, arg, val_size);
4717             break;
4718 
4719         case IOV_SVAL(IOV_EXTLOOP):
4720             bus->ext_loop = bool_val;
4721             break;
4722 
4723         case IOV_GVAL(IOV_PKTGEN):
4724             bcmerror = dhdsdio_pktgen_get(bus, arg);
4725             break;
4726 
4727         case IOV_SVAL(IOV_PKTGEN):
4728             bcmerror = dhdsdio_pktgen_set(bus, arg);
4729             break;
4730 #endif /* SDTEST */
4731 
4732 #if defined(USE_SDIOFIFO_IOVAR)
4733         case IOV_GVAL(IOV_WATERMARK):
4734             int_val = (int32)watermark;
4735             bcopy(&int_val, arg, val_size);
4736             break;
4737 
4738         case IOV_SVAL(IOV_WATERMARK):
4739             watermark = (uint)int_val;
4740             watermark = (watermark > SBSDIO_WATERMARK_MASK)
4741                             ? SBSDIO_WATERMARK_MASK
4742                             : watermark;
4743             DHD_ERROR(("Setting watermark as 0x%x.\n", watermark));
4744             bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK,
4745                              (uint8)watermark, NULL);
4746             break;
4747 
4748         case IOV_GVAL(IOV_MESBUSYCTRL):
4749             int_val = (int32)mesbusyctrl;
4750             bcopy(&int_val, arg, val_size);
4751             break;
4752 
4753         case IOV_SVAL(IOV_MESBUSYCTRL):
4754             mesbusyctrl = (uint)int_val;
4755             mesbusyctrl = (mesbusyctrl > SBSDIO_MESBUSYCTRL_MASK)
4756                               ? SBSDIO_MESBUSYCTRL_MASK
4757                               : mesbusyctrl;
4758             DHD_ERROR(("Setting mesbusyctrl as 0x%x.\n", mesbusyctrl));
4759             bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
4760                              ((uint8)mesbusyctrl | 0x80), NULL);
4761             break;
4762 #endif // endif
4763 
4764         case IOV_GVAL(IOV_DONGLEISOLATION):
4765             int_val = bus->dhd->dongle_isolation;
4766             bcopy(&int_val, arg, val_size);
4767             break;
4768 
4769         case IOV_SVAL(IOV_DONGLEISOLATION):
4770             bus->dhd->dongle_isolation = bool_val;
4771             break;
4772 
4773         case IOV_SVAL(IOV_DEVRESET):
4774             DHD_TRACE(
4775                 ("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n",
4776                  __FUNCTION__, bool_val, bus->dhd->dongle_reset,
4777                  bus->dhd->busstate));
4778 
4779             ASSERT(bus->dhd->osh);
4780 
4781             /* must release sdlock, since devreset also acquires it */
4782             dhd_os_sdunlock(bus->dhd);
4783             dhd_bus_devreset(bus->dhd, (uint8)bool_val);
4784             dhd_os_sdlock(bus->dhd);
4785             break;
4786             /*
4787              * softap firmware is updated through module parameter or android
4788              * private command
4789              */
4790 
4791         case IOV_GVAL(IOV_DEVRESET):
4792             DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__));
4793 
4794             /* Get its status */
4795             int_val = (bool)bus->dhd->dongle_reset;
4796             bcopy(&int_val, arg, val_size);
4797 
4798             break;
4799 
4800         case IOV_GVAL(IOV_KSO):
4801             int_val = dhdsdio_sleepcsr_get(bus);
4802             bcopy(&int_val, arg, val_size);
4803             break;
4804 
4805         case IOV_GVAL(IOV_DEVCAP):
4806             int_val = dhdsdio_devcap_get(bus);
4807             bcopy(&int_val, arg, val_size);
4808             break;
4809 
4810         case IOV_SVAL(IOV_DEVCAP):
4811             dhdsdio_devcap_set(bus, (uint8)int_val);
4812             break;
4813         case IOV_GVAL(IOV_TXGLOMSIZE):
4814             int_val = (int32)bus->txglomsize;
4815             bcopy(&int_val, arg, val_size);
4816             break;
4817 
4818         case IOV_SVAL(IOV_TXGLOMSIZE):
4819             if (int_val > SDPCM_MAXGLOM_SIZE) {
4820                 bcmerror = BCME_ERROR;
4821             } else {
4822                 bus->txglomsize = (uint)int_val;
4823             }
4824             break;
4825         case IOV_SVAL(IOV_HANGREPORT):
4826             bus->dhd->hang_report = bool_val;
4827             DHD_ERROR(("%s: Set hang_report as %d\n", __FUNCTION__,
4828                        bus->dhd->hang_report));
4829             break;
4830 
4831         case IOV_GVAL(IOV_HANGREPORT):
4832             int_val = (int32)bus->dhd->hang_report;
4833             bcopy(&int_val, arg, val_size);
4834             break;
4835 
4836         case IOV_GVAL(IOV_TXINRX_THRES):
4837             int_val = bus->txinrx_thres;
4838             bcopy(&int_val, arg, val_size);
4839             break;
4840         case IOV_SVAL(IOV_TXINRX_THRES):
4841             if (int_val < 0) {
4842                 bcmerror = BCME_BADARG;
4843             } else {
4844                 bus->txinrx_thres = int_val;
4845             }
4846             break;
4847 
4848         case IOV_GVAL(IOV_SDIO_SUSPEND):
4849             int_val = (bus->dhd->busstate == DHD_BUS_SUSPEND) ? 1 : 0;
4850             bcopy(&int_val, arg, val_size);
4851             break;
4852 
4853         case IOV_SVAL(IOV_SDIO_SUSPEND):
4854             if (bool_val) { /* Suspend */
4855                 dhdsdio_suspend(bus);
4856             } else { /* Resume */
4857                 dhdsdio_resume(bus);
4858             }
4859             break;
4860 
4861 #if defined(DEBUGGER) || defined(DHD_DSCOPE)
4862         case IOV_SVAL(IOV_GDB_SERVER):
4863             if (bool_val == TRUE) {
4864                 debugger_init((void *)bus, &bus_ops, int_val,
4865                               SI_ENUM_BASE(bus->sih));
4866             } else {
4867                 debugger_close();
4868             }
4869             break;
4870 #endif /* DEBUGGER || DHD_DSCOPE */
4871 
4872         default:
4873             bcmerror = BCME_UNSUPPORTED;
4874             break;
4875     }
4876 
4877 exit:
4878     if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched &&
4879         NO_OTHER_ACTIVE_BUS_USER(bus)) {
4880         bus->activity = FALSE;
4881         dhdsdio_bussleep(bus, TRUE);
4882         dhdsdio_clkctl(bus, CLK_NONE, FALSE);
4883     }
4884 
4885     dhd_os_sdunlock(bus->dhd);
4886 
4887     return bcmerror;
4888 }
4889 
dhdsdio_write_vars(dhd_bus_t * bus)4890 static int dhdsdio_write_vars(dhd_bus_t *bus)
4891 {
4892     int bcmerror = 0;
4893     uint32 varsize, phys_size;
4894     uint32 varaddr;
4895     uint8 *vbuffer;
4896     uint32 varsizew;
4897 #ifdef DHD_DEBUG
4898     uint8 *nvram_ularray;
4899 #endif /* DHD_DEBUG */
4900 
4901     /* Even if there are no vars are to be written, we still need to set the
4902      * ramsize. */
4903     varsize = bus->varsz ? ROUNDUP(bus->varsz, 0x4) : 0;
4904     varaddr = (bus->ramsize - 0x4) - varsize;
4905 
4906     // terence 20150412: fix for nvram failed to download
4907     if (bus->dhd->conf->chip == BCM43340_CHIP_ID ||
4908         bus->dhd->conf->chip == BCM43341_CHIP_ID) {
4909         varsize = varsize ? ROUNDUP(varsize, 0x40) : 0;
4910         varaddr = (bus->ramsize - 0x40) - varsize;
4911     }
4912 
4913     varaddr += bus->dongle_ram_base;
4914 
4915     if (bus->vars) {
4916         if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 0x7)) {
4917             if (((varaddr & 0x3C) == 0x3C) && (varsize > 0x4)) {
4918                 DHD_ERROR(("PR85623WAR in place\n"));
4919                 varsize += 0x4;
4920                 varaddr -= 0x4;
4921             }
4922         }
4923 
4924         vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize);
4925         if (!vbuffer) {
4926             return BCME_NOMEM;
4927         }
4928 
4929         bzero(vbuffer, varsize);
4930         bcopy(bus->vars, vbuffer, bus->varsz);
4931 
4932         /* Write the vars list */
4933         bcmerror = dhdsdio_membytes(bus, TRUE, varaddr, vbuffer, varsize);
4934         if (bcmerror) {
4935             DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
4936                        __FUNCTION__, bcmerror, varsize, varaddr));
4937             return bcmerror;
4938         }
4939 
4940 #ifdef DHD_DEBUG
4941         /* Verify NVRAM bytes */
4942         DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize));
4943         nvram_ularray = (uint8 *)MALLOC(bus->dhd->osh, varsize);
4944         if (!nvram_ularray) {
4945             MFREE(bus->dhd->osh, vbuffer, varsize);
4946             return BCME_NOMEM;
4947         }
4948 
4949         /* Upload image to verify downloaded contents. */
4950         memset(nvram_ularray, 0xaa, varsize);
4951 
4952         /* Read the vars list to temp buffer for comparison */
4953         bcmerror =
4954             dhdsdio_membytes(bus, FALSE, varaddr, nvram_ularray, varsize);
4955         if (bcmerror) {
4956             DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n",
4957                        __FUNCTION__, bcmerror, varsize, varaddr));
4958         }
4959         /* Compare the org NVRAM with the one read from RAM */
4960         if (memcmp(vbuffer, nvram_ularray, varsize)) {
4961             DHD_ERROR(
4962                 ("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__));
4963         } else {
4964             DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n",
4965                        __FUNCTION__));
4966         }
4967 
4968         MFREE(bus->dhd->osh, nvram_ularray, varsize);
4969 #endif /* DHD_DEBUG */
4970 
4971         MFREE(bus->dhd->osh, vbuffer, varsize);
4972     }
4973 
4974 #ifdef MINIME
4975     phys_size = bus->ramsize;
4976 #else
4977     phys_size = REMAP_ENAB(bus) ? bus->ramsize : bus->orig_ramsize;
4978 #endif
4979 
4980     phys_size += bus->dongle_ram_base;
4981 
4982     /* adjust to the user specified RAM */
4983     DHD_INFO(("Physical memory size: %d, usable memory size: %d\n", phys_size,
4984               bus->ramsize));
4985     DHD_INFO(("Vars are at %d, orig varsize is %d\n", varaddr, varsize));
4986     varsize = ((phys_size - 0x4) - varaddr);
4987 
4988     /*
4989      * Determine the length token:
4990      * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits.
4991      */
4992 #ifdef DHD_DEBUG
4993     if (bcmerror) {
4994         varsizew = 0;
4995     } else
4996 #endif /* DHD_DEBUG */
4997     {
4998         varsizew = varsize / 0x4;
4999         varsizew = (~varsizew << 0x10) | (varsizew & 0x0000FFFF);
5000         varsizew = htol32(varsizew);
5001     }
5002 
5003     DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize, varsizew));
5004 
5005     /* Write the length token to the last word */
5006     bcmerror =
5007         dhdsdio_membytes(bus, TRUE, (phys_size - 0x4), (uint8 *)&varsizew, 0x4);
5008 
5009     return bcmerror;
5010 }
5011 
dhd_bus_is_multibp_capable(struct dhd_bus * bus)5012 bool dhd_bus_is_multibp_capable(struct dhd_bus *bus)
5013 {
5014     return MULTIBP_CAP(bus->sih);
5015 }
5016 
dhdsdio_download_state(dhd_bus_t * bus,bool enter)5017 static int dhdsdio_download_state(dhd_bus_t *bus, bool enter)
5018 {
5019     uint retries;
5020     int bcmerror = 0;
5021     int foundcr4 = 0;
5022 
5023     if (!bus->sih) {
5024         return BCME_ERROR;
5025     }
5026     /* To enter download state, disable ARM and reset SOCRAM.
5027      * To exit download state, simply reset ARM (default is RAM boot).
5028      */
5029     if (enter) {
5030         bus->alp_only = TRUE;
5031 
5032         if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
5033             !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
5034             if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
5035                 foundcr4 = 1;
5036             } else {
5037                 DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
5038                 bcmerror = BCME_ERROR;
5039                 goto fail;
5040             }
5041         }
5042 
5043         if (!foundcr4) {
5044             si_core_disable(bus->sih, 0);
5045             if (bcmsdh_regfail(bus->sdh)) {
5046                 bcmerror = BCME_SDIO_ERROR;
5047                 goto fail;
5048             }
5049 
5050             if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
5051                 DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
5052                 bcmerror = BCME_ERROR;
5053                 goto fail;
5054             }
5055 
5056             si_core_reset(bus->sih, 0, 0);
5057             if (bcmsdh_regfail(bus->sdh)) {
5058                 DHD_ERROR(
5059                     ("%s: Failure trying reset SOCRAM core?\n", __FUNCTION__));
5060                 bcmerror = BCME_SDIO_ERROR;
5061                 goto fail;
5062             }
5063 
5064             /* Disable remap for download */
5065             if (REMAP_ENAB(bus) && si_socdevram_remap_isenb(bus->sih)) {
5066                 dhdsdio_devram_remap(bus, FALSE);
5067             }
5068 
5069             if (CHIPID(bus->sih->chip) == BCM43430_CHIP_ID ||
5070                 CHIPID(bus->sih->chip) == BCM43018_CHIP_ID) {
5071                 /* Disabling Remap for SRAM_3 */
5072                 si_socram_set_bankpda(bus->sih, 0x3, 0x0);
5073             }
5074 
5075             /* Clear the top bit of memory */
5076             if (bus->ramsize) {
5077                 uint32 zeros = 0;
5078                 if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 0x4,
5079                                      (uint8 *)&zeros, 0x4) < 0) {
5080                     bcmerror = BCME_SDIO_ERROR;
5081                     goto fail;
5082                 }
5083             }
5084         } else {
5085             /* For CR4,
5086              * Halt ARM
5087              * Remove ARM reset
5088              * Read RAM base address [0x18_0000]
5089              * [next] Download firmware
5090              * [done at else] Populate the reset vector
5091              * [done at else] Remove ARM halt
5092              */
5093             /* Halt ARM & remove reset */
5094             si_core_reset(bus->sih, SICF_CPUHALT, SICF_CPUHALT);
5095         }
5096     } else {
5097         if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
5098             if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
5099                 DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
5100                 bcmerror = BCME_ERROR;
5101                 goto fail;
5102             }
5103 
5104             if (!si_iscoreup(bus->sih)) {
5105                 DHD_ERROR(
5106                     ("%s: SOCRAM core is down after reset?\n", __FUNCTION__));
5107                 bcmerror = BCME_ERROR;
5108                 goto fail;
5109             }
5110 
5111             if ((bcmerror = dhdsdio_write_vars(bus))) {
5112                 DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__));
5113                 goto fail;
5114             }
5115 
5116             /* Enable remap before ARM reset but after vars.
5117              * No backplane access in remap mode
5118              */
5119             if (REMAP_ENAB(bus) && !si_socdevram_remap_isenb(bus->sih)) {
5120                 dhdsdio_devram_remap(bus, TRUE);
5121             }
5122 #ifdef BCMSDIOLITE
5123             if (!si_setcore(bus->sih, CC_CORE_ID, 0)) {
5124                 DHD_ERROR(
5125                     ("%s: Can't set to Chip Common core?\n", __FUNCTION__));
5126                 bcmerror = BCME_ERROR;
5127                 goto fail;
5128             }
5129 #else
5130             if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
5131                 !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
5132                 DHD_ERROR(
5133                     ("%s: Can't change back to SDIO core?\n", __FUNCTION__));
5134                 bcmerror = BCME_ERROR;
5135                 goto fail;
5136             }
5137 #endif // endif
5138             W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
5139 
5140             if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
5141                 !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
5142                 DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
5143                 bcmerror = BCME_ERROR;
5144                 goto fail;
5145             }
5146         } else {
5147             /* cr4 has no socram, but tcm's */
5148             /* write vars */
5149             if ((bcmerror = dhdsdio_write_vars(bus))) {
5150                 DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__));
5151                 goto fail;
5152             }
5153 #ifdef BCMSDIOLITE
5154             if (!si_setcore(bus->sih, CC_CORE_ID, 0)) {
5155                 DHD_ERROR(
5156                     ("%s: Can't set to Chip Common core?\n", __FUNCTION__));
5157                 bcmerror = BCME_ERROR;
5158                 goto fail;
5159             }
5160 #else
5161             if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
5162                 !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
5163                 DHD_ERROR(
5164                     ("%s: Can't change back to SDIO core?\n", __FUNCTION__));
5165                 bcmerror = BCME_ERROR;
5166                 goto fail;
5167             }
5168 #endif // endif
5169             W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
5170 
5171             /* switch back to arm core again */
5172             if (!(si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) {
5173                 DHD_ERROR(("%s: Failed to find ARM CR4 core!\n", __FUNCTION__));
5174                 bcmerror = BCME_ERROR;
5175                 goto fail;
5176             }
5177             /* write address 0 with reset instruction */
5178             bcmerror = dhdsdio_membytes(bus, TRUE, 0, (uint8 *)&bus->resetinstr,
5179                                         sizeof(bus->resetinstr));
5180             if (bcmerror == BCME_OK) {
5181                 uint32 tmp;
5182                 /* verify write */
5183                 bcmerror =
5184                     dhdsdio_membytes(bus, FALSE, 0, (uint8 *)&tmp, sizeof(tmp));
5185                 if (bcmerror == BCME_OK && tmp != bus->resetinstr) {
5186                     DHD_ERROR(("%s: Failed to write 0x%08x to addr 0\n",
5187                                __FUNCTION__, bus->resetinstr));
5188                     DHD_ERROR(("%s: contents of addr 0 is 0x%08x\n",
5189                                __FUNCTION__, tmp));
5190                     bcmerror = BCME_SDIO_ERROR;
5191                     goto fail;
5192                 }
5193             }
5194             /* now remove reset and halt and continue to run CR4 */
5195         }
5196 
5197         si_core_reset(bus->sih, 0, 0);
5198         if (bcmsdh_regfail(bus->sdh)) {
5199             DHD_ERROR(
5200                 ("%s: Failure trying to reset ARM core?\n", __FUNCTION__));
5201             bcmerror = BCME_SDIO_ERROR;
5202             goto fail;
5203         }
5204 
5205         /* Allow HT Clock now that the ARM is running. */
5206         bus->alp_only = FALSE;
5207 
5208         bus->dhd->busstate = DHD_BUS_LOAD;
5209     }
5210 
5211 fail:
5212     /* Always return to SDIOD core */
5213     if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) {
5214         si_setcore(bus->sih, SDIOD_CORE_ID, 0);
5215     }
5216 
5217     return bcmerror;
5218 }
5219 
dhd_bus_iovar_op(dhd_pub_t * dhdp,const char * name,void * params,int plen,void * arg,int len,bool set)5220 int dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, void *params, int plen,
5221                      void *arg, int len, bool set)
5222 {
5223     dhd_bus_t *bus = dhdp->bus;
5224     const bcm_iovar_t *vi = NULL;
5225     int bcmerror = 0;
5226     int val_size;
5227     uint32 actionid;
5228 
5229     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5230 
5231     ASSERT(name);
5232     ASSERT(len >= 0);
5233 
5234     /* Get MUST have return space */
5235     ASSERT(set || (arg && len));
5236 
5237     /* Set does NOT take qualifiers */
5238     ASSERT(!set || (!params && !plen));
5239 
5240     /* Look up var locally; if not found pass to host driver */
5241     if ((vi = bcm_iovar_lookup(dhdsdio_iovars, name)) == NULL) {
5242         dhd_os_sdlock(bus->dhd);
5243 
5244         BUS_WAKE(bus);
5245 
5246         /* Turn on clock in case SD command needs backplane */
5247         dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
5248 
5249         bcmerror = bcmsdh_iovar_op(bus->sdh, name, params, plen, arg, len, set);
5250 
5251         /* Check for bus configuration changes of interest */
5252 
5253         /* If it was divisor change, read the new one */
5254         if (set && strcmp(name, "sd_divisor") == 0) {
5255             if (bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
5256                                 &bus->sd_divisor, sizeof(int32),
5257                                 FALSE) != BCME_OK) {
5258                 bus->sd_divisor = -1;
5259                 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
5260             } else {
5261                 DHD_INFO(("%s: noted %s update, value now %d\n", __FUNCTION__,
5262                           name, bus->sd_divisor));
5263             }
5264         }
5265         /* If it was a mode change, read the new one */
5266         if (set && strcmp(name, "sd_mode") == 0) {
5267             if (bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0, &bus->sd_mode,
5268                                 sizeof(int32), FALSE) != BCME_OK) {
5269                 bus->sd_mode = -1;
5270                 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
5271             } else {
5272                 DHD_INFO(("%s: noted %s update, value now %d\n", __FUNCTION__,
5273                           name, bus->sd_mode));
5274             }
5275         }
5276         /* Similar check for blocksize change */
5277         if (set && strcmp(name, "sd_blocksize") == 0) {
5278             int32 fnum = 0x2;
5279             if (bcmsdh_iovar_op(bus->sdh, "sd_blocksize", &fnum, sizeof(int32),
5280                                 &bus->blocksize, sizeof(int32),
5281                                 FALSE) != BCME_OK) {
5282                 bus->blocksize = 0;
5283                 DHD_ERROR(("%s: fail on fn %d %s get\n", __FUNCTION__, fnum,
5284                            "sd_blocksize"));
5285             } else {
5286                 DHD_INFO(("%s: noted fn %d %s update, value now %d\n",
5287                           __FUNCTION__, fnum, "sd_blocksize", bus->blocksize));
5288 
5289                 dhdsdio_tune_fifoparam(bus);
5290             }
5291         }
5292         bus->roundup = MIN(max_roundup, bus->blocksize);
5293 
5294         if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched &&
5295             NO_OTHER_ACTIVE_BUS_USER(bus)) {
5296             bus->activity = FALSE;
5297             dhdsdio_bussleep(bus, TRUE);
5298             dhdsdio_clkctl(bus, CLK_NONE, FALSE);
5299         }
5300 
5301         dhd_os_sdunlock(bus->dhd);
5302         goto exit;
5303     }
5304 
5305     DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__, name,
5306              (set ? "set" : "get"), len, plen));
5307 
5308     /* set up 'params' pointer in case this is a set command so that
5309      * the convenience int and bool code can be common to set and get
5310      */
5311     if (params == NULL) {
5312         params = arg;
5313         plen = len;
5314     }
5315 
5316     if (vi->type == IOVT_VOID) {
5317         val_size = 0;
5318     } else if (vi->type == IOVT_BUFFER) {
5319         val_size = len;
5320     } else {
5321         /* all other types are integer sized */
5322         val_size = sizeof(int);
5323     }
5324 
5325     actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
5326     bcmerror = dhdsdio_doiovar(bus, vi, actionid, name, params, plen, arg, len,
5327                                val_size);
5328 
5329 exit:
5330     return bcmerror;
5331 }
5332 
dhd_bus_stop(struct dhd_bus * bus,bool enforce_mutex)5333 void dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
5334 {
5335     osl_t *osh;
5336     uint32 local_hostintmask;
5337     uint8 saveclk;
5338     uint retries;
5339     int err;
5340     bool wlfc_enabled = FALSE;
5341     unsigned long flags;
5342 
5343     if (!bus->dhd) {
5344         return;
5345     }
5346 
5347     osh = bus->dhd->osh;
5348     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5349 
5350     bcmsdh_waitlockfree(bus->sdh);
5351 
5352     if (enforce_mutex) {
5353         dhd_os_sdlock(bus->dhd);
5354     }
5355 
5356     if ((bus->dhd->busstate == DHD_BUS_DOWN) || bus->dhd->hang_was_sent) {
5357         /* if Firmware already hangs disbale any interrupt */
5358         DHD_ERROR(("%s: making DHD_BUS_DOWN\n", __FUNCTION__));
5359         bus->dhd->busstate = DHD_BUS_DOWN;
5360         bus->hostintmask = 0;
5361         bcmsdh_intr_disable(bus->sdh);
5362     } else {
5363         BUS_WAKE(bus);
5364         if (KSO_ENAB(bus)) {
5365             /* Enable clock for device interrupts */
5366             dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
5367 
5368             /* Disable and clear interrupts at the chip level also */
5369             W_SDREG(0, &bus->regs->hostintmask, retries);
5370             local_hostintmask = bus->hostintmask;
5371             bus->hostintmask = 0;
5372 
5373             /* Force clocks on backplane to be sure F2 interrupt propagates */
5374             saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
5375                                       SBSDIO_FUNC1_CHIPCLKCSR, &err);
5376             if (!err) {
5377                 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
5378                                  (saveclk | SBSDIO_FORCE_HT), &err);
5379             }
5380             if (err) {
5381                 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n",
5382                            __FUNCTION__, err));
5383             }
5384 
5385             /* Turn off the bus (F2), free any pending packets */
5386             DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
5387             bcmsdh_intr_disable(bus->sdh);
5388 #ifndef BCMSPI
5389             bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN,
5390                              SDIO_FUNC_ENABLE_1, NULL);
5391 #endif /* !BCMSPI */
5392 
5393             /* Clear any pending interrupts now that F2 is disabled */
5394             W_SDREG(local_hostintmask, &bus->regs->intstatus, retries);
5395         }
5396 
5397         /* Turn off the backplane clock (only) */
5398         dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
5399 
5400         /* Change our idea of bus state */
5401         DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
5402         DHD_ERROR(("%s: making DHD_BUS_DOWN\n", __FUNCTION__));
5403         bus->dhd->busstate = DHD_BUS_DOWN;
5404         DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
5405     }
5406 
5407 #ifdef PROP_TXSTATUS
5408     wlfc_enabled =
5409         (dhd_wlfc_cleanup_txq(bus->dhd, NULL, 0) != WLFC_UNSUPPORTED);
5410 #endif // endif
5411     if (!wlfc_enabled) {
5412 #ifdef DHDTCPACK_SUPPRESS
5413         /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt,
5414          * when there is a newly coming packet from network stack.
5415          */
5416         dhd_tcpack_info_tbl_clean(bus->dhd);
5417 #endif /* DHDTCPACK_SUPPRESS */
5418         dhd_os_sdlock_txq(bus->dhd);
5419         /* Clear the data packet queues */
5420         pktq_flush(osh, &bus->txq, TRUE);
5421         dhd_os_sdunlock_txq(bus->dhd);
5422     }
5423 
5424     /* Clear any held glomming stuff */
5425     if (bus->glomd) {
5426         PKTFREE(osh, bus->glomd, FALSE);
5427     }
5428 
5429     if (bus->glom) {
5430         PKTFREE(osh, bus->glom, FALSE);
5431     }
5432 
5433     bus->glom = bus->glomd = NULL;
5434 
5435     /* Clear rx control and wake any waiters */
5436     bus->rxlen = 0;
5437     dhd_os_ioctl_resp_wake(bus->dhd);
5438 
5439     /* Reset some F2 state stuff */
5440     bus->rxskip = FALSE;
5441     bus->tx_seq = bus->rx_seq = 0;
5442 
5443     bus->tx_max = 0x4;
5444 
5445     if (enforce_mutex) {
5446         dhd_os_sdunlock(bus->dhd);
5447     }
5448 }
5449 
5450 #if defined(BCMSDIOH_TXGLOM) && defined(BCMSDIOH_STD)
5451 extern uint sd_txglom;
5452 #endif // endif
dhd_txglom_enable(dhd_pub_t * dhdp,bool enable)5453 void dhd_txglom_enable(dhd_pub_t *dhdp, bool enable)
5454 {
5455     /* can't enable host txglom by default, some platforms have no
5456      * (or crappy) ADMA support and txglom will cause kernel assertions (e.g.
5457      * panda board)
5458      */
5459     dhd_bus_t *bus = dhdp->bus;
5460 #ifdef BCMSDIOH_TXGLOM
5461     uint32 rxglom;
5462     int32 ret;
5463 
5464     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5465 
5466 #ifdef BCMSDIOH_STD
5467     if (enable) {
5468         enable = sd_txglom;
5469     }
5470 #endif /* BCMSDIOH_STD */
5471 
5472     if (enable) {
5473         rxglom = 1;
5474         ret = dhd_iovar(dhdp, 0, "bus:rxglom", (char *)&rxglom, sizeof(rxglom),
5475                         NULL, 0, TRUE);
5476         if (ret >= 0) {
5477             bus->txglom_enable = TRUE;
5478         } else {
5479 #ifdef BCMSDIOH_STD
5480             sd_txglom = 0;
5481 #endif /* BCMSDIOH_STD */
5482             bus->txglom_enable = FALSE;
5483         }
5484     } else
5485 #endif /* BCMSDIOH_TXGLOM */
5486         bus->txglom_enable = FALSE;
5487     printf("%s: enable %d\n", __FUNCTION__, bus->txglom_enable);
5488     dhd_conf_set_txglom_params(bus->dhd, bus->txglom_enable);
5489     bcmsdh_set_mode(bus->sdh, bus->dhd->conf->txglom_mode);
5490 }
5491 
dhd_bus_init(dhd_pub_t * dhdp,bool enforce_mutex)5492 int dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
5493 {
5494     dhd_bus_t *bus = dhdp->bus;
5495     dhd_timeout_t tmo;
5496     uint retries = 0;
5497     uint8 ready, enable;
5498     int err, ret = 0;
5499 #ifdef BCMSPI
5500     uint32 dstatus = 0; /* gSPI device-status bits */
5501 #else                   /* BCMSPI */
5502     uint8 saveclk;
5503 #endif                  /* BCMSPI */
5504 #if defined(SDIO_ISR_THREAD)
5505     int intr_extn;
5506 #endif
5507 
5508     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5509 
5510     ASSERT(bus->dhd);
5511     if (!bus->dhd) {
5512         return 0;
5513     }
5514 
5515     if (enforce_mutex) {
5516         dhd_os_sdlock(bus->dhd);
5517     }
5518 
5519     if (bus->sih->chip == BCM43362_CHIP_ID) {
5520         printf("%s: delay 100ms for BCM43362\n", __FUNCTION__);
5521         OSL_DELAY(0x186A0); // terence 20131209: delay for 43362
5522     }
5523 
5524     /* Make sure backplane clock is on, needed to generate F2 interrupt */
5525     dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
5526     if (bus->clkstate != CLK_AVAIL) {
5527         DHD_ERROR(("%s: clock state is wrong. state = %d\n", __FUNCTION__,
5528                    bus->clkstate));
5529         ret = -1;
5530         goto exit;
5531     }
5532 
5533 #ifdef BCMSPI
5534     /* fake "ready" for spi, wake-wlan would have already enabled F1 and F2 */
5535     ready = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
5536     enable = 0;
5537 
5538     /* Give the dongle some time to do its thing and set IOR2 */
5539     dhd_timeout_start(&tmo, WAIT_F2RXFIFORDY * WAIT_F2RXFIFORDY_DELAY * 0x3E8);
5540     while (!enable && !dhd_timeout_expired(&tmo)) {
5541         dstatus =
5542             bcmsdh_cfg_read_word(bus->sdh, SDIO_FUNC_0, SPID_STATUS_REG, NULL);
5543         if (dstatus & STATUS_F2_RX_READY) {
5544             enable = TRUE;
5545         }
5546     }
5547 
5548     if (enable) {
5549         DHD_ERROR(("Took %u usec before dongle is ready\n", tmo.elapsed));
5550         enable = ready;
5551     } else {
5552         DHD_ERROR(
5553             ("dstatus when timed out on f2-fifo not ready = 0x%x\n", dstatus));
5554         DHD_ERROR(("Waited %u usec, dongle is not ready\n", tmo.elapsed));
5555         ret = -1;
5556         goto exit;
5557     }
5558 
5559 #else /* !BCMSPI */
5560     /* Force clocks on backplane to be sure F2 interrupt propagates */
5561     saveclk =
5562         bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
5563 
5564     if (!err) {
5565         if (bus->sih->chip == BCM43012_CHIP_ID) {
5566             bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
5567                              (saveclk | SBSDIO_HT_AVAIL_REQ), &err);
5568         } else {
5569             bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
5570                              (saveclk | SBSDIO_FORCE_HT), &err);
5571         }
5572     }
5573 
5574     if (err) {
5575         DHD_ERROR(
5576             ("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
5577         ret = -1;
5578         goto exit;
5579     }
5580 
5581     /* Enable function 0x2 (frame transfers) */
5582     W_SDREG((SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT),
5583             &bus->regs->tosbmailboxdata, retries);
5584     enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
5585 
5586     bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
5587 
5588     /* Give the dongle some time to do its thing and set IOR2 */
5589     dhd_timeout_start(&tmo, DHD_WAIT_F2RDY * 0x3E8);
5590 
5591     ready = 0;
5592     while (ready != enable && !dhd_timeout_expired(&tmo)) {
5593         ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL);
5594     }
5595 
5596 #endif /* !BCMSPI */
5597 
5598     DHD_ERROR(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n", __FUNCTION__,
5599                enable, ready, tmo.elapsed));
5600 
5601 #if defined(SDIO_ISR_THREAD)
5602     if (dhdp->conf->intr_extn) {
5603         intr_extn =
5604             bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_INTR_EXTN, NULL);
5605         if (intr_extn & 0x1) {
5606             intr_extn |= 0x2;
5607             bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_INTR_EXTN,
5608                              intr_extn, NULL);
5609         }
5610     }
5611 #endif
5612 
5613     /* If F2 successfully enabled, set core and enable interrupts */
5614     if (ready == enable) {
5615         /* Make sure we're talking to the core. */
5616 #ifdef BCMSDIOLITE
5617         bus->regs = si_setcore(bus->sih, CC_CORE_ID, 0);
5618         ASSERT(bus->regs != NULL);
5619 #else
5620         if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0))) {
5621             bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0);
5622         }
5623         ASSERT(bus->regs != NULL);
5624 #endif // endif
5625         /* Set up the interrupt mask and enable interrupts */
5626         bus->hostintmask = HOSTINTMASK;
5627         /* corerev 4 could use the newer interrupt logic to detect the frames */
5628 #ifndef BCMSPI
5629         if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 0x4) &&
5630             (bus->rxint_mode != SDIO_DEVICE_HMB_RXINT)) {
5631             bus->hostintmask &= ~I_HMB_FRAME_IND;
5632             bus->hostintmask |= I_XMTDATA_AVAIL;
5633         }
5634 #endif /* BCMSPI */
5635         W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
5636 
5637         if (bus->sih->buscorerev < 0xF) {
5638             bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK,
5639                              (uint8)watermark, &err);
5640         }
5641 
5642         /* Set bus state according to enable result */
5643         dhdp->busstate = DHD_BUS_DATA;
5644 
5645         bus->intdis = FALSE;
5646         if (bus->intr) {
5647             DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
5648 #ifndef BCMSPI_ANDROID
5649             bcmsdh_intr_enable(bus->sdh);
5650 #endif /* !BCMSPI_ANDROID */
5651         } else {
5652             DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
5653             bcmsdh_intr_disable(bus->sdh);
5654         }
5655     }
5656 
5657 #ifndef BCMSPI
5658 
5659     else {
5660         /* Disable F2 again */
5661         enable = SDIO_FUNC_ENABLE_1;
5662         bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
5663     }
5664 
5665     if (dhdsdio_sr_cap(bus)) {
5666         dhdsdio_sr_init(bus);
5667         /* Masking the chip active interrupt  permanantly */
5668         bus->hostintmask &= ~I_CHIPACTIVE;
5669         W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
5670         DHD_INFO(("%s: disable I_CHIPACTIVE in hostintmask[0x%08x]\n",
5671                   __FUNCTION__, bus->hostintmask));
5672     } else {
5673         bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
5674                          saveclk, &err);
5675     }
5676 #endif /* !BCMSPI */
5677 
5678     /* If we didn't come up, turn off backplane clock */
5679     if (dhdp->busstate != DHD_BUS_DATA) {
5680         dhdsdio_clkctl(bus, CLK_NONE, FALSE);
5681     }
5682 
5683 exit:
5684     if (enforce_mutex) {
5685         dhd_os_sdunlock(bus->dhd);
5686     }
5687 
5688     return ret;
5689 }
5690 
dhdsdio_rxfail(dhd_bus_t * bus,bool abort,bool rtx)5691 static void dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx)
5692 {
5693     bcmsdh_info_t *sdh = bus->sdh;
5694     sdpcmd_regs_t *regs = bus->regs;
5695     uint retries = 0;
5696     uint16 lastrbc;
5697     uint8 hi, lo;
5698     int err;
5699 
5700     DHD_ERROR(("%s: %sterminate frame%s\n", __FUNCTION__,
5701                (abort ? "abort command, " : ""), (rtx ? ", send NAK" : "")));
5702 
5703     if (!KSO_ENAB(bus)) {
5704         DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
5705         return;
5706     }
5707 
5708     if (abort) {
5709         bcmsdh_abort(sdh, SDIO_FUNC_2);
5710     }
5711 
5712     bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM,
5713                      &err);
5714     if (err) {
5715         DHD_ERROR(("%s: SBSDIO_FUNC1_FRAMECTRL cmd err\n", __FUNCTION__));
5716         goto fail;
5717     }
5718     bus->f1regdata++;
5719 
5720     /* Wait until the packet has been flushed (device/FIFO stable) */
5721     for (lastrbc = retries = 0xffff; retries > 0; retries--) {
5722         hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL);
5723         lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, &err);
5724         if (err) {
5725             DHD_ERROR(("%s: SBSDIO_FUNC1_RFAMEBCLO cmd err\n", __FUNCTION__));
5726             goto fail;
5727         }
5728 
5729         bus->f1regdata += 0x2;
5730 
5731         if ((hi == 0) && (lo == 0)) {
5732             break;
5733         }
5734 
5735         if ((hi > (lastrbc >> 0x8)) && (lo > (lastrbc & 0x00ff))) {
5736             DHD_ERROR(("%s: count growing: last 0x%04x now 0x%04x\n",
5737                        __FUNCTION__, lastrbc, ((hi << 0x8) + lo)));
5738         }
5739         lastrbc = (hi << 0x8) + lo;
5740     }
5741 
5742     if (!retries) {
5743         DHD_ERROR(
5744             ("%s: count never zeroed: last 0x%04x\n", __FUNCTION__, lastrbc));
5745     } else {
5746         DHD_INFO(("%s: flush took %d iterations\n", __FUNCTION__,
5747                   (0xffff - retries)));
5748     }
5749 
5750     if (rtx) {
5751         bus->rxrtx++;
5752         W_SDREG(SMB_NAK, &regs->tosbmailbox, retries);
5753         bus->f1regdata++;
5754         if (retries <= retry_limit) {
5755             bus->rxskip = TRUE;
5756         }
5757     }
5758 
5759     /* Clear partial in any case */
5760     bus->nextlen = 0;
5761 
5762 fail:
5763     /* If we can't reach the device, signal failure */
5764     if (err || bcmsdh_regfail(sdh)) {
5765         DHD_ERROR(("%s: making DHD_BUS_DOWN\n", __FUNCTION__));
5766         bus->dhd->busstate = DHD_BUS_DOWN;
5767     }
5768 }
5769 
dhdsdio_read_control(dhd_bus_t * bus,uint8 * hdr,uint len,uint doff)5770 static void dhdsdio_read_control(dhd_bus_t *bus, uint8 *hdr, uint len,
5771                                  uint doff)
5772 {
5773     bcmsdh_info_t *sdh = bus->sdh;
5774     uint rdlen, pad;
5775 
5776     int sdret;
5777 
5778     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5779 
5780     /* Control data already received in aligned rxctl */
5781     if ((bus->bus == SPI_BUS) && (!bus->usebufpool)) {
5782         goto gotpkt;
5783     }
5784 
5785     ASSERT(bus->rxbuf);
5786     /* Set rxctl for frame (w/optional alignment) */
5787     bus->rxctl = bus->rxbuf;
5788     if (dhd_alignctl) {
5789         bus->rxctl += firstread;
5790         if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN))) {
5791             bus->rxctl += (DHD_SDALIGN - pad);
5792         }
5793         bus->rxctl -= firstread;
5794     }
5795     ASSERT(bus->rxctl >= bus->rxbuf);
5796 
5797     /* Copy the already-read portion over */
5798     bcopy(hdr, bus->rxctl, firstread);
5799     if (len <= firstread) {
5800         goto gotpkt;
5801     }
5802 
5803     /* Copy the full data pkt in gSPI case and process ioctl. */
5804     if (bus->bus == SPI_BUS) {
5805         bcopy(hdr, bus->rxctl, len);
5806         goto gotpkt;
5807     }
5808 
5809     /* Raise rdlen to next SDIO block to avoid tail command */
5810     rdlen = len - firstread;
5811     if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
5812         pad = bus->blocksize - (rdlen % bus->blocksize);
5813         if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
5814             ((len + pad) < bus->dhd->maxctl)) {
5815             rdlen += pad;
5816         }
5817     } else if (rdlen % DHD_SDALIGN) {
5818         rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
5819     }
5820 
5821     /* Satisfy length-alignment requirements */
5822     if (forcealign && (rdlen & (ALIGNMENT - 1))) {
5823         rdlen = ROUNDUP(rdlen, ALIGNMENT);
5824     }
5825 
5826     /* Drop if the read is too big or it exceeds our maximum */
5827     if ((rdlen + firstread) > bus->dhd->maxctl) {
5828         DHD_ERROR(("%s: %d-byte control read exceeds %d-byte buffer\n",
5829                    __FUNCTION__, rdlen, bus->dhd->maxctl));
5830         bus->dhd->rx_errors++;
5831         dhdsdio_rxfail(bus, FALSE, FALSE);
5832         goto done;
5833     }
5834 
5835     if ((len - doff) > bus->dhd->maxctl) {
5836         DHD_ERROR(
5837             ("%s: %d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
5838              __FUNCTION__, len, (len - doff), bus->dhd->maxctl));
5839         bus->dhd->rx_errors++;
5840         bus->rx_toolong++;
5841         dhdsdio_rxfail(bus, FALSE, FALSE);
5842         goto done;
5843     }
5844 
5845     /* Read remainder of frame body into the rxctl buffer */
5846     sdret =
5847         dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
5848                             (bus->rxctl + firstread), rdlen, NULL, NULL, NULL);
5849     bus->f2rxdata++;
5850     ASSERT(sdret != BCME_PENDING);
5851 
5852     /* Control frame failures need retransmission */
5853     if (sdret < 0) {
5854         DHD_ERROR(("%s: read %d control bytes failed: %d\n", __FUNCTION__,
5855                    rdlen, sdret));
5856         bus->rxc_errors++; /* dhd.rx_ctlerrs is higher level */
5857         dhdsdio_rxfail(bus, TRUE, TRUE);
5858         goto done;
5859     }
5860 
5861 gotpkt:
5862 
5863 #ifdef DHD_DEBUG
5864     if (DHD_BYTES_ON() && DHD_CTL_ON()) {
5865         prhex("RxCtrl", bus->rxctl, len);
5866     }
5867 #endif // endif
5868 
5869     /* Point to valid data and indicate its length */
5870     bus->rxctl += doff;
5871     bus->rxlen = len - doff;
5872 
5873 done:
5874     /* Awake any waiters */
5875     dhd_os_ioctl_resp_wake(bus->dhd);
5876 }
5877 int dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf,
5878                                  uint reorder_info_len, void **pkt,
5879                                  uint32 *pkt_count);
5880 
dhdsdio_rxglom(dhd_bus_t * bus,uint8 rxseq)5881 static uint8 dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
5882 {
5883     uint16 dlen, totlen;
5884     uint8 *dptr, num = 0;
5885 
5886     uint16 sublen, check;
5887     void *pfirst, *plast, *pnext;
5888     void *list_tail[DHD_MAX_IFS] = {NULL};
5889     void *list_head[DHD_MAX_IFS] = {NULL};
5890     uint8 idx;
5891     osl_t *osh = bus->dhd->osh;
5892 
5893     int errcode;
5894     uint8 chan, seq, doff, sfdoff;
5895     uint8 txmax;
5896     uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN];
5897     uint reorder_info_len;
5898 
5899     int ifidx = 0;
5900     bool usechain = bus->use_rxchain;
5901 
5902     /* If packets, issue read(s) and send up packet chain */
5903     /* Return sequence numbers consumed? */
5904 
5905     DHD_TRACE(
5906         ("dhdsdio_rxglom: start: glomd %p glom %p\n", bus->glomd, bus->glom));
5907 
5908     /* If there's a descriptor, generate the packet chain */
5909     if (bus->glomd) {
5910         dhd_os_sdlock_rxq(bus->dhd);
5911 
5912         pfirst = plast = pnext = NULL;
5913         dlen = (uint16)PKTLEN(osh, bus->glomd);
5914         dptr = PKTDATA(osh, bus->glomd);
5915         if (!dlen || (dlen & 1)) {
5916             DHD_ERROR(("%s: bad glomd len (%d), ignore descriptor\n",
5917                        __FUNCTION__, dlen));
5918             dlen = 0;
5919         }
5920 
5921         for (totlen = num = 0; dlen; num++) {
5922             /* Get (and move past) next length */
5923             sublen = ltoh16_ua(dptr);
5924             dlen -= sizeof(uint16);
5925             dptr += sizeof(uint16);
5926             if ((sublen < SDPCM_HDRLEN) ||
5927                 ((num == 0) && (sublen < (0x2 * SDPCM_HDRLEN)))) {
5928                 DHD_ERROR(("%s: descriptor len %d bad: %d\n", __FUNCTION__, num,
5929                            sublen));
5930                 pnext = NULL;
5931                 break;
5932             }
5933             if (sublen % DHD_SDALIGN) {
5934                 DHD_ERROR(("%s: sublen %d not a multiple of %d\n", __FUNCTION__,
5935                            sublen, DHD_SDALIGN));
5936                 usechain = FALSE;
5937             }
5938             totlen += sublen;
5939 
5940             /* For last frame, adjust read len so total is a block multiple */
5941             if (!dlen) {
5942                 sublen += (ROUNDUP(totlen, bus->blocksize) - totlen);
5943                 totlen = ROUNDUP(totlen, bus->blocksize);
5944             }
5945 
5946             /* Allocate/chain packet for next subframe */
5947             if ((pnext = PKTGET(osh, sublen + DHD_SDALIGN, FALSE)) == NULL) {
5948                 DHD_ERROR(("%s: PKTGET failed, num %d len %d\n", __FUNCTION__,
5949                            num, sublen));
5950                 break;
5951             }
5952             ASSERT(!PKTLINK(pnext));
5953             if (!pfirst) {
5954                 ASSERT(!plast);
5955                 pfirst = plast = pnext;
5956             } else {
5957                 ASSERT(plast);
5958                 PKTSETNEXT(osh, plast, pnext);
5959                 plast = pnext;
5960             }
5961 
5962             /* Adhere to start alignment requirements */
5963             PKTALIGN(osh, pnext, sublen, DHD_SDALIGN);
5964         }
5965 
5966         /* If all allocations succeeded, save packet chain in bus structure */
5967         if (pnext) {
5968             DHD_GLOM(("%s: allocated %d-byte packet chain for %d subframes\n",
5969                       __FUNCTION__, totlen, num));
5970             if (DHD_GLOM_ON() && bus->nextlen) {
5971                 if (totlen != bus->nextlen) {
5972                     DHD_GLOM(("%s: glomdesc mismatch: nextlen %d glomdesc %d "
5973                               "rxseq %d\n",
5974                               __FUNCTION__, bus->nextlen, totlen, rxseq));
5975                 }
5976             }
5977             bus->glom = pfirst;
5978             pfirst = pnext = NULL;
5979         } else {
5980             if (pfirst) {
5981                 PKTFREE(osh, pfirst, FALSE);
5982             }
5983             bus->glom = NULL;
5984             num = 0;
5985         }
5986 
5987         /* Done with descriptor packet */
5988         PKTFREE(osh, bus->glomd, FALSE);
5989         bus->glomd = NULL;
5990         bus->nextlen = 0;
5991 
5992         dhd_os_sdunlock_rxq(bus->dhd);
5993     }
5994 
5995     /* Ok -- either we just generated a packet chain, or had one from before */
5996     if (bus->glom) {
5997         if (DHD_GLOM_ON()) {
5998             DHD_GLOM(
5999                 ("%s: attempt superframe read, packet chain:\n", __FUNCTION__));
6000             for (pnext = bus->glom; pnext; pnext = PKTNEXT(osh, pnext)) {
6001                 DHD_GLOM(("    %p: %p len 0x%04x (%d)\n", pnext,
6002                           (uint8 *)PKTDATA(osh, pnext), PKTLEN(osh, pnext),
6003                           PKTLEN(osh, pnext)));
6004             }
6005         }
6006 
6007         pfirst = bus->glom;
6008         dlen = (uint16)pkttotlen(osh, pfirst);
6009 
6010         /* Do an SDIO read for the superframe.  Configurable iovar to
6011          * read directly into the chained packet, or allocate a large
6012          * packet and and copy into the chain.
6013          */
6014         if (usechain) {
6015             errcode = dhd_bcmsdh_recv_buf(
6016                 bus, bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2, F2SYNC,
6017                 (uint8 *)PKTDATA(osh, pfirst), dlen, pfirst, NULL, NULL);
6018         } else if (bus->dataptr) {
6019             errcode = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(bus->sdh),
6020                                           SDIO_FUNC_2, F2SYNC, bus->dataptr,
6021                                           dlen, NULL, NULL, NULL);
6022             sublen = (uint16)pktfrombuf(osh, pfirst, 0, dlen, bus->dataptr);
6023             if (sublen != dlen) {
6024                 DHD_ERROR(("%s: FAILED TO COPY, dlen %d sublen %d\n",
6025                            __FUNCTION__, dlen, sublen));
6026                 errcode = -1;
6027             }
6028             pnext = NULL;
6029             BCM_REFERENCE(pnext);
6030         } else {
6031             DHD_ERROR(("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", dlen));
6032             errcode = -1;
6033         }
6034         bus->f2rxdata++;
6035         ASSERT(errcode != BCME_PENDING);
6036 
6037         /* On failure, kill the superframe, allow a couple retries */
6038         if (errcode < 0) {
6039             DHD_ERROR(("%s: glom read of %d bytes failed: %d\n", __FUNCTION__,
6040                        dlen, errcode));
6041             bus->dhd->rx_errors++;
6042 
6043             if (bus->glomerr++ < 0x3) {
6044                 dhdsdio_rxfail(bus, TRUE, TRUE);
6045             } else {
6046                 bus->glomerr = 0;
6047                 dhdsdio_rxfail(bus, TRUE, FALSE);
6048                 dhd_os_sdlock_rxq(bus->dhd);
6049                 PKTFREE(osh, bus->glom, FALSE);
6050                 dhd_os_sdunlock_rxq(bus->dhd);
6051                 bus->rxglomfail++;
6052                 bus->glom = NULL;
6053             }
6054             return 0;
6055         }
6056 
6057 #ifdef DHD_DEBUG
6058         if (DHD_GLOM_ON()) {
6059             prhex("SUPERFRAME", PKTDATA(osh, pfirst),
6060                   MIN(PKTLEN(osh, pfirst), 0x30));
6061         }
6062 #endif // endif
6063 
6064         /* Validate the superframe header */
6065         dptr = (uint8 *)PKTDATA(osh, pfirst);
6066         sublen = ltoh16_ua(dptr);
6067         check = ltoh16_ua(dptr + sizeof(uint16));
6068 
6069         chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
6070         seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
6071         bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
6072         if ((bus->nextlen << 0x4) > MAX_RX_DATASZ) {
6073             DHD_INFO(("%s: got frame w/nextlen too large (%d) seq %d\n",
6074                       __FUNCTION__, bus->nextlen, seq));
6075             bus->nextlen = 0;
6076         }
6077         doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
6078         txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
6079 
6080         errcode = 0;
6081         if ((uint16) ~(sublen ^ check)) {
6082             DHD_ERROR(
6083                 ("%s (superframe): HW hdr error: len/check 0x%04x/0x%04x\n",
6084                  __FUNCTION__, sublen, check));
6085             errcode = -1;
6086         } else if (ROUNDUP(sublen, bus->blocksize) != dlen) {
6087             DHD_ERROR(
6088                 ("%s (superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n",
6089                  __FUNCTION__, sublen, ROUNDUP(sublen, bus->blocksize), dlen));
6090             errcode = -1;
6091         } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) !=
6092                    SDPCM_GLOM_CHANNEL) {
6093             DHD_ERROR(("%s (superframe): bad channel %d\n", __FUNCTION__,
6094                        SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN])));
6095             errcode = -1;
6096         } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) {
6097             DHD_ERROR(
6098                 ("%s (superframe): got second descriptor?\n", __FUNCTION__));
6099             errcode = -1;
6100         } else if ((doff < SDPCM_HDRLEN) ||
6101                    (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN))) {
6102             DHD_ERROR((
6103                 "%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n",
6104                 __FUNCTION__, doff, sublen, PKTLEN(osh, pfirst), SDPCM_HDRLEN));
6105             errcode = -1;
6106         }
6107 
6108         /* Check sequence number of superframe SW header */
6109         if (rxseq != seq) {
6110             DHD_INFO(("%s: (superframe) rx_seq %d, expected %d\n", __FUNCTION__,
6111                       seq, rxseq));
6112             bus->rx_badseq++;
6113             rxseq = seq;
6114         }
6115 
6116         /* Check window for sanity */
6117         if ((uint8)(txmax - bus->tx_seq) > 0x70) {
6118             DHD_INFO(("%s: got unlikely tx max %d with tx_seq %d\n",
6119                       __FUNCTION__, txmax, bus->tx_seq));
6120             txmax = bus->tx_max;
6121         }
6122         bus->tx_max = txmax;
6123 
6124         /* Remove superframe header, remember offset */
6125         PKTPULL(osh, pfirst, doff);
6126         sfdoff = doff;
6127 
6128         /* Validate all the subframe headers */
6129         for (num = 0, pnext = pfirst; pnext && !errcode;
6130              num++, pnext = PKTNEXT(osh, pnext)) {
6131             dptr = (uint8 *)PKTDATA(osh, pnext);
6132             dlen = (uint16)PKTLEN(osh, pnext);
6133             sublen = ltoh16_ua(dptr);
6134             check = ltoh16_ua(dptr + sizeof(uint16));
6135             chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
6136             doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
6137 #ifdef DHD_DEBUG
6138             if (DHD_GLOM_ON()) {
6139                 prhex("subframe", dptr, 0x20);
6140             }
6141 #endif // endif
6142 
6143             if ((uint16) ~(sublen ^ check)) {
6144                 DHD_ERROR(("%s (subframe %d): HW hdr error: "
6145                            "len/check 0x%04x/0x%04x\n",
6146                            __FUNCTION__, num, sublen, check));
6147                 errcode = -1;
6148             } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) {
6149                 DHD_ERROR(("%s (subframe %d): length mismatch: "
6150                            "len 0x%04x, expect 0x%04x\n",
6151                            __FUNCTION__, num, sublen, dlen));
6152                 errcode = -1;
6153             } else if ((chan != SDPCM_DATA_CHANNEL) &&
6154                        (chan != SDPCM_EVENT_CHANNEL)) {
6155                 DHD_ERROR(("%s (subframe %d): bad channel %d\n", __FUNCTION__,
6156                            num, chan));
6157                 errcode = -1;
6158             } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) {
6159                 DHD_ERROR(
6160                     ("%s (subframe %d): Bad data offset %d: HW %d min %d\n",
6161                      __FUNCTION__, num, doff, sublen, SDPCM_HDRLEN));
6162                 errcode = -1;
6163             }
6164         }
6165 
6166         if (errcode) {
6167             /* Terminate frame on error, request a couple retries */
6168             if (bus->glomerr++ < 0x3) {
6169                 /* Restore superframe header space */
6170                 PKTPUSH(osh, pfirst, sfdoff);
6171                 dhdsdio_rxfail(bus, TRUE, TRUE);
6172             } else {
6173                 bus->glomerr = 0;
6174                 dhdsdio_rxfail(bus, TRUE, FALSE);
6175                 dhd_os_sdlock_rxq(bus->dhd);
6176                 PKTFREE(osh, bus->glom, FALSE);
6177                 dhd_os_sdunlock_rxq(bus->dhd);
6178                 bus->rxglomfail++;
6179                 bus->glom = NULL;
6180             }
6181             bus->nextlen = 0;
6182             return 0;
6183         }
6184 
6185         /* Basic SD framing looks ok - process each packet (header) */
6186         bus->glom = NULL;
6187         plast = NULL;
6188 
6189         dhd_os_sdlock_rxq(bus->dhd);
6190         for (num = 0; pfirst; rxseq++, pfirst = pnext) {
6191             pnext = PKTNEXT(osh, pfirst);
6192             PKTSETNEXT(osh, pfirst, NULL);
6193 
6194             dptr = (uint8 *)PKTDATA(osh, pfirst);
6195             sublen = ltoh16_ua(dptr);
6196             chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
6197             seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
6198             doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
6199 
6200             DHD_GLOM(
6201                 ("%s: Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n",
6202                  __FUNCTION__, num, pfirst, PKTDATA(osh, pfirst),
6203                  PKTLEN(osh, pfirst), sublen, chan, seq));
6204 
6205             ASSERT((chan == SDPCM_DATA_CHANNEL) ||
6206                    (chan == SDPCM_EVENT_CHANNEL));
6207 
6208             if (rxseq != seq) {
6209                 DHD_GLOM(
6210                     ("%s: rx_seq %d, expected %d\n", __FUNCTION__, seq, rxseq));
6211                 bus->rx_badseq++;
6212                 rxseq = seq;
6213             }
6214 
6215 #ifdef DHD_DEBUG
6216             if (DHD_BYTES_ON() && DHD_DATA_ON()) {
6217                 prhex("Rx Subframe Data", dptr, dlen);
6218             }
6219 #endif // endif
6220 
6221             PKTSETLEN(osh, pfirst, sublen);
6222             PKTPULL(osh, pfirst, doff);
6223 
6224             reorder_info_len = sizeof(reorder_info_buf);
6225 
6226             if (PKTLEN(osh, pfirst) == 0) {
6227                 PKTFREE(bus->dhd->osh, pfirst, FALSE);
6228                 continue;
6229             } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst,
6230                                         reorder_info_buf,
6231                                         &reorder_info_len) != 0) {
6232                 DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
6233                 bus->dhd->rx_errors++;
6234                 PKTFREE(osh, pfirst, FALSE);
6235                 continue;
6236             }
6237             if (reorder_info_len) {
6238                 uint32 free_buf_count;
6239                 void *ppfirst;
6240 
6241                 ppfirst = pfirst;
6242                 /* Reordering info from the firmware */
6243                 dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf,
6244                                              reorder_info_len, &ppfirst,
6245                                              &free_buf_count);
6246 
6247                 if (free_buf_count == 0) {
6248                     continue;
6249                 } else {
6250                     void *temp;
6251 
6252                     /*  go to the end of the chain and attach the pnext there */
6253                     temp = ppfirst;
6254                     while (PKTNEXT(osh, temp) != NULL) {
6255                         temp = PKTNEXT(osh, temp);
6256                     }
6257                     pfirst = temp;
6258                     if (list_tail[ifidx] == NULL) {
6259                         list_head[ifidx] = ppfirst;
6260                     } else {
6261                         PKTSETNEXT(osh, list_tail[ifidx], ppfirst);
6262                     }
6263                     list_tail[ifidx] = pfirst;
6264                 }
6265 
6266                 num += (uint8)free_buf_count;
6267             } else {
6268                 /* this packet will go up, link back into chain and count it */
6269 
6270                 if (list_tail[ifidx] == NULL) {
6271                     list_head[ifidx] = list_tail[ifidx] = pfirst;
6272                 } else {
6273                     PKTSETNEXT(osh, list_tail[ifidx], pfirst);
6274                     list_tail[ifidx] = pfirst;
6275                 }
6276                 num++;
6277             }
6278 #ifdef DHD_DEBUG
6279             if (DHD_GLOM_ON()) {
6280                 DHD_GLOM(("%s subframe %d to stack, %p(%p/%d) nxt/lnk %p/%p\n",
6281                           __FUNCTION__, num, pfirst, PKTDATA(osh, pfirst),
6282                           PKTLEN(osh, pfirst), PKTNEXT(osh, pfirst),
6283                           PKTLINK(pfirst)));
6284                 prhex("", (uint8 *)PKTDATA(osh, pfirst),
6285                       MIN(PKTLEN(osh, pfirst), 0x20));
6286             }
6287 #endif /* DHD_DEBUG */
6288         }
6289         dhd_os_sdunlock_rxq(bus->dhd);
6290 
6291         for (idx = 0; idx < DHD_MAX_IFS; idx++) {
6292             if (list_head[idx]) {
6293                 void *temp;
6294                 uint8 cnt = 0;
6295                 temp = list_head[idx];
6296                 do {
6297                     temp = PKTNEXT(osh, temp);
6298                     cnt++;
6299                 } while (temp);
6300                 if (cnt) {
6301                     dhd_os_sdunlock(bus->dhd);
6302                     dhd_rx_frame(bus->dhd, idx, list_head[idx], cnt, 0);
6303                     dhd_os_sdlock(bus->dhd);
6304 #if defined(SDIO_ISR_THREAD)
6305                     /* terence 20150615: fix for below error due to bussleep in
6306                      * watchdog after dhd_os_sdunlock here, so call BUS_WAKE to
6307                      * wake up bus again dhd_bcmsdh_recv_buf: Device asleep
6308                      * dhdsdio_readframes: RXHEADER FAILED: -40
6309                      * dhdsdio_rxfail: abort command, terminate frame, send NAK
6310                      */
6311                     BUS_WAKE(bus);
6312 #endif
6313                 }
6314             }
6315         }
6316         bus->rxglomframes++;
6317         bus->rxglompkts += num;
6318     }
6319     return num;
6320 }
6321 
6322 /* Return TRUE if there may be more frames to read */
dhdsdio_readframes(dhd_bus_t * bus,uint maxframes,bool * finished)6323 static uint dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
6324 {
6325     osl_t *osh = bus->dhd->osh;
6326     bcmsdh_info_t *sdh = bus->sdh;
6327 
6328     uint16 len, check;     /* Extracted hardware header fields */
6329     uint8 chan, seq, doff; /* Extracted software header fields */
6330     uint8 fcbits;          /* Extracted fcbits from software header */
6331     uint8 delta;
6332 
6333     void *pkt;       /* Packet for event or data frames */
6334     uint16 pad;      /* Number of pad bytes to read */
6335     uint16 rdlen;    /* Total number of bytes to read */
6336     uint8 rxseq;     /* Next sequence number to expect */
6337     uint rxleft = 0; /* Remaining number of frames allowed */
6338     int sdret;       /* Return code from bcmsdh calls */
6339     uint8 txmax;     /* Maximum tx sequence offered */
6340 #ifdef BCMSPI
6341     uint32 dstatus = 0;  /* gSPI device status bits of */
6342 #endif                   /* BCMSPI */
6343     bool len_consistent; /* Result of comparing readahead len and len from
6344                             hw-hdr */
6345     uint8 *rxbuf;
6346     int ifidx = 0;
6347     uint rxcount = 0; /* Total frames read */
6348     uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN];
6349     uint reorder_info_len;
6350     uint pkt_count;
6351 
6352 #if defined(DHD_DEBUG) || defined(SDTEST)
6353     bool sdtest = FALSE; /* To limit message spew from test mode */
6354 #endif                   // endif
6355 
6356     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6357     bus->readframes = TRUE;
6358 
6359     if (!KSO_ENAB(bus)) {
6360         DHD_ERROR(("%s: KSO off\n", __FUNCTION__));
6361         bus->readframes = FALSE;
6362         return 0;
6363     }
6364 
6365     ASSERT(maxframes);
6366 
6367 #ifdef SDTEST
6368     /* Allow pktgen to override maxframes */
6369     if (bus->pktgen_count && (bus->pktgen_mode == DHD_PKTGEN_RECV)) {
6370         maxframes = bus->pktgen_count;
6371         sdtest = TRUE;
6372     }
6373 #endif // endif
6374 
6375     /* Not finished unless we encounter no more frames indication */
6376     *finished = FALSE;
6377 
6378 #ifdef BCMSPI
6379     /* Get pktlen from gSPI device F0 reg. */
6380     if (bus->bus == SPI_BUS) {
6381         /* Peek in dstatus bits and find out size to do rx-read. */
6382         dstatus = bcmsdh_get_dstatus(bus->sdh);
6383         if (dstatus == 0) {
6384             DHD_ERROR(
6385                 ("%s:ZERO spi dstatus, a case observed in PR61352 hit !!!\n",
6386                  __FUNCTION__));
6387         }
6388 
6389         DHD_TRACE(("Device status from regread = 0x%x\n", dstatus));
6390         DHD_TRACE(("Device status from bit-reconstruction = 0x%x\n",
6391                    bcmsdh_get_dstatus((void *)bus->sdh)));
6392 
6393         if ((dstatus & STATUS_F2_PKT_AVAILABLE) &&
6394             (((dstatus & STATUS_UNDERFLOW)) == 0)) {
6395             bus->nextlen =
6396                 ((dstatus & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT);
6397             /* '0' size with pkt-available interrupt is eqvt to 2048 bytes */
6398             bus->nextlen = (bus->nextlen == 0) ? SPI_MAX_PKT_LEN : bus->nextlen;
6399             if (bus->dwordmode) {
6400                 bus->nextlen = bus->nextlen << 0x2;
6401             }
6402             DHD_TRACE(("Entering %s: length to be read from gSPI = %d\n",
6403                        __FUNCTION__, bus->nextlen));
6404         } else {
6405             if (dstatus & STATUS_F2_PKT_AVAILABLE) {
6406                 DHD_ERROR(("Underflow during %s.\n", __FUNCTION__));
6407             } else {
6408                 DHD_ERROR(("False pkt-available intr.\n"));
6409             }
6410             *finished = TRUE;
6411             return (maxframes - rxleft);
6412         }
6413     }
6414 #endif /* BCMSPI */
6415 
6416     for (rxseq = bus->rx_seq, rxleft = maxframes;
6417          !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN;
6418          rxseq++, rxleft--) {
6419 #ifdef DHDTCPACK_SUP_DBG
6420         if (bus->dhd->tcpack_sup_mode != TCPACK_SUP_DELAYTX) {
6421             if (bus->dotxinrx == FALSE) {
6422                 DHD_ERROR(("%s %d: dotxinrx FALSE with tcpack_sub_mode %d\n",
6423                            __FUNCTION__, __LINE__, bus->dhd->tcpack_sup_mode));
6424             }
6425         }
6426 #ifdef DEBUG_COUNTER
6427         else if (pktq_mlen(&bus->txq, ~bus->flowcontrol) > 0) {
6428             tack_tbl.cnt[bus->dotxinrx ? 0x6 : 0x7]++;
6429         }
6430 #endif /* DEBUG_COUNTER */
6431 #endif /* DHDTCPACK_SUP_DBG */
6432         /* tx more to improve rx performance */
6433         if (TXCTLOK(bus) && bus->ctrl_frame_stat &&
6434             (bus->clkstate == CLK_AVAIL)) {
6435             dhdsdio_sendpendctl(bus);
6436         } else if (bus->dotxinrx && (bus->clkstate == CLK_AVAIL) &&
6437                    !bus->fcstate && DATAOK(bus) &&
6438                    (pktq_mlen(&bus->txq, ~bus->flowcontrol) >
6439                     bus->txinrx_thres)) {
6440             dhdsdio_sendfromq(bus, dhd_txbound);
6441 #ifdef DHDTCPACK_SUPPRESS
6442             /* In TCPACK_SUP_DELAYTX mode, do txinrx only if
6443              * 1. Any DATA packet to TX
6444              * 2. TCPACK to TCPDATA PSH packets.
6445              * in bus txq.
6446              */
6447             bus->dotxinrx = (bus->dhd->tcpack_sup_mode == TCPACK_SUP_DELAYTX)
6448                                 ? FALSE
6449                                 : TRUE;
6450 #endif // endif
6451         }
6452 
6453         /* Handle glomming separately */
6454         if (bus->glom || bus->glomd) {
6455             uint8 cnt;
6456             DHD_GLOM(("%s: calling rxglom: glomd %p, glom %p\n", __FUNCTION__,
6457                       bus->glomd, bus->glom));
6458             cnt = dhdsdio_rxglom(bus, rxseq);
6459             DHD_GLOM(("%s: rxglom returned %d\n", __FUNCTION__, cnt));
6460             rxseq += cnt - 1;
6461             rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1;
6462             continue;
6463         }
6464 
6465         /* Try doing single read if we can */
6466         if (dhd_readahead && bus->nextlen) {
6467             uint16 nextlen = bus->nextlen;
6468             bus->nextlen = 0;
6469 
6470             if (bus->bus == SPI_BUS) {
6471                 rdlen = len = nextlen;
6472             } else {
6473                 rdlen = len = nextlen << 0x4;
6474 
6475                 /* Pad read to blocksize for efficiency */
6476                 if (bus->roundup && bus->blocksize &&
6477                     (rdlen > bus->blocksize)) {
6478                     pad = bus->blocksize - (rdlen % bus->blocksize);
6479                     if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
6480                         ((rdlen + pad + firstread) < MAX_RX_DATASZ)) {
6481                         rdlen += pad;
6482                     }
6483                 } else if (rdlen % DHD_SDALIGN) {
6484                     rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
6485                 }
6486             }
6487 
6488             /* We use bus->rxctl buffer in WinXP for initial control pkt
6489              * receives. Later we use buffer-poll for data as well as control
6490              * packets. This is required because dhd receives full frame in gSPI
6491              * unlike SDIO. After the frame is received we have to distinguish
6492              * whether it is data or non-data frame.
6493              */
6494             /* Allocate a packet buffer */
6495             dhd_os_sdlock_rxq(bus->dhd);
6496             if (!(pkt = PKTGET(osh, rdlen + DHD_SDALIGN, FALSE))) {
6497                 if (bus->bus == SPI_BUS) {
6498                     bus->usebufpool = FALSE;
6499                     bus->rxctl = bus->rxbuf;
6500                     if (dhd_alignctl) {
6501                         bus->rxctl += firstread;
6502                         if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN))) {
6503                             bus->rxctl += (DHD_SDALIGN - pad);
6504                         }
6505                         bus->rxctl -= firstread;
6506                     }
6507                     ASSERT(bus->rxctl >= bus->rxbuf);
6508                     rxbuf = bus->rxctl;
6509                     /* Read the entire frame */
6510                     sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh),
6511                                                 SDIO_FUNC_2, F2SYNC, rxbuf,
6512                                                 rdlen, NULL, NULL, NULL);
6513                     bus->f2rxdata++;
6514                     ASSERT(sdret != BCME_PENDING);
6515 
6516 #ifdef BCMSPI
6517                     if (bcmsdh_get_dstatus((void *)bus->sdh) &
6518                         STATUS_UNDERFLOW) {
6519                         bus->nextlen = 0;
6520                         *finished = TRUE;
6521                         DHD_ERROR(("%s: read %d control bytes failed "
6522                                    "due to spi underflow\n",
6523                                    __FUNCTION__, rdlen));
6524                         /* dhd.rx_ctlerrs is higher level */
6525                         bus->rxc_errors++;
6526                         dhd_os_sdunlock_rxq(bus->dhd);
6527                         continue;
6528                     }
6529 #endif /* BCMSPI */
6530 
6531                     /* Control frame failures need retransmission */
6532                     if (sdret < 0) {
6533                         DHD_ERROR(("%s: read %d control bytes failed: %d\n",
6534                                    __FUNCTION__, rdlen, sdret));
6535                         /* dhd.rx_ctlerrs is higher level */
6536                         bus->rxc_errors++;
6537                         dhd_os_sdunlock_rxq(bus->dhd);
6538                         dhdsdio_rxfail(bus, TRUE,
6539                                        (bus->bus == SPI_BUS) ? FALSE : TRUE);
6540                         continue;
6541                     }
6542                 } else {
6543                     /* Give up on data, request rtx of events */
6544                     DHD_ERROR(("%s (nextlen): PKTGET failed: len %d rdlen %d "
6545                                "expected rxseq %d\n",
6546                                __FUNCTION__, len, rdlen, rxseq));
6547                     /* Just go try again w/normal header read */
6548                     dhd_os_sdunlock_rxq(bus->dhd);
6549                     continue;
6550                 }
6551             } else {
6552                 if (bus->bus == SPI_BUS) {
6553                     bus->usebufpool = TRUE;
6554                 }
6555 
6556                 ASSERT(!PKTLINK(pkt));
6557                 PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
6558                 rxbuf = (uint8 *)PKTDATA(osh, pkt);
6559                 /* Read the entire frame */
6560                 sdret =
6561                     dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2,
6562                                         F2SYNC, rxbuf, rdlen, pkt, NULL, NULL);
6563                 bus->f2rxdata++;
6564                 ASSERT(sdret != BCME_PENDING);
6565 #ifdef BCMSPI
6566                 if (bcmsdh_get_dstatus((void *)bus->sdh) & STATUS_UNDERFLOW) {
6567                     bus->nextlen = 0;
6568                     *finished = TRUE;
6569                     DHD_ERROR(("%s (nextlen): read %d bytes failed due "
6570                                "to spi underflow\n",
6571                                __FUNCTION__, rdlen));
6572                     PKTFREE(bus->dhd->osh, pkt, FALSE);
6573                     bus->dhd->rx_errors++;
6574                     dhd_os_sdunlock_rxq(bus->dhd);
6575                     continue;
6576                 }
6577 #endif /* BCMSPI */
6578 
6579                 if (sdret < 0) {
6580                     DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n",
6581                                __FUNCTION__, rdlen, sdret));
6582                     PKTFREE(bus->dhd->osh, pkt, FALSE);
6583                     bus->dhd->rx_errors++;
6584                     dhd_os_sdunlock_rxq(bus->dhd);
6585                     /* Force retry w/normal header read.  Don't attempt NAK for
6586                      * gSPI
6587                      */
6588                     dhdsdio_rxfail(bus, TRUE,
6589                                    (bus->bus == SPI_BUS) ? FALSE : TRUE);
6590                     continue;
6591                 }
6592             }
6593             dhd_os_sdunlock_rxq(bus->dhd);
6594 
6595             /* Now check the header */
6596             bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN);
6597 
6598             /* Extract hardware header fields */
6599             len = ltoh16_ua(bus->rxhdr);
6600             check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
6601             /* All zeros means readahead info was bad */
6602             if (!(len | check)) {
6603                 DHD_INFO(("%s (nextlen): read zeros in HW header???\n",
6604                           __FUNCTION__));
6605                 dhd_os_sdlock_rxq(bus->dhd);
6606                 PKTFREE2();
6607                 dhd_os_sdunlock_rxq(bus->dhd);
6608                 GSPI_PR55150_BAILOUT;
6609                 continue;
6610             }
6611 
6612             /* Validate check bytes */
6613             if ((uint16) ~(len ^ check)) {
6614                 DHD_ERROR(("%s (nextlen): HW hdr error: nextlen/len/check"
6615                            " 0x%04x/0x%04x/0x%04x\n",
6616                            __FUNCTION__, nextlen, len, check));
6617                 dhd_os_sdlock_rxq(bus->dhd);
6618                 PKTFREE2();
6619                 dhd_os_sdunlock_rxq(bus->dhd);
6620                 bus->rx_badhdr++;
6621                 dhdsdio_rxfail(bus, FALSE, FALSE);
6622                 GSPI_PR55150_BAILOUT;
6623                 continue;
6624             }
6625 
6626             /* Validate frame length */
6627             if (len < SDPCM_HDRLEN) {
6628                 DHD_ERROR(("%s (nextlen): HW hdr length invalid: %d\n",
6629                            __FUNCTION__, len));
6630                 dhd_os_sdlock_rxq(bus->dhd);
6631                 PKTFREE2();
6632                 dhd_os_sdunlock_rxq(bus->dhd);
6633                 GSPI_PR55150_BAILOUT;
6634                 continue;
6635             }
6636 
6637             /* Check for consistency with readahead info */
6638 #ifdef BCMSPI
6639             if (bus->bus == SPI_BUS) {
6640                 if (bus->dwordmode) {
6641                     uint16 spilen;
6642                     spilen = ROUNDUP(len, 0x4);
6643                     len_consistent = (nextlen != spilen);
6644                 } else {
6645                     len_consistent = (nextlen != len);
6646                 }
6647             } else
6648 #endif /* BCMSPI */
6649                 len_consistent = (nextlen != (ROUNDUP(len, 0x10) >> 0x4));
6650             if (len_consistent) {
6651                 /* Mismatch, force retry w/normal header (may be >4K) */
6652                 DHD_ERROR(("%s (nextlen): mismatch, nextlen %d len %d rnd %d; "
6653                            "expected rxseq %d\n",
6654                            __FUNCTION__, nextlen, len, ROUNDUP(len, 0x10),
6655                            rxseq));
6656                 dhd_os_sdlock_rxq(bus->dhd);
6657                 PKTFREE2();
6658                 dhd_os_sdunlock_rxq(bus->dhd);
6659                 dhdsdio_rxfail(bus, TRUE, (bus->bus == SPI_BUS) ? FALSE : TRUE);
6660                 GSPI_PR55150_BAILOUT;
6661                 continue;
6662             }
6663 
6664             /* Extract software header fields */
6665             chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6666             seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6667             doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6668             txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6669 
6670 #ifdef BCMSPI
6671             /* Save the readahead length if there is one */
6672             if (bus->bus == SPI_BUS) {
6673                 /* Use reconstructed dstatus bits and find out readahead size */
6674                 dstatus = bcmsdh_get_dstatus((void *)bus->sdh);
6675                 DHD_INFO(("Device status from bit-reconstruction = 0x%x\n",
6676                           bcmsdh_get_dstatus((void *)bus->sdh)));
6677                 if (dstatus & STATUS_F2_PKT_AVAILABLE) {
6678                     bus->nextlen = ((dstatus & STATUS_F2_PKT_LEN_MASK) >>
6679                                     STATUS_F2_PKT_LEN_SHIFT);
6680                     bus->nextlen =
6681                         (bus->nextlen == 0) ? SPI_MAX_PKT_LEN : bus->nextlen;
6682                     if (bus->dwordmode) {
6683                         bus->nextlen = bus->nextlen << 0x2;
6684                     }
6685                     DHD_INFO(("readahead len from gSPI = %d \n", bus->nextlen));
6686                     bus->dhd->rx_readahead_cnt++;
6687                 } else {
6688                     bus->nextlen = 0;
6689                     *finished = TRUE;
6690                 }
6691             } else {
6692 #endif /* BCMSPI */
6693                 bus->nextlen =
6694                     bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
6695                 if ((bus->nextlen << 0x4) > MAX_RX_DATASZ) {
6696                     DHD_INFO(("%s (nextlen): got frame w/nextlen too large"
6697                               " (%d), seq %d\n",
6698                               __FUNCTION__, bus->nextlen, seq));
6699                     bus->nextlen = 0;
6700                 }
6701 
6702                 bus->dhd->rx_readahead_cnt++;
6703 #ifdef BCMSPI
6704             }
6705 #endif /* BCMSPI */
6706             /* Handle Flow Control */
6707             fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6708 
6709             delta = 0;
6710             if (~bus->flowcontrol & fcbits) {
6711                 bus->fc_xoff++;
6712                 delta = 1;
6713             }
6714             if (bus->flowcontrol & ~fcbits) {
6715                 bus->fc_xon++;
6716                 delta = 1;
6717             }
6718 
6719             if (delta) {
6720                 bus->fc_rcvd++;
6721                 bus->flowcontrol = fcbits;
6722             }
6723 
6724             /* Check and update sequence number */
6725             if (rxseq != seq) {
6726                 DHD_INFO(("%s (nextlen): rx_seq %d, expected %d\n",
6727                           __FUNCTION__, seq, rxseq));
6728                 bus->rx_badseq++;
6729                 rxseq = seq;
6730             }
6731 
6732             /* Check window for sanity */
6733             if ((uint8)(txmax - bus->tx_seq) > 0x70) {
6734 #ifdef BCMSPI
6735                 if ((bus->bus == SPI_BUS) && !(dstatus & STATUS_F2_RX_READY)) {
6736                     DHD_INFO(("%s: got unlikely tx max %d with tx_seq %d\n",
6737                               __FUNCTION__, txmax, bus->tx_seq));
6738                     txmax = bus->tx_seq + 0x2;
6739                 } else {
6740 #endif /* BCMSPI */
6741                     DHD_INFO(("%s: got unlikely tx max %d with tx_seq %d\n",
6742                               __FUNCTION__, txmax, bus->tx_seq));
6743                     txmax = bus->tx_max;
6744 #ifdef BCMSPI
6745                 }
6746 #endif /* BCMSPI */
6747             }
6748             bus->tx_max = txmax;
6749 
6750 #ifdef DHD_DEBUG
6751             if (DHD_BYTES_ON() && DHD_DATA_ON()) {
6752                 prhex("Rx Data", rxbuf, len);
6753             } else if (DHD_HDRS_ON()) {
6754                 prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
6755             }
6756 #endif // endif
6757 
6758             if (chan == SDPCM_CONTROL_CHANNEL) {
6759                 if (bus->bus == SPI_BUS) {
6760                     dhdsdio_read_control(bus, rxbuf, len, doff);
6761                     if (bus->usebufpool) {
6762                         dhd_os_sdlock_rxq(bus->dhd);
6763                         PKTFREE(bus->dhd->osh, pkt, FALSE);
6764                         dhd_os_sdunlock_rxq(bus->dhd);
6765                     }
6766                     continue;
6767                 } else {
6768                     DHD_ERROR(("%s (nextlen): readahead on control"
6769                                " packet %d?\n",
6770                                __FUNCTION__, seq));
6771                     /* Force retry w/normal header read */
6772                     bus->nextlen = 0;
6773                     dhdsdio_rxfail(bus, FALSE, TRUE);
6774                     dhd_os_sdlock_rxq(bus->dhd);
6775                     PKTFREE2();
6776                     dhd_os_sdunlock_rxq(bus->dhd);
6777                     continue;
6778                 }
6779             }
6780 
6781             if ((bus->bus == SPI_BUS) && !bus->usebufpool) {
6782                 DHD_ERROR(("Received %d bytes on %d channel. Running out of "
6783                            "rx pktbuf's or not yet malloced.\n",
6784                            len, chan));
6785                 continue;
6786             }
6787 
6788             /* Validate data offset */
6789             if ((doff < SDPCM_HDRLEN) || (doff > len)) {
6790                 DHD_ERROR(
6791                     ("%s (nextlen): bad data offset %d: HW len %d min %d\n",
6792                      __FUNCTION__, doff, len, SDPCM_HDRLEN));
6793                 dhd_os_sdlock_rxq(bus->dhd);
6794                 PKTFREE2();
6795                 dhd_os_sdunlock_rxq(bus->dhd);
6796                 ASSERT(0);
6797                 dhdsdio_rxfail(bus, FALSE, FALSE);
6798                 continue;
6799             }
6800 
6801             /* All done with this one -- now deliver the packet */
6802             goto deliver;
6803         }
6804         /* gSPI frames should not be handled in fractions */
6805         if (bus->bus == SPI_BUS) {
6806             break;
6807         }
6808 
6809         /* Read frame header (hardware and software) */
6810         sdret =
6811             dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
6812                                 bus->rxhdr, firstread, NULL, NULL, NULL);
6813         bus->f2rxhdrs++;
6814         ASSERT(sdret != BCME_PENDING);
6815 
6816         if (sdret < 0) {
6817             DHD_ERROR(("%s: RXHEADER FAILED: %d\n", __FUNCTION__, sdret));
6818             bus->rx_hdrfail++;
6819             dhdsdio_rxfail(bus, TRUE, TRUE);
6820             continue;
6821         }
6822 
6823 #ifdef DHD_DEBUG
6824         if (DHD_BYTES_ON() || DHD_HDRS_ON()) {
6825             prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
6826         }
6827 #endif // endif
6828 
6829         /* Extract hardware header fields */
6830         len = ltoh16_ua(bus->rxhdr);
6831         check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
6832         /* All zeros means no more frames */
6833         if (!(len | check)) {
6834             *finished = TRUE;
6835             break;
6836         }
6837         /* Validate check bytes */
6838         if ((uint16) ~(len ^ check)) {
6839             DHD_ERROR(("%s: HW hdr error: len/check 0x%04x/0x%04x\n",
6840                        __FUNCTION__, len, check));
6841             bus->rx_badhdr++;
6842             dhdsdio_rxfail(bus, FALSE, FALSE);
6843             continue;
6844         }
6845         /* Validate frame length */
6846         if (len < SDPCM_HDRLEN) {
6847             DHD_ERROR(("%s: HW hdr length invalid: %d\n", __FUNCTION__, len));
6848             continue;
6849         }
6850 
6851         /* Extract software header fields */
6852         chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6853         seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6854         doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6855         txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6856 
6857         /* Validate data offset */
6858         if ((doff < SDPCM_HDRLEN) || (doff > len)) {
6859             DHD_ERROR(("%s: Bad data offset %d: HW len %d, min %d seq %d\n",
6860                        __FUNCTION__, doff, len, SDPCM_HDRLEN, seq));
6861             bus->rx_badhdr++;
6862             ASSERT(0);
6863             dhdsdio_rxfail(bus, FALSE, FALSE);
6864             continue;
6865         }
6866 
6867         /* Save the readahead length if there is one */
6868         bus->nextlen = bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
6869         if ((bus->nextlen << 0x4) > MAX_RX_DATASZ) {
6870             DHD_INFO(
6871                 ("%s (nextlen): got frame w/nextlen too large (%d), seq %d\n",
6872                  __FUNCTION__, bus->nextlen, seq));
6873             bus->nextlen = 0;
6874         }
6875 
6876         /* Handle Flow Control */
6877         fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6878 
6879         delta = 0;
6880         if (~bus->flowcontrol & fcbits) {
6881             bus->fc_xoff++;
6882             delta = 1;
6883         }
6884         if (bus->flowcontrol & ~fcbits) {
6885             bus->fc_xon++;
6886             delta = 1;
6887         }
6888 
6889         if (delta) {
6890             bus->fc_rcvd++;
6891             bus->flowcontrol = fcbits;
6892         }
6893 
6894         /* Check and update sequence number */
6895         if (rxseq != seq) {
6896             DHD_INFO(
6897                 ("%s: rx_seq %d, expected %d\n", __FUNCTION__, seq, rxseq));
6898             bus->rx_badseq++;
6899             rxseq = seq;
6900         }
6901 
6902         /* Check window for sanity */
6903         if ((uint8)(txmax - bus->tx_seq) > 0x70) {
6904             DHD_INFO(("%s: got unlikely tx max %d with tx_seq %d\n",
6905                       __FUNCTION__, txmax, bus->tx_seq));
6906             txmax = bus->tx_max;
6907         }
6908         bus->tx_max = txmax;
6909 
6910         /* Call a separate function for control frames */
6911         if (chan == SDPCM_CONTROL_CHANNEL) {
6912             dhdsdio_read_control(bus, bus->rxhdr, len, doff);
6913             continue;
6914         }
6915 
6916         ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL) ||
6917                (chan == SDPCM_TEST_CHANNEL) || (chan == SDPCM_GLOM_CHANNEL));
6918 
6919         /* Length to read */
6920         rdlen = (len > firstread) ? (len - firstread) : 0;
6921 
6922         /* May pad read to blocksize for efficiency */
6923         if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
6924             pad = bus->blocksize - (rdlen % bus->blocksize);
6925             if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
6926                 ((rdlen + pad + firstread) < MAX_RX_DATASZ)) {
6927                 rdlen += pad;
6928             }
6929         } else if (rdlen % DHD_SDALIGN) {
6930             rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
6931         }
6932 
6933         /* Satisfy length-alignment requirements */
6934         if (forcealign && (rdlen & (ALIGNMENT - 1))) {
6935             rdlen = ROUNDUP(rdlen, ALIGNMENT);
6936         }
6937 
6938         if ((rdlen + firstread) > MAX_RX_DATASZ) {
6939             /* Too long -- skip this frame */
6940             DHD_ERROR(
6941                 ("%s: too long: len %d rdlen %d\n", __FUNCTION__, len, rdlen));
6942             bus->dhd->rx_errors++;
6943             bus->rx_toolong++;
6944             dhdsdio_rxfail(bus, FALSE, FALSE);
6945             continue;
6946         }
6947 
6948         dhd_os_sdlock_rxq(bus->dhd);
6949         if (!(pkt = PKTGET(osh, (rdlen + firstread + DHD_SDALIGN), FALSE))) {
6950             /* Give up on data, request rtx of events */
6951             DHD_ERROR(("%s: PKTGET failed: rdlen %d chan %d\n", __FUNCTION__,
6952                        rdlen, chan));
6953             bus->dhd->rx_dropped++;
6954             dhd_os_sdunlock_rxq(bus->dhd);
6955             dhdsdio_rxfail(bus, FALSE, RETRYCHAN(chan));
6956             continue;
6957         }
6958         dhd_os_sdunlock_rxq(bus->dhd);
6959 
6960         ASSERT(!PKTLINK(pkt));
6961 
6962         /* Leave room for what we already read, and align remainder */
6963         ASSERT(firstread < (PKTLEN(osh, pkt)));
6964         PKTPULL(osh, pkt, firstread);
6965         PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
6966 
6967         /* Read the remaining frame data */
6968         sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2,
6969                                     F2SYNC, ((uint8 *)PKTDATA(osh, pkt)), rdlen,
6970                                     pkt, NULL, NULL);
6971         bus->f2rxdata++;
6972         ASSERT(sdret != BCME_PENDING);
6973 
6974         if (sdret < 0) {
6975             DHD_ERROR(("%s: read %d %s bytes failed: %d\n", __FUNCTION__, rdlen,
6976                        ((chan == SDPCM_EVENT_CHANNEL)
6977                             ? "event"
6978                             : ((chan == SDPCM_DATA_CHANNEL) ? "data" : "test")),
6979                        sdret));
6980             dhd_os_sdlock_rxq(bus->dhd);
6981             PKTFREE(bus->dhd->osh, pkt, FALSE);
6982             dhd_os_sdunlock_rxq(bus->dhd);
6983             bus->dhd->rx_errors++;
6984             dhdsdio_rxfail(bus, TRUE, RETRYCHAN(chan));
6985             continue;
6986         }
6987 
6988         /* Copy the already-read portion */
6989         PKTPUSH(osh, pkt, firstread);
6990         bcopy(bus->rxhdr, PKTDATA(osh, pkt), firstread);
6991 
6992 #ifdef DHD_DEBUG
6993         if (DHD_BYTES_ON() && DHD_DATA_ON()) {
6994             prhex("Rx Data", PKTDATA(osh, pkt), len);
6995         }
6996 #endif // endif
6997 
6998     deliver:
6999         /* Save superframe descriptor and allocate packet frame */
7000         if (chan == SDPCM_GLOM_CHANNEL) {
7001             if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) {
7002                 DHD_GLOM(("%s: got glom descriptor, %d bytes:\n", __FUNCTION__,
7003                           len));
7004 #ifdef DHD_DEBUG
7005                 if (DHD_GLOM_ON()) {
7006                     prhex("Glom Data", PKTDATA(osh, pkt), len);
7007                 }
7008 #endif // endif
7009                 PKTSETLEN(osh, pkt, len);
7010                 ASSERT(doff == SDPCM_HDRLEN);
7011                 PKTPULL(osh, pkt, SDPCM_HDRLEN);
7012                 bus->glomd = pkt;
7013             } else {
7014                 DHD_ERROR(
7015                     ("%s: glom superframe w/o descriptor!\n", __FUNCTION__));
7016                 dhdsdio_rxfail(bus, FALSE, FALSE);
7017             }
7018             continue;
7019         }
7020 
7021         /* Fill in packet len and prio, deliver upward */
7022         PKTSETLEN(osh, pkt, len);
7023         PKTPULL(osh, pkt, doff);
7024 
7025 #ifdef SDTEST
7026         /* Test channel packets are processed separately */
7027         if (chan == SDPCM_TEST_CHANNEL) {
7028             dhdsdio_testrcv(bus, pkt, seq);
7029             continue;
7030         }
7031 #endif /* SDTEST */
7032 
7033         if (PKTLEN(osh, pkt) == 0) {
7034             dhd_os_sdlock_rxq(bus->dhd);
7035             PKTFREE(bus->dhd->osh, pkt, FALSE);
7036             dhd_os_sdunlock_rxq(bus->dhd);
7037             continue;
7038         } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pkt, reorder_info_buf,
7039                                     &reorder_info_len) != 0) {
7040             DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
7041             dhd_os_sdlock_rxq(bus->dhd);
7042             PKTFREE(bus->dhd->osh, pkt, FALSE);
7043             dhd_os_sdunlock_rxq(bus->dhd);
7044             bus->dhd->rx_errors++;
7045             continue;
7046         }
7047 
7048         if (reorder_info_len) {
7049             /* Reordering info from the firmware */
7050             dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf,
7051                                          reorder_info_len, &pkt, &pkt_count);
7052             if (pkt_count == 0) {
7053                 continue;
7054             }
7055         } else {
7056             pkt_count = 1;
7057         }
7058 
7059         /* Unlock during rx call */
7060         dhd_os_sdunlock(bus->dhd);
7061         dhd_rx_frame(bus->dhd, ifidx, pkt, pkt_count, chan);
7062         dhd_os_sdlock(bus->dhd);
7063 #if defined(SDIO_ISR_THREAD)
7064         /* terence 20150615: fix for below error due to bussleep in watchdog
7065          * after dhd_os_sdunlock here, so call BUS_WAKE to wake up bus again
7066          * dhd_bcmsdh_recv_buf: Device asleep
7067          * dhdsdio_readframes: RXHEADER FAILED: -40
7068          * dhdsdio_rxfail: abort command, terminate frame, send NAK
7069          */
7070         BUS_WAKE(bus);
7071 #endif
7072     }
7073     rxcount = maxframes - rxleft;
7074 #ifdef DHD_DEBUG
7075     /* Message if we hit the limit */
7076     if (!rxleft && !sdtest) {
7077         DHD_DATA(("%s: hit rx limit of %d frames\n", __FUNCTION__, maxframes));
7078     } else
7079 #endif /* DHD_DEBUG */
7080         DHD_DATA(("%s: processed %d frames\n", __FUNCTION__, rxcount));
7081     /* Back off rxseq if awaiting rtx, update rx_seq */
7082     if (bus->rxskip) {
7083         rxseq--;
7084     }
7085     bus->rx_seq = rxseq;
7086 
7087     if (bus->reqbussleep) {
7088         dhdsdio_bussleep(bus, TRUE);
7089         bus->reqbussleep = FALSE;
7090     }
7091     bus->readframes = FALSE;
7092 
7093     return rxcount;
7094 }
7095 
dhdsdio_hostmail(dhd_bus_t * bus,uint32 * hmbd)7096 static uint32 dhdsdio_hostmail(dhd_bus_t *bus, uint32 *hmbd)
7097 {
7098     sdpcmd_regs_t *regs = bus->regs;
7099     uint32 intstatus = 0;
7100     uint32 hmb_data;
7101     uint8 fcbits;
7102     uint retries = 0;
7103 
7104     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7105 
7106     /* Read mailbox data and ack that we did so */
7107     R_SDREG(hmb_data, &regs->tohostmailboxdata, retries);
7108     if (retries <= retry_limit) {
7109         W_SDREG(SMB_INT_ACK, &regs->tosbmailbox, retries);
7110     }
7111     bus->f1regdata += 0x2;
7112 
7113     /* Dongle recomposed rx frames, accept them again */
7114     if (hmb_data & HMB_DATA_NAKHANDLED) {
7115         DHD_INFO(
7116             ("Dongle reports NAK handled, expect rtx of %d\n", bus->rx_seq));
7117         if (!bus->rxskip) {
7118             DHD_ERROR(("%s: unexpected NAKHANDLED!\n", __FUNCTION__));
7119         }
7120         bus->rxskip = FALSE;
7121         intstatus |= FRAME_AVAIL_MASK(bus);
7122     }
7123 
7124     /*
7125      * DEVREADY does not occur with gSPI.
7126      */
7127     if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) {
7128         bus->sdpcm_ver =
7129             (hmb_data & HMB_DATA_VERSION_MASK) >> HMB_DATA_VERSION_SHIFT;
7130         if (bus->sdpcm_ver != SDPCM_PROT_VERSION) {
7131             DHD_ERROR(("Version mismatch, dongle reports %d, expecting %d\n",
7132                        bus->sdpcm_ver, SDPCM_PROT_VERSION));
7133         } else {
7134             DHD_INFO(("Dongle ready, protocol version %d\n", bus->sdpcm_ver));
7135         }
7136 #ifndef BCMSPI
7137         /* make sure for the SDIO_DEVICE_RXDATAINT_MODE_1 corecontrol is proper
7138          */
7139         if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 0x4) &&
7140             (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) {
7141             uint32 val;
7142 
7143             val = R_REG(bus->dhd->osh, &bus->regs->corecontrol);
7144             val &= ~CC_XMTDATAAVAIL_MODE;
7145             val |= CC_XMTDATAAVAIL_CTRL;
7146             W_REG(bus->dhd->osh, &bus->regs->corecontrol, val);
7147 
7148             val = R_REG(bus->dhd->osh, &bus->regs->corecontrol);
7149         }
7150 #endif /* BCMSPI */
7151 
7152 #ifdef DHD_DEBUG
7153         /* Retrieve console state address now that firmware should have updated
7154          * it */
7155         {
7156             sdpcm_shared_t shared;
7157             if (dhdsdio_readshared(bus, &shared) == 0) {
7158                 bus->console_addr = shared.console_addr;
7159             }
7160         }
7161 #endif /* DHD_DEBUG */
7162     }
7163 
7164     /*
7165      * Flow Control has been moved into the RX headers and this out of band
7166      * method isn't used any more.  Leave this here for possibly remaining
7167      * backward compatible with older dongles
7168      */
7169     if (hmb_data & HMB_DATA_FC) {
7170         fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >> HMB_DATA_FCDATA_SHIFT;
7171 
7172         if (fcbits & ~bus->flowcontrol) {
7173             bus->fc_xoff++;
7174         }
7175         if (bus->flowcontrol & ~fcbits) {
7176             bus->fc_xon++;
7177         }
7178 
7179         bus->fc_rcvd++;
7180         bus->flowcontrol = fcbits;
7181     }
7182 
7183     /* At least print a message if FW halted */
7184     if (hmb_data & HMB_DATA_FWHALT) {
7185         DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED : set BUS DOWN\n"));
7186         dhdsdio_checkdied(bus, NULL, 0);
7187         DHD_ERROR(("Not doing bus down untill memdump done \n"));
7188     }
7189 
7190     /* Shouldn't be any others */
7191     if (hmb_data & ~(HMB_DATA_DEVREADY | HMB_DATA_FWHALT | HMB_DATA_NAKHANDLED |
7192                      HMB_DATA_FC | HMB_DATA_FWREADY | HMB_DATA_FCDATA_MASK |
7193                      HMB_DATA_VERSION_MASK)) {
7194         DHD_ERROR(("Unknown mailbox data content: 0x%02x\n", hmb_data));
7195     }
7196 
7197     if (hmbd) {
7198         *hmbd = hmb_data;
7199     }
7200 
7201     return intstatus;
7202 }
7203 
7204 #ifdef BCMSDIO_INTSTATUS_WAR
dhdsdio_read_intstatus_byte(dhd_bus_t * bus)7205 static uint32 dhdsdio_read_intstatus_byte(dhd_bus_t *bus)
7206 {
7207     bcmsdh_info_t *sdh = bus->sdh;
7208     sdpcmd_regs_t *regs = bus->regs;
7209     uint32 newstatus = 0, intstatus_byte = 0;
7210     uint retries = 0;
7211     int err1 = 0, err2 = 0, err3 = 0, err4 = 0;
7212 
7213     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7214 
7215     /* read_intr_mode:
7216      * 0: word mode only (default)
7217      * 1: byte mode after read word failed
7218      * 2: byte mode only
7219      */
7220     if (bus->dhd->conf->read_intr_mode) {
7221         if (bus->dhd->conf->read_intr_mode == 1) {
7222             R_SDREG(newstatus, &regs->intstatus, retries);
7223             if (!bcmsdh_regfail(bus->sdh)) {
7224                 goto exit;
7225             }
7226         }
7227         intstatus_byte = bcmsdh_cfg_read(
7228             bus->sdh, SDIO_FUNC_1,
7229             ((unsigned long)&regs->intstatus & 0xffff) + 0, &err1);
7230         if (!err1) {
7231             newstatus |= intstatus_byte;
7232         }
7233         intstatus_byte =
7234             bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
7235                             ((unsigned long)&regs->intstatus & 0xffff) + 1,
7236                             &err2)
7237             << 0x8;
7238         if (!err2) {
7239             newstatus |= intstatus_byte;
7240         }
7241         intstatus_byte |=
7242             bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
7243                             ((unsigned long)&regs->intstatus & 0xffff) + 0x2,
7244                             &err3)
7245             << 0x10;
7246         if (!err3) {
7247             newstatus |= intstatus_byte;
7248         }
7249         intstatus_byte |=
7250             bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
7251                             ((unsigned long)&regs->intstatus & 0xffff) + 0x3,
7252                             &err4)
7253             << 0x18;
7254         if (!err4) {
7255             newstatus |= intstatus_byte;
7256         }
7257 
7258         if (!err1 || !err2 || !err3 || !err4) {
7259             sdh->regfail = FALSE;
7260         }
7261     } else {
7262         R_SDREG(newstatus, &regs->intstatus, retries);
7263     }
7264 
7265 exit:
7266     return newstatus;
7267 }
7268 #endif
7269 
dhdsdio_dpc(dhd_bus_t * bus)7270 static bool dhdsdio_dpc(dhd_bus_t *bus)
7271 {
7272     bcmsdh_info_t *sdh = bus->sdh;
7273     sdpcmd_regs_t *regs = bus->regs;
7274     uint32 intstatus, newstatus = 0;
7275     uint retries = 0;
7276     uint rxlimit = dhd_rxbound; /* Rx frames to read before resched */
7277     uint txlimit = dhd_txbound; /* Tx frames to send before resched */
7278     uint framecnt = 0;          /* Temporary counter of tx/rx frames */
7279     bool rxdone = TRUE;         /* Flag for no more read data */
7280     bool resched = FALSE;       /* Flag indicating resched wanted */
7281     unsigned long flags;
7282 #ifdef DEBUG_DPC_THREAD_WATCHDOG
7283     bool is_resched_by_readframe = FALSE;
7284 #endif /* DEBUG_DPC_THREAD_WATCHDOG */
7285     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7286 
7287     dhd_os_sdlock(bus->dhd);
7288     DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
7289     if (bus->dhd->busstate == DHD_BUS_DOWN) {
7290         DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__));
7291         bus->intstatus = 0;
7292         DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
7293         dhd_os_sdunlock(bus->dhd);
7294         return 0;
7295     }
7296 
7297     DHD_BUS_BUSY_SET_IN_DPC(bus->dhd);
7298     DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
7299 
7300     /* Start with leftover status bits */
7301     intstatus = bus->intstatus;
7302 
7303     if (!SLPAUTO_ENAB(bus) && !KSO_ENAB(bus)) {
7304         DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
7305         goto exit;
7306     }
7307 
7308     /* If waiting for HTAVAIL, check status */
7309     if (!SLPAUTO_ENAB(bus) && (bus->clkstate == CLK_PENDING)) {
7310         int err;
7311         uint8 clkctl, devctl = 0;
7312 
7313 #ifdef DHD_DEBUG
7314         /* Check for inconsistent device control */
7315         devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
7316         if (err) {
7317             DHD_ERROR(("%s: error reading DEVCTL: %d\n", __FUNCTION__, err));
7318             DHD_ERROR(("%s: making DHD_BUS_DOWN\n", __FUNCTION__));
7319             bus->dhd->busstate = DHD_BUS_DOWN;
7320         } else {
7321             ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY);
7322         }
7323 #endif /* DHD_DEBUG */
7324 
7325         /* Read CSR, if clock on switch to AVAIL, else ignore */
7326         clkctl =
7327             bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
7328         if (err) {
7329             DHD_ERROR(("%s: error reading CSR: %d\n", __FUNCTION__, err));
7330             DHD_ERROR(("%s: making DHD_BUS_DOWN\n", __FUNCTION__));
7331             bus->dhd->busstate = DHD_BUS_DOWN;
7332         }
7333 
7334         DHD_INFO(
7335             ("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", devctl, clkctl));
7336 
7337         if (SBSDIO_HTAV(clkctl)) {
7338             devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
7339             if (err) {
7340                 DHD_ERROR(
7341                     ("%s: error reading DEVCTL: %d\n", __FUNCTION__, err));
7342                 DHD_ERROR(("%s: making DHD_BUS_DOWN\n", __FUNCTION__));
7343                 bus->dhd->busstate = DHD_BUS_DOWN;
7344             }
7345             devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
7346             bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
7347             if (err) {
7348                 DHD_ERROR(
7349                     ("%s: error writing DEVCTL: %d\n", __FUNCTION__, err));
7350                 DHD_ERROR(("%s: making DHD_BUS_DOWN\n", __FUNCTION__));
7351                 bus->dhd->busstate = DHD_BUS_DOWN;
7352             }
7353             bus->clkstate = CLK_AVAIL;
7354         } else {
7355             goto clkwait;
7356         }
7357     }
7358 
7359     BUS_WAKE(bus);
7360 
7361     /* Make sure backplane clock is on */
7362     dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
7363     if (bus->clkstate != CLK_AVAIL) {
7364         goto clkwait;
7365     }
7366 
7367     /* Pending interrupt indicates new device status */
7368     if (bus->ipend) {
7369         bus->ipend = FALSE;
7370 #if defined(BT_OVER_SDIO)
7371         bcmsdh_btsdio_process_f3_intr();
7372 #endif /* defined (BT_OVER_SDIO) */
7373 
7374 #ifdef BCMSDIO_INTSTATUS_WAR
7375         newstatus = dhdsdio_read_intstatus_byte(bus);
7376 #else
7377         R_SDREG(newstatus, &regs->intstatus, retries);
7378 #endif
7379         bus->f1regdata++;
7380         if (bcmsdh_regfail(bus->sdh)) {
7381             newstatus = 0;
7382         }
7383         newstatus &= bus->hostintmask;
7384         bus->fcstate = !!(newstatus & I_HMB_FC_STATE);
7385         if (newstatus) {
7386             bus->f1regdata++;
7387 #ifndef BCMSPI
7388             if ((bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_0) &&
7389                 (newstatus == I_XMTDATA_AVAIL)) {
7390             } else
7391 #endif /* BCMSPI */
7392                 W_SDREG(newstatus, &regs->intstatus, retries);
7393         }
7394     }
7395 
7396     /* Merge new bits with previous */
7397     intstatus |= newstatus;
7398     bus->intstatus = 0;
7399 
7400     /* Handle flow-control change: read new state in case our ack
7401      * crossed another change interrupt.  If change still set, assume
7402      * FC ON for safety, let next loop through do the debounce.
7403      */
7404     if (intstatus & I_HMB_FC_CHANGE) {
7405         intstatus &= ~I_HMB_FC_CHANGE;
7406         W_SDREG(I_HMB_FC_CHANGE, &regs->intstatus, retries);
7407         R_SDREG(newstatus, &regs->intstatus, retries);
7408         bus->f1regdata += 0x2;
7409         bus->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
7410         intstatus |= (newstatus & bus->hostintmask);
7411     }
7412 
7413     /* Handle host mailbox indication */
7414     if (intstatus & I_HMB_HOST_INT) {
7415         uint32 hmbdata = 0;
7416 
7417         intstatus &= ~I_HMB_HOST_INT;
7418         intstatus |= dhdsdio_hostmail(bus, &hmbdata);
7419 
7420 #ifdef DHD_ULP
7421         /* ULP prototyping. Redowload fw on oob interupt */
7422 
7423         /* all the writes after this point CAN use cached sbwad value */
7424         bcmsdh_force_sbwad_calc(bus->sdh, FALSE);
7425 
7426         if (dhd_ulp_pre_redownload_check(bus->dhd, bus->sdh, hmbdata)) {
7427             if (dhd_bus_ulp_reinit_fw(bus) < 0) {
7428                 DHD_ERROR(
7429                     ("%s:%d FW redownload failed\n", __FUNCTION__, __LINE__));
7430                 goto exit;
7431             }
7432         }
7433 #endif // endif
7434     }
7435 
7436 #ifdef DHD_UCODE_DOWNLOAD
7437 exit_ucode:
7438 #endif /* DHD_UCODE_DOWNLOAD */
7439 
7440     /* Just being here means nothing more to do for chipactive */
7441     if (intstatus & I_CHIPACTIVE) {
7442         intstatus &= ~I_CHIPACTIVE;
7443     }
7444 
7445     /* Handle host mailbox indication */
7446     if (intstatus & I_HMB_HOST_INT) {
7447         intstatus &= ~I_HMB_HOST_INT;
7448         intstatus |= dhdsdio_hostmail(bus, NULL);
7449     }
7450 
7451     /* Generally don't ask for these, can get CRC errors... */
7452     if (intstatus & I_WR_OOSYNC) {
7453         DHD_ERROR(("Dongle reports WR_OOSYNC\n"));
7454         intstatus &= ~I_WR_OOSYNC;
7455     }
7456 
7457     if (intstatus & I_RD_OOSYNC) {
7458         DHD_ERROR(("Dongle reports RD_OOSYNC\n"));
7459         intstatus &= ~I_RD_OOSYNC;
7460     }
7461 
7462     if (intstatus & I_SBINT) {
7463         DHD_ERROR(("Dongle reports SBINT\n"));
7464         intstatus &= ~I_SBINT;
7465     }
7466 
7467     /* Would be active due to wake-wlan in gSPI */
7468     if (intstatus & I_CHIPACTIVE) {
7469         DHD_INFO(("Dongle reports CHIPACTIVE\n"));
7470         intstatus &= ~I_CHIPACTIVE;
7471     }
7472 
7473     if (intstatus & I_HMB_FC_STATE) {
7474         DHD_INFO(("Dongle reports HMB_FC_STATE\n"));
7475         intstatus &= ~I_HMB_FC_STATE;
7476     }
7477 
7478     /* Ignore frame indications if rxskip is set */
7479     if (bus->rxskip) {
7480         intstatus &= ~FRAME_AVAIL_MASK(bus);
7481     }
7482 
7483     /* On frame indication, read available frames */
7484     if (PKT_AVAILABLE(bus, intstatus)) {
7485         framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone);
7486         if (rxdone || bus->rxskip) {
7487             intstatus &= ~FRAME_AVAIL_MASK(bus);
7488         }
7489         rxlimit -= MIN(framecnt, rxlimit);
7490     }
7491     /* Keep still-pending events for next scheduling */
7492     bus->intstatus = intstatus;
7493 
7494 clkwait:
7495     /* Re-enable interrupts to detect new device events (mailbox, rx frame)
7496      * or clock availability.  (Allows tx loop to check ipend if desired.)
7497      * (Unless register access seems hosed, as we may not be able to ACK...)
7498      */
7499     if (bus->intr && bus->intdis && !bcmsdh_regfail(sdh) &&
7500         !(bus->dhd->conf->oob_enabled_later && !bus->ctrl_frame_stat)) {
7501         DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n",
7502                   __FUNCTION__, rxdone, framecnt));
7503         bus->intdis = FALSE;
7504 #if defined(OOB_INTR_ONLY)
7505         bcmsdh_oob_intr_set(bus->sdh, TRUE);
7506 #endif /* defined(OOB_INTR_ONLY) */
7507         bcmsdh_intr_enable(sdh);
7508 #ifdef BCMSPI_ANDROID
7509         if (*dhd_spi_lockcount == 0) {
7510             bcmsdh_oob_intr_set(bus->sdh, TRUE);
7511         }
7512 #endif /* BCMSPI_ANDROID */
7513     }
7514 
7515 #if defined(OOB_INTR_ONLY) && !defined(HW_OOB)
7516     /* In case of SW-OOB(using edge trigger),
7517      * Check interrupt status in the dongle again after enable irq on the host.
7518      * and rechedule dpc if interrupt is pended in the dongle.
7519      * There is a chance to miss OOB interrupt while irq is disabled on the
7520      * host. No need to do this with HW-OOB(level trigger)
7521      */
7522     R_SDREG(newstatus, &regs->intstatus, retries);
7523     if (bcmsdh_regfail(bus->sdh)) {
7524         newstatus = 0;
7525     }
7526     if (newstatus & bus->hostintmask) {
7527         bus->ipend = TRUE;
7528         resched = TRUE;
7529     }
7530 #endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */
7531 
7532 #ifdef BCMSDIO_RXLIM_POST
7533     if (!DATAOK(bus) && bus->rxlim_en) {
7534         uint8 rxlim = 0;
7535         if (0 ==
7536             dhdsdio_membytes(bus, FALSE, bus->rxlim_addr, (uint8 *)&rxlim, 1)) {
7537             if (bus->tx_max != rxlim) {
7538                 DHD_INFO(("%s: bus->tx_max/rxlim=%d/%d\n", __FUNCTION__,
7539                           bus->tx_max, rxlim));
7540                 bus->tx_max = rxlim;
7541             }
7542         }
7543     }
7544 #endif /* BCMSDIO_RXLIM_POST */
7545 
7546 #ifdef PROP_TXSTATUS
7547     dhd_wlfc_commit_packets(bus->dhd, (f_commitpkt_t)dhd_bus_txdata,
7548                             (void *)bus, NULL, FALSE);
7549 #endif // endif
7550 
7551     if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) {
7552         dhdsdio_sendpendctl(bus);
7553     }
7554 #ifdef CONSOLE_DPC
7555     else if (DATAOK(bus) && strlen(bus->cons_cmd) &&
7556              (bus->clkstate == CLK_AVAIL) && !bus->fcstate) {
7557         dhd_bus_console_in(bus->dhd, bus->cons_cmd, strlen(bus->cons_cmd));
7558     }
7559 #endif
7560 
7561     /* Send queued frames (limit 1 if rx may still be pending) */
7562     else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
7563              pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit &&
7564              DATAOK(bus)) {
7565 #ifdef DHD_ULP
7566         if (dhd_ulp_f2_ready(bus->dhd, bus->sdh)) {
7567 #endif /* DHD_ULP */
7568             if (bus->dhd->conf->dhd_txminmax < 0) {
7569                 framecnt = rxdone ? txlimit : MIN(txlimit, DATABUFCNT(bus));
7570             } else {
7571                 framecnt = rxdone ? txlimit
7572                                   : MIN(txlimit, bus->dhd->conf->dhd_txminmax);
7573             }
7574             framecnt = dhdsdio_sendfromq(bus, framecnt);
7575             txlimit -= framecnt;
7576 #ifdef DHD_ULP
7577         } else {
7578             /* In other transient states like DHD_ULP_, after the states are
7579              * DHD_ULP_F2ENAB_CLEARING and DHD_ULP_F2ENAB_SETTING,
7580              * dpc is scheduled after steady-state and dhdsdio_sendfromq() will
7581              * execute again
7582              */
7583         }
7584 #endif /* DHD_ULP */
7585     }
7586     /* Resched the DPC if ctrl cmd is pending on bus credit */
7587     if (bus->ctrl_frame_stat) {
7588         if (bus->dhd->conf->txctl_tmo_fix) {
7589             set_current_state(TASK_INTERRUPTIBLE);
7590             if (!kthread_should_stop()) {
7591                 schedule_timeout(1);
7592             }
7593             set_current_state(TASK_RUNNING);
7594         }
7595         resched = TRUE;
7596     }
7597 
7598     /* Resched if events or tx frames are pending, else await next interrupt */
7599     /* On failed register access, all bets are off: no resched or interrupts */
7600     if ((bus->dhd->busstate == DHD_BUS_DOWN) || bcmsdh_regfail(sdh)) {
7601         if ((bus->sih && bus->sih->buscorerev >= 0xC) &&
7602             !(dhdsdio_sleepcsr_get(bus) & SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) {
7603             /* Bus failed because of KSO */
7604             DHD_ERROR(("%s: Bus failed due to KSO\n", __FUNCTION__));
7605             bus->kso = FALSE;
7606         } else {
7607             DHD_ERROR(
7608                 ("%s: failed backplane access over SDIO, halting operation\n",
7609                  __FUNCTION__));
7610             DHD_ERROR(("%s: making DHD_BUS_DOWN\n", __FUNCTION__));
7611             bus->dhd->busstate = DHD_BUS_DOWN;
7612             bus->intstatus = 0;
7613         }
7614     } else if (bus->clkstate == CLK_PENDING) {
7615         /* Awaiting I_CHIPACTIVE; don't resched */
7616     } else if (bus->intstatus || bus->ipend ||
7617                (!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) &&
7618                 DATAOK(bus)) ||
7619                PKT_AVAILABLE(bus, bus->intstatus)) { /* Read multiple frames */
7620         resched = TRUE;
7621     }
7622 
7623     bus->dpc_sched = resched;
7624 
7625     /* If we're done for now, turn off clock request. */
7626     if ((bus->idletime == DHD_IDLE_IMMEDIATE) &&
7627         (bus->clkstate != CLK_PENDING) && NO_OTHER_ACTIVE_BUS_USER(bus)) {
7628         bus->activity = FALSE;
7629         dhdsdio_bussleep(bus, TRUE);
7630         dhdsdio_clkctl(bus, CLK_NONE, FALSE);
7631     }
7632 
7633 exit:
7634 
7635     if (!resched) {
7636         /* Re-enable interrupts to detect new device events (mailbox, rx frame)
7637          * or clock availability.  (Allows tx loop to check ipend if desired.)
7638          * (Unless register access seems hosed, as we may not be able to ACK...)
7639          */
7640         if (bus->intr && bus->intdis && !bcmsdh_regfail(sdh) &&
7641             (bus->dhd->conf->oob_enabled_later && !bus->ctrl_frame_stat)) {
7642             DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n",
7643                       __FUNCTION__, rxdone, framecnt));
7644             bus->intdis = FALSE;
7645 #if defined(OOB_INTR_ONLY)
7646             bcmsdh_oob_intr_set(bus->sdh, TRUE);
7647 #endif /* defined(OOB_INTR_ONLY) */
7648             bcmsdh_intr_enable(sdh);
7649         }
7650         if (dhd_dpcpoll) {
7651             if (dhdsdio_readframes(bus, dhd_rxbound, &rxdone) != 0) {
7652                 resched = TRUE;
7653 #ifdef DEBUG_DPC_THREAD_WATCHDOG
7654                 is_resched_by_readframe = TRUE;
7655 #endif /* DEBUG_DPC_THREAD_WATCHDOG */
7656             }
7657         }
7658     }
7659 
7660 #ifdef TPUT_MONITOR
7661     dhd_conf_tput_monitor(bus->dhd);
7662 #endif
7663 
7664     if (bus->ctrl_wait && TXCTLOK(bus)) {
7665         wake_up_interruptible(&bus->ctrl_tx_wait);
7666     }
7667     dhd_os_sdunlock(bus->dhd);
7668 #ifdef DEBUG_DPC_THREAD_WATCHDOG
7669     if (bus->dhd->dhd_bug_on) {
7670         DHD_INFO(("%s: resched = %d ctrl_frame_stat = %d intstatus 0x%08x"
7671                   " ipend = %d pktq_mlen = %d is_resched_by_readframe = %d \n",
7672                   __FUNCTION__, resched, bus->ctrl_frame_stat, bus->intstatus,
7673                   bus->ipend, pktq_mlen(&bus->txq, ~bus->flowcontrol),
7674                   is_resched_by_readframe));
7675 
7676         bus->dhd->dhd_bug_on = FALSE;
7677     }
7678 #endif /* DEBUG_DPC_THREAD_WATCHDOG */
7679 
7680     DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
7681     DHD_BUS_BUSY_CLEAR_IN_DPC(bus->dhd);
7682     dhd_os_busbusy_wake(bus->dhd);
7683     DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
7684 
7685     return resched;
7686 }
7687 
dhd_bus_dpc(struct dhd_bus * bus)7688 bool dhd_bus_dpc(struct dhd_bus *bus)
7689 {
7690     bool resched;
7691 
7692     /* Call the DPC directly. */
7693     DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
7694     resched = dhdsdio_dpc(bus);
7695 
7696     return resched;
7697 }
7698 
dhdsdio_isr(void * arg)7699 void dhdsdio_isr(void *arg)
7700 {
7701     dhd_bus_t *bus = (dhd_bus_t *)arg;
7702     bcmsdh_info_t *sdh;
7703 
7704     if (!bus) {
7705         DHD_ERROR(("%s : bus is null pointer , exit \n", __FUNCTION__));
7706         return;
7707     }
7708     sdh = bus->sdh;
7709 
7710     if (bus->dhd->busstate == DHD_BUS_DOWN) {
7711         DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
7712         return;
7713     }
7714 
7715     DHD_INTR(("%s: Enter\n", __FUNCTION__));
7716 
7717     /* Count the interrupt call */
7718     bus->intrcount++;
7719     bus->ipend = TRUE;
7720 
7721     /* Shouldn't get this interrupt if we're sleeping? */
7722     if (!SLPAUTO_ENAB(bus)) {
7723         if (bus->sleeping) {
7724             DHD_ERROR(("INTERRUPT WHILE SLEEPING??\n"));
7725             return;
7726         } else if (!KSO_ENAB(bus)) {
7727             DHD_ERROR(("ISR in devsleep 1\n"));
7728         }
7729     }
7730 
7731     /* Disable additional interrupts (is this needed now)? */
7732     if (bus->intr) {
7733         DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
7734     } else {
7735         DHD_ERROR(("dhdsdio_isr() w/o interrupt configured!\n"));
7736     }
7737 
7738 #ifdef BCMSPI_ANDROID
7739     bcmsdh_oob_intr_set(bus->sdh, FALSE);
7740 #endif /* BCMSPI_ANDROID */
7741     bcmsdh_intr_disable(sdh);
7742     bus->intdis = TRUE;
7743 
7744 #if defined(SDIO_ISR_THREAD)
7745     DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
7746     DHD_OS_WAKE_LOCK(bus->dhd);
7747     /* terence 20150209: dpc should be scheded again if dpc_sched is TRUE or
7748        dhd_bus_txdata can not schedule anymore because dpc_sched is TRUE now.
7749      */
7750     if (dhdsdio_dpc(bus)) {
7751         bus->dpc_sched = TRUE;
7752         dhd_sched_dpc(bus->dhd);
7753     }
7754     DHD_OS_WAKE_UNLOCK(bus->dhd);
7755 #else
7756     bus->dpc_sched = TRUE;
7757     dhd_sched_dpc(bus->dhd);
7758 #endif /* defined(SDIO_ISR_THREAD) */
7759 }
7760 
7761 #ifdef PKT_STATICS
dhd_bus_dump_txpktstatics(dhd_pub_t * dhdp)7762 void dhd_bus_dump_txpktstatics(dhd_pub_t *dhdp)
7763 {
7764     dhd_bus_t *bus = dhdp->bus;
7765     uint32 total = 0;
7766     uint i;
7767 
7768     printf("%s: TYPE EVENT: %d pkts (size=%d) transfered\n", __FUNCTION__,
7769            bus->tx_statics.event_count, bus->tx_statics.event_size);
7770     printf("%s: TYPE CTRL:  %d pkts (size=%d) transfered\n", __FUNCTION__,
7771            bus->tx_statics.ctrl_count, bus->tx_statics.ctrl_size);
7772     printf("%s: TYPE DATA:  %d pkts (size=%d) transfered\n", __FUNCTION__,
7773            bus->tx_statics.data_count, bus->tx_statics.data_size);
7774     printf("%s: Glom size distribution:\n", __FUNCTION__);
7775     for (i = 0; i < bus->tx_statics.glom_max; i++) {
7776         total += bus->tx_statics.glom_cnt[i];
7777     }
7778     printk(KERN_CONT DHD_LOG_PREFIXS);
7779     for (i = 0; i < bus->tx_statics.glom_max; i++) {
7780         printk(KERN_CONT "%02d: %5d", i + 1, bus->tx_statics.glom_cnt[i]);
7781         if ((i + 1) % 0x8) {
7782             printk(KERN_CONT ", ");
7783         } else {
7784             printk("\n");
7785             printk(KERN_CONT DHD_LOG_PREFIXS);
7786         }
7787     }
7788     printk("\n");
7789     printk(KERN_CONT DHD_LOG_PREFIXS);
7790     for (i = 0; i < bus->tx_statics.glom_max; i++) {
7791         printk(KERN_CONT "%02d:%5d%%", i + 1,
7792                (bus->tx_statics.glom_cnt[i] * 0x64) / total);
7793         if ((i + 1) % 0x8) {
7794             printk(KERN_CONT ", ");
7795         } else {
7796             printk("\n");
7797             printk(KERN_CONT DHD_LOG_PREFIXS);
7798         }
7799     }
7800     printk("\n");
7801     printf("%s: Glom spend time distribution(us):\n", __FUNCTION__);
7802     printk(KERN_CONT DHD_LOG_PREFIXS);
7803     for (i = 0; i < bus->tx_statics.glom_max; i++) {
7804         printk(KERN_CONT "%02d: %5u", i + 1, bus->tx_statics.glom_cnt_us[i]);
7805         if ((i + 1) % 0x8) {
7806             printk(KERN_CONT ", ");
7807         } else {
7808             printk("\n");
7809             printk(KERN_CONT DHD_LOG_PREFIXS);
7810         }
7811     }
7812     printk("\n");
7813     if (total) {
7814         printf("%s: data(%d)/glom(%d)=%d, glom_max=%d\n", __FUNCTION__,
7815                bus->tx_statics.data_count, total,
7816                bus->tx_statics.data_count / total, bus->tx_statics.glom_max);
7817     }
7818     printf("%s: TYPE RX GLOM: %d pkts (size=%d) transfered\n", __FUNCTION__,
7819            bus->tx_statics.glom_count, bus->tx_statics.glom_size);
7820     printf("%s: TYPE TEST: %d pkts (size=%d) transfered\n", __FUNCTION__,
7821            bus->tx_statics.test_count, bus->tx_statics.test_size);
7822 
7823 #ifdef KSO_DEBUG
7824     printf("%s: kso try distribution(us):\n", __FUNCTION__);
7825     printk(KERN_CONT DHD_LOG_PREFIXS);
7826     for (i = 0; i < 0xA; i++) {
7827         printk(KERN_CONT "[%d]: %d, ", i, dhdp->conf->kso_try_array[i]);
7828     }
7829     printk("\n");
7830 #endif
7831 }
7832 
dhd_bus_clear_txpktstatics(dhd_pub_t * dhdp)7833 void dhd_bus_clear_txpktstatics(dhd_pub_t *dhdp)
7834 {
7835     dhd_bus_t *bus = dhdp->bus;
7836     memset((uint8 *)&bus->tx_statics, 0, sizeof(pkt_statics_t));
7837 }
7838 #endif
7839 
7840 #ifdef SDTEST
dhdsdio_pktgen_init(dhd_bus_t * bus)7841 static void dhdsdio_pktgen_init(dhd_bus_t *bus)
7842 {
7843     /* Default to specified length, or full range */
7844     if (dhd_pktgen_len) {
7845         bus->pktgen_maxlen = MIN(dhd_pktgen_len, MAX_PKTGEN_LEN);
7846         bus->pktgen_minlen = bus->pktgen_maxlen;
7847     } else {
7848         bus->pktgen_maxlen = MAX_PKTGEN_LEN;
7849         bus->pktgen_minlen = 0;
7850     }
7851     bus->pktgen_len = (uint16)bus->pktgen_minlen;
7852 
7853     /* Default to per-watchdog burst with 10s print time */
7854     bus->pktgen_freq = 1;
7855     bus->pktgen_print = dhd_watchdog_ms ? (0x2710 / dhd_watchdog_ms) : 0;
7856     bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 0x3E7) / 0x3E8;
7857 
7858     /* Default to echo mode */
7859     bus->pktgen_mode = DHD_PKTGEN_ECHO;
7860     bus->pktgen_stop = 1;
7861 }
7862 
dhdsdio_pktgen(dhd_bus_t * bus)7863 static void dhdsdio_pktgen(dhd_bus_t *bus)
7864 {
7865     void *pkt;
7866     uint8 *data;
7867     uint pktcount;
7868     uint fillbyte;
7869     osl_t *osh = bus->dhd->osh;
7870     uint16 len;
7871     ulong time_lapse;
7872     uint sent_pkts;
7873     uint rcvd_pkts;
7874 
7875     /* Display current count if appropriate */
7876     if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) {
7877         bus->pktgen_ptick = 0;
7878         printf("%s: send attempts %d, rcvd %d, errors %d\n", __FUNCTION__,
7879                bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
7880 
7881         /* Print throughput stats only for constant length packet runs */
7882         if (bus->pktgen_minlen == bus->pktgen_maxlen) {
7883             time_lapse = jiffies - bus->pktgen_prev_time;
7884             bus->pktgen_prev_time = jiffies;
7885             sent_pkts = bus->pktgen_sent - bus->pktgen_prev_sent;
7886             bus->pktgen_prev_sent = bus->pktgen_sent;
7887             rcvd_pkts = bus->pktgen_rcvd - bus->pktgen_prev_rcvd;
7888             bus->pktgen_prev_rcvd = bus->pktgen_rcvd;
7889 
7890             printf(
7891                 "%s: Tx Throughput %d kbps, Rx Throughput %d kbps\n",
7892                 __FUNCTION__,
7893                 (sent_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) *
7894                     0x8,
7895                 (rcvd_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) *
7896                     0x8);
7897         }
7898     }
7899 
7900     /* For recv mode, just make sure dongle has started sending */
7901     if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
7902         if (bus->pktgen_rcv_state == PKTGEN_RCV_IDLE) {
7903             bus->pktgen_rcv_state = PKTGEN_RCV_ONGOING;
7904             dhdsdio_sdtest_set(bus, bus->pktgen_total);
7905         }
7906         return;
7907     }
7908 
7909     /* Otherwise, generate or request the specified number of packets */
7910     for (pktcount = 0; pktcount < bus->pktgen_count; pktcount++) {
7911         /* Stop if total has been reached */
7912         if (bus->pktgen_total && (bus->pktgen_sent >= bus->pktgen_total)) {
7913             bus->pktgen_count = 0;
7914             break;
7915         }
7916 
7917         /* Allocate an appropriate-sized packet */
7918         if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) {
7919             len = SDPCM_TEST_PKT_CNT_FLD_LEN;
7920         } else {
7921             len = bus->pktgen_len;
7922         }
7923         if (!(pkt = PKTGET(
7924                   osh, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN),
7925                   TRUE))) {
7926             ;
7927             DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
7928             break;
7929         }
7930         PKTALIGN(osh, pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN),
7931                  DHD_SDALIGN);
7932         data = (uint8 *)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
7933 
7934         /* Write test header cmd and extra based on mode */
7935         switch (bus->pktgen_mode) {
7936             case DHD_PKTGEN_ECHO:
7937                 *data++ = SDPCM_TEST_ECHOREQ;
7938                 *data++ = (uint8)bus->pktgen_sent;
7939                 break;
7940 
7941             case DHD_PKTGEN_SEND:
7942                 *data++ = SDPCM_TEST_DISCARD;
7943                 *data++ = (uint8)bus->pktgen_sent;
7944                 break;
7945 
7946             case DHD_PKTGEN_RXBURST:
7947                 *data++ = SDPCM_TEST_BURST;
7948                 *data++ =
7949                     (uint8)
7950                         bus->pktgen_count; /* Just for backward compatability */
7951                 break;
7952 
7953             default:
7954                 DHD_ERROR(("Unrecognized pktgen mode %d\n", bus->pktgen_mode));
7955                 PKTFREE(osh, pkt, TRUE);
7956                 bus->pktgen_count = 0;
7957                 return;
7958         }
7959 
7960         /* Write test header length field */
7961         *data++ = (bus->pktgen_len >> 0);
7962         *data++ = (bus->pktgen_len >> 0x8);
7963 
7964         /* Write frame count in a 4 byte field adjucent to SDPCM test header for
7965          * burst mode
7966          */
7967         if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) {
7968             *data++ = (uint8)(bus->pktgen_count >> 0);
7969             *data++ = (uint8)(bus->pktgen_count >> 0x8);
7970             *data++ = (uint8)(bus->pktgen_count >> 0x10);
7971             *data++ = (uint8)(bus->pktgen_count >> 0x18);
7972         } else {
7973             /* Then fill in the remainder -- N/A for burst */
7974             for (fillbyte = 0; fillbyte < len; fillbyte++) {
7975                 *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent);
7976             }
7977         }
7978 
7979 #ifdef DHD_DEBUG
7980         if (DHD_BYTES_ON() && DHD_DATA_ON()) {
7981             data = (uint8 *)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
7982             prhex("dhdsdio_pktgen: Tx Data", data,
7983                   PKTLEN(osh, pkt) - SDPCM_HDRLEN);
7984         }
7985 #endif // endif
7986 
7987         /* Send it */
7988         if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) != BCME_OK) {
7989             bus->pktgen_fail++;
7990             if (bus->pktgen_stop && bus->pktgen_stop == bus->pktgen_fail) {
7991                 bus->pktgen_count = 0;
7992             }
7993         }
7994         bus->pktgen_sent++;
7995 
7996         /* Bump length if not fixed, wrap at max */
7997         if (++bus->pktgen_len > bus->pktgen_maxlen) {
7998             bus->pktgen_len = (uint16)bus->pktgen_minlen;
7999         }
8000 
8001         /* Special case for burst mode: just send one request! */
8002         if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) {
8003             break;
8004         }
8005     }
8006 }
8007 
dhdsdio_sdtest_set(dhd_bus_t * bus,uint count)8008 static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint count)
8009 {
8010     void *pkt;
8011     uint8 *data;
8012     osl_t *osh = bus->dhd->osh;
8013 
8014     /* Allocate the packet */
8015     if (!(pkt = PKTGET(osh,
8016                        SDPCM_HDRLEN + SDPCM_TEST_HDRLEN +
8017                            SDPCM_TEST_PKT_CNT_FLD_LEN + DHD_SDALIGN,
8018                        TRUE))) {
8019         DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
8020         return;
8021     }
8022     PKTALIGN(osh, pkt,
8023              (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + SDPCM_TEST_PKT_CNT_FLD_LEN),
8024              DHD_SDALIGN);
8025     data = (uint8 *)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
8026 
8027     /* Fill in the test header */
8028     *data++ = SDPCM_TEST_SEND;
8029     *data++ = (count > 0) ? TRUE : FALSE;
8030     *data++ = (bus->pktgen_maxlen >> 0);
8031     *data++ = (bus->pktgen_maxlen >> 0x8);
8032     *data++ = (uint8)(count >> 0);
8033     *data++ = (uint8)(count >> 0x8);
8034     *data++ = (uint8)(count >> 0x10);
8035     *data++ = (uint8)(count >> 0x18);
8036 
8037     /* Send it */
8038     if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) != BCME_OK) {
8039         bus->pktgen_fail++;
8040     }
8041 }
8042 
dhdsdio_testrcv(dhd_bus_t * bus,void * pkt,uint seq)8043 static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq)
8044 {
8045     osl_t *osh = bus->dhd->osh;
8046     uint8 *data;
8047     uint pktlen;
8048 
8049     uint8 cmd;
8050     uint8 extra;
8051     uint16 len;
8052     uint16 offset;
8053 
8054     /* Check for min length */
8055     if ((pktlen = PKTLEN(osh, pkt)) < SDPCM_TEST_HDRLEN) {
8056         DHD_ERROR(("dhdsdio_restrcv: toss runt frame, pktlen %d\n", pktlen));
8057         PKTFREE(osh, pkt, FALSE);
8058         return;
8059     }
8060 
8061     /* Extract header fields */
8062     data = PKTDATA(osh, pkt);
8063     cmd = *data++;
8064     extra = *data++;
8065     len = *data++;
8066     len += *data++ << 0x8;
8067     DHD_TRACE(("%s:cmd:%d, xtra:%d,len:%d\n", __FUNCTION__, cmd, extra, len));
8068     /* Check length for relevant commands */
8069     if (cmd == SDPCM_TEST_DISCARD || cmd == SDPCM_TEST_ECHOREQ ||
8070         cmd == SDPCM_TEST_ECHORSP) {
8071         if (pktlen != len + SDPCM_TEST_HDRLEN) {
8072             DHD_ERROR(
8073                 ("dhdsdio_testrcv: frame length mismatch, pktlen %d seq %d"
8074                  " cmd %d extra %d len %d\n",
8075                  pktlen, seq, cmd, extra, len));
8076             PKTFREE(osh, pkt, FALSE);
8077             return;
8078         }
8079     }
8080 
8081     /* Process as per command */
8082     switch (cmd) {
8083         case SDPCM_TEST_ECHOREQ:
8084             /* Rx->Tx turnaround ok (even on NDIS w/current implementation) */
8085             *(uint8 *)(PKTDATA(osh, pkt)) = SDPCM_TEST_ECHORSP;
8086             if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) ==
8087                 BCME_OK) {
8088                 bus->pktgen_sent++;
8089             } else {
8090                 bus->pktgen_fail++;
8091                 PKTFREE(osh, pkt, FALSE);
8092             }
8093             bus->pktgen_rcvd++;
8094             break;
8095 
8096         case SDPCM_TEST_ECHORSP:
8097             if (bus->ext_loop) {
8098                 PKTFREE(osh, pkt, FALSE);
8099                 bus->pktgen_rcvd++;
8100                 break;
8101             }
8102 
8103             for (offset = 0; offset < len; offset++, data++) {
8104                 if (*data != SDPCM_TEST_FILL(offset, extra)) {
8105                     DHD_ERROR(("dhdsdio_testrcv: echo data mismatch: "
8106                                "offset %d (len %d) expect 0x%02x rcvd 0x%02x\n",
8107                                offset, len, SDPCM_TEST_FILL(offset, extra),
8108                                *data));
8109                     break;
8110                 }
8111             }
8112             PKTFREE(osh, pkt, FALSE);
8113             bus->pktgen_rcvd++;
8114             break;
8115 
8116         case SDPCM_TEST_DISCARD: {
8117             int i = 0;
8118             uint8 *prn = data;
8119             uint8 testval = extra;
8120             for (i = 0; i < len; i++) {
8121                 if (*prn != testval) {
8122                     DHD_ERROR(("DIErr@Pkt#:%d,Ix:%d, expected:0x%x, got:0x%x\n",
8123                                i, bus->pktgen_rcvd_rcvsession, testval, *prn));
8124                     prn++;
8125                     testval++;
8126                 }
8127             }
8128         }
8129             PKTFREE(osh, pkt, FALSE);
8130             bus->pktgen_rcvd++;
8131             break;
8132 
8133         case SDPCM_TEST_BURST:
8134         case SDPCM_TEST_SEND:
8135         default:
8136             DHD_INFO(("dhdsdio_testrcv: unsupported or unknown command, pktlen "
8137                       "%d seq %d"
8138                       " cmd %d extra %d len %d\n",
8139                       pktlen, seq, cmd, extra, len));
8140             PKTFREE(osh, pkt, FALSE);
8141             break;
8142     }
8143 
8144     /* For recv mode, stop at limit (and tell dongle to stop sending) */
8145     if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
8146         if (bus->pktgen_rcv_state != PKTGEN_RCV_IDLE) {
8147             bus->pktgen_rcvd_rcvsession++;
8148 
8149             if (bus->pktgen_total &&
8150                 (bus->pktgen_rcvd_rcvsession >= bus->pktgen_total)) {
8151                 bus->pktgen_count = 0;
8152                 DHD_ERROR(("Pktgen:rcv test complete!\n"));
8153                 bus->pktgen_rcv_state = PKTGEN_RCV_IDLE;
8154                 dhdsdio_sdtest_set(bus, FALSE);
8155                 bus->pktgen_rcvd_rcvsession = 0;
8156             }
8157         }
8158     }
8159 }
8160 #endif /* SDTEST */
8161 
dhd_bus_oob_intr_register(dhd_pub_t * dhdp)8162 int dhd_bus_oob_intr_register(dhd_pub_t *dhdp)
8163 {
8164     int err = 0;
8165 
8166 #if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
8167     err = bcmsdh_oob_intr_register(dhdp->bus->sdh, dhdsdio_isr, dhdp->bus);
8168 #endif // endif
8169     return err;
8170 }
8171 
dhd_bus_oob_intr_unregister(dhd_pub_t * dhdp)8172 void dhd_bus_oob_intr_unregister(dhd_pub_t *dhdp)
8173 {
8174 #if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
8175     bcmsdh_oob_intr_unregister(dhdp->bus->sdh);
8176 #endif // endif
8177 }
8178 
dhd_bus_oob_intr_set(dhd_pub_t * dhdp,bool enable)8179 void dhd_bus_oob_intr_set(dhd_pub_t *dhdp, bool enable)
8180 {
8181 #if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
8182     bcmsdh_oob_intr_set(dhdp->bus->sdh, enable);
8183 #endif // endif
8184 }
8185 
dhd_bus_dev_pm_stay_awake(dhd_pub_t * dhdpub)8186 void dhd_bus_dev_pm_stay_awake(dhd_pub_t *dhdpub)
8187 {
8188     bcmsdh_dev_pm_stay_awake(dhdpub->bus->sdh);
8189 }
8190 
dhd_bus_dev_pm_relax(dhd_pub_t * dhdpub)8191 void dhd_bus_dev_pm_relax(dhd_pub_t *dhdpub)
8192 {
8193     bcmsdh_dev_relax(dhdpub->bus->sdh);
8194 }
8195 
dhd_bus_dev_pm_enabled(dhd_pub_t * dhdpub)8196 bool dhd_bus_dev_pm_enabled(dhd_pub_t *dhdpub)
8197 {
8198     bool enabled = FALSE;
8199 
8200     enabled = bcmsdh_dev_pm_enabled(dhdpub->bus->sdh);
8201     return enabled;
8202 }
8203 
dhd_bus_watchdog(dhd_pub_t * dhdp)8204 extern bool dhd_bus_watchdog(dhd_pub_t *dhdp)
8205 {
8206     dhd_bus_t *bus;
8207     unsigned long flags;
8208 
8209     DHD_TIMER(("%s: Enter\n", __FUNCTION__));
8210 
8211     bus = dhdp->bus;
8212 
8213     if (bus->dhd->dongle_reset) {
8214         return FALSE;
8215     }
8216 
8217     if (bus->dhd->hang_was_sent) {
8218         dhd_os_wd_timer(bus->dhd, 0);
8219         return FALSE;
8220     }
8221 
8222     /* Ignore the timer if simulating bus down */
8223     if (!SLPAUTO_ENAB(bus) && bus->sleeping) {
8224         return FALSE;
8225     }
8226 
8227     DHD_LINUX_GENERAL_LOCK(dhdp, flags);
8228     if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhdp) ||
8229         DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(dhdp)) {
8230         DHD_LINUX_GENERAL_UNLOCK(dhdp, flags);
8231         return FALSE;
8232     }
8233     DHD_BUS_BUSY_SET_IN_WD(dhdp);
8234     DHD_LINUX_GENERAL_UNLOCK(dhdp, flags);
8235 
8236     dhd_os_sdlock(bus->dhd);
8237 
8238     /* Poll period: check device if appropriate. */
8239     // terence 20160615: remove !SLPAUTO_ENAB(bus) to fix not able to polling if
8240     // sr supported
8241     if (1 && (bus->poll && (++bus->polltick >= bus->pollrate))) {
8242         uint32 intstatus = 0;
8243 
8244         /* Reset poll tick */
8245         bus->polltick = 0;
8246 
8247         /* Check device if no interrupts */
8248         if (!bus->intr || (bus->intrcount == bus->lastintrs)) {
8249 #ifndef BCMSPI
8250             if (!bus->dpc_sched) {
8251                 uint8 devpend;
8252                 devpend = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0,
8253                                           SDIOD_CCCR_INTPEND, NULL);
8254                 intstatus = devpend & (INTR_STATUS_FUNC1 | INTR_STATUS_FUNC2);
8255             }
8256 #else
8257             if (!bus->dpc_sched) {
8258                 uint32 devpend;
8259                 devpend = bcmsdh_cfg_read_word(bus->sdh, SDIO_FUNC_0,
8260                                                SPID_STATUS_REG, NULL);
8261                 intstatus = devpend & STATUS_F2_PKT_AVAILABLE;
8262             }
8263 #endif /* !BCMSPI */
8264 
8265             /* If there is something, make like the ISR and schedule the DPC */
8266             if (intstatus) {
8267                 bus->pollcnt++;
8268                 bus->ipend = TRUE;
8269                 if (bus->intr) {
8270                     bcmsdh_intr_disable(bus->sdh);
8271                 }
8272                 bus->dpc_sched = TRUE;
8273                 dhd_sched_dpc(bus->dhd);
8274             }
8275         }
8276 
8277         /* Update interrupt tracking */
8278         bus->lastintrs = bus->intrcount;
8279     }
8280 
8281     if ((!bus->dpc_sched) && pktq_n_pkts_tot(&bus->txq)) {
8282         bus->dpc_sched = TRUE;
8283         dhd_sched_dpc(bus->dhd);
8284     }
8285 
8286 #ifdef DHD_DEBUG
8287     /* Poll for console output periodically */
8288     if (dhdp->busstate == DHD_BUS_DATA && dhdp->dhd_console_ms != 0) {
8289         bus->console.count += dhd_watchdog_ms;
8290         if (bus->console.count >= dhdp->dhd_console_ms) {
8291             bus->console.count -= dhdp->dhd_console_ms;
8292             /* Make sure backplane clock is on */
8293             if (SLPAUTO_ENAB(bus)) {
8294                 dhdsdio_bussleep(bus, FALSE);
8295             } else {
8296                 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
8297             }
8298             if (dhdsdio_readconsole(bus) < 0) {
8299                 dhdp->dhd_console_ms = 0; /* On error, stop trying */
8300             }
8301         }
8302     }
8303 #endif /* DHD_DEBUG */
8304 
8305 #ifdef SDTEST
8306     /* Generate packets if configured */
8307     if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) {
8308         /* Make sure backplane clock is on */
8309         if (SLPAUTO_ENAB(bus)) {
8310             dhdsdio_bussleep(bus, FALSE);
8311         } else {
8312             dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
8313         }
8314         bus->pktgen_tick = 0;
8315         dhdsdio_pktgen(bus);
8316     }
8317 #endif // endif
8318 
8319     /* On idle timeout clear activity flag and/or turn off clock */
8320 #ifdef DHD_USE_IDLECOUNT
8321     if (bus->activity) {
8322         bus->activity = FALSE;
8323     } else {
8324         bus->idlecount++;
8325 
8326         /*
8327          * If the condition to switch off the clock is reached And if
8328          * BT is inactive (in case of BT_OVER_SDIO build) turn off clk.
8329          *
8330          * Consider the following case, DHD is configured with
8331          * 1) idletime == DHD_IDLE_IMMEDIATE
8332          * 2) BT is the last user of the clock
8333          * We cannot disable the clock from __dhdsdio_clk_disable
8334          * since WLAN might be using it. If WLAN is active then
8335          * from the respective function/context after doing the job
8336          * the clk is turned off.
8337          * But if WLAN is actually inactive then the watchdog should
8338          * disable the clock. So the condition check below should be
8339          * bus->idletime != 0 instead of idletime == 0
8340          */
8341         if ((bus->idletime != 0) && (bus->idlecount >= bus->idletime) &&
8342             NO_OTHER_ACTIVE_BUS_USER(bus)) {
8343             DHD_TIMER(("%s: DHD Idle state!!\n", __FUNCTION__));
8344             if (!bus->poll && SLPAUTO_ENAB(bus)) {
8345                 if (dhdsdio_bussleep(bus, TRUE) != BCME_BUSY) {
8346                     dhd_os_wd_timer(bus->dhd, 0);
8347                 }
8348             } else {
8349                 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
8350             }
8351 
8352             bus->idlecount = 0;
8353         }
8354     }
8355 #else
8356     if ((bus->idletime != 0) && (bus->clkstate == CLK_AVAIL) &&
8357         NO_OTHER_ACTIVE_BUS_USER(bus)) {
8358         if (++bus->idlecount >= bus->idletime) {
8359             bus->idlecount = 0;
8360             if (bus->activity) {
8361                 bus->activity = FALSE;
8362                 if (!bus->poll && SLPAUTO_ENAB(bus)) {
8363                     if (!bus->readframes) {
8364                         dhdsdio_bussleep(bus, TRUE);
8365                     } else {
8366                         bus->reqbussleep = TRUE;
8367                     }
8368                 } else {
8369                     dhdsdio_clkctl(bus, CLK_NONE, FALSE);
8370                 }
8371             }
8372         }
8373     }
8374 #endif /* DHD_USE_IDLECOUNT */
8375 
8376     dhd_os_sdunlock(bus->dhd);
8377 
8378     DHD_LINUX_GENERAL_LOCK(dhdp, flags);
8379     DHD_BUS_BUSY_CLEAR_IN_WD(dhdp);
8380     dhd_os_busbusy_wake(dhdp);
8381     DHD_LINUX_GENERAL_UNLOCK(dhdp, flags);
8382 
8383     return bus->ipend;
8384 }
8385 
dhd_bus_console_in(dhd_pub_t * dhdp,uchar * msg,uint msglen)8386 extern int dhd_bus_console_in(dhd_pub_t *dhdp, uchar *msg, uint msglen)
8387 {
8388     dhd_bus_t *bus = dhdp->bus;
8389     uint32 addr, val;
8390     int rv;
8391     void *pkt;
8392 
8393 #ifndef CONSOLE_DPC
8394     /* Exclusive bus access */
8395     dhd_os_sdlock(bus->dhd);
8396 #endif
8397 
8398     /* Address could be zero if CONSOLE := 0 in dongle Makefile */
8399     if (bus->console_addr == 0) {
8400         rv = BCME_UNSUPPORTED;
8401         goto exit;
8402     }
8403 
8404     /* Don't allow input if dongle is in reset */
8405     if (bus->dhd->dongle_reset) {
8406         rv = BCME_NOTREADY;
8407         goto exit;
8408     }
8409 
8410 #ifndef CONSOLE_DPC
8411     if (!DATAOK(bus)) {
8412         DHD_CTL(
8413             ("%s: No bus credit bus->tx_max %d, bus->tx_seq %d, pktq_len %d\n",
8414              __FUNCTION__, bus->tx_max, bus->tx_seq,
8415              pktq_n_pkts_tot(&bus->txq)));
8416         rv = BCME_NOTREADY;
8417         goto exit;
8418     }
8419 
8420     /* Request clock to allow SDIO accesses */
8421     BUS_WAKE(bus);
8422     /* No pend allowed since txpkt is called later, ht clk has to be on */
8423     dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
8424 #endif
8425 
8426     /* Zero cbuf_index */
8427     addr = bus->console_addr + OFFSETOF(hnd_cons_t, cbuf_idx);
8428     val = htol32(0);
8429     if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) <
8430         0) {
8431         goto done;
8432     }
8433 
8434     /* Write message into cbuf */
8435     addr = bus->console_addr + OFFSETOF(hnd_cons_t, cbuf);
8436     if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0) {
8437         goto done;
8438     }
8439 
8440     /* Write length into vcons_in */
8441     addr = bus->console_addr + OFFSETOF(hnd_cons_t, vcons_in);
8442     val = htol32(msglen);
8443     if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) <
8444         0) {
8445         goto done;
8446     }
8447 
8448     /* Bump dongle by sending an empty packet on the event channel.
8449      * sdpcm_sendup (RX) checks for virtual console input.
8450      */
8451     if ((pkt = PKTGET(bus->dhd->osh, 0x4 + SDPCM_RESERVE, TRUE)) != NULL) {
8452         rv = dhdsdio_txpkt(bus, SDPCM_EVENT_CHANNEL, &pkt, 1, TRUE);
8453     }
8454 
8455 done:
8456 #ifndef CONSOLE_DPC
8457     if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched &&
8458         NO_OTHER_ACTIVE_BUS_USER(bus)) {
8459         bus->activity = FALSE;
8460         dhdsdio_bussleep(bus, TRUE);
8461         dhdsdio_clkctl(bus, CLK_NONE, FALSE);
8462     }
8463 #endif
8464 
8465 exit:
8466 #ifdef CONSOLE_DPC
8467     memset(bus->cons_cmd, 0, sizeof(bus->cons_cmd));
8468 #else
8469     dhd_os_sdunlock(bus->dhd);
8470 #endif
8471     return rv;
8472 }
8473 
8474 #ifdef CONSOLE_DPC
dhd_bus_txcons(dhd_pub_t * dhdp,uchar * msg,uint msglen)8475 extern int dhd_bus_txcons(dhd_pub_t *dhdp, uchar *msg, uint msglen)
8476 {
8477     dhd_bus_t *bus = dhdp->bus;
8478     int ret = BCME_OK;
8479 
8480     dhd_os_sdlock(bus->dhd);
8481 
8482     /* Address could be zero if CONSOLE := 0 in dongle Makefile */
8483     if (bus->console_addr == 0) {
8484         ret = BCME_UNSUPPORTED;
8485         goto exit;
8486     }
8487 
8488     /* Don't allow input if dongle is in reset */
8489     if (bus->dhd->dongle_reset) {
8490         ret = BCME_NOTREADY;
8491         goto exit;
8492     }
8493 
8494     if (msglen >= sizeof(bus->cons_cmd)) {
8495         DHD_ERROR(("%s: \"%s\"(%d) too long\n", __FUNCTION__, msg, msglen));
8496         ret = BCME_BADARG;
8497         goto exit;
8498     }
8499 
8500     if (!strlen(bus->cons_cmd)) {
8501         strncpy(bus->cons_cmd, msg, sizeof(bus->cons_cmd));
8502         DHD_CTL(("%s: \"%s\" delay send, tx_max %d, tx_seq %d, pktq_len %d\n",
8503                  __FUNCTION__, bus->cons_cmd, bus->tx_max, bus->tx_seq,
8504                  pktq_n_pkts_tot(&bus->txq)));
8505         if (!bus->dpc_sched) {
8506             bus->dpc_sched = TRUE;
8507             dhd_sched_dpc(bus->dhd);
8508         }
8509     } else {
8510         DHD_CTL(("%s: \"%s\" is pending, tx_max %d, tx_seq %d, pktq_len %d\n",
8511                  __FUNCTION__, bus->cons_cmd, bus->tx_max, bus->tx_seq,
8512                  pktq_n_pkts_tot(&bus->txq)));
8513         ret = BCME_NOTREADY;
8514     }
8515 
8516 exit:
8517     dhd_os_sdunlock(bus->dhd);
8518 
8519     return ret;
8520 }
8521 #endif
8522 
8523 #if defined(DHD_DEBUG) && !defined(BCMSDIOLITE)
dhd_dump_cis(uint fn,uint8 * cis)8524 static void dhd_dump_cis(uint fn, uint8 *cis)
8525 {
8526     uint byte, tag, tdata;
8527     DHD_INFO(("Function %d CIS:\n", fn));
8528 
8529     for (tdata = byte = 0; byte < SBSDIO_CIS_SIZE_LIMIT; byte++) {
8530         if ((byte % 0x10) == 0) {
8531             DHD_INFO(("    "));
8532         }
8533         DHD_INFO(("%02x ", cis[byte]));
8534         if ((byte % 0x10) == 0xF) {
8535             DHD_INFO(("\n"));
8536         }
8537         if (!tdata--) {
8538             tag = cis[byte];
8539             if (tag == 0xff) {
8540                 break;
8541             } else if (!tag) {
8542                 tdata = 0;
8543             } else if ((byte + 1) < SBSDIO_CIS_SIZE_LIMIT) {
8544                 tdata = cis[byte + 1] + 1;
8545             } else {
8546                 DHD_INFO(("]"));
8547             }
8548         }
8549     }
8550     if ((byte % 0x10) != 0xF) {
8551         DHD_INFO(("\n"));
8552     }
8553 }
8554 #endif /* DHD_DEBUG */
8555 
dhdsdio_chipmatch(uint16 chipid)8556 static bool dhdsdio_chipmatch(uint16 chipid)
8557 {
8558     if (chipid == BCM4330_CHIP_ID) {
8559         return TRUE;
8560     }
8561     if (chipid == BCM43362_CHIP_ID) {
8562         return TRUE;
8563     }
8564     if (chipid == BCM43340_CHIP_ID) {
8565         return TRUE;
8566     }
8567     if (chipid == BCM43341_CHIP_ID) {
8568         return TRUE;
8569     }
8570     if (chipid == BCM4334_CHIP_ID) {
8571         return TRUE;
8572     }
8573     if (chipid == BCM4324_CHIP_ID) {
8574         return TRUE;
8575     }
8576     if (chipid == BCM4335_CHIP_ID) {
8577         return TRUE;
8578     }
8579     if (chipid == BCM4339_CHIP_ID) {
8580         return TRUE;
8581     }
8582     if (BCM4345_CHIP(chipid)) {
8583         return TRUE;
8584     }
8585     if (chipid == BCM4350_CHIP_ID) {
8586         return TRUE;
8587     }
8588     if (chipid == BCM4354_CHIP_ID) {
8589         return TRUE;
8590     }
8591     if (chipid == BCM4358_CHIP_ID) {
8592         return TRUE;
8593     }
8594     if (chipid == BCM43569_CHIP_ID) {
8595         return TRUE;
8596     }
8597     if (chipid == BCM4371_CHIP_ID) {
8598         return TRUE;
8599     }
8600     if (chipid == BCM43430_CHIP_ID) {
8601         return TRUE;
8602     }
8603     if (chipid == BCM43018_CHIP_ID) {
8604         return TRUE;
8605     }
8606     if (BCM4349_CHIP(chipid)) {
8607         return TRUE;
8608     }
8609     if (chipid == BCM4364_CHIP_ID) {
8610         return TRUE;
8611     }
8612 
8613     if (chipid == BCM43012_CHIP_ID) {
8614         return TRUE;
8615     }
8616 
8617     if (chipid == BCM43014_CHIP_ID) {
8618         return TRUE;
8619     }
8620 
8621     if (chipid == BCM4369_CHIP_ID) {
8622         return TRUE;
8623     }
8624     if (chipid == BCM4362_CHIP_ID) {
8625         return TRUE;
8626     }
8627     if (chipid == BCM43751_CHIP_ID) {
8628         return TRUE;
8629     }
8630     if (chipid == BCM43752_CHIP_ID) {
8631         return TRUE;
8632     }
8633 
8634     return FALSE;
8635 }
8636 
dhdsdio_probe(uint16 venid,uint16 devid,uint16 bus_no,uint16 slot,uint16 func,uint bustype,void * regsva,osl_t * osh,void * sdh)8637 static void *dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no,
8638                            uint16 slot, uint16 func, uint bustype, void *regsva,
8639                            osl_t *osh, void *sdh)
8640 {
8641     int ret;
8642     dhd_bus_t *bus;
8643 
8644     DHD_MUTEX_LOCK();
8645 
8646     /* Init global variables at run-time, not as part of the declaration.
8647      * This is required to support init/de-init of the driver. Initialization
8648      * of globals as part of the declaration results in non-deterministic
8649      * behavior since the value of the globals may be different on the
8650      * first time that the driver is initialized vs subsequent initializations.
8651      */
8652     dhd_txbound = DHD_TXBOUND;
8653     dhd_rxbound = DHD_RXBOUND;
8654 #ifdef BCMSPI
8655     dhd_alignctl = FALSE;
8656 #else
8657     dhd_alignctl = TRUE;
8658 #endif /* BCMSPI */
8659     sd1idle = TRUE;
8660     dhd_readahead = TRUE;
8661     retrydata = FALSE;
8662 
8663 #ifdef DISABLE_FLOW_CONTROL
8664     dhd_doflow = FALSE;
8665 #endif /* DISABLE_FLOW_CONTROL */
8666     dhd_dongle_ramsize = 0;
8667     dhd_txminmax = DHD_TXMINMAX;
8668 
8669 #ifdef BCMSPI
8670     forcealign = FALSE;
8671 #else
8672     forcealign = TRUE;
8673 #endif /* !BCMSPI */
8674 
8675     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
8676     DHD_INFO(("%s: venid 0x%04x devid 0x%04x\n", __FUNCTION__, venid, devid));
8677 
8678     /* We make assumptions about address window mappings */
8679     ASSERT((uintptr)regsva == si_enum_base(devid));
8680 
8681     /* BCMSDH passes venid and devid based on CIS parsing -- but low-power start
8682      * means early parse could fail, so here we should get either an ID
8683      * we recognize OR (-1) indicating we must request power first.
8684      */
8685     /* Check the Vendor ID */
8686     switch (venid) {
8687         case 0x0000:
8688         case VENDOR_BROADCOM:
8689             break;
8690         default:
8691             DHD_ERROR(("%s: unknown vendor: 0x%04x\n", __FUNCTION__, venid));
8692             goto forcereturn;
8693     }
8694 
8695     /* Check the Device ID and make sure it's one that we support */
8696     switch (devid) {
8697         case 0:
8698             DHD_INFO(("%s: allow device id 0, will check chip internals\n",
8699                       __FUNCTION__));
8700             break;
8701 
8702         default:
8703             DHD_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n",
8704                        __FUNCTION__, venid, devid));
8705             goto forcereturn;
8706     }
8707 
8708     if (osh == NULL) {
8709         DHD_ERROR(("%s: osh is NULL!\n", __FUNCTION__));
8710         goto forcereturn;
8711     }
8712 
8713     /* Allocate private bus interface state */
8714     if (!(bus = MALLOC(osh, sizeof(dhd_bus_t)))) {
8715         DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__));
8716         goto fail;
8717     }
8718     bzero(bus, sizeof(dhd_bus_t));
8719     bus->sdh = sdh;
8720     bus->cl_devid = (uint16)devid;
8721     bus->bus = DHD_BUS;
8722     bus->bus_num = bus_no;
8723     bus->slot_num = slot;
8724     bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
8725     bus->usebufpool =
8726         FALSE; /* Use bufpool if allocated, else use locally malloced rxbuf */
8727 #ifdef BT_OVER_SDIO
8728     bus->bt_use_count = 0;
8729 #endif // endif
8730 
8731 #if defined(SUPPORT_P2P_GO_PS)
8732     init_waitqueue_head(&bus->bus_sleep);
8733 #endif /* LINUX && SUPPORT_P2P_GO_PS */
8734     init_waitqueue_head(&bus->ctrl_tx_wait);
8735 
8736     /* attempt to attach to the dongle */
8737     if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) {
8738         DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __FUNCTION__));
8739         goto fail;
8740     }
8741 
8742     /* Attach to the dhd/OS/network interface */
8743     if (!(bus->dhd = dhd_attach(osh, bus, SDPCM_RESERVE))) {
8744         DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__));
8745         goto fail;
8746     }
8747 
8748 #if defined(GET_OTP_MAC_ENABLE) || defined(GET_OTP_MODULE_NAME)
8749     dhd_conf_get_otp(bus->dhd, sdh, bus->sih);
8750 #endif
8751 
8752     /* Allocate buffers */
8753     if (!(dhdsdio_probe_malloc(bus, osh, sdh))) {
8754         DHD_ERROR(("%s: dhdsdio_probe_malloc failed\n", __FUNCTION__));
8755         goto fail;
8756     }
8757 
8758     if (!(dhdsdio_probe_init(bus, osh, sdh))) {
8759         DHD_ERROR(("%s: dhdsdio_probe_init failed\n", __FUNCTION__));
8760         goto fail;
8761     }
8762 
8763     if (bus->intr) {
8764         /* Register interrupt callback, but mask it (not operational yet). */
8765         DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n",
8766                   __FUNCTION__));
8767         bcmsdh_intr_disable(sdh);
8768         if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) {
8769             DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n",
8770                        __FUNCTION__, ret));
8771             goto fail;
8772         }
8773         DHD_INTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__));
8774     } else {
8775         DHD_INFO(("%s: SDIO interrupt function is NOT registered due to "
8776                   "polling mode\n",
8777                   __FUNCTION__));
8778     }
8779 
8780     DHD_INFO(("%s: completed!!\n", __FUNCTION__));
8781 
8782     /* if firmware path present try to download and bring up bus */
8783     bus->dhd->hang_report = TRUE;
8784 #if defined(BT_OVER_SDIO)
8785     /* At this point Regulators are turned on and iconditionaly sdio bus is
8786      * started based upon dhd_download_fw_on_driverload check, so increase the
8787      * bus user count, this count will only be disabled inside dhd_register_if()
8788      * function if flag dhd_download_fw_on_driverload is set to false, i.e FW
8789      * download during insmod is not needed, otherwise it will not be
8790      * decremented so that WALN will always hold the bus untill rmmod is done.
8791      */
8792     dhdsdio_bus_usr_cnt_inc(bus->dhd);
8793 #endif /* BT_OVER_SDIO */
8794 
8795     /* Ok, have the per-port tell the stack we're open for business */
8796     if (dhd_attach_net(bus->dhd, TRUE) != 0) {
8797         DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__));
8798         goto fail;
8799     }
8800 
8801 #ifdef BCMHOST_XTAL_PU_TIME_MOD
8802     bcmsdh_reg_write(bus->sdh, 0x18000620, 0x2, 0xB);
8803     bcmsdh_reg_write(bus->sdh, 0x18000628, 0x4, 0x00F80001);
8804 #endif /* BCMHOST_XTAL_PU_TIME_MOD */
8805 
8806 #if defined(MULTIPLE_SUPPLICANT)
8807     wl_android_post_init(); // terence 20120530: fix critical section in
8808                             // dhd_open and dhdsdio_probe
8809 #endif                      /* MULTIPLE_SUPPLICANT */
8810     DHD_MUTEX_UNLOCK();
8811 
8812     return bus;
8813 
8814 fail:
8815     dhdsdio_release(bus, osh);
8816 
8817 forcereturn:
8818     DHD_MUTEX_UNLOCK();
8819 
8820     return NULL;
8821 }
8822 
dhdsdio_probe_attach(struct dhd_bus * bus,osl_t * osh,void * sdh,void * regsva,uint16 devid)8823 static bool dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh,
8824                                  void *regsva, uint16 devid)
8825 {
8826 #ifndef BCMSPI
8827     uint8 clkctl = 0;
8828 #endif /* !BCMSPI */
8829     uint fn, numfn;
8830     uint8 *cis[SDIOD_MAX_IOFUNCS];
8831     int32 value;
8832     int err = 0;
8833 
8834     BCM_REFERENCE(value);
8835     bus->alp_only = TRUE;
8836     bus->sih = NULL;
8837 
8838     /* Return the window to backplane enumeration space for core access */
8839     if (dhdsdio_set_siaddr_window(bus, si_enum_base(devid))) {
8840         DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__));
8841     }
8842 
8843 #if defined(DHD_DEBUG)
8844     DHD_ERROR(("F1 signature read @0x18000000=0x%4x\n",
8845                bcmsdh_reg_read(bus->sdh, si_enum_base(devid), 0x4)));
8846 #endif // endif
8847 
8848 #ifndef BCMSPI /* wake-wlan in gSPI will bring up the htavail/alpavail clocks. \
8849                 */
8850 
8851     /* Force PLL off until si_attach() programs PLL control regs */
8852 
8853     bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
8854                      DHD_INIT_CLKCTL1, &err);
8855     if (!err) {
8856         clkctl =
8857             bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
8858     }
8859 
8860     if (err || ((clkctl & ~SBSDIO_AVBITS) != DHD_INIT_CLKCTL1)) {
8861         DHD_ERROR(("dhdsdio_probe: ChipClkCSR access: err %d wrote 0x%02x read "
8862                    "0x%02x\n",
8863                    err, DHD_INIT_CLKCTL1, clkctl));
8864         goto fail;
8865     }
8866 
8867 #endif /* !BCMSPI */
8868 #ifndef BCMSPI
8869     numfn = bcmsdh_query_iofnum(sdh);
8870     ASSERT(numfn <= SDIOD_MAX_IOFUNCS);
8871 
8872     /* Make sure ALP is available before trying to read CIS */
8873     SPINWAIT(((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
8874                                         SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
8875               !SBSDIO_ALPAV(clkctl)),
8876              PMU_MAX_TRANSITION_DLY);
8877 
8878     /* Now request ALP be put on the bus */
8879     bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
8880                      DHD_INIT_CLKCTL2, &err);
8881     OSL_DELAY(0x41);
8882 #else
8883     numfn =
8884         0; /* internally func is hardcoded to 1 as gSPI has cis on F1 only */
8885 #endif /* !BCMSPI */
8886 #ifndef BCMSDIOLITE
8887     if (DHD_INFO_ON()) {
8888         for (fn = 0; fn <= numfn; fn++) {
8889             if (!(cis[fn] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) {
8890                 DHD_INFO(("dhdsdio_probe: fn %d cis malloc failed\n", fn));
8891                 break;
8892             }
8893             bzero(cis[fn], SBSDIO_CIS_SIZE_LIMIT);
8894 
8895             if ((err = bcmsdh_cis_read(sdh, fn, cis[fn],
8896                                        SBSDIO_CIS_SIZE_LIMIT))) {
8897                 DHD_INFO(("dhdsdio_probe: fn %d cis read err %d\n", fn, err));
8898                 MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
8899                 break;
8900             }
8901 #ifdef DHD_DEBUG
8902             if (DHD_INFO_ON()) {
8903                 dhd_dump_cis(fn, cis[fn]);
8904             }
8905 #endif /* DHD_DEBUG */
8906         }
8907         while (fn-- > 0) {
8908             ASSERT(cis[fn]);
8909             MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
8910         }
8911     }
8912 #else
8913     BCM_REFERENCE(cis);
8914     BCM_REFERENCE(fn);
8915 #endif /* DHD_DEBUG */
8916 
8917     if (err) {
8918         DHD_ERROR(("dhdsdio_probe: failure reading or parsing CIS\n"));
8919         goto fail;
8920     }
8921     /* si_attach() will provide an SI handle and scan the backplane */
8922     if (!(bus->sih = si_attach((uint)devid, osh, regsva, DHD_BUS, sdh,
8923                                &bus->vars, &bus->varsz))) {
8924         DHD_ERROR(("%s: si_attach failed!\n", __FUNCTION__));
8925         goto fail;
8926     }
8927 
8928 #ifdef DHD_DEBUG
8929     DHD_ERROR(("F1 signature OK, socitype:0x%x chip:0x%4x rev:0x%x pkg:0x%x\n",
8930                bus->sih->socitype, bus->sih->chip, bus->sih->chiprev,
8931                bus->sih->chippkg));
8932 #endif /* DHD_DEBUG */
8933 
8934     bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev);
8935 
8936     if (!dhdsdio_chipmatch((uint16)bus->sih->chip)) {
8937         DHD_ERROR(
8938             ("%s: unsupported chip: 0x%04x\n", __FUNCTION__, bus->sih->chip));
8939         goto fail;
8940     }
8941 
8942     if (bus->sih->buscorerev >= 0xC) {
8943         dhdsdio_clk_kso_init(bus);
8944     } else {
8945         bus->kso = TRUE;
8946     }
8947 
8948     si_sdiod_drive_strength_init(bus->sih, osh, dhd_sdiod_drive_strength);
8949 
8950     /* Get info on the ARM and SOCRAM cores... */
8951     if (!DHD_NOPMU(bus)) {
8952         if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) ||
8953             (si_setcore(bus->sih, ARMCM3_CORE_ID, 0)) ||
8954             (si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) {
8955             bus->armrev = si_corerev(bus->sih);
8956         } else {
8957             DHD_ERROR(("%s: failed to find ARM core!\n", __FUNCTION__));
8958             goto fail;
8959         }
8960 
8961         if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
8962             if (!(bus->orig_ramsize = si_socram_size(bus->sih))) {
8963                 DHD_ERROR(
8964                     ("%s: failed to find SOCRAM memory!\n", __FUNCTION__));
8965                 goto fail;
8966             }
8967         } else {
8968             /* cr4 has a different way to find the RAM size from TCM's */
8969             if (!(bus->orig_ramsize = si_tcm_size(bus->sih))) {
8970                 DHD_ERROR(
8971                     ("%s: failed to find CR4-TCM memory!\n", __FUNCTION__));
8972                 goto fail;
8973             }
8974             /* also populate base address */
8975             switch ((uint16)bus->sih->chip) {
8976                 case BCM4335_CHIP_ID:
8977                 case BCM4339_CHIP_ID:
8978                     bus->dongle_ram_base = CR4_4335_RAM_BASE;
8979                     break;
8980                 case BCM4350_CHIP_ID:
8981                 case BCM4354_CHIP_ID:
8982                 case BCM4358_CHIP_ID:
8983                 case BCM43569_CHIP_ID:
8984                 case BCM4371_CHIP_ID:
8985                     bus->dongle_ram_base = CR4_4350_RAM_BASE;
8986                     break;
8987                 case BCM4360_CHIP_ID:
8988                     bus->dongle_ram_base = CR4_4360_RAM_BASE;
8989                     break;
8990                 CASE_BCM4345_CHIP:
8991                     bus->dongle_ram_base =
8992                         (bus->sih->chiprev < 0x6) /* from 4345C0 */
8993                             ? CR4_4345_LT_C0_RAM_BASE
8994                             : CR4_4345_GE_C0_RAM_BASE;
8995                     break;
8996                 case BCM4349_CHIP_GRPID:
8997                     /* RAM based changed from 4349c0(revid=9) onwards */
8998                     bus->dongle_ram_base = ((bus->sih->chiprev < 0x9)
8999                                                 ? CR4_4349_RAM_BASE
9000                                                 : CR4_4349_RAM_BASE_FROM_REV_9);
9001                     break;
9002                 case BCM4364_CHIP_ID:
9003                     bus->dongle_ram_base = CR4_4364_RAM_BASE;
9004                     break;
9005                 case BCM4362_CHIP_ID:
9006                     bus->dongle_ram_base = CR4_4362_RAM_BASE;
9007                     break;
9008                 case BCM43751_CHIP_ID:
9009                     bus->dongle_ram_base = CR4_43751_RAM_BASE;
9010                     break;
9011                 case BCM43752_CHIP_ID:
9012                     bus->dongle_ram_base = CR4_43752_RAM_BASE;
9013                     break;
9014                 case BCM4369_CHIP_ID:
9015                     bus->dongle_ram_base = CR4_4369_RAM_BASE;
9016                     break;
9017                 default:
9018                     bus->dongle_ram_base = 0;
9019                     DHD_ERROR(("%s: WARNING: Using default ram base at 0x%x\n",
9020                                __FUNCTION__, bus->dongle_ram_base));
9021             }
9022         }
9023         bus->ramsize = bus->orig_ramsize;
9024         if (dhd_dongle_ramsize) {
9025             dhd_dongle_setramsize(bus, dhd_dongle_ramsize);
9026         }
9027 
9028         DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d) at 0x%x\n",
9029                    bus->ramsize, bus->orig_ramsize, bus->dongle_ram_base));
9030 
9031         bus->srmemsize = si_socram_srmem_size(bus->sih);
9032     }
9033 
9034     /* ...but normally deal with the SDPCMDEV core */
9035 #ifdef BCMSDIOLITE
9036     if (!(bus->regs = si_setcore(bus->sih, CC_CORE_ID, 0))) {
9037         DHD_ERROR(("%s: failed to find Chip Common core!\n", __FUNCTION__));
9038         goto fail;
9039     }
9040 #else
9041     if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) &&
9042         !(bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0))) {
9043         DHD_ERROR(("%s: failed to find SDIODEV core!\n", __FUNCTION__));
9044         goto fail;
9045     }
9046 #endif // endif
9047     bus->sdpcmrev = si_corerev(bus->sih);
9048 
9049     /* Set core control so an SDIO reset does a backplane reset */
9050     OR_REG(osh, &bus->regs->corecontrol, CC_BPRESEN);
9051 #ifndef BCMSPI
9052     bus->rxint_mode = SDIO_DEVICE_HMB_RXINT;
9053 
9054     if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 0x4) &&
9055         (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) {
9056         uint32 val;
9057 
9058         val = R_REG(osh, &bus->regs->corecontrol);
9059         val &= ~CC_XMTDATAAVAIL_MODE;
9060         val |= CC_XMTDATAAVAIL_CTRL;
9061         W_REG(osh, &bus->regs->corecontrol, val);
9062     }
9063 #endif /* BCMSPI */
9064 
9065     pktq_init(&bus->txq, (PRIOMASK + 1), QLEN);
9066 
9067     /* Locate an appropriately-aligned portion of hdrbuf */
9068 #ifndef DYNAMIC_MAX_HDR_READ
9069     bus->rxhdr = (uint8 *)ROUNDUP((uintptr)&bus->hdrbuf[0], DHD_SDALIGN);
9070 #endif
9071 
9072     /* Set the poll and/or interrupt flags */
9073     bus->intr = (bool)dhd_intr;
9074     if ((bus->poll = (bool)dhd_poll)) {
9075         bus->pollrate = 1;
9076     }
9077 
9078     /* Setting default Glom size */
9079     bus->txglomsize = SDPCM_DEFGLOM_SIZE;
9080 
9081     return TRUE;
9082 
9083 fail:
9084     if (bus->sih != NULL) {
9085         si_detach(bus->sih);
9086         bus->sih = NULL;
9087     }
9088     return FALSE;
9089 }
9090 
dhdsdio_probe_malloc(dhd_bus_t * bus,osl_t * osh,void * sdh)9091 static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh)
9092 {
9093     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
9094 
9095     if (bus->dhd->maxctl) {
9096         bus->rxblen =
9097             ROUNDUP((bus->dhd->maxctl + SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN;
9098         if (!(bus->rxbuf =
9099                   DHD_OS_PREALLOC(bus->dhd, DHD_PREALLOC_RXBUF, bus->rxblen))) {
9100             DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n", __FUNCTION__,
9101                        bus->rxblen));
9102             goto fail;
9103         }
9104     }
9105     /* Allocate buffer to receive glomed packet */
9106     if (!(bus->databuf =
9107               DHD_OS_PREALLOC(bus->dhd, DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) {
9108         DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n", __FUNCTION__,
9109                    MAX_DATA_BUF));
9110         /* release rxbuf which was already located as above */
9111         if (!bus->rxblen) {
9112             DHD_OS_PREFREE(bus->dhd, bus->rxbuf, bus->rxblen);
9113         }
9114         goto fail;
9115     }
9116     /* Allocate buffer to membuf */
9117     bus->membuf = MALLOC(osh, MAX_MEM_BUF);
9118     if (bus->membuf == NULL) {
9119         DHD_ERROR(("%s: MALLOC of %d-byte membuf failed\n", __FUNCTION__,
9120                    MAX_MEM_BUF));
9121         if (bus->databuf) {
9122 #ifndef CONFIG_DHD_USE_STATIC_BUF
9123             MFREE(osh, bus->databuf, MAX_DATA_BUF);
9124 #endif
9125             bus->databuf = NULL;
9126         }
9127         /* release rxbuf which was already located as above */
9128         if (!bus->rxblen) {
9129             DHD_OS_PREFREE(bus->dhd, bus->rxbuf, bus->rxblen);
9130         }
9131         goto fail;
9132     }
9133     memset(bus->membuf, 0, MAX_MEM_BUF);
9134 
9135     /* Align the buffer */
9136     if ((uintptr)bus->databuf % DHD_SDALIGN) {
9137         bus->dataptr = bus->databuf +
9138                        (DHD_SDALIGN - ((uintptr)bus->databuf % DHD_SDALIGN));
9139     } else {
9140         bus->dataptr = bus->databuf;
9141     }
9142 
9143     return TRUE;
9144 
9145 fail:
9146     return FALSE;
9147 }
9148 
dhdsdio_probe_init(dhd_bus_t * bus,osl_t * osh,void * sdh)9149 static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh)
9150 {
9151     int32 fnum;
9152 
9153     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
9154 
9155     bus->_srenab = FALSE;
9156 
9157 #ifdef SDTEST
9158     dhdsdio_pktgen_init(bus);
9159 #endif /* SDTEST */
9160 
9161 #ifndef BCMSPI
9162     /* Disable F2 to clear any intermediate frame state on the dongle */
9163     bcmsdh_cfg_write(sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1,
9164                      NULL);
9165 #endif /* !BCMSPI */
9166 
9167     DHD_ERROR(("%s: making DHD_BUS_DOWN\n", __FUNCTION__));
9168     bus->dhd->busstate = DHD_BUS_DOWN;
9169     bus->sleeping = FALSE;
9170     bus->rxflow = FALSE;
9171     bus->prev_rxlim_hit = 0;
9172 
9173 #ifndef BCMSPI
9174     /* Done with backplane-dependent accesses, can drop clock... */
9175     bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
9176 #endif /* !BCMSPI */
9177 
9178     /* ...and initialize clock/power states */
9179     bus->clkstate = CLK_SDONLY;
9180     bus->idletime = (int32)dhd_idletime;
9181     bus->idleclock = DHD_IDLE_ACTIVE;
9182 
9183     /* Query the SD clock speed */
9184     if (bcmsdh_iovar_op(sdh, "sd_divisor", NULL, 0, &bus->sd_divisor,
9185                         sizeof(int32), FALSE) != BCME_OK) {
9186         DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_divisor"));
9187         bus->sd_divisor = -1;
9188     } else {
9189         DHD_INFO(("%s: Initial value for %s is %d\n", __FUNCTION__,
9190                   "sd_divisor", bus->sd_divisor));
9191     }
9192 
9193     /* Query the SD bus mode */
9194     if (bcmsdh_iovar_op(sdh, "sd_mode", NULL, 0, &bus->sd_mode, sizeof(int32),
9195                         FALSE) != BCME_OK) {
9196         DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_mode"));
9197         bus->sd_mode = -1;
9198     } else {
9199         DHD_INFO(("%s: Initial value for %s is %d\n", __FUNCTION__, "sd_mode",
9200                   bus->sd_mode));
9201     }
9202 
9203     /* Query the F2 block size, set roundup accordingly */
9204     fnum = 0x2;
9205     if (bcmsdh_iovar_op(sdh, "sd_blocksize", &fnum, sizeof(int32),
9206                         &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
9207         bus->blocksize = 0;
9208         DHD_ERROR(
9209             ("%s: fail on fn %d %s get\n", __FUNCTION__, fnum, "sd_blocksize"));
9210     } else {
9211         DHD_INFO(("%s: Initial value for fn %d %s is %d\n", __FUNCTION__, fnum,
9212                   "sd_blocksize", bus->blocksize));
9213 
9214         dhdsdio_tune_fifoparam(bus);
9215     }
9216     bus->roundup = MIN(max_roundup, bus->blocksize);
9217 
9218 #ifdef DHDENABLE_TAILPAD
9219     if (bus->pad_pkt) {
9220         PKTFREE(osh, bus->pad_pkt, FALSE);
9221     }
9222     bus->pad_pkt = PKTGET(osh, SDIO_MAX_BLOCK_SIZE, FALSE);
9223     if (bus->pad_pkt == NULL) {
9224         DHD_ERROR(("failed to allocate padding packet\n"));
9225     } else {
9226         int alignment_offset = 0;
9227         uintptr pktprt = (uintptr)PKTDATA(osh, bus->pad_pkt);
9228         if (!(pktprt & 1) && (pktprt = (pktprt % DHD_SDALIGN))) {
9229             PKTPUSH(osh, bus->pad_pkt, alignment_offset);
9230         }
9231         PKTSETNEXT(osh, bus->pad_pkt, NULL);
9232     }
9233 #endif /* DHDENABLE_TAILPAD */
9234 
9235     /* Query if bus module supports packet chaining, default to use if supported
9236      */
9237     if (bcmsdh_iovar_op(sdh, "sd_rxchain", NULL, 0, &bus->sd_rxchain,
9238                         sizeof(int32), FALSE) != BCME_OK) {
9239         bus->sd_rxchain = FALSE;
9240     } else {
9241         DHD_INFO(("%s: bus module (through bcmsdh API) %s chaining\n",
9242                   __FUNCTION__,
9243                   (bus->sd_rxchain ? "supports" : "does not support")));
9244     }
9245     bus->use_rxchain = (bool)bus->sd_rxchain;
9246     bus->txinrx_thres = CUSTOM_TXINRX_THRES;
9247     /* TX first in dhdsdio_readframes() */
9248     bus->dotxinrx = TRUE;
9249 
9250 #ifdef PKT_STATICS
9251     dhd_bus_clear_txpktstatics(bus->dhd);
9252 #endif
9253 
9254     return TRUE;
9255 }
9256 
dhd_bus_download_firmware(struct dhd_bus * bus,osl_t * osh,char * pfw_path,char * pnv_path,char * pclm_path,char * pconf_path)9257 int dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, char *pfw_path,
9258                               char *pnv_path, char *pclm_path, char *pconf_path)
9259 {
9260     int ret;
9261 
9262     bus->fw_path = pfw_path;
9263     bus->nv_path = pnv_path;
9264     bus->dhd->clm_path = pclm_path;
9265     bus->dhd->conf_path = pconf_path;
9266 
9267     ret = dhdsdio_download_firmware(bus, osh, bus->sdh);
9268 
9269     return ret;
9270 }
9271 
dhd_set_bus_params(struct dhd_bus * bus)9272 int dhd_set_bus_params(struct dhd_bus *bus)
9273 {
9274     int ret = 0;
9275 
9276     if (bus->dhd->conf->dhd_poll >= 0) {
9277         bus->poll = bus->dhd->conf->dhd_poll;
9278         if (!bus->pollrate) {
9279             bus->pollrate = 1;
9280         }
9281         printf("%s: set polling mode %d\n", __FUNCTION__,
9282                bus->dhd->conf->dhd_poll);
9283     }
9284     if (bus->dhd->conf->use_rxchain >= 0) {
9285         bus->use_rxchain = (bool)bus->dhd->conf->use_rxchain;
9286     }
9287     if (bus->dhd->conf->txinrx_thres >= 0) {
9288         bus->txinrx_thres = bus->dhd->conf->txinrx_thres;
9289     }
9290     if (bus->dhd->conf->txglomsize >= 0) {
9291         bus->txglomsize = bus->dhd->conf->txglomsize;
9292     }
9293 #ifdef MINIME
9294     if (bus->dhd->conf->fw_type == FW_TYPE_MINIME) {
9295         bus->ramsize = bus->dhd->conf->ramsize;
9296         printf("%s: set ramsize 0x%x\n", __FUNCTION__, bus->ramsize);
9297     }
9298 #endif
9299 #ifdef DYNAMIC_MAX_HDR_READ
9300     if (bus->dhd->conf->max_hdr_read <= 0) {
9301         bus->dhd->conf->max_hdr_read = MAX_HDR_READ;
9302     }
9303     if (bus->hdrbufp) {
9304         MFREE(bus->dhd->osh, bus->hdrbufp,
9305               bus->dhd->conf->max_hdr_read + DHD_SDALIGN);
9306     }
9307     bus->hdrbufp =
9308         MALLOC(bus->dhd->osh, bus->dhd->conf->max_hdr_read + DHD_SDALIGN);
9309     if (bus->hdrbufp == NULL) {
9310         DHD_ERROR(("%s: MALLOC of %d-byte hdrbufp failed\n", __FUNCTION__,
9311                    bus->dhd->conf->max_hdr_read + DHD_SDALIGN));
9312         ret = -1;
9313         goto exit;
9314     }
9315     bus->rxhdr = (uint8 *)ROUNDUP((uintptr)bus->hdrbufp, DHD_SDALIGN);
9316 
9317 exit:
9318 #endif
9319     return ret;
9320 }
9321 
dhdsdio_download_firmware(struct dhd_bus * bus,osl_t * osh,void * sdh)9322 static int dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh)
9323 {
9324     int ret;
9325 
9326 #if defined(SUPPORT_MULTIPLE_REVISION)
9327     if (concate_revision(bus, bus->fw_path, bus->nv_path) != 0) {
9328         DHD_ERROR(("%s: fail to concatnate revison \n", __FUNCTION__));
9329         return BCME_BADARG;
9330     }
9331 #endif /* SUPPORT_MULTIPLE_REVISION */
9332 
9333 #if defined(DHD_BLOB_EXISTENCE_CHECK)
9334     dhd_set_blob_support(bus->dhd, bus->fw_path);
9335 #endif /* DHD_BLOB_EXISTENCE_CHECK */
9336 
9337     DHD_TRACE_HW4(("%s: firmware path=%s, nvram path=%s\n", __FUNCTION__,
9338                    bus->fw_path, bus->nv_path));
9339     DHD_OS_WAKE_LOCK(bus->dhd);
9340 
9341     dhd_conf_set_path_params(bus->dhd, bus->fw_path, bus->nv_path);
9342     ret = dhd_set_bus_params(bus);
9343     if (ret) {
9344         goto exit;
9345     }
9346 
9347     /* Download the firmware */
9348     dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
9349 
9350     ret = _dhdsdio_download_firmware(bus);
9351 
9352     dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
9353 
9354 exit:
9355     DHD_OS_WAKE_UNLOCK(bus->dhd);
9356     return ret;
9357 }
9358 
9359 /* Detach and free everything */
dhdsdio_release(dhd_bus_t * bus,osl_t * osh)9360 static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh)
9361 {
9362     bool dongle_isolation = FALSE;
9363     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
9364 
9365     if (bus) {
9366         ASSERT(osh);
9367 
9368         if (bus->dhd) {
9369 #if defined(DEBUGGER) || defined(DHD_DSCOPE)
9370             debugger_close();
9371 #endif /* DEBUGGER || DHD_DSCOPE */
9372             dongle_isolation = bus->dhd->dongle_isolation;
9373             dhd_detach(bus->dhd);
9374         }
9375 
9376         /* De-register interrupt handler */
9377         bcmsdh_intr_disable(bus->sdh);
9378         bcmsdh_intr_dereg(bus->sdh);
9379 
9380         if (bus->dhd) {
9381             dhdsdio_release_dongle(bus, osh, dongle_isolation, TRUE);
9382             dhd_free(bus->dhd);
9383             bus->dhd = NULL;
9384         }
9385 
9386         dhdsdio_release_malloc(bus, osh);
9387 
9388 #ifdef DHD_DEBUG
9389         if (bus->console.buf != NULL) {
9390             MFREE(osh, bus->console.buf, bus->console.bufsize);
9391         }
9392 #endif // endif
9393 
9394 #ifdef DHDENABLE_TAILPAD
9395         if (bus->pad_pkt) {
9396             PKTFREE(osh, bus->pad_pkt, FALSE);
9397         }
9398 #endif /* DHDENABLE_TAILPAD */
9399 #ifdef DYNAMIC_MAX_HDR_READ
9400         if (bus->hdrbufp) {
9401             MFREE(osh, bus->hdrbufp, MAX_HDR_READ + DHD_SDALIGN);
9402         }
9403 #endif
9404 
9405         MFREE(osh, bus, sizeof(dhd_bus_t));
9406     }
9407 
9408     DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
9409 }
9410 
dhdsdio_release_malloc(dhd_bus_t * bus,osl_t * osh)9411 static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh)
9412 {
9413     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
9414 
9415     if (bus->dhd && bus->dhd->dongle_reset) {
9416         return;
9417     }
9418 
9419     if (bus->rxbuf) {
9420 #ifndef CONFIG_DHD_USE_STATIC_BUF
9421         MFREE(osh, bus->rxbuf, bus->rxblen);
9422 #endif // endif
9423         bus->rxctl = bus->rxbuf = NULL;
9424         bus->rxlen = 0;
9425     }
9426 
9427     if (bus->databuf) {
9428 #ifndef CONFIG_DHD_USE_STATIC_BUF
9429         MFREE(osh, bus->databuf, MAX_DATA_BUF);
9430 #endif // endif
9431         bus->databuf = NULL;
9432     }
9433 
9434     if (bus->membuf) {
9435         MFREE(osh, bus->membuf, MAX_MEM_BUF);
9436         bus->membuf = NULL;
9437     }
9438 
9439     if (bus->vars && bus->varsz) {
9440         MFREE(osh, bus->vars, bus->varsz);
9441         bus->vars = NULL;
9442     }
9443 }
9444 
dhdsdio_release_dongle(dhd_bus_t * bus,osl_t * osh,bool dongle_isolation,bool reset_flag)9445 static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh,
9446                                    bool dongle_isolation, bool reset_flag)
9447 {
9448     DHD_TRACE(("%s: Enter bus->dhd %p bus->dhd->dongle_reset %d \n",
9449                __FUNCTION__, bus->dhd, bus->dhd->dongle_reset));
9450 
9451     if ((bus->dhd && bus->dhd->dongle_reset) && reset_flag) {
9452         return;
9453     }
9454 
9455     if (bus->sih) {
9456         /* In Win10, system will be BSOD if using "sysprep" to do OS image */
9457         /* Skip this will not cause the BSOD. */
9458 #if !defined(BCMLXSDMMC)
9459         if (bus->dhd) {
9460             dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
9461         }
9462         if (KSO_ENAB(bus) && (dongle_isolation == FALSE)) {
9463             si_watchdog(bus->sih, 0x4);
9464         }
9465 #endif /* !defined(BCMLXSDMMC) */
9466         if (bus->dhd) {
9467             dhdsdio_clkctl(bus, CLK_NONE, FALSE);
9468         }
9469         si_detach(bus->sih);
9470         bus->sih = NULL;
9471         if (bus->vars && bus->varsz) {
9472             MFREE(osh, bus->vars, bus->varsz);
9473         }
9474         bus->vars = NULL;
9475     }
9476 
9477     DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
9478 }
9479 
dhdsdio_disconnect(void * ptr)9480 static void dhdsdio_disconnect(void *ptr)
9481 {
9482     dhd_bus_t *bus = (dhd_bus_t *)ptr;
9483 
9484     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
9485 
9486     DHD_MUTEX_LOCK();
9487     if (bus) {
9488         ASSERT(bus->dhd);
9489         /* Advertise bus remove during rmmod */
9490         dhdsdio_advertise_bus_remove(bus->dhd);
9491         dhdsdio_release(bus, bus->dhd->osh);
9492     }
9493     DHD_MUTEX_UNLOCK();
9494 
9495     DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
9496 }
9497 
dhdsdio_suspend(void * context)9498 static int dhdsdio_suspend(void *context)
9499 {
9500     int ret = 0;
9501 #ifdef SUPPORT_P2P_GO_PS
9502     int wait_time = 0;
9503 #endif /* SUPPORT_P2P_GO_PS */
9504 
9505     dhd_bus_t *bus = (dhd_bus_t *)context;
9506     unsigned long flags;
9507 
9508     DHD_ERROR(("%s Enter\n", __FUNCTION__));
9509     if (bus->dhd == NULL) {
9510         DHD_ERROR(("bus not inited\n"));
9511         return BCME_ERROR;
9512     }
9513     if (bus->dhd->prot == NULL) {
9514         DHD_ERROR(("prot is not inited\n"));
9515         return BCME_ERROR;
9516     }
9517 
9518     if (bus->dhd->up == FALSE) {
9519         return BCME_OK;
9520     }
9521 
9522     DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
9523     if (bus->dhd->busstate != DHD_BUS_DATA &&
9524         bus->dhd->busstate != DHD_BUS_SUSPEND) {
9525         DHD_ERROR(("not in a readystate to LPBK  is not inited\n"));
9526         DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
9527         return BCME_ERROR;
9528     }
9529     DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
9530     if (bus->dhd->dongle_reset) {
9531         DHD_ERROR(("Dongle is in reset state.\n"));
9532         return -EIO;
9533     }
9534 
9535     DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
9536     /* stop all interface network queue. */
9537     dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
9538     bus->dhd->busstate = DHD_BUS_SUSPEND;
9539     if (DHD_BUS_BUSY_CHECK_IN_TX(bus->dhd)) {
9540         DHD_ERROR(("Tx Request is not ended\n"));
9541         bus->dhd->busstate = DHD_BUS_DATA;
9542         /* resume all interface network queue. */
9543         dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
9544         DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
9545         return -EBUSY;
9546     }
9547     DHD_BUS_BUSY_SET_SUSPEND_IN_PROGRESS(bus->dhd);
9548     DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
9549 
9550 #ifdef SUPPORT_P2P_GO_PS
9551     if (bus->idletime > 0) {
9552         wait_time = msecs_to_jiffies(bus->idletime * dhd_watchdog_ms);
9553     }
9554 #endif /* SUPPORT_P2P_GO_PS */
9555     ret = dhd_os_check_wakelock(bus->dhd);
9556 #ifdef SUPPORT_P2P_GO_PS
9557     // terence 20141124: fix for suspend issue
9558     if (SLPAUTO_ENAB(bus) && (!ret) && (bus->dhd->up) &&
9559         (bus->dhd->op_mode != DHD_FLAG_HOSTAP_MODE)) {
9560         if (wait_event_timeout(bus->bus_sleep, bus->sleeping, wait_time) == 0) {
9561             if (!bus->sleeping) {
9562                 ret = 1;
9563             }
9564         }
9565     }
9566 #endif /* SUPPORT_P2P_GO_PS */
9567 
9568     DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
9569     if (ret) {
9570         bus->dhd->busstate = DHD_BUS_DATA;
9571         /* resume all interface network queue. */
9572         dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
9573     }
9574     DHD_BUS_BUSY_CLEAR_SUSPEND_IN_PROGRESS(bus->dhd);
9575     dhd_os_busbusy_wake(bus->dhd);
9576     DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
9577     return ret;
9578 }
9579 
dhdsdio_resume(void * context)9580 static int dhdsdio_resume(void *context)
9581 {
9582     dhd_bus_t *bus = (dhd_bus_t *)context;
9583     ulong flags;
9584 
9585     DHD_ERROR(("%s Enter\n", __FUNCTION__));
9586 
9587     if (bus->dhd->up == FALSE) {
9588         return BCME_OK;
9589     }
9590 
9591     DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
9592     DHD_BUS_BUSY_SET_RESUME_IN_PROGRESS(bus->dhd);
9593     DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
9594 
9595 #if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
9596     if (dhd_os_check_if_up(bus->dhd)) {
9597         bcmsdh_oob_intr_set(bus->sdh, TRUE);
9598     }
9599 #endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
9600 
9601     DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
9602     DHD_BUS_BUSY_CLEAR_RESUME_IN_PROGRESS(bus->dhd);
9603     bus->dhd->busstate = DHD_BUS_DATA;
9604     dhd_os_busbusy_wake(bus->dhd);
9605     /* resume all interface network queue. */
9606     dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
9607     DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
9608 
9609     return 0;
9610 }
9611 
9612 /* Register/Unregister functions are called by the main DHD entry
9613  * point (e.g. module insertion) to link with the bus driver, in
9614  * order to look for or await the device.
9615  */
9616 
9617 static bcmsdh_driver_t dhd_sdio = {dhdsdio_probe, dhdsdio_disconnect,
9618                                    dhdsdio_suspend, dhdsdio_resume};
9619 
dhd_bus_register(void)9620 int dhd_bus_register(void)
9621 {
9622     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
9623 
9624     return bcmsdh_register(&dhd_sdio);
9625 }
9626 
dhd_bus_unregister(void)9627 void dhd_bus_unregister(void)
9628 {
9629     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
9630 
9631     bcmsdh_unregister();
9632 }
9633 
9634 #if defined(BCMLXSDMMC)
9635 /* Register a dummy SDIO client driver in order to be notified of new SDIO
9636  * device */
dhd_bus_reg_sdio_notify(void * semaphore)9637 int dhd_bus_reg_sdio_notify(void *semaphore)
9638 {
9639     return bcmsdh_reg_sdio_notify(semaphore);
9640 }
9641 
dhd_bus_unreg_sdio_notify(void)9642 void dhd_bus_unreg_sdio_notify(void)
9643 {
9644     bcmsdh_unreg_sdio_notify();
9645 }
9646 #endif /* defined(BCMLXSDMMC) */
9647 
dhdsdio_download_code_file(struct dhd_bus * bus,char * pfw_path)9648 static int dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path)
9649 {
9650     int bcmerror = -1;
9651     int offset = 0;
9652     int len;
9653     void *image = NULL;
9654     uint8 *memblock = NULL, *memptr;
9655 #ifdef CHECK_DOWNLOAD_FW
9656     uint8 *memptr_tmp = NULL; // terence: check downloaded firmware is correct
9657 #endif
9658     uint memblock_size = MEMBLOCK;
9659 #ifdef DHD_DEBUG_DOWNLOADTIME
9660     unsigned long initial_jiffies = 0;
9661     uint firmware_sz = 0;
9662 #endif // endif
9663 
9664     DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, pfw_path));
9665 
9666     image = dhd_os_open_image1(bus->dhd, pfw_path);
9667     if (image == NULL) {
9668         printf("%s: Open firmware file failed %s\n", __FUNCTION__, pfw_path);
9669         goto err;
9670     }
9671 
9672     /* Update the dongle image download block size depending on the F1 block
9673      * size */
9674     if (sd_f1_blocksize == 0x200) {
9675         memblock_size = MAX_MEMBLOCK;
9676     }
9677     memptr = memblock = MALLOC(bus->dhd->osh, memblock_size + DHD_SDALIGN);
9678     if (memblock == NULL) {
9679         DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__,
9680                    memblock_size));
9681         goto err;
9682     }
9683 #ifdef CHECK_DOWNLOAD_FW
9684     if (bus->dhd->conf->fwchk) {
9685         memptr_tmp = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN);
9686         if (memptr_tmp == NULL) {
9687             DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__,
9688                        MEMBLOCK));
9689             goto err;
9690         }
9691     }
9692 #endif
9693     if ((uint32)(uintptr)memblock % DHD_SDALIGN) {
9694         memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN));
9695     }
9696 
9697 #ifdef DHD_DEBUG_DOWNLOADTIME
9698     initial_jiffies = jiffies;
9699 #endif // endif
9700 
9701     /* Download image */
9702     while (
9703         (len = dhd_os_get_image_block((char *)memptr, memblock_size, image))) {
9704         // terence 20150412: fix for firmware failed to download
9705         if (bus->dhd->conf->chip == BCM43340_CHIP_ID ||
9706             bus->dhd->conf->chip == BCM43341_CHIP_ID) {
9707             if (len % 0x40 != 0) {
9708                 memset(memptr + len, 0, len % 0x40);
9709                 len += (0x40 - len % 0x40);
9710             }
9711         }
9712         if (len < 0) {
9713             DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__,
9714                        len));
9715             bcmerror = BCME_ERROR;
9716             goto err;
9717         }
9718         /* check if CR4 */
9719         if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
9720             /* if address is 0, store the reset instruction to be written in 0
9721              */
9722 
9723             if (offset == 0) {
9724                 bus->resetinstr = *(((uint32 *)memptr));
9725                 /* Add start of RAM address to the address given by user */
9726                 offset += bus->dongle_ram_base;
9727             }
9728         }
9729 
9730         bcmerror = dhdsdio_membytes(bus, TRUE, offset, memptr, len);
9731         if (bcmerror) {
9732             DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
9733                        __FUNCTION__, bcmerror, memblock_size, offset));
9734             goto err;
9735         }
9736 
9737 #ifdef CHECK_DOWNLOAD_FW
9738         if (bus->dhd->conf->fwchk) {
9739             bcmerror = dhdsdio_membytes(bus, FALSE, offset, memptr_tmp, len);
9740             if (bcmerror) {
9741                 DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
9742                            __FUNCTION__, bcmerror, MEMBLOCK, offset));
9743                 goto err;
9744             }
9745             if (memcmp(memptr_tmp, memptr, len)) {
9746                 DHD_ERROR(("%s: Downloaded image is corrupted at 0x%08x\n",
9747                            __FUNCTION__, offset));
9748                 bcmerror = BCME_ERROR;
9749                 goto err;
9750             } else {
9751                 DHD_INFO(("%s: Download, Upload and compare succeeded.\n",
9752                           __FUNCTION__));
9753             }
9754         }
9755 #endif
9756 
9757         offset += memblock_size;
9758 #ifdef DHD_DEBUG_DOWNLOADTIME
9759         firmware_sz += len;
9760 #endif // endif
9761     }
9762 
9763 #ifdef DHD_DEBUG_DOWNLOADTIME
9764     DHD_ERROR(("Firmware download time for %u bytes: %u ms\n", firmware_sz,
9765                jiffies_to_msecs(jiffies - initial_jiffies)));
9766 #endif // endif
9767 
9768 err:
9769     if (memblock) {
9770         MFREE(bus->dhd->osh, memblock, memblock_size + DHD_SDALIGN);
9771     }
9772 #ifdef CHECK_DOWNLOAD_FW
9773     if (bus->dhd->conf->fwchk) {
9774         if (memptr_tmp) {
9775             MFREE(bus->dhd->osh, memptr_tmp, MEMBLOCK + DHD_SDALIGN);
9776         }
9777     }
9778 #endif
9779 
9780     if (image) {
9781         dhd_os_close_image1(bus->dhd, image);
9782     }
9783 
9784     return bcmerror;
9785 }
9786 
9787 #ifdef DHD_UCODE_DOWNLOAD
9788 /* Currently supported only for the chips in which ucode RAM is AXI addressable
9789  */
dhdsdio_ucode_base(struct dhd_bus * bus)9790 static uint32 dhdsdio_ucode_base(struct dhd_bus *bus)
9791 {
9792     uint32 ucode_base = 0;
9793 
9794     switch ((uint16)bus->sih->chip) {
9795         case BCM43012_CHIP_ID:
9796             ucode_base = 0xE8020000;
9797             break;
9798         default:
9799             DHD_ERROR(("%s: Unsupported!\n", __func__));
9800             break;
9801     }
9802 
9803     return ucode_base;
9804 }
9805 
dhdsdio_download_ucode_file(struct dhd_bus * bus,char * ucode_path)9806 static int dhdsdio_download_ucode_file(struct dhd_bus *bus, char *ucode_path)
9807 {
9808     int bcmerror = -1;
9809     int offset = 0;
9810     int len;
9811     uint32 ucode_base;
9812     void *image = NULL;
9813     uint8 *memblock = NULL, *memptr;
9814     uint memblock_size = MEMBLOCK;
9815 #ifdef DHD_DEBUG_DOWNLOADTIME
9816     unsigned long initial_jiffies = 0;
9817     uint firmware_sz = 0;
9818 #endif // endif
9819 
9820     DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, ucode_path));
9821 
9822     ucode_base = dhdsdio_ucode_base(bus);
9823 
9824     image = dhd_os_open_image1(bus->dhd, ucode_path);
9825     if (image == NULL) {
9826         goto err;
9827     }
9828 
9829     /* Update the dongle image download block size depending on the F1 block
9830      * size */
9831     if (sd_f1_blocksize == 0x200) {
9832         memblock_size = MAX_MEMBLOCK;
9833     }
9834 
9835     memptr = memblock = MALLOC(bus->dhd->osh, memblock_size + DHD_SDALIGN);
9836     if (memblock == NULL) {
9837         DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__,
9838                    memblock_size));
9839         goto err;
9840     }
9841     if ((uint32)(uintptr)memblock % DHD_SDALIGN) {
9842         memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN));
9843     }
9844 
9845 #ifdef DHD_DEBUG_DOWNLOADTIME
9846     initial_jiffies = jiffies;
9847 #endif // endif
9848 
9849     /* Download image */
9850     while (
9851         (len = dhd_os_get_image_block((char *)memptr, memblock_size, image))) {
9852         if (len < 0) {
9853             DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__,
9854                        len));
9855             bcmerror = BCME_ERROR;
9856             goto err;
9857         }
9858 
9859         bcmerror =
9860             dhdsdio_membytes(bus, TRUE, (ucode_base + offset), memptr, len);
9861         if (bcmerror) {
9862             DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
9863                        __FUNCTION__, bcmerror, memblock_size, offset));
9864             goto err;
9865         }
9866 
9867         offset += memblock_size;
9868 #ifdef DHD_DEBUG_DOWNLOADTIME
9869         firmware_sz += len;
9870 #endif // endif
9871     }
9872 
9873 #ifdef DHD_DEBUG_DOWNLOADTIME
9874     DHD_ERROR(("ucode download time for %u bytes: %u ms\n", firmware_sz,
9875                jiffies_to_msecs(jiffies - initial_jiffies)));
9876 #endif // endif
9877 
9878 err:
9879     if (memblock) {
9880         MFREE(bus->dhd->osh, memblock, memblock_size + DHD_SDALIGN);
9881     }
9882 
9883     if (image) {
9884         dhd_os_close_image1(bus->dhd, image);
9885     }
9886 
9887     return bcmerror;
9888 } /* dhdsdio_download_ucode_file */
9889 
dhd_bus_ucode_download(struct dhd_bus * bus)9890 void dhd_bus_ucode_download(struct dhd_bus *bus)
9891 {
9892     uint32 shaddr = 0, shdata = 0;
9893 
9894     shaddr = bus->dongle_ram_base + bus->ramsize - 0x4;
9895     dhdsdio_membytes(bus, FALSE, shaddr, (uint8 *)&shdata, 0x4);
9896 
9897     DHD_TRACE(("%s: shdata:[0x%08x :0x%08x]\n", __func__, shaddr, shdata));
9898 
9899     if (shdata == UCODE_DOWNLOAD_REQUEST) {
9900         DHD_ERROR(("%s: Received ucode download request!\n", __func__));
9901 
9902         /* Download the ucode */
9903         if (!dhd_get_ucode_path(bus->dhd)) {
9904             DHD_ERROR(("%s: bus->uc_path not set!\n", __func__));
9905             return;
9906         }
9907         dhdsdio_download_ucode_file(bus, dhd_get_ucode_path(bus->dhd));
9908 
9909         DHD_ERROR(("%s: Ucode downloaded successfully!\n", __func__));
9910 
9911         shdata = UCODE_DOWNLOAD_COMPLETE;
9912         dhdsdio_membytes(bus, TRUE, shaddr, (uint8 *)&shdata, 0x4);
9913     }
9914 }
9915 
9916 #endif /* DHD_UCODE_DOWNLOAD */
9917 
dhdsdio_download_nvram(struct dhd_bus * bus)9918 static int dhdsdio_download_nvram(struct dhd_bus *bus)
9919 {
9920     int bcmerror = -1;
9921     uint len;
9922     void *image = NULL;
9923     char *memblock = NULL;
9924     char *bufp;
9925     char *pnv_path;
9926     bool nvram_file_exists;
9927 
9928     pnv_path = bus->nv_path;
9929 
9930     nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0'));
9931 
9932     /* For Get nvram from UEFI */
9933     if (nvram_file_exists) {
9934         image = dhd_os_open_image1(bus->dhd, pnv_path);
9935         if (image == NULL) {
9936             printf("%s: Open nvram file failed %s\n", __FUNCTION__, pnv_path);
9937             goto err;
9938         }
9939     }
9940 
9941     memblock = MALLOC(bus->dhd->osh, MAX_NVRAMBUF_SIZE);
9942     if (memblock == NULL) {
9943         DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__,
9944                    MAX_NVRAMBUF_SIZE));
9945         goto err;
9946     }
9947 
9948     /* For Get nvram from image or UEFI (when image == NULL ) */
9949     len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image);
9950     if (len > 0 && len < MAX_NVRAMBUF_SIZE) {
9951         bufp = (char *)memblock;
9952         bufp[len] = 0;
9953         len = process_nvram_vars(bufp, len);
9954         if (len % 0x4) {
9955             len += 0x4 - (len % 0x4);
9956         }
9957         bufp += len;
9958         *bufp++ = 0;
9959         if (len) {
9960             bcmerror = dhdsdio_downloadvars(bus, memblock, len + 1);
9961         }
9962         if (bcmerror) {
9963             DHD_ERROR(
9964                 ("%s: error downloading vars: %d\n", __FUNCTION__, bcmerror));
9965         }
9966     } else {
9967         DHD_ERROR(("%s: error reading nvram file: %d\n", __FUNCTION__, len));
9968         bcmerror = BCME_SDIO_ERROR;
9969     }
9970 
9971 err:
9972     if (memblock) {
9973         MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE);
9974     }
9975 
9976     if (image) {
9977         dhd_os_close_image1(bus->dhd, image);
9978     }
9979 
9980     return bcmerror;
9981 }
9982 
_dhdsdio_download_firmware(struct dhd_bus * bus)9983 static int _dhdsdio_download_firmware(struct dhd_bus *bus)
9984 {
9985     int bcmerror = -1;
9986 
9987     bool embed = FALSE; /* download embedded firmware */
9988     bool dlok = FALSE;  /* download firmware succeeded */
9989 
9990     /* Out immediately if no image to download */
9991     if ((bus->fw_path == NULL) || (bus->fw_path[0] == '\0')) {
9992         return bcmerror;
9993     }
9994 
9995     /* Keep arm in reset */
9996     if (dhdsdio_download_state(bus, TRUE)) {
9997         DHD_ERROR(("%s: error placing ARM core in reset\n", __FUNCTION__));
9998         goto err;
9999     }
10000 
10001     /* External image takes precedence if specified */
10002     if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) {
10003         if (dhdsdio_download_code_file(bus, bus->fw_path)) {
10004             DHD_ERROR(
10005                 ("%s: dongle image file download failed\n", __FUNCTION__));
10006             goto err;
10007         } else {
10008             embed = FALSE;
10009             dlok = TRUE;
10010         }
10011     }
10012 
10013     BCM_REFERENCE(embed);
10014     if (!dlok) {
10015         DHD_ERROR(("%s: dongle image download failed\n", __FUNCTION__));
10016         goto err;
10017     }
10018 
10019     /* External nvram takes precedence if specified */
10020     if (dhdsdio_download_nvram(bus)) {
10021         DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__));
10022         goto err;
10023     }
10024 
10025     /* Take arm out of reset */
10026     if (dhdsdio_download_state(bus, FALSE)) {
10027         DHD_ERROR(("%s: error getting out of ARM core reset\n", __FUNCTION__));
10028         goto err;
10029     }
10030 
10031     bcmerror = 0;
10032 
10033 err:
10034     return bcmerror;
10035 }
10036 
dhd_bcmsdh_recv_buf(dhd_bus_t * bus,uint32 addr,uint fn,uint flags,uint8 * buf,uint nbytes,void * pkt,bcmsdh_cmplt_fn_t complete_fn,void * handle)10037 static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
10038                                uint8 *buf, uint nbytes, void *pkt,
10039                                bcmsdh_cmplt_fn_t complete_fn, void *handle)
10040 {
10041     int status;
10042 
10043     if (!KSO_ENAB(bus)) {
10044         DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
10045         return BCME_NODEVICE;
10046     }
10047 
10048     status = bcmsdh_recv_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt,
10049                              complete_fn, handle);
10050 
10051     return status;
10052 }
10053 
dhd_bcmsdh_send_buf(dhd_bus_t * bus,uint32 addr,uint fn,uint flags,uint8 * buf,uint nbytes,void * pkt,bcmsdh_cmplt_fn_t complete_fn,void * handle,int max_retry)10054 static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
10055                                uint8 *buf, uint nbytes, void *pkt,
10056                                bcmsdh_cmplt_fn_t complete_fn, void *handle,
10057                                int max_retry)
10058 {
10059     int ret;
10060     int i = 0;
10061     int retries = 0;
10062     bcmsdh_info_t *sdh;
10063 
10064     if (!KSO_ENAB(bus)) {
10065         DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
10066         return BCME_NODEVICE;
10067     }
10068 
10069     sdh = bus->sdh;
10070     do {
10071         ret = bcmsdh_send_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt,
10072                               complete_fn, handle);
10073 
10074         bus->f2txdata++;
10075         ASSERT(ret != BCME_PENDING);
10076 
10077         if (ret == BCME_NODEVICE) {
10078             DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__));
10079         } else if (ret < 0) {
10080             /* On failure, abort the command and terminate the frame */
10081             DHD_ERROR(
10082                 ("%s: sdio error %d, abort command and terminate frame.\n",
10083                  __FUNCTION__, ret));
10084             bus->tx_sderrs++;
10085             bus->f1regdata++;
10086             bus->dhd->tx_errors++;
10087             bcmsdh_abort(sdh, SDIO_FUNC_2);
10088             bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
10089                              SFC_WF_TERM, NULL);
10090             for (i = 0; i < READ_FRM_CNT_RETRIES; i++) {
10091                 uint8 hi, lo;
10092                 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WFRAMEBCHI,
10093                                      NULL);
10094                 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WFRAMEBCLO,
10095                                      NULL);
10096                 bus->f1regdata += 0x2;
10097                 if ((hi == 0) && (lo == 0)) {
10098                     break;
10099                 }
10100             }
10101         }
10102     } while ((ret < 0) && retrydata && ++retries < max_retry);
10103 
10104     return ret;
10105 }
10106 
dhd_bus_is_ioready(struct dhd_bus * bus)10107 uint8 dhd_bus_is_ioready(struct dhd_bus *bus)
10108 {
10109     uint8 enable;
10110     bcmsdh_info_t *sdh;
10111     ASSERT(bus);
10112     ASSERT(bus->sih != NULL);
10113     enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
10114     sdh = bus->sdh;
10115     return (enable ==
10116             bcmsdh_cfg_read(sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL));
10117 }
10118 
dhd_bus_chip(struct dhd_bus * bus)10119 uint dhd_bus_chip(struct dhd_bus *bus)
10120 {
10121     ASSERT(bus->sih != NULL);
10122     return bus->sih->chip;
10123 }
10124 
dhd_bus_chiprev(struct dhd_bus * bus)10125 uint dhd_bus_chiprev(struct dhd_bus *bus)
10126 {
10127     ASSERT(bus);
10128     ASSERT(bus->sih != NULL);
10129     return bus->sih->chiprev;
10130 }
10131 
dhd_bus_pub(struct dhd_bus * bus)10132 void *dhd_bus_pub(struct dhd_bus *bus)
10133 {
10134     return bus->dhd;
10135 }
10136 
dhd_bus_sih(struct dhd_bus * bus)10137 void *dhd_bus_sih(struct dhd_bus *bus)
10138 {
10139     return (void *)bus->sih;
10140 }
10141 
dhd_bus_txq(struct dhd_bus * bus)10142 void *dhd_bus_txq(struct dhd_bus *bus)
10143 {
10144     return &bus->txq;
10145 }
10146 
dhd_bus_hdrlen(struct dhd_bus * bus)10147 uint dhd_bus_hdrlen(struct dhd_bus *bus)
10148 {
10149     return (bus->txglom_enable) ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN;
10150 }
10151 
dhd_bus_set_dotxinrx(struct dhd_bus * bus,bool val)10152 void dhd_bus_set_dotxinrx(struct dhd_bus *bus, bool val)
10153 {
10154     bus->dotxinrx = val;
10155 }
10156 
10157 /*
10158  *  dhdsdio_advertise_bus_cleanup advertises that clean up is under progress
10159  * to other bus user contexts like Tx, Rx, IOVAR, WD etc and it waits for other
10160  * contexts to gracefully exit. All the bus usage contexts before marking
10161  * busstate as busy, will check for whether the busstate is DHD_BUS_DOWN or
10162  * DHD_BUS_DOWN_IN_PROGRESS, if so they will exit from there itself without
10163  * marking dhd_bus_busy_state as BUSY.
10164  */
dhdsdio_advertise_bus_cleanup(dhd_pub_t * dhdp)10165 static void dhdsdio_advertise_bus_cleanup(dhd_pub_t *dhdp)
10166 {
10167     unsigned long flags;
10168     int timeleft;
10169 
10170     DHD_LINUX_GENERAL_LOCK(dhdp, flags);
10171     dhdp->busstate = DHD_BUS_DOWN_IN_PROGRESS;
10172     DHD_LINUX_GENERAL_UNLOCK(dhdp, flags);
10173 
10174     timeleft = dhd_os_busbusy_wait_negation(dhdp, &dhdp->dhd_bus_busy_state);
10175     if ((timeleft == 0) || (timeleft == 1)) {
10176         DHD_ERROR(("%s : Timeout due to dhd_bus_busy_state=0x%x\n",
10177                    __FUNCTION__, dhdp->dhd_bus_busy_state));
10178         ASSERT(0);
10179     }
10180 
10181     return;
10182 }
10183 
dhdsdio_advertise_bus_remove(dhd_pub_t * dhdp)10184 static void dhdsdio_advertise_bus_remove(dhd_pub_t *dhdp)
10185 {
10186     unsigned long flags;
10187     int timeleft;
10188 
10189     DHD_LINUX_GENERAL_LOCK(dhdp, flags);
10190     dhdp->busstate = DHD_BUS_REMOVE;
10191     DHD_LINUX_GENERAL_UNLOCK(dhdp, flags);
10192 
10193     timeleft = dhd_os_busbusy_wait_negation(dhdp, &dhdp->dhd_bus_busy_state);
10194     if ((timeleft == 0) || (timeleft == 1)) {
10195         DHD_ERROR(("%s : Timeout due to dhd_bus_busy_state=0x%x\n",
10196                    __FUNCTION__, dhdp->dhd_bus_busy_state));
10197         ASSERT(0);
10198     }
10199 
10200     return;
10201 }
10202 
dhd_bus_devreset(dhd_pub_t * dhdp,uint8 flag)10203 int dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
10204 {
10205     int bcmerror = 0;
10206     dhd_bus_t *bus;
10207     unsigned long flags;
10208 
10209     bus = dhdp->bus;
10210 
10211     if (flag == TRUE) {
10212         if (!bus->dhd->dongle_reset) {
10213             DHD_ERROR(("%s: == Power OFF ==\n", __FUNCTION__));
10214             dhdsdio_advertise_bus_cleanup(bus->dhd);
10215             dhd_os_sdlock(dhdp);
10216             dhd_os_wd_timer(dhdp, 0);
10217 #if !defined(IGNORE_ETH0_DOWN)
10218             /* Force flow control as protection when stop come before
10219              * ifconfig_down */
10220             dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
10221 #endif /* !defined(IGNORE_ETH0_DOWN) */
10222             /* Expect app to have torn down any connection before calling */
10223             /* Stop the bus, disable F2 */
10224             dhd_bus_stop(bus, FALSE);
10225 #if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
10226             /* Clean up any pending IRQ */
10227             dhd_enable_oob_intr(bus, FALSE);
10228             bcmsdh_oob_intr_set(bus->sdh, FALSE);
10229             bcmsdh_oob_intr_unregister(bus->sdh);
10230 #endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
10231 
10232             /* Clean tx/rx buffer pointers, detach from the dongle */
10233             dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE, TRUE);
10234 
10235             bus->dhd->dongle_reset = TRUE;
10236             DHD_ERROR(("%s: making dhdpub up FALSE\n", __FUNCTION__));
10237             bus->dhd->up = FALSE;
10238             dhd_txglom_enable(dhdp, FALSE);
10239             dhd_os_sdunlock(dhdp);
10240 
10241             DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
10242             DHD_ERROR(("%s: making DHD_BUS_DOWN\n", __FUNCTION__));
10243             bus->dhd->busstate = DHD_BUS_DOWN;
10244             DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
10245 
10246             printf("%s:  WLAN OFF DONE\n", __FUNCTION__);
10247             /* App can now remove power from device */
10248         } else {
10249             bcmerror = BCME_SDIO_ERROR;
10250         }
10251     } else {
10252         /* App must have restored power to device before calling */
10253 
10254         printf("%s: == Power ON ==\n", __FUNCTION__);
10255 
10256         if (bus->dhd->dongle_reset) {
10257             /* Turn on WLAN */
10258             dhd_os_sdlock(dhdp);
10259             /* Reset SD client -- required if devreset is called
10260              * via 'dhd devreset' iovar
10261              */
10262             bcmsdh_reset(bus->sdh);
10263             /* Attempt to re-attach & download */
10264             if (dhdsdio_probe_attach(
10265                     bus, bus->dhd->osh, bus->sdh,
10266                     (uint32 *)(uintptr)si_enum_base(bus->cl_devid),
10267                     bus->cl_devid)) {
10268                 DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
10269                 DHD_ERROR(("%s: making DHD_BUS_DOWN\n", __FUNCTION__));
10270                 bus->dhd->busstate = DHD_BUS_DOWN;
10271                 DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
10272 
10273                 /* Attempt to download binary to the dongle */
10274                 if (dhdsdio_probe_init(bus, bus->dhd->osh, bus->sdh) &&
10275                     dhdsdio_download_firmware(bus, bus->dhd->osh, bus->sdh) >= 0) {
10276                     /* Re-init bus, enable F2 transfer */
10277                     bcmerror = dhd_bus_init((dhd_pub_t *)bus->dhd, FALSE);
10278                     if (bcmerror == BCME_OK) {
10279 #if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
10280                         dhd_enable_oob_intr(bus, TRUE);
10281                         bcmsdh_oob_intr_register(bus->sdh, dhdsdio_isr, bus);
10282                         bcmsdh_oob_intr_set(bus->sdh, TRUE);
10283 #elif defined(FORCE_WOWLAN)
10284                         dhd_enable_oob_intr(bus, TRUE);
10285 #endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
10286 
10287                         bus->dhd->dongle_reset = FALSE;
10288                         bus->dhd->up = TRUE;
10289 
10290 #if !defined(IGNORE_ETH0_DOWN)
10291                         /* Restore flow control  */
10292                         dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
10293 #endif // endif
10294                         dhd_os_wd_timer(dhdp, dhd_watchdog_ms);
10295 
10296                         DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__));
10297                     } else {
10298                         dhd_bus_stop(bus, FALSE);
10299                         dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE, FALSE);
10300                     }
10301                 } else {
10302                     DHD_ERROR(("%s Failed to download binary to the dongle\n",
10303                                __FUNCTION__));
10304                     if (bus->sih != NULL) {
10305                         si_detach(bus->sih);
10306                         bus->sih = NULL;
10307                     }
10308                     bcmerror = BCME_SDIO_ERROR;
10309                 }
10310             } else {
10311                 bcmerror = BCME_SDIO_ERROR;
10312             }
10313 
10314             dhd_os_sdunlock(dhdp);
10315         } else {
10316             printf("%s called when dongle is not in reset\n", __FUNCTION__);
10317             printf("Will call dhd_bus_start instead\n");
10318             dhd_bus_resume(dhdp, 1);
10319 #if defined(HW_OOB) || defined(FORCE_WOWLAN)
10320             dhd_conf_set_hw_oob_intr(
10321                 bus->sdh,
10322                 bus->sih); // terence 20120615: fix for OOB initial issue
10323 #endif
10324             if ((bcmerror = dhd_bus_start(dhdp)) != 0) {
10325                 DHD_ERROR(("%s: dhd_bus_start fail with %d\n", __FUNCTION__,
10326                            bcmerror));
10327             }
10328         }
10329     }
10330 
10331 #ifdef PKT_STATICS
10332     dhd_bus_clear_txpktstatics(dhdp);
10333 #endif
10334     return bcmerror;
10335 }
10336 
dhd_bus_suspend(dhd_pub_t * dhdpub)10337 int dhd_bus_suspend(dhd_pub_t *dhdpub)
10338 {
10339     return bcmsdh_stop(dhdpub->bus->sdh);
10340 }
10341 
dhd_bus_resume(dhd_pub_t * dhdpub,int stage)10342 int dhd_bus_resume(dhd_pub_t *dhdpub, int stage)
10343 {
10344     return bcmsdh_start(dhdpub->bus->sdh, stage);
10345 }
10346 
10347 /* Get Chip ID version */
dhd_bus_chip_id(dhd_pub_t * dhdp)10348 uint dhd_bus_chip_id(dhd_pub_t *dhdp)
10349 {
10350     dhd_bus_t *bus = dhdp->bus;
10351 
10352     if (bus && bus->sih) {
10353         return bus->sih->chip;
10354     } else {
10355         return 0;
10356     }
10357 }
10358 
10359 /* Get Chip Rev ID version */
dhd_bus_chiprev_id(dhd_pub_t * dhdp)10360 uint dhd_bus_chiprev_id(dhd_pub_t *dhdp)
10361 {
10362     dhd_bus_t *bus = dhdp->bus;
10363 
10364     if (bus && bus->sih) {
10365         return bus->sih->chiprev;
10366     } else {
10367         return 0;
10368     }
10369 }
10370 
10371 /* Get Chip Pkg ID version */
dhd_bus_chippkg_id(dhd_pub_t * dhdp)10372 uint dhd_bus_chippkg_id(dhd_pub_t *dhdp)
10373 {
10374     dhd_bus_t *bus = dhdp->bus;
10375 
10376     return bus->sih->chippkg;
10377 }
10378 
dhd_bus_get_ids(struct dhd_bus * bus,uint32 * bus_type,uint32 * bus_num,uint32 * slot_num)10379 int dhd_bus_get_ids(struct dhd_bus *bus, uint32 *bus_type, uint32 *bus_num,
10380                     uint32 *slot_num)
10381 {
10382     *bus_type = bus->bus;
10383     *bus_num = bus->bus_num;
10384     *slot_num = bus->slot_num;
10385     return 0;
10386 }
10387 
dhd_bus_membytes(dhd_pub_t * dhdp,bool set,uint32 address,uint8 * data,uint size)10388 int dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data,
10389                      uint size)
10390 {
10391     dhd_bus_t *bus;
10392 
10393     bus = dhdp->bus;
10394     return dhdsdio_membytes(bus, set, address, data, size);
10395 }
10396 
10397 #if defined(SUPPORT_MULTIPLE_REVISION)
concate_revision_bcm4335(dhd_bus_t * bus,char * fw_path,char * nv_path)10398 static int concate_revision_bcm4335(dhd_bus_t *bus, char *fw_path,
10399                                     char *nv_path)
10400 {
10401     uint chipver;
10402 #if defined(SUPPORT_MULTIPLE_CHIPS)
10403     char chipver_tag[0xA] = "_4335";
10404 #else
10405     char chipver_tag[0x4] = {
10406         0,
10407     };
10408 #endif /* defined(SUPPORT_MULTIPLE_CHIPS) */
10409     DHD_TRACE(("%s: BCM4335 Multiple Revision Check\n", __FUNCTION__));
10410     if (bus->sih->chip != BCM4335_CHIP_ID) {
10411         DHD_ERROR(("%s:Chip is not BCM4335\n", __FUNCTION__));
10412         return -1;
10413     }
10414     chipver = bus->sih->chiprev;
10415     DHD_ERROR(("CHIP VER = [0x%x]\n", chipver));
10416     if (chipver == 0x0) {
10417         DHD_ERROR(("----- CHIP bcm4335_A0 -----\n"));
10418         strcat(chipver_tag, "_a0");
10419     } else if (chipver == 0x1) {
10420         DHD_ERROR(("----- CHIP bcm4335_B0 -----\n"));
10421 #if defined(SUPPORT_MULTIPLE_CHIPS)
10422         strcat(chipver_tag, "_b0");
10423 #endif /* defined(SUPPORT_MULTIPLE_CHIPS) */
10424     }
10425 
10426     strcat(fw_path, chipver_tag);
10427     strcat(nv_path, chipver_tag);
10428     return 0;
10429 }
10430 
concate_revision_bcm4339(dhd_bus_t * bus,char * fw_path,char * nv_path)10431 static int concate_revision_bcm4339(dhd_bus_t *bus, char *fw_path,
10432                                     char *nv_path)
10433 {
10434     uint chipver;
10435 #if defined(SUPPORT_MULTIPLE_CHIPS)
10436     char chipver_tag[0xA] = "_4339";
10437 #else
10438     char chipver_tag[0x4] = {
10439         0,
10440     };
10441 #endif /* defined(SUPPORT_MULTIPLE_CHIPS) */
10442 
10443     DHD_TRACE(("%s: BCM4339 Multiple Revision Check\n", __FUNCTION__));
10444     if (bus->sih->chip != BCM4339_CHIP_ID) {
10445         DHD_ERROR(("%s:Chip is not BCM4339\n", __FUNCTION__));
10446         return -1;
10447     }
10448     chipver = bus->sih->chiprev;
10449     DHD_ERROR(("CHIP VER = [0x%x]\n", chipver));
10450     if (chipver == 0x1) {
10451         DHD_ERROR(("----- CHIP bcm4339_A0 -----\n"));
10452         strcat(chipver_tag, "_a0");
10453     } else {
10454         DHD_ERROR(("----- CHIP bcm4339 unknown revision %d -----\n", chipver));
10455     }
10456 
10457     strcat(fw_path, chipver_tag);
10458     strcat(nv_path, chipver_tag);
10459     return 0;
10460 }
10461 
concate_revision_bcm4350(dhd_bus_t * bus,char * fw_path,char * nv_path)10462 static int concate_revision_bcm4350(dhd_bus_t *bus, char *fw_path,
10463                                     char *nv_path)
10464 {
10465     uint32 chip_ver;
10466 #if defined(SUPPORT_MULTIPLE_CHIPS)
10467     char chipver_tag[0xA] = {
10468         0,
10469     };
10470 #else
10471     char chipver_tag[0x4] = {
10472         0,
10473     };
10474 #endif /* defined(SUPPORT_MULTIPLE_CHIPS) */
10475     chip_ver = bus->sih->chiprev;
10476 
10477 #if defined(SUPPORT_MULTIPLE_CHIPS)
10478     if (chip_ver == 0x3) {
10479         strcat(chipver_tag, "_4354");
10480     } else {
10481         strcat(chipver_tag, "_4350");
10482     }
10483 #endif // endif
10484 
10485     if (chip_ver == 0x3) {
10486         DHD_ERROR(("----- CHIP 4354 A0 -----\n"));
10487         strcat(chipver_tag, "_a0");
10488     } else {
10489         DHD_ERROR(("----- Unknown chip version, ver=%x -----\n", chip_ver));
10490     }
10491 
10492     strcat(fw_path, chipver_tag);
10493     strcat(nv_path, chipver_tag);
10494     return 0;
10495 }
10496 
concate_revision_bcm4354(dhd_bus_t * bus,char * fw_path,char * nv_path)10497 static int concate_revision_bcm4354(dhd_bus_t *bus, char *fw_path,
10498                                     char *nv_path)
10499 {
10500     uint32 chip_ver;
10501 #if defined(SUPPORT_MULTIPLE_CHIPS)
10502     char chipver_tag[0xA] = "_4354";
10503 #else
10504     char chipver_tag[0x4] = {
10505         0,
10506     };
10507 #endif /* SUPPORT_MULTIPLE_CHIPS */
10508 
10509     chip_ver = bus->sih->chiprev;
10510     if (chip_ver == 1) {
10511         DHD_ERROR(("----- CHIP 4354 A1 -----\n"));
10512         strcat(chipver_tag, "_a1");
10513     } else {
10514         DHD_ERROR(("----- Unknown chip version, ver=%x -----\n", chip_ver));
10515     }
10516 
10517     strcat(fw_path, chipver_tag);
10518     strcat(nv_path, chipver_tag);
10519 
10520     return 0;
10521 }
10522 
concate_revision_bcm43454(dhd_bus_t * bus,char * fw_path,char * nv_path)10523 static int concate_revision_bcm43454(dhd_bus_t *bus, char *fw_path,
10524                                      char *nv_path)
10525 {
10526     char chipver_tag[0xA] = {
10527         0,
10528     };
10529 #ifdef SUPPORT_MULTIPLE_BOARD_REV_FROM_DT
10530     int base_system_rev_for_nv = 0;
10531 #endif /* SUPPORT_MULTIPLE_BOARD_REV_FROM_DT */
10532 
10533     DHD_TRACE(("%s: BCM43454 Multiple Revision Check\n", __FUNCTION__));
10534     if (bus->sih->chip != BCM43454_CHIP_ID) {
10535         DHD_ERROR(("%s:Chip is not BCM43454!\n", __FUNCTION__));
10536         return -1;
10537     }
10538 #ifdef SUPPORT_MULTIPLE_BOARD_REV_FROM_DT
10539     base_system_rev_for_nv = dhd_get_system_rev();
10540     if (base_system_rev_for_nv > 0) {
10541         DHD_ERROR(("----- Board Rev  [%d] -----\n", base_system_rev_for_nv));
10542         sprintf(chipver_tag, "_r%02d", base_system_rev_for_nv);
10543     }
10544 #endif /* SUPPORT_MULTIPLE_BOARD_REV_FROM_DT */
10545 #ifdef SUPPORT_MULTIPLE_BOARD_REV_FROM_HW
10546     DHD_ERROR(("----- Rev [%d] Fot MULTIPLE Board. -----\n", system_hw_rev));
10547     if ((system_hw_rev >= 0x8) && (system_hw_rev <= 0xB)) {
10548         DHD_ERROR(("This HW is Rev 08 ~ 11. this is For FD-HW\n"));
10549         strcat(chipver_tag, "_FD");
10550     }
10551 #endif /* SUPPORT_MULTIPLE_BOARD_REV_FROM_HW */
10552 
10553     strcat(nv_path, chipver_tag);
10554     return 0;
10555 }
10556 
concate_revision(dhd_bus_t * bus,char * fw_path,char * nv_path)10557 int concate_revision(dhd_bus_t *bus, char *fw_path, char *nv_path)
10558 {
10559     int res = 0;
10560 
10561     if (!bus || !bus->sih) {
10562         DHD_ERROR(("%s:Bus is Invalid\n", __FUNCTION__));
10563         return -1;
10564     }
10565 
10566     switch (bus->sih->chip) {
10567         case BCM4335_CHIP_ID:
10568             res = concate_revision_bcm4335(bus, fw_path, nv_path);
10569 
10570             break;
10571         case BCM4339_CHIP_ID:
10572             res = concate_revision_bcm4339(bus, fw_path, nv_path);
10573             break;
10574         case BCM4350_CHIP_ID:
10575             res = concate_revision_bcm4350(bus, fw_path, nv_path);
10576             break;
10577         case BCM4354_CHIP_ID:
10578             res = concate_revision_bcm4354(bus, fw_path, nv_path);
10579             break;
10580         case BCM43454_CHIP_ID:
10581             res = concate_revision_bcm43454(bus, fw_path, nv_path);
10582             break;
10583 
10584         default:
10585             DHD_ERROR(("REVISION SPECIFIC feature is not required\n"));
10586             return res;
10587     }
10588 
10589     if (res == 0) {
10590     }
10591     return res;
10592 }
10593 #endif /* SUPPORT_MULTIPLE_REVISION */
10594 
dhd_bus_update_fw_nv_path(struct dhd_bus * bus,char * pfw_path,char * pnv_path,char * pclm_path,char * pconf_path)10595 void dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path,
10596                                char *pnv_path, char *pclm_path,
10597                                char *pconf_path)
10598 {
10599     bus->fw_path = pfw_path;
10600     bus->nv_path = pnv_path;
10601     bus->dhd->clm_path = pclm_path;
10602     bus->dhd->conf_path = pconf_path;
10603 }
10604 
dhd_enableOOB(dhd_pub_t * dhd,bool sleep)10605 int dhd_enableOOB(dhd_pub_t *dhd, bool sleep)
10606 {
10607     dhd_bus_t *bus = dhd->bus;
10608     sdpcmd_regs_t *regs = bus->regs;
10609     uint retries = 0;
10610 
10611     if (sleep) {
10612         dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
10613         /* Tell device to start using OOB wakeup */
10614         W_SDREG(SMB_USE_OOB, &regs->tosbmailbox, retries);
10615         if (retries > retry_limit) {
10616             DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
10617             return BCME_BUSY;
10618         }
10619         /* Turn off our contribution to the HT clock request */
10620         dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
10621     } else {
10622         /* Make sure the controller has the bus up */
10623         dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
10624 
10625         /* Send misc interrupt to indicate OOB not needed */
10626         W_SDREG(0, &regs->tosbmailboxdata, retries);
10627         if (retries <= retry_limit) {
10628             W_SDREG(SMB_DEV_INT, &regs->tosbmailbox, retries);
10629         }
10630 
10631         if (retries > retry_limit) {
10632             DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
10633         }
10634 
10635         /* Make sure we have SD bus access */
10636         dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
10637     }
10638     return BCME_OK;
10639 }
10640 
dhd_bus_pktq_flush(dhd_pub_t * dhdp)10641 void dhd_bus_pktq_flush(dhd_pub_t *dhdp)
10642 {
10643     dhd_bus_t *bus = dhdp->bus;
10644     bool wlfc_enabled = FALSE;
10645 
10646 #ifdef PROP_TXSTATUS
10647     wlfc_enabled = (dhd_wlfc_cleanup_txq(dhdp, NULL, 0) != WLFC_UNSUPPORTED);
10648 #endif // endif
10649     if (!wlfc_enabled) {
10650 #ifdef DHDTCPACK_SUPPRESS
10651         /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt,
10652          * when there is a newly coming packet from network stack.
10653          */
10654         dhd_tcpack_info_tbl_clean(bus->dhd);
10655 #endif /* DHDTCPACK_SUPPRESS */
10656         /* Clear the data packet queues */
10657         pktq_flush(dhdp->osh, &bus->txq, TRUE);
10658     }
10659 }
10660 
10661 #ifdef BCMSDIO
dhd_sr_config(dhd_pub_t * dhd,bool on)10662 int dhd_sr_config(dhd_pub_t *dhd, bool on)
10663 {
10664     dhd_bus_t *bus = dhd->bus;
10665 
10666     if (!bus->_srenab) {
10667         return -1;
10668     }
10669 
10670     return dhdsdio_clk_devsleep_iovar(bus, on);
10671 }
10672 
dhd_get_chipid(dhd_pub_t * dhd)10673 uint16 dhd_get_chipid(dhd_pub_t *dhd)
10674 {
10675     dhd_bus_t *bus = dhd->bus;
10676 
10677     if (bus && bus->sih) {
10678         return (uint16)bus->sih->chip;
10679     } else {
10680         return 0;
10681     }
10682 }
10683 #endif /* BCMSDIO */
10684 
10685 #ifdef DEBUGGER
dhd_sdio_reg_read(struct dhd_bus * bus,ulong addr)10686 static uint32 dhd_sdio_reg_read(struct dhd_bus *bus, ulong addr)
10687 {
10688     uint32 rval;
10689 
10690     dhd_os_sdlock(bus->dhd);
10691 
10692     BUS_WAKE(bus);
10693 
10694     dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
10695 
10696     rval = bcmsdh_reg_read(bus->sdh, addr, 0x4);
10697 
10698     dhd_os_sdunlock(bus->dhd);
10699 
10700     return rval;
10701 }
10702 
dhd_sdio_reg_write(struct dhd_bus * bus,ulong addr,uint32 val)10703 static void dhd_sdio_reg_write(struct dhd_bus *bus, ulong addr, uint32 val)
10704 {
10705     dhd_os_sdlock(bus->dhd);
10706 
10707     BUS_WAKE(bus);
10708 
10709     dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
10710 
10711     bcmsdh_reg_write(bus->sdh, addr, 0x4, val);
10712 
10713     dhd_os_sdunlock(bus->dhd);
10714 }
10715 
10716 #endif /* DEBUGGER */
10717 
10718 #if defined(BT_OVER_SDIO)
dhd_bus_cfg_read(void * h,uint fun_num,uint32 addr,int * err)10719 uint8 dhd_bus_cfg_read(void *h, uint fun_num, uint32 addr, int *err)
10720 {
10721     uint8 intrd;
10722     dhd_pub_t *dhdp = (dhd_pub_t *)h;
10723     dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus;
10724 
10725     dhd_os_sdlock(bus->dhd);
10726 
10727     intrd = bcmsdh_cfg_read(bus->sdh, fun_num, addr, err);
10728 
10729     dhd_os_sdunlock(bus->dhd);
10730 
10731     return intrd;
10732 }
10733 EXPORT_SYMBOL(dhd_bus_cfg_read);
10734 
dhd_bus_cfg_write(void * h,uint fun_num,uint32 addr,uint8 val,int * err)10735 void dhd_bus_cfg_write(void *h, uint fun_num, uint32 addr, uint8 val, int *err)
10736 {
10737     dhd_pub_t *dhdp = (dhd_pub_t *)h;
10738     dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus;
10739 
10740     dhd_os_sdlock(bus->dhd);
10741 
10742     bcmsdh_cfg_write(bus->sdh, fun_num, addr, val, err);
10743 
10744     dhd_os_sdunlock(bus->dhd);
10745 }
10746 EXPORT_SYMBOL(dhd_bus_cfg_write);
10747 
extract_hex_field(char * line,uint16 start_pos,uint16 num_chars,uint16 * value)10748 static int extract_hex_field(char *line, uint16 start_pos, uint16 num_chars,
10749                              uint16 *value)
10750 {
10751     char field[0x8];
10752 
10753     strncpy(field, line + start_pos, num_chars);
10754     field[num_chars] = '\0';
10755 
10756     return (sscanf(field, "%hX", value) == 1);
10757 }
10758 
read_more_btbytes(struct dhd_bus * bus,void * file,char * line,int * addr_mode,uint16 * hi_addr,uint32 * dest_addr,uint8 * data_bytes,uint32 * num_bytes)10759 static int read_more_btbytes(struct dhd_bus *bus, void *file, char *line,
10760                              int *addr_mode, uint16 *hi_addr, uint32 *dest_addr,
10761                              uint8 *data_bytes, uint32 *num_bytes)
10762 {
10763     int str_len;
10764     uint16 num_data_bytes, addr, data_pos, type, w, i;
10765     uint32 abs_base_addr32 = 0;
10766     *num_bytes = 0;
10767 
10768     while (!*num_bytes) {
10769         str_len = dhd_os_gets_image(bus->dhd, line, BTFW_MAX_STR_LEN, file);
10770 
10771         DHD_TRACE(("%s: Len :0x%x  %s\n", __FUNCTION__, str_len, line));
10772 
10773         if (str_len == 0) {
10774             break;
10775         } else if (str_len > 0x9) {
10776             extract_hex_field(line, 1, 0x2, &num_data_bytes);
10777             extract_hex_field(line, 0x3, 0x4, &addr);
10778             extract_hex_field(line, 0x7, 0x2, &type);
10779 
10780             data_pos = 0x9;
10781             for (i = 0; i < num_data_bytes; i++) {
10782                 extract_hex_field(line, data_pos, 0x2, &w);
10783                 data_bytes[i] = (uint8)(w & 0x00FF);
10784                 data_pos += 0x2;
10785             }
10786 
10787             if (type == BTFW_HEX_LINE_TYPE_EXTENDED_ADDRESS) {
10788                 *hi_addr = (data_bytes[0] << 0x8) | data_bytes[1];
10789                 *addr_mode = BTFW_ADDR_MODE_EXTENDED;
10790             } else if (type == BTFW_HEX_LINE_TYPE_EXTENDED_SEGMENT_ADDRESS) {
10791                 *hi_addr = (data_bytes[0] << 0x8) | data_bytes[1];
10792                 *addr_mode = BTFW_ADDR_MODE_SEGMENT;
10793             } else if (type == BTFW_HEX_LINE_TYPE_ABSOLUTE_32BIT_ADDRESS) {
10794                 abs_base_addr32 = (data_bytes[0] << 0x18) |
10795                                   (data_bytes[1] << 0x10) | (data_bytes[0x2] << 0x8) |
10796                                   data_bytes[0x3];
10797                 *addr_mode = BTFW_ADDR_MODE_LINEAR32;
10798             } else if (type == BTFW_HEX_LINE_TYPE_DATA) {
10799                 *dest_addr = addr;
10800                 if (*addr_mode == BTFW_ADDR_MODE_EXTENDED) {
10801                     *dest_addr += (*hi_addr << 0x10);
10802                 } else if (*addr_mode == BTFW_ADDR_MODE_SEGMENT) {
10803                     *dest_addr += (*hi_addr << 0x4);
10804                 } else if (*addr_mode == BTFW_ADDR_MODE_LINEAR32) {
10805                     *dest_addr += abs_base_addr32;
10806                 }
10807                 *num_bytes = num_data_bytes;
10808             }
10809         }
10810     }
10811     return (*num_bytes > 0);
10812 }
10813 
_dhdsdio_download_btfw(struct dhd_bus * bus)10814 static int _dhdsdio_download_btfw(struct dhd_bus *bus)
10815 {
10816     int bcm_error = -1;
10817     void *image = NULL;
10818     uint8 *mem_blk = NULL, *mem_ptr = NULL, *data_ptr = NULL;
10819 
10820     uint32 offset_addr = 0, offset_len = 0, bytes_to_write = 0;
10821 
10822     char *line = NULL;
10823     uint32 dest_addr = 0, num_bytes;
10824     uint16 hiAddress = 0;
10825     uint32 start_addr, start_data, end_addr, end_data, i, index, pad,
10826         bt2wlan_pwrup_adr;
10827 
10828     int addr_mode = BTFW_ADDR_MODE_EXTENDED;
10829 
10830     /* Out immediately if no image to download */
10831     if ((bus->btfw_path == NULL) || (bus->btfw_path[0] == '\0')) {
10832         return 0;
10833     }
10834 
10835     image = dhd_os_open_image1(bus->dhd, bus->btfw_path);
10836     if (image == NULL) {
10837         goto err;
10838     }
10839 
10840     mem_ptr = mem_blk =
10841         MALLOC(bus->dhd->osh, BTFW_DOWNLOAD_BLK_SIZE + DHD_SDALIGN);
10842     if (mem_blk == NULL) {
10843         DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__,
10844                    BTFW_DOWNLOAD_BLK_SIZE + DHD_SDALIGN));
10845         goto err;
10846     }
10847     if ((uint32)(uintptr)mem_blk % DHD_SDALIGN) {
10848         mem_ptr += (DHD_SDALIGN - ((uint32)(uintptr)mem_blk % DHD_SDALIGN));
10849     }
10850 
10851     data_ptr = MALLOC(bus->dhd->osh, BTFW_DOWNLOAD_BLK_SIZE - 0x8);
10852     if (data_ptr == NULL) {
10853         DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__,
10854                    BTFW_DOWNLOAD_BLK_SIZE - 0x8));
10855         goto err;
10856     }
10857     /* Write to BT register to hold WLAN wake high during BT FW download */
10858     bt2wlan_pwrup_adr = BTMEM_OFFSET + BT2WLAN_PWRUP_ADDR;
10859     bcmsdh_reg_write(bus->sdh, bt2wlan_pwrup_adr, 0x4, BT2WLAN_PWRUP_WAKE);
10860     /*
10861      * Wait for at least 2msec for the clock to be ready/Available.
10862      */
10863     OSL_DELAY(0x7D0);
10864 
10865     line = MALLOC(bus->dhd->osh, BTFW_MAX_STR_LEN);
10866     if (line == NULL) {
10867         DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__,
10868                    BTFW_MAX_STR_LEN));
10869         goto err;
10870     }
10871     memset(line, 0, BTFW_MAX_STR_LEN);
10872 
10873     while (read_more_btbytes(bus, image, line, &addr_mode, &hiAddress,
10874                              &dest_addr, data_ptr, &num_bytes)) {
10875         DHD_TRACE(("read %d bytes at address %08X\n", num_bytes, dest_addr));
10876 
10877         start_addr = BTMEM_OFFSET + dest_addr;
10878         index = 0;
10879 
10880         /* Make sure the start address is 4 byte aligned to avoid alignment
10881          * issues with SD host controllers
10882          */
10883         if (!ISALIGNED(start_addr, 0x4)) {
10884             pad = start_addr % 0x4;
10885             start_addr = ROUNDDN(start_addr, 0x4);
10886             start_data = bcmsdh_reg_read(bus->sdh, start_addr, 0x4);
10887             for (i = 0; i < pad; i++, index++) {
10888                 mem_ptr[index] = (uint8)((uint8 *)&start_data)[i];
10889             }
10890         }
10891         bcopy(data_ptr, &(mem_ptr[index]), num_bytes);
10892         index += num_bytes;
10893 
10894         /* Make sure the length is multiple of 4bytes to avoid alignment issues
10895          * with SD host controllers
10896          */
10897         end_addr = start_addr + index;
10898         if (!ISALIGNED(end_addr, 0x4)) {
10899             end_addr = ROUNDDN(end_addr, 0x4);
10900             end_data = bcmsdh_reg_read(bus->sdh, end_addr, 0x4);
10901             for (i = (index % 0x4); i < 0x4; i++, index++) {
10902                 mem_ptr[index] = (uint8)((uint8 *)&end_data)[i];
10903             }
10904         }
10905 
10906         offset_addr = start_addr & 0xFFF;
10907         offset_len = offset_addr + index;
10908         if (offset_len <= 0x1000) {
10909             bcm_error = dhdsdio_membytes(bus, TRUE, start_addr, mem_ptr, index);
10910             if (bcm_error) {
10911                 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
10912                            __FUNCTION__, bcm_error, num_bytes, start_addr));
10913                 goto err;
10914             }
10915         } else {
10916             bytes_to_write = 0x1000 - offset_addr;
10917             bcm_error = dhdsdio_membytes(bus, TRUE, start_addr, mem_ptr,
10918                                          bytes_to_write);
10919             if (bcm_error) {
10920                 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
10921                            __FUNCTION__, bcm_error, num_bytes, start_addr));
10922                 goto err;
10923             }
10924 
10925             OSL_DELAY(0x2710);
10926 
10927             bcm_error = dhdsdio_membytes(
10928                 bus, TRUE, (start_addr + bytes_to_write),
10929                 (mem_ptr + bytes_to_write), (index - bytes_to_write));
10930             if (bcm_error) {
10931                 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
10932                            __FUNCTION__, bcm_error, num_bytes, start_addr));
10933                 goto err;
10934             }
10935         }
10936         memset(line, 0, BTFW_MAX_STR_LEN);
10937     }
10938 
10939     bcm_error = 0;
10940 err:
10941     if (mem_blk) {
10942         MFREE(bus->dhd->osh, mem_blk, BTFW_DOWNLOAD_BLK_SIZE + DHD_SDALIGN);
10943     }
10944 
10945     if (data_ptr) {
10946         MFREE(bus->dhd->osh, data_ptr, BTFW_DOWNLOAD_BLK_SIZE - 0x8);
10947     }
10948 
10949     if (line) {
10950         MFREE(bus->dhd->osh, line, BTFW_MAX_STR_LEN);
10951     }
10952 
10953     if (image) {
10954         dhd_os_close_image1(bus->dhd, image);
10955     }
10956 
10957     return bcm_error;
10958 }
10959 
dhdsdio_download_btfw(struct dhd_bus * bus,osl_t * osh,void * sdh)10960 static int dhdsdio_download_btfw(struct dhd_bus *bus, osl_t *osh, void *sdh)
10961 {
10962     int ret;
10963 
10964     DHD_TRACE(("%s: btfw path=%s\n", __FUNCTION__, bus->btfw_path));
10965     DHD_OS_WAKE_LOCK(bus->dhd);
10966     dhd_os_sdlock(bus->dhd);
10967 
10968     /* Download the firmware */
10969     ret = _dhdsdio_download_btfw(bus);
10970 
10971     dhd_os_sdunlock(bus->dhd);
10972     DHD_OS_WAKE_UNLOCK(bus->dhd);
10973 
10974     return ret;
10975 }
10976 
dhd_bus_download_btfw(struct dhd_bus * bus,osl_t * osh,char * pbtfw_path)10977 int dhd_bus_download_btfw(struct dhd_bus *bus, osl_t *osh, char *pbtfw_path)
10978 {
10979     int ret;
10980 
10981     bus->btfw_path = pbtfw_path;
10982 
10983     ret = dhdsdio_download_btfw(bus, osh, bus->sdh);
10984 
10985     return ret;
10986 }
10987 #endif /* defined (BT_OVER_SDIO) */
10988 
dhd_bus_dump_trap_info(dhd_bus_t * bus,struct bcmstrbuf * strbuf)10989 void dhd_bus_dump_trap_info(dhd_bus_t *bus, struct bcmstrbuf *strbuf)
10990 {
10991     trap_t *tr = &bus->dhd->last_trap_info;
10992 
10993     bcm_bprintf(
10994         strbuf,
10995         "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x,"
10996         "lp 0x%x, rpc 0x%x Trap offset 0x%x, "
10997         "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, "
10998         "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n",
10999         ltoh32(tr->type), ltoh32(tr->epc), ltoh32(tr->cpsr), ltoh32(tr->spsr),
11000         ltoh32(tr->r13), ltoh32(tr->r14), ltoh32(tr->pc),
11001         ltoh32(bus->dongle_trap_addr), ltoh32(tr->r0), ltoh32(tr->r1),
11002         ltoh32(tr->r2), ltoh32(tr->r3), ltoh32(tr->r4), ltoh32(tr->r5),
11003         ltoh32(tr->r6), ltoh32(tr->r7));
11004 }
11005 
dhd_bcmsdh_send_buffer(void * bus,uint8 * frame,uint16 len)11006 static int dhd_bcmsdh_send_buffer(void *bus, uint8 *frame, uint16 len)
11007 {
11008     int ret = -1;
11009 
11010     ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(((dhd_bus_t *)bus)->sdh),
11011                               SDIO_FUNC_2, F2SYNC, frame, len, NULL, NULL, NULL,
11012                               TXRETRIES);
11013     if (ret == BCME_OK) {
11014         ((dhd_bus_t *)bus)->tx_seq =
11015             (((dhd_bus_t *)bus)->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
11016     }
11017     return ret;
11018 }
11019 
11020 /* Function to set the min res mask depending on the chip ID used */
dhd_bus_set_default_min_res_mask(struct dhd_bus * bus)11021 bool dhd_bus_set_default_min_res_mask(struct dhd_bus *bus)
11022 {
11023     if ((bus == NULL) || (bus->sih == NULL)) {
11024         DHD_ERROR(("%s(): Invalid Arguments \r\n", __FUNCTION__));
11025         return FALSE;
11026     }
11027 
11028     switch (bus->sih->chip) {
11029         case BCM4339_CHIP_ID:
11030             bcmsdh_reg_write(bus->sdh, SI_ENUM_BASE(bus->sih) + 0x618, 0x4,
11031                              0x3fcaf377);
11032             if (bcmsdh_regfail(bus->sdh)) {
11033                 DHD_ERROR(("%s:%d Setting min_res_mask failed\n", __FUNCTION__,
11034                            __LINE__));
11035                 return FALSE;
11036             }
11037             break;
11038 
11039         case BCM43012_CHIP_ID:
11040             bcmsdh_reg_write(bus->sdh,
11041                              si_get_pmu_reg_addr(
11042                                  bus->sih, OFFSETOF(pmuregs_t, min_res_mask)),
11043                              0x4, DEFAULT_43012_MIN_RES_MASK);
11044             if (bcmsdh_regfail(bus->sdh)) {
11045                 DHD_ERROR(("%s:%d Setting min_res_mask failed\n", __FUNCTION__,
11046                            __LINE__));
11047                 return FALSE;
11048             }
11049             break;
11050 
11051         default:
11052             DHD_ERROR(("%s: Unhandled chip id\n", __FUNCTION__));
11053             return FALSE;
11054     }
11055 
11056     return TRUE;
11057 }
11058 
11059 /* Function to reset PMU registers */
dhd_bus_pmu_reg_reset(dhd_pub_t * dhdp)11060 void dhd_bus_pmu_reg_reset(dhd_pub_t *dhdp)
11061 {
11062     struct dhd_bus *bus = dhdp->bus;
11063     bcmsdh_reg_write(
11064         bus->sdh, si_get_pmu_reg_addr(bus->sih, OFFSETOF(pmuregs_t, swscratch)),
11065         0x4, 0x0);
11066     if (bcmsdh_regfail(bus->sdh)) {
11067         DHD_ERROR(
11068             ("%s:%d Setting min_res_mask failed\n", __FUNCTION__, __LINE__));
11069     }
11070 }
11071 
11072 #ifdef DHD_ULP
11073 
11074 /* Function to disable console messages on entering ULP mode */
dhd_bus_ulp_disable_console(dhd_pub_t * dhdp)11075 void dhd_bus_ulp_disable_console(dhd_pub_t *dhdp)
11076 {
11077 #ifdef DHD_DEBUG
11078     DHD_ERROR(("Flushing and disabling console messages\n"));
11079 
11080     /* Save the console print interval */
11081     dhd_ulp_save_console_interval(dhdp);
11082 
11083     /* Flush the console buffer before disabling */
11084     dhdsdio_readconsole(dhdp->bus);
11085     dhdp->dhd_console_ms = 0;
11086 #endif /* DHD_DEBUG */
11087 }
11088 
11089 /* Function for redownloading firmaware */
dhd_bus_ulp_reinit_fw(dhd_bus_t * bus)11090 static int dhd_bus_ulp_reinit_fw(dhd_bus_t *bus)
11091 {
11092     int bcmerror = 0;
11093 
11094     /* After firmware redownload tx/rx seq are reset accordingly these values
11095     are reset on DHD side tx_max is initially set to 4, which later is updated
11096     by FW
11097     */
11098     bus->tx_seq = bus->rx_seq = 0;
11099     bus->tx_max = 0x4;
11100 
11101     if (dhd_bus_download_firmware(bus, bus->dhd->osh, bus->fw_path,
11102                                   bus->nv_path) >= 0) {
11103         /* Re-init bus, enable F2 transfer */
11104         bcmerror = dhd_bus_init((dhd_pub_t *)bus->dhd, FALSE);
11105         if (bcmerror == BCME_OK) {
11106             bus->dhd->up = TRUE;
11107             dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
11108 
11109             dhd_ulp_set_ulp_state(bus->dhd, DHD_ULP_READY);
11110 #if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
11111             dhd_enable_oob_intr(bus, TRUE);
11112             bcmsdh_oob_intr_set(bus->sdh, TRUE);
11113 #endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
11114 #ifdef DHD_DEBUG
11115             /* Re-enable the console messages on FW redownload to default value
11116              */
11117             dhd_ulp_restore_console_interval(bus->dhd);
11118 #endif /* DHD_DEBUG */
11119         } else {
11120             DHD_ERROR(("bus init failed\n"));
11121             dhd_bus_stop(bus, FALSE);
11122             dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE, FALSE);
11123         }
11124     } else {
11125         bcmerror = BCME_SDIO_ERROR;
11126     }
11127 
11128     return bcmerror;
11129 }
11130 #endif /* DHD_ULP */
11131 
dhd_bus_readwrite_bp_addr(dhd_pub_t * dhdp,uint addr,uint size,uint * data,bool read)11132 int dhd_bus_readwrite_bp_addr(dhd_pub_t *dhdp, uint addr, uint size, uint *data,
11133                               bool read)
11134 {
11135     int bcmerror = 0;
11136     struct dhd_bus *bus = dhdp->bus;
11137 
11138     if (read) {
11139         *data = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
11140     } else {
11141         bcmsdh_reg_write(bus->sdh, addr, size, *data);
11142     }
11143 
11144     if (bcmsdh_regfail(bus->sdh)) {
11145         bcmerror = BCME_SDIO_ERROR;
11146     }
11147 
11148     return bcmerror;
11149 }
11150 
dhd_get_idletime(dhd_pub_t * dhd)11151 int dhd_get_idletime(dhd_pub_t *dhd)
11152 {
11153     return dhd->bus->idletime;
11154 }
11155 
11156 #ifdef DHD_WAKE_STATUS
dhd_bus_get_wakecount(dhd_pub_t * dhd)11157 wake_counts_t *dhd_bus_get_wakecount(dhd_pub_t *dhd)
11158 {
11159     if (!dhd->bus) {
11160         return NULL;
11161     }
11162     return &dhd->bus->wake_counts;
11163 }
dhd_bus_get_bus_wake(dhd_pub_t * dhd)11164 int dhd_bus_get_bus_wake(dhd_pub_t *dhd)
11165 {
11166     return bcmsdh_set_get_wake(dhd->bus->sdh, 0);
11167 }
11168 #endif /* DHD_WAKE_STATUS */
11169 
dhd_bus_sleep(dhd_pub_t * dhdp,bool sleep,uint32 * intstatus)11170 int dhd_bus_sleep(dhd_pub_t *dhdp, bool sleep, uint32 *intstatus)
11171 {
11172     dhd_bus_t *bus = dhdp->bus;
11173     uint32 retry = 0;
11174     int ret = 0;
11175 
11176     if (bus) {
11177         dhd_os_sdlock(dhdp);
11178         BUS_WAKE(bus);
11179         R_SDREG(*intstatus, &bus->regs->intstatus, retry);
11180         if (sleep) {
11181             if (SLPAUTO_ENAB(bus)) {
11182                 ret = dhdsdio_bussleep(bus, sleep);
11183                 if (ret != BCME_BUSY) {
11184                     dhd_os_wd_timer(bus->dhd, 0);
11185                 }
11186             } else {
11187                 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
11188             }
11189         }
11190         dhd_os_sdunlock(dhdp);
11191     } else {
11192         DHD_ERROR(("bus is NULL\n"));
11193         ret = -1;
11194     }
11195 
11196     return ret;
11197 }
11198