aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/bcmdhd/dhd_sdio.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/bcmdhd/dhd_sdio.c')
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_sdio.c1407
1 files changed, 1104 insertions, 303 deletions
diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c
index 422ad034f5e..138e8e5d0f0 100644
--- a/drivers/net/wireless/bcmdhd/dhd_sdio.c
+++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: dhd_sdio.c 357859 2012-09-20 06:34:26Z $
+ * $Id: dhd_sdio.c 394690 2013-04-03 09:18:44Z $
*/
#include <typedefs.h>
@@ -79,10 +79,13 @@
#define PRIOMASK 7
#define TXRETRIES 2 /* # of retries for tx frames */
-
+#ifndef DHD_RXBOUND
#define DHD_RXBOUND 50 /* Default for max rx frames in one scheduling */
+#endif
+#ifndef DHD_TXBOUND
#define DHD_TXBOUND 20 /* Default for max tx frames in one scheduling */
+#endif
#define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */
@@ -155,7 +158,9 @@ extern void bcmsdh_set_irq(int flag);
#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
#ifdef PROP_TXSTATUS
extern void dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success);
+extern void dhd_wlfc_trigger_pktcommit(dhd_pub_t *dhd);
#endif
+
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
DEFINE_MUTEX(_dhd_sdio_mutex_lock_);
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
@@ -183,14 +188,16 @@ typedef struct dhd_console {
#define MIN_RSRC_SR 0x3
#define CORE_CAPEXT_ADDR (SI_ENUM_BASE + 0x64c)
#define CORE_CAPEXT_SR_SUPPORTED_MASK (1 << 1)
-#define RCTL_MACPHY_DISABLE_MASK (1 << 26)
-#define RCTL_LOGIC_DISABLE_MASK (1 << 27)
+#define RCTL_MACPHY_DISABLE_MASK (1 << 26)
+#define RCTL_LOGIC_DISABLE_MASK (1 << 27)
#define OOB_WAKEUP_ENAB(bus) ((bus)->_oobwakeup)
#define GPIO_DEV_SRSTATE 16 /* Host gpio17 mapped to device gpio0 SR state */
#define GPIO_DEV_SRSTATE_TIMEOUT 320000 /* 320ms */
#define GPIO_DEV_WAKEUP 17 /* Host gpio17 mapped to device gpio1 wakeup */
#define CC_CHIPCTRL2_GPIO1_WAKEUP (1 << 0)
+#define OVERFLOW_BLKSZ512_WM 48
+#define OVERFLOW_BLKSZ512_MES 80
#define CC_PMUCC3 (0x3)
/* Private data for SDIO bus interaction */
@@ -304,6 +311,13 @@ typedef struct dhd_bus {
uint pktgen_ptick; /* Burst counter for printing */
uint pktgen_sent; /* Number of test packets generated */
uint pktgen_rcvd; /* Number of test packets received */
+ uint pktgen_prev_time; /* Time at which previous stats where printed */
+ uint pktgen_prev_sent; /* Number of test packets generated when
+ * previous stats were printed
+ */
+ uint pktgen_prev_rcvd; /* Number of test packets received when
+ * previous stats were printed
+ */
uint pktgen_fail; /* Number of failed send attempts */
uint16 pktgen_len; /* Length of next packet to send */
#define PKTGEN_RCV_IDLE (0)
@@ -391,7 +405,11 @@ uint dhd_txminmax = DHD_TXMINMAX;
#define DONGLE_MIN_MEMSIZE (128 *1024)
int dhd_dongle_memsize;
+#ifndef REPEAT_READFRAME
static bool dhd_doflow;
+#else
+extern bool dhd_doflow;
+#endif /* REPEAT_READFRAME */
static bool dhd_alignctl;
static bool sd1idle;
@@ -399,13 +417,17 @@ static bool sd1idle;
static bool retrydata;
#define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata)
-#if defined(SDIO_CRC_ERROR_FIX)
+#ifdef BCMSPI
+/* At a watermark around 8 the spid hits underflow error. */
+static const uint watermark = 32;
+static const uint mesbusyctrl = 0;
+#elif defined(SDIO_CRC_ERROR_FIX)
static uint watermark = 48;
static uint mesbusyctrl = 80;
#else
static const uint watermark = 8;
static const uint mesbusyctrl = 0;
-#endif
+#endif /* BCMSPI */
static const uint firstread = DHD_FIRSTREAD;
#define HDATLEN (firstread - (SDPCM_HDRLEN))
@@ -443,7 +465,6 @@ static const uint max_roundup = 512;
/* Try doing readahead */
static bool dhd_readahead;
-
/* To check if there's window offered */
#define DATAOK(bus) \
(((uint8)(bus->tx_max - bus->tx_seq) > 1) && \
@@ -538,7 +559,7 @@ do { \
\
R_SDREG(intstatuserr, &bus->regs->intstatus, retries); \
printf("dstatussw = 0x%x, dstatushw = 0x%x, intstatus = 0x%x\n", \
- dstatussw, dstatushw, intstatuserr); \
+ dstatussw, dstatushw, intstatuserr); \
\
bus->nextlen = 0; \
*finished = TRUE; \
@@ -561,7 +582,7 @@ do { \
#ifdef SDTEST
static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq);
-static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint8 count);
+static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint count);
#endif
#ifdef DHD_DEBUG
@@ -591,7 +612,7 @@ 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, void *handle);
#ifdef BCMSDIOH_TXGLOM
-static void dhd_bcmsdh_glom_post(dhd_bus_t *bus, uint8 *frame, uint len);
+static void dhd_bcmsdh_glom_post(dhd_bus_t *bus, uint8 *frame, void *pkt, uint len);
static void dhd_bcmsdh_glom_clear(dhd_bus_t *bus);
#endif
@@ -613,6 +634,39 @@ extern uint32 dhd_get_htsf(void *dhd, int ifidx);
#endif /* WLMEDIA_HTSF */
static void
+dhd_overflow_war(struct dhd_bus *bus)
+{
+ int err;
+ uint8 devctl, wm, mes;
+
+ /* See .ppt in PR for these recommended values */
+ if (bus->blocksize == 512) {
+ wm = OVERFLOW_BLKSZ512_WM;
+ mes = OVERFLOW_BLKSZ512_MES;
+ } else {
+ mes = bus->blocksize/4;
+ wm = bus->blocksize/4;
+ }
+
+
+ /* Update watermark */
+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, wm, &err);
+
+ devctl = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
+ devctl |= SBSDIO_DEVCTL_F2WM_ENAB;
+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
+
+ /* Update MES */
+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
+ (mes | SBSDIO_MESBUSYCTRL_ENAB), &err);
+
+ DHD_INFO(("Apply overflow WAR: 0x%02x 0x%02x 0x%02x\n",
+ bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err),
+ bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, &err),
+ bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, &err)));
+}
+
+static void
dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size)
{
int32 min_size = DONGLE_MIN_MEMSIZE;
@@ -693,7 +747,7 @@ static bool
dhdsdio_sr_cap(dhd_bus_t *bus)
{
bool cap = FALSE;
- uint32 min = 0, core_capext, addr, data;
+ uint32 core_capext, addr, data;
if (bus->sih->chip == BCM4324_CHIP_ID) {
addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
@@ -712,9 +766,7 @@ dhdsdio_sr_cap(dhd_bus_t *bus)
if (bus->sih->chip == BCM4324_CHIP_ID) {
/* FIX: Should change to query SR control register instead */
- min = bcmsdh_reg_read(bus->sdh, MIN_RSRC_ADDR, 4);
- if (min == MIN_RSRC_SR)
- cap = TRUE;
+ cap = TRUE;
} else if (bus->sih->chip == BCM4335_CHIP_ID) {
uint32 enabval = 0;
addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
@@ -807,7 +859,12 @@ dhdsdio_clk_kso_init(dhd_bus_t *bus)
}
#define KSO_DBG(x)
+#define KSO_WAIT_US 50
+#if defined(CUSTOMER_HW4)
#define MAX_KSO_ATTEMPTS 64
+#else
+#define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US)
+#endif /* CUSTOMER_HW4 */
static int
dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on)
{
@@ -826,9 +883,8 @@ dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on)
bmask = cmp_val;
msleep(3);
-
} else {
- /* Put device to sleep, turn off KSO */
+ /* Put device to sleep, turn off KSO */
cmp_val = 0;
bmask = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK;
}
@@ -839,17 +895,15 @@ dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on)
break;
KSO_DBG(("%s> KSO wr/rd retry:%d, ERR:%x \n", __FUNCTION__, try_cnt, err));
- OSL_DELAY(50);
+ OSL_DELAY(KSO_WAIT_US);
bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err);
-
} while (try_cnt++ < MAX_KSO_ATTEMPTS);
- if (try_cnt > 1) {
+ if (try_cnt > 2)
KSO_DBG(("%s> op:%s, try_cnt:%d, rd_val:%x, ERR:%x \n",
__FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err));
- }
if (try_cnt > MAX_KSO_ATTEMPTS) {
DHD_ERROR(("%s> op:%s, ERROR: try_cnt:%d, rd_val:%x, ERR:%x \n",
@@ -1061,6 +1115,8 @@ dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on)
bus->kso = on ? FALSE : TRUE;
else {
DHD_ERROR(("%s: Sleep request failed: on:%d err:%d\n", __FUNCTION__, on, err));
+ if (!on && retry > 2)
+ bus->kso = TRUE;
}
return err;
@@ -1078,9 +1134,6 @@ dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok)
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
-#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
- pendok = FALSE;
-#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
clkctl = 0;
sdh = bus->sdh;
@@ -1119,12 +1172,6 @@ dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok)
ht_avail_error = 0;
}
- if (pendok &&
- ((bus->sih->buscoretype == PCMCIA_CORE_ID) && (bus->sih->buscorerev == 9))) {
- uint32 dummy, retries;
- R_SDREG(dummy, &bus->regs->clockctlstatus, retries);
- BCM_REFERENCE(dummy);
- }
/* Check current status */
clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
@@ -1133,6 +1180,7 @@ dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok)
return BCME_ERROR;
}
+#if !defined(OOB_INTR_ONLY)
/* Go to pending and await interrupt if appropriate */
if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
/* Allow only clock-available interrupt */
@@ -1148,11 +1196,15 @@ dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok)
DHD_INFO(("CLKCTL: set PENDING\n"));
bus->clkstate = CLK_PENDING;
return BCME_OK;
- } else if (bus->clkstate == CLK_PENDING) {
- /* Cancel CA-only interrupt filter */
- devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
- devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
- bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
+ } else
+#endif /* !defined (OOB_INTR_ONLY) */
+ {
+ if (bus->clkstate == CLK_PENDING) {
+ /* Cancel CA-only interrupt filter */
+ devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
+ devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
+ }
}
/* Otherwise, wait here (polling) for HT Avail */
@@ -1196,6 +1248,7 @@ dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok)
#endif /* DHD_USE_IDLECOUNT */
} else {
clkreq = 0;
+
if (bus->clkstate == CLK_PENDING) {
/* Cancel CA-only interrupt filter */
devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
@@ -1484,16 +1537,15 @@ dhdsdio_bussleep(dhd_bus_t *bus, bool sleep)
return err;
}
-#if defined(CUSTOMER_HW4) && defined(DYNAMIC_F2_BLKSIZE_OF_PROPTXSTATUS)
-int
-dhdsdio_func_blocksize(dhd_pub_t *dhd, int function_num, int block_size)
+#if defined(CUSTOMER_HW4) && defined(USE_DYNAMIC_F2_BLKSIZE)
+int dhdsdio_func_blocksize(dhd_pub_t *dhd, int function_num, int block_size)
{
int func_blk_size = function_num;
int bcmerr = 0;
int result;
- bcmerr = dhd_bus_iovar_op(dhd, "sd_blocksize", &func_blk_size, sizeof(int), &result,
- sizeof(int), 0);
+ bcmerr = dhd_bus_iovar_op(dhd, "sd_blocksize", &func_blk_size,
+ sizeof(int), &result, sizeof(int), IOV_GET);
if (bcmerr != BCME_OK) {
DHD_ERROR(("%s: Get F%d Block size error\n", __FUNCTION__, function_num));
@@ -1501,14 +1553,11 @@ dhdsdio_func_blocksize(dhd_pub_t *dhd, int function_num, int block_size)
}
if (result != block_size) {
-
- DHD_ERROR(("%s: F%d Block size set from %d to %d\n", __FUNCTION__,
- function_num, result, block_size));
-
+ DHD_TRACE_HW4(("%s: F%d Block size set from %d to %d\n",
+ __FUNCTION__, function_num, result, block_size));
func_blk_size = function_num << 16 | block_size;
- bcmerr = dhd_bus_iovar_op(dhd, "sd_blocksize", &func_blk_size, sizeof(int32),
- &result, sizeof(int32), 1);
-
+ bcmerr = dhd_bus_iovar_op(dhd, "sd_blocksize", NULL,
+ 0, &func_blk_size, sizeof(int32), IOV_SET);
if (bcmerr != BCME_OK) {
DHD_ERROR(("%s: Set F2 Block size error\n", __FUNCTION__));
return BCME_ERROR;
@@ -1516,9 +1565,8 @@ dhdsdio_func_blocksize(dhd_pub_t *dhd, int function_num, int block_size)
}
return BCME_OK;
-
}
-#endif /* CUSTOMER_HW4 && DYNAMIC_F2_BLKSIZE_OF_PROPTXSTATUS */
+#endif /* CUSTOMER_HW4 && USE_DYNAMIC_F2_BLKSIZE */
#if defined(OOB_INTR_ONLY)
void
@@ -1551,6 +1599,236 @@ dhd_enable_oob_intr(struct dhd_bus *bus, bool enable)
}
#endif /* defined(OOB_INTR_ONLY) */
+
+#ifdef DHDTCPACK_SUPPRESS
+extern bool dhd_use_tcpack_suppress;
+
+/* Please be sure this function is called under dhd_os_tcpacklock() */
+void dhd_onoff_tcpack_sup(void *pub, bool on)
+{
+ dhd_pub_t *dhdp = (dhd_pub_t *)pub;
+
+ if (dhd_use_tcpack_suppress != on) {
+
+ DHD_ERROR(("dhd_onoff_tcpack_sup: %d -> %d\n", dhd_use_tcpack_suppress, on));
+ dhd_use_tcpack_suppress = on;
+ dhdp->tcp_ack_info_cnt = 0;
+ bzero(dhdp->tcp_ack_info_tbl, sizeof(struct tcp_ack_info)*MAXTCPSTREAMS);
+
+ } else
+ DHD_ERROR(("dhd_onoff_tcpack_sup: alread %d\n", on));
+
+ return;
+}
+
+inline void dhd_tcpack_check_xmit(dhd_pub_t *dhdp, void *pkt)
+{
+ uint8 i;
+ tcp_ack_info_t *tcp_ack_info = NULL;
+ int tbl_cnt;
+
+ dhd_os_tcpacklock(dhdp);
+ tbl_cnt = dhdp->tcp_ack_info_cnt;
+ for (i = 0; i < tbl_cnt; i++) {
+ tcp_ack_info = &dhdp->tcp_ack_info_tbl[i];
+ if (tcp_ack_info->p_tcpackinqueue == pkt) {
+ /* This pkt is being transmitted so remove the tcp_ack_info of it.
+ * compact the array unless the last element,
+ * then the pkt's array is removed.
+ */
+ if (i < tbl_cnt-1) {
+ memmove(&dhdp->tcp_ack_info_tbl[i],
+ &dhdp->tcp_ack_info_tbl[i+1],
+ sizeof(struct tcp_ack_info)*(tbl_cnt - (i+1)));
+ }
+ bzero(&dhdp->tcp_ack_info_tbl[tbl_cnt-1], sizeof(struct tcp_ack_info));
+ if (--dhdp->tcp_ack_info_cnt < 0) {
+ DHD_ERROR(("dhdsdio_sendfromq:(ERROR) tcp_ack_info_cnt %d"
+ " Stop using tcpack_suppress\n", dhdp->tcp_ack_info_cnt));
+ dhd_onoff_tcpack_sup(dhdp, FALSE);
+ }
+ break;
+ }
+ }
+ dhd_os_tcpackunlock(dhdp);
+}
+
+bool
+dhd_tcpack_suppress(dhd_pub_t *dhdp, void *pkt)
+{
+ uint8 *eh_header;
+ uint16 eh_type;
+ uint8 *ip_header;
+ uint8 *tcp_header;
+ uint32 ip_hdr_len;
+ uint32 cur_framelen;
+ uint8 bdc_hdr_len = BDC_HEADER_LEN;
+ uint8 wlfc_hdr_len = 0;
+ uint8 *data = PKTDATA(dhdp->osh, pkt);
+ cur_framelen = PKTLEN(dhdp->osh, pkt);
+
+#ifdef PROP_TXSTATUS
+ /* In this case, BDC header is not pushed in dhd_sendpkt() */
+ if (dhdp->wlfc_state) {
+ bdc_hdr_len = 0;
+ wlfc_hdr_len = 8;
+ }
+#endif
+ if (cur_framelen < bdc_hdr_len + ETHER_HDR_LEN) {
+ DHD_TRACE(("dhd_tcpack_suppress: Too short packet length %d\n", cur_framelen));
+ return FALSE;
+ }
+
+ /* Get rid of BDC header */
+ eh_header = data + bdc_hdr_len;
+ cur_framelen -= bdc_hdr_len;
+ eh_type = eh_header[12] << 8 | eh_header[13];
+
+ if (eh_type != ETHER_TYPE_IP) {
+ DHD_TRACE(("dhd_tcpack_suppress: Not a IP packet 0x%x\n", eh_type));
+ return FALSE;
+ }
+
+ DHD_TRACE(("dhd_tcpack_suppress: IP pkt! 0x%x\n", eh_type));
+
+ ip_header = eh_header + ETHER_HDR_LEN;
+ cur_framelen -= ETHER_HDR_LEN;
+ ip_hdr_len = 4 * (ip_header[0] & 0x0f);
+
+ if ((ip_header[0] & 0xf0) != 0x40) {
+ DHD_TRACE(("dhd_tcpack_suppress: Not IPv4!\n"));
+ return FALSE;
+ }
+
+ if (cur_framelen < ip_hdr_len) {
+ DHD_ERROR(("dhd_tcpack_suppress: IP packet length %d wrong!\n", cur_framelen));
+ return FALSE;
+ }
+
+ /* not tcp */
+ if (ip_header[9] != 0x06) {
+ DHD_TRACE(("dhd_tcpack_suppress: Not a TCP packet 0x%x\n", ip_header[9]));
+ return FALSE;
+ }
+
+ DHD_TRACE(("dhd_tcpack_suppress: TCP pkt!\n"));
+
+ tcp_header = ip_header + ip_hdr_len;
+
+ /* is it an ack ? */
+ if (tcp_header[13] == 0x10) {
+#if defined(DHD_DEBUG)
+ uint32 tcp_seq_num = tcp_header[4] << 24 | tcp_header[5] << 16 |
+ tcp_header[6] << 8 | tcp_header[7];
+#endif
+ uint32 tcp_ack_num = tcp_header[8] << 24 | tcp_header[9] << 16 |
+ tcp_header[10] << 8 | tcp_header[11];
+ uint16 ip_tcp_ttllen = (ip_header[3] & 0xff) + (ip_header[2] << 8);
+ uint32 tcp_hdr_len = 4*((tcp_header[12] & 0xf0) >> 4);
+ DHD_TRACE(("dhd_tcpack_suppress: TCP ACK seq %ud ack %ud\n",
+ tcp_seq_num, tcp_ack_num));
+
+
+ /* zero length ? */
+ if (ip_tcp_ttllen == ip_hdr_len + tcp_hdr_len) {
+ int i;
+ tcp_ack_info_t *tcp_ack_info = NULL;
+ DHD_TRACE(("dhd_tcpack_suppress: TCP ACK zero length\n"));
+ /* Look for tcp_ack_info that has the same
+ * ip src/dst addrs and tcp src/dst ports
+ */
+ dhd_os_tcpacklock(dhdp);
+ for (i = 0; i < dhdp->tcp_ack_info_cnt; i++) {
+ if (dhdp->tcp_ack_info_tbl[i].p_tcpackinqueue &&
+ !memcmp(&ip_header[12], dhdp->tcp_ack_info_tbl[i].ipaddrs, 8) &&
+ !memcmp(tcp_header, dhdp->tcp_ack_info_tbl[i].tcpports, 4)) {
+ tcp_ack_info = &dhdp->tcp_ack_info_tbl[i];
+ break;
+ }
+ }
+
+ if (i == dhdp->tcp_ack_info_cnt && i < MAXTCPSTREAMS)
+ tcp_ack_info = &dhdp->tcp_ack_info_tbl[dhdp->tcp_ack_info_cnt++];
+
+ if (!tcp_ack_info) {
+ DHD_TRACE(("dhd_tcpack_suppress: No empty tcp ack info"
+ "%d %d %d %d, %d %d %d %d\n",
+ tcp_header[0], tcp_header[1], tcp_header[2], tcp_header[3],
+ dhdp->tcp_ack_info_tbl[i].tcpports[0],
+ dhdp->tcp_ack_info_tbl[i].tcpports[1],
+ dhdp->tcp_ack_info_tbl[i].tcpports[2],
+ dhdp->tcp_ack_info_tbl[i].tcpports[3]));
+ dhd_os_tcpackunlock(dhdp);
+ return FALSE;
+ }
+
+ if (tcp_ack_info->p_tcpackinqueue) {
+ if (tcp_ack_num > tcp_ack_info->tcpack_number) {
+ void *prevpkt = tcp_ack_info->p_tcpackinqueue;
+ uint8 pushed_len = SDPCM_HDRLEN +
+ (BDC_HEADER_LEN - bdc_hdr_len) + wlfc_hdr_len;
+#ifdef PROP_TXSTATUS
+ /* In case the prev pkt is delayenqueued
+ * but not delayedequeued yet, it may not have
+ * any additional header yet.
+ */
+ if (dhdp->wlfc_state && (PKTLEN(dhdp->osh, prevpkt) ==
+ tcp_ack_info->ip_tcp_ttllen + ETHER_HDR_LEN))
+ pushed_len = 0;
+#endif
+ if ((ip_tcp_ttllen == tcp_ack_info->ip_tcp_ttllen) &&
+ (PKTLEN(dhdp->osh, pkt) ==
+ PKTLEN(dhdp->osh, prevpkt) - pushed_len)) {
+ bcopy(PKTDATA(dhdp->osh, pkt),
+ PKTDATA(dhdp->osh, prevpkt) + pushed_len,
+ PKTLEN(dhdp->osh, pkt));
+ PKTFREE(dhdp->osh, pkt, FALSE);
+ DHD_TRACE(("dhd_tcpack_suppress: pkt 0x%p"
+ " TCP ACK replace %ud -> %ud\n", prevpkt,
+ tcp_ack_info->tcpack_number, tcp_ack_num));
+ tcp_ack_info->tcpack_number = tcp_ack_num;
+ dhd_os_tcpackunlock(dhdp);
+ return TRUE;
+ } else
+ DHD_TRACE(("dhd_tcpack_suppress: len mismatch"
+ " %d(%d) %d(%d)\n",
+ PKTLEN(dhdp->osh, pkt), ip_tcp_ttllen,
+ PKTLEN(dhdp->osh, prevpkt),
+ tcp_ack_info->ip_tcp_ttllen));
+ } else {
+#ifdef TCPACK_TEST
+ void *prevpkt = tcp_ack_info->p_tcpackinqueue;
+#endif
+ DHD_TRACE(("dhd_tcpack_suppress: TCP ACK number reverse"
+ " prev %ud (0x%p) new %ud (0x%p)\n",
+ tcp_ack_info->tcpack_number,
+ tcp_ack_info->p_tcpackinqueue,
+ tcp_ack_num, pkt));
+#ifdef TCPACK_TEST
+ if (PKTLEN(dhdp->osh, pkt) == PKTLEN(dhdp->osh, prevpkt)) {
+ PKTFREE(dhdp->osh, pkt, FALSE);
+ dhd_os_tcpackunlock(dhdp);
+ return TRUE;
+ }
+#endif
+ }
+ } else {
+ tcp_ack_info->p_tcpackinqueue = pkt;
+ tcp_ack_info->tcpack_number = tcp_ack_num;
+ tcp_ack_info->ip_tcp_ttllen = ip_tcp_ttllen;
+ bcopy(&ip_header[12], tcp_ack_info->ipaddrs, 8);
+ bcopy(tcp_header, tcp_ack_info->tcpports, 4);
+ }
+ dhd_os_tcpackunlock(dhdp);
+ } else
+ DHD_TRACE(("dhd_tcpack_suppress: TCP ACK with DATA len %d\n",
+ ip_tcp_ttllen - ip_hdr_len - tcp_hdr_len));
+ }
+ return FALSE;
+}
+#endif /* DHDTCPACK_SUPPRESS */
+
+
/* Writes a HW/SW header into the packet and sends it. */
/* Assumes: (a) header space already there, (b) caller holds lock */
static int
@@ -1562,6 +1840,7 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_on
uint16 len, pad1 = 0;
uint32 swheader;
uint retries = 0;
+ uint32 real_pad = 0;
bcmsdh_info_t *sdh;
void *new;
int i;
@@ -1574,12 +1853,17 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_on
htsfts_t *htsf_ts;
#endif
-
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
sdh = bus->sdh;
osh = bus->dhd->osh;
+#ifdef DHDTCPACK_SUPPRESS
+ if (dhd_use_tcpack_suppress) {
+ dhd_tcpack_check_xmit(bus->dhd, pkt);
+ }
+#endif /* DHDTCPACK_SUPPRESS */
+
if (bus->dhd->dongle_reset) {
ret = BCME_NOTREADY;
goto done;
@@ -1599,7 +1883,7 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_on
#endif /* WLMEDIA_HTSF */
/* Add alignment padding, allocate new packet if needed */
- if (!((uintptr)frame & 1) && (pad1 = ((uintptr)frame % DHD_SDALIGN))) {
+ if ((pad1 = ((uintptr)frame % DHD_SDALIGN))) {
if (PKTHEADROOM(osh, pkt) < pad1) {
DHD_INFO(("%s: insufficient headroom %d for %d pad1\n",
__FUNCTION__, (int)PKTHEADROOM(osh, pkt), pad1));
@@ -1649,8 +1933,13 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_on
htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN + sizeof(swheader));
if (queue_only) {
- if (forcealign && (len & (ALIGNMENT - 1)))
- len = ROUNDUP(len, ALIGNMENT);
+ uint8 alignment = ALIGNMENT;
+#if defined(BCMLXSDMMC) && defined(CUSTOMER_HW4)
+ if (bus->glom_mode == SDPCM_TXGLOM_MDESC)
+ alignment = DHD_SDALIGN;
+#endif /* defined(BCMLXSDMMC) && defined(CUSTOMER_HW4) */
+ if (forcealign && (len & (alignment - 1)))
+ len = ROUNDUP(len, alignment);
/* Hardware extention tag */
/* 2byte frame length, 1byte-, 1byte frame flag,
* 2byte-hdrlength, 2byte padlenght
@@ -1659,8 +1948,19 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_on
hwheader2 = (len - act_len) << 16;
htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
+ real_pad = len - act_len;
+ if (PKTTAILROOM(osh, pkt) < real_pad) {
+ DHD_INFO(("%s 1: insufficient tailroom %d for %d real_pad\n",
+ __FUNCTION__, (int)PKTTAILROOM(osh, pkt), real_pad));
+ if (PKTPADTAILROOM(osh, pkt, real_pad)) {
+ DHD_ERROR(("padding error size %d\n", real_pad));
+ }
+ }
+#ifdef BCMLXSDMMC
+ PKTSETLEN(osh, pkt, len);
+#endif /* BCMLXSDMMC */
/* Post the frame pointer to sdio glom array */
- dhd_bcmsdh_glom_post(bus, frame, len);
+ dhd_bcmsdh_glom_post(bus, frame, pkt, len);
/* Save the pkt pointer in bus glom array */
bus->glom_pkt_arr[bus->glom_cnt] = pkt;
bus->glom_total_len += len;
@@ -1692,9 +1992,20 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_on
hwheader2 = (len - act_len) << 16;
htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
-
+ real_pad = len - act_len;
+ if (PKTTAILROOM(osh, pkt) < real_pad) {
+ DHD_INFO(("%s 2: insufficient tailroom %d"
+ " for %d real_pad\n",
+ __FUNCTION__, (int)PKTTAILROOM(osh, pkt), real_pad));
+ if (PKTPADTAILROOM(osh, pkt, real_pad)) {
+ DHD_ERROR(("padding error size %d\n", real_pad));
+ }
+ }
+#ifdef BCMLXSDMMC
+ PKTSETLEN(osh, pkt, len);
+#endif /* BCMLXSDMMC */
/* Post the frame pointer to sdio glom array */
- dhd_bcmsdh_glom_post(bus, frame, len);
+ dhd_bcmsdh_glom_post(bus, frame, pkt, len);
/* Save the pkt pointer in bus glom array */
bus->glom_pkt_arr[bus->glom_cnt] = pkt;
bus->glom_cnt++;
@@ -1708,6 +2019,7 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_on
} else
#endif /* BCMSDIOH_TXGLOM */
{
+ uint32 act_len = len;
/* Software tag: channel, sequence number, data offset */
swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq |
(((pad1 + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
@@ -1752,8 +2064,15 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_on
DHD_ERROR(("%s: sending unrounded %d-byte packet\n", __FUNCTION__, len));
#endif
}
+ real_pad = len - act_len;
+ if (PKTTAILROOM(osh, pkt) < real_pad) {
+ DHD_INFO(("%s 3: insufficient tailroom %d for %d real_pad\n",
+ __FUNCTION__, (int)PKTTAILROOM(osh, pkt), real_pad));
+ if (PKTPADTAILROOM(osh, pkt, real_pad)) {
+ DHD_ERROR(("padding error size %d\n", real_pad));
+ }
+ }
}
-
do {
ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
frame, len, pkt, NULL, NULL);
@@ -1816,13 +2135,20 @@ done:
#ifdef BCMSDIOH_TXGLOM
uint32 doff;
if (bus->glom_enable) {
+#ifdef BCMLXSDMMC
+ uint32 pad2 = 0;
+#endif /* BCMLXSDMMC */
pkt = bus->glom_pkt_arr[bus->glom_cnt - pkt_cnt];
frame = (uint8*)PKTDATA(osh, pkt);
doff = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN);
doff = (doff & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT;
+#ifdef BCMLXSDMMC
+ pad2 = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + 4) >> 16;
+ PKTSETLEN(osh, pkt, PKTLEN(osh, pkt) - pad2);
+#endif /* BCMLXSDMMC */
PKTPULL(osh, pkt, doff);
} else
-#endif
+#endif /* BCMSDIOH_TXGLOM */
{
PKTPULL(osh, pkt, SDPCM_HDRLEN + pad1);
}
@@ -1833,7 +2159,13 @@ done:
dhd_os_sdlock(bus->dhd);
} else {
#endif /* PROP_TXSTATUS */
+#ifdef SDTEST
+ if (chan != SDPCM_TEST_CHANNEL) {
+ dhd_txcomplete(bus->dhd, pkt, ret != 0);
+ }
+#else /* SDTEST */
dhd_txcomplete(bus->dhd, pkt, ret != 0);
+#endif /* SDTEST */
if (free_pkt)
PKTFREE(osh, pkt, TRUE);
@@ -1956,8 +2288,6 @@ dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
}
else
ret = BCME_OK;
- dhd_os_sdunlock_txq(bus->dhd);
-
if ((pktq_len(&bus->txq) >= FCHI) && dhd_doflow)
dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
@@ -1965,6 +2295,8 @@ dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
if (pktq_plen(&bus->txq, prec) > qcount[prec])
qcount[prec] = pktq_plen(&bus->txq, prec);
#endif
+ dhd_os_sdunlock_txq(bus->dhd);
+
/* Schedule DPC if needed to send queued packet(s) */
if (dhd_deferred_tx && !bus->dpc_sched) {
bus->dpc_sched = TRUE;
@@ -2018,6 +2350,7 @@ dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
uint cnt = 0;
uint datalen;
uint8 tx_prec_map;
+ uint8 txpktqlen = 0;
#ifdef BCMSDIOH_TXGLOM
uint i;
uint8 glom_cnt;
@@ -2034,31 +2367,35 @@ dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
}
tx_prec_map = ~bus->flowcontrol;
-
/* Send frames until the limit or some other event */
for (cnt = 0; (cnt < maxframes) && DATAOK(bus); cnt++) {
#ifdef BCMSDIOH_TXGLOM
if (bus->glom_enable) {
+ void *pkttable[SDPCM_MAXGLOM_SIZE];
+ dhd_os_sdlock_txq(bus->dhd);
glom_cnt = MIN(DATABUFCNT(bus), bus->glomsize);
glom_cnt = MIN(glom_cnt, pktq_mlen(&bus->txq, tx_prec_map));
glom_cnt = MIN(glom_cnt, maxframes-cnt);
/* Limiting the size to 2pkts in case of copy */
if (bus->glom_mode == SDPCM_TXGLOM_CPY)
- glom_cnt = MIN(glom_cnt, 5);
+ glom_cnt = MIN(glom_cnt, 10);
+
+ for (i = 0; i < glom_cnt; i++)
+ pkttable[i] = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out);
+
+ txpktqlen = pktq_len(&bus->txq);
+ dhd_os_sdunlock_txq(bus->dhd);
if (glom_cnt == 0)
break;
datalen = 0;
for (i = 0; i < glom_cnt; i++) {
- dhd_os_sdlock_txq(bus->dhd);
- if ((pkt = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out)) == NULL) {
+ if ((pkt = pkttable[i]) == NULL) {
/* This case should not happen */
DHD_ERROR(("No pkts in the queue for glomming\n"));
- dhd_os_sdunlock_txq(bus->dhd);
break;
}
- dhd_os_sdunlock_txq(bus->dhd);
datalen += (PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN);
#ifndef SDTEST
@@ -2081,9 +2418,11 @@ dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
{
dhd_os_sdlock_txq(bus->dhd);
if ((pkt = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out)) == NULL) {
+ txpktqlen = pktq_len(&bus->txq);
dhd_os_sdunlock_txq(bus->dhd);
break;
}
+ txpktqlen = pktq_len(&bus->txq);
dhd_os_sdunlock_txq(bus->dhd);
datalen = PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN;
@@ -2118,12 +2457,68 @@ dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
/* Deflow-control stack if needed */
if (dhd_doflow && dhd->up && (dhd->busstate == DHD_BUS_DATA) &&
- dhd->txoff && (pktq_len(&bus->txq) < FCLOW))
+ dhd->txoff && (txpktqlen < FCLOW))
dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
return cnt;
}
+static void
+dhdsdio_sendpendctl(dhd_bus_t *bus)
+{
+ bcmsdh_info_t *sdh = bus->sdh;
+ int ret, i;
+ uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN;
+
+#ifdef BCMSDIOH_TXGLOM
+ if (bus->glom_enable)
+ frame_seq += SDPCM_HWEXT_LEN;
+#endif
+
+ if (*frame_seq != bus->tx_seq) {
+ DHD_INFO(("%s IOCTL frame seq lag detected!"
+ " frm_seq:%d != bus->tx_seq:%d, corrected\n",
+ __FUNCTION__, *frame_seq, bus->tx_seq));
+ *frame_seq = bus->tx_seq;
+ }
+
+ ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
+ (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len,
+ NULL, NULL, NULL);
+ ASSERT(ret != BCME_PENDING);
+ if (ret == BCME_NODEVICE) {
+ DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__));
+ } else if (ret < 0) {
+ /* On failure, abort the command and terminate the frame */
+ DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
+ __FUNCTION__, ret));
+ bus->tx_sderrs++;
+
+ bcmsdh_abort(sdh, SDIO_FUNC_2);
+
+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
+ SFC_WF_TERM, NULL);
+ bus->f1regdata++;
+
+ for (i = 0; i < 3; i++) {
+ uint8 hi, lo;
+ hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
+ SBSDIO_FUNC1_WFRAMEBCHI, NULL);
+ lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
+ SBSDIO_FUNC1_WFRAMEBCLO, NULL);
+ bus->f1regdata += 2;
+ if ((hi == 0) && (lo == 0))
+ break;
+ }
+ }
+ if (ret == 0) {
+ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
+ }
+
+ bus->ctrl_frame_stat = FALSE;
+ dhd_wait_event_wakeup(bus->dhd);
+}
+
int
dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
{
@@ -2235,9 +2630,18 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
ret = 0;
} else {
bus->dhd->txcnt_timeout++;
- if (!bus->dhd->hang_was_sent)
+ if (!bus->dhd->hang_was_sent) {
+#ifdef CUSTOMER_HW4
+ uint32 status, retry = 0;
+ R_SDREG(status, &bus->regs->intstatus, retry);
+ DHD_TRACE_HW4(("%s: txcnt_timeout, INT status=0x%08X\n",
+ __FUNCTION__, status));
+ DHD_TRACE_HW4(("%s : tx_max : %d, tx_seq : %d, clkstate : %d \n",
+ __FUNCTION__, bus->tx_max, bus->tx_seq, bus->clkstate));
+#endif /* CUSTOMER_HW4 */
DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n",
__FUNCTION__, bus->dhd->txcnt_timeout));
+ }
ret = -1;
bus->ctrl_frame_stat = FALSE;
goto done;
@@ -2309,7 +2713,7 @@ done:
else
bus->dhd->tx_ctlpkts++;
- if (bus->dhd->txcnt_timeout >= MAX_CNTL_TIMEOUT)
+ if (bus->dhd->txcnt_timeout >= MAX_CNTL_TX_TIMEOUT)
return -ETIMEDOUT;
return ret ? -EIO : 0;
@@ -2338,7 +2742,7 @@ dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
if (rxlen) {
DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n",
- __FUNCTION__, rxlen, msglen));
+ __FUNCTION__, rxlen, msglen));
} else if (timeleft == 0) {
#ifdef DHD_DEBUG
uint32 status, retry = 0;
@@ -2367,8 +2771,10 @@ dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
#endif /* DHD_DEBUG */
}
if (timeleft == 0) {
- bus->dhd->rxcnt_timeout++;
- DHD_ERROR(("%s: rxcnt_timeout=%d\n", __FUNCTION__, bus->dhd->rxcnt_timeout));
+ if (rxlen == 0)
+ bus->dhd->rxcnt_timeout++;
+ DHD_ERROR(("%s: rxcnt_timeout=%d, rxlen=%d\n", __FUNCTION__,
+ bus->dhd->rxcnt_timeout, rxlen));
}
else
bus->dhd->rxcnt_timeout = 0;
@@ -2378,7 +2784,7 @@ dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
else
bus->dhd->rx_ctlerrs++;
- if (bus->dhd->rxcnt_timeout >= MAX_CNTL_TIMEOUT)
+ if (bus->dhd->rxcnt_timeout >= MAX_CNTL_RX_TIMEOUT)
return -ETIMEDOUT;
if (bus->dhd->dongle_trap_occured)
@@ -2646,12 +3052,15 @@ dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg)
bus->pktgen_stop = pktgen.stop;
bus->pktgen_tick = bus->pktgen_ptick = 0;
+ bus->pktgen_prev_time = jiffies;
bus->pktgen_len = MAX(bus->pktgen_len, bus->pktgen_minlen);
bus->pktgen_len = MIN(bus->pktgen_len, bus->pktgen_maxlen);
/* Clear counts for a new pktgen (mode change, or was stopped) */
- if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode))
- bus->pktgen_sent = bus->pktgen_rcvd = bus->pktgen_fail = 0;
+ if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode)) {
+ bus->pktgen_sent = bus->pktgen_prev_sent = bus->pktgen_rcvd = 0;
+ bus->pktgen_prev_rcvd = bus->pktgen_fail = 0;
+ }
return 0;
}
@@ -2886,6 +3295,9 @@ dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size)
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+ if (DHD_NOCHECKDIED_ON())
+ return 0;
+
if (data == NULL) {
/*
* Called after a rx ctrl timeout. "data" is NULL.
@@ -3113,7 +3525,8 @@ dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror)
uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB;
}
else if (bus->sih->chip == BCM4334_CHIP_ID ||
- bus->sih->chip == BCM43341_CHIP_ID) {
+ bus->sih->chip == BCM43341_CHIP_ID ||
+ 0) {
if (enable) {
/* Moved to PMU chipcontrol 1 from 4330 */
int_val &= ~gpio_sel;
@@ -3309,6 +3722,16 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch
DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__,
(set ? "write" : "read"), size, address));
+ /* check if CR4 */
+ if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
+ /* if address is 0, store the reset instruction to be written in 0 */
+
+ if (address == 0) {
+ bus->resetinstr = *(((uint32*)params) + 2);
+ }
+ /* Add start of RAM address to the address given by user */
+ address += bus->dongle_ram_base;
+ } else {
/* If we know about SOCRAM, check for a fit */
if ((bus->orig_ramsize) &&
((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize)))
@@ -3350,6 +3773,7 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch
break;
}
}
+ }
/* Generate the actual data pointer */
data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg;
@@ -3604,13 +4028,14 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch
case IOV_SVAL(IOV_MESBUSYCTRL):
mesbusyctrl = (uint)int_val;
mesbusyctrl = (mesbusyctrl > SBSDIO_MESBUSYCTRL_MASK)
- ? SBSDIO_MESBUSYCTRL_MASK : mesbusyctrl;
+ ? SBSDIO_MESBUSYCTRL_MASK : mesbusyctrl;
DHD_ERROR(("Setting mesbusyctrl as 0x%x.\n", mesbusyctrl));
bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
((uint8)mesbusyctrl | 0x80), NULL);
break;
#endif /* SDIO_CRC_ERROR_FIX */
+
case IOV_GVAL(IOV_DONGLEISOLATION):
int_val = bus->dhd->dongle_isolation;
bcopy(&int_val, arg, val_size);
@@ -3840,6 +4265,8 @@ dhdsdio_download_state(dhd_bus_t *bus, bool enter)
int bcmerror = 0;
int foundcr4 = 0;
+ if (!bus->sih)
+ return BCME_ERROR;
/* To enter download state, disable ARM and reset SOCRAM.
* To exit download state, simply reset ARM (default is RAM boot).
*/
@@ -3851,45 +4278,47 @@ dhdsdio_download_state(dhd_bus_t *bus, bool enter)
if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
foundcr4 = 1;
} else {
- DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
- bcmerror = BCME_ERROR;
- goto fail;
- }
+ DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
+ bcmerror = BCME_ERROR;
+ goto fail;
+ }
}
if (!foundcr4) {
- si_core_disable(bus->sih, 0);
- if (bcmsdh_regfail(bus->sdh)) {
- bcmerror = BCME_SDIO_ERROR;
- goto fail;
- }
-
- if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
- DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
- bcmerror = BCME_ERROR;
- goto fail;
- }
-
- si_core_reset(bus->sih, 0, 0);
- if (bcmsdh_regfail(bus->sdh)) {
- DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n", __FUNCTION__));
- bcmerror = BCME_SDIO_ERROR;
- goto fail;
- }
+ si_core_disable(bus->sih, 0);
+ if (bcmsdh_regfail(bus->sdh)) {
+ bcmerror = BCME_SDIO_ERROR;
+ goto fail;
+ }
- /* Disable remap for download */
- if (REMAP_ENAB(bus) && si_socdevram_remap_isenb(bus->sih))
- dhdsdio_devram_remap(bus, FALSE);
+ if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
+ DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
+ bcmerror = BCME_ERROR;
+ goto fail;
+ }
- /* Clear the top bit of memory */
- if (bus->ramsize) {
- uint32 zeros = 0;
- if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4, (uint8*)&zeros, 4) < 0) {
+ si_core_reset(bus->sih, 0, 0);
+ if (bcmsdh_regfail(bus->sdh)) {
+ DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n",
+ __FUNCTION__));
bcmerror = BCME_SDIO_ERROR;
goto fail;
}
- }
- } else {
+
+ /* Disable remap for download */
+ if (REMAP_ENAB(bus) && si_socdevram_remap_isenb(bus->sih))
+ dhdsdio_devram_remap(bus, FALSE);
+
+ /* Clear the top bit of memory */
+ if (bus->ramsize) {
+ uint32 zeros = 0;
+ if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4,
+ (uint8*)&zeros, 4) < 0) {
+ bcmerror = BCME_SDIO_ERROR;
+ goto fail;
+ }
+ }
+ } else {
/* For CR4,
* Halt ARM
* Remove ARM reset
@@ -3903,42 +4332,44 @@ dhdsdio_download_state(dhd_bus_t *bus, bool enter)
}
} else {
if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
- if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
- DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
- bcmerror = BCME_ERROR;
- goto fail;
- }
+ if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
+ DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
+ bcmerror = BCME_ERROR;
+ goto fail;
+ }
- if (!si_iscoreup(bus->sih)) {
- DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__));
- bcmerror = BCME_ERROR;
- goto fail;
- }
+ if (!si_iscoreup(bus->sih)) {
+ DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__));
+ bcmerror = BCME_ERROR;
+ goto fail;
+ }
- if ((bcmerror = dhdsdio_write_vars(bus))) {
- DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__));
- goto fail;
- }
- /* Enable remap before ARM reset but after vars.
- * No backplane access in remap mode
- */
- if (REMAP_ENAB(bus) && !si_socdevram_remap_isenb(bus->sih))
- dhdsdio_devram_remap(bus, TRUE);
+ if ((bcmerror = dhdsdio_write_vars(bus))) {
+ DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__));
+ goto fail;
+ }
- if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
- !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
- DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
- bcmerror = BCME_ERROR;
- goto fail;
- }
- W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
+ /* Enable remap before ARM reset but after vars.
+ * No backplane access in remap mode
+ */
+ if (REMAP_ENAB(bus) && !si_socdevram_remap_isenb(bus->sih))
+ dhdsdio_devram_remap(bus, TRUE);
- if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
- !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
- DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
- bcmerror = BCME_ERROR;
- goto fail;
- }
+ if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
+ !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
+ DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
+ bcmerror = BCME_ERROR;
+ goto fail;
+ }
+ W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
+
+
+ if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
+ !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
+ DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
+ bcmerror = BCME_ERROR;
+ goto fail;
+ }
} else {
/* cr4 has no socram, but tcm's */
/* write vars */
@@ -4055,6 +4486,9 @@ dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name,
} else {
DHD_INFO(("%s: noted %s update, value now %d\n",
__FUNCTION__, "sd_blocksize", bus->blocksize));
+
+ if (bus->sih->chip == BCM4335_CHIP_ID)
+ dhd_overflow_war(bus);
}
}
bus->roundup = MIN(max_roundup, bus->blocksize);
@@ -4114,10 +4548,12 @@ dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
dhd_os_sdlock(bus->dhd);
if ((bus->dhd->busstate == DHD_BUS_DOWN) || bus->dhd->hang_was_sent) {
+ /* if Firmware already hangs disbale any interrupt */
bus->dhd->busstate = DHD_BUS_DOWN;
bus->hostintmask = 0;
bcmsdh_intr_disable(bus->sdh);
} else {
+
BUS_WAKE(bus);
if (KSO_ENAB(bus)) {
@@ -4132,33 +4568,34 @@ dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
if (KSO_ENAB(bus)) {
- /* Enable clock for device interrupts */
- dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
+ /* Enable clock for device interrupts */
+ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
- /* Disable and clear interrupts at the chip level also */
- W_SDREG(0, &bus->regs->hostintmask, retries);
- local_hostintmask = bus->hostintmask;
- bus->hostintmask = 0;
+ /* Disable and clear interrupts at the chip level also */
+ W_SDREG(0, &bus->regs->hostintmask, retries);
+ local_hostintmask = bus->hostintmask;
+ bus->hostintmask = 0;
- /* Force clocks on backplane to be sure F2 interrupt propagates */
- saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
- if (!err) {
- bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
- (saveclk | SBSDIO_FORCE_HT), &err);
- }
- if (err) {
- DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
- }
+ /* Force clocks on backplane to be sure F2 interrupt propagates */
+ saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
+ if (!err) {
+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
+ (saveclk | SBSDIO_FORCE_HT), &err);
+ }
+ if (err) {
+ DHD_ERROR(("%s: Failed to force clock for F2: err %d\n",
+ __FUNCTION__, err));
+ }
- /* Turn off the bus (F2), free any pending packets */
- DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
- bcmsdh_intr_disable(bus->sdh);
+ /* Turn off the bus (F2), free any pending packets */
+ DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
+ bcmsdh_intr_disable(bus->sdh);
#ifndef BCMSPI
- bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
-#endif
+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
+#endif /* !BCMSPI */
- /* Clear any pending interrupts now that F2 is disabled */
- W_SDREG(local_hostintmask, &bus->regs->intstatus, retries);
+ /* Clear any pending interrupts now that F2 is disabled */
+ W_SDREG(local_hostintmask, &bus->regs->intstatus, retries);
}
/* Turn off the backplane clock (only) */
@@ -4185,6 +4622,8 @@ dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
bus->rxskip = FALSE;
bus->tx_seq = bus->rx_seq = 0;
+ bus->tx_max = 4;
+
if (enforce_mutex)
dhd_os_sdunlock(bus->dhd);
}
@@ -4327,8 +4766,10 @@ dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
mesbusyctrl = watermark = bus->blocksize / 4;
}
#endif /* SDIO_CRC_ERROR_FIX */
-
- bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, &err);
+ if (bus->sih->chip != BCM4335_CHIP_ID) {
+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK,
+ (uint8)watermark, &err);
+ }
#ifdef SDIO_CRC_ERROR_FIX
bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
(uint8)mesbusyctrl|0x80, &err);
@@ -4401,12 +4842,21 @@ dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx)
}
bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err);
+ if (err) {
+ DHD_ERROR(("%s: SBSDIO_FUNC1_FRAMECTRL cmd err\n", __FUNCTION__));
+ goto fail;
+ }
bus->f1regdata++;
/* Wait until the packet has been flushed (device/FIFO stable) */
for (lastrbc = retries = 0xffff; retries > 0; retries--) {
hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL);
- lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, NULL);
+ lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, &err);
+ if (err) {
+ DHD_ERROR(("%s: SBSDIO_FUNC1_RFAMEBCLO cmd err\n", __FUNCTION__));
+ goto fail;
+ }
+
bus->f1regdata += 2;
if ((hi == 0) && (lo == 0))
@@ -4437,6 +4887,7 @@ dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx)
/* Clear partial in any case */
bus->nextlen = 0;
+fail:
/* If we can't reach the device, signal failure */
if (err || bcmsdh_regfail(sdh))
bus->dhd->busstate = DHD_BUS_DOWN;
@@ -4542,11 +4993,6 @@ done:
dhd_os_ioctl_resp_wake(bus->dhd);
}
-#ifdef CUSTOMER_HW4
-int pkt_free;
-int caller;
-void *free_ptr;
-#endif
static uint8
dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
{
@@ -4569,9 +5015,6 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
int ifidx = 0;
bool usechain = bus->use_rxchain;
-#ifdef CUSTOMER_HW4
- pkt_free = 0;
-#endif
/* If packets, issue read(s) and send up packet chain */
/* Return sequence numbers consumed? */
@@ -4889,11 +5332,6 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
reorder_info_len = sizeof(reorder_info_buf);
if (PKTLEN(osh, pfirst) == 0) {
-#ifdef CUSTOMER_HW4
- pkt_free = 1;
- caller = 1;
- free_ptr = pfirst;
-#endif
PKTFREE(bus->dhd->osh, pfirst, FALSE);
continue;
} else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst, reorder_info_buf,
@@ -4986,7 +5424,12 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
/* Return TRUE if there may be more frames to read */
static uint
+#ifdef REPEAT_READFRAME
+dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished, bool tx_enable)
+#else
dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
+#endif
+
{
osl_t *osh = bus->dhd->osh;
bcmsdh_info_t *sdh = bus->sdh;
@@ -5018,9 +5461,6 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
bool sdtest = FALSE; /* To limit message spew from test mode */
#endif
-#ifdef CUSTOMER_HW4
- pkt_free = 0;
-#endif
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
bus->readframes = TRUE;
@@ -5043,7 +5483,6 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
/* Not finished unless we encounter no more frames indication */
*finished = FALSE;
-
#ifdef BCMSPI
/* Get pktlen from gSPI device F0 reg. */
if (bus->bus == SPI_BUS) {
@@ -5082,8 +5521,19 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
rxseq++, rxleft--) {
#ifdef DHDTHREAD
+
+ if (
+#ifdef REPEAT_READFRAME
+ tx_enable &&
+#endif
+ TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL))
+ dhdsdio_sendpendctl(bus);
/* tx more to improve rx performance */
- if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
+ else if (
+#ifdef REPEAT_READFRAME
+ tx_enable &&
+#endif
+ (bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) {
dhdsdio_sendfromq(bus, dhd_txbound);
}
@@ -5665,11 +6115,6 @@ deliver:
if (PKTLEN(osh, pkt) == 0) {
dhd_os_sdlock_rxq(bus->dhd);
-#ifdef CUSTOMER_HW4
- pkt_free = 1;
- caller = 0;
- free_ptr = pkt;
-#endif
PKTFREE(bus->dhd->osh, pkt, FALSE);
dhd_os_sdunlock_rxq(bus->dhd);
continue;
@@ -5692,7 +6137,6 @@ deliver:
else
pkt_count = 1;
-
/* Unlock during rx call */
dhd_os_sdunlock(bus->dhd);
dhd_rx_frame(bus->dhd, ifidx, pkt, pkt_count, chan);
@@ -5803,7 +6247,7 @@ dhdsdio_hostmail(dhd_bus_t *bus)
#ifdef DHD_DEBUG
/* At least print a message if FW halted */
if (hmb_data & HMB_DATA_FWHALT) {
- DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED\n"));
+ DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED : set BUS DOWN\n"));
dhdsdio_checkdied(bus, NULL, 0);
bus->dhd->busstate = DHD_BUS_DOWN;
}
@@ -5823,6 +6267,10 @@ dhdsdio_hostmail(dhd_bus_t *bus)
return intstatus;
}
+#ifdef REPEAT_READFRAME
+extern uint dhd_dpcpoll;
+#endif
+
static bool
dhdsdio_dpc(dhd_bus_t *bus)
{
@@ -5900,7 +6348,6 @@ dhdsdio_dpc(dhd_bus_t *bus)
}
BUS_WAKE(bus);
-
/* Make sure backplane clock is on */
dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
if (bus->clkstate != CLK_AVAIL)
@@ -5931,6 +6378,7 @@ dhdsdio_dpc(dhd_bus_t *bus)
intstatus |= newstatus;
bus->intstatus = 0;
+
/* Handle flow-control change: read new state in case our ack
* crossed another change interrupt. If change still set, assume
* FC ON for safety, let next loop through do the debounce.
@@ -5985,7 +6433,11 @@ dhdsdio_dpc(dhd_bus_t *bus)
/* On frame indication, read available frames */
if (PKT_AVAILABLE(bus, intstatus)) {
+#ifdef REPEAT_READFRAME
+ framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone, true);
+#else
framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone);
+#endif
if (rxdone || bus->rxskip)
intstatus &= ~FRAME_AVAIL_MASK(bus);
rxlimit -= MIN(framecnt, rxlimit);
@@ -6025,54 +6477,13 @@ clkwait:
}
#endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */
- if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) {
- int ret, i;
-
- uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN;
-
- if (*frame_seq != bus->tx_seq) {
- DHD_INFO(("%s IOCTL frame seq lag detected!"
- " frm_seq:%d != bus->tx_seq:%d, corrected\n",
- __FUNCTION__, *frame_seq, bus->tx_seq));
- *frame_seq = bus->tx_seq;
- }
-
- ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
- (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len,
- NULL, NULL, NULL);
- ASSERT(ret != BCME_PENDING);
- if (ret == BCME_NODEVICE) {
- DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__));
- } else if (ret < 0) {
- /* On failure, abort the command and terminate the frame */
- DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
- __FUNCTION__, ret));
- bus->tx_sderrs++;
-
- bcmsdh_abort(sdh, SDIO_FUNC_2);
-
- bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
- SFC_WF_TERM, NULL);
- bus->f1regdata++;
+#ifdef PROP_TXSTATUS
+ dhd_wlfc_trigger_pktcommit(bus->dhd);
+#endif
- for (i = 0; i < 3; i++) {
- uint8 hi, lo;
- hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
- SBSDIO_FUNC1_WFRAMEBCHI, NULL);
- lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
- SBSDIO_FUNC1_WFRAMEBCLO, NULL);
- bus->f1regdata += 2;
- if ((hi == 0) && (lo == 0))
- break;
- }
- }
- if (ret == 0) {
- bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
- }
- bus->ctrl_frame_stat = FALSE;
- dhd_wait_event_wakeup(bus->dhd);
- }
+ if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL))
+ dhdsdio_sendpendctl(bus);
/* Send queued frames (limit 1 if rx may still be pending) */
else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) {
@@ -6081,11 +6492,8 @@ clkwait:
txlimit -= framecnt;
}
/* Resched the DPC if ctrl cmd is pending on bus credit */
- if (bus->ctrl_frame_stat) {
- DHD_TRACE_HW4(("%s : tx_max : %d, tx_seq : %d, clkstate : %d \n",
- __FUNCTION__, bus->tx_max, bus->tx_seq, bus->clkstate));
+ if (bus->ctrl_frame_stat)
resched = TRUE;
- }
/* Resched if events or tx frames are pending, else await next interrupt */
/* On failed register access, all bets are off: no resched or interrupts */
@@ -6118,6 +6526,12 @@ clkwait:
}
exit:
+#ifdef REPEAT_READFRAME
+ if (!resched && dhd_dpcpoll) {
+ resched = dhdsdio_readframes(bus, dhd_rxbound, &rxdone, true);
+ }
+#endif
+
dhd_os_sdunlock(bus->dhd);
return resched;
}
@@ -6185,7 +6599,6 @@ dhdsdio_isr(void *arg)
while (dhdsdio_dpc(bus));
DHD_OS_WAKE_UNLOCK(bus->dhd);
#else
-
bus->dpc_sched = TRUE;
dhd_sched_dpc(bus->dhd);
@@ -6209,7 +6622,7 @@ dhdsdio_pktgen_init(dhd_bus_t *bus)
/* Default to per-watchdog burst with 10s print time */
bus->pktgen_freq = 1;
- bus->pktgen_print = dhd_watchdog_ms ? (10000/dhd_watchdog_ms):0;
+ bus->pktgen_print = dhd_watchdog_ms ? (10000 / dhd_watchdog_ms) : 0;
bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000;
/* Default to echo mode */
@@ -6226,19 +6639,37 @@ dhdsdio_pktgen(dhd_bus_t *bus)
uint fillbyte;
osl_t *osh = bus->dhd->osh;
uint16 len;
+ ulong time_lapse;
+ uint sent_pkts;
+ uint rcvd_pkts;
/* Display current count if appropriate */
if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) {
bus->pktgen_ptick = 0;
- printf("%s: send attempts %d rcvd %d\n",
- __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd);
+ printf("%s: send attempts %d, rcvd %d, errors %d\n",
+ __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
+
+ /* Print throughput stats only for constant length packet runs */
+ if (bus->pktgen_minlen == bus->pktgen_maxlen) {
+ time_lapse = jiffies - bus->pktgen_prev_time;
+ bus->pktgen_prev_time = jiffies;
+ sent_pkts = bus->pktgen_sent - bus->pktgen_prev_sent;
+ bus->pktgen_prev_sent = bus->pktgen_sent;
+ rcvd_pkts = bus->pktgen_rcvd - bus->pktgen_prev_rcvd;
+ bus->pktgen_prev_rcvd = bus->pktgen_rcvd;
+
+ printf("%s: Tx Throughput %d kbps, Rx Throughput %d kbps\n",
+ __FUNCTION__,
+ (sent_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8,
+ (rcvd_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8);
+ }
}
/* For recv mode, just make sure dongle has started sending */
if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
if (bus->pktgen_rcv_state == PKTGEN_RCV_IDLE) {
bus->pktgen_rcv_state = PKTGEN_RCV_ONGOING;
- dhdsdio_sdtest_set(bus, (uint8)bus->pktgen_total);
+ dhdsdio_sdtest_set(bus, bus->pktgen_total);
}
return;
}
@@ -6252,7 +6683,11 @@ dhdsdio_pktgen(dhd_bus_t *bus)
}
/* Allocate an appropriate-sized packet */
- len = bus->pktgen_len;
+ if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) {
+ len = SDPCM_TEST_PKT_CNT_FLD_LEN;
+ } else {
+ len = bus->pktgen_len;
+ }
if (!(pkt = PKTGET(osh, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN),
TRUE))) {;
DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
@@ -6275,7 +6710,7 @@ dhdsdio_pktgen(dhd_bus_t *bus)
case DHD_PKTGEN_RXBURST:
*data++ = SDPCM_TEST_BURST;
- *data++ = (uint8)bus->pktgen_count;
+ *data++ = (uint8)bus->pktgen_count; /* Just for backward compatability */
break;
default:
@@ -6286,12 +6721,23 @@ dhdsdio_pktgen(dhd_bus_t *bus)
}
/* Write test header length field */
- *data++ = (len >> 0);
- *data++ = (len >> 8);
+ *data++ = (bus->pktgen_len >> 0);
+ *data++ = (bus->pktgen_len >> 8);
- /* Then fill in the remainder -- N/A for burst, but who cares... */
- for (fillbyte = 0; fillbyte < len; fillbyte++)
- *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent);
+ /* Write frame count in a 4 byte field adjucent to SDPCM test header for
+ * burst mode
+ */
+ if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) {
+ *data++ = (uint8)(bus->pktgen_count >> 0);
+ *data++ = (uint8)(bus->pktgen_count >> 8);
+ *data++ = (uint8)(bus->pktgen_count >> 16);
+ *data++ = (uint8)(bus->pktgen_count >> 24);
+ } else {
+
+ /* Then fill in the remainder -- N/A for burst */
+ for (fillbyte = 0; fillbyte < len; fillbyte++)
+ *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent);
+ }
#ifdef DHD_DEBUG
if (DHD_BYTES_ON() && DHD_DATA_ON()) {
@@ -6319,25 +6765,31 @@ dhdsdio_pktgen(dhd_bus_t *bus)
}
static void
-dhdsdio_sdtest_set(dhd_bus_t *bus, uint8 count)
+dhdsdio_sdtest_set(dhd_bus_t *bus, uint count)
{
void *pkt;
uint8 *data;
osl_t *osh = bus->dhd->osh;
/* Allocate the packet */
- if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN, TRUE))) {
+ if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN +
+ SDPCM_TEST_PKT_CNT_FLD_LEN + DHD_SDALIGN, TRUE))) {
DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
return;
}
- PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN);
+ PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN +
+ SDPCM_TEST_PKT_CNT_FLD_LEN), DHD_SDALIGN);
data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
/* Fill in the test header */
*data++ = SDPCM_TEST_SEND;
- *data++ = count;
+ *data++ = (count > 0)?TRUE:FALSE;
*data++ = (bus->pktgen_maxlen >> 0);
*data++ = (bus->pktgen_maxlen >> 8);
+ *data++ = (uint8)(count >> 0);
+ *data++ = (uint8)(count >> 8);
+ *data++ = (uint8)(count >> 16);
+ *data++ = (uint8)(count >> 24);
/* Send it */
if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE, FALSE))
@@ -6505,7 +6957,7 @@ dhd_bus_watchdog(dhd_pub_t *dhdp)
if (!bus->dpc_sched) {
uint32 devpend;
devpend = bcmsdh_cfg_read_word(bus->sdh, SDIO_FUNC_0,
- SPID_STATUS_REG, NULL);
+ SPID_STATUS_REG, NULL);
intstatus = devpend & STATUS_F2_PKT_AVAILABLE;
}
#endif /* !BCMSPI */
@@ -6548,7 +7000,10 @@ dhd_bus_watchdog(dhd_pub_t *dhdp)
/* Generate packets if configured */
if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) {
/* Make sure backplane clock is on */
- dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
+ if (SLPAUTO_ENAB(bus))
+ dhdsdio_bussleep(bus, FALSE);
+ else
+ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
bus->pktgen_tick = 0;
dhdsdio_pktgen(bus);
}
@@ -6563,7 +7018,6 @@ dhd_bus_watchdog(dhd_pub_t *dhdp)
if (bus->idlecount >= bus->idletime) {
DHD_TIMER(("%s: DHD Idle state!!\n", __FUNCTION__));
-
if (SLPAUTO_ENAB(bus)) {
if (dhdsdio_bussleep(bus, TRUE) != BCME_BUSY)
dhd_os_wd_timer(bus->dhd, 0);
@@ -6708,16 +7162,24 @@ dhdsdio_chipmatch(uint16 chipid)
return TRUE;
if (chipid == BCM4314_CHIP_ID)
return TRUE;
- if (chipid == BCM4334_CHIP_ID)
+ if (chipid == BCM43242_CHIP_ID)
return TRUE;
if (chipid == BCM43341_CHIP_ID)
return TRUE;
+ if (chipid == BCM43143_CHIP_ID)
+ return TRUE;
+ if (chipid == BCM43342_CHIP_ID)
+ return TRUE;
+ if (chipid == BCM4334_CHIP_ID)
+ return TRUE;
if (chipid == BCM43239_CHIP_ID)
return TRUE;
if (chipid == BCM4324_CHIP_ID)
return TRUE;
if (chipid == BCM4335_CHIP_ID)
return TRUE;
+ if (chipid == BCM4350_CHIP_ID)
+ return TRUE;
return FALSE;
}
@@ -6732,7 +7194,6 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
#endif /* GET_CUSTOM_MAC_ENABLE */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
-
if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) {
DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__));
}
@@ -6758,7 +7219,11 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
sd1idle = TRUE;
dhd_readahead = TRUE;
retrydata = FALSE;
+#ifndef REPEAT_READFRAME
dhd_doflow = FALSE;
+#else
+ dhd_doflow = TRUE;
+#endif /* REPEAT_READFRAME */
dhd_dongle_memsize = 0;
dhd_txminmax = DHD_TXMINMAX;
@@ -6899,7 +7364,6 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
if (dhd_download_fw_on_driverload) {
if ((ret = dhd_bus_start(bus->dhd)) != 0) {
DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__));
- if (ret == BCME_NOTUP)
goto fail;
}
}
@@ -6933,6 +7397,284 @@ forcereturn:
return NULL;
}
+#ifdef REGON_BP_HANG_FIX
+static int dhd_sdio_backplane_reset(struct dhd_bus *bus)
+{
+ uint32 temp = 0;
+ DHD_ERROR(("Resetting the backplane to avoid failure in firmware download..\n"));
+
+ temp = bcmsdh_reg_read(bus->sdh, 0x180021e0, 4);
+ DHD_INFO(("SDIO Clk Control Reg = %x\n", temp));
+
+ /* Force HT req from PMU */
+ bcmsdh_reg_write(bus->sdh, 0x18000644, 4, 0x6000005);
+
+ /* Increase the clock stretch duration. */
+ bcmsdh_reg_write(bus->sdh, 0x18000630, 4, 0xC8FFC8);
+
+ /* Setting ALP clock request in SDIOD clock control status register */
+ bcmsdh_reg_write(bus->sdh, 0x180021e0, 4, 0x41);
+
+ /* Allowing clock from SR engine to SR memory */
+ bcmsdh_reg_write(bus->sdh, 0x18004400, 4, 0xf92f1);
+ /* Disabling SR Engine before SR binary download. */
+ bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
+ bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x0);
+
+ /* Enabling clock from backplane to SR memory */
+ bcmsdh_reg_write(bus->sdh, 0x18004400, 4, 0xf9af1);
+
+ /* Initializing SR memory address register in SOCRAM */
+ bcmsdh_reg_write(bus->sdh, 0x18004408, 4, 0x0);
+
+ /* Downloading the SR binary */
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0xc0002000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x80008000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x1051f080);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x80008000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x1050f080);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x80008000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x1050f080);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x80008000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x1050f080);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000004);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000604);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00001604);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00001404);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a08c80);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010001);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x14a00000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00011404);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00002000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x04a00000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00002000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0xf8000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00002000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x04a00000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00002000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0xf8000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00011604);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010604);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010004);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x14a00000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000004);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010001);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x14a00000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010004);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x14a00000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000008);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x04a00000);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000008);
+ bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0xfc000000);
+ /* SR Binary Download complete */
+
+ /* Allowing clock from SR engine to SR memory */
+ bcmsdh_reg_write(bus->sdh, 0x18004400, 4, 0xf92f1);
+
+ /* Turning ON SR Engine to initiate backplane reset Repeated ?? Maharana */
+ bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
+ bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x0);
+ bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
+ bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x2);
+ bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
+ bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x3);
+ bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
+ bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x37);
+ bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
+ temp = bcmsdh_reg_read(bus->sdh, 0x18000654, 4);
+ DHD_INFO(("0x18000654 = %x\n", temp));
+ bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x800037);
+ OSL_DELAY(100000);
+ /* Rolling back the original values for clock stretch and PMU timers */
+ bcmsdh_reg_write(bus->sdh, 0x18000644, 4, 0x0);
+ bcmsdh_reg_write(bus->sdh, 0x18000630, 4, 0xC800C8);
+ /* Removing ALP clock request in SDIOD clock control status register */
+ bcmsdh_reg_write(bus->sdh, 0x180021e0, 4, 0x40);
+ OSL_DELAY(10000);
+ return TRUE;
+}
+
+static int dhdsdio_sdio_hang_war(struct dhd_bus *bus)
+{
+ uint32 temp = 0, temp2 = 0, counter = 0, BT_pwr_up = 0, BT_ready = 0;
+ /* Removing reset of D11 Core */
+ bcmsdh_reg_write(bus->sdh, 0x18101408, 4, 0x3);
+ bcmsdh_reg_write(bus->sdh, 0x18101800, 4, 0x0);
+ bcmsdh_reg_write(bus->sdh, 0x18101408, 4, 0x1);
+ /* Reading CLB XTAL BT cntrl register */
+ bcmsdh_reg_write(bus->sdh, 0x180013D8, 2, 0xD1);
+ bcmsdh_reg_write(bus->sdh, 0x180013DA, 2, 0x12);
+ bcmsdh_reg_write(bus->sdh, 0x180013D8, 2, 0x2D0);
+ /* Read if BT is powered up */
+ temp = bcmsdh_reg_read(bus->sdh, 0x180013DA, 2);
+ /* Read BT_ready from WLAN wireless register */
+ temp2 = bcmsdh_reg_read(bus->sdh, 0x1800002C, 4);
+ /*
+ Check if the BT is powered up and ready. The duration between BT being powered up
+ and BT becoming ready is the problematic window for WLAN. If we move ahead at this
+ time then we may encounter a corrupted backplane later. So we wait for BT to be ready
+ and then proceed after checking the health of the backplane. If the backplane shows
+ indications of failure then we have to do a full reset of the backplane using SR engine
+ and then proceed.
+ */
+ (temp & 0xF0) ? (BT_pwr_up = 1):(BT_pwr_up = 0);
+ (temp2 & (1<<17)) ? (BT_ready = 1):(BT_ready = 0);
+ DHD_ERROR(("WARNING: Checking if BT is ready BT_pwr_up = %x"
+ "BT_ready = %x \n", BT_pwr_up, BT_ready));
+ while (BT_pwr_up && !BT_ready)
+ {
+ OSL_DELAY(1000);
+ bcmsdh_reg_write(bus->sdh, 0x180013D8, 2, 0x2D0);
+ temp = bcmsdh_reg_read(bus->sdh, 0x180013DA, 2);
+ temp2 = bcmsdh_reg_read(bus->sdh, 0x1800002C, 4);
+ (temp & 0xF0) ? (BT_pwr_up = 1):(BT_pwr_up = 0);
+ (temp2 & (1<<17)) ? (BT_ready = 1):(BT_ready = 0);
+ counter++;
+ if (counter == 5000)
+ {
+ DHD_ERROR(("WARNING: Going ahead after 5 secs with"
+ "risk of failure because BT ready is not yet set\n"));
+ break;
+ }
+ }
+ DHD_ERROR(("\nWARNING: WL Proceeding BT_pwr_up = %x BT_ready = %x"
+ "\n", BT_pwr_up, BT_ready));
+ counter = 0;
+ OSL_DELAY(10000);
+ /*
+ Get the information of who accessed the crucial backplane entities
+ by reading read and write access registers
+ */
+ DHD_TRACE(("%d: Read Value @ 0x18104808 = %x."
+ "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18104808, 4)));
+ DHD_TRACE(("%d: Read Value @ 0x1810480C = %x."
+ "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810480C, 4)));
+ DHD_TRACE(("%d: Read Value @ 0x18106808 = %x."
+ "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18106808, 4)));
+ DHD_TRACE(("%d: Read Value @ 0x1810680C = %x."
+ "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810680C, 4)));
+ DHD_TRACE(("%d: Read Value @ 0x18107808 = %x."
+ "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18107808, 4)));
+ DHD_TRACE(("%d: Read Value @ 0x1810780C = %x."
+ "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810780C, 4)));
+ DHD_TRACE(("%d: Read Value @ 0x18108808 = %x."
+ "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18108808, 4)));
+ DHD_TRACE(("%d: Read Value @ 0x1810880C = %x."
+ "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810880C, 4)));
+ DHD_TRACE(("%d: Read Value @ 0x18109808 = %x."
+ "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18109808, 4)));
+ DHD_TRACE(("%d: Read Value @ 0x1810980C = %x."
+ "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810980C, 4)));
+ DHD_TRACE(("%d: Read Value @ 0x1810C808 = %x."
+ "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810c808, 4)));
+ DHD_TRACE(("%d: Read Value @ 0x1810C80C = %x."
+ "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810c80C, 4)));
+ counter = 0;
+ while ((bcmsdh_reg_read(bus->sdh, 0x18104808, 4) == 5) ||
+ (bcmsdh_reg_read(bus->sdh, 0x1810480C, 4) == 5) ||
+ (bcmsdh_reg_read(bus->sdh, 0x18106808, 4) == 5) ||
+ (bcmsdh_reg_read(bus->sdh, 0x1810680C, 4) == 5) ||
+ (bcmsdh_reg_read(bus->sdh, 0x1810780C, 4) == 5) ||
+ (bcmsdh_reg_read(bus->sdh, 0x1810780C, 4) == 5) ||
+ (bcmsdh_reg_read(bus->sdh, 0x1810880C, 4) == 5) ||
+ (bcmsdh_reg_read(bus->sdh, 0x1810880C, 4) == 5) ||
+ (bcmsdh_reg_read(bus->sdh, 0x1810980C, 4) == 5) ||
+ (bcmsdh_reg_read(bus->sdh, 0x1810980C, 4) == 5) ||
+ (bcmsdh_reg_read(bus->sdh, 0x1810C80C, 4) == 5) ||
+ (bcmsdh_reg_read(bus->sdh, 0x1810C80C, 4) == 5))
+ {
+ if (++counter > 10)
+ {
+ DHD_ERROR(("Unable to recover the backkplane corruption"
+ "..Tried %d times.. Exiting\n", counter));
+ break;
+ }
+ OSL_DELAY(10000);
+ dhd_sdio_backplane_reset(bus);
+ /*
+ Get the information of who accessed the crucial backplane
+ entities by reading read and write access registers
+ */
+ DHD_ERROR(("%d: Read Value @ 0x18104808 = %x."
+ "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18104808, 4)));
+ DHD_ERROR(("%d: Read Value @ 0x1810480C = %x."
+ "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810480C, 4)));
+ DHD_ERROR(("%d: Read Value @ 0x18106808 = %x."
+ "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18106808, 4)));
+ DHD_ERROR(("%d: Read Value @ 0x1810680C = %x."
+ "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810680C, 4)));
+ DHD_ERROR(("%d: Read Value @ 0x18107808 = %x."
+ "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18107808, 4)));
+ DHD_ERROR(("%d: Read Value @ 0x1810780C = %x."
+ "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810780C, 4)));
+ DHD_ERROR(("%d: Read Value @ 0x18108808 = %x."
+ "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18108808, 4)));
+ DHD_ERROR(("%d: Read Value @ 0x1810880C = %x."
+ "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810880C, 4)));
+ DHD_ERROR(("%d: Read Value @ 0x18109808 = %x."
+ "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18109808, 4)));
+ DHD_ERROR(("%d: Read Value @ 0x1810980C = %x."
+ "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810980C, 4)));
+ DHD_ERROR(("%d: Read Value @ 0x1810C808 = %x."
+ "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810c808, 4)));
+ DHD_ERROR(("%d: Read Value @ 0x1810C80C = %x."
+ "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810c80C, 4)));
+ }
+ /* Set the WL ready to indicate BT that we are done with backplane reset */
+ DHD_ERROR(("Setting up AXI_OK\n"));
+ bcmsdh_reg_write(bus->sdh, 0x18000658, 4, 0x3);
+ temp = bcmsdh_reg_read(bus->sdh, 0x1800065c, 4);
+ temp |= 0x80000000;
+ bcmsdh_reg_write(bus->sdh, 0x1800065c, 4, temp);
+ return TRUE;
+}
+#endif /* REGON_BP_HANG_FIX */
static bool
dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
uint16 devid)
@@ -7031,6 +7773,12 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
goto fail;
}
+#ifdef REGON_BP_HANG_FIX
+ /* WAR - for 43241 B0-B1-B2. B3 onwards do not need this */
+ if (((uint16)bus->sih->chip == BCM4324_CHIP_ID) && (bus->sih->chiprev < 3))
+ dhdsdio_sdio_hang_war(bus);
+#endif /* REGON_BP_HANG_FIX */
+
bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev);
if (!dhdsdio_chipmatch((uint16)bus->sih->chip)) {
@@ -7062,10 +7810,10 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
}
if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
- if (!(bus->orig_ramsize = si_socram_size(bus->sih))) {
- DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__));
- goto fail;
- }
+ if (!(bus->orig_ramsize = si_socram_size(bus->sih))) {
+ DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__));
+ goto fail;
+ }
} else {
/* cr4 has a different way to find the RAM size from TCM's */
if (!(bus->orig_ramsize = si_tcm_size(bus->sih))) {
@@ -7073,14 +7821,28 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
goto fail;
}
/* also populate base address */
- bus->dongle_ram_base = CR4_RAM_BASE;
+ switch ((uint16)bus->sih->chip) {
+ case BCM4335_CHIP_ID:
+ bus->dongle_ram_base = CR4_4335_RAM_BASE;
+ break;
+ case BCM4350_CHIP_ID:
+ bus->dongle_ram_base = CR4_4350_RAM_BASE;
+ break;
+ case BCM4360_CHIP_ID:
+ bus->dongle_ram_base = CR4_4360_RAM_BASE;
+ break;
+ default:
+ bus->dongle_ram_base = 0;
+ DHD_ERROR(("%s: WARNING: Using default ram base at 0x%x\n",
+ __FUNCTION__, bus->dongle_ram_base));
+ }
}
bus->ramsize = bus->orig_ramsize;
if (dhd_dongle_memsize)
dhd_dongle_setmemsize(bus, dhd_dongle_memsize);
- DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d)\n",
- bus->ramsize, bus->orig_ramsize));
+ DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d) at 0x%x\n",
+ bus->ramsize, bus->orig_ramsize, bus->dongle_ram_base));
bus->srmemsize = si_socram_srmem_size(bus->sih);
}
@@ -7123,7 +7885,7 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
#ifdef BCMSDIOH_TXGLOM
/* Setting default Glom mode */
- bus->glom_mode = SDPCM_TXGLOM_CPY;
+ bus->glom_mode = bcmsdh_set_mode(bus->sdh, SDPCM_DEFGLOM_MODE);
/* Setting default Glom size */
bus->glomsize = SDPCM_DEFGLOM_SIZE;
#endif
@@ -7233,6 +7995,9 @@ dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh)
} else {
DHD_INFO(("%s: Initial value for %s is %d\n",
__FUNCTION__, "sd_blocksize", bus->blocksize));
+
+ if (bus->sih->chip == BCM4335_CHIP_ID)
+ dhd_overflow_war(bus);
}
bus->roundup = MIN(max_roundup, bus->blocksize);
@@ -7372,10 +8137,10 @@ dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool r
return;
if (bus->sih) {
+#if !defined(BCMLXSDMMC)
if (bus->dhd) {
dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
}
-#if !defined(BCMLXSDMMC)
if (KSO_ENAB(bus) && (dongle_isolation == FALSE))
si_watchdog(bus->sih, 4);
#endif /* !defined(BCMLXSDMMC) */
@@ -7397,8 +8162,9 @@ dhdsdio_disconnect(void *ptr)
{
dhd_bus_t *bus = (dhd_bus_t *)ptr;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) {
DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__));
}
@@ -7408,7 +8174,6 @@ dhdsdio_disconnect(void *ptr)
mutex_lock(&_dhd_sdio_mutex_lock_);
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
if (bus) {
ASSERT(bus->dhd);
@@ -7420,6 +8185,7 @@ dhdsdio_disconnect(void *ptr)
DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__));
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
+
DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
}
@@ -7475,6 +8241,17 @@ dhdsdio_download_code_array(struct dhd_bus *bus)
/* Download image */
while ((offset + MEMBLOCK) < sizeof(dlarray)) {
+ /* check if CR4 */
+ if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
+ /* if address is 0, store the reset instruction to be written in 0 */
+
+ if (offset == 0) {
+ bus->resetinstr = *(((uint32*)dlarray));
+ /* Add start of RAM address to the address given by user */
+ offset += bus->dongle_ram_base;
+ }
+ }
+
bcmerror = dhdsdio_membytes(bus, TRUE, offset,
(uint8 *) (dlarray + offset), MEMBLOCK);
if (bcmerror) {
@@ -7572,6 +8349,17 @@ dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path)
bcmerror = BCME_ERROR;
goto err;
}
+ /* check if CR4 */
+ if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
+ /* if address is 0, store the reset instruction to be written in 0 */
+
+ if (offset == 0) {
+ bus->resetinstr = *(((uint32*)memptr));
+ /* Add start of RAM address to the address given by user */
+ offset += bus->dongle_ram_base;
+ }
+ }
+
bcmerror = dhdsdio_membytes(bus, TRUE, offset, memptr, len);
if (bcmerror) {
DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
@@ -7721,6 +8509,7 @@ _dhdsdio_download_firmware(struct dhd_bus *bus)
dlok = TRUE;
}
}
+
#ifdef BCMEMBEDIMAGE
if (embed) {
if (dhdsdio_download_code_array(bus)) {
@@ -7791,9 +8580,9 @@ dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf
#ifdef BCMSDIOH_TXGLOM
static void
-dhd_bcmsdh_glom_post(dhd_bus_t *bus, uint8 *frame, uint len)
+dhd_bcmsdh_glom_post(dhd_bus_t *bus, uint8 *frame, void *pkt, uint len)
{
- bcmsdh_glom_post(bus->sdh, frame, len);
+ bcmsdh_glom_post(bus->sdh, frame, pkt, len);
}
static void
@@ -7947,23 +8736,6 @@ uint dhd_bus_chip_id(dhd_pub_t *dhdp)
return bus->sih->chip;
}
-
-/* Get Chip Rev ID version */
-uint dhd_bus_chiprev_id(dhd_pub_t *dhdp)
-{
- dhd_bus_t *bus = dhdp->bus;
-
- return bus->sih->chiprev;
-}
-
-/* Get Chip Pkg ID version */
-uint dhd_bus_chippkg_id(dhd_pub_t *dhdp)
-{
- dhd_bus_t *bus = dhdp->bus;
-
- return bus->sih->chippkg;
-}
-
int
dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size)
{
@@ -7972,7 +8744,7 @@ dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint si
bus = dhdp->bus;
return dhdsdio_membytes(bus, set, address, data, size);
}
-#if defined(SUPPORT_MULTIPLE_REVISION)
+#if defined(CUSTOMER_HW4) && defined(SUPPORT_MULTIPLE_REVISION)
static int
concate_revision_bcm4334(dhd_bus_t *bus, char *path, int path_len)
{
@@ -7982,7 +8754,7 @@ concate_revision_bcm4334(dhd_bus_t *bus, char *path, int path_len)
uint chipver;
uint32 unique_id;
uint8 data[4];
- char chipver_tag[4] = "_b0";
+ char chipver_tag[4] = "_b?";
DHD_TRACE(("%s: BCM4334 Multiple Revision Check\n", __FUNCTION__));
if (bus->sih->chip != BCM4334_CHIP_ID) {
@@ -7999,14 +8771,12 @@ concate_revision_bcm4334(dhd_bus_t *bus, char *path, int path_len)
DHD_ERROR(("CHIP VER = [0x%x]\n", chipver));
if (chipver == 1) {
DHD_ERROR(("----- CHIP bcm4334_B0 -----\n"));
- chipver_tag[2] = '0';
strcpy(chipver_tag, "_b0");
} else if (chipver == 2) {
DHD_ERROR(("----- CHIP bcm4334_B1 -----\n"));
- chipver_tag[2] = '1';
+ strcpy(chipver_tag, "_b1");
} else if (chipver == 3) {
DHD_ERROR(("----- CHIP bcm4334_B2 -----\n"));
- chipver_tag[2] = '2';
strcpy(chipver_tag, "_b2");
}
else {
@@ -8019,18 +8789,49 @@ concate_revision_bcm4334(dhd_bus_t *bus, char *path, int path_len)
return 0;
}
-int
-concate_revision(dhd_bus_t *bus, char *path, int path_len)
+static int
+concate_revision_bcm4335
+ (dhd_bus_t *bus, char *fw_path, int fw_path_len, char *nv_path, int nv_path_len)
{
+ uint chipver;
+ char chipver_tag[4] = {0, };
+
+ DHD_TRACE(("%s: BCM4335 Multiple Revision Check\n", __FUNCTION__));
+ if (bus->sih->chip != BCM4335_CHIP_ID) {
+ DHD_ERROR(("%s:Chip is not BCM4335\n", __FUNCTION__));
+ return -1;
+ }
+ chipver = bus->sih->chiprev;
+ DHD_ERROR(("CHIP VER = [0x%x]\n", chipver));
+ if (chipver == 0x0) {
+ DHD_ERROR(("----- CHIP bcm4335_A0 -----\n"));
+ strcpy(chipver_tag, "_a0");
+ } else if (chipver == 0x1) {
+ DHD_ERROR(("----- CHIP bcm4335_B0 -----\n"));
+ }
+ strcat(fw_path, chipver_tag);
+ strcat(nv_path, chipver_tag);
+
+ return 0;
+
+}
+int
+concate_revision(dhd_bus_t *bus, char *fw_path, int fw_path_len, char *nv_path, int nv_path_len)
+{
if (!bus || !bus->sih) {
DHD_ERROR(("%s:Bus is Invalid\n", __FUNCTION__));
return -1;
}
- if (bus->sih->chip == BCM4334_CHIP_ID) {
- return concate_revision_bcm4334(bus, path, path_len);
+ switch (bus->sih->chip) {
+ case BCM4334_CHIP_ID:
+ return concate_revision_bcm4334(bus, fw_path, fw_path_len);
+ case BCM4335_CHIP_ID:
+ return concate_revision_bcm4335(bus, fw_path, fw_path_len,
+ nv_path, nv_path_len);
}
+
DHD_ERROR(("REVISION SPECIFIC feature is not required\n"));
- return -1;
+ return 0;
}
-#endif /* MULTIPLE_REVISION */
+#endif /* CUSTOMER_HW4 && SUPPORT_MULTIPLE_REVISION */