2021-10-18 23:15:46

by Sean Wang

[permalink] [raw]
Subject: [PATCH v5 00/17] Add MT7921 SDIO WiFi support

From: Sean Wang <[email protected]>

The patchset adds the SDIO support to the MT7921 driver, basically are
made up of 3 parts.

PART 1: patch 1-5, 8-9 and 13-15
These are preliminary patches for mt7921s driver to refactor and reuse the
current mt7921e driver as much as possible.

PART 2: patch 6-7, 10-11
These are preliminary patches for mt7921s driver to refactor and reuse the
current mt7663s driver as much as possible.

PART 3: patch 12 and 16-17
These are specific patches for mt7921s driver and reset mechanism in the
same framework where mt7921e have been supported.

The patchset are built and generated against the current mt76 with the
tag mt76-for-kvalo-2021-10-12 plus the extra pending patches [1] expected to
be merged to mt76 tree soon to help the review and merge process be easier.

The change list from v1 to v2
1. rework the whole driver according to the new patches added
("mt76: introduce __mt76_mcu_send_firmware routine"),
("mt76: not accounting the MCU header size in __mt76_mcu_send_firmware for mt7915/21") and
("mt76: sdio: move common code in mt76_sdio module")
2. drop pci_init.c and sdio_init.c by moving the related logic to pci.c and sdio.c, respectively.
3. cosmetics the patches like removing unnecessary new line, adding an extra space to fixed_map table and so on ...
4. fix typo in commit message

The change list from v2 to v3
1. rebase onto the latest mt76 branch
2. update per Lorenzo comments on v2
3. fix scheduling while atomic in mt7921_mac_sta_poll for mt7921s driver

The change list from v3 to v4
1. change the title of coverletter
2. fix the git message in patch 14
3. rebase onto the mt76-for-kvalo-2021-10-12

The change list from v4 to v5
1. fix endianess warning in mt76_connac_mcu_parse_tx_resource
2. rework the driver with the the following additional patches
a. mt76: sdio: introduce parse_irq callback
b. mt76: sdio: export mt76s_alloc_rx_queue and mt76s_alloc_tx routines

[1] The pending patch list prior to add MT7921 SDIO support

dee0a13bcd6e mt76: mt7921: get rid of unused variable in mt7921_mac_tx_free
d56281936470 mt76: mt7921: get rid of unused variable in mt7921_tx_complete_skb
ef853b3f16ef mt76: connac: fix possible NULL pointer dereference in mt76_connac_get_phy_mode_v2
215246fecd9f mt76: mt7915: improve code readability for xmit-queue handler
9953a1186155 mt76: mt7915: introduce mt76 debugfs sub-dir for ext-phy
c7cf56ad8385 mt76: rely on phy pointer in mt76_register_debugfs_fops routine signature
43366b8cef53 mt76: mt7921: add MU EDCA cmd support
44c7f544a257 mt76: sdio: export mt76s_alloc_rx_queue and mt76s_alloc_tx routines

Lorenzo Bianconi (2):
mt76: sdio: move common code in mt76_sdio module
mt76: sdio: introduce parse_irq callback

Sean Wang (15):
mt76: mt7921: refactor mac.c to be bus independent
mt76: mt7921: refactor dma.c to be pcie specific
mt76: mt7921: refactor mcu.c to be bus independent
mt76: mt7921: refactor init.c to be bus independent
mt76: mt7921: add MT7921_COMMON module
mt76: connac: move mcu reg access utility routines in mt76_connac_lib
module
mt76: mt7663s: rely on mcu reg access utility
mt76: mt7921: make all event parser reusable between mt7921s and
mt7921e
mt76: mt7921: use physical addr to unify register access
mt76: sdio: extend sdio module to support CONNAC2
mt76: connac: extend mcu_get_nic_capability
mt76: mt7921: rely on mcu_get_nic_capability
mt76: mt7921: refactor mt7921_mcu_send_message
mt76: mt7921: introduce mt7921s support
mt76: mt7921s: add reset support

drivers/net/wireless/mediatek/mt76/Makefile | 2 +-
drivers/net/wireless/mediatek/mt76/mt76.h | 24 ++
.../wireless/mediatek/mt76/mt7615/Makefile | 2 +-
.../net/wireless/mediatek/mt76/mt7615/mcu.c | 28 --
.../wireless/mediatek/mt76/mt7615/mt7615.h | 18 +-
.../net/wireless/mediatek/mt76/mt7615/sdio.c | 288 ++------------
.../wireless/mediatek/mt76/mt7615/sdio_mcu.c | 11 +-
.../wireless/mediatek/mt76/mt76_connac_mcu.c | 93 +++++
.../wireless/mediatek/mt76/mt76_connac_mcu.h | 2 +
.../net/wireless/mediatek/mt76/mt7921/Kconfig | 18 +-
.../wireless/mediatek/mt76/mt7921/Makefile | 8 +-
.../wireless/mediatek/mt76/mt7921/debugfs.c | 18 +-
.../net/wireless/mediatek/mt76/mt7921/dma.c | 38 +-
.../wireless/mediatek/mt76/mt7921/eeprom.c | 101 -----
.../net/wireless/mediatek/mt76/mt7921/init.c | 51 +--
.../net/wireless/mediatek/mt76/mt7921/mac.c | 375 ++----------------
.../net/wireless/mediatek/mt76/mt7921/mac.h | 4 +
.../net/wireless/mediatek/mt76/mt7921/main.c | 8 +
.../net/wireless/mediatek/mt76/mt7921/mcu.c | 135 ++-----
.../wireless/mediatek/mt76/mt7921/mt7921.h | 107 ++++-
.../net/wireless/mediatek/mt76/mt7921/pci.c | 48 ++-
.../wireless/mediatek/mt76/mt7921/pci_mac.c | 348 ++++++++++++++++
.../wireless/mediatek/mt76/mt7921/pci_mcu.c | 115 ++++++
.../net/wireless/mediatek/mt76/mt7921/regs.h | 22 +-
.../net/wireless/mediatek/mt76/mt7921/sdio.c | 317 +++++++++++++++
.../wireless/mediatek/mt76/mt7921/sdio_mac.c | 220 ++++++++++
.../wireless/mediatek/mt76/mt7921/sdio_mcu.c | 135 +++++++
drivers/net/wireless/mediatek/mt76/sdio.c | 282 +++++++++++++
.../mediatek/mt76/{mt7615 => }/sdio.h | 33 +-
.../mediatek/mt76/{mt7615 => }/sdio_txrx.c | 134 ++++---
30 files changed, 1995 insertions(+), 990 deletions(-)
delete mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/eeprom.c
create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c
create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c
create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/sdio.c
create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c
create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c
rename drivers/net/wireless/mediatek/mt76/{mt7615 => }/sdio.h (72%)
rename drivers/net/wireless/mediatek/mt76/{mt7615 => }/sdio_txrx.c (67%)

--
2.25.1


2021-10-18 23:15:46

by Sean Wang

[permalink] [raw]
Subject: [PATCH v5 03/17] mt76: mt7921: refactor mcu.c to be bus independent

From: Sean Wang <[email protected]>

This is a preliminary patch to introduce mt7921s support.

Make mcu.c reusable between mt7921s and mt7921e

Tested-by: Deren Wu <[email protected]>
Acked-by: Lorenzo Bianconi <[email protected]>
Signed-off-by: Sean Wang <[email protected]>
---
.../wireless/mediatek/mt76/mt7921/Makefile | 3 +-
.../net/wireless/mediatek/mt76/mt7921/init.c | 1 +
.../net/wireless/mediatek/mt76/mt7921/mac.c | 5 +-
.../net/wireless/mediatek/mt76/mt7921/mcu.c | 94 ++----------------
.../wireless/mediatek/mt76/mt7921/mt7921.h | 20 +++-
.../net/wireless/mediatek/mt76/mt7921/pci.c | 3 +
.../wireless/mediatek/mt76/mt7921/pci_mac.c | 2 +
.../wireless/mediatek/mt76/mt7921/pci_mcu.c | 97 +++++++++++++++++++
8 files changed, 130 insertions(+), 95 deletions(-)
create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile
index 554202358470..4cb0b000cfe1 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile
@@ -4,5 +4,6 @@ obj-$(CONFIG_MT7921E) += mt7921e.o

CFLAGS_trace.o := -I$(src)

-mt7921e-y := pci.o pci_mac.o mac.o mcu.o dma.o eeprom.o main.o init.o debugfs.o trace.o
+mt7921e-y := pci.o pci_mac.o pci_mcu.o mac.o mcu.o dma.o eeprom.o main.o \
+ init.o debugfs.o trace.o
mt7921e-$(CONFIG_NL80211_TESTMODE) += testmode.o
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
index 4ef54343cef3..7956a57510c4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
@@ -304,6 +304,7 @@ void mt7921_unregister_device(struct mt7921_dev *dev)
mt7921_tx_token_put(dev);
mt7921_mcu_drv_pmctrl(dev);
mt7921_dma_cleanup(dev);
+ mt7921_wfsys_reset(dev);
mt7921_mcu_exit(dev);

tasklet_disable(&dev->irq_tasklet);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
index eb27d8ab4a8b..bb6f0cea93bb 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
@@ -1276,12 +1276,9 @@ void mt7921_mac_reset_work(struct work_struct *work)
cancel_work_sync(&pm->wake_work);

mutex_lock(&dev->mt76.mutex);
- for (i = 0; i < 10; i++) {
- __mt7921_mcu_drv_pmctrl(dev);
-
+ for (i = 0; i < 10; i++)
if (!mt7921_dev_reset(dev))
break;
- }
mutex_unlock(&dev->mt76.mutex);

if (i == 10)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
index 457365f40d30..54a2c846fd0d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -160,9 +160,8 @@ mt7921_mcu_parse_eeprom(struct mt76_dev *dev, struct sk_buff *skb)
return 0;
}

-static int
-mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd,
- struct sk_buff *skb, int seq)
+int mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd,
+ struct sk_buff *skb, int seq)
{
struct mt7921_mcu_rxd *rxd;
int mcu_cmd = cmd & MCU_CMD_MASK;
@@ -224,9 +223,8 @@ mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd,
return ret;
}

-static int
-mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
- int cmd, int *wait_seq)
+int mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
+ int cmd, int *wait_seq)
{
struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
int txd_len, mcu_cmd = cmd & MCU_CMD_MASK;
@@ -590,7 +588,7 @@ int mt7921_mcu_uni_rx_ba(struct mt7921_dev *dev,
enable, false);
}

-static int mt7921_mcu_restart(struct mt76_dev *dev)
+int mt7921_mcu_restart(struct mt76_dev *dev)
{
struct {
u8 power_mode;
@@ -603,20 +601,6 @@ static int mt7921_mcu_restart(struct mt76_dev *dev)
sizeof(req), false);
}

-static int mt7921_driver_own(struct mt7921_dev *dev)
-{
- u32 reg = mt7921_reg_map_l1(dev, MT_TOP_LPCR_HOST_BAND0);
-
- mt76_wr(dev, reg, MT_TOP_LPCR_HOST_DRV_OWN);
- if (!mt76_poll_msec(dev, reg, MT_TOP_LPCR_HOST_FW_OWN,
- 0, 500)) {
- dev_err(dev->mt76.dev, "Timeout for driver own\n");
- return -EIO;
- }
-
- return 0;
-}
-
static u32 mt7921_get_data_mode(struct mt7921_dev *dev, u32 info)
{
u32 mode = DL_MODE_NEED_RSP;
@@ -883,7 +867,6 @@ static int mt7921_load_firmware(struct mt7921_dev *dev)
}

fw_loaded:
- mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false);

#ifdef CONFIG_PM
dev->mt76.hw->wiphy->wowlan = &mt76_connac_wowlan_support;
@@ -911,10 +894,6 @@ int mt7921_run_firmware(struct mt7921_dev *dev)
{
int err;

- err = mt7921_driver_own(dev);
- if (err)
- return err;
-
err = mt7921_load_firmware(dev);
if (err)
return err;
@@ -925,23 +904,8 @@ int mt7921_run_firmware(struct mt7921_dev *dev)
return mt76_connac_mcu_get_nic_capability(&dev->mphy);
}

-int mt7921_mcu_init(struct mt7921_dev *dev)
-{
- static const struct mt76_mcu_ops mt7921_mcu_ops = {
- .headroom = sizeof(struct mt7921_mcu_txd),
- .mcu_skb_send_msg = mt7921_mcu_send_message,
- .mcu_parse_response = mt7921_mcu_parse_response,
- .mcu_restart = mt7921_mcu_restart,
- };
-
- dev->mt76.mcu_ops = &mt7921_mcu_ops;
-
- return mt7921_run_firmware(dev);
-}
-
void mt7921_mcu_exit(struct mt7921_dev *dev)
{
- mt7921_wfsys_reset(dev);
skb_queue_purge(&dev->mt76.mcu.res_q);
}

@@ -1280,35 +1244,6 @@ int mt7921_mcu_sta_update(struct mt7921_dev *dev, struct ieee80211_sta *sta,
return mt76_connac_mcu_sta_cmd(&dev->mphy, &info);
}

-int __mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev)
-{
- struct mt76_phy *mphy = &dev->mt76.phy;
- struct mt76_connac_pm *pm = &dev->pm;
- int i, err = 0;
-
- for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) {
- mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_CLR_OWN);
- if (mt76_poll_msec(dev, MT_CONN_ON_LPCTL,
- PCIE_LPCR_HOST_OWN_SYNC, 0, 50))
- break;
- }
-
- if (i == MT7921_DRV_OWN_RETRY_COUNT) {
- dev_err(dev->mt76.dev, "driver own failed\n");
- err = -EIO;
- goto out;
- }
-
- mt7921_wpdma_reinit_cond(dev);
- clear_bit(MT76_STATE_PM, &mphy->state);
-
- pm->stats.last_wake_event = jiffies;
- pm->stats.doze_time += pm->stats.last_wake_event -
- pm->stats.last_doze_event;
-out:
- return err;
-}
-
int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev)
{
struct mt76_phy *mphy = &dev->mt76.phy;
@@ -1334,29 +1269,14 @@ int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev)
{
struct mt76_phy *mphy = &dev->mt76.phy;
struct mt76_connac_pm *pm = &dev->pm;
- int i, err = 0;
+ int err = 0;

mutex_lock(&pm->mutex);

if (mt76_connac_skip_fw_pmctrl(mphy, pm))
goto out;

- for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) {
- mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_SET_OWN);
- if (mt76_poll_msec(dev, MT_CONN_ON_LPCTL,
- PCIE_LPCR_HOST_OWN_SYNC, 4, 50))
- break;
- }
-
- if (i == MT7921_DRV_OWN_RETRY_COUNT) {
- dev_err(dev->mt76.dev, "firmware own failed\n");
- clear_bit(MT76_STATE_PM, &mphy->state);
- err = -EIO;
- }
-
- pm->stats.last_doze_event = jiffies;
- pm->stats.awake_time += pm->stats.last_doze_event -
- pm->stats.last_wake_event;
+ err = __mt7921_mcu_fw_pmctrl(dev);
out:
mutex_unlock(&pm->mutex);

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
index a6c3661b2bdd..9c15c9bdd41e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
@@ -133,9 +133,15 @@ struct mt7921_phy {
struct delayed_work scan_work;
};

-#define mt7921_dev_reset(dev) ((dev)->hif_ops->reset(dev))
+#define mt7921_dev_reset(dev) ((dev)->hif_ops->reset(dev))
+#define mt7921_mcu_init(dev) ((dev)->hif_ops->mcu_init(dev))
+#define __mt7921_mcu_drv_pmctrl(dev) ((dev)->hif_ops->drv_own(dev))
+#define __mt7921_mcu_fw_pmctrl(dev) ((dev)->hif_ops->fw_own(dev))
struct mt7921_hif_ops {
int (*reset)(struct mt7921_dev *dev);
+ int (*mcu_init)(struct mt7921_dev *dev);
+ int (*drv_own)(struct mt7921_dev *dev);
+ int (*fw_own)(struct mt7921_dev *dev);
};

struct mt7921_dev {
@@ -250,7 +256,6 @@ int mt7921_wpdma_reset(struct mt7921_dev *dev, bool force);
int mt7921_wpdma_reinit_cond(struct mt7921_dev *dev);
void mt7921_dma_cleanup(struct mt7921_dev *dev);
int mt7921_run_firmware(struct mt7921_dev *dev);
-int mt7921_mcu_init(struct mt7921_dev *dev);
int mt7921_mcu_add_key(struct mt7921_dev *dev, struct ieee80211_vif *vif,
struct mt7921_sta *msta, struct ieee80211_key_conf *key,
enum set_key_cmd cmd);
@@ -364,7 +369,6 @@ int mt7921_mcu_uni_rx_ba(struct mt7921_dev *dev,
bool enable);
void mt7921_scan_work(struct work_struct *work);
int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif);
-int __mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev);
int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev);
int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev);
void mt7921_pm_wake_work(struct work_struct *work);
@@ -383,7 +387,17 @@ void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi,
bool beacon);
void mt7921_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi);
void mt7921_mac_sta_poll(struct mt7921_dev *dev);
+int mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
+ int cmd, int *wait_seq);
+int mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd,
+ struct sk_buff *skb, int seq);
+int mt7921_mcu_restart(struct mt76_dev *dev);
+
void mt7921e_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
struct sk_buff *skb);
int mt7921e_mac_reset(struct mt7921_dev *dev);
+int mt7921e_mcu_init(struct mt7921_dev *dev);
+int mt7921e_mcu_drv_pmctrl(struct mt7921_dev *dev);
+int mt7921e_mcu_fw_pmctrl(struct mt7921_dev *dev);
+
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
index fb19cff4a697..171aa2daef4d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
@@ -117,6 +117,9 @@ static int mt7921_pci_probe(struct pci_dev *pdev,

static const struct mt7921_hif_ops mt7921_pcie_ops = {
.reset = mt7921e_mac_reset,
+ .mcu_init = mt7921e_mcu_init,
+ .drv_own = mt7921e_mcu_drv_pmctrl,
+ .fw_own = mt7921e_mcu_fw_pmctrl,
};

struct mt7921_dev *dev;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c
index 312e42db40bd..f9547d27356e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c
@@ -282,6 +282,8 @@ int mt7921e_mac_reset(struct mt7921_dev *dev)
{
int i, err;

+ mt7921e_mcu_drv_pmctrl(dev);
+
mt76_connac_free_pending_tx_skbs(&dev->pm, NULL);

mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c
new file mode 100644
index 000000000000..9ac3bc25f067
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2021 MediaTek Inc. */
+
+#include "mt7921.h"
+#include "mcu.h"
+
+static int mt7921e_driver_own(struct mt7921_dev *dev)
+{
+ u32 reg = mt7921_reg_map_l1(dev, MT_TOP_LPCR_HOST_BAND0);
+
+ mt76_wr(dev, reg, MT_TOP_LPCR_HOST_DRV_OWN);
+ if (!mt76_poll_msec(dev, reg, MT_TOP_LPCR_HOST_FW_OWN,
+ 0, 500)) {
+ dev_err(dev->mt76.dev, "Timeout for driver own\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int mt7921e_mcu_init(struct mt7921_dev *dev)
+{
+ static const struct mt76_mcu_ops mt7921_mcu_ops = {
+ .headroom = sizeof(struct mt7921_mcu_txd),
+ .mcu_skb_send_msg = mt7921_mcu_send_message,
+ .mcu_parse_response = mt7921_mcu_parse_response,
+ .mcu_restart = mt7921_mcu_restart,
+ };
+ int err;
+
+ dev->mt76.mcu_ops = &mt7921_mcu_ops;
+
+ err = mt7921e_driver_own(dev);
+ if (err)
+ return err;
+
+ err = mt7921_run_firmware(dev);
+
+ mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false);
+
+ return err;
+}
+
+int mt7921e_mcu_drv_pmctrl(struct mt7921_dev *dev)
+{
+ struct mt76_phy *mphy = &dev->mt76.phy;
+ struct mt76_connac_pm *pm = &dev->pm;
+ int i, err = 0;
+
+ for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) {
+ mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_CLR_OWN);
+ if (mt76_poll_msec(dev, MT_CONN_ON_LPCTL,
+ PCIE_LPCR_HOST_OWN_SYNC, 0, 50))
+ break;
+ }
+
+ if (i == MT7921_DRV_OWN_RETRY_COUNT) {
+ dev_err(dev->mt76.dev, "driver own failed\n");
+ err = -EIO;
+ goto out;
+ }
+
+ mt7921_wpdma_reinit_cond(dev);
+ clear_bit(MT76_STATE_PM, &mphy->state);
+
+ pm->stats.last_wake_event = jiffies;
+ pm->stats.doze_time += pm->stats.last_wake_event -
+ pm->stats.last_doze_event;
+out:
+ return err;
+}
+
+int mt7921e_mcu_fw_pmctrl(struct mt7921_dev *dev)
+{
+ struct mt76_phy *mphy = &dev->mt76.phy;
+ struct mt76_connac_pm *pm = &dev->pm;
+ int i, err = 0;
+
+ for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) {
+ mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_SET_OWN);
+ if (mt76_poll_msec(dev, MT_CONN_ON_LPCTL,
+ PCIE_LPCR_HOST_OWN_SYNC, 4, 50))
+ break;
+ }
+
+ if (i == MT7921_DRV_OWN_RETRY_COUNT) {
+ dev_err(dev->mt76.dev, "firmware own failed\n");
+ clear_bit(MT76_STATE_PM, &mphy->state);
+ err = -EIO;
+ }
+
+ pm->stats.last_doze_event = jiffies;
+ pm->stats.awake_time += pm->stats.last_doze_event -
+ pm->stats.last_wake_event;
+
+ return err;
+}
--
2.25.1

2021-10-18 23:17:29

by Sean Wang

[permalink] [raw]
Subject: [PATCH v5 02/17] mt76: mt7921: refactor dma.c to be pcie specific

From: Sean Wang <[email protected]>

This is a preliminary patch to introduce mt7921s support.

make dma.c be used dedicately for mt7921e.

by moving out mt7921_tx_cleanup from dma.c to mcu.c and then renaming
mt7921_tx_cleanup to refect the exact thing the function actually does.

Finally, dma.c totally become pcie specific one, only needed to
be compiled only when CONFIG_MT7921E is enabled.

Tested-by: Deren Wu <[email protected]>
Acked-by: Lorenzo Bianconi <[email protected]>
Signed-off-by: Sean Wang <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt7921/dma.c | 8 +-------
drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 2 +-
drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 7 ++++++-
3 files changed, 8 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
index 802e40e42040..d3e2036a1974 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
@@ -19,12 +19,6 @@ int mt7921_init_tx_queues(struct mt7921_phy *phy, int idx, int n_desc)
return 0;
}

-void mt7921_tx_cleanup(struct mt7921_dev *dev)
-{
- mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false);
- mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WA], false);
-}
-
static int mt7921_poll_tx(struct napi_struct *napi, int budget)
{
struct mt7921_dev *dev;
@@ -37,7 +31,7 @@ static int mt7921_poll_tx(struct napi_struct *napi, int budget)
return 0;
}

- mt7921_tx_cleanup(dev);
+ mt7921_mcu_tx_cleanup(dev);
if (napi_complete(napi))
mt7921_irq_enable(dev, MT_INT_TX_DONE_ALL);
mt76_connac_pm_unref(&dev->mphy, &dev->pm);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
index 0857d523bb06..eb27d8ab4a8b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
@@ -1386,7 +1386,7 @@ void mt7921_pm_wake_work(struct work_struct *work)
mt76_for_each_q_rx(&dev->mt76, i)
napi_schedule(&dev->mt76.napi[i]);
mt76_connac_pm_dequeue_skbs(mphy, &dev->pm);
- mt7921_tx_cleanup(dev);
+ mt7921_mcu_tx_cleanup(dev);
if (test_bit(MT76_STATE_RUNNING, &mphy->state))
ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work,
MT7921_WATCHDOG_TIME);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
index 70c0f41180a1..a6c3661b2bdd 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
@@ -316,6 +316,12 @@ static inline bool mt7921_dma_need_reinit(struct mt7921_dev *dev)
return !mt76_get_field(dev, MT_WFDMA_DUMMY_CR, MT_WFDMA_NEED_REINIT);
}

+static inline void mt7921_mcu_tx_cleanup(struct mt7921_dev *dev)
+{
+ mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false);
+ mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WA], false);
+}
+
int mt7921_mac_init(struct mt7921_dev *dev);
bool mt7921_mac_wtbl_update(struct mt7921_dev *dev, int idx, u32 mask);
void mt7921_mac_reset_counters(struct mt7921_phy *phy);
@@ -330,7 +336,6 @@ void mt7921_mac_work(struct work_struct *work);
void mt7921_mac_reset_work(struct work_struct *work);
void mt7921_mac_update_mib_stats(struct mt7921_phy *phy);
void mt7921_reset(struct mt76_dev *mdev);
-void mt7921_tx_cleanup(struct mt7921_dev *dev);
int mt7921e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
enum mt76_txq_id qid, struct mt76_wcid *wcid,
struct ieee80211_sta *sta,
--
2.25.1

2021-10-18 23:17:29

by Sean Wang

[permalink] [raw]
Subject: [PATCH v5 14/17] mt76: mt7921: rely on mcu_get_nic_capability

From: Sean Wang <[email protected]>

Rely on mcu_get_nic_capability to obtain Tx quota information
for the SDIO device, get PHY capability, MAC address and then we can
totally drop mt7921/eeprom.c and any unnecessary code.

Noting that mt76_connac_mcu_get_nic_capability should be run before set
flag MT76_STATE_MCU_RUNNING being set to setup the proper parameters
like Tx quota control before the device is started to running.

Tested-by: Deren Wu <[email protected]>
Acked-by: Lorenzo Bianconi <[email protected]>
Signed-off-by: Sean Wang <[email protected]>
---
.../wireless/mediatek/mt76/mt7615/sdio_mcu.c | 1 +
.../wireless/mediatek/mt76/mt7921/Makefile | 2 +-
.../wireless/mediatek/mt76/mt7921/eeprom.c | 101 ------------------
.../net/wireless/mediatek/mt76/mt7921/init.c | 10 +-
.../net/wireless/mediatek/mt76/mt7921/mcu.c | 8 +-
.../wireless/mediatek/mt76/mt7921/mt7921.h | 8 --
.../net/wireless/mediatek/mt76/sdio_txrx.c | 3 +-
7 files changed, 10 insertions(+), 123 deletions(-)
delete mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/eeprom.c

diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c
index f76986c807ab..dc9a2f0b45a5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c
@@ -27,6 +27,7 @@ static int mt7663s_mcu_init_sched(struct mt7615_dev *dev)
MT_HIF1_MIN_QUOTA);
sdio->sched.ple_data_quota = mt76_get_field(dev, MT_PLE_PG_HIF0_GROUP,
MT_HIF0_MIN_QUOTA);
+ sdio->sched.pse_page_size = MT_PSE_PAGE_SZ;
txdwcnt = mt76_get_field(dev, MT_PP_TXDWCNT,
MT_PP_TXDWCNT_TX1_ADD_DW_CNT);
sdio->sched.deficit = txdwcnt << 2;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile
index 8cea896d5965..5f32c2c71134 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile
@@ -5,6 +5,6 @@ obj-$(CONFIG_MT7921E) += mt7921e.o

CFLAGS_trace.o := -I$(src)

-mt7921-common-y := mac.o mcu.o eeprom.o main.o init.o debugfs.o trace.o
+mt7921-common-y := mac.o mcu.o main.o init.o debugfs.o trace.o
mt7921-common-$(CONFIG_NL80211_TESTMODE) += testmode.o
mt7921e-y := pci.o pci_mac.o pci_mcu.o dma.o
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7921/eeprom.c
deleted file mode 100644
index 4d0a4aeac6bf..000000000000
--- a/drivers/net/wireless/mediatek/mt76/mt7921/eeprom.c
+++ /dev/null
@@ -1,101 +0,0 @@
-// SPDX-License-Identifier: ISC
-/* Copyright (C) 2020 MediaTek Inc. */
-
-#include "mt7921.h"
-#include "eeprom.h"
-
-static u32 mt7921_eeprom_read(struct mt7921_dev *dev, u32 offset)
-{
- u8 *data = dev->mt76.eeprom.data;
-
- if (data[offset] == 0xff)
- mt7921_mcu_get_eeprom(dev, offset);
-
- return data[offset];
-}
-
-static int mt7921_eeprom_load(struct mt7921_dev *dev)
-{
- int ret;
-
- ret = mt76_eeprom_init(&dev->mt76, MT7921_EEPROM_SIZE);
- if (ret < 0)
- return ret;
-
- memset(dev->mt76.eeprom.data, -1, MT7921_EEPROM_SIZE);
-
- return 0;
-}
-
-static int mt7921_check_eeprom(struct mt7921_dev *dev)
-{
- u8 *eeprom = dev->mt76.eeprom.data;
- u16 val;
-
- mt7921_eeprom_read(dev, MT_EE_CHIP_ID);
- val = get_unaligned_le16(eeprom);
-
- switch (val) {
- case 0x7922:
- case 0x7961:
- return 0;
- default:
- return -EINVAL;
- }
-}
-
-void mt7921_eeprom_parse_band_config(struct mt7921_phy *phy)
-{
- struct mt7921_dev *dev = phy->dev;
- u32 val;
-
- val = mt7921_eeprom_read(dev, MT_EE_WIFI_CONF);
- val = FIELD_GET(MT_EE_WIFI_CONF_BAND_SEL, val);
-
- switch (val) {
- case MT_EE_5GHZ:
- phy->mt76->cap.has_5ghz = true;
- break;
- case MT_EE_2GHZ:
- phy->mt76->cap.has_2ghz = true;
- break;
- default:
- phy->mt76->cap.has_2ghz = true;
- phy->mt76->cap.has_5ghz = true;
- break;
- }
-}
-
-static void mt7921_eeprom_parse_hw_cap(struct mt7921_dev *dev)
-{
- u8 tx_mask;
-
- mt7921_eeprom_parse_band_config(&dev->phy);
-
- /* TODO: read NSS with MCU_CMD_NIC_CAPV2 */
- tx_mask = 2;
- dev->chainmask = BIT(tx_mask) - 1;
- dev->mphy.antenna_mask = dev->chainmask;
- dev->mphy.chainmask = dev->mphy.antenna_mask;
-}
-
-int mt7921_eeprom_init(struct mt7921_dev *dev)
-{
- int ret;
-
- ret = mt7921_eeprom_load(dev);
- if (ret < 0)
- return ret;
-
- ret = mt7921_check_eeprom(dev);
- if (ret)
- return ret;
-
- mt7921_eeprom_parse_hw_cap(dev);
- memcpy(dev->mphy.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
- ETH_ALEN);
-
- mt76_eeprom_override(&dev->mphy);
-
- return 0;
-}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
index d310d6e1e566..6a4b014e8afd 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
@@ -149,7 +149,6 @@ EXPORT_SYMBOL_GPL(mt7921_mac_init);

static int __mt7921_init_hardware(struct mt7921_dev *dev)
{
- struct mt76_dev *mdev = &dev->mt76;
int ret;

/* force firmware operation mode into normal state,
@@ -160,9 +159,7 @@ static int __mt7921_init_hardware(struct mt7921_dev *dev)
if (ret)
goto out;

- ret = mt7921_eeprom_init(dev);
- if (ret)
- goto out;
+ mt76_eeprom_override(&dev->mphy);

ret = mt7921_mcu_set_eeprom(dev);
if (ret)
@@ -170,11 +167,6 @@ static int __mt7921_init_hardware(struct mt7921_dev *dev)

ret = mt7921_mac_init(dev);
out:
- if (ret && mdev->eeprom.data) {
- devm_kfree(mdev->dev, mdev->eeprom.data);
- mdev->eeprom.data = NULL;
- }
-
return ret;
}

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
index e315eb4186d3..a95495069a4d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -906,10 +906,12 @@ int mt7921_run_firmware(struct mt7921_dev *dev)
if (err)
return err;

- set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
- mt7921_mcu_fw_log_2_host(dev, 1);
+ err = mt76_connac_mcu_get_nic_capability(&dev->mphy);
+ if (err)
+ return err;

- return mt76_connac_mcu_get_nic_capability(&dev->mphy);
+ set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
+ return mt7921_mcu_fw_log_2_host(dev, 1);
}
EXPORT_SYMBOL_GPL(mt7921_run_firmware);

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
index 295f57ce7eba..2082b4d2a23d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
@@ -156,8 +156,6 @@ struct mt7921_dev {
struct mt7921_phy phy;
struct tasklet_struct irq_tasklet;

- u16 chainmask;
-
struct work_struct reset_work;
bool hw_full_reset:1;
bool hw_init_done:1;
@@ -247,12 +245,6 @@ u32 mt7921_reg_map(struct mt7921_dev *dev, u32 addr);
int __mt7921_start(struct mt7921_phy *phy);
int mt7921_register_device(struct mt7921_dev *dev);
void mt7921_unregister_device(struct mt7921_dev *dev);
-int mt7921_eeprom_init(struct mt7921_dev *dev);
-void mt7921_eeprom_parse_band_config(struct mt7921_phy *phy);
-int mt7921_eeprom_get_target_power(struct mt7921_dev *dev,
- struct ieee80211_channel *chan,
- u8 chain_idx);
-void mt7921_eeprom_init_sku(struct mt7921_dev *dev);
int mt7921_dma_init(struct mt7921_dev *dev);
int mt7921_wpdma_reset(struct mt7921_dev *dev, bool force);
int mt7921_wpdma_reinit_cond(struct mt7921_dev *dev);
diff --git a/drivers/net/wireless/mediatek/mt76/sdio_txrx.c b/drivers/net/wireless/mediatek/mt76/sdio_txrx.c
index 2728d45a2e61..9b4c95a47d47 100644
--- a/drivers/net/wireless/mediatek/mt76/sdio_txrx.c
+++ b/drivers/net/wireless/mediatek/mt76/sdio_txrx.c
@@ -173,7 +173,8 @@ mt76s_tx_pick_quota(struct mt76_sdio *sdio, bool mcu, int buf_sz,
{
int pse_sz;

- pse_sz = DIV_ROUND_UP(buf_sz + sdio->sched.deficit, MT_PSE_PAGE_SZ);
+ pse_sz = DIV_ROUND_UP(buf_sz + sdio->sched.deficit,
+ sdio->sched.pse_page_size);

if (mcu && sdio->hw_ver == MT76_CONNAC2_SDIO)
pse_sz = 1;
--
2.25.1

2021-10-18 23:17:29

by Sean Wang

[permalink] [raw]
Subject: [PATCH v5 17/17] mt76: mt7921s: add reset support

From: Sean Wang <[email protected]>

Introduce wifi chip reset support for mt7921 device to recover
mcu hangs or abnormal wifi system.

Tested-by: Deren Wu <[email protected]>
Acked-by: Lorenzo Bianconi <[email protected]>
Co-developed-by: Deren Wu <[email protected]>
Signed-off-by: Deren Wu <[email protected]>
Signed-off-by: Sean Wang <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt76.h | 2 +
.../net/wireless/mediatek/mt76/mt7921/init.c | 2 +
.../net/wireless/mediatek/mt76/mt7921/mcu.c | 1 +
.../wireless/mediatek/mt76/mt7921/mt7921.h | 4 +
.../net/wireless/mediatek/mt76/mt7921/sdio.c | 3 +
.../wireless/mediatek/mt76/mt7921/sdio_mac.c | 133 ++++++++++++++++++
.../wireless/mediatek/mt76/mt7921/sdio_mcu.c | 8 ++
.../net/wireless/mediatek/mt76/sdio_txrx.c | 32 ++++-
8 files changed, 184 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index 46e8fe3869c2..32d68ecf4c3a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -507,6 +507,7 @@ struct mt76_sdio {
struct sdio_func *func;
void *intr_data;
u8 hw_ver;
+ wait_queue_head_t wait;

struct {
int pse_data_quota;
@@ -1255,6 +1256,7 @@ int mt76s_alloc_tx(struct mt76_dev *dev);
void mt76s_deinit(struct mt76_dev *dev);
void mt76s_sdio_irq(struct sdio_func *func);
void mt76s_txrx_worker(struct mt76_sdio *sdio);
+bool mt76s_txqs_empty(struct mt76_dev *dev);
int mt76s_hw_init(struct mt76_dev *dev, struct sdio_func *func,
int hw_ver);
u32 mt76s_rr(struct mt76_dev *dev, u32 offset);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
index 2b7260be224f..87265045e2dd 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
@@ -217,6 +217,8 @@ int mt7921_register_device(struct mt7921_dev *dev)
spin_lock_init(&dev->pm.wake.lock);
mutex_init(&dev->pm.mutex);
init_waitqueue_head(&dev->pm.wait);
+ if (mt76_is_sdio(&dev->mt76))
+ init_waitqueue_head(&dev->mt76.sdio.wait);
spin_lock_init(&dev->pm.txq_lock);
INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7921_mac_work);
INIT_DELAYED_WORK(&dev->phy.scan_work, mt7921_scan_work);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
index 571f559d3363..6ada1ebe7d68 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -438,6 +438,7 @@ mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb)
mt7921_mcu_debug_msg_event(dev, skb);
break;
case MCU_EVENT_COREDUMP:
+ dev->fw_assert = true;
mt76_connac_mcu_coredump_event(&dev->mt76, skb,
&dev->coredump);
return;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
index 05e0d4371d32..eebf367be296 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
@@ -182,6 +182,7 @@ struct mt7921_dev {
struct work_struct reset_work;
bool hw_full_reset:1;
bool hw_init_done:1;
+ bool fw_assert:1;

struct list_head sta_poll_list;
spinlock_t sta_poll_lock;
@@ -425,6 +426,9 @@ void mt7921e_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
struct sk_buff *skb);
int mt7921e_mac_reset(struct mt7921_dev *dev);
int mt7921e_mcu_init(struct mt7921_dev *dev);
+int mt7921s_wfsys_reset(struct mt7921_dev *dev);
+int mt7921s_mac_reset(struct mt7921_dev *dev);
+int mt7921s_init_reset(struct mt7921_dev *dev);
int mt7921e_mcu_drv_pmctrl(struct mt7921_dev *dev);
int mt7921e_mcu_fw_pmctrl(struct mt7921_dev *dev);

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c
index e0ad97f27fea..ddf0eeb8b688 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c
@@ -46,6 +46,7 @@ static void mt7921s_unregister_device(struct mt7921_dev *dev)
cancel_work_sync(&pm->wake_work);

mt76s_deinit(&dev->mt76);
+ mt7921s_wfsys_reset(dev);
mt7921_mcu_exit(dev);

mt76_free_device(&dev->mt76);
@@ -104,6 +105,8 @@ static int mt7921s_probe(struct sdio_func *func,
.type = MT76_BUS_SDIO,
};
static const struct mt7921_hif_ops mt7921_sdio_ops = {
+ .init_reset = mt7921s_init_reset,
+ .reset = mt7921s_mac_reset,
.mcu_init = mt7921s_mcu_init,
.drv_own = mt7921s_mcu_drv_pmctrl,
.fw_own = mt7921s_mcu_fw_pmctrl,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c
index 91a7acd49ee4..137f86a6dbf8 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c
@@ -5,6 +5,139 @@
#include <linux/mmc/sdio_func.h>
#include "mt7921.h"
#include "mac.h"
+#include "../sdio.h"
+
+static void mt7921s_enable_irq(struct mt76_dev *dev)
+{
+ struct mt76_sdio *sdio = &dev->sdio;
+
+ sdio_claim_host(sdio->func);
+ sdio_writel(sdio->func, WHLPCR_INT_EN_SET, MCR_WHLPCR, NULL);
+ sdio_release_host(sdio->func);
+}
+
+static void mt7921s_disable_irq(struct mt76_dev *dev)
+{
+ struct mt76_sdio *sdio = &dev->sdio;
+
+ sdio_claim_host(sdio->func);
+ sdio_writel(sdio->func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, NULL);
+ sdio_release_host(sdio->func);
+}
+
+static u32 mt7921s_read_whcr(struct mt76_dev *dev)
+{
+ return sdio_readl(dev->sdio.func, MCR_WHCR, NULL);
+}
+
+int mt7921s_wfsys_reset(struct mt7921_dev *dev)
+{
+ struct mt76_sdio *sdio = &dev->mt76.sdio;
+ u32 val, status;
+
+ mt7921s_mcu_drv_pmctrl(dev);
+
+ sdio_claim_host(sdio->func);
+
+ val = sdio_readl(sdio->func, MCR_WHCR, NULL);
+ val &= ~WF_WHOLE_PATH_RSTB;
+ sdio_writel(sdio->func, val, MCR_WHCR, NULL);
+
+ msleep(50);
+
+ val = sdio_readl(sdio->func, MCR_WHCR, NULL);
+ val &= ~WF_SDIO_WF_PATH_RSTB;
+ sdio_writel(sdio->func, val, MCR_WHCR, NULL);
+
+ usleep_range(1000, 2000);
+
+ val = sdio_readl(sdio->func, MCR_WHCR, NULL);
+ val |= WF_WHOLE_PATH_RSTB;
+ sdio_writel(sdio->func, val, MCR_WHCR, NULL);
+
+ readx_poll_timeout(mt7921s_read_whcr, &dev->mt76, status,
+ status & WF_RST_DONE, 50000, 2000000);
+
+ sdio_release_host(sdio->func);
+
+ /* activate mt7921s again */
+ mt7921s_mcu_fw_pmctrl(dev);
+ mt7921s_mcu_drv_pmctrl(dev);
+
+ return 0;
+}
+
+int mt7921s_init_reset(struct mt7921_dev *dev)
+{
+ set_bit(MT76_MCU_RESET, &dev->mphy.state);
+
+ wake_up(&dev->mt76.mcu.wait);
+ skb_queue_purge(&dev->mt76.mcu.res_q);
+ wait_event_timeout(dev->mt76.sdio.wait,
+ mt76s_txqs_empty(&dev->mt76), 5 * HZ);
+ mt76_worker_disable(&dev->mt76.sdio.txrx_worker);
+
+ mt7921s_disable_irq(&dev->mt76);
+ mt7921s_wfsys_reset(dev);
+
+ mt76_worker_enable(&dev->mt76.sdio.txrx_worker);
+ clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
+ clear_bit(MT76_MCU_RESET, &dev->mphy.state);
+ mt7921s_enable_irq(&dev->mt76);
+
+ return 0;
+}
+
+int mt7921s_mac_reset(struct mt7921_dev *dev)
+{
+ int err;
+
+ mt76_connac_free_pending_tx_skbs(&dev->pm, NULL);
+ mt76_txq_schedule_all(&dev->mphy);
+ mt76_worker_disable(&dev->mt76.tx_worker);
+ set_bit(MT76_RESET, &dev->mphy.state);
+ set_bit(MT76_MCU_RESET, &dev->mphy.state);
+ wake_up(&dev->mt76.mcu.wait);
+ skb_queue_purge(&dev->mt76.mcu.res_q);
+ wait_event_timeout(dev->mt76.sdio.wait,
+ mt76s_txqs_empty(&dev->mt76), 5 * HZ);
+ mt76_worker_disable(&dev->mt76.sdio.txrx_worker);
+ mt76_worker_disable(&dev->mt76.sdio.status_worker);
+ mt76_worker_disable(&dev->mt76.sdio.net_worker);
+ cancel_work_sync(&dev->mt76.sdio.stat_work);
+
+ mt7921s_disable_irq(&dev->mt76);
+ mt7921s_wfsys_reset(dev);
+
+ mt76_worker_enable(&dev->mt76.sdio.txrx_worker);
+ mt76_worker_enable(&dev->mt76.sdio.status_worker);
+ mt76_worker_enable(&dev->mt76.sdio.net_worker);
+
+ dev->fw_assert = false;
+ clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
+ clear_bit(MT76_MCU_RESET, &dev->mphy.state);
+ mt7921s_enable_irq(&dev->mt76);
+
+ err = mt7921_run_firmware(dev);
+ if (err)
+ goto out;
+
+ err = mt7921_mcu_set_eeprom(dev);
+ if (err)
+ goto out;
+
+ err = mt7921_mac_init(dev);
+ if (err)
+ goto out;
+
+ err = __mt7921_start(&dev->phy);
+out:
+ clear_bit(MT76_RESET, &dev->mphy.state);
+
+ mt76_worker_enable(&dev->mt76.tx_worker);
+
+ return err;
+}

static void
mt7921s_write_txwi(struct mt7921_dev *dev, struct mt76_wcid *wcid,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c
index 049e06d7c3fb..437cddad9a90 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c
@@ -21,6 +21,14 @@ mt7921s_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
enum mt76_mcuq_id txq = MT_MCUQ_WM;
int ret, pad;

+ /* We just return in case firmware assertion to avoid blocking the
+ * common workqueue to run, for example, the coredump work might be
+ * blocked by mt7921_mac_work that is excuting register access via sdio
+ * bus.
+ */
+ if (dev->fw_assert)
+ return -EBUSY;
+
ret = mt7921_mcu_fill_message(mdev, skb, cmd, seq);
if (ret)
return ret;
diff --git a/drivers/net/wireless/mediatek/mt76/sdio_txrx.c b/drivers/net/wireless/mediatek/mt76/sdio_txrx.c
index 9b4c95a47d47..649a56790b89 100644
--- a/drivers/net/wireless/mediatek/mt76/sdio_txrx.c
+++ b/drivers/net/wireless/mediatek/mt76/sdio_txrx.c
@@ -235,6 +235,9 @@ static int mt76s_tx_run_queue(struct mt76_dev *dev, struct mt76_queue *q)

smp_rmb();

+ if (test_bit(MT76_MCU_RESET, &dev->phy.state))
+ goto next;
+
if (!test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state)) {
__skb_put_zero(e->skb, 4);
err = __mt76s_xmit_queue(dev, e->skb->data,
@@ -313,6 +316,13 @@ void mt76s_txrx_worker(struct mt76_sdio *sdio)
ret = mt76s_rx_handler(dev);
if (ret > 0)
nframes += ret;
+
+ if (test_bit(MT76_MCU_RESET, &dev->phy.state)) {
+ if (!mt76s_txqs_empty(dev))
+ continue;
+ else
+ wake_up(&sdio->wait);
+ }
} while (nframes > 0);

/* enable interrupt */
@@ -326,9 +336,29 @@ void mt76s_sdio_irq(struct sdio_func *func)
struct mt76_dev *dev = sdio_get_drvdata(func);
struct mt76_sdio *sdio = &dev->sdio;

- if (!test_bit(MT76_STATE_INITIALIZED, &dev->phy.state))
+ if (!test_bit(MT76_STATE_INITIALIZED, &dev->phy.state) ||
+ test_bit(MT76_MCU_RESET, &dev->phy.state))
return;

mt76_worker_schedule(&sdio->txrx_worker);
}
EXPORT_SYMBOL_GPL(mt76s_sdio_irq);
+
+bool mt76s_txqs_empty(struct mt76_dev *dev)
+{
+ struct mt76_queue *q;
+ int i;
+
+ for (i = 0; i <= MT_TXQ_PSD + 1; i++) {
+ if (i <= MT_TXQ_PSD)
+ q = dev->phy.q_tx[i];
+ else
+ q = dev->q_mcu[MT_MCUQ_WM];
+
+ if (q->first != q->head)
+ return false;
+ }
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(mt76s_txqs_empty);
--
2.25.1

2021-10-18 23:20:35

by Sean Wang

[permalink] [raw]
Subject: [PATCH v5 07/17] mt76: mt7663s: rely on mcu reg access utility

From: Sean Wang <[email protected]>

rely on mcu reg access utility and drop the duplicated code.

Acked-by: Lorenzo Bianconi <[email protected]>
Signed-off-by: Sean Wang <[email protected]>
---
.../net/wireless/mediatek/mt76/mt7615/mcu.c | 28 -------------------
.../wireless/mediatek/mt76/mt7615/mt7615.h | 2 --
.../wireless/mediatek/mt76/mt7615/sdio_mcu.c | 4 +--
3 files changed, 2 insertions(+), 32 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
index 2ba730808f3b..2cb3969e6432 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
@@ -2769,31 +2769,3 @@ int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif,
return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_ROC, &req,
sizeof(req), false);
}
-
-u32 mt7615_mcu_reg_rr(struct mt76_dev *dev, u32 offset)
-{
- struct {
- __le32 addr;
- __le32 val;
- } __packed req = {
- .addr = cpu_to_le32(offset),
- };
-
- return mt76_mcu_send_msg(dev, MCU_CMD_REG_READ, &req, sizeof(req),
- true);
-}
-EXPORT_SYMBOL_GPL(mt7615_mcu_reg_rr);
-
-void mt7615_mcu_reg_wr(struct mt76_dev *dev, u32 offset, u32 val)
-{
- struct {
- __le32 addr;
- __le32 val;
- } __packed req = {
- .addr = cpu_to_le32(offset),
- .val = cpu_to_le32(val),
- };
-
- mt76_mcu_send_msg(dev, MCU_CMD_REG_WRITE, &req, sizeof(req), false);
-}
-EXPORT_SYMBOL_GPL(mt7615_mcu_reg_wr);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
index 58a98b5c0cbc..437f14f06e63 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
@@ -553,8 +553,6 @@ int mt7615_mac_set_beacon_filter(struct mt7615_phy *phy,
int mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif,
bool enable);
int __mt7663_load_firmware(struct mt7615_dev *dev);
-u32 mt7615_mcu_reg_rr(struct mt76_dev *dev, u32 offset);
-void mt7615_mcu_reg_wr(struct mt76_dev *dev, u32 offset, u32 val);
void mt7615_coredump_work(struct work_struct *work);

void mt7622_trigger_hif_int(struct mt7615_dev *dev, bool en);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c
index 45c1cd3b9f49..517419bb7772 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c
@@ -137,8 +137,8 @@ int mt7663s_mcu_init(struct mt7615_dev *dev)
.mcu_skb_send_msg = mt7663s_mcu_send_message,
.mcu_parse_response = mt7615_mcu_parse_response,
.mcu_restart = mt7615_mcu_restart,
- .mcu_rr = mt7615_mcu_reg_rr,
- .mcu_wr = mt7615_mcu_reg_wr,
+ .mcu_rr = mt76_connac_mcu_reg_rr,
+ .mcu_wr = mt76_connac_mcu_reg_wr,
};
struct mt7615_mcu_ops *mcu_ops;
int ret;
--
2.25.1

2021-10-18 23:20:35

by Sean Wang

[permalink] [raw]
Subject: [PATCH v5 13/17] mt76: connac: extend mcu_get_nic_capability

From: Sean Wang <[email protected]>

Extend mcu_get_nic_capability to obtain tx resource for SDIO device,
MAC address, and PHY capability.

Tested-by: Deren Wu <[email protected]>
Acked-by: Lorenzo Bianconi <[email protected]>
Signed-off-by: Sean Wang <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt76.h | 1 +
.../wireless/mediatek/mt76/mt76_connac_mcu.c | 66 +++++++++++++++++++
2 files changed, 67 insertions(+)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index 85afe05d7f30..46e8fe3869c2 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -512,6 +512,7 @@ struct mt76_sdio {
int pse_data_quota;
int ple_data_quota;
int pse_mcu_quota;
+ int pse_page_size;
int deficit;
} sched;

diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
index 70d72dfa239e..32e25180fc1e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
@@ -1722,6 +1722,61 @@ void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb,
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_coredump_event);

+static void mt76_connac_mcu_parse_tx_resource(struct mt76_dev *dev,
+ struct sk_buff *skb)
+{
+ struct mt76_sdio *sdio = &dev->sdio;
+ struct mt76_connac_tx_resource {
+ __le32 version;
+ __le32 pse_data_quota;
+ __le32 pse_mcu_quota;
+ __le32 ple_data_quota;
+ __le32 ple_mcu_quota;
+ __le16 pse_page_size;
+ __le16 ple_page_size;
+ u8 pp_padding;
+ u8 pad[3];
+ } __packed * tx_res;
+
+ tx_res = (struct mt76_connac_tx_resource *)skb->data;
+ sdio->sched.pse_data_quota = le32_to_cpu(tx_res->pse_data_quota);
+ sdio->sched.pse_mcu_quota = le32_to_cpu(tx_res->pse_mcu_quota);
+ sdio->sched.ple_data_quota = le32_to_cpu(tx_res->ple_data_quota);
+ sdio->sched.pse_page_size = le16_to_cpu(tx_res->pse_page_size);
+ sdio->sched.deficit = tx_res->pp_padding;
+}
+
+static void mt76_connac_mcu_parse_phy_cap(struct mt76_dev *dev,
+ struct sk_buff *skb)
+{
+ struct mt76_connac_phy_cap {
+ u8 ht;
+ u8 vht;
+ u8 _5g;
+ u8 max_bw;
+ u8 nss;
+ u8 dbdc;
+ u8 tx_ldpc;
+ u8 rx_ldpc;
+ u8 tx_stbc;
+ u8 rx_stbc;
+ u8 hw_path;
+ u8 he;
+ } __packed * cap;
+
+ enum {
+ WF0_24G,
+ WF0_5G
+ };
+
+ cap = (struct mt76_connac_phy_cap *)skb->data;
+
+ dev->phy.antenna_mask = BIT(cap->nss) - 1;
+ dev->phy.chainmask = dev->phy.antenna_mask;
+ dev->phy.cap.has_2ghz = cap->hw_path & BIT(WF0_24G);
+ dev->phy.cap.has_5ghz = cap->hw_path & BIT(WF0_5G);
+}
+
int mt76_connac_mcu_get_nic_capability(struct mt76_phy *phy)
{
struct mt76_connac_cap_hdr {
@@ -1764,6 +1819,17 @@ int mt76_connac_mcu_get_nic_capability(struct mt76_phy *phy)
case MT_NIC_CAP_6G:
phy->cap.has_6ghz = skb->data[0];
break;
+ case MT_NIC_CAP_MAC_ADDR:
+ memcpy(phy->macaddr, (void *)skb->data, ETH_ALEN);
+ break;
+ case MT_NIC_CAP_PHY:
+ mt76_connac_mcu_parse_phy_cap(phy->dev, skb);
+ break;
+ case MT_NIC_CAP_TX_RESOURCE:
+ if (mt76_is_sdio(phy->dev))
+ mt76_connac_mcu_parse_tx_resource(phy->dev,
+ skb);
+ break;
default:
break;
}
--
2.25.1

2021-10-18 23:20:36

by Sean Wang

[permalink] [raw]
Subject: [PATCH v5 04/17] mt76: mt7921: refactor init.c to be bus independent

From: Sean Wang <[email protected]>

This is a preliminary patch to introduce mt7921s support.

Make init.c reusable between mt7921s and mt7921e

Tested-by: Deren Wu <[email protected]>
Acked-by: Lorenzo Bianconi <[email protected]>
Signed-off-by: Sean Wang <[email protected]>
---
.../net/wireless/mediatek/mt76/mt7921/dma.c | 3 ++
.../net/wireless/mediatek/mt76/mt7921/init.c | 27 +--------------
.../wireless/mediatek/mt76/mt7921/mt7921.h | 2 ++
.../net/wireless/mediatek/mt76/mt7921/pci.c | 33 ++++++++++++++++++-
4 files changed, 38 insertions(+), 27 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
index d3e2036a1974..8f29d09179e4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
@@ -343,6 +343,9 @@ int mt7921_dma_init(struct mt7921_dev *dev)
struct mt76_bus_ops *bus_ops;
int ret;

+ dev->phy.dev = dev;
+ dev->phy.mt76 = &dev->mt76.phy;
+ dev->mt76.phy.priv = &dev->phy;
dev->bus_ops = dev->mt76.bus;
bus_ops = devm_kmemdup(dev->mt76.dev, dev->bus_ops, sizeof(*bus_ops),
GFP_KERNEL);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
index 7956a57510c4..f0fd32c424c6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
@@ -181,10 +181,6 @@ static int mt7921_init_hardware(struct mt7921_dev *dev)
{
int ret, idx, i;

- ret = mt7921_dma_init(dev);
- if (ret)
- return ret;
-
set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state);

for (i = 0; i < MT7921_MCU_INIT_RETRY_COUNT; i++) {
@@ -192,7 +188,7 @@ static int mt7921_init_hardware(struct mt7921_dev *dev)
if (!ret)
break;

- mt7921_wpdma_reset(dev, true);
+ mt7921_init_reset(dev);
}

if (i == MT7921_MCU_INIT_RETRY_COUNT) {
@@ -289,24 +285,3 @@ int mt7921_register_device(struct mt7921_dev *dev)

return 0;
}
-
-void mt7921_unregister_device(struct mt7921_dev *dev)
-{
- int i;
- struct mt76_connac_pm *pm = &dev->pm;
-
- mt76_unregister_device(&dev->mt76);
- mt76_for_each_q_rx(&dev->mt76, i)
- napi_disable(&dev->mt76.napi[i]);
- cancel_delayed_work_sync(&pm->ps_work);
- cancel_work_sync(&pm->wake_work);
-
- mt7921_tx_token_put(dev);
- mt7921_mcu_drv_pmctrl(dev);
- mt7921_dma_cleanup(dev);
- mt7921_wfsys_reset(dev);
- mt7921_mcu_exit(dev);
-
- tasklet_disable(&dev->irq_tasklet);
- mt76_free_device(&dev->mt76);
-}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
index 9c15c9bdd41e..295f57ce7eba 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
@@ -133,11 +133,13 @@ struct mt7921_phy {
struct delayed_work scan_work;
};

+#define mt7921_init_reset(dev) ((dev)->hif_ops->init_reset(dev))
#define mt7921_dev_reset(dev) ((dev)->hif_ops->reset(dev))
#define mt7921_mcu_init(dev) ((dev)->hif_ops->mcu_init(dev))
#define __mt7921_mcu_drv_pmctrl(dev) ((dev)->hif_ops->drv_own(dev))
#define __mt7921_mcu_fw_pmctrl(dev) ((dev)->hif_ops->fw_own(dev))
struct mt7921_hif_ops {
+ int (*init_reset)(struct mt7921_dev *dev);
int (*reset)(struct mt7921_dev *dev);
int (*mcu_init)(struct mt7921_dev *dev);
int (*drv_own)(struct mt7921_dev *dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
index 171aa2daef4d..305b63fa1a8a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
@@ -93,6 +93,32 @@ static void mt7921_irq_tasklet(unsigned long data)
napi_schedule(&dev->mt76.napi[MT_RXQ_MAIN]);
}

+static int mt7921e_init_reset(struct mt7921_dev *dev)
+{
+ return mt7921_wpdma_reset(dev, true);
+}
+
+static void mt7921e_unregister_device(struct mt7921_dev *dev)
+{
+ int i;
+ struct mt76_connac_pm *pm = &dev->pm;
+
+ mt76_unregister_device(&dev->mt76);
+ mt76_for_each_q_rx(&dev->mt76, i)
+ napi_disable(&dev->mt76.napi[i]);
+ cancel_delayed_work_sync(&pm->ps_work);
+ cancel_work_sync(&pm->wake_work);
+
+ mt7921_tx_token_put(dev);
+ mt7921_mcu_drv_pmctrl(dev);
+ mt7921_dma_cleanup(dev);
+ mt7921_wfsys_reset(dev);
+ mt7921_mcu_exit(dev);
+
+ tasklet_disable(&dev->irq_tasklet);
+ mt76_free_device(&dev->mt76);
+}
+
static int mt7921_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
@@ -116,6 +142,7 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
};

static const struct mt7921_hif_ops mt7921_pcie_ops = {
+ .init_reset = mt7921e_init_reset,
.reset = mt7921e_mac_reset,
.mcu_init = mt7921e_mcu_init,
.drv_own = mt7921e_mcu_drv_pmctrl,
@@ -172,6 +199,10 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
if (ret)
goto err_free_dev;

+ ret = mt7921_dma_init(dev);
+ if (ret)
+ goto err_free_irq;
+
ret = mt7921_register_device(dev);
if (ret)
goto err_free_irq;
@@ -193,7 +224,7 @@ static void mt7921_pci_remove(struct pci_dev *pdev)
struct mt76_dev *mdev = pci_get_drvdata(pdev);
struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);

- mt7921_unregister_device(dev);
+ mt7921e_unregister_device(dev);
devm_free_irq(&pdev->dev, pdev->irq, dev);
pci_free_irq_vectors(pdev);
}
--
2.25.1

2021-10-18 23:20:44

by Sean Wang

[permalink] [raw]
Subject: [PATCH v5 01/17] mt76: mt7921: refactor mac.c to be bus independent

From: Sean Wang <[email protected]>

This is a preliminary patch to introduce mt7921s support.

Split out a new pci_mac.c from mac.c to make mac.c reusable between
mt7921s and mt7921e.

Tested-by: Deren Wu <[email protected]>
Acked-by: Lorenzo Bianconi <[email protected]>
Signed-off-by: Sean Wang <[email protected]>
---
.../wireless/mediatek/mt76/mt7921/Makefile | 2 +-
.../net/wireless/mediatek/mt76/mt7921/mac.c | 342 +----------------
.../wireless/mediatek/mt76/mt7921/mt7921.h | 25 +-
.../net/wireless/mediatek/mt76/mt7921/pci.c | 12 +-
.../wireless/mediatek/mt76/mt7921/pci_mac.c | 346 ++++++++++++++++++
5 files changed, 383 insertions(+), 344 deletions(-)
create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile
index 3471d82fc265..554202358470 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile
@@ -4,5 +4,5 @@ obj-$(CONFIG_MT7921E) += mt7921e.o

CFLAGS_trace.o := -I$(src)

-mt7921e-y := pci.o mac.o mcu.o dma.o eeprom.o main.o init.o debugfs.o trace.o
+mt7921e-y := pci.o pci_mac.o mac.o mcu.o dma.o eeprom.o main.o init.o debugfs.o trace.o
mt7921e-$(CONFIG_NL80211_TESTMODE) += testmode.o
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
index 0659ff290af9..0857d523bb06 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
@@ -49,7 +49,7 @@ bool mt7921_mac_wtbl_update(struct mt7921_dev *dev, int idx, u32 mask)
0, 5000);
}

-static void mt7921_mac_sta_poll(struct mt7921_dev *dev)
+void mt7921_mac_sta_poll(struct mt7921_dev *dev)
{
static const u8 ac_to_tid[] = {
[IEEE80211_AC_BE] = 0,
@@ -68,8 +68,6 @@ static void mt7921_mac_sta_poll(struct mt7921_dev *dev)
list_splice_init(&dev->sta_poll_list, &sta_poll_list);
spin_unlock_bh(&dev->sta_poll_lock);

- rcu_read_lock();
-
while (true) {
bool clear = false;
u32 addr, val;
@@ -166,8 +164,6 @@ static void mt7921_mac_sta_poll(struct mt7921_dev *dev)
rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI;
}
}
-
- rcu_read_unlock();
}

static void
@@ -836,11 +832,10 @@ mt7921_mac_write_txwi_80211(struct mt7921_dev *dev, __le32 *txwi,
txwi[7] |= cpu_to_le32(val);
}

-static void
-mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi,
- struct sk_buff *skb, struct mt76_wcid *wcid,
- struct ieee80211_key_conf *key, int pid,
- bool beacon)
+void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi,
+ struct sk_buff *skb, struct mt76_wcid *wcid,
+ struct ieee80211_key_conf *key, int pid,
+ bool beacon)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_vif *vif = info->control.vif;
@@ -922,87 +917,7 @@ mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi,
}
}

-static void
-mt7921_write_hw_txp(struct mt7921_dev *dev, struct mt76_tx_info *tx_info,
- void *txp_ptr, u32 id)
-{
- struct mt7921_hw_txp *txp = txp_ptr;
- struct mt7921_txp_ptr *ptr = &txp->ptr[0];
- int i, nbuf = tx_info->nbuf - 1;
-
- tx_info->buf[0].len = MT_TXD_SIZE + sizeof(*txp);
- tx_info->nbuf = 1;
-
- txp->msdu_id[0] = cpu_to_le16(id | MT_MSDU_ID_VALID);
-
- for (i = 0; i < nbuf; i++) {
- u16 len = tx_info->buf[i + 1].len & MT_TXD_LEN_MASK;
- u32 addr = tx_info->buf[i + 1].addr;
-
- if (i == nbuf - 1)
- len |= MT_TXD_LEN_LAST;
-
- if (i & 1) {
- ptr->buf1 = cpu_to_le32(addr);
- ptr->len1 = cpu_to_le16(len);
- ptr++;
- } else {
- ptr->buf0 = cpu_to_le32(addr);
- ptr->len0 = cpu_to_le16(len);
- }
- }
-}
-
-int mt7921_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
- enum mt76_txq_id qid, struct mt76_wcid *wcid,
- struct ieee80211_sta *sta,
- struct mt76_tx_info *tx_info)
-{
- struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
- struct ieee80211_key_conf *key = info->control.hw_key;
- struct mt76_txwi_cache *t;
- struct mt7921_txp_common *txp;
- int id, pid;
- u8 *txwi = (u8 *)txwi_ptr;
-
- if (unlikely(tx_info->skb->len <= ETH_HLEN))
- return -EINVAL;
-
- if (!wcid)
- wcid = &dev->mt76.global_wcid;
-
- t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size);
- t->skb = tx_info->skb;
-
- id = mt76_token_consume(mdev, &t);
- if (id < 0)
- return id;
-
- if (sta) {
- struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv;
-
- if (time_after(jiffies, msta->last_txs + HZ / 4)) {
- info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
- msta->last_txs = jiffies;
- }
- }
-
- pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
- mt7921_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key,
- pid, false);
-
- txp = (struct mt7921_txp_common *)(txwi + MT_TXD_SIZE);
- memset(txp, 0, sizeof(struct mt7921_txp_common));
- mt7921_write_hw_txp(dev, tx_info, txp, id);
-
- tx_info->skb = DMA_DUMMY_DATA;
-
- return 0;
-}
-
-static void
-mt7921_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
+void mt7921_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
{
struct mt7921_sta *msta;
u16 fc, tid;
@@ -1026,141 +941,6 @@ mt7921_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
ieee80211_start_tx_ba_session(sta, tid, 0);
}

-static void
-mt7921_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *t)
-{
- struct mt7921_txp_common *txp;
- int i;
-
- txp = mt7921_txwi_to_txp(dev, t);
-
- for (i = 0; i < ARRAY_SIZE(txp->hw.ptr); i++) {
- struct mt7921_txp_ptr *ptr = &txp->hw.ptr[i];
- bool last;
- u16 len;
-
- len = le16_to_cpu(ptr->len0);
- last = len & MT_TXD_LEN_LAST;
- len &= MT_TXD_LEN_MASK;
- dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf0), len,
- DMA_TO_DEVICE);
- if (last)
- break;
-
- len = le16_to_cpu(ptr->len1);
- last = len & MT_TXD_LEN_LAST;
- len &= MT_TXD_LEN_MASK;
- dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf1), len,
- DMA_TO_DEVICE);
- if (last)
- break;
- }
-}
-
-static void
-mt7921_txwi_free(struct mt7921_dev *dev, struct mt76_txwi_cache *t,
- struct ieee80211_sta *sta, bool clear_status,
- struct list_head *free_list)
-{
- struct mt76_dev *mdev = &dev->mt76;
- __le32 *txwi;
- u16 wcid_idx;
-
- mt7921_txp_skb_unmap(mdev, t);
- if (!t->skb)
- goto out;
-
- txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t);
- if (sta) {
- struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
-
- if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
- mt7921_tx_check_aggr(sta, txwi);
-
- wcid_idx = wcid->idx;
- } else {
- wcid_idx = FIELD_GET(MT_TXD1_WLAN_IDX, le32_to_cpu(txwi[1]));
- }
-
- __mt76_tx_complete_skb(mdev, wcid_idx, t->skb, free_list);
-
-out:
- t->skb = NULL;
- mt76_put_txwi(mdev, t);
-}
-
-static void
-mt7921_mac_tx_free(struct mt7921_dev *dev, struct sk_buff *skb)
-{
- struct mt7921_tx_free *free = (struct mt7921_tx_free *)skb->data;
- struct mt76_dev *mdev = &dev->mt76;
- struct mt76_txwi_cache *txwi;
- struct ieee80211_sta *sta = NULL;
- LIST_HEAD(free_list);
- struct sk_buff *tmp;
- bool wake = false;
- u8 i, count;
-
- /* clean DMA queues and unmap buffers first */
- mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_PSD], false);
- mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BE], false);
-
- /* TODO: MT_TX_FREE_LATENCY is msdu time from the TXD is queued into PLE,
- * to the time ack is received or dropped by hw (air + hw queue time).
- * Should avoid accessing WTBL to get Tx airtime, and use it instead.
- */
- count = FIELD_GET(MT_TX_FREE_MSDU_CNT, le16_to_cpu(free->ctrl));
- for (i = 0; i < count; i++) {
- u32 msdu, info = le32_to_cpu(free->info[i]);
- u8 stat;
-
- /* 1'b1: new wcid pair.
- * 1'b0: msdu_id with the same 'wcid pair' as above.
- */
- if (info & MT_TX_FREE_PAIR) {
- struct mt7921_sta *msta;
- struct mt76_wcid *wcid;
- u16 idx;
-
- count++;
- idx = FIELD_GET(MT_TX_FREE_WLAN_ID, info);
- wcid = rcu_dereference(dev->mt76.wcid[idx]);
- sta = wcid_to_sta(wcid);
- if (!sta)
- continue;
-
- msta = container_of(wcid, struct mt7921_sta, wcid);
- spin_lock_bh(&dev->sta_poll_lock);
- if (list_empty(&msta->poll_list))
- list_add_tail(&msta->poll_list, &dev->sta_poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
- continue;
- }
-
- msdu = FIELD_GET(MT_TX_FREE_MSDU_ID, info);
- stat = FIELD_GET(MT_TX_FREE_STATUS, info);
-
- txwi = mt76_token_release(mdev, msdu, &wake);
- if (!txwi)
- continue;
-
- mt7921_txwi_free(dev, txwi, sta, stat, &free_list);
- }
-
- if (wake)
- mt76_set_tx_blocked(&dev->mt76, false);
-
- napi_consume_skb(skb, 1);
-
- list_for_each_entry_safe(skb, tmp, &free_list, list) {
- skb_list_del_init(skb);
- napi_consume_skb(skb, 1);
- }
-
- mt7921_mac_sta_poll(dev);
- mt76_worker_schedule(&dev->mt76.tx_worker);
-}
-
static bool
mt7921_mac_add_txs_skb(struct mt7921_dev *dev, struct mt76_wcid *wcid, int pid,
__le32 *txs_data)
@@ -1328,9 +1108,6 @@ void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
type = PKT_TYPE_NORMAL_MCU;

switch (type) {
- case PKT_TYPE_TXRX_NOTIFY:
- mt7921_mac_tx_free(dev, skb);
- break;
case PKT_TYPE_RX_EVENT:
mt7921_mcu_rx_event(dev, skb);
break;
@@ -1352,29 +1129,6 @@ void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
}
}

-void mt7921_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
-{
- if (!e->txwi) {
- dev_kfree_skb_any(e->skb);
- return;
- }
-
- /* error path */
- if (e->skb == DMA_DUMMY_DATA) {
- struct mt76_txwi_cache *t;
- struct mt7921_txp_common *txp;
- u16 token;
-
- txp = mt7921_txwi_to_txp(mdev, e->txwi);
- token = le16_to_cpu(txp->hw.msdu_id[0]) & ~MT_MSDU_ID_VALID;
- t = mt76_token_put(mdev, token);
- e->skb = t ? t->skb : NULL;
- }
-
- if (e->skb)
- mt76_tx_complete_skb(mdev, e->wcid, e->skb);
-}
-
void mt7921_mac_reset_counters(struct mt7921_phy *phy)
{
struct mt7921_dev *dev = phy->dev;
@@ -1490,20 +1244,6 @@ void mt7921_update_channel(struct mt76_phy *mphy)
mt76_connac_power_save_sched(mphy, &dev->pm);
}

-void mt7921_tx_token_put(struct mt7921_dev *dev)
-{
- struct mt76_txwi_cache *txwi;
- int id;
-
- spin_lock_bh(&dev->mt76.token_lock);
- idr_for_each_entry(&dev->mt76.token, txwi, id) {
- mt7921_txwi_free(dev, txwi, NULL, false, NULL);
- dev->mt76.token_count--;
- }
- spin_unlock_bh(&dev->mt76.token_lock);
- idr_destroy(&dev->mt76.token);
-}
-
static void
mt7921_vif_connect_iter(void *priv, u8 *mac,
struct ieee80211_vif *vif)
@@ -1518,74 +1258,6 @@ mt7921_vif_connect_iter(void *priv, u8 *mac,
mt7921_mcu_set_tx(dev, vif);
}

-static int
-mt7921_mac_reset(struct mt7921_dev *dev)
-{
- int i, err;
-
- mt76_connac_free_pending_tx_skbs(&dev->pm, NULL);
-
- mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0);
- mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0);
-
- set_bit(MT76_RESET, &dev->mphy.state);
- set_bit(MT76_MCU_RESET, &dev->mphy.state);
- wake_up(&dev->mt76.mcu.wait);
- skb_queue_purge(&dev->mt76.mcu.res_q);
-
- mt76_txq_schedule_all(&dev->mphy);
-
- mt76_worker_disable(&dev->mt76.tx_worker);
- napi_disable(&dev->mt76.napi[MT_RXQ_MAIN]);
- napi_disable(&dev->mt76.napi[MT_RXQ_MCU]);
- napi_disable(&dev->mt76.napi[MT_RXQ_MCU_WA]);
- napi_disable(&dev->mt76.tx_napi);
-
- mt7921_tx_token_put(dev);
- idr_init(&dev->mt76.token);
-
- mt7921_wpdma_reset(dev, true);
-
- local_bh_disable();
- mt76_for_each_q_rx(&dev->mt76, i) {
- napi_enable(&dev->mt76.napi[i]);
- napi_schedule(&dev->mt76.napi[i]);
- }
- local_bh_enable();
-
- clear_bit(MT76_MCU_RESET, &dev->mphy.state);
-
- mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA,
- MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
- MT_INT_MCU_CMD);
- mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
-
- err = mt7921_run_firmware(dev);
- if (err)
- goto out;
-
- err = mt7921_mcu_set_eeprom(dev);
- if (err)
- goto out;
-
- err = mt7921_mac_init(dev);
- if (err)
- goto out;
-
- err = __mt7921_start(&dev->phy);
-out:
- clear_bit(MT76_RESET, &dev->mphy.state);
-
- local_bh_disable();
- napi_enable(&dev->mt76.tx_napi);
- napi_schedule(&dev->mt76.tx_napi);
- local_bh_enable();
-
- mt76_worker_enable(&dev->mt76.tx_worker);
-
- return err;
-}
-
/* system error recovery */
void mt7921_mac_reset_work(struct work_struct *work)
{
@@ -1607,7 +1279,7 @@ void mt7921_mac_reset_work(struct work_struct *work)
for (i = 0; i < 10; i++) {
__mt7921_mcu_drv_pmctrl(dev);

- if (!mt7921_mac_reset(dev))
+ if (!mt7921_dev_reset(dev))
break;
}
mutex_unlock(&dev->mt76.mutex);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
index e14b86b1c6d1..70c0f41180a1 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
@@ -133,6 +133,11 @@ struct mt7921_phy {
struct delayed_work scan_work;
};

+#define mt7921_dev_reset(dev) ((dev)->hif_ops->reset(dev))
+struct mt7921_hif_ops {
+ int (*reset)(struct mt7921_dev *dev);
+};
+
struct mt7921_dev {
union { /* must be first */
struct mt76_dev mt76;
@@ -156,6 +161,7 @@ struct mt7921_dev {

struct mt76_connac_pm pm;
struct mt76_connac_coredump coredump;
+ const struct mt7921_hif_ops *hif_ops;
};

enum {
@@ -325,13 +331,13 @@ void mt7921_mac_reset_work(struct work_struct *work);
void mt7921_mac_update_mib_stats(struct mt7921_phy *phy);
void mt7921_reset(struct mt76_dev *mdev);
void mt7921_tx_cleanup(struct mt7921_dev *dev);
-int mt7921_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
- enum mt76_txq_id qid, struct mt76_wcid *wcid,
- struct ieee80211_sta *sta,
- struct mt76_tx_info *tx_info);
+int mt7921e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+ enum mt76_txq_id qid, struct mt76_wcid *wcid,
+ struct ieee80211_sta *sta,
+ struct mt76_tx_info *tx_info);

void mt7921_tx_worker(struct mt76_worker *w);
-void mt7921_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e);
+void mt7921e_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e);
int mt7921_init_tx_queues(struct mt7921_phy *phy, int idx, int n_desc);
void mt7921_tx_token_put(struct mt7921_dev *dev);
void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
@@ -366,4 +372,13 @@ int mt7921_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
void *data, int len);
int mt7921_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
struct netlink_callback *cb, void *data, int len);
+void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi,
+ struct sk_buff *skb, struct mt76_wcid *wcid,
+ struct ieee80211_key_conf *key, int pid,
+ bool beacon);
+void mt7921_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi);
+void mt7921_mac_sta_poll(struct mt7921_dev *dev);
+void mt7921e_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
+ struct sk_buff *skb);
+int mt7921e_mac_reset(struct mt7921_dev *dev);
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
index b5622b612613..fb19cff4a697 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
@@ -104,9 +104,9 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
SURVEY_INFO_TIME_RX |
SURVEY_INFO_TIME_BSS_RX,
.token_size = MT7921_TOKEN_SIZE,
- .tx_prepare_skb = mt7921_tx_prepare_skb,
- .tx_complete_skb = mt7921_tx_complete_skb,
- .rx_skb = mt7921_queue_rx_skb,
+ .tx_prepare_skb = mt7921e_tx_prepare_skb,
+ .tx_complete_skb = mt7921e_tx_complete_skb,
+ .rx_skb = mt7921e_queue_rx_skb,
.rx_poll_complete = mt7921_rx_poll_complete,
.sta_ps = mt7921_sta_ps,
.sta_add = mt7921_mac_sta_add,
@@ -114,6 +114,11 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
.sta_remove = mt7921_mac_sta_remove,
.update_survey = mt7921_update_channel,
};
+
+ static const struct mt7921_hif_ops mt7921_pcie_ops = {
+ .reset = mt7921e_mac_reset,
+ };
+
struct mt7921_dev *dev;
struct mt76_dev *mdev;
int ret;
@@ -147,6 +152,7 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
}

dev = container_of(mdev, struct mt7921_dev, mt76);
+ dev->hif_ops = &mt7921_pcie_ops;

mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]);
tasklet_init(&dev->irq_tasklet, mt7921_irq_tasklet, (unsigned long)dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c
new file mode 100644
index 000000000000..312e42db40bd
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c
@@ -0,0 +1,346 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2021 MediaTek Inc. */
+
+#include "mt7921.h"
+#include "../dma.h"
+#include "mac.h"
+
+static void
+mt7921_write_hw_txp(struct mt7921_dev *dev, struct mt76_tx_info *tx_info,
+ void *txp_ptr, u32 id)
+{
+ struct mt7921_hw_txp *txp = txp_ptr;
+ struct mt7921_txp_ptr *ptr = &txp->ptr[0];
+ int i, nbuf = tx_info->nbuf - 1;
+
+ tx_info->buf[0].len = MT_TXD_SIZE + sizeof(*txp);
+ tx_info->nbuf = 1;
+
+ txp->msdu_id[0] = cpu_to_le16(id | MT_MSDU_ID_VALID);
+
+ for (i = 0; i < nbuf; i++) {
+ u16 len = tx_info->buf[i + 1].len & MT_TXD_LEN_MASK;
+ u32 addr = tx_info->buf[i + 1].addr;
+
+ if (i == nbuf - 1)
+ len |= MT_TXD_LEN_LAST;
+
+ if (i & 1) {
+ ptr->buf1 = cpu_to_le32(addr);
+ ptr->len1 = cpu_to_le16(len);
+ ptr++;
+ } else {
+ ptr->buf0 = cpu_to_le32(addr);
+ ptr->len0 = cpu_to_le16(len);
+ }
+ }
+}
+
+int mt7921e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+ enum mt76_txq_id qid, struct mt76_wcid *wcid,
+ struct ieee80211_sta *sta,
+ struct mt76_tx_info *tx_info)
+{
+ struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
+ struct ieee80211_key_conf *key = info->control.hw_key;
+ struct mt76_txwi_cache *t;
+ struct mt7921_txp_common *txp;
+ int id, pid;
+ u8 *txwi = (u8 *)txwi_ptr;
+
+ if (unlikely(tx_info->skb->len <= ETH_HLEN))
+ return -EINVAL;
+
+ if (!wcid)
+ wcid = &dev->mt76.global_wcid;
+
+ t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size);
+ t->skb = tx_info->skb;
+
+ id = mt76_token_consume(mdev, &t);
+ if (id < 0)
+ return id;
+
+ if (sta) {
+ struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv;
+
+ if (time_after(jiffies, msta->last_txs + HZ / 4)) {
+ info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
+ msta->last_txs = jiffies;
+ }
+ }
+
+ pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
+ mt7921_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key,
+ pid, false);
+
+ txp = (struct mt7921_txp_common *)(txwi + MT_TXD_SIZE);
+ memset(txp, 0, sizeof(struct mt7921_txp_common));
+ mt7921_write_hw_txp(dev, tx_info, txp, id);
+
+ tx_info->skb = DMA_DUMMY_DATA;
+
+ return 0;
+}
+
+static void
+mt7921_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *t)
+{
+ struct mt7921_txp_common *txp;
+ int i;
+
+ txp = mt7921_txwi_to_txp(dev, t);
+
+ for (i = 0; i < ARRAY_SIZE(txp->hw.ptr); i++) {
+ struct mt7921_txp_ptr *ptr = &txp->hw.ptr[i];
+ bool last;
+ u16 len;
+
+ len = le16_to_cpu(ptr->len0);
+ last = len & MT_TXD_LEN_LAST;
+ len &= MT_TXD_LEN_MASK;
+ dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf0), len,
+ DMA_TO_DEVICE);
+ if (last)
+ break;
+
+ len = le16_to_cpu(ptr->len1);
+ last = len & MT_TXD_LEN_LAST;
+ len &= MT_TXD_LEN_MASK;
+ dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf1), len,
+ DMA_TO_DEVICE);
+ if (last)
+ break;
+ }
+}
+
+static void
+mt7921_txwi_free(struct mt7921_dev *dev, struct mt76_txwi_cache *t,
+ struct ieee80211_sta *sta, bool clear_status,
+ struct list_head *free_list)
+{
+ struct mt76_dev *mdev = &dev->mt76;
+ __le32 *txwi;
+ u16 wcid_idx;
+
+ mt7921_txp_skb_unmap(mdev, t);
+ if (!t->skb)
+ goto out;
+
+ txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t);
+ if (sta) {
+ struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
+
+ if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
+ mt7921_tx_check_aggr(sta, txwi);
+
+ wcid_idx = wcid->idx;
+ } else {
+ wcid_idx = FIELD_GET(MT_TXD1_WLAN_IDX, le32_to_cpu(txwi[1]));
+ }
+
+ __mt76_tx_complete_skb(mdev, wcid_idx, t->skb, free_list);
+
+out:
+ t->skb = NULL;
+ mt76_put_txwi(mdev, t);
+}
+
+static void
+mt7921_mac_tx_free(struct mt7921_dev *dev, struct sk_buff *skb)
+{
+ struct mt7921_tx_free *free = (struct mt7921_tx_free *)skb->data;
+ struct mt76_dev *mdev = &dev->mt76;
+ struct mt76_txwi_cache *txwi;
+ struct ieee80211_sta *sta = NULL;
+ LIST_HEAD(free_list);
+ struct sk_buff *tmp;
+ bool wake = false;
+ u8 i, count;
+
+ /* clean DMA queues and unmap buffers first */
+ mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_PSD], false);
+ mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BE], false);
+
+ /* TODO: MT_TX_FREE_LATENCY is msdu time from the TXD is queued into PLE,
+ * to the time ack is received or dropped by hw (air + hw queue time).
+ * Should avoid accessing WTBL to get Tx airtime, and use it instead.
+ */
+ count = FIELD_GET(MT_TX_FREE_MSDU_CNT, le16_to_cpu(free->ctrl));
+ for (i = 0; i < count; i++) {
+ u32 msdu, info = le32_to_cpu(free->info[i]);
+ u8 stat;
+
+ /* 1'b1: new wcid pair.
+ * 1'b0: msdu_id with the same 'wcid pair' as above.
+ */
+ if (info & MT_TX_FREE_PAIR) {
+ struct mt7921_sta *msta;
+ struct mt76_wcid *wcid;
+ u16 idx;
+
+ count++;
+ idx = FIELD_GET(MT_TX_FREE_WLAN_ID, info);
+ wcid = rcu_dereference(dev->mt76.wcid[idx]);
+ sta = wcid_to_sta(wcid);
+ if (!sta)
+ continue;
+
+ msta = container_of(wcid, struct mt7921_sta, wcid);
+ spin_lock_bh(&dev->sta_poll_lock);
+ if (list_empty(&msta->poll_list))
+ list_add_tail(&msta->poll_list, &dev->sta_poll_list);
+ spin_unlock_bh(&dev->sta_poll_lock);
+ continue;
+ }
+
+ msdu = FIELD_GET(MT_TX_FREE_MSDU_ID, info);
+ stat = FIELD_GET(MT_TX_FREE_STATUS, info);
+
+ txwi = mt76_token_release(mdev, msdu, &wake);
+ if (!txwi)
+ continue;
+
+ mt7921_txwi_free(dev, txwi, sta, stat, &free_list);
+ }
+
+ if (wake)
+ mt76_set_tx_blocked(&dev->mt76, false);
+
+ napi_consume_skb(skb, 1);
+
+ list_for_each_entry_safe(skb, tmp, &free_list, list) {
+ skb_list_del_init(skb);
+ napi_consume_skb(skb, 1);
+ }
+
+ rcu_read_lock();
+ mt7921_mac_sta_poll(dev);
+ rcu_read_unlock();
+
+ mt76_worker_schedule(&dev->mt76.tx_worker);
+}
+
+void mt7921e_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
+ struct sk_buff *skb)
+{
+ struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
+ __le32 *rxd = (__le32 *)skb->data;
+ enum rx_pkt_type type;
+
+ type = FIELD_GET(MT_RXD0_PKT_TYPE, le32_to_cpu(rxd[0]));
+
+ switch (type) {
+ case PKT_TYPE_TXRX_NOTIFY:
+ mt7921_mac_tx_free(dev, skb);
+ break;
+ default:
+ mt7921_queue_rx_skb(mdev, q, skb);
+ break;
+ }
+}
+
+void mt7921e_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
+{
+ if (!e->txwi) {
+ dev_kfree_skb_any(e->skb);
+ return;
+ }
+
+ /* error path */
+ if (e->skb == DMA_DUMMY_DATA) {
+ struct mt76_txwi_cache *t;
+ struct mt7921_txp_common *txp;
+ u16 token;
+
+ txp = mt7921_txwi_to_txp(mdev, e->txwi);
+ token = le16_to_cpu(txp->hw.msdu_id[0]) & ~MT_MSDU_ID_VALID;
+ t = mt76_token_put(mdev, token);
+ e->skb = t ? t->skb : NULL;
+ }
+
+ if (e->skb)
+ mt76_tx_complete_skb(mdev, e->wcid, e->skb);
+}
+
+void mt7921_tx_token_put(struct mt7921_dev *dev)
+{
+ struct mt76_txwi_cache *txwi;
+ int id;
+
+ spin_lock_bh(&dev->mt76.token_lock);
+ idr_for_each_entry(&dev->mt76.token, txwi, id) {
+ mt7921_txwi_free(dev, txwi, NULL, false, NULL);
+ dev->mt76.token_count--;
+ }
+ spin_unlock_bh(&dev->mt76.token_lock);
+ idr_destroy(&dev->mt76.token);
+}
+
+int mt7921e_mac_reset(struct mt7921_dev *dev)
+{
+ int i, err;
+
+ mt76_connac_free_pending_tx_skbs(&dev->pm, NULL);
+
+ mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0);
+ mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0);
+
+ set_bit(MT76_RESET, &dev->mphy.state);
+ set_bit(MT76_MCU_RESET, &dev->mphy.state);
+ wake_up(&dev->mt76.mcu.wait);
+ skb_queue_purge(&dev->mt76.mcu.res_q);
+
+ mt76_txq_schedule_all(&dev->mphy);
+
+ mt76_worker_disable(&dev->mt76.tx_worker);
+ napi_disable(&dev->mt76.napi[MT_RXQ_MAIN]);
+ napi_disable(&dev->mt76.napi[MT_RXQ_MCU]);
+ napi_disable(&dev->mt76.napi[MT_RXQ_MCU_WA]);
+ napi_disable(&dev->mt76.tx_napi);
+
+ mt7921_tx_token_put(dev);
+ idr_init(&dev->mt76.token);
+
+ mt7921_wpdma_reset(dev, true);
+
+ local_bh_disable();
+ mt76_for_each_q_rx(&dev->mt76, i) {
+ napi_enable(&dev->mt76.napi[i]);
+ napi_schedule(&dev->mt76.napi[i]);
+ }
+ local_bh_enable();
+
+ clear_bit(MT76_MCU_RESET, &dev->mphy.state);
+
+ mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA,
+ MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
+ MT_INT_MCU_CMD);
+ mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
+
+ err = mt7921_run_firmware(dev);
+ if (err)
+ goto out;
+
+ err = mt7921_mcu_set_eeprom(dev);
+ if (err)
+ goto out;
+
+ err = mt7921_mac_init(dev);
+ if (err)
+ goto out;
+
+ err = __mt7921_start(&dev->phy);
+out:
+ clear_bit(MT76_RESET, &dev->mphy.state);
+
+ local_bh_disable();
+ napi_enable(&dev->mt76.tx_napi);
+ napi_schedule(&dev->mt76.tx_napi);
+ local_bh_enable();
+
+ mt76_worker_enable(&dev->mt76.tx_worker);
+
+ return err;
+}
--
2.25.1

2021-10-18 23:20:53

by Sean Wang

[permalink] [raw]
Subject: [PATCH v5 10/17] mt76: sdio: move common code in mt76_sdio module

From: Lorenzo Bianconi <[email protected]>

Move sdio common code in mt76_sdio module.
This is a preliminary patch to support mt7921s devices.

Co-developed-by: Sean Wang <[email protected]>
Signed-off-by: Sean Wang <[email protected]>
Signed-off-by: Lorenzo Bianconi <[email protected]>
---
drivers/net/wireless/mediatek/mt76/Makefile | 2 +-
drivers/net/wireless/mediatek/mt76/mt76.h | 16 +
.../wireless/mediatek/mt76/mt7615/Makefile | 2 +-
.../wireless/mediatek/mt76/mt7615/mt7615.h | 4 -
.../net/wireless/mediatek/mt76/mt7615/sdio.c | 279 ++----------------
.../wireless/mediatek/mt76/mt7615/sdio_mcu.c | 6 +-
drivers/net/wireless/mediatek/mt76/sdio.c | 265 +++++++++++++++++
.../mediatek/mt76/{mt7615 => }/sdio.h | 0
.../mediatek/mt76/{mt7615 => }/sdio_txrx.c | 82 +++--
9 files changed, 343 insertions(+), 313 deletions(-)
rename drivers/net/wireless/mediatek/mt76/{mt7615 => }/sdio.h (100%)
rename drivers/net/wireless/mediatek/mt76/{mt7615 => }/sdio_txrx.c (74%)

diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile
index 94efe3c29053..79ab850a45a2 100644
--- a/drivers/net/wireless/mediatek/mt76/Makefile
+++ b/drivers/net/wireless/mediatek/mt76/Makefile
@@ -14,7 +14,7 @@ mt76-$(CONFIG_PCI) += pci.o
mt76-$(CONFIG_NL80211_TESTMODE) += testmode.o

mt76-usb-y := usb.o usb_trace.o
-mt76-sdio-y := sdio.o
+mt76-sdio-y := sdio.o sdio_txrx.o

CFLAGS_trace.o := -I$(src)
CFLAGS_usb_trace.o := -I$(src)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index a28e5c0a158f..8dc4bbaca15d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -1248,6 +1248,22 @@ int mt76s_init(struct mt76_dev *dev, struct sdio_func *func,
int mt76s_alloc_rx_queue(struct mt76_dev *dev, enum mt76_rxq_id qid);
int mt76s_alloc_tx(struct mt76_dev *dev);
void mt76s_deinit(struct mt76_dev *dev);
+void mt76s_sdio_irq(struct sdio_func *func);
+void mt76s_txrx_worker(struct mt76_sdio *sdio);
+int mt76s_hw_init(struct mt76_dev *dev, struct sdio_func *func);
+u32 mt76s_rr(struct mt76_dev *dev, u32 offset);
+void mt76s_wr(struct mt76_dev *dev, u32 offset, u32 val);
+u32 mt76s_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val);
+u32 mt76s_read_pcr(struct mt76_dev *dev);
+void mt76s_write_copy(struct mt76_dev *dev, u32 offset,
+ const void *data, int len);
+void mt76s_read_copy(struct mt76_dev *dev, u32 offset,
+ void *data, int len);
+int mt76s_wr_rp(struct mt76_dev *dev, u32 base,
+ const struct mt76_reg_pair *data,
+ int len);
+int mt76s_rd_rp(struct mt76_dev *dev, u32 base,
+ struct mt76_reg_pair *data, int len);

struct sk_buff *
mt76_mcu_msg_alloc(struct mt76_dev *dev, const void *data,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/Makefile b/drivers/net/wireless/mediatek/mt76/mt7615/Makefile
index 83f9861ff522..2b97b9dde477 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/Makefile
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/Makefile
@@ -17,4 +17,4 @@ mt7615e-$(CONFIG_MT7622_WMAC) += soc.o

mt7663-usb-sdio-common-y := usb_sdio.o
mt7663u-y := usb.o usb_mcu.o
-mt7663s-y := sdio.o sdio_mcu.o sdio_txrx.o
+mt7663s-y := sdio.o sdio_mcu.o
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
index 437f14f06e63..77bd59813d47 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
@@ -569,10 +569,6 @@ int mt7663_usb_sdio_register_device(struct mt7615_dev *dev);
int mt7663u_mcu_init(struct mt7615_dev *dev);

/* sdio */
-u32 mt7663s_read_pcr(struct mt7615_dev *dev);
int mt7663s_mcu_init(struct mt7615_dev *dev);
-void mt7663s_txrx_worker(struct mt76_worker *w);
-void mt7663s_rx_work(struct work_struct *work);
-void mt7663s_sdio_irq(struct sdio_func *func);

#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c
index ff1e62035f37..14108e3fadda 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c
@@ -14,8 +14,8 @@
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio_func.h>

+#include "../sdio.h"
#include "mt7615.h"
-#include "sdio.h"
#include "mac.h"
#include "mcu.h"

@@ -24,200 +24,19 @@ static const struct sdio_device_id mt7663s_table[] = {
{ } /* Terminating entry */
};

-static u32 mt7663s_read_whisr(struct mt76_dev *dev)
+static void mt7663s_txrx_worker(struct mt76_worker *w)
{
- return sdio_readl(dev->sdio.func, MCR_WHISR, NULL);
-}
-
-u32 mt7663s_read_pcr(struct mt7615_dev *dev)
-{
- struct mt76_sdio *sdio = &dev->mt76.sdio;
-
- return sdio_readl(sdio->func, MCR_WHLPCR, NULL);
-}
-
-static u32 mt7663s_read_mailbox(struct mt76_dev *dev, u32 offset)
-{
- struct sdio_func *func = dev->sdio.func;
- u32 val = ~0, status;
- int err;
-
- sdio_claim_host(func);
-
- sdio_writel(func, offset, MCR_H2DSM0R, &err);
- if (err < 0) {
- dev_err(dev->dev, "failed setting address [err=%d]\n", err);
- goto out;
- }
-
- sdio_writel(func, H2D_SW_INT_READ, MCR_WSICR, &err);
- if (err < 0) {
- dev_err(dev->dev, "failed setting read mode [err=%d]\n", err);
- goto out;
- }
-
- err = readx_poll_timeout(mt7663s_read_whisr, dev, status,
- status & H2D_SW_INT_READ, 0, 1000000);
- if (err < 0) {
- dev_err(dev->dev, "query whisr timeout\n");
- goto out;
- }
-
- sdio_writel(func, H2D_SW_INT_READ, MCR_WHISR, &err);
- if (err < 0) {
- dev_err(dev->dev, "failed setting read mode [err=%d]\n", err);
- goto out;
- }
-
- val = sdio_readl(func, MCR_H2DSM0R, &err);
- if (err < 0) {
- dev_err(dev->dev, "failed reading h2dsm0r [err=%d]\n", err);
- goto out;
- }
-
- if (val != offset) {
- dev_err(dev->dev, "register mismatch\n");
- val = ~0;
- goto out;
- }
-
- val = sdio_readl(func, MCR_D2HRM1R, &err);
- if (err < 0)
- dev_err(dev->dev, "failed reading d2hrm1r [err=%d]\n", err);
-
-out:
- sdio_release_host(func);
-
- return val;
-}
-
-static void mt7663s_write_mailbox(struct mt76_dev *dev, u32 offset, u32 val)
-{
- struct sdio_func *func = dev->sdio.func;
- u32 status;
- int err;
-
- sdio_claim_host(func);
-
- sdio_writel(func, offset, MCR_H2DSM0R, &err);
- if (err < 0) {
- dev_err(dev->dev, "failed setting address [err=%d]\n", err);
- goto out;
- }
-
- sdio_writel(func, val, MCR_H2DSM1R, &err);
- if (err < 0) {
- dev_err(dev->dev,
- "failed setting write value [err=%d]\n", err);
- goto out;
- }
-
- sdio_writel(func, H2D_SW_INT_WRITE, MCR_WSICR, &err);
- if (err < 0) {
- dev_err(dev->dev, "failed setting write mode [err=%d]\n", err);
- goto out;
- }
-
- err = readx_poll_timeout(mt7663s_read_whisr, dev, status,
- status & H2D_SW_INT_WRITE, 0, 1000000);
- if (err < 0) {
- dev_err(dev->dev, "query whisr timeout\n");
- goto out;
- }
-
- sdio_writel(func, H2D_SW_INT_WRITE, MCR_WHISR, &err);
- if (err < 0) {
- dev_err(dev->dev, "failed setting write mode [err=%d]\n", err);
- goto out;
- }
-
- val = sdio_readl(func, MCR_H2DSM0R, &err);
- if (err < 0) {
- dev_err(dev->dev, "failed reading h2dsm0r [err=%d]\n", err);
- goto out;
- }
-
- if (val != offset)
- dev_err(dev->dev, "register mismatch\n");
-
-out:
- sdio_release_host(func);
-}
-
-static u32 mt7663s_rr(struct mt76_dev *dev, u32 offset)
-{
- if (test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state))
- return dev->mcu_ops->mcu_rr(dev, offset);
- else
- return mt7663s_read_mailbox(dev, offset);
-}
-
-static void mt7663s_wr(struct mt76_dev *dev, u32 offset, u32 val)
-{
- if (test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state))
- dev->mcu_ops->mcu_wr(dev, offset, val);
- else
- mt7663s_write_mailbox(dev, offset, val);
-}
-
-static u32 mt7663s_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val)
-{
- val |= mt7663s_rr(dev, offset) & ~mask;
- mt7663s_wr(dev, offset, val);
-
- return val;
-}
-
-static void mt7663s_write_copy(struct mt76_dev *dev, u32 offset,
- const void *data, int len)
-{
- const u32 *val = data;
- int i;
-
- for (i = 0; i < len / sizeof(u32); i++) {
- mt7663s_wr(dev, offset, val[i]);
- offset += sizeof(u32);
- }
-}
-
-static void mt7663s_read_copy(struct mt76_dev *dev, u32 offset,
- void *data, int len)
-{
- u32 *val = data;
- int i;
-
- for (i = 0; i < len / sizeof(u32); i++) {
- val[i] = mt7663s_rr(dev, offset);
- offset += sizeof(u32);
- }
-}
+ struct mt76_sdio *sdio = container_of(w, struct mt76_sdio,
+ txrx_worker);
+ struct mt76_dev *mdev = container_of(sdio, struct mt76_dev, sdio);
+ struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);

-static int mt7663s_wr_rp(struct mt76_dev *dev, u32 base,
- const struct mt76_reg_pair *data,
- int len)
-{
- int i;
-
- for (i = 0; i < len; i++) {
- mt7663s_wr(dev, data->reg, data->value);
- data++;
- }
-
- return 0;
-}
-
-static int mt7663s_rd_rp(struct mt76_dev *dev, u32 base,
- struct mt76_reg_pair *data,
- int len)
-{
- int i;
-
- for (i = 0; i < len; i++) {
- data->value = mt7663s_rr(dev, data->reg);
- data++;
+ if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
+ queue_work(mdev->wq, &dev->pm.wake_work);
+ return;
}
-
- return 0;
+ mt76s_txrx_worker(sdio);
+ mt76_connac_pm_unref(&dev->mphy, &dev->pm);
}

static void mt7663s_init_work(struct work_struct *work)
@@ -231,66 +50,6 @@ static void mt7663s_init_work(struct work_struct *work)
mt7615_init_work(dev);
}

-static int mt7663s_hw_init(struct mt7615_dev *dev, struct sdio_func *func)
-{
- u32 status, ctrl;
- int ret;
-
- sdio_claim_host(func);
-
- ret = sdio_enable_func(func);
- if (ret < 0)
- goto release;
-
- /* Get ownership from the device */
- sdio_writel(func, WHLPCR_INT_EN_CLR | WHLPCR_FW_OWN_REQ_CLR,
- MCR_WHLPCR, &ret);
- if (ret < 0)
- goto disable_func;
-
- ret = readx_poll_timeout(mt7663s_read_pcr, dev, status,
- status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000);
- if (ret < 0) {
- dev_err(dev->mt76.dev, "Cannot get ownership from device");
- goto disable_func;
- }
-
- ret = sdio_set_block_size(func, 512);
- if (ret < 0)
- goto disable_func;
-
- /* Enable interrupt */
- sdio_writel(func, WHLPCR_INT_EN_SET, MCR_WHLPCR, &ret);
- if (ret < 0)
- goto disable_func;
-
- ctrl = WHIER_RX0_DONE_INT_EN | WHIER_TX_DONE_INT_EN;
- sdio_writel(func, ctrl, MCR_WHIER, &ret);
- if (ret < 0)
- goto disable_func;
-
- /* set WHISR as read clear and Rx aggregation number as 16 */
- ctrl = FIELD_PREP(MAX_HIF_RX_LEN_NUM, 16);
- sdio_writel(func, ctrl, MCR_WHCR, &ret);
- if (ret < 0)
- goto disable_func;
-
- ret = sdio_claim_irq(func, mt7663s_sdio_irq);
- if (ret < 0)
- goto disable_func;
-
- sdio_release_host(func);
-
- return 0;
-
-disable_func:
- sdio_disable_func(func);
-release:
- sdio_release_host(func);
-
- return ret;
-}
-
static int mt7663s_probe(struct sdio_func *func,
const struct sdio_device_id *id)
{
@@ -307,13 +66,13 @@ static int mt7663s_probe(struct sdio_func *func,
.update_survey = mt7615_update_channel,
};
static const struct mt76_bus_ops mt7663s_ops = {
- .rr = mt7663s_rr,
- .rmw = mt7663s_rmw,
- .wr = mt7663s_wr,
- .write_copy = mt7663s_write_copy,
- .read_copy = mt7663s_read_copy,
- .wr_rp = mt7663s_wr_rp,
- .rd_rp = mt7663s_rd_rp,
+ .rr = mt76s_rr,
+ .rmw = mt76s_rmw,
+ .wr = mt76s_wr,
+ .write_copy = mt76s_write_copy,
+ .read_copy = mt76s_read_copy,
+ .wr_rp = mt76s_wr_rp,
+ .rd_rp = mt76s_rd_rp,
.type = MT76_BUS_SDIO,
};
struct ieee80211_ops *ops;
@@ -341,7 +100,7 @@ static int mt7663s_probe(struct sdio_func *func,
if (ret < 0)
goto error;

- ret = mt7663s_hw_init(dev, func);
+ ret = mt76s_hw_init(mdev, func);
if (ret)
goto error;

diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c
index 517419bb7772..f76986c807ab 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c
@@ -10,11 +10,11 @@
#include <linux/module.h>
#include <linux/iopoll.h>

+#include "../sdio.h"
#include "mt7615.h"
#include "mac.h"
#include "mcu.h"
#include "regs.h"
-#include "sdio.h"

static int mt7663s_mcu_init_sched(struct mt7615_dev *dev)
{
@@ -63,7 +63,7 @@ static int __mt7663s_mcu_drv_pmctrl(struct mt7615_dev *dev)

sdio_writel(func, WHLPCR_FW_OWN_REQ_CLR, MCR_WHLPCR, NULL);

- ret = readx_poll_timeout(mt7663s_read_pcr, dev, status,
+ ret = readx_poll_timeout(mt76s_read_pcr, &dev->mt76, status,
status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000);
if (ret < 0) {
dev_err(dev->mt76.dev, "Cannot get ownership from device");
@@ -111,7 +111,7 @@ static int mt7663s_mcu_fw_pmctrl(struct mt7615_dev *dev)

sdio_writel(func, WHLPCR_FW_OWN_REQ_SET, MCR_WHLPCR, NULL);

- ret = readx_poll_timeout(mt7663s_read_pcr, dev, status,
+ ret = readx_poll_timeout(mt76s_read_pcr, &dev->mt76, status,
!(status & WHLPCR_IS_DRIVER_OWN), 2000, 1000000);
if (ret < 0) {
dev_err(dev->mt76.dev, "Cannot set ownership to device");
diff --git a/drivers/net/wireless/mediatek/mt76/sdio.c b/drivers/net/wireless/mediatek/mt76/sdio.c
index f7a1838b4576..7e613462b60e 100644
--- a/drivers/net/wireless/mediatek/mt76/sdio.c
+++ b/drivers/net/wireless/mediatek/mt76/sdio.c
@@ -16,6 +16,271 @@
#include <linux/kthread.h>

#include "mt76.h"
+#include "sdio.h"
+
+static u32 mt76s_read_whisr(struct mt76_dev *dev)
+{
+ return sdio_readl(dev->sdio.func, MCR_WHISR, NULL);
+}
+
+u32 mt76s_read_pcr(struct mt76_dev *dev)
+{
+ struct mt76_sdio *sdio = &dev->sdio;
+
+ return sdio_readl(sdio->func, MCR_WHLPCR, NULL);
+}
+EXPORT_SYMBOL_GPL(mt76s_read_pcr);
+
+static u32 mt76s_read_mailbox(struct mt76_dev *dev, u32 offset)
+{
+ struct sdio_func *func = dev->sdio.func;
+ u32 val = ~0, status;
+ int err;
+
+ sdio_claim_host(func);
+
+ sdio_writel(func, offset, MCR_H2DSM0R, &err);
+ if (err < 0) {
+ dev_err(dev->dev, "failed setting address [err=%d]\n", err);
+ goto out;
+ }
+
+ sdio_writel(func, H2D_SW_INT_READ, MCR_WSICR, &err);
+ if (err < 0) {
+ dev_err(dev->dev, "failed setting read mode [err=%d]\n", err);
+ goto out;
+ }
+
+ err = readx_poll_timeout(mt76s_read_whisr, dev, status,
+ status & H2D_SW_INT_READ, 0, 1000000);
+ if (err < 0) {
+ dev_err(dev->dev, "query whisr timeout\n");
+ goto out;
+ }
+
+ sdio_writel(func, H2D_SW_INT_READ, MCR_WHISR, &err);
+ if (err < 0) {
+ dev_err(dev->dev, "failed setting read mode [err=%d]\n", err);
+ goto out;
+ }
+
+ val = sdio_readl(func, MCR_H2DSM0R, &err);
+ if (err < 0) {
+ dev_err(dev->dev, "failed reading h2dsm0r [err=%d]\n", err);
+ goto out;
+ }
+
+ if (val != offset) {
+ dev_err(dev->dev, "register mismatch\n");
+ val = ~0;
+ goto out;
+ }
+
+ val = sdio_readl(func, MCR_D2HRM1R, &err);
+ if (err < 0)
+ dev_err(dev->dev, "failed reading d2hrm1r [err=%d]\n", err);
+
+out:
+ sdio_release_host(func);
+
+ return val;
+}
+
+static void mt76s_write_mailbox(struct mt76_dev *dev, u32 offset, u32 val)
+{
+ struct sdio_func *func = dev->sdio.func;
+ u32 status;
+ int err;
+
+ sdio_claim_host(func);
+
+ sdio_writel(func, offset, MCR_H2DSM0R, &err);
+ if (err < 0) {
+ dev_err(dev->dev, "failed setting address [err=%d]\n", err);
+ goto out;
+ }
+
+ sdio_writel(func, val, MCR_H2DSM1R, &err);
+ if (err < 0) {
+ dev_err(dev->dev,
+ "failed setting write value [err=%d]\n", err);
+ goto out;
+ }
+
+ sdio_writel(func, H2D_SW_INT_WRITE, MCR_WSICR, &err);
+ if (err < 0) {
+ dev_err(dev->dev, "failed setting write mode [err=%d]\n", err);
+ goto out;
+ }
+
+ err = readx_poll_timeout(mt76s_read_whisr, dev, status,
+ status & H2D_SW_INT_WRITE, 0, 1000000);
+ if (err < 0) {
+ dev_err(dev->dev, "query whisr timeout\n");
+ goto out;
+ }
+
+ sdio_writel(func, H2D_SW_INT_WRITE, MCR_WHISR, &err);
+ if (err < 0) {
+ dev_err(dev->dev, "failed setting write mode [err=%d]\n", err);
+ goto out;
+ }
+
+ val = sdio_readl(func, MCR_H2DSM0R, &err);
+ if (err < 0) {
+ dev_err(dev->dev, "failed reading h2dsm0r [err=%d]\n", err);
+ goto out;
+ }
+
+ if (val != offset)
+ dev_err(dev->dev, "register mismatch\n");
+
+out:
+ sdio_release_host(func);
+}
+
+u32 mt76s_rr(struct mt76_dev *dev, u32 offset)
+{
+ if (test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state))
+ return dev->mcu_ops->mcu_rr(dev, offset);
+ else
+ return mt76s_read_mailbox(dev, offset);
+}
+EXPORT_SYMBOL_GPL(mt76s_rr);
+
+void mt76s_wr(struct mt76_dev *dev, u32 offset, u32 val)
+{
+ if (test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state))
+ dev->mcu_ops->mcu_wr(dev, offset, val);
+ else
+ mt76s_write_mailbox(dev, offset, val);
+}
+EXPORT_SYMBOL_GPL(mt76s_wr);
+
+u32 mt76s_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val)
+{
+ val |= mt76s_rr(dev, offset) & ~mask;
+ mt76s_wr(dev, offset, val);
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(mt76s_rmw);
+
+void mt76s_write_copy(struct mt76_dev *dev, u32 offset,
+ const void *data, int len)
+{
+ const u32 *val = data;
+ int i;
+
+ for (i = 0; i < len / sizeof(u32); i++) {
+ mt76s_wr(dev, offset, val[i]);
+ offset += sizeof(u32);
+ }
+}
+EXPORT_SYMBOL_GPL(mt76s_write_copy);
+
+void mt76s_read_copy(struct mt76_dev *dev, u32 offset,
+ void *data, int len)
+{
+ u32 *val = data;
+ int i;
+
+ for (i = 0; i < len / sizeof(u32); i++) {
+ val[i] = mt76s_rr(dev, offset);
+ offset += sizeof(u32);
+ }
+}
+EXPORT_SYMBOL_GPL(mt76s_read_copy);
+
+int mt76s_wr_rp(struct mt76_dev *dev, u32 base,
+ const struct mt76_reg_pair *data,
+ int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ mt76s_wr(dev, data->reg, data->value);
+ data++;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt76s_wr_rp);
+
+int mt76s_rd_rp(struct mt76_dev *dev, u32 base,
+ struct mt76_reg_pair *data, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ data->value = mt76s_rr(dev, data->reg);
+ data++;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt76s_rd_rp);
+
+int mt76s_hw_init(struct mt76_dev *dev, struct sdio_func *func)
+{
+ u32 status, ctrl;
+ int ret;
+
+ sdio_claim_host(func);
+
+ ret = sdio_enable_func(func);
+ if (ret < 0)
+ goto release;
+
+ /* Get ownership from the device */
+ sdio_writel(func, WHLPCR_INT_EN_CLR | WHLPCR_FW_OWN_REQ_CLR,
+ MCR_WHLPCR, &ret);
+ if (ret < 0)
+ goto disable_func;
+
+ ret = readx_poll_timeout(mt76s_read_pcr, dev, status,
+ status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000);
+ if (ret < 0) {
+ dev_err(dev->dev, "Cannot get ownership from device");
+ goto disable_func;
+ }
+
+ ret = sdio_set_block_size(func, 512);
+ if (ret < 0)
+ goto disable_func;
+
+ /* Enable interrupt */
+ sdio_writel(func, WHLPCR_INT_EN_SET, MCR_WHLPCR, &ret);
+ if (ret < 0)
+ goto disable_func;
+
+ ctrl = WHIER_RX0_DONE_INT_EN | WHIER_TX_DONE_INT_EN;
+ sdio_writel(func, ctrl, MCR_WHIER, &ret);
+ if (ret < 0)
+ goto disable_func;
+
+ /* set WHISR as read clear and Rx aggregation number as 16 */
+ ctrl = FIELD_PREP(MAX_HIF_RX_LEN_NUM, 16);
+ sdio_writel(func, ctrl, MCR_WHCR, &ret);
+ if (ret < 0)
+ goto disable_func;
+
+ ret = sdio_claim_irq(func, mt76s_sdio_irq);
+ if (ret < 0)
+ goto disable_func;
+
+ sdio_release_host(func);
+
+ return 0;
+
+disable_func:
+ sdio_disable_func(func);
+release:
+ sdio_release_host(func);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mt76s_hw_init);

int mt76s_alloc_rx_queue(struct mt76_dev *dev, enum mt76_rxq_id qid)
{
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.h b/drivers/net/wireless/mediatek/mt76/sdio.h
similarity index 100%
rename from drivers/net/wireless/mediatek/mt76/mt7615/sdio.h
rename to drivers/net/wireless/mediatek/mt76/sdio.h
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c b/drivers/net/wireless/mediatek/mt76/sdio_txrx.c
similarity index 74%
rename from drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c
rename to drivers/net/wireless/mediatek/mt76/sdio_txrx.c
index 04f4c89b7499..ceb3dc0613d6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c
+++ b/drivers/net/wireless/mediatek/mt76/sdio_txrx.c
@@ -14,12 +14,11 @@
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio_func.h>

-#include "../trace.h"
-#include "mt7615.h"
+#include "trace.h"
#include "sdio.h"
-#include "mac.h"
+#include "mt76.h"

-static int mt7663s_refill_sched_quota(struct mt76_dev *dev, u32 *data)
+static int mt76s_refill_sched_quota(struct mt76_dev *dev, u32 *data)
{
u32 ple_ac_data_quota[] = {
FIELD_GET(TXQ_CNT_L, data[4]), /* VO */
@@ -53,8 +52,8 @@ static int mt7663s_refill_sched_quota(struct mt76_dev *dev, u32 *data)
return pse_data_quota + ple_data_quota + pse_mcu_quota;
}

-static struct sk_buff *mt7663s_build_rx_skb(void *data, int data_len,
- int buf_len)
+static struct sk_buff *
+mt76s_build_rx_skb(void *data, int data_len, int buf_len)
{
int len = min_t(int, data_len, MT_SKB_HEAD_LEN);
struct sk_buff *skb;
@@ -78,8 +77,9 @@ static struct sk_buff *mt7663s_build_rx_skb(void *data, int data_len,
return skb;
}

-static int mt7663s_rx_run_queue(struct mt76_dev *dev, enum mt76_rxq_id qid,
- struct mt76s_intr *intr)
+static int
+mt76s_rx_run_queue(struct mt76_dev *dev, enum mt76_rxq_id qid,
+ struct mt76s_intr *intr)
{
struct mt76_queue *q = &dev->q_rx[qid];
struct mt76_sdio *sdio = &dev->sdio;
@@ -114,7 +114,7 @@ static int mt7663s_rx_run_queue(struct mt76_dev *dev, enum mt76_rxq_id qid,
struct mt76_queue_entry *e = &q->entry[index];

len = intr->rx.len[qid][i];
- e->skb = mt7663s_build_rx_skb(buf, len, round_up(len + 4, 4));
+ e->skb = mt76s_build_rx_skb(buf, len, round_up(len + 4, 4));
if (!e->skb)
break;

@@ -132,7 +132,7 @@ static int mt7663s_rx_run_queue(struct mt76_dev *dev, enum mt76_rxq_id qid,
return i;
}

-static int mt7663s_rx_handler(struct mt76_dev *dev)
+static int mt76s_rx_handler(struct mt76_dev *dev)
{
struct mt76_sdio *sdio = &dev->sdio;
struct mt76s_intr *intr = sdio->intr_data;
@@ -145,7 +145,7 @@ static int mt7663s_rx_handler(struct mt76_dev *dev)
trace_dev_irq(dev, intr->isr, 0);

if (intr->isr & WHIER_RX0_DONE_INT_EN) {
- ret = mt7663s_rx_run_queue(dev, 0, intr);
+ ret = mt76s_rx_run_queue(dev, 0, intr);
if (ret > 0) {
mt76_worker_schedule(&sdio->net_worker);
nframes += ret;
@@ -153,20 +153,21 @@ static int mt7663s_rx_handler(struct mt76_dev *dev)
}

if (intr->isr & WHIER_RX1_DONE_INT_EN) {
- ret = mt7663s_rx_run_queue(dev, 1, intr);
+ ret = mt76s_rx_run_queue(dev, 1, intr);
if (ret > 0) {
mt76_worker_schedule(&sdio->net_worker);
nframes += ret;
}
}

- nframes += !!mt7663s_refill_sched_quota(dev, intr->tx.wtqcr);
+ nframes += !!mt76s_refill_sched_quota(dev, intr->tx.wtqcr);

return nframes;
}

-static int mt7663s_tx_pick_quota(struct mt76_sdio *sdio, bool mcu, int buf_sz,
- int *pse_size, int *ple_size)
+static int
+mt76s_tx_pick_quota(struct mt76_sdio *sdio, bool mcu, int buf_sz,
+ int *pse_size, int *ple_size)
{
int pse_sz;

@@ -187,8 +188,9 @@ static int mt7663s_tx_pick_quota(struct mt76_sdio *sdio, bool mcu, int buf_sz,
return 0;
}

-static void mt7663s_tx_update_quota(struct mt76_sdio *sdio, bool mcu,
- int pse_size, int ple_size)
+static void
+mt76s_tx_update_quota(struct mt76_sdio *sdio, bool mcu, int pse_size,
+ int ple_size)
{
if (mcu) {
sdio->sched.pse_mcu_quota -= pse_size;
@@ -198,7 +200,7 @@ static void mt7663s_tx_update_quota(struct mt76_sdio *sdio, bool mcu,
}
}

-static int __mt7663s_xmit_queue(struct mt76_dev *dev, u8 *data, int len)
+static int __mt76s_xmit_queue(struct mt76_dev *dev, u8 *data, int len)
{
struct mt76_sdio *sdio = &dev->sdio;
int err;
@@ -213,7 +215,7 @@ static int __mt7663s_xmit_queue(struct mt76_dev *dev, u8 *data, int len)
return err;
}

-static int mt7663s_tx_run_queue(struct mt76_dev *dev, struct mt76_queue *q)
+static int mt76s_tx_run_queue(struct mt76_dev *dev, struct mt76_queue *q)
{
int qid, err, nframes = 0, len = 0, pse_sz = 0, ple_sz = 0;
bool mcu = q == dev->q_mcu[MT_MCUQ_WM];
@@ -229,8 +231,8 @@ static int mt7663s_tx_run_queue(struct mt76_dev *dev, struct mt76_queue *q)

if (!test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state)) {
__skb_put_zero(e->skb, 4);
- err = __mt7663s_xmit_queue(dev, e->skb->data,
- e->skb->len);
+ err = __mt76s_xmit_queue(dev, e->skb->data,
+ e->skb->len);
if (err)
return err;

@@ -241,8 +243,8 @@ static int mt7663s_tx_run_queue(struct mt76_dev *dev, struct mt76_queue *q)
if (len + e->skb->len + pad + 4 > MT76S_XMIT_BUF_SZ)
break;

- if (mt7663s_tx_pick_quota(sdio, mcu, e->buf_sz, &pse_sz,
- &ple_sz))
+ if (mt76s_tx_pick_quota(sdio, mcu, e->buf_sz, &pse_sz,
+ &ple_sz))
break;

memcpy(sdio->xmit_buf[qid] + len, e->skb->data,
@@ -268,30 +270,22 @@ static int mt7663s_tx_run_queue(struct mt76_dev *dev, struct mt76_queue *q)

if (nframes) {
memset(sdio->xmit_buf[qid] + len, 0, 4);
- err = __mt7663s_xmit_queue(dev, sdio->xmit_buf[qid], len + 4);
+ err = __mt76s_xmit_queue(dev, sdio->xmit_buf[qid], len + 4);
if (err)
return err;
}
- mt7663s_tx_update_quota(sdio, mcu, pse_sz, ple_sz);
+ mt76s_tx_update_quota(sdio, mcu, pse_sz, ple_sz);

mt76_worker_schedule(&sdio->status_worker);

return nframes;
}

-void mt7663s_txrx_worker(struct mt76_worker *w)
+void mt76s_txrx_worker(struct mt76_sdio *sdio)
{
- struct mt76_sdio *sdio = container_of(w, struct mt76_sdio,
- txrx_worker);
- struct mt76_dev *mdev = container_of(sdio, struct mt76_dev, sdio);
- struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
+ struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio);
int i, nframes, ret;

- if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
- queue_work(mdev->wq, &dev->pm.wake_work);
- return;
- }
-
/* disable interrupt */
sdio_claim_host(sdio->func);
sdio_writel(sdio->func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, NULL);
@@ -301,16 +295,16 @@ void mt7663s_txrx_worker(struct mt76_worker *w)

/* tx */
for (i = 0; i <= MT_TXQ_PSD; i++) {
- ret = mt7663s_tx_run_queue(mdev, mdev->phy.q_tx[i]);
+ ret = mt76s_tx_run_queue(dev, dev->phy.q_tx[i]);
if (ret > 0)
nframes += ret;
}
- ret = mt7663s_tx_run_queue(mdev, mdev->q_mcu[MT_MCUQ_WM]);
+ ret = mt76s_tx_run_queue(dev, dev->q_mcu[MT_MCUQ_WM]);
if (ret > 0)
nframes += ret;

/* rx */
- ret = mt7663s_rx_handler(mdev);
+ ret = mt76s_rx_handler(dev);
if (ret > 0)
nframes += ret;
} while (nframes > 0);
@@ -318,17 +312,17 @@ void mt7663s_txrx_worker(struct mt76_worker *w)
/* enable interrupt */
sdio_writel(sdio->func, WHLPCR_INT_EN_SET, MCR_WHLPCR, NULL);
sdio_release_host(sdio->func);
-
- mt76_connac_pm_unref(&dev->mphy, &dev->pm);
}
+EXPORT_SYMBOL_GPL(mt76s_txrx_worker);

-void mt7663s_sdio_irq(struct sdio_func *func)
+void mt76s_sdio_irq(struct sdio_func *func)
{
- struct mt7615_dev *dev = sdio_get_drvdata(func);
- struct mt76_sdio *sdio = &dev->mt76.sdio;
+ struct mt76_dev *dev = sdio_get_drvdata(func);
+ struct mt76_sdio *sdio = &dev->sdio;

- if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.phy.state))
+ if (!test_bit(MT76_STATE_INITIALIZED, &dev->phy.state))
return;

mt76_worker_schedule(&sdio->txrx_worker);
}
+EXPORT_SYMBOL_GPL(mt76s_sdio_irq);
--
2.25.1

2021-10-18 23:21:03

by Sean Wang

[permalink] [raw]
Subject: [PATCH v5 16/17] mt76: mt7921: introduce mt7921s support

From: Sean Wang <[email protected]>

Introduce support for mt7921s 802.11ax (Wi-Fi 6) 2x2:2SS chipset.

Tested-by: Deren Wu <[email protected]>
Co-developed-by: Lorenzo Bianconi <[email protected]>
Signed-off-by: Lorenzo Bianconi <[email protected]>
Signed-off-by: Sean Wang <[email protected]>
---
.../net/wireless/mediatek/mt76/mt7921/Kconfig | 10 +
.../wireless/mediatek/mt76/mt7921/Makefile | 2 +
.../wireless/mediatek/mt76/mt7921/debugfs.c | 18 +-
.../net/wireless/mediatek/mt76/mt7921/init.c | 11 +-
.../net/wireless/mediatek/mt76/mt7921/mac.c | 22 +-
.../net/wireless/mediatek/mt76/mt7921/mac.h | 4 +
.../net/wireless/mediatek/mt76/mt7921/mcu.c | 14 +-
.../wireless/mediatek/mt76/mt7921/mt7921.h | 43 +++
.../net/wireless/mediatek/mt76/mt7921/sdio.c | 314 ++++++++++++++++++
.../wireless/mediatek/mt76/mt7921/sdio_mac.c | 87 +++++
.../wireless/mediatek/mt76/mt7921/sdio_mcu.c | 127 +++++++
11 files changed, 637 insertions(+), 15 deletions(-)
create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/sdio.c
create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c
create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig
index 071746809b1c..ce3a06227901 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig
@@ -13,3 +13,13 @@ config MT7921E
This adds support for MT7921E 802.11ax 2x2:2SS wireless devices.

To compile this driver as a module, choose M here.
+
+config MT7921S
+ tristate "MediaTek MT7921S (SDIO) support"
+ select MT76_SDIO
+ select MT7921_COMMON
+ depends on MAC80211
+ help
+ This adds support for MT7921S 802.11ax 2x2:2SS wireless devices.
+
+ To compile this driver as a module, choose M here.
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile
index 5f32c2c71134..1187acedfeda 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile
@@ -2,9 +2,11 @@

obj-$(CONFIG_MT7921_COMMON) += mt7921-common.o
obj-$(CONFIG_MT7921E) += mt7921e.o
+obj-$(CONFIG_MT7921S) += mt7921s.o

CFLAGS_trace.o := -I$(src)

mt7921-common-y := mac.o mcu.o main.o init.o debugfs.o trace.o
mt7921-common-$(CONFIG_NL80211_TESTMODE) += testmode.o
mt7921e-y := pci.o pci_mac.o pci_mcu.o dma.o
+mt7921s-y := sdio.o sdio_mac.o sdio_mcu.o
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
index 71aabb632e05..68f393c07a31 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
@@ -413,6 +413,20 @@ static int mt7921_chip_reset(void *data, u64 val)

DEFINE_DEBUGFS_ATTRIBUTE(fops_reset, NULL, mt7921_chip_reset, "%lld\n");

+static int
+mt7921s_sched_quota_read(struct seq_file *s, void *data)
+{
+ struct mt7921_dev *dev = dev_get_drvdata(s->private);
+ struct mt76_sdio *sdio = &dev->mt76.sdio;
+
+ seq_printf(s, "pse_data_quota\t%d\n", sdio->sched.pse_data_quota);
+ seq_printf(s, "ple_data_quota\t%d\n", sdio->sched.ple_data_quota);
+ seq_printf(s, "pse_mcu_quota\t%d\n", sdio->sched.pse_mcu_quota);
+ seq_printf(s, "sched_deficit\t%d\n", sdio->sched.deficit);
+
+ return 0;
+}
+
int mt7921_init_debugfs(struct mt7921_dev *dev)
{
struct dentry *dir;
@@ -436,6 +450,8 @@ int mt7921_init_debugfs(struct mt7921_dev *dev)
debugfs_create_devm_seqfile(dev->mt76.dev, "runtime_pm_stats", dir,
mt7921_pm_stats);
debugfs_create_file("deep-sleep", 0600, dir, dev, &fops_ds);
-
+ if (mt76_is_sdio(&dev->mt76))
+ debugfs_create_devm_seqfile(dev->mt76.dev, "sched-quota", dir,
+ mt7921s_sched_quota_read);
return 0;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
index 6a4b014e8afd..2b7260be224f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
@@ -231,8 +231,15 @@ int mt7921_register_device(struct mt7921_dev *dev)
dev->pm.idle_timeout = MT7921_PM_TIMEOUT;
dev->pm.stats.last_wake_event = jiffies;
dev->pm.stats.last_doze_event = jiffies;
- dev->pm.enable = true;
- dev->pm.ds_enable = true;
+
+ /* TODO: mt7921s run sleep mode on default */
+ if (mt76_is_mmio(&dev->mt76)) {
+ dev->pm.enable = true;
+ dev->pm.ds_enable = true;
+ }
+
+ if (mt76_is_sdio(&dev->mt76))
+ hw->extra_tx_headroom += MT_SDIO_TXD_SIZE + MT_SDIO_HDR_SIZE;

ret = mt7921_init_hardware(dev);
if (ret)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
index e49dfcf5558d..f5b179601030 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
@@ -843,6 +843,8 @@ void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi,
struct ieee80211_vif *vif = info->control.vif;
struct mt76_phy *mphy = &dev->mphy;
u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
+ bool is_mmio = mt76_is_mmio(&dev->mt76);
+ u32 sz_txd = is_mmio ? MT_TXD_SIZE : MT_SDIO_TXD_SIZE;
bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
u16 tx_count = 15;
u32 val;
@@ -858,15 +860,15 @@ void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi,
p_fmt = MT_TX_TYPE_FW;
q_idx = MT_LMAC_BCN0;
} else if (skb_get_queue_mapping(skb) >= MT_TXQ_PSD) {
- p_fmt = MT_TX_TYPE_CT;
+ p_fmt = is_mmio ? MT_TX_TYPE_CT : MT_TX_TYPE_SF;
q_idx = MT_LMAC_ALTX0;
} else {
- p_fmt = MT_TX_TYPE_CT;
+ p_fmt = is_mmio ? MT_TX_TYPE_CT : MT_TX_TYPE_SF;
q_idx = wmm_idx * MT7921_MAX_WMM_SETS +
mt7921_lmac_mapping(dev, skb_get_queue_mapping(skb));
}

- val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + MT_TXD_SIZE) |
+ val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) |
FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) |
FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
txwi[0] = cpu_to_le32(val);
@@ -1384,12 +1386,18 @@ void mt7921_pm_wake_work(struct work_struct *work)
mphy = dev->phy.mt76;

if (!mt7921_mcu_drv_pmctrl(dev)) {
+ struct mt76_dev *mdev = &dev->mt76;
int i;

- mt76_for_each_q_rx(&dev->mt76, i)
- napi_schedule(&dev->mt76.napi[i]);
- mt76_connac_pm_dequeue_skbs(mphy, &dev->pm);
- mt7921_mcu_tx_cleanup(dev);
+ if (mt76_is_sdio(mdev)) {
+ mt76_connac_pm_dequeue_skbs(mphy, &dev->pm);
+ mt76_worker_schedule(&mdev->sdio.txrx_worker);
+ } else {
+ mt76_for_each_q_rx(mdev, i)
+ napi_schedule(&mdev->napi[i]);
+ mt76_connac_pm_dequeue_skbs(mphy, &dev->pm);
+ mt7921_mcu_tx_cleanup(dev);
+ }
if (test_bit(MT76_STATE_RUNNING, &mphy->state))
ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work,
MT7921_WATCHDOG_TIME);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h
index ad2e52c97aa8..544a1c33126a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h
@@ -199,6 +199,10 @@ enum tx_mcu_port_q_idx {

#define MT_TXD_SIZE (8 * 4)

+#define MT_SDIO_TXD_SIZE (MT_TXD_SIZE + 8 * 4)
+#define MT_SDIO_TAIL_SIZE 8
+#define MT_SDIO_HDR_SIZE 4
+
#define MT_TXD0_Q_IDX GENMASK(31, 25)
#define MT_TXD0_PKT_FMT GENMASK(24, 23)
#define MT_TXD0_ETH_TYPE_OFFSET GENMASK(22, 16)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
index 44e74e43ee78..571f559d3363 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -650,7 +650,9 @@ static int mt7921_load_patch(struct mt7921_dev *dev)
{
const struct mt7921_patch_hdr *hdr;
const struct firmware *fw = NULL;
- int i, ret, sem;
+ int i, ret, sem, max_len;
+
+ max_len = mt76_is_sdio(&dev->mt76) ? 2048 : 4096;

sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, true);
switch (sem) {
@@ -706,7 +708,7 @@ static int mt7921_load_patch(struct mt7921_dev *dev)
}

ret = __mt76_mcu_send_firmware(&dev->mt76, MCU_CMD_FW_SCATTER,
- dl, len, 4096);
+ dl, len, max_len);
if (ret) {
dev_err(dev->mt76.dev, "Failed to send patch\n");
goto out;
@@ -753,9 +755,11 @@ mt7921_mcu_send_ram_firmware(struct mt7921_dev *dev,
const struct mt7921_fw_trailer *hdr,
const u8 *data, bool is_wa)
{
- int i, offset = 0;
+ int i, offset = 0, max_len;
u32 override = 0, option = 0;

+ max_len = mt76_is_sdio(&dev->mt76) ? 2048 : 4096;
+
for (i = 0; i < hdr->n_region; i++) {
const struct mt7921_fw_region *region;
int err;
@@ -778,7 +782,7 @@ mt7921_mcu_send_ram_firmware(struct mt7921_dev *dev,
}

err = __mt76_mcu_send_firmware(&dev->mt76, MCU_CMD_FW_SCATTER,
- data + offset, len, 4096);
+ data + offset, len, max_len);
if (err) {
dev_err(dev->mt76.dev, "Failed to send firmware.\n");
return err;
@@ -851,7 +855,7 @@ static int mt7921_load_firmware(struct mt7921_dev *dev)
int ret;

ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY);
- if (ret) {
+ if (ret && mt76_is_mmio(&dev->mt76)) {
dev_dbg(dev->mt76.dev, "Firmware is already download\n");
goto fw_loaded;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
index f4b85ec530bd..05e0d4371d32 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
@@ -47,6 +47,29 @@
#define MT7921_SKU_MAX_DELTA_IDX MT7921_SKU_RATE_NUM
#define MT7921_SKU_TABLE_SIZE (MT7921_SKU_RATE_NUM + 1)

+#define MT7921_SDIO_HDR_TX_BYTES GENMASK(15, 0)
+#define MT7921_SDIO_HDR_PKT_TYPE GENMASK(17, 16)
+
+enum mt7921_sdio_pkt_type {
+ MT7921_SDIO_TXD,
+ MT7921_SDIO_DATA,
+ MT7921_SDIO_CMD,
+ MT7921_SDIO_FWDL,
+};
+
+struct mt7921_sdio_intr {
+ u32 isr;
+ struct {
+ u32 wtqcr[16];
+ } tx;
+ struct {
+ u16 num[2];
+ u16 len0[16];
+ u16 len1[128];
+ } rx;
+ u32 rec_mb[2];
+} __packed;
+
#define to_rssi(field, rxv) ((FIELD_GET(field, rxv) - 220) / 2)
#define to_rcpi(rssi) (2 * (rssi) + 220)

@@ -321,6 +344,17 @@ static inline void mt7921_mcu_tx_cleanup(struct mt7921_dev *dev)
mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WA], false);
}

+static inline void mt7921_skb_add_sdio_hdr(struct sk_buff *skb,
+ enum mt7921_sdio_pkt_type type)
+{
+ u32 hdr;
+
+ hdr = FIELD_PREP(MT7921_SDIO_HDR_TX_BYTES, skb->len + sizeof(hdr)) |
+ FIELD_PREP(MT7921_SDIO_HDR_PKT_TYPE, type);
+
+ put_unaligned_le32(hdr, skb_push(skb, sizeof(hdr)));
+}
+
int mt7921_mac_init(struct mt7921_dev *dev);
bool mt7921_mac_wtbl_update(struct mt7921_dev *dev, int idx, u32 mask);
void mt7921_mac_reset_counters(struct mt7921_phy *phy);
@@ -394,4 +428,13 @@ int mt7921e_mcu_init(struct mt7921_dev *dev);
int mt7921e_mcu_drv_pmctrl(struct mt7921_dev *dev);
int mt7921e_mcu_fw_pmctrl(struct mt7921_dev *dev);

+int mt7921s_mcu_init(struct mt7921_dev *dev);
+int mt7921s_mcu_drv_pmctrl(struct mt7921_dev *dev);
+int mt7921s_mcu_fw_pmctrl(struct mt7921_dev *dev);
+int mt7921s_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+ enum mt76_txq_id qid, struct mt76_wcid *wcid,
+ struct ieee80211_sta *sta,
+ struct mt76_tx_info *tx_info);
+void mt7921s_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e);
+bool mt7921s_tx_status_data(struct mt76_dev *mdev, u8 *update);
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c
new file mode 100644
index 000000000000..e0ad97f27fea
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c
@@ -0,0 +1,314 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2021 MediaTek Inc.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio_func.h>
+
+#include "mt7921.h"
+#include "../sdio.h"
+#include "mac.h"
+#include "mcu.h"
+
+static const struct sdio_device_id mt7921s_table[] = {
+ { SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7901) },
+ { } /* Terminating entry */
+};
+
+static void mt7921s_txrx_worker(struct mt76_worker *w)
+{
+ struct mt76_sdio *sdio = container_of(w, struct mt76_sdio,
+ txrx_worker);
+ struct mt76_dev *mdev = container_of(sdio, struct mt76_dev, sdio);
+ struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
+
+ if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
+ queue_work(mdev->wq, &dev->pm.wake_work);
+ return;
+ }
+
+ mt76s_txrx_worker(sdio);
+ mt76_connac_pm_unref(&dev->mphy, &dev->pm);
+}
+
+static void mt7921s_unregister_device(struct mt7921_dev *dev)
+{
+ struct mt76_connac_pm *pm = &dev->pm;
+
+ mt76_unregister_device(&dev->mt76);
+ cancel_delayed_work_sync(&pm->ps_work);
+ cancel_work_sync(&pm->wake_work);
+
+ mt76s_deinit(&dev->mt76);
+ mt7921_mcu_exit(dev);
+
+ mt76_free_device(&dev->mt76);
+}
+
+static int mt7921s_parse_intr(struct mt76_dev *dev, struct mt76s_intr *intr)
+{
+ struct mt76_sdio *sdio = &dev->sdio;
+ struct mt7921_sdio_intr *irq_data = sdio->intr_data;
+ int i, err;
+
+ err = sdio_readsb(sdio->func, irq_data, MCR_WHISR, sizeof(*irq_data));
+ if (err < 0)
+ return err;
+
+ intr->isr = irq_data->isr;
+ intr->rec_mb = irq_data->rec_mb;
+ intr->tx.wtqcr = irq_data->tx.wtqcr;
+ intr->rx.num = irq_data->rx.num;
+ for (i = 0; i < 2 ; i++) {
+ if (!i)
+ intr->rx.len[0] = irq_data->rx.len0;
+ else
+ intr->rx.len[1] = irq_data->rx.len1;
+ }
+
+ return 0;
+}
+
+static int mt7921s_probe(struct sdio_func *func,
+ const struct sdio_device_id *id)
+{
+ static const struct mt76_driver_ops drv_ops = {
+ .txwi_size = MT_SDIO_TXD_SIZE,
+ .survey_flags = SURVEY_INFO_TIME_TX |
+ SURVEY_INFO_TIME_RX |
+ SURVEY_INFO_TIME_BSS_RX,
+ .tx_prepare_skb = mt7921s_tx_prepare_skb,
+ .tx_complete_skb = mt7921s_tx_complete_skb,
+ .tx_status_data = mt7921s_tx_status_data,
+ .rx_skb = mt7921_queue_rx_skb,
+ .sta_ps = mt7921_sta_ps,
+ .sta_add = mt7921_mac_sta_add,
+ .sta_assoc = mt7921_mac_sta_assoc,
+ .sta_remove = mt7921_mac_sta_remove,
+ .update_survey = mt7921_update_channel,
+ };
+ static const struct mt76_bus_ops mt7921s_ops = {
+ .rr = mt76s_rr,
+ .rmw = mt76s_rmw,
+ .wr = mt76s_wr,
+ .write_copy = mt76s_write_copy,
+ .read_copy = mt76s_read_copy,
+ .wr_rp = mt76s_wr_rp,
+ .rd_rp = mt76s_rd_rp,
+ .type = MT76_BUS_SDIO,
+ };
+ static const struct mt7921_hif_ops mt7921_sdio_ops = {
+ .mcu_init = mt7921s_mcu_init,
+ .drv_own = mt7921s_mcu_drv_pmctrl,
+ .fw_own = mt7921s_mcu_fw_pmctrl,
+ };
+
+ struct mt7921_dev *dev;
+ struct mt76_dev *mdev;
+ int ret, i;
+
+ mdev = mt76_alloc_device(&func->dev, sizeof(*dev), &mt7921_ops,
+ &drv_ops);
+ if (!mdev)
+ return -ENOMEM;
+
+ dev = container_of(mdev, struct mt7921_dev, mt76);
+ dev->hif_ops = &mt7921_sdio_ops;
+
+ sdio_set_drvdata(func, dev);
+
+ ret = mt76s_init(mdev, func, &mt7921s_ops);
+ if (ret < 0)
+ goto error;
+
+ ret = mt76s_hw_init(mdev, func, MT76_CONNAC2_SDIO);
+ if (ret)
+ goto error;
+
+ mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) |
+ (mt76_rr(dev, MT_HW_REV) & 0xff);
+ dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
+
+ mdev->sdio.parse_irq = mt7921s_parse_intr;
+ mdev->sdio.intr_data = devm_kmalloc(mdev->dev,
+ sizeof(struct mt7921_sdio_intr),
+ GFP_KERNEL);
+ if (!mdev->sdio.intr_data) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(mdev->sdio.xmit_buf); i++) {
+ mdev->sdio.xmit_buf[i] = devm_kmalloc(mdev->dev,
+ MT76S_XMIT_BUF_SZ,
+ GFP_KERNEL);
+ if (!mdev->sdio.xmit_buf[i]) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ }
+
+ ret = mt76s_alloc_rx_queue(mdev, MT_RXQ_MAIN);
+ if (ret)
+ goto error;
+
+ ret = mt76s_alloc_rx_queue(mdev, MT_RXQ_MCU);
+ if (ret)
+ goto error;
+
+ ret = mt76s_alloc_tx(mdev);
+ if (ret)
+ goto error;
+
+ ret = mt76_worker_setup(mt76_hw(dev), &mdev->sdio.txrx_worker,
+ mt7921s_txrx_worker, "sdio-txrx");
+ if (ret)
+ goto error;
+
+ sched_set_fifo_low(mdev->sdio.txrx_worker.task);
+
+ ret = mt7921_register_device(dev);
+ if (ret)
+ goto error;
+
+ return 0;
+
+error:
+ mt76s_deinit(&dev->mt76);
+ mt76_free_device(&dev->mt76);
+
+ return ret;
+}
+
+static void mt7921s_remove(struct sdio_func *func)
+{
+ struct mt7921_dev *dev = sdio_get_drvdata(func);
+
+ mt7921s_unregister_device(dev);
+}
+
+#ifdef CONFIG_PM
+static int mt7921s_suspend(struct device *__dev)
+{
+ struct sdio_func *func = dev_to_sdio_func(__dev);
+ struct mt7921_dev *dev = sdio_get_drvdata(func);
+ struct mt76_connac_pm *pm = &dev->pm;
+ struct mt76_dev *mdev = &dev->mt76;
+ bool hif_suspend;
+ int err;
+
+ pm->suspended = true;
+ cancel_delayed_work_sync(&pm->ps_work);
+ cancel_work_sync(&pm->wake_work);
+
+ err = mt7921_mcu_drv_pmctrl(dev);
+ if (err < 0)
+ goto restore_suspend;
+
+ hif_suspend = !test_bit(MT76_STATE_SUSPEND, &dev->mphy.state);
+ if (hif_suspend) {
+ err = mt76_connac_mcu_set_hif_suspend(mdev, true);
+ if (err)
+ goto restore_suspend;
+ }
+
+ /* always enable deep sleep during suspend to reduce
+ * power consumption
+ */
+ mt76_connac_mcu_set_deep_sleep(mdev, true);
+
+ mt76_txq_schedule_all(&dev->mphy);
+ mt76_worker_disable(&mdev->tx_worker);
+ mt76_worker_disable(&mdev->sdio.txrx_worker);
+ mt76_worker_disable(&mdev->sdio.status_worker);
+ mt76_worker_disable(&mdev->sdio.net_worker);
+ cancel_work_sync(&mdev->sdio.stat_work);
+ clear_bit(MT76_READING_STATS, &dev->mphy.state);
+
+ mt76_tx_status_check(mdev, true);
+
+ err = mt7921_mcu_fw_pmctrl(dev);
+ if (err)
+ goto restore_worker;
+
+ sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+
+ return 0;
+
+restore_worker:
+ mt76_worker_enable(&mdev->tx_worker);
+ mt76_worker_enable(&mdev->sdio.txrx_worker);
+ mt76_worker_enable(&mdev->sdio.status_worker);
+ mt76_worker_enable(&mdev->sdio.net_worker);
+
+ if (!pm->ds_enable)
+ mt76_connac_mcu_set_deep_sleep(mdev, false);
+
+ if (hif_suspend)
+ mt76_connac_mcu_set_hif_suspend(mdev, false);
+
+restore_suspend:
+ pm->suspended = false;
+
+ return err;
+}
+
+static int mt7921s_resume(struct device *__dev)
+{
+ struct sdio_func *func = dev_to_sdio_func(__dev);
+ struct mt7921_dev *dev = sdio_get_drvdata(func);
+ struct mt76_connac_pm *pm = &dev->pm;
+ struct mt76_dev *mdev = &dev->mt76;
+ int err;
+
+ pm->suspended = false;
+
+ err = mt7921_mcu_drv_pmctrl(dev);
+ if (err < 0)
+ return err;
+
+ mt76_worker_enable(&mdev->tx_worker);
+ mt76_worker_enable(&mdev->sdio.txrx_worker);
+ mt76_worker_enable(&mdev->sdio.status_worker);
+ mt76_worker_enable(&mdev->sdio.net_worker);
+
+ /* restore previous ds setting */
+ if (!pm->ds_enable)
+ mt76_connac_mcu_set_deep_sleep(mdev, false);
+
+ if (!test_bit(MT76_STATE_SUSPEND, &dev->mphy.state))
+ err = mt76_connac_mcu_set_hif_suspend(mdev, false);
+
+ return err;
+}
+
+static const struct dev_pm_ops mt7921s_pm_ops = {
+ .suspend = mt7921s_suspend,
+ .resume = mt7921s_resume,
+};
+#endif
+
+MODULE_DEVICE_TABLE(sdio, mt7921s_table);
+MODULE_FIRMWARE(MT7921_FIRMWARE_WM);
+MODULE_FIRMWARE(MT7921_ROM_PATCH);
+
+static struct sdio_driver mt7921s_driver = {
+ .name = KBUILD_MODNAME,
+ .probe = mt7921s_probe,
+ .remove = mt7921s_remove,
+ .id_table = mt7921s_table,
+#ifdef CONFIG_PM
+ .drv = {
+ .pm = &mt7921s_pm_ops,
+ }
+#endif
+};
+module_sdio_driver(mt7921s_driver);
+MODULE_AUTHOR("Sean Wang <[email protected]>");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c
new file mode 100644
index 000000000000..91a7acd49ee4
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2021 MediaTek Inc. */
+
+#include <linux/iopoll.h>
+#include <linux/mmc/sdio_func.h>
+#include "mt7921.h"
+#include "mac.h"
+
+static void
+mt7921s_write_txwi(struct mt7921_dev *dev, struct mt76_wcid *wcid,
+ enum mt76_txq_id qid, struct ieee80211_sta *sta,
+ struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_key_conf *key = info->control.hw_key;
+ __le32 *txwi;
+ int pid;
+
+ pid = mt76_tx_status_skb_add(&dev->mt76, wcid, skb);
+ txwi = (__le32 *)(skb->data - MT_SDIO_TXD_SIZE);
+ memset(txwi, 0, MT_SDIO_TXD_SIZE);
+ mt7921_mac_write_txwi(dev, txwi, skb, wcid, key, pid, false);
+ skb_push(skb, MT_SDIO_TXD_SIZE);
+}
+
+int mt7921s_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+ enum mt76_txq_id qid, struct mt76_wcid *wcid,
+ struct ieee80211_sta *sta,
+ struct mt76_tx_info *tx_info)
+{
+ struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
+ struct sk_buff *skb = tx_info->skb;
+ int pad;
+
+ if (unlikely(tx_info->skb->len <= ETH_HLEN))
+ return -EINVAL;
+
+ if (!wcid)
+ wcid = &dev->mt76.global_wcid;
+
+ if (sta) {
+ struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv;
+
+ if (time_after(jiffies, msta->last_txs + HZ / 4)) {
+ info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
+ msta->last_txs = jiffies;
+ }
+ }
+
+ mt7921s_write_txwi(dev, wcid, qid, sta, skb);
+
+ mt7921_skb_add_sdio_hdr(skb, MT7921_SDIO_DATA);
+ pad = round_up(skb->len, 4) - skb->len;
+
+ return mt76_skb_adjust_pad(skb, pad);
+}
+
+void mt7921s_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
+{
+ __le32 *txwi = (__le32 *)(e->skb->data + MT_SDIO_HDR_SIZE);
+ unsigned int headroom = MT_SDIO_TXD_SIZE + MT_SDIO_HDR_SIZE;
+ struct ieee80211_sta *sta;
+ struct mt76_wcid *wcid;
+ u16 idx;
+
+ idx = FIELD_GET(MT_TXD1_WLAN_IDX, le32_to_cpu(txwi[1]));
+ wcid = rcu_dereference(mdev->wcid[idx]);
+ sta = wcid_to_sta(wcid);
+
+ if (sta && likely(e->skb->protocol != cpu_to_be16(ETH_P_PAE)))
+ mt7921_tx_check_aggr(sta, txwi);
+
+ skb_pull(e->skb, headroom);
+ mt76_tx_complete_skb(mdev, e->wcid, e->skb);
+}
+
+bool mt7921s_tx_status_data(struct mt76_dev *mdev, u8 *update)
+{
+ struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
+
+ mt7921_mutex_acquire(dev);
+ mt7921_mac_sta_poll(dev);
+ mt7921_mutex_release(dev);
+
+ return 0;
+}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c
new file mode 100644
index 000000000000..049e06d7c3fb
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2021 MediaTek Inc. */
+
+#include <linux/kernel.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/module.h>
+#include <linux/iopoll.h>
+
+#include "mt7921.h"
+#include "../sdio.h"
+#include "mac.h"
+#include "mcu.h"
+#include "regs.h"
+
+static int
+mt7921s_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
+ int cmd, int *seq)
+{
+ struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
+ enum mt7921_sdio_pkt_type type = MT7921_SDIO_CMD;
+ enum mt76_mcuq_id txq = MT_MCUQ_WM;
+ int ret, pad;
+
+ ret = mt7921_mcu_fill_message(mdev, skb, cmd, seq);
+ if (ret)
+ return ret;
+
+ if (cmd == MCU_CMD_FW_SCATTER)
+ type = MT7921_SDIO_FWDL;
+
+ mt7921_skb_add_sdio_hdr(skb, type);
+ pad = round_up(skb->len, 4) - skb->len;
+ __skb_put_zero(skb, pad);
+
+ ret = mt76_tx_queue_skb_raw(dev, mdev->q_mcu[txq], skb, 0);
+ if (ret)
+ return ret;
+
+ mt76_queue_kick(dev, mdev->q_mcu[txq]);
+
+ return ret;
+}
+
+int mt7921s_mcu_init(struct mt7921_dev *dev)
+{
+ static const struct mt76_mcu_ops mt7921s_mcu_ops = {
+ .headroom = MT_SDIO_HDR_SIZE + sizeof(struct mt7921_mcu_txd),
+ .tailroom = MT_SDIO_TAIL_SIZE,
+ .mcu_skb_send_msg = mt7921s_mcu_send_message,
+ .mcu_parse_response = mt7921_mcu_parse_response,
+ .mcu_rr = mt76_connac_mcu_reg_rr,
+ .mcu_wr = mt76_connac_mcu_reg_wr,
+ };
+ int ret;
+
+ mt7921s_mcu_drv_pmctrl(dev);
+
+ dev->mt76.mcu_ops = &mt7921s_mcu_ops;
+
+ ret = mt7921_run_firmware(dev);
+ if (ret)
+ return ret;
+
+ set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
+
+ return 0;
+}
+
+int mt7921s_mcu_drv_pmctrl(struct mt7921_dev *dev)
+{
+ struct sdio_func *func = dev->mt76.sdio.func;
+ struct mt76_phy *mphy = &dev->mt76.phy;
+ struct mt76_connac_pm *pm = &dev->pm;
+ int err = 0;
+ u32 status;
+
+ sdio_claim_host(func);
+
+ sdio_writel(func, WHLPCR_FW_OWN_REQ_CLR, MCR_WHLPCR, NULL);
+
+ err = readx_poll_timeout(mt76s_read_pcr, &dev->mt76, status,
+ status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000);
+ sdio_release_host(func);
+
+ if (err < 0) {
+ dev_err(dev->mt76.dev, "driver own failed\n");
+ err = -EIO;
+ goto out;
+ }
+
+ clear_bit(MT76_STATE_PM, &mphy->state);
+
+ pm->stats.last_wake_event = jiffies;
+ pm->stats.doze_time += pm->stats.last_wake_event -
+ pm->stats.last_doze_event;
+out:
+ return err;
+}
+
+int mt7921s_mcu_fw_pmctrl(struct mt7921_dev *dev)
+{
+ struct sdio_func *func = dev->mt76.sdio.func;
+ struct mt76_phy *mphy = &dev->mt76.phy;
+ struct mt76_connac_pm *pm = &dev->pm;
+ int err = 0;
+ u32 status;
+
+ sdio_claim_host(func);
+
+ sdio_writel(func, WHLPCR_FW_OWN_REQ_SET, MCR_WHLPCR, NULL);
+
+ err = readx_poll_timeout(mt76s_read_pcr, &dev->mt76, status,
+ !(status & WHLPCR_IS_DRIVER_OWN), 2000, 1000000);
+ sdio_release_host(func);
+
+ if (err < 0) {
+ dev_err(dev->mt76.dev, "firmware own failed\n");
+ clear_bit(MT76_STATE_PM, &mphy->state);
+ err = -EIO;
+ }
+
+ pm->stats.last_doze_event = jiffies;
+ pm->stats.awake_time += pm->stats.last_doze_event -
+ pm->stats.last_wake_event;
+
+ return err;
+}
--
2.25.1