summaryrefslogtreecommitdiff
path: root/dhd_custom_google.c
diff options
context:
space:
mode:
Diffstat (limited to 'dhd_custom_google.c')
-rw-r--r--dhd_custom_google.c439
1 files changed, 437 insertions, 2 deletions
diff --git a/dhd_custom_google.c b/dhd_custom_google.c
index 5158e3b..5bd91e8 100644
--- a/dhd_custom_google.c
+++ b/dhd_custom_google.c
@@ -841,7 +841,7 @@ struct resource dhd_wlan_resources = {
.start = 0, /* Dummy */
.end = 0, /* Dummy */
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE |
- IORESOURCE_IRQ_HIGHEDGE,
+ IORESOURCE_IRQ_HIGHLEVEL,
};
EXPORT_SYMBOL(dhd_wlan_resources);
@@ -864,6 +864,432 @@ struct wifi_platform_data dhd_wlan_control = {
};
EXPORT_SYMBOL(dhd_wlan_control);
+
+#ifdef WLAN_TRACKER
+#include <wlan_ptracker_client.h>
+#include <wldev_common.h>
+#include <wl_cfg80211.h>
+#include <dhd_linux_priv.h>
+
+static int
+dhd_twt_setup(void *priv, struct dytwt_setup_param *setup)
+{
+ wl_twt_config_t val;
+ struct net_device *dev = (struct net_device *)priv;
+ s32 bw;
+ u8 mybuf[WLC_IOCTL_SMLEN] = {0};
+ u8 resp_buf[WLC_IOCTL_SMLEN] = {0};
+ uint8 *rem = mybuf;
+ uint16 rem_len = sizeof(mybuf);
+
+ bzero(&val, sizeof(val));
+ val.version = WL_TWT_SETUP_VER;
+ val.length = sizeof(val.version) + sizeof(val.length);
+
+ /* Default values, Override Below */
+ val.desc.flow_flags = 0;
+ val.desc.wake_time_h = 0xFFFFFFFF;
+ val.desc.wake_time_l = 0xFFFFFFFF;
+ val.desc.wake_int_min = 0xFFFFFFFF;
+ val.desc.wake_int_max = 0xFFFFFFFF;
+ val.desc.wake_dur_min = 0xFFFFFFFF;
+ val.desc.wake_dur_max = 0xFFFFFFFF;
+ val.desc.avg_pkt_num = 0xFFFFFFFF;
+ val.desc.avg_pkt_size = 0xFFFFFFFF;
+
+ /* Flow Flag for setup cmd: request, flow type: unannounced */
+ val.desc.flow_flags |= WL_TWT_FLOW_FLAG_REQUEST;
+ val.desc.flow_flags |= WL_TWT_FLOW_FLAG_UNANNOUNCED;
+ /* Config ID */
+ val.desc.configID = setup->config_id;
+ /* negotiation_type */
+ val.desc.negotiation_type = setup->nego_type;
+ /* Wake Duration */
+ val.desc.wake_dur = setup->wake_duration;
+ /* Wake interval */
+ val.desc.wake_int = setup->wake_interval;
+
+ bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_CONFIG,
+ sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
+ if (bw != BCME_OK) {
+ goto exit;
+ }
+
+ bw = wldev_iovar_setbuf(dev, "twt",
+ mybuf, sizeof(mybuf) - rem_len, resp_buf, WLC_IOCTL_SMLEN, NULL);
+ if (bw < 0) {
+ pr_err("twt config set failed. ret:%d\n", bw);
+ } else {
+ pr_err("twt config setup succeeded, config ID %d "
+ "Negotiation type %d flow flags %d\n", val.desc.configID,
+ val.desc.negotiation_type, val.desc.flow_flags);
+ }
+exit:
+ return bw;
+}
+
+static int
+dhd_twt_teardown(void *priv, struct dytwt_setup_param *setup)
+{
+ wl_twt_teardown_t val;
+ struct net_device *dev = (struct net_device *)priv;
+ s32 bw;
+ u8 mybuf[WLC_IOCTL_SMLEN] = {0};
+ u8 res_buf[WLC_IOCTL_SMLEN] = {0};
+ uint8 *rem = mybuf;
+ uint16 rem_len = sizeof(mybuf);
+
+ bzero(&val, sizeof(val));
+ val.version = WL_TWT_TEARDOWN_VER;
+ val.length = sizeof(val.version) + sizeof(val.length);
+
+ /* Default values, Override Below */
+ val.teardesc.flow_id = 0xFF;
+ val.teardesc.bid = 0xFF;
+ /* Config ID */
+ val.configID = setup->config_id;
+ /* negotiation_type */
+ val.teardesc.negotiation_type = setup->nego_type;
+
+ bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_TEARDOWN,
+ sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
+ if (bw != BCME_OK) {
+ goto exit;
+ }
+
+ bw = wldev_iovar_setbuf(dev, "twt",
+ mybuf, sizeof(mybuf) - rem_len, res_buf, WLC_IOCTL_SMLEN, NULL);
+ if (bw < 0) {
+ pr_err("twt teardown failed. ret:%d\n", bw);
+ } else {
+ pr_err("twt teardown succeeded, config ID %d "
+ "Negotiation type %d alltwt %d\n", val.configID,
+ val.teardesc.negotiation_type, val.teardesc.alltwt);
+ }
+exit:
+ return bw;
+}
+
+static void dhd_twt_stats2_dytwt(wl_twt_stats_v2_t *src, struct dytwt_stats *dest)
+{
+ wl_twt_peer_stats_v2_t *peer_stats = &src->peer_stats_list[0];
+
+ dest->sp_seq = peer_stats->sp_seq;
+ dest->tx_ucast_pkts = peer_stats->tx_ucast_pkts;
+ dest->tx_pkts_min = peer_stats->tx_pkts_min;
+ dest->tx_pkts_max = peer_stats->tx_pkts_max;
+ dest->tx_pkts_avg = peer_stats->tx_pkts_avg;
+ dest->tx_failures = peer_stats->tx_failures;
+ dest->rx_ucast_pkts = peer_stats->rx_ucast_pkts;
+ dest->rx_pkts_min = peer_stats->rx_pkts_min;
+ dest->rx_pkts_max = peer_stats->rx_pkts_max;
+ dest->rx_pkts_avg = peer_stats->rx_pkts_avg;
+ dest->rx_pkts_retried = peer_stats->rx_pkts_retried;
+ dest->tx_pkt_sz_avg = peer_stats->tx_pkt_sz_avg;
+ dest->rx_pkt_sz_avg = peer_stats->rx_pkt_sz_avg;
+ dest->eosp_dur_avg = peer_stats->eosp_dur_avg;
+ dest->eosp_count = peer_stats->eosp_count;
+}
+
+static int
+dhd_twt_get_stats(void *priv, struct dytwt_stats *stats)
+{
+ struct net_device *dev = (struct net_device *)priv;
+ wl_twt_stats_cmd_v1_t query;
+ wl_twt_stats_v2_t stats_v2;
+ int ret = BCME_OK;
+ char iovbuf[WLC_IOCTL_SMLEN] = {0, };
+ uint8 *pxtlv = NULL;
+ uint8 *iovresp = NULL;
+ uint16 buflen = 0, bufstart = 0;
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
+
+ bzero(&query, sizeof(query));
+ query.version = WL_TWT_STATS_CMD_VERSION_1;
+ query.length = sizeof(query) - OFFSETOF(wl_twt_stats_cmd_v1_t, peer);
+
+ /* Default values, Override Below */
+ query.num_bid = 0xFF;
+ query.num_fid = 0xFF;
+ query.configID = stats->config_id;
+
+ iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
+ if (iovresp == NULL) {
+ WL_ERR(("%s: iov resp memory alloc exited\n", __FUNCTION__));
+ goto exit;
+ }
+ //query.flags |= WL_TWT_STATS_CMD_FLAGS_RESET;
+ buflen = bufstart = WLC_IOCTL_SMLEN;
+ pxtlv = (uint8 *)iovbuf;
+ ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_STATS,
+ sizeof(query), (uint8 *)&query, BCM_XTLV_OPTION_ALIGN32);
+ if (ret != BCME_OK) {
+ WL_ERR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret));
+ goto exit;
+ }
+
+ if ((ret = wldev_iovar_getbuf(dev, "twt", iovbuf, bufstart-buflen,
+ iovresp, WLC_IOCTL_MEDLEN, NULL))) {
+ WL_ERR(("twt status failed with err=%d \n", ret));
+ goto exit;
+ }
+
+ (void)memcpy_s(&stats_v2, sizeof(stats_v2), iovresp, sizeof(stats_v2));
+ if (dtoh16(stats_v2.version) == WL_TWT_STATS_VERSION_2 &&
+ stats_v2.num_stats) {
+ dhd_twt_stats2_dytwt((wl_twt_stats_v2_t*)iovresp, stats);
+ } else {
+ ret = BCME_UNSUPPORTED;
+ WL_ERR(("Version 1 unsupported. ver %d, \n", dtoh16(stats_v2.version)));
+ goto exit;
+ }
+exit:
+ if (iovresp) {
+ MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN);
+ }
+ return ret;
+}
+
+static void dhd_twt_status2_dytwt(
+ wl_twt_status_v1_t *result,
+ struct dytwt_status *status)
+{
+ int i;
+ wl_twt_sdesc_v0_t *sdesc = NULL;
+
+ for (i = 0 ; i < WL_TWT_MAX_ITWT; i++) {
+ if (result->itwt_status[i].configID != status->config_id)
+ continue;
+ sdesc = &result->itwt_status[i].desc;
+ status->config_id = result->itwt_status[i].configID;
+ status->flow_id = sdesc->flow_id;
+ status->flow_flags = sdesc->flow_flags;
+ status->setup_cmd = sdesc->setup_cmd;
+ status->channel = sdesc->channel;
+ status->nego_type = sdesc->negotiation_type;
+ status->wake_dur = sdesc->wake_dur;
+ status->wake_int = sdesc->wake_int;
+ }
+}
+
+static int
+dhd_twt_get_status(void *priv, struct dytwt_status *status)
+{
+ struct net_device *dev = (struct net_device *)priv;
+ wl_twt_status_cmd_v1_t query;
+ wl_twt_status_v1_t result;
+ int ret = BCME_OK;
+ char iovbuf[WLC_IOCTL_SMLEN] = {0, };
+ uint8 *pxtlv = NULL;
+ uint8 *iovresp = NULL;
+ uint16 buflen = 0, bufstart = 0;
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
+
+ bzero(&query, sizeof(query));
+ bzero(&result, sizeof(result));
+ query.version = WL_TWT_CMD_STATUS_VERSION_1;
+ query.length = sizeof(query) - OFFSETOF(wl_twt_status_cmd_v1_t, peer);
+
+ query.configID = status->config_id;
+
+ iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
+ if (iovresp == NULL) {
+ WL_ERR(("%s: iov resp memory alloc exited\n", __FUNCTION__));
+ goto exit;
+ }
+ buflen = bufstart = WLC_IOCTL_SMLEN;
+ pxtlv = (uint8 *)iovbuf;
+ ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_STATUS,
+ sizeof(query), (uint8 *)&query, BCM_XTLV_OPTION_ALIGN32);
+ if (ret != BCME_OK) {
+ WL_ERR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret));
+ goto exit;
+ }
+
+ if ((ret = wldev_iovar_getbuf(dev, "twt", iovbuf, bufstart-buflen,
+ iovresp, WLC_IOCTL_MEDLEN, NULL))) {
+ WL_ERR(("twt status failed with err=%d \n", ret));
+ goto exit;
+ }
+
+ (void)memcpy_s(&result, sizeof(result), iovresp, sizeof(result));
+ printk("wlan_ptracker: %s(): version: %d, length: %d\n",
+ __func__, result.version, result.length);
+ if (dtoh16(result.version) == WL_TWT_CMD_STATUS_VERSION_1) {
+ dhd_twt_status2_dytwt(&result, status);
+ } else {
+ ret = BCME_UNSUPPORTED;
+ WL_ERR(("Version 1 unsupported. ver %d, \n", dtoh16(result.version)));
+ goto exit;
+ }
+exit:
+ if (iovresp) {
+ MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN);
+ }
+ return ret;
+}
+
+static int
+dhd_twt_cap(void *priv, struct dytwt_cap *cap)
+{
+ int ret = BCME_OK;
+ struct net_device *dev = (struct net_device *)priv;
+ char iovbuf[WLC_IOCTL_SMLEN] = {0, };
+ uint8 *pxtlv = NULL;
+ uint8 *iovresp = NULL;
+ wl_twt_cap_cmd_t cmd_cap;
+ wl_twt_cap_t result;
+ scb_val_t scbval;
+ uint16 buflen = 0, bufstart = 0;
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
+
+ /* Query link speed */
+ ret = wldev_get_link_speed(dev, &cap->link_speed);
+ if (unlikely(ret)) {
+ WL_ERR(("get_link speed error (%d)\n", ret));
+ goto exit;
+ }
+
+ /* Query RSSI */
+ bzero(&scbval, sizeof(scb_val_t));
+ ret = wldev_get_rssi(dev, &scbval);
+ if (unlikely(ret)) {
+ WL_ERR(("get_rssi error (%d)\n", ret));
+ goto exit;
+ }
+ cap->rssi = scbval.val;
+ bzero(&cmd_cap, sizeof(cmd_cap));
+
+ cmd_cap.version = WL_TWT_CAP_CMD_VERSION_1;
+ cmd_cap.length = sizeof(cmd_cap) - OFFSETOF(wl_twt_cap_cmd_t, peer);
+
+ iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
+ if (iovresp == NULL) {
+ pr_err("%s: iov resp memory alloc exited\n", __FUNCTION__);
+ goto exit;
+ }
+
+ buflen = bufstart = WLC_IOCTL_SMLEN;
+ pxtlv = (uint8 *)iovbuf;
+
+ ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_CAP,
+ sizeof(cmd_cap), (uint8 *)&cmd_cap, BCM_XTLV_OPTION_ALIGN32);
+ if (ret != BCME_OK) {
+ pr_err("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret);
+ goto exit;
+ }
+
+ if ((ret = wldev_iovar_getbuf(dev, "twt", iovbuf, bufstart-buflen,
+ iovresp, WLC_IOCTL_MEDLEN, NULL))) {
+ pr_err("Getting twt status failed with err=%d \n", ret);
+ goto exit;
+ }
+
+ (void)memcpy_s(&result, sizeof(result), iovresp, sizeof(result));
+
+ if (dtoh16(result.version) == WL_TWT_CAP_CMD_VERSION_1) {
+ pr_err("capability ver %d, \n", dtoh16(result.version));
+ cap->device_cap = dtoh16(result.device_cap);
+ cap->peer_cap = dtoh16(result.peer_cap);
+ return ret;
+ } else {
+ ret = BCME_UNSUPPORTED;
+ pr_err("Version 1 unsupported. ver %d, \n", dtoh16(result.version));
+ goto exit;
+ }
+exit:
+ if (iovresp) {
+ MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN);
+ }
+ return ret;
+}
+
+extern ssize_t show_pwrstats_path(struct dhd_info *dev, char *buf);
+
+static u64 twt_pwrstate_hex_get(char *buf)
+{
+ char *ptr = buf;
+ char *token = strsep(&ptr, "\x0a");
+
+ /* remove prefix space */
+ token++;
+ return simple_strtoull(token, NULL, 16);
+}
+
+#define DHD_PWR_STAT_STR_SIZE 512
+static int dhd_twt_pwstate(void *priv, struct dytwt_pwr_state *state)
+{
+ char buf[DHD_PWR_STAT_STR_SIZE];
+ struct net_device *dev = (struct net_device *)priv;
+ struct dhd_info *dhd = DHD_DEV_INFO(dev);
+ char *ptr = &buf[0];
+ char *token;
+ int cnt = 0;
+ int ret;
+
+ ret = show_pwrstats_path(dhd, buf);
+ if (!ret)
+ goto out;
+
+ token = strsep(&ptr, ":");
+ while (token) {
+ if (cnt == 3)
+ state->awake = twt_pwrstate_hex_get(token);
+ if (cnt == 6)
+ state->count = twt_pwrstate_hex_get(token);
+ if (cnt == 7)
+ state->asleep = twt_pwrstate_hex_get(token);
+ token = strsep(&ptr, ":");
+ cnt++;
+ }
+out:
+ return 0;
+}
+
+struct dytwt_client_ops twt_ops = {
+ .setup = dhd_twt_setup,
+ .teardown = dhd_twt_teardown,
+ .get_cap = dhd_twt_cap,
+ .get_pwrstates = dhd_twt_pwstate,
+ .get_stats = dhd_twt_get_stats,
+ .get_status = dhd_twt_get_status,
+};
+
+struct wlan_ptracker_client client = {
+ .ifname = "wlan0",
+ .dytwt_ops = &twt_ops,
+ .cb = NULL,
+};
+
+static int dhd_plat_ptracker_register(void)
+{
+ return wlan_ptracker_register_client(&client);
+}
+
+static void dhd_plat_ptracker_unregister(void)
+{
+ wlan_ptracker_unregister_client(&client);
+}
+
+static u32 custom_notify_table[] = {
+ WLAN_PTRACKER_NOTIFY_SUSPEN, //CUSTOM_NOTIFY_BUS_SUSPEND,
+ WLAN_PTRACKER_NOTIFY_STA_CONNECT, //CUSTOM_NOTIFY_STA_CONNECT,
+ WLAN_PTRACKER_NOTIFY_STA_DISCONNECT, //CUSTOM_NOTIFY_STA_DISCONNECT,
+ WLAN_PTRACKER_NOTIFY_DYTWT_DISABLE, //CUSTOM_NOTIFY_TWT_SETUP,
+ WLAN_PTRACKER_NOTIFY_DYTWT_ENABLE, //CUSTOM_NOTIFY_TWT_TEARDOWN,
+};
+
+int
+dhd_custom_notify(u32 id)
+{
+ u32 _id = custom_notify_table[id];
+
+ if (!client.cb)
+ return 0;
+ return client.cb(&client, _id);
+}
+#endif /* WLAN_TRACKER */
+
int
dhd_wlan_init(void)
{
@@ -903,6 +1329,10 @@ dhd_wlan_init(void)
dhd_wlan_init_hardware_info();
#endif /* SUPPORT_MULTIPLE_NVRAM || SUPPORT_MULTIPLE_CLMBLOB */
+#ifdef WLAN_TRACKER
+ dhd_plat_ptracker_register();
+#endif /* WLAN_TRACKER */
+
fail:
DHD_ERROR(("%s: FINISH.......\n", __FUNCTION__));
return ret;
@@ -918,6 +1348,10 @@ dhd_wlan_deinit(void)
gpio_free(wlan_reg_on);
}
+#ifdef WLAN_TRACKER
+ dhd_plat_ptracker_unregister();
+#endif /* WLAN_TRACKER */
+
#ifdef DHD_COREDUMP
platform_device_unregister(&sscd_dev);
#endif /* DHD_COREDUMP */
@@ -928,7 +1362,7 @@ dhd_wlan_deinit(void)
void dhd_plat_l1ss_ctrl(bool ctrl)
{
#if defined(CONFIG_SOC_GOOGLE)
- printk(KERN_DEBUG "%s: Control L1ss RC side %d \n", __FUNCTION__, ctrl);
+ DHD_CONS_ONLY(("%s: Control L1ss RC side %d \n", __FUNCTION__, ctrl));
exynos_pcie_rc_l1ss_ctrl(ctrl, PCIE_L1SS_CTRL_WIFI, 1);
#endif /* CONFIG_SOC_GOOGLE */
return;
@@ -1005,6 +1439,7 @@ uint16 dhd_plat_align_rxbuf_size(uint16 rxbufpost_sz)
#endif
}
+
#ifndef BCMDHD_MODULAR
/* Required only for Built-in DHD */
device_initcall(dhd_wlan_init);