summaryrefslogtreecommitdiff
path: root/ANDROID_3.4.5/drivers/net/wireless/bcmdhd.1.28.23.x.cn_ap6330/dhd_cdc.c
diff options
context:
space:
mode:
Diffstat (limited to 'ANDROID_3.4.5/drivers/net/wireless/bcmdhd.1.28.23.x.cn_ap6330/dhd_cdc.c')
-rwxr-xr-xANDROID_3.4.5/drivers/net/wireless/bcmdhd.1.28.23.x.cn_ap6330/dhd_cdc.c3198
1 files changed, 0 insertions, 3198 deletions
diff --git a/ANDROID_3.4.5/drivers/net/wireless/bcmdhd.1.28.23.x.cn_ap6330/dhd_cdc.c b/ANDROID_3.4.5/drivers/net/wireless/bcmdhd.1.28.23.x.cn_ap6330/dhd_cdc.c
deleted file mode 100755
index 1498904f..00000000
--- a/ANDROID_3.4.5/drivers/net/wireless/bcmdhd.1.28.23.x.cn_ap6330/dhd_cdc.c
+++ /dev/null
@@ -1,3198 +0,0 @@
-/*
- * DHD Protocol Module for CDC and BDC.
- *
- * Copyright (C) 1999-2012, Broadcom Corporation
- *
- * Unless you and Broadcom execute a separate written software license
- * agreement governing use of this software, this software is licensed to you
- * under the terms of the GNU General Public License version 2 (the "GPL"),
- * available at http://www.broadcom.com/licenses/GPLv2.php, with the
- * following added to such license:
- *
- * As a special exception, the copyright holders of this software give you
- * permission to link this software with independent modules, and to copy and
- * distribute the resulting executable under terms of your choice, provided that
- * you also meet, for each linked independent module, the terms and conditions of
- * the license of that module. An independent module is a module which is not
- * derived from this software. The special exception does not apply to any
- * modifications of the software.
- *
- * Notwithstanding the above, under no circumstances may you combine this
- * 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 368762 2012-11-14 21:59:17Z $
- *
- * 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
- * for dongle offload.)
- */
-
-#include <typedefs.h>
-#include <osl.h>
-
-#include <bcmutils.h>
-#include <bcmcdc.h>
-#include <bcmendian.h>
-
-#include <dngl_stats.h>
-#include <dhd.h>
-#include <dhd_proto.h>
-#include <dhd_bus.h>
-#include <dhd_dbg.h>
-
-
-#ifdef PROP_TXSTATUS
-#include <wlfc_proto.h>
-#include <dhd_wlfc.h>
-#endif
-
-
-#define RETRIES 2 /* # of retries to retrieve matching ioctl response */
-#define BUS_HEADER_LEN (24+DHD_SDALIGN) /* Must be at least SDPCM_RESERVE
- * defined in dhd_sdio.c (amount of header tha might be added)
- * plus any space that might be needed for alignment padding.
- */
-#define ROUND_UP_MARGIN 2048 /* Biggest SDIO block size possible for
- * round off at the end of buffer
- */
-
-#define BUS_RETRIES 1 /* # of retries before aborting a bus tx operation */
-
-#ifdef PROP_TXSTATUS
-typedef struct dhd_wlfc_commit_info {
- uint8 needs_hdr;
- uint8 ac_fifo_credit_spent;
- ewlfc_packet_state_t pkt_type;
- wlfc_mac_descriptor_t* mac_entry;
- void* p;
-} dhd_wlfc_commit_info_t;
-#endif /* PROP_TXSTATUS */
-
-
-typedef struct dhd_prot {
- uint16 reqid;
- uint8 pending;
- uint32 lastcmd;
- uint8 bus_header[BUS_HEADER_LEN];
- cdc_ioctl_t msg;
- unsigned char buf[WLC_IOCTL_MAXLEN + ROUND_UP_MARGIN];
-} dhd_prot_t;
-
-
-static int
-dhdcdc_msg(dhd_pub_t *dhd)
-{
- int err = 0;
- dhd_prot_t *prot = dhd->prot;
- int len = ltoh32(prot->msg.len) + sizeof(cdc_ioctl_t);
-
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
-
- DHD_OS_WAKE_LOCK(dhd);
-
- /* NOTE : cdc->msg.len holds the desired length of the buffer to be
- * returned. Only up to CDC_MAX_MSG_SIZE of this buffer area
- * is actually sent to the dongle
- */
- if (len > CDC_MAX_MSG_SIZE)
- len = CDC_MAX_MSG_SIZE;
-
- /* Send request */
- err = dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len);
-
- DHD_OS_WAKE_UNLOCK(dhd);
- return err;
-}
-
-static int
-dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len)
-{
- int ret;
- int cdc_len = len + sizeof(cdc_ioctl_t);
- dhd_prot_t *prot = dhd->prot;
-
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
-
- do {
- ret = dhd_bus_rxctl(dhd->bus, (uchar*)&prot->msg, cdc_len);
- if (ret < 0)
- break;
- } while (CDC_IOC_ID(ltoh32(prot->msg.flags)) != id);
-
- return ret;
-}
-
-static int
-dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action)
-{
- dhd_prot_t *prot = dhd->prot;
- cdc_ioctl_t *msg = &prot->msg;
- void *info;
- int ret = 0, retries = 0;
- uint32 id, flags = 0;
-
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
- DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len));
-
-
- /* Respond "bcmerror" and "bcmerrorstr" with local cache */
- if (cmd == WLC_GET_VAR && buf)
- {
- if (!strcmp((char *)buf, "bcmerrorstr"))
- {
- strncpy((char *)buf, bcmerrorstr(dhd->dongle_error), BCME_STRLEN);
- goto done;
- }
- else if (!strcmp((char *)buf, "bcmerror"))
- {
- *(int *)buf = dhd->dongle_error;
- goto done;
- }
- }
-
- memset(msg, 0, sizeof(cdc_ioctl_t));
-
- msg->cmd = htol32(cmd);
- msg->len = htol32(len);
- msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT);
- CDC_SET_IF_IDX(msg, ifidx);
- /* add additional action bits */
- action &= WL_IOCTL_ACTION_MASK;
- msg->flags |= (action << CDCF_IOC_ACTION_SHIFT);
- msg->flags = htol32(msg->flags);
-
- if (buf)
- memcpy(prot->buf, buf, len);
-
- if ((ret = dhdcdc_msg(dhd)) < 0) {
- if (!dhd->hang_was_sent)
- DHD_ERROR(("dhdcdc_query_ioctl: dhdcdc_msg failed w/status %d\n", ret));
- goto done;
- }
-
-retry:
- /* wait for interrupt and get first fragment */
- if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0)
- goto done;
-
- flags = ltoh32(msg->flags);
- id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT;
-
- if ((id < prot->reqid) && (++retries < RETRIES))
- goto retry;
- if (id != prot->reqid) {
- DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n",
- dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid));
- ret = -EINVAL;
- goto done;
- }
-
- /* Check info buffer */
- info = (void*)&msg[1];
-
- /* Copy info buffer */
- if (buf)
- {
- if (ret < (int)len)
- len = ret;
- memcpy(buf, info, len);
- }
-
- /* Check the ERROR flag */
- if (flags & CDCF_IOC_ERROR)
- {
- ret = ltoh32(msg->status);
- /* Cache error from dongle */
- dhd->dongle_error = ret;
- }
-
-done:
- return ret;
-}
-
-static int
-dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action)
-{
- dhd_prot_t *prot = dhd->prot;
- cdc_ioctl_t *msg = &prot->msg;
- int ret = 0;
- uint32 flags, id;
-
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
- DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len));
-
- if (dhd->busstate == DHD_BUS_DOWN) {
- DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
- return -EIO;
- }
-
- /* don't talk to the dongle if fw is about to be reloaded */
- if (dhd->hang_was_sent) {
- DHD_ERROR(("%s: HANG was sent up earlier. Not talking to the chip\n",
- __FUNCTION__));
- return -EIO;
- }
-
- memset(msg, 0, sizeof(cdc_ioctl_t));
-
- msg->cmd = htol32(cmd);
- msg->len = htol32(len);
- msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT);
- CDC_SET_IF_IDX(msg, ifidx);
- /* add additional action bits */
- action &= WL_IOCTL_ACTION_MASK;
- msg->flags |= (action << CDCF_IOC_ACTION_SHIFT) | CDCF_IOC_SET;
- msg->flags = htol32(msg->flags);
-
- if (buf)
- memcpy(prot->buf, buf, len);
-
- if ((ret = dhdcdc_msg(dhd)) < 0) {
- DHD_ERROR(("%s: dhdcdc_msg failed w/status %d\n", __FUNCTION__, ret));
- goto done;
- }
-
- if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0)
- goto done;
-
- flags = ltoh32(msg->flags);
- id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT;
-
- if (id != prot->reqid) {
- DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n",
- dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid));
- ret = -EINVAL;
- goto done;
- }
-
- /* Check the ERROR flag */
- if (flags & CDCF_IOC_ERROR)
- {
- ret = ltoh32(msg->status);
- /* Cache error from dongle */
- dhd->dongle_error = ret;
- }
-
-done:
- return ret;
-}
-
-
-int
-dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len)
-{
- dhd_prot_t *prot = dhd->prot;
- int ret = -1;
- uint8 action;
-#if defined(NDIS630)
- bool acquired = FALSE;
-#endif
- static int error_cnt = 0;
-
- if ((dhd->busstate == DHD_BUS_DOWN) || dhd->hang_was_sent) {
- DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
- goto done;
- }
-#if defined(NDIS630)
- if (dhd_os_proto_block(dhd))
- {
- acquired = TRUE;
- }
- else
- {
- /* attempt to acquire protocol mutex timed out. */
- ret = -1;
- return ret;
- }
-#endif /* NDIS630 */
-
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
-
- ASSERT(len <= WLC_IOCTL_MAXLEN);
-
- if (len > WLC_IOCTL_MAXLEN)
- goto done;
-
- if (prot->pending == TRUE) {
- DHD_ERROR(("CDC packet is pending!!!! cmd=0x%x (%lu) lastcmd=0x%x (%lu)\n",
- ioc->cmd, (unsigned long)ioc->cmd, prot->lastcmd,
- (unsigned long)prot->lastcmd));
- if ((ioc->cmd == WLC_SET_VAR) || (ioc->cmd == WLC_GET_VAR)) {
- DHD_TRACE(("iovar cmd=%s\n", (char*)buf));
- }
- goto done;
- }
-
- prot->pending = TRUE;
- prot->lastcmd = ioc->cmd;
- action = ioc->set;
- if (action & WL_IOCTL_ACTION_SET)
- ret = dhdcdc_set_ioctl(dhd, ifidx, ioc->cmd, buf, len, action);
- else {
- ret = dhdcdc_query_ioctl(dhd, ifidx, ioc->cmd, buf, len, action);
- if (ret > 0)
- ioc->used = ret - sizeof(cdc_ioctl_t);
- }
- // terence 20130805: send hang event to wpa_supplicant
- if (ret == -EIO) {
- error_cnt++;
- if (error_cnt > 2)
- ret = -ETIMEDOUT;
- } else
- error_cnt = 0;
-
- /* Too many programs assume ioctl() returns 0 on success */
- if (ret >= 0)
- ret = 0;
- else {
- cdc_ioctl_t *msg = &prot->msg;
- ioc->needed = ltoh32(msg->len); /* len == needed when set/query fails from dongle */
- }
-
- /* Intercept the wme_dp ioctl here */
- if ((!ret) && (ioc->cmd == WLC_SET_VAR) && (!strcmp(buf, "wme_dp"))) {
- int slen, val = 0;
-
- slen = strlen("wme_dp") + 1;
- if (len >= (int)(slen + sizeof(int)))
- bcopy(((char *)buf + slen), &val, sizeof(int));
- dhd->wme_dp = (uint8) ltoh32(val);
- }
-
- prot->pending = FALSE;
-
-done:
-#if defined(NDIS630)
- if (acquired)
- dhd_os_proto_unblock(dhd);
-#endif
- return ret;
-}
-
-int
-dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name,
- void *params, int plen, void *arg, int len, bool set)
-{
- return BCME_UNSUPPORTED;
-}
-
-#ifdef PROP_TXSTATUS
-void
-dhd_wlfc_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
-{
- int i;
- uint8* ea;
- athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)
- dhdp->wlfc_state;
- wlfc_hanger_t* h;
- wlfc_mac_descriptor_t* mac_table;
- wlfc_mac_descriptor_t* interfaces;
- char* iftypes[] = {"STA", "AP", "WDS", "p2pGO", "p2pCL"};
-
- if (wlfc == NULL) {
- bcm_bprintf(strbuf, "wlfc not initialized yet\n");
- return;
- }
- h = (wlfc_hanger_t*)wlfc->hanger;
- if (h == NULL) {
- bcm_bprintf(strbuf, "wlfc-hanger not initialized yet\n");
- }
-
- mac_table = wlfc->destination_entries.nodes;
- interfaces = wlfc->destination_entries.interfaces;
- bcm_bprintf(strbuf, "---- wlfc stats ----\n");
- if (h) {
- bcm_bprintf(strbuf, "wlfc hanger (pushed,popped,f_push,"
- "f_pop,f_slot, pending) = (%d,%d,%d,%d,%d,%d)\n",
- h->pushed,
- h->popped,
- h->failed_to_push,
- h->failed_to_pop,
- h->failed_slotfind,
- (h->pushed - h->popped));
- }
-
- 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",
- 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, "\n");
- for (i = 0; i < WLFC_MAX_IFNUM; i++) {
- if (interfaces[i].occupied) {
- char* iftype_desc;
-
- if (interfaces[i].iftype > WLC_E_IF_ROLE_P2P_CLIENT)
- iftype_desc = "<Unknown";
- else
- iftype_desc = iftypes[interfaces[i].iftype];
-
- ea = interfaces[i].ea;
- bcm_bprintf(strbuf, "INTERFACE[%d].ea = "
- "[%02x:%02x:%02x:%02x:%02x:%02x], if:%d, type: %s"
- "netif_flow_control:%s\n", i,
- ea[0], ea[1], ea[2], ea[3], ea[4], ea[5],
- interfaces[i].interface_id,
- iftype_desc, ((wlfc->hostif_flow_state[i] == OFF)
- ? " OFF":" ON"));
-
- bcm_bprintf(strbuf, "INTERFACE[%d].DELAYQ(len,state,credit)"
- "= (%d,%s,%d)\n",
- i,
- interfaces[i].psq.len,
- ((interfaces[i].state ==
- WLFC_STATE_OPEN) ? " OPEN":"CLOSE"),
- interfaces[i].requested_credit);
-
- bcm_bprintf(strbuf, "INTERFACE[%d].DELAYQ"
- "(sup,ac0),(sup,ac1),(sup,ac2),(sup,ac3) = "
- "(%d,%d),(%d,%d),(%d,%d),(%d,%d)\n",
- i,
- interfaces[i].psq.q[0].len,
- interfaces[i].psq.q[1].len,
- interfaces[i].psq.q[2].len,
- interfaces[i].psq.q[3].len,
- interfaces[i].psq.q[4].len,
- interfaces[i].psq.q[5].len,
- interfaces[i].psq.q[6].len,
- interfaces[i].psq.q[7].len);
- }
- }
-
- bcm_bprintf(strbuf, "\n");
- for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) {
- if (mac_table[i].occupied) {
- ea = mac_table[i].ea;
- bcm_bprintf(strbuf, "MAC_table[%d].ea = "
- "[%02x:%02x:%02x:%02x:%02x:%02x], if:%d \n", i,
- ea[0], ea[1], ea[2], ea[3], ea[4], ea[5],
- mac_table[i].interface_id);
-
- bcm_bprintf(strbuf, "MAC_table[%d].DELAYQ(len,state,credit)"
- "= (%d,%s,%d)\n",
- i,
- mac_table[i].psq.len,
- ((mac_table[i].state ==
- WLFC_STATE_OPEN) ? " OPEN":"CLOSE"),
- mac_table[i].requested_credit);
-#ifdef PROP_TXSTATUS_DEBUG
- bcm_bprintf(strbuf, "MAC_table[%d]: (opened, closed) = (%d, %d)\n",
- i, mac_table[i].opened_ct, mac_table[i].closed_ct);
-#endif
- bcm_bprintf(strbuf, "MAC_table[%d].DELAYQ"
- "(sup,ac0),(sup,ac1),(sup,ac2),(sup,ac3) = "
- "(%d,%d),(%d,%d),(%d,%d),(%d,%d)\n",
- i,
- mac_table[i].psq.q[0].len,
- mac_table[i].psq.q[1].len,
- mac_table[i].psq.q[2].len,
- mac_table[i].psq.q[3].len,
- mac_table[i].psq.q[4].len,
- mac_table[i].psq.q[5].len,
- mac_table[i].psq.q[6].len,
- mac_table[i].psq.q[7].len);
- }
- }
-
-#ifdef PROP_TXSTATUS_DEBUG
- {
- int avg;
- int moving_avg = 0;
- int moving_samples;
-
- if (wlfc->stats.latency_sample_count) {
- moving_samples = sizeof(wlfc->stats.deltas)/sizeof(uint32);
-
- for (i = 0; i < moving_samples; i++)
- moving_avg += wlfc->stats.deltas[i];
- moving_avg /= moving_samples;
-
- avg = (100 * wlfc->stats.total_status_latency) /
- wlfc->stats.latency_sample_count;
- bcm_bprintf(strbuf, "txstatus latency (average, last, moving[%d]) = "
- "(%d.%d, %03d, %03d)\n",
- moving_samples, avg/100, (avg - (avg/100)*100),
- wlfc->stats.latency_most_recent,
- moving_avg);
- }
- }
-
- bcm_bprintf(strbuf, "wlfc- fifo[0-5] credit stats: sent = (%d,%d,%d,%d,%d,%d), "
- "back = (%d,%d,%d,%d,%d,%d)\n",
- wlfc->stats.fifo_credits_sent[0],
- wlfc->stats.fifo_credits_sent[1],
- wlfc->stats.fifo_credits_sent[2],
- wlfc->stats.fifo_credits_sent[3],
- wlfc->stats.fifo_credits_sent[4],
- wlfc->stats.fifo_credits_sent[5],
-
- wlfc->stats.fifo_credits_back[0],
- wlfc->stats.fifo_credits_back[1],
- wlfc->stats.fifo_credits_back[2],
- wlfc->stats.fifo_credits_back[3],
- wlfc->stats.fifo_credits_back[4],
- wlfc->stats.fifo_credits_back[5]);
- {
- uint32 fifo_cr_sent = 0;
- uint32 fifo_cr_acked = 0;
- uint32 request_cr_sent = 0;
- uint32 request_cr_ack = 0;
- uint32 bc_mc_cr_ack = 0;
-
- for (i = 0; i < sizeof(wlfc->stats.fifo_credits_sent)/sizeof(uint32); i++) {
- fifo_cr_sent += wlfc->stats.fifo_credits_sent[i];
- }
-
- for (i = 0; i < sizeof(wlfc->stats.fifo_credits_back)/sizeof(uint32); i++) {
- fifo_cr_acked += wlfc->stats.fifo_credits_back[i];
- }
-
- for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) {
- if (wlfc->destination_entries.nodes[i].occupied) {
- request_cr_sent +=
- wlfc->destination_entries.nodes[i].dstncredit_sent_packets;
- }
- }
- for (i = 0; i < WLFC_MAX_IFNUM; i++) {
- if (wlfc->destination_entries.interfaces[i].occupied) {
- request_cr_sent +=
- wlfc->destination_entries.interfaces[i].dstncredit_sent_packets;
- }
- }
- for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) {
- if (wlfc->destination_entries.nodes[i].occupied) {
- request_cr_ack +=
- wlfc->destination_entries.nodes[i].dstncredit_acks;
- }
- }
- for (i = 0; i < WLFC_MAX_IFNUM; i++) {
- if (wlfc->destination_entries.interfaces[i].occupied) {
- request_cr_ack +=
- wlfc->destination_entries.interfaces[i].dstncredit_acks;
- }
- }
- bcm_bprintf(strbuf, "wlfc- (sent, status) => pq(%d,%d), vq(%d,%d),"
- "other:%d, bc_mc:%d, signal-only, (sent,freed): (%d,%d)",
- fifo_cr_sent, fifo_cr_acked,
- request_cr_sent, request_cr_ack,
- wlfc->destination_entries.other.dstncredit_acks,
- bc_mc_cr_ack,
- wlfc->stats.signal_only_pkts_sent, wlfc->stats.signal_only_pkts_freed);
- }
-#endif /* PROP_TXSTATUS_DEBUG */
- bcm_bprintf(strbuf, "\n");
- bcm_bprintf(strbuf, "wlfc- pkt((in,2bus,txstats,hdrpull),(dropped,hdr_only,wlc_tossed)"
- "(freed,free_err,rollback)) = "
- "((%d,%d,%d,%d),(%d,%d,%d),(%d,%d,%d))\n",
- wlfc->stats.pktin,
- wlfc->stats.pkt2bus,
- wlfc->stats.txstatus_in,
- wlfc->stats.dhd_hdrpulls,
-
- wlfc->stats.pktdropped,
- wlfc->stats.wlfc_header_only_pkt,
- wlfc->stats.wlc_tossed_pkts,
-
- wlfc->stats.pkt_freed,
- wlfc->stats.pkt_free_err, wlfc->stats.rollback);
-
- bcm_bprintf(strbuf, "wlfc- suppress((d11,wlc,err),enq(d11,wl,hq,mac?),retx(d11,wlc,hq)) = "
- "((%d,%d,%d),(%d,%d,%d,%d),(%d,%d,%d))\n",
-
- wlfc->stats.d11_suppress,
- wlfc->stats.wl_suppress,
- wlfc->stats.bad_suppress,
-
- wlfc->stats.psq_d11sup_enq,
- wlfc->stats.psq_wlsup_enq,
- wlfc->stats.psq_hostq_enq,
- wlfc->stats.mac_handle_notfound,
-
- wlfc->stats.psq_d11sup_retx,
- wlfc->stats.psq_wlsup_retx,
- wlfc->stats.psq_hostq_retx);
- return;
-}
-
-/* Create a place to store all packet pointers submitted to the firmware until
- a status comes back, suppress or otherwise.
-
- hang-er: noun, a contrivance on which things are hung, as a hook.
-*/
-static void*
-dhd_wlfc_hanger_create(osl_t *osh, int max_items)
-{
- int i;
- wlfc_hanger_t* hanger;
-
- /* allow only up to a specific size for now */
- ASSERT(max_items == WLFC_HANGER_MAXITEMS);
-
- if ((hanger = (wlfc_hanger_t*)MALLOC(osh, WLFC_HANGER_SIZE(max_items))) == NULL)
- return NULL;
-
- memset(hanger, 0, WLFC_HANGER_SIZE(max_items));
- hanger->max_items = max_items;
-
- for (i = 0; i < hanger->max_items; i++) {
- hanger->items[i].state = WLFC_HANGER_ITEM_STATE_FREE;
- }
- return hanger;
-}
-
-static int
-dhd_wlfc_hanger_delete(osl_t *osh, void* hanger)
-{
- wlfc_hanger_t* h = (wlfc_hanger_t*)hanger;
-
- if (h) {
- MFREE(osh, h, WLFC_HANGER_SIZE(h->max_items));
- return BCME_OK;
- }
- return BCME_BADARG;
-}
-
-static uint16
-dhd_wlfc_hanger_get_free_slot(void* hanger)
-{
- uint32 i;
- wlfc_hanger_t* h = (wlfc_hanger_t*)hanger;
-
- if (h) {
- 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++;
- }
- return WLFC_HANGER_MAXITEMS;
-}
-
-static int
-dhd_wlfc_hanger_get_genbit(void* hanger, void* pkt, uint32 slot_id, int* gen)
-{
- int rc = BCME_OK;
- wlfc_hanger_t* h = (wlfc_hanger_t*)hanger;
-
- *gen = 0xff;
-
- /* this packet was not pushed at the time it went to the firmware */
- if (slot_id == WLFC_HANGER_MAXITEMS)
- return BCME_NOTFOUND;
-
- if (h) {
- if ((h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) ||
- (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED)) {
- *gen = h->items[slot_id].gen;
- }
- else {
- rc = BCME_NOTFOUND;
- }
- }
- else
- rc = BCME_BADARG;
- return rc;
-}
-
-static int
-dhd_wlfc_hanger_pushpkt(void* hanger, void* pkt, uint32 slot_id)
-{
- int rc = BCME_OK;
- wlfc_hanger_t* h = (wlfc_hanger_t*)hanger;
-
- if (h && (slot_id < WLFC_HANGER_MAXITEMS)) {
- if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_FREE) {
- h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE;
- h->items[slot_id].pkt = pkt;
- h->items[slot_id].identifier = slot_id;
- h->pushed++;
- }
- else {
- h->failed_to_push++;
- rc = BCME_NOTFOUND;
- }
- }
- else
- rc = BCME_BADARG;
- return rc;
-}
-
-static int
-dhd_wlfc_hanger_poppkt(void* hanger, uint32 slot_id, void** pktout, int remove_from_hanger)
-{
- int rc = BCME_OK;
- wlfc_hanger_t* h = (wlfc_hanger_t*)hanger;
-
- /* this packet was not pushed at the time it went to the firmware */
- if (slot_id == WLFC_HANGER_MAXITEMS)
- return BCME_NOTFOUND;
-
- if (h) {
- if (h->items[slot_id].state != WLFC_HANGER_ITEM_STATE_FREE) {
- *pktout = h->items[slot_id].pkt;
- if (remove_from_hanger) {
- h->items[slot_id].state =
- WLFC_HANGER_ITEM_STATE_FREE;
- h->items[slot_id].pkt = NULL;
- h->items[slot_id].identifier = 0;
- h->items[slot_id].gen = 0xff;
- h->popped++;
- }
- }
- else {
- h->failed_to_pop++;
- rc = BCME_NOTFOUND;
- }
- }
- else
- rc = BCME_BADARG;
- return rc;
-}
-
-static int
-dhd_wlfc_hanger_mark_suppressed(void* hanger, uint32 slot_id, uint8 gen)
-{
- int rc = BCME_OK;
- wlfc_hanger_t* h = (wlfc_hanger_t*)hanger;
-
- /* this packet was not pushed at the time it went to the firmware */
- if (slot_id == WLFC_HANGER_MAXITEMS)
- return BCME_NOTFOUND;
- if (h) {
- h->items[slot_id].gen = gen;
- if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) {
- h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED;
- }
- else
- rc = BCME_BADARG;
- }
- else
- rc = BCME_BADARG;
-
- return rc;
-}
-
-static int
-_dhd_wlfc_pushheader(athost_wl_status_info_t* ctx, void* p, bool tim_signal,
- uint8 tim_bmp, uint8 mac_handle, uint32 htodtag)
-{
- uint32 wl_pktinfo = 0;
- uint8* wlh;
- uint8 dataOffset;
- uint8 fillers;
- uint8 tim_signal_len = 0;
-
- struct bdc_header *h;
-
- if (tim_signal) {
- tim_signal_len = 1 + 1 + WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP;
- }
-
- /* +2 is for Type[1] and Len[1] in TLV, plus TIM signal */
- dataOffset = WLFC_CTL_VALUE_LEN_PKTTAG + 2 + tim_signal_len;
- fillers = ROUNDUP(dataOffset, 4) - dataOffset;
- dataOffset += fillers;
-
- PKTPUSH(ctx->osh, p, dataOffset);
- wlh = (uint8*) PKTDATA(ctx->osh, p);
-
- wl_pktinfo = htol32(htodtag);
-
- wlh[0] = WLFC_CTL_TYPE_PKTTAG;
- wlh[1] = WLFC_CTL_VALUE_LEN_PKTTAG;
- memcpy(&wlh[2], &wl_pktinfo, sizeof(uint32));
-
- if (tim_signal_len) {
- wlh[dataOffset - fillers - tim_signal_len ] =
- WLFC_CTL_TYPE_PENDING_TRAFFIC_BMP;
- wlh[dataOffset - fillers - tim_signal_len + 1] =
- WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP;
- wlh[dataOffset - fillers - tim_signal_len + 2] = mac_handle;
- wlh[dataOffset - fillers - tim_signal_len + 3] = tim_bmp;
- }
- if (fillers)
- memset(&wlh[dataOffset - fillers], WLFC_CTL_TYPE_FILLER, fillers);
-
- PKTPUSH(ctx->osh, p, BDC_HEADER_LEN);
- h = (struct bdc_header *)PKTDATA(ctx->osh, p);
- h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT);
- if (PKTSUMNEEDED(p))
- h->flags |= BDC_FLAG_SUM_NEEDED;
-
-
- h->priority = (PKTPRIO(p) & BDC_PRIORITY_MASK);
- h->flags2 = 0;
- h->dataOffset = dataOffset >> 2;
- BDC_SET_IF_IDX(h, DHD_PKTTAG_IF(PKTTAG(p)));
- return BCME_OK;
-}
-
-static int
-_dhd_wlfc_pullheader(athost_wl_status_info_t* ctx, void* pktbuf)
-{
- struct bdc_header *h;
-
- if (PKTLEN(ctx->osh, pktbuf) < BDC_HEADER_LEN) {
- WLFC_DBGMESG(("%s: rx data too short (%d < %d)\n", __FUNCTION__,
- PKTLEN(ctx->osh, pktbuf), BDC_HEADER_LEN));
- return BCME_ERROR;
- }
- h = (struct bdc_header *)PKTDATA(ctx->osh, pktbuf);
-
- /* pull BDC header */
- PKTPULL(ctx->osh, pktbuf, BDC_HEADER_LEN);
-
- 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)));
- return BCME_ERROR;
- }
- /* pull wl-header */
- PKTPULL(ctx->osh, pktbuf, (h->dataOffset << 2));
- return BCME_OK;
-}
-
-static wlfc_mac_descriptor_t*
-_dhd_wlfc_find_table_entry(athost_wl_status_info_t* ctx, void* p)
-{
- int i;
- wlfc_mac_descriptor_t* table = ctx->destination_entries.nodes;
- uint8 ifid = DHD_PKTTAG_IF(PKTTAG(p));
- uint8* dstn = DHD_PKTTAG_DSTN(PKTTAG(p));
-
- if (((ctx->destination_entries.interfaces[ifid].iftype == WLC_E_IF_ROLE_STA) ||
- ETHER_ISMULTI(dstn) ||
- (ctx->destination_entries.interfaces[ifid].iftype == WLC_E_IF_ROLE_P2P_CLIENT)) &&
- (ctx->destination_entries.interfaces[ifid].occupied)) {
- return &ctx->destination_entries.interfaces[ifid];
- }
-
- for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) {
- if (table[i].occupied) {
- if (table[i].interface_id == ifid) {
- if (!memcmp(table[i].ea, dstn, ETHER_ADDR_LEN))
- return &table[i];
- }
- }
- }
- return &ctx->destination_entries.other;
-}
-
-static int
-_dhd_wlfc_rollback_packet_toq(athost_wl_status_info_t* ctx,
- void* p, ewlfc_packet_state_t pkt_type, uint32 hslot)
-{
- /*
- 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
-
- Note: hslot is used only when header removal is done.
- */
- wlfc_mac_descriptor_t* entry;
- void* pktout;
- int rc = BCME_OK;
- int prec;
-
- entry = _dhd_wlfc_find_table_entry(ctx, p);
- prec = DHD_PKTTAG_FIFO(PKTTAG(p));
- if (entry != NULL) {
- if (pkt_type == eWLFC_PKTTYPE_SUPPRESSED) {
- /* wl-header is saved for suppressed packets */
- if (WLFC_PKTQ_PENQ_HEAD(&entry->psq, ((prec << 1) + 1), p) == NULL) {
- WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__));
- rc = BCME_ERROR;
- }
- }
- else {
- /* remove header first */
- rc = _dhd_wlfc_pullheader(ctx, p);
- 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);
- PKTFREE(ctx->osh, p, TRUE);
- rc = BCME_ERROR;
- return rc;
- }
-
- if (pkt_type == eWLFC_PKTTYPE_DELAYED) {
- /* delay-q packets are going to delay-q */
- if (WLFC_PKTQ_PENQ_HEAD(&entry->psq, (prec << 1), p) == NULL) {
- WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__));
- 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);
-
- /* decrement sequence count */
- WLFC_DECR_SEQCOUNT(entry, prec);
- }
- /*
- if this packet did not count against FIFO credit, it must have
- taken a requested_credit from the firmware (for pspoll etc.)
- */
- if (!DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) {
- entry->requested_credit++;
- }
- }
- else {
- WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__));
- rc = BCME_ERROR;
- }
- if (rc != BCME_OK)
- ctx->stats.rollback_failed++;
- else
- ctx->stats.rollback++;
-
- return rc;
-}
-
-static void
-_dhd_wlfc_flow_control_check(athost_wl_status_info_t* ctx, struct pktq* pq, uint8 if_id)
-{
- if ((pq->len <= WLFC_FLOWCONTROL_LOWATER) && (ctx->hostif_flow_state[if_id] == ON)) {
- /* start traffic */
- ctx->hostif_flow_state[if_id] = OFF;
- /*
- WLFC_DBGMESG(("qlen:%02d, if:%02d, ->OFF, start traffic %s()\n",
- 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)) {
- /* stop traffic */
- ctx->hostif_flow_state[if_id] = ON;
- /*
- WLFC_DBGMESG(("qlen:%02d, if:%02d, ->ON, stop traffic %s()\n",
- 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;
- }
- return;
-}
-
-static int
-_dhd_wlfc_send_signalonly_packet(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry,
- uint8 ta_bmp)
-{
- int rc = BCME_OK;
- void* p = NULL;
- int dummylen = ((dhd_pub_t *)ctx->dhdp)->hdrlen+ 12;
-
- /* allocate a dummy packet */
- p = PKTGET(ctx->osh, dummylen, TRUE);
- if (p) {
- PKTPULL(ctx->osh, p, dummylen);
- DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), 0);
- _dhd_wlfc_pushheader(ctx, p, TRUE, ta_bmp, entry->mac_handle, 0);
- DHD_PKTTAG_SETSIGNALONLY(PKTTAG(p), 1);
-#ifdef PROP_TXSTATUS_DEBUG
- ctx->stats.signal_only_pkts_sent++;
-#endif
- rc = dhd_bus_txdata(((dhd_pub_t *)ctx->dhdp)->bus, p, FALSE);
- if (rc != BCME_OK) {
- PKTFREE(ctx->osh, p, TRUE);
- }
- }
- else {
- DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n",
- __FUNCTION__, dummylen));
- rc = BCME_NOMEM;
- }
- return rc;
-}
-
-/* Return TRUE if traffic availability changed */
-static bool
-_dhd_wlfc_traffic_pending_check(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry,
- int prec)
-{
- bool rc = FALSE;
-
- if (entry->state == WLFC_STATE_CLOSE) {
- if ((pktq_plen(&entry->psq, (prec << 1)) == 0) &&
- (pktq_plen(&entry->psq, ((prec << 1) + 1)) == 0)) {
-
- if (entry->traffic_pending_bmp & NBITVAL(prec)) {
- rc = TRUE;
- entry->traffic_pending_bmp =
- entry->traffic_pending_bmp & ~ NBITVAL(prec);
- }
- }
- else {
- if (!(entry->traffic_pending_bmp & NBITVAL(prec))) {
- rc = TRUE;
- entry->traffic_pending_bmp =
- entry->traffic_pending_bmp | NBITVAL(prec);
- }
- }
- }
- if (rc) {
- /* request a TIM update to firmware at the next piggyback opportunity */
- if (entry->traffic_lastreported_bmp != entry->traffic_pending_bmp) {
- entry->send_tim_signal = 1;
- _dhd_wlfc_send_signalonly_packet(ctx, entry, entry->traffic_pending_bmp);
- entry->traffic_lastreported_bmp = entry->traffic_pending_bmp;
- entry->send_tim_signal = 0;
- }
- else {
- rc = FALSE;
- }
- }
- return rc;
-}
-
-static int
-_dhd_wlfc_enque_suppressed(athost_wl_status_info_t* ctx, int prec, void* p)
-{
- wlfc_mac_descriptor_t* entry;
-
- entry = _dhd_wlfc_find_table_entry(ctx, p);
- if (entry == NULL) {
- WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__));
- return BCME_NOTFOUND;
- }
- /*
- - 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) + 1), p) == NULL) {
- ctx->stats.delayq_full_error++;
- /* WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); */
- WLFC_DBGMESG(("s"));
- return BCME_ERROR;
- }
- /* A packet has been pushed, update traffic availability bitmap, if applicable */
- _dhd_wlfc_traffic_pending_check(ctx, entry, prec);
- _dhd_wlfc_flow_control_check(ctx, &entry->psq, DHD_PKTTAG_IF(PKTTAG(p)));
- return BCME_OK;
-}
-
-static int
-_dhd_wlfc_pretx_pktprocess(athost_wl_status_info_t* ctx,
- wlfc_mac_descriptor_t* entry, void* p, int header_needed, uint32* slot)
-{
- int rc = BCME_OK;
- int hslot = WLFC_HANGER_MAXITEMS;
- bool send_tim_update = FALSE;
- uint32 htod = 0;
- uint8 free_ctr;
-
- *slot = hslot;
-
- if (entry == NULL) {
- entry = _dhd_wlfc_find_table_entry(ctx, p);
- }
-
- if (entry == NULL) {
- WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__));
- return BCME_ERROR;
- }
- if (entry->send_tim_signal) {
- send_tim_update = TRUE;
- entry->send_tim_signal = 0;
- entry->traffic_lastreported_bmp = entry->traffic_pending_bmp;
- }
- if (header_needed) {
- hslot = dhd_wlfc_hanger_get_free_slot(ctx->hanger);
- free_ctr = WLFC_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p)));
- DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), htod);
- WLFC_PKTFLAG_SET_GENERATION(htod, entry->generation);
- entry->transit_count++;
- }
- else {
- hslot = WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p)));
- free_ctr = WLFC_PKTID_FREERUNCTR_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p)));
- }
- WLFC_PKTID_HSLOT_SET(htod, hslot);
- WLFC_PKTID_FREERUNCTR_SET(htod, free_ctr);
- DHD_PKTTAG_SETPKTDIR(PKTTAG(p), 1);
- 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
- explicit request from the firmware side.
- */
- WLFC_PKTFLAG_SET_PKTREQUESTED(htod);
- }
- else {
- WLFC_PKTFLAG_CLR_PKTREQUESTED(htod);
- }
- if (header_needed) {
- rc = _dhd_wlfc_pushheader(ctx, p, send_tim_update,
- entry->traffic_lastreported_bmp, entry->mac_handle, htod);
- if (rc == BCME_OK) {
- DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), htod);
- /*
- a new header was created for this packet.
- push to hanger slot and scrub q. Since bus
- send succeeded, increment seq number as well.
- */
- rc = dhd_wlfc_hanger_pushpkt(ctx->hanger, p, hslot);
- if (rc == BCME_OK) {
- /* increment free running sequence count */
- WLFC_INCR_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p)));
-#ifdef PROP_TXSTATUS_DEBUG
- ((wlfc_hanger_t*)(ctx->hanger))->items[hslot].push_time =
- OSL_SYSUPTIME();
-#endif
- }
- else {
- WLFC_DBGMESG(("%s() hanger_pushpkt() failed, rc: %d\n",
- __FUNCTION__, rc));
- }
- }
- }
- else {
- int gen;
-
- /* remove old header */
- rc = _dhd_wlfc_pullheader(ctx, p);
- if (rc == BCME_OK) {
- hslot = WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p)));
- dhd_wlfc_hanger_get_genbit(ctx->hanger, p, hslot, &gen);
-
- WLFC_PKTFLAG_SET_GENERATION(htod, gen);
- free_ctr = WLFC_PKTID_FREERUNCTR_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p)));
- /* push new header */
- _dhd_wlfc_pushheader(ctx, p, send_tim_update,
- entry->traffic_lastreported_bmp, entry->mac_handle, htod);
- }
- }
- *slot = hslot;
- return rc;
-}
-
-static int
-_dhd_wlfc_is_destination_closed(athost_wl_status_info_t* ctx,
- wlfc_mac_descriptor_t* entry, int prec)
-{
- if (ctx->destination_entries.interfaces[entry->interface_id].iftype ==
- WLC_E_IF_ROLE_P2P_GO) {
- /* - destination interface is of type p2p GO.
- For a p2pGO interface, if the destination is OPEN but the interface is
- CLOSEd, do not send traffic. But if the dstn is CLOSEd while there is
- destination-specific-credit left send packets. This is because the
- firmware storing the destination-specific-requested packet in queue.
- */
- if ((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) &&
- (entry->requested_packet == 0))
- return 1;
- }
- /* AP, p2p_go -> unicast desc entry, STA/p2p_cl -> interface desc. entry */
- if (((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) &&
- (entry->requested_packet == 0)) ||
- (!(entry->ac_bitmap & (1 << prec))))
- return 1;
-
- return 0;
-}
-
-static void*
-_dhd_wlfc_deque_delayedq(athost_wl_status_info_t* ctx,
- int prec, uint8* ac_credit_spent, uint8* needs_hdr, wlfc_mac_descriptor_t** entry_out)
-{
- wlfc_mac_descriptor_t* entry;
- wlfc_mac_descriptor_t* table;
- uint8 token_pos;
- int total_entries;
- void* p = NULL;
- int pout;
- int i;
-
- *entry_out = NULL;
- token_pos = ctx->token_pos[prec];
- /* most cases a packet will count against FIFO credit */
- *ac_credit_spent = 1;
- *needs_hdr = 1;
-
- /* search all entries, include nodes as well as interfaces */
- table = (wlfc_mac_descriptor_t*)&ctx->destination_entries;
- total_entries = sizeof(ctx->destination_entries)/sizeof(wlfc_mac_descriptor_t);
-
- for (i = 0; i < total_entries; i++) {
- entry = &table[(token_pos + i) % total_entries];
- if (entry->occupied) {
- if (!_dhd_wlfc_is_destination_closed(ctx, entry, prec)) {
- p = pktq_mdeq(&entry->psq,
- /* higher precedence will be picked up first,
- * i.e. suppressed packets before delayed ones
- */
- NBITVAL((prec << 1) + 1), &pout);
- *needs_hdr = 0;
-
- if (p == NULL) {
- if (entry->suppressed == TRUE) {
- if ((entry->suppr_transit_count <=
- entry->suppress_count)) {
- entry->suppressed = FALSE;
- } else {
- return NULL;
- }
- }
- /* De-Q from delay Q */
- p = pktq_mdeq(&entry->psq,
- NBITVAL((prec << 1)),
- &pout);
- *needs_hdr = 1;
- }
-
- if (p != NULL) {
- /* did the packet come from suppress sub-queue? */
- if (entry->requested_credit > 0) {
- entry->requested_credit--;
-#ifdef PROP_TXSTATUS_DEBUG
- entry->dstncredit_sent_packets++;
-#endif
- /*
- if the packet was pulled out while destination is in
- closed state but had a non-zero packets requested,
- then this should not count against the FIFO credit.
- That is due to the fact that the firmware will
- most likely hold onto this packet until a suitable
- time later to push it to the appropriate AC FIFO.
- */
- if (entry->state == WLFC_STATE_CLOSE)
- *ac_credit_spent = 0;
- }
- else if (entry->requested_packet > 0) {
- entry->requested_packet--;
- DHD_PKTTAG_SETONETIMEPKTRQST(PKTTAG(p));
- if (entry->state == WLFC_STATE_CLOSE)
- *ac_credit_spent = 0;
- }
- /* move token to ensure fair round-robin */
- ctx->token_pos[prec] =
- (token_pos + i + 1) % total_entries;
- *entry_out = entry;
- _dhd_wlfc_flow_control_check(ctx, &entry->psq,
- DHD_PKTTAG_IF(PKTTAG(p)));
- /*
- A packet has been picked up, update traffic
- availability bitmap, if applicable
- */
- _dhd_wlfc_traffic_pending_check(ctx, entry, prec);
- return p;
- }
- }
- }
- }
- return NULL;
-}
-
-static void*
-_dhd_wlfc_deque_sendq(athost_wl_status_info_t* ctx, 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 (entry == NULL) {
- WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__));
- return p;
- }
-
- 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;
- }
- }
- }
- return p;
-}
-
-static int
-_dhd_wlfc_mac_entry_update(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry,
- ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea)
-{
- int rc = BCME_OK;
-
- if (action == eWLFC_MAC_ENTRY_ACTION_ADD) {
- entry->occupied = 1;
- entry->state = WLFC_STATE_OPEN;
- entry->requested_credit = 0;
- entry->interface_id = ifid;
- entry->iftype = iftype;
- entry->ac_bitmap = 0xff; /* update this when handling APSD */
- /* for an interface entry we may not care about the MAC address */
- if (ea != NULL)
- memcpy(&entry->ea[0], ea, ETHER_ADDR_LEN);
- pktq_init(&entry->psq, WLFC_PSQ_PREC_COUNT, WLFC_PSQ_LEN);
- }
- else if (action == eWLFC_MAC_ENTRY_ACTION_UPDATE) {
- entry->occupied = 1;
- entry->state = WLFC_STATE_OPEN;
- entry->requested_credit = 0;
- entry->interface_id = ifid;
- entry->iftype = iftype;
- entry->ac_bitmap = 0xff; /* update this when handling APSD */
- /* for an interface entry we may not care about the MAC address */
- if (ea != NULL)
- memcpy(&entry->ea[0], ea, ETHER_ADDR_LEN);
- }
- else if (action == eWLFC_MAC_ENTRY_ACTION_DEL) {
- entry->occupied = 0;
- entry->state = WLFC_STATE_CLOSE;
- entry->requested_credit = 0;
- /* enable after packets are queued-deqeued properly.
- pktq_flush(dhd->osh, &entry->psq, FALSE, NULL, 0);
- */
- }
- return rc;
-}
-
-int
-_dhd_wlfc_borrow_credit(athost_wl_status_info_t* ctx, uint8 available_credit_map, int borrower_ac)
-{
- int lender_ac;
- int rc = BCME_ERROR;
-
- if (ctx == NULL || available_credit_map == 0) {
- WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__));
- return BCME_BADARG;
- }
-
- /* Borrow from lowest priority available AC (including BC/MC credits) */
- for (lender_ac = 0; lender_ac <= AC_COUNT; lender_ac++) {
- if ((available_credit_map && (1 << lender_ac)) &&
- (ctx->FIFO_credit[lender_ac] > 0)) {
- ctx->credits_borrowed[borrower_ac][lender_ac]++;
- ctx->FIFO_credit[lender_ac]--;
- rc = BCME_OK;
- break;
- }
- }
-
- return rc;
-}
-
-int
-dhd_wlfc_interface_entry_update(void* state,
- ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea)
-{
- athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state;
- wlfc_mac_descriptor_t* entry;
-
- 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);
-}
-
-int
-dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits)
-{
- athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state;
-
- /* update the AC FIFO credit map */
- ctx->FIFO_credit[0] = credits[0];
- ctx->FIFO_credit[1] = credits[1];
- ctx->FIFO_credit[2] = credits[2];
- ctx->FIFO_credit[3] = credits[3];
- /* credit for bc/mc packets */
- ctx->FIFO_credit[4] = credits[4];
- /* credit for ATIM FIFO is not used yet. */
- ctx->FIFO_credit[5] = 0;
- return BCME_OK;
-}
-
-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)
-{
- uint32 hslot;
- int rc;
-
- /*
- if ac_fifo_credit_spent = 0
-
- This packet will not count against the FIFO credit.
- To ensure the txstatus corresponding to this packet
- does not provide an implied credit (default behavior)
- mark the packet accordingly.
-
- if ac_fifo_credit_spent = 1
-
- This is a normal packet and it counts against the FIFO
- credit count.
- */
- DHD_PKTTAG_SETCREDITCHECK(PKTTAG(commit_info->p), commit_info->ac_fifo_credit_spent);
- rc = _dhd_wlfc_pretx_pktprocess(ctx, commit_info->mac_entry, commit_info->p,
- commit_info->needs_hdr, &hslot);
-
- if (rc == BCME_OK)
- rc = fcommit(commit_ctx, commit_info->p, TRUE);
- else
- ctx->stats.generic_error++;
-
- if (rc == BCME_OK) {
- ctx->stats.pkt2bus++;
- if (commit_info->ac_fifo_credit_spent) {
- 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.
- - remove wl-header for a delayed packet
- - save wl-header header for suppressed packets
- */
- rc = _dhd_wlfc_rollback_packet_toq(ctx, commit_info->p,
- (commit_info->pkt_type), hslot);
- if (rc != BCME_OK)
- ctx->stats.rollback_failed++;
-
- rc = BCME_ERROR;
- }
-
- return rc;
-}
-
-int
-dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx)
-{
- int ac;
- int credit;
- int rc;
- dhd_wlfc_commit_info_t commit_info;
- athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state;
- int credit_count = 0;
- int bus_retry_count = 0;
- uint8 ac_available = 0; /* Bitmask for 4 ACs + BC/MC */
-
- if ((state == NULL) ||
- (fcommit == NULL)) {
- WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__));
- return BCME_BADARG;
- }
-
- memset(&commit_info, 0, sizeof(commit_info));
-
- /*
- Commit packets for regular AC traffic. Higher priority first.
- First, use up FIFO credits available to each AC. Based on distribution
- and credits left, borrow from other ACs as applicable
-
- -NOTE:
- If the bus between the host and firmware is overwhelmed by the
- traffic from host, it is possible that higher priority traffic
- starves the lower priority queue. If that occurs often, we may
- have to employ weighted round-robin or ucode scheme to avoid
- 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)))) {
- ASSERT(ac == AC_COUNT);
-
- 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;
- }
- }
- }
- }
-
- } while (commit_info.p);
-
- for (credit = 0; credit < ctx->FIFO_credit[ac];) {
- commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac,
- &(commit_info.ac_fifo_credit_spent),
- &(commit_info.needs_hdr),
- &(commit_info.mac_entry));
-
- if (commit_info.p == NULL)
- break;
-
- commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED :
- eWLFC_PKTTYPE_SUPPRESSED;
-
- 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) {
- credit++;
- }
- }
- else {
- bus_retry_count++;
- if (bus_retry_count >= BUS_RETRIES) {
- DHD_ERROR(("dhd_wlfc_commit_packets(): bus error\n"));
- ctx->FIFO_credit[ac] -= credit;
- return rc;
- }
- }
- }
-
- ctx->FIFO_credit[ac] -= credit;
-
-
- /* If no credits were used, the queue is idle and can be re-used
- Note that resv credits cannot be borrowed
- */
- if (initial_credit_count == ctx->FIFO_credit[ac]) {
- ac_available |= (1 << ac);
- credit_count += ctx->FIFO_credit[ac];
- }
- }
-
- /* We borrow only for AC_BE and only if no other traffic seen for DEFER_PERIOD
-
- Note that (ac_available & WLFC_AC_BE_TRAFFIC_ONLY) is done to:
- a) ignore BC/MC for deferring borrow
- b) ignore AC_BE being available along with other ACs
- (this should happen only for pure BC/MC traffic)
-
- i.e. AC_VI, AC_VO, AC_BK all MUST be available (i.e. no traffic) and
- we do not care if AC_BE and BC/MC are available or not
- */
- if ((ac_available & WLFC_AC_BE_TRAFFIC_ONLY) == WLFC_AC_BE_TRAFFIC_ONLY) {
-
- if (ctx->allow_credit_borrow) {
- ac = 1; /* Set ac to AC_BE and borrow credits */
- }
- else {
- int delta;
- int curr_t = OSL_SYSUPTIME();
-
- if (curr_t > ctx->borrow_defer_timestamp)
- delta = curr_t - ctx->borrow_defer_timestamp;
- else
- delta = 0xffffffff + curr_t - ctx->borrow_defer_timestamp;
-
- if (delta >= WLFC_BORROW_DEFER_PERIOD_MS) {
- /* Reset borrow but defer to next iteration (defensive borrowing) */
- ctx->allow_credit_borrow = TRUE;
- ctx->borrow_defer_timestamp = 0;
- }
- return BCME_OK;
- }
- }
- else {
- /* If we have multiple AC traffic, turn off borrowing, mark time and bail out */
- ctx->allow_credit_borrow = FALSE;
- ctx->borrow_defer_timestamp = OSL_SYSUPTIME();
- return BCME_OK;
- }
-
- /* At this point, borrow all credits only for "ac" (which should be set above to AC_BE)
- Generically use "ac" only in case we extend to all ACs in future
- */
- for (; (credit_count > 0);) {
-
- commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac,
- &(commit_info.ac_fifo_credit_spent),
- &(commit_info.needs_hdr),
- &(commit_info.mac_entry));
- if (commit_info.p == NULL)
- break;
-
- commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED :
- eWLFC_PKTTYPE_SUPPRESSED;
-
- 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(("dhd_wlfc_commit_packets(): bus error\n"));
- return rc;
- }
- }
- }
-
- return BCME_OK;
-}
-
-static uint8
-dhd_wlfc_find_mac_desc_id_from_mac(dhd_pub_t *dhdp, uint8* ea)
-{
- wlfc_mac_descriptor_t* table =
- ((athost_wl_status_info_t*)dhdp->wlfc_state)->destination_entries.nodes;
- uint8 table_index;
-
- if (ea != NULL) {
- for (table_index = 0; table_index < WLFC_MAC_DESC_TABLE_SIZE; table_index++) {
- if ((memcmp(ea, &table[table_index].ea[0], ETHER_ADDR_LEN) == 0) &&
- table[table_index].occupied)
- return table_index;
- }
- }
- return WLFC_MAC_DESC_ID_INVALID;
-}
-
-void
-dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success, bool wake_locked)
-{
- athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)
- dhd->wlfc_state;
- void* p;
- int fifo_id;
-
- if (!wake_locked)
- dhd_os_wlfc_block(dhd);
-
- if (DHD_PKTTAG_SIGNALONLY(PKTTAG(txp))) {
-#ifdef PROP_TXSTATUS_DEBUG
- wlfc->stats.signal_only_pkts_freed++;
-#endif
- if (success)
- /* is this a signal-only packet? */
- PKTFREE(wlfc->osh, txp, TRUE);
- if (!wake_locked)
- dhd_os_wlfc_unblock(dhd);
- return;
- }
- if (!success) {
- WLFC_DBGMESG(("At: %s():%d, bus_complete() failure for %p, htod_tag:0x%08x\n",
- __FUNCTION__, __LINE__, txp, DHD_PKTTAG_H2DTAG(PKTTAG(txp))));
- dhd_wlfc_hanger_poppkt(wlfc->hanger, WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG
- (PKTTAG(txp))), &p, 1);
-
- /* indicate failure and free the packet */
- dhd_txcomplete(dhd, txp, FALSE);
-
- /* return the credit, if necessary */
- if (DHD_PKTTAG_CREDITCHECK(PKTTAG(txp))) {
- int lender, credit_returned = 0; /* Note that borrower is fifo_id */
-
- fifo_id = DHD_PKTTAG_FIFO(PKTTAG(txp));
-
- /* 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]++;
- }
- }
-
- PKTFREE(wlfc->osh, txp, TRUE);
- }
- if (!wake_locked)
- 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)
-{
- uint8 status_flag;
- uint32 status;
- int ret;
- int remove_from_hanger = 1;
- void* pktbuf;
- uint8 fifo_id;
- 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);
- 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++;
- }
-
- ret = dhd_wlfc_hanger_poppkt(wlfc->hanger,
- WLFC_PKTID_HSLOT_GET(status), &pktbuf, remove_from_hanger);
- if (ret != BCME_OK) {
- /* do something */
- return ret;
- }
-
- 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--;
- /* This packet is transmitted Successfully by
- * dongle even 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;
-}
-
-static int
-dhd_wlfc_fifocreditback_indicate(dhd_pub_t *dhd, uint8* credits)
-{
- int i;
- athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)
- dhd->wlfc_state;
- for (i = 0; i < WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK; i++) {
-#ifdef PROP_TXSTATUS_DEBUG
- wlfc->stats.fifo_credits_back[i] += credits[i];
-#endif
- /* update FIFO credits */
- if (wlfc->proptxstatus_mode == WLFC_FCMODE_EXPLICIT_CREDIT)
- {
- int lender; /* Note that borrower is i */
-
- /* Return credits to highest priority lender first */
- for (lender = AC_COUNT; (lender >= 0) && (credits[i] > 0); lender--) {
- if (wlfc->credits_borrowed[i][lender] > 0) {
- if (credits[i] >= wlfc->credits_borrowed[i][lender]) {
- credits[i] -= wlfc->credits_borrowed[i][lender];
- wlfc->FIFO_credit[lender] +=
- wlfc->credits_borrowed[i][lender];
- wlfc->credits_borrowed[i][lender] = 0;
- }
- else {
- wlfc->credits_borrowed[i][lender] -= credits[i];
- wlfc->FIFO_credit[lender] += credits[i];
- credits[i] = 0;
- }
- }
- }
-
- /* If we have more credits left over, these must belong to the AC */
- if (credits[i] > 0) {
- wlfc->FIFO_credit[i] += credits[i];
- }
- }
- }
-
- return BCME_OK;
-}
-
-static int
-dhd_wlfc_dbg_senum_check(dhd_pub_t *dhd, uint8 *value)
-{
- uint32 timestamp;
-
- (void)dhd;
-
- bcopy(&value[2], &timestamp, sizeof(uint32));
- DHD_INFO(("RXPKT: SEQ: %d, timestamp %d\n", value[1], timestamp));
- return BCME_OK;
-}
-
-
-static int
-dhd_wlfc_rssi_indicate(dhd_pub_t *dhd, uint8* rssi)
-{
- (void)dhd;
- (void)rssi;
- return BCME_OK;
-}
-
-static int
-dhd_wlfc_mac_table_update(dhd_pub_t *dhd, uint8* value, uint8 type)
-{
- int rc;
- athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)
- dhd->wlfc_state;
- wlfc_mac_descriptor_t* table;
- uint8 existing_index;
- uint8 table_index;
- uint8 ifid;
- uint8* ea;
-
- WLFC_DBGMESG(("%s(), mac [%02x:%02x:%02x:%02x:%02x:%02x],%s,idx:%d,id:0x%02x\n",
- __FUNCTION__, value[2], value[3], value[4], value[5], value[6], value[7],
- ((type == WLFC_CTL_TYPE_MACDESC_ADD) ? "ADD":"DEL"),
- WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]), value[0]));
-
- table = wlfc->destination_entries.nodes;
- table_index = WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]);
- ifid = value[1];
- ea = &value[2];
-
- if (type == WLFC_CTL_TYPE_MACDESC_ADD) {
- existing_index = dhd_wlfc_find_mac_desc_id_from_mac(dhd, &value[2]);
- if (existing_index == WLFC_MAC_DESC_ID_INVALID) {
- /* this MAC entry does not exist, create one */
- if (!table[table_index].occupied) {
- table[table_index].mac_handle = value[0];
- rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index],
- eWLFC_MAC_ENTRY_ACTION_ADD, ifid,
- wlfc->destination_entries.interfaces[ifid].iftype,
- ea);
- }
- else {
- /* the space should have been empty, but it's not */
- wlfc->stats.mac_update_failed++;
- }
- }
- else {
- /*
- there is an existing entry, move it to new index
- if necessary.
- */
- if (existing_index != table_index) {
- /* if we already have an entry, free the old one */
- table[existing_index].occupied = 0;
- table[existing_index].state = WLFC_STATE_CLOSE;
- table[existing_index].requested_credit = 0;
- table[existing_index].interface_id = 0;
- /* enable after packets are queued-deqeued properly.
- pktq_flush(dhd->osh, &table[existing_index].psq, FALSE, NULL, 0);
- */
- }
- }
- }
- if (type == WLFC_CTL_TYPE_MACDESC_DEL) {
- if (table[table_index].occupied) {
- rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index],
- eWLFC_MAC_ENTRY_ACTION_DEL, ifid,
- wlfc->destination_entries.interfaces[ifid].iftype,
- ea);
- }
- else {
- /* the space should have been occupied, but it's not */
- wlfc->stats.mac_update_failed++;
- }
- }
- BCM_REFERENCE(rc);
- return BCME_OK;
-}
-
-static int
-dhd_wlfc_psmode_update(dhd_pub_t *dhd, uint8* value, uint8 type)
-{
- /* Handle PS on/off indication */
- athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)
- dhd->wlfc_state;
- wlfc_mac_descriptor_t* table;
- wlfc_mac_descriptor_t* desc;
- uint8 mac_handle = value[0];
- int i;
-
- table = wlfc->destination_entries.nodes;
- desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)];
- if (desc->occupied) {
- /* a fresh PS mode should wipe old ps credits? */
- desc->requested_credit = 0;
- if (type == WLFC_CTL_TYPE_MAC_OPEN) {
- desc->state = WLFC_STATE_OPEN;
- DHD_WLFC_CTRINC_MAC_OPEN(desc);
- }
- else {
- desc->state = WLFC_STATE_CLOSE;
- DHD_WLFC_CTRINC_MAC_CLOSE(desc);
- /*
- Indicate to firmware if there is any traffic pending.
- */
- for (i = AC_BE; i < AC_COUNT; i++) {
- _dhd_wlfc_traffic_pending_check(wlfc, desc, i);
- }
- }
- }
- else {
- wlfc->stats.psmode_update_failed++;
- }
- return BCME_OK;
-}
-
-static int
-dhd_wlfc_interface_update(dhd_pub_t *dhd, uint8* value, uint8 type)
-{
- /* Handle PS on/off indication */
- athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)
- dhd->wlfc_state;
- wlfc_mac_descriptor_t* table;
- uint8 if_id = value[0];
-
- if (if_id < WLFC_MAX_IFNUM) {
- table = wlfc->destination_entries.interfaces;
- if (table[if_id].occupied) {
- if (type == WLFC_CTL_TYPE_INTERFACE_OPEN) {
- table[if_id].state = WLFC_STATE_OPEN;
- /* WLFC_DBGMESG(("INTERFACE[%d] OPEN\n", if_id)); */
- }
- else {
- table[if_id].state = WLFC_STATE_CLOSE;
- /* WLFC_DBGMESG(("INTERFACE[%d] CLOSE\n", if_id)); */
- }
- return BCME_OK;
- }
- }
- wlfc->stats.interface_update_failed++;
-
- return BCME_OK;
-}
-
-static int
-dhd_wlfc_credit_request(dhd_pub_t *dhd, uint8* value)
-{
- athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)
- dhd->wlfc_state;
- wlfc_mac_descriptor_t* table;
- wlfc_mac_descriptor_t* desc;
- uint8 mac_handle;
- uint8 credit;
-
- table = wlfc->destination_entries.nodes;
- mac_handle = value[1];
- credit = value[0];
-
- desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)];
- if (desc->occupied) {
- desc->requested_credit = credit;
-
- desc->ac_bitmap = value[2];
- }
- else {
- wlfc->stats.credit_request_failed++;
- }
- return BCME_OK;
-}
-
-static int
-dhd_wlfc_packet_request(dhd_pub_t *dhd, uint8* value)
-{
- athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)
- dhd->wlfc_state;
- wlfc_mac_descriptor_t* table;
- wlfc_mac_descriptor_t* desc;
- uint8 mac_handle;
- uint8 packet_count;
-
- table = wlfc->destination_entries.nodes;
- mac_handle = value[1];
- packet_count = value[0];
-
- desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)];
- if (desc->occupied) {
- desc->requested_packet = packet_count;
-
- desc->ac_bitmap = value[2];
- }
- else {
- wlfc->stats.packet_request_failed++;
- }
- return BCME_OK;
-}
-
-static void
-dhd_wlfc_reorderinfo_indicate(uint8 *val, uint8 len, uchar *info_buf, uint *info_len)
-{
- if (info_len) {
- if (info_buf) {
- bcopy(val, info_buf, len);
- *info_len = len;
- }
- else
- *info_len = 0;
- }
-}
-
-static int
-dhd_wlfc_parse_header_info(dhd_pub_t *dhd, void* pktbuf, int tlv_hdr_len, uchar *reorder_info_buf,
- uint *reorder_info_len)
-{
- uint8 type, len;
- uint8* value;
- uint8* tmpbuf;
- uint16 remainder = tlv_hdr_len;
- uint16 processed = 0;
- athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)
- dhd->wlfc_state;
- tmpbuf = (uint8*)PKTDATA(dhd->osh, pktbuf);
- if (remainder) {
- while ((processed < (WLFC_MAX_PENDING_DATALEN * 2)) && (remainder > 0)) {
- type = tmpbuf[processed];
- if (type == WLFC_CTL_TYPE_FILLER) {
- remainder -= 1;
- processed += 1;
- continue;
- }
-
- len = tmpbuf[processed + 1];
- value = &tmpbuf[processed + 2];
-
- if (remainder < (2 + len))
- break;
-
- remainder -= 2 + len;
- 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,
- reorder_info_len);
- else if (type == WLFC_CTL_TYPE_FIFO_CREDITBACK)
- dhd_wlfc_fifocreditback_indicate(dhd, value);
-
- else if (type == WLFC_CTL_TYPE_RSSI)
- dhd_wlfc_rssi_indicate(dhd, value);
-
- else if (type == WLFC_CTL_TYPE_MAC_REQUEST_CREDIT)
- dhd_wlfc_credit_request(dhd, value);
-
- else if (type == WLFC_CTL_TYPE_MAC_REQUEST_PACKET)
- dhd_wlfc_packet_request(dhd, value);
-
- else if ((type == WLFC_CTL_TYPE_MAC_OPEN) ||
- (type == WLFC_CTL_TYPE_MAC_CLOSE))
- dhd_wlfc_psmode_update(dhd, value, type);
-
- else if ((type == WLFC_CTL_TYPE_MACDESC_ADD) ||
- (type == WLFC_CTL_TYPE_MACDESC_DEL))
- dhd_wlfc_mac_table_update(dhd, value, type);
-
- else if (type == WLFC_CTL_TYPE_TRANS_ID)
- dhd_wlfc_dbg_senum_check(dhd, value);
-
- else if ((type == WLFC_CTL_TYPE_INTERFACE_OPEN) ||
- (type == WLFC_CTL_TYPE_INTERFACE_CLOSE)) {
- dhd_wlfc_interface_update(dhd, value, type);
- }
- }
- if (remainder != 0) {
- /* trouble..., something is not right */
- wlfc->stats.tlv_parse_failed++;
- }
- }
- return BCME_OK;
-}
-
-int
-dhd_wlfc_init(dhd_pub_t *dhd)
-{
- char iovbuf[12]; /* Room for "tlv" + '\0' + parameter */
- /* enable all signals & indicate host proptxstatus logic is active */
- uint32 tlv = dhd->wlfc_enabled?
- WLFC_FLAGS_RSSI_SIGNALS |
- WLFC_FLAGS_XONXOFF_SIGNALS |
- WLFC_FLAGS_CREDIT_STATUS_SIGNALS |
- WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE |
- WLFC_FLAGS_HOST_RXRERODER_ACTIVE : 0;
- /* WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE | WLFC_FLAGS_HOST_RXRERODER_ACTIVE : 0; */
-
-
- /*
- try to enable/disable signaling by sending "tlv" iovar. if that fails,
- fallback to no flow control? Print a message for now.
- */
-
- /* enable proptxtstatus signaling by default */
- bcm_mkiovar("tlv", (char *)&tlv, 4, iovbuf, sizeof(iovbuf));
- if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) < 0) {
- DHD_ERROR(("dhd_wlfc_init(): failed to enable/disable bdcv2 tlv signaling\n"));
- }
- else {
- /*
- Leaving the message for now, it should be removed after a while; once
- the tlv situation is stable.
- */
- DHD_ERROR(("dhd_wlfc_init(): successfully %s bdcv2 tlv signaling, %d\n",
- dhd->wlfc_enabled?"enabled":"disabled", tlv));
- }
- return BCME_OK;
-}
-
-int
-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;
-
- /* 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)
- return BCME_NOMEM;
-
- /* initialize state space */
- wlfc = (athost_wl_status_info_t*)dhd->wlfc_state;
- memset(wlfc, 0, sizeof(athost_wl_status_info_t));
-
- /* remember osh & dhdp */
- wlfc->osh = dhd->osh;
- wlfc->dhdp = dhd;
-
- wlfc->hanger =
- dhd_wlfc_hanger_create(dhd->osh, WLFC_HANGER_MAXITEMS);
- if (wlfc->hanger == NULL) {
- MFREE(dhd->osh, dhd->wlfc_state, sizeof(athost_wl_status_info_t));
- dhd->wlfc_state = NULL;
- return BCME_NOMEM;
- }
-
- /* initialize all interfaces to accept traffic */
- for (i = 0; i < WLFC_MAX_IFNUM; i++) {
- 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;
- wlfc->destination_entries.other.interface_id = 0;
-
- wlfc->proptxstatus_mode = WLFC_FCMODE_EXPLICIT_CREDIT;
-
- wlfc->allow_credit_borrow = TRUE;
- wlfc->borrow_defer_timestamp = 0;
-
- return BCME_OK;
-}
-
-/* release all packet resources */
-void
-dhd_wlfc_cleanup(dhd_pub_t *dhd)
-{
- int i;
- int total_entries;
- athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)
- dhd->wlfc_state;
- wlfc_mac_descriptor_t* table;
- wlfc_hanger_t* h;
- 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);
- /* search all entries, include nodes as well as interfaces */
- table = (wlfc_mac_descriptor_t*)&wlfc->destination_entries;
-
- for (i = 0; i < total_entries; i++) {
- if (table[i].occupied) {
- 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);
- }
- 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);
- 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 */
- h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE;
- }
- break;
- }
- }
- pkt = pktq_pdeq(txq, prec);
- }
- }
- /* 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) {
- PKTFREE(wlfc->osh, h->items[i].pkt, TRUE);
- h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE;
- } 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;
- }
- }
-
- return;
-}
-
-void
-dhd_wlfc_deinit(dhd_pub_t *dhd)
-{
- /* cleanup all psq related resources */
- athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)
- dhd->wlfc_state;
-
- DHD_TRACE(("Enter %s\n", __FUNCTION__));
-
- dhd_os_wlfc_block(dhd);
- if (dhd->wlfc_state == NULL) {
- dhd_os_wlfc_unblock(dhd);
- return;
- }
-
-#ifdef PROP_TXSTATUS_DEBUG
- {
- int i;
- wlfc_hanger_t* h = (wlfc_hanger_t*)wlfc->hanger;
- for (i = 0; i < h->max_items; i++) {
- if (h->items[i].state != WLFC_HANGER_ITEM_STATE_FREE) {
- WLFC_DBGMESG(("%s() pkt[%d] = 0x%p, FIFO_credit_used:%d\n",
- __FUNCTION__, i, h->items[i].pkt,
- DHD_PKTTAG_CREDITCHECK(PKTTAG(h->items[i].pkt))));
- }
- }
- }
-#endif
- /* delete hanger */
- dhd_wlfc_hanger_delete(dhd->osh, wlfc->hanger);
-
- /* free top structure */
- MFREE(dhd->osh, dhd->wlfc_state, sizeof(athost_wl_status_info_t));
- dhd->wlfc_state = NULL;
- dhd_os_wlfc_unblock(dhd);
-
- return;
-}
-#endif /* PROP_TXSTATUS */
-
-void
-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
-}
-
-void
-dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *pktbuf)
-{
-#ifdef BDC
- struct bdc_header *h;
-#endif /* BDC */
-
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
-
-#ifdef BDC
- /* Push BDC header used to convey priority for buses that don't */
-
- PKTPUSH(dhd->osh, pktbuf, BDC_HEADER_LEN);
-
- h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf);
-
- h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT);
- if (PKTSUMNEEDED(pktbuf))
- h->flags |= BDC_FLAG_SUM_NEEDED;
-
-
- h->priority = (PKTPRIO(pktbuf) & BDC_PRIORITY_MASK);
- h->flags2 = 0;
- h->dataOffset = 0;
-#endif /* BDC */
- BDC_SET_IF_IDX(h, ifidx);
-}
-
-int
-dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf, uchar *reorder_buf_info,
- uint *reorder_info_len)
-{
-#ifdef BDC
- struct bdc_header *h;
-#endif
- uint8 data_offset = 0;
-
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
-
-#ifdef BDC
- if (reorder_info_len)
- *reorder_info_len = 0;
- /* Pop BDC header used to convey priority for buses that don't */
-
- if (PKTLEN(dhd->osh, pktbuf) < BDC_HEADER_LEN) {
- DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__,
- PKTLEN(dhd->osh, pktbuf), BDC_HEADER_LEN));
- return BCME_ERROR;
- }
-
- 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 (((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));
- if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) == BDC_PROTO_VER_1)
- h->dataOffset = 0;
- else
- return BCME_ERROR;
- }
-
- if (h->flags & BDC_FLAG_SUM_GOOD) {
- DHD_INFO(("%s: BDC packet received with good rx-csum, flags 0x%x\n",
- dhd_ifname(dhd, *ifidx), h->flags));
- PKTSETSUMGOOD(pktbuf, TRUE);
- }
-
- 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) (data_offset << 2)) {
- DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__,
- PKTLEN(dhd->osh, pktbuf), (data_offset * 4)));
- return BCME_ERROR;
- }
-#endif
-#ifdef PROP_TXSTATUS
- if (dhd->wlfc_state &&
- ((athost_wl_status_info_t*)dhd->wlfc_state)->proptxstatus_mode
- != WLFC_FCMODE_NONE &&
- (!DHD_PKTTAG_PKTDIR(PKTTAG(pktbuf)))) {
- /*
- - parse txstatus only for packets that came from the firmware
- */
- dhd_os_wlfc_block(dhd);
- 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_os_wlfc_unblock(dhd);
- }
-#endif /* PROP_TXSTATUS */
-
-exit:
-#if !defined(NDIS630)
- PKTPULL(dhd->osh, pktbuf, (data_offset << 2));
-#endif
- 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)
-{
- dhd_prot_t *cdc;
-
- if (!(cdc = (dhd_prot_t *)DHD_OS_PREALLOC(dhd->osh, DHD_PREALLOC_PROT,
- sizeof(dhd_prot_t)))) {
- DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
- goto fail;
- }
- memset(cdc, 0, sizeof(dhd_prot_t));
-
- /* ensure that the msg buf directly follows the cdc msg struct */
- if ((uintptr)(&cdc->msg + 1) != (uintptr)cdc->buf) {
- DHD_ERROR(("dhd_prot_t is not correctly defined\n"));
- goto fail;
- }
-
- dhd->prot = cdc;
-#ifdef BDC
- dhd->hdrlen += BDC_HEADER_LEN;
-#endif
- dhd->maxctl = WLC_IOCTL_MAXLEN + sizeof(cdc_ioctl_t) + ROUND_UP_MARGIN;
- return 0;
-
-fail:
-#ifndef CONFIG_DHD_USE_STATIC_BUF
- if (cdc != NULL)
- MFREE(dhd->osh, cdc, sizeof(dhd_prot_t));
-#endif /* CONFIG_DHD_USE_STATIC_BUF */
- return BCME_NOMEM;
-}
-
-/* ~NOTE~ What if another thread is waiting on the semaphore? Holding it? */
-void
-dhd_prot_detach(dhd_pub_t *dhd)
-{
-#ifdef PROP_TXSTATUS
- dhd_wlfc_deinit(dhd);
-#endif
-#ifndef CONFIG_DHD_USE_STATIC_BUF
- MFREE(dhd->osh, dhd->prot, sizeof(dhd_prot_t));
-#endif /* CONFIG_DHD_USE_STATIC_BUF */
- dhd->prot = NULL;
-}
-
-void
-dhd_prot_dstats(dhd_pub_t *dhd)
-{
- /* No stats from dongle added yet, copy bus stats */
- dhd->dstats.tx_packets = dhd->tx_packets;
- dhd->dstats.tx_errors = dhd->tx_errors;
- dhd->dstats.rx_packets = dhd->rx_packets;
- dhd->dstats.rx_errors = dhd->rx_errors;
- dhd->dstats.rx_dropped = dhd->rx_dropped;
- dhd->dstats.multicast = dhd->rx_multicast;
- return;
-}
-
-int
-dhd_prot_init(dhd_pub_t *dhd)
-{
- int ret = 0;
- wlc_rev_info_t revinfo;
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
-
-
- /* Get the device rev info */
- memset(&revinfo, 0, sizeof(revinfo));
- ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_REVINFO, &revinfo, sizeof(revinfo), FALSE, 0);
- if (ret < 0)
- goto done;
-
-
-#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;
-
-done:
- return ret;
-}
-
-void
-dhd_prot_stop(dhd_pub_t *dhd)
-{
- /* Nothing to do for CDC */
-}
-
-
-static void
-dhd_get_hostreorder_pkts(void *osh, struct reorder_info *ptr, void **pkt,
- uint32 *pkt_count, void **pplast, uint8 start, uint8 end)
-{
- uint i;
- void *plast = NULL, *p;
- uint32 pkt_cnt = 0;
-
- if (ptr->pend_pkts == 0) {
- DHD_REORDER(("%s: no packets in reorder queue \n", __FUNCTION__));
- *pplast = NULL;
- *pkt_count = 0;
- *pkt = NULL;
- return;
- }
- if (start == end)
- i = ptr->max_idx + 1;
- else {
- if (start > end)
- i = ((ptr->max_idx + 1) - start) + end;
- else
- i = end - start;
- }
- while (i) {
- p = (void *)(ptr->p[start]);
- ptr->p[start] = NULL;
-
- if (p != NULL) {
- if (plast == NULL)
- *pkt = p;
- else
- PKTSETNEXT(osh, plast, p);
-
- plast = p;
- pkt_cnt++;
- }
- i--;
- if (start++ == ptr->max_idx)
- start = 0;
- }
- *pplast = plast;
- *pkt_count = (uint32)pkt_cnt;
-}
-
-int
-dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reorder_info_len,
- void **pkt, uint32 *pkt_count)
-{
- uint8 flow_id, max_idx, cur_idx, exp_idx;
- struct reorder_info *ptr;
- uint8 flags;
- void *cur_pkt, *plast = NULL;
- uint32 cnt = 0;
-
- if (pkt == NULL) {
- if (pkt_count != NULL)
- *pkt_count = 0;
- return 0;
- }
-
- flow_id = reorder_info_buf[WLHOST_REORDERDATA_FLOWID_OFFSET];
- flags = reorder_info_buf[WLHOST_REORDERDATA_FLAGS_OFFSET];
-
- DHD_REORDER(("flow_id %d, flags 0x%02x, idx(%d, %d, %d)\n", flow_id, flags,
- reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET],
- reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET],
- reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET]));
-
- /* validate flags and flow id */
- if (flags == 0xFF) {
- DHD_ERROR(("%s: invalid flags...so ignore this packet\n", __FUNCTION__));
- *pkt_count = 1;
- return 0;
- }
-
- cur_pkt = *pkt;
- *pkt = NULL;
-
- ptr = dhd->reorder_bufs[flow_id];
- if (flags & WLHOST_REORDERDATA_DEL_FLOW) {
- uint32 buf_size = sizeof(struct reorder_info);
-
- DHD_REORDER(("%s: Flags indicating to delete a flow id %d\n",
- __FUNCTION__, flow_id));
-
- if (ptr == NULL) {
- DHD_ERROR(("%s: received flags to cleanup, but no flow (%d) yet\n",
- __FUNCTION__, flow_id));
- *pkt_count = 1;
- *pkt = cur_pkt;
- return 0;
- }
-
- dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast,
- ptr->exp_idx, ptr->exp_idx);
- /* set it to the last packet */
- if (plast) {
- PKTSETNEXT(dhd->osh, plast, cur_pkt);
- cnt++;
- }
- else {
- if (cnt != 0) {
- DHD_ERROR(("%s: del flow: something fishy, pending packets %d\n",
- __FUNCTION__, cnt));
- }
- *pkt = cur_pkt;
- cnt = 1;
- }
- buf_size += ((ptr->max_idx + 1) * sizeof(void *));
- MFREE(dhd->osh, ptr, buf_size);
- dhd->reorder_bufs[flow_id] = NULL;
- *pkt_count = cnt;
- return 0;
- }
- /* all the other cases depend on the existance of the reorder struct for that flow id */
- if (ptr == NULL) {
- uint32 buf_size_alloc = sizeof(reorder_info_t);
- max_idx = reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET];
-
- buf_size_alloc += ((max_idx + 1) * sizeof(void*));
- /* allocate space to hold the buffers, index etc */
-
- DHD_REORDER(("%s: alloc buffer of size %d size, reorder info id %d, maxidx %d\n",
- __FUNCTION__, buf_size_alloc, flow_id, max_idx));
- ptr = (struct reorder_info *)MALLOC(dhd->osh, buf_size_alloc);
- if (ptr == NULL) {
- DHD_ERROR(("%s: Malloc failed to alloc buffer\n", __FUNCTION__));
- *pkt_count = 1;
- return 0;
- }
- bzero(ptr, buf_size_alloc);
- dhd->reorder_bufs[flow_id] = ptr;
- ptr->p = (void *)(ptr+1);
- ptr->max_idx = max_idx;
- }
- if (flags & WLHOST_REORDERDATA_NEW_HOLE) {
- DHD_REORDER(("%s: new hole, so cleanup pending buffers\n", __FUNCTION__));
- if (ptr->pend_pkts) {
- dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast,
- ptr->exp_idx, ptr->exp_idx);
- ptr->pend_pkts = 0;
- }
- ptr->cur_idx = reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET];
- ptr->exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET];
- ptr->max_idx = reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET];
- ptr->p[ptr->cur_idx] = cur_pkt;
- ptr->pend_pkts++;
- *pkt_count = cnt;
- }
- else if (flags & WLHOST_REORDERDATA_CURIDX_VALID) {
- cur_idx = reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET];
- exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET];
-
-
- if ((exp_idx == ptr->exp_idx) && (cur_idx != ptr->exp_idx)) {
- /* still in the current hole */
- /* enqueue the current on the buffer chain */
- if (ptr->p[cur_idx] != NULL) {
- DHD_REORDER(("%s: HOLE: ERROR buffer pending..free it\n",
- __FUNCTION__));
- PKTFREE(dhd->osh, ptr->p[cur_idx], TRUE);
- ptr->p[cur_idx] = NULL;
- }
- ptr->p[cur_idx] = cur_pkt;
- ptr->pend_pkts++;
- ptr->cur_idx = cur_idx;
- DHD_REORDER(("%s: fill up a hole..pending packets is %d\n",
- __FUNCTION__, ptr->pend_pkts));
- *pkt_count = 0;
- *pkt = NULL;
- }
- else if (ptr->exp_idx == cur_idx) {
- /* got the right one ..flush from cur to exp and update exp */
- DHD_REORDER(("%s: got the right one now, cur_idx is %d\n",
- __FUNCTION__, cur_idx));
- if (ptr->p[cur_idx] != NULL) {
- DHD_REORDER(("%s: Error buffer pending..free it\n",
- __FUNCTION__));
- PKTFREE(dhd->osh, ptr->p[cur_idx], TRUE);
- ptr->p[cur_idx] = NULL;
- }
- ptr->p[cur_idx] = cur_pkt;
- ptr->pend_pkts++;
-
- ptr->cur_idx = cur_idx;
- ptr->exp_idx = exp_idx;
-
- dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast,
- cur_idx, exp_idx);
- ptr->pend_pkts -= (uint8)cnt;
- *pkt_count = cnt;
- DHD_REORDER(("%s: freeing up buffers %d, still pending %d\n",
- __FUNCTION__, cnt, ptr->pend_pkts));
- }
- else {
- uint8 end_idx;
- bool flush_current = FALSE;
- /* both cur and exp are moved now .. */
- DHD_REORDER(("%s:, flow %d, both moved, cur %d(%d), exp %d(%d)\n",
- __FUNCTION__, flow_id, ptr->cur_idx, cur_idx,
- ptr->exp_idx, exp_idx));
- if (flags & WLHOST_REORDERDATA_FLUSH_ALL)
- end_idx = ptr->exp_idx;
- else
- end_idx = exp_idx;
-
- /* flush pkts first */
- dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast,
- ptr->exp_idx, end_idx);
-
- if (cur_idx == ptr->max_idx) {
- if (exp_idx == 0)
- flush_current = TRUE;
- } else {
- if (exp_idx == cur_idx + 1)
- flush_current = TRUE;
- }
- if (flush_current) {
- if (plast)
- PKTSETNEXT(dhd->osh, plast, cur_pkt);
- else
- *pkt = cur_pkt;
- cnt++;
- }
- else {
- ptr->p[cur_idx] = cur_pkt;
- ptr->pend_pkts++;
- }
- ptr->exp_idx = exp_idx;
- ptr->cur_idx = cur_idx;
- *pkt_count = cnt;
- }
- }
- else {
- uint8 end_idx;
- /* no real packet but update to exp_seq...that means explicit window move */
- exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET];
-
- DHD_REORDER(("%s: move the window, cur_idx is %d, exp is %d, new exp is %d\n",
- __FUNCTION__, ptr->cur_idx, ptr->exp_idx, exp_idx));
- if (flags & WLHOST_REORDERDATA_FLUSH_ALL)
- end_idx = ptr->exp_idx;
- else
- end_idx = exp_idx;
-
- dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, ptr->exp_idx, end_idx);
- ptr->pend_pkts -= (uint8)cnt;
- if (plast)
- PKTSETNEXT(dhd->osh, plast, cur_pkt);
- else
- *pkt = cur_pkt;
- cnt++;
- *pkt_count = cnt;
- /* set the new expected idx */
- ptr->exp_idx = exp_idx;
- }
- return 0;
-}