Commit 89590777 authored by Po Hao Huang's avatar Po Hao Huang Committed by Kalle Valo

rtw89: 8852a: add ieee80211_ops::hw_scan

Declare this function allows us to use customized scanning policy, so
each scan takes less time. This is a similar implementation to hw_scan
in rtw88, except that we offload more items to firmware and extend the
maximum IE length. For backward compatibility, we fallback to sw_scan
when firmware does not support this feature.
Signed-off-by: default avatarPo Hao Huang <phhuang@realtek.com>
Signed-off-by: default avatarPing-Ke Shih <pkshih@realtek.com>
Signed-off-by: default avatarKalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20220225030851.13327-2-pkshih@realtek.com
parent e715f10f
......@@ -374,6 +374,7 @@ void rtw89_set_channel(struct rtw89_dev *rtwdev)
hal->current_channel = center_chan;
hal->current_freq = ch_param.center_freq;
hal->prev_primary_channel = hal->current_primary_channel;
hal->prev_band_type = hal->current_band_type;
hal->current_primary_channel = ch_param.primary_chan;
hal->current_band_type = ch_param.band_type;
hal->current_subband = ch_param.subband_type;
......@@ -1242,6 +1243,15 @@ static void rtw89_core_hw_to_sband_rate(struct ieee80211_rx_status *rx_status)
if (rx_status->band == NL80211_BAND_2GHZ ||
rx_status->encoding != RX_ENC_LEGACY)
return;
/* Some control frames' freq(ACKs in this case) are reported wrong due
* to FW notify timing, set to lowest rate to prevent overflow.
*/
if (rx_status->rate_idx < RTW89_HW_RATE_OFDM6) {
rx_status->rate_idx = 0;
return;
}
/* No 4 CCK rates for non-2G */
rx_status->rate_idx -= 4;
}
......@@ -1418,6 +1428,7 @@ static void rtw89_core_update_rx_status(struct rtw89_dev *rtwdev,
struct ieee80211_rx_status *rx_status)
{
struct ieee80211_hw *hw = rtwdev->hw;
struct rtw89_hal *hal = &rtwdev->hal;
u16 data_rate;
u8 data_rate_mode;
......@@ -1425,6 +1436,13 @@ static void rtw89_core_update_rx_status(struct rtw89_dev *rtwdev,
rx_status->freq = hw->conf.chandef.chan->center_freq;
rx_status->band = hw->conf.chandef.chan->band;
if (rtwdev->scanning && rtwdev->fw.scan_offload) {
rx_status->freq =
ieee80211_channel_to_frequency(hal->current_channel,
hal->current_band_type);
rx_status->band = rtwdev->hal.current_band_type;
}
if (desc_info->icv_err || desc_info->crc32_err)
rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
......@@ -1757,6 +1775,16 @@ static void rtw89_core_txq_schedule(struct rtw89_dev *rtwdev, u8 ac, bool *reinv
ieee80211_txq_schedule_end(hw, ac);
}
static void rtw89_ips_work(struct work_struct *work)
{
struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
ips_work);
mutex_lock(&rtwdev->mutex);
rtw89_enter_ips(rtwdev);
mutex_unlock(&rtwdev->mutex);
}
static void rtw89_core_txq_work(struct work_struct *w)
{
struct rtw89_dev *rtwdev = container_of(w, struct rtw89_dev, txq_work);
......@@ -2570,10 +2598,16 @@ int rtw89_core_init(struct rtw89_dev *rtwdev)
{
struct rtw89_btc *btc = &rtwdev->btc;
int ret;
u8 band;
INIT_LIST_HEAD(&rtwdev->ba_list);
INIT_LIST_HEAD(&rtwdev->rtwvifs_list);
INIT_LIST_HEAD(&rtwdev->early_h2c_list);
for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; band++) {
if (!(rtwdev->chip->support_bands & BIT(band)))
continue;
INIT_LIST_HEAD(&rtwdev->scan_info.pkt_list[band]);
}
INIT_WORK(&rtwdev->ba_work, rtw89_core_ba_work);
INIT_WORK(&rtwdev->txq_work, rtw89_core_txq_work);
INIT_DELAYED_WORK(&rtwdev->txq_reinvoke_work, rtw89_core_txq_reinvoke_work);
......@@ -2589,6 +2623,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev)
rtwdev->total_sta_assoc = 0;
INIT_WORK(&rtwdev->c2h_work, rtw89_fw_c2h_work);
INIT_WORK(&rtwdev->ips_work, rtw89_ips_work);
skb_queue_head_init(&rtwdev->c2h_queue);
rtw89_core_ppdu_sts_init(rtwdev);
rtw89_traffic_stats_init(rtwdev, &rtwdev->stats);
......@@ -2624,6 +2659,41 @@ void rtw89_core_deinit(struct rtw89_dev *rtwdev)
}
EXPORT_SYMBOL(rtw89_core_deinit);
void rtw89_core_scan_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
const u8 *mac_addr, bool hw_scan)
{
struct rtw89_hal *hal = &rtwdev->hal;
rtwdev->scanning = true;
rtw89_leave_lps(rtwdev);
if (hw_scan && rtwvif->net_type == RTW89_NET_TYPE_NO_LINK)
rtw89_leave_ips(rtwdev);
ether_addr_copy(rtwvif->mac_addr, mac_addr);
rtw89_btc_ntfy_scan_start(rtwdev, RTW89_PHY_0, hal->current_band_type);
rtw89_chip_rfk_scan(rtwdev, true);
rtw89_hci_recalc_int_mit(rtwdev);
rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, mac_addr);
}
void rtw89_core_scan_complete(struct rtw89_dev *rtwdev,
struct ieee80211_vif *vif, bool hw_scan)
{
struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
ether_addr_copy(rtwvif->mac_addr, vif->addr);
rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL);
rtw89_chip_rfk_scan(rtwdev, false);
rtw89_btc_ntfy_scan_finish(rtwdev, RTW89_PHY_0);
rtwdev->scanning = false;
rtwdev->dig.bypass_dig = true;
if (hw_scan && rtwvif->net_type == RTW89_NET_TYPE_NO_LINK)
ieee80211_queue_work(rtwdev->hw, &rtwdev->ips_work);
}
static void rtw89_read_chip_ver(struct rtw89_dev *rtwdev)
{
u8 cv;
......@@ -2739,6 +2809,7 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev)
ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
ieee80211_hw_set(hw, SUPPORTS_PS);
ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS);
hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP);
......@@ -2747,6 +2818,9 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev)
hw->wiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
hw->wiphy->max_scan_ssids = RTW89_SCANOFLD_MAX_SSID;
hw->wiphy->max_scan_ie_len = RTW89_SCANOFLD_MAX_IE_LEN;
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0);
ret = rtw89_core_set_supported_band(rtwdev);
......
......@@ -1991,6 +1991,8 @@ struct rtw89_vif {
struct ieee80211_tx_queue_params tx_params[IEEE80211_NUM_ACS];
struct rtw89_traffic_stats stats;
struct rtw89_phy_rate_pattern rate_pattern;
struct cfg80211_scan_request *scan_req;
struct ieee80211_scan_ies *scan_ies;
};
enum rtw89_lv1_rcvy_step {
......@@ -2373,6 +2375,7 @@ struct rtw89_fw_info {
struct rtw89_fw_suit wowlan;
bool fw_log_enable;
bool old_ht_ra_format;
bool scan_offload;
};
struct rtw89_cam_info {
......@@ -2414,6 +2417,7 @@ struct rtw89_hal {
u8 current_primary_channel;
enum rtw89_subband current_subband;
u8 current_band_width;
u8 prev_band_type;
u8 current_band_type;
u32 sw_amsdu_max_size;
u32 antenna_tx;
......@@ -2424,6 +2428,7 @@ struct rtw89_hal {
};
#define RTW89_MAX_MAC_ID_NUM 128
#define RTW89_MAX_PKT_OFLD_NUM 255
enum rtw89_flags {
RTW89_FLAG_POWERON,
......@@ -2836,11 +2841,21 @@ struct rtw89_early_h2c {
u16 h2c_len;
};
struct rtw89_hw_scan_info {
struct ieee80211_vif *scanning_vif;
struct list_head pkt_list[NUM_NL80211_BANDS];
u8 op_pri_ch;
u8 op_chan;
u8 op_bw;
u8 op_band;
};
struct rtw89_dev {
struct ieee80211_hw *hw;
struct device *dev;
bool dbcc_en;
struct rtw89_hw_scan_info scan_info;
const struct rtw89_chip_info *chip;
struct rtw89_hal hal;
struct rtw89_mac_info mac;
......@@ -2867,6 +2882,7 @@ struct rtw89_dev {
struct sk_buff_head c2h_queue;
struct work_struct c2h_work;
struct work_struct ips_work;
struct list_head early_h2c_list;
......@@ -2875,6 +2891,7 @@ struct rtw89_dev {
DECLARE_BITMAP(hw_port, RTW89_PORT_NUM);
DECLARE_BITMAP(mac_id_map, RTW89_MAX_MAC_ID_NUM);
DECLARE_BITMAP(flags, NUM_OF_RTW89_FLAGS);
DECLARE_BITMAP(pkt_offload, RTW89_MAX_PKT_OFLD_NUM);
struct rtw89_phy_stat phystat;
struct rtw89_dack_info dack;
......@@ -3491,5 +3508,9 @@ void rtw89_traffic_stats_init(struct rtw89_dev *rtwdev,
int rtw89_core_start(struct rtw89_dev *rtwdev);
void rtw89_core_stop(struct rtw89_dev *rtwdev);
void rtw89_core_update_beacon_work(struct work_struct *work);
void rtw89_core_scan_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
const u8 *mac_addr, bool hw_scan);
void rtw89_core_scan_complete(struct rtw89_dev *rtwdev,
struct ieee80211_vif *vif, bool hw_scan);
#endif
......@@ -23,6 +23,7 @@ enum rtw89_debug_mask {
RTW89_DBG_FW = BIT(12),
RTW89_DBG_BTC = BIT(13),
RTW89_DBG_BF = BIT(14),
RTW89_DBG_HW_SCAN = BIT(15),
};
enum rtw89_debug_mac_reg_sel {
......
This diff is collapsed.
This diff is collapsed.
......@@ -3129,6 +3129,57 @@ rtw89_mac_c2h_macid_pause(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len
{
}
static bool rtw89_is_op_chan(struct rtw89_dev *rtwdev, u8 band, u8 channel)
{
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
return band == scan_info->op_band && channel == scan_info->op_pri_ch;
}
static void
rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *c2h,
u32 len)
{
struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif;
struct rtw89_hal *hal = &rtwdev->hal;
u8 reason, status, tx_fail, band;
u16 chan;
tx_fail = RTW89_GET_MAC_C2H_SCANOFLD_TX_FAIL(c2h->data);
status = RTW89_GET_MAC_C2H_SCANOFLD_STATUS(c2h->data);
chan = RTW89_GET_MAC_C2H_SCANOFLD_PRI_CH(c2h->data);
reason = RTW89_GET_MAC_C2H_SCANOFLD_RSP(c2h->data);
band = RTW89_GET_MAC_C2H_SCANOFLD_BAND(c2h->data);
if (!(rtwdev->chip->support_bands & BIT(NL80211_BAND_6GHZ)))
band = chan > 14 ? RTW89_BAND_5G : RTW89_BAND_2G;
rtw89_debug(rtwdev, RTW89_DBG_HW_SCAN,
"band: %d, chan: %d, reason: %d, status: %d, tx_fail: %d\n",
band, chan, reason, status, tx_fail);
switch (reason) {
case RTW89_SCAN_LEAVE_CH_NOTIFY:
if (rtw89_is_op_chan(rtwdev, band, chan))
ieee80211_stop_queues(rtwdev->hw);
return;
case RTW89_SCAN_END_SCAN_NOTIFY:
rtw89_hw_scan_complete(rtwdev, vif, false);
break;
case RTW89_SCAN_ENTER_CH_NOTIFY:
if (rtw89_is_op_chan(rtwdev, band, chan))
ieee80211_wake_queues(rtwdev->hw);
break;
default:
return;
}
hal->prev_band_type = hal->current_band_type;
hal->prev_primary_channel = hal->current_channel;
hal->current_channel = chan;
hal->current_band_type = band;
}
static void
rtw89_mac_c2h_rec_ack(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
{
......@@ -3172,6 +3223,7 @@ void (* const rtw89_mac_c2h_ofld_handler[])(struct rtw89_dev *rtwdev,
[RTW89_MAC_C2H_FUNC_PKT_OFLD_RSP] = NULL,
[RTW89_MAC_C2H_FUNC_BCN_RESEND] = NULL,
[RTW89_MAC_C2H_FUNC_MACID_PAUSE] = rtw89_mac_c2h_macid_pause,
[RTW89_MAC_C2H_FUNC_SCANOFLD_RSP] = rtw89_mac_c2h_scanofld_rsp,
};
static
......
......@@ -301,6 +301,7 @@ enum rtw89_mac_c2h_ofld_func {
RTW89_MAC_C2H_FUNC_PKT_OFLD_RSP,
RTW89_MAC_C2H_FUNC_BCN_RESEND,
RTW89_MAC_C2H_FUNC_MACID_PAUSE,
RTW89_MAC_C2H_FUNC_SCANOFLD_RSP = 0x9,
RTW89_MAC_C2H_FUNC_OFLD_MAX,
};
......
......@@ -66,6 +66,9 @@ static int rtw89_ops_config(struct ieee80211_hw *hw, u32 changed)
{
struct rtw89_dev *rtwdev = hw->priv;
/* let previous ips work finish to ensure we don't leave ips twice */
cancel_work_sync(&rtwdev->ips_work);
mutex_lock(&rtwdev->mutex);
rtw89_leave_ps_mode(rtwdev);
......@@ -347,6 +350,13 @@ static void rtw89_ops_bss_info_changed(struct ieee80211_hw *hw,
rtw89_phy_set_bss_color(rtwdev, vif);
rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, vif);
rtw89_mac_port_update(rtwdev, rtwvif);
rtw89_store_op_chan(rtwdev);
} else {
/* Abort ongoing scan if cancel_scan isn't issued
* when disconnected by peer
*/
if (rtwdev->scanning)
rtw89_hw_scan_abort(rtwdev, vif);
}
}
......@@ -684,15 +694,9 @@ static void rtw89_ops_sw_scan_start(struct ieee80211_hw *hw,
{
struct rtw89_dev *rtwdev = hw->priv;
struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
struct rtw89_hal *hal = &rtwdev->hal;
mutex_lock(&rtwdev->mutex);
rtwdev->scanning = true;
rtw89_leave_lps(rtwdev);
rtw89_btc_ntfy_scan_start(rtwdev, RTW89_PHY_0, hal->current_band_type);
rtw89_chip_rfk_scan(rtwdev, true);
rtw89_hci_recalc_int_mit(rtwdev);
rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, mac_addr);
rtw89_core_scan_start(rtwdev, rtwvif, mac_addr, false);
mutex_unlock(&rtwdev->mutex);
}
......@@ -700,14 +704,9 @@ static void rtw89_ops_sw_scan_complete(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct rtw89_dev *rtwdev = hw->priv;
struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
mutex_lock(&rtwdev->mutex);
rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL);
rtw89_chip_rfk_scan(rtwdev, false);
rtw89_btc_ntfy_scan_finish(rtwdev, RTW89_PHY_0);
rtwdev->scanning = false;
rtwdev->dig.bypass_dig = true;
rtw89_core_scan_complete(rtwdev, vif, false);
mutex_unlock(&rtwdev->mutex);
}
......@@ -720,6 +719,46 @@ static void rtw89_ops_reconfig_complete(struct ieee80211_hw *hw,
rtw89_ser_recfg_done(rtwdev);
}
static int rtw89_ops_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_scan_request *req)
{
struct rtw89_dev *rtwdev = hw->priv;
int ret = 0;
if (!rtwdev->fw.scan_offload)
return 1;
if (rtwdev->scanning)
return -EBUSY;
mutex_lock(&rtwdev->mutex);
rtw89_hw_scan_start(rtwdev, vif, req);
ret = rtw89_hw_scan_offload(rtwdev, vif, true);
if (ret) {
rtw89_hw_scan_abort(rtwdev, vif);
rtw89_err(rtwdev, "HW scan failed with status: %d\n", ret);
}
mutex_unlock(&rtwdev->mutex);
return ret;
}
static void rtw89_ops_cancel_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct rtw89_dev *rtwdev = hw->priv;
if (!rtwdev->fw.scan_offload)
return;
if (!rtwdev->scanning)
return;
mutex_lock(&rtwdev->mutex);
rtw89_hw_scan_abort(rtwdev, vif);
mutex_unlock(&rtwdev->mutex);
}
const struct ieee80211_ops rtw89_ops = {
.tx = rtw89_ops_tx,
.wake_tx_queue = rtw89_ops_wake_tx_queue,
......@@ -746,6 +785,8 @@ const struct ieee80211_ops rtw89_ops = {
.sw_scan_start = rtw89_ops_sw_scan_start,
.sw_scan_complete = rtw89_ops_sw_scan_complete,
.reconfig_complete = rtw89_ops_reconfig_complete,
.hw_scan = rtw89_ops_hw_scan,
.cancel_hw_scan = rtw89_ops_cancel_hw_scan,
.set_sar_specs = rtw89_ops_set_sar_specs,
};
EXPORT_SYMBOL(rtw89_ops);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment