summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
authorManikanta <mmaddireddy@nvidia.com>2014-02-28 15:42:47 +0530
committerVenu Byravarasu <vbyravarasu@nvidia.com>2014-04-07 22:15:31 -0700
commit6204a40b26e05d40adf4c82c7fd0e4053b9a1672 (patch)
treea9c2f3924275cbeef187cd74050de6c20f071f92 /drivers/net
parent8e9e49fa9a96116f44a86cdba2e084d09827641a (diff)
net: wireless: bcmdhd: add nvidia specific changes
- Wifi mitigation strategy changes - Modify "disable_proptx" flag when proptx is set - NULL check for wl_cfgp2p_generate_bss_mac - Disable block ack for UP7 - Key installation timing fix - Fix division by zero - Add flag to enable MCC - Set dpc rt thread priority to max - Add edp changes for wifi in driver - Power off card when not in use Bug 1473913 Change-Id: I3572adf2fe368d19f1c35fff715b31dbedfa300d Signed-off-by: Manikanta <mmaddireddy@nvidia.com> Reviewed-on: http://git-master/r/375971 Reviewed-by: Nagarjuna Kristam <nkristam@nvidia.com> Tested-by: Nagarjuna Kristam <nkristam@nvidia.com> Reviewed-by: Narayan Reddy <narayanr@nvidia.com> GVS: Gerrit_Virtual_Submit Reviewed-by: Venu Byravarasu <vbyravarasu@nvidia.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/bcm43241/Makefile2
-rwxr-xr-xdrivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c4
-rwxr-xr-xdrivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c5
-rwxr-xr-xdrivers/net/wireless/bcmdhd/dhd_common.c2
-rwxr-xr-xdrivers/net/wireless/bcmdhd/dhd_linux.c25
-rwxr-xr-xdrivers/net/wireless/bcmdhd/dhd_linux_platdev.c14
-rwxr-xr-xdrivers/net/wireless/bcmdhd/dhd_qmon.c4
-rwxr-xr-xdrivers/net/wireless/bcmdhd/include/wlioctl.h16
-rwxr-xr-xdrivers/net/wireless/bcmdhd/wl_android.c12
-rwxr-xr-xdrivers/net/wireless/bcmdhd/wl_cfg80211.c9
-rwxr-xr-xdrivers/net/wireless/bcmdhd/wl_cfgp2p.c6
-rwxr-xr-xdrivers/net/wireless/bcmdhd/wldev_common.c344
-rwxr-xr-xdrivers/net/wireless/bcmdhd/wldev_common.h6
13 files changed, 444 insertions, 5 deletions
diff --git a/drivers/net/wireless/bcm43241/Makefile b/drivers/net/wireless/bcm43241/Makefile
index e2cfab69c774..8f2af0f960e4 100644
--- a/drivers/net/wireless/bcm43241/Makefile
+++ b/drivers/net/wireless/bcm43241/Makefile
@@ -129,6 +129,8 @@ ifneq ($(CONFIG_BCM43241),)
DHDCFLAGS += -DCUSTOM_GLOM_SETTING=1 -DCUSTOM_SDIO_F2_BLKSIZE=128
DHDCFLAGS += -DAMPDU_HOSTREORDER
DHDCFLAGS += -DPROP_TXSTATUS_VSDB
+ DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=32
+ DHDCFLAGS += -DCUSTOM_DPC_PRIO_SETTING=99
ifeq ($(CONFIG_BCM43241),m)
DHDCFLAGS += -fno-pic
endif
diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
index 181cf47a22a0..390ad0b92357 100755
--- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
+++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
@@ -1331,7 +1331,7 @@ sdioh_start(sdioh_info_t *sd, int stage)
2.6.27. The implementation prior to that is buggy, and needs broadcom's
patch for it
*/
- if ((ret = sdio_reset_comm(sd->func[0]->card))) {
+ if ((ret = mmc_power_restore_host(sd->func[0]->card->host))) {
sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret));
return ret;
}
@@ -1418,6 +1418,8 @@ sdioh_stop(sdioh_info_t *sd)
#endif
bcmsdh_oob_intr_set(sd->bcmsdh, FALSE);
#endif /* !defined(OOB_INTR_ONLY) */
+ if (mmc_power_save_host((sd->func[0])->card->host))
+ sd_err(("%s card power save fail\n", __FUNCTION__));
}
else
sd_err(("%s Failed\n", __FUNCTION__));
diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c
index ff988f0f3485..a5b667460e7d 100755
--- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c
+++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c
@@ -176,8 +176,11 @@ static int bcmsdh_sdmmc_probe(struct sdio_func *func,
sd_info(("Function#: 0x%04x\n", func->num));
/* 4318 doesn't have function 2 */
- if ((func->num == 2) || (func->num == 1 && func->device == 0x4))
+ if ((func->num == 2) || (func->num == 1 && func->device == 0x4)) {
ret = sdioh_probe(func);
+ if (mmc_power_save_host(func->card->host))
+ sd_err(("%s: card power save fail", __FUNCTION__));
+ }
return ret;
}
diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c
index dcc20e3f0480..21ce01d23667 100755
--- a/drivers/net/wireless/bcmdhd/dhd_common.c
+++ b/drivers/net/wireless/bcmdhd/dhd_common.c
@@ -83,6 +83,7 @@ uint32 dhd_conn_event;
uint32 dhd_conn_status;
uint32 dhd_conn_reason;
+extern int disable_proptx;
extern int dhd_iscan_request(void * dhdp, uint16 action);
extern void dhd_ind_scan_confirm(void *h, bool status);
extern int dhd_iscan_in_progress(void *h);
@@ -432,6 +433,7 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch
if (bcmerror != BCME_OK)
goto exit;
+ disable_proptx = int_val ? FALSE : TRUE;
/* wlfc is already set as desired */
if (wlfc_enab == (int_val == 0 ? FALSE : TRUE))
goto exit;
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c
index 4f8dde7453c8..1533ec9780bb 100755
--- a/drivers/net/wireless/bcmdhd/dhd_linux.c
+++ b/drivers/net/wireless/bcmdhd/dhd_linux.c
@@ -4006,6 +4006,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
struct ether_addr ea_addr;
#endif /* GET_CUSTOM_MAC_ENABLE */
+#ifdef CUSTOM_AMPDU_BA_WSIZE
+ struct ampdu_tid_control atc;
+#endif
#ifdef DISABLE_11N
uint32 nmode = 0;
#endif /* DISABLE_11N */
@@ -4316,6 +4319,12 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
__FUNCTION__, ampdu_ba_wsize, ret));
}
}
+
+ atc.tid = 7;
+ atc.enable = 0;
+ bcm_mkiovar("ampdu_rx_tid", (char *)&atc, sizeof(atc), iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+
#endif
#if defined(CUSTOM_AMPDU_MPDU)
ampdu_mpdu = CUSTOM_AMPDU_MPDU;
@@ -4524,6 +4533,22 @@ done:
return ret;
}
+void dhd_set_ampdu_rx_tid(struct net_device *dev, int ampdu_rx_tid)
+{
+ int i, ret = 0;
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
+ dhd_pub_t *pub = &dhd->pub;
+ char iovbuf[32];
+ for (i = 0; i < 8; i++) { /* One bit each for traffic class CS7 - CS0 */
+ struct ampdu_tid_control atc;
+ atc.tid = i;
+ atc.enable = (ampdu_rx_tid >> i) & 1;
+ bcm_mkiovar("ampdu_rx_tid", (char *)&atc, sizeof(atc), iovbuf,sizeof(iovbuf));
+ ret = dhd_wl_ioctl_cmd(pub, WLC_SET_VAR, iovbuf, sizeof(iovbuf),TRUE, 0);
+ if (ret < 0)
+ DHD_ERROR(("%s failed %d\n", __func__, ret));
+ }
+}
int
dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, int set)
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux_platdev.c b/drivers/net/wireless/bcmdhd/dhd_linux_platdev.c
index d49bc61e2ac5..f6115e53b605 100755
--- a/drivers/net/wireless/bcmdhd/dhd_linux_platdev.c
+++ b/drivers/net/wireless/bcmdhd/dhd_linux_platdev.c
@@ -163,7 +163,13 @@ int wifi_platform_set_power(wifi_adapter_info_t *adapter, bool on, unsigned long
}
#endif /* ENABLE_4335BT_WAR */
+ if (on)
+ sysedp_set_state(plat_data->sysedpc, on);
+
err = plat_data->set_power(on);
+
+ if (!on)
+ sysedp_set_state(plat_data->sysedpc, on);
}
if (msec && !err)
@@ -231,6 +237,8 @@ static int wifi_plat_dev_drv_probe(struct platform_device *pdev)
{
struct resource *resource;
wifi_adapter_info_t *adapter;
+ struct wifi_platform_data *wifi_ctrl =
+ (struct wifi_platform_data *)(pdev->dev.platform_data);
/* Android style wifi platform data device ("bcmdhd_wlan" or "bcm4329_wlan")
* is kept for backward compatibility and supports only 1 adapter
@@ -248,6 +256,7 @@ static int wifi_plat_dev_drv_probe(struct platform_device *pdev)
adapter->intr_flags = resource->flags & IRQF_TRIGGER_MASK;
}
+ wifi_ctrl->sysedpc = sysedp_create_consumer("wifi", "wifi");
wifi_plat_dev_probe_ret = dhd_wifi_platform_load();
return wifi_plat_dev_probe_ret;
}
@@ -255,6 +264,8 @@ static int wifi_plat_dev_drv_probe(struct platform_device *pdev)
static int wifi_plat_dev_drv_remove(struct platform_device *pdev)
{
wifi_adapter_info_t *adapter;
+ struct wifi_platform_data *wifi_ctrl =
+ (struct wifi_platform_data *)(pdev->dev.platform_data);
/* Android style wifi platform data device ("bcmdhd_wlan" or "bcm4329_wlan")
* is kept for backward compatibility and supports only 1 adapter
@@ -267,6 +278,9 @@ static int wifi_plat_dev_drv_remove(struct platform_device *pdev)
wifi_platform_bus_enumerate(adapter, FALSE);
}
+ sysedp_free_consumer(wifi_ctrl->sysedpc);
+ wifi_ctrl->sysedpc = 0;
+
return 0;
}
diff --git a/drivers/net/wireless/bcmdhd/dhd_qmon.c b/drivers/net/wireless/bcmdhd/dhd_qmon.c
index dc2534a093d2..b93cecd2ef4f 100755
--- a/drivers/net/wireless/bcmdhd/dhd_qmon.c
+++ b/drivers/net/wireless/bcmdhd/dhd_qmon.c
@@ -156,9 +156,11 @@ dhd_qmon_getpercent(dhd_pub_t *dhdp)
if (queued_time_last)
time_cumul_adjust = now - queued_time_last;
- percent = (uint32)((time_cumul_adjust + queued_time_cumul
+ if ((now - qmon->queued_time_last_io) > 0) {
+ percent = (uint32)((time_cumul_adjust + queued_time_cumul
- qmon->queued_time_cumul_last) * 100) /
(uint32)(now - qmon->queued_time_last_io);
+ }
qmon->queued_time_cumul_last = queued_time_cumul + time_cumul_adjust;
qmon->queued_time_last_io = now;
diff --git a/drivers/net/wireless/bcmdhd/include/wlioctl.h b/drivers/net/wireless/bcmdhd/include/wlioctl.h
index b3785cad9eb8..3fa105845cdc 100755
--- a/drivers/net/wireless/bcmdhd/include/wlioctl.h
+++ b/drivers/net/wireless/bcmdhd/include/wlioctl.h
@@ -2070,6 +2070,22 @@ typedef struct {
} wl_delta_stats_t;
+/* structure to store per-rate rx statistics */
+typedef struct wl_scb_rx_rate_stats {
+ uint32 rx1mbps[2]; /* packets rx at 1Mbps */
+ uint32 rx2mbps[2]; /* packets rx at 2Mbps */
+ uint32 rx5mbps5[2]; /* packets rx at 5.5Mbps */
+ uint32 rx6mbps[2]; /* packets rx at 6Mbps */
+ uint32 rx9mbps[2]; /* packets rx at 9Mbps */
+ uint32 rx11mbps[2]; /* packets rx at 11Mbps */
+ uint32 rx12mbps[2]; /* packets rx at 12Mbps */
+ uint32 rx18mbps[2]; /* packets rx at 18Mbps */
+ uint32 rx24mbps[2]; /* packets rx at 24Mbps */
+ uint32 rx36mbps[2]; /* packets rx at 36Mbps */
+ uint32 rx48mbps[2]; /* packets rx at 48Mbps */
+ uint32 rx54mbps[2]; /* packets rx at 54Mbps */
+} wl_scb_rx_rate_stats_t;
+
typedef struct {
uint32 packets;
uint32 bytes;
diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c
index a94e6ef13622..21610bb7e14e 100755
--- a/drivers/net/wireless/bcmdhd/wl_android.c
+++ b/drivers/net/wireless/bcmdhd/wl_android.c
@@ -90,6 +90,10 @@
#define CMD_KEEP_ALIVE "KEEPALIVE"
+#define CMD_SETMIRACAST "SETMIRACAST"
+#define CMD_ASSOCRESPIE "ASSOCRESPIE"
+#define CMD_MAXLINKSPEED "MAXLINKSPEED"
+#define CMD_RXRATESTATS "RXRATESTATS"
/* CCX Private Commands */
@@ -1499,6 +1503,14 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
int skip = strlen(CMD_KEEP_ALIVE) + 1;
bytes_written = wl_keep_alive_set(net, command + skip, priv_cmd.total_len - skip);
}
+ else if (strnicmp(command, CMD_SETMIRACAST, strlen(CMD_SETMIRACAST)) == 0)
+ bytes_written = wldev_miracast_tuning(net, command, priv_cmd.total_len);
+ else if (strnicmp(command, CMD_ASSOCRESPIE, strlen(CMD_ASSOCRESPIE)) == 0)
+ bytes_written = wldev_get_assoc_resp_ie(net, command, priv_cmd.total_len);
+ else if (strnicmp(command, CMD_MAXLINKSPEED, strlen(CMD_MAXLINKSPEED))== 0)
+ bytes_written = wldev_get_max_linkspeed(net, command, priv_cmd.total_len);
+ else if (strnicmp(command, CMD_RXRATESTATS, strlen(CMD_RXRATESTATS)) == 0)
+ bytes_written = wldev_get_rx_rate_stats(net, command, priv_cmd.total_len);
else if (strnicmp(command, CMD_ROAM_OFFLOAD, strlen(CMD_ROAM_OFFLOAD)) == 0) {
int enable = *(command + strlen(CMD_ROAM_OFFLOAD) + 1) - '0';
bytes_written = wl_cfg80211_enable_roam_offload(net, enable);
diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
index 786e53c63a96..20eb61d1d47f 100755
--- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c
+++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
@@ -200,7 +200,11 @@ static const struct ieee80211_iface_limit common_if_limits[] = {
static const struct ieee80211_iface_combination
common_iface_combinations[] = {
{
- .num_different_channels = NUM_DIFF_CHANNELS,
+#ifdef DHD_ENABLE_MCC
+ .num_different_channels = 2,
+#else
+ .num_different_channels = 1,
+#endif
.max_interfaces = 4,
.limits = common_if_limits,
.n_limits = ARRAY_SIZE(common_if_limits),
@@ -3707,7 +3711,8 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
}
swap_key_from_BE(&key);
/* need to guarantee EAPOL 4/4 send out before set key */
- dhd_wait_pend8021x(dev);
+ if (mode != WL_MODE_AP)
+ dhd_wait_pend8021x(dev);
err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
if (unlikely(err)) {
diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
index d4eb1ba0d4bd..992d606b2bd2 100755
--- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
+++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
@@ -1857,6 +1857,12 @@ void
wl_cfgp2p_generate_bss_mac(struct ether_addr *primary_addr,
struct ether_addr *out_dev_addr, struct ether_addr *out_int_addr)
{
+
+ if ((out_dev_addr == NULL) || (out_int_addr == NULL)) {
+ WL_ERR(("Invalid input data\n"));
+ return;
+ }
+
memset(out_dev_addr, 0, sizeof(*out_dev_addr));
memset(out_int_addr, 0, sizeof(*out_int_addr));
diff --git a/drivers/net/wireless/bcmdhd/wldev_common.c b/drivers/net/wireless/bcmdhd/wldev_common.c
index 2d4831b49dd7..6eda0961f022 100755
--- a/drivers/net/wireless/bcmdhd/wldev_common.c
+++ b/drivers/net/wireless/bcmdhd/wldev_common.c
@@ -383,3 +383,347 @@ int wldev_set_country(
}
return 0;
}
+
+/* tuning performance for miracast */
+int wldev_miracast_tuning(
+ struct net_device *dev, char *command, int total_len)
+{
+ int error = 0;
+ int mode = 0;
+ int ampdu_mpdu;
+ int roam_off;
+ int ampdu_rx_tid = -1;
+#ifdef VSDB_BW_ALLOCATE_ENABLE
+ int mchan_algo;
+ int mchan_bw;
+#endif /* VSDB_BW_ALLOCATE_ENABLE */
+
+ if (sscanf(command, "%*s %d", &mode) != 1) {
+ WLDEV_ERROR(("Failed to get mode\n"));
+ return -1;
+ }
+
+set_mode:
+
+ WLDEV_ERROR(("mode: %d\n", mode));
+
+ if (mode == 0) {
+ /* Normal mode: restore everything to default */
+ ampdu_mpdu = -1; /* FW default */
+#if defined(ROAM_ENABLE)
+ roam_off = 0; /* roam enable */
+#elif defined(DISABLE_BUILTIN_ROAM)
+ roam_off = 1; /* roam disable */
+#endif
+#ifdef VSDB_BW_ALLOCATE_ENABLE
+ mchan_algo = 0; /* Default */
+ mchan_bw = 50; /* 50:50 */
+#endif /* VSDB_BW_ALLOCATE_ENABLE */
+ }
+ else if (mode == 1) {
+ /* Miracast source mode */
+ ampdu_mpdu = 8; /* for tx latency */
+#if defined(ROAM_ENABLE) || defined(DISABLE_BUILTIN_ROAM)
+ roam_off = 1; /* roam disable */
+#endif
+#ifdef VSDB_BW_ALLOCATE_ENABLE
+ mchan_algo = 1; /* BW based */
+ mchan_bw = 25; /* 25:75 */
+#endif /* VSDB_BW_ALLOCATE_ENABLE */
+ }
+ else if (mode == 2) {
+ /* Miracast sink/PC Gaming mode */
+ ampdu_mpdu = 8; /* FW default */
+#if defined(ROAM_ENABLE) || defined(DISABLE_BUILTIN_ROAM)
+ roam_off = 1; /* roam disable */
+#endif
+#ifdef VSDB_BW_ALLOCATE_ENABLE
+ mchan_algo = 0; /* Default */
+ mchan_bw = 50; /* 50:50 */
+#endif /* VSDB_BW_ALLOCATE_ENABLE */
+ } else if (mode == 3) {
+ ampdu_rx_tid = 0;
+ mode = 2;
+ goto set_mode;
+ } else if (mode == 4) {
+ ampdu_rx_tid = 0x7f;
+ mode = 0;
+ goto set_mode;
+ }
+ else {
+ WLDEV_ERROR(("Unknown mode: %d\n", mode));
+ return -1;
+ }
+
+ /* Update ampdu_mpdu */
+ error = wldev_iovar_setint(dev, "ampdu_mpdu", ampdu_mpdu);
+ if (error) {
+ WLDEV_ERROR(("Failed to set ampdu_mpdu: mode:%d, error:%d\n",
+ mode, error));
+ return -1;
+ }
+
+#if defined(ROAM_ENABLE) || defined(DISABLE_BUILTIN_ROAM)
+ error = wldev_iovar_setint(dev, "roam_off", roam_off);
+ if (error) {
+ WLDEV_ERROR(("Failed to set roam_off: mode:%d, error:%d\n",
+ mode, error));
+ return -1;
+ }
+#endif /* ROAM_ENABLE || DISABLE_BUILTIN_ROAM */
+
+#ifdef VSDB_BW_ALLOCATE_ENABLE
+ error = wldev_iovar_setint(dev, "mchan_algo", mchan_algo);
+ if (error) {
+ WLDEV_ERROR(("Failed to set mchan_algo: mode:%d, error:%d\n",
+ mode, error));
+ return -1;
+ }
+
+ error = wldev_iovar_setint(dev, "mchan_bw", mchan_bw);
+ if (error) {
+ WLDEV_ERROR(("Failed to set mchan_bw: mode:%d, error:%d\n",
+ mode, error));
+ return -1;
+ }
+#endif /* VSDB_BW_ALLOCATE_ENABLE */
+
+ if (ampdu_rx_tid != -1)
+ dhd_set_ampdu_rx_tid(dev, ampdu_rx_tid);
+
+ return error;
+}
+
+int wldev_get_assoc_resp_ie(
+ struct net_device *dev, char *command, int total_len)
+{
+ wl_assoc_info_t *assoc_info;
+ char smbuf[WLC_IOCTL_SMLEN];
+ char bssid[6], null_bssid[6];
+ int resp_ies_len = 0;
+ int bytes_written = 0;
+ int error, i;
+
+ bzero(bssid, 6);
+ bzero(null_bssid, 6);
+
+ /* Check Association */
+ error = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), 0);
+ if (error == BCME_NOTASSOCIATED) {
+ /* Not associated */
+ bytes_written += snprintf(&command[bytes_written], total_len, "NA");
+ goto done;
+ }
+ else if (error < 0) {
+ WLDEV_ERROR(("WLC_GET_BSSID failed = %d\n", error));
+ return -1;
+ }
+ else if (memcmp(bssid, null_bssid, ETHER_ADDR_LEN) == 0) {
+ /* Zero BSSID: Not associated */
+ bytes_written += snprintf(&command[bytes_written], total_len, "NA");
+ goto done;
+ }
+
+ /* Get assoc_info */
+ bzero(smbuf, sizeof(smbuf));
+ error = wldev_iovar_getbuf(dev, "assoc_info", NULL, 0, smbuf, sizeof(smbuf), NULL);
+ if (error < 0) {
+ WLDEV_ERROR(("get assoc_info failed = %d\n", error));
+ return -1;
+ }
+
+ assoc_info = (wl_assoc_info_t *)smbuf;
+ resp_ies_len = dtoh32(assoc_info->resp_len) - sizeof(struct dot11_assoc_resp);
+
+ /* Retrieve assoc resp IEs */
+ if (resp_ies_len) {
+ error = wldev_iovar_getbuf(dev, "assoc_resp_ies",
+ NULL, 0, smbuf, sizeof(smbuf), NULL);
+ if (error < 0) {
+ WLDEV_ERROR(("get assoc_resp_ies failed = %d\n", error));
+ return -1;
+ }
+
+ /* Length */
+ bytes_written += snprintf(&command[bytes_written], total_len, "%d,", resp_ies_len);
+
+ /* IEs */
+ if ((total_len - bytes_written) > resp_ies_len) {
+ for (i = 0; i < resp_ies_len; i++) {
+ bytes_written += sprintf(&command[bytes_written], "%02x", smbuf[i]);
+ }
+ } else {
+ WLDEV_ERROR(("Not enough buffer\n"));
+ return -1;
+ }
+ } else {
+ WLDEV_ERROR(("Zero Length assoc resp ies = %d\n", resp_ies_len));
+ return -1;
+ }
+
+done:
+
+ return bytes_written;
+}
+
+int wldev_get_max_linkspeed(
+ struct net_device *dev, char *command, int total_len)
+{
+ wl_assoc_info_t *assoc_info;
+ char smbuf[WLC_IOCTL_SMLEN];
+ char bssid[6], null_bssid[6];
+ int resp_ies_len = 0;
+ int bytes_written = 0;
+ int error, i;
+
+ bzero(bssid, 6);
+ bzero(null_bssid, 6);
+
+ /* Check Association */
+ error = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), 0);
+ if (error == BCME_NOTASSOCIATED) {
+ /* Not associated */
+ bytes_written += snprintf(&command[bytes_written],
+ total_len, "-1");
+ goto done;
+ } else if (error < 0) {
+ WLDEV_ERROR(("WLC_GET_BSSID failed = %d\n", error));
+ return -1;
+ } else if (memcmp(bssid, null_bssid, ETHER_ADDR_LEN) == 0) {
+ /* Zero BSSID: Not associated */
+ bytes_written += snprintf(&command[bytes_written],
+ total_len, "-1");
+ goto done;
+ }
+ /* Get assoc_info */
+ bzero(smbuf, sizeof(smbuf));
+ error = wldev_iovar_getbuf(dev, "assoc_info", NULL, 0, smbuf,
+ sizeof(smbuf), NULL);
+ if (error < 0) {
+ WLDEV_ERROR(("get assoc_info failed = %d\n", error));
+ return -1;
+ }
+
+ assoc_info = (wl_assoc_info_t *)smbuf;
+ resp_ies_len = dtoh32(assoc_info->resp_len) -
+ sizeof(struct dot11_assoc_resp);
+
+ /* Retrieve assoc resp IEs */
+ if (resp_ies_len) {
+ error = wldev_iovar_getbuf(dev, "assoc_resp_ies", NULL, 0,
+ smbuf, sizeof(smbuf), NULL);
+ if (error < 0) {
+ WLDEV_ERROR(("get assoc_resp_ies failed = %d\n",
+ error));
+ return -1;
+ }
+
+ {
+ int maxRate = 0;
+ struct dot11IE {
+ unsigned char ie;
+ unsigned char len;
+ unsigned char data[0];
+ } *dot11IE = (struct dot11IE *)smbuf;
+ int remaining = resp_ies_len;
+
+ while (1) {
+ if (remaining < 2)
+ break;
+ if (remaining < dot11IE->len + 2)
+ break;
+ switch (dot11IE->ie) {
+ case 0x01: /* supported rates */
+ case 0x32: /* extended supported rates */
+ for (i = 0; i < dot11IE->len; i++) {
+ int rate = ((dot11IE->data[i] &
+ 0x7f) / 2);
+ if (rate > maxRate)
+ maxRate = rate;
+ }
+ break;
+ case 0x2d: /* HT capabilities */
+ case 0x3d: /* HT operation */
+ /* 11n supported */
+ maxRate = 150; /* Just return an 11n
+ rate for now. Could implement detailed
+ parser later. */
+ break;
+ default:
+ break;
+ }
+
+ /* next IE */
+ dot11IE = (struct dot11IE *)
+ ((unsigned char *)dot11IE + dot11IE->len + 2);
+ remaining -= (dot11IE->len + 2);
+ }
+ bytes_written += snprintf(&command[bytes_written],
+ total_len, "MaxLinkSpeed %d",
+ maxRate);
+ goto done;
+ }
+ } else {
+ WLDEV_ERROR(("Zero Length assoc resp ies = %d\n",
+ resp_ies_len));
+ return -1;
+ }
+
+done:
+
+ return bytes_written;
+
+}
+
+int wldev_get_rx_rate_stats(
+ struct net_device *dev, char *command, int total_len)
+{
+ wl_scb_rx_rate_stats_t *rstats;
+ struct ether_addr ea;
+ char smbuf[WLC_IOCTL_SMLEN];
+ char eabuf[18] = {0, };
+ int bytes_written = 0;
+ int error;
+
+ memcpy(eabuf, command+strlen("RXRATESTATS")+1, 17);
+
+ if (!bcm_ether_atoe(eabuf, &ea)) {
+ WLDEV_ERROR(("Invalid MAC Address\n"));
+ return -1;
+ }
+
+ error = wldev_iovar_getbuf(dev, "rx_rate_stats",
+ &ea, ETHER_ADDR_LEN, smbuf, sizeof(smbuf), NULL);
+ if (error < 0) {
+ WLDEV_ERROR(("get rx_rate_stats failed = %d\n", error));
+ return -1;
+ }
+
+ rstats = (wl_scb_rx_rate_stats_t *)smbuf;
+ bytes_written = sprintf(command, "1/%d/%d,",
+ dtoh32(rstats->rx1mbps[0]), dtoh32(rstats->rx1mbps[1]));
+ bytes_written += sprintf(command+bytes_written, "2/%d/%d,",
+ dtoh32(rstats->rx2mbps[0]), dtoh32(rstats->rx2mbps[1]));
+ bytes_written += sprintf(command+bytes_written, "5.5/%d/%d,",
+ dtoh32(rstats->rx5mbps5[0]), dtoh32(rstats->rx5mbps5[1]));
+ bytes_written += sprintf(command+bytes_written, "6/%d/%d,",
+ dtoh32(rstats->rx6mbps[0]), dtoh32(rstats->rx6mbps[1]));
+ bytes_written += sprintf(command+bytes_written, "9/%d/%d,",
+ dtoh32(rstats->rx9mbps[0]), dtoh32(rstats->rx9mbps[1]));
+ bytes_written += sprintf(command+bytes_written, "11/%d/%d,",
+ dtoh32(rstats->rx11mbps[0]), dtoh32(rstats->rx11mbps[1]));
+ bytes_written += sprintf(command+bytes_written, "12/%d/%d,",
+ dtoh32(rstats->rx12mbps[0]), dtoh32(rstats->rx12mbps[1]));
+ bytes_written += sprintf(command+bytes_written, "18/%d/%d,",
+ dtoh32(rstats->rx18mbps[0]), dtoh32(rstats->rx18mbps[1]));
+ bytes_written += sprintf(command+bytes_written, "24/%d/%d,",
+ dtoh32(rstats->rx24mbps[0]), dtoh32(rstats->rx24mbps[1]));
+ bytes_written += sprintf(command+bytes_written, "36/%d/%d,",
+ dtoh32(rstats->rx36mbps[0]), dtoh32(rstats->rx36mbps[1]));
+ bytes_written += sprintf(command+bytes_written, "48/%d/%d,",
+ dtoh32(rstats->rx48mbps[0]), dtoh32(rstats->rx48mbps[1]));
+ bytes_written += sprintf(command+bytes_written, "54/%d/%d",
+ dtoh32(rstats->rx54mbps[0]), dtoh32(rstats->rx54mbps[1]));
+
+ return bytes_written;
+}
diff --git a/drivers/net/wireless/bcmdhd/wldev_common.h b/drivers/net/wireless/bcmdhd/wldev_common.h
index 378d7bd5ceba..101dc91fba65 100755
--- a/drivers/net/wireless/bcmdhd/wldev_common.h
+++ b/drivers/net/wireless/bcmdhd/wldev_common.h
@@ -115,4 +115,10 @@ int wldev_get_band(struct net_device *dev, uint *pband);
int wldev_set_band(struct net_device *dev, uint band);
+
+int wldev_miracast_tuning(struct net_device *dev, char *command, int total_len);
+int wldev_get_assoc_resp_ie(struct net_device *dev, char *command, int total_len);
+int wldev_get_rx_rate_stats(struct net_device *dev, char *command, int total_len);
+int wldev_get_max_linkspeed(struct net_device *dev, char *command, int total_len);
+extern void dhd_set_ampdu_rx_tid(struct net_device *dev, int ampdu_rx_tid);
#endif /* __WLDEV_COMMON_H__ */