mac80211: rtl8xxxu: sync with linux-next 20240229
[openwrt/staging/mans0n.git] / package / kernel / mac80211 / patches / rtl / 001-20-v6.9-wifi-rtl8xxxu-make-supporting-AP-mode-only-on-port-0.patch
diff --git a/package/kernel/mac80211/patches/rtl/001-20-v6.9-wifi-rtl8xxxu-make-supporting-AP-mode-only-on-port-0.patch b/package/kernel/mac80211/patches/rtl/001-20-v6.9-wifi-rtl8xxxu-make-supporting-AP-mode-only-on-port-0.patch
new file mode 100644 (file)
index 0000000..4b55b0e
--- /dev/null
@@ -0,0 +1,130 @@
+From 69abad618efd17e50bc6f880332ab36b660b0b34 Mon Sep 17 00:00:00 2001
+From: Martin Kaistra <martin.kaistra@linutronix.de>
+Date: Fri, 22 Dec 2023 11:14:41 +0100
+Subject: [PATCH 20/21] wifi: rtl8xxxu: make supporting AP mode only on port 0
+ transparent
+
+When the driver is used for concurrent mode, both virtual interfaces can
+be set to station or AP mode, though only one can be in AP mode at the
+same time.
+
+In order to keep the code simple, use only hw port 0 for AP mode. When
+an interface is added in AP mode which would be assigned to port 1, use
+a switch_port function to transparently swap the mapping between virtual
+interface and hw port.
+
+Signed-off-by: Martin Kaistra <martin.kaistra@linutronix.de>
+Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
+Signed-off-by: Kalle Valo <kvalo@kernel.org>
+Link: https://msgid.link/20231222101442.626837-21-martin.kaistra@linutronix.de
+---
+ .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 91 ++++++++++++++++++-
+ 1 file changed, 89 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
++++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
+@@ -6624,6 +6624,91 @@ error:
+       return ret;
+ }
++static void rtl8xxxu_switch_ports(struct rtl8xxxu_priv *priv)
++{
++      u8 macid[ETH_ALEN], bssid[ETH_ALEN], macid_1[ETH_ALEN], bssid_1[ETH_ALEN];
++      u8 msr, bcn_ctrl, bcn_ctrl_1, atimwnd[2], atimwnd_1[2];
++      struct rtl8xxxu_vif *rtlvif;
++      struct ieee80211_vif *vif;
++      u8 tsftr[8], tsftr_1[8];
++      int i;
++
++      msr = rtl8xxxu_read8(priv, REG_MSR);
++      bcn_ctrl = rtl8xxxu_read8(priv, REG_BEACON_CTRL);
++      bcn_ctrl_1 = rtl8xxxu_read8(priv, REG_BEACON_CTRL_1);
++
++      for (i = 0; i < ARRAY_SIZE(atimwnd); i++)
++              atimwnd[i] = rtl8xxxu_read8(priv, REG_ATIMWND + i);
++      for (i = 0; i < ARRAY_SIZE(atimwnd_1); i++)
++              atimwnd_1[i] = rtl8xxxu_read8(priv, REG_ATIMWND_1 + i);
++
++      for (i = 0; i < ARRAY_SIZE(tsftr); i++)
++              tsftr[i] = rtl8xxxu_read8(priv, REG_TSFTR + i);
++      for (i = 0; i < ARRAY_SIZE(tsftr); i++)
++              tsftr_1[i] = rtl8xxxu_read8(priv, REG_TSFTR1 + i);
++
++      for (i = 0; i < ARRAY_SIZE(macid); i++)
++              macid[i] = rtl8xxxu_read8(priv, REG_MACID + i);
++
++      for (i = 0; i < ARRAY_SIZE(bssid); i++)
++              bssid[i] = rtl8xxxu_read8(priv, REG_BSSID + i);
++
++      for (i = 0; i < ARRAY_SIZE(macid_1); i++)
++              macid_1[i] = rtl8xxxu_read8(priv, REG_MACID1 + i);
++
++      for (i = 0; i < ARRAY_SIZE(bssid_1); i++)
++              bssid_1[i] = rtl8xxxu_read8(priv, REG_BSSID1 + i);
++
++      /* disable bcn function, disable update TSF */
++      rtl8xxxu_write8(priv, REG_BEACON_CTRL, (bcn_ctrl &
++                      (~BEACON_FUNCTION_ENABLE)) | BEACON_DISABLE_TSF_UPDATE);
++      rtl8xxxu_write8(priv, REG_BEACON_CTRL_1, (bcn_ctrl_1 &
++                      (~BEACON_FUNCTION_ENABLE)) | BEACON_DISABLE_TSF_UPDATE);
++
++      /* switch msr */
++      msr = (msr & 0xf0) | ((msr & 0x03) << 2) | ((msr & 0x0c) >> 2);
++      rtl8xxxu_write8(priv, REG_MSR, msr);
++
++      /* write port0 */
++      rtl8xxxu_write8(priv, REG_BEACON_CTRL, bcn_ctrl_1 & ~BEACON_FUNCTION_ENABLE);
++      for (i = 0; i < ARRAY_SIZE(atimwnd_1); i++)
++              rtl8xxxu_write8(priv, REG_ATIMWND + i, atimwnd_1[i]);
++      for (i = 0; i < ARRAY_SIZE(tsftr_1); i++)
++              rtl8xxxu_write8(priv, REG_TSFTR + i, tsftr_1[i]);
++      for (i = 0; i < ARRAY_SIZE(macid_1); i++)
++              rtl8xxxu_write8(priv, REG_MACID + i, macid_1[i]);
++      for (i = 0; i < ARRAY_SIZE(bssid_1); i++)
++              rtl8xxxu_write8(priv, REG_BSSID + i, bssid_1[i]);
++
++      /* write port1 */
++      rtl8xxxu_write8(priv, REG_BEACON_CTRL_1, bcn_ctrl & ~BEACON_FUNCTION_ENABLE);
++      for (i = 0; i < ARRAY_SIZE(atimwnd); i++)
++              rtl8xxxu_write8(priv, REG_ATIMWND_1 + i, atimwnd[i]);
++      for (i = 0; i < ARRAY_SIZE(tsftr); i++)
++              rtl8xxxu_write8(priv, REG_TSFTR1 + i, tsftr[i]);
++      for (i = 0; i < ARRAY_SIZE(macid); i++)
++              rtl8xxxu_write8(priv, REG_MACID1 + i, macid[i]);
++      for (i = 0; i < ARRAY_SIZE(bssid); i++)
++              rtl8xxxu_write8(priv, REG_BSSID1 + i, bssid[i]);
++
++      /* write bcn ctl */
++      rtl8xxxu_write8(priv, REG_BEACON_CTRL, bcn_ctrl_1);
++      rtl8xxxu_write8(priv, REG_BEACON_CTRL_1, bcn_ctrl);
++
++      vif = priv->vifs[0];
++      priv->vifs[0] = priv->vifs[1];
++      priv->vifs[1] = vif;
++
++      /* priv->vifs[0] is NULL here, based on how this function is currently
++       * called from rtl8xxxu_add_interface().
++       * When this function will be used in the future for a different
++       * scenario, please check whether vifs[0] or vifs[1] can be NULL and if
++       * necessary add code to set port_num = 1.
++       */
++      rtlvif = (struct rtl8xxxu_vif *)priv->vifs[1]->drv_priv;
++      rtlvif->port_num = 1;
++}
++
+ static int rtl8xxxu_add_interface(struct ieee80211_hw *hw,
+                                 struct ieee80211_vif *vif)
+ {
+@@ -6651,8 +6736,10 @@ static int rtl8xxxu_add_interface(struct
+               }
+               break;
+       case NL80211_IFTYPE_AP:
+-              if (port_num == 1)
+-                      return -EOPNOTSUPP;
++              if (port_num == 1) {
++                      rtl8xxxu_switch_ports(priv);
++                      port_num = 0;
++              }
+               rtl8xxxu_write8(priv, REG_BEACON_CTRL,
+                               BEACON_DISABLE_TSF_UPDATE | BEACON_CTRL_MBSSID);