diff options
| author | Zhang Qian <zhangq@codeaurora.org> | 2016-12-23 11:10:48 +0800 |
|---|---|---|
| committer | Sandeep Puligilla <spuligil@codeaurora.org> | 2017-03-10 20:26:54 -0800 |
| commit | 6db9889fbd58afb4e12a8ab387aa8b130d42b41b (patch) | |
| tree | 8aff69242e75b993e9ea4b807c70db5ab4a9d174 | |
| parent | 8553db2fcd1bc895e9f210f7cae5031e1a12c801 (diff) | |
qcacld-3.0: Add peer ps change and TX failure indication
qcacld-2.0 to qcacld-3.0 propagation
This change indicates Peer STA's power state change and TX
failure to NL80211.
Vendor command QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT(127)
is introduced by this change.
Change-Id: Iaa1c14e5cdc5a7d04beebbff1149daf871f9ef5a
CRs-fixed: 1048388
| -rw-r--r-- | core/hdd/src/wlan_hdd_cfg80211.c | 6 | ||||
| -rw-r--r-- | core/hdd/src/wlan_hdd_cfg80211.h | 56 | ||||
| -rw-r--r-- | core/hdd/src/wlan_hdd_main.c | 3 | ||||
| -rw-r--r-- | core/hdd/src/wlan_hdd_stats.c | 200 | ||||
| -rw-r--r-- | core/hdd/src/wlan_hdd_stats.h | 14 |
5 files changed, 279 insertions, 0 deletions
diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 5f965c9b388d..2f3a7f9834b3 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -963,6 +963,12 @@ static const struct nl80211_vendor_cmd_info wlan_hdd_cfg80211_vendor_events[] = .subcmd = QCA_NL80211_VENDOR_SUBCMD_LL_STATS_PEERS_RESULTS }, + [QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT + }, #endif /* WLAN_FEATURE_LINK_LAYER_STATS */ [QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE_CHANGE_INDEX] = { .vendor_id = diff --git a/core/hdd/src/wlan_hdd_cfg80211.h b/core/hdd/src/wlan_hdd_cfg80211.h index c739edf352c5..c667d9b41db7 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.h +++ b/core/hdd/src/wlan_hdd_cfg80211.h @@ -295,6 +295,8 @@ typedef enum { * indicated through an event using the same sub command through * @QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_STATUS. Attributes are * listed in qca_wlan_vendor_attr_sap_conditional_chan_switch + * @QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT: Command/event used to config + * indication period and threshold for MAC layer counters. * @QCA_NL80211_VENDOR_SUBCMD_CONFIGURE_TDLS: Configure the TDLS behavior * in the host driver. The different TDLS configurations are defined * by the attributes in enum qca_wlan_vendor_attr_tdls_configuration. @@ -445,6 +447,8 @@ enum qca_nl80211_vendor_subcmds { QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP = 123, QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH = 124, + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT = 127, + /* Encrypt/Decrypt command */ QCA_NL80211_VENDOR_SUBCMD_ENCRYPTION_TEST = 137, @@ -640,6 +644,7 @@ enum qca_wlan_vendor_attr_get_station_info { * @QCA_NL80211_VENDOR_SUBCMD_LL_RADIO_STATS_INDEX: Radio stats * @QCA_NL80211_VENDOR_SUBCMD_LL_IFACE_STATS_INDEX: Iface stats * @QCA_NL80211_VENDOR_SUBCMD_LL_PEER_INFO_STATS_INDEX: Peer info stats + * @QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT_INDEX: MAC layer counters * @QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE_CHANGE_INDEX: Ext tdls state change * @QCA_NL80211_VENDOR_SUBCMD_DO_ACS_INDEX: ACS command * @QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH_INDEX: Pass Roam and Auth info @@ -698,6 +703,7 @@ enum qca_nl80211_vendor_subcmds_index { QCA_NL80211_VENDOR_SUBCMD_LL_RADIO_STATS_INDEX, QCA_NL80211_VENDOR_SUBCMD_LL_IFACE_STATS_INDEX, QCA_NL80211_VENDOR_SUBCMD_LL_PEER_INFO_STATS_INDEX, + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT_INDEX, #endif /* WLAN_FEATURE_LINK_LAYER_STATS */ QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE_CHANGE_INDEX, @@ -3288,6 +3294,56 @@ enum qca_vendor_attr_sar_limits { QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_AFTER_LAST - 1 }; +/** + * enum qca_wlan_vendor_attr_ll_stats_ext - Attributes for MAC layer monitoring + * offload which is an extension for LL_STATS. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD: Monitoring period. Unit in ms. + * If MAC counters do not exceed the threshold, FW will report monitored + * link layer counters periodically as this setting. The first report is + * always triggered by this timer. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD: It is a percentage(1 ~ 99). + * For each MAC layer counter, FW holds two copies. One is the current value. + * The other is the last report. Once a current counter's increment is larger + * than the theshold, FW will indicate that counter to host even the + * monitoring timer does not expire. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS: Peer sta's MAC address + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_CHG: Peer sta power state change + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_STATE: Current power state of + * peer STA. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TID: TID of msdu + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NUM_MSDU: Count of msdu with the same + * failure code. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS: TX failure code + * 1: TX packet discarded + * 2: No ACK + * 3: Postpone + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS: peer MAC address + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_STATE: Peer STA current state + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM: number of peers +*/ +enum qca_wlan_vendor_attr_ll_stats_ext { + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_INVALID = 0, + + /* Attributes for configurations */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD, + + /* Peer STA power state change */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_CHG, + + /* TX failure event */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TID, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NUM_MSDU, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_STATE, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_LAST, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX = + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_LAST - 1 +}; + struct cfg80211_bss *wlan_hdd_cfg80211_update_bss_db(hdd_adapter_t *pAdapter, tCsrRoamInfo *pRoamInfo); diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index ce37736fad9d..69d33a7d6cb7 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -8837,6 +8837,9 @@ int hdd_register_cb(hdd_context_t *hdd_ctx) sme_rso_cmd_status_cb(hdd_ctx->hHal, wlan_hdd_rso_cmd_status_cb); + sme_set_link_layer_ext_cb(hdd_ctx->hHal, + wlan_hdd_cfg80211_link_layer_stats_ext_callback); + status = sme_set_lost_link_info_cb(hdd_ctx->hHal, hdd_lost_link_info_cb); /* print error and not block the startup process */ diff --git a/core/hdd/src/wlan_hdd_stats.c b/core/hdd/src/wlan_hdd_stats.c index 90aaaa3b3126..3b8e483c85ce 100644 --- a/core/hdd/src/wlan_hdd_stats.c +++ b/core/hdd/src/wlan_hdd_stats.c @@ -1572,6 +1572,206 @@ int wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy, return ret; } +/** + * hdd_populate_per_peer_ps_info() - populate per peer sta's PS info + * @wifi_peer_info: peer information + * @vendor_event: buffer for vendor event + * + * Return: 0 success + */ +static inline int +hdd_populate_per_peer_ps_info(tSirWifiPeerInfo *wifi_peer_info, + struct sk_buff *vendor_event) +{ + if (!wifi_peer_info) { + hdd_err("Invalid pointer to peer info."); + return -EINVAL; + } + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_STATE, + wifi_peer_info->power_saving) || + nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS, + QDF_MAC_ADDR_SIZE, &wifi_peer_info->peerMacAddress)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail."); + return -EINVAL; + } + return 0; +} + +/** + * hdd_populate_wifi_peer_ps_info() - populate peer sta's power state + * @data: stats for peer STA + * @vendor_event: buffer for vendor event + * + * Return: 0 success + */ +static int hdd_populate_wifi_peer_ps_info(tSirWifiPeerStat *data, + struct sk_buff *vendor_event) +{ + uint32_t peer_num, i; + tSirWifiPeerInfo *wifi_peer_info; + struct nlattr *peer_info, *peers; + + if (!data) { + hdd_err("Invalid pointer to Wifi peer stat."); + return -EINVAL; + } + + peer_num = data->numPeers; + if (peer_num == 0) { + hdd_err("Peer number is zero."); + return -EINVAL; + } + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM, + peer_num)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + return -EINVAL; + } + + peer_info = nla_nest_start(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_CHG); + if (peer_info == NULL) { + hdd_err("nla_nest_start failed"); + return -EINVAL; + } + + for (i = 0; i < peer_num; i++) { + wifi_peer_info = &data->peerInfo[i]; + peers = nla_nest_start(vendor_event, i); + + if (hdd_populate_per_peer_ps_info(wifi_peer_info, + vendor_event)) + return -EINVAL; + + nla_nest_end(vendor_event, peers); + } + nla_nest_end(vendor_event, peer_info); + + return 0; +} + +/** + * hdd_populate_tx_failure_info() - populate TX failure info + * @tx_fail: TX failure info + * @skb: buffer for vendor event + * + * Return: 0 Success + */ +static inline int +hdd_populate_tx_failure_info(struct sir_wifi_iface_tx_fail *tx_fail, + struct sk_buff *skb) +{ + int status = 0; + + if (tx_fail == NULL || skb == NULL) + return -EINVAL; + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TID, + tx_fail->tid) || + nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NUM_MSDU, + tx_fail->msdu_num) || + nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS, + tx_fail->status)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + status = -EINVAL; + } + + return status; +} + +/** + * wlan_hdd_cfg80211_link_layer_stats_ext_callback() - Callback for LL ext + * @ctx: HDD context + * @rsp: msg from FW + * + * This function is an extension of + * wlan_hdd_cfg80211_link_layer_stats_callback. It converts + * monitoring parameters offloaded to NL data and send the same to the + * kernel/upper layers. + * + * Return: None + */ +void wlan_hdd_cfg80211_link_layer_stats_ext_callback(tHddHandle ctx, + tSirLLStatsResults *rsp) +{ + hdd_context_t *hdd_ctx; + struct sk_buff *skb = NULL; + uint32_t param_id, index; + hdd_adapter_t *adapter = NULL; + tSirLLStatsResults *linkLayer_stats_results; + tSirWifiPeerStat *peer_stats; + uint8_t *results; + int status; + + ENTER(); + + if (!ctx) { + hdd_err("Invalid HDD context."); + return; + } + + if (!rsp) { + hdd_err("Invalid result."); + return; + } + + hdd_ctx = (hdd_context_t *)ctx; + linkLayer_stats_results = (tSirLLStatsResults *)rsp; + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return; + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, + linkLayer_stats_results->ifaceId); + + if (NULL == adapter) { + hdd_err("vdev_id %d does not exist with host.", + linkLayer_stats_results->ifaceId); + return; + } + + index = QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT_INDEX; + skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + NULL, LL_STATS_EVENT_BUF_SIZE + NLMSG_HDRLEN, + index, GFP_KERNEL); + if (!skb) { + hdd_err("cfg80211_vendor_event_alloc failed."); + goto exit; + } + + results = linkLayer_stats_results->results; + param_id = linkLayer_stats_results->paramId; + hdd_info("LL_STATS RESP paramID = 0x%x, ifaceId = %u, result = %p", + linkLayer_stats_results->paramId, + linkLayer_stats_results->ifaceId, + linkLayer_stats_results->results); + if (param_id & WMI_LL_STATS_EXT_PS_CHG) { + peer_stats = (tSirWifiPeerStat *)results; + status = hdd_populate_wifi_peer_ps_info(peer_stats, skb); + } else if (param_id & WMI_LL_STATS_EXT_TX_FAIL) { + struct sir_wifi_iface_tx_fail *tx_fail; + + tx_fail = (struct sir_wifi_iface_tx_fail *)results; + status = hdd_populate_tx_failure_info(tx_fail, skb); + } else if (param_id & WMI_LL_STATS_EXT_MAC_COUNTER) { + hdd_info("MAC counters stats"); + } else { + hdd_info("Unknown link layer stats"); + } + +exit: + if (status == 0) + cfg80211_vendor_event(skb, GFP_KERNEL); + else + kfree_skb(skb); + EXIT(); +} + #endif /* WLAN_FEATURE_LINK_LAYER_STATS */ #ifdef WLAN_FEATURE_STATS_EXT diff --git a/core/hdd/src/wlan_hdd_stats.h b/core/hdd/src/wlan_hdd_stats.h index 7b9bba501796..8465041ad8d5 100644 --- a/core/hdd/src/wlan_hdd_stats.h +++ b/core/hdd/src/wlan_hdd_stats.h @@ -238,5 +238,19 @@ int wlan_hdd_get_rcpi(hdd_adapter_t *adapter, uint8_t *mac, int32_t *rcpi_value, enum rcpi_measurement_type measurement_type); +/** + * wlan_hdd_cfg80211_link_layer_stats_ext_callback() - Callback for LL ext + * @ctx: HDD context + * @rsp: msg from FW + * + * This function is an extension of + * wlan_hdd_cfg80211_link_layer_stats_callback. It converts + * monitoring parameters offloaded to NL data and send the same to the + * kernel/upper layers. + * + * Return: None. + */ +void wlan_hdd_cfg80211_link_layer_stats_ext_callback(tHddHandle ctx, + tSirLLStatsResults *rsp); #endif /* end #if !defined(WLAN_HDD_STATS_H) */ |
