/drivers/net/wireless/bcmdhd/dhd_sdio.c
C | 6359 lines | 4798 code | 999 blank | 562 comment | 1138 complexity | 3c52bd19fa50b30dca420548ef79f3e5 MD5 | raw file
Possible License(s): LGPL-2.0, AGPL-1.0, GPL-2.0
Large files files are truncated, but you can click here to view the full file
1/* 2 * DHD Bus Module for SDIO 3 * 4 * Copyright (C) 1999-2011, 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 * $Id: dhd_sdio.c 326662 2012-04-10 06:38:08Z $ 25 */ 26 27#include <typedefs.h> 28#include <osl.h> 29#include <bcmsdh.h> 30 31#ifdef BCMEMBEDIMAGE 32#include BCMEMBEDIMAGE 33#endif /* BCMEMBEDIMAGE */ 34 35#include <bcmdefs.h> 36#include <bcmutils.h> 37#include <bcmendian.h> 38#include <bcmdevs.h> 39 40#include <siutils.h> 41#include <hndpmu.h> 42#include <hndsoc.h> 43#include <bcmsdpcm.h> 44#if defined(DHD_DEBUG) 45#include <hndrte_armtrap.h> 46#include <hndrte_cons.h> 47#endif /* defined(DHD_DEBUG) */ 48#include <sbchipc.h> 49#include <sbhnddma.h> 50 51#include <sdio.h> 52#include <sbsdio.h> 53#include <sbsdpcmdev.h> 54#include <bcmsdpcm.h> 55#include <bcmsdbus.h> 56 57#include <proto/ethernet.h> 58#include <proto/802.1d.h> 59#include <proto/802.11.h> 60 61#include <dngl_stats.h> 62#include <dhd.h> 63#include <dhd_bus.h> 64#include <dhd_proto.h> 65#include <dhd_dbg.h> 66#include <dhdioctl.h> 67#include <sdiovar.h> 68 69#ifndef DHDSDIO_MEM_DUMP_FNAME 70#define DHDSDIO_MEM_DUMP_FNAME "mem_dump" 71#endif 72 73#define QLEN 256 /* bulk rx and tx queue lengths */ 74#define FCHI (QLEN - 10) 75#define FCLOW (FCHI / 2) 76#define PRIOMASK 7 77 78#define TXRETRIES 2 /* # of retries for tx frames */ 79 80#define DHD_RXBOUND 50 /* Default for max rx frames in one scheduling */ 81 82#define DHD_TXBOUND 20 /* Default for max tx frames in one scheduling */ 83 84#define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */ 85 86#define MEMBLOCK 2048 /* Block size used for downloading of dongle image */ 87#define MAX_NVRAMBUF_SIZE 4096 /* max nvram buf size */ 88#define MAX_DATA_BUF (32 * 1024) /* Must be large enough to hold biggest possible glom */ 89 90#ifndef DHD_FIRSTREAD 91#define DHD_FIRSTREAD 32 92#endif 93#if !ISPOWEROF2(DHD_FIRSTREAD) 94#error DHD_FIRSTREAD is not a power of 2! 95#endif 96 97/* Total length of frame header for dongle protocol */ 98#define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN) 99#ifdef SDTEST 100#define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN) 101#else 102#define SDPCM_RESERVE (SDPCM_HDRLEN + DHD_SDALIGN) 103#endif 104 105/* Space for header read, limit for data packets */ 106#ifndef MAX_HDR_READ 107#define MAX_HDR_READ 32 108#endif 109#if !ISPOWEROF2(MAX_HDR_READ) 110#error MAX_HDR_READ is not a power of 2! 111#endif 112 113#define MAX_RX_DATASZ 2048 114 115/* Maximum milliseconds to wait for F2 to come up */ 116#define DHD_WAIT_F2RDY 3000 117 118/* Bump up limit on waiting for HT to account for first startup; 119 * if the image is doing a CRC calculation before programming the PMU 120 * for HT availability, it could take a couple hundred ms more, so 121 * max out at a 1 second (1000000us). 122 */ 123#if (PMU_MAX_TRANSITION_DLY <= 1000000) 124#undef PMU_MAX_TRANSITION_DLY 125#define PMU_MAX_TRANSITION_DLY 1000000 126#endif 127 128/* Value for ChipClockCSR during initial setup */ 129#define DHD_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ) 130#define DHD_INIT_CLKCTL2 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP) 131 132/* Flags for SDH calls */ 133#define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED) 134 135/* Packet free applicable unconditionally for sdio and sdspi. Conditional if 136 * bufpool was present for gspi bus. 137 */ 138#define PKTFREE2() if ((bus->bus != SPI_BUS) || bus->usebufpool) \ 139 PKTFREE(bus->dhd->osh, pkt, FALSE); 140DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep); 141#if defined(OOB_INTR_ONLY) 142extern void bcmsdh_set_irq(int flag); 143#endif /* defined(OOB_INTR_ONLY) */ 144#ifdef PROP_TXSTATUS 145extern void dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success); 146#endif 147 148#ifdef DHD_DEBUG 149/* Device console log buffer state */ 150#define CONSOLE_LINE_MAX 192 151#define CONSOLE_BUFFER_MAX 2024 152typedef struct dhd_console { 153 uint count; /* Poll interval msec counter */ 154 uint log_addr; /* Log struct address (fixed) */ 155 hndrte_log_t log; /* Log struct (host copy) */ 156 uint bufsize; /* Size of log buffer */ 157 uint8 *buf; /* Log buffer (host copy) */ 158 uint last; /* Last buffer read index */ 159} dhd_console_t; 160#endif /* DHD_DEBUG */ 161 162/* Private data for SDIO bus interaction */ 163typedef struct dhd_bus { 164 dhd_pub_t *dhd; 165 166 bcmsdh_info_t *sdh; /* Handle for BCMSDH calls */ 167 si_t *sih; /* Handle for SI calls */ 168 char *vars; /* Variables (from CIS and/or other) */ 169 uint varsz; /* Size of variables buffer */ 170 uint32 sbaddr; /* Current SB window pointer (-1, invalid) */ 171 172 sdpcmd_regs_t *regs; /* Registers for SDIO core */ 173 uint sdpcmrev; /* SDIO core revision */ 174 uint armrev; /* CPU core revision */ 175 uint ramrev; /* SOCRAM core revision */ 176 uint32 ramsize; /* Size of RAM in SOCRAM (bytes) */ 177 uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */ 178 179 uint32 bus; /* gSPI or SDIO bus */ 180 uint32 hostintmask; /* Copy of Host Interrupt Mask */ 181 uint32 intstatus; /* Intstatus bits (events) pending */ 182 bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */ 183 bool fcstate; /* State of dongle flow-control */ 184 185 uint16 cl_devid; /* cached devid for dhdsdio_probe_attach() */ 186 char *fw_path; /* module_param: path to firmware image */ 187 char *nv_path; /* module_param: path to nvram vars file */ 188 const char *nvram_params; /* user specified nvram params. */ 189 190 uint blocksize; /* Block size of SDIO transfers */ 191 uint roundup; /* Max roundup limit */ 192 193 struct pktq txq; /* Queue length used for flow-control */ 194 uint8 flowcontrol; /* per prio flow control bitmask */ 195 uint8 tx_seq; /* Transmit sequence number (next) */ 196 uint8 tx_max; /* Maximum transmit sequence allowed */ 197 198 uint8 hdrbuf[MAX_HDR_READ + DHD_SDALIGN]; 199 uint8 *rxhdr; /* Header of current rx frame (in hdrbuf) */ 200 uint16 nextlen; /* Next Read Len from last header */ 201 uint8 rx_seq; /* Receive sequence number (expected) */ 202 bool rxskip; /* Skip receive (awaiting NAK ACK) */ 203 204 void *glomd; /* Packet containing glomming descriptor */ 205 void *glom; /* Packet chain for glommed superframe */ 206 uint glomerr; /* Glom packet read errors */ 207 208 uint8 *rxbuf; /* Buffer for receiving control packets */ 209 uint rxblen; /* Allocated length of rxbuf */ 210 uint8 *rxctl; /* Aligned pointer into rxbuf */ 211 uint8 *databuf; /* Buffer for receiving big glom packet */ 212 uint8 *dataptr; /* Aligned pointer into databuf */ 213 uint rxlen; /* Length of valid data in buffer */ 214 215 uint8 sdpcm_ver; /* Bus protocol reported by dongle */ 216 217 bool intr; /* Use interrupts */ 218 bool poll; /* Use polling */ 219 bool ipend; /* Device interrupt is pending */ 220 bool intdis; /* Interrupts disabled by isr */ 221 uint intrcount; /* Count of device interrupt callbacks */ 222 uint lastintrs; /* Count as of last watchdog timer */ 223 uint spurious; /* Count of spurious interrupts */ 224 uint pollrate; /* Ticks between device polls */ 225 uint polltick; /* Tick counter */ 226 uint pollcnt; /* Count of active polls */ 227 228#ifdef DHD_DEBUG 229 dhd_console_t console; /* Console output polling support */ 230 uint console_addr; /* Console address from shared struct */ 231#endif /* DHD_DEBUG */ 232 233 uint regfails; /* Count of R_REG/W_REG failures */ 234 235 uint clkstate; /* State of sd and backplane clock(s) */ 236 bool activity; /* Activity flag for clock down */ 237 int32 idletime; /* Control for activity timeout */ 238 int32 idlecount; /* Activity timeout counter */ 239 int32 idleclock; /* How to set bus driver when idle */ 240 int32 sd_divisor; /* Speed control to bus driver */ 241 int32 sd_mode; /* Mode control to bus driver */ 242 int32 sd_rxchain; /* If bcmsdh api accepts PKT chains */ 243 bool use_rxchain; /* If dhd should use PKT chains */ 244 bool sleeping; /* Is SDIO bus sleeping? */ 245 bool rxflow_mode; /* Rx flow control mode */ 246 bool rxflow; /* Is rx flow control on */ 247 uint prev_rxlim_hit; /* Is prev rx limit exceeded (per dpc schedule) */ 248 bool alp_only; /* Don't use HT clock (ALP only) */ 249 /* Field to decide if rx of control frames happen in rxbuf or lb-pool */ 250 bool usebufpool; 251 252#ifdef SDTEST 253 /* external loopback */ 254 bool ext_loop; 255 uint8 loopid; 256 257 /* pktgen configuration */ 258 uint pktgen_freq; /* Ticks between bursts */ 259 uint pktgen_count; /* Packets to send each burst */ 260 uint pktgen_print; /* Bursts between count displays */ 261 uint pktgen_total; /* Stop after this many */ 262 uint pktgen_minlen; /* Minimum packet data len */ 263 uint pktgen_maxlen; /* Maximum packet data len */ 264 uint pktgen_mode; /* Configured mode: tx, rx, or echo */ 265 uint pktgen_stop; /* Number of tx failures causing stop */ 266 267 /* active pktgen fields */ 268 uint pktgen_tick; /* Tick counter for bursts */ 269 uint pktgen_ptick; /* Burst counter for printing */ 270 uint pktgen_sent; /* Number of test packets generated */ 271 uint pktgen_rcvd; /* Number of test packets received */ 272 uint pktgen_fail; /* Number of failed send attempts */ 273 uint16 pktgen_len; /* Length of next packet to send */ 274#define PKTGEN_RCV_IDLE (0) 275#define PKTGEN_RCV_ONGOING (1) 276 uint16 pktgen_rcv_state; /* receive state */ 277 uint pktgen_rcvd_rcvsession; /* test pkts rcvd per rcv session. */ 278#endif /* SDTEST */ 279 280 /* Some additional counters */ 281 uint tx_sderrs; /* Count of tx attempts with sd errors */ 282 uint fcqueued; /* Tx packets that got queued */ 283 uint rxrtx; /* Count of rtx requests (NAK to dongle) */ 284 uint rx_toolong; /* Receive frames too long to receive */ 285 uint rxc_errors; /* SDIO errors when reading control frames */ 286 uint rx_hdrfail; /* SDIO errors on header reads */ 287 uint rx_badhdr; /* Bad received headers (roosync?) */ 288 uint rx_badseq; /* Mismatched rx sequence number */ 289 uint fc_rcvd; /* Number of flow-control events received */ 290 uint fc_xoff; /* Number which turned on flow-control */ 291 uint fc_xon; /* Number which turned off flow-control */ 292 uint rxglomfail; /* Failed deglom attempts */ 293 uint rxglomframes; /* Number of glom frames (superframes) */ 294 uint rxglompkts; /* Number of packets from glom frames */ 295 uint f2rxhdrs; /* Number of header reads */ 296 uint f2rxdata; /* Number of frame data reads */ 297 uint f2txdata; /* Number of f2 frame writes */ 298 uint f1regdata; /* Number of f1 register accesses */ 299 300 uint8 *ctrl_frame_buf; 301 uint32 ctrl_frame_len; 302 bool ctrl_frame_stat; 303 uint32 rxint_mode; /* rx interrupt mode */ 304} dhd_bus_t; 305 306/* clkstate */ 307#define CLK_NONE 0 308#define CLK_SDONLY 1 309#define CLK_PENDING 2 /* Not used yet */ 310#define CLK_AVAIL 3 311 312#define DHD_NOPMU(dhd) (FALSE) 313 314#ifdef DHD_DEBUG 315static int qcount[NUMPRIO]; 316static int tx_packets[NUMPRIO]; 317#endif /* DHD_DEBUG */ 318 319/* Deferred transmit */ 320const uint dhd_deferred_tx = 1; 321 322extern uint dhd_watchdog_ms; 323extern void dhd_os_wd_timer(void *bus, uint wdtick); 324 325/* Tx/Rx bounds */ 326uint dhd_txbound; 327uint dhd_rxbound; 328uint dhd_txminmax = DHD_TXMINMAX; 329 330/* override the RAM size if possible */ 331#define DONGLE_MIN_MEMSIZE (128 *1024) 332int dhd_dongle_memsize; 333 334static bool dhd_doflow; 335static bool dhd_alignctl; 336 337static bool sd1idle; 338 339static bool retrydata; 340#define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata) 341 342static const uint watermark = 8; 343static const uint firstread = DHD_FIRSTREAD; 344 345#define HDATLEN (firstread - (SDPCM_HDRLEN)) 346 347/* Retry count for register access failures */ 348static const uint retry_limit = 20; 349 350/* Force even SD lengths (some host controllers mess up on odd bytes) */ 351static bool forcealign; 352 353/* Flag to indicate if we should download firmware on driver load */ 354uint dhd_download_fw_on_driverload = TRUE; 355 356#define ALIGNMENT 4 357 358#if defined(OOB_INTR_ONLY) && defined(HW_OOB) 359extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable); 360#endif 361 362#if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) 363#error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD 364#endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */ 365#define PKTALIGN(osh, p, len, align) \ 366 do { \ 367 uint datalign; \ 368 datalign = (uintptr)PKTDATA((osh), (p)); \ 369 datalign = ROUNDUP(datalign, (align)) - datalign; \ 370 ASSERT(datalign < (align)); \ 371 ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign)); \ 372 if (datalign) \ 373 PKTPULL((osh), (p), datalign); \ 374 PKTSETLEN((osh), (p), (len)); \ 375 } while (0) 376 377/* Limit on rounding up frames */ 378static const uint max_roundup = 512; 379 380/* Try doing readahead */ 381static bool dhd_readahead; 382 383/* To check if there's window offered */ 384#define DATAOK(bus) \ 385 (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \ 386 (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0)) 387 388/* To check if there's window offered for ctrl frame */ 389#define TXCTLOK(bus) \ 390 (((uint8)(bus->tx_max - bus->tx_seq) != 0) && \ 391 (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0)) 392 393/* Macros to get register read/write status */ 394/* NOTE: these assume a local dhdsdio_bus_t *bus! */ 395#define R_SDREG(regvar, regaddr, retryvar) \ 396do { \ 397 retryvar = 0; \ 398 do { \ 399 regvar = R_REG(bus->dhd->osh, regaddr); \ 400 } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \ 401 if(retryvar > 1) \ 402 DHD_ERROR(("%s: regvar[ %d ], retryvar[ %d ], regfails[ %d ], bcmsdh_regfail[ %d ] \n",__FUNCTION__,regvar, retryvar ,bus->regfails, bcmsdh_regfail(bus->sdh))); \ 403 if (retryvar) { \ 404 bus->regfails += (retryvar-1); \ 405 if (retryvar > retry_limit) { \ 406 DHD_ERROR(("%s: FAILED" #regvar "READ, LINE %d\n", \ 407 __FUNCTION__, __LINE__)); \ 408 regvar = 0; \ 409 } \ 410 } \ 411} while (0) 412 413#define W_SDREG(regval, regaddr, retryvar) \ 414do { \ 415 retryvar = 0; \ 416 do { \ 417 W_REG(bus->dhd->osh, regaddr, regval); \ 418 } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \ 419 if (retryvar) { \ 420 bus->regfails += (retryvar-1); \ 421 if (retryvar > retry_limit) \ 422 DHD_ERROR(("%s: FAILED REGISTER WRITE, LINE %d\n", \ 423 __FUNCTION__, __LINE__)); \ 424 } \ 425} while (0) 426 427#define BUS_WAKE(bus) \ 428 do { \ 429 if ((bus)->sleeping) \ 430 dhdsdio_bussleep((bus), FALSE); \ 431 } while (0); 432 433/* 434 * pktavail interrupts from dongle to host can be managed in 3 different ways 435 * whenever there is a packet available in dongle to transmit to host. 436 * 437 * Mode 0: Dongle writes the software host mailbox and host is interrupted. 438 * Mode 1: (sdiod core rev >= 4) 439 * Device sets a new bit in the intstatus whenever there is a packet 440 * available in fifo. Host can't clear this specific status bit until all the 441 * packets are read from the FIFO. No need to ack dongle intstatus. 442 * Mode 2: (sdiod core rev >= 4) 443 * Device sets a bit in the intstatus, and host acks this by writing 444 * one to this bit. Dongle won't generate anymore packet interrupts 445 * until host reads all the packets from the dongle and reads a zero to 446 * figure that there are no more packets. No need to disable host ints. 447 * Need to ack the intstatus. 448 */ 449 450#define SDIO_DEVICE_HMB_RXINT 0 /* default old way */ 451#define SDIO_DEVICE_RXDATAINT_MODE_0 1 /* from sdiod rev 4 */ 452#define SDIO_DEVICE_RXDATAINT_MODE_1 2 /* from sdiod rev 4 */ 453 454 455#define FRAME_AVAIL_MASK(bus) \ 456 ((bus->rxint_mode == SDIO_DEVICE_HMB_RXINT) ? I_HMB_FRAME_IND : I_XMTDATA_AVAIL) 457 458#define DHD_BUS SDIO_BUS 459 460#define PKT_AVAILABLE(bus, intstatus) ((intstatus) & (FRAME_AVAIL_MASK(bus))) 461 462#define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE) 463 464#define GSPI_PR55150_BAILOUT 465 466 467#ifdef SDTEST 468static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq); 469static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint8 count); 470#endif 471 472#ifdef DHD_DEBUG 473static int dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size); 474static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror); 475#endif /* DHD_DEBUG */ 476 477static int dhdsdio_download_state(dhd_bus_t *bus, bool enter); 478 479static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh); 480static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh); 481static void dhdsdio_disconnect(void *ptr); 482static bool dhdsdio_chipmatch(uint16 chipid); 483static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh, 484 void * regsva, uint16 devid); 485static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh); 486static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh); 487static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, 488 bool reset_flag); 489 490static void dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size); 491static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, 492 uint8 *buf, uint nbytes, 493 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle); 494static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, 495 uint8 *buf, uint nbytes, 496 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle); 497 498static bool dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh); 499static int _dhdsdio_download_firmware(dhd_bus_t *bus); 500 501static int dhdsdio_download_code_file(dhd_bus_t *bus, char *image_path); 502static int dhdsdio_download_nvram(dhd_bus_t *bus); 503#ifdef BCMEMBEDIMAGE 504static int dhdsdio_download_code_array(dhd_bus_t *bus); 505#endif 506 507#ifdef WLMEDIA_HTSF 508#include <htsf.h> 509extern uint32 dhd_get_htsf(void *dhd, int ifidx); 510#endif /* WLMEDIA_HTSF */ 511 512extern int chip_is_b1; 513 514static void 515dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size) 516{ 517 int32 min_size = DONGLE_MIN_MEMSIZE; 518 /* Restrict the memsize to user specified limit */ 519 DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n", 520 dhd_dongle_memsize, min_size)); 521 if ((dhd_dongle_memsize > min_size) && 522 (dhd_dongle_memsize < (int32)bus->orig_ramsize)) 523 bus->ramsize = dhd_dongle_memsize; 524} 525 526static int 527dhdsdio_set_siaddr_window(dhd_bus_t *bus, uint32 address) 528{ 529 int err = 0; 530 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, 531 (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err); 532 if (!err) 533 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID, 534 (address >> 16) & SBSDIO_SBADDRMID_MASK, &err); 535 if (!err) 536 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH, 537 (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err); 538 return err; 539} 540 541 542/* Turn backplane clock on or off */ 543static int 544dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) 545{ 546 int err; 547 uint8 clkctl, clkreq, devctl; 548 bcmsdh_info_t *sdh; 549 550 DHD_TRACE(("%s: Enter\n", __FUNCTION__)); 551 552#if defined(OOB_INTR_ONLY) 553 pendok = FALSE; 554#endif 555 clkctl = 0; 556 sdh = bus->sdh; 557 558 559 if (on) { 560 /* Request HT Avail */ 561 clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ; 562 563 564 565 566 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); 567 if (err) { 568 DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err)); 569 return BCME_ERROR; 570 } 571 572 if (pendok && 573 ((bus->sih->buscoretype == PCMCIA_CORE_ID) && (bus->sih->buscorerev == 9))) { 574 uint32 dummy, retries; 575 R_SDREG(dummy, &bus->regs->clockctlstatus, retries); 576 } 577 578 /* Check current status */ 579 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); 580 if (err) { 581 DHD_ERROR(("%s: HT Avail read error: %d\n", __FUNCTION__, err)); 582 return BCME_ERROR; 583 } 584 585 /* Go to pending and await interrupt if appropriate */ 586 if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) { 587 /* Allow only clock-available interrupt */ 588 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); 589 if (err) { 590 DHD_ERROR(("%s: Devctl access error setting CA: %d\n", 591 __FUNCTION__, err)); 592 return BCME_ERROR; 593 } 594 595 devctl |= SBSDIO_DEVCTL_CA_INT_ONLY; 596 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); 597 DHD_INFO(("CLKCTL: set PENDING\n")); 598 bus->clkstate = CLK_PENDING; 599 return BCME_OK; 600 } else if (bus->clkstate == CLK_PENDING) { 601 /* Cancel CA-only interrupt filter */ 602 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); 603 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; 604 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); 605 } 606 607 /* Otherwise, wait here (polling) for HT Avail */ 608 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { 609 SPINWAIT_SLEEP(sdioh_spinwait_sleep, 610 ((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, 611 SBSDIO_FUNC1_CHIPCLKCSR, &err)), 612 !SBSDIO_CLKAV(clkctl, bus->alp_only)), PMU_MAX_TRANSITION_DLY); 613 } 614 if (err) { 615 DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err)); 616 return BCME_ERROR; 617 } 618 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { 619 DHD_ERROR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n", 620 __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl)); 621 return BCME_ERROR; 622 } 623 624 625 /* Mark clock available */ 626 bus->clkstate = CLK_AVAIL; 627 DHD_INFO(("CLKCTL: turned ON\n")); 628 629#if defined(DHD_DEBUG) 630 if (bus->alp_only == TRUE) { 631#if !defined(BCMLXSDMMC) 632 if (!SBSDIO_ALPONLY(clkctl)) { 633 DHD_ERROR(("%s: HT Clock, when ALP Only\n", __FUNCTION__)); 634 } 635#endif /* !defined(BCMLXSDMMC) */ 636 } else { 637 if (SBSDIO_ALPONLY(clkctl)) { 638 DHD_ERROR(("%s: HT Clock should be on.\n", __FUNCTION__)); 639 } 640 } 641#endif /* defined (DHD_DEBUG) */ 642 643 bus->activity = TRUE; 644 } else { 645 clkreq = 0; 646 647 if (bus->clkstate == CLK_PENDING) { 648 /* Cancel CA-only interrupt filter */ 649 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); 650 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; 651 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); 652 } 653 654 bus->clkstate = CLK_SDONLY; 655 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); 656 DHD_INFO(("CLKCTL: turned OFF\n")); 657 if (err) { 658 DHD_ERROR(("%s: Failed access turning clock off: %d\n", 659 __FUNCTION__, err)); 660 return BCME_ERROR; 661 } 662 } 663 return BCME_OK; 664} 665 666/* Change idle/active SD state */ 667static int 668dhdsdio_sdclk(dhd_bus_t *bus, bool on) 669{ 670 int err; 671 int32 iovalue; 672 673 DHD_TRACE(("%s: Enter\n", __FUNCTION__)); 674 675 if (on) { 676 if (bus->idleclock == DHD_IDLE_STOP) { 677 /* Turn on clock and restore mode */ 678 iovalue = 1; 679 err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0, 680 &iovalue, sizeof(iovalue), TRUE); 681 if (err) { 682 DHD_ERROR(("%s: error enabling sd_clock: %d\n", 683 __FUNCTION__, err)); 684 return BCME_ERROR; 685 } 686 687 iovalue = bus->sd_mode; 688 err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0, 689 &iovalue, sizeof(iovalue), TRUE); 690 if (err) { 691 DHD_ERROR(("%s: error changing sd_mode: %d\n", 692 __FUNCTION__, err)); 693 return BCME_ERROR; 694 } 695 } else if (bus->idleclock != DHD_IDLE_ACTIVE) { 696 /* Restore clock speed */ 697 iovalue = bus->sd_divisor; 698 err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, 699 &iovalue, sizeof(iovalue), TRUE); 700 if (err) { 701 DHD_ERROR(("%s: error restoring sd_divisor: %d\n", 702 __FUNCTION__, err)); 703 return BCME_ERROR; 704 } 705 } 706 bus->clkstate = CLK_SDONLY; 707 } else { 708 /* Stop or slow the SD clock itself */ 709 if ((bus->sd_divisor == -1) || (bus->sd_mode == -1)) { 710 DHD_TRACE(("%s: can't idle clock, divisor %d mode %d\n", 711 __FUNCTION__, bus->sd_divisor, bus->sd_mode)); 712 return BCME_ERROR; 713 } 714 if (bus->idleclock == DHD_IDLE_STOP) { 715 if (sd1idle) { 716 /* Change to SD1 mode and turn off clock */ 717 iovalue = 1; 718 err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0, 719 &iovalue, sizeof(iovalue), TRUE); 720 if (err) { 721 DHD_ERROR(("%s: error changing sd_clock: %d\n", 722 __FUNCTION__, err)); 723 return BCME_ERROR; 724 } 725 } 726 727 iovalue = 0; 728 err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0, 729 &iovalue, sizeof(iovalue), TRUE); 730 if (err) { 731 DHD_ERROR(("%s: error disabling sd_clock: %d\n", 732 __FUNCTION__, err)); 733 return BCME_ERROR; 734 } 735 } else if (bus->idleclock != DHD_IDLE_ACTIVE) { 736 /* Set divisor to idle value */ 737 iovalue = bus->idleclock; 738 err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, 739 &iovalue, sizeof(iovalue), TRUE); 740 if (err) { 741 DHD_ERROR(("%s: error changing sd_divisor: %d\n", 742 __FUNCTION__, err)); 743 return BCME_ERROR; 744 } 745 } 746 bus->clkstate = CLK_NONE; 747 } 748 749 return BCME_OK; 750} 751 752/* Transition SD and backplane clock readiness */ 753static int 754dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok) 755{ 756 int ret = BCME_OK; 757#ifdef DHD_DEBUG 758 uint oldstate = bus->clkstate; 759#endif /* DHD_DEBUG */ 760 761 DHD_TRACE(("%s: Enter\n", __FUNCTION__)); 762 763 /* Early exit if we're already there */ 764 if (bus->clkstate == target) { 765 if (target == CLK_AVAIL) { 766 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); 767 bus->activity = TRUE; 768 } 769 return ret; 770 } 771 772 switch (target) { 773 case CLK_AVAIL: 774 /* Make sure SD clock is available */ 775 if (bus->clkstate == CLK_NONE) 776 dhdsdio_sdclk(bus, TRUE); 777 /* Now request HT Avail on the backplane */ 778 ret = dhdsdio_htclk(bus, TRUE, pendok); 779 if (ret == BCME_OK) { 780 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); 781 bus->activity = TRUE; 782 } 783 break; 784 785 case CLK_SDONLY: 786 /* Remove HT request, or bring up SD clock */ 787 if (bus->clkstate == CLK_NONE) 788 ret = dhdsdio_sdclk(bus, TRUE); 789 else if (bus->clkstate == CLK_AVAIL) 790 ret = dhdsdio_htclk(bus, FALSE, FALSE); 791 else 792 DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n", 793 bus->clkstate, target)); 794 if (ret == BCME_OK) { 795 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); 796 } 797 break; 798 799 case CLK_NONE: 800 /* Make sure to remove HT request */ 801 if (bus->clkstate == CLK_AVAIL) 802 ret = dhdsdio_htclk(bus, FALSE, FALSE); 803 /* Now remove the SD clock */ 804 ret = dhdsdio_sdclk(bus, FALSE); 805#ifdef DHD_DEBUG 806 if (dhd_console_ms == 0) 807#endif /* DHD_DEBUG */ 808 if (bus->poll == 0) 809 dhd_os_wd_timer(bus->dhd, 0); 810 break; 811 } 812#ifdef DHD_DEBUG 813 DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate)); 814#endif /* DHD_DEBUG */ 815 816 return ret; 817} 818 819static int 820dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) 821{ 822 bcmsdh_info_t *sdh = bus->sdh; 823 sdpcmd_regs_t *regs = bus->regs; 824 uint retries = 0; 825 826 DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n", 827 (sleep ? "SLEEP" : "WAKE"), 828 (bus->sleeping ? "SLEEP" : "WAKE"))); 829 830 /* Done if we're already in the requested state */ 831 if (sleep == bus->sleeping) 832 return BCME_OK; 833 834 /* Going to sleep: set the alarm and turn off the lights... */ 835 if (sleep) { 836 /* Don't sleep if something is pending */ 837 if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq)) 838 return BCME_BUSY; 839 840 841 /* Disable SDIO interrupts (no longer interested) */ 842 bcmsdh_intr_disable(bus->sdh); 843 844 /* Make sure the controller has the bus up */ 845 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); 846 847 /* Tell device to start using OOB wakeup */ 848 W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries); 849 if (retries > retry_limit) 850 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n")); 851 852 /* Turn off our contribution to the HT clock request */ 853 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); 854 855 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 856 SBSDIO_FORCE_HW_CLKREQ_OFF, NULL); 857 858 /* Isolate the bus */ 859 if (bus->sih->chip != BCM4329_CHIP_ID && bus->sih->chip != BCM4319_CHIP_ID) { 860 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 861 SBSDIO_DEVCTL_PADS_ISO, NULL); 862 } 863 864 /* Change state */ 865 bus->sleeping = TRUE; 866 867 } else { 868 /* Waking up: bus power up is ok, set local state */ 869 870 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 871 0, NULL); 872 873 /* Force pad isolation off if possible (in case power never toggled) */ 874 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL); 875 876 877 /* Make sure the controller has the bus up */ 878 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); 879 880 /* Send misc interrupt to indicate OOB not needed */ 881 W_SDREG(0, ®s->tosbmailboxdata, retries); 882 if (retries <= retry_limit) 883 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries); 884 885 if (retries > retry_limit) 886 DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n")); 887 888 /* Make sure we have SD bus access */ 889 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); 890 891 /* Change state */ 892 bus->sleeping = FALSE; 893 894 /* Enable interrupts again */ 895 if (bus->intr && (bus->dhd->busstate == DHD_BUS_DATA)) { 896 bus->intdis = FALSE; 897 bcmsdh_intr_enable(bus->sdh); 898 } 899 } 900 901 return BCME_OK; 902} 903 904#if defined(OOB_INTR_ONLY) 905void 906dhd_enable_oob_intr(struct dhd_bus *bus, bool enable) 907{ 908#if defined(HW_OOB) 909 bcmsdh_enable_hw_oob_intr(bus->sdh, enable); 910#else 911 sdpcmd_regs_t *regs = bus->regs; 912 uint retries = 0; 913 914 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); 915 if (enable == TRUE) { 916 917 /* Tell device to start using OOB wakeup */ 918 W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries); 919 if (retries > retry_limit) 920 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n")); 921 922 } else { 923 /* Send misc interrupt to indicate OOB not needed */ 924 W_SDREG(0, ®s->tosbmailboxdata, retries); 925 if (retries <= retry_limit) 926 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries); 927 } 928 929 /* Turn off our contribution to the HT clock request */ 930 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); 931#endif /* !defined(HW_OOB) */ 932} 933#endif /* defined(OOB_INTR_ONLY) */ 934 935/* Writes a HW/SW header into the packet and sends it. */ 936/* Assumes: (a) header space already there, (b) caller holds lock */ 937static int 938dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt) 939{ 940 int ret; 941 osl_t *osh; 942 uint8 *frame; 943 uint16 len, pad1 = 0; 944 uint32 swheader; 945 uint retries = 0; 946 bcmsdh_info_t *sdh; 947 void *new; 948 int i; 949#ifdef WLMEDIA_HTSF 950 char *p; 951 htsfts_t *htsf_ts; 952#endif 953 954 955 DHD_TRACE(("%s: Enter\n", __FUNCTION__)); 956 957 sdh = bus->sdh; 958 osh = bus->dhd->osh; 959 960 if (bus->dhd->dongle_reset) { 961 ret = BCME_NOTREADY; 962 goto done; 963 } 964 965 frame = (uint8*)PKTDATA(osh, pkt); 966 967#ifdef WLMEDIA_HTSF 968 if (PKTLEN(osh, pkt) >= 100) { 969 p = PKTDATA(osh, pkt); 970 htsf_ts = (htsfts_t*) (p + HTSF_HOSTOFFSET + 12); 971 if (htsf_ts->magic == HTSFMAGIC) { 972 htsf_ts->c20 = get_cycles(); 973 htsf_ts->t20 = dhd_get_htsf(bus->dhd->info, 0); 974 } 975 } 976#endif /* WLMEDIA_HTSF */ 977 978 /* Add alignment padding, allocate new packet if needed */ 979 if ((pad1 = ((uintptr)frame % DHD_SDALIGN))) { 980 if (PKTHEADROOM(osh, pkt) < pad1) { 981 DHD_INFO(("%s: insufficient headroom %d for %d pad1\n", 982 __FUNCTION__, (int)PKTHEADROOM(osh, pkt), pad1)); 983 bus->dhd->tx_realloc++; 984 new = PKTGET(osh, (PKTLEN(osh, pkt) + DHD_SDALIGN), TRUE); 985 if (!new) { 986 DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n", 987 __FUNCTION__, PKTLEN(osh, pkt) + DHD_SDALIGN)); 988 ret = BCME_NOMEM; 989 goto done; 990 } 991 992 PKTALIGN(osh, new, PKTLEN(osh, pkt), DHD_SDALIGN); 993 bcopy(PKTDATA(osh, pkt), PKTDATA(osh, new), PKTLEN(osh, pkt)); 994 if (free_pkt) 995 PKTFREE(osh, pkt, TRUE); 996 /* free the pkt if canned one is not used */ 997 free_pkt = TRUE; 998 pkt = new; 999 frame = (uint8*)PKTDATA(osh, pkt); 1000 ASSERT(((uintptr)frame % DHD_SDALIGN) == 0); 1001 pad1 = 0; 1002 } else { 1003 PKTPUSH(osh, pkt, pad1); 1004 frame = (uint8*)PKTDATA(osh, pkt); 1005 1006 ASSERT((pad1 + SDPCM_HDRLEN) <= (int) PKTLEN(osh, pkt)); 1007 bzero(frame, pad1 + SDPCM_HDRLEN); 1008 } 1009 } 1010 ASSERT(pad1 < DHD_SDALIGN); 1011 1012 /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */ 1013 len = (uint16)PKTLEN(osh, pkt); 1014 *(uint16*)frame = htol16(len); 1015 *(((uint16*)frame) + 1) = htol16(~len); 1016 1017 /* Software tag: channel, sequence number, data offset */ 1018 swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq | 1019 (((pad1 + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); 1020 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN); 1021 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); 1022 1023#ifdef DHD_DEBUG 1024 if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets)) { 1025 tx_packets[PKTPRIO(pkt)]++; 1026 } 1027 if (DHD_BYTES_ON() && 1028 (((DHD_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) || 1029 (DHD_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) { 1030 prhex("Tx Frame", frame, len); 1031 } else if (DHD_HDRS_ON()) { 1032 prhex("TxHdr", frame, MIN(len, 16)); 1033 } 1034#endif 1035 1036 /* Raise len to next SDIO block to eliminate tail command */ 1037 if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { 1038 uint16 pad2 = bus->blocksize - (len % bus->blocksize); 1039 if ((pad2 <= bus->roundup) && (pad2 < bus->blocksize)) 1040#ifdef NOTUSED 1041 if (pad2 <= PKTTAILROOM(osh, pkt)) 1042#endif /* NOTUSED */ 1043 len += pad2; 1044 } else if (len % DHD_SDALIGN) { 1045 len += DHD_SDALIGN - (len % DHD_SDALIGN); 1046 } 1047 1048 /* Some controllers have trouble with odd bytes -- round to even */ 1049 if (forcealign && (len & (ALIGNMENT - 1))) { 1050#ifdef NOTUSED 1051 if (PKTTAILROOM(osh, pkt)) 1052#endif 1053 len = ROUNDUP(len, ALIGNMENT); 1054#ifdef NOTUSED 1055 else 1056 DHD_ERROR(("%s: sending unrounded %d-byte packet\n", __FUNCTION__, len)); 1057#endif 1058 } 1059 1060 do { 1061 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, 1062 frame, len, pkt, NULL, NULL); 1063 bus->f2txdata++; 1064 ASSERT(ret != BCME_PENDING); 1065 1066 if (ret < 0) { 1067 /* On failure, abort the command and terminate the frame */ 1068 DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n", 1069 __FUNCTION__, ret)); 1070 bus->tx_sderrs++; 1071 1072 bcmsdh_abort(sdh, SDIO_FUNC_2); 1073 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, 1074 SFC_WF_TERM, NULL); 1075 bus->f1regdata++; 1076 1077 for (i = 0; i < 3; i++) { 1078 uint8 hi, lo; 1079 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, 1080 SBSDIO_FUNC1_WFRAMEBCHI, NULL); 1081 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, 1082 SBSDIO_FUNC1_WFRAMEBCLO, NULL); 1083 bus->f1regdata += 2; 1084 if ((hi == 0) && (lo == 0)) 1085 break; 1086 } 1087 1088 } 1089 if (ret == 0) { 1090 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; 1091 } 1092 } while ((ret < 0) && retrydata && retries++ < TXRETRIES); 1093 1094done: 1095 /* restore pkt buffer pointer before calling tx complete routine */ 1096 PKTPULL(osh, pkt, SDPCM_HDRLEN + pad1); 1097#ifdef PROP_TXSTATUS 1098 if (bus->dhd->wlfc_state) { 1099 dhd_os_sdunlock(bus->dhd); 1100 dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0); 1101 dhd_os_sdlock(bus->dhd); 1102 } else { 1103#endif /* PROP_TXSTATUS */ 1104 dhd_txcomplete(bus->dhd, pkt, ret != 0); 1105 if (free_pkt) 1106 PKTFREE(osh, pkt, TRUE); 1107 1108#ifdef PROP_TXSTATUS 1109 } 1110#endif 1111 return ret; 1112} 1113 1114int 1115dhd_bus_txdata(struct dhd_bus *bus, void *pkt) 1116{ 1117 int ret = BCME_ERROR; 1118 osl_t *osh; 1119 uint datalen, prec; 1120 1121 DHD_TRACE(("%s: Enter\n", __FUNCTION__)); 1122 1123 osh = bus->dhd->osh; 1124 datalen = PKTLEN(osh, pkt); 1125 1126#ifdef SDTEST 1127 /* Push the test header if doing loopback */ 1128 if (bus->ext_loop) { 1129 uint8* data; 1130 PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN); 1131 data = PKTDATA(osh, pkt); 1132 *data++ = SDPCM_TEST_ECHOREQ; 1133 *data++ = (uint8)bus->loopid++; 1134 *data++ = (datalen >> 0); 1135 *data++ = (datalen >> 8); 1136 datalen += SDPCM_TEST_HDRLEN; 1137 } 1138#endif /* SDTEST */ 1139 1140 /* Add space for the header */ 1141 PKTPUSH(osh, pkt, SDPCM_HDRLEN); 1142 ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2)); 1143 1144 prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK)); 1145#ifndef DHDTHREAD 1146 /* Lock: we're about to use shared data/code (and SDIO) */ 1147 dhd_os_sdlock(bus->dhd); 1148#endif /* DHDTHREAD */ 1149 1150 /* Check for existing queue, current flow-control, pending event, or pending clock */ 1151 if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched || 1152 (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) || 1153 (bus->clkstate != CLK_AVAIL)) { 1154 DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__, 1155 pktq_len(&bus->txq))); 1156 bus->fcqueued++; 1157 1158 /* Priority based enq */ 1159 dhd_os_sdlock_txq(bus->dhd); 1160 if (dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec) == FALSE) { 1161 PKTPULL(osh, pkt, SDPCM_HDRLEN); 1162#ifndef DHDTHREAD 1163 /* Need to also release txqlock before releasing sdlock. 1164 * This thread still has txqlock and releases sdlock. 1165 * Deadlock happens when dpc() grabs sdlock first then 1166 * attempts to grab txqlock. 1167 */ 1168 dhd_os_sdunlock_txq(bus->dhd); 1169 dhd_os_sdunlock(bus->dhd); 1170#endif 1171#ifdef PROP_TXSTATUS 1172 if (bus->dhd->wlfc_state) 1173 dhd_wlfc_txcomplete(bus->dhd, pkt, FALSE); 1174 else 1175#endif 1176 dhd_txcomplete(bus->dhd, pkt, FALSE); 1177#ifndef DHDTHREAD 1178 dhd_os_sdlock(bus->dhd); 1179 dhd_os_sdlock_txq(bus->dhd); 1180#endif 1181#ifdef PROP_TXSTATUS 1182 /* let the caller decide whether to free the packet */ 1183 if (!bus->dhd->wlfc_state) 1184#endif 1185 PKTFREE(osh, pkt, TRUE); 1186 ret = BCME_NORESOURCE; 1187 } 1188 else 1189 ret = BCME_OK; 1190 dhd_os_sdunlock_txq(bus->dhd); 1191 1192 if ((pktq_len(&bus->txq) >= FCHI) && dhd_doflow) 1193 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON); 1194 1195#ifdef DHD_DEBUG 1196 if (pktq_plen(&bus->txq, prec) > qcount[prec]) 1197 qcount[prec] = pktq_plen(&bus->txq, prec); 1198#endif 1199 /* Schedule DPC if needed to send queued packet(s) */ 1200 if (dhd_deferred_tx && !bus->dpc_sched) { 1201 bus->dpc_sched = TRUE; 1202 dhd_sched_dpc(bus->dhd); 1203 } 1204 } else { 1205#ifdef DHDTHREAD 1206 /* Lock: we're about to use shared data/code (and SDIO) */ 1207 dhd_os_sdlock(bus->dhd); 1208#endif /* DHDTHREAD */ 1209 1210 /* Otherwise, send it now */ 1211 BUS_WAKE(bus); 1212 /* Make sure back plane ht clk is on, no pending allowed */ 1213 dhdsdio_clkctl(bus, CLK_AVAIL, TRUE); 1214#ifndef SDTEST 1215 ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE); 1216#else 1217 ret = dhdsdio_txpkt(bus, pkt, 1218 (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE); 1219#endif 1220 if (ret) 1221 bus->dhd->tx_errors++; 1222 else 1223 bus->dhd->dstats.tx_bytes += datalen; 1224 1225 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { 1226 bus->activity = FALSE; 1227 dhdsdio_clkctl(bus, CLK_NONE, TRUE); 1228 } 1229 1230#ifdef DHDTHREAD 1231 dhd_os_sdunlock(bus->dhd); 1232#endif /* DHDTHREAD */ 1233 } 1234 1235#ifndef DHDTHREAD 1236 dhd_os_sdunlock(bus->dhd); 1237#endif /* DHDTHREAD */ 1238 1239 return ret; 1240} 1241 1242static uint 1243dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes) 1244{ 1245 void *pkt; 1246 uint32 intstatus = 0; 1247 uint retries = 0; 1248 int ret = 0, prec_out; 1249 uint cnt = 0; 1250 uint datalen; 1251 uint8 tx_prec_map; 1252 1253 dhd_pub_t *dhd = bus->dhd; 1254 sdpcmd_regs_t *regs = bus->regs; 1255 1256 DHD_TRACE(("%s: Enter\n", __FUNCTION__)); 1257 1258 tx_prec_map = ~bus->flowcontrol; 1259 1260 /* Send frames until the limit or some other event */ 1261 for (cnt = 0; (cnt < maxframes) && DATAOK(bus); cnt++) { 1262 dhd_os_sdlock_txq(bus->dhd); 1263 if ((pkt = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out)) == NULL) { 1264 dhd_os_sdunlock_txq(bus->dhd); 1265 break; 1266 } 1267 dhd_os_sdunlock_txq(bus->dhd); 1268 datalen = PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN; 1269 1270#ifndef SDTEST 1271 ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE); 1272#else 1273 ret = dhdsdio_txpkt(bus, pkt, 1274 (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE); 1275#endif 1276 if (ret) 1277 bus->dhd->tx_errors++; 1278 else 1279 bus->dhd->dstats.tx_bytes += datalen; 1280 1281 /* In poll mode, need to check for other events */ 1282 if (!bus->intr && cnt) 1283 { 1284 /* Check device status, signal pending interrupt */ 1285 R_SDREG(intstatus, ®s->intstatus, retries); 1286 bus->f2txdata++; 1287 if (bcmsdh_regfail(bus->sdh)) 1288 break; 1289 if (intstatus & bus->hostintmask) 1290 bus->ipend = TRUE; 1291 } 1292 } 1293 1294 /* Deflow-control stack if needed */ 1295 if (dhd_doflow && dhd->up && (dhd->busstate == DHD_BUS_DATA) && 1296 dhd->txoff && (pktq_len(&bus->txq) < FCLOW)) 1297 dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF); 1298 1299 return cnt; 1300} 1301 1302int 1303dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) 1304{ 1305 uint8 *frame; 1306 uint16 len; 1307 uint32 swheader; 1308 uint retries = 0; 1309 bcmsdh_info_t *sdh = bus->sdh; 1310 uint8 doff = 0; 1311 int ret = -1; 1312 int i; 1313 1314 DHD_TRACE(("%s: Enter\n", __FUNCTION__)); 1315 1316 if (bus->dhd->dongle_reset) 1317 return -EIO; 1318 1319 /* Back the pointer to make a room for bus header */ 1320 frame = msg - SDPCM_HDRLEN; 1321 len = (msglen += SDPCM_HDRLEN); 1322 1323 /* Add alignment padding (optional for ctl frames) */ 1324 if (dhd_alignctl) { 1325 if ((doff = ((uintptr)frame % DHD_SDALIGN))) { 1326 frame -= doff; 1327 len += doff; 1328 msglen += doff; 1329 bzero(frame, doff + SDPCM_HDRLEN); 1330 } 1331 ASSERT(doff < DHD_SDALIGN); 1332 } 1333 doff += SDPCM_HDRLEN; 1334 1335 /* Round send length to next SDIO block */ 1336 if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { 1337 uint16 pad = bus->blocksize - (len % bus->blocksize); 1338 if ((pad <= bus->roundup) && (pad < bus->blocksize)) 1339 len += pad; 1340 } else if (len % DHD_SDALIGN) { 1341 len += DHD_SDALIGN - (len % DHD_SDALIGN); 1342 } 1343 1344 /* Satisfy length-alignment requirements */ 1345 if (forcealign && (len & (ALIGNMENT - 1))) 1346 len = ROUNDUP(len, ALIGNMENT); 1347 1348 ASSERT(ISALIGNED((uintptr)frame, 2)); 1349 1350 1351 /* Need to lock here to protect txseq and SDIO tx calls */ 1352 dhd_os_sdlock(bus->dhd); 1353 1354 BUS_WAKE(bus); 1355 1356 /* Make sure backplane clock is on */ 1357 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); 1358 1359 /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */ 1360 *(uint16*)frame = htol16((uint16)msglen); 1361 *(((uint16*)frame) + 1) = htol16(~msglen); 1362 1363 /* Software tag: channel, sequence number, data offset */ 1364 swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) 1365 | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); 1366 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN); 1367 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); 1368 1369 if (!TXCTLOK(bus)) { 1370 DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n", 1371 __FUNCTION__, bus->tx_max, bus->tx_seq)); 1372 bus->ctrl_frame_stat = TRUE; 1373 /* Send from dpc */ 1374 bus->ctrl_frame_buf = frame; 1375 bus->ctrl_frame_len = len; 1376 dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat); 1377 if (bus->ctrl_frame_stat == FALSE) { 1378 DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__)); 1379 ret = 0; 1380 } else { 1381 bus->dhd->txcnt_timeout++; 1382 if (!bus->dhd->hang_was_sent) 1383 DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n", 1384 __FUNCTION__, bus->dhd->txcnt_timeout)); 1385 ret = -1; 1386 bus->ctrl_frame_stat = FALSE; 1387 goto done; 1388 } 1389 } 1390 1391 bus->dhd->txcnt_timeout = 0; 1392 1393 if (ret == -1) { 1394#ifdef DHD_DEBUG 1395 if (DHD_BYTES_ON() && DHD_CTL_ON()) { 1396 prhex("Tx Frame", frame, len); 1397 } else if (DHD_HDRS_ON()) { 1398 prhex("TxHdr", frame, MIN(len, 16)); 1399 } 1400#endif 1401 1402 do { 1403 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, 1404 frame, len, NULL, NULL, NULL); 1405 ASSERT(ret != BCME_PENDING); 1406 1407 if (ret < 0) { 1408 /* On failure, abort the command and terminate the frame */ 1409 DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n", 1410 __FUNCTION__, ret)); 1411 bus->tx_sderrs++; 1412 1413 bcmsdh_abort(sdh, SDIO_FUNC_2); 1414 1415 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, 1416 SFC_WF_TERM, NULL); 1417 bus->f1regdata++; 1418 1419 for (i = 0; i < 3; i++) { 1420 uint8 hi, lo; 1421 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, 1422 SBSDIO_FUNC1_WFRAMEBCHI, NULL); 1423 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, 1424 SBSDIO_FUNC1_WFRAMEBCLO, NULL); 1425 bus->f1regdata += 2; 1426 if ((hi == 0) && (lo == 0)) 1427 break; 1428 } 1429 1430 } 1431 if (ret == 0) { 1432 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; 1433 } 1434 } while ((ret < 0) && retries++ < TXRETRIES); 1435 } 1436 1437done: 1438 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { 1439 bus->activity = FALSE; 1440 dhdsdio_clkctl(bus, CLK_NONE, TRUE); 1441 } 1442 1443 dhd_os_sdunlock(bus->dhd); 1444 1445 if (ret) 1446 bus->dhd->tx_ctlerrs++; 1447 else 1448 bus->dhd->tx_ctlpkts++; 1449 1450 if (bus->dhd->txcnt_timeout >= MAX_CNTL_TIMEOUT) 1451 return -ETIMEDOUT; 1452 1453 return ret ? -EIO : 0; 1454} 1455 1456int 1457dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) 1458{ 1459 int timeleft; 1460 uint rxlen = 0; 1461 bool pending = FALSE; 1462 1463 DHD_TRACE(("%s: Enter\n", __FUNCTION__)); 1464 1465 if (bus->dhd->dongle_reset) 1466 return -EIO; 1467 1468 /* Wait until control frame is available */ 1469 timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, &pending); 1470 1471 dhd_os_sdlock(bus->dhd); 1472 rxlen = bus->rxlen; 1473 bcopy(bus->rxctl, msg, MIN(msglen, rxlen)); 1474 bus->rxlen = 0; 1475 dhd_os_sdunlock(bus->dhd); 1476 1477 if (rxlen) { 1478 DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n", 1479 __FUNCTION__, rxlen, msglen)); 1480 } else if (timeleft == 0) { 1481 DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__)); 1482#ifdef DHD_DEBUG 1483 dhd_os_sdlock(bus->dhd); 1484 dhdsdio_checkdied(bus, NULL, 0); 1485 dhd_os_sdunlock(bus->dhd); 1486#endif /* DHD_DEBUG */ 1487 } else if (pending == TRUE) { 1488 /* signal pending */ 1489 DHD_ERROR(("%s: signal pending\n", __FUNCTION__)); 1490 return -EINTR; 1491 } else { 1492 DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__)); 1493#ifdef DHD_DEBUG 1494 dhd_os_sdlock(bus->dhd); 1495 dhdsdio_checkdied(bus, NULL, 0); 1496 dhd_os_sdunlock(bus->dhd); 1497#endif /* DHD_DEBUG */ 1498 } 1499 if (timeleft == 0) { 1500 bus->dhd->rxcnt_timeout++; 1501 DHD_ERROR(("%s: rxcnt_timeout=%d\n", __FUNCTION__, bus->dhd->rxcnt_timeout)); 1502 } 1503 else 1504 bus->dhd->rxcnt_timeout = 0; 1505 1506 if (rxlen) 1507 bus->dhd->rx_ctlpkts++; 1508 else 1509 bus->dhd->rx_ctlerrs++; 1510 1511 if (bus->dhd->rxcnt_timeout >= MAX_CNTL_TIMEOUT) 1512 return -ETIMEDOUT; 1513 1514 return rxlen ? (int)rxlen : -EIO; 1515} 1516 1517/* IOVar table */ 1518enum { 1519 IOV_INTR = 1, 1520 IOV_POLLRATE, 1521 IOV_SDREG, 1522 IOV_SBREG, 1523 IOV_SDCIS, 1524 IOV_MEMBYTES, 1525 IOV_MEMSIZE, 1526#ifdef DHD_DEBUG 1527 IOV_CHECKDIED, 1528 IOV_SERIALCONS, 1529#endif /* DHD_DEBUG */ 1530 IOV_DOWNLOAD, 1531 IOV_SOCRAM_STATE, 1532 IOV_FORCEEVEN, 1533 IOV_SDIOD_DRIVE, 1534 IOV_READAHEAD, 1535 IOV_SDRXCHAIN, 1536 IOV_ALIGNCTL, 1537 IOV_SDALIGN, 1538 IOV_DEVRESET, 1539 IOV_CPU, 1540#ifdef SDTEST 1541 IOV_PKTGEN, 1542 IOV_EXTLOOP, 1543#endif /* SDTEST */ 1544 IOV_SPROM, 1545 IOV_TXBOUND, 1546 IOV_RXBOUND, 1547 IOV_TXMINMAX, 1548 IOV_IDLETIME, 1549 IOV_IDLECLOCK, 1550 IOV_SD1IDLE, 1551 IOV_SLEEP, 1552 IOV_DONGLEISOLATION, 1553 IOV_VARS, 1554#ifdef SOFTAP 1555 IOV_FWPATH 1556#endif 1557}; 1558 1559const bcm_iovar_t dhdsdio_iovars[] = { 1560 {"intr", IOV_INTR, 0, IOVT_BOOL, 0 }, 1561 {"sleep", IOV_SLEEP, 0, IOVT_BOOL, 0 }, 1562 {"pollrate", IOV_POLLRATE, 0, IOVT_UINT32, 0 }, 1563 {"idletime", IOV_IDLETIME, 0, IOVT_INT32, 0 }, 1564 {"idleclock", IOV_IDLECLOCK, 0, IOVT_INT32, 0 }, 1565 {"sd1idle", IOV_SD1IDLE, 0, IOVT_BOOL, 0 }, 1566 {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) }, 1567 {"memsize", IOV_MEMSIZE, 0, IOVT_UINT32, 0 }, 1568 {"download", IOV_DOWNLOAD, 0, IOVT_BOOL, 0 }, 1569 {"socram_state", IOV_SOCRAM_STATE, 0, IOVT_BOOL, 0 }, 1570 {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 }, 1571 {"sdiod_drive", IOV_SDIOD_DRIVE, 0, IOVT_UINT32, 0 }, 1572 {"readahead", IOV_READAHEAD, 0, IOVT_BOOL, 0 }, 1573 {"sdrxchain", IOV_SDRXCHAIN, 0, IOVT_BOOL, 0 }, 1574 {"alignctl", IOV_ALIGNCTL, 0, IOVT_BOOL, 0 }, 1575 {"sdalign", IOV_SDALIGN, 0, IOVT_BOOL, 0 }, 1576 {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0 }, 1577#ifdef DHD_DEBUG 1578 {"sdreg", IOV_SDREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, 1579 {"sbreg", IOV_SBREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, 1580 {"sd_cis", IOV_SDCIS, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN }, 1581 {"forcealign", IOV_FORCEEVEN, 0, IOVT_BOOL, 0 }, 1582 {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0 }, 1583 {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 }, 1584 {"txminmax", IOV_TXMINMAX, 0, IOVT_UINT32, 0 }, 1585 {"cpu", IOV_CPU, 0, IOVT_BOOL, 0 }, 1586#ifdef DHD_DEBUG 1587 {"checkdied", IOV_CHECKDIED, 0, IOVT_BUFFER, 0 }, 1588 {"serial", IOV_SERIALCONS, 0, IOVT_UINT32, 0 }, 1589#endif /* DHD_DEBUG */ 1590#endif /* DHD_DEBUG */ 1591#ifdef SDTEST 1592 {"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0 }, 1593 {"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) }, 1594#endif /* SDTEST */ 1595 {"dngl_isolation", IOV_DONGLEISOLATION, 0, IOVT_UINT32, 0 }, 1596#ifdef SOFTAP 1597 {"fwpath", IOV_FWPATH, 0, IOVT_BUFFER, 0 }, 1598#endif 1599 {NULL, 0, 0, 0, 0 } 1600}; 1601 1602static void 1603dhd_dump_pct(struct bcmstrbuf *strbuf, char *desc, uint num, uint div) 1604{ 1605 uint q1, q2; 1606 1607 if (!div) { 1608 bcm_bprintf(strbuf, "%s N/A", desc); 1609 } else { 1610 q1 = num / div; 1611 q2 = (100 * (num - (q1 * div))) / div; 1612 bcm_bprintf(strbuf, "%s %d.%02d", desc, q1, q2); 1613 } 1614} 1615 1616void 1617dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) 1618{ 1619 dhd_bus_t *bus = dhdp->bus; 1620 1621 bcm_bprintf(strbuf, "Bus SDIO structure:\n"); 1622 bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n", 1623 bus->hostintmask, bus->intstatus, bus->sdpcm_ver); 1624 bcm_bprintf(strbuf, "fcstate %d qlen %d tx_seq %d, max %d, rxskip %d rxlen %d rx_seq %d\n", 1625 bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip, 1626 bus->rxlen, bus->rx_seq); 1627 bcm_bprintf(strbuf, "intr %d intrcount %d lastintrs %d spurious %d\n", 1628 bus->intr, bus->intrcount, bus->lastintrs, bus->spurious); 1629 bcm_bprintf(strbuf, "pollrate %d pollcnt %d regfails %d\n", 1630 bus->pollrate, bus->pollcnt, bus->regfails); 1631 1632 bcm_bprintf(strbuf, "\nAdditional counters:\n"); 1633 bcm_bprintf(strbuf, "tx_sderrs %d fcqueued %d rxrtx %d rx_toolong %d rxc_errors %d\n", 1634 bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong, 1635 bus->rxc_errors); 1636 bcm_bprintf(strbuf, "rx_hdrfail %d badhdr %d badseq %d\n", 1637 bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq); 1638 bcm_bprintf(strbuf, "fc_rcvd %d, fc_xoff %d, fc_xon %d\n", 1639 bus->fc_rcvd, bus->fc_xoff, bus->fc_xon); 1640 bcm_bprintf(strbuf, "rxglomfail %d, rxglomframes %d, rxglompkts %d\n", 1641 bus->rxglomfail, bus->rxglomframes, bus->rxglompkts); 1642 bcm_bprintf(strbuf, "f2rx (hdrs/data) %d (%d/%d), f2tx %d f1regs %d\n", 1643 (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata, 1644 bus->f2txdata, bus->f1regdata); 1645 { 1646 dhd_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->dhd->rx_packets, 1647 (bus->f2rxhdrs + bus->f2rxdata)); 1648 dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->rx_packets, bus->f1regdata); 1649 dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->rx_packets, 1650 (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata)); 1651 dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->rx_packets, bus->intrcount); 1652 bcm_bprintf(strbuf, "\n"); 1653 1654 dhd_dump_pct(strbuf, "Rx: glom pct", (100 …
Large files files are truncated, but you can click here to view the full file