OSDN Git Service

net: wireless: bcmdhd: Update to version 5.90.125.78
authorDmitry Shmidt <dimitrysh@google.com>
Wed, 7 Sep 2011 17:30:45 +0000 (10:30 -0700)
committerDmitry Shmidt <dimitrysh@google.com>
Wed, 7 Sep 2011 17:47:58 +0000 (10:47 -0700)
- Add BT-Coex support to cfg80211
- Add private event logic to cfg80211 when FW hangs
- Reduce passive dwell time to 130 ms
- Fix proptx initialize fail issue
- Implement codes for WPS2.0 using cfg80211
- Clean any left virtual interfaces in primary dhd_stop context
- Skip waiting for rtnl_lock in cfg80211 callback if already taken
- Skip writing to file FW trap info

Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
14 files changed:
drivers/net/wireless/bcmdhd/dhd.h
drivers/net/wireless/bcmdhd/dhd_cdc.c
drivers/net/wireless/bcmdhd/dhd_common.c
drivers/net/wireless/bcmdhd/dhd_linux.c
drivers/net/wireless/bcmdhd/dhd_linux_sched.c
drivers/net/wireless/bcmdhd/dhd_sdio.c
drivers/net/wireless/bcmdhd/dhd_wlfc.h
drivers/net/wireless/bcmdhd/include/epivers.h
drivers/net/wireless/bcmdhd/linux_osl.c
drivers/net/wireless/bcmdhd/wl_android.c
drivers/net/wireless/bcmdhd/wl_cfg80211.c
drivers/net/wireless/bcmdhd/wl_cfg80211.h
drivers/net/wireless/bcmdhd/wl_cfgp2p.c
drivers/net/wireless/bcmdhd/wl_iw.c

index 735d39b..5d9e678 100644 (file)
@@ -202,7 +202,7 @@ typedef struct dhd_pub {
        void* wlfc_state;
 #endif
        bool    dongle_isolation;
-
+       int   hang_was_sent;
 #ifdef WLMEDIA_HTSF
        uint8 htsfdlystat_sz; /* Size of delay stats, max 255B */
 #endif
@@ -389,7 +389,7 @@ extern void dhd_os_sdlock_rxq(dhd_pub_t * pub);
 extern void dhd_os_sdunlock_rxq(dhd_pub_t * pub);
 extern void dhd_os_sdlock_sndup_rxq(dhd_pub_t * pub);
 extern void dhd_customer_gpio_wlan_ctrl(int onoff);
-extern int  dhd_custom_get_mac_address(unsigned char *buf);
+extern int dhd_custom_get_mac_address(unsigned char *buf);
 extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub);
 extern void dhd_os_sdlock_eventq(dhd_pub_t * pub);
 extern void dhd_os_sdunlock_eventq(dhd_pub_t * pub);
index 54ce6ff..a86ea56 100644 (file)
                                 * 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;
@@ -152,7 +163,8 @@ dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uin
                memcpy(prot->buf, buf, len);
 
        if ((ret = dhdcdc_msg(dhd)) < 0) {
-               DHD_ERROR(("dhdcdc_query_ioctl: dhdcdc_msg failed w/status %d\n", ret));
+               if (!dhd->hang_was_sent)
+                       DHD_ERROR(("dhdcdc_query_ioctl: dhdcdc_msg failed w/status %d\n", ret));
                goto done;
        }
 
@@ -206,6 +218,17 @@ dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8
 
        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));
 
@@ -629,8 +652,8 @@ dhd_wlfc_hanger_get_free_slot(void* hanger)
                        if (h->items[i].state == WLFC_HANGER_ITEM_STATE_FREE)
                                return (uint16)i;
                }
+               h->failed_slotfind++;
        }
-       h->failed_slotfind++;
        return WLFC_HANGER_MAXITEMS;
 }
 
@@ -1287,6 +1310,30 @@ _dhd_wlfc_mac_entry_update(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t*
 }
 
 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)
 {
@@ -1313,6 +1360,7 @@ dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits)
        /* 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;
 }
 
@@ -1345,17 +1393,68 @@ dhd_wlfc_enque_sendq(void* state, int prec, void* p)
 }
 
 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);
+       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 {
+               /*
+                  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;
-       uint8 ac_fifo_credit_spent;
-       uint8 needs_hdr;
-       uint32 hslot;
-       void* p;
        int rc;
+       dhd_wlfc_commit_info_t  commit_info;
        athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state;
-       wlfc_mac_descriptor_t* mac_entry;
+       int credit_count = 0;
+       int bus_retry_count = 0;
+       uint8 ac_available = 0;  /* Bitmask for 4 ACs + BC/MC */
 
        if ((state == NULL) ||
                (fcommit == NULL)) {
@@ -1363,8 +1462,12 @@ dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx)
                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
@@ -1373,96 +1476,189 @@ dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx)
        have to employ weighted round-robin or ucode scheme to avoid
        low priority packet starvation.
        */
+
        for (ac = AC_COUNT; ac >= 0; ac--) {
-               for (credit = 0; credit < ctx->FIFO_credit[ac];) {
-                       p = _dhd_wlfc_deque_delayedq(ctx, ac, &ac_fifo_credit_spent, &needs_hdr,
-                               &mac_entry);
-                       if (p == NULL)
-                               break;
-                       /*
-                       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.
+               int initial_credit_count = ctx->FIFO_credit[ac];
 
-                       if ac_fifo_credit_spent = 1
+               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));
 
-                       This is a normal packet and it counts against the FIFO
-                       credit count.
-                       */
-                       DHD_PKTTAG_SETCREDITCHECK(PKTTAG(p), ac_fifo_credit_spent);
-                       rc = _dhd_wlfc_pretx_pktprocess(ctx, mac_entry, p, needs_hdr, &hslot);
+                       if (commit_info.p == NULL)
+                               break;
 
-                       if (rc == BCME_OK)
-                               rc = fcommit(commit_ctx, p);
-                       else
-                               ctx->stats.generic_error++;
+                       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) {
-                               ctx->stats.pkt2bus++;
-                               if (ac_fifo_credit_spent) {
-                                       ctx->stats.sendq_pkts[ac]++;
-                                       WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac);
-                                       /*
-                                       1 FIFO credit has been spent by sending this packet
-                                       to the device.
-                                       */
+                               if (commit_info.ac_fifo_credit_spent) {
                                        credit++;
                                }
                        }
                        else {
-                               /* bus commit has failed, rollback. */
-                               rc = _dhd_wlfc_rollback_packet_toq(ctx,
-                                       p,
-                                       /*
-                                       - remove wl-header for a delayed packet
-                                       - save wl-header header for suppressed packets
-                                       */
-                                       (needs_hdr ? eWLFC_PKTTYPE_DELAYED :
-                                       eWLFC_PKTTYPE_SUPPRESSED),
-                                       hslot);
-                               if (rc != BCME_OK)
-                                       ctx->stats.rollback_failed++;
+                               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;
-               /* packets from SENDQ are fresh and they'd need header */
-               needs_hdr = 1;
+
+               /* 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;
+
                for (credit = 0; credit < ctx->FIFO_credit[ac];) {
-                       p = _dhd_wlfc_deque_sendq(ctx, ac, &ac_fifo_credit_spent);
-                       if (p == NULL)
+                       commit_info.p = _dhd_wlfc_deque_sendq(ctx, ac,
+                                       &(commit_info.ac_fifo_credit_spent));
+                       if (commit_info.p == NULL)
                                break;
 
-                       DHD_PKTTAG_SETCREDITCHECK(PKTTAG(p), ac_fifo_credit_spent);
-                       rc = _dhd_wlfc_pretx_pktprocess(ctx, NULL, p, needs_hdr, &hslot);
-                       if (rc == BCME_OK)
-                               rc = fcommit(commit_ctx, p);
-                       else
-                               ctx->stats.generic_error++;
+                       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) {
-                               ctx->stats.pkt2bus++;
-                               if (ac_fifo_credit_spent) {
-                                       WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac);
-                                       ctx->stats.sendq_pkts[ac]++;
+                               if (commit_info.ac_fifo_credit_spent) {
                                        credit++;
                                }
                        }
                        else {
-                               /* bus commit has failed, rollback. */
-                               rc = _dhd_wlfc_rollback_packet_toq(ctx,
-                                       p,
-                                       /* remove wl-header while rolling back */
-                                       eWLFC_PKTTYPE_NEW,
-                                       hslot);
-                               if (rc != BCME_OK)
-                                       ctx->stats.rollback_failed++;
+                               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;
+                       }
+               }
+       }
+
+       /* 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;
+
+       for (; (credit_count > 0);) {
+
+               commit_info.p = _dhd_wlfc_deque_sendq(ctx, ac,
+                               &(commit_info.ac_fifo_credit_spent));
+               if (commit_info.p == NULL)
+                       break;
+
+               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;
 }
 
@@ -1489,6 +1685,7 @@ dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success)
        athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)
                dhd->wlfc_state;
        void* p;
+       int fifo_id;
 
        if (DHD_PKTTAG_SIGNALONLY(PKTTAG(txp))) {
 #ifdef PROP_TXSTATUS_DEBUG
@@ -1506,11 +1703,29 @@ dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success)
 
                /* indicate failure and free the packet */
                dhd_txcomplete(dhd, txp, FALSE);
-               PKTFREE(wlfc->osh, txp, TRUE);
 
                /* return the credit, if necessary */
-               if (DHD_PKTTAG_CREDITCHECK(PKTTAG(txp)))
-                       wlfc->FIFO_credit[DHD_PKTTAG_FIFO(PKTTAG(txp))]++;
+               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);
        }
        return;
 }
@@ -1593,7 +1808,21 @@ dhd_wlfc_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info)
        /* pick up the implicit credit from this packet */
        if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pktbuf))) {
                if (wlfc->proptxstatus_mode == WLFC_FCMODE_IMPLIED_CREDIT) {
-                       wlfc->FIFO_credit[fifo_id]++;
+                       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 {
@@ -1644,8 +1873,33 @@ dhd_wlfc_fifocreditback_indicate(dhd_pub_t *dhd, uint8* credits)
 #endif
                /* update FIFO credits */
                if (wlfc->proptxstatus_mode == WLFC_FCMODE_EXPLICIT_CREDIT)
-                       wlfc->FIFO_credit[i] += credits[i];
+               {
+                       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;
 }
 
@@ -1986,6 +2240,9 @@ dhd_wlfc_enable(dhd_pub_t *dhd)
 
        wlfc->proptxstatus_mode = WLFC_FCMODE_EXPLICIT_CREDIT;
 
+       wlfc->allow_credit_borrow = TRUE;
+       wlfc->borrow_defer_timestamp = 0;
+
        return BCME_OK;
 }
 
@@ -2165,7 +2422,7 @@ dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf)
                dhd_wlfc_parse_header_info(dhd, pktbuf, (h->dataOffset << 2));
                ((athost_wl_status_info_t*)dhd->wlfc_state)->stats.dhd_hdrpulls++;
                dhd_wlfc_commit_packets(dhd->wlfc_state, (f_commitpkt_t)dhd_bus_txdata,
-                       dhd->bus);
+                       (void *)dhd->bus);
                dhd_os_wlfc_unblock(dhd);
        }
 #endif /* PROP_TXSTATUS */
@@ -2232,7 +2489,6 @@ dhd_prot_dstats(dhd_pub_t *dhd)
        return;
 }
 
-
 int
 dhd_prot_init(dhd_pub_t *dhd)
 {
index 13791cd..94d3262 100644 (file)
@@ -1970,7 +1970,7 @@ dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr,
                pfn_element.wpa_auth = htod32(WPA_AUTH_PFN_ANY);
                pfn_element.wsec = htod32(0);
                pfn_element.infra = htod32(1);
-
+               pfn_element.flags = htod32(ENABLE << WL_PFN_HIDDEN_BIT);
                memcpy((char *)pfn_element.ssid.SSID, ssids_local[i].SSID, ssids_local[i].SSID_len);
                pfn_element.ssid.SSID_len = ssids_local[i].SSID_len;
 
index 569bd7f..61b1aef 100644 (file)
@@ -132,7 +132,11 @@ MODULE_LICENSE("GPL v2");
 
 #include <dhd_bus.h>
 
+#ifndef PROP_TXSTATUS
 #define DBUS_RX_BUFFER_SIZE_DHD(net)   (net->mtu + net->hard_header_len + dhd->pub.hdrlen)
+#else
+#define DBUS_RX_BUFFER_SIZE_DHD(net)   (net->mtu + net->hard_header_len + dhd->pub.hdrlen + 128)
+#endif
 
 #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15)
 const char *
@@ -218,7 +222,7 @@ typedef struct dhd_info {
        struct semaphore proto_sem;
 #ifdef PROP_TXSTATUS
        spinlock_t      wlfc_spinlock;
-#endif
+#endif /* PROP_TXSTATUS */
 #ifdef WLMEDIA_HTSF
        htsf_t  htsf;
 #endif
@@ -258,8 +262,6 @@ typedef struct dhd_info {
        int wakelock_counter;
        int wakelock_timeout_enable;
 
-       int hang_was_sent;
-
        /* Thread to issue ioctl for multicast */
        bool set_macaddress;
        struct ether_addr macvalue;
@@ -498,7 +500,6 @@ static struct notifier_block dhd_sleep_pm_notifier = {
 extern int register_pm_notifier(struct notifier_block *nb);
 extern int unregister_pm_notifier(struct notifier_block *nb);
 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
-       /* && defined(DHD_GPL) */
 
 static void dhd_set_packet_filter(int value, dhd_pub_t *dhd)
 {
@@ -976,10 +977,8 @@ dhd_op_if(dhd_if_t *ifp)
                                        dhd_net_attach)) {
                                        ifp->state = 0;
                                        return;
-                       }
-
+                               }
 #endif
-
                        if ((err = dhd_net_attach(&dhd->pub, ifp->idx)) != 0) {
                                DHD_ERROR(("%s: dhd_net_attach failed, err %d\n",
                                        __FUNCTION__, err));
@@ -1037,7 +1036,7 @@ dhd_op_if(dhd_if_t *ifp)
                        ap_net_dev = NULL;   /*  NULL  SOFTAP global wl0.1 as well */
                dhd_os_spin_unlock(&dhd->pub, flags);
 #endif /*  SOFTAP */
-       MFREE(dhd->pub.osh, ifp, sizeof(*ifp));
+               MFREE(dhd->pub.osh, ifp, sizeof(*ifp));
        }
 }
 
@@ -1413,6 +1412,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
                        continue;
                }
 
+
                pnext = PKTNEXT(dhdp->osh, pktbuf);
                PKTSETNEXT(wl->sh.osh, pktbuf, NULL);
 
@@ -2078,6 +2078,14 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
                goto done;
        }
 
+       /* send to dongle only if we are not waiting for reload already */
+       if (dhd->pub.hang_was_sent) {
+               DHD_ERROR(("%s: HANG was sent up earlier. Not talking to the chip\n",
+                       __FUNCTION__));
+               bcmerror = BCME_DONGLE_DOWN;
+               goto done;
+       }
+
        /* check for local dhd ioctl and handle it */
        if (driver == DHD_IOCTL_MAGIC) {
                bcmerror = dhd_ioctl((void *)&dhd->pub, &ioc, buf, buflen);
@@ -2185,6 +2193,41 @@ done:
 }
 
 static int
+dhd_cleanup_virt_ifaces(dhd_info_t *dhd)
+{
+       int i = 1; /* Leave ifidx 0 [Primary Interface] */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+       int rollback_lock = FALSE;
+#endif
+
+       DHD_TRACE(("%s: Enter \n", __func__));
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+       /* release lock for unregister_netdev */
+       if (rtnl_is_locked()) {
+               rtnl_unlock();
+               rollback_lock = TRUE;
+       }
+#endif
+
+       for (i = 1; i < DHD_MAX_IFS; i++) {
+               if (dhd->iflist[i]) {
+                       DHD_TRACE(("Deleting IF: %d \n", i));
+                       dhd->iflist[i]->state = WLC_E_IF_DEL;
+                       dhd->iflist[i]->idx = i;
+                       dhd_op_if(dhd->iflist[i]);
+               }
+       }
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+       if (rollback_lock)
+               rtnl_lock();
+#endif
+
+       return 0;
+}
+
+static int
 dhd_stop(struct net_device *net)
 {
        int ifidx;
@@ -2197,8 +2240,17 @@ dhd_stop(struct net_device *net)
        ifidx = dhd_net2idx(dhd, net);
 
 #ifdef WL_CFG80211
-       if (ifidx == 0)
+       if (ifidx == 0) {
                wl_cfg80211_down();
+
+               /** For CFG80211: Clean up all the left over virtual interfaces
+                * when the primary Interface is brought down. [ifconfig wlan0 down]
+                */
+               if ((dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) &&
+                       (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) {
+                       dhd_cleanup_virt_ifaces(dhd);
+               }
+       }
 #endif
 
 #ifdef PROP_TXSTATUS
@@ -2238,6 +2290,7 @@ dhd_open(struct net_device *net)
                strcpy(fw_path, firmware_path);
                firmware_path[0] = '\0';
        }
+
 #if !defined(WL_CFG80211)
        /** Force start if ifconfig_up gets called before START command
         *  We keep WEXT's wl_control_wl_start to provide backward compatibility
@@ -2262,7 +2315,9 @@ dhd_open(struct net_device *net)
        if (ifidx == 0) {
                atomic_set(&dhd->pend_8021x_cnt, 0);
 #if defined(WL_CFG80211)
+               DHD_ERROR(("\n%s\n", dhd_version));
                wl_android_wifi_on(net);
+               dhd->pub.hang_was_sent = 0;
 #endif
 
                if (dhd->pub.busstate != DHD_BUS_DATA) {
@@ -2610,7 +2665,7 @@ dhd_bus_start(dhd_pub_t *dhdp)
 
        ASSERT(dhd);
 
-       DHD_TRACE(("%s: \n", __FUNCTION__));
+       DHD_TRACE(("Enter %s:\n", __FUNCTION__));
 
        dhd_os_sdlock(dhdp);
 
@@ -2706,6 +2761,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
 #endif
        int scan_assoc_time = 40;
        int scan_unassoc_time = 40;
+       int scan_passive_time = 130;
        char buf[WLC_IOCTL_SMLEN];
        char *ptr;
        uint32 listen_interval = LISTEN_INTERVAL; /* Default Listen Interval in Beacons */
@@ -2946,14 +3002,16 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
                sizeof(scan_assoc_time), TRUE, 0);
        dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time,
                sizeof(scan_unassoc_time), TRUE, 0);
+       dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_PASSIVE_TIME, (char *)&scan_passive_time,
+               sizeof(scan_passive_time), TRUE, 0);
 
 #ifdef ARP_OFFLOAD_SUPPORT
        /* Set and enable ARP offload feature for STA only  */
-       if (arpoe
 #if defined(SOFTAP)
-                       && (!ap_fw_loaded)
-#endif /* (OEM_ANDROID) && defined(SOFTAP)  */
-               ) {
+       if (arpoe && !ap_fw_loaded) {
+#else
+       if (arpoe) {
+#endif 
                dhd_arp_offload_set(dhd, dhd_arp_mode);
                dhd_arp_offload_enable(dhd, arpoe);
        } else {
@@ -2970,7 +3028,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
        dhd->pktfilter[1] = NULL;
        dhd->pktfilter[2] = NULL;
        dhd->pktfilter[3] = NULL;
-
 #if defined(SOFTAP)
        if (ap_fw_loaded) {
                int i;
@@ -2979,13 +3036,12 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
                                0, dhd_master_mode);
                }
        }
-#endif /* (SOFTAP) */
+#endif /* defined(SOFTAP) */
 #endif /* PKT_FILTER_SUPPORT */
 
        /* Force STA UP */
-       ret = dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0);
-       if (ret < 0)
-               goto done;
+       if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0)) < 0)
+               DHD_ERROR(("%s Setting WL UP failed %d\n", __FUNCTION__, ret));
 
 
 done:
@@ -3065,7 +3121,8 @@ int dhd_change_mtu(dhd_pub_t *dhdp, int new_mtu, int ifidx)
 
 #ifdef ARP_OFFLOAD_SUPPORT
 /* add or remove AOE host ip(s) (up to 8 IPs on the interface)  */
-void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add)
+void
+aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add)
 {
        u32 ipv4_buf[MAX_IPV4_ENTRIES]; /* temp save for AOE host_ip table */
        int i;
@@ -3088,14 +3145,11 @@ void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add)
        }
 
        for (i = 0; i < MAX_IPV4_ENTRIES; i++) {
-
                if (add && (ipv4_buf[i] == 0)) {
-
-                               ipv4_buf[i]     = ipa;
+                               ipv4_buf[i] = ipa;
                                add = FALSE; /* added ipa to local table  */
                                DHD_ARPOE(("%s: Saved new IP in temp arp_hostip[%d]\n",
                                __FUNCTION__, i));
-
                } else if (ipv4_buf[i] == ipa) {
                        ipv4_buf[i]     = 0;
                        DHD_ARPOE(("%s: removed IP:%x from temp table %d\n",
@@ -3160,14 +3214,14 @@ static int dhd_device_event(struct notifier_block *this,
 #ifdef AOE_IP_ALIAS_SUPPORT
                if (!(ifa->ifa_label[strlen(ifa->ifa_label)-2] == 0x3a)) {
                                DHD_ARPOE(("%s: primary interface is down, AOE clr all\n",
-                                       __FUNCTION__));
+                                          __FUNCTION__));
                                dhd_aoe_hostip_clr(&dhd->pub);
                                dhd_aoe_arp_clr(&dhd->pub);
                } else
                        aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, FALSE);
 #else
-       dhd_aoe_hostip_clr(&dhd->pub);
-       dhd_aoe_arp_clr(&dhd->pub);
+                       dhd_aoe_hostip_clr(&dhd->pub);
+                       dhd_aoe_arp_clr(&dhd->pub);
 #endif
                        break;
 
@@ -3221,9 +3275,9 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx)
                net->netdev_ops = &dhd_ops_pri;
 #endif
        } else {
-       /*
-        * We have to use the primary MAC for virtual interfaces
-        */
+               /*
+                * We have to use the primary MAC for virtual interfaces
+                */
                memcpy(temp_addr, dhd->iflist[ifidx]->mac_addr, ETHER_ADDR_LEN);
                /*
                 * Android sets the locally administered bit to indicate that this is a
@@ -3362,15 +3416,10 @@ void dhd_detach(dhd_pub_t *dhdp)
 
        /* delete all interfaces, start with virtual  */
        if (dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) {
-               int i = 1;
                dhd_if_t *ifp;
 
-               for (i = 1; i < DHD_MAX_IFS; i++)
-                       if (dhd->iflist[i]) {
-                               dhd->iflist[i]->state = WLC_E_IF_DEL;
-                               dhd->iflist[i]->idx = i;
-                               dhd_op_if(dhd->iflist[i]);
-                       }
+               /* Cleanup all virtual Interfaces */
+               dhd_cleanup_virt_ifaces(dhd);
 
                /*  delete primary interface 0 */
                ifp = dhd->iflist[0];
@@ -3428,8 +3477,8 @@ void dhd_detach(dhd_pub_t *dhdp)
 #endif
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
-       unregister_pm_notifier(&dhd_sleep_pm_notifier);
-#endif
+               unregister_pm_notifier(&dhd_sleep_pm_notifier);
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
 
        if (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) {
 #ifdef CONFIG_HAS_WAKELOCK
@@ -3437,7 +3486,6 @@ void dhd_detach(dhd_pub_t *dhdp)
                wake_lock_destroy(&dhd->wl_rxwake);
 #endif
        }
-
 }
 
 
@@ -3509,7 +3557,6 @@ dhd_module_init(void)
 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
        error = dhd_bus_register();
 
-
        if (!error)
                printf("\n%s\n", dhd_version);
        else {
@@ -4156,11 +4203,14 @@ int net_os_send_hang_message(struct net_device *dev)
        int ret = 0;
 
        if (dhd) {
-               if (!dhd->hang_was_sent) {
-                       dhd->hang_was_sent = 1;
+               if (!dhd->pub.hang_was_sent) {
+                       dhd->pub.hang_was_sent = 1;
 #if defined(CONFIG_WIRELESS_EXT)
                        ret = wl_iw_send_priv_event(dev, "HANG");
 #endif
+#if defined(WL_CFG80211)
+                       ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED);
+#endif
                }
        }
        return ret;
index 72290b5..aadd122 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/sched.h>
+#include <typedefs.h>
 #include <linuxver.h>
 
 int setScheduler(struct task_struct *p, int policy, struct sched_param *param)
index c412edd..cdb2448 100644 (file)
@@ -147,6 +147,8 @@ extern void dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success);
 
 #ifdef DHD_DEBUG
 /* Device console log buffer state */
+#define CONSOLE_LINE_MAX       192
+#define CONSOLE_BUFFER_MAX     2024
 typedef struct dhd_console {
        uint            count;                  /* Poll interval msec counter */
        uint            log_addr;               /* Log struct address (fixed) */
@@ -429,7 +431,7 @@ do { \
  * Mode 0:     Dongle writes the software host mailbox and host is interrupted.
  * Mode 1:     (sdiod core rev >= 4)
  *             Device sets a new bit in the intstatus whenever there is a packet
- *             available in fifo.  Host can't clear this specific status bit until all the 
+ *             available in fifo.  Host can't clear this specific status bit until all the
  *             packets are read from the FIFO.  No need to ack dongle intstatus.
  * Mode 2:     (sdiod core rev >= 4)
  *             Device sets a bit in the intstatus, and host acks this by writing
@@ -463,9 +465,9 @@ static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint8 count);
 
 #ifdef DHD_DEBUG
 static int dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size);
-static int dhdsdio_mem_dump(dhd_bus_t *bus);
 static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror);
 #endif /* DHD_DEBUG */
+
 static int dhdsdio_download_state(dhd_bus_t *bus, bool enter);
 
 static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh);
@@ -1374,7 +1376,8 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
                        DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__));
                        ret = 0;
                } else {
-                       DHD_ERROR(("%s: ctrl_frame_stat == TRUE\n", __FUNCTION__));
+                       if (!bus->dhd->hang_was_sent)
+                               DHD_ERROR(("%s: ctrl_frame_stat == TRUE\n", __FUNCTION__));
                        ret = -1;
                        bus->ctrl_frame_stat = FALSE;
                        goto done;
@@ -1528,9 +1531,9 @@ enum {
        IOV_SD1IDLE,
        IOV_SLEEP,
        IOV_DONGLEISOLATION,
-       IOV_VARS
+       IOV_VARS,
 #ifdef SOFTAP
-    , IOV_FWPATH
+       IOV_FWPATH
 #endif
 };
 
@@ -1836,6 +1839,7 @@ dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
 
        if ((sh->flags & SDPCM_SHARED_VERSION_MASK) == 3 && SDPCM_SHARED_VERSION == 1)
                return BCME_OK;
+
        if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
                DHD_ERROR(("%s: sdpcm_shared version %d in dhd "
                           "is different than sdpcm_shared version %d in dongle\n",
@@ -1847,7 +1851,6 @@ dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
        return BCME_OK;
 }
 
-#define CONSOLE_LINE_MAX       192
 
 static int
 dhdsdio_readconsole(dhd_bus_t *bus)
@@ -1925,11 +1928,16 @@ dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size)
        int bcmerror = 0;
        uint msize = 512;
        char *mbuffer = NULL;
+       char *console_buffer = NULL;
        uint maxstrlen = 256;
        char *str = NULL;
        trap_t tr;
        sdpcm_shared_t sdpcm_shared;
        struct bcmstrbuf strbuf;
+       uint32 console_ptr, console_size, console_index;
+       uint8 line[CONSOLE_LINE_MAX], ch;
+       uint32 n, i, addr;
+       int rv;
 
        DHD_TRACE(("%s: Enter\n", __FUNCTION__));
 
@@ -2013,86 +2021,76 @@ dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size)
                        bcm_bprintf(&strbuf,
                        "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x,"
                        "lp 0x%x, rpc 0x%x Trap offset 0x%x, "
-                       "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n",
+                       "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n",
                        ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr),
                        ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc),
                        ltoh32(sdpcm_shared.trap_addr),
                        ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3),
                        ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7));
+
+                       addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log);
+                       if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&console_ptr, sizeof(console_ptr))) < 0)
+                               goto printbuf;
+
+                       addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.buf_size);
+                       if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&console_size, sizeof(console_size))) < 0)
+                               goto printbuf;
+
+                       addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.idx);
+                       if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&console_index, sizeof(console_index))) < 0)
+                               goto printbuf;
+
+                       console_ptr = ltoh32(console_ptr);
+                       console_size = ltoh32(console_size);
+                       console_index = ltoh32(console_index);
+
+                       if (console_size > CONSOLE_BUFFER_MAX || !(console_buffer = MALLOC(bus->dhd->osh, console_size)))
+                               goto printbuf;
+
+                       if ((rv = dhdsdio_membytes(bus, FALSE, console_ptr, (uint8 *)console_buffer, console_size)) < 0)
+                               goto printbuf;
+
+                       for ( i = 0, n = 0; i < console_size; i += n + 1 ) {
+                               for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
+                                       ch = console_buffer[ (console_index + i + n) % console_size];
+                                       if (ch == '\n')
+                                               break;
+                                       line[n] = ch;
+                               }
+
+
+                               if (n > 0) {
+                                       if (line[n - 1] == '\r')
+                                               n--;
+                                       line[n] = 0;
+                                       /* Don't use DHD_ERROR macro since we print a lot of information quickly */
+                                       /* The macro will truncate a lot of the printfs */
+
+                                       if (dhd_msg_level & DHD_ERROR_VAL)
+                                               printf("CONSOLE: %s\n", line);
+                               }
+                       }
                }
        }
 
+printbuf:
        if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) {
                DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf));
        }
 
-#ifdef DHD_DEBUG
-       if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
-               /* Mem dump to a file on device */
-               dhdsdio_mem_dump(bus);
-       }
-#endif /* DHD_DEBUG */
 
 done:
        if (mbuffer)
                MFREE(bus->dhd->osh, mbuffer, msize);
        if (str)
                MFREE(bus->dhd->osh, str, maxstrlen);
+       if (console_buffer)
+               MFREE(bus->dhd->osh, console_buffer, console_size);
 
        return bcmerror;
 }
+#endif /* #ifdef DHD_DEBUG */
 
-static int
-dhdsdio_mem_dump(dhd_bus_t *bus)
-{
-       int ret = 0;
-       int size; /* Full mem size */
-       int start = 0; /* Start address */
-       int read_size = 0; /* Read size of each iteration */
-       uint8 *buf = NULL, *databuf = NULL;
-
-       /* Get full mem size */
-       size = bus->ramsize;
-       buf = MALLOC(bus->dhd->osh, size);
-       if (!buf) {
-               printf("%s: Out of memory (%d bytes)\n", __FUNCTION__, size);
-               return -1;
-       }
-
-       /* Read mem content */
-       printf("Dump dongle memory");
-       databuf = buf;
-       while (size)
-       {
-               read_size = MIN(MEMBLOCK, size);
-               if ((ret = dhdsdio_membytes(bus, FALSE, start, databuf, read_size)))
-               {
-                       printf("%s: Error membytes %d\n", __FUNCTION__, ret);
-                       if (buf) {
-                               MFREE(bus->dhd->osh, buf, size);
-                       }
-                       return -1;
-               }
-               printf(".");
-
-               /* Decrement size and increment start address */
-               size -= read_size;
-               start += read_size;
-               databuf += read_size;
-       }
-       printf("Done\n");
-
-       /* free buf before return !!! */
-       if (write_to_file(bus->dhd, buf, bus->ramsize))
-       {
-               printf("%s: Error writing to files\n", __FUNCTION__);
-               return -1;
-       }
-
-       /* buf free handled in write_to_file, not here */
-       return 0;
-}
-#endif /* defined(DHD_DEBUG) */
 
 int
 dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len)
@@ -3040,6 +3038,7 @@ dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
                dhd_os_sdunlock(bus->dhd);
 }
 
+
 int
 dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
 {
@@ -4352,6 +4351,13 @@ dhdsdio_hostmail(dhd_bus_t *bus)
                bus->flowcontrol = fcbits;
        }
 
+#ifdef DHD_DEBUG
+       /* At least print a message if FW halted */
+       if (hmb_data & HMB_DATA_FWHALT) {
+               DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED\n"));
+               dhdsdio_checkdied(bus, NULL, 0);
+       }
+#endif /* DHD_DEBUG */
 
        /* Shouldn't be any others */
        if (hmb_data & ~(HMB_DATA_DEVREADY |
@@ -5176,6 +5182,9 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
 #ifdef GET_CUSTOM_MAC_ENABLE
        struct ether_addr ea_addr;
 #endif /* GET_CUSTOM_MAC_ENABLE */
+#ifdef PROP_TXSTATUS
+       uint up = 0;
+#endif
 
        /* Init global variables at run-time, not as part of the declaration.
         * This is required to support init/de-init of the driver. Initialization
@@ -5342,6 +5351,10 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
                goto fail;
        }
 
+#ifdef PROP_TXSTATUS
+       if (dhd_download_fw_on_driverload)
+               dhd_wl_ioctl_cmd(bus->dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0);
+#endif
        return bus;
 
 fail:
@@ -5916,7 +5929,7 @@ err:
        return bcmerror;
 }
 
-/* 
+/*
        EXAMPLE: nvram_array
        nvram_arry format:
        name=value
@@ -6190,16 +6203,16 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
                                                dhd_enable_oob_intr(bus, TRUE);
 #endif /* defined(OOB_INTR_ONLY) */
 
-                                       bus->dhd->dongle_reset = FALSE;
-                                       bus->dhd->up = TRUE;
+                                               bus->dhd->dongle_reset = FALSE;
+                                               bus->dhd->up = TRUE;
 
 #if !defined(IGNORE_ETH0_DOWN)
-                                       /* Restore flow control  */
-                                       dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
+                                               /* Restore flow control  */
+                                               dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
 #endif 
-                                       dhd_os_wd_timer(dhdp, dhd_watchdog_ms);
+                                               dhd_os_wd_timer(dhdp, dhd_watchdog_ms);
 
-                                       DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__));
+                                               DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__));
                                        } else {
                                                dhd_bus_stop(bus, FALSE);
                                                dhdsdio_release_dongle(bus, bus->dhd->osh,
index 53db62c..59d018b 100644 (file)
@@ -201,6 +201,14 @@ typedef struct athost_wl_stat_counters {
 #define WLFC_FCMODE_IMPLIED_CREDIT             1
 #define WLFC_FCMODE_EXPLICIT_CREDIT            2
 
+#define WLFC_BORROW_DEFER_PERIOD_MS 100
+
+/* Mask to represent available ACs (note: BC/MC is ignored */
+#define WLFC_AC_MASK 0xF
+
+/* Mask to check for only on-going AC_BE traffic */
+#define WLFC_AC_BE_TRAFFIC_ONLY 0xD
+
 typedef struct athost_wl_status_info {
        uint8   last_seqid_to_wlc;
 
@@ -213,7 +221,11 @@ typedef struct athost_wl_status_info {
        athost_wl_stat_counters_t stats;
 
        /* the additional ones are for bc/mc and ATIM FIFO */
-       int     FIFO_credit[AC_COUNT + 2];
+       int             FIFO_credit[AC_COUNT + 2];
+
+       /* Credit borrow counts for each FIFO from each of the other FIFOs */
+       int             credits_borrowed[AC_COUNT + 2][AC_COUNT + 2];
+
        struct  pktq SENDQ;
 
        /* packet hanger and MAC->handle lookup table */
@@ -228,7 +240,7 @@ typedef struct athost_wl_status_info {
                wlfc_mac_descriptor_t   other;
        } destination_entries;
        /* token position for different priority packets */
-       uint8   token_pos[AC_COUNT];
+       uint8   token_pos[AC_COUNT+1];
        /* ON/OFF state for flow control to the host network interface */
        uint8   hostif_flow_state[WLFC_MAX_IFNUM];
        uint8   host_ifidx;
@@ -243,6 +255,12 @@ typedef struct athost_wl_status_info {
        2 - Use explicit credit
        */
        uint8   proptxstatus_mode;
+
+       /* To borrow credits */
+       uint8   allow_credit_borrow;
+
+       /* Timestamp to compute how long to defer borrowing for */
+       uint32  borrow_defer_timestamp;
 } athost_wl_status_info_t;
 
 #endif /* __wlfc_host_driver_definitions_h__ */
index ec060c9..ab96c07 100644 (file)
 
 #define        EPI_RC_NUMBER           125
 
-#define        EPI_INCREMENTAL_NUMBER  74
+#define        EPI_INCREMENTAL_NUMBER  78
 
 #define        EPI_BUILD_NUMBER        0
 
-#define        EPI_VERSION             5, 90, 125, 74
+#define        EPI_VERSION             5, 90, 125, 78
 
-#define        EPI_VERSION_NUM         0x055a7d4a
+#define        EPI_VERSION_NUM         0x055a7d4e
 
 #define EPI_VERSION_DEV                5.90.125
 
 
-#define        EPI_VERSION_STR         "5.90.125.74"
+#define        EPI_VERSION_STR         "5.90.125.78"
 
 #endif 
index 239b15d..17b68e5 100644 (file)
 #define BCM_MEM_FILENAME_LEN   24              
 
 #ifdef DHD_USE_STATIC_BUF
-#define MAX_STATIC_BUF_NUM 16
-#define STATIC_BUF_SIZE        (PAGE_SIZE*2)
-#define STATIC_BUF_TOTAL_LEN (MAX_STATIC_BUF_NUM*STATIC_BUF_SIZE)
+#define STATIC_BUF_MAX_NUM     16
+#define STATIC_BUF_SIZE                (PAGE_SIZE * 2)
+#define STATIC_BUF_TOTAL_LEN   (STATIC_BUF_MAX_NUM * STATIC_BUF_SIZE)
+
 typedef struct bcm_static_buf {
        struct semaphore static_sem;
        unsigned char *buf_ptr;
-       unsigned char buf_use[MAX_STATIC_BUF_NUM];
+       unsigned char buf_use[STATIC_BUF_MAX_NUM];
 } bcm_static_buf_t;
 
 static bcm_static_buf_t *bcm_static_buf = 0;
 
-#define MAX_STATIC_PKT_NUM 8
+#define STATIC_PKT_MAX_NUM     8
+
 typedef struct bcm_static_pkt {
-       struct sk_buff *skb_4k[MAX_STATIC_PKT_NUM];
-       struct sk_buff *skb_8k[MAX_STATIC_PKT_NUM];
+       struct sk_buff *skb_4k[STATIC_PKT_MAX_NUM];
+       struct sk_buff *skb_8k[STATIC_PKT_MAX_NUM];
        struct semaphore osl_pkt_sem;
-       unsigned char pkt_use[MAX_STATIC_PKT_NUM*2];
+       unsigned char pkt_use[STATIC_PKT_MAX_NUM * 2];
 } bcm_static_pkt_t;
 static bcm_static_pkt_t *bcm_static_skb = 0;
 #endif 
@@ -228,8 +230,8 @@ osl_attach(void *pdev, uint bustype, bool pkttag)
                bcm_static_skb = (bcm_static_pkt_t *)((char *)bcm_static_buf + 2048);
                skb_buff_ptr = dhd_os_prealloc(osh, 4, 0);
 
-               bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *)*16);
-               for (i = 0; i < MAX_STATIC_PKT_NUM*2; i++)
+               bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *) * 16);
+               for (i = 0; i < STATIC_PKT_MAX_NUM * 2; i++)
                        bcm_static_skb->pkt_use[i] = 0;
 
                sema_init(&bcm_static_skb->osl_pkt_sem, 1);
@@ -548,84 +550,69 @@ osl_pktget_static(osl_t *osh, uint len)
        struct sk_buff *skb;
 
 
-       if (len > (PAGE_SIZE*2))
-       {
+       if (len > (PAGE_SIZE * 2)) {
+               printk("%s: attempt to allocate huge packet (0x%x)\n", __FUNCTION__, len);
                printk("Do we really need this big skb??\n");
                return osl_pktget(osh, len);
        }
 
 
        down(&bcm_static_skb->osl_pkt_sem);
-       if (len <= PAGE_SIZE)
-       {
 
-               for (i = 0; i < MAX_STATIC_PKT_NUM; i++)
-               {
+       if (len <= PAGE_SIZE) {
+               for (i = 0; i < STATIC_PKT_MAX_NUM; i++) {
                        if (bcm_static_skb->pkt_use[i] == 0)
                                break;
                }
 
-               if (i != MAX_STATIC_PKT_NUM)
-               {
+               if (i != STATIC_PKT_MAX_NUM) {
                        bcm_static_skb->pkt_use[i] = 1;
                        up(&bcm_static_skb->osl_pkt_sem);
-
                        skb = bcm_static_skb->skb_4k[i];
                        skb->tail = skb->data + len;
                        skb->len = len;
-
                        return skb;
                }
        }
 
 
-       for (i = 0; i < MAX_STATIC_PKT_NUM; i++)
-       {
-               if (bcm_static_skb->pkt_use[i+MAX_STATIC_PKT_NUM] == 0)
+       for (i = 0; i < STATIC_PKT_MAX_NUM; i++) {
+               if (bcm_static_skb->pkt_use[i+STATIC_PKT_MAX_NUM] == 0)
                        break;
        }
 
-       if (i != MAX_STATIC_PKT_NUM)
-       {
-               bcm_static_skb->pkt_use[i+MAX_STATIC_PKT_NUM] = 1;
+       if (i != STATIC_PKT_MAX_NUM) {
+               bcm_static_skb->pkt_use[i+STATIC_PKT_MAX_NUM] = 1;
                up(&bcm_static_skb->osl_pkt_sem);
                skb = bcm_static_skb->skb_8k[i];
                skb->tail = skb->data + len;
                skb->len = len;
-
                return skb;
        }
 
-
        up(&bcm_static_skb->osl_pkt_sem);
-       printk("all static pkt in use!\n");
+       printk("%s: all static pkt in use!\n", __FUNCTION__);
        return osl_pktget(osh, len);
 }
 
-
 void
 osl_pktfree_static(osl_t *osh, void *p, bool send)
 {
        int i;
 
-       for (i = 0; i < MAX_STATIC_PKT_NUM; i++)
-       {
-               if (p == bcm_static_skb->skb_4k[i])
-               {
+       for (i = 0; i < STATIC_PKT_MAX_NUM; i++) {
+               if (p == bcm_static_skb->skb_4k[i]) {
                        down(&bcm_static_skb->osl_pkt_sem);
                        bcm_static_skb->pkt_use[i] = 0;
                        up(&bcm_static_skb->osl_pkt_sem);
-
                        return;
                }
        }
 
-       for (i = 0; i < MAX_STATIC_PKT_NUM; i++)
-       {
-               if (p == bcm_static_skb->skb_8k[i])
-               {
+       for (i = 0; i < STATIC_PKT_MAX_NUM; i++) {
+               if (p == bcm_static_skb->skb_8k[i]) {
                        down(&bcm_static_skb->osl_pkt_sem);
-                       bcm_static_skb->pkt_use[i + MAX_STATIC_PKT_NUM] = 0;
+                       bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM] = 0;
                        up(&bcm_static_skb->osl_pkt_sem);
 
                        return;
index cefa7f9..36110f9 100644 (file)
@@ -108,6 +108,7 @@ uint dhd_dev_reset(struct net_device *dev, uint8 flag);
 void dhd_dev_init_ioctl(struct net_device *dev);
 #ifdef WL_CFG80211
 int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr);
+int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command);
 #else
 int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr) { return 0; }
 #endif
@@ -454,6 +455,9 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
                        net_os_set_packet_filter(net, 0); /* DHCP starts */
                else
                        net_os_set_packet_filter(net, 1); /* DHCP ends */
+#ifdef WL_CFG80211
+               bytes_written = wl_cfg80211_set_btcoex_dhcp(net, command);
+#endif
        }
        else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) {
                bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len);
index 08a9a04..8a77231 100644 (file)
@@ -123,6 +123,32 @@ static ctl_table wl_sysctl_table[] = {
 static struct ctl_table_header *wl_sysctl_hdr;
 #endif /* CONFIG_SYSCTL */
 
+#define COEX_DHCP
+
+#if defined(COEX_DHCP)
+#define BT_DHCP_eSCO_FIX               /* use New SCO/eSCO smart YG
+                                        * suppression
+                                        */
+#define BT_DHCP_USE_FLAGS              /* this flag boost wifi pkt priority
+                                        * to max, caution: -not fair to sco
+                                        */
+#define BT_DHCP_OPPR_WIN_TIME  2500    /* T1 start SCO/ESCo priority
+                                        * suppression
+                                        */
+#define BT_DHCP_FLAG_FORCE_TIME 5500   /* T2 turn off SCO/SCO supperesion
+                                        * is (timeout)
+                                        */
+enum wl_cfg80211_btcoex_status {
+       BT_DHCP_IDLE,
+       BT_DHCP_START,
+       BT_DHCP_OPPR_WIN,
+       BT_DHCP_FLAG_FORCE_TIMEOUT
+};
+
+static int wl_cfg80211_btcoex_init(struct wl_priv *wl);
+static void wl_cfg80211_btcoex_deinit(struct wl_priv *wl);
+#endif
+
 /* This is to override regulatory domains defined in cfg80211 module (reg.c)
  * By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN
  * and NL80211_RRF_NO_IBSS for 5GHz channels (for 36..48 and 149..165).
@@ -909,7 +935,6 @@ fail:
        return ERR_PTR(-ENODEV);
 }
 
-
 static s32
 wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev)
 {
@@ -944,7 +969,6 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev)
                        timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
                                (wl->scan_request == false),
                                msecs_to_jiffies(MAX_WAIT_TIME));
-
                        if (timeout > 0 && (!wl->scan_request)) {
                                WL_DBG(("IFDEL Operations Done"));
                        } else {
@@ -1063,6 +1087,7 @@ s32
 wl_cfg80211_ifdel_ops(struct net_device *net)
 {
        struct wl_priv *wl = wlcfg_drv_priv;
+       int rollback_lock = FALSE;
 
        if (!net || !net->name) {
                WL_DBG(("net is NULL\n"));
@@ -1073,10 +1098,15 @@ wl_cfg80211_ifdel_ops(struct net_device *net)
 
                /* Abort any pending scan requests */
                wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
-               rtnl_lock();
+               if (!rtnl_is_locked()) {
+                       rtnl_lock();
+                       rollback_lock = TRUE;
+               }
                WL_INFO(("ESCAN COMPLETED\n"));
                wl_notify_escan_complete(wl, true);
-               rtnl_unlock();
+
+               if (rollback_lock)
+                       rtnl_unlock();
        }
 
        /* Wake up any waiting thread */
@@ -1093,7 +1123,6 @@ wl_cfg80211_notify_ifdel(struct net_device *net)
 
        if (wl->p2p->vif_created) {
                s32 index = 0;
-
                WL_DBG(("IF_DEL event called from dongle, net %x, vif name: %s\n",
                        (unsigned int)net, wl->p2p->vir_ifname));
 
@@ -1459,6 +1488,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
        struct wl_priv *wl = wiphy_priv(wiphy);
        struct cfg80211_ssid *ssids;
        struct wl_scan_req *sr = wl_to_sr(wl);
+       wpa_ie_fixed_t *wps_ie;
        s32 passive_scan;
        bool iscan_req;
        bool escan_req;
@@ -1466,7 +1496,8 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
        bool p2p_ssid;
        s32 err = 0;
        s32 i;
-
+       u32 wpsie_len = 0;
+       u8 wpsie[IE_MAX_LEN];
        if (unlikely(wl_get_drv_status(wl, SCANNING))) {
                WL_ERR(("Scanning already : status (%d)\n", (int)wl->status));
                return -EAGAIN;
@@ -1531,6 +1562,26 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
                                                }
                                        }
                                }
+                               if (!wl->p2p_supported || !p2p_scan(wl)) {
+                                       if (ndev == wl_to_prmry_ndev(wl)) {
+                                               /* find the WPSIE */
+                                               memset(wpsie, 0, sizeof(wpsie));
+                                               if ((wps_ie = wl_cfgp2p_find_wpsie(
+                                                       (u8 *)request->ie,
+                                                       request->ie_len)) != NULL) {
+                                                       wpsie_len =
+                                                       wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN;
+                                                       memcpy(wpsie, wps_ie, wpsie_len);
+                                               } else {
+                                                       wpsie_len = 0;
+                                               }
+                                               err = wl_cfgp2p_set_management_ie(wl, ndev, -1,
+                                                       VNDR_IE_PRBREQ_FLAG, wpsie, wpsie_len);
+                                               if (unlikely(err)) {
+                                                       goto scan_out;
+                                               }
+                                       }
+                               }
                        }
                }
        } else {                /* scan in ibss */
@@ -1615,6 +1666,7 @@ wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
 
        WL_DBG(("Enter \n"));
        CHECK_SYS_UP(wl);
+
        err = __wl_cfg80211_scan(wiphy, ndev, request, NULL);
        if (unlikely(err)) {
                WL_ERR(("scan error (%d)\n", err));
@@ -2100,9 +2152,12 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
        size_t join_params_size;
        s32 err = 0;
        wpa_ie_fixed_t *wpa_ie;
+       wpa_ie_fixed_t *wps_ie;
        bcm_tlv_t *wpa2_ie;
        u8* wpaie  = 0;
        u32 wpaie_len = 0;
+       u32 wpsie_len = 0;
+       u8 wpsie[IE_MAX_LEN];
        WL_DBG(("In\n"));
        CHECK_SYS_UP(wl);
 
@@ -2126,7 +2181,7 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
                        wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev),
                                VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len);
                } else if (p2p_on(wl) && (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)) {
-                       /* This is the connect req after WPS is done [credentials exchanged] 
+                       /* This is the connect req after WPS is done [credentials exchanged]
                         * currently identified with WPA_VERSION_2 .
                         * Update the previously set IEs with
                         * the newly received IEs from Supplicant. This will remove the WPS IE from
@@ -2158,8 +2213,21 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
                                ioctlbuf, sizeof(ioctlbuf));
                        }
 
+                       /* find the WPSIE */
+                       memset(wpsie, 0, sizeof(wpsie));
+                       if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)sme->ie,
+                               sme->ie_len)) != NULL) {
+                               wpsie_len = wps_ie->length +WPA_RSN_IE_TAG_FIXED_LEN;
+                               memcpy(wpsie, wps_ie, wpsie_len);
+                       } else {
+                               wpsie_len = 0;
+                       }
+                       err = wl_cfgp2p_set_management_ie(wl, dev, -1,
+                               VNDR_IE_ASSOCREQ_FLAG, wpsie, wpsie_len);
+                       if (unlikely(err)) {
+                               return err;
+                       }
        }
-
        if (unlikely(!sme->ssid)) {
                WL_ERR(("Invalid ssid\n"));
                return -EOPNOTSUPP;
@@ -2594,17 +2662,6 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
                }
                return err;
        }
-
-#ifdef NOT_YET
-       /* TODO: Removed in P2P twig, check later --lin */
-       val = 0;                /* assume open key. otherwise 1 */
-       val = htod32(val);
-       err = wldev_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val), false);
-       if (unlikely(err)) {
-               WL_ERR(("WLC_SET_AUTH error (%d)\n", err));
-               return err;
-       }
-#endif
        return err;
 }
 
@@ -3145,9 +3202,6 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
                                wl_cfgp2p_set_management_ie(wl, dev, bssidx,
                                        VNDR_IE_PRBRSP_FLAG,
                                        (u8 *)wps_ie, wpsie_len + p2pie_len);
-                               /* remove WLC_E_PROBREQ_MSG event to prevent HOSTAPD
-                                * from responding many probe request
-                                */
                        }
                }
                cfg80211_mgmt_tx_status(dev, *cookie, buf, len, true, GFP_KERNEL);
@@ -3198,7 +3252,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
                wifi_p2p_pub_act_frame_t *act_frm =
                        (wifi_p2p_pub_act_frame_t *) (action_frame->data);
                /*
-                * To make sure to send successfully action frame, we have to turn off mpc 
+                * To make sure to send successfully action frame, we have to turn off mpc
                 */
                if ((act_frm->subtype == P2P_PAF_GON_REQ)||
                  (act_frm->subtype == P2P_PAF_GON_RSP)) {
@@ -3702,8 +3756,11 @@ wl_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
                        } else {
                                WL_DBG(("No WPSIE in beacon \n"));
                        }
-                       wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), false);
-
+                       err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), false);
+                       if (unlikely(err)) {
+                               WL_ERR(("WLC_UP error (%d)\n", err));
+                               return err;
+                       }
                        memset(&join_params, 0, sizeof(join_params));
                        /* join parameters starts with ssid */
                        join_params_size = sizeof(join_params.ssid);
@@ -4222,7 +4279,7 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
 
        } else {
                WL_DBG(("wl_notify_connect_status : event %d status : %d \n",
-                       ntoh32(e->event_type), ntoh32(e->status)));
+               ntoh32(e->event_type), ntoh32(e->status)));
                if (wl_is_linkup(wl, e, ndev)) {
                        wl_link_up(wl);
                        act = true;
@@ -4859,7 +4916,11 @@ static s32 wl_init_priv_mem(struct wl_priv *wl)
                WL_ERR(("pmk list alloc failed\n"));
                goto init_priv_mem_out;
        }
-
+       wl->sta_info = (void *)kzalloc(sizeof(*wl->sta_info), GFP_KERNEL);
+       if (unlikely(!wl->sta_info)) {
+               WL_ERR(("sta info  alloc failed\n"));
+               goto init_priv_mem_out;
+       }
        return 0;
 
 init_priv_mem_out:
@@ -4892,6 +4953,8 @@ static void wl_deinit_priv_mem(struct wl_priv *wl)
        wl->fw = NULL;
        kfree(wl->pmk_list);
        wl->pmk_list = NULL;
+       kfree(wl->sta_info);
+       wl->sta_info = NULL;
        if (wl->ap_info) {
                kfree(wl->ap_info->wpa_ie);
                kfree(wl->ap_info->rsn_ie);
@@ -5428,6 +5491,11 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data)
                goto cfg80211_attach_out;
        }
 #endif
+#if defined(COEX_DHCP)
+       if (wl_cfg80211_btcoex_init(wl))
+               goto cfg80211_attach_out;
+#endif /* COEX_DHCP */
+
        wlcfg_drv_priv = wl;
        return err;
 
@@ -5444,6 +5512,11 @@ void wl_cfg80211_detach(void)
        wl = wlcfg_drv_priv;
 
        WL_TRACE(("In\n"));
+
+#if defined(COEX_DHCP)
+       wl_cfg80211_btcoex_deinit(wl);
+#endif /* COEX_DHCP */
+
 #if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
        if (wl_sysctl_hdr)
                unregister_sysctl_table(wl_sysctl_hdr);
@@ -6120,6 +6193,20 @@ s32 wl_cfg80211_up(void)
        return err;
 }
 
+/* Private Event  to Supplicant with indication that FW hangs */
+int wl_cfg80211_hang(struct net_device *dev, u16 reason)
+{
+       struct wl_priv *wl;
+       wl = wlcfg_drv_priv;
+
+       WL_ERR(("In : FW crash Eventing\n"));
+       cfg80211_disconnected(dev, reason, NULL, 0, GFP_KERNEL);
+       if (wl != NULL) {
+               wl_link_down(wl);
+       }
+       return 0;
+}
+
 s32 wl_cfg80211_down(void)
 {
        struct wl_priv *wl;
@@ -6547,3 +6634,480 @@ static int wl_setup_rfkill(struct wl_priv *wl, bool setup)
 err_out:
        return err;
 }
+
+#if defined(COEX_DHCP)
+/*
+ * get named driver variable to uint register value and return error indication
+ * calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, &reg_value)
+ */
+static int
+dev_wlc_intvar_get_reg(struct net_device *dev, char *name,
+       uint reg, int *retval)
+{
+       union {
+               char buf[WLC_IOCTL_SMLEN];
+               int val;
+       } var;
+       int error;
+
+       bcm_mkiovar(name, (char *)(&reg), sizeof(reg),
+               (char *)(&var), sizeof(var.buf));
+       error = wldev_ioctl(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf), false);
+
+       *retval = dtoh32(var.val);
+       return (error);
+}
+
+static int
+dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
+       char ioctlbuf[1024];
+#else
+       static char ioctlbuf[1024];
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */
+
+       bcm_mkiovar(name, buf, len, ioctlbuf, sizeof(ioctlbuf));
+
+       return (wldev_ioctl(dev, WLC_SET_VAR, ioctlbuf, sizeof(ioctlbuf), false));
+}
+/*
+get named driver variable to uint register value and return error indication
+calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value)
+*/
+static int
+dev_wlc_intvar_set_reg(struct net_device *dev, char *name, char *addr, char * val)
+{
+       char reg_addr[8];
+
+       memset(reg_addr, 0, sizeof(reg_addr));
+       memcpy((char *)&reg_addr[0], (char *)addr, 4);
+       memcpy((char *)&reg_addr[4], (char *)val, 4);
+
+       return (dev_wlc_bufvar_set(dev, name, (char *)&reg_addr[0], sizeof(reg_addr)));
+}
+
+static bool btcoex_is_sco_active(struct net_device *dev)
+{
+       int ioc_res = 0;
+       bool res = FALSE;
+       int sco_id_cnt = 0;
+       int param27;
+       int i;
+
+       for (i = 0; i < 12; i++) {
+
+               ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, &param27);
+
+               WL_INFO(("%s, sample[%d], btc params: 27:%x\n",
+                       __FUNCTION__, i, param27));
+
+               if (ioc_res < 0) {
+                       WL_ERR(("%s ioc read btc params error\n", __FUNCTION__));
+                       break;
+               }
+
+               if ((param27 & 0x6) == 2) { /* count both sco & esco  */
+                       sco_id_cnt++;
+               }
+
+               if (sco_id_cnt > 2) {
+                       WL_INFO(("%s, sco/esco detected, pkt id_cnt:%d  samples:%d\n",
+                               __FUNCTION__, sco_id_cnt, i));
+                       res = TRUE;
+                       break;
+               }
+
+               msleep(5);
+       }
+
+       return res;
+}
+
+#if defined(BT_DHCP_eSCO_FIX)
+/* Enhanced BT COEX settings for eSCO compatibility during DHCP window */
+static int set_btc_esco_params(struct net_device *dev, bool trump_sco)
+{
+       static bool saved_status = FALSE;
+
+       char buf_reg50va_dhcp_on[8] =
+               { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 };
+       char buf_reg51va_dhcp_on[8] =
+               { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+       char buf_reg64va_dhcp_on[8] =
+               { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+       char buf_reg65va_dhcp_on[8] =
+               { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+       char buf_reg71va_dhcp_on[8] =
+               { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+       uint32 regaddr;
+       static uint32 saved_reg50;
+       static uint32 saved_reg51;
+       static uint32 saved_reg64;
+       static uint32 saved_reg65;
+       static uint32 saved_reg71;
+
+       if (trump_sco) {
+               /* this should reduce eSCO agressive retransmit
+                * w/o breaking it
+                */
+
+               /* 1st save current */
+               WL_INFO(("Do new SCO/eSCO coex algo {save &"
+                         "override}\n"));
+               if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) &&
+                       (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) &&
+                       (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) &&
+                       (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) &&
+                       (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) {
+                       saved_status = TRUE;
+                       WL_INFO(("%s saved bt_params[50,51,64,65,71]:"
+                                 "0x%x 0x%x 0x%x 0x%x 0x%x\n",
+                                 __FUNCTION__, saved_reg50, saved_reg51,
+                                 saved_reg64, saved_reg65, saved_reg71));
+               } else {
+                       WL_ERR((":%s: save btc_params failed\n",
+                               __FUNCTION__));
+                       saved_status = FALSE;
+                       return -1;
+               }
+
+               WL_INFO(("override with [50,51,64,65,71]:"
+                         "0x%x 0x%x 0x%x 0x%x 0x%x\n",
+                         *(u32 *)(buf_reg50va_dhcp_on+4),
+                         *(u32 *)(buf_reg51va_dhcp_on+4),
+                         *(u32 *)(buf_reg64va_dhcp_on+4),
+                         *(u32 *)(buf_reg65va_dhcp_on+4),
+                         *(u32 *)(buf_reg71va_dhcp_on+4)));
+
+               dev_wlc_bufvar_set(dev, "btc_params",
+                       (char *)&buf_reg50va_dhcp_on[0], 8);
+               dev_wlc_bufvar_set(dev, "btc_params",
+                       (char *)&buf_reg51va_dhcp_on[0], 8);
+               dev_wlc_bufvar_set(dev, "btc_params",
+                       (char *)&buf_reg64va_dhcp_on[0], 8);
+               dev_wlc_bufvar_set(dev, "btc_params",
+                       (char *)&buf_reg65va_dhcp_on[0], 8);
+               dev_wlc_bufvar_set(dev, "btc_params",
+                       (char *)&buf_reg71va_dhcp_on[0], 8);
+
+               saved_status = TRUE;
+       } else if (saved_status) {
+               /* restore previously saved bt params */
+               WL_INFO(("Do new SCO/eSCO coex algo {save &"
+                         "override}\n"));
+
+               regaddr = 50;
+               dev_wlc_intvar_set_reg(dev, "btc_params",
+                       (char *)&regaddr, (char *)&saved_reg50);
+               regaddr = 51;
+               dev_wlc_intvar_set_reg(dev, "btc_params",
+                       (char *)&regaddr, (char *)&saved_reg51);
+               regaddr = 64;
+               dev_wlc_intvar_set_reg(dev, "btc_params",
+                       (char *)&regaddr, (char *)&saved_reg64);
+               regaddr = 65;
+               dev_wlc_intvar_set_reg(dev, "btc_params",
+                       (char *)&regaddr, (char *)&saved_reg65);
+               regaddr = 71;
+               dev_wlc_intvar_set_reg(dev, "btc_params",
+                       (char *)&regaddr, (char *)&saved_reg71);
+
+               WL_INFO(("restore bt_params[50,51,64,65,71]:"
+                       "0x%x 0x%x 0x%x 0x%x 0x%x\n",
+                       saved_reg50, saved_reg51, saved_reg64,
+                       saved_reg65, saved_reg71));
+
+               saved_status = FALSE;
+       } else {
+               WL_ERR((":%s att to restore not saved BTCOEX params\n",
+                       __FUNCTION__));
+               return -1;
+       }
+       return 0;
+}
+#endif /* BT_DHCP_eSCO_FIX */
+
+static void
+wl_cfg80211_bt_setflag(struct net_device *dev, bool set)
+{
+#if defined(BT_DHCP_USE_FLAGS)
+       char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 };
+       char buf_flag7_default[8]   = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+       rtnl_lock();
+#endif
+
+#if defined(BT_DHCP_eSCO_FIX)
+       /* set = 1, save & turn on  0 - off & restore prev settings */
+       set_btc_esco_params(dev, set);
+#endif
+
+#if defined(BT_DHCP_USE_FLAGS)
+       WL_TRACE(("WI-FI priority boost via bt flags, set:%d\n", set));
+       if (set == TRUE)
+               /* Forcing bt_flag7  */
+               dev_wlc_bufvar_set(dev, "btc_flags",
+                       (char *)&buf_flag7_dhcp_on[0],
+                       sizeof(buf_flag7_dhcp_on));
+       else
+               /* Restoring default bt flag7 */
+               dev_wlc_bufvar_set(dev, "btc_flags",
+                       (char *)&buf_flag7_default[0],
+                       sizeof(buf_flag7_default));
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+       rtnl_unlock();
+#endif
+}
+
+static void wl_cfg80211_bt_timerfunc(ulong data)
+{
+       struct btcoex_info *bt_local = (struct btcoex_info *)data;
+       WL_TRACE(("%s\n", __FUNCTION__));
+       bt_local->timer_on = 0;
+       schedule_work(&bt_local->work);
+}
+
+static void wl_cfg80211_bt_handler(struct work_struct *work)
+{
+       struct btcoex_info *btcx_inf;
+
+       btcx_inf = container_of(work, struct btcoex_info, work);
+
+       if (btcx_inf->timer_on) {
+               btcx_inf->timer_on = 0;
+               del_timer_sync(&btcx_inf->timer);
+       }
+
+       switch (btcx_inf->bt_state) {
+               case BT_DHCP_START:
+                       /* DHCP started
+                        * provide OPPORTUNITY window to get DHCP address
+                        */
+                       WL_TRACE(("%s bt_dhcp stm: started \n",
+                               __FUNCTION__));
+                       btcx_inf->bt_state = BT_DHCP_OPPR_WIN;
+                       mod_timer(&btcx_inf->timer,
+                               jiffies + BT_DHCP_OPPR_WIN_TIME*HZ/1000);
+                       btcx_inf->timer_on = 1;
+                       break;
+
+               case BT_DHCP_OPPR_WIN:
+                       if (btcx_inf->dhcp_done) {
+                               WL_TRACE(("%s DHCP Done before T1 expiration\n",
+                                       __FUNCTION__));
+                               goto btc_coex_idle;
+                       }
+
+                       /* DHCP is not over yet, start lowering BT priority
+                        * enforce btc_params + flags if necessary
+                        */
+                       WL_TRACE(("%s DHCP T1:%d expired\n", __FUNCTION__,
+                               BT_DHCP_OPPR_WIN_TIME));
+                       if (btcx_inf->dev)
+                               wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE);
+                       btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT;
+                       mod_timer(&btcx_inf->timer,
+                               jiffies + BT_DHCP_FLAG_FORCE_TIME*HZ/1000);
+                       btcx_inf->timer_on = 1;
+                       break;
+
+               case BT_DHCP_FLAG_FORCE_TIMEOUT:
+                       if (btcx_inf->dhcp_done) {
+                               WL_TRACE(("%s DHCP Done before T2 expiration\n",
+                                       __FUNCTION__));
+                       } else {
+                               /* Noo dhcp during T1+T2, restore BT priority */
+                               WL_TRACE(("%s DHCP wait interval T2:%d"
+                                         "msec expired\n", __FUNCTION__,
+                                         BT_DHCP_FLAG_FORCE_TIME));
+                       }
+
+                       /* Restoring default bt priority */
+                       if (btcx_inf->dev)
+                               wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
+btc_coex_idle:
+                       btcx_inf->bt_state = BT_DHCP_IDLE;
+                       btcx_inf->timer_on = 0;
+                       break;
+
+               default:
+                       WL_ERR(("%s error g_status=%d !!!\n", __FUNCTION__,
+                               btcx_inf->bt_state));
+                       if (btcx_inf->dev)
+                               wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
+                       btcx_inf->bt_state = BT_DHCP_IDLE;
+                       btcx_inf->timer_on = 0;
+                       break;
+       }
+
+       net_os_wake_unlock(btcx_inf->dev);
+}
+
+static int wl_cfg80211_btcoex_init(struct wl_priv *wl)
+{
+       struct btcoex_info *btco_inf = NULL;
+
+       btco_inf = kmalloc(sizeof(struct btcoex_info), GFP_KERNEL);
+       if (!btco_inf)
+               return -ENOMEM;
+
+       btco_inf->bt_state = BT_DHCP_IDLE;
+       btco_inf->ts_dhcp_start = 0;
+       btco_inf->ts_dhcp_ok = 0;
+       /* Set up timer for BT  */
+       btco_inf->timer_ms = 10;
+       init_timer(&btco_inf->timer);
+       btco_inf->timer.data = (ulong)btco_inf;
+       btco_inf->timer.function = wl_cfg80211_bt_timerfunc;
+
+       btco_inf->dev = wl->wdev->netdev;
+
+       INIT_WORK(&btco_inf->work, wl_cfg80211_bt_handler);
+
+       wl->btcoex_info = btco_inf;
+       return 0;
+}
+
+static void
+wl_cfg80211_btcoex_deinit(struct wl_priv *wl)
+{
+       if (!wl->btcoex_info)
+               return;
+
+       if (!wl->btcoex_info->timer_on) {
+               wl->btcoex_info->timer_on = 0;
+               del_timer_sync(&wl->btcoex_info->timer);
+       }
+
+       cancel_work_sync(&wl->btcoex_info->work);
+
+       kfree(wl->btcoex_info);
+       wl->btcoex_info = NULL;
+}
+#endif         /* OEM_ANDROID */
+
+int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command)
+{
+       char powermode_val = 0;
+       char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 };
+       char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 };
+       char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 };
+
+       uint32 regaddr;
+       static uint32 saved_reg66;
+       static uint32 saved_reg41;
+       static uint32 saved_reg68;
+       static bool saved_status = FALSE;
+
+#ifdef COEX_DHCP
+       char buf_flag7_default[8] =   { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
+       struct btcoex_info *btco_inf = wlcfg_drv_priv->btcoex_info;
+#endif /* COEX_DHCP */
+
+       /* Figure out powermode 1 or o command */
+       strncpy((char *)&powermode_val, command + strlen("BTCOEXMODE") +1, 1);
+
+       if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) {
+
+               WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__));
+
+               /* Retrieve and saved orig regs value */
+               if ((saved_status == FALSE) &&
+                       (!dev_wlc_intvar_get_reg(dev, "btc_params", 66,  &saved_reg66)) &&
+                       (!dev_wlc_intvar_get_reg(dev, "btc_params", 41,  &saved_reg41)) &&
+                       (!dev_wlc_intvar_get_reg(dev, "btc_params", 68,  &saved_reg68)))   {
+                               saved_status = TRUE;
+                               WL_INFO(("Saved 0x%x 0x%x 0x%x\n",
+                                       saved_reg66, saved_reg41, saved_reg68));
+
+                               /* Disable PM mode during dhpc session */
+
+                               /* Disable PM mode during dhpc session */
+#ifdef COEX_DHCP
+                               /* Start  BT timer only for SCO connection */
+                               if (btcoex_is_sco_active(dev)) {
+                                       /* btc_params 66 */
+                                       dev_wlc_bufvar_set(dev, "btc_params",
+                                               (char *)&buf_reg66va_dhcp_on[0],
+                                               sizeof(buf_reg66va_dhcp_on));
+                                       /* btc_params 41 0x33 */
+                                       dev_wlc_bufvar_set(dev, "btc_params",
+                                               (char *)&buf_reg41va_dhcp_on[0],
+                                               sizeof(buf_reg41va_dhcp_on));
+                                       /* btc_params 68 0x190 */
+                                       dev_wlc_bufvar_set(dev, "btc_params",
+                                               (char *)&buf_reg68va_dhcp_on[0],
+                                               sizeof(buf_reg68va_dhcp_on));
+                                       saved_status = TRUE;
+
+                                       btco_inf->bt_state = BT_DHCP_START;
+                                       btco_inf->timer_on = 1;
+                                       mod_timer(&btco_inf->timer, btco_inf->timer.expires);
+                                       WL_INFO(("%s enable BT DHCP Timer\n",
+                                       __FUNCTION__));
+                               }
+#endif /* COEX_DHCP */
+               }
+               else if (saved_status == TRUE) {
+                       WL_ERR(("%s was called w/o DHCP OFF. Continue\n", __FUNCTION__));
+               }
+       }
+       else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) {
+
+
+               /* Restoring PM mode */
+
+#ifdef COEX_DHCP
+               /* Stop any bt timer because DHCP session is done */
+               WL_INFO(("%s disable BT DHCP Timer\n", __FUNCTION__));
+               if (btco_inf->timer_on) {
+                       btco_inf->timer_on = 0;
+                       del_timer_sync(&btco_inf->timer);
+
+                       if (btco_inf->bt_state != BT_DHCP_IDLE) {
+                       /* need to restore original btc flags & extra btc params */
+                               WL_INFO(("%s bt->bt_state:%d\n",
+                                       __FUNCTION__, btco_inf->bt_state));
+                               /* wake up btcoex thread to restore btlags+params  */
+                               schedule_work(&btco_inf->work);
+                       }
+               }
+
+               /* Restoring btc_flag paramter anyway */
+               if (saved_status == TRUE)
+                       dev_wlc_bufvar_set(dev, "btc_flags",
+                               (char *)&buf_flag7_default[0], sizeof(buf_flag7_default));
+#endif /* COEX_DHCP */
+
+               /* Restore original values */
+               if (saved_status == TRUE) {
+                       regaddr = 66;
+                       dev_wlc_intvar_set_reg(dev, "btc_params",
+                               (char *)&regaddr, (char *)&saved_reg66);
+                       regaddr = 41;
+                       dev_wlc_intvar_set_reg(dev, "btc_params",
+                               (char *)&regaddr, (char *)&saved_reg41);
+                       regaddr = 68;
+                       dev_wlc_intvar_set_reg(dev, "btc_params",
+                               (char *)&regaddr, (char *)&saved_reg68);
+
+                       WL_INFO(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n",
+                               saved_reg66, saved_reg41, saved_reg68));
+               }
+               saved_status = FALSE;
+
+       }
+       else {
+               WL_ERR(("%s Unkwown yet power setting, ignored\n",
+                       __FUNCTION__));
+       }
+
+       snprintf(command, 3, "OK");
+
+       return (strlen("OK"));
+}
index a563724..4159bd7 100644 (file)
@@ -323,6 +323,27 @@ struct ap_info {
        u8 *wps_ie;
        bool security_mode;
 };
+struct btcoex_info {
+       struct timer_list timer;
+       uint32 timer_ms;
+       uint32 timer_on;
+       uint32 ts_dhcp_start;   /* ms ts ecord time stats */
+       uint32 ts_dhcp_ok;      /* ms ts ecord time stats */
+       bool dhcp_done;         /* flag, indicates that host done with
+                                * dhcp before t1/t2 expiration
+                                */
+       int bt_state;
+       struct work_struct work;
+       struct net_device *dev;
+};
+
+struct sta_info {
+       /* Structure to hold WPS IE for a STA */
+       u8  probe_req_ie[IE_MAX_LEN];
+       u8  assoc_req_ie[IE_MAX_LEN];
+       u32 probe_req_ie_len;
+       u32 assoc_req_ie_len;
+};
 /* dongle private data of cfg80211 interface */
 struct wl_priv {
        struct wireless_dev *wdev;      /* representing wl cfg80211 device */
@@ -343,8 +364,6 @@ struct wl_priv {
        struct wl_cfg80211_bss_info *bss_info;
        /* information element object for internal purpose */
        struct wl_ie ie;
-       u8 scan_ie_buf[2048];
-       int scan_ie_len;
        struct ether_addr bssid;        /* bssid of currently engaged network */
 
        /* for synchronization of main event thread */
@@ -357,7 +376,7 @@ struct wl_priv {
        /* control firwmare and nvram paramter downloading */
        struct wl_fw_ctrl *fw;
        struct wl_pmk_list *pmk_list;   /* wpa2 pmk list */
-       tsk_ctl_t event_tsk;            /* task of main event handler thread */
+       tsk_ctl_t event_tsk;            /* task of main event handler thread */
        unsigned long status;           /* current dongle status */
        void *pub;
        u32 channel;            /* current channel */
@@ -385,9 +404,10 @@ struct wl_priv {
        u64 cache_cookie;
        wait_queue_head_t dongle_event_wait;
        struct ap_info *ap_info;
+       struct sta_info *sta_info;
        struct p2p_info *p2p;
        bool p2p_supported;
-       s8 last_eventmask[WL_EVENTING_MASK_LEN];
+       struct btcoex_info *btcoex_info;
 };
 
 #define wl_to_wiphy(w) (w->wdev->wiphy)
@@ -507,6 +527,7 @@ extern void wl_cfg80211_release_fw(void);
 extern s8 *wl_cfg80211_get_fwname(void);
 extern s8 *wl_cfg80211_get_nvramname(void);
 extern s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr);
+extern int wl_cfg80211_hang(struct net_device *dev, u16 reason);
 #ifdef CONFIG_SYSCTL
 extern s32 wl_cfg80211_sysctl_export_devaddr(void *data);
 #endif
index a5ad9e0..2487a67 100644 (file)
@@ -627,16 +627,14 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss
        s32 ret = BCME_OK;
        u32 pos;
        u8  *ie_buf;
-       u8  *mgmt_ie_buf;
-       u32 mgmt_ie_buf_len;
-       u32 *mgmt_ie_len;
+       u8  *mgmt_ie_buf = NULL;
+       u32 mgmt_ie_buf_len = 0;
+       u32 *mgmt_ie_len = 0;
        u8 ie_id, ie_len;
        u8 delete = 0;
 #define IE_TYPE(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie)
 #define IE_TYPE_LEN(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie_len)
-       if (bssidx == -1)
-               return BCME_BADARG;
-       if (wl->p2p_supported && p2p_on(wl)) {
+       if (wl->p2p_supported && p2p_on(wl) && bssidx != -1) {
                if (bssidx == P2PAPI_BSSCFG_PRIMARY)
                        bssidx =  wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE);
                switch (pktflag) {
@@ -671,7 +669,7 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss
                                CFGP2P_ERR(("not suitable type\n"));
                                return -1;
                }
-       } else {
+       } else if (get_mode_by_netdev(wl, ndev) == WL_MODE_AP) {
                switch (pktflag) {
                        case VNDR_IE_PRBRSP_FLAG :
                                mgmt_ie_buf = wl->ap_info->probe_res_ie;
@@ -689,37 +687,63 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss
                                CFGP2P_ERR(("not suitable type\n"));
                                return -1;
                }
+               bssidx = 0;
+       } else if (bssidx == -1 && get_mode_by_netdev(wl, ndev) == WL_MODE_BSS) {
+               switch (pktflag) {
+                       case VNDR_IE_PRBREQ_FLAG :
+                               mgmt_ie_buf = wl->sta_info->probe_req_ie;
+                               mgmt_ie_len = &wl->sta_info->probe_req_ie_len;
+                               mgmt_ie_buf_len = sizeof(wl->sta_info->probe_req_ie);
+                               break;
+                       case VNDR_IE_ASSOCREQ_FLAG :
+                               mgmt_ie_buf = wl->sta_info->assoc_req_ie;
+                               mgmt_ie_len = &wl->sta_info->assoc_req_ie_len;
+                               mgmt_ie_buf_len = sizeof(wl->sta_info->assoc_req_ie);
+                               break;
+                       default:
+                               mgmt_ie_buf = NULL;
+                               mgmt_ie_len = NULL;
+                               CFGP2P_ERR(("not suitable type\n"));
+                               return -1;
+               }
+               bssidx = 0;
+       } else {
+               CFGP2P_ERR(("not suitable type\n"));
+               return -1;
        }
-       /* Add if there is any extra IE */
-       if (vndr_ie && vndr_ie_len) {
-               CFGP2P_INFO(("Request has extra IE"));
-               if (vndr_ie_len > mgmt_ie_buf_len) {
-                       CFGP2P_ERR(("extra IE size too big\n"));
-                       ret = -ENOMEM;
-               } else {
-                       if (mgmt_ie_buf != NULL) {
-                               if ((vndr_ie_len == *mgmt_ie_len) &&
-                                    (memcmp(mgmt_ie_buf, vndr_ie, vndr_ie_len) == 0)) {
-                                       CFGP2P_INFO(("Previous mgmt IE is equals to current IE"));
-                                       goto exit;
-                               }
-                               pos = 0;
-                               delete = 1;
-                               ie_buf = (u8 *) mgmt_ie_buf;
-                               while (pos < *mgmt_ie_len) {
-                                       ie_id = ie_buf[pos++];
-                                       ie_len = ie_buf[pos++];
-                                       CFGP2P_INFO(("DELELED ID(%d), Len(%d),"
-                                               "OUI(%02x:%02x:%02x)\n",
-                                               ie_id, ie_len, ie_buf[pos],
+
+       if (vndr_ie_len > mgmt_ie_buf_len) {
+               CFGP2P_ERR(("extra IE size too big\n"));
+               ret = -ENOMEM;
+       } else {
+               if (mgmt_ie_buf != NULL) {
+                       if (vndr_ie_len && (vndr_ie_len == *mgmt_ie_len) &&
+                            (memcmp(mgmt_ie_buf, vndr_ie, vndr_ie_len) == 0)) {
+                               CFGP2P_INFO(("Previous mgmt IE is equals to current IE"));
+                               goto exit;
+                       }
+                       pos = 0;
+                       delete = 1;
+                       ie_buf = (u8 *) mgmt_ie_buf;
+                       while (pos < *mgmt_ie_len) {
+                               ie_id = ie_buf[pos++];
+                               ie_len = ie_buf[pos++];
+                               if ((ie_id == DOT11_MNG_VS_ID) &&
+                                  (wl_cfgp2p_is_wps_ie(&ie_buf[pos-2], NULL, 0) ||
+                                       wl_cfgp2p_is_p2p_ie(&ie_buf[pos-2], NULL, 0))) {
+                                       CFGP2P_INFO(("DELELED ID : %d, Len : %d , OUI :"
+                                               "%02x:%02x:%02x\n", ie_id, ie_len, ie_buf[pos],
                                                ie_buf[pos+1], ie_buf[pos+2]));
-                                       ret = wl_cfgp2p_vndr_ie(ndev, bssidx, pktflag,
-                                           ie_buf+pos, VNDR_SPEC_ELEMENT_ID,
-                                               ie_buf+pos+3, ie_len-3, delete);
-                                       pos += ie_len;
+                                       ret = wl_cfgp2p_vndr_ie(ndev, bssidx, pktflag, ie_buf+pos,
+                                           VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3, ie_len-3, delete);
                                }
-
+                               pos += ie_len;
                        }
+
+               }
+               *mgmt_ie_len = 0;
+               /* Add if there is any extra IE */
+               if (vndr_ie && vndr_ie_len) {
                        /* save the current IE in wl struct */
                        memcpy(mgmt_ie_buf, vndr_ie, vndr_ie_len);
                        *mgmt_ie_len = vndr_ie_len;
@@ -741,7 +765,6 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss
                                pos += ie_len;
                        }
                }
-
        }
 #undef IE_TYPE
 #undef IE_TYPE_LEN
index 9b8184a..ef77cdc 100644 (file)
@@ -1266,6 +1266,7 @@ wl_iw_set_dtim_skip(
                                &iovbuf, sizeof(iovbuf))) >= 0) {
                                p += snprintf(p, MAX_WX_STRING, "OK");
 
+                               
                                net_os_set_dtim_skip(dev, bcn_li_dtim);
 
                                WL_TRACE(("%s: set dtim_skip %d OK\n", __FUNCTION__,
@@ -1737,6 +1738,7 @@ wl_iw_control_wl_off(
                sdioh_stop(NULL);
 #endif
 
+               
                net_os_set_dtim_skip(dev, 0);
 
                dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
@@ -2415,7 +2417,7 @@ wl_iw_get_range(
        list = (wl_uint32_list_t *)channels;
 
        dwrq->length = sizeof(struct iw_range);
-       memset(range, 0, sizeof(range));
+       memset(range, 0, sizeof(*range));
 
        
        range->min_nwid = range->max_nwid = 0;
@@ -4472,7 +4474,7 @@ wl_iw_set_essid(
        g_ssid.SSID_len = htod32(g_ssid.SSID_len);
 
        
-       memset(join_params, 0, sizeof(join_params));
+       memset(join_params, 0, sizeof(*join_params));
        join_params_size = sizeof(join_params->ssid);
 
        memcpy(join_params->ssid.SSID, g_ssid.SSID, g_ssid.SSID_len);
@@ -6297,6 +6299,8 @@ wl_iw_add_wps_probe_req_ie(
                str_ptr += WPS_PROBE_REQ_IE_CMD_LENGTH;
                datalen = wrqu->data.length - WPS_PROBE_REQ_IE_CMD_LENGTH;
 
+               
+               
                buflen = sizeof(vndr_ie_setbuf_t) + datalen - sizeof(vndr_ie_t);
                ie_setbuf = (vndr_ie_setbuf_t *)kmalloc(buflen, GFP_KERNEL);
                if (!ie_setbuf) {
@@ -6306,16 +6310,21 @@ wl_iw_add_wps_probe_req_ie(
 
                memset(ie_setbuf, 0x00, buflen);
 
+               
                strncpy(ie_setbuf->cmd, "add", VNDR_IE_CMD_LEN - 1);
                ie_setbuf->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
 
+               
                iecount = htod32(1);
                memcpy((void *)&ie_setbuf->vndr_ie_buffer.iecount, &iecount, sizeof(int));
 
+               
                pktflag = 0x10;
-               memcpy((void *)&ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag, sizeof(uint32));
+               memcpy((void *)&ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].pktflag,
+                       &pktflag, sizeof(uint32));
 
-               memcpy((void *)&ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data, str_ptr, datalen);
+               memcpy((void *)&ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data,
+                       str_ptr, datalen);
 
                total_len = strlen("vndr_ie ") + buflen;
                bufptr = (char *)kmalloc(total_len, GFP_KERNEL);
@@ -7528,11 +7537,15 @@ wl_iw_set_priv(
                        ret = wl_iw_set_cscan(dev, info, (union iwreq_data *)dwrq, extra);
 #endif 
 #ifdef CONFIG_WPS2
-               else if (strnicmp(extra, WPS_ADD_PROBE_REQ_IE_CMD, strlen(WPS_ADD_PROBE_REQ_IE_CMD)) == 0)
-                       ret = wl_iw_add_wps_probe_req_ie(dev, info, (union iwreq_data *)dwrq, extra);
-               else if (strnicmp(extra, WPS_DEL_PROBE_REQ_IE_CMD, strlen(WPS_DEL_PROBE_REQ_IE_CMD)) == 0)
-                       ret = wl_iw_del_wps_probe_req_ie(dev, info, (union iwreq_data *)dwrq, extra);
-#endif
+               else if (strnicmp(extra, WPS_ADD_PROBE_REQ_IE_CMD,
+                       strlen(WPS_ADD_PROBE_REQ_IE_CMD)) == 0)
+                       ret = wl_iw_add_wps_probe_req_ie(dev, info,
+                               (union iwreq_data *)dwrq, extra);
+               else if (strnicmp(extra, WPS_DEL_PROBE_REQ_IE_CMD,
+                       strlen(WPS_DEL_PROBE_REQ_IE_CMD)) == 0)
+                       ret = wl_iw_del_wps_probe_req_ie(dev, info,
+                               (union iwreq_data *)dwrq, extra);
+#endif 
                else if (strnicmp(extra, "POWERMODE", strlen("POWERMODE")) == 0)
                        ret = wl_iw_set_power_mode(dev, info, (union iwreq_data *)dwrq, extra);
                else if (strnicmp(extra, "BTCOEXMODE", strlen("BTCOEXMODE")) == 0)
@@ -7761,8 +7774,8 @@ static const struct iw_priv_args wl_iw_priv_args[] =
 
        {
                WL_AP_STA_LIST,
-               0,                     
-               IW_PRIV_TYPE_CHAR | 0, 
+               IW_PRIV_TYPE_CHAR | 0,  
+               IW_PRIV_TYPE_CHAR | 1024,  
                "AP_GET_STA_LIST"
        },