// SPDX-License-Identifier: GPL-2.0-only /****************************************************************************** * * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2015 Intel Deutschland GmbH * Copyright(c) 2018, 2020-2021, 2025 Intel Corporation * * Portions of this file are derived from the ipw3945 project, as well * as portionhelp of the ieee80211 subsystem header files.
*****************************************************************************/
/* * iwl_good_plcp_health - checks for plcp error. * * When the plcp error is exceeding the thresholds, reset the radio * to improve the throughput.
*/ staticbool iwlagn_good_plcp_health(struct iwl_priv *priv, struct statistics_rx_phy *cur_ofdm, struct statistics_rx_ht_phy *cur_ofdm_ht, unsignedint msecs)
{ int delta; int threshold = priv->plcp_delta_threshold;
/* * There is no easy and better way to force reset the radio, * the only known method is switching channel which will force to * reset and tune the radio. * Use internal short scan (single channel) operation to should * achieve this objective. * Driver should reset the radio when number of consecutive missed * beacon, or any other uCode error condition detected.
*/
IWL_DEBUG_INFO(priv, "perform radio reset.\n");
iwl_internal_short_hw_scan(priv); return 0;
}
/* Only gather statistics and update time stamp when not associated */ if (!iwl_is_any_associated(priv)) return;
/* Do not check/recover when do not have enough statistics data */ if (msecs < 99) return;
if (!iwlagn_good_plcp_health(priv, cur_ofdm, cur_ofdm_ht, msecs))
iwl_force_rf_reset(priv, false);
}
/* Calculate noise level, based on measurements during network silence just * before arriving beacon. This measurement can be done only if we know
* exactly when to expect beacons, therefore only when we're associated. */ staticvoid iwlagn_rx_calc_noise(struct iwl_priv *priv)
{ struct statistics_rx_non_phy *rx_info; int num_active_rx = 0; int total_silence = 0; int bcn_silence_a, bcn_silence_b, bcn_silence_c; int last_rx_noise;
if (bcn_silence_a) {
total_silence += bcn_silence_a;
num_active_rx++;
} if (bcn_silence_b) {
total_silence += bcn_silence_b;
num_active_rx++;
} if (bcn_silence_c) {
total_silence += bcn_silence_c;
num_active_rx++;
}
/* Average among active antennas */ if (num_active_rx)
last_rx_noise = (total_silence / num_active_rx) - 107; else
last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
IWL_DEBUG_CALIB(priv, "inband silence a %u, b %u, c %u, dBm %d\n",
bcn_silence_a, bcn_silence_b, bcn_silence_c,
last_rx_noise);
}
#ifdef CONFIG_IWLWIFI_DEBUGFS /* * based on the assumption of all statistics counter are in DWORD * FIXME: This function is for debugging, do not deal with * the case of counters roll-over.
*/ staticvoid accum_stats(__le32 *prev, __le32 *cur, __le32 *delta,
__le32 *max_delta, __le32 *accum, int size)
{ int i;
for (i = 0;
i < size / sizeof(__le32);
i++, prev++, cur++, delta++, max_delta++, accum++) { if (le32_to_cpu(*cur) > le32_to_cpu(*prev)) {
*delta = cpu_to_le32(
le32_to_cpu(*cur) - le32_to_cpu(*prev));
le32_add_cpu(accum, le32_to_cpu(*delta)); if (le32_to_cpu(*delta) > le32_to_cpu(*max_delta))
*max_delta = *delta;
}
}
}
/* Reschedule the statistics timer to occur in * reg_recalib_period seconds to ensure we get a * thermal update even if the uCode doesn't give
* us one */
mod_timer(&priv->statistics_periodic, jiffies +
secs_to_jiffies(reg_recalib_period));
if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) &&
(pkt->hdr.cmd == STATISTICS_NOTIFICATION)) {
iwlagn_rx_calc_noise(priv);
queue_work(priv->workqueue, &priv->run_time_calib_work);
} if (priv->lib->temperature && change)
priv->lib->temperature(priv);
if (le32_to_cpu(stats->flag) & UCODE_STATISTICS_CLEAR_MSK) { #ifdef CONFIG_IWLWIFI_DEBUGFS
memset(&priv->accum_stats, 0, sizeof(priv->accum_stats));
memset(&priv->delta_stats, 0, sizeof(priv->delta_stats));
memset(&priv->max_delta_stats, 0, sizeof(priv->max_delta_stats)); #endif
IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
}
iwlagn_rx_statistics(priv, rxb);
}
/* Handle notification from uCode that card's power state is changing
* due to software, hardware, or critical temperature RFKILL */ staticvoid iwlagn_rx_card_state_notif(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb)
{ struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_card_state_notif *card_state_notif = (void *)pkt->data;
u32 flags = le32_to_cpu(card_state_notif->flags); unsignedlong status = priv->status;
/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD).
* This will be used later in iwl_rx_reply_rx() for REPLY_RX_MPDU_CMD. */ staticvoid iwlagn_rx_reply_rx_phy(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb)
{ struct iwl_rx_packet *pkt = rxb_addr(rxb);
/* * returns non-zero if packet should be dropped
*/ staticint iwlagn_set_decrypted_flag(struct iwl_priv *priv, struct ieee80211_hdr *hdr,
u32 decrypt_res, struct ieee80211_rx_status *stats)
{
u16 fc = le16_to_cpu(hdr->frame_control);
/* * All contexts have the same setting here due to it being * a module parameter, so OK to check any context.
*/ if (priv->contexts[IWL_RXON_CTX_BSS].active.filter_flags &
RXON_FILTER_DIS_DECRYPT_MSK) return 0;
if (!(fc & IEEE80211_FCTL_PROTECTED)) return 0;
IWL_DEBUG_RX(priv, "decrypt_res:0x%x\n", decrypt_res); switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) { case RX_RES_STATUS_SEC_TYPE_TKIP: /* The uCode has got a bad phase 1 Key, pushes the packet.
* Decryption will be done in SW. */ if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
RX_RES_STATUS_BAD_KEY_TTAK) break;
fallthrough; case RX_RES_STATUS_SEC_TYPE_WEP: if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
RX_RES_STATUS_BAD_ICV_MIC) { /* bad ICV, the packet is destroyed since the
* decryption is inplace, drop it */
IWL_DEBUG_RX(priv, "Packet destroyed\n"); return -1;
}
fallthrough; case RX_RES_STATUS_SEC_TYPE_CCMP: if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
RX_RES_STATUS_DECRYPT_OK) {
IWL_DEBUG_RX(priv, "hw decrypt successfully!!!\n");
stats->flag |= RX_FLAG_DECRYPTED;
} break;
/* We only process data packets if the interface is open */ if (unlikely(!priv->is_open)) {
IWL_DEBUG_DROP_LIMIT(priv, "Dropping packet while interface is not open.\n"); return;
}
/* In case of HW accelerated crypto and bad decryption, drop */ if (!iwlwifi_mod_params.swcrypto &&
iwlagn_set_decrypted_flag(priv, hdr, ampdu_status, stats)) return;
/* Dont use dev_alloc_skb(), we'll have enough headroom once * ieee80211_hdr pulled.
*/
skb = alloc_skb(128, GFP_ATOMIC); if (!skb) {
IWL_ERR(priv, "alloc_skb failed\n"); return;
} /* If frame is small enough to fit in skb->head, pull it completely. * If not, only pull ieee80211_hdr so that splice() or TCP coalesce * are more efficient.
*/
hdrlen = (len <= skb_tailroom(skb)) ? len : sizeof(*hdr);
skb_put_data(skb, hdr, hdrlen);
fraglen = len - hdrlen;
if (fraglen) { int offset = (u8 *)hdr + hdrlen -
(u8 *)rxb_addr(rxb) + rxb_offset(rxb);
/* * Wake any queues that were stopped due to a passive channel tx * failure. This can happen because the regulatory enforcement in * the device waits for a beacon before allowing transmission, * sometimes even after already having transmitted frames for the * association because the new RXON may reset the information.
*/ if (unlikely(ieee80211_is_beacon(fc) && priv->passive_no_rx)) {
for_each_context(priv, ctx) { if (!ether_addr_equal(hdr->addr3,
ctx->active.bssid_addr)) continue;
iwlagn_lift_passive_no_rx(priv);
}
}
case RX_RES_STATUS_SEC_TYPE_CCMP: /* alg is CCM: check MIC only */ if (!(decrypt_in & RX_MPDU_RES_STATUS_MIC_OK)) /* Bad MIC */
decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; else
decrypt_out |= RX_RES_STATUS_DECRYPT_OK;
break;
case RX_RES_STATUS_SEC_TYPE_TKIP: if (!(decrypt_in & RX_MPDU_RES_STATUS_TTAK_OK)) { /* Bad TTAK */
decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK; break;
}
fallthrough; default: if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK))
decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; else
decrypt_out |= RX_RES_STATUS_DECRYPT_OK; break;
}
/* Calc max signal level (dBm) among 3 possible receivers */ staticint iwlagn_calc_rssi(struct iwl_priv *priv, struct iwl_rx_phy_res *rx_resp)
{ /* data from PHY/DSP regarding signal strength, etc., * contents are always there, not configurable by host
*/ struct iwlagn_non_cfg_phy *ncphy =
(struct iwlagn_non_cfg_phy *)rx_resp->non_cfg_phy_buf;
u32 val, rssi_a, rssi_b, rssi_c, max_rssi;
u8 agc;
val = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_AGC_IDX]);
agc = (val & IWLAGN_OFDM_AGC_MSK) >> IWLAGN_OFDM_AGC_BIT_POS;
/* Find max rssi among 3 possible receivers. * These values are measured by the digital signal processor (DSP). * They should stay fairly constant even as the signal strength varies, * if the radio's automatic gain control (AGC) is working right. * AGC value (see below) will provide the "interesting" info.
*/
val = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_RSSI_AB_IDX]);
rssi_a = (val & IWLAGN_OFDM_RSSI_INBAND_A_BITMSK) >>
IWLAGN_OFDM_RSSI_A_BIT_POS;
rssi_b = (val & IWLAGN_OFDM_RSSI_INBAND_B_BITMSK) >>
IWLAGN_OFDM_RSSI_B_BIT_POS;
val = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_RSSI_C_IDX]);
rssi_c = (val & IWLAGN_OFDM_RSSI_INBAND_C_BITMSK) >>
IWLAGN_OFDM_RSSI_C_BIT_POS;
if ((unlikely(phy_res->cfg_phy_cnt > 20))) {
IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d\n",
phy_res->cfg_phy_cnt); return;
}
if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) ||
!(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) {
IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n",
le32_to_cpu(rx_pkt_status)); return;
}
/* This will be used in several places later */
rate_n_flags = le32_to_cpu(phy_res->rate_n_flags);
/* rx_status carries information about the packet to mac80211 */
rx_status.mactime = le64_to_cpu(phy_res->timestamp);
rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
rx_status.freq =
ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel),
rx_status.band);
rx_status.rate_idx =
iwlagn_hwrate_to_mac80211_idx(rate_n_flags, rx_status.band);
rx_status.flag = 0;
/* TSF isn't reliable. In order to allow smooth user experience,
* this W/A doesn't propagate it to the mac80211 */ /*rx_status.flag |= RX_FLAG_MACTIME_START;*/
/* * "antenna number" * * It seems that the antenna field in the phy flags value * is actually a bit field. This is undefined by radiotap, * it wants an actual antenna number but I always get "7" * for most legacy frames I receive indicating that the * same frame was received on all three RX chains. * * I think this field should be removed in favor of a * new 802.11n radiotap field "RX chains" that is defined * as a bitmask.
*/
rx_status.antenna =
(le16_to_cpu(phy_res->phy_flags) & RX_RES_PHY_FLAGS_ANTENNA_MSK)
>> RX_RES_PHY_FLAGS_ANTENNA_POS;
/* set the preamble flag if appropriate */ if (phy_res->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
rx_status.enc_flags |= RX_ENC_FLAG_SHORTPRE;
if (phy_res->phy_flags & RX_RES_PHY_FLAGS_AGG_MSK) { /* * We know which subframes of an A-MPDU belong * together since we get a single PHY response * from the firmware for all of them
*/
rx_status.flag |= RX_FLAG_AMPDU_DETAILS;
rx_status.ampdu_reference = priv->ampdu_ref;
}
/* Set up the HT phy flags */ if (rate_n_flags & RATE_MCS_HT_MSK)
rx_status.encoding = RX_ENC_HT; if (rate_n_flags & RATE_MCS_HT40_MSK)
rx_status.bw = RATE_INFO_BW_40; else
rx_status.bw = RATE_INFO_BW_20; if (rate_n_flags & RATE_MCS_SGI_MSK)
rx_status.enc_flags |= RX_ENC_FLAG_SHORT_GI; if (rate_n_flags & RATE_MCS_GF_MSK)
rx_status.enc_flags |= RX_ENC_FLAG_HT_GF;
/* * iwl_setup_rx_handlers - Initialize Rx handler callbacks * * Setup the RX handlers for each of the reply types sent from the uCode * to the host.
*/ void iwl_setup_rx_handlers(struct iwl_priv *priv)
{ void (**handlers)(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb);
/* * The same handler is used for both the REPLY to a discrete * statistics request from the host as well as for the periodic * statistics notifications (after received beacons) from the uCode.
*/
handlers[REPLY_STATISTICS_CMD] = iwlagn_rx_reply_statistics;
handlers[STATISTICS_NOTIFICATION] = iwlagn_rx_statistics;
/* * Do the notification wait before RX handlers so * even if the RX handler consumes the RXB we have * access to it in the notification wait entry.
*/
iwl_notification_wait_notify(&priv->notif_wait, pkt);
/* Based on type of command response or notification, * handle those that need handling via function in
* rx_handlers table. See iwl_setup_rx_handlers() */ if (priv->rx_handlers[pkt->hdr.cmd]) {
priv->rx_handlers_stats[pkt->hdr.cmd]++;
priv->rx_handlers[pkt->hdr.cmd](priv, rxb);
} else { /* No handling needed */
IWL_DEBUG_RX(priv, "No handler needed for %s, 0x%02x\n",
iwl_get_cmd_string(priv->trans,
WIDE_ID(0, pkt->hdr.cmd)),
pkt->hdr.cmd);
}
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.35 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.