2022-11-18 05:15:37

by Ping-Ke Shih

[permalink] [raw]
Subject: [PATCH 0/6] wifi: rtw89: preparation of MCC

This patchset is preparation of MCC, which needs many handshakes between
driver and firmware, so rtw89_wait_for_cond() and rtw89_complete_cond()
are introduced to assist this work.

Based on above APIs, implement H2C and C2H handlers to interactive with
firmware, and callers of H2C will be added by another patchset.

Another basic preparation is to link rtw89_vif and channel context, but
we still use first entry as default currently, so adjust index of instance
of chandef when remove_chanctx().

Zong-Zhe Yang (6):
wifi: rtw89: rfk: rename rtw89_mcc_info to rtw89_rfk_mcc_info
wifi: rtw89: check if atomic before queuing c2h
wifi: rtw89: introduce helpers to wait/complete on condition
wifi: rtw89: mac: process MCC related C2H
wifi: rtw89: fw: implement MCC related H2C
wifi: rtw89: link rtw89_vif and chanctx stuffs

drivers/net/wireless/realtek/rtw89/chan.c | 40 +-
drivers/net/wireless/realtek/rtw89/core.c | 37 ++
drivers/net/wireless/realtek/rtw89/core.h | 60 ++-
drivers/net/wireless/realtek/rtw89/fw.c | 386 ++++++++++++++-
drivers/net/wireless/realtek/rtw89/fw.h | 449 +++++++++++++++++-
drivers/net/wireless/realtek/rtw89/mac.c | 181 +++++++
drivers/net/wireless/realtek/rtw89/mac.h | 35 ++
drivers/net/wireless/realtek/rtw89/mac80211.c | 1 +
drivers/net/wireless/realtek/rtw89/rtw8852c.c | 4 +-
.../net/wireless/realtek/rtw89/rtw8852c_rfk.c | 20 +-
10 files changed, 1178 insertions(+), 35 deletions(-)

--
2.25.1



2022-11-18 05:15:37

by Ping-Ke Shih

[permalink] [raw]
Subject: [PATCH 1/6] wifi: rtw89: rfk: rename rtw89_mcc_info to rtw89_rfk_mcc_info

From: Zong-Zhe Yang <[email protected]>

The `rtw89_mcc_info mcc` is only for RFK MCC stuffs instead of common
MCC management info. Replace it with `rtw89_rfk_mcc_info rfk_mcc` to
avoid confusion and reserve `struct rtw89_mcc_info mcc` for MCC management
code.

(No logic changes.)

Signed-off-by: Zong-Zhe Yang <[email protected]>
Signed-off-by: Ping-Ke Shih <[email protected]>
---
drivers/net/wireless/realtek/rtw89/core.h | 4 ++--
drivers/net/wireless/realtek/rtw89/fw.c | 10 +++++-----
drivers/net/wireless/realtek/rtw89/rtw8852c.c | 4 ++--
.../net/wireless/realtek/rtw89/rtw8852c_rfk.c | 20 +++++++++----------
4 files changed, 19 insertions(+), 19 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index b60de6662548b..3fff666c0e84a 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -3021,7 +3021,7 @@ struct rtw89_dack_info {
#define RTW89_IQK_CHS_NR 2
#define RTW89_IQK_PATH_NR 4

-struct rtw89_mcc_info {
+struct rtw89_rfk_mcc_info {
u8 ch[RTW89_IQK_CHS_NR];
u8 band[RTW89_IQK_CHS_NR];
u8 table_idx;
@@ -3567,7 +3567,7 @@ struct rtw89_dev {
struct rtw89_dack_info dack;
struct rtw89_iqk_info iqk;
struct rtw89_dpk_info dpk;
- struct rtw89_mcc_info mcc;
+ struct rtw89_rfk_mcc_info rfk_mcc;
struct rtw89_lck_info lck;
struct rtw89_rx_dck_info rx_dck;
bool is_tssi_mode[RF_PATH_MAX];
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index 10c5ed21da025..3d7b99e15967e 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -2263,7 +2263,7 @@ int rtw89_fw_h2c_rf_reg(struct rtw89_dev *rtwdev,
int rtw89_fw_h2c_rf_ntfy_mcc(struct rtw89_dev *rtwdev)
{
const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
- struct rtw89_mcc_info *mcc_info = &rtwdev->mcc;
+ struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc;
struct rtw89_fw_h2c_rf_get_mccch *mccch;
struct sk_buff *skb;
int ret;
@@ -2276,10 +2276,10 @@ int rtw89_fw_h2c_rf_ntfy_mcc(struct rtw89_dev *rtwdev)
skb_put(skb, sizeof(*mccch));
mccch = (struct rtw89_fw_h2c_rf_get_mccch *)skb->data;

- mccch->ch_0 = cpu_to_le32(mcc_info->ch[0]);
- mccch->ch_1 = cpu_to_le32(mcc_info->ch[1]);
- mccch->band_0 = cpu_to_le32(mcc_info->band[0]);
- mccch->band_1 = cpu_to_le32(mcc_info->band[1]);
+ mccch->ch_0 = cpu_to_le32(rfk_mcc->ch[0]);
+ mccch->ch_1 = cpu_to_le32(rfk_mcc->ch[1]);
+ mccch->band_0 = cpu_to_le32(rfk_mcc->band[0]);
+ mccch->band_1 = cpu_to_le32(rfk_mcc->band[1]);
mccch->current_channel = cpu_to_le32(chan->channel);
mccch->current_band_type = cpu_to_le32(chan->band_type);

diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
index 6619ba7307199..fcd5703845467 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
@@ -1832,11 +1832,11 @@ static void rtw8852c_set_channel_help(struct rtw89_dev *rtwdev, bool enter,

static void rtw8852c_rfk_init(struct rtw89_dev *rtwdev)
{
- struct rtw89_mcc_info *mcc_info = &rtwdev->mcc;
+ struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc;

rtwdev->is_tssi_mode[RF_PATH_A] = false;
rtwdev->is_tssi_mode[RF_PATH_B] = false;
- memset(mcc_info, 0, sizeof(*mcc_info));
+ memset(rfk_mcc, 0, sizeof(*rfk_mcc));
rtw8852c_lck_init(rtwdev);

rtw8852c_rck(rtwdev);
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c
index b0672b906e7bc..60cd676fe22c9 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c
@@ -1030,9 +1030,9 @@ static bool _iqk_nbtxk(struct rtw89_dev *rtwdev,

static bool _lok_finetune_check(struct rtw89_dev *rtwdev, u8 path)
{
- struct rtw89_mcc_info *mcc_info = &rtwdev->mcc;
+ struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc;
struct rtw89_iqk_info *iqk_info = &rtwdev->iqk;
- u8 idx = mcc_info->table_idx;
+ u8 idx = rfk_mcc->table_idx;
bool is_fail1, is_fail2;
u32 val;
u32 core_i;
@@ -1375,10 +1375,10 @@ static void _iqk_afebb_restore(struct rtw89_dev *rtwdev,

static void _iqk_preset(struct rtw89_dev *rtwdev, u8 path)
{
- struct rtw89_mcc_info *mcc_info = &rtwdev->mcc;
+ struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc;
u8 idx = 0;

- idx = mcc_info->table_idx;
+ idx = rfk_mcc->table_idx;
rtw89_phy_write32_mask(rtwdev, R_COEF_SEL + (path << 8), B_COEF_SEL_IQC, idx);
rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), B_CFIR_LUT_G3, idx);
rtw89_write_rf(rtwdev, path, RR_RSV1, RR_RSV1_RST, 0x0);
@@ -3824,20 +3824,20 @@ void rtw8852c_set_channel_rf(struct rtw89_dev *rtwdev,
void rtw8852c_mcc_get_ch_info(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
{
const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
- struct rtw89_mcc_info *mcc_info = &rtwdev->mcc;
- u8 idx = mcc_info->table_idx;
+ struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc;
+ u8 idx = rfk_mcc->table_idx;
int i;

for (i = 0; i < RTW89_IQK_CHS_NR; i++) {
- if (mcc_info->ch[idx] == 0)
+ if (rfk_mcc->ch[idx] == 0)
break;
if (++idx >= RTW89_IQK_CHS_NR)
idx = 0;
}

- mcc_info->table_idx = idx;
- mcc_info->ch[idx] = chan->channel;
- mcc_info->band[idx] = chan->band_type;
+ rfk_mcc->table_idx = idx;
+ rfk_mcc->ch[idx] = chan->channel;
+ rfk_mcc->band[idx] = chan->band_type;
}

void rtw8852c_rck(struct rtw89_dev *rtwdev)
--
2.25.1


2022-11-18 05:15:54

by Ping-Ke Shih

[permalink] [raw]
Subject: [PATCH 3/6] wifi: rtw89: introduce helpers to wait/complete on condition

From: Zong-Zhe Yang <[email protected]>

MCC (multi-channel concurrency) related H2Cs require to wait for C2H
responses to judge the execution result and data. We introduce helpers
to assist this process. Besides, we would like the helpers to be generic
for use in driver even outside of MCC H2C/C2H, so we make a independent
patch for them.

In the following, I describe the things first.
```
(A) C2H is generated by FW, and then transferred upto driver. Hence,
driver cannot get it immediately without a bit waitting/blocking.
For this, we choose to use wait_for_completion_*() instead of
busy polling.
(B) From the driver management perspective, a scenario, e.g. MCC,
may have mulitple kind of H2C functions requiring this process
to wait for corresponding C2Hs. But, the driver management flow
uses mutex to protect each behavior. So, one scenario triggers
one H2C function at one time. To avoid rampant instances of
struct completion for each H2C function, we choose to use one
struct completion with one condition flag for one scenario.
(C) C2Hs, which H2Cs will be waitting for, cannot be ordered with
driver management flow, i.e. cannot enqueue work to the same
ordered workqueue and cannot lock by the same mutex, to prevent
H2C side from getting no C2H responses. So, those C2Hs are parsed
in interrupt context directly as done in previous commit.
(D) Following (C), the above underline H2Cs and C2Hs will be handled
in different contexts without sync. So, we use atomic_cmpxchg()
to compare and change the condition in atomic.
```

So, we introduce struct rtw89_wait_info which combines struct completion
and atomic_t. Then, the below are the descriptions for helper functions.
* rtw89_wait_for_cond() to wait for a completion based on a condition.
* rtw89_complete_cond() to complete a given condition and carry data.
Each rtw89_wait_info instance independently determines the meaning of
its waitting conditions. But, RTW89_WAIT_COND_IDLE (UINT_MAX) is reserved.

Signed-off-by: Zong-Zhe Yang <[email protected]>
Signed-off-by: Ping-Ke Shih <[email protected]>
---
drivers/net/wireless/realtek/rtw89/core.c | 35 +++++++++++++++++++++++
drivers/net/wireless/realtek/rtw89/core.h | 31 ++++++++++++++++++++
2 files changed, 66 insertions(+)

diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index f30aadc41f2be..e0b044a33207a 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -2941,6 +2941,41 @@ void rtw89_core_update_beacon_work(struct work_struct *work)
mutex_unlock(&rtwdev->mutex);
}

+int rtw89_wait_for_cond(struct rtw89_wait_info *wait, unsigned int cond)
+{
+ struct completion *cmpl = &wait->completion;
+ unsigned long timeout;
+ unsigned int cur;
+
+ cur = atomic_cmpxchg(&wait->cond, RTW89_WAIT_COND_IDLE, cond);
+ if (cur != RTW89_WAIT_COND_IDLE)
+ return -EBUSY;
+
+ timeout = wait_for_completion_timeout(cmpl, RTW89_WAIT_FOR_COND_TIMEOUT);
+ if (timeout == 0) {
+ atomic_set(&wait->cond, RTW89_WAIT_COND_IDLE);
+ return -ETIMEDOUT;
+ }
+
+ if (wait->data.err)
+ return -EFAULT;
+
+ return 0;
+}
+
+void rtw89_complete_cond(struct rtw89_wait_info *wait, unsigned int cond,
+ const struct rtw89_completion_data *data)
+{
+ unsigned int cur;
+
+ cur = atomic_cmpxchg(&wait->cond, cond, RTW89_WAIT_COND_IDLE);
+ if (cur != cond)
+ return;
+
+ wait->data = *data;
+ complete(&wait->completion);
+}
+
int rtw89_core_start(struct rtw89_dev *rtwdev)
{
int ret;
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 3fff666c0e84a..5a7d5514bba9a 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -2802,6 +2802,34 @@ struct rtw89_mac_info {
u8 cpwm_seq_num;
};

+struct rtw89_completion_data {
+ bool err;
+#define RTW89_COMPLETION_BUF_SIZE 24
+ u8 buf[RTW89_COMPLETION_BUF_SIZE];
+};
+
+#define rtw89_completion_cast(cmpl_data, ptr) \
+({ \
+ typecheck(struct rtw89_completion_data *, cmpl_data); \
+ BUILD_BUG_ON(sizeof(*(ptr)) > RTW89_COMPLETION_BUF_SIZE); \
+ (typeof(ptr))(cmpl_data)->buf; \
+})
+
+struct rtw89_wait_info {
+#define RTW89_WAIT_COND_IDLE UINT_MAX
+ atomic_t cond;
+ struct completion completion;
+ struct rtw89_completion_data data;
+};
+
+#define RTW89_WAIT_FOR_COND_TIMEOUT msecs_to_jiffies(100)
+
+static inline void rtw89_init_wait(struct rtw89_wait_info *wait)
+{
+ init_completion(&wait->completion);
+ atomic_set(&wait->cond, RTW89_WAIT_COND_IDLE);
+}
+
enum rtw89_fw_type {
RTW89_FW_NORMAL = 1,
RTW89_FW_WOWLAN = 3,
@@ -4440,6 +4468,9 @@ int rtw89_regd_init(struct rtw89_dev *rtwdev,
void rtw89_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request);
void rtw89_traffic_stats_init(struct rtw89_dev *rtwdev,
struct rtw89_traffic_stats *stats);
+int rtw89_wait_for_cond(struct rtw89_wait_info *wait, unsigned int cond);
+void rtw89_complete_cond(struct rtw89_wait_info *wait, unsigned int cond,
+ const struct rtw89_completion_data *data);
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);
--
2.25.1


2022-11-18 05:15:54

by Ping-Ke Shih

[permalink] [raw]
Subject: [PATCH 2/6] wifi: rtw89: check if atomic before queuing c2h

From: Zong-Zhe Yang <[email protected]>

Before queuing C2H work, we check atomicity of the C2H's handler first now.
If atomic or lock-free, handle it directly; otherwise, handle it with mutex
in work as previous. This prepares for MAC MCC C2Hs which require to be
processed directly. And, their handlers will be functions which can be
considered atomic.

Signed-off-by: Zong-Zhe Yang <[email protected]>
Signed-off-by: Ping-Ke Shih <[email protected]>
---
drivers/net/wireless/realtek/rtw89/fw.c | 47 ++++++++++++++++++++++--
drivers/net/wireless/realtek/rtw89/fw.h | 14 +++++++
drivers/net/wireless/realtek/rtw89/mac.c | 10 +++++
drivers/net/wireless/realtek/rtw89/mac.h | 1 +
4 files changed, 68 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index 3d7b99e15967e..544f6d4b68735 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -11,6 +11,9 @@
#include "phy.h"
#include "reg.h"

+static void rtw89_fw_c2h_cmd_handle(struct rtw89_dev *rtwdev,
+ struct sk_buff *skb);
+
static struct sk_buff *rtw89_fw_h2c_alloc_skb(struct rtw89_dev *rtwdev, u32 len,
bool header)
{
@@ -2382,8 +2385,43 @@ void rtw89_fw_free_all_early_h2c(struct rtw89_dev *rtwdev)
mutex_unlock(&rtwdev->mutex);
}

+static void rtw89_fw_c2h_parse_attr(struct sk_buff *c2h)
+{
+ struct rtw89_fw_c2h_attr *attr = RTW89_SKB_C2H_CB(c2h);
+
+ attr->category = RTW89_GET_C2H_CATEGORY(c2h->data);
+ attr->class = RTW89_GET_C2H_CLASS(c2h->data);
+ attr->func = RTW89_GET_C2H_FUNC(c2h->data);
+ attr->len = RTW89_GET_C2H_LEN(c2h->data);
+}
+
+static bool rtw89_fw_c2h_chk_atomic(struct rtw89_dev *rtwdev,
+ struct sk_buff *c2h)
+{
+ struct rtw89_fw_c2h_attr *attr = RTW89_SKB_C2H_CB(c2h);
+ u8 category = attr->category;
+ u8 class = attr->class;
+ u8 func = attr->func;
+
+ switch (category) {
+ default:
+ return false;
+ case RTW89_C2H_CAT_MAC:
+ return rtw89_mac_c2h_chk_atomic(rtwdev, class, func);
+ }
+}
+
void rtw89_fw_c2h_irqsafe(struct rtw89_dev *rtwdev, struct sk_buff *c2h)
{
+ rtw89_fw_c2h_parse_attr(c2h);
+ if (!rtw89_fw_c2h_chk_atomic(rtwdev, c2h))
+ goto enqueue;
+
+ rtw89_fw_c2h_cmd_handle(rtwdev, c2h);
+ dev_kfree_skb_any(c2h);
+ return;
+
+enqueue:
skb_queue_tail(&rtwdev->c2h_queue, c2h);
ieee80211_queue_work(rtwdev->hw, &rtwdev->c2h_work);
}
@@ -2391,10 +2429,11 @@ void rtw89_fw_c2h_irqsafe(struct rtw89_dev *rtwdev, struct sk_buff *c2h)
static void rtw89_fw_c2h_cmd_handle(struct rtw89_dev *rtwdev,
struct sk_buff *skb)
{
- u8 category = RTW89_GET_C2H_CATEGORY(skb->data);
- u8 class = RTW89_GET_C2H_CLASS(skb->data);
- u8 func = RTW89_GET_C2H_FUNC(skb->data);
- u16 len = RTW89_GET_C2H_LEN(skb->data);
+ struct rtw89_fw_c2h_attr *attr = RTW89_SKB_C2H_CB(skb);
+ u8 category = attr->category;
+ u8 class = attr->class;
+ u8 func = attr->func;
+ u16 len = attr->len;
bool dump = true;

if (!test_bit(RTW89_FLAG_RUNNING, rtwdev->flags))
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index 509a3eac5ffe3..d76d0c80f0256 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -2778,6 +2778,20 @@ static inline void RTW89_SET_FWCMD_TSF32_TOGL_EARLY(void *cmd, u32 val)
#define RTW89_GET_C2H_LEN(c2h) \
le32_get_bits(*((const __le32 *)(c2h) + 1), GENMASK(13, 0))

+struct rtw89_fw_c2h_attr {
+ u8 category;
+ u8 class;
+ u8 func;
+ u16 len;
+};
+
+static inline struct rtw89_fw_c2h_attr *RTW89_SKB_C2H_CB(struct sk_buff *skb)
+{
+ static_assert(sizeof(skb->cb) >= sizeof(struct rtw89_fw_c2h_attr));
+
+ return (struct rtw89_fw_c2h_attr *)skb->cb;
+}
+
#define RTW89_GET_C2H_LOG_SRT_PRT(c2h) (char *)((__le32 *)(c2h) + 2)
#define RTW89_GET_C2H_LOG_LEN(len) ((len) - RTW89_C2H_HEADER_LEN)

diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c
index ecd603a881345..df83d1bebe543 100644
--- a/drivers/net/wireless/realtek/rtw89/mac.c
+++ b/drivers/net/wireless/realtek/rtw89/mac.c
@@ -4201,6 +4201,16 @@ void (* const rtw89_mac_c2h_info_handler[])(struct rtw89_dev *rtwdev,
[RTW89_MAC_C2H_FUNC_BCN_CNT] = rtw89_mac_c2h_bcn_cnt,
};

+bool rtw89_mac_c2h_chk_atomic(struct rtw89_dev *rtwdev, u8 class, u8 func)
+{
+ switch (class) {
+ default:
+ return false;
+ case RTW89_MAC_C2H_CLASS_MCC:
+ return true;
+ }
+}
+
void rtw89_mac_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
u32 len, u8 class, u8 func)
{
diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h
index 045e8ec61a41e..82b9e81fe4744 100644
--- a/drivers/net/wireless/realtek/rtw89/mac.h
+++ b/drivers/net/wireless/realtek/rtw89/mac.h
@@ -894,6 +894,7 @@ static inline int rtw89_chip_disable_bb_rf(struct rtw89_dev *rtwdev)

u32 rtw89_mac_get_err_status(struct rtw89_dev *rtwdev);
int rtw89_mac_set_err_status(struct rtw89_dev *rtwdev, u32 err);
+bool rtw89_mac_c2h_chk_atomic(struct rtw89_dev *rtwdev, u8 class, u8 func);
void rtw89_mac_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
u32 len, u8 class, u8 func);
int rtw89_mac_setup_phycap(struct rtw89_dev *rtwdev);
--
2.25.1


2022-11-18 05:16:11

by Ping-Ke Shih

[permalink] [raw]
Subject: [PATCH 4/6] wifi: rtw89: mac: process MCC related C2H

From: Zong-Zhe Yang <[email protected]>

Process C2H(s) related to MCC (multi-channel concurrency). These handling,
which either call rtw89_complete_cond() or show message in debug mode, can
be considered atomic/lock-free. So, they should be safe to be processed
directly after C2H pre-check in previous patch.

Signed-off-by: Zong-Zhe Yang <[email protected]>
Signed-off-by: Ping-Ke Shih <[email protected]>
---
drivers/net/wireless/realtek/rtw89/core.c | 2 +
drivers/net/wireless/realtek/rtw89/core.h | 5 +
drivers/net/wireless/realtek/rtw89/fw.h | 66 +++++++++
drivers/net/wireless/realtek/rtw89/mac.c | 171 ++++++++++++++++++++++
drivers/net/wireless/realtek/rtw89/mac.h | 34 +++++
5 files changed, 278 insertions(+)

diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index e0b044a33207a..d7f80751eee3a 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -3097,6 +3097,8 @@ int rtw89_core_init(struct rtw89_dev *rtwdev)
mutex_init(&rtwdev->rf_mutex);
rtwdev->total_sta_assoc = 0;

+ rtw89_init_wait(&rtwdev->mcc.wait);
+
INIT_WORK(&rtwdev->c2h_work, rtw89_fw_c2h_work);
INIT_WORK(&rtwdev->ips_work, rtw89_ips_work);
skb_queue_head_init(&rtwdev->c2h_queue);
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 5a7d5514bba9a..cbcbf09dbb273 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -3542,6 +3542,10 @@ struct rtw89_wow_param {
struct list_head pkt_list;
};

+struct rtw89_mcc_info {
+ struct rtw89_wait_info wait;
+};
+
struct rtw89_dev {
struct ieee80211_hw *hw;
struct device *dev;
@@ -3552,6 +3556,7 @@ struct rtw89_dev {
const struct rtw89_chip_info *chip;
const struct rtw89_pci_info *pci_info;
struct rtw89_hal hal;
+ struct rtw89_mcc_info mcc;
struct rtw89_mac_info mac;
struct rtw89_fw_info fw;
struct rtw89_hci_info hci;
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index d76d0c80f0256..6d9c3dc58f037 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -2859,6 +2859,53 @@ static inline struct rtw89_fw_c2h_attr *RTW89_SKB_C2H_CB(struct sk_buff *skb)
#define RTW89_GET_MAC_C2H_SCANOFLD_BAND(c2h) \
le32_get_bits(*((const __le32 *)(c2h) + 5), GENMASK(25, 24))

+#define RTW89_GET_MAC_C2H_MCC_RCV_ACK_GROUP(c2h) \
+ le32_get_bits(*((const __le32 *)(c2h)), GENMASK(1, 0))
+#define RTW89_GET_MAC_C2H_MCC_RCV_ACK_H2C_FUNC(c2h) \
+ le32_get_bits(*((const __le32 *)(c2h)), GENMASK(15, 8))
+
+#define RTW89_GET_MAC_C2H_MCC_REQ_ACK_GROUP(c2h) \
+ le32_get_bits(*((const __le32 *)(c2h)), GENMASK(1, 0))
+#define RTW89_GET_MAC_C2H_MCC_REQ_ACK_H2C_RETURN(c2h) \
+ le32_get_bits(*((const __le32 *)(c2h)), GENMASK(7, 2))
+#define RTW89_GET_MAC_C2H_MCC_REQ_ACK_H2C_FUNC(c2h) \
+ le32_get_bits(*((const __le32 *)(c2h)), GENMASK(15, 8))
+
+struct rtw89_mac_mcc_tsf_rpt {
+ u32 macid_x;
+ u32 macid_y;
+ u32 tsf_x_low;
+ u32 tsf_x_high;
+ u32 tsf_y_low;
+ u32 tsf_y_high;
+};
+
+#define RTW89_GET_MAC_C2H_MCC_TSF_RPT_MACID_X(c2h) \
+ le32_get_bits(*((const __le32 *)(c2h)), GENMASK(7, 0))
+#define RTW89_GET_MAC_C2H_MCC_TSF_RPT_MACID_Y(c2h) \
+ le32_get_bits(*((const __le32 *)(c2h)), GENMASK(15, 8))
+#define RTW89_GET_MAC_C2H_MCC_TSF_RPT_GROUP(c2h) \
+ le32_get_bits(*((const __le32 *)(c2h)), GENMASK(17, 16))
+#define RTW89_GET_MAC_C2H_MCC_TSF_RPT_TSF_LOW_X(c2h) \
+ le32_get_bits(*((const __le32 *)(c2h) + 1), GENMASK(31, 0))
+#define RTW89_GET_MAC_C2H_MCC_TSF_RPT_TSF_HIGH_X(c2h) \
+ le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(31, 0))
+#define RTW89_GET_MAC_C2H_MCC_TSF_RPT_TSF_LOW_Y(c2h) \
+ le32_get_bits(*((const __le32 *)(c2h) + 3), GENMASK(31, 0))
+#define RTW89_GET_MAC_C2H_MCC_TSF_RPT_TSF_HIGH_Y(c2h) \
+ le32_get_bits(*((const __le32 *)(c2h) + 4), GENMASK(31, 0))
+
+#define RTW89_GET_MAC_C2H_MCC_STATUS_RPT_STATUS(c2h) \
+ le32_get_bits(*((const __le32 *)(c2h)), GENMASK(5, 0))
+#define RTW89_GET_MAC_C2H_MCC_STATUS_RPT_GROUP(c2h) \
+ le32_get_bits(*((const __le32 *)(c2h)), GENMASK(7, 6))
+#define RTW89_GET_MAC_C2H_MCC_STATUS_RPT_MACID(c2h) \
+ le32_get_bits(*((const __le32 *)(c2h)), GENMASK(15, 8))
+#define RTW89_GET_MAC_C2H_MCC_STATUS_RPT_TSF_LOW(c2h) \
+ le32_get_bits(*((const __le32 *)(c2h) + 1), GENMASK(31, 0))
+#define RTW89_GET_MAC_C2H_MCC_STATUS_RPT_TSF_HIGH(c2h) \
+ le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(31, 0))
+
#define RTW89_FW_HDR_SIZE 32
#define RTW89_FW_SECTION_HDR_SIZE 16

@@ -2980,6 +3027,25 @@ struct rtw89_fw_h2c_rf_reg_info {
#define H2C_CL_BA_CAM 0xc
#define H2C_FUNC_MAC_BA_CAM 0x0

+/* CLASS 14 - MCC */
+#define H2C_CL_MCC 0xe
+enum rtw89_mcc_h2c_func {
+ H2C_FUNC_ADD_MCC = 0x0,
+ H2C_FUNC_START_MCC = 0x1,
+ H2C_FUNC_STOP_MCC = 0x2,
+ H2C_FUNC_DEL_MCC_GROUP = 0x3,
+ H2C_FUNC_RESET_MCC_GROUP = 0x4,
+ H2C_FUNC_MCC_REQ_TSF = 0x5,
+ H2C_FUNC_MCC_MACID_BITMAP = 0x6,
+ H2C_FUNC_MCC_SYNC = 0x7,
+ H2C_FUNC_MCC_SET_DURATION = 0x8,
+
+ NUM_OF_RTW89_MCC_H2C_FUNC,
+};
+
+#define RTW89_MCC_WAIT_COND(group, func) \
+ ((group) * NUM_OF_RTW89_MCC_H2C_FUNC + (func))
+
#define H2C_CAT_OUTSRC 0x2

#define H2C_CL_OUTSRC_RA 0x1
diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c
index df83d1bebe543..6395c28f3d8ac 100644
--- a/drivers/net/wireless/realtek/rtw89/mac.c
+++ b/drivers/net/wireless/realtek/rtw89/mac.c
@@ -4180,6 +4180,164 @@ rtw89_mac_c2h_tsf32_toggle_rpt(struct rtw89_dev *rtwdev, struct sk_buff *c2h,
{
}

+static void
+rtw89_mac_c2h_mcc_rcv_ack(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
+{
+ u8 group = RTW89_GET_MAC_C2H_MCC_RCV_ACK_GROUP(c2h->data);
+ u8 func = RTW89_GET_MAC_C2H_MCC_RCV_ACK_H2C_FUNC(c2h->data);
+
+ switch (func) {
+ case H2C_FUNC_ADD_MCC:
+ case H2C_FUNC_START_MCC:
+ case H2C_FUNC_STOP_MCC:
+ case H2C_FUNC_DEL_MCC_GROUP:
+ case H2C_FUNC_RESET_MCC_GROUP:
+ case H2C_FUNC_MCC_REQ_TSF:
+ case H2C_FUNC_MCC_MACID_BITMAP:
+ case H2C_FUNC_MCC_SYNC:
+ case H2C_FUNC_MCC_SET_DURATION:
+ break;
+ default:
+ rtw89_debug(rtwdev, RTW89_DBG_FW,
+ "invalid MCC C2H RCV ACK: func %d\n", func);
+ return;
+ }
+
+ rtw89_debug(rtwdev, RTW89_DBG_FW,
+ "MCC C2H RCV ACK: group %d, func %d\n", group, func);
+}
+
+static void
+rtw89_mac_c2h_mcc_req_ack(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
+{
+ u8 group = RTW89_GET_MAC_C2H_MCC_REQ_ACK_GROUP(c2h->data);
+ u8 func = RTW89_GET_MAC_C2H_MCC_REQ_ACK_H2C_FUNC(c2h->data);
+ u8 retcode = RTW89_GET_MAC_C2H_MCC_REQ_ACK_H2C_RETURN(c2h->data);
+ struct rtw89_completion_data data = {};
+ unsigned int cond;
+ bool next = false;
+
+ switch (func) {
+ case H2C_FUNC_MCC_REQ_TSF:
+ next = true;
+ break;
+ case H2C_FUNC_MCC_MACID_BITMAP:
+ case H2C_FUNC_MCC_SYNC:
+ case H2C_FUNC_MCC_SET_DURATION:
+ break;
+ case H2C_FUNC_ADD_MCC:
+ case H2C_FUNC_START_MCC:
+ case H2C_FUNC_STOP_MCC:
+ case H2C_FUNC_DEL_MCC_GROUP:
+ case H2C_FUNC_RESET_MCC_GROUP:
+ default:
+ rtw89_debug(rtwdev, RTW89_DBG_FW,
+ "invalid MCC C2H REQ ACK: func %d\n", func);
+ return;
+ }
+
+ rtw89_debug(rtwdev, RTW89_DBG_FW,
+ "MCC C2H REQ ACK: group %d, func %d, return code %d\n",
+ group, func, retcode);
+
+ if (!retcode && next)
+ return;
+
+ data.err = !!retcode;
+ cond = RTW89_MCC_WAIT_COND(group, func);
+ rtw89_complete_cond(&rtwdev->mcc.wait, cond, &data);
+}
+
+static void
+rtw89_mac_c2h_mcc_tsf_rpt(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
+{
+ u8 group = RTW89_GET_MAC_C2H_MCC_TSF_RPT_GROUP(c2h->data);
+ struct rtw89_completion_data data = {};
+ struct rtw89_mac_mcc_tsf_rpt *rpt;
+ unsigned int cond;
+
+ rpt = rtw89_completion_cast(&data, rpt);
+ rpt->macid_x = RTW89_GET_MAC_C2H_MCC_TSF_RPT_MACID_X(c2h->data);
+ rpt->macid_y = RTW89_GET_MAC_C2H_MCC_TSF_RPT_MACID_Y(c2h->data);
+ rpt->tsf_x_low = RTW89_GET_MAC_C2H_MCC_TSF_RPT_TSF_LOW_X(c2h->data);
+ rpt->tsf_x_high = RTW89_GET_MAC_C2H_MCC_TSF_RPT_TSF_HIGH_X(c2h->data);
+ rpt->tsf_y_low = RTW89_GET_MAC_C2H_MCC_TSF_RPT_TSF_LOW_Y(c2h->data);
+ rpt->tsf_y_high = RTW89_GET_MAC_C2H_MCC_TSF_RPT_TSF_HIGH_Y(c2h->data);
+
+ cond = RTW89_MCC_WAIT_COND(group, H2C_FUNC_MCC_REQ_TSF);
+ rtw89_complete_cond(&rtwdev->mcc.wait, cond, &data);
+}
+
+static void
+rtw89_mac_c2h_mcc_status_rpt(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
+{
+ u8 group = RTW89_GET_MAC_C2H_MCC_STATUS_RPT_GROUP(c2h->data);
+ u8 macid = RTW89_GET_MAC_C2H_MCC_STATUS_RPT_MACID(c2h->data);
+ u8 status = RTW89_GET_MAC_C2H_MCC_STATUS_RPT_STATUS(c2h->data);
+ u32 tsf_low = RTW89_GET_MAC_C2H_MCC_STATUS_RPT_TSF_LOW(c2h->data);
+ u32 tsf_high = RTW89_GET_MAC_C2H_MCC_STATUS_RPT_TSF_HIGH(c2h->data);
+ struct rtw89_completion_data data = {};
+ unsigned int cond;
+ bool rsp = true;
+ bool err;
+ u8 func;
+
+ switch (status) {
+ case RTW89_MAC_MCC_ADD_ROLE_OK:
+ case RTW89_MAC_MCC_ADD_ROLE_FAIL:
+ func = H2C_FUNC_ADD_MCC;
+ err = status == RTW89_MAC_MCC_ADD_ROLE_FAIL;
+ break;
+ case RTW89_MAC_MCC_START_GROUP_OK:
+ case RTW89_MAC_MCC_START_GROUP_FAIL:
+ func = H2C_FUNC_START_MCC;
+ err = status == RTW89_MAC_MCC_START_GROUP_FAIL;
+ break;
+ case RTW89_MAC_MCC_STOP_GROUP_OK:
+ case RTW89_MAC_MCC_STOP_GROUP_FAIL:
+ func = H2C_FUNC_STOP_MCC;
+ err = status == RTW89_MAC_MCC_STOP_GROUP_FAIL;
+ break;
+ case RTW89_MAC_MCC_DEL_GROUP_OK:
+ case RTW89_MAC_MCC_DEL_GROUP_FAIL:
+ func = H2C_FUNC_DEL_MCC_GROUP;
+ err = status == RTW89_MAC_MCC_DEL_GROUP_FAIL;
+ break;
+ case RTW89_MAC_MCC_RESET_GROUP_OK:
+ case RTW89_MAC_MCC_RESET_GROUP_FAIL:
+ func = H2C_FUNC_RESET_MCC_GROUP;
+ err = status == RTW89_MAC_MCC_RESET_GROUP_FAIL;
+ break;
+ case RTW89_MAC_MCC_SWITCH_CH_OK:
+ case RTW89_MAC_MCC_SWITCH_CH_FAIL:
+ case RTW89_MAC_MCC_TXNULL0_OK:
+ case RTW89_MAC_MCC_TXNULL0_FAIL:
+ case RTW89_MAC_MCC_TXNULL1_OK:
+ case RTW89_MAC_MCC_TXNULL1_FAIL:
+ case RTW89_MAC_MCC_SWITCH_EARLY:
+ case RTW89_MAC_MCC_TBTT:
+ case RTW89_MAC_MCC_DURATION_START:
+ case RTW89_MAC_MCC_DURATION_END:
+ rsp = false;
+ break;
+ default:
+ rtw89_debug(rtwdev, RTW89_DBG_FW,
+ "invalid MCC C2H STS RPT: status %d\n", status);
+ return;
+ }
+
+ rtw89_debug(rtwdev, RTW89_DBG_FW,
+ "MCC C2H STS RPT: group %d, macid %d, status %d, tsf {%d, %d}\n",
+ group, macid, status, tsf_low, tsf_high);
+
+ if (!rsp)
+ return;
+
+ data.err = err;
+ cond = RTW89_MCC_WAIT_COND(group, func);
+ rtw89_complete_cond(&rtwdev->mcc.wait, cond, &data);
+}
+
static
void (* const rtw89_mac_c2h_ofld_handler[])(struct rtw89_dev *rtwdev,
struct sk_buff *c2h, u32 len) = {
@@ -4201,6 +4359,15 @@ void (* const rtw89_mac_c2h_info_handler[])(struct rtw89_dev *rtwdev,
[RTW89_MAC_C2H_FUNC_BCN_CNT] = rtw89_mac_c2h_bcn_cnt,
};

+static
+void (* const rtw89_mac_c2h_mcc_handler[])(struct rtw89_dev *rtwdev,
+ struct sk_buff *c2h, u32 len) = {
+ [RTW89_MAC_C2H_FUNC_MCC_RCV_ACK] = rtw89_mac_c2h_mcc_rcv_ack,
+ [RTW89_MAC_C2H_FUNC_MCC_REQ_ACK] = rtw89_mac_c2h_mcc_req_ack,
+ [RTW89_MAC_C2H_FUNC_MCC_TSF_RPT] = rtw89_mac_c2h_mcc_tsf_rpt,
+ [RTW89_MAC_C2H_FUNC_MCC_STATUS_RPT] = rtw89_mac_c2h_mcc_status_rpt,
+};
+
bool rtw89_mac_c2h_chk_atomic(struct rtw89_dev *rtwdev, u8 class, u8 func)
{
switch (class) {
@@ -4226,6 +4393,10 @@ void rtw89_mac_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
if (func < RTW89_MAC_C2H_FUNC_OFLD_MAX)
handler = rtw89_mac_c2h_ofld_handler[func];
break;
+ case RTW89_MAC_C2H_CLASS_MCC:
+ if (func < NUM_OF_RTW89_MAC_C2H_FUNC_MCC)
+ handler = rtw89_mac_c2h_mcc_handler[func];
+ break;
case RTW89_MAC_C2H_CLASS_FWDBG:
return;
default:
diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h
index 82b9e81fe4744..adb0c86a98d3e 100644
--- a/drivers/net/wireless/realtek/rtw89/mac.h
+++ b/drivers/net/wireless/realtek/rtw89/mac.h
@@ -368,6 +368,15 @@ enum rtw89_mac_c2h_info_func {
RTW89_MAC_C2H_FUNC_INFO_MAX,
};

+enum rtw89_mac_c2h_mcc_func {
+ RTW89_MAC_C2H_FUNC_MCC_RCV_ACK = 0,
+ RTW89_MAC_C2H_FUNC_MCC_REQ_ACK = 1,
+ RTW89_MAC_C2H_FUNC_MCC_TSF_RPT = 2,
+ RTW89_MAC_C2H_FUNC_MCC_STATUS_RPT = 3,
+
+ NUM_OF_RTW89_MAC_C2H_FUNC_MCC,
+};
+
enum rtw89_mac_c2h_class {
RTW89_MAC_C2H_CLASS_INFO,
RTW89_MAC_C2H_CLASS_OFLD,
@@ -378,6 +387,31 @@ enum rtw89_mac_c2h_class {
RTW89_MAC_C2H_CLASS_MAX,
};

+enum rtw89_mac_mcc_status {
+ RTW89_MAC_MCC_ADD_ROLE_OK = 0,
+ RTW89_MAC_MCC_START_GROUP_OK = 1,
+ RTW89_MAC_MCC_STOP_GROUP_OK = 2,
+ RTW89_MAC_MCC_DEL_GROUP_OK = 3,
+ RTW89_MAC_MCC_RESET_GROUP_OK = 4,
+ RTW89_MAC_MCC_SWITCH_CH_OK = 5,
+ RTW89_MAC_MCC_TXNULL0_OK = 6,
+ RTW89_MAC_MCC_TXNULL1_OK = 7,
+
+ RTW89_MAC_MCC_SWITCH_EARLY = 10,
+ RTW89_MAC_MCC_TBTT = 11,
+ RTW89_MAC_MCC_DURATION_START = 12,
+ RTW89_MAC_MCC_DURATION_END = 13,
+
+ RTW89_MAC_MCC_ADD_ROLE_FAIL = 20,
+ RTW89_MAC_MCC_START_GROUP_FAIL = 21,
+ RTW89_MAC_MCC_STOP_GROUP_FAIL = 22,
+ RTW89_MAC_MCC_DEL_GROUP_FAIL = 23,
+ RTW89_MAC_MCC_RESET_GROUP_FAIL = 24,
+ RTW89_MAC_MCC_SWITCH_CH_FAIL = 25,
+ RTW89_MAC_MCC_TXNULL0_FAIL = 26,
+ RTW89_MAC_MCC_TXNULL1_FAIL = 27,
+};
+
struct rtw89_mac_ax_coex {
#define RTW89_MAC_AX_COEX_RTK_MODE 0
#define RTW89_MAC_AX_COEX_CSR_MODE 1
--
2.25.1


2022-11-18 05:16:26

by Ping-Ke Shih

[permalink] [raw]
Subject: [PATCH 6/6] wifi: rtw89: link rtw89_vif and chanctx stuffs

From: Zong-Zhe Yang <[email protected]>

First, introduce struct rtw89_sub_entity for chanctx related stuffs.
Second, add enum rtw89_sub_entity_idx to rtw89_vif for vif operation
to access its/right chanctx stuffs after future multi-channel support.

Besides, RTW89_SUB_ENTITY_0 is the default chanctx entry throughout
driver, i.e. it's used for things which may not have a target chanctx
yet. So, we need to ensure that RTW89_SUB_ENTITY_0 is always working.
If there is at least one alive chanctx, then one of them must take
RTW89_SUB_ENTITY_0. If no alive chanctx, RTW89_SUB_ENTITY_0 will be
filled by rtw89_config_default_chandef().

Signed-off-by: Zong-Zhe Yang <[email protected]>
Signed-off-by: Ping-Ke Shih <[email protected]>
---
drivers/net/wireless/realtek/rtw89/chan.c | 40 +++++++++++++++++--
drivers/net/wireless/realtek/rtw89/core.h | 20 ++++++----
drivers/net/wireless/realtek/rtw89/mac80211.c | 1 +
3 files changed, 50 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c
index a4f61c2f65123..90596806bc93f 100644
--- a/drivers/net/wireless/realtek/rtw89/chan.c
+++ b/drivers/net/wireless/realtek/rtw89/chan.c
@@ -4,6 +4,7 @@

#include "chan.h"
#include "debug.h"
+#include "util.h"

static enum rtw89_subband rtw89_get_subband_type(enum rtw89_band band,
u8 center_chan)
@@ -108,8 +109,8 @@ bool rtw89_assign_entity_chan(struct rtw89_dev *rtwdev,
const struct rtw89_chan *new)
{
struct rtw89_hal *hal = &rtwdev->hal;
- struct rtw89_chan *chan = &hal->chan[idx];
- struct rtw89_chan_rcd *rcd = &hal->chan_rcd[idx];
+ struct rtw89_chan *chan = &hal->sub[idx].chan;
+ struct rtw89_chan_rcd *rcd = &hal->sub[idx].rcd;
bool band_changed;

rcd->prev_primary_channel = chan->primary_channel;
@@ -127,7 +128,7 @@ static void __rtw89_config_entity_chandef(struct rtw89_dev *rtwdev,
{
struct rtw89_hal *hal = &rtwdev->hal;

- hal->chandef[idx] = *chandef;
+ hal->sub[idx].chandef = *chandef;

if (from_stack)
set_bit(idx, hal->entity_map);
@@ -195,6 +196,7 @@ int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev,
rtw89_config_entity_chandef(rtwdev, idx, &ctx->def);
rtw89_set_channel(rtwdev);
cfg->idx = idx;
+ hal->sub[idx].cfg = cfg;
return 0;
}

@@ -203,8 +205,34 @@ void rtw89_chanctx_ops_remove(struct rtw89_dev *rtwdev,
{
struct rtw89_hal *hal = &rtwdev->hal;
struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
+ struct rtw89_vif *rtwvif;
+ u8 drop, roll;

- clear_bit(cfg->idx, hal->entity_map);
+ drop = cfg->idx;
+ if (drop != RTW89_SUB_ENTITY_0)
+ goto out;
+
+ roll = find_next_bit(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY, drop + 1);
+
+ /* Follow rtw89_config_default_chandef() when rtw89_entity_recalc(). */
+ if (roll == NUM_OF_RTW89_SUB_ENTITY)
+ goto out;
+
+ /* RTW89_SUB_ENTITY_0 is going to release, and another exists.
+ * Make another roll down to RTW89_SUB_ENTITY_0 to replace.
+ */
+ hal->sub[roll].cfg->idx = RTW89_SUB_ENTITY_0;
+ hal->sub[RTW89_SUB_ENTITY_0] = hal->sub[roll];
+
+ rtw89_for_each_rtwvif(rtwdev, rtwvif) {
+ if (rtwvif->sub_entity_idx == roll)
+ rtwvif->sub_entity_idx = RTW89_SUB_ENTITY_0;
+ }
+
+ drop = roll;
+
+out:
+ clear_bit(drop, hal->entity_map);
rtw89_set_channel(rtwdev);
}

@@ -225,6 +253,9 @@ int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev,
struct rtw89_vif *rtwvif,
struct ieee80211_chanctx_conf *ctx)
{
+ struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
+
+ rtwvif->sub_entity_idx = cfg->idx;
return 0;
}

@@ -232,4 +263,5 @@ void rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev,
struct rtw89_vif *rtwvif,
struct ieee80211_chanctx_conf *ctx)
{
+ rtwvif->sub_entity_idx = RTW89_SUB_ENTITY_0;
}
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index cbcbf09dbb273..fdf0a2d63d53c 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -2239,6 +2239,8 @@ struct rtw89_phy_rate_pattern {
struct rtw89_vif {
struct list_head list;
struct rtw89_dev *rtwdev;
+ enum rtw89_sub_entity_idx sub_entity_idx;
+
u8 mac_id;
u8 port;
u8 mac_addr[ETH_ALEN];
@@ -2949,6 +2951,13 @@ enum rtw89_entity_mode {
RTW89_ENTITY_MODE_SCC,
};

+struct rtw89_sub_entity {
+ struct cfg80211_chan_def chandef;
+ struct rtw89_chan chan;
+ struct rtw89_chan_rcd rcd;
+ struct rtw89_chanctx_cfg *cfg;
+};
+
struct rtw89_hal {
u32 rx_fltr;
u8 cv;
@@ -2962,13 +2971,10 @@ struct rtw89_hal {
bool support_igi;

DECLARE_BITMAP(entity_map, NUM_OF_RTW89_SUB_ENTITY);
- struct cfg80211_chan_def chandef[NUM_OF_RTW89_SUB_ENTITY];
+ struct rtw89_sub_entity sub[NUM_OF_RTW89_SUB_ENTITY];

bool entity_active;
enum rtw89_entity_mode entity_mode;
-
- struct rtw89_chan chan[NUM_OF_RTW89_SUB_ENTITY];
- struct rtw89_chan_rcd chan_rcd[NUM_OF_RTW89_SUB_ENTITY];
};

#define RTW89_MAX_MAC_ID_NUM 128
@@ -4132,7 +4138,7 @@ const struct cfg80211_chan_def *rtw89_chandef_get(struct rtw89_dev *rtwdev,
{
struct rtw89_hal *hal = &rtwdev->hal;

- return &hal->chandef[idx];
+ return &hal->sub[idx].chandef;
}

static inline
@@ -4141,7 +4147,7 @@ const struct rtw89_chan *rtw89_chan_get(struct rtw89_dev *rtwdev,
{
struct rtw89_hal *hal = &rtwdev->hal;

- return &hal->chan[idx];
+ return &hal->sub[idx].chan;
}

static inline
@@ -4150,7 +4156,7 @@ const struct rtw89_chan_rcd *rtw89_chan_rcd_get(struct rtw89_dev *rtwdev,
{
struct rtw89_hal *hal = &rtwdev->hal;

- return &hal->chan_rcd[idx];
+ return &hal->sub[idx].rcd;
}

static inline void rtw89_chip_fem_setup(struct rtw89_dev *rtwdev)
diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c
index 6e79bf899901d..3c8c7c6adbf08 100644
--- a/drivers/net/wireless/realtek/rtw89/mac80211.c
+++ b/drivers/net/wireless/realtek/rtw89/mac80211.c
@@ -131,6 +131,7 @@ static int rtw89_ops_add_interface(struct ieee80211_hw *hw,
rtwvif->bcn_hit_cond = 0;
rtwvif->mac_idx = RTW89_MAC_0;
rtwvif->phy_idx = RTW89_PHY_0;
+ rtwvif->sub_entity_idx = RTW89_SUB_ENTITY_0;
rtwvif->hit_rule = 0;
ether_addr_copy(rtwvif->mac_addr, vif->addr);

--
2.25.1


2022-11-18 05:16:27

by Ping-Ke Shih

[permalink] [raw]
Subject: [PATCH 5/6] wifi: rtw89: fw: implement MCC related H2C

From: Zong-Zhe Yang <[email protected]>

These MCC H2C(s) require to wait for MCC C2H to determine if the
execution is successful. Through rtw89_wait_for_cond(), we make
them wait for either a completion with data from MCC C2H handlers,
which calls rtw89_complete_cond(), or timeout.

Signed-off-by: Zong-Zhe Yang <[email protected]>
Signed-off-by: Ping-Ke Shih <[email protected]>
---
drivers/net/wireless/realtek/rtw89/fw.c | 329 +++++++++++++++++++++
drivers/net/wireless/realtek/rtw89/fw.h | 369 +++++++++++++++++++++++-
2 files changed, 697 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index 544f6d4b68735..c469fd1322803 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -3263,3 +3263,332 @@ int rtw89_fw_wow_cam_update(struct rtw89_dev *rtwdev,

return ret;
}
+
+static int rtw89_h2c_tx_and_wait(struct rtw89_dev *rtwdev, struct sk_buff *skb,
+ struct rtw89_wait_info *wait, unsigned int cond)
+{
+ int ret;
+
+ ret = rtw89_h2c_tx(rtwdev, skb, false);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+ dev_kfree_skb_any(skb);
+ return -EBUSY;
+ }
+
+ return rtw89_wait_for_cond(wait, cond);
+}
+
+#define H2C_ADD_MCC_LEN 16
+int rtw89_fw_h2c_add_mcc(struct rtw89_dev *rtwdev,
+ const struct rtw89_fw_mcc_add_req *p)
+{
+ struct rtw89_wait_info *wait = &rtwdev->mcc.wait;
+ struct sk_buff *skb;
+ unsigned int cond;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_ADD_MCC_LEN);
+ if (!skb) {
+ rtw89_err(rtwdev,
+ "failed to alloc skb for add mcc\n");
+ return -ENOMEM;
+ }
+
+ skb_put(skb, H2C_ADD_MCC_LEN);
+ RTW89_SET_FWCMD_ADD_MCC_MACID(skb->data, p->macid);
+ RTW89_SET_FWCMD_ADD_MCC_CENTRAL_CH_SEG0(skb->data, p->central_ch_seg0);
+ RTW89_SET_FWCMD_ADD_MCC_CENTRAL_CH_SEG1(skb->data, p->central_ch_seg1);
+ RTW89_SET_FWCMD_ADD_MCC_PRIMARY_CH(skb->data, p->primary_ch);
+ RTW89_SET_FWCMD_ADD_MCC_BANDWIDTH(skb->data, p->bandwidth);
+ RTW89_SET_FWCMD_ADD_MCC_GROUP(skb->data, p->group);
+ RTW89_SET_FWCMD_ADD_MCC_C2H_RPT(skb->data, p->c2h_rpt);
+ RTW89_SET_FWCMD_ADD_MCC_DIS_TX_NULL(skb->data, p->dis_tx_null);
+ RTW89_SET_FWCMD_ADD_MCC_DIS_SW_RETRY(skb->data, p->dis_sw_retry);
+ RTW89_SET_FWCMD_ADD_MCC_IN_CURR_CH(skb->data, p->in_curr_ch);
+ RTW89_SET_FWCMD_ADD_MCC_SW_RETRY_COUNT(skb->data, p->sw_retry_count);
+ RTW89_SET_FWCMD_ADD_MCC_TX_NULL_EARLY(skb->data, p->tx_null_early);
+ RTW89_SET_FWCMD_ADD_MCC_BTC_IN_2G(skb->data, p->btc_in_2g);
+ RTW89_SET_FWCMD_ADD_MCC_PTA_EN(skb->data, p->pta_en);
+ RTW89_SET_FWCMD_ADD_MCC_RFK_BY_PASS(skb->data, p->rfk_by_pass);
+ RTW89_SET_FWCMD_ADD_MCC_CH_BAND_TYPE(skb->data, p->ch_band_type);
+ RTW89_SET_FWCMD_ADD_MCC_DURATION(skb->data, p->duration);
+ RTW89_SET_FWCMD_ADD_MCC_COURTESY_EN(skb->data, p->courtesy_en);
+ RTW89_SET_FWCMD_ADD_MCC_COURTESY_NUM(skb->data, p->courtesy_num);
+ RTW89_SET_FWCMD_ADD_MCC_COURTESY_TARGET(skb->data, p->courtesy_target);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_MAC,
+ H2C_CL_MCC,
+ H2C_FUNC_ADD_MCC, 0, 0,
+ H2C_ADD_MCC_LEN);
+
+ cond = RTW89_MCC_WAIT_COND(p->group, H2C_FUNC_ADD_MCC);
+ return rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond);
+}
+
+#define H2C_START_MCC_LEN 12
+int rtw89_fw_h2c_start_mcc(struct rtw89_dev *rtwdev,
+ const struct rtw89_fw_mcc_start_req *p)
+{
+ struct rtw89_wait_info *wait = &rtwdev->mcc.wait;
+ struct sk_buff *skb;
+ unsigned int cond;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_START_MCC_LEN);
+ if (!skb) {
+ rtw89_err(rtwdev,
+ "failed to alloc skb for start mcc\n");
+ return -ENOMEM;
+ }
+
+ skb_put(skb, H2C_START_MCC_LEN);
+ RTW89_SET_FWCMD_START_MCC_GROUP(skb->data, p->group);
+ RTW89_SET_FWCMD_START_MCC_BTC_IN_GROUP(skb->data, p->btc_in_group);
+ RTW89_SET_FWCMD_START_MCC_OLD_GROUP_ACTION(skb->data, p->old_group_action);
+ RTW89_SET_FWCMD_START_MCC_OLD_GROUP(skb->data, p->old_group);
+ RTW89_SET_FWCMD_START_MCC_NOTIFY_CNT(skb->data, p->notify_cnt);
+ RTW89_SET_FWCMD_START_MCC_NOTIFY_RXDBG_EN(skb->data, p->notify_rxdbg_en);
+ RTW89_SET_FWCMD_START_MCC_MACID(skb->data, p->macid);
+ RTW89_SET_FWCMD_START_MCC_TSF_LOW(skb->data, p->tsf_low);
+ RTW89_SET_FWCMD_START_MCC_TSF_HIGH(skb->data, p->tsf_high);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_MAC,
+ H2C_CL_MCC,
+ H2C_FUNC_START_MCC, 0, 0,
+ H2C_START_MCC_LEN);
+
+ cond = RTW89_MCC_WAIT_COND(p->group, H2C_FUNC_START_MCC);
+ return rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond);
+}
+
+#define H2C_STOP_MCC_LEN 4
+int rtw89_fw_h2c_stop_mcc(struct rtw89_dev *rtwdev, u8 group, u8 macid,
+ bool prev_groups)
+{
+ struct rtw89_wait_info *wait = &rtwdev->mcc.wait;
+ struct sk_buff *skb;
+ unsigned int cond;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_STOP_MCC_LEN);
+ if (!skb) {
+ rtw89_err(rtwdev,
+ "failed to alloc skb for stop mcc\n");
+ return -ENOMEM;
+ }
+
+ skb_put(skb, H2C_STOP_MCC_LEN);
+ RTW89_SET_FWCMD_STOP_MCC_MACID(skb->data, macid);
+ RTW89_SET_FWCMD_STOP_MCC_GROUP(skb->data, group);
+ RTW89_SET_FWCMD_STOP_MCC_PREV_GROUPS(skb->data, prev_groups);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_MAC,
+ H2C_CL_MCC,
+ H2C_FUNC_STOP_MCC, 0, 0,
+ H2C_STOP_MCC_LEN);
+
+ cond = RTW89_MCC_WAIT_COND(group, H2C_FUNC_STOP_MCC);
+ return rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond);
+}
+
+#define H2C_DEL_MCC_GROUP_LEN 4
+int rtw89_fw_h2c_del_mcc_group(struct rtw89_dev *rtwdev, u8 group,
+ bool prev_groups)
+{
+ struct rtw89_wait_info *wait = &rtwdev->mcc.wait;
+ struct sk_buff *skb;
+ unsigned int cond;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_DEL_MCC_GROUP_LEN);
+ if (!skb) {
+ rtw89_err(rtwdev,
+ "failed to alloc skb for del mcc group\n");
+ return -ENOMEM;
+ }
+
+ skb_put(skb, H2C_DEL_MCC_GROUP_LEN);
+ RTW89_SET_FWCMD_DEL_MCC_GROUP_GROUP(skb->data, group);
+ RTW89_SET_FWCMD_DEL_MCC_GROUP_PREV_GROUPS(skb->data, prev_groups);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_MAC,
+ H2C_CL_MCC,
+ H2C_FUNC_DEL_MCC_GROUP, 0, 0,
+ H2C_DEL_MCC_GROUP_LEN);
+
+ cond = RTW89_MCC_WAIT_COND(group, H2C_FUNC_DEL_MCC_GROUP);
+ return rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond);
+}
+
+#define H2C_RESET_MCC_GROUP_LEN 4
+int rtw89_fw_h2c_reset_mcc_group(struct rtw89_dev *rtwdev, u8 group)
+{
+ struct rtw89_wait_info *wait = &rtwdev->mcc.wait;
+ struct sk_buff *skb;
+ unsigned int cond;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_RESET_MCC_GROUP_LEN);
+ if (!skb) {
+ rtw89_err(rtwdev,
+ "failed to alloc skb for reset mcc group\n");
+ return -ENOMEM;
+ }
+
+ skb_put(skb, H2C_RESET_MCC_GROUP_LEN);
+ RTW89_SET_FWCMD_RESET_MCC_GROUP_GROUP(skb->data, group);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_MAC,
+ H2C_CL_MCC,
+ H2C_FUNC_RESET_MCC_GROUP, 0, 0,
+ H2C_RESET_MCC_GROUP_LEN);
+
+ cond = RTW89_MCC_WAIT_COND(group, H2C_FUNC_RESET_MCC_GROUP);
+ return rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond);
+}
+
+#define H2C_MCC_REQ_TSF_LEN 4
+int rtw89_fw_h2c_mcc_req_tsf(struct rtw89_dev *rtwdev,
+ const struct rtw89_fw_mcc_tsf_req *req,
+ struct rtw89_mac_mcc_tsf_rpt *rpt)
+{
+ struct rtw89_wait_info *wait = &rtwdev->mcc.wait;
+ struct rtw89_mac_mcc_tsf_rpt *tmp;
+ struct sk_buff *skb;
+ unsigned int cond;
+ int ret;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_MCC_REQ_TSF_LEN);
+ if (!skb) {
+ rtw89_err(rtwdev,
+ "failed to alloc skb for mcc req tsf\n");
+ return -ENOMEM;
+ }
+
+ skb_put(skb, H2C_MCC_REQ_TSF_LEN);
+ RTW89_SET_FWCMD_MCC_REQ_TSF_GROUP(skb->data, req->group);
+ RTW89_SET_FWCMD_MCC_REQ_TSF_MACID_X(skb->data, req->macid_x);
+ RTW89_SET_FWCMD_MCC_REQ_TSF_MACID_Y(skb->data, req->macid_y);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_MAC,
+ H2C_CL_MCC,
+ H2C_FUNC_MCC_REQ_TSF, 0, 0,
+ H2C_MCC_REQ_TSF_LEN);
+
+ cond = RTW89_MCC_WAIT_COND(req->group, H2C_FUNC_MCC_REQ_TSF);
+ ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond);
+ if (ret)
+ return ret;
+
+ tmp = rtw89_completion_cast(&wait->data, rpt);
+ *rpt = *tmp;
+
+ return 0;
+}
+
+#define H2C_MCC_MACID_BITMAP_DSC_LEN 4
+int rtw89_fw_h2c_mcc_macid_bitamp(struct rtw89_dev *rtwdev, u8 group, u8 macid,
+ u8 *bitmap)
+{
+ struct rtw89_wait_info *wait = &rtwdev->mcc.wait;
+ struct sk_buff *skb;
+ unsigned int cond;
+ u8 map_len;
+ u8 h2c_len;
+
+ BUILD_BUG_ON(RTW89_MAX_MAC_ID_NUM % 8);
+ map_len = RTW89_MAX_MAC_ID_NUM / 8;
+ h2c_len = H2C_MCC_MACID_BITMAP_DSC_LEN + map_len;
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, h2c_len);
+ if (!skb) {
+ rtw89_err(rtwdev,
+ "failed to alloc skb for mcc macid bitmap\n");
+ return -ENOMEM;
+ }
+
+ skb_put(skb, h2c_len);
+ RTW89_SET_FWCMD_MCC_MACID_BITMAP_GROUP(skb->data, group);
+ RTW89_SET_FWCMD_MCC_MACID_BITMAP_MACID(skb->data, macid);
+ RTW89_SET_FWCMD_MCC_MACID_BITMAP_BITMAP_LENGTH(skb->data, map_len);
+ RTW89_SET_FWCMD_MCC_MACID_BITMAP_BITMAP(skb->data, bitmap, map_len);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_MAC,
+ H2C_CL_MCC,
+ H2C_FUNC_MCC_MACID_BITMAP, 0, 0,
+ h2c_len);
+
+ cond = RTW89_MCC_WAIT_COND(group, H2C_FUNC_MCC_MACID_BITMAP);
+ return rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond);
+}
+
+#define H2C_MCC_SYNC_LEN 4
+int rtw89_fw_h2c_mcc_sync(struct rtw89_dev *rtwdev, u8 group, u8 source,
+ u8 target, u8 offset)
+{
+ struct rtw89_wait_info *wait = &rtwdev->mcc.wait;
+ struct sk_buff *skb;
+ unsigned int cond;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_MCC_SYNC_LEN);
+ if (!skb) {
+ rtw89_err(rtwdev,
+ "failed to alloc skb for mcc sync\n");
+ return -ENOMEM;
+ }
+
+ skb_put(skb, H2C_MCC_SYNC_LEN);
+ RTW89_SET_FWCMD_MCC_SYNC_GROUP(skb->data, group);
+ RTW89_SET_FWCMD_MCC_SYNC_MACID_SOURCE(skb->data, source);
+ RTW89_SET_FWCMD_MCC_SYNC_MACID_TARGET(skb->data, target);
+ RTW89_SET_FWCMD_MCC_SYNC_SYNC_OFFSET(skb->data, offset);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_MAC,
+ H2C_CL_MCC,
+ H2C_FUNC_MCC_SYNC, 0, 0,
+ H2C_MCC_SYNC_LEN);
+
+ cond = RTW89_MCC_WAIT_COND(group, H2C_FUNC_MCC_SYNC);
+ return rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond);
+}
+
+#define H2C_MCC_SET_DURATION_LEN 20
+int rtw89_fw_h2c_mcc_set_duration(struct rtw89_dev *rtwdev,
+ const struct rtw89_fw_mcc_duration *p)
+{
+ struct rtw89_wait_info *wait = &rtwdev->mcc.wait;
+ struct sk_buff *skb;
+ unsigned int cond;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_MCC_SET_DURATION_LEN);
+ if (!skb) {
+ rtw89_err(rtwdev,
+ "failed to alloc skb for mcc set duration\n");
+ return -ENOMEM;
+ }
+
+ skb_put(skb, H2C_MCC_SET_DURATION_LEN);
+ RTW89_SET_FWCMD_MCC_SET_DURATION_GROUP(skb->data, p->group);
+ RTW89_SET_FWCMD_MCC_SET_DURATION_BTC_IN_GROUP(skb->data, p->btc_in_group);
+ RTW89_SET_FWCMD_MCC_SET_DURATION_START_MACID(skb->data, p->start_macid);
+ RTW89_SET_FWCMD_MCC_SET_DURATION_MACID_X(skb->data, p->macid_x);
+ RTW89_SET_FWCMD_MCC_SET_DURATION_MACID_Y(skb->data, p->macid_y);
+ RTW89_SET_FWCMD_MCC_SET_DURATION_START_TSF_LOW(skb->data,
+ p->start_tsf_low);
+ RTW89_SET_FWCMD_MCC_SET_DURATION_START_TSF_HIGH(skb->data,
+ p->start_tsf_high);
+ RTW89_SET_FWCMD_MCC_SET_DURATION_DURATION_X(skb->data, p->duration_x);
+ RTW89_SET_FWCMD_MCC_SET_DURATION_DURATION_Y(skb->data, p->duration_y);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_MAC,
+ H2C_CL_MCC,
+ H2C_FUNC_MCC_SET_DURATION, 0, 0,
+ H2C_MCC_SET_DURATION_LEN);
+
+ cond = RTW89_MCC_WAIT_COND(p->group, H2C_FUNC_MCC_SET_DURATION);
+ return rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond);
+}
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index 6d9c3dc58f037..6d53d1a6c907c 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -2767,6 +2767,355 @@ static inline void RTW89_SET_FWCMD_TSF32_TOGL_EARLY(void *cmd, u32 val)
le32p_replace_bits((__le32 *)cmd, val, GENMASK(31, 16));
}

+enum rtw89_fw_mcc_c2h_rpt_cfg {
+ RTW89_FW_MCC_C2H_RPT_OFF = 0,
+ RTW89_FW_MCC_C2H_RPT_FAIL_ONLY = 1,
+ RTW89_FW_MCC_C2H_RPT_ALL = 2,
+};
+
+struct rtw89_fw_mcc_add_req {
+ u8 macid;
+ u8 central_ch_seg0;
+ u8 central_ch_seg1;
+ u8 primary_ch;
+ enum rtw89_bandwidth bandwidth: 4;
+ u32 group: 2;
+ u32 c2h_rpt: 2;
+ u32 dis_tx_null: 1;
+ u32 dis_sw_retry: 1;
+ u32 in_curr_ch: 1;
+ u32 sw_retry_count: 3;
+ u32 tx_null_early: 4;
+ u32 btc_in_2g: 1;
+ u32 pta_en: 1;
+ u32 rfk_by_pass: 1;
+ u32 ch_band_type: 2;
+ u32 rsvd0: 9;
+ u32 duration;
+ u8 courtesy_en;
+ u8 courtesy_num;
+ u8 courtesy_target;
+ u8 rsvd1;
+};
+
+static inline void RTW89_SET_FWCMD_ADD_MCC_MACID(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, GENMASK(7, 0));
+}
+
+static inline void RTW89_SET_FWCMD_ADD_MCC_CENTRAL_CH_SEG0(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, GENMASK(15, 8));
+}
+
+static inline void RTW89_SET_FWCMD_ADD_MCC_CENTRAL_CH_SEG1(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, GENMASK(23, 16));
+}
+
+static inline void RTW89_SET_FWCMD_ADD_MCC_PRIMARY_CH(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, GENMASK(31, 24));
+}
+
+static inline void RTW89_SET_FWCMD_ADD_MCC_BANDWIDTH(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd + 1, val, GENMASK(3, 0));
+}
+
+static inline void RTW89_SET_FWCMD_ADD_MCC_GROUP(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd + 1, val, GENMASK(5, 4));
+}
+
+static inline void RTW89_SET_FWCMD_ADD_MCC_C2H_RPT(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd + 1, val, GENMASK(7, 6));
+}
+
+static inline void RTW89_SET_FWCMD_ADD_MCC_DIS_TX_NULL(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd + 1, val, BIT(8));
+}
+
+static inline void RTW89_SET_FWCMD_ADD_MCC_DIS_SW_RETRY(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd + 1, val, BIT(9));
+}
+
+static inline void RTW89_SET_FWCMD_ADD_MCC_IN_CURR_CH(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd + 1, val, BIT(10));
+}
+
+static inline void RTW89_SET_FWCMD_ADD_MCC_SW_RETRY_COUNT(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd + 1, val, GENMASK(13, 11));
+}
+
+static inline void RTW89_SET_FWCMD_ADD_MCC_TX_NULL_EARLY(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd + 1, val, GENMASK(17, 14));
+}
+
+static inline void RTW89_SET_FWCMD_ADD_MCC_BTC_IN_2G(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd + 1, val, BIT(18));
+}
+
+static inline void RTW89_SET_FWCMD_ADD_MCC_PTA_EN(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd + 1, val, BIT(19));
+}
+
+static inline void RTW89_SET_FWCMD_ADD_MCC_RFK_BY_PASS(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd + 1, val, BIT(20));
+}
+
+static inline void RTW89_SET_FWCMD_ADD_MCC_CH_BAND_TYPE(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd + 1, val, GENMASK(22, 21));
+}
+
+static inline void RTW89_SET_FWCMD_ADD_MCC_DURATION(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd + 2, val, GENMASK(31, 0));
+}
+
+static inline void RTW89_SET_FWCMD_ADD_MCC_COURTESY_EN(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd + 3, val, BIT(0));
+}
+
+static inline void RTW89_SET_FWCMD_ADD_MCC_COURTESY_NUM(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd + 3, val, GENMASK(15, 8));
+}
+
+static inline void RTW89_SET_FWCMD_ADD_MCC_COURTESY_TARGET(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd + 3, val, GENMASK(23, 16));
+}
+
+struct rtw89_fw_mcc_start_req {
+ u32 group: 2;
+ u32 btc_in_group: 1;
+ u32 old_group_action: 2;
+ u32 old_group: 2;
+ u32 rsvd0: 9;
+ u32 notify_cnt: 3;
+ u32 rsvd1: 2;
+ u32 notify_rxdbg_en: 1;
+ u32 rsvd2: 2;
+ u32 macid: 8;
+ u32 tsf_low;
+ u32 tsf_high;
+};
+
+static inline void RTW89_SET_FWCMD_START_MCC_GROUP(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, GENMASK(1, 0));
+}
+
+static inline void RTW89_SET_FWCMD_START_MCC_BTC_IN_GROUP(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, BIT(2));
+}
+
+static inline void RTW89_SET_FWCMD_START_MCC_OLD_GROUP_ACTION(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, GENMASK(4, 3));
+}
+
+static inline void RTW89_SET_FWCMD_START_MCC_OLD_GROUP(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, GENMASK(6, 5));
+}
+
+static inline void RTW89_SET_FWCMD_START_MCC_NOTIFY_CNT(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, GENMASK(18, 16));
+}
+
+static inline void RTW89_SET_FWCMD_START_MCC_NOTIFY_RXDBG_EN(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, BIT(21));
+}
+
+static inline void RTW89_SET_FWCMD_START_MCC_MACID(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, GENMASK(31, 24));
+}
+
+static inline void RTW89_SET_FWCMD_START_MCC_TSF_LOW(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd + 1, val, GENMASK(31, 0));
+}
+
+static inline void RTW89_SET_FWCMD_START_MCC_TSF_HIGH(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd + 2, val, GENMASK(31, 0));
+}
+
+static inline void RTW89_SET_FWCMD_STOP_MCC_MACID(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, GENMASK(7, 0));
+}
+
+static inline void RTW89_SET_FWCMD_STOP_MCC_GROUP(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, GENMASK(9, 8));
+}
+
+static inline void RTW89_SET_FWCMD_STOP_MCC_PREV_GROUPS(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, BIT(10));
+}
+
+static inline void RTW89_SET_FWCMD_DEL_MCC_GROUP_GROUP(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, GENMASK(1, 0));
+}
+
+static inline void RTW89_SET_FWCMD_DEL_MCC_GROUP_PREV_GROUPS(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, BIT(2));
+}
+
+static inline void RTW89_SET_FWCMD_RESET_MCC_GROUP_GROUP(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, GENMASK(1, 0));
+}
+
+struct rtw89_fw_mcc_tsf_req {
+ u8 group: 2;
+ u8 rsvd0: 6;
+ u8 macid_x;
+ u8 macid_y;
+ u8 rsvd1;
+};
+
+static inline void RTW89_SET_FWCMD_MCC_REQ_TSF_GROUP(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, GENMASK(1, 0));
+}
+
+static inline void RTW89_SET_FWCMD_MCC_REQ_TSF_MACID_X(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, GENMASK(15, 8));
+}
+
+static inline void RTW89_SET_FWCMD_MCC_REQ_TSF_MACID_Y(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, GENMASK(23, 16));
+}
+
+static inline void RTW89_SET_FWCMD_MCC_MACID_BITMAP_GROUP(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, GENMASK(1, 0));
+}
+
+static inline void RTW89_SET_FWCMD_MCC_MACID_BITMAP_MACID(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, GENMASK(15, 8));
+}
+
+static inline void RTW89_SET_FWCMD_MCC_MACID_BITMAP_BITMAP_LENGTH(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, GENMASK(23, 16));
+}
+
+static inline void RTW89_SET_FWCMD_MCC_MACID_BITMAP_BITMAP(void *cmd,
+ u8 *bitmap, u8 len)
+{
+ memcpy((__le32 *)cmd + 1, bitmap, len);
+}
+
+static inline void RTW89_SET_FWCMD_MCC_SYNC_GROUP(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, GENMASK(1, 0));
+}
+
+static inline void RTW89_SET_FWCMD_MCC_SYNC_MACID_SOURCE(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, GENMASK(15, 8));
+}
+
+static inline void RTW89_SET_FWCMD_MCC_SYNC_MACID_TARGET(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, GENMASK(23, 16));
+}
+
+static inline void RTW89_SET_FWCMD_MCC_SYNC_SYNC_OFFSET(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, GENMASK(31, 24));
+}
+
+struct rtw89_fw_mcc_duration {
+ u32 group: 2;
+ u32 btc_in_group: 1;
+ u32 rsvd0: 5;
+ u32 start_macid: 8;
+ u32 macid_x: 8;
+ u32 macid_y: 8;
+ u32 start_tsf_low;
+ u32 start_tsf_high;
+ u32 duration_x;
+ u32 duration_y;
+};
+
+static inline void RTW89_SET_FWCMD_MCC_SET_DURATION_GROUP(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, GENMASK(1, 0));
+}
+
+static
+inline void RTW89_SET_FWCMD_MCC_SET_DURATION_BTC_IN_GROUP(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, BIT(2));
+}
+
+static
+inline void RTW89_SET_FWCMD_MCC_SET_DURATION_START_MACID(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, GENMASK(15, 8));
+}
+
+static inline void RTW89_SET_FWCMD_MCC_SET_DURATION_MACID_X(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, GENMASK(23, 16));
+}
+
+static inline void RTW89_SET_FWCMD_MCC_SET_DURATION_MACID_Y(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd, val, GENMASK(31, 24));
+}
+
+static
+inline void RTW89_SET_FWCMD_MCC_SET_DURATION_START_TSF_LOW(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd + 1, val, GENMASK(31, 0));
+}
+
+static
+inline void RTW89_SET_FWCMD_MCC_SET_DURATION_START_TSF_HIGH(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd + 2, val, GENMASK(31, 0));
+}
+
+static
+inline void RTW89_SET_FWCMD_MCC_SET_DURATION_DURATION_X(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd + 3, val, GENMASK(31, 0));
+}
+
+static
+inline void RTW89_SET_FWCMD_MCC_SET_DURATION_DURATION_Y(void *cmd, u32 val)
+{
+ le32p_replace_bits((__le32 *)cmd + 4, val, GENMASK(31, 0));
+}
+
#define RTW89_C2H_HEADER_LEN 8

#define RTW89_GET_C2H_CATEGORY(c2h) \
@@ -3183,9 +3532,27 @@ int rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
bool enable);
int rtw89_fw_h2c_wow_wakeup_ctrl(struct rtw89_dev *rtwdev,
struct rtw89_vif *rtwvif, bool enable);
-
int rtw89_fw_wow_cam_update(struct rtw89_dev *rtwdev,
struct rtw89_wow_cam_info *cam_info);
+int rtw89_fw_h2c_add_mcc(struct rtw89_dev *rtwdev,
+ const struct rtw89_fw_mcc_add_req *p);
+int rtw89_fw_h2c_start_mcc(struct rtw89_dev *rtwdev,
+ const struct rtw89_fw_mcc_start_req *p);
+int rtw89_fw_h2c_stop_mcc(struct rtw89_dev *rtwdev, u8 group, u8 macid,
+ bool prev_groups);
+int rtw89_fw_h2c_del_mcc_group(struct rtw89_dev *rtwdev, u8 group,
+ bool prev_groups);
+int rtw89_fw_h2c_reset_mcc_group(struct rtw89_dev *rtwdev, u8 group);
+int rtw89_fw_h2c_mcc_req_tsf(struct rtw89_dev *rtwdev,
+ const struct rtw89_fw_mcc_tsf_req *req,
+ struct rtw89_mac_mcc_tsf_rpt *rpt);
+int rtw89_fw_h2c_mcc_macid_bitamp(struct rtw89_dev *rtwdev, u8 group, u8 macid,
+ u8 *bitmap);
+int rtw89_fw_h2c_mcc_sync(struct rtw89_dev *rtwdev, u8 group, u8 source,
+ u8 target, u8 offset);
+int rtw89_fw_h2c_mcc_set_duration(struct rtw89_dev *rtwdev,
+ const struct rtw89_fw_mcc_duration *p);
+
static inline void rtw89_fw_h2c_init_ba_cam(struct rtw89_dev *rtwdev)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
--
2.25.1


2022-11-28 13:36:29

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 3/6] wifi: rtw89: introduce helpers to wait/complete on condition

Ping-Ke Shih <[email protected]> writes:

> From: Zong-Zhe Yang <[email protected]>
>
> MCC (multi-channel concurrency) related H2Cs require to wait for C2H
> responses to judge the execution result and data. We introduce helpers
> to assist this process. Besides, we would like the helpers to be generic
> for use in driver even outside of MCC H2C/C2H, so we make a independent
> patch for them.
>
> In the following, I describe the things first.
> ```
> (A) C2H is generated by FW, and then transferred upto driver. Hence,
> driver cannot get it immediately without a bit waitting/blocking.
> For this, we choose to use wait_for_completion_*() instead of
> busy polling.
> (B) From the driver management perspective, a scenario, e.g. MCC,
> may have mulitple kind of H2C functions requiring this process
> to wait for corresponding C2Hs. But, the driver management flow
> uses mutex to protect each behavior. So, one scenario triggers
> one H2C function at one time. To avoid rampant instances of
> struct completion for each H2C function, we choose to use one
> struct completion with one condition flag for one scenario.
> (C) C2Hs, which H2Cs will be waitting for, cannot be ordered with
> driver management flow, i.e. cannot enqueue work to the same
> ordered workqueue and cannot lock by the same mutex, to prevent
> H2C side from getting no C2H responses. So, those C2Hs are parsed
> in interrupt context directly as done in previous commit.
> (D) Following (C), the above underline H2Cs and C2Hs will be handled
> in different contexts without sync. So, we use atomic_cmpxchg()
> to compare and change the condition in atomic.
> ```
>
> So, we introduce struct rtw89_wait_info which combines struct completion
> and atomic_t. Then, the below are the descriptions for helper functions.
> * rtw89_wait_for_cond() to wait for a completion based on a condition.
> * rtw89_complete_cond() to complete a given condition and carry data.
> Each rtw89_wait_info instance independently determines the meaning of
> its waitting conditions. But, RTW89_WAIT_COND_IDLE (UINT_MAX) is reserved.
>
> Signed-off-by: Zong-Zhe Yang <[email protected]>
> Signed-off-by: Ping-Ke Shih <[email protected]>

Just nitpicking a couple of items:

Otherwise an excellent commit log but the meaning of C2H and H2C is not
clear for me. I guess they mean "chip to host" and "host to chip", but
would be good to clarify that in the beginning.

> --- a/drivers/net/wireless/realtek/rtw89/core.h
> +++ b/drivers/net/wireless/realtek/rtw89/core.h
> @@ -2802,6 +2802,34 @@ struct rtw89_mac_info {
> u8 cpwm_seq_num;
> };
>
> +struct rtw89_completion_data {
> + bool err;
> +#define RTW89_COMPLETION_BUF_SIZE 24
> + u8 buf[RTW89_COMPLETION_BUF_SIZE];
> +};

Having a define withing a struct looks odd to me, I would prefer to have
it outside of the struct.

> +#define rtw89_completion_cast(cmpl_data, ptr) \
> +({ \
> + typecheck(struct rtw89_completion_data *, cmpl_data); \
> + BUILD_BUG_ON(sizeof(*(ptr)) > RTW89_COMPLETION_BUF_SIZE); \
> + (typeof(ptr))(cmpl_data)->buf; \
> +})

Wouldn't this be cleaner as a static inline function?

> +struct rtw89_wait_info {
> +#define RTW89_WAIT_COND_IDLE UINT_MAX
> + atomic_t cond;
> + struct completion completion;
> + struct rtw89_completion_data data;
> +};

Also here would prefer the define outside the struct.

--
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

2022-11-28 13:38:00

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 4/6] wifi: rtw89: mac: process MCC related C2H

Ping-Ke Shih <[email protected]> writes:

> From: Zong-Zhe Yang <[email protected]>
>
> Process C2H(s) related to MCC (multi-channel concurrency). These handling,
> which either call rtw89_complete_cond() or show message in debug mode, can
> be considered atomic/lock-free. So, they should be safe to be processed
> directly after C2H pre-check in previous patch.
>
> Signed-off-by: Zong-Zhe Yang <[email protected]>
> Signed-off-by: Ping-Ke Shih <[email protected]>

[...]

> +static
> +void (* const rtw89_mac_c2h_mcc_handler[])(struct rtw89_dev *rtwdev,
> + struct sk_buff *c2h, u32 len) = {
> + [RTW89_MAC_C2H_FUNC_MCC_RCV_ACK] = rtw89_mac_c2h_mcc_rcv_ack,
> + [RTW89_MAC_C2H_FUNC_MCC_REQ_ACK] = rtw89_mac_c2h_mcc_req_ack,
> + [RTW89_MAC_C2H_FUNC_MCC_TSF_RPT] = rtw89_mac_c2h_mcc_tsf_rpt,
> + [RTW89_MAC_C2H_FUNC_MCC_STATUS_RPT] = rtw89_mac_c2h_mcc_status_rpt,
> +};

static const?

--
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

2022-11-29 00:35:55

by Ping-Ke Shih

[permalink] [raw]
Subject: RE: [PATCH 4/6] wifi: rtw89: mac: process MCC related C2H



> -----Original Message-----
> From: Kalle Valo <[email protected]>
> Sent: Monday, November 28, 2022 9:31 PM
> To: Ping-Ke Shih <[email protected]>
> Cc: Kevin Yang <[email protected]>; [email protected]
> Subject: Re: [PATCH 4/6] wifi: rtw89: mac: process MCC related C2H
>
> Ping-Ke Shih <[email protected]> writes:
>
> > From: Zong-Zhe Yang <[email protected]>
> >
> > Process C2H(s) related to MCC (multi-channel concurrency). These handling,
> > which either call rtw89_complete_cond() or show message in debug mode, can
> > be considered atomic/lock-free. So, they should be safe to be processed
> > directly after C2H pre-check in previous patch.
> >
> > Signed-off-by: Zong-Zhe Yang <[email protected]>
> > Signed-off-by: Ping-Ke Shih <[email protected]>
>
> [...]
>
> > +static
> > +void (* const rtw89_mac_c2h_mcc_handler[])(struct rtw89_dev *rtwdev,
> > + struct sk_buff *c2h, u32 len) = {
> > + [RTW89_MAC_C2H_FUNC_MCC_RCV_ACK] = rtw89_mac_c2h_mcc_rcv_ack,
> > + [RTW89_MAC_C2H_FUNC_MCC_REQ_ACK] = rtw89_mac_c2h_mcc_req_ack,
> > + [RTW89_MAC_C2H_FUNC_MCC_TSF_RPT] = rtw89_mac_c2h_mcc_tsf_rpt,
> > + [RTW89_MAC_C2H_FUNC_MCC_STATUS_RPT] = rtw89_mac_c2h_mcc_status_rpt,
> > +};
>
> static const?
>

These are function pointers, so const is before instance name,
i.e. '... const rtw89_mac_c2h_mcc_handler ..'

Checking it with objdump, which shows '.rodata' also:

$ objdump -t mac.o | grep rtw89_mac_c2h_mcc_handler
00000000000000a0 l O .rodata 0000000000000020 rtw89_mac_c2h_mcc_handler

--
Ping-Ke

2022-11-29 04:28:50

by Ping-Ke Shih

[permalink] [raw]
Subject: RE: [PATCH 3/6] wifi: rtw89: introduce helpers to wait/complete on condition


> -----Original Message-----
> From: Kalle Valo <[email protected]>
> Sent: Monday, November 28, 2022 9:29 PM
> To: Ping-Ke Shih <[email protected]>
> Cc: Kevin Yang <[email protected]>; [email protected]
> Subject: Re: [PATCH 3/6] wifi: rtw89: introduce helpers to wait/complete on condition
>
> Ping-Ke Shih <[email protected]> writes:
>
> > From: Zong-Zhe Yang <[email protected]>
> >
> > MCC (multi-channel concurrency) related H2Cs require to wait for C2H
> > responses to judge the execution result and data. We introduce helpers
> > to assist this process. Besides, we would like the helpers to be generic
> > for use in driver even outside of MCC H2C/C2H, so we make a independent
> > patch for them.
> >
> > In the following, I describe the things first.
> > ```
> > (A) C2H is generated by FW, and then transferred upto driver. Hence,
> > driver cannot get it immediately without a bit waitting/blocking.
> > For this, we choose to use wait_for_completion_*() instead of
> > busy polling.
> > (B) From the driver management perspective, a scenario, e.g. MCC,
> > may have mulitple kind of H2C functions requiring this process
> > to wait for corresponding C2Hs. But, the driver management flow
> > uses mutex to protect each behavior. So, one scenario triggers
> > one H2C function at one time. To avoid rampant instances of
> > struct completion for each H2C function, we choose to use one
> > struct completion with one condition flag for one scenario.
> > (C) C2Hs, which H2Cs will be waitting for, cannot be ordered with
> > driver management flow, i.e. cannot enqueue work to the same
> > ordered workqueue and cannot lock by the same mutex, to prevent
> > H2C side from getting no C2H responses. So, those C2Hs are parsed
> > in interrupt context directly as done in previous commit.
> > (D) Following (C), the above underline H2Cs and C2Hs will be handled
> > in different contexts without sync. So, we use atomic_cmpxchg()
> > to compare and change the condition in atomic.
> > ```
> >
> > So, we introduce struct rtw89_wait_info which combines struct completion
> > and atomic_t. Then, the below are the descriptions for helper functions.
> > * rtw89_wait_for_cond() to wait for a completion based on a condition.
> > * rtw89_complete_cond() to complete a given condition and carry data.
> > Each rtw89_wait_info instance independently determines the meaning of
> > its waitting conditions. But, RTW89_WAIT_COND_IDLE (UINT_MAX) is reserved.
> >
> > Signed-off-by: Zong-Zhe Yang <[email protected]>
> > Signed-off-by: Ping-Ke Shih <[email protected]>
>
> Just nitpicking a couple of items:
>
> Otherwise an excellent commit log but the meaning of C2H and H2C is not
> clear for me. I guess they mean "chip to host" and "host to chip", but
> would be good to clarify that in the beginning.

will add them by v2.

>
> > --- a/drivers/net/wireless/realtek/rtw89/core.h
> > +++ b/drivers/net/wireless/realtek/rtw89/core.h
> > @@ -2802,6 +2802,34 @@ struct rtw89_mac_info {
> > u8 cpwm_seq_num;
> > };
> >
> > +struct rtw89_completion_data {
> > + bool err;
> > +#define RTW89_COMPLETION_BUF_SIZE 24
> > + u8 buf[RTW89_COMPLETION_BUF_SIZE];
> > +};
>
> Having a define withing a struct looks odd to me, I would prefer to have
> it outside of the struct.

will fix it by v2.

>
> > +#define rtw89_completion_cast(cmpl_data, ptr) \
> > +({ \
> > + typecheck(struct rtw89_completion_data *, cmpl_data); \
> > + BUILD_BUG_ON(sizeof(*(ptr)) > RTW89_COMPLETION_BUF_SIZE); \
> > + (typeof(ptr))(cmpl_data)->buf; \
> > +})
>
> Wouldn't this be cleaner as a static inline function?

inline function isn't suitable, because 'ptr' could be various type.
We plan to do casting barely at callers.

>
> > +struct rtw89_wait_info {
> > +#define RTW89_WAIT_COND_IDLE UINT_MAX
> > + atomic_t cond;
> > + struct completion completion;
> > + struct rtw89_completion_data data;
> > +};
>
> Also here would prefer the define outside the struct.

will fix it by v2.

Thank you
Ping-Ke


2022-11-29 05:57:54

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 4/6] wifi: rtw89: mac: process MCC related C2H

Ping-Ke Shih <[email protected]> writes:

>> -----Original Message-----
>> From: Kalle Valo <[email protected]>
>> Sent: Monday, November 28, 2022 9:31 PM
>> To: Ping-Ke Shih <[email protected]>
>> Cc: Kevin Yang <[email protected]>; [email protected]
>> Subject: Re: [PATCH 4/6] wifi: rtw89: mac: process MCC related C2H
>>
>> Ping-Ke Shih <[email protected]> writes:
>>
>> > From: Zong-Zhe Yang <[email protected]>
>> >
>> > Process C2H(s) related to MCC (multi-channel concurrency). These handling,
>> > which either call rtw89_complete_cond() or show message in debug mode, can
>> > be considered atomic/lock-free. So, they should be safe to be processed
>> > directly after C2H pre-check in previous patch.
>> >
>> > Signed-off-by: Zong-Zhe Yang <[email protected]>
>> > Signed-off-by: Ping-Ke Shih <[email protected]>
>>
>> [...]
>>
>> > +static
>> > +void (* const rtw89_mac_c2h_mcc_handler[])(struct rtw89_dev *rtwdev,
>> > + struct sk_buff *c2h, u32 len) = {
>> > + [RTW89_MAC_C2H_FUNC_MCC_RCV_ACK] = rtw89_mac_c2h_mcc_rcv_ack,
>> > + [RTW89_MAC_C2H_FUNC_MCC_REQ_ACK] = rtw89_mac_c2h_mcc_req_ack,
>> > + [RTW89_MAC_C2H_FUNC_MCC_TSF_RPT] = rtw89_mac_c2h_mcc_tsf_rpt,
>> > + [RTW89_MAC_C2H_FUNC_MCC_STATUS_RPT] = rtw89_mac_c2h_mcc_status_rpt,
>> > +};
>>
>> static const?
>>
>
> These are function pointers, so const is before instance name,
> i.e. '... const rtw89_mac_c2h_mcc_handler ..'

Ah indeed, missed that. Thanks.

--
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches