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

wifi: rtw89: split scan including lots of channels

The size limit of H2C commands is 2048. With regulatory that enables
U-NII-6 ~ UNII-8 channels, channel list length combining with channel info
length will exceed that. Split the channel list to parts and do scan
multiple times to workaround that.
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/20220908051257.25353-10-pkshih@realtek.com
parent 3a1e7cb1
...@@ -3318,6 +3318,7 @@ struct rtw89_hw_scan_info { ...@@ -3318,6 +3318,7 @@ struct rtw89_hw_scan_info {
u8 op_chan; u8 op_chan;
u8 op_bw; u8 op_bw;
u8 op_band; u8 op_band;
u32 last_chan_idx;
}; };
enum rtw89_phy_bb_gain_band { enum rtw89_phy_bb_gain_band {
...@@ -3744,6 +3745,16 @@ static inline struct ieee80211_vif *rtwvif_to_vif(struct rtw89_vif *rtwvif) ...@@ -3744,6 +3745,16 @@ static inline struct ieee80211_vif *rtwvif_to_vif(struct rtw89_vif *rtwvif)
return container_of(p, struct ieee80211_vif, drv_priv); return container_of(p, struct ieee80211_vif, drv_priv);
} }
static inline struct ieee80211_vif *rtwvif_to_vif_safe(struct rtw89_vif *rtwvif)
{
return rtwvif ? rtwvif_to_vif(rtwvif) : NULL;
}
static inline struct rtw89_vif *vif_to_rtwvif_safe(struct ieee80211_vif *vif)
{
return vif ? (struct rtw89_vif *)vif->drv_priv : NULL;
}
static inline struct ieee80211_sta *rtwsta_to_sta(struct rtw89_sta *rtwsta) static inline struct ieee80211_sta *rtwsta_to_sta(struct rtw89_sta *rtwsta)
{ {
void *p = rtwsta; void *p = rtwsta;
......
...@@ -2451,13 +2451,16 @@ static int rtw89_hw_scan_add_chan_list(struct rtw89_dev *rtwdev, ...@@ -2451,13 +2451,16 @@ static int rtw89_hw_scan_add_chan_list(struct rtw89_dev *rtwdev,
struct ieee80211_channel *channel; struct ieee80211_channel *channel;
struct list_head chan_list; struct list_head chan_list;
bool random_seq = req->flags & NL80211_SCAN_FLAG_RANDOM_SN; bool random_seq = req->flags & NL80211_SCAN_FLAG_RANDOM_SN;
int list_len = req->n_channels, off_chan_time = 0; int list_len, off_chan_time = 0;
enum rtw89_chan_type type; enum rtw89_chan_type type;
int ret = 0, i; int ret = 0;
u32 idx;
INIT_LIST_HEAD(&chan_list); INIT_LIST_HEAD(&chan_list);
for (i = 0; i < req->n_channels; i++) { for (idx = rtwdev->scan_info.last_chan_idx, list_len = 0;
channel = req->channels[i]; idx < req->n_channels && list_len < RTW89_SCAN_LIST_LIMIT;
idx++, list_len++) {
channel = req->channels[idx];
ch_info = kzalloc(sizeof(*ch_info), GFP_KERNEL); ch_info = kzalloc(sizeof(*ch_info), GFP_KERNEL);
if (!ch_info) { if (!ch_info) {
ret = -ENOMEM; ret = -ENOMEM;
...@@ -2498,6 +2501,7 @@ static int rtw89_hw_scan_add_chan_list(struct rtw89_dev *rtwdev, ...@@ -2498,6 +2501,7 @@ static int rtw89_hw_scan_add_chan_list(struct rtw89_dev *rtwdev,
list_add_tail(&ch_info->list, &chan_list); list_add_tail(&ch_info->list, &chan_list);
off_chan_time += ch_info->period; off_chan_time += ch_info->period;
} }
rtwdev->scan_info.last_chan_idx = idx;
ret = rtw89_fw_h2c_scan_list_offload(rtwdev, list_len, &chan_list); ret = rtw89_fw_h2c_scan_list_offload(rtwdev, list_len, &chan_list);
out: out:
...@@ -2532,6 +2536,7 @@ void rtw89_hw_scan_start(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, ...@@ -2532,6 +2536,7 @@ void rtw89_hw_scan_start(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
u8 mac_addr[ETH_ALEN]; u8 mac_addr[ETH_ALEN];
rtwdev->scan_info.scanning_vif = vif; rtwdev->scan_info.scanning_vif = vif;
rtwdev->scan_info.last_chan_idx = 0;
rtwvif->scan_ies = &scan_req->ies; rtwvif->scan_ies = &scan_req->ies;
rtwvif->scan_req = req; rtwvif->scan_req = req;
ieee80211_stop_queues(rtwdev->hw); ieee80211_stop_queues(rtwdev->hw);
...@@ -2579,6 +2584,7 @@ void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, ...@@ -2579,6 +2584,7 @@ void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
rtwvif = (struct rtw89_vif *)vif->drv_priv; rtwvif = (struct rtw89_vif *)vif->drv_priv;
rtwvif->scan_req = NULL; rtwvif->scan_req = NULL;
rtwvif->scan_ies = NULL; rtwvif->scan_ies = NULL;
rtwdev->scan_info.last_chan_idx = 0;
rtwdev->scan_info.scanning_vif = NULL; rtwdev->scan_info.scanning_vif = NULL;
if (rtwvif->net_type != RTW89_NET_TYPE_NO_LINK) if (rtwvif->net_type != RTW89_NET_TYPE_NO_LINK)
......
...@@ -188,6 +188,7 @@ struct rtw89_h2creg_sch_tx_en { ...@@ -188,6 +188,7 @@ struct rtw89_h2creg_sch_tx_en {
u16 rsvd:15; u16 rsvd:15;
} __packed; } __packed;
#define RTW89_H2C_MAX_SIZE 2048
#define RTW89_CHANNEL_TIME 45 #define RTW89_CHANNEL_TIME 45
#define RTW89_DFS_CHAN_TIME 105 #define RTW89_DFS_CHAN_TIME 105
#define RTW89_OFF_CHAN_TIME 100 #define RTW89_OFF_CHAN_TIME 100
...@@ -198,6 +199,9 @@ struct rtw89_h2creg_sch_tx_en { ...@@ -198,6 +199,9 @@ struct rtw89_h2creg_sch_tx_en {
#define RTW89_SCANOFLD_PKT_NONE 0xFF #define RTW89_SCANOFLD_PKT_NONE 0xFF
#define RTW89_SCANOFLD_DEBUG_MASK 0x1F #define RTW89_SCANOFLD_DEBUG_MASK 0x1F
#define RTW89_MAC_CHINFO_SIZE 24 #define RTW89_MAC_CHINFO_SIZE 24
#define RTW89_SCAN_LIST_GUARD 4
#define RTW89_SCAN_LIST_LIMIT \
((RTW89_H2C_MAX_SIZE / RTW89_MAC_CHINFO_SIZE) - RTW89_SCAN_LIST_GUARD)
struct rtw89_mac_chinfo { struct rtw89_mac_chinfo {
u8 period; u8 period;
......
...@@ -3734,9 +3734,12 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *c2h, ...@@ -3734,9 +3734,12 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *c2h,
u32 len) u32 len)
{ {
struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif; struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif;
struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif);
struct rtw89_chan new; struct rtw89_chan new;
u8 reason, status, tx_fail, band, actual_period; u8 reason, status, tx_fail, band, actual_period;
u32 last_chan = rtwdev->scan_info.last_chan_idx;
u16 chan; u16 chan;
int ret;
tx_fail = RTW89_GET_MAC_C2H_SCANOFLD_TX_FAIL(c2h->data); tx_fail = RTW89_GET_MAC_C2H_SCANOFLD_TX_FAIL(c2h->data);
status = RTW89_GET_MAC_C2H_SCANOFLD_STATUS(c2h->data); status = RTW89_GET_MAC_C2H_SCANOFLD_STATUS(c2h->data);
...@@ -3758,7 +3761,16 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *c2h, ...@@ -3758,7 +3761,16 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *c2h,
ieee80211_stop_queues(rtwdev->hw); ieee80211_stop_queues(rtwdev->hw);
return; return;
case RTW89_SCAN_END_SCAN_NOTIFY: case RTW89_SCAN_END_SCAN_NOTIFY:
rtw89_hw_scan_complete(rtwdev, vif, false); if (rtwvif && rtwvif->scan_req &&
last_chan < rtwvif->scan_req->n_channels) {
ret = rtw89_hw_scan_offload(rtwdev, vif, true);
if (ret) {
rtw89_hw_scan_abort(rtwdev, vif);
rtw89_warn(rtwdev, "HW scan failed: %d\n", ret);
}
} else {
rtw89_hw_scan_complete(rtwdev, vif, false);
}
break; break;
case RTW89_SCAN_ENTER_CH_NOTIFY: case RTW89_SCAN_ENTER_CH_NOTIFY:
rtw89_chan_create(&new, chan, chan, band, RTW89_CHANNEL_WIDTH_20); rtw89_chan_create(&new, chan, chan, band, RTW89_CHANNEL_WIDTH_20);
......
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