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

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
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -3318,6 +3318,7 @@ struct rtw89_hw_scan_info {
	u8 op_chan;
	u8 op_bw;
	u8 op_band;
	u32 last_chan_idx;
};

enum rtw89_phy_bb_gain_band {
@@ -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);
}

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)
{
	void *p = rtwsta;
+10 −4
Original line number Diff line number Diff line
@@ -2451,13 +2451,16 @@ static int rtw89_hw_scan_add_chan_list(struct rtw89_dev *rtwdev,
	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;
	int list_len, off_chan_time = 0;
	enum rtw89_chan_type type;
	int ret = 0, i;
	int ret = 0;
	u32 idx;

	INIT_LIST_HEAD(&chan_list);
	for (i = 0; i < req->n_channels; i++) {
		channel = req->channels[i];
	for (idx = rtwdev->scan_info.last_chan_idx, list_len = 0;
	     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);
		if (!ch_info) {
			ret = -ENOMEM;
@@ -2498,6 +2501,7 @@ static int rtw89_hw_scan_add_chan_list(struct rtw89_dev *rtwdev,
		list_add_tail(&ch_info->list, &chan_list);
		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);

out:
@@ -2532,6 +2536,7 @@ void rtw89_hw_scan_start(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
	u8 mac_addr[ETH_ALEN];

	rtwdev->scan_info.scanning_vif = vif;
	rtwdev->scan_info.last_chan_idx = 0;
	rtwvif->scan_ies = &scan_req->ies;
	rtwvif->scan_req = req;
	ieee80211_stop_queues(rtwdev->hw);
@@ -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->scan_req = NULL;
	rtwvif->scan_ies = NULL;
	rtwdev->scan_info.last_chan_idx = 0;
	rtwdev->scan_info.scanning_vif = NULL;

	if (rtwvif->net_type != RTW89_NET_TYPE_NO_LINK)
+4 −0
Original line number Diff line number Diff line
@@ -188,6 +188,7 @@ struct rtw89_h2creg_sch_tx_en {
	u16 rsvd:15;
} __packed;

#define RTW89_H2C_MAX_SIZE 2048
#define RTW89_CHANNEL_TIME 45
#define RTW89_DFS_CHAN_TIME 105
#define RTW89_OFF_CHAN_TIME 100
@@ -198,6 +199,9 @@ struct rtw89_h2creg_sch_tx_en {
#define RTW89_SCANOFLD_PKT_NONE 0xFF
#define RTW89_SCANOFLD_DEBUG_MASK 0x1F
#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 {
	u8 period;
+13 −1
Original line number Diff line number Diff line
@@ -3734,9 +3734,12 @@ 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_vif *rtwvif = vif_to_rtwvif_safe(vif);
	struct rtw89_chan new;
	u8 reason, status, tx_fail, band, actual_period;
	u32 last_chan = rtwdev->scan_info.last_chan_idx;
	u16 chan;
	int ret;

	tx_fail = RTW89_GET_MAC_C2H_SCANOFLD_TX_FAIL(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,
			ieee80211_stop_queues(rtwdev->hw);
		return;
	case RTW89_SCAN_END_SCAN_NOTIFY:
		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;
	case RTW89_SCAN_ENTER_CH_NOTIFY:
		rtw89_chan_create(&new, chan, chan, band, RTW89_CHANNEL_WIDTH_20);