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

wifi: rtw89: prepare scan leaf functions for wifi 7 ICs

The channel field slightly differs between WiFi 6 and WiFi 7.
So we prepare some required functions in advance, this doesn't change
existing wifi 6 ICs behavior. This H2C prepares the channel list
to be scanned for. With layout as the following:

+--------+--------------------+-------------------+-----------------------+
| header | number of channels | channel info size | channel_info * number |
+--------+--------------------+-------------------+-----------------------+
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://msgid.link/20240126063356.17857-4-pkshih@realtek.com
parent ac54faf5
......@@ -4078,6 +4078,102 @@ int rtw89_fw_h2c_scan_list_offload(struct rtw89_dev *rtwdev, int ch_num,
return 0;
}
int rtw89_fw_h2c_scan_list_offload_be(struct rtw89_dev *rtwdev, int ch_num,
struct list_head *chan_list)
{
struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait;
struct rtw89_h2c_chinfo_elem_be *elem;
struct rtw89_mac_chinfo_be *ch_info;
struct rtw89_h2c_chinfo *h2c;
struct sk_buff *skb;
unsigned int cond;
int skb_len;
int ret;
static_assert(sizeof(*elem) == RTW89_MAC_CHINFO_SIZE);
skb_len = struct_size(h2c, elem, ch_num);
skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, skb_len);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for h2c scan list\n");
return -ENOMEM;
}
skb_put(skb, sizeof(*h2c));
h2c = (struct rtw89_h2c_chinfo *)skb->data;
h2c->ch_num = ch_num;
h2c->elem_size = sizeof(*elem) / 4; /* in unit of 4 bytes */
h2c->arg = u8_encode_bits(RTW89_PHY_0, RTW89_H2C_CHINFO_ARG_MAC_IDX_MASK);
list_for_each_entry(ch_info, chan_list, list) {
elem = (struct rtw89_h2c_chinfo_elem_be *)skb_put(skb, sizeof(*elem));
elem->w0 = le32_encode_bits(ch_info->period, RTW89_H2C_CHINFO_BE_W0_PERIOD) |
le32_encode_bits(ch_info->dwell_time, RTW89_H2C_CHINFO_BE_W0_DWELL) |
le32_encode_bits(ch_info->central_ch,
RTW89_H2C_CHINFO_BE_W0_CENTER_CH) |
le32_encode_bits(ch_info->pri_ch, RTW89_H2C_CHINFO_BE_W0_PRI_CH);
elem->w1 = le32_encode_bits(ch_info->bw, RTW89_H2C_CHINFO_BE_W1_BW) |
le32_encode_bits(ch_info->ch_band, RTW89_H2C_CHINFO_BE_W1_CH_BAND) |
le32_encode_bits(ch_info->dfs_ch, RTW89_H2C_CHINFO_BE_W1_DFS) |
le32_encode_bits(ch_info->pause_data,
RTW89_H2C_CHINFO_BE_W1_PAUSE_DATA) |
le32_encode_bits(ch_info->tx_null, RTW89_H2C_CHINFO_BE_W1_TX_NULL) |
le32_encode_bits(ch_info->rand_seq_num,
RTW89_H2C_CHINFO_BE_W1_RANDOM) |
le32_encode_bits(ch_info->notify_action,
RTW89_H2C_CHINFO_BE_W1_NOTIFY) |
le32_encode_bits(ch_info->probe_id != 0xff ? 1 : 0,
RTW89_H2C_CHINFO_BE_W1_PROBE) |
le32_encode_bits(ch_info->leave_crit,
RTW89_H2C_CHINFO_BE_W1_EARLY_LEAVE_CRIT) |
le32_encode_bits(ch_info->chkpt_timer,
RTW89_H2C_CHINFO_BE_W1_CHKPT_TIMER);
elem->w2 = le32_encode_bits(ch_info->leave_time,
RTW89_H2C_CHINFO_BE_W2_EARLY_LEAVE_TIME) |
le32_encode_bits(ch_info->leave_th,
RTW89_H2C_CHINFO_BE_W2_EARLY_LEAVE_TH) |
le32_encode_bits(ch_info->tx_pkt_ctrl,
RTW89_H2C_CHINFO_BE_W2_TX_PKT_CTRL);
elem->w3 = le32_encode_bits(ch_info->pkt_id[0], RTW89_H2C_CHINFO_BE_W3_PKT0) |
le32_encode_bits(ch_info->pkt_id[1], RTW89_H2C_CHINFO_BE_W3_PKT1) |
le32_encode_bits(ch_info->pkt_id[2], RTW89_H2C_CHINFO_BE_W3_PKT2) |
le32_encode_bits(ch_info->pkt_id[3], RTW89_H2C_CHINFO_BE_W3_PKT3);
elem->w4 = le32_encode_bits(ch_info->pkt_id[4], RTW89_H2C_CHINFO_BE_W4_PKT4) |
le32_encode_bits(ch_info->pkt_id[5], RTW89_H2C_CHINFO_BE_W4_PKT5) |
le32_encode_bits(ch_info->pkt_id[6], RTW89_H2C_CHINFO_BE_W4_PKT6) |
le32_encode_bits(ch_info->pkt_id[7], RTW89_H2C_CHINFO_BE_W4_PKT7);
elem->w5 = le32_encode_bits(ch_info->sw_def, RTW89_H2C_CHINFO_BE_W5_SW_DEF) |
le32_encode_bits(ch_info->fw_probe0_ssids,
RTW89_H2C_CHINFO_BE_W5_FW_PROBE0_SSIDS);
elem->w6 = le32_encode_bits(ch_info->fw_probe0_shortssids,
RTW89_H2C_CHINFO_BE_W6_FW_PROBE0_SHORTSSIDS) |
le32_encode_bits(ch_info->fw_probe0_bssids,
RTW89_H2C_CHINFO_BE_W6_FW_PROBE0_BSSIDS);
}
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);
cond = RTW89_SCANOFLD_WAIT_COND_ADD_CH;
ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond);
if (ret) {
rtw89_debug(rtwdev, RTW89_DBG_FW, "failed to add scan ofld ch\n");
return ret;
}
return 0;
}
int rtw89_fw_h2c_scan_offload(struct rtw89_dev *rtwdev,
struct rtw89_scan_option *option,
struct rtw89_vif *rtwvif)
......@@ -4769,8 +4865,66 @@ static void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type,
}
}
static int rtw89_hw_scan_add_chan_list(struct rtw89_dev *rtwdev,
struct rtw89_vif *rtwvif, bool connected)
static void rtw89_hw_scan_add_chan_be(struct rtw89_dev *rtwdev, int chan_type,
int ssid_num,
struct rtw89_mac_chinfo_be *ch_info)
{
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif;
struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
struct cfg80211_scan_request *req = rtwvif->scan_req;
struct rtw89_pktofld_info *info;
u8 band, probe_count = 0, i;
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_null = false;
ch_info->pause_data = false;
ch_info->probe_id = RTW89_SCANOFLD_PKT_NONE;
if (ssid_num) {
band = rtw89_hw_to_nl80211_band(ch_info->ch_band);
list_for_each_entry(info, &scan_info->pkt_list[band], list) {
if (info->channel_6ghz &&
ch_info->pri_ch != info->channel_6ghz)
continue;
ch_info->pkt_id[probe_count++] = info->id;
if (probe_count >= RTW89_SCANOFLD_MAX_SSID)
break;
}
}
if (ch_info->ch_band == RTW89_BAND_6G) {
if ((ssid_num == 1 && req->ssids[0].ssid_len == 0) ||
!ch_info->is_psc) {
ch_info->probe_id = RTW89_SCANOFLD_PKT_NONE;
if (!req->duration_mandatory)
ch_info->period -= RTW89_DWELL_TIME_6G;
}
}
for (i = probe_count; i < RTW89_SCANOFLD_MAX_SSID; i++)
ch_info->pkt_id[i] = RTW89_SCANOFLD_PKT_NONE;
switch (chan_type) {
case RTW89_CHAN_DFS:
if (ch_info->ch_band != RTW89_BAND_6G)
ch_info->period =
max_t(u8, ch_info->period, RTW89_DFS_CHAN_TIME);
ch_info->dwell_time = RTW89_DWELL_TIME;
break;
case RTW89_CHAN_ACTIVE:
break;
default:
rtw89_warn(rtwdev, "Channel type out of bound\n");
break;
}
}
int rtw89_hw_scan_add_chan_list(struct rtw89_dev *rtwdev,
struct rtw89_vif *rtwvif, bool connected)
{
struct cfg80211_scan_request *req = rtwvif->scan_req;
struct rtw89_mac_chinfo *ch_info, *tmp;
......@@ -4846,9 +5000,69 @@ static int rtw89_hw_scan_add_chan_list(struct rtw89_dev *rtwdev,
return ret;
}
int rtw89_hw_scan_add_chan_list_be(struct rtw89_dev *rtwdev,
struct rtw89_vif *rtwvif, bool connected)
{
struct cfg80211_scan_request *req = rtwvif->scan_req;
struct rtw89_mac_chinfo_be *ch_info, *tmp;
struct ieee80211_channel *channel;
struct list_head chan_list;
enum rtw89_chan_type type;
int list_len, ret;
bool random_seq;
u32 idx;
random_seq = !!(req->flags & NL80211_SCAN_FLAG_RANDOM_SN);
INIT_LIST_HEAD(&chan_list);
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;
goto out;
}
if (req->duration_mandatory)
ch_info->period = req->duration;
else if (channel->band == NL80211_BAND_6GHZ)
ch_info->period = RTW89_CHANNEL_TIME_6G + RTW89_DWELL_TIME_6G;
else
ch_info->period = RTW89_CHANNEL_TIME;
ch_info->ch_band = rtw89_nl80211_to_hw_band(channel->band);
ch_info->central_ch = channel->hw_value;
ch_info->pri_ch = channel->hw_value;
ch_info->rand_seq_num = random_seq;
ch_info->is_psc = cfg80211_channel_is_psc(channel);
if (channel->flags & (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IR))
type = RTW89_CHAN_DFS;
else
type = RTW89_CHAN_ACTIVE;
rtw89_hw_scan_add_chan_be(rtwdev, type, req->n_ssids, ch_info);
list_add_tail(&ch_info->list, &chan_list);
}
rtwdev->scan_info.last_chan_idx = idx;
ret = rtw89_fw_h2c_scan_list_offload_be(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, bool connected)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
int ret;
ret = rtw89_hw_scan_update_probe_req(rtwdev, rtwvif);
......@@ -4856,7 +5070,7 @@ static int rtw89_hw_scan_prehandle(struct rtw89_dev *rtwdev,
rtw89_err(rtwdev, "Update probe request failed\n");
goto out;
}
ret = rtw89_hw_scan_add_chan_list(rtwdev, rtwvif, connected);
ret = mac->add_chan_list(rtwdev, rtwvif, connected);
out:
return ret;
}
......
......@@ -297,6 +297,34 @@ struct rtw89_mac_chinfo {
bool is_psc;
};
struct rtw89_mac_chinfo_be {
u8 period;
u8 dwell_time;
u8 central_ch;
u8 pri_ch;
u8 bw:3;
u8 ch_band:2;
u8 dfs_ch:1;
u8 pause_data:1;
u8 tx_null:1;
u8 rand_seq_num:1;
u8 notify_action:5;
u8 probe_id;
u8 leave_crit;
u8 chkpt_timer;
u8 leave_time;
u8 leave_th;
u16 tx_pkt_ctrl;
u8 pkt_id[RTW89_SCANOFLD_MAX_SSID];
u8 sw_def;
u16 fw_probe0_ssids;
u16 fw_probe0_shortssids;
u16 fw_probe0_bssids;
struct list_head list;
bool is_psc;
};
struct rtw89_scan_option {
bool enable;
bool target_ch_mode;
......@@ -2708,14 +2736,57 @@ struct rtw89_h2c_chinfo_elem {
#define RTW89_H2C_CHINFO_W3_PKT7 GENMASK(31, 24)
#define RTW89_H2C_CHINFO_W4_POWER_IDX GENMASK(15, 0)
struct rtw89_h2c_chinfo_elem_be {
__le32 w0;
__le32 w1;
__le32 w2;
__le32 w3;
__le32 w4;
__le32 w5;
__le32 w6;
} __packed;
#define RTW89_H2C_CHINFO_BE_W0_PERIOD GENMASK(7, 0)
#define RTW89_H2C_CHINFO_BE_W0_DWELL GENMASK(15, 8)
#define RTW89_H2C_CHINFO_BE_W0_CENTER_CH GENMASK(23, 16)
#define RTW89_H2C_CHINFO_BE_W0_PRI_CH GENMASK(31, 24)
#define RTW89_H2C_CHINFO_BE_W1_BW GENMASK(2, 0)
#define RTW89_H2C_CHINFO_BE_W1_CH_BAND GENMASK(4, 3)
#define RTW89_H2C_CHINFO_BE_W1_DFS BIT(5)
#define RTW89_H2C_CHINFO_BE_W1_PAUSE_DATA BIT(6)
#define RTW89_H2C_CHINFO_BE_W1_TX_NULL BIT(7)
#define RTW89_H2C_CHINFO_BE_W1_RANDOM BIT(8)
#define RTW89_H2C_CHINFO_BE_W1_NOTIFY GENMASK(13, 9)
#define RTW89_H2C_CHINFO_BE_W1_PROBE BIT(14)
#define RTW89_H2C_CHINFO_BE_W1_EARLY_LEAVE_CRIT GENMASK(17, 15)
#define RTW89_H2C_CHINFO_BE_W1_CHKPT_TIMER GENMASK(31, 24)
#define RTW89_H2C_CHINFO_BE_W2_EARLY_LEAVE_TIME GENMASK(7, 0)
#define RTW89_H2C_CHINFO_BE_W2_EARLY_LEAVE_TH GENMASK(15, 8)
#define RTW89_H2C_CHINFO_BE_W2_TX_PKT_CTRL GENMASK(31, 16)
#define RTW89_H2C_CHINFO_BE_W3_PKT0 GENMASK(7, 0)
#define RTW89_H2C_CHINFO_BE_W3_PKT1 GENMASK(15, 8)
#define RTW89_H2C_CHINFO_BE_W3_PKT2 GENMASK(23, 16)
#define RTW89_H2C_CHINFO_BE_W3_PKT3 GENMASK(31, 24)
#define RTW89_H2C_CHINFO_BE_W4_PKT4 GENMASK(7, 0)
#define RTW89_H2C_CHINFO_BE_W4_PKT5 GENMASK(15, 8)
#define RTW89_H2C_CHINFO_BE_W4_PKT6 GENMASK(23, 16)
#define RTW89_H2C_CHINFO_BE_W4_PKT7 GENMASK(31, 24)
#define RTW89_H2C_CHINFO_BE_W5_SW_DEF GENMASK(7, 0)
#define RTW89_H2C_CHINFO_BE_W5_FW_PROBE0_SSIDS GENMASK(31, 16)
#define RTW89_H2C_CHINFO_BE_W6_FW_PROBE0_SHORTSSIDS GENMASK(15, 0)
#define RTW89_H2C_CHINFO_BE_W6_FW_PROBE0_BSSIDS GENMASK(31, 16)
struct rtw89_h2c_chinfo {
u8 ch_num;
u8 elem_size;
u8 arg;
u8 rsvd0;
u8 rsvd1;
struct rtw89_h2c_chinfo_elem elem[] __counted_by(ch_num);
} __packed;
#define RTW89_H2C_CHINFO_ARG_MAC_IDX_MASK BIT(0)
#define RTW89_H2C_CHINFO_ARG_APPEND_MASK BIT(1)
struct rtw89_h2c_scanofld {
__le32 w0;
__le32 w1;
......@@ -3933,6 +4004,8 @@ 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 ch_num,
struct list_head *chan_list);
int rtw89_fw_h2c_scan_list_offload_be(struct rtw89_dev *rtwdev, int ch_num,
struct list_head *chan_list);
int rtw89_fw_h2c_scan_offload(struct rtw89_dev *rtwdev,
struct rtw89_scan_option *opt,
struct rtw89_vif *vif);
......@@ -3975,6 +4048,10 @@ void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
bool enable);
void rtw89_hw_scan_abort(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif);
int rtw89_hw_scan_add_chan_list(struct rtw89_dev *rtwdev,
struct rtw89_vif *rtwvif, bool connected);
int rtw89_hw_scan_add_chan_list_be(struct rtw89_dev *rtwdev,
struct rtw89_vif *rtwvif, bool connected);
int rtw89_fw_h2c_trigger_cpu_exception(struct rtw89_dev *rtwdev);
int rtw89_fw_h2c_pkt_drop(struct rtw89_dev *rtwdev,
const struct rtw89_pkt_drop_params *params);
......
......@@ -6225,5 +6225,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = {
.dump_err_status = rtw89_mac_dump_err_status_ax,
.is_txq_empty = mac_is_txq_empty_ax,
.add_chan_list = rtw89_hw_scan_add_chan_list,
};
EXPORT_SYMBOL(rtw89_mac_gen_ax);
......@@ -953,6 +953,9 @@ struct rtw89_mac_gen_def {
enum mac_ax_err_info err);
bool (*is_txq_empty)(struct rtw89_dev *rtwdev);
int (*add_chan_list)(struct rtw89_dev *rtwdev,
struct rtw89_vif *rtwvif, bool connected);
};
extern const struct rtw89_mac_gen_def rtw89_mac_gen_ax;
......
......@@ -2364,5 +2364,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = {
.dump_err_status = rtw89_mac_dump_err_status_be,
.is_txq_empty = mac_is_txq_empty_be,
.add_chan_list = rtw89_hw_scan_add_chan_list_be,
};
EXPORT_SYMBOL(rtw89_mac_gen_be);
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