Samsung VZW MB1 update
/drivers/net/wireless/bcmdhd/dhd_cdc.c
blob:4f4894618ab678cd96f403066457afc31f25a820 -> blob:b22940af61c09916e7ccd8535606705307c5e324
--- drivers/net/wireless/bcmdhd/dhd_cdc.c
+++ 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 357848 2012-09-20 05:38:41Z $
+ * $Id: dhd_cdc.c 364003 2012-10-22 02:22:16Z $
*
* 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,11 @@ 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 */
+#endif /* CUSTOMER_HW4 && USE_DYNAMIC_F2_BLKSIZE */
typedef struct dhd_prot {
uint16 reqid;
@@ -703,13 +703,16 @@ dhd_wlfc_hanger_delete(osl_t *osh, void*
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)
+ for (i = (h->slot_pos + 1); i != h->slot_pos;) {
+ if (h->items[i].state == WLFC_HANGER_ITEM_STATE_FREE) {
+ h->slot_pos = i;
return (uint16)i;
+ }
+ (i == h->max_items)? i = 0 : i++;
}
h->failed_slotfind++;
}
@@ -892,7 +895,7 @@ _dhd_wlfc_pullheader(athost_wl_status_in
if (PKTLEN(ctx->osh, pktbuf) < (h->dataOffset << 2)) {
WLFC_DBGMESG(("%s: rx data too short (%d < %d)\n", __FUNCTION__,
- PKTLEN(ctx->osh, pktbuf), (h->dataOffset << 2)));
+ PKTLEN(ctx->osh, pktbuf), (h->dataOffset << 2)));
return BCME_ERROR;
}
/* pull wl-header */
@@ -958,7 +961,7 @@ _dhd_wlfc_rollback_packet_toq(athost_wl_
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);
@@ -1559,7 +1562,8 @@ _dhd_wlfc_handle_packet_commit(athost_wl
ctx->stats.sendq_pkts[ac]++;
WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac);
}
- }
+ } else if (rc == BCME_NORESOURCE)
+ rc = BCME_ERROR;
else {
/*
bus commit has failed, rollback.
@@ -1838,6 +1842,179 @@ dhd_wlfc_txcomplete(dhd_pub_t *dhd, void
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)
@@ -2290,6 +2467,8 @@ dhd_wlfc_parse_header_info(dhd_pub_t *dh
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,
@@ -2371,6 +2550,8 @@ dhd_wlfc_enable(dhd_pub_t *dhd)
int i;
athost_wl_status_info_t* wlfc;
+ DHD_TRACE(("Enter %s\n", __FUNCTION__));
+
if (!dhd->wlfc_enabled || dhd->wlfc_state)
return BCME_OK;
@@ -2415,9 +2596,10 @@ 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;
}
@@ -2434,10 +2616,13 @@ dhd_wlfc_cleanup(dhd_pub_t *dhd)
int prec;
void *pkt = NULL;
struct pktq *txq = NULL;
+
+ DHD_TRACE(("Enter %s\n", __FUNCTION__));
if (dhd->wlfc_state == NULL)
return;
/* flush bus->txq */
txq = dhd_bus_txq(dhd->bus);
+
/* any in the hanger? */
h = (wlfc_hanger_t*)wlfc->hanger;
total_entries = sizeof(wlfc->destination_entries)/sizeof(wlfc_mac_descriptor_t);
@@ -2466,6 +2651,8 @@ dhd_wlfc_cleanup(dhd_pub_t *dhd)
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 */
@@ -2487,6 +2674,7 @@ dhd_wlfc_cleanup(dhd_pub_t *dhd)
h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE;
}
}
+
return;
}
@@ -2497,9 +2685,11 @@ dhd_wlfc_deinit(dhd_pub_t *dhd)
athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)
dhd->wlfc_state;
- if (dhd->wlfc_state == NULL)
+ dhd_os_wlfc_block(dhd);
+ if (dhd->wlfc_state == NULL) {
+ dhd_os_wlfc_unblock(dhd);
return;
-
+ }
#ifdef PROP_TXSTATUS_DEBUG
{
int i;
@@ -2519,9 +2709,11 @@ 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)
+ 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 && DYNAMIC_F2_BLKSIZE_OF_PROPTXSTATUS */
+#endif /* CUSTOMER_HW4 && USE_DYNAMIC_F2_BLKSIZE */
return;
}
#endif /* PROP_TXSTATUS */
@@ -2634,8 +2826,6 @@ dhd_prot_hdrpull(dhd_pub_t *dhd, int *if
dhd_wlfc_parse_header_info(dhd, pktbuf, (h->dataOffset << 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);
}
#endif /* PROP_TXSTATUS */
@@ -2645,6 +2835,22 @@ dhd_prot_hdrpull(dhd_pub_t *dhd, int *if
return 0;
}
+#if defined(PROP_TXSTATUS)
+void
+dhd_wlfc_trigger_pktcommit(dhd_pub_t *dhd)
+{
+ if (dhd->wlfc_state &&
+ (((athost_wl_status_info_t*)dhd->wlfc_state)->proptxstatus_mode
+ != WLFC_FCMODE_NONE)) {
+ dhd_os_wlfc_block(dhd);
+ dhd_wlfc_commit_packets(dhd->wlfc_state, (f_commitpkt_t)dhd_bus_txdata,
+ (void *)dhd->bus);
+ dhd_os_wlfc_unblock(dhd);
+ }
+}
+#endif
+
+
int
dhd_prot_attach(dhd_pub_t *dhd)
{
@@ -2719,15 +2925,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;