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