mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-12 21:44:06 +08:00
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: Po Hao Huang <phhuang@realtek.com> Signed-off-by: Ping-Ke Shih <pkshih@realtek.com> Signed-off-by: Kalle Valo <kvalo@kernel.org> Link: https://lore.kernel.org/r/20220225030851.13327-2-pkshih@realtek.com
This commit is contained in:
parent
e715f10f3d
commit
8959077797
@ -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 {
|
||||
|
@ -201,6 +201,10 @@ static void rtw89_fw_recognize_features(struct rtw89_dev *rtwdev)
|
||||
if (chip->chip_id == RTL8852A &&
|
||||
RTW89_FW_SUIT_VER_CODE(fw_suit) <= RTW89_FW_VER_CODE(0, 13, 29, 0))
|
||||
rtwdev->fw.old_ht_ra_format = true;
|
||||
|
||||
if (chip->chip_id == RTL8852A &&
|
||||
RTW89_FW_SUIT_VER_CODE(fw_suit) >= RTW89_FW_VER_CODE(0, 13, 35, 0))
|
||||
rtwdev->fw.scan_offload = true;
|
||||
}
|
||||
|
||||
int rtw89_fw_recognize(struct rtw89_dev *rtwdev)
|
||||
@ -1467,6 +1471,198 @@ fail:
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
#define H2C_LEN_PKT_OFLD 4
|
||||
int rtw89_fw_h2c_del_pkt_offload(struct rtw89_dev *rtwdev, u8 id)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
u8 *cmd;
|
||||
|
||||
skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_LEN_PKT_OFLD);
|
||||
if (!skb) {
|
||||
rtw89_err(rtwdev, "failed to alloc skb for h2c pkt offload\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
skb_put(skb, H2C_LEN_PKT_OFLD);
|
||||
cmd = skb->data;
|
||||
|
||||
RTW89_SET_FWCMD_PACKET_OFLD_PKT_IDX(cmd, id);
|
||||
RTW89_SET_FWCMD_PACKET_OFLD_PKT_OP(cmd, RTW89_PKT_OFLD_OP_DEL);
|
||||
|
||||
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
|
||||
H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD,
|
||||
H2C_FUNC_PACKET_OFLD, 1, 1,
|
||||
H2C_LEN_PKT_OFLD);
|
||||
|
||||
if (rtw89_h2c_tx(rtwdev, skb, false)) {
|
||||
rtw89_err(rtwdev, "failed to send h2c\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
dev_kfree_skb_any(skb);
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
int rtw89_fw_h2c_add_pkt_offload(struct rtw89_dev *rtwdev, u8 *id,
|
||||
struct sk_buff *skb_ofld)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
u8 *cmd;
|
||||
u8 alloc_id;
|
||||
|
||||
alloc_id = rtw89_core_acquire_bit_map(rtwdev->pkt_offload,
|
||||
RTW89_MAX_PKT_OFLD_NUM);
|
||||
if (alloc_id == RTW89_MAX_PKT_OFLD_NUM)
|
||||
return -ENOSPC;
|
||||
|
||||
*id = alloc_id;
|
||||
|
||||
skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_LEN_PKT_OFLD + skb_ofld->len);
|
||||
if (!skb) {
|
||||
rtw89_err(rtwdev, "failed to alloc skb for h2c pkt offload\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
skb_put(skb, H2C_LEN_PKT_OFLD);
|
||||
cmd = skb->data;
|
||||
|
||||
RTW89_SET_FWCMD_PACKET_OFLD_PKT_IDX(cmd, alloc_id);
|
||||
RTW89_SET_FWCMD_PACKET_OFLD_PKT_OP(cmd, RTW89_PKT_OFLD_OP_ADD);
|
||||
RTW89_SET_FWCMD_PACKET_OFLD_PKT_LENGTH(cmd, skb_ofld->len);
|
||||
skb_put_data(skb, skb_ofld->data, skb_ofld->len);
|
||||
|
||||
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
|
||||
H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD,
|
||||
H2C_FUNC_PACKET_OFLD, 1, 1,
|
||||
H2C_LEN_PKT_OFLD + skb_ofld->len);
|
||||
|
||||
if (rtw89_h2c_tx(rtwdev, skb, false)) {
|
||||
rtw89_err(rtwdev, "failed to send h2c\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
dev_kfree_skb_any(skb);
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
#define H2C_LEN_SCAN_LIST_OFFLOAD 4
|
||||
int rtw89_fw_h2c_scan_list_offload(struct rtw89_dev *rtwdev, int len,
|
||||
struct list_head *chan_list)
|
||||
{
|
||||
struct rtw89_mac_chinfo *ch_info;
|
||||
struct sk_buff *skb;
|
||||
int skb_len = H2C_LEN_SCAN_LIST_OFFLOAD + len * RTW89_MAC_CHINFO_SIZE;
|
||||
u8 *cmd;
|
||||
|
||||
skb = rtw89_fw_h2c_alloc_skb_with_hdr(skb_len);
|
||||
if (!skb) {
|
||||
rtw89_err(rtwdev, "failed to alloc skb for h2c scan list\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
skb_put(skb, H2C_LEN_SCAN_LIST_OFFLOAD);
|
||||
cmd = skb->data;
|
||||
|
||||
RTW89_SET_FWCMD_SCANOFLD_CH_NUM(cmd, len);
|
||||
/* in unit of 4 bytes */
|
||||
RTW89_SET_FWCMD_SCANOFLD_CH_SIZE(cmd, RTW89_MAC_CHINFO_SIZE / 4);
|
||||
|
||||
list_for_each_entry(ch_info, chan_list, list) {
|
||||
cmd = skb_put(skb, RTW89_MAC_CHINFO_SIZE);
|
||||
|
||||
RTW89_SET_FWCMD_CHINFO_PERIOD(cmd, ch_info->period);
|
||||
RTW89_SET_FWCMD_CHINFO_DWELL(cmd, ch_info->dwell_time);
|
||||
RTW89_SET_FWCMD_CHINFO_CENTER_CH(cmd, ch_info->central_ch);
|
||||
RTW89_SET_FWCMD_CHINFO_PRI_CH(cmd, ch_info->pri_ch);
|
||||
RTW89_SET_FWCMD_CHINFO_BW(cmd, ch_info->bw);
|
||||
RTW89_SET_FWCMD_CHINFO_ACTION(cmd, ch_info->notify_action);
|
||||
RTW89_SET_FWCMD_CHINFO_NUM_PKT(cmd, ch_info->num_pkt);
|
||||
RTW89_SET_FWCMD_CHINFO_TX(cmd, ch_info->tx_pkt);
|
||||
RTW89_SET_FWCMD_CHINFO_PAUSE_DATA(cmd, ch_info->pause_data);
|
||||
RTW89_SET_FWCMD_CHINFO_BAND(cmd, ch_info->ch_band);
|
||||
RTW89_SET_FWCMD_CHINFO_PKT_ID(cmd, ch_info->probe_id);
|
||||
RTW89_SET_FWCMD_CHINFO_DFS(cmd, ch_info->dfs_ch);
|
||||
RTW89_SET_FWCMD_CHINFO_TX_NULL(cmd, ch_info->tx_null);
|
||||
RTW89_SET_FWCMD_CHINFO_RANDOM(cmd, ch_info->rand_seq_num);
|
||||
RTW89_SET_FWCMD_CHINFO_PKT0(cmd, ch_info->pkt_id[0]);
|
||||
RTW89_SET_FWCMD_CHINFO_PKT1(cmd, ch_info->pkt_id[1]);
|
||||
RTW89_SET_FWCMD_CHINFO_PKT2(cmd, ch_info->pkt_id[2]);
|
||||
RTW89_SET_FWCMD_CHINFO_PKT3(cmd, ch_info->pkt_id[3]);
|
||||
RTW89_SET_FWCMD_CHINFO_PKT4(cmd, ch_info->pkt_id[4]);
|
||||
RTW89_SET_FWCMD_CHINFO_PKT5(cmd, ch_info->pkt_id[5]);
|
||||
RTW89_SET_FWCMD_CHINFO_PKT6(cmd, ch_info->pkt_id[6]);
|
||||
RTW89_SET_FWCMD_CHINFO_PKT7(cmd, ch_info->pkt_id[7]);
|
||||
}
|
||||
|
||||
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
|
||||
H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD,
|
||||
H2C_FUNC_ADD_SCANOFLD_CH, 1, 1, skb_len);
|
||||
|
||||
if (rtw89_h2c_tx(rtwdev, skb, false)) {
|
||||
rtw89_err(rtwdev, "failed to send h2c\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
dev_kfree_skb_any(skb);
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
#define H2C_LEN_SCAN_OFFLOAD 20
|
||||
int rtw89_fw_h2c_scan_offload(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_scan_option *option,
|
||||
struct rtw89_vif *rtwvif)
|
||||
{
|
||||
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
|
||||
struct sk_buff *skb;
|
||||
u8 *cmd;
|
||||
|
||||
skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_LEN_SCAN_OFFLOAD);
|
||||
if (!skb) {
|
||||
rtw89_err(rtwdev, "failed to alloc skb for h2c scan offload\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
skb_put(skb, H2C_LEN_SCAN_OFFLOAD);
|
||||
cmd = skb->data;
|
||||
|
||||
RTW89_SET_FWCMD_SCANOFLD_MACID(cmd, rtwvif->mac_id);
|
||||
RTW89_SET_FWCMD_SCANOFLD_PORT_ID(cmd, rtwvif->port);
|
||||
RTW89_SET_FWCMD_SCANOFLD_BAND(cmd, RTW89_PHY_0);
|
||||
RTW89_SET_FWCMD_SCANOFLD_OPERATION(cmd, option->enable);
|
||||
RTW89_SET_FWCMD_SCANOFLD_NOTIFY_END(cmd, true);
|
||||
RTW89_SET_FWCMD_SCANOFLD_TARGET_CH_MODE(cmd, option->target_ch_mode);
|
||||
RTW89_SET_FWCMD_SCANOFLD_START_MODE(cmd, RTW89_SCAN_IMMEDIATE);
|
||||
RTW89_SET_FWCMD_SCANOFLD_SCAN_TYPE(cmd, RTW89_SCAN_ONCE);
|
||||
if (option->target_ch_mode) {
|
||||
RTW89_SET_FWCMD_SCANOFLD_TARGET_CH_BW(cmd, scan_info->op_bw);
|
||||
RTW89_SET_FWCMD_SCANOFLD_TARGET_PRI_CH(cmd,
|
||||
scan_info->op_pri_ch);
|
||||
RTW89_SET_FWCMD_SCANOFLD_TARGET_CENTRAL_CH(cmd,
|
||||
scan_info->op_chan);
|
||||
}
|
||||
|
||||
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
|
||||
H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD,
|
||||
H2C_FUNC_SCANOFLD, 1, 1,
|
||||
H2C_LEN_SCAN_OFFLOAD);
|
||||
|
||||
if (rtw89_h2c_tx(rtwdev, skb, false)) {
|
||||
rtw89_err(rtwdev, "failed to send h2c\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
dev_kfree_skb_any(skb);
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
int rtw89_fw_h2c_rf_reg(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_fw_h2c_rf_reg_info *info,
|
||||
u16 len, u8 page)
|
||||
@ -1739,3 +1935,322 @@ void rtw89_fw_st_dbg_dump(struct rtw89_dev *rtwdev)
|
||||
|
||||
rtw89_fw_prog_cnt_dump(rtwdev);
|
||||
}
|
||||
|
||||
static void rtw89_release_pkt_list(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
struct list_head *pkt_list = rtwdev->scan_info.pkt_list;
|
||||
struct rtw89_pktofld_info *info, *tmp;
|
||||
u8 idx;
|
||||
|
||||
for (idx = RTW89_BAND_2G; idx < NUM_NL80211_BANDS; idx++) {
|
||||
if (!(rtwdev->chip->support_bands & BIT(idx)))
|
||||
continue;
|
||||
|
||||
list_for_each_entry_safe(info, tmp, &pkt_list[idx], list) {
|
||||
rtw89_fw_h2c_del_pkt_offload(rtwdev, info->id);
|
||||
rtw89_core_release_bit_map(rtwdev->pkt_offload,
|
||||
info->id);
|
||||
list_del(&info->list);
|
||||
kfree(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int rtw89_append_probe_req_ie(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_vif *rtwvif,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
|
||||
struct ieee80211_scan_ies *ies = rtwvif->scan_ies;
|
||||
struct rtw89_pktofld_info *info;
|
||||
struct sk_buff *new;
|
||||
int ret;
|
||||
u8 band;
|
||||
|
||||
for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; band++) {
|
||||
if (!(rtwdev->chip->support_bands & BIT(band)))
|
||||
continue;
|
||||
|
||||
new = skb_copy(skb, GFP_KERNEL);
|
||||
if (!new) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
skb_put_data(new, ies->ies[band], ies->len[band]);
|
||||
skb_put_data(new, ies->common_ies, ies->common_ie_len);
|
||||
|
||||
info = kzalloc(sizeof(*info), GFP_KERNEL);
|
||||
if (!info) {
|
||||
ret = -ENOMEM;
|
||||
kfree_skb(new);
|
||||
goto out;
|
||||
}
|
||||
|
||||
list_add_tail(&info->list, &scan_info->pkt_list[band]);
|
||||
ret = rtw89_fw_h2c_add_pkt_offload(rtwdev, &info->id, new);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
kfree_skb(new);
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtw89_hw_scan_update_probe_req(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_vif *rtwvif)
|
||||
{
|
||||
struct cfg80211_scan_request *req = rtwvif->scan_req;
|
||||
struct sk_buff *skb;
|
||||
u8 num = req->n_ssids, i;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
skb = ieee80211_probereq_get(rtwdev->hw, rtwvif->mac_addr,
|
||||
req->ssids[i].ssid,
|
||||
req->ssids[i].ssid_len,
|
||||
req->ie_len);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = rtw89_append_probe_req_ie(rtwdev, rtwvif, skb);
|
||||
kfree_skb(skb);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type,
|
||||
int ssid_num,
|
||||
struct rtw89_mac_chinfo *ch_info)
|
||||
{
|
||||
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
|
||||
struct rtw89_pktofld_info *info;
|
||||
u8 band, probe_count = 0;
|
||||
|
||||
ch_info->notify_action = RTW89_SCANOFLD_DEBUG_MASK;
|
||||
ch_info->dfs_ch = chan_type == RTW89_CHAN_DFS;
|
||||
ch_info->bw = RTW89_SCAN_WIDTH;
|
||||
ch_info->tx_pkt = true;
|
||||
ch_info->cfg_tx_pwr = false;
|
||||
ch_info->tx_pwr_idx = 0;
|
||||
ch_info->tx_null = false;
|
||||
ch_info->pause_data = false;
|
||||
|
||||
if (ssid_num) {
|
||||
ch_info->num_pkt = ssid_num;
|
||||
band = ch_info->ch_band;
|
||||
|
||||
list_for_each_entry(info, &scan_info->pkt_list[band], list) {
|
||||
ch_info->probe_id = info->id;
|
||||
ch_info->pkt_id[probe_count] = info->id;
|
||||
if (++probe_count >= ssid_num)
|
||||
break;
|
||||
}
|
||||
if (probe_count != ssid_num)
|
||||
rtw89_err(rtwdev, "SSID num differs from list len\n");
|
||||
}
|
||||
|
||||
switch (chan_type) {
|
||||
case RTW89_CHAN_OPERATE:
|
||||
ch_info->probe_id = RTW89_SCANOFLD_PKT_NONE;
|
||||
ch_info->central_ch = scan_info->op_chan;
|
||||
ch_info->pri_ch = scan_info->op_pri_ch;
|
||||
ch_info->ch_band = scan_info->op_band;
|
||||
ch_info->bw = scan_info->op_bw;
|
||||
ch_info->tx_null = true;
|
||||
ch_info->num_pkt = 0;
|
||||
break;
|
||||
case RTW89_CHAN_DFS:
|
||||
ch_info->period = min_t(u8, ch_info->period,
|
||||
RTW89_DFS_CHAN_TIME);
|
||||
ch_info->dwell_time = RTW89_DWELL_TIME;
|
||||
break;
|
||||
case RTW89_CHAN_ACTIVE:
|
||||
break;
|
||||
default:
|
||||
rtw89_err(rtwdev, "Channel type out of bound\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int rtw89_hw_scan_add_chan_list(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_vif *rtwvif)
|
||||
{
|
||||
struct cfg80211_scan_request *req = rtwvif->scan_req;
|
||||
struct rtw89_mac_chinfo *ch_info, *tmp;
|
||||
struct ieee80211_channel *channel;
|
||||
struct list_head chan_list;
|
||||
bool random_seq = req->flags & NL80211_SCAN_FLAG_RANDOM_SN;
|
||||
int list_len = req->n_channels, off_chan_time = 0;
|
||||
enum rtw89_chan_type type;
|
||||
int ret = 0, i;
|
||||
|
||||
INIT_LIST_HEAD(&chan_list);
|
||||
for (i = 0; i < req->n_channels; i++) {
|
||||
channel = req->channels[i];
|
||||
ch_info = kzalloc(sizeof(*ch_info), GFP_KERNEL);
|
||||
if (!ch_info) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ch_info->period = req->duration_mandatory ?
|
||||
req->duration : RTW89_CHANNEL_TIME;
|
||||
ch_info->ch_band = channel->band;
|
||||
ch_info->central_ch = channel->hw_value;
|
||||
ch_info->pri_ch = channel->hw_value;
|
||||
ch_info->rand_seq_num = random_seq;
|
||||
|
||||
if (channel->flags &
|
||||
(IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IR))
|
||||
type = RTW89_CHAN_DFS;
|
||||
else
|
||||
type = RTW89_CHAN_ACTIVE;
|
||||
rtw89_hw_scan_add_chan(rtwdev, type, req->n_ssids, ch_info);
|
||||
|
||||
if (rtwvif->net_type != RTW89_NET_TYPE_NO_LINK &&
|
||||
off_chan_time + ch_info->period > RTW89_OFF_CHAN_TIME) {
|
||||
tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
|
||||
if (!tmp) {
|
||||
ret = -ENOMEM;
|
||||
kfree(ch_info);
|
||||
goto out;
|
||||
}
|
||||
|
||||
type = RTW89_CHAN_OPERATE;
|
||||
tmp->period = req->duration_mandatory ?
|
||||
req->duration : RTW89_CHANNEL_TIME;
|
||||
rtw89_hw_scan_add_chan(rtwdev, type, 0, tmp);
|
||||
list_add_tail(&tmp->list, &chan_list);
|
||||
off_chan_time = 0;
|
||||
list_len++;
|
||||
}
|
||||
list_add_tail(&ch_info->list, &chan_list);
|
||||
off_chan_time += ch_info->period;
|
||||
}
|
||||
rtw89_fw_h2c_scan_list_offload(rtwdev, list_len, &chan_list);
|
||||
|
||||
out:
|
||||
list_for_each_entry_safe(ch_info, tmp, &chan_list, list) {
|
||||
list_del(&ch_info->list);
|
||||
kfree(ch_info);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtw89_hw_scan_prehandle(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_vif *rtwvif)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = rtw89_hw_scan_update_probe_req(rtwdev, rtwvif);
|
||||
if (ret) {
|
||||
rtw89_err(rtwdev, "Update probe request failed\n");
|
||||
goto out;
|
||||
}
|
||||
ret = rtw89_hw_scan_add_chan_list(rtwdev, rtwvif);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void rtw89_hw_scan_start(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
|
||||
struct ieee80211_scan_request *scan_req)
|
||||
{
|
||||
struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
|
||||
struct cfg80211_scan_request *req = &scan_req->req;
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
|
||||
rtwdev->scan_info.scanning_vif = vif;
|
||||
rtwvif->scan_ies = &scan_req->ies;
|
||||
rtwvif->scan_req = req;
|
||||
ieee80211_stop_queues(rtwdev->hw);
|
||||
|
||||
if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR)
|
||||
get_random_mask_addr(mac_addr, req->mac_addr,
|
||||
req->mac_addr_mask);
|
||||
else
|
||||
ether_addr_copy(mac_addr, vif->addr);
|
||||
rtw89_core_scan_start(rtwdev, rtwvif, mac_addr, true);
|
||||
|
||||
rtwdev->hal.rx_fltr &= ~B_AX_A_BCN_CHK_EN;
|
||||
rtwdev->hal.rx_fltr &= ~B_AX_A_BC;
|
||||
rtwdev->hal.rx_fltr &= ~B_AX_A_A1_MATCH;
|
||||
rtw89_write32_mask(rtwdev,
|
||||
rtw89_mac_reg_by_idx(R_AX_RX_FLTR_OPT, RTW89_MAC_0),
|
||||
B_AX_RX_FLTR_CFG_MASK,
|
||||
rtwdev->hal.rx_fltr);
|
||||
}
|
||||
|
||||
void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
|
||||
bool aborted)
|
||||
{
|
||||
struct cfg80211_scan_info info = {
|
||||
.aborted = aborted,
|
||||
};
|
||||
struct rtw89_vif *rtwvif;
|
||||
|
||||
if (!vif)
|
||||
return;
|
||||
|
||||
rtwdev->hal.rx_fltr |= B_AX_A_BCN_CHK_EN;
|
||||
rtwdev->hal.rx_fltr |= B_AX_A_BC;
|
||||
rtwdev->hal.rx_fltr |= B_AX_A_A1_MATCH;
|
||||
rtw89_write32_mask(rtwdev,
|
||||
rtw89_mac_reg_by_idx(R_AX_RX_FLTR_OPT, RTW89_MAC_0),
|
||||
B_AX_RX_FLTR_CFG_MASK,
|
||||
rtwdev->hal.rx_fltr);
|
||||
|
||||
rtw89_core_scan_complete(rtwdev, vif, true);
|
||||
ieee80211_scan_completed(rtwdev->hw, &info);
|
||||
ieee80211_wake_queues(rtwdev->hw);
|
||||
|
||||
rtw89_release_pkt_list(rtwdev);
|
||||
rtwvif = (struct rtw89_vif *)vif->drv_priv;
|
||||
rtwvif->scan_req = NULL;
|
||||
rtwvif->scan_ies = NULL;
|
||||
rtwdev->scan_info.scanning_vif = NULL;
|
||||
}
|
||||
|
||||
void rtw89_hw_scan_abort(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif)
|
||||
{
|
||||
rtw89_hw_scan_offload(rtwdev, vif, false);
|
||||
rtw89_hw_scan_complete(rtwdev, vif, true);
|
||||
}
|
||||
|
||||
int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
|
||||
bool enable)
|
||||
{
|
||||
struct rtw89_scan_option opt = {0};
|
||||
struct rtw89_vif *rtwvif;
|
||||
int ret = 0;
|
||||
|
||||
rtwvif = vif ? (struct rtw89_vif *)vif->drv_priv : NULL;
|
||||
if (!rtwvif)
|
||||
return -EINVAL;
|
||||
|
||||
opt.enable = enable;
|
||||
opt.target_ch_mode = rtwvif->net_type != RTW89_NET_TYPE_NO_LINK;
|
||||
if (enable) {
|
||||
ret = rtw89_hw_scan_prehandle(rtwdev, rtwvif);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
rtw89_fw_h2c_scan_offload(rtwdev, &opt, rtwvif);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void rtw89_store_op_chan(struct rtw89_dev *rtwdev)
|
||||
{
|
||||
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
|
||||
struct rtw89_hal *hal = &rtwdev->hal;
|
||||
|
||||
scan_info->op_pri_ch = hal->current_primary_channel;
|
||||
scan_info->op_chan = hal->current_channel;
|
||||
scan_info->op_bw = hal->current_band_width;
|
||||
scan_info->op_band = hal->current_band_type;
|
||||
}
|
||||
|
@ -123,6 +123,27 @@ enum rtw89_fw_log_comp {
|
||||
RTW89_FW_LOG_COMP_MCC = 20,
|
||||
};
|
||||
|
||||
enum rtw89_pkt_offload_op {
|
||||
RTW89_PKT_OFLD_OP_ADD,
|
||||
RTW89_PKT_OFLD_OP_DEL,
|
||||
RTW89_PKT_OFLD_OP_READ,
|
||||
};
|
||||
|
||||
enum rtw89_scanofld_notify_reason {
|
||||
RTW89_SCAN_DWELL_NOTIFY,
|
||||
RTW89_SCAN_PRE_TX_NOTIFY,
|
||||
RTW89_SCAN_POST_TX_NOTIFY,
|
||||
RTW89_SCAN_ENTER_CH_NOTIFY,
|
||||
RTW89_SCAN_LEAVE_CH_NOTIFY,
|
||||
RTW89_SCAN_END_SCAN_NOTIFY,
|
||||
};
|
||||
|
||||
enum rtw89_chan_type {
|
||||
RTW89_CHAN_OPERATE = 0,
|
||||
RTW89_CHAN_ACTIVE,
|
||||
RTW89_CHAN_DFS,
|
||||
};
|
||||
|
||||
#define FWDL_SECTION_MAX_NUM 10
|
||||
#define FWDL_SECTION_CHKSUM_LEN 8
|
||||
#define FWDL_SECTION_PER_PKT_LEN 2020
|
||||
@ -156,6 +177,50 @@ struct rtw89_h2creg_sch_tx_en {
|
||||
u16 rsvd:15;
|
||||
} __packed;
|
||||
|
||||
#define RTW89_CHANNEL_TIME 45
|
||||
#define RTW89_DFS_CHAN_TIME 105
|
||||
#define RTW89_OFF_CHAN_TIME 100
|
||||
#define RTW89_DWELL_TIME 20
|
||||
#define RTW89_SCAN_WIDTH 0
|
||||
#define RTW89_SCANOFLD_MAX_SSID 8
|
||||
#define RTW89_SCANOFLD_MAX_IE_LEN 512
|
||||
#define RTW89_SCANOFLD_PKT_NONE 0xFF
|
||||
#define RTW89_SCANOFLD_DEBUG_MASK 0x1F
|
||||
#define RTW89_MAC_CHINFO_SIZE 20
|
||||
|
||||
struct rtw89_mac_chinfo {
|
||||
u8 period;
|
||||
u8 dwell_time;
|
||||
u8 central_ch;
|
||||
u8 pri_ch;
|
||||
u8 bw:3;
|
||||
u8 notify_action:5;
|
||||
u8 num_pkt:4;
|
||||
u8 tx_pkt:1;
|
||||
u8 pause_data:1;
|
||||
u8 ch_band:2;
|
||||
u8 probe_id;
|
||||
u8 dfs_ch:1;
|
||||
u8 tx_null:1;
|
||||
u8 rand_seq_num:1;
|
||||
u8 cfg_tx_pwr:1;
|
||||
u8 rsvd0: 4;
|
||||
u8 pkt_id[RTW89_SCANOFLD_MAX_SSID];
|
||||
u16 tx_pwr_idx;
|
||||
u8 rsvd1;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct rtw89_scan_option {
|
||||
bool enable;
|
||||
bool target_ch_mode;
|
||||
};
|
||||
|
||||
struct rtw89_pktofld_info {
|
||||
struct list_head list;
|
||||
u8 id;
|
||||
};
|
||||
|
||||
static inline void RTW89_SET_FWCMD_RA_IS_DIS(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(0));
|
||||
@ -1436,6 +1501,14 @@ enum rtw89_btc_cxdrvinfo {
|
||||
CXDRVINFO_MAX,
|
||||
};
|
||||
|
||||
enum rtw89_scan_mode {
|
||||
RTW89_SCAN_IMMEDIATE,
|
||||
};
|
||||
|
||||
enum rtw89_scan_type {
|
||||
RTW89_SCAN_ONCE,
|
||||
};
|
||||
|
||||
static inline void RTW89_SET_FWCMD_CXHDR_TYPE(void *cmd, u8 val)
|
||||
{
|
||||
u8p_replace_bits((u8 *)(cmd) + 0, val, GENMASK(7, 0));
|
||||
@ -1706,6 +1779,242 @@ static inline void RTW89_SET_FWCMD_CXRFK_TYPE(void *cmd, u32 val)
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 2), val, GENMASK(17, 10));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_PACKET_OFLD_PKT_IDX(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd)), val, GENMASK(7, 0));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_PACKET_OFLD_PKT_OP(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd)), val, GENMASK(10, 8));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_PACKET_OFLD_PKT_LENGTH(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd)), val, GENMASK(31, 16));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_SCANOFLD_CH_NUM(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd)), val, GENMASK(7, 0));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_SCANOFLD_CH_SIZE(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd)), val, GENMASK(15, 8));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_CHINFO_PERIOD(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd)), val, GENMASK(7, 0));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_CHINFO_DWELL(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd)), val, GENMASK(15, 8));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_CHINFO_CENTER_CH(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd)), val, GENMASK(23, 16));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_CHINFO_PRI_CH(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd)), val, GENMASK(31, 24));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_CHINFO_BW(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, GENMASK(2, 0));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_CHINFO_ACTION(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, GENMASK(7, 3));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_CHINFO_NUM_PKT(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, GENMASK(11, 8));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_CHINFO_TX(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, BIT(12));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_CHINFO_PAUSE_DATA(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, BIT(13));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_CHINFO_BAND(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, GENMASK(15, 14));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_CHINFO_PKT_ID(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, GENMASK(23, 16));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_CHINFO_DFS(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, BIT(24));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_CHINFO_TX_NULL(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, BIT(25));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_CHINFO_RANDOM(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, BIT(26));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_CHINFO_CFG_TX(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, BIT(27));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_CHINFO_PKT0(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 8), val, GENMASK(7, 0));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_CHINFO_PKT1(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 8), val, GENMASK(15, 8));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_CHINFO_PKT2(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 8), val, GENMASK(23, 16));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_CHINFO_PKT3(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 8), val, GENMASK(31, 24));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_CHINFO_PKT4(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 12), val, GENMASK(7, 0));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_CHINFO_PKT5(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 12), val, GENMASK(15, 8));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_CHINFO_PKT6(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 12), val, GENMASK(23, 16));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_CHINFO_PKT7(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 12), val, GENMASK(31, 24));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_CHINFO_POWER_IDX(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 16), val, GENMASK(15, 0));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_SCANOFLD_MACID(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd)), val, GENMASK(7, 0));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_SCANOFLD_NORM_CY(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd)), val, GENMASK(15, 8));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_SCANOFLD_PORT_ID(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd)), val, GENMASK(18, 16));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_SCANOFLD_BAND(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd)), val, BIT(19));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_SCANOFLD_OPERATION(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd)), val, GENMASK(21, 20));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_SCANOFLD_TARGET_CH_BAND(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd)), val, GENMASK(23, 22));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_SCANOFLD_NOTIFY_END(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, BIT(0));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_SCANOFLD_TARGET_CH_MODE(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, BIT(1));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_SCANOFLD_START_MODE(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, BIT(2));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_SCANOFLD_SCAN_TYPE(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, GENMASK(4, 3));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_SCANOFLD_TARGET_CH_BW(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, GENMASK(7, 5));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_SCANOFLD_TARGET_PRI_CH(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, GENMASK(15, 8));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_SCANOFLD_TARGET_CENTRAL_CH(void *cmd,
|
||||
u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, GENMASK(23, 16));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_SCANOFLD_PROBE_REQ_PKT_ID(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, GENMASK(31, 24));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_SCANOFLD_NORM_PD(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 8), val, GENMASK(15, 0));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_SCANOFLD_SLOW_PD(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 8), val, GENMASK(23, 16));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_SCANOFLD_TSF_HIGH(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 12), val, GENMASK(31, 0));
|
||||
}
|
||||
|
||||
static inline void RTW89_SET_FWCMD_SCANOFLD_TSF_SLOW(void *cmd, u32 val)
|
||||
{
|
||||
le32p_replace_bits((__le32 *)((u8 *)(cmd) + 16), val, GENMASK(31, 0));
|
||||
}
|
||||
|
||||
#define RTW89_C2H_HEADER_LEN 8
|
||||
|
||||
#define RTW89_GET_C2H_CATEGORY(c2h) \
|
||||
@ -1762,6 +2071,26 @@ static inline void RTW89_SET_FWCMD_CXRFK_TYPE(void *cmd, u32 val)
|
||||
#define RTW89_MK_HT_RATE(nss, mcs) (FIELD_PREP(GENMASK(4, 3), nss) | \
|
||||
FIELD_PREP(GENMASK(2, 0), mcs))
|
||||
|
||||
#define RTW89_GET_MAC_C2H_PKTOFLD_ID(c2h) \
|
||||
le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(7, 0))
|
||||
#define RTW89_GET_MAC_C2H_PKTOFLD_OP(c2h) \
|
||||
le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(10, 8))
|
||||
#define RTW89_GET_MAC_C2H_PKTOFLD_LEN(c2h) \
|
||||
le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(31, 16))
|
||||
|
||||
#define RTW89_GET_MAC_C2H_SCANOFLD_PRI_CH(c2h) \
|
||||
le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(7, 0))
|
||||
#define RTW89_GET_MAC_C2H_SCANOFLD_RSP(c2h) \
|
||||
le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(19, 16))
|
||||
#define RTW89_GET_MAC_C2H_SCANOFLD_STATUS(c2h) \
|
||||
le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(23, 20))
|
||||
#define RTW89_GET_MAC_C2H_SCANOFLD_TX_FAIL(c2h) \
|
||||
le32_get_bits(*((const __le32 *)(c2h) + 5), GENMASK(3, 0))
|
||||
#define RTW89_GET_MAC_C2H_SCANOFLD_AIR_DENSITY(c2h) \
|
||||
le32_get_bits(*((const __le32 *)(c2h) + 5), GENMASK(7, 4))
|
||||
#define RTW89_GET_MAC_C2H_SCANOFLD_BAND(c2h) \
|
||||
le32_get_bits(*((const __le32 *)(c2h) + 5), GENMASK(25, 24))
|
||||
|
||||
#define RTW89_FW_HDR_SIZE 32
|
||||
#define RTW89_FW_SECTION_HDR_SIZE 16
|
||||
|
||||
@ -1842,9 +2171,12 @@ struct rtw89_fw_h2c_rf_reg_info {
|
||||
|
||||
/* CLASS 9 - FW offload */
|
||||
#define H2C_CL_MAC_FW_OFLD 0x9
|
||||
#define H2C_FUNC_PACKET_OFLD 0x1
|
||||
#define H2C_FUNC_MAC_MACID_PAUSE 0x8
|
||||
#define H2C_FUNC_USR_EDCA 0xF
|
||||
#define H2C_FUNC_OFLD_CFG 0x14
|
||||
#define H2C_FUNC_ADD_SCANOFLD_CH 0x16
|
||||
#define H2C_FUNC_SCANOFLD 0x17
|
||||
|
||||
/* CLASS 10 - Security CAM */
|
||||
#define H2C_CL_MAC_SEC_CAM 0xa
|
||||
@ -1900,6 +2232,14 @@ int rtw89_fw_h2c_cxdrv_init(struct rtw89_dev *rtwdev);
|
||||
int rtw89_fw_h2c_cxdrv_role(struct rtw89_dev *rtwdev);
|
||||
int rtw89_fw_h2c_cxdrv_ctrl(struct rtw89_dev *rtwdev);
|
||||
int rtw89_fw_h2c_cxdrv_rfk(struct rtw89_dev *rtwdev);
|
||||
int rtw89_fw_h2c_del_pkt_offload(struct rtw89_dev *rtwdev, u8 id);
|
||||
int rtw89_fw_h2c_add_pkt_offload(struct rtw89_dev *rtwdev, u8 *id,
|
||||
struct sk_buff *skb_ofld);
|
||||
int rtw89_fw_h2c_scan_list_offload(struct rtw89_dev *rtwdev, int len,
|
||||
struct list_head *chan_list);
|
||||
int rtw89_fw_h2c_scan_offload(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_scan_option *opt,
|
||||
struct rtw89_vif *vif);
|
||||
int rtw89_fw_h2c_rf_reg(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_fw_h2c_rf_reg_info *info,
|
||||
u16 len, u8 page);
|
||||
@ -1922,5 +2262,16 @@ int rtw89_fw_msg_reg(struct rtw89_dev *rtwdev,
|
||||
struct rtw89_mac_c2h_info *c2h_info);
|
||||
int rtw89_fw_h2c_fw_log(struct rtw89_dev *rtwdev, bool enable);
|
||||
void rtw89_fw_st_dbg_dump(struct rtw89_dev *rtwdev);
|
||||
void rtw89_store_op_chan(struct rtw89_dev *rtwdev);
|
||||
void rtw89_hw_scan_start(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
|
||||
struct ieee80211_scan_request *req);
|
||||
void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
|
||||
bool aborted);
|
||||
int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
|
||||
bool enable);
|
||||
void rtw89_hw_scan_status_report(struct rtw89_dev *rtwdev, struct sk_buff *skb);
|
||||
void rtw89_hw_scan_chan_switch(struct rtw89_dev *rtwdev, struct sk_buff *skb);
|
||||
void rtw89_hw_scan_abort(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif);
|
||||
void rtw89_store_op_chan(struct rtw89_dev *rtwdev);
|
||||
|
||||
#endif
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user