qcacld-3.0: Report more information in survey dump

qcacld-2.0 to qcacld-3.0 propagation

Currently host only report connected frequency and noise in
survey dump.
Add changes to report all supported frequencies, active time,
TX time, busy time and noise.

CRs-Fixed: 1061040
Change-Id: I2fa509f53b47d65ba0f4abbc438834b85b9c21f6
This commit is contained in:
Kapil Gupta 2017-02-07 15:21:15 +05:30 • committed by qcabuildsw
commit 4f0c0c1c50
13 changed files with 399 additions and 61 deletions

View file

@ -1611,6 +1611,8 @@ struct hdd_context_s {
struct suspend_resume_stats suspend_resume_stats;
struct hdd_runtime_pm_context runtime_context;
bool roaming_in_progress;
struct scan_chan_info *chan_info;
struct mutex chan_info_lock;
/* bit map to set/reset TDLS by different sources */
unsigned long tdls_source_bitmap;
/* tdls source timer to enable/disable TDLS on p2p listen */
@ -2192,5 +2194,22 @@ void hdd_set_roaming_in_progress(bool value);
int wlan_hdd_sap_get_valid_channellist(hdd_adapter_t *adapter,
uint32_t *channel_count,
uint8_t *channel_list);
/**
* wlan_hdd_init_chan_info() - initialize channel info variables
* @hdd_ctx: hdd ctx
*
* This API initialize channel info variables
*
* Return: None
*/
void wlan_hdd_init_chan_info(hdd_context_t *hdd_ctx);
/**
* wlan_hdd_deinit_chan_info() - deinitialize channel info variables
* @hdd_ctx: hdd ctx
*
* This API deinitialize channel info variables
*
* Return: None
*/
void wlan_hdd_deinit_chan_info(hdd_context_t *hdd_ctx);
#endif /* end #if !defined(WLAN_HDD_MAIN_H) */

View file

@ -7088,6 +7088,8 @@ QDF_STATUS hdd_set_sme_config(hdd_context_t *pHddCtx)
CSR_STA_ROAM_POLICY_DFS_ENABLED;
smeConfig->csrConfig.sta_roam_policy_params.skip_unsafe_channels = 0;
smeConfig->snr_monitor_enabled = pHddCtx->config->fEnableSNRMonitoring;
smeConfig->csrConfig.tx_aggregation_size =
pHddCtx->config->tx_aggregation_size;
smeConfig->csrConfig.rx_aggregation_size =

View file

@ -16505,6 +16505,145 @@ void wlan_hdd_clear_link_layer_stats(hdd_adapter_t *adapter)
return;
}
#define CNT_DIFF(cur, prev) \
((cur >= prev) ? (cur - prev) : (cur + (MAX_COUNT - (prev) + 1)))
#define MAX_COUNT 0xffffffff
static void hdd_update_chan_info(hdd_context_t *hdd_ctx,
struct scan_chan_info *chan,
struct scan_chan_info *info, uint32_t cmd_flag)
{
if ((info->cmd_flag != WMI_CHAN_InFO_START_RESP) &&
(info->cmd_flag != WMI_CHAN_InFO_END_RESP))
hdd_err("cmd flag is invalid: %d", info->cmd_flag);
mutex_lock(&hdd_ctx->chan_info_lock);
if (info->cmd_flag == WMI_CHAN_InFO_START_RESP)
qdf_mem_zero(chan, sizeof(*chan));
chan->freq = info->freq;
chan->noise_floor = info->noise_floor;
chan->clock_freq = info->clock_freq;
chan->cmd_flag = info->cmd_flag;
chan->cycle_count = CNT_DIFF(info->cycle_count, chan->cycle_count);
chan->rx_clear_count =
CNT_DIFF(info->rx_clear_count, chan->rx_clear_count);
chan->tx_frame_count =
CNT_DIFF(info->tx_frame_count, chan->tx_frame_count);
mutex_unlock(&hdd_ctx->chan_info_lock);
}
#undef CNT_DIFF
#undef MAX_COUNT
/**
* wlan_hdd_chan_info_cb() - channel info callback
* @chan_info: struct scan_chan_info
*
* Store channel info into HDD context
*
* Return: None.
*/
static void wlan_hdd_chan_info_cb(struct scan_chan_info *info)
{
hdd_context_t *hdd_ctx;
struct scan_chan_info *chan;
uint8_t idx;
ENTER();
hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
if (wlan_hdd_validate_context(hdd_ctx) != 0) {
hdd_err("hdd_ctx is invalid");
return;
}
if (!hdd_ctx->chan_info) {
hdd_err("chan_info is NULL");
return;
}
chan = hdd_ctx->chan_info;
for (idx = 0; idx < SIR_MAX_NUM_CHANNELS; idx++) {
if (chan[idx].freq == info->freq) {
hdd_update_chan_info(hdd_ctx, &chan[idx], info,
info->cmd_flag);
hdd_info("cmd:%d freq:%u nf:%d cc:%u rcc:%u clk:%u cmd:%d tfc:%d index:%d",
chan[idx].cmd_flag, chan[idx].freq,
chan[idx].noise_floor,
chan[idx].cycle_count, chan[idx].rx_clear_count,
chan[idx].clock_freq, chan[idx].cmd_flag,
chan[idx].tx_frame_count, idx);
if (chan[idx].freq == 0)
break;
}
}
EXIT();
}
/**
* wlan_hdd_init_chan_info() - init chan info in hdd context
* @hdd_ctx: HDD context pointer
*
* Return: none
*/
void wlan_hdd_init_chan_info(hdd_context_t *hdd_ctx)
{
uint8_t num_2g, num_5g, index = 0;
if (!hdd_ctx->config->fEnableSNRMonitoring) {
hdd_info("SNR monitoring is disabled");
return;
}
hdd_ctx->chan_info =
qdf_mem_malloc(sizeof(struct scan_chan_info)
* QDF_MAX_NUM_CHAN);
if (hdd_ctx->chan_info == NULL) {
hdd_err("Failed to malloc for chan info");
return;
}
mutex_init(&hdd_ctx->chan_info_lock);
num_2g = QDF_ARRAY_SIZE(hdd_channels_2_4_ghz);
for (; index < num_2g; index++) {
hdd_ctx->chan_info[index].freq =
hdd_channels_2_4_ghz[index].center_freq;
}
num_5g = QDF_ARRAY_SIZE(hdd_channels_5_ghz);
for (; (index - num_2g) < num_5g; index++) {
if (cds_is_dsrc_channel(
hdd_channels_5_ghz[index - num_2g].center_freq))
continue;
hdd_ctx->chan_info[index].freq =
hdd_channels_5_ghz[index - num_2g].center_freq;
}
sme_set_chan_info_callback(hdd_ctx->hHal,
&wlan_hdd_chan_info_cb);
}
/**
* wlan_hdd_deinit_chan_info() - deinit chan info in hdd context
* @hdd_ctx: hdd context pointer
*
* Return: none
*/
void wlan_hdd_deinit_chan_info(hdd_context_t *hdd_ctx)
{
struct scan_chan_info *chan;
chan = hdd_ctx->chan_info;
hdd_ctx->chan_info = NULL;
if (chan)
qdf_mem_free(chan);
}
/**
* struct cfg80211_ops - cfg80211_ops
*

View file

@ -4940,6 +4940,7 @@ static void hdd_wlan_exit(hdd_context_t *hdd_ctx)
cds_flush_work(&hdd_ctx->roc_req_work);
wlansap_global_deinit();
wlan_hdd_deinit_chan_info(hdd_ctx);
wiphy_unregister(wiphy);
wlan_hdd_cfg80211_deinit(wiphy);
@ -8406,6 +8407,8 @@ int hdd_wlan_startup(struct device *dev)
if (hdd_ipa_init(hdd_ctx) == QDF_STATUS_E_FAILURE)
goto err_wiphy_unregister;
wlan_hdd_init_chan_info(hdd_ctx);
hdd_initialize_mac_address(hdd_ctx);
rtnl_held = hdd_hold_rtnl_lock();

View file

@ -2401,6 +2401,106 @@ struct net_device_stats *hdd_get_stats(struct net_device *dev)
ENTER_DEV(dev);
return &adapter->stats;
}
/*
* time = cycle_count * cycle
* cycle = 1 / clock_freq
* Since the unit of clock_freq reported from
* FW is MHZ, and we want to calculate time in
* ms level, the result is
* time = cycle / (clock_freq * 1000)
*/
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
static bool wlan_fill_survey_result(struct survey_info *survey, int opfreq,
struct scan_chan_info *chan_info,
struct ieee80211_channel *channels)
{
uint64_t clock_freq = chan_info->clock_freq * 1000;
if (channels->center_freq != (uint16_t)chan_info->freq)
return false;
survey->channel = channels;
survey->noise = chan_info->noise_floor;
survey->filled = SURVEY_INFO_NOISE_DBM;
if (opfreq == chan_info->freq)
survey->filled |= SURVEY_INFO_IN_USE;
if (clock_freq == 0)
return true;
survey->time = chan_info->cycle_count / clock_freq;
survey->time_busy = chan_info->rx_clear_count / clock_freq;
survey->time_tx = chan_info->tx_frame_count / clock_freq;
survey->filled |= SURVEY_INFO_TIME |
SURVEY_INFO_TIME_BUSY |
SURVEY_INFO_TIME_TX;
return true;
}
#else
static bool wlan_fill_survey_result(struct survey_info *survey, int opfreq,
struct scan_chan_info *chan_info,
struct ieee80211_channel *channels)
{
uint64_t clock_freq = chan_info->clock_freq * 1000;
if (channels->center_freq != (uint16_t)chan_info->freq)
return false;
survey->channel = channels;
survey->noise = chan_info->noise_floor;
survey->filled = SURVEY_INFO_NOISE_DBM;
if (opfreq == chan_info->freq)
survey->filled |= SURVEY_INFO_IN_USE;
if (clock_freq == 0)
return true;
survey->channel_time = chan_info->cycle_count / clock_freq;
survey->channel_time_busy = chan_info->rx_clear_count / clock_freq;
survey->channel_time_tx = chan_info->tx_frame_count / clock_freq;
survey->filled |= SURVEY_INFO_CHANNEL_TIME |
SURVEY_INFO_CHANNEL_TIME_BUSY |
SURVEY_INFO_CHANNEL_TIME_TX;
return true;
}
#endif
static bool wlan_hdd_update_survey_info(struct wiphy *wiphy,
hdd_adapter_t *pAdapter, struct survey_info *survey, int idx)
{
bool filled = false;
int i, j = 0;
uint32_t channel = 0, opfreq; /* Initialization Required */
hdd_context_t *pHddCtx;
pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
sme_get_operation_channel(pHddCtx->hHal, &channel, pAdapter->sessionId);
hdd_wlan_get_freq(channel, &opfreq);
mutex_lock(&pHddCtx->chan_info_lock);
for (i = 0; i < IEEE80211_NUM_BANDS && !filled; i++) {
if (wiphy->bands[i] == NULL)
continue;
for (j = 0; j < wiphy->bands[i]->n_channels && !filled; j++) {
struct ieee80211_supported_band *band = wiphy->bands[i];
filled = wlan_fill_survey_result(survey, opfreq,
&pHddCtx->chan_info[idx],
&band->channels[j]);
}
}
mutex_unlock(&pHddCtx->chan_info_lock);
return filled;
}
/**
* __wlan_hdd_cfg80211_dump_survey() - get survey related info
* @wiphy: Pointer to wiphy
@ -2417,86 +2517,45 @@ static int __wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy,
hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
hdd_context_t *pHddCtx;
hdd_station_ctx_t *pHddStaCtx;
tHalHandle halHandle;
uint32_t channel = 0, freq = 0; /* Initialization Required */
int8_t snr, rssi;
int status, i, j, filled = 0;
int status;
bool filled = false;
ENTER_DEV(dev);
if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
hdd_info("dump survey index:%d", idx);
if (idx > QDF_MAX_NUM_CHAN - 1)
return -EINVAL;
pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
status = wlan_hdd_validate_context(pHddCtx);
if (0 != status)
return status;
if (pHddCtx->chan_info == NULL) {
hdd_err("chan_info is NULL");
return -EINVAL;
}
if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
hdd_err("Command not allowed in FTM mode");
return -EINVAL;
}
pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
status = wlan_hdd_validate_context(pHddCtx);
if (0 != status)
return status;
pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
if (0 == pHddCtx->config->fEnableSNRMonitoring ||
0 != pAdapter->survey_idx ||
eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
/* The survey dump ops when implemented completely is expected
* to return a survey of all channels and the ops is called by
* the kernel with incremental values of the argument 'idx'
* till it returns -ENONET. But we can only support the survey
* for the operating channel for now. survey_idx is used to
* track that the ops is called only once and then return
* -ENONET for the next iteration
*/
pAdapter->survey_idx = 0;
if (pHddCtx->config->fEnableSNRMonitoring == 0)
return -ENONET;
if (pHddStaCtx->hdd_ReassocScenario) {
hdd_info("Roaming in progress, hence return");
return -ENONET;
}
if (!pHddStaCtx->hdd_ReassocScenario) {
hdd_err("Roaming in progress, hence return");
filled = wlan_hdd_update_survey_info(wiphy, pAdapter, survey, idx);
if (!filled)
return -ENONET;
}
halHandle = WLAN_HDD_GET_HAL_CTX(pAdapter);
wlan_hdd_get_snr(pAdapter, &snr);
wlan_hdd_get_rssi(pAdapter, &rssi);
MTRACE(qdf_trace(QDF_MODULE_ID_HDD,
TRACE_CODE_HDD_CFG80211_DUMP_SURVEY,
pAdapter->sessionId, pAdapter->device_mode));
sme_get_operation_channel(halHandle, &channel, pAdapter->sessionId);
hdd_wlan_get_freq(channel, &freq);
for (i = 0; i < NUM_NL80211_BANDS; i++) {
if (NULL == wiphy->bands[i])
continue;
for (j = 0; j < wiphy->bands[i]->n_channels; j++) {
struct ieee80211_supported_band *band = wiphy->bands[i];
if (band->channels[j].center_freq == (uint16_t) freq) {
survey->channel = &band->channels[j];
/* The Rx BDs contain SNR values in dB for the
* received frames while the supplicant expects
* noise. So we calculate and return the value
* of noise (dBm)
* SNR (dB) = RSSI (dBm) - NOISE (dBm)
*/
survey->noise = rssi - snr;
survey->filled = SURVEY_INFO_NOISE_DBM;
filled = 1;
}
}
}
if (filled)
pAdapter->survey_idx = 1;
else {
pAdapter->survey_idx = 0;
return -ENONET;
}
EXIT();
return 0;
}

View file

@ -969,6 +969,8 @@ typedef struct sAniSirGlobal {
bool sta_prefer_80MHz_over_160MHz;
struct wlan_objmgr_psoc *psoc;
enum country_src reg_hint_src;
bool snr_monitor_enabled;
void (*chan_info_cb)(struct scan_chan_info *chan_info);
} tAniSirGlobal;
typedef enum {

View file

@ -6889,4 +6889,23 @@ struct wow_pulse_mode {
*/
QDF_STATUS umac_send_mb_message_to_mac(void *msg);
/**
* struct scan_chan_info - channel info
* @freq: radio frequence
* @cmd flag: cmd flag
* @noise_floor: noise floor
* @cycle_count: cycle count
* @rx_clear_count: rx clear count
* @tx_frame_count: TX frame count
* @clock_freq: clock frequence MHZ
*/
struct scan_chan_info {
uint32_t freq;
uint32_t cmd_flag;
uint32_t noise_floor;
uint32_t cycle_count;
uint32_t rx_clear_count;
uint32_t tx_frame_count;
uint32_t clock_freq;
};
#endif /* __SIR_API_H */

View file

@ -91,6 +91,7 @@ typedef void (*hdd_ftm_msg_processor)(void *);
typedef struct _smeConfigParams {
tCsrConfigParam csrConfig;
struct rrm_config_param rrmConfig;
bool snr_monitor_enabled;
} tSmeConfigParams, *tpSmeConfigParams;
#ifdef FEATURE_WLAN_TDLS
@ -1386,4 +1387,15 @@ void sme_set_cc_src(tHalHandle hal_handle, enum country_src);
QDF_STATUS sme_set_wow_pulse(struct wow_pulse_mode *wow_pulse_set_info);
#endif
/**
* sme_set_chan_info_callback() - Register chan info callback
* @hal - MAC global handle
* @callback_routine - callback routine from HDD
*
* This API is invoked by HDD to register its callback to mac
*
* Return: QDF_STATUS
*/
void sme_set_chan_info_callback(tHalHandle hal_handle,
void (*callback)(struct scan_chan_info *chan_info));
#endif /* #if !defined( __SME_API_H ) */

View file

@ -1456,6 +1456,9 @@ QDF_STATUS sme_update_config(tHalHandle hHal, tpSmeConfigParams pSmeConfigParams
QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,
"Could not pass on WNI_CFG_SCAN_IN_POWERSAVE to CFG");
}
pMac->snr_monitor_enabled = pSmeConfigParams->snr_monitor_enabled;
return status;
}
@ -16439,6 +16442,19 @@ QDF_STATUS sme_create_mon_session(tHalHandle hal_handle, tSirMacAddr bss_id)
return status;
}
void sme_set_chan_info_callback(tHalHandle hal_handle,
void (*callback)(struct scan_chan_info *chan_info))
{
tpAniSirGlobal mac;
if (hal_handle == NULL) {
QDF_ASSERT(0);
return;
}
mac = PMAC_STRUCT(hal_handle);
mac->chan_info_cb = callback;
}
/**
* sme_set_adaptive_dwelltime_config() - Update Adaptive dwelltime configuration
* @hal: The handle returned by macOpen

View file

@ -2358,4 +2358,17 @@ int wma_form_rx_packet(qdf_nbuf_t buf,
QDF_STATUS wma_mgmt_unified_cmd_send(struct wlan_objmgr_vdev *vdev,
qdf_nbuf_t buf, uint32_t desc_id,
void *mgmt_tx_params);
/**
* wma_chan_info_event_handler() - chan info event handler
* @handle: wma handle
* @event_buf: event handler data
* @len: length of @event_buf
*
* this function will handle the WMI_CHAN_INFO_EVENTID
*
* Return: int
*/
int wma_chan_info_event_handler(void *handle, uint8_t *event_buf,
uint32_t len);
#endif

View file

@ -8671,3 +8671,49 @@ int wma_unified_power_debug_stats_event_handler(void *handle,
return 0;
}
#endif
int wma_chan_info_event_handler(void *handle, uint8_t *event_buf,
uint32_t len)
{
tp_wma_handle wma = (tp_wma_handle)handle;
WMI_CHAN_INFO_EVENTID_param_tlvs *param_buf;
wmi_chan_info_event_fixed_param *event;
struct scan_chan_info buf;
tpAniSirGlobal mac = NULL;
WMA_LOGD("%s: Enter", __func__);
if (wma != NULL && wma->cds_context != NULL)
mac = (tpAniSirGlobal)cds_get_context(QDF_MODULE_ID_PE);
if (!mac) {
WMA_LOGE("%s: Invalid mac context", __func__);
return -EINVAL;
}
WMA_LOGD("%s: monitor:%d", __func__, mac->snr_monitor_enabled);
if (mac->snr_monitor_enabled && mac->chan_info_cb) {
param_buf =
(WMI_CHAN_INFO_EVENTID_param_tlvs *)event_buf;
if (!param_buf) {
WMA_LOGA("%s: Invalid chan info event", __func__);
return -EINVAL;
}
event = param_buf->fixed_param;
if (!event) {
WMA_LOGA("%s: Invalid fixed param", __func__);
return -EINVAL;
}
buf.tx_frame_count = event->tx_frame_cnt;
buf.clock_freq = event->mac_clk_mhz;
buf.cmd_flag = event->cmd_flags;
buf.freq = event->freq;
buf.noise_floor = event->noise_floor;
buf.cycle_count = event->cycle_count;
buf.rx_clear_count = event->rx_clear_count;
mac->chan_info_cb(&buf);
}
return 0;
}

View file

@ -2338,6 +2338,10 @@ QDF_STATUS wma_open(struct wlan_objmgr_psoc *psoc, void *cds_context,
WMI_VDEV_ENCRYPT_DECRYPT_DATA_RESP_EVENTID,
wma_encrypt_decrypt_msg_handler,
WMA_RX_SERIALIZER_CTX);
wmi_unified_register_event_handler(wma_handle->wmi_handle,
WMI_CHAN_INFO_EVENTID,
wma_chan_info_event_handler,
WMA_RX_SERIALIZER_CTX);
wma_ndp_register_all_event_handlers(wma_handle);
wma_target_if_open(wma_handle);
target_if_open(wma_get_psoc_from_scn_handle);

View file

@ -260,6 +260,10 @@ QDF_STATUS wma_get_buf_start_scan_cmd(tp_wma_handle wma_handle,
/* add DS param IE in probe req frame */
cmd->scan_ctrl_flags |= WMI_SCAN_ADD_DS_IE_IN_PROBE_REQ;
/* set flag to get chan stats */
if (pMac->snr_monitor_enabled)
cmd->scan_ctrl_flags |= WMI_SCAN_CHAN_STAT_EVENT;
/* do not add OFDM rates in 11B mode */
if (scan_req->dot11mode != WNI_CFG_DOT11_MODE_11B)
cmd->scan_ctrl_flags |= WMI_SCAN_ADD_OFDM_RATES;