@@ -23,6 +23,11 @@ static bool rtw89_disable_ps_mode;
module_param_named(disable_ps_mode, rtw89_disable_ps_mode, bool, 0644);
MODULE_PARM_DESC(disable_ps_mode, "Set Y to disable low power mode");
+bool rtw89_use_chanctx;
+module_param_named(use_chanctx, rtw89_use_chanctx, bool, 0644);
+MODULE_PARM_DESC(use_chanctx,
+ "Indicate whether to use channel context required for concurrency");
+
#define RTW89_DEF_CHAN(_freq, _hw_val, _flags, _band) \
{ .center_freq = _freq, .hw_value = _hw_val, .flags = _flags, .band = _band, }
#define RTW89_DEF_CHAN_2G(_freq, _hw_val) \
@@ -3220,7 +3225,7 @@ struct ieee80211_hw *rtw89_alloc_ieee80211_hw(u32 bus_data_size,
if (!ops)
goto err;
- if (chip->support_chanctx_num == 0) {
+ if (!rtw89_use_chanctx || chip->support_chanctx_num == 0) {
ops->add_chanctx = NULL;
ops->remove_chanctx = NULL;
ops->change_chanctx = NULL;
@@ -16,6 +16,7 @@ struct rtw89_dev;
struct rtw89_pci_info;
extern const struct ieee80211_ops rtw89_ops;
+extern bool rtw89_use_chanctx;
#define MASKBYTE0 0xff
#define MASKBYTE1 0xff00
@@ -2560,6 +2561,10 @@ struct rtw89_fw_suit {
(((major) << 24) | ((minor) << 16) | ((sub) << 8) | (idx))
#define RTW89_FW_SUIT_VER_CODE(s) \
RTW89_FW_VER_CODE((s)->major_ver, (s)->minor_ver, (s)->sub_ver, (s)->sub_idex)
+#define RTW89_FW_VER_MAJOR(ver_code) FIELD_GET(GENMASK(31, 24), ver_code)
+#define RTW89_FW_VER_MINOR(ver_code) FIELD_GET(GENMASK(23, 16), ver_code)
+#define RTW89_FW_VER_SUB(ver_code) FIELD_GET(GENMASK(15, 8), ver_code)
+#define RTW89_FW_VER_IDX(ver_code) FIELD_GET(GENMASK(7, 0), ver_code)
struct rtw89_fw_info {
const struct firmware *firmware;
@@ -196,6 +196,29 @@ int __rtw89_fw_recognize(struct rtw89_dev *rtwdev, enum rtw89_fw_type type)
return 0;
}
+static
+int __fw_feat_err_check_non_hw_scan(struct rtw89_dev *rtwdev, u32 required_vercode)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+
+ if (!rtw89_use_chanctx)
+ return 0;
+
+ if (chip->support_chanctx_num == 0) {
+ rtw89_warn(rtwdev,
+ "Run without chanctx because chip hasn't claimed it.\n");
+ return 0;
+ }
+
+ rtw89_err(rtwdev,
+ "Please upgrade FW to at least %lu.%lu.%lu.%lu or disable use_chanctx.\n",
+ RTW89_FW_VER_MAJOR(required_vercode),
+ RTW89_FW_VER_MINOR(required_vercode),
+ RTW89_FW_VER_SUB(required_vercode),
+ RTW89_FW_VER_IDX(required_vercode));
+ return -ENOENT;
+}
+
#define __DEF_FW_FEAT_COND(__cond, __op) \
static bool __fw_feat_cond_ ## __cond(u32 suit_ver_code, u32 comp_ver_code) \
{ \
@@ -210,29 +233,36 @@ struct __fw_feat_cfg {
enum rtw89_fw_feature feature;
u32 ver_code;
bool (*cond)(u32 suit_ver_code, u32 comp_ver_code);
+ int (*err_check)(struct rtw89_dev *rtwdev, u32 required_vercode);
};
-#define __CFG_FW_FEAT(_chip, _cond, _maj, _min, _sub, _idx, _feat) \
+#define __CFG_FW_FEAT(_chip, _cond, _maj, _min, _sub, _idx, _feat, _argv...) \
{ \
.chip_id = _chip, \
.feature = RTW89_FW_FEATURE_ ## _feat, \
.ver_code = RTW89_FW_VER_CODE(_maj, _min, _sub, _idx), \
.cond = __fw_feat_cond_ ## _cond, \
+ ##_argv,\
}
+#define __CFG_FW_FEAT_SCAN_OFFLOAD(_chip, _cond, _maj, _min, _sub, _idx) \
+ __CFG_FW_FEAT(_chip, _cond, _maj, _min, _sub, _idx, SCAN_OFFLOAD, \
+ .err_check = __fw_feat_err_check_non_hw_scan)
+
static const struct __fw_feat_cfg fw_feat_tbl[] = {
__CFG_FW_FEAT(RTL8852A, le, 0, 13, 29, 0, OLD_HT_RA_FORMAT),
- __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, SCAN_OFFLOAD),
+ __CFG_FW_FEAT_SCAN_OFFLOAD(RTL8852A, ge, 0, 13, 35, 0),
__CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, TX_WAKE),
__CFG_FW_FEAT(RTL8852A, ge, 0, 13, 36, 0, CRASH_TRIGGER),
};
-static void rtw89_fw_recognize_features(struct rtw89_dev *rtwdev)
+static int rtw89_fw_recognize_features(struct rtw89_dev *rtwdev)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
const struct __fw_feat_cfg *ent;
const struct rtw89_fw_suit *fw_suit;
u32 suit_ver_code;
+ int ret;
int i;
fw_suit = rtw89_fw_suit_get(rtwdev, RTW89_FW_NORMAL);
@@ -243,9 +273,19 @@ static void rtw89_fw_recognize_features(struct rtw89_dev *rtwdev)
if (chip->chip_id != ent->chip_id)
continue;
- if (ent->cond(suit_ver_code, ent->ver_code))
+ if (ent->cond(suit_ver_code, ent->ver_code)) {
RTW89_SET_FW_FEATURE(ent->feature, &rtwdev->fw);
+ continue;
+ }
+
+ if (ent->err_check) {
+ ret = ent->err_check(rtwdev, ent->ver_code);
+ if (ret)
+ return ret;
+ }
}
+
+ return 0;
}
int rtw89_fw_recognize(struct rtw89_dev *rtwdev)
@@ -259,7 +299,9 @@ int rtw89_fw_recognize(struct rtw89_dev *rtwdev)
/* It still works if wowlan firmware isn't existing. */
__rtw89_fw_recognize(rtwdev, RTW89_FW_WOWLAN);
- rtw89_fw_recognize_features(rtwdev);
+ ret = rtw89_fw_recognize_features(rtwdev);
+ if (ret)
+ return ret;
return 0;
}