diff options
author | sbrissen <sbrissen@hotmail.com> | 2013-04-24 13:09:33 -0400 |
---|---|---|
committer | sbrissen <sbrissen@hotmail.com> | 2013-04-25 10:50:50 -0400 |
commit | c421809918b7106b40a81134f9fb5103146fc715 (patch) | |
tree | 89b0147d51d2b2650c5ded666a08613ba0cab3c1 /drivers/net/wireless/bcmdhd/dhd_cdc.c | |
parent | 43aaedbcde478c8e032771d62a1956133b29b1d4 (diff) | |
download | kernel_samsung_smdk4412-c421809918b7106b40a81134f9fb5103146fc715.zip kernel_samsung_smdk4412-c421809918b7106b40a81134f9fb5103146fc715.tar.gz kernel_samsung_smdk4412-c421809918b7106b40a81134f9fb5103146fc715.tar.bz2 |
update bcmdhd driver from GT-9505 Source
drivers pulled from http://review.cyanogenmod.org/#/c/36122/
Change-Id: Ide4aef99ee1d594f4222ae69aca0bdb7d563e80a
Diffstat (limited to 'drivers/net/wireless/bcmdhd/dhd_cdc.c')
-rw-r--r-- | drivers/net/wireless/bcmdhd/dhd_cdc.c | 587 |
1 files changed, 378 insertions, 209 deletions
diff --git a/drivers/net/wireless/bcmdhd/dhd_cdc.c b/drivers/net/wireless/bcmdhd/dhd_cdc.c index cd44b92..9e405b0 100644 --- a/drivers/net/wireless/bcmdhd/dhd_cdc.c +++ b/drivers/net/wireless/bcmdhd/dhd_cdc.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_cdc.c 355825 2012-09-10 03:22:40Z $ + * $Id: dhd_cdc.c 390461 2013-03-12 07:21:34Z $ * * BDC is like CDC, except it includes a header for data packets to convey * packet priority over the bus, and flags (e.g. to indicate checksum status @@ -69,11 +69,10 @@ typedef struct dhd_wlfc_commit_info { } dhd_wlfc_commit_info_t; #endif /* PROP_TXSTATUS */ -#if defined(CUSTOMER_HW4) && defined(DYNAMIC_F2_BLKSIZE_OF_PROPTXSTATUS) +#if defined(CUSTOMER_HW4) && defined(USE_DYNAMIC_F2_BLKSIZE) extern uint sd_f2_blocksize; -extern int -dhdsdio_func_blocksize(dhd_pub_t *dhd, int function_num, int block_size); -#endif /* CUSTOMER_HW4 && DYNAMIC_F2_BLKSIZE_OF_PROPTXSTATUS */ +extern int dhdsdio_func_blocksize(dhd_pub_t *dhd, int function_num, int block_size); +#endif /* CUSTOMER_HW4 && USE_DYNAMIC_F2_BLKSIZE */ typedef struct dhd_prot { uint16 reqid; @@ -121,7 +120,7 @@ dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len) #if defined(CUSTOMER_HW4) DHD_OS_WAKE_LOCK(dhd); -#endif +#endif /* OEM_ANDROID && CUSTOMER_HW4 */ do { ret = dhd_bus_rxctl(dhd->bus, (uchar*)&prot->msg, cdc_len); @@ -131,7 +130,7 @@ dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len) #if defined(CUSTOMER_HW4) DHD_OS_WAKE_UNLOCK(dhd); -#endif +#endif /* OEM_ANDROID && CUSTOMER_HW4 */ return ret; } @@ -234,9 +233,9 @@ done: return ret; } -#ifdef CONFIG_CONTROL_PM +#if defined(CUSTOMER_HW4) && defined(CONFIG_CONTROL_PM) extern bool g_pm_control; -#endif +#endif /* CUSTOMER_HW4 & CONFIG_CONTROL_PM */ static int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) @@ -261,13 +260,13 @@ dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 return -EIO; } -#ifdef CONFIG_CONTROL_PM +#if defined(CUSTOMER_HW4) && defined(CONFIG_CONTROL_PM) if ((g_pm_control == TRUE) && (cmd == WLC_SET_PM)) { DHD_ERROR(("SET PM ignored!!!!!!!!!!!!!!!!!!!!!!\n")); goto done; } -#endif +#endif /* CUSTOMER_HW4 && CONFIG_CONTROL_PM */ memset(msg, 0, sizeof(cdc_ioctl_t)); @@ -441,29 +440,21 @@ dhd_wlfc_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) } bcm_bprintf(strbuf, "wlfc fail(tlv,credit_rqst,mac_update,psmode_update), " - "(dq_full,sendq_full, rollback_fail) = (%d,%d,%d,%d), (%d,%d,%d)\n", + "(dq_full,rollback_fail) = (%d,%d,%d,%d), (%d,%d)\n", wlfc->stats.tlv_parse_failed, wlfc->stats.credit_request_failed, wlfc->stats.mac_update_failed, wlfc->stats.psmode_update_failed, wlfc->stats.delayq_full_error, - wlfc->stats.sendq_full_error, wlfc->stats.rollback_failed); - bcm_bprintf(strbuf, "SENDQ (len,credit,sent) " - "(AC0[%d,%d,%d],AC1[%d,%d,%d],AC2[%d,%d,%d],AC3[%d,%d,%d],BC_MC[%d,%d,%d])\n", - wlfc->SENDQ.q[0].len, wlfc->FIFO_credit[0], wlfc->stats.sendq_pkts[0], - wlfc->SENDQ.q[1].len, wlfc->FIFO_credit[1], wlfc->stats.sendq_pkts[1], - wlfc->SENDQ.q[2].len, wlfc->FIFO_credit[2], wlfc->stats.sendq_pkts[2], - wlfc->SENDQ.q[3].len, wlfc->FIFO_credit[3], wlfc->stats.sendq_pkts[3], - wlfc->SENDQ.q[4].len, wlfc->FIFO_credit[4], wlfc->stats.sendq_pkts[4]); - -#ifdef PROP_TXSTATUS_DEBUG - bcm_bprintf(strbuf, "SENDQ dropped: AC[0-3]:(%d,%d,%d,%d), (bcmc,atim):(%d,%d)\n", - wlfc->stats.dropped_qfull[0], wlfc->stats.dropped_qfull[1], - wlfc->stats.dropped_qfull[2], wlfc->stats.dropped_qfull[3], - wlfc->stats.dropped_qfull[4], wlfc->stats.dropped_qfull[5]); -#endif + bcm_bprintf(strbuf, "PKTS (credit,sent) " + "(AC0[%d,%d],AC1[%d,%d],AC2[%d,%d],AC3[%d,%d],BC_MC[%d,%d])\n", + wlfc->FIFO_credit[0], wlfc->stats.send_pkts[0], + wlfc->FIFO_credit[1], wlfc->stats.send_pkts[1], + wlfc->FIFO_credit[2], wlfc->stats.send_pkts[2], + wlfc->FIFO_credit[3], wlfc->stats.send_pkts[3], + wlfc->FIFO_credit[4], wlfc->stats.send_pkts[4]); bcm_bprintf(strbuf, "\n"); for (i = 0; i < WLFC_MAX_IFNUM; i++) { @@ -659,6 +650,8 @@ dhd_wlfc_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) wlfc->stats.psq_d11sup_retx, wlfc->stats.psq_wlsup_retx, wlfc->stats.psq_hostq_retx); + bcm_bprintf(strbuf, "wlfc- generic error: %d", wlfc->stats.generic_error); + return; } @@ -703,13 +696,22 @@ dhd_wlfc_hanger_delete(osl_t *osh, void* hanger) static uint16 dhd_wlfc_hanger_get_free_slot(void* hanger) { - int i; + uint32 i; wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; if (h) { - for (i = 0; i < h->max_items; i++) { - if (h->items[i].state == WLFC_HANGER_ITEM_STATE_FREE) + i = h->slot_pos + 1; + if (i == h->max_items) { + i = 0; + } + while (i != h->slot_pos) { + if (h->items[i].state == WLFC_HANGER_ITEM_STATE_FREE) { + h->slot_pos = i; return (uint16)i; + } + i++; + if (i == h->max_items) + i = 0; } h->failed_slotfind++; } @@ -895,6 +897,7 @@ _dhd_wlfc_pullheader(athost_wl_status_info_t* ctx, void* pktbuf) PKTLEN(ctx->osh, pktbuf), (h->dataOffset << 2))); return BCME_ERROR; } + /* pull wl-header */ PKTPULL(ctx->osh, pktbuf, (h->dataOffset << 2)); return BCME_OK; @@ -933,8 +936,6 @@ _dhd_wlfc_rollback_packet_toq(athost_wl_status_info_t* ctx, /* put the packet back to the head of queue - - a packet from send-q will need to go back to send-q and not delay-q - since that will change the order of packets. - suppressed packet goes back to suppress sub-queue - pull out the header, if new or delayed packet @@ -958,7 +959,7 @@ _dhd_wlfc_rollback_packet_toq(athost_wl_status_info_t* ctx, else { /* remove header first */ rc = _dhd_wlfc_pullheader(ctx, p); - if (rc != BCME_OK) { + if (rc != BCME_OK) { WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); /* free the hanger slot */ dhd_wlfc_hanger_poppkt(ctx->hanger, hslot, &pktout, 1); @@ -974,13 +975,7 @@ _dhd_wlfc_rollback_packet_toq(athost_wl_status_info_t* ctx, rc = BCME_ERROR; } } - else { - /* these are going to SENDQ */ - if (WLFC_PKTQ_PENQ_HEAD(&ctx->SENDQ, prec, p) == NULL) { - WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - rc = BCME_ERROR; - } - } + /* free the hanger slot */ dhd_wlfc_hanger_poppkt(ctx->hanger, hslot, &pktout, 1); @@ -1018,7 +1013,9 @@ _dhd_wlfc_flow_control_check(athost_wl_status_info_t* ctx, struct pktq* pq, uint pq->len, if_id, __FUNCTION__)); */ WLFC_DBGMESG(("F")); + dhd_txflowcontrol(ctx->dhdp, if_id, OFF); + ctx->toggle_host_if = 0; } if ((pq->len >= WLFC_FLOWCONTROL_HIWATER) && (ctx->hostif_flow_state[if_id] == OFF)) { @@ -1029,7 +1026,9 @@ _dhd_wlfc_flow_control_check(athost_wl_status_info_t* ctx, struct pktq* pq, uint pq->len, if_id, __FUNCTION__)); */ WLFC_DBGMESG(("N")); + dhd_txflowcontrol(ctx->dhdp, if_id, ON); + ctx->host_ifidx = if_id; ctx->toggle_host_if = 1; } @@ -1176,6 +1175,7 @@ _dhd_wlfc_pretx_pktprocess(athost_wl_status_info_t* ctx, WL_TXSTATUS_SET_FLAGS(htod, WLFC_PKTFLAG_PKTFROMHOST); WL_TXSTATUS_SET_FIFO(htod, DHD_PKTTAG_FIFO(PKTTAG(p))); + if (!DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) { /* Indicate that this packet is being sent in response to an @@ -1287,7 +1287,7 @@ _dhd_wlfc_deque_delayedq(athost_wl_status_info_t* ctx, * i.e. suppressed packets before delayed ones */ NBITVAL((prec << 1) + 1), &pout); - *needs_hdr = 0; + *needs_hdr = 0; if (p == NULL) { if (entry->suppressed == TRUE) { @@ -1348,56 +1348,44 @@ _dhd_wlfc_deque_delayedq(athost_wl_status_info_t* ctx, return NULL; } -static void* -_dhd_wlfc_deque_sendq(athost_wl_status_info_t* ctx, int prec) +static int +_dhd_wlfc_enque_delayq(athost_wl_status_info_t* ctx, void* pktbuf, int prec) { wlfc_mac_descriptor_t* entry; - void* p; - - p = pktq_pdeq(&ctx->SENDQ, prec); - if (p != NULL) { - if (ETHER_ISMULTI(DHD_PKTTAG_DSTN(PKTTAG(p)))) - /* bc/mc packets do not have a delay queue */ - return p; - - entry = _dhd_wlfc_find_table_entry(ctx, p); + if (pktbuf != NULL) { + entry = _dhd_wlfc_find_table_entry(ctx, pktbuf); if (entry == NULL) { WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return p; + return BCME_ERROR; } - while ((p != NULL)) { - /* - - suppressed packets go to sub_queue[2*prec + 1] AND - - delayed packets go to sub_queue[2*prec + 0] to ensure - order of delivery. - */ - if (WLFC_PKTQ_PENQ(&entry->psq, (prec << 1), p) == NULL) { - WLFC_DBGMESG(("D")); - /* dhd_txcomplete(ctx->dhdp, p, FALSE); */ - PKTFREE(ctx->osh, p, TRUE); - ctx->stats.delayq_full_error++; - } - /* - A packet has been pushed, update traffic availability bitmap, - if applicable - */ - _dhd_wlfc_traffic_pending_check(ctx, entry, prec); - - p = pktq_pdeq(&ctx->SENDQ, prec); - if (p == NULL) - break; - - entry = _dhd_wlfc_find_table_entry(ctx, p); - - if ((entry == NULL) || (ETHER_ISMULTI(DHD_PKTTAG_DSTN(PKTTAG(p))))) { - return p; - } + /* + - suppressed packets go to sub_queue[2*prec + 1] AND + - delayed packets go to sub_queue[2*prec + 0] to ensure + order of delivery. + */ + if (WLFC_PKTQ_PENQ(&entry->psq, (prec << 1), pktbuf) == NULL) { + WLFC_DBGMESG(("D")); + /* dhd_txcomplete(ctx->dhdp, p, FALSE); */ + PKTFREE(ctx->osh, pktbuf, TRUE); + ctx->stats.delayq_full_error++; + return BCME_ERROR; } + /* + A packet has been pushed, update traffic availability bitmap, + if applicable + */ + _dhd_wlfc_traffic_pending_check(ctx, entry, prec); + } - return p; + return BCME_OK; +} + +bool ifpkt_fn(void* p, int ifid) +{ + return (ifid == DHD_PKTTAG_IF(PKTTAG(p))); } static int @@ -1436,6 +1424,12 @@ _dhd_wlfc_mac_entry_update(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* /* enable after packets are queued-deqeued properly. pktq_flush(dhd->osh, &entry->psq, FALSE, NULL, 0); */ + + memset(&entry->ea[0],0, ETHER_ADDR_LEN); + entry->transit_count = 0; + entry->suppr_transit_count = 0; + entry->suppress_count = 0; + entry->suppressed = 0; } return rc; } @@ -1471,12 +1465,16 @@ dhd_wlfc_interface_entry_update(void* state, { athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; wlfc_mac_descriptor_t* entry; + int ret; if (ifid >= WLFC_MAX_IFNUM) return BCME_BADARG; entry = &ctx->destination_entries.interfaces[ifid]; - return _dhd_wlfc_mac_entry_update(ctx, entry, action, ifid, iftype, ea); + ret = _dhd_wlfc_mac_entry_update(ctx, entry, action, ifid, iftype, ea); + if (action == eWLFC_MAC_ENTRY_ACTION_DEL) + dhd_wlfc_cleanup(ctx->dhdp, ifpkt_fn, ifid); + return ret; } int @@ -1497,34 +1495,6 @@ dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits) } int -dhd_wlfc_enque_sendq(void* state, int prec, void* p) -{ - athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; - - if ((state == NULL) || - /* prec = AC_COUNT is used for bc/mc queue */ - (prec > AC_COUNT) || - (p == NULL)) { - WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - if (FALSE == dhd_prec_enq(ctx->dhdp, &ctx->SENDQ, p, prec)) { - ctx->stats.sendq_full_error++; - /* - WLFC_DBGMESG(("Error: %s():%d, qlen:%d\n", - __FUNCTION__, __LINE__, ctx->SENDQ.len)); - */ - WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, prec); - WLFC_DBGMESG(("Q")); - PKTFREE(ctx->osh, p, TRUE); - return BCME_ERROR; - } - ctx->stats.pktin++; - /* _dhd_wlfc_flow_control_check(ctx, &ctx->SENDQ, DHD_PKTTAG_IF(PKTTAG(p))); */ - return BCME_OK; -} - -int _dhd_wlfc_handle_packet_commit(athost_wl_status_info_t* ctx, int ac, dhd_wlfc_commit_info_t *commit_info, f_commitpkt_t fcommit, void* commit_ctx) { @@ -1556,10 +1526,11 @@ _dhd_wlfc_handle_packet_commit(athost_wl_status_info_t* ctx, int ac, if (rc == BCME_OK) { ctx->stats.pkt2bus++; if (commit_info->ac_fifo_credit_spent) { - ctx->stats.sendq_pkts[ac]++; + ctx->stats.send_pkts[ac]++; WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac); } - } + } else if (rc == BCME_NORESOURCE) + rc = BCME_ERROR; else { /* bus commit has failed, rollback. @@ -1578,7 +1549,7 @@ _dhd_wlfc_handle_packet_commit(athost_wl_status_info_t* ctx, int ac, } int -dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx) +dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx, void *pktbuf) { int ac; int credit; @@ -1610,45 +1581,51 @@ dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx) low priority packet starvation. */ - for (ac = AC_COUNT; ac >= 0; ac--) { - - int initial_credit_count = ctx->FIFO_credit[ac]; - - /* packets from SENDQ are fresh and they'd need header and have no MAC entry */ - commit_info.needs_hdr = 1; - commit_info.mac_entry = NULL; - commit_info.pkt_type = eWLFC_PKTTYPE_NEW; - - do { - commit_info.p = _dhd_wlfc_deque_sendq(ctx, ac); - if (commit_info.p == NULL) - break; - else if (ETHER_ISMULTI(DHD_PKTTAG_DSTN(PKTTAG(commit_info.p)))) { + if (pktbuf) { + ac = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); + if (ETHER_ISMULTI(DHD_PKTTAG_DSTN(PKTTAG(pktbuf)))) { ASSERT(ac == AC_COUNT); - - if (ctx->FIFO_credit[ac]) { - rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, - fcommit, commit_ctx); + commit_info.needs_hdr = 1; + commit_info.mac_entry = NULL; + commit_info.pkt_type = eWLFC_PKTTYPE_NEW; + commit_info.p = pktbuf; + if (ctx->FIFO_credit[ac]) { + rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, + fcommit, commit_ctx); /* Bus commits may fail (e.g. flow control); abort after retries */ - if (rc == BCME_OK) { - if (commit_info.ac_fifo_credit_spent) { - (void) _dhd_wlfc_borrow_credit(ctx, - ac_available, ac); - credit_count--; - } - } else { - bus_retry_count++; - if (bus_retry_count >= BUS_RETRIES) { - DHD_ERROR((" %s: bus error\n", - __FUNCTION__)); - return rc; - } + if (rc == BCME_OK) { + if (commit_info.ac_fifo_credit_spent) { + (void) _dhd_wlfc_borrow_credit(ctx, + ac_available, ac); + credit_count--; + } + } else { + bus_retry_count++; + if (bus_retry_count >= BUS_RETRIES) { + DHD_ERROR((" %s: bus error %d\n", + __FUNCTION__, rc)); + return rc; } } } + } + else { + /* en-queue the packets to respective queue. */ + rc = _dhd_wlfc_enque_delayq(ctx, pktbuf, ac); + } + } + + for (ac = AC_COUNT; ac >= 0; ac--) { - } while (commit_info.p); + int initial_credit_count = ctx->FIFO_credit[ac]; + + /* packets from delayQ with less priority are fresh and they'd need header and + * have no MAC entry + */ + commit_info.needs_hdr = 1; + commit_info.mac_entry = NULL; + commit_info.pkt_type = eWLFC_PKTTYPE_NEW; for (credit = 0; credit < ctx->FIFO_credit[ac];) { commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac, @@ -1674,7 +1651,7 @@ dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx) else { bus_retry_count++; if (bus_retry_count >= BUS_RETRIES) { - DHD_ERROR(("dhd_wlfc_commit_packets(): bus error\n")); + DHD_ERROR(("%s: bus error %d\n", __FUNCTION__, rc)); ctx->FIFO_credit[ac] -= credit; return rc; } @@ -1760,7 +1737,7 @@ dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx) else { bus_retry_count++; if (bus_retry_count >= BUS_RETRIES) { - DHD_ERROR(("dhd_wlfc_commit_packets(): bus error\n")); + DHD_ERROR(("%s: bus error %d\n", __FUNCTION__, rc)); return rc; } } @@ -1794,15 +1771,13 @@ dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success) void* p; int fifo_id; - dhd_os_wlfc_block(dhd); if (DHD_PKTTAG_SIGNALONLY(PKTTAG(txp))) { #ifdef PROP_TXSTATUS_DEBUG wlfc->stats.signal_only_pkts_freed++; #endif + /* is this a signal-only packet? */ if (success) - /* is this a signal-only packet? */ PKTFREE(wlfc->osh, txp, TRUE); - dhd_os_wlfc_unblock(dhd); return; } if (!success) { @@ -1837,10 +1812,182 @@ dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success) PKTFREE(wlfc->osh, txp, TRUE); } - dhd_os_wlfc_unblock(dhd); return; } +static int +dhd_wlfc_compressed_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info, uint8 len) +{ + uint8 status_flag; + uint32 status; + int ret; + int remove_from_hanger = 1; + void* pktbuf; + uint8 fifo_id; + uint8 count = 0; + uint32 status_g; + uint32 hslot, hcnt; + wlfc_mac_descriptor_t* entry = NULL; + athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) + dhd->wlfc_state; + + memcpy(&status, pkt_info, sizeof(uint32)); + status_flag = WL_TXSTATUS_GET_FLAGS(status); + status_g = status & 0xff000000; + hslot = (status & 0x00ffff00) >> 8; + hcnt = status & 0xff; + len = pkt_info[4]; + + wlfc->stats.txstatus_in++; + + if (status_flag == WLFC_CTL_PKTFLAG_DISCARD) { + wlfc->stats.pkt_freed++; + } + + else if (status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) { + wlfc->stats.d11_suppress++; + remove_from_hanger = 0; + } + + else if (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS) { + wlfc->stats.wl_suppress++; + remove_from_hanger = 0; + } + + else if (status_flag == WLFC_CTL_PKTFLAG_TOSSED_BYWLC) { + wlfc->stats.wlc_tossed_pkts++; + } + while (count < len) { + status = (status_g << 24) | (hslot << 8) | (hcnt); + count++; + hslot++; + hcnt++; + + ret = dhd_wlfc_hanger_poppkt(wlfc->hanger, + WLFC_PKTID_HSLOT_GET(status), &pktbuf, remove_from_hanger); + if (ret != BCME_OK) { + /* do something */ + continue; + } + + entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); + + if (!remove_from_hanger) { + /* this packet was suppressed */ + if (!entry->suppressed || entry->generation != WLFC_PKTID_GEN(status)) { + entry->suppressed = TRUE; + entry->suppress_count = pktq_mlen(&entry->psq, + NBITVAL((WL_TXSTATUS_GET_FIFO(status) << 1) + 1)); + entry->suppr_transit_count = entry->transit_count; + } + entry->generation = WLFC_PKTID_GEN(status); + } + +#ifdef PROP_TXSTATUS_DEBUG + { + uint32 new_t = OSL_SYSUPTIME(); + uint32 old_t; + uint32 delta; + old_t = ((wlfc_hanger_t*)(wlfc->hanger))->items[ + WLFC_PKTID_HSLOT_GET(status)].push_time; + + + wlfc->stats.latency_sample_count++; + if (new_t > old_t) + delta = new_t - old_t; + else + delta = 0xffffffff + new_t - old_t; + wlfc->stats.total_status_latency += delta; + wlfc->stats.latency_most_recent = delta; + + wlfc->stats.deltas[wlfc->stats.idx_delta++] = delta; + if (wlfc->stats.idx_delta == sizeof(wlfc->stats.deltas)/sizeof(uint32)) + wlfc->stats.idx_delta = 0; + } +#endif /* PROP_TXSTATUS_DEBUG */ + + fifo_id = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); + + /* pick up the implicit credit from this packet */ + if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pktbuf))) { + if (wlfc->proptxstatus_mode == WLFC_FCMODE_IMPLIED_CREDIT) { + + int lender, credit_returned = 0; /* Note that borrower is fifo_id */ + + /* Return credits to highest priority lender first */ + for (lender = AC_COUNT; lender >= 0; lender--) { + if (wlfc->credits_borrowed[fifo_id][lender] > 0) { + wlfc->FIFO_credit[lender]++; + wlfc->credits_borrowed[fifo_id][lender]--; + credit_returned = 1; + break; + } + } + + if (!credit_returned) { + wlfc->FIFO_credit[fifo_id]++; + } + } + } + else { + /* + if this packet did not count against FIFO credit, it must have + taken a requested_credit from the destination entry (for pspoll etc.) + */ + if (!entry) { + + entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); + } + if (!DHD_PKTTAG_ONETIMEPKTRQST(PKTTAG(pktbuf))) + entry->requested_credit++; +#ifdef PROP_TXSTATUS_DEBUG + entry->dstncredit_acks++; +#endif + } + if ((status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) || + (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS)) { + + ret = _dhd_wlfc_enque_suppressed(wlfc, fifo_id, pktbuf); + if (ret != BCME_OK) { + /* delay q is full, drop this packet */ + dhd_wlfc_hanger_poppkt(wlfc->hanger, WLFC_PKTID_HSLOT_GET(status), + &pktbuf, 1); + + /* indicate failure and free the packet */ + dhd_txcomplete(dhd, pktbuf, FALSE); + entry->transit_count--; + /* packet is transmitted Successfully by dongle + * after first suppress. + */ + if (entry->suppressed) { + entry->suppr_transit_count--; + } + PKTFREE(wlfc->osh, pktbuf, TRUE); + } else { + /* Mark suppressed to avoid a double free during wlfc cleanup */ + + dhd_wlfc_hanger_mark_suppressed(wlfc->hanger, + WLFC_PKTID_HSLOT_GET(status), WLFC_PKTID_GEN(status)); + entry->suppress_count++; + } + } + else { + dhd_txcomplete(dhd, pktbuf, TRUE); + entry->transit_count--; + + /* This packet is transmitted Successfully by dongle + * even after first suppress. + */ + if (entry->suppressed) { + entry->suppr_transit_count--; + } + /* free the packet */ + PKTFREE(wlfc->osh, pktbuf, TRUE); + } + } + return BCME_OK; +} + /* Handle discard or suppress indication */ static int dhd_wlfc_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info) @@ -1891,7 +2038,7 @@ dhd_wlfc_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info) if (!entry->suppressed || entry->generation != WLFC_PKTID_GEN(status)) { entry->suppressed = TRUE; entry->suppress_count = pktq_mlen(&entry->psq, - NBITVAL((WL_TXSTATUS_GET_FIFO(status) << 1) + 1)); + NBITVAL((WL_TXSTATUS_GET_FIFO(status) << 1) + 1)); entry->suppr_transit_count = entry->transit_count; } entry->generation = WLFC_PKTID_GEN(status); @@ -1970,15 +2117,14 @@ dhd_wlfc_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info) /* indicate failure and free the packet */ dhd_txcomplete(dhd, pktbuf, FALSE); entry->transit_count--; - /* This packet is transmitted Successfully by - * dongle even after first suppress. - */ + /* packet is transmitted Successfully by dongle after first suppress. */ if (entry->suppressed) { entry->suppr_transit_count--; } PKTFREE(wlfc->osh, pktbuf, TRUE); } else { /* Mark suppressed to avoid a double free during wlfc cleanup */ + dhd_wlfc_hanger_mark_suppressed(wlfc->hanger, WLFC_PKTID_HSLOT_GET(status), WLFC_PKTID_GEN(status)); entry->suppress_count++; @@ -2293,6 +2439,8 @@ dhd_wlfc_parse_header_info(dhd_pub_t *dhd, void* pktbuf, int tlv_hdr_len, uchar processed += 2 + len; if (type == WLFC_CTL_TYPE_TXSTATUS) dhd_wlfc_txstatus_update(dhd, value); + if (type == WLFC_CTL_TYPE_COMP_TXSTATUS) + dhd_wlfc_compressed_txstatus_update(dhd, value, len); else if (type == WLFC_CTL_TYPE_HOST_REORDER_RXPKTS) dhd_wlfc_reorderinfo_indicate(value, len, reorder_info_buf, @@ -2380,7 +2528,10 @@ dhd_wlfc_enable(dhd_pub_t *dhd) /* allocate space to track txstatus propagated from firmware */ dhd->wlfc_state = MALLOC(dhd->osh, sizeof(athost_wl_status_info_t)); if (dhd->wlfc_state == NULL) + { + DHD_ERROR(("Failed to malloc dhd->wlfc_state\n")); return BCME_NOMEM; + } /* initialize state space */ wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; @@ -2403,12 +2554,6 @@ dhd_wlfc_enable(dhd_pub_t *dhd) wlfc->hostif_flow_state[i] = OFF; } - /* - create the SENDQ containing - sub-queues for all AC precedences + 1 for bc/mc traffic - */ - pktq_init(&wlfc->SENDQ, (AC_COUNT + 1), WLFC_SENDQ_LEN); - wlfc->destination_entries.other.state = WLFC_STATE_OPEN; /* bc/mc FIFO is always open [credit aside], i.e. b[5] */ wlfc->destination_entries.other.ac_bitmap = 0x1f; @@ -2418,15 +2563,15 @@ dhd_wlfc_enable(dhd_pub_t *dhd) wlfc->allow_credit_borrow = TRUE; wlfc->borrow_defer_timestamp = 0; -#if defined(CUSTOMER_HW4) && defined(DYNAMIC_F2_BLKSIZE_OF_PROPTXSTATUS) - dhdsdio_func_blocksize(dhd, 2, VSDB_F2_BLKSIZE); -#endif /* CUSTOMER_HW4 && DYNAMIC_F2_BLKSIZE_OF_PROPTXSTATUS */ +#if defined(CUSTOMER_HW4) && defined(USE_DYNAMIC_F2_BLKSIZE) + dhdsdio_func_blocksize(dhd, 2, DYNAMIC_F2_BLKSIZE_FOR_NONLEGACY); +#endif /* CUSTOMER_HW4 && USE_DYNAMIC_F2_BLKSIZE */ return BCME_OK; } /* release all packet resources */ void -dhd_wlfc_cleanup(dhd_pub_t *dhd) +dhd_wlfc_cleanup(dhd_pub_t *dhd, ifpkt_cb_t fn, int arg) { int i; int total_entries; @@ -2448,29 +2593,25 @@ dhd_wlfc_cleanup(dhd_pub_t *dhd) table = (wlfc_mac_descriptor_t*)&wlfc->destination_entries; for (i = 0; i < total_entries; i++) { - if (table[i].occupied) { + if (table[i].occupied && (fn == NULL || (arg == table[i].interface_id))) { if (table[i].psq.len) { WLFC_DBGMESG(("%s(): DELAYQ[%d].len = %d\n", __FUNCTION__, i, table[i].psq.len)); /* release packets held in DELAYQ */ - pktq_flush(wlfc->osh, &table[i].psq, TRUE, NULL, 0); + pktq_flush(wlfc->osh, &table[i].psq, TRUE, fn, arg); } - table[i].occupied = 0; + if (fn == NULL) + table[i].occupied = 0; } } - /* release packets held in SENDQ */ - if (wlfc->SENDQ.len) - pktq_flush(wlfc->osh, &wlfc->SENDQ, TRUE, NULL, 0); for (prec = 0; prec < txq->num_prec; prec++) { - pkt = pktq_pdeq(txq, prec); + pkt = pktq_pdeq_with_fn(txq, prec, fn, arg); while (pkt) { for (i = 0; i < h->max_items; i++) { if (pkt == h->items[i].pkt) { if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) { PKTFREE(wlfc->osh, h->items[i].pkt, TRUE); h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; - h->items[i].pkt = NULL; - h->items[i].identifier = 0; } else if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED) { /* These are already freed from the psq */ @@ -2485,17 +2626,15 @@ dhd_wlfc_cleanup(dhd_pub_t *dhd) /* flush remained pkt in hanger queue, not in bus->txq */ for (i = 0; i < h->max_items; i++) { if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) { - if (!dhd->hang_was_sent) { + if (fn == NULL || (*fn)(h->items[i].pkt, arg)) { PKTFREE(wlfc->osh, h->items[i].pkt, TRUE); - } else { - printk("%s: Skip freeing skb %p\n", __func__, h->items[i].pkt); + h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; } - h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; - h->items[i].pkt = NULL; - h->items[i].identifier = 0; } else if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED) { - /* These are freed from the psq so no need to free again */ - h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; + if (fn == NULL || (*fn)(h->items[i].pkt, arg)) { + /* These are freed from the psq so no need to free again */ + h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; + } } } return; @@ -2513,6 +2652,7 @@ dhd_wlfc_deinit(dhd_pub_t *dhd) dhd_os_wlfc_unblock(dhd); return; } + #ifdef PROP_TXSTATUS_DEBUG { int i; @@ -2532,10 +2672,10 @@ dhd_wlfc_deinit(dhd_pub_t *dhd) /* free top structure */ MFREE(dhd->osh, dhd->wlfc_state, sizeof(athost_wl_status_info_t)); dhd->wlfc_state = NULL; -#if defined(CUSTOMER_HW4) && defined(DYNAMIC_F2_BLKSIZE_OF_PROPTXSTATUS) - dhdsdio_func_blocksize(dhd, 2, sd_f2_blocksize); -#endif /* CUSTOMER_HW4 && DYNAMIC_F2_BLKSIZE_OF_PROPTXSTATUS */ dhd_os_wlfc_unblock(dhd); +#if defined(CUSTOMER_HW4) && defined(USE_DYNAMIC_F2_BLKSIZE) + dhdsdio_func_blocksize(dhd, 2, sd_f2_blocksize); +#endif /* CUSTOMER_HW4 && USE_DYNAMIC_F2_BLKSIZE */ return; } #endif /* PROP_TXSTATUS */ @@ -2545,15 +2685,17 @@ dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) { bcm_bprintf(strbuf, "Protocol CDC: reqid %d\n", dhdp->prot->reqid); #ifdef PROP_TXSTATUS - dhd_os_wlfc_block(dhdp); if (dhdp->wlfc_state) dhd_wlfc_dump(dhdp, strbuf); - dhd_os_wlfc_unblock(dhdp); #endif } +/* The FreeBSD PKTPUSH could change the packet buf pinter + so we need to make it changable +*/ +#define PKTBUF pktbuf void -dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *pktbuf) +dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *PKTBUF) { #ifdef BDC struct bdc_header *h; @@ -2564,21 +2706,22 @@ dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *pktbuf) #ifdef BDC /* Push BDC header used to convey priority for buses that don't */ - PKTPUSH(dhd->osh, pktbuf, BDC_HEADER_LEN); + PKTPUSH(dhd->osh, PKTBUF, BDC_HEADER_LEN); - h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf); + h = (struct bdc_header *)PKTDATA(dhd->osh, PKTBUF); h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); - if (PKTSUMNEEDED(pktbuf)) + if (PKTSUMNEEDED(PKTBUF)) h->flags |= BDC_FLAG_SUM_NEEDED; - h->priority = (PKTPRIO(pktbuf) & BDC_PRIORITY_MASK); + h->priority = (PKTPRIO(PKTBUF) & BDC_PRIORITY_MASK); h->flags2 = 0; h->dataOffset = 0; #endif /* BDC */ BDC_SET_IF_IDX(h, ifidx); } +#undef PKTBUF /* Only defined in the above routine */ int dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf, uchar *reorder_buf_info, @@ -2587,6 +2730,7 @@ dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf, uchar *reorder_buf_in #ifdef BDC struct bdc_header *h; #endif + uint8 data_offset = 0; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); @@ -2603,15 +2747,23 @@ dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf, uchar *reorder_buf_in h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf); +#if defined(NDIS630) + h->dataOffset = 0; +#endif + + if (!ifidx) { + /* for tx packet, skip the analysis */ + data_offset = h->dataOffset; + PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN); + goto exit; + } + if ((*ifidx = BDC_GET_IF_IDX(h)) >= DHD_MAX_IFS) { DHD_ERROR(("%s: rx data ifnum out of range (%d)\n", __FUNCTION__, *ifidx)); return BCME_ERROR; } -#if defined(NDIS630) - h->dataOffset = 0; -#endif if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != BDC_PROTO_VER) { DHD_ERROR(("%s: non-BDC packet received, flags = 0x%x\n", dhd_ifname(dhd, *ifidx), h->flags)); @@ -2628,17 +2780,19 @@ dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf, uchar *reorder_buf_in } PKTSETPRIO(pktbuf, (h->priority & BDC_PRIORITY_MASK)); + data_offset = h->dataOffset; PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN); #endif /* BDC */ #if !defined(NDIS630) - if (PKTLEN(dhd->osh, pktbuf) < (uint32) (h->dataOffset << 2)) { + if (PKTLEN(dhd->osh, pktbuf) < (uint32) (data_offset << 2)) { DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__, - PKTLEN(dhd->osh, pktbuf), (h->dataOffset * 4))); + PKTLEN(dhd->osh, pktbuf), (data_offset * 4))); return BCME_ERROR; } #endif #ifdef PROP_TXSTATUS + dhd_os_wlfc_block(dhd); if (dhd->wlfc_state && ((athost_wl_status_info_t*)dhd->wlfc_state)->proptxstatus_mode != WLFC_FCMODE_NONE && @@ -2646,21 +2800,36 @@ dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf, uchar *reorder_buf_in /* - parse txstatus only for packets that came from the firmware */ - dhd_os_wlfc_block(dhd); - dhd_wlfc_parse_header_info(dhd, pktbuf, (h->dataOffset << 2), + dhd_wlfc_parse_header_info(dhd, pktbuf, (data_offset << 2), reorder_buf_info, reorder_info_len); ((athost_wl_status_info_t*)dhd->wlfc_state)->stats.dhd_hdrpulls++; - dhd_wlfc_commit_packets(dhd->wlfc_state, (f_commitpkt_t)dhd_bus_txdata, - (void *)dhd->bus); - dhd_os_wlfc_unblock(dhd); } + dhd_os_wlfc_unblock(dhd); #endif /* PROP_TXSTATUS */ + +exit: #if !defined(NDIS630) - PKTPULL(dhd->osh, pktbuf, (h->dataOffset << 2)); + PKTPULL(dhd->osh, pktbuf, (data_offset << 2)); #endif return 0; } +#if defined(PROP_TXSTATUS) +void +dhd_wlfc_trigger_pktcommit(dhd_pub_t *dhd) +{ + dhd_os_wlfc_block(dhd); + if (dhd->wlfc_state && + (((athost_wl_status_info_t*)dhd->wlfc_state)->proptxstatus_mode + != WLFC_FCMODE_NONE)) { + dhd_wlfc_commit_packets(dhd->wlfc_state, (f_commitpkt_t)dhd_bus_txdata, + (void *)dhd->bus, NULL); + } + dhd_os_wlfc_unblock(dhd); +} +#endif + + int dhd_prot_attach(dhd_pub_t *dhd) { @@ -2735,15 +2904,15 @@ dhd_prot_init(dhd_pub_t *dhd) goto done; -#ifdef PROP_TXSTATUS - ret = dhd_wlfc_init(dhd); -#endif - #if defined(WL_CFG80211) if (dhd_download_fw_on_driverload) #endif /* defined(WL_CFG80211) */ ret = dhd_preinit_ioctls(dhd); +#ifdef PROP_TXSTATUS + ret = dhd_wlfc_init(dhd); +#endif + /* Always assumes wl for now */ dhd->iswl = TRUE; @@ -2777,7 +2946,7 @@ dhd_get_hostreorder_pkts(void *osh, struct reorder_info *ptr, void **pkt, i = ptr->max_idx + 1; else { if (start > end) - i = (ptr->max_idx - end) + start; + i = ((ptr->max_idx + 1) - start) + end; else i = end - start; } @@ -2844,7 +3013,7 @@ dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reord __FUNCTION__, flow_id)); if (ptr == NULL) { - DHD_ERROR(("%s: received flags to cleanup, but no flow (%d) yet\n", + DHD_REORDER(("%s: received flags to cleanup, but no flow (%d) yet\n", __FUNCTION__, flow_id)); *pkt_count = 1; *pkt = cur_pkt; |