To support SCC (1 STA + 1 AP), we need to deal some hardware things:
1. AP mode only can work on hardware port 0
2. adjust and enlarge reserved pages for two VIFs
Other things are to coordinate two VIFs work well to prevent interference
with each other, like scan thing.
Po-Hao Huang (7):
wifi: rtw88: add bitmap for dynamic port settings
wifi: rtw88: add port switch for AP mode
wifi: rtw88: 8822c: extend reserved page number
wifi: rtw88: disallow scan and PS during AP mode
wifi: rtw88: refine reserved page flow for AP mode
wifi: rtw88: prevent scan abort with other VIFs
wifi: rtw88: 8822c: add iface combination
drivers/net/wireless/realtek/rtw88/fw.c | 9 +-
drivers/net/wireless/realtek/rtw88/fw.h | 2 +-
drivers/net/wireless/realtek/rtw88/mac.c | 2 +-
drivers/net/wireless/realtek/rtw88/mac80211.c | 38 ++++++-
drivers/net/wireless/realtek/rtw88/main.c | 107 +++++++++++++++++-
drivers/net/wireless/realtek/rtw88/main.h | 13 +++
drivers/net/wireless/realtek/rtw88/rtw8723d.c | 1 +
drivers/net/wireless/realtek/rtw88/rtw8821c.c | 1 +
drivers/net/wireless/realtek/rtw88/rtw8822b.c | 1 +
drivers/net/wireless/realtek/rtw88/rtw8822c.c | 1 +
10 files changed, 165 insertions(+), 10 deletions(-)
--
2.25.1
From: Po-Hao Huang <[email protected]>
Switch port settings if AP mode does not start on port 0 because of
hardware limitation. For some ICs, beacons on ports other than zero
could misbehave and do not issue properly, to fix this we change AP
VIFs to port zero when multiple interfaces is active.
Signed-off-by: Po-Hao Huang <[email protected]>
Signed-off-by: Ping-Ke Shih <[email protected]>
---
drivers/net/wireless/realtek/rtw88/mac80211.c | 1 +
drivers/net/wireless/realtek/rtw88/main.c | 79 +++++++++++++++++++
drivers/net/wireless/realtek/rtw88/main.h | 1 +
3 files changed, 81 insertions(+)
diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c
index d026094a72c40..19c4d7c29759e 100644
--- a/drivers/net/wireless/realtek/rtw88/mac80211.c
+++ b/drivers/net/wireless/realtek/rtw88/mac80211.c
@@ -212,6 +212,7 @@ static int rtw_ops_add_interface(struct ieee80211_hw *hw,
rtwvif->bcn_ctrl = bcn_ctrl;
config |= PORT_SET_BCN_CTRL;
rtw_vif_port_config(rtwdev, rtwvif, config);
+ rtw_core_port_switch(rtwdev, vif);
mutex_unlock(&rtwdev->mutex);
diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c
index 39b18c7468c9e..ba05a5d68d05e 100644
--- a/drivers/net/wireless/realtek/rtw88/main.c
+++ b/drivers/net/wireless/realtek/rtw88/main.c
@@ -2244,6 +2244,85 @@ void rtw_unregister_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw)
}
EXPORT_SYMBOL(rtw_unregister_hw);
+static
+void rtw_swap_reg_nbytes(struct rtw_dev *rtwdev, const struct rtw_hw_reg *reg1,
+ const struct rtw_hw_reg *reg2, u8 nbytes)
+{
+ u8 i;
+
+ for (i = 0; i < nbytes; i++) {
+ u8 v1 = rtw_read8(rtwdev, reg1->addr + i);
+ u8 v2 = rtw_read8(rtwdev, reg2->addr + i);
+
+ rtw_write8(rtwdev, reg1->addr + i, v2);
+ rtw_write8(rtwdev, reg2->addr + i, v1);
+ }
+}
+
+static
+void rtw_swap_reg_mask(struct rtw_dev *rtwdev, const struct rtw_hw_reg *reg1,
+ const struct rtw_hw_reg *reg2)
+{
+ u32 v1, v2;
+
+ v1 = rtw_read32_mask(rtwdev, reg1->addr, reg1->mask);
+ v2 = rtw_read32_mask(rtwdev, reg2->addr, reg2->mask);
+ rtw_write32_mask(rtwdev, reg2->addr, reg2->mask, v1);
+ rtw_write32_mask(rtwdev, reg1->addr, reg1->mask, v2);
+}
+
+struct rtw_iter_port_switch_data {
+ struct rtw_dev *rtwdev;
+ struct rtw_vif *rtwvif_ap;
+};
+
+static void rtw_port_switch_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
+{
+ struct rtw_iter_port_switch_data *iter_data = data;
+ struct rtw_dev *rtwdev = iter_data->rtwdev;
+ struct rtw_vif *rtwvif_target = (struct rtw_vif *)vif->drv_priv;
+ struct rtw_vif *rtwvif_ap = iter_data->rtwvif_ap;
+ const struct rtw_hw_reg *reg1, *reg2;
+
+ if (rtwvif_target->port != RTW_PORT_0)
+ return;
+
+ rtw_info(rtwdev, "AP port switch from %d -> %d\n", rtwvif_ap->port,
+ rtwvif_target->port);
+
+ reg1 = &rtwvif_ap->conf->net_type;
+ reg2 = &rtwvif_target->conf->net_type;
+ rtw_swap_reg_mask(rtwdev, reg1, reg2);
+
+ reg1 = &rtwvif_ap->conf->mac_addr;
+ reg2 = &rtwvif_target->conf->mac_addr;
+ rtw_swap_reg_nbytes(rtwdev, reg1, reg2, ETH_ALEN);
+
+ reg1 = &rtwvif_ap->conf->bssid;
+ reg2 = &rtwvif_target->conf->bssid;
+ rtw_swap_reg_nbytes(rtwdev, reg1, reg2, ETH_ALEN);
+
+ reg1 = &rtwvif_ap->conf->bcn_ctrl;
+ reg2 = &rtwvif_target->conf->bcn_ctrl;
+ rtw_swap_reg_nbytes(rtwdev, reg1, reg2, 1);
+
+ swap(rtwvif_target->port, rtwvif_ap->port);
+ swap(rtwvif_target->conf, rtwvif_ap->conf);
+}
+
+void rtw_core_port_switch(struct rtw_dev *rtwdev, struct ieee80211_vif *vif)
+{
+ struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
+ struct rtw_iter_port_switch_data iter_data;
+
+ if (vif->type != NL80211_IFTYPE_AP || rtwvif->port == RTW_PORT_0)
+ return;
+
+ iter_data.rtwdev = rtwdev;
+ iter_data.rtwvif_ap = rtwvif;
+ rtw_iterate_vifs(rtwdev, rtw_port_switch_iter, &iter_data);
+}
+
MODULE_AUTHOR("Realtek Corporation");
MODULE_DESCRIPTION("Realtek 802.11ac wireless core module");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h
index efac271497f5b..790ebf781bc41 100644
--- a/drivers/net/wireless/realtek/rtw88/main.h
+++ b/drivers/net/wireless/realtek/rtw88/main.h
@@ -2198,4 +2198,5 @@ void rtw_set_txrx_1ss(struct rtw_dev *rtwdev, bool config_1ss);
void rtw_update_channel(struct rtw_dev *rtwdev, u8 center_channel,
u8 primary_channel, enum rtw_supported_band band,
enum rtw_bandwidth bandwidth);
+void rtw_core_port_switch(struct rtw_dev *rtwdev, struct ieee80211_vif *vif);
#endif
--
2.25.1
Ping-Ke Shih <[email protected]> writes:
> From: Po-Hao Huang <[email protected]>
>
> Switch port settings if AP mode does not start on port 0 because of
> hardware limitation. For some ICs, beacons on ports other than zero
> could misbehave and do not issue properly, to fix this we change AP
> VIFs to port zero when multiple interfaces is active.
>
> Signed-off-by: Po-Hao Huang <[email protected]>
> Signed-off-by: Ping-Ke Shih <[email protected]>
[...]
> +static void rtw_port_switch_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
> +{
> + struct rtw_iter_port_switch_data *iter_data = data;
> + struct rtw_dev *rtwdev = iter_data->rtwdev;
> + struct rtw_vif *rtwvif_target = (struct rtw_vif *)vif->drv_priv;
> + struct rtw_vif *rtwvif_ap = iter_data->rtwvif_ap;
> + const struct rtw_hw_reg *reg1, *reg2;
> +
> + if (rtwvif_target->port != RTW_PORT_0)
> + return;
> +
> + rtw_info(rtwdev, "AP port switch from %d -> %d\n", rtwvif_ap->port,
> + rtwvif_target->port);
This looks more like a debug message. In normal operations (after the
initialisation) the drivers should be quiet and only print messages when
something unexpected happens.
--
https://patchwork.kernel.org/project/linux-wireless/list/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches