diff options
author | Manikanta <mmaddireddy@nvidia.com> | 2014-02-28 15:42:47 +0530 |
---|---|---|
committer | Venu Byravarasu <vbyravarasu@nvidia.com> | 2014-04-07 22:15:31 -0700 |
commit | 6204a40b26e05d40adf4c82c7fd0e4053b9a1672 (patch) | |
tree | a9c2f3924275cbeef187cd74050de6c20f071f92 /drivers/net | |
parent | 8e9e49fa9a96116f44a86cdba2e084d09827641a (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/Makefile | 2 | ||||
-rwxr-xr-x | drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c | 4 | ||||
-rwxr-xr-x | drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c | 5 | ||||
-rwxr-xr-x | drivers/net/wireless/bcmdhd/dhd_common.c | 2 | ||||
-rwxr-xr-x | drivers/net/wireless/bcmdhd/dhd_linux.c | 25 | ||||
-rwxr-xr-x | drivers/net/wireless/bcmdhd/dhd_linux_platdev.c | 14 | ||||
-rwxr-xr-x | drivers/net/wireless/bcmdhd/dhd_qmon.c | 4 | ||||
-rwxr-xr-x | drivers/net/wireless/bcmdhd/include/wlioctl.h | 16 | ||||
-rwxr-xr-x | drivers/net/wireless/bcmdhd/wl_android.c | 12 | ||||
-rwxr-xr-x | drivers/net/wireless/bcmdhd/wl_cfg80211.c | 9 | ||||
-rwxr-xr-x | drivers/net/wireless/bcmdhd/wl_cfgp2p.c | 6 | ||||
-rwxr-xr-x | drivers/net/wireless/bcmdhd/wldev_common.c | 344 | ||||
-rwxr-xr-x | drivers/net/wireless/bcmdhd/wldev_common.h | 6 |
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__ */ |