aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/bcmdhd/dhd_cdc.c
diff options
context:
space:
mode:
authorsbrissen <sbrissen@hotmail.com>2013-04-24 13:09:33 -0400
committersbrissen <sbrissen@hotmail.com>2013-04-25 10:50:50 -0400
commitc421809918b7106b40a81134f9fb5103146fc715 (patch)
tree89b0147d51d2b2650c5ded666a08613ba0cab3c1 /drivers/net/wireless/bcmdhd/dhd_cdc.c
parent43aaedbcde478c8e032771d62a1956133b29b1d4 (diff)
downloadkernel_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.c587
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;