static bool
wlan_dcs_wlan_interference_process(
struct wlan_host_dcs_im_tgt_stats *curr_stats,
struct dcs_pdev_priv_obj *dcs_pdev_priv)
{
struct wlan_host_dcs_im_tgt_stats *prev_stats;
struct pdev_dcs_params dcs_host_params;
struct pdev_dcs_im_stats *p_dcs_im_stats;
bool start_dcs_cbk_handler = false;
uint32_t reg_tsf_delta = 0;
uint32_t scaled_reg_tsf_delta;
uint32_t rxclr_delta = 0;
uint32_t rxclr_ext_delta = 0;
uint32_t cycle_count_delta = 0;
uint32_t scaled_cycle_count_delta;
uint32_t tx_frame_delta = 0;
uint32_t rx_frame_delta = 0;
uint32_t my_bss_rx_delta = 0;
uint32_t reg_total_cu = 0;
uint32_t reg_tx_cu = 0;
uint32_t reg_rx_cu = 0;
uint32_t obss_rx_cu = 0;
uint32_t reg_unused_cu = 0;
uint32_t rx_time_cu = 0;
uint32_t reg_ofdm_phyerr_delta = 0;
uint32_t reg_cck_phyerr_delta = 0;
uint32_t reg_ofdm_phyerr_cu = 0;
uint32_t ofdm_phy_err_rate = 0;
uint32_t cck_phy_err_rate = 0;
uint32_t max_phy_err_rate = 0;
uint32_t max_phy_err_count = 0;
uint32_t total_wasted_cu = 0;
uint32_t wasted_tx_cu = 0;
uint32_t tx_err = 0;
uint32_t too_many_phy_errors = 0;
if (!curr_stats) {
dcs_err("curr_stats is NULL");
goto end;
}
if (!dcs_pdev_priv) {
dcs_err("dcs pdev private object is NULL");
goto end;
}
dcs_host_params = dcs_pdev_priv->dcs_host_params;
p_dcs_im_stats = &dcs_pdev_priv->dcs_im_stats;
prev_stats = &dcs_pdev_priv->dcs_im_stats.prev_dcs_im_stats;
if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE))
wlan_dcs_im_print_stats(prev_stats, curr_stats);
/*
* Counters would have wrapped. Ideally we should be able to figure this
* out, but we never know how many times counters wrapped, just ignore.
*/
if ((curr_stats->mib_stats.listen_time <= 0) ||
(curr_stats->reg_tsf32 <= prev_stats->reg_tsf32)) {
if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE))
dcs_debug("ignoring due to negative TSF value");
goto copy_stats;
}
reg_tsf_delta = curr_stats->reg_tsf32 - prev_stats->reg_tsf32;
/*
* Do nothing if current stats are not seeming good, probably
* a reset happened on chip, force cleared
*/
if (prev_stats->mib_stats.reg_rxclr_cnt >
curr_stats->mib_stats.reg_rxclr_cnt) {
if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE))
dcs_debug("ignoring due to negative rxclr count");
goto copy_stats;
}
rxclr_delta = curr_stats->mib_stats.reg_rxclr_cnt -
prev_stats->mib_stats.reg_rxclr_cnt;
rxclr_ext_delta = curr_stats->mib_stats.reg_rxclr_ext_cnt -
prev_stats->mib_stats.reg_rxclr_ext_cnt;
tx_frame_delta = curr_stats->mib_stats.reg_tx_frame_cnt -
prev_stats->mib_stats.reg_tx_frame_cnt;
rx_frame_delta = curr_stats->mib_stats.reg_rx_frame_cnt -
prev_stats->mib_stats.reg_rx_frame_cnt;
cycle_count_delta = curr_stats->mib_stats.reg_cycle_cnt -
prev_stats->mib_stats.reg_cycle_cnt;
my_bss_rx_delta = curr_stats->my_bss_rx_cycle_count -
prev_stats->my_bss_rx_cycle_count;
if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE))
dcs_debug("rxclr_delta: %u, rxclr_ext_delta: %u, tx_frame_delta: %u, rx_frame_delta: %u, cycle_count_delta: %u, my_bss_rx_delta: %u",
rxclr_delta, rxclr_ext_delta, tx_frame_delta,
rx_frame_delta, cycle_count_delta, my_bss_rx_delta);
/* Update user stats */
wlan_dcs_pdev_obj_lock(dcs_pdev_priv);
if (dcs_pdev_priv->dcs_host_params.user_request_count) {
struct wlan_host_dcs_im_user_stats *p_user_stats =
&p_dcs_im_stats->user_dcs_im_stats;
p_user_stats->cycle_count += cycle_count_delta;
p_user_stats->rxclr_count += rxclr_delta;
p_user_stats->rx_frame_count += rx_frame_delta;
p_user_stats->my_bss_rx_cycle_count += my_bss_rx_delta;
if (0 == p_user_stats->max_rssi &&
0 == p_user_stats->min_rssi) {
p_user_stats->max_rssi = curr_stats->last_ack_rssi;
p_user_stats->min_rssi = curr_stats->last_ack_rssi;
} else {
if (curr_stats->last_ack_rssi > p_user_stats->max_rssi)
p_user_stats->max_rssi =
curr_stats->last_ack_rssi;
if (curr_stats->last_ack_rssi < p_user_stats->min_rssi)
p_user_stats->min_rssi =
curr_stats->last_ack_rssi;
}
dcs_pdev_priv->dcs_host_params.user_request_count--;
if (0 == dcs_pdev_priv->dcs_host_params.user_request_count)
dcs_pdev_priv->dcs_host_params.notify_user = 1;
}
wlan_dcs_pdev_obj_unlock(dcs_pdev_priv);
/*
* Total channel utiliztaion is the amount of time RXCLR is
* counted. RXCLR is counted, when 'RX is NOT clear', please
* refer to mac documentation. It means either TX or RX is ON
*
* Why shift by 8 ? after multiplication it could overflow. At one
* second rate, normally neither cycle_count_delta nor the tsf_delta
* would be zero after shift by 8 bits. In corner case, host resets
* dcs stats, and at the same time tsf counters is wrapped.
* Then all the variable in prev_stats are 0, and the variable in
* curr_stats may be a small value, so add check for cycle_count_delta
* and the tsf_delta after shift by 8 bits.
*/
scaled_cycle_count_delta = cycle_count_delta >> 8;
scaled_reg_tsf_delta = reg_tsf_delta >> 8;
if (!scaled_cycle_count_delta || !scaled_reg_tsf_delta) {
if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE))
dcs_debug("cycle count or TSF NULL --Investigate--");
goto copy_stats;
}
reg_total_cu = ((rxclr_delta >> 8) * 100) / scaled_cycle_count_delta;
reg_tx_cu = ((tx_frame_delta >> 8) * 100) / scaled_cycle_count_delta;
reg_rx_cu = ((rx_frame_delta >> 8) * 100) / scaled_cycle_count_delta;
rx_time_cu = ((curr_stats->rx_time >> 8) * 100) / scaled_reg_tsf_delta;
obss_rx_cu = (((rx_frame_delta - my_bss_rx_delta) >> 8) * 100) /
scaled_cycle_count_delta;
wlan_dcs_update_chan_util(p_dcs_im_stats, reg_rx_cu, reg_tx_cu,
obss_rx_cu, reg_total_cu,
curr_stats->chan_nf);
/*
* Amount of the time AP received cannot go higher than the receive
* cycle count delta. If at all it is, there should have been a
* computation error, ceil it to receive_cycle_count_diff
*/
if (rx_time_cu > reg_rx_cu)
rx_time_cu = reg_rx_cu;
if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE))
dcs_debug("reg_total_cu: %u, reg_tx_cu: %u, reg_rx_cu: %u, rx_time_cu: %u, obss_rx_cu: %u dcs_algorithm: %d",
reg_total_cu, reg_tx_cu, reg_rx_cu,
rx_time_cu, obss_rx_cu,
dcs_host_params.dcs_algorithm_process);
/*
* For below scenario, will ignore dcs event data and won't do
* interference detection algorithm calculation:
* 1: Current SAP channel isn't on 5G band
* 2: In the process of ACS
* 3: In the process of dcs disabling dcs_restart_delay time duration
*/
if (!dcs_host_params.dcs_algorithm_process)
goto copy_stats;
/*
* Unusable channel utilization is amount of time that we
* spent in backoff or waiting for other transmit/receive to
* complete. If there is interference it is more likely that
* we overshoot the limit. In case of multiple stations, we
* still see increased channel utilization. This assumption may
* not be true for the VOW scenario where either multicast or
* unicast-UDP is used ( mixed traffic would still cause high
* channel utilization).
*/
wasted_tx_cu = ((curr_stats->tx_waste_time >> 8) * 100) /
scaled_reg_tsf_delta;
/*
* Transmit channel utilization cannot go higher than the amount of time
* wasted, if so cap the wastage to transmit channel utillzation. This
* could happen to compution error.
*/
if (reg_tx_cu < wasted_tx_cu)
wasted_tx_cu = reg_tx_cu;
tx_err = (reg_tx_cu && wasted_tx_cu) ?
(wasted_tx_cu * 100) / reg_tx_cu : 0;
/*
* The below actually gives amount of time we are not using, or the
* interferer is active.
* rx_time_cu is what computed receive time *NOT* rx_cycle_count
* rx_cycle_count is our receive+interferer's transmit
* un-used is really total_cycle_counts -
* (our_rx_time(rx_time_cu) + our_receive_time)
*/
reg_unused_cu = (reg_total_cu >= (reg_tx_cu + rx_time_cu)) ?
(reg_total_cu - (reg_tx_cu + rx_time_cu)) : 0;
/* If any retransmissions are there, count them as wastage */
total_wasted_cu = reg_unused_cu + wasted_tx_cu;
/* Check ofdm and cck errors */
if (unlikely(curr_stats->mib_stats.reg_ofdm_phyerr_cnt <
prev_stats->mib_stats.reg_ofdm_phyerr_cnt))
reg_ofdm_phyerr_delta =
curr_stats->mib_stats.reg_ofdm_phyerr_cnt;
else
reg_ofdm_phyerr_delta =
curr_stats->mib_stats.reg_ofdm_phyerr_cnt -
prev_stats->mib_stats.reg_ofdm_phyerr_cnt;
if (unlikely(curr_stats->mib_stats.reg_cck_phyerr_cnt <
prev_stats->mib_stats.reg_cck_phyerr_cnt))
reg_cck_phyerr_delta = curr_stats->mib_stats.reg_cck_phyerr_cnt;
else
reg_cck_phyerr_delta =
curr_stats->mib_stats.reg_cck_phyerr_cnt -
prev_stats->mib_stats.reg_cck_phyerr_cnt;
/*
* Add the influence of ofdm phy errors to the wasted channel
* utillization, this computed through time wasted in errors
*/
reg_ofdm_phyerr_cu = reg_ofdm_phyerr_delta *
dcs_host_params.phy_err_penalty;
total_wasted_cu +=
(reg_ofdm_phyerr_cu > 0) ?
(((reg_ofdm_phyerr_cu >> 8) * 100) / scaled_reg_tsf_delta) : 0;
ofdm_phy_err_rate = (curr_stats->mib_stats.reg_ofdm_phyerr_cnt * 1000) /
curr_stats->mib_stats.listen_time;
cck_phy_err_rate = (curr_stats->mib_stats.reg_cck_phyerr_cnt * 1000) /
curr_stats->mib_stats.listen_time;
if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) {
dcs_debug("reg_unused_cu: %u, reg_ofdm_phyerr_delta: %u, reg_cck_phyerr_delta: %u, reg_ofdm_phyerr_cu: %u",
reg_unused_cu, reg_ofdm_phyerr_delta,
reg_cck_phyerr_delta, reg_ofdm_phyerr_cu);
dcs_debug("total_wasted_cu: %u, ofdm_phy_err_rate: %u, cck_phy_err_rate: %u",
total_wasted_cu, ofdm_phy_err_rate, cck_phy_err_rate);
dcs_debug("new_unused_cu: %u, reg_ofdm_phy_error_cu: %u",
reg_unused_cu,
(curr_stats->mib_stats.reg_ofdm_phyerr_cnt * 100) /
curr_stats->mib_stats.listen_time);
}
/* Check if the error rates are higher than the thresholds */
max_phy_err_rate = QDF_MAX(ofdm_phy_err_rate, cck_phy_err_rate);
max_phy_err_count = QDF_MAX(curr_stats->mib_stats.reg_ofdm_phyerr_cnt,
curr_stats->mib_stats.reg_cck_phyerr_cnt);
if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE))
dcs_debug("max_phy_err_rate: %u, max_phy_err_count: %u",
max_phy_err_rate, max_phy_err_count);
if (((max_phy_err_rate >= dcs_host_params.phy_err_threshold) &&
(max_phy_err_count > dcs_host_params.phy_err_threshold)) ||
(curr_stats->phyerr_cnt > dcs_host_params.radar_err_threshold))
too_many_phy_errors = 1;
if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_CRITICAL)) {
dcs_debug("total_cu: %u, tx_cu: %u, rx_cu: %u, rx_time_cu: %u, unused cu: %u",
reg_total_cu, reg_tx_cu,
reg_rx_cu, rx_time_cu, reg_unused_cu);
dcs_debug("phyerr: %u, total_wasted_cu: %u, phyerror_cu: %u, wasted_cu: %u, reg_tx_cu: %u, reg_rx_cu: %u",
too_many_phy_errors, total_wasted_cu,
reg_ofdm_phyerr_cu, wasted_tx_cu,
reg_tx_cu, reg_rx_cu);
dcs_debug("tx_err: %u", tx_err);
}
if (reg_unused_cu >= dcs_host_params.coch_intfr_threshold)
/* Quickly reach to decision */
p_dcs_im_stats->im_intfr_cnt += 2;
else if (too_many_phy_errors &&
(((total_wasted_cu >
(dcs_host_params.coch_intfr_threshold + 10)) &&
((reg_tx_cu + reg_rx_cu) > dcs_host_params.user_max_cu)) ||
((reg_tx_cu > DCS_TX_MAX_CU) &&
(tx_err >= dcs_host_params.tx_err_threshold))))
p_dcs_im_stats->im_intfr_cnt++;
if (p_dcs_im_stats->im_intfr_cnt >=
dcs_host_params.intfr_detection_threshold) {
if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_CRITICAL)) {
dcs_debug("interference threshold exceeded");
dcs_debug("unused_cu: %u, too_any_phy_errors: %u, total_wasted_cu: %u, reg_tx_cu: %u, reg_rx_cu: %u",
reg_unused_cu, too_many_phy_errors,
total_wasted_cu, reg_tx_cu, reg_rx_cu);
}
p_dcs_im_stats->im_intfr_cnt = 0;
p_dcs_im_stats->im_samp_cnt = 0;
/*
* Once the interference is detected, change the channel, as on
* today this is common routine for wirelesslan and
* non-wirelesslan interference. Name as such kept the same
* because of the DA code, which is using the same function.
*/
start_dcs_cbk_handler = true;
} else if (0 == p_dcs_im_stats->im_intfr_cnt ||
p_dcs_im_stats->im_samp_cnt >=
dcs_host_params.intfr_detection_window) {
p_dcs_im_stats->im_intfr_cnt = 0;
p_dcs_im_stats->im_samp_cnt = 0;
}
/* Count the current run too */
p_dcs_im_stats->im_samp_cnt++;
if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE))
dcs_debug("intfr_count: %u, sample_count: %u",
p_dcs_im_stats->im_intfr_cnt,
p_dcs_im_stats->im_samp_cnt);
copy_stats:
/* Copy the stats for next cycle */
wlan_dcs_im_copy_stats(prev_stats, curr_stats);
end:
return start_dcs_cbk_handler;
}
请详细分析这个函数,它是如何评估干扰和信道利用率的?