2021-09-15 01:15:59

by Sean Wang

[permalink] [raw]
Subject: [PATCH v1 00/16] Add MT7921 SDIO 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, 9, 10 and 12-14
These are preliminary patches for mt7921s driver to refactor and reuse the
current mt7921e driver as much as possible.

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

PART 3: patch 11 and 15-16
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 tree plus
the extra pending patches [1] expected to be merged to mt76 tree soon to
help the review and merge process be easier.

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

bc8238b1d71b mt76: mt7921s: add reset support
e1aa6be18238 mt76: mt7921: introduce mt7921s support
917c58fea5ae mt76: mt7921: refactor mt7921_mcu_send_message
6cc82d84bde6 mt76: mt7921: rely on mcu_get_nic_capability
c2ffb6abccee mt76: connac: extend mcu_get_nic_capability
b1c9fdc84dc4 mt76: connac: extend mt76_connac_sdio module to support CONNAC2
d251c19578f1 mt76: mt7921: use physical addr to unify register access
faf43c5f538a mt76: mt7921: make all event parser resuable between mt7921s and mt7921e
4d7725450ead mt76: mt7663s: rely on mt76_connac_sdio common library
85e99d7c663c mt76: connac: move sdio utility routines in mt76_connac_sdio module
bc35b5486170 mt76: connac: move mcu reg access utility routines in mt76_connac_lib module
fec36e88c44b mt76: mt7921: add MT7921_COMMON module
210a8cd3ab66 mt76: mt7921: refactor init.c to be bus independent
37519dafa027 mt76: mt7921: refactor mcu.c to be bus independent
aa4827ded213 mt76: mt7921: refactor dma.c to be pcie specific
f0d66c706432 mt76: mt7921: refactor mac.c to be bus independent
39ac94bb3154 mt76: schedule status timeout at dma completion
3e9f849d0fa4 mt76: substitute sk_buff_head status_list with spinlock_t status_lock
f739888cbc9a mt76: remove mt76_wcid pointer from mt76_tx_status_check signature
7282f018bbd5 mt76: introduce packet_id idr
f067947571dc mt76: mt7921: add 6GHz support
2a29c573f44a mt76: add 6GHz support
ba4e1c352d91 mt76: connac: enable hw amsdu @ 6GHz
ed3294b6241b mt76: connac: add 6GHz support to mt76_connac_mcu_uni_add_bss
ad7d31a50d49 mt76: connac: add 6GHz support to mt76_connac_mcu_sta_tlv
017ba00f2c14 mt76: connac: set 6G phymode in single-sku support
9516ab381214 mt76: connac: add 6GHz support to mt76_connac_mcu_set_channel_domain
1afbef896fdd mt76: connac: enable 6GHz band for hw scan
527c23367b96 mt76: mt7921: remove mt7921_sta_stats
efb4fe718da9 mt76: mt7921: remove mcu rate reporting code
2950bd783385 mt76: mt7921: report tx rate directly from tx status
dd82125f72a4 mt76: mt7921: add support for tx status reporting
c0937116aefd mt76: mt7921: start reworking tx rate reporting
914640e9777d mt76: mt7921: update mib counters dumping phy stats
4d8d84d63bd3 mt76: mt7921: always wake device if necessary in debugfs
67a7fa715caf mt76: mt7921: move mt7921_queue_rx_skb to mac.c
8011d3c37132 mt76: mt7921: fix retrying release semaphore without end
50c452b6ad50 mt76: mt7921: robustify hardware initialization flow
9c19de7d8b1d (nbd/mt76) mt76: mt7615: checkpatch cleanup

Sean Wang (16):
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: connac: move sdio utility routines in mt76_connac_sdio module
mt76: mt7663s: rely on mt76_connac_sdio common library
mt76: mt7921: make all event parser resuable between mt7921s and
mt7921e
mt76: mt7921: use physical addr to unify register access
mt76: connac: extend mt76_connac_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/Kconfig | 5 +
drivers/net/wireless/mediatek/mt76/Makefile | 2 +
drivers/net/wireless/mediatek/mt76/mcu.c | 8 +-
drivers/net/wireless/mediatek/mt76/mt76.h | 4 +
.../net/wireless/mediatek/mt76/mt7615/Kconfig | 2 +-
.../wireless/mediatek/mt76/mt7615/Makefile | 2 +-
.../net/wireless/mediatek/mt76/mt7615/mcu.c | 28 --
.../wireless/mediatek/mt76/mt7615/mt7615.h | 6 -
.../net/wireless/mediatek/mt76/mt7615/sdio.c | 310 ++-------------
.../wireless/mediatek/mt76/mt7615/sdio_mcu.c | 9 +-
.../wireless/mediatek/mt76/mt76_connac_mcu.c | 93 +++++
.../wireless/mediatek/mt76/mt76_connac_mcu.h | 3 +
.../wireless/mediatek/mt76/mt76_connac_sdio.c | 363 +++++++++++++++++
.../{mt7615/sdio.h => mt76_connac_sdio.h} | 81 +++-
.../sdio_txrx.c => mt76_connac_sdio_txrx.c} | 177 ++++++---
.../net/wireless/mediatek/mt76/mt7921/Kconfig | 19 +-
.../wireless/mediatek/mt76/mt7921/Makefile | 8 +-
.../wireless/mediatek/mt76/mt7921/debugfs.c | 18 +-
.../net/wireless/mediatek/mt76/mt7921/dma.c | 35 +-
.../wireless/mediatek/mt76/mt7921/eeprom.c | 101 -----
.../net/wireless/mediatek/mt76/mt7921/init.c | 52 +--
.../net/wireless/mediatek/mt76/mt7921/mac.c | 364 ++----------------
.../net/wireless/mediatek/mt76/mt7921/mac.h | 4 +
.../net/wireless/mediatek/mt76/mt7921/main.c | 7 +
.../net/wireless/mediatek/mt76/mt7921/mcu.c | 131 ++-----
.../wireless/mediatek/mt76/mt7921/mt7921.h | 92 ++++-
.../net/wireless/mediatek/mt76/mt7921/pci.c | 20 +-
.../wireless/mediatek/mt76/mt7921/pci_init.c | 26 ++
.../wireless/mediatek/mt76/mt7921/pci_mac.c | 347 +++++++++++++++++
.../wireless/mediatek/mt76/mt7921/pci_mcu.c | 115 ++++++
.../net/wireless/mediatek/mt76/mt7921/regs.h | 22 +-
.../net/wireless/mediatek/mt76/mt7921/sdio.c | 262 +++++++++++++
.../wireless/mediatek/mt76/mt7921/sdio_init.c | 23 ++
.../wireless/mediatek/mt76/mt7921/sdio_mac.c | 202 ++++++++++
.../wireless/mediatek/mt76/mt7921/sdio_mcu.c | 133 +++++++
.../wireless/mediatek/mt76/mt7921/testmode.c | 2 +-
36 files changed, 2069 insertions(+), 1007 deletions(-)
create mode 100644 drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.c
rename drivers/net/wireless/mediatek/mt76/{mt7615/sdio.h => mt76_connac_sdio.h} (51%)
rename drivers/net/wireless/mediatek/mt76/{mt7615/sdio_txrx.c => mt76_connac_sdio_txrx.c} (58%)
delete mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/eeprom.c
create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/pci_init.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_init.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

--
2.25.1


2021-09-15 01:16:17

by Sean Wang

[permalink] [raw]
Subject: [PATCH v1 01/16] 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]>
Signed-off-by: Sean Wang <[email protected]>
---
.../wireless/mediatek/mt76/mt7921/Makefile | 2 +-
.../net/wireless/mediatek/mt76/mt7921/mac.c | 331 +----------------
.../wireless/mediatek/mt76/mt7921/mt7921.h | 25 +-
.../net/wireless/mediatek/mt76/mt7921/pci.c | 12 +-
.../wireless/mediatek/mt76/mt7921/pci_mac.c | 345 ++++++++++++++++++
5 files changed, 379 insertions(+), 336 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 27f13228c5a7..d811702a3a2c 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,
@@ -836,7 +836,7 @@ mt7921_mac_write_txwi_80211(struct mt7921_dev *dev, __le32 *txwi,
txwi[7] |= cpu_to_le32(val);
}

-static void
+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,
@@ -922,86 +922,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
+void
mt7921_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
{
struct mt7921_sta *msta;
@@ -1026,143 +947,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 mt7921_phy *phy;
- 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);
- phy = msta->vif->phy;
- 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)
@@ -1330,9 +1114,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;
@@ -1354,33 +1135,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)
-{
- struct mt7921_dev *dev;
-
- if (!e->txwi) {
- dev_kfree_skb_any(e->skb);
- return;
- }
-
- dev = container_of(mdev, struct mt7921_dev, mt76);
-
- /* 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;
@@ -1496,20 +1250,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)
@@ -1524,69 +1264,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);
-
- mt76_for_each_q_rx(&dev->mt76, i) {
- napi_enable(&dev->mt76.napi[i]);
- napi_schedule(&dev->mt76.napi[i]);
- }
-
- 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);
-
- napi_enable(&dev->mt76.tx_napi);
- napi_schedule(&dev->mt76.tx_napi);
- mt76_worker_enable(&dev->mt76.tx_worker);
-
- return err;
-}
-
/* system error recovery */
void mt7921_mac_reset_work(struct work_struct *work)
{
@@ -1608,7 +1285,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 cd710360d180..b01b9b7c42b4 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..f211dafa311c
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c
@@ -0,0 +1,345 @@
+// 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 mt7921_phy *phy;
+ 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);
+ phy = msta->vif->phy;
+ 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);
+}
+
+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)
+{
+ struct mt7921_dev *dev;
+
+ if (!e->txwi) {
+ dev_kfree_skb_any(e->skb);
+ return;
+ }
+
+ dev = container_of(mdev, struct mt7921_dev, mt76);
+
+ /* 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);
+
+ mt76_for_each_q_rx(&dev->mt76, i) {
+ napi_enable(&dev->mt76.napi[i]);
+ napi_schedule(&dev->mt76.napi[i]);
+ }
+
+ 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);
+
+ napi_enable(&dev->mt76.tx_napi);
+ napi_schedule(&dev->mt76.tx_napi);
+ mt76_worker_enable(&dev->mt76.tx_worker);
+
+ return err;
+}
--
2.25.1

2021-09-15 01:16:23

by Sean Wang

[permalink] [raw]
Subject: [PATCH v1 04/16] 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]>
Signed-off-by: Sean Wang <[email protected]>
---
.../wireless/mediatek/mt76/mt7921/Makefile | 4 +--
.../net/wireless/mediatek/mt76/mt7921/dma.c | 8 ++++++
.../net/wireless/mediatek/mt76/mt7921/init.c | 28 +------------------
.../wireless/mediatek/mt76/mt7921/mt7921.h | 3 ++
.../net/wireless/mediatek/mt76/mt7921/pci.c | 5 ++++
.../wireless/mediatek/mt76/mt7921/pci_init.c | 26 +++++++++++++++++
6 files changed, 45 insertions(+), 29 deletions(-)
create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/pci_init.c

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

CFLAGS_trace.o := -I$(src)

-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-y := pci.o pci_mac.o pci_mcu.o pci_init.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/dma.c b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
index d3e2036a1974..be24241fb8e6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
@@ -313,6 +313,11 @@ int mt7921_wpdma_reset(struct mt7921_dev *dev, bool force)
return 0;
}

+int mt7921e_init_reset(struct mt7921_dev *dev)
+{
+ return mt7921_wpdma_reset(dev, true);
+}
+
int mt7921_wpdma_reinit_cond(struct mt7921_dev *dev)
{
struct mt76_connac_pm *pm = &dev->pm;
@@ -343,6 +348,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 7c7a26102e11..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,25 +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);
- mt7921_mcu_fw_pmctrl(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 dbace154bfa5..60f4552cb212 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_drv_own(dev) ((dev)->hif_ops->drv_own(dev))
#define mt7921_fw_own(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);
@@ -394,5 +396,6 @@ 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);
+int mt7921e_init_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 b16bcee08cd7..f6bc3505b06a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
@@ -116,6 +116,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 +173,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;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci_init.c
new file mode 100644
index 000000000000..4511fec79d43
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_init.c
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2021 MediaTek Inc. */
+
+#include "mt7921.h"
+
+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);
+ mt7921_mcu_fw_pmctrl(dev);
+
+ tasklet_disable(&dev->irq_tasklet);
+ mt76_free_device(&dev->mt76);
+}
--
2.25.1

2021-09-15 01:16:25

by Sean Wang

[permalink] [raw]
Subject: [PATCH v1 03/16] 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]>
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 | 90 ++---------------
.../wireless/mediatek/mt76/mt7921/mt7921.h | 18 +++-
.../net/wireless/mediatek/mt76/mt7921/pci.c | 3 +
.../wireless/mediatek/mt76/mt7921/pci_mac.c | 2 +
.../wireless/mediatek/mt76/mt7921/pci_mcu.c | 97 +++++++++++++++++++
.../wireless/mediatek/mt76/mt7921/testmode.c | 2 +-
9 files changed, 129 insertions(+), 92 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 97b931ea07c1..7c7a26102e11 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);
mt7921_mcu_fw_pmctrl(dev);

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
index 580a88b7841e..c26d986e08e6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
@@ -1282,12 +1282,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 6ba431347b3b..0648443eb283 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -160,7 +160,7 @@ mt7921_mcu_parse_eeprom(struct mt76_dev *dev, struct sk_buff *skb)
return 0;
}

-static int
+int
mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd,
struct sk_buff *skb, int seq)
{
@@ -224,7 +224,7 @@ mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd,
return ret;
}

-static int
+int
mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
int cmd, int *wait_seq)
{
@@ -590,7 +590,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 +603,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 +869,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 +896,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 +906,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);
}

@@ -1231,35 +1197,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;
@@ -1271,7 +1208,7 @@ int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev)
if (!test_bit(MT76_STATE_PM, &mphy->state))
goto out;

- err = __mt7921_mcu_drv_pmctrl(dev);
+ err = mt7921_drv_own(dev);
out:
mutex_unlock(&pm->mutex);

@@ -1285,29 +1222,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_fw_own(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 4c1c7c4eafac..dbace154bfa5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
@@ -134,8 +134,14 @@ struct mt7921_phy {
};

#define mt7921_dev_reset(dev) ((dev)->hif_ops->reset(dev))
+#define mt7921_mcu_init(dev) ((dev)->hif_ops->mcu_init(dev))
+#define mt7921_drv_own(dev) ((dev)->hif_ops->drv_own(dev))
+#define mt7921_fw_own(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);
@@ -359,7 +364,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);
@@ -378,7 +382,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 b01b9b7c42b4..b16bcee08cd7 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 f211dafa311c..f0734be57dce 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c
@@ -286,6 +286,8 @@ 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;
+}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/testmode.c b/drivers/net/wireless/mediatek/mt76/mt7921/testmode.c
index 8bd43879dd6f..d22bbd9da58f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/testmode.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/testmode.c
@@ -57,7 +57,7 @@ mt7921_tm_set(struct mt7921_dev *dev, struct mt7921_tm_cmd *req)
pm->enable = false;
cancel_delayed_work_sync(&pm->ps_work);
cancel_work_sync(&pm->wake_work);
- __mt7921_mcu_drv_pmctrl(dev);
+ mt7921_drv_own(dev);

mt76_wr(dev, MT_WF_RFCR(0), dev->mt76.rxfilter);
phy->test.state = MT76_TM_STATE_ON;
--
2.25.1

2021-09-15 01:17:16

by Sean Wang

[permalink] [raw]
Subject: [PATCH v1 12/16] 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]>
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 58fd0c7831f4..3062cda2e770 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 a53f6344a184..cee17b48b296 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
@@ -1716,6 +1716,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 = le32_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 {
@@ -1758,6 +1813,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-09-15 01:17:53

by Sean Wang

[permalink] [raw]
Subject: [PATCH v1 09/16] mt76: mt7921: make all event parser resuable between mt7921s and mt7921e

From: Sean Wang <[email protected]>

The longer event such as the event for mcu_get_nic_capability would hold
the data in paged fragment skb for the SDIO device so we turn the skb to
be linearized skb before accessing it to reuse the same event parser
betweem mt7921s and mt7921e.

Tested-by: Deren Wu <[email protected]>
Signed-off-by: Sean Wang <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
index f5a8f7fa4244..8e49df20a8cb 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -458,7 +458,14 @@ mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb)

void mt7921_mcu_rx_event(struct mt7921_dev *dev, struct sk_buff *skb)
{
- struct mt7921_mcu_rxd *rxd = (struct mt7921_mcu_rxd *)skb->data;
+ struct mt7921_mcu_rxd *rxd;
+ int ret;
+
+ ret = skb_linearize(skb);
+ if (ret)
+ return;
+
+ rxd = (struct mt7921_mcu_rxd *)skb->data;

if (rxd->eid == 0x6) {
mt76_mcu_rx_event(&dev->mt76, skb);
--
2.25.1

2021-09-15 01:18:36

by Sean Wang

[permalink] [raw]
Subject: [PATCH v1 02/16] 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]>
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/mcu.c | 6 ++++++
drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 2 +-
4 files changed, 9 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 d811702a3a2c..580a88b7841e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
@@ -1392,7 +1392,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/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
index ecdc879216b9..6ba431347b3b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -1369,3 +1369,9 @@ int mt7921_get_txpwr_info(struct mt7921_dev *dev, struct mt7921_txpwr *txpwr)

return 0;
}
+
+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);
+}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
index 70c0f41180a1..4c1c7c4eafac 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
@@ -330,7 +330,7 @@ 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);
+void mt7921_mcu_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-09-15 01:18:44

by Sean Wang

[permalink] [raw]
Subject: [PATCH v1 06/16] mt76: connac: move mcu reg access utility routines in mt76_connac_lib module

From: Sean Wang <[email protected]>

Move mcu reg access shared between mt7663s and mt7921s in mt76_connac_lib
module.

Tested-by: Deren Wu <[email protected]>
Signed-off-by: Sean Wang <[email protected]>
---
.../wireless/mediatek/mt76/mt76_connac_mcu.c | 27 +++++++++++++++++++
.../wireless/mediatek/mt76/mt76_connac_mcu.h | 3 +++
2 files changed, 30 insertions(+)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
index ae692052de97..a53f6344a184 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
@@ -2406,6 +2406,33 @@ void mt76_connac_mcu_set_suspend_iter(void *priv, u8 *mac,
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_suspend_iter);

+u32 mt76_connac_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(mt76_connac_mcu_reg_rr);
+
+void mt76_connac_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(mt76_connac_mcu_reg_wr);
#endif /* CONFIG_PM */

MODULE_AUTHOR("Lorenzo Bianconi <[email protected]>");
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
index ea46dde364e1..6444cb6a73d6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
@@ -1111,4 +1111,7 @@ void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb,
int mt76_connac_mcu_set_rate_txpower(struct mt76_phy *phy);
int mt76_connac_mcu_set_p2p_oppps(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
+u32 mt76_connac_mcu_reg_rr(struct mt76_dev *dev, u32 offset);
+void mt76_connac_mcu_reg_wr(struct mt76_dev *dev, u32 offset, u32 val);
+
#endif /* __MT76_CONNAC_MCU_H */
--
2.25.1

2021-09-15 01:25:40

by Sean Wang

[permalink] [raw]
Subject: [PATCH v1 14/16] mt76: mt7921: refactor mt7921_mcu_send_message

From: Sean Wang <[email protected]>

This is a preliminary patch to introduce mt7921s support.

Refactor mt7921_mcu_send_message to be sharable between mt7921e and
mt7921e.

Tested-by: Deren Wu <[email protected]>
Signed-off-by: Sean Wang <[email protected]>
---
.../net/wireless/mediatek/mt76/mt7921/mcu.c | 11 ++++-------
.../net/wireless/mediatek/mt76/mt7921/mt7921.h | 2 +-
.../wireless/mediatek/mt76/mt7921/pci_mcu.c | 18 ++++++++++++++++++
3 files changed, 23 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
index b3e257594f92..2de5a2ba43b2 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -227,12 +227,11 @@ EXPORT_SYMBOL_GPL(mt7921_mcu_parse_response);


int
-mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
+mt7921_mcu_fill_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;
- enum mt76_mcuq_id txq = MT_MCUQ_WM;
struct mt7921_uni_txd *uni_txd;
struct mt7921_mcu_txd *mcu_txd;
__le32 *txd;
@@ -254,10 +253,8 @@ mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
if (!seq)
seq = ++dev->mt76.mcu.msg_seq & 0xf;

- if (cmd == MCU_CMD_FW_SCATTER) {
- txq = MT_MCUQ_FWDL;
+ if (cmd == MCU_CMD_FW_SCATTER)
goto exit;
- }

txd_len = cmd & MCU_UNI_PREFIX ? sizeof(*uni_txd) : sizeof(*mcu_txd);
txd = (__le32 *)skb_push(skb, txd_len);
@@ -321,9 +318,9 @@ mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
if (wait_seq)
*wait_seq = seq;

- return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[txq], skb, 0);
+ return 0;
}
-EXPORT_SYMBOL_GPL(mt7921_mcu_send_message);
+EXPORT_SYMBOL_GPL(mt7921_mcu_fill_message);

static void
mt7921_mcu_scan_event(struct mt7921_dev *dev, struct sk_buff *skb)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
index bd52e39e8181..01c356b315ec 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
@@ -376,7 +376,7 @@ 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 mt7921_mcu_fill_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);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c
index 9ac3bc25f067..583a89a34734 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c
@@ -18,6 +18,24 @@ static int mt7921e_driver_own(struct mt7921_dev *dev)
return 0;
}

+static int
+mt7921_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 mt76_mcuq_id txq = MT_MCUQ_WM;
+ int ret;
+
+ ret = mt7921_mcu_fill_message(mdev, skb, cmd, seq);
+ if (ret)
+ return ret;
+
+ if (cmd == MCU_CMD_FW_SCATTER)
+ txq = MT_MCUQ_FWDL;
+
+ return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[txq], skb, 0);
+}
+
int mt7921e_mcu_init(struct mt7921_dev *dev)
{
static const struct mt76_mcu_ops mt7921_mcu_ops = {
--
2.25.1

2021-09-15 01:25:47

by Sean Wang

[permalink] [raw]
Subject: [PATCH v1 05/16] mt76: mt7921: add MT7921_COMMON module

From: Sean Wang <[email protected]>

This is a preliminary patch to introduce mt7921s support.

MT7921_COMMON module grouping bus independent objects the both mt7921e and
mt7921s can share with and have to rely on.

Tested-by: Deren Wu <[email protected]>
Signed-off-by: Sean Wang <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt7921/Kconfig | 8 ++++++--
drivers/net/wireless/mediatek/mt76/mt7921/Makefile | 7 ++++---
drivers/net/wireless/mediatek/mt76/mt7921/init.c | 2 ++
drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 6 ++++++
drivers/net/wireless/mediatek/mt76/mt7921/main.c | 7 +++++++
drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 10 ++++++++++
6 files changed, 35 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig
index 001f2b9cec26..071746809b1c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig
@@ -1,8 +1,12 @@
# SPDX-License-Identifier: ISC
-config MT7921E
- tristate "MediaTek MT7921E (PCIe) support"
+config MT7921_COMMON
+ tristate
select MT76_CONNAC_LIB
select WANT_DEV_COREDUMP
+
+config MT7921E
+ tristate "MediaTek MT7921E (PCIe) support"
+ select MT7921_COMMON
depends on MAC80211
depends on PCI
help
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile
index 15f940a23ea9..32f87d946bc7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile
@@ -1,9 +1,10 @@
# SPDX-License-Identifier: ISC

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

CFLAGS_trace.o := -I$(src)

-mt7921e-y := pci.o pci_mac.o pci_mcu.o pci_init.o mac.o mcu.o dma.o \
- eeprom.o main.o init.o debugfs.o trace.o
-mt7921e-$(CONFIG_NL80211_TESTMODE) += testmode.o
+mt7921-common-y := mac.o mcu.o eeprom.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 pci_init.o dma.o
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
index f0fd32c424c6..d310d6e1e566 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
@@ -145,6 +145,7 @@ int mt7921_mac_init(struct mt7921_dev *dev)

return mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b, 0);
}
+EXPORT_SYMBOL_GPL(mt7921_mac_init);

static int __mt7921_init_hardware(struct mt7921_dev *dev)
{
@@ -285,3 +286,4 @@ int mt7921_register_device(struct mt7921_dev *dev)

return 0;
}
+EXPORT_SYMBOL_GPL(mt7921_register_device);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
index c26d986e08e6..0cb6dc118711 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
@@ -39,6 +39,7 @@ static struct mt76_wcid *mt7921_rx_get_wcid(struct mt7921_dev *dev,
void mt7921_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps)
{
}
+EXPORT_SYMBOL_GPL(mt7921_sta_ps);

bool mt7921_mac_wtbl_update(struct mt7921_dev *dev, int idx, u32 mask)
{
@@ -169,6 +170,7 @@ void mt7921_mac_sta_poll(struct mt7921_dev *dev)

rcu_read_unlock();
}
+EXPORT_SYMBOL_GPL(mt7921_mac_sta_poll);

static void
mt7921_mac_decode_he_radiotap_ru(struct mt76_rx_status *status,
@@ -921,6 +923,7 @@ mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi,
txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
}
}
+EXPORT_SYMBOL_GPL(mt7921_mac_write_txwi);

void
mt7921_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
@@ -946,6 +949,7 @@ mt7921_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
if (!test_and_set_bit(tid, &msta->ampdu_state))
ieee80211_start_tx_ba_session(sta, tid, 0);
}
+EXPORT_SYMBOL_GPL(mt7921_tx_check_aggr);

static bool
mt7921_mac_add_txs_skb(struct mt7921_dev *dev, struct mt76_wcid *wcid, int pid,
@@ -1134,6 +1138,7 @@ void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
break;
}
}
+EXPORT_SYMBOL_GPL(mt7921_queue_rx_skb);

void mt7921_mac_reset_counters(struct mt7921_phy *phy)
{
@@ -1249,6 +1254,7 @@ void mt7921_update_channel(struct mt76_phy *mphy)

mt76_connac_power_save_sched(mphy, &dev->pm);
}
+EXPORT_SYMBOL_GPL(mt7921_update_channel);

static void
mt7921_vif_connect_iter(void *priv, u8 *mac,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
index c51266e40cb4..cbffa8478329 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
@@ -237,6 +237,7 @@ int __mt7921_start(struct mt7921_phy *phy)

return 0;
}
+EXPORT_SYMBOL_GPL(__mt7921_start);

static int mt7921_start(struct ieee80211_hw *hw)
{
@@ -646,6 +647,7 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,

return 0;
}
+EXPORT_SYMBOL_GPL(mt7921_mac_sta_add);

void mt7921_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
@@ -667,6 +669,7 @@ void mt7921_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif,

mt7921_mutex_release(dev);
}
+EXPORT_SYMBOL_GPL(mt7921_mac_sta_assoc);

void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
@@ -698,6 +701,7 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,

mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
}
+EXPORT_SYMBOL_GPL(mt7921_mac_sta_remove);

void mt7921_tx_worker(struct mt76_worker *w)
{
@@ -1250,3 +1254,6 @@ const struct ieee80211_ops mt7921_ops = {
.flush = mt7921_flush,
.set_sar_specs = mt7921_set_sar_specs,
};
+EXPORT_SYMBOL_GPL(mt7921_ops);
+
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
index 0648443eb283..f5a8f7fa4244 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -223,6 +223,8 @@ mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd,

return ret;
}
+EXPORT_SYMBOL_GPL(mt7921_mcu_parse_response);
+

int
mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
@@ -321,6 +323,7 @@ mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,

return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[txq], skb, 0);
}
+EXPORT_SYMBOL_GPL(mt7921_mcu_send_message);

static void
mt7921_mcu_scan_event(struct mt7921_dev *dev, struct sk_buff *skb)
@@ -602,6 +605,7 @@ int mt7921_mcu_restart(struct mt76_dev *dev)
return mt76_mcu_send_msg(dev, MCU_CMD_NIC_POWER_CTRL, &req,
sizeof(req), false);
}
+EXPORT_SYMBOL_GPL(mt7921_mcu_restart);

static u32 mt7921_get_data_mode(struct mt7921_dev *dev, u32 info)
{
@@ -905,11 +909,13 @@ int mt7921_run_firmware(struct mt7921_dev *dev)

return mt76_connac_mcu_get_nic_capability(&dev->mphy);
}
+EXPORT_SYMBOL_GPL(mt7921_run_firmware);

void mt7921_mcu_exit(struct mt7921_dev *dev)
{
skb_queue_purge(&dev->mt76.mcu.res_q);
}
+EXPORT_SYMBOL_GPL(mt7921_mcu_exit);

int mt7921_mcu_set_tx(struct mt7921_dev *dev, struct ieee80211_vif *vif)
{
@@ -1035,6 +1041,7 @@ int mt7921_mcu_set_eeprom(struct mt7921_dev *dev)
return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE,
&req, sizeof(req), true);
}
+EXPORT_SYMBOL_GPL(mt7921_mcu_set_eeprom);

int mt7921_mcu_get_eeprom(struct mt7921_dev *dev, u32 offset)
{
@@ -1217,6 +1224,7 @@ int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev)

return err;
}
+EXPORT_SYMBOL_GPL(mt7921_mcu_drv_pmctrl);

int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev)
{
@@ -1238,6 +1246,7 @@ int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev)

return err;
}
+EXPORT_SYMBOL_GPL(mt7921_mcu_fw_pmctrl);

int mt7921_mcu_set_beacon_filter(struct mt7921_dev *dev,
struct ieee80211_vif *vif,
@@ -1297,3 +1306,4 @@ 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);
}
+EXPORT_SYMBOL_GPL(mt7921_mcu_tx_cleanup);
--
2.25.1

2021-09-15 01:25:49

by Sean Wang

[permalink] [raw]
Subject: [PATCH v1 08/16] mt76: mt7663s: rely on mt76_connac_sdio common library

From: Sean Wang <[email protected]>

Rely on mt76_connac_sdio common library and remove unneeded code

Tested-by: Deren Wu <[email protected]>
Signed-off-by: Sean Wang <[email protected]>
---
.../net/wireless/mediatek/mt76/mt7615/Kconfig | 2 +-
.../wireless/mediatek/mt76/mt7615/Makefile | 2 +-
.../net/wireless/mediatek/mt76/mt7615/mcu.c | 28 --
.../wireless/mediatek/mt76/mt7615/mt7615.h | 6 -
.../net/wireless/mediatek/mt76/mt7615/sdio.c | 309 ++--------------
.../net/wireless/mediatek/mt76/mt7615/sdio.h | 115 ------
.../wireless/mediatek/mt76/mt7615/sdio_mcu.c | 8 +-
.../wireless/mediatek/mt76/mt7615/sdio_txrx.c | 334 ------------------
8 files changed, 35 insertions(+), 769 deletions(-)
delete mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/sdio.h
delete mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c

diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig
index 30fba36ff46b..110211cc9e57 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig
@@ -47,9 +47,9 @@ config MT7663U
config MT7663S
tristate "MediaTek MT7663S (SDIO) support"
select MT76_SDIO
+ select MT76_CONNAC_SDIO
select MT7663_USB_SDIO_COMMON
depends on MAC80211
- depends on MMC
help
This adds support for MT7663S 802.11ac 2x2:2 wireless devices.

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/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
index 684240e4624c..583cf815a696 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
@@ -2759,31 +2759,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..77bd59813d47 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);
@@ -571,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 fb0f8f34b8f2..97660262b2de 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c
@@ -15,7 +15,7 @@
#include <linux/mmc/sdio_func.h>

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

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

-static u32 mt7663s_read_whisr(struct mt76_dev *dev)
-{
- 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);
- }
-}
-
-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++;
- }
-
- return 0;
-}
-
static void mt7663s_init_work(struct work_struct *work)
{
struct mt7615_dev *dev;
@@ -231,64 +35,32 @@ 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)
+static void mt7663s_txrx_worker(struct mt76_worker *w)
{
- u32 status, ctrl;
- int ret;
-
- sdio_claim_host(func);
-
- ret = sdio_enable_func(func);
- if (ret < 0)
- goto release;
+ 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);

- /* 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;
+ if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
+ queue_work(mdev->wq, &dev->pm.wake_work);
+ return;
}

- 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;
+ mt76_connac_sdio_txrx(mdev);

- ret = sdio_claim_irq(func, mt7663s_sdio_irq);
- if (ret < 0)
- goto disable_func;
-
- sdio_release_host(func);
+ mt76_connac_pm_unref(&dev->mphy, &dev->pm);
+}

- return 0;
+static void mt7663s_irq(struct sdio_func *func)
+{
+ struct mt7615_dev *dev = sdio_get_drvdata(func);
+ struct mt76_sdio *sdio = &dev->mt76.sdio;

-disable_func:
- sdio_disable_func(func);
-release:
- sdio_release_host(func);
+ if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.phy.state))
+ return;

- return ret;
+ mt76_worker_schedule(&sdio->txrx_worker);
}

static int mt7663s_probe(struct sdio_func *func,
@@ -307,19 +79,19 @@ 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 = mt76_connac_sdio_rr,
+ .rmw = mt76_connac_sdio_rmw,
+ .wr = mt76_connac_sdio_wr,
+ .write_copy = mt76_connac_sdio_write_copy,
+ .read_copy = mt76_connac_sdio_read_copy,
+ .wr_rp = mt76_connac_sdio_wr_rp,
+ .rd_rp = mt76_connac_sdio_rd_rp,
.type = MT76_BUS_SDIO,
};
struct ieee80211_ops *ops;
struct mt7615_dev *dev;
struct mt76_dev *mdev;
- int i, ret;
+ int ret;

ops = devm_kmemdup(&func->dev, &mt7615_ops, sizeof(mt7615_ops),
GFP_KERNEL);
@@ -341,7 +113,7 @@ static int mt7663s_probe(struct sdio_func *func,
if (ret < 0)
goto error;

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

@@ -349,35 +121,14 @@ static int mt7663s_probe(struct sdio_func *func,
(mt76_rr(dev, MT_HW_REV) & 0xff);
dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev);

- mdev->sdio.intr_data = devm_kmalloc(mdev->dev,
- sizeof(struct mt76s_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_queues(&dev->mt76);
+ ret = mt76_connac_sdio_init(mdev, mt7663s_txrx_worker);
if (ret)
goto error;

- ret = mt76_worker_setup(mt76_hw(dev), &mdev->sdio.txrx_worker,
- mt7663s_txrx_worker, "sdio-txrx");
+ ret = mt76s_alloc_queues(&dev->mt76);
if (ret)
goto error;

- sched_set_fifo_low(mdev->sdio.txrx_worker.task);
-
ret = mt7663_usb_sdio_register_device(dev);
if (ret)
goto error;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.h b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.h
deleted file mode 100644
index 03877d89e152..000000000000
--- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/* SPDX-License-Identifier: ISC */
-/* Copyright (C) 2020 MediaTek Inc.
- *
- * Author: Sean Wang <[email protected]>
- */
-
-#ifndef __MT76S_H
-#define __MT76S_H
-
-#define MT_PSE_PAGE_SZ 128
-
-#define MCR_WCIR 0x0000
-#define MCR_WHLPCR 0x0004
-#define WHLPCR_FW_OWN_REQ_CLR BIT(9)
-#define WHLPCR_FW_OWN_REQ_SET BIT(8)
-#define WHLPCR_IS_DRIVER_OWN BIT(8)
-#define WHLPCR_INT_EN_CLR BIT(1)
-#define WHLPCR_INT_EN_SET BIT(0)
-
-#define MCR_WSDIOCSR 0x0008
-#define MCR_WHCR 0x000C
-#define W_INT_CLR_CTRL BIT(1)
-#define RECV_MAILBOX_RD_CLR_EN BIT(2)
-#define MAX_HIF_RX_LEN_NUM GENMASK(13, 8)
-#define RX_ENHANCE_MODE BIT(16)
-
-#define MCR_WHISR 0x0010
-#define MCR_WHIER 0x0014
-#define WHIER_D2H_SW_INT GENMASK(31, 8)
-#define WHIER_FW_OWN_BACK_INT_EN BIT(7)
-#define WHIER_ABNORMAL_INT_EN BIT(6)
-#define WHIER_RX1_DONE_INT_EN BIT(2)
-#define WHIER_RX0_DONE_INT_EN BIT(1)
-#define WHIER_TX_DONE_INT_EN BIT(0)
-#define WHIER_DEFAULT (WHIER_RX0_DONE_INT_EN | \
- WHIER_RX1_DONE_INT_EN | \
- WHIER_TX_DONE_INT_EN | \
- WHIER_ABNORMAL_INT_EN | \
- WHIER_D2H_SW_INT)
-
-#define MCR_WASR 0x0020
-#define MCR_WSICR 0x0024
-#define MCR_WTSR0 0x0028
-#define TQ0_CNT GENMASK(7, 0)
-#define TQ1_CNT GENMASK(15, 8)
-#define TQ2_CNT GENMASK(23, 16)
-#define TQ3_CNT GENMASK(31, 24)
-
-#define MCR_WTSR1 0x002c
-#define TQ4_CNT GENMASK(7, 0)
-#define TQ5_CNT GENMASK(15, 8)
-#define TQ6_CNT GENMASK(23, 16)
-#define TQ7_CNT GENMASK(31, 24)
-
-#define MCR_WTDR1 0x0034
-#define MCR_WRDR0 0x0050
-#define MCR_WRDR1 0x0054
-#define MCR_WRDR(p) (0x0050 + 4 * (p))
-#define MCR_H2DSM0R 0x0070
-#define H2D_SW_INT_READ BIT(16)
-#define H2D_SW_INT_WRITE BIT(17)
-
-#define MCR_H2DSM1R 0x0074
-#define MCR_D2HRM0R 0x0078
-#define MCR_D2HRM1R 0x007c
-#define MCR_D2HRM2R 0x0080
-#define MCR_WRPLR 0x0090
-#define RX0_PACKET_LENGTH GENMASK(15, 0)
-#define RX1_PACKET_LENGTH GENMASK(31, 16)
-
-#define MCR_WTMDR 0x00b0
-#define MCR_WTMCR 0x00b4
-#define MCR_WTMDPCR0 0x00b8
-#define MCR_WTMDPCR1 0x00bc
-#define MCR_WPLRCR 0x00d4
-#define MCR_WSR 0x00D8
-#define MCR_CLKIOCR 0x0100
-#define MCR_CMDIOCR 0x0104
-#define MCR_DAT0IOCR 0x0108
-#define MCR_DAT1IOCR 0x010C
-#define MCR_DAT2IOCR 0x0110
-#define MCR_DAT3IOCR 0x0114
-#define MCR_CLKDLYCR 0x0118
-#define MCR_CMDDLYCR 0x011C
-#define MCR_ODATDLYCR 0x0120
-#define MCR_IDATDLYCR1 0x0124
-#define MCR_IDATDLYCR2 0x0128
-#define MCR_ILCHCR 0x012C
-#define MCR_WTQCR0 0x0130
-#define MCR_WTQCR1 0x0134
-#define MCR_WTQCR2 0x0138
-#define MCR_WTQCR3 0x013C
-#define MCR_WTQCR4 0x0140
-#define MCR_WTQCR5 0x0144
-#define MCR_WTQCR6 0x0148
-#define MCR_WTQCR7 0x014C
-#define MCR_WTQCR(x) (0x130 + 4 * (x))
-#define TXQ_CNT_L GENMASK(15, 0)
-#define TXQ_CNT_H GENMASK(31, 16)
-
-#define MCR_SWPCDBGR 0x0154
-
-struct mt76s_intr {
- u32 isr;
- struct {
- u32 wtqcr[8];
- } tx;
- struct {
- u16 num[2];
- u16 len[2][16];
- } rx;
- u32 rec_mb[2];
-} __packed;
-
-#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c
index 77e6a57b2dc0..a7cb7cc373b7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c
@@ -14,7 +14,7 @@
#include "mac.h"
#include "mcu.h"
#include "regs.h"
-#include "sdio.h"
+#include "../mt76_connac_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(mt76_connac_sdio_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(mt76_connac_sdio_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");
@@ -137,8 +137,6 @@ 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,
};
struct mt7615_mcu_ops *mcu_ops;
int ret;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c
deleted file mode 100644
index 04f4c89b7499..000000000000
--- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c
+++ /dev/null
@@ -1,334 +0,0 @@
-// SPDX-License-Identifier: ISC
-/* Copyright (C) 2020 MediaTek Inc.
- *
- * Author: Felix Fietkau <[email protected]>
- * Lorenzo Bianconi <[email protected]>
- * Sean Wang <[email protected]>
- */
-
-#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 "../trace.h"
-#include "mt7615.h"
-#include "sdio.h"
-#include "mac.h"
-
-static int mt7663s_refill_sched_quota(struct mt76_dev *dev, u32 *data)
-{
- u32 ple_ac_data_quota[] = {
- FIELD_GET(TXQ_CNT_L, data[4]), /* VO */
- FIELD_GET(TXQ_CNT_H, data[3]), /* VI */
- FIELD_GET(TXQ_CNT_L, data[3]), /* BE */
- FIELD_GET(TXQ_CNT_H, data[2]), /* BK */
- };
- u32 pse_ac_data_quota[] = {
- FIELD_GET(TXQ_CNT_H, data[1]), /* VO */
- FIELD_GET(TXQ_CNT_L, data[1]), /* VI */
- FIELD_GET(TXQ_CNT_H, data[0]), /* BE */
- FIELD_GET(TXQ_CNT_L, data[0]), /* BK */
- };
- u32 pse_mcu_quota = FIELD_GET(TXQ_CNT_L, data[2]);
- u32 pse_data_quota = 0, ple_data_quota = 0;
- struct mt76_sdio *sdio = &dev->sdio;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(pse_ac_data_quota); i++) {
- pse_data_quota += pse_ac_data_quota[i];
- ple_data_quota += ple_ac_data_quota[i];
- }
-
- if (!pse_data_quota && !ple_data_quota && !pse_mcu_quota)
- return 0;
-
- sdio->sched.pse_mcu_quota += pse_mcu_quota;
- sdio->sched.pse_data_quota += pse_data_quota;
- sdio->sched.ple_data_quota += ple_data_quota;
-
- 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)
-{
- int len = min_t(int, data_len, MT_SKB_HEAD_LEN);
- struct sk_buff *skb;
-
- skb = alloc_skb(len, GFP_KERNEL);
- if (!skb)
- return NULL;
-
- skb_put_data(skb, data, len);
- if (data_len > len) {
- struct page *page;
-
- data += len;
- page = virt_to_head_page(data);
- skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
- page, data - page_address(page),
- data_len - len, buf_len);
- get_page(page);
- }
-
- return skb;
-}
-
-static int mt7663s_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;
- int len = 0, err, i;
- struct page *page;
- u8 *buf;
-
- for (i = 0; i < intr->rx.num[qid]; i++)
- len += round_up(intr->rx.len[qid][i] + 4, 4);
-
- if (!len)
- return 0;
-
- if (len > sdio->func->cur_blksize)
- len = roundup(len, sdio->func->cur_blksize);
-
- page = __dev_alloc_pages(GFP_KERNEL, get_order(len));
- if (!page)
- return -ENOMEM;
-
- buf = page_address(page);
-
- err = sdio_readsb(sdio->func, buf, MCR_WRDR(qid), len);
- if (err < 0) {
- dev_err(dev->dev, "sdio read data failed:%d\n", err);
- put_page(page);
- return err;
- }
-
- for (i = 0; i < intr->rx.num[qid]; i++) {
- int index = (q->head + i) % q->ndesc;
- 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));
- if (!e->skb)
- break;
-
- buf += round_up(len + 4, 4);
- if (q->queued + i + 1 == q->ndesc)
- break;
- }
- put_page(page);
-
- spin_lock_bh(&q->lock);
- q->head = (q->head + i) % q->ndesc;
- q->queued += i;
- spin_unlock_bh(&q->lock);
-
- return i;
-}
-
-static int mt7663s_rx_handler(struct mt76_dev *dev)
-{
- struct mt76_sdio *sdio = &dev->sdio;
- struct mt76s_intr *intr = sdio->intr_data;
- int nframes = 0, ret;
-
- ret = sdio_readsb(sdio->func, intr, MCR_WHISR, sizeof(*intr));
- if (ret < 0)
- return ret;
-
- trace_dev_irq(dev, intr->isr, 0);
-
- if (intr->isr & WHIER_RX0_DONE_INT_EN) {
- ret = mt7663s_rx_run_queue(dev, 0, intr);
- if (ret > 0) {
- mt76_worker_schedule(&sdio->net_worker);
- nframes += ret;
- }
- }
-
- if (intr->isr & WHIER_RX1_DONE_INT_EN) {
- ret = mt7663s_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);
-
- return nframes;
-}
-
-static int mt7663s_tx_pick_quota(struct mt76_sdio *sdio, bool mcu, int buf_sz,
- int *pse_size, int *ple_size)
-{
- int pse_sz;
-
- pse_sz = DIV_ROUND_UP(buf_sz + sdio->sched.deficit, MT_PSE_PAGE_SZ);
-
- if (mcu) {
- if (sdio->sched.pse_mcu_quota < *pse_size + pse_sz)
- return -EBUSY;
- } else {
- if (sdio->sched.pse_data_quota < *pse_size + pse_sz ||
- sdio->sched.ple_data_quota < *ple_size + 1)
- return -EBUSY;
-
- *ple_size = *ple_size + 1;
- }
- *pse_size = *pse_size + pse_sz;
-
- return 0;
-}
-
-static void mt7663s_tx_update_quota(struct mt76_sdio *sdio, bool mcu,
- int pse_size, int ple_size)
-{
- if (mcu) {
- sdio->sched.pse_mcu_quota -= pse_size;
- } else {
- sdio->sched.pse_data_quota -= pse_size;
- sdio->sched.ple_data_quota -= ple_size;
- }
-}
-
-static int __mt7663s_xmit_queue(struct mt76_dev *dev, u8 *data, int len)
-{
- struct mt76_sdio *sdio = &dev->sdio;
- int err;
-
- if (len > sdio->func->cur_blksize)
- len = roundup(len, sdio->func->cur_blksize);
-
- err = sdio_writesb(sdio->func, MCR_WTDR1, data, len);
- if (err)
- dev_err(dev->dev, "sdio write failed: %d\n", err);
-
- return err;
-}
-
-static int mt7663s_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];
- struct mt76_sdio *sdio = &dev->sdio;
- u8 pad;
-
- qid = mcu ? ARRAY_SIZE(sdio->xmit_buf) - 1 : q->qid;
- while (q->first != q->head) {
- struct mt76_queue_entry *e = &q->entry[q->first];
- struct sk_buff *iter;
-
- smp_rmb();
-
- 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);
- if (err)
- return err;
-
- goto next;
- }
-
- pad = roundup(e->skb->len, 4) - e->skb->len;
- 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))
- break;
-
- memcpy(sdio->xmit_buf[qid] + len, e->skb->data,
- skb_headlen(e->skb));
- len += skb_headlen(e->skb);
- nframes++;
-
- skb_walk_frags(e->skb, iter) {
- memcpy(sdio->xmit_buf[qid] + len, iter->data,
- iter->len);
- len += iter->len;
- nframes++;
- }
-
- if (unlikely(pad)) {
- memset(sdio->xmit_buf[qid] + len, 0, pad);
- len += pad;
- }
-next:
- q->first = (q->first + 1) % q->ndesc;
- e->done = true;
- }
-
- if (nframes) {
- memset(sdio->xmit_buf[qid] + len, 0, 4);
- err = __mt7663s_xmit_queue(dev, sdio->xmit_buf[qid], len + 4);
- if (err)
- return err;
- }
- mt7663s_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)
-{
- 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);
- 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);
-
- do {
- nframes = 0;
-
- /* tx */
- for (i = 0; i <= MT_TXQ_PSD; i++) {
- ret = mt7663s_tx_run_queue(mdev, mdev->phy.q_tx[i]);
- if (ret > 0)
- nframes += ret;
- }
- ret = mt7663s_tx_run_queue(mdev, mdev->q_mcu[MT_MCUQ_WM]);
- if (ret > 0)
- nframes += ret;
-
- /* rx */
- ret = mt7663s_rx_handler(mdev);
- if (ret > 0)
- nframes += ret;
- } while (nframes > 0);
-
- /* 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);
-}
-
-void mt7663s_sdio_irq(struct sdio_func *func)
-{
- struct mt7615_dev *dev = sdio_get_drvdata(func);
- struct mt76_sdio *sdio = &dev->mt76.sdio;
-
- if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.phy.state))
- return;
-
- mt76_worker_schedule(&sdio->txrx_worker);
-}
--
2.25.1

2021-09-15 01:25:50

by Sean Wang

[permalink] [raw]
Subject: [PATCH v1 13/16] 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]>
Signed-off-by: Sean Wang <[email protected]>
---
.../wireless/mediatek/mt76/mt7615/sdio_mcu.c | 1 +
.../mediatek/mt76/mt76_connac_sdio_txrx.c | 3 +-
.../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 --
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 a7cb7cc373b7..da53bd5cc533 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/mt76_connac_sdio_txrx.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio_txrx.c
index c6a9d8fb4295..22a8058a1705 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio_txrx.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio_txrx.c
@@ -212,7 +212,8 @@ static int mt76_connac_sdio_tx_pick_quota(struct mt76_sdio *sdio, bool mcu,
{
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;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile
index 32f87d946bc7..983d40fb3fb6 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 pci_init.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 8e49df20a8cb..b3e257594f92 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -911,10 +911,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 60f4552cb212..bd52e39e8181 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);
--
2.25.1

2021-09-15 01:25:51

by Sean Wang

[permalink] [raw]
Subject: [PATCH v1 10/16] mt76: mt7921: use physical addr to unify register access

From: Sean Wang <[email protected]>

Use physical address to unify the register access and reorder the
entries in fixed_map table to accelerate the address lookup for
MT7921e.

Tested-by: Deren Wu <[email protected]>
Signed-off-by: Sean Wang <[email protected]>
---
.../net/wireless/mediatek/mt76/mt7921/dma.c | 19 ++++++++--------
.../net/wireless/mediatek/mt76/mt7921/regs.h | 22 +++++++++----------
2 files changed, 21 insertions(+), 20 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
index be24241fb8e6..f31c4aef8b27 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
@@ -85,6 +85,14 @@ static u32 __mt7921_reg_addr(struct mt7921_dev *dev, u32 addr)
u32 mapped;
u32 size;
} fixed_map[] = {
+ { 0x820d0000, 0x30000, 0x10000 }, /* WF_LMAC_TOP (WF_WTBLON) */
+ { 0x820ed000, 0x24800, 0x0800 }, /* WF_LMAC_TOP BN0 (WF_MIB) */
+ { 0x820e4000, 0x21000, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_TMAC) */
+ { 0x820e7000, 0x21e00, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_DMA) */
+ { 0x820eb000, 0x24200, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_LPON) */
+ { 0x820e2000, 0x20800, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_AGG) */
+ { 0x820e3000, 0x20c00, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_ARB) */
+ { 0x820e5000, 0x21400, 0x0800 }, /* WF_LMAC_TOP BN0 (WF_RMAC) */
{ 0x00400000, 0x80000, 0x10000}, /* WF_MCU_SYSRAM */
{ 0x00410000, 0x90000, 0x10000}, /* WF_MCU_SYSRAM (configure register) */
{ 0x40000000, 0x70000, 0x10000}, /* WF_UMAC_SYSRAM */
@@ -99,22 +107,15 @@ static u32 __mt7921_reg_addr(struct mt7921_dev *dev, u32 addr)
{ 0x81020000, 0xc0000, 0x10000 }, /* WF_TOP_MISC_ON */
{ 0x820c0000, 0x08000, 0x4000 }, /* WF_UMAC_TOP (PLE) */
{ 0x820c8000, 0x0c000, 0x2000 }, /* WF_UMAC_TOP (PSE) */
- { 0x820cc000, 0x0e000, 0x2000 }, /* WF_UMAC_TOP (PP) */
+ { 0x820cc000, 0x0e000, 0x1000 }, /* WF_UMAC_TOP (PP) */
+ { 0x820cd000, 0x0f000, 0x1000 }, /* WF_MDP_TOP */
{ 0x820ce000, 0x21c00, 0x0200 }, /* WF_LMAC_TOP (WF_SEC) */
{ 0x820cf000, 0x22000, 0x1000 }, /* WF_LMAC_TOP (WF_PF) */
- { 0x820d0000, 0x30000, 0x10000 }, /* WF_LMAC_TOP (WF_WTBLON) */
{ 0x820e0000, 0x20000, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_CFG) */
{ 0x820e1000, 0x20400, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_TRB) */
- { 0x820e2000, 0x20800, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_AGG) */
- { 0x820e3000, 0x20c00, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_ARB) */
- { 0x820e4000, 0x21000, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_TMAC) */
- { 0x820e5000, 0x21400, 0x0800 }, /* WF_LMAC_TOP BN0 (WF_RMAC) */
- { 0x820e7000, 0x21e00, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_DMA) */
{ 0x820e9000, 0x23400, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_WTBLOFF) */
{ 0x820ea000, 0x24000, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_ETBF) */
- { 0x820eb000, 0x24200, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_LPON) */
{ 0x820ec000, 0x24600, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_INT) */
- { 0x820ed000, 0x24800, 0x0800 }, /* WF_LMAC_TOP BN0 (WF_MIB) */
{ 0x820f0000, 0xa0000, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_CFG) */
{ 0x820f1000, 0xa0600, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_TRB) */
{ 0x820f2000, 0xa0800, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_AGG) */
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regs.h b/drivers/net/wireless/mediatek/mt76/mt7921/regs.h
index 26fb11823762..cb6069024320 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/regs.h
@@ -14,7 +14,7 @@
#define MT_MCU_INT_EVENT_SER_TRIGGER BIT(2)
#define MT_MCU_INT_EVENT_RESET_DONE BIT(3)

-#define MT_PLE_BASE 0x8000
+#define MT_PLE_BASE 0x820c0000
#define MT_PLE(ofs) (MT_PLE_BASE + (ofs))

#define MT_PLE_FL_Q0_CTRL MT_PLE(0x1b0)
@@ -26,7 +26,7 @@
((n) << 2))
#define MT_PLE_AMSDU_PACK_MSDU_CNT(n) MT_PLE(0x10e0 + ((n) << 2))

-#define MT_MDP_BASE 0xf000
+#define MT_MDP_BASE 0x820cd000
#define MT_MDP(ofs) (MT_MDP_BASE + (ofs))

#define MT_MDP_DCR0 MT_MDP(0x000)
@@ -49,7 +49,7 @@
#define MT_MDP_TO_WM 1

/* TMAC: band 0(0x21000), band 1(0xa1000) */
-#define MT_WF_TMAC_BASE(_band) ((_band) ? 0xa1000 : 0x21000)
+#define MT_WF_TMAC_BASE(_band) ((_band) ? 0x820f4000 : 0x820e4000)
#define MT_WF_TMAC(_band, ofs) (MT_WF_TMAC_BASE(_band) + (ofs))

#define MT_TMAC_TCR0(_band) MT_WF_TMAC(_band, 0)
@@ -74,7 +74,7 @@
#define MT_TMAC_TRCR0(_band) MT_WF_TMAC(_band, 0x09c)
#define MT_TMAC_TFCR0(_band) MT_WF_TMAC(_band, 0x1e0)

-#define MT_WF_DMA_BASE(_band) ((_band) ? 0xa1e00 : 0x21e00)
+#define MT_WF_DMA_BASE(_band) ((_band) ? 0x820f7000 : 0x820e7000)
#define MT_WF_DMA(_band, ofs) (MT_WF_DMA_BASE(_band) + (ofs))

#define MT_DMA_DCR0(_band) MT_WF_DMA(_band, 0x000)
@@ -82,7 +82,7 @@
#define MT_DMA_DCR0_RXD_G5_EN BIT(23)

/* LPON: band 0(0x24200), band 1(0xa4200) */
-#define MT_WF_LPON_BASE(_band) ((_band) ? 0xa4200 : 0x24200)
+#define MT_WF_LPON_BASE(_band) ((_band) ? 0x820fb000 : 0x820eb000)
#define MT_WF_LPON(_band, ofs) (MT_WF_LPON_BASE(_band) + (ofs))

#define MT_LPON_UTTR0(_band) MT_WF_LPON(_band, 0x080)
@@ -93,7 +93,7 @@
#define MT_LPON_TCR_SW_WRITE BIT(0)

/* MIB: band 0(0x24800), band 1(0xa4800) */
-#define MT_WF_MIB_BASE(_band) ((_band) ? 0xa4800 : 0x24800)
+#define MT_WF_MIB_BASE(_band) ((_band) ? 0x820fd000 : 0x820ed000)
#define MT_WF_MIB(_band, ofs) (MT_WF_MIB_BASE(_band) + (ofs))

#define MT_MIB_SCR1(_band) MT_WF_MIB(_band, 0x004)
@@ -142,7 +142,7 @@
#define MT_MIB_ARNG(_band, n) MT_WF_MIB(_band, 0x0b0 + ((n) << 2))
#define MT_MIB_ARNCR_RANGE(val, n) (((val) >> ((n) << 3)) & GENMASK(7, 0))

-#define MT_WTBLON_TOP_BASE 0x34000
+#define MT_WTBLON_TOP_BASE 0x820d4000
#define MT_WTBLON_TOP(ofs) (MT_WTBLON_TOP_BASE + (ofs))
#define MT_WTBLON_TOP_WDUCR MT_WTBLON_TOP(0x200)
#define MT_WTBLON_TOP_WDUCR_GROUP GENMASK(2, 0)
@@ -152,7 +152,7 @@
#define MT_WTBL_UPDATE_ADM_COUNT_CLEAR BIT(12)
#define MT_WTBL_UPDATE_BUSY BIT(31)

-#define MT_WTBL_BASE 0x38000
+#define MT_WTBL_BASE 0x820d8000
#define MT_WTBL_LMAC_ID GENMASK(14, 8)
#define MT_WTBL_LMAC_DW GENMASK(7, 2)
#define MT_WTBL_LMAC_OFFS(_id, _dw) (MT_WTBL_BASE | \
@@ -160,7 +160,7 @@
FIELD_PREP(MT_WTBL_LMAC_DW, _dw))

/* AGG: band 0(0x20800), band 1(0xa0800) */
-#define MT_WF_AGG_BASE(_band) ((_band) ? 0xa0800 : 0x20800)
+#define MT_WF_AGG_BASE(_band) ((_band) ? 0x820f2000 : 0x820e2000)
#define MT_WF_AGG(_band, ofs) (MT_WF_AGG_BASE(_band) + (ofs))

#define MT_AGG_AWSCR0(_band, _n) MT_WF_AGG(_band, 0x05c + (_n) * 4)
@@ -191,7 +191,7 @@
#define MT_AGG_ATCR3(_band) MT_WF_AGG(_band, 0x0f4)

/* ARB: band 0(0x20c00), band 1(0xa0c00) */
-#define MT_WF_ARB_BASE(_band) ((_band) ? 0xa0c00 : 0x20c00)
+#define MT_WF_ARB_BASE(_band) ((_band) ? 0x820f3000 : 0x820e3000)
#define MT_WF_ARB(_band, ofs) (MT_WF_ARB_BASE(_band) + (ofs))

#define MT_ARB_SCR(_band) MT_WF_ARB(_band, 0x080)
@@ -201,7 +201,7 @@
#define MT_ARB_DRNGR0(_band, _n) MT_WF_ARB(_band, 0x194 + (_n) * 4)

/* RMAC: band 0(0x21400), band 1(0xa1400) */
-#define MT_WF_RMAC_BASE(_band) ((_band) ? 0xa1400 : 0x21400)
+#define MT_WF_RMAC_BASE(_band) ((_band) ? 0x820f5000 : 0x820e5000)
#define MT_WF_RMAC(_band, ofs) (MT_WF_RMAC_BASE(_band) + (ofs))

#define MT_WF_RFCR(_band) MT_WF_RMAC(_band, 0x000)
--
2.25.1

2021-09-15 01:26:18

by Sean Wang

[permalink] [raw]
Subject: [PATCH v1 15/16] 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]>
Signed-off-by: Sean Wang <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mcu.c | 8 +-
.../net/wireless/mediatek/mt76/mt7921/Kconfig | 11 +
.../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 | 2 +-
.../wireless/mediatek/mt76/mt7921/mt7921.h | 31 +++
.../net/wireless/mediatek/mt76/mt7921/sdio.c | 259 ++++++++++++++++++
.../wireless/mediatek/mt76/mt7921/sdio_init.c | 22 ++
.../wireless/mediatek/mt76/mt7921/sdio_mac.c | 88 ++++++
.../wireless/mediatek/mt76/mt7921/sdio_mcu.c | 125 +++++++++
13 files changed, 590 insertions(+), 13 deletions(-)
create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/sdio.c
create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/sdio_init.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/mcu.c b/drivers/net/wireless/mediatek/mt76/mcu.c
index d3a5e2c4f12a..e174b8eb58e7 100644
--- a/drivers/net/wireless/mediatek/mt76/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mcu.c
@@ -4,6 +4,7 @@
*/

#include "mt76.h"
+#include "mt76_connac.h"

struct sk_buff *
mt76_mcu_msg_alloc(struct mt76_dev *dev, const void *data,
@@ -109,10 +110,13 @@ EXPORT_SYMBOL_GPL(mt76_mcu_skb_send_and_get_msg);
int mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const void *data,
int len)
{
- int err, cur_len;
+ int err, cur_len, max_len = 4096 - dev->mcu_ops->headroom;
+
+ if (is_mt7921(dev) && mt76_is_sdio(dev))
+ max_len = 2048;

while (len > 0) {
- cur_len = min_t(int, 4096 - dev->mcu_ops->headroom, len);
+ cur_len = min_t(int, max_len, len);

err = mt76_mcu_send_msg(dev, cmd, data, cur_len, false);
if (err)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig
index 071746809b1c..705215e71cdc 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig
@@ -13,3 +13,14 @@ 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 MT76_CONNAC_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 983d40fb3fb6..68117a20dd44 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 pci_init.o dma.o
+mt7921s-y := sdio.o sdio_mac.o sdio_mcu.o sdio_init.o
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
index 11f8acf4f59e..0bb413615331 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 0cb6dc118711..08c3099c682b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
@@ -848,6 +848,8 @@ 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;
@@ -863,15 +865,15 @@ 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);
@@ -1390,12 +1392,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 2de5a2ba43b2..e20bfa5f05c4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -856,7 +856,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 01c356b315ec..a94baa024e3c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
@@ -47,6 +47,16 @@
#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,
+};
+
#define to_rssi(field, rxv) ((FIELD_GET(field, rxv) - 220) / 2)
#define to_rcpi(rssi) (2 * (rssi) + 220)

@@ -315,6 +325,17 @@ 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_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);
@@ -390,4 +411,14 @@ int mt7921e_mcu_drv_pmctrl(struct mt7921_dev *dev);
int mt7921e_mcu_fw_pmctrl(struct mt7921_dev *dev);
int mt7921e_init_reset(struct mt7921_dev *dev);

+int mt7921s_mcu_init(struct mt7921_dev *dev);
+void mt7921s_unregister_device(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..786025360fcb
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c
@@ -0,0 +1,259 @@
+// 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 "../mt76_connac_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;
+ }
+
+ mt76_connac_sdio_txrx(mdev);
+
+ mt76_connac_pm_unref(&dev->mphy, &dev->pm);
+}
+
+static void mt7921s_irq(struct sdio_func *func)
+{
+ struct mt7921_dev *dev = sdio_get_drvdata(func);
+ struct mt76_sdio *sdio = &dev->mt76.sdio;
+
+ if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.phy.state))
+ return;
+
+ mt76_worker_schedule(&sdio->txrx_worker);
+}
+
+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 = mt76_connac_sdio_rr,
+ .rmw = mt76_connac_sdio_rmw,
+ .wr = mt76_connac_sdio_wr,
+ .write_copy = mt76_connac_sdio_write_copy,
+ .read_copy = mt76_connac_sdio_read_copy,
+ .wr_rp = mt76_connac_sdio_wr_rp,
+ .rd_rp = mt76_connac_sdio_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;
+
+ 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 = mt76_connac_sdio_hw_init(mdev, func, MT76_CONNAC2_SDIO,
+ mt7921s_irq);
+ 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);
+
+ ret = mt76_connac_sdio_init(mdev, mt7921s_txrx_worker);
+ if (ret)
+ goto error;
+
+ ret = mt76s_alloc_queues(&dev->mt76);
+ if (ret)
+ goto error;
+
+ 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_init.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_init.c
new file mode 100644
index 000000000000..2ede48efa989
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_init.c
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2021 MediaTek Inc. */
+
+#include <linux/etherdevice.h>
+#include "mt7921.h"
+#include "mac.h"
+#include "mcu.h"
+#include "eeprom.h"
+
+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);
+}
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..4d53a9281a75
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c
@@ -0,0 +1,88 @@
+// 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"
+#include "../mt76_connac_sdio.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..12cb7e8bb9f0
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c
@@ -0,0 +1,125 @@
+// 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 "../mt76_connac_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,
+ };
+ 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(mt76_connac_sdio_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(mt76_connac_sdio_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

2021-09-15 01:27:05

by Sean Wang

[permalink] [raw]
Subject: [PATCH v1 11/16] mt76: connac: extend mt76_connac_sdio module to support CONNAC2

From: Sean Wang <[email protected]>

Extend mt76_connac_sdio module to support CONNAC2 hw that mt7921s rely on.

Tested-by: Deren Wu <[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/mt7615/sdio.c | 3 +-
.../wireless/mediatek/mt76/mt76_connac_sdio.c | 34 ++++++++--
.../wireless/mediatek/mt76/mt76_connac_sdio.h | 52 ++++++++++++++-
.../mediatek/mt76/mt76_connac_sdio_txrx.c | 63 ++++++++++++++++---
5 files changed, 137 insertions(+), 17 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index e76fb04de047..58fd0c7831f4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -505,6 +505,8 @@ struct mt76_sdio {

struct sdio_func *func;
void *intr_data;
+ int intr_size;
+ u8 hw_ver;

struct {
int pse_data_quota;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c
index 97660262b2de..4506c9ff319e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c
@@ -113,7 +113,8 @@ static int mt7663s_probe(struct sdio_func *func,
if (ret < 0)
goto error;

- ret = mt76_connac_sdio_hw_init(mdev, func, mt7663s_irq);
+ ret = mt76_connac_sdio_hw_init(mdev, func, MT76_CONNAC_SDIO,
+ mt7663s_irq);
if (ret)
goto error;

diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.c
index d18a66e5445f..c11f044841dd 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.c
@@ -221,11 +221,13 @@ int mt76_connac_sdio_rd_rp(struct mt76_dev *dev, u32 base,
EXPORT_SYMBOL_GPL(mt76_connac_sdio_rd_rp);

int mt76_connac_sdio_hw_init(struct mt76_dev *dev, struct sdio_func *func,
- sdio_irq_handler_t *irq_handler)
+ int hw_ver, sdio_irq_handler_t *irq_handler)
{
u32 status, ctrl;
int ret;

+ dev->sdio.hw_ver = hw_ver;
+
sdio_claim_host(func);

ret = sdio_enable_func(func);
@@ -255,12 +257,27 @@ int mt76_connac_sdio_hw_init(struct mt76_dev *dev, struct sdio_func *func,
goto disable_func;

ctrl = WHIER_RX0_DONE_INT_EN | WHIER_TX_DONE_INT_EN;
+ if (hw_ver == MT76_CONNAC2_SDIO)
+ ctrl |= WHIER_RX1_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);
+ switch (hw_ver) {
+ case MT76_CONNAC_SDIO:
+ /* set WHISR as read clear and Rx aggregation number as 16 */
+ ctrl = FIELD_PREP(MAX_HIF_RX_LEN_NUM, 16);
+ break;
+ default:
+ ctrl = sdio_readl(func, MCR_WHCR, &ret);
+ if (ret < 0)
+ goto disable_func;
+ ctrl &= ~MAX_HIF_RX_LEN_NUM_CONNAC2;
+ ctrl &= ~W_INT_CLR_CTRL; /* read clear */
+ ctrl |= FIELD_PREP(MAX_HIF_RX_LEN_NUM_CONNAC2, 0);
+ break;
+ }
+
sdio_writel(func, ctrl, MCR_WHCR, &ret);
if (ret < 0)
goto disable_func;
@@ -287,8 +304,17 @@ int mt76_connac_sdio_init(struct mt76_dev *dev,
{
int i, ret;

+ switch (dev->sdio.hw_ver) {
+ case MT76_CONNAC_SDIO:
+ dev->sdio.intr_size = sizeof(struct mt76_connac_sdio_intr);
+ break;
+ default:
+ dev->sdio.intr_size = sizeof(struct mt76_connac2_sdio_intr);
+ break;
+ }
+
dev->sdio.intr_data = devm_kmalloc(dev->dev,
- sizeof(struct mt76s_intr),
+ dev->sdio.intr_size,
GFP_KERNEL);
if (!dev->sdio.intr_data)
return -ENOMEM;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.h
index e176d6e562b2..a476e54361cc 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.h
@@ -21,7 +21,12 @@
#define MCR_WHCR 0x000C
#define W_INT_CLR_CTRL BIT(1)
#define RECV_MAILBOX_RD_CLR_EN BIT(2)
+#define WF_SYS_RSTB BIT(4) /* supported in CONNAC2 */
+#define WF_WHOLE_PATH_RSTB BIT(5) /* supported in CONNAC2 */
+#define WF_SDIO_WF_PATH_RSTB BIT(6) /* supported in CONNAC2 */
#define MAX_HIF_RX_LEN_NUM GENMASK(13, 8)
+#define MAX_HIF_RX_LEN_NUM_CONNAC2 GENMASK(14, 8) /* supported in CONNAC2 */
+#define WF_RST_DONE BIT(15) /* supported in CONNAC2 */
#define RX_ENHANCE_MODE BIT(16)

#define MCR_WHISR 0x0010
@@ -29,6 +34,7 @@
#define WHIER_D2H_SW_INT GENMASK(31, 8)
#define WHIER_FW_OWN_BACK_INT_EN BIT(7)
#define WHIER_ABNORMAL_INT_EN BIT(6)
+#define WHIER_WDT_INT_EN BIT(5) /* supported in CONNAC2 */
#define WHIER_RX1_DONE_INT_EN BIT(2)
#define WHIER_RX0_DONE_INT_EN BIT(1)
#define WHIER_TX_DONE_INT_EN BIT(0)
@@ -100,7 +106,37 @@

#define MCR_SWPCDBGR 0x0154

-struct mt76s_intr {
+#define MCR_H2DSM2R 0x0160 /* supported in CONNAC2 */
+#define MCR_H2DSM3R 0x0164 /* supported in CONNAC2 */
+#define MCR_D2HRM3R 0x0174 /* supported in CONNAC2 */
+#define MCR_WTQCR8 0x0190 /* supported in CONNAC2 */
+#define MCR_WTQCR9 0x0194 /* supported in CONNAC2 */
+#define MCR_WTQCR10 0x0198 /* supported in CONNAC2 */
+#define MCR_WTQCR11 0x019C /* supported in CONNAC2 */
+#define MCR_WTQCR12 0x01A0 /* supported in CONNAC2 */
+#define MCR_WTQCR13 0x01A4 /* supported in CONNAC2 */
+#define MCR_WTQCR14 0x01A8 /* supported in CONNAC2 */
+#define MCR_WTQCR15 0x01AC /* supported in CONNAC2 */
+
+enum mt76_connac_sdio_ver {
+ MT76_CONNAC_SDIO,
+ MT76_CONNAC2_SDIO,
+};
+
+struct mt76_connac2_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;
+
+struct mt76_connac_sdio_intr {
u32 isr;
struct {
u32 wtqcr[8];
@@ -112,6 +148,18 @@ struct mt76s_intr {
u32 rec_mb[2];
} __packed;

+struct mt76s_intr {
+ u32 isr;
+ struct {
+ u32 *wtqcr;
+ } tx;
+ struct {
+ u16 num[2];
+ u16 *len[2];
+ } rx;
+ u32 rec_mb[2];
+};
+
u32 mt76_connac_sdio_read_pcr(struct mt76_dev *dev);
u32 mt76_connac_sdio_read_mailbox(struct mt76_dev *dev, u32 offset);
void mt76_connac_sdio_write_mailbox(struct mt76_dev *dev, u32 offset, u32 val);
@@ -131,7 +179,7 @@ int mt76_connac_sdio_rd_rp(struct mt76_dev *dev, u32 base,

void mt76_connac_sdio_txrx(struct mt76_dev *dev);
int mt76_connac_sdio_hw_init(struct mt76_dev *dev, struct sdio_func *func,
- sdio_irq_handler_t *irq_handler);
+ int hw_ver, sdio_irq_handler_t *irq_handler);
int mt76_connac_sdio_init(struct mt76_dev *dev,
void (*txrx_worker)(struct mt76_worker *));
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio_txrx.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio_txrx.c
index 3ef42f90f3f5..c6a9d8fb4295 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio_txrx.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio_txrx.c
@@ -81,7 +81,7 @@ static int mt76_connac_sdio_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_queue *q = &dev->q_rx[0];
struct mt76_sdio *sdio = &dev->sdio;
int len = 0, err, i;
struct page *page;
@@ -112,8 +112,10 @@ static int mt76_connac_sdio_rx_run_queue(struct mt76_dev *dev,
for (i = 0; i < intr->rx.num[qid]; i++) {
int index = (q->head + i) % q->ndesc;
struct mt76_queue_entry *e = &q->entry[index];
+ __le32 *rxd = (__le32 *)buf;

- len = intr->rx.len[qid][i];
+ /* parse rxd to get the actual packet length */
+ len = FIELD_GET(GENMASK(15, 0), le32_to_cpu(rxd[0]));
e->skb = mt76_connac_sdio_build_rx_skb(buf, len,
round_up(len + 4, 4));
if (!e->skb)
@@ -133,35 +135,73 @@ static int mt76_connac_sdio_rx_run_queue(struct mt76_dev *dev,
return i;
}

+static void mt76_connac_sdio_intr_parse(struct mt76_dev *dev,
+ void *data,
+ struct mt76s_intr *intr)
+{
+ struct mt76_connac_sdio_intr *intr_v1;
+ struct mt76_connac2_sdio_intr *intr_v2;
+ int i;
+
+ switch (dev->sdio.hw_ver) {
+ case MT76_CONNAC_SDIO:
+ intr_v1 = data;
+ intr->isr = intr_v1->isr;
+ intr->tx.wtqcr = intr_v1->tx.wtqcr;
+ for (i = 0; i < 2 ; i++) {
+ intr->rx.num[i] = intr_v1->rx.num[i];
+ intr->rx.len[i] = intr_v1->rx.len[i];
+ intr->rec_mb[i] = intr_v1->rec_mb[i];
+ }
+ break;
+ default:
+ intr_v2 = data;
+ intr->isr = intr_v2->isr;
+ intr->tx.wtqcr = intr_v2->tx.wtqcr;
+ for (i = 0; i < 2 ; i++) {
+ intr->rx.num[i] = intr_v2->rx.num[i];
+ if (!i)
+ intr->rx.len[0] = intr_v2->rx.len0;
+ else
+ intr->rx.len[1] = intr_v2->rx.len1;
+ intr->rec_mb[i] = intr_v2->rec_mb[i];
+ }
+ break;
+ }
+}
+
static int mt76_connac_sdio_rx_handler(struct mt76_dev *dev)
{
struct mt76_sdio *sdio = &dev->sdio;
- struct mt76s_intr *intr = sdio->intr_data;
+ void *data = sdio->intr_data;
+ struct mt76s_intr intr;
int nframes = 0, ret;

- ret = sdio_readsb(sdio->func, intr, MCR_WHISR, sizeof(*intr));
+ ret = sdio_readsb(sdio->func, data, MCR_WHISR, sdio->intr_size);
if (ret < 0)
return ret;

- trace_dev_irq(dev, intr->isr, 0);
+ mt76_connac_sdio_intr_parse(dev, data, &intr);

- if (intr->isr & WHIER_RX0_DONE_INT_EN) {
- ret = mt76_connac_sdio_rx_run_queue(dev, 0, intr);
+ trace_dev_irq(dev, intr.isr, 0);
+
+ if (intr.isr & WHIER_RX0_DONE_INT_EN) {
+ ret = mt76_connac_sdio_rx_run_queue(dev, 0, &intr);
if (ret > 0) {
mt76_worker_schedule(&sdio->net_worker);
nframes += ret;
}
}

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

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

return nframes;
}
@@ -174,6 +214,9 @@ static int mt76_connac_sdio_tx_pick_quota(struct mt76_sdio *sdio, bool mcu,

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

+ if (mcu && sdio->hw_ver == MT76_CONNAC2_SDIO)
+ pse_sz = 1;
+
if (mcu) {
if (sdio->sched.pse_mcu_quota < *pse_size + pse_sz)
return -EBUSY;
--
2.25.1

2021-09-15 01:27:18

by Sean Wang

[permalink] [raw]
Subject: [PATCH v1 16/16] 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]>
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 | 1 +
.../wireless/mediatek/mt76/mt76_connac_sdio.c | 20 +++
.../wireless/mediatek/mt76/mt76_connac_sdio.h | 3 +
.../mediatek/mt76/mt76_connac_sdio_txrx.c | 29 +++++
.../net/wireless/mediatek/mt76/mt7921/init.c | 2 +
.../net/wireless/mediatek/mt76/mt7921/mcu.c | 1 +
.../wireless/mediatek/mt76/mt7921/mt7921.h | 5 +
.../net/wireless/mediatek/mt76/mt7921/sdio.c | 5 +-
.../wireless/mediatek/mt76/mt7921/sdio_init.c | 1 +
.../wireless/mediatek/mt76/mt7921/sdio_mac.c | 114 ++++++++++++++++++
.../wireless/mediatek/mt76/mt7921/sdio_mcu.c | 8 ++
11 files changed, 188 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index 3062cda2e770..a4e09373dcdc 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -507,6 +507,7 @@ struct mt76_sdio {
void *intr_data;
int intr_size;
u8 hw_ver;
+ wait_queue_head_t wait;

struct {
int pse_data_quota;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.c
index c11f044841dd..075557844dfd 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.c
@@ -338,6 +338,26 @@ int mt76_connac_sdio_init(struct mt76_dev *dev,
}
EXPORT_SYMBOL_GPL(mt76_connac_sdio_init);

+void mt76_connac_sdio_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);
+}
+EXPORT_SYMBOL_GPL(mt76_connac_sdio_enable_irq);
+
+void mt76_connac_sdio_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);
+}
+EXPORT_SYMBOL_GPL(mt76_connac_sdio_disable_irq);
+
MODULE_AUTHOR("Sean Wang <[email protected]>");
MODULE_AUTHOR("Lorenzo Bianconi <[email protected]>");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.h
index a476e54361cc..e4395a332cff 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.h
@@ -182,4 +182,7 @@ int mt76_connac_sdio_hw_init(struct mt76_dev *dev, struct sdio_func *func,
int hw_ver, sdio_irq_handler_t *irq_handler);
int mt76_connac_sdio_init(struct mt76_dev *dev,
void (*txrx_worker)(struct mt76_worker *));
+void mt76_connac_sdio_enable_irq(struct mt76_dev *dev);
+void mt76_connac_sdio_disable_irq(struct mt76_dev *dev);
+bool mt76_connac_sdio_txqs_empty(struct mt76_dev *dev);
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio_txrx.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio_txrx.c
index 22a8058a1705..b4b96edfbdb4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio_txrx.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio_txrx.c
@@ -275,6 +275,9 @@ static int mt76_connac_sdio_tx_run_queue(struct mt76_dev *dev,

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 = __mt76_connac_sdio_xmit_queue(dev, e->skb->data,
@@ -327,6 +330,25 @@ static int mt76_connac_sdio_tx_run_queue(struct mt76_dev *dev,
return nframes;
}

+bool mt76_connac_sdio_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(mt76_connac_sdio_txqs_empty);
+
void mt76_connac_sdio_txrx(struct mt76_dev *dev)
{
struct mt76_sdio *sdio = &dev->sdio;
@@ -353,6 +375,13 @@ void mt76_connac_sdio_txrx(struct mt76_dev *dev)
ret = mt76_connac_sdio_rx_handler(dev);
if (ret > 0)
nframes += ret;
+
+ if (test_bit(MT76_MCU_RESET, &dev->phy.state)) {
+ if (!mt76_connac_sdio_txqs_empty(dev))
+ continue;
+ else
+ wake_up(&sdio->wait);
+ }
} while (nframes > 0);

/* enable interrupt */
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 e20bfa5f05c4..d2e2aa6cfb49 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -441,6 +441,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 a94baa024e3c..43e344aa6d97 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
@@ -169,6 +169,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;
@@ -412,6 +413,9 @@ int mt7921e_mcu_fw_pmctrl(struct mt7921_dev *dev);
int mt7921e_init_reset(struct mt7921_dev *dev);

int mt7921s_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);
void mt7921s_unregister_device(struct mt7921_dev *dev);
int mt7921s_mcu_drv_pmctrl(struct mt7921_dev *dev);
int mt7921s_mcu_fw_pmctrl(struct mt7921_dev *dev);
@@ -421,4 +425,5 @@ int mt7921s_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
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
index 786025360fcb..3afc23ff81c4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c
@@ -43,7 +43,8 @@ static void mt7921s_irq(struct sdio_func *func)
struct mt7921_dev *dev = sdio_get_drvdata(func);
struct mt76_sdio *sdio = &dev->mt76.sdio;

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

mt76_worker_schedule(&sdio->txrx_worker);
@@ -78,6 +79,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_init.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_init.c
index 2ede48efa989..d87a4b2dfda2 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_init.c
@@ -16,6 +16,7 @@ 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);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c
index 4d53a9281a75..9c899c11c60f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c
@@ -7,6 +7,120 @@
#include "mac.h"
#include "../mt76_connac_sdio.h"

+static u32 mt7921s_sdio_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_sdio_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,
+ mt76_connac_sdio_txqs_empty(&dev->mt76), 5 * HZ);
+ mt76_worker_disable(&dev->mt76.sdio.txrx_worker);
+
+ mt76_connac_sdio_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);
+ mt76_connac_sdio_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,
+ mt76_connac_sdio_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);
+
+ mt76_connac_sdio_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);
+ mt76_connac_sdio_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,
enum mt76_txq_id qid, struct ieee80211_sta *sta,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c
index 12cb7e8bb9f0..2b5544aa1c16 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;
--
2.25.1

2021-09-15 01:27:19

by Sean Wang

[permalink] [raw]
Subject: [PATCH v1 07/16] mt76: connac: move sdio utility routines in mt76_connac_sdio module

From: Sean Wang <[email protected]>

This is a preliminary patch before introduce mt7921s support to hold the
common sdio utilities between mt7663s and mt7921s in mt76_connac_sdio
module.

mt76/mt76_connac_sdio.c, mt76/mt76_connac_sdio.h and
mt76/mt76_connac_sdio_txrx.c originate from mt7615/sdio.c, mt7615/sdio.h
and mt7615/sdio_txrx.c and the patch don't add any logic change.

Tested-by: Deren Wu <[email protected]>
Signed-off-by: Sean Wang <[email protected]>
---
drivers/net/wireless/mediatek/mt76/Kconfig | 5 +
drivers/net/wireless/mediatek/mt76/Makefile | 2 +
.../wireless/mediatek/mt76/mt76_connac_sdio.c | 317 +++++++++++++++++
.../wireless/mediatek/mt76/mt76_connac_sdio.h | 137 ++++++++
.../mediatek/mt76/mt76_connac_sdio_txrx.c | 318 ++++++++++++++++++
5 files changed, 779 insertions(+)
create mode 100644 drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.c
create mode 100644 drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.h
create mode 100644 drivers/net/wireless/mediatek/mt76/mt76_connac_sdio_txrx.c

diff --git a/drivers/net/wireless/mediatek/mt76/Kconfig b/drivers/net/wireless/mediatek/mt76/Kconfig
index 9ff43f1fc50d..a6b388bfb563 100644
--- a/drivers/net/wireless/mediatek/mt76/Kconfig
+++ b/drivers/net/wireless/mediatek/mt76/Kconfig
@@ -28,6 +28,11 @@ config MT76_CONNAC_LIB
tristate
select MT76_CORE

+config MT76_CONNAC_SDIO
+ tristate
+ depends on MMC
+ select MT76_CONNAC_LIB
+
source "drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig"
source "drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig"
source "drivers/net/wireless/mediatek/mt76/mt7603/Kconfig"
diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile
index 94efe3c29053..17b2ed93f6a3 100644
--- a/drivers/net/wireless/mediatek/mt76/Makefile
+++ b/drivers/net/wireless/mediatek/mt76/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_MT76_SDIO) += mt76-sdio.o
obj-$(CONFIG_MT76x02_LIB) += mt76x02-lib.o
obj-$(CONFIG_MT76x02_USB) += mt76x02-usb.o
obj-$(CONFIG_MT76_CONNAC_LIB) += mt76-connac-lib.o
+obj-$(CONFIG_MT76_CONNAC_SDIO) += mt76-connac-sdio.o

mt76-y := \
mmio.o util.o trace.o dma.o mac80211.o debugfs.o eeprom.o \
@@ -28,6 +29,7 @@ mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o mt76x02_mcu.o \
mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o

mt76-connac-lib-y := mt76_connac_mcu.o mt76_connac_mac.o
+mt76-connac-sdio-y := mt76_connac_sdio.o mt76_connac_sdio_txrx.o

obj-$(CONFIG_MT76x0_COMMON) += mt76x0/
obj-$(CONFIG_MT76x2_COMMON) += mt76x2/
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.c
new file mode 100644
index 000000000000..d18a66e5445f
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.c
@@ -0,0 +1,317 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2020-2021 MediaTek Inc.
+ *
+ * Author: Felix Fietkau <[email protected]>
+ * Lorenzo Bianconi <[email protected]>
+ * Sean Wang <[email protected]>
+ */
+
+#include <linux/iopoll.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sdio_func.h>
+
+#include "mt76.h"
+#include "mt76_connac_mcu.h"
+#include "mt76_connac_sdio.h"
+
+static u32 mt76_connac_sdio_read_whisr(struct mt76_dev *dev)
+{
+ return sdio_readl(dev->sdio.func, MCR_WHISR, NULL);
+}
+
+u32 mt76_connac_sdio_read_pcr(struct mt76_dev *dev)
+{
+ struct mt76_sdio *sdio = &dev->sdio;
+
+ return sdio_readl(sdio->func, MCR_WHLPCR, NULL);
+}
+EXPORT_SYMBOL_GPL(mt76_connac_sdio_read_pcr);
+
+u32 mt76_connac_sdio_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(mt76_connac_sdio_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;
+}
+EXPORT_SYMBOL_GPL(mt76_connac_sdio_read_mailbox);
+
+void mt76_connac_sdio_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(mt76_connac_sdio_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);
+}
+EXPORT_SYMBOL_GPL(mt76_connac_sdio_write_mailbox);
+
+u32 mt76_connac_sdio_rr(struct mt76_dev *dev, u32 offset)
+{
+ if (test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state))
+ return mt76_connac_mcu_reg_rr(dev, offset);
+ else
+ return mt76_connac_sdio_read_mailbox(dev, offset);
+}
+EXPORT_SYMBOL_GPL(mt76_connac_sdio_rr);
+
+void mt76_connac_sdio_wr(struct mt76_dev *dev, u32 offset, u32 val)
+{
+ if (test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state))
+ mt76_connac_mcu_reg_wr(dev, offset, val);
+ else
+ mt76_connac_sdio_write_mailbox(dev, offset, val);
+}
+EXPORT_SYMBOL_GPL(mt76_connac_sdio_wr);
+
+u32 mt76_connac_sdio_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val)
+{
+ val |= mt76_connac_sdio_rr(dev, offset) & ~mask;
+ mt76_connac_sdio_wr(dev, offset, val);
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(mt76_connac_sdio_rmw);
+
+void mt76_connac_sdio_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++) {
+ mt76_connac_sdio_wr(dev, offset, val[i]);
+ offset += sizeof(u32);
+ }
+}
+EXPORT_SYMBOL_GPL(mt76_connac_sdio_write_copy);
+
+void mt76_connac_sdio_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] = mt76_connac_sdio_rr(dev, offset);
+ offset += sizeof(u32);
+ }
+}
+EXPORT_SYMBOL_GPL(mt76_connac_sdio_read_copy);
+
+int mt76_connac_sdio_wr_rp(struct mt76_dev *dev, u32 base,
+ const struct mt76_reg_pair *data,
+ int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ mt76_connac_sdio_wr(dev, data->reg, data->value);
+ data++;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt76_connac_sdio_wr_rp);
+
+int mt76_connac_sdio_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 = mt76_connac_sdio_rr(dev, data->reg);
+ data++;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt76_connac_sdio_rd_rp);
+
+int mt76_connac_sdio_hw_init(struct mt76_dev *dev, struct sdio_func *func,
+ sdio_irq_handler_t *irq_handler)
+{
+ 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(mt76_connac_sdio_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, irq_handler);
+ 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(mt76_connac_sdio_hw_init);
+
+int mt76_connac_sdio_init(struct mt76_dev *dev,
+ void (*txrx_worker)(struct mt76_worker *))
+{
+ int i, ret;
+
+ dev->sdio.intr_data = devm_kmalloc(dev->dev,
+ sizeof(struct mt76s_intr),
+ GFP_KERNEL);
+ if (!dev->sdio.intr_data)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(dev->sdio.xmit_buf); i++) {
+ dev->sdio.xmit_buf[i] = devm_kmalloc(dev->dev,
+ MT76S_XMIT_BUF_SZ,
+ GFP_KERNEL);
+ if (!dev->sdio.xmit_buf[i])
+ return -ENOMEM;
+ }
+
+ ret = mt76_worker_setup(dev->hw, &dev->sdio.txrx_worker, txrx_worker,
+ "sdio-txrx");
+ if (ret)
+ return ret;
+
+ sched_set_fifo_low(dev->sdio.txrx_worker.task);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt76_connac_sdio_init);
+
+MODULE_AUTHOR("Sean Wang <[email protected]>");
+MODULE_AUTHOR("Lorenzo Bianconi <[email protected]>");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.h
new file mode 100644
index 000000000000..e176d6e562b2
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.h
@@ -0,0 +1,137 @@
+/* SPDX-License-Identifier: ISC */
+/* Copyright (C) 2020-2021 MediaTek Inc.
+ *
+ * Author: Sean Wang <[email protected]>
+ */
+
+#ifndef __MT76_CONNAC_SDIO_H
+#define __MT76_CONNAC_SDIO_H
+
+#define MT_PSE_PAGE_SZ 128
+
+#define MCR_WCIR 0x0000
+#define MCR_WHLPCR 0x0004
+#define WHLPCR_FW_OWN_REQ_CLR BIT(9)
+#define WHLPCR_FW_OWN_REQ_SET BIT(8)
+#define WHLPCR_IS_DRIVER_OWN BIT(8)
+#define WHLPCR_INT_EN_CLR BIT(1)
+#define WHLPCR_INT_EN_SET BIT(0)
+
+#define MCR_WSDIOCSR 0x0008
+#define MCR_WHCR 0x000C
+#define W_INT_CLR_CTRL BIT(1)
+#define RECV_MAILBOX_RD_CLR_EN BIT(2)
+#define MAX_HIF_RX_LEN_NUM GENMASK(13, 8)
+#define RX_ENHANCE_MODE BIT(16)
+
+#define MCR_WHISR 0x0010
+#define MCR_WHIER 0x0014
+#define WHIER_D2H_SW_INT GENMASK(31, 8)
+#define WHIER_FW_OWN_BACK_INT_EN BIT(7)
+#define WHIER_ABNORMAL_INT_EN BIT(6)
+#define WHIER_RX1_DONE_INT_EN BIT(2)
+#define WHIER_RX0_DONE_INT_EN BIT(1)
+#define WHIER_TX_DONE_INT_EN BIT(0)
+#define WHIER_DEFAULT (WHIER_RX0_DONE_INT_EN | \
+ WHIER_RX1_DONE_INT_EN | \
+ WHIER_TX_DONE_INT_EN | \
+ WHIER_ABNORMAL_INT_EN | \
+ WHIER_D2H_SW_INT)
+
+#define MCR_WASR 0x0020
+#define MCR_WSICR 0x0024
+#define MCR_WTSR0 0x0028
+#define TQ0_CNT GENMASK(7, 0)
+#define TQ1_CNT GENMASK(15, 8)
+#define TQ2_CNT GENMASK(23, 16)
+#define TQ3_CNT GENMASK(31, 24)
+
+#define MCR_WTSR1 0x002c
+#define TQ4_CNT GENMASK(7, 0)
+#define TQ5_CNT GENMASK(15, 8)
+#define TQ6_CNT GENMASK(23, 16)
+#define TQ7_CNT GENMASK(31, 24)
+
+#define MCR_WTDR1 0x0034
+#define MCR_WRDR0 0x0050
+#define MCR_WRDR1 0x0054
+#define MCR_WRDR(p) (0x0050 + 4 * (p))
+#define MCR_H2DSM0R 0x0070
+#define H2D_SW_INT_READ BIT(16)
+#define H2D_SW_INT_WRITE BIT(17)
+
+#define MCR_H2DSM1R 0x0074
+#define MCR_D2HRM0R 0x0078
+#define MCR_D2HRM1R 0x007c
+#define MCR_D2HRM2R 0x0080
+#define MCR_WRPLR 0x0090
+#define RX0_PACKET_LENGTH GENMASK(15, 0)
+#define RX1_PACKET_LENGTH GENMASK(31, 16)
+
+#define MCR_WTMDR 0x00b0
+#define MCR_WTMCR 0x00b4
+#define MCR_WTMDPCR0 0x00b8
+#define MCR_WTMDPCR1 0x00bc
+#define MCR_WPLRCR 0x00d4
+#define MCR_WSR 0x00D8
+#define MCR_CLKIOCR 0x0100
+#define MCR_CMDIOCR 0x0104
+#define MCR_DAT0IOCR 0x0108
+#define MCR_DAT1IOCR 0x010C
+#define MCR_DAT2IOCR 0x0110
+#define MCR_DAT3IOCR 0x0114
+#define MCR_CLKDLYCR 0x0118
+#define MCR_CMDDLYCR 0x011C
+#define MCR_ODATDLYCR 0x0120
+#define MCR_IDATDLYCR1 0x0124
+#define MCR_IDATDLYCR2 0x0128
+#define MCR_ILCHCR 0x012C
+#define MCR_WTQCR0 0x0130
+#define MCR_WTQCR1 0x0134
+#define MCR_WTQCR2 0x0138
+#define MCR_WTQCR3 0x013C
+#define MCR_WTQCR4 0x0140
+#define MCR_WTQCR5 0x0144
+#define MCR_WTQCR6 0x0148
+#define MCR_WTQCR7 0x014C
+#define MCR_WTQCR(x) (0x130 + 4 * (x))
+#define TXQ_CNT_L GENMASK(15, 0)
+#define TXQ_CNT_H GENMASK(31, 16)
+
+#define MCR_SWPCDBGR 0x0154
+
+struct mt76s_intr {
+ u32 isr;
+ struct {
+ u32 wtqcr[8];
+ } tx;
+ struct {
+ u16 num[2];
+ u16 len[2][16];
+ } rx;
+ u32 rec_mb[2];
+} __packed;
+
+u32 mt76_connac_sdio_read_pcr(struct mt76_dev *dev);
+u32 mt76_connac_sdio_read_mailbox(struct mt76_dev *dev, u32 offset);
+void mt76_connac_sdio_write_mailbox(struct mt76_dev *dev, u32 offset, u32 val);
+u32 mt76_connac_sdio_rr(struct mt76_dev *dev, u32 offset);
+void mt76_connac_sdio_wr(struct mt76_dev *dev, u32 offset, u32 val);
+u32 mt76_connac_sdio_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val);
+void mt76_connac_sdio_write_copy(struct mt76_dev *dev, u32 offset,
+ const void *data, int len);
+void mt76_connac_sdio_read_copy(struct mt76_dev *dev, u32 offset,
+ void *data, int len);
+int mt76_connac_sdio_wr_rp(struct mt76_dev *dev, u32 base,
+ const struct mt76_reg_pair *data,
+ int len);
+int mt76_connac_sdio_rd_rp(struct mt76_dev *dev, u32 base,
+ struct mt76_reg_pair *data,
+ int len);
+
+void mt76_connac_sdio_txrx(struct mt76_dev *dev);
+int mt76_connac_sdio_hw_init(struct mt76_dev *dev, struct sdio_func *func,
+ sdio_irq_handler_t *irq_handler);
+int mt76_connac_sdio_init(struct mt76_dev *dev,
+ void (*txrx_worker)(struct mt76_worker *));
+#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio_txrx.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio_txrx.c
new file mode 100644
index 000000000000..3ef42f90f3f5
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio_txrx.c
@@ -0,0 +1,318 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2020-2021 MediaTek Inc.
+ *
+ * Author: Felix Fietkau <[email protected]>
+ * Lorenzo Bianconi <[email protected]>
+ * Sean Wang <[email protected]>
+ */
+
+#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 "trace.h"
+#include "mt76.h"
+#include "mt76_connac_sdio.h"
+
+static int mt76_connac_sdio_refill_sched_quota(struct mt76_dev *dev, u32 *data)
+{
+ u32 ple_ac_data_quota[] = {
+ FIELD_GET(TXQ_CNT_L, data[4]), /* VO */
+ FIELD_GET(TXQ_CNT_H, data[3]), /* VI */
+ FIELD_GET(TXQ_CNT_L, data[3]), /* BE */
+ FIELD_GET(TXQ_CNT_H, data[2]), /* BK */
+ };
+ u32 pse_ac_data_quota[] = {
+ FIELD_GET(TXQ_CNT_H, data[1]), /* VO */
+ FIELD_GET(TXQ_CNT_L, data[1]), /* VI */
+ FIELD_GET(TXQ_CNT_H, data[0]), /* BE */
+ FIELD_GET(TXQ_CNT_L, data[0]), /* BK */
+ };
+ u32 pse_mcu_quota = FIELD_GET(TXQ_CNT_L, data[2]);
+ u32 pse_data_quota = 0, ple_data_quota = 0;
+ struct mt76_sdio *sdio = &dev->sdio;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pse_ac_data_quota); i++) {
+ pse_data_quota += pse_ac_data_quota[i];
+ ple_data_quota += ple_ac_data_quota[i];
+ }
+
+ if (!pse_data_quota && !ple_data_quota && !pse_mcu_quota)
+ return 0;
+
+ sdio->sched.pse_mcu_quota += pse_mcu_quota;
+ sdio->sched.pse_data_quota += pse_data_quota;
+ sdio->sched.ple_data_quota += ple_data_quota;
+
+ return pse_data_quota + ple_data_quota + pse_mcu_quota;
+}
+
+static struct sk_buff *mt76_connac_sdio_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;
+
+ skb = alloc_skb(len, GFP_KERNEL);
+ if (!skb)
+ return NULL;
+
+ skb_put_data(skb, data, len);
+ if (data_len > len) {
+ struct page *page;
+
+ data += len;
+ page = virt_to_head_page(data);
+ skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
+ page, data - page_address(page),
+ data_len - len, buf_len);
+ get_page(page);
+ }
+
+ return skb;
+}
+
+static int mt76_connac_sdio_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;
+ int len = 0, err, i;
+ struct page *page;
+ u8 *buf;
+
+ for (i = 0; i < intr->rx.num[qid]; i++)
+ len += round_up(intr->rx.len[qid][i] + 4, 4);
+
+ if (!len)
+ return 0;
+
+ if (len > sdio->func->cur_blksize)
+ len = roundup(len, sdio->func->cur_blksize);
+
+ page = __dev_alloc_pages(GFP_KERNEL, get_order(len));
+ if (!page)
+ return -ENOMEM;
+
+ buf = page_address(page);
+
+ err = sdio_readsb(sdio->func, buf, MCR_WRDR(qid), len);
+ if (err < 0) {
+ dev_err(dev->dev, "sdio read data failed:%d\n", err);
+ put_page(page);
+ return err;
+ }
+
+ for (i = 0; i < intr->rx.num[qid]; i++) {
+ int index = (q->head + i) % q->ndesc;
+ struct mt76_queue_entry *e = &q->entry[index];
+
+ len = intr->rx.len[qid][i];
+ e->skb = mt76_connac_sdio_build_rx_skb(buf, len,
+ round_up(len + 4, 4));
+ if (!e->skb)
+ break;
+
+ buf += round_up(len + 4, 4);
+ if (q->queued + i + 1 == q->ndesc)
+ break;
+ }
+ put_page(page);
+
+ spin_lock_bh(&q->lock);
+ q->head = (q->head + i) % q->ndesc;
+ q->queued += i;
+ spin_unlock_bh(&q->lock);
+
+ return i;
+}
+
+static int mt76_connac_sdio_rx_handler(struct mt76_dev *dev)
+{
+ struct mt76_sdio *sdio = &dev->sdio;
+ struct mt76s_intr *intr = sdio->intr_data;
+ int nframes = 0, ret;
+
+ ret = sdio_readsb(sdio->func, intr, MCR_WHISR, sizeof(*intr));
+ if (ret < 0)
+ return ret;
+
+ trace_dev_irq(dev, intr->isr, 0);
+
+ if (intr->isr & WHIER_RX0_DONE_INT_EN) {
+ ret = mt76_connac_sdio_rx_run_queue(dev, 0, intr);
+ if (ret > 0) {
+ mt76_worker_schedule(&sdio->net_worker);
+ nframes += ret;
+ }
+ }
+
+ if (intr->isr & WHIER_RX1_DONE_INT_EN) {
+ ret = mt76_connac_sdio_rx_run_queue(dev, 1, intr);
+ if (ret > 0) {
+ mt76_worker_schedule(&sdio->net_worker);
+ nframes += ret;
+ }
+ }
+
+ nframes += !!mt76_connac_sdio_refill_sched_quota(dev, intr->tx.wtqcr);
+
+ return nframes;
+}
+
+static int mt76_connac_sdio_tx_pick_quota(struct mt76_sdio *sdio, bool mcu,
+ int buf_sz, int *pse_size,
+ int *ple_size)
+{
+ int pse_sz;
+
+ pse_sz = DIV_ROUND_UP(buf_sz + sdio->sched.deficit, MT_PSE_PAGE_SZ);
+
+ if (mcu) {
+ if (sdio->sched.pse_mcu_quota < *pse_size + pse_sz)
+ return -EBUSY;
+ } else {
+ if (sdio->sched.pse_data_quota < *pse_size + pse_sz ||
+ sdio->sched.ple_data_quota < *ple_size + 1)
+ return -EBUSY;
+
+ *ple_size = *ple_size + 1;
+ }
+ *pse_size = *pse_size + pse_sz;
+
+ return 0;
+}
+
+static void mt76_connac_sdio_tx_update_quota(struct mt76_sdio *sdio, bool mcu,
+ int pse_size, int ple_size)
+{
+ if (mcu) {
+ sdio->sched.pse_mcu_quota -= pse_size;
+ } else {
+ sdio->sched.pse_data_quota -= pse_size;
+ sdio->sched.ple_data_quota -= ple_size;
+ }
+}
+
+static int __mt76_connac_sdio_xmit_queue(struct mt76_dev *dev, u8 *data,
+ int len)
+{
+ struct mt76_sdio *sdio = &dev->sdio;
+ int err;
+
+ if (len > sdio->func->cur_blksize)
+ len = roundup(len, sdio->func->cur_blksize);
+
+ err = sdio_writesb(sdio->func, MCR_WTDR1, data, len);
+ if (err)
+ dev_err(dev->dev, "sdio write failed: %d\n", err);
+
+ return err;
+}
+
+static int mt76_connac_sdio_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];
+ struct mt76_sdio *sdio = &dev->sdio;
+ u8 pad;
+
+ qid = mcu ? ARRAY_SIZE(sdio->xmit_buf) - 1 : q->qid;
+ while (q->first != q->head) {
+ struct mt76_queue_entry *e = &q->entry[q->first];
+ struct sk_buff *iter;
+
+ smp_rmb();
+
+ if (!test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state)) {
+ __skb_put_zero(e->skb, 4);
+ err = __mt76_connac_sdio_xmit_queue(dev, e->skb->data,
+ e->skb->len);
+ if (err)
+ return err;
+
+ goto next;
+ }
+
+ pad = roundup(e->skb->len, 4) - e->skb->len;
+ if (len + e->skb->len + pad + 4 > MT76S_XMIT_BUF_SZ)
+ break;
+
+ if (mt76_connac_sdio_tx_pick_quota(sdio, mcu, e->buf_sz, &pse_sz,
+ &ple_sz))
+ break;
+
+ memcpy(sdio->xmit_buf[qid] + len, e->skb->data,
+ skb_headlen(e->skb));
+ len += skb_headlen(e->skb);
+ nframes++;
+
+ skb_walk_frags(e->skb, iter) {
+ memcpy(sdio->xmit_buf[qid] + len, iter->data,
+ iter->len);
+ len += iter->len;
+ nframes++;
+ }
+
+ if (unlikely(pad)) {
+ memset(sdio->xmit_buf[qid] + len, 0, pad);
+ len += pad;
+ }
+next:
+ q->first = (q->first + 1) % q->ndesc;
+ e->done = true;
+ }
+
+ if (nframes) {
+ memset(sdio->xmit_buf[qid] + len, 0, 4);
+ err = __mt76_connac_sdio_xmit_queue(dev, sdio->xmit_buf[qid], len + 4);
+ if (err)
+ return err;
+ }
+ mt76_connac_sdio_tx_update_quota(sdio, mcu, pse_sz, ple_sz);
+
+ mt76_worker_schedule(&sdio->status_worker);
+
+ return nframes;
+}
+
+void mt76_connac_sdio_txrx(struct mt76_dev *dev)
+{
+ struct mt76_sdio *sdio = &dev->sdio;
+ int i, nframes, ret;
+
+ /* disable interrupt */
+ sdio_claim_host(sdio->func);
+ sdio_writel(sdio->func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, NULL);
+
+ do {
+ nframes = 0;
+
+ /* tx */
+ for (i = 0; i <= MT_TXQ_PSD; i++) {
+ ret = mt76_connac_sdio_tx_run_queue(dev, dev->phy.q_tx[i]);
+ if (ret > 0)
+ nframes += ret;
+ }
+ ret = mt76_connac_sdio_tx_run_queue(dev, dev->q_mcu[MT_MCUQ_WM]);
+ if (ret > 0)
+ nframes += ret;
+
+ /* rx */
+ ret = mt76_connac_sdio_rx_handler(dev);
+ if (ret > 0)
+ nframes += ret;
+ } while (nframes > 0);
+
+ /* enable interrupt */
+ sdio_writel(sdio->func, WHLPCR_INT_EN_SET, MCR_WHLPCR, NULL);
+ sdio_release_host(sdio->func);
+}
+EXPORT_SYMBOL_GPL(mt76_connac_sdio_txrx);
--
2.25.1

2021-09-15 13:02:30

by Lorenzo Bianconi

[permalink] [raw]
Subject: Re: [PATCH v1 01/16] 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.

Hi Sean,

mostly fine, just few nitpicks inline.

Regards,
Lorenzo

>
> Tested-by: Deren Wu <[email protected]>
> Signed-off-by: Sean Wang <[email protected]>
> ---
> .../wireless/mediatek/mt76/mt7921/Makefile | 2 +-
> .../net/wireless/mediatek/mt76/mt7921/mac.c | 331 +----------------
> .../wireless/mediatek/mt76/mt7921/mt7921.h | 25 +-
> .../net/wireless/mediatek/mt76/mt7921/pci.c | 12 +-
> .../wireless/mediatek/mt76/mt7921/pci_mac.c | 345 ++++++++++++++++++
> 5 files changed, 379 insertions(+), 336 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 27f13228c5a7..d811702a3a2c 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,
> @@ -836,7 +836,7 @@ mt7921_mac_write_txwi_80211(struct mt7921_dev *dev, __le32 *txwi,
> txwi[7] |= cpu_to_le32(val);
> }
>
> -static void
> +void

can you please remove new line here?

> 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,
> @@ -922,86 +922,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
> +void

can you please remove new line here?

> mt7921_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
> {
> struct mt7921_sta *msta;
> @@ -1026,143 +947,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 mt7921_phy *phy;
> - 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);
> - phy = msta->vif->phy;
> - 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)
> @@ -1330,9 +1114,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;
> @@ -1354,33 +1135,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)
> -{
> - struct mt7921_dev *dev;
> -
> - if (!e->txwi) {
> - dev_kfree_skb_any(e->skb);
> - return;
> - }
> -
> - dev = container_of(mdev, struct mt7921_dev, mt76);
> -
> - /* 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;
> @@ -1496,20 +1250,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)
> @@ -1524,69 +1264,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);
> -
> - mt76_for_each_q_rx(&dev->mt76, i) {
> - napi_enable(&dev->mt76.napi[i]);
> - napi_schedule(&dev->mt76.napi[i]);
> - }
> -
> - 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);
> -
> - napi_enable(&dev->mt76.tx_napi);
> - napi_schedule(&dev->mt76.tx_napi);
> - mt76_worker_enable(&dev->mt76.tx_worker);
> -
> - return err;
> -}
> -
> /* system error recovery */
> void mt7921_mac_reset_work(struct work_struct *work)
> {
> @@ -1608,7 +1285,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 cd710360d180..b01b9b7c42b4 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..f211dafa311c
> --- /dev/null
> +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c
> @@ -0,0 +1,345 @@
> +// 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 mt7921_phy *phy;
> + 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);
> + phy = msta->vif->phy;
> + 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);
> +}
> +
> +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)
> +{
> + struct mt7921_dev *dev;
> +
> + if (!e->txwi) {
> + dev_kfree_skb_any(e->skb);
> + return;
> + }
> +
> + dev = container_of(mdev, struct mt7921_dev, mt76);
> +
> + /* 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

can you please remove new line here?

> +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);
> +
> + mt76_for_each_q_rx(&dev->mt76, i) {
> + napi_enable(&dev->mt76.napi[i]);
> + napi_schedule(&dev->mt76.napi[i]);
> + }
> +
> + 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);
> +
> + napi_enable(&dev->mt76.tx_napi);
> + napi_schedule(&dev->mt76.tx_napi);
> + mt76_worker_enable(&dev->mt76.tx_worker);
> +
> + return err;
> +}
> --
> 2.25.1
>


Attachments:
(No filename) (26.77 kB)
signature.asc (235.00 B)
Download all attachments

2021-09-15 13:03:30

by Lorenzo Bianconi

[permalink] [raw]
Subject: Re: [PATCH v1 02/16] 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]>
> 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/mcu.c | 6 ++++++
> drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 2 +-
> 4 files changed, 9 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 d811702a3a2c..580a88b7841e 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
> @@ -1392,7 +1392,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/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
> index ecdc879216b9..6ba431347b3b 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
> @@ -1369,3 +1369,9 @@ int mt7921_get_txpwr_info(struct mt7921_dev *dev, struct mt7921_txpwr *txpwr)
>
> return 0;
> }
> +
> +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);
> +}

I guess it can be inline in mt7921.h, are you reusing it later?

> diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
> index 70c0f41180a1..4c1c7c4eafac 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
> +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
> @@ -330,7 +330,7 @@ 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);
> +void mt7921_mcu_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
>


Attachments:
(No filename) (3.96 kB)
signature.asc (235.00 B)
Download all attachments

2021-09-15 13:09:29

by Lorenzo Bianconi

[permalink] [raw]
Subject: Re: [PATCH v1 03/16] 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]>
> 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 | 90 ++---------------
> .../wireless/mediatek/mt76/mt7921/mt7921.h | 18 +++-
> .../net/wireless/mediatek/mt76/mt7921/pci.c | 3 +
> .../wireless/mediatek/mt76/mt7921/pci_mac.c | 2 +
> .../wireless/mediatek/mt76/mt7921/pci_mcu.c | 97 +++++++++++++++++++
> .../wireless/mediatek/mt76/mt7921/testmode.c | 2 +-
> 9 files changed, 129 insertions(+), 92 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 97b931ea07c1..7c7a26102e11 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);
> mt7921_mcu_fw_pmctrl(dev);
>
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
> index 580a88b7841e..c26d986e08e6 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
> @@ -1282,12 +1282,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 6ba431347b3b..0648443eb283 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
> @@ -160,7 +160,7 @@ mt7921_mcu_parse_eeprom(struct mt76_dev *dev, struct sk_buff *skb)
> return 0;
> }
>
> -static int
> +int

no new-line here

> mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd,
> struct sk_buff *skb, int seq)
> {
> @@ -224,7 +224,7 @@ mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd,
> return ret;
> }
>
> -static int
> +int

no new-line here

> mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
> int cmd, int *wait_seq)
> {
> @@ -590,7 +590,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 +603,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 +869,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 +896,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 +906,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);
> }
>
> @@ -1231,35 +1197,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;
> @@ -1271,7 +1208,7 @@ int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev)
> if (!test_bit(MT76_STATE_PM, &mphy->state))
> goto out;
>
> - err = __mt7921_mcu_drv_pmctrl(dev);
> + err = mt7921_drv_own(dev);
> out:
> mutex_unlock(&pm->mutex);
>
> @@ -1285,29 +1222,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_fw_own(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 4c1c7c4eafac..dbace154bfa5 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
> +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
> @@ -134,8 +134,14 @@ struct mt7921_phy {
> };
>
> #define mt7921_dev_reset(dev) ((dev)->hif_ops->reset(dev))
> +#define mt7921_mcu_init(dev) ((dev)->hif_ops->mcu_init(dev))
> +#define mt7921_drv_own(dev) ((dev)->hif_ops->drv_own(dev))
> +#define mt7921_fw_own(dev) ((dev)->hif_ops->fw_own(dev))

mt7921_drv_own and mt7921_fw_own seems a bit misleading, why not something
like:

mt7921_mcu_drv_pmctrl and mt7921_mcu_fw_pmctrl

are they already used?

> 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);
> @@ -359,7 +364,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);
> @@ -378,7 +382,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 b01b9b7c42b4..b16bcee08cd7 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 f211dafa311c..f0734be57dce 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c
> @@ -286,6 +286,8 @@ 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;
> +}
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/testmode.c b/drivers/net/wireless/mediatek/mt76/mt7921/testmode.c
> index 8bd43879dd6f..d22bbd9da58f 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7921/testmode.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7921/testmode.c
> @@ -57,7 +57,7 @@ mt7921_tm_set(struct mt7921_dev *dev, struct mt7921_tm_cmd *req)
> pm->enable = false;
> cancel_delayed_work_sync(&pm->ps_work);
> cancel_work_sync(&pm->wake_work);
> - __mt7921_mcu_drv_pmctrl(dev);
> + mt7921_drv_own(dev);
>
> mt76_wr(dev, MT_WF_RFCR(0), dev->mt76.rxfilter);
> phy->test.state = MT76_TM_STATE_ON;
> --
> 2.25.1
>


Attachments:
(No filename) (15.12 kB)
signature.asc (235.00 B)
Download all attachments

2021-09-15 13:15:12

by Lorenzo Bianconi

[permalink] [raw]
Subject: Re: [PATCH v1 04/16] 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]>
> Signed-off-by: Sean Wang <[email protected]>
> ---
> .../wireless/mediatek/mt76/mt7921/Makefile | 4 +--
> .../net/wireless/mediatek/mt76/mt7921/dma.c | 8 ++++++
> .../net/wireless/mediatek/mt76/mt7921/init.c | 28 +------------------
> .../wireless/mediatek/mt76/mt7921/mt7921.h | 3 ++
> .../net/wireless/mediatek/mt76/mt7921/pci.c | 5 ++++
> .../wireless/mediatek/mt76/mt7921/pci_init.c | 26 +++++++++++++++++
> 6 files changed, 45 insertions(+), 29 deletions(-)
> create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/pci_init.c
>
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile
> index 4cb0b000cfe1..15f940a23ea9 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile
> +++ b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile
> @@ -4,6 +4,6 @@ obj-$(CONFIG_MT7921E) += mt7921e.o
>
> CFLAGS_trace.o := -I$(src)
>
> -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-y := pci.o pci_mac.o pci_mcu.o pci_init.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/dma.c b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
> index d3e2036a1974..be24241fb8e6 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
> @@ -313,6 +313,11 @@ int mt7921_wpdma_reset(struct mt7921_dev *dev, bool force)
> return 0;
> }
>
> +int mt7921e_init_reset(struct mt7921_dev *dev)
> +{
> + return mt7921_wpdma_reset(dev, true);
> +}

it seems used only in pci.c, right? maybe you can move it there and make it
static.

> +
> int mt7921_wpdma_reinit_cond(struct mt7921_dev *dev)
> {
> struct mt76_connac_pm *pm = &dev->pm;
> @@ -343,6 +348,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 7c7a26102e11..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,25 +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);
> - mt7921_mcu_fw_pmctrl(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 dbace154bfa5..60f4552cb212 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_drv_own(dev) ((dev)->hif_ops->drv_own(dev))
> #define mt7921_fw_own(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);
> @@ -394,5 +396,6 @@ 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);
> +int mt7921e_init_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 b16bcee08cd7..f6bc3505b06a 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
> @@ -116,6 +116,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 +173,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;
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci_init.c
> new file mode 100644
> index 000000000000..4511fec79d43
> --- /dev/null
> +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_init.c
> @@ -0,0 +1,26 @@
> +// SPDX-License-Identifier: ISC
> +/* Copyright (C) 2021 MediaTek Inc. */
> +
> +#include "mt7921.h"
> +
> +void mt7921_unregister_device(struct mt7921_dev *dev)

same here, we have pci_init.c just for mt7921_unregister_device(). Just move it
in pci.c and call it mt7921e_unregister_device(). Agree?

Regards,
Lorenzo

> +{
> + 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);
> + mt7921_mcu_fw_pmctrl(dev);
> +
> + tasklet_disable(&dev->irq_tasklet);
> + mt76_free_device(&dev->mt76);
> +}
> --
> 2.25.1
>


Attachments:
(No filename) (7.10 kB)
signature.asc (235.00 B)
Download all attachments

2021-09-15 13:21:42

by Lorenzo Bianconi

[permalink] [raw]
Subject: Re: [PATCH v1 07/16] mt76: connac: move sdio utility routines in mt76_connac_sdio module

On Sep 15, Sean Wang wrote:
> From: Sean Wang <[email protected]>
>
> This is a preliminary patch before introduce mt7921s support to hold the
> common sdio utilities between mt7663s and mt7921s in mt76_connac_sdio
> module.
>
> mt76/mt76_connac_sdio.c, mt76/mt76_connac_sdio.h and
> mt76/mt76_connac_sdio_txrx.c originate from mt7615/sdio.c, mt7615/sdio.h
> and mt7615/sdio_txrx.c and the patch don't add any logic change.
>
> Tested-by: Deren Wu <[email protected]>
> Signed-off-by: Sean Wang <[email protected]>
> ---
> drivers/net/wireless/mediatek/mt76/Kconfig | 5 +
> drivers/net/wireless/mediatek/mt76/Makefile | 2 +
> .../wireless/mediatek/mt76/mt76_connac_sdio.c | 317 +++++++++++++++++
> .../wireless/mediatek/mt76/mt76_connac_sdio.h | 137 ++++++++
> .../mediatek/mt76/mt76_connac_sdio_txrx.c | 318 ++++++++++++++++++
> 5 files changed, 779 insertions(+)
> create mode 100644 drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.c
> create mode 100644 drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.h
> create mode 100644 drivers/net/wireless/mediatek/mt76/mt76_connac_sdio_txrx.c
>
> diff --git a/drivers/net/wireless/mediatek/mt76/Kconfig b/drivers/net/wireless/mediatek/mt76/Kconfig
> index 9ff43f1fc50d..a6b388bfb563 100644
> --- a/drivers/net/wireless/mediatek/mt76/Kconfig
> +++ b/drivers/net/wireless/mediatek/mt76/Kconfig
> @@ -28,6 +28,11 @@ config MT76_CONNAC_LIB
> tristate
> select MT76_CORE
>
> +config MT76_CONNAC_SDIO
> + tristate
> + depends on MMC
> + select MT76_CONNAC_LIB
> +
> source "drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig"
> source "drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig"
> source "drivers/net/wireless/mediatek/mt76/mt7603/Kconfig"
> diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile
> index 94efe3c29053..17b2ed93f6a3 100644
> --- a/drivers/net/wireless/mediatek/mt76/Makefile
> +++ b/drivers/net/wireless/mediatek/mt76/Makefile
> @@ -5,6 +5,7 @@ obj-$(CONFIG_MT76_SDIO) += mt76-sdio.o
> obj-$(CONFIG_MT76x02_LIB) += mt76x02-lib.o
> obj-$(CONFIG_MT76x02_USB) += mt76x02-usb.o
> obj-$(CONFIG_MT76_CONNAC_LIB) += mt76-connac-lib.o
> +obj-$(CONFIG_MT76_CONNAC_SDIO) += mt76-connac-sdio.o
>
> mt76-y := \
> mmio.o util.o trace.o dma.o mac80211.o debugfs.o eeprom.o \
> @@ -28,6 +29,7 @@ mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o mt76x02_mcu.o \
> mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o
>
> mt76-connac-lib-y := mt76_connac_mcu.o mt76_connac_mac.o
> +mt76-connac-sdio-y := mt76_connac_sdio.o mt76_connac_sdio_txrx.o
>
> obj-$(CONFIG_MT76x0_COMMON) += mt76x0/
> obj-$(CONFIG_MT76x2_COMMON) += mt76x2/
> diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.c
> new file mode 100644
> index 000000000000..d18a66e5445f
> --- /dev/null
> +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.c
> @@ -0,0 +1,317 @@
> +// SPDX-License-Identifier: ISC
> +/* Copyright (C) 2020-2021 MediaTek Inc.
> + *
> + * Author: Felix Fietkau <[email protected]>
> + * Lorenzo Bianconi <[email protected]>
> + * Sean Wang <[email protected]>
> + */
> +
> +#include <linux/iopoll.h>
> +#include <linux/mmc/host.h>
> +#include <linux/mmc/sdio_func.h>
> +
> +#include "mt76.h"
> +#include "mt76_connac_mcu.h"
> +#include "mt76_connac_sdio.h"
> +
> +static u32 mt76_connac_sdio_read_whisr(struct mt76_dev *dev)
> +{
> + return sdio_readl(dev->sdio.func, MCR_WHISR, NULL);
> +}
> +
> +u32 mt76_connac_sdio_read_pcr(struct mt76_dev *dev)
> +{
> + struct mt76_sdio *sdio = &dev->sdio;
> +
> + return sdio_readl(sdio->func, MCR_WHLPCR, NULL);
> +}
> +EXPORT_SYMBOL_GPL(mt76_connac_sdio_read_pcr);
> +
> +u32 mt76_connac_sdio_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(mt76_connac_sdio_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;
> +}
> +EXPORT_SYMBOL_GPL(mt76_connac_sdio_read_mailbox);
> +
> +void mt76_connac_sdio_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(mt76_connac_sdio_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);
> +}
> +EXPORT_SYMBOL_GPL(mt76_connac_sdio_write_mailbox);
> +
> +u32 mt76_connac_sdio_rr(struct mt76_dev *dev, u32 offset)
> +{
> + if (test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state))
> + return mt76_connac_mcu_reg_rr(dev, offset);
> + else
> + return mt76_connac_sdio_read_mailbox(dev, offset);
> +}
> +EXPORT_SYMBOL_GPL(mt76_connac_sdio_rr);
> +
> +void mt76_connac_sdio_wr(struct mt76_dev *dev, u32 offset, u32 val)
> +{
> + if (test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state))
> + mt76_connac_mcu_reg_wr(dev, offset, val);
> + else
> + mt76_connac_sdio_write_mailbox(dev, offset, val);
> +}
> +EXPORT_SYMBOL_GPL(mt76_connac_sdio_wr);
> +
> +u32 mt76_connac_sdio_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val)
> +{
> + val |= mt76_connac_sdio_rr(dev, offset) & ~mask;
> + mt76_connac_sdio_wr(dev, offset, val);
> +
> + return val;
> +}
> +EXPORT_SYMBOL_GPL(mt76_connac_sdio_rmw);
> +
> +void mt76_connac_sdio_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++) {
> + mt76_connac_sdio_wr(dev, offset, val[i]);
> + offset += sizeof(u32);
> + }
> +}
> +EXPORT_SYMBOL_GPL(mt76_connac_sdio_write_copy);
> +
> +void mt76_connac_sdio_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] = mt76_connac_sdio_rr(dev, offset);
> + offset += sizeof(u32);
> + }
> +}
> +EXPORT_SYMBOL_GPL(mt76_connac_sdio_read_copy);
> +
> +int mt76_connac_sdio_wr_rp(struct mt76_dev *dev, u32 base,
> + const struct mt76_reg_pair *data,
> + int len)
> +{
> + int i;
> +
> + for (i = 0; i < len; i++) {
> + mt76_connac_sdio_wr(dev, data->reg, data->value);
> + data++;
> + }
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(mt76_connac_sdio_wr_rp);
> +
> +int mt76_connac_sdio_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 = mt76_connac_sdio_rr(dev, data->reg);
> + data++;
> + }
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(mt76_connac_sdio_rd_rp);
> +
> +int mt76_connac_sdio_hw_init(struct mt76_dev *dev, struct sdio_func *func,
> + sdio_irq_handler_t *irq_handler)
> +{
> + 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(mt76_connac_sdio_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, irq_handler);

The only difference between mt7921s_irq and mt7663s_irq is the RESET check,
right? Maybe we just need to add the same check for mt7663s_irq and move the
routine here?

> + 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(mt76_connac_sdio_hw_init);
> +
> +int mt76_connac_sdio_init(struct mt76_dev *dev,
> + void (*txrx_worker)(struct mt76_worker *))
> +{
> + int i, ret;
> +
> + dev->sdio.intr_data = devm_kmalloc(dev->dev,
> + sizeof(struct mt76s_intr),
> + GFP_KERNEL);
> + if (!dev->sdio.intr_data)
> + return -ENOMEM;
> +
> + for (i = 0; i < ARRAY_SIZE(dev->sdio.xmit_buf); i++) {
> + dev->sdio.xmit_buf[i] = devm_kmalloc(dev->dev,
> + MT76S_XMIT_BUF_SZ,
> + GFP_KERNEL);
> + if (!dev->sdio.xmit_buf[i])
> + return -ENOMEM;
> + }
> +
> + ret = mt76_worker_setup(dev->hw, &dev->sdio.txrx_worker, txrx_worker,
> + "sdio-txrx");

Same here, I guess we can move mt7921s_txrx_worker here and share it with
mt7663s

> + if (ret)
> + return ret;
> +
> + sched_set_fifo_low(dev->sdio.txrx_worker.task);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(mt76_connac_sdio_init);
> +
> +MODULE_AUTHOR("Sean Wang <[email protected]>");
> +MODULE_AUTHOR("Lorenzo Bianconi <[email protected]>");
> +MODULE_LICENSE("Dual BSD/GPL");
> diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.h
> new file mode 100644
> index 000000000000..e176d6e562b2
> --- /dev/null
> +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.h
> @@ -0,0 +1,137 @@
> +/* SPDX-License-Identifier: ISC */
> +/* Copyright (C) 2020-2021 MediaTek Inc.
> + *
> + * Author: Sean Wang <[email protected]>
> + */
> +
> +#ifndef __MT76_CONNAC_SDIO_H
> +#define __MT76_CONNAC_SDIO_H
> +
> +#define MT_PSE_PAGE_SZ 128
> +
> +#define MCR_WCIR 0x0000
> +#define MCR_WHLPCR 0x0004
> +#define WHLPCR_FW_OWN_REQ_CLR BIT(9)
> +#define WHLPCR_FW_OWN_REQ_SET BIT(8)
> +#define WHLPCR_IS_DRIVER_OWN BIT(8)
> +#define WHLPCR_INT_EN_CLR BIT(1)
> +#define WHLPCR_INT_EN_SET BIT(0)
> +
> +#define MCR_WSDIOCSR 0x0008
> +#define MCR_WHCR 0x000C
> +#define W_INT_CLR_CTRL BIT(1)
> +#define RECV_MAILBOX_RD_CLR_EN BIT(2)
> +#define MAX_HIF_RX_LEN_NUM GENMASK(13, 8)
> +#define RX_ENHANCE_MODE BIT(16)
> +
> +#define MCR_WHISR 0x0010
> +#define MCR_WHIER 0x0014
> +#define WHIER_D2H_SW_INT GENMASK(31, 8)
> +#define WHIER_FW_OWN_BACK_INT_EN BIT(7)
> +#define WHIER_ABNORMAL_INT_EN BIT(6)
> +#define WHIER_RX1_DONE_INT_EN BIT(2)
> +#define WHIER_RX0_DONE_INT_EN BIT(1)
> +#define WHIER_TX_DONE_INT_EN BIT(0)
> +#define WHIER_DEFAULT (WHIER_RX0_DONE_INT_EN | \
> + WHIER_RX1_DONE_INT_EN | \
> + WHIER_TX_DONE_INT_EN | \
> + WHIER_ABNORMAL_INT_EN | \
> + WHIER_D2H_SW_INT)
> +
> +#define MCR_WASR 0x0020
> +#define MCR_WSICR 0x0024
> +#define MCR_WTSR0 0x0028
> +#define TQ0_CNT GENMASK(7, 0)
> +#define TQ1_CNT GENMASK(15, 8)
> +#define TQ2_CNT GENMASK(23, 16)
> +#define TQ3_CNT GENMASK(31, 24)
> +
> +#define MCR_WTSR1 0x002c
> +#define TQ4_CNT GENMASK(7, 0)
> +#define TQ5_CNT GENMASK(15, 8)
> +#define TQ6_CNT GENMASK(23, 16)
> +#define TQ7_CNT GENMASK(31, 24)
> +
> +#define MCR_WTDR1 0x0034
> +#define MCR_WRDR0 0x0050
> +#define MCR_WRDR1 0x0054
> +#define MCR_WRDR(p) (0x0050 + 4 * (p))
> +#define MCR_H2DSM0R 0x0070
> +#define H2D_SW_INT_READ BIT(16)
> +#define H2D_SW_INT_WRITE BIT(17)
> +
> +#define MCR_H2DSM1R 0x0074
> +#define MCR_D2HRM0R 0x0078
> +#define MCR_D2HRM1R 0x007c
> +#define MCR_D2HRM2R 0x0080
> +#define MCR_WRPLR 0x0090
> +#define RX0_PACKET_LENGTH GENMASK(15, 0)
> +#define RX1_PACKET_LENGTH GENMASK(31, 16)
> +
> +#define MCR_WTMDR 0x00b0
> +#define MCR_WTMCR 0x00b4
> +#define MCR_WTMDPCR0 0x00b8
> +#define MCR_WTMDPCR1 0x00bc
> +#define MCR_WPLRCR 0x00d4
> +#define MCR_WSR 0x00D8
> +#define MCR_CLKIOCR 0x0100
> +#define MCR_CMDIOCR 0x0104
> +#define MCR_DAT0IOCR 0x0108
> +#define MCR_DAT1IOCR 0x010C
> +#define MCR_DAT2IOCR 0x0110
> +#define MCR_DAT3IOCR 0x0114
> +#define MCR_CLKDLYCR 0x0118
> +#define MCR_CMDDLYCR 0x011C
> +#define MCR_ODATDLYCR 0x0120
> +#define MCR_IDATDLYCR1 0x0124
> +#define MCR_IDATDLYCR2 0x0128
> +#define MCR_ILCHCR 0x012C
> +#define MCR_WTQCR0 0x0130
> +#define MCR_WTQCR1 0x0134
> +#define MCR_WTQCR2 0x0138
> +#define MCR_WTQCR3 0x013C
> +#define MCR_WTQCR4 0x0140
> +#define MCR_WTQCR5 0x0144
> +#define MCR_WTQCR6 0x0148
> +#define MCR_WTQCR7 0x014C
> +#define MCR_WTQCR(x) (0x130 + 4 * (x))
> +#define TXQ_CNT_L GENMASK(15, 0)
> +#define TXQ_CNT_H GENMASK(31, 16)
> +
> +#define MCR_SWPCDBGR 0x0154
> +
> +struct mt76s_intr {
> + u32 isr;
> + struct {
> + u32 wtqcr[8];
> + } tx;
> + struct {
> + u16 num[2];
> + u16 len[2][16];
> + } rx;
> + u32 rec_mb[2];
> +} __packed;
> +
> +u32 mt76_connac_sdio_read_pcr(struct mt76_dev *dev);
> +u32 mt76_connac_sdio_read_mailbox(struct mt76_dev *dev, u32 offset);
> +void mt76_connac_sdio_write_mailbox(struct mt76_dev *dev, u32 offset, u32 val);
> +u32 mt76_connac_sdio_rr(struct mt76_dev *dev, u32 offset);
> +void mt76_connac_sdio_wr(struct mt76_dev *dev, u32 offset, u32 val);
> +u32 mt76_connac_sdio_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val);
> +void mt76_connac_sdio_write_copy(struct mt76_dev *dev, u32 offset,
> + const void *data, int len);
> +void mt76_connac_sdio_read_copy(struct mt76_dev *dev, u32 offset,
> + void *data, int len);
> +int mt76_connac_sdio_wr_rp(struct mt76_dev *dev, u32 base,
> + const struct mt76_reg_pair *data,
> + int len);
> +int mt76_connac_sdio_rd_rp(struct mt76_dev *dev, u32 base,
> + struct mt76_reg_pair *data,
> + int len);
> +
> +void mt76_connac_sdio_txrx(struct mt76_dev *dev);
> +int mt76_connac_sdio_hw_init(struct mt76_dev *dev, struct sdio_func *func,
> + sdio_irq_handler_t *irq_handler);
> +int mt76_connac_sdio_init(struct mt76_dev *dev,
> + void (*txrx_worker)(struct mt76_worker *));
> +#endif
> diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio_txrx.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio_txrx.c
> new file mode 100644
> index 000000000000..3ef42f90f3f5
> --- /dev/null
> +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio_txrx.c
> @@ -0,0 +1,318 @@
> +// SPDX-License-Identifier: ISC
> +/* Copyright (C) 2020-2021 MediaTek Inc.
> + *
> + * Author: Felix Fietkau <[email protected]>
> + * Lorenzo Bianconi <[email protected]>
> + * Sean Wang <[email protected]>
> + */
> +
> +#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 "trace.h"
> +#include "mt76.h"
> +#include "mt76_connac_sdio.h"
> +
> +static int mt76_connac_sdio_refill_sched_quota(struct mt76_dev *dev, u32 *data)
> +{
> + u32 ple_ac_data_quota[] = {
> + FIELD_GET(TXQ_CNT_L, data[4]), /* VO */
> + FIELD_GET(TXQ_CNT_H, data[3]), /* VI */
> + FIELD_GET(TXQ_CNT_L, data[3]), /* BE */
> + FIELD_GET(TXQ_CNT_H, data[2]), /* BK */
> + };
> + u32 pse_ac_data_quota[] = {
> + FIELD_GET(TXQ_CNT_H, data[1]), /* VO */
> + FIELD_GET(TXQ_CNT_L, data[1]), /* VI */
> + FIELD_GET(TXQ_CNT_H, data[0]), /* BE */
> + FIELD_GET(TXQ_CNT_L, data[0]), /* BK */
> + };
> + u32 pse_mcu_quota = FIELD_GET(TXQ_CNT_L, data[2]);
> + u32 pse_data_quota = 0, ple_data_quota = 0;
> + struct mt76_sdio *sdio = &dev->sdio;
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(pse_ac_data_quota); i++) {
> + pse_data_quota += pse_ac_data_quota[i];
> + ple_data_quota += ple_ac_data_quota[i];
> + }
> +
> + if (!pse_data_quota && !ple_data_quota && !pse_mcu_quota)
> + return 0;
> +
> + sdio->sched.pse_mcu_quota += pse_mcu_quota;
> + sdio->sched.pse_data_quota += pse_data_quota;
> + sdio->sched.ple_data_quota += ple_data_quota;
> +
> + return pse_data_quota + ple_data_quota + pse_mcu_quota;
> +}
> +
> +static struct sk_buff *mt76_connac_sdio_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;
> +
> + skb = alloc_skb(len, GFP_KERNEL);
> + if (!skb)
> + return NULL;
> +
> + skb_put_data(skb, data, len);
> + if (data_len > len) {
> + struct page *page;
> +
> + data += len;
> + page = virt_to_head_page(data);
> + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
> + page, data - page_address(page),
> + data_len - len, buf_len);
> + get_page(page);
> + }
> +
> + return skb;
> +}
> +
> +static int mt76_connac_sdio_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;
> + int len = 0, err, i;
> + struct page *page;
> + u8 *buf;
> +
> + for (i = 0; i < intr->rx.num[qid]; i++)
> + len += round_up(intr->rx.len[qid][i] + 4, 4);
> +
> + if (!len)
> + return 0;
> +
> + if (len > sdio->func->cur_blksize)
> + len = roundup(len, sdio->func->cur_blksize);
> +
> + page = __dev_alloc_pages(GFP_KERNEL, get_order(len));
> + if (!page)
> + return -ENOMEM;
> +
> + buf = page_address(page);
> +
> + err = sdio_readsb(sdio->func, buf, MCR_WRDR(qid), len);
> + if (err < 0) {
> + dev_err(dev->dev, "sdio read data failed:%d\n", err);
> + put_page(page);
> + return err;
> + }
> +
> + for (i = 0; i < intr->rx.num[qid]; i++) {
> + int index = (q->head + i) % q->ndesc;
> + struct mt76_queue_entry *e = &q->entry[index];
> +
> + len = intr->rx.len[qid][i];
> + e->skb = mt76_connac_sdio_build_rx_skb(buf, len,
> + round_up(len + 4, 4));
> + if (!e->skb)
> + break;
> +
> + buf += round_up(len + 4, 4);
> + if (q->queued + i + 1 == q->ndesc)
> + break;
> + }
> + put_page(page);
> +
> + spin_lock_bh(&q->lock);
> + q->head = (q->head + i) % q->ndesc;
> + q->queued += i;
> + spin_unlock_bh(&q->lock);
> +
> + return i;
> +}
> +
> +static int mt76_connac_sdio_rx_handler(struct mt76_dev *dev)
> +{
> + struct mt76_sdio *sdio = &dev->sdio;
> + struct mt76s_intr *intr = sdio->intr_data;
> + int nframes = 0, ret;
> +
> + ret = sdio_readsb(sdio->func, intr, MCR_WHISR, sizeof(*intr));
> + if (ret < 0)
> + return ret;
> +
> + trace_dev_irq(dev, intr->isr, 0);
> +
> + if (intr->isr & WHIER_RX0_DONE_INT_EN) {
> + ret = mt76_connac_sdio_rx_run_queue(dev, 0, intr);
> + if (ret > 0) {
> + mt76_worker_schedule(&sdio->net_worker);
> + nframes += ret;
> + }
> + }
> +
> + if (intr->isr & WHIER_RX1_DONE_INT_EN) {
> + ret = mt76_connac_sdio_rx_run_queue(dev, 1, intr);
> + if (ret > 0) {
> + mt76_worker_schedule(&sdio->net_worker);
> + nframes += ret;
> + }
> + }
> +
> + nframes += !!mt76_connac_sdio_refill_sched_quota(dev, intr->tx.wtqcr);
> +
> + return nframes;
> +}
> +
> +static int mt76_connac_sdio_tx_pick_quota(struct mt76_sdio *sdio, bool mcu,
> + int buf_sz, int *pse_size,
> + int *ple_size)
> +{
> + int pse_sz;
> +
> + pse_sz = DIV_ROUND_UP(buf_sz + sdio->sched.deficit, MT_PSE_PAGE_SZ);
> +
> + if (mcu) {
> + if (sdio->sched.pse_mcu_quota < *pse_size + pse_sz)
> + return -EBUSY;
> + } else {
> + if (sdio->sched.pse_data_quota < *pse_size + pse_sz ||
> + sdio->sched.ple_data_quota < *ple_size + 1)
> + return -EBUSY;
> +
> + *ple_size = *ple_size + 1;
> + }
> + *pse_size = *pse_size + pse_sz;
> +
> + return 0;
> +}
> +
> +static void mt76_connac_sdio_tx_update_quota(struct mt76_sdio *sdio, bool mcu,
> + int pse_size, int ple_size)
> +{
> + if (mcu) {
> + sdio->sched.pse_mcu_quota -= pse_size;
> + } else {
> + sdio->sched.pse_data_quota -= pse_size;
> + sdio->sched.ple_data_quota -= ple_size;
> + }
> +}
> +
> +static int __mt76_connac_sdio_xmit_queue(struct mt76_dev *dev, u8 *data,
> + int len)
> +{
> + struct mt76_sdio *sdio = &dev->sdio;
> + int err;
> +
> + if (len > sdio->func->cur_blksize)
> + len = roundup(len, sdio->func->cur_blksize);
> +
> + err = sdio_writesb(sdio->func, MCR_WTDR1, data, len);
> + if (err)
> + dev_err(dev->dev, "sdio write failed: %d\n", err);
> +
> + return err;
> +}
> +
> +static int mt76_connac_sdio_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];
> + struct mt76_sdio *sdio = &dev->sdio;
> + u8 pad;
> +
> + qid = mcu ? ARRAY_SIZE(sdio->xmit_buf) - 1 : q->qid;
> + while (q->first != q->head) {
> + struct mt76_queue_entry *e = &q->entry[q->first];
> + struct sk_buff *iter;
> +
> + smp_rmb();
> +
> + if (!test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state)) {
> + __skb_put_zero(e->skb, 4);
> + err = __mt76_connac_sdio_xmit_queue(dev, e->skb->data,
> + e->skb->len);
> + if (err)
> + return err;
> +
> + goto next;
> + }
> +
> + pad = roundup(e->skb->len, 4) - e->skb->len;
> + if (len + e->skb->len + pad + 4 > MT76S_XMIT_BUF_SZ)
> + break;
> +
> + if (mt76_connac_sdio_tx_pick_quota(sdio, mcu, e->buf_sz, &pse_sz,
> + &ple_sz))
> + break;
> +
> + memcpy(sdio->xmit_buf[qid] + len, e->skb->data,
> + skb_headlen(e->skb));
> + len += skb_headlen(e->skb);
> + nframes++;
> +
> + skb_walk_frags(e->skb, iter) {
> + memcpy(sdio->xmit_buf[qid] + len, iter->data,
> + iter->len);
> + len += iter->len;
> + nframes++;
> + }
> +
> + if (unlikely(pad)) {
> + memset(sdio->xmit_buf[qid] + len, 0, pad);
> + len += pad;
> + }
> +next:
> + q->first = (q->first + 1) % q->ndesc;
> + e->done = true;
> + }
> +
> + if (nframes) {
> + memset(sdio->xmit_buf[qid] + len, 0, 4);
> + err = __mt76_connac_sdio_xmit_queue(dev, sdio->xmit_buf[qid], len + 4);
> + if (err)
> + return err;
> + }
> + mt76_connac_sdio_tx_update_quota(sdio, mcu, pse_sz, ple_sz);
> +
> + mt76_worker_schedule(&sdio->status_worker);
> +
> + return nframes;
> +}
> +
> +void mt76_connac_sdio_txrx(struct mt76_dev *dev)
> +{
> + struct mt76_sdio *sdio = &dev->sdio;
> + int i, nframes, ret;
> +
> + /* disable interrupt */
> + sdio_claim_host(sdio->func);
> + sdio_writel(sdio->func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, NULL);
> +
> + do {
> + nframes = 0;
> +
> + /* tx */
> + for (i = 0; i <= MT_TXQ_PSD; i++) {
> + ret = mt76_connac_sdio_tx_run_queue(dev, dev->phy.q_tx[i]);
> + if (ret > 0)
> + nframes += ret;
> + }
> + ret = mt76_connac_sdio_tx_run_queue(dev, dev->q_mcu[MT_MCUQ_WM]);
> + if (ret > 0)
> + nframes += ret;
> +
> + /* rx */
> + ret = mt76_connac_sdio_rx_handler(dev);
> + if (ret > 0)
> + nframes += ret;
> + } while (nframes > 0);
> +
> + /* enable interrupt */
> + sdio_writel(sdio->func, WHLPCR_INT_EN_SET, MCR_WHLPCR, NULL);
> + sdio_release_host(sdio->func);
> +}
> +EXPORT_SYMBOL_GPL(mt76_connac_sdio_txrx);
> --
> 2.25.1
>


Attachments:
(No filename) (25.28 kB)
signature.asc (235.00 B)
Download all attachments

2021-09-15 13:24:50

by Lorenzo Bianconi

[permalink] [raw]
Subject: Re: [PATCH v1 09/16] mt76: mt7921: make all event parser resuable between mt7921s and mt7921e

> From: Sean Wang <[email protected]>
>
> The longer event such as the event for mcu_get_nic_capability would hold
> the data in paged fragment skb for the SDIO device so we turn the skb to
> be linearized skb before accessing it to reuse the same event parser
> betweem mt7921s and mt7921e.
>
> Tested-by: Deren Wu <[email protected]>
> Signed-off-by: Sean Wang <[email protected]>
> ---
> drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 9 ++++++++-
> 1 file changed, 8 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
> index f5a8f7fa4244..8e49df20a8cb 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
> @@ -458,7 +458,14 @@ mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb)
>
> void mt7921_mcu_rx_event(struct mt7921_dev *dev, struct sk_buff *skb)
> {
> - struct mt7921_mcu_rxd *rxd = (struct mt7921_mcu_rxd *)skb->data;
> + struct mt7921_mcu_rxd *rxd;
> + int ret;
> +
> + ret = skb_linearize(skb);

is it true for sdio only? if so what about doing something like:

if (mt76_is_sdio() && skb_linearize(skb))
return;

> + if (ret)
> + return;
> +
> + rxd = (struct mt7921_mcu_rxd *)skb->data;
>
> if (rxd->eid == 0x6) {
> mt76_mcu_rx_event(&dev->mt76, skb);
> --
> 2.25.1
>


Attachments:
(No filename) (1.41 kB)
signature.asc (235.00 B)
Download all attachments

2021-09-15 13:26:41

by Lorenzo Bianconi

[permalink] [raw]
Subject: Re: [PATCH v1 10/16] mt76: mt7921: use physical addr to unify register access

On Sep 15, Sean Wang wrote:
> From: Sean Wang <[email protected]>
>
> Use physical address to unify the register access and reorder the
> entries in fixed_map table to accelerate the address lookup for
> MT7921e.
>
> Tested-by: Deren Wu <[email protected]>
> Signed-off-by: Sean Wang <[email protected]>
> ---
> .../net/wireless/mediatek/mt76/mt7921/dma.c | 19 ++++++++--------
> .../net/wireless/mediatek/mt76/mt7921/regs.h | 22 +++++++++----------
> 2 files changed, 21 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
> index be24241fb8e6..f31c4aef8b27 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
> @@ -85,6 +85,14 @@ static u32 __mt7921_reg_addr(struct mt7921_dev *dev, u32 addr)
> u32 mapped;
> u32 size;
> } fixed_map[] = {
> + { 0x820d0000, 0x30000, 0x10000 }, /* WF_LMAC_TOP (WF_WTBLON) */
> + { 0x820ed000, 0x24800, 0x0800 }, /* WF_LMAC_TOP BN0 (WF_MIB) */
> + { 0x820e4000, 0x21000, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_TMAC) */
> + { 0x820e7000, 0x21e00, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_DMA) */
> + { 0x820eb000, 0x24200, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_LPON) */
> + { 0x820e2000, 0x20800, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_AGG) */
> + { 0x820e3000, 0x20c00, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_ARB) */
> + { 0x820e5000, 0x21400, 0x0800 }, /* WF_LMAC_TOP BN0 (WF_RMAC) */
> { 0x00400000, 0x80000, 0x10000}, /* WF_MCU_SYSRAM */
> { 0x00410000, 0x90000, 0x10000}, /* WF_MCU_SYSRAM (configure register) */
> { 0x40000000, 0x70000, 0x10000}, /* WF_UMAC_SYSRAM */

not related to this patch, but since you are chaing it can you please add a
space at the end of the line above? Thanks :)

Regards,
Lorenzo

> @@ -99,22 +107,15 @@ static u32 __mt7921_reg_addr(struct mt7921_dev *dev, u32 addr)
> { 0x81020000, 0xc0000, 0x10000 }, /* WF_TOP_MISC_ON */
> { 0x820c0000, 0x08000, 0x4000 }, /* WF_UMAC_TOP (PLE) */
> { 0x820c8000, 0x0c000, 0x2000 }, /* WF_UMAC_TOP (PSE) */
> - { 0x820cc000, 0x0e000, 0x2000 }, /* WF_UMAC_TOP (PP) */
> + { 0x820cc000, 0x0e000, 0x1000 }, /* WF_UMAC_TOP (PP) */
> + { 0x820cd000, 0x0f000, 0x1000 }, /* WF_MDP_TOP */
> { 0x820ce000, 0x21c00, 0x0200 }, /* WF_LMAC_TOP (WF_SEC) */
> { 0x820cf000, 0x22000, 0x1000 }, /* WF_LMAC_TOP (WF_PF) */
> - { 0x820d0000, 0x30000, 0x10000 }, /* WF_LMAC_TOP (WF_WTBLON) */
> { 0x820e0000, 0x20000, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_CFG) */
> { 0x820e1000, 0x20400, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_TRB) */
> - { 0x820e2000, 0x20800, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_AGG) */
> - { 0x820e3000, 0x20c00, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_ARB) */
> - { 0x820e4000, 0x21000, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_TMAC) */
> - { 0x820e5000, 0x21400, 0x0800 }, /* WF_LMAC_TOP BN0 (WF_RMAC) */
> - { 0x820e7000, 0x21e00, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_DMA) */
> { 0x820e9000, 0x23400, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_WTBLOFF) */
> { 0x820ea000, 0x24000, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_ETBF) */
> - { 0x820eb000, 0x24200, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_LPON) */
> { 0x820ec000, 0x24600, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_INT) */
> - { 0x820ed000, 0x24800, 0x0800 }, /* WF_LMAC_TOP BN0 (WF_MIB) */
> { 0x820f0000, 0xa0000, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_CFG) */
> { 0x820f1000, 0xa0600, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_TRB) */
> { 0x820f2000, 0xa0800, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_AGG) */
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regs.h b/drivers/net/wireless/mediatek/mt76/mt7921/regs.h
> index 26fb11823762..cb6069024320 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7921/regs.h
> +++ b/drivers/net/wireless/mediatek/mt76/mt7921/regs.h
> @@ -14,7 +14,7 @@
> #define MT_MCU_INT_EVENT_SER_TRIGGER BIT(2)
> #define MT_MCU_INT_EVENT_RESET_DONE BIT(3)
>
> -#define MT_PLE_BASE 0x8000
> +#define MT_PLE_BASE 0x820c0000
> #define MT_PLE(ofs) (MT_PLE_BASE + (ofs))
>
> #define MT_PLE_FL_Q0_CTRL MT_PLE(0x1b0)
> @@ -26,7 +26,7 @@
> ((n) << 2))
> #define MT_PLE_AMSDU_PACK_MSDU_CNT(n) MT_PLE(0x10e0 + ((n) << 2))
>
> -#define MT_MDP_BASE 0xf000
> +#define MT_MDP_BASE 0x820cd000
> #define MT_MDP(ofs) (MT_MDP_BASE + (ofs))
>
> #define MT_MDP_DCR0 MT_MDP(0x000)
> @@ -49,7 +49,7 @@
> #define MT_MDP_TO_WM 1
>
> /* TMAC: band 0(0x21000), band 1(0xa1000) */
> -#define MT_WF_TMAC_BASE(_band) ((_band) ? 0xa1000 : 0x21000)
> +#define MT_WF_TMAC_BASE(_band) ((_band) ? 0x820f4000 : 0x820e4000)
> #define MT_WF_TMAC(_band, ofs) (MT_WF_TMAC_BASE(_band) + (ofs))
>
> #define MT_TMAC_TCR0(_band) MT_WF_TMAC(_band, 0)
> @@ -74,7 +74,7 @@
> #define MT_TMAC_TRCR0(_band) MT_WF_TMAC(_band, 0x09c)
> #define MT_TMAC_TFCR0(_band) MT_WF_TMAC(_band, 0x1e0)
>
> -#define MT_WF_DMA_BASE(_band) ((_band) ? 0xa1e00 : 0x21e00)
> +#define MT_WF_DMA_BASE(_band) ((_band) ? 0x820f7000 : 0x820e7000)
> #define MT_WF_DMA(_band, ofs) (MT_WF_DMA_BASE(_band) + (ofs))
>
> #define MT_DMA_DCR0(_band) MT_WF_DMA(_band, 0x000)
> @@ -82,7 +82,7 @@
> #define MT_DMA_DCR0_RXD_G5_EN BIT(23)
>
> /* LPON: band 0(0x24200), band 1(0xa4200) */
> -#define MT_WF_LPON_BASE(_band) ((_band) ? 0xa4200 : 0x24200)
> +#define MT_WF_LPON_BASE(_band) ((_band) ? 0x820fb000 : 0x820eb000)
> #define MT_WF_LPON(_band, ofs) (MT_WF_LPON_BASE(_band) + (ofs))
>
> #define MT_LPON_UTTR0(_band) MT_WF_LPON(_band, 0x080)
> @@ -93,7 +93,7 @@
> #define MT_LPON_TCR_SW_WRITE BIT(0)
>
> /* MIB: band 0(0x24800), band 1(0xa4800) */
> -#define MT_WF_MIB_BASE(_band) ((_band) ? 0xa4800 : 0x24800)
> +#define MT_WF_MIB_BASE(_band) ((_band) ? 0x820fd000 : 0x820ed000)
> #define MT_WF_MIB(_band, ofs) (MT_WF_MIB_BASE(_band) + (ofs))
>
> #define MT_MIB_SCR1(_band) MT_WF_MIB(_band, 0x004)
> @@ -142,7 +142,7 @@
> #define MT_MIB_ARNG(_band, n) MT_WF_MIB(_band, 0x0b0 + ((n) << 2))
> #define MT_MIB_ARNCR_RANGE(val, n) (((val) >> ((n) << 3)) & GENMASK(7, 0))
>
> -#define MT_WTBLON_TOP_BASE 0x34000
> +#define MT_WTBLON_TOP_BASE 0x820d4000
> #define MT_WTBLON_TOP(ofs) (MT_WTBLON_TOP_BASE + (ofs))
> #define MT_WTBLON_TOP_WDUCR MT_WTBLON_TOP(0x200)
> #define MT_WTBLON_TOP_WDUCR_GROUP GENMASK(2, 0)
> @@ -152,7 +152,7 @@
> #define MT_WTBL_UPDATE_ADM_COUNT_CLEAR BIT(12)
> #define MT_WTBL_UPDATE_BUSY BIT(31)
>
> -#define MT_WTBL_BASE 0x38000
> +#define MT_WTBL_BASE 0x820d8000
> #define MT_WTBL_LMAC_ID GENMASK(14, 8)
> #define MT_WTBL_LMAC_DW GENMASK(7, 2)
> #define MT_WTBL_LMAC_OFFS(_id, _dw) (MT_WTBL_BASE | \
> @@ -160,7 +160,7 @@
> FIELD_PREP(MT_WTBL_LMAC_DW, _dw))
>
> /* AGG: band 0(0x20800), band 1(0xa0800) */
> -#define MT_WF_AGG_BASE(_band) ((_band) ? 0xa0800 : 0x20800)
> +#define MT_WF_AGG_BASE(_band) ((_band) ? 0x820f2000 : 0x820e2000)
> #define MT_WF_AGG(_band, ofs) (MT_WF_AGG_BASE(_band) + (ofs))
>
> #define MT_AGG_AWSCR0(_band, _n) MT_WF_AGG(_band, 0x05c + (_n) * 4)
> @@ -191,7 +191,7 @@
> #define MT_AGG_ATCR3(_band) MT_WF_AGG(_band, 0x0f4)
>
> /* ARB: band 0(0x20c00), band 1(0xa0c00) */
> -#define MT_WF_ARB_BASE(_band) ((_band) ? 0xa0c00 : 0x20c00)
> +#define MT_WF_ARB_BASE(_band) ((_band) ? 0x820f3000 : 0x820e3000)
> #define MT_WF_ARB(_band, ofs) (MT_WF_ARB_BASE(_band) + (ofs))
>
> #define MT_ARB_SCR(_band) MT_WF_ARB(_band, 0x080)
> @@ -201,7 +201,7 @@
> #define MT_ARB_DRNGR0(_band, _n) MT_WF_ARB(_band, 0x194 + (_n) * 4)
>
> /* RMAC: band 0(0x21400), band 1(0xa1400) */
> -#define MT_WF_RMAC_BASE(_band) ((_band) ? 0xa1400 : 0x21400)
> +#define MT_WF_RMAC_BASE(_band) ((_band) ? 0x820f5000 : 0x820e5000)
> #define MT_WF_RMAC(_band, ofs) (MT_WF_RMAC_BASE(_band) + (ofs))
>
> #define MT_WF_RFCR(_band) MT_WF_RMAC(_band, 0x000)
> --
> 2.25.1
>


Attachments:
(No filename) (7.79 kB)
signature.asc (235.00 B)
Download all attachments

2021-09-15 13:32:04

by Lorenzo Bianconi

[permalink] [raw]
Subject: Re: [PATCH v1 09/16] mt76: mt7921: make all event parser resuable between mt7921s and mt7921e

> > From: Sean Wang <[email protected]>
> >
> > The longer event such as the event for mcu_get_nic_capability would hold
> > the data in paged fragment skb for the SDIO device so we turn the skb to
> > be linearized skb before accessing it to reuse the same event parser
> > betweem mt7921s and mt7921e.
> >
> > Tested-by: Deren Wu <[email protected]>
> > Signed-off-by: Sean Wang <[email protected]>
> > ---
> > drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 9 ++++++++-
> > 1 file changed, 8 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
> > index f5a8f7fa4244..8e49df20a8cb 100644
> > --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
> > +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
> > @@ -458,7 +458,14 @@ mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb)
> >
> > void mt7921_mcu_rx_event(struct mt7921_dev *dev, struct sk_buff *skb)
> > {
> > - struct mt7921_mcu_rxd *rxd = (struct mt7921_mcu_rxd *)skb->data;
> > + struct mt7921_mcu_rxd *rxd;
> > + int ret;
> > +
> > + ret = skb_linearize(skb);
>
> is it true for sdio only? if so what about doing something like:
>
> if (mt76_is_sdio() && skb_linearize(skb))
> return;

please ignore this comment, it is already in skb_linearize()

>
> > + if (ret)
> > + return;
> > +
> > + rxd = (struct mt7921_mcu_rxd *)skb->data;
> >
> > if (rxd->eid == 0x6) {
> > mt76_mcu_rx_event(&dev->mt76, skb);
> > --
> > 2.25.1
> >



Attachments:
(No filename) (1.56 kB)
signature.asc (235.00 B)
Download all attachments

2021-09-15 14:32:28

by Lorenzo Bianconi

[permalink] [raw]
Subject: Re: [PATCH v1 07/16] mt76: connac: move sdio utility routines in mt76_connac_sdio module

> On Sep 15, Sean Wang wrote:
> > From: Sean Wang <[email protected]>
> >
> > This is a preliminary patch before introduce mt7921s support to hold the
> > common sdio utilities between mt7663s and mt7921s in mt76_connac_sdio
> > module.
> >
> > mt76/mt76_connac_sdio.c, mt76/mt76_connac_sdio.h and
> > mt76/mt76_connac_sdio_txrx.c originate from mt7615/sdio.c, mt7615/sdio.h
> > and mt7615/sdio_txrx.c and the patch don't add any logic change.
> >
> > Tested-by: Deren Wu <[email protected]>
> > Signed-off-by: Sean Wang <[email protected]>
> > ---
> > drivers/net/wireless/mediatek/mt76/Kconfig | 5 +
> > drivers/net/wireless/mediatek/mt76/Makefile | 2 +
> > .../wireless/mediatek/mt76/mt76_connac_sdio.c | 317 +++++++++++++++++
> > .../wireless/mediatek/mt76/mt76_connac_sdio.h | 137 ++++++++
> > .../mediatek/mt76/mt76_connac_sdio_txrx.c | 318 ++++++++++++++++++
> > 5 files changed, 779 insertions(+)
> > create mode 100644 drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.c
> > create mode 100644 drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.h
> > create mode 100644 drivers/net/wireless/mediatek/mt76/mt76_connac_sdio_txrx.c
> >
> > diff --git a/drivers/net/wireless/mediatek/mt76/Kconfig b/drivers/net/wireless/mediatek/mt76/Kconfig
> > index 9ff43f1fc50d..a6b388bfb563 100644
> > --- a/drivers/net/wireless/mediatek/mt76/Kconfig
> > +++ b/drivers/net/wireless/mediatek/mt76/Kconfig
> > @@ -28,6 +28,11 @@ config MT76_CONNAC_LIB
> > tristate
> > select MT76_CORE
> >
> > +config MT76_CONNAC_SDIO
> > + tristate
> > + depends on MMC
> > + select MT76_CONNAC_LIB
> > +
> > source "drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig"
> > source "drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig"
> > source "drivers/net/wireless/mediatek/mt76/mt7603/Kconfig"
> > diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile
> > index 94efe3c29053..17b2ed93f6a3 100644
> > --- a/drivers/net/wireless/mediatek/mt76/Makefile
> > +++ b/drivers/net/wireless/mediatek/mt76/Makefile
> > @@ -5,6 +5,7 @@ obj-$(CONFIG_MT76_SDIO) += mt76-sdio.o
> > obj-$(CONFIG_MT76x02_LIB) += mt76x02-lib.o
> > obj-$(CONFIG_MT76x02_USB) += mt76x02-usb.o
> > obj-$(CONFIG_MT76_CONNAC_LIB) += mt76-connac-lib.o
> > +obj-$(CONFIG_MT76_CONNAC_SDIO) += mt76-connac-sdio.o
> >
> > mt76-y := \
> > mmio.o util.o trace.o dma.o mac80211.o debugfs.o eeprom.o \
> > @@ -28,6 +29,7 @@ mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o mt76x02_mcu.o \
> > mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o
> >
> > mt76-connac-lib-y := mt76_connac_mcu.o mt76_connac_mac.o
> > +mt76-connac-sdio-y := mt76_connac_sdio.o mt76_connac_sdio_txrx.o
> >
> > obj-$(CONFIG_MT76x0_COMMON) += mt76x0/
> > obj-$(CONFIG_MT76x2_COMMON) += mt76x2/
> > diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.c
> > new file mode 100644
> > index 000000000000..d18a66e5445f
> > --- /dev/null
> > +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.c
> > @@ -0,0 +1,317 @@
> > +// SPDX-License-Identifier: ISC
> > +/* Copyright (C) 2020-2021 MediaTek Inc.
> > + *
> > + * Author: Felix Fietkau <[email protected]>
> > + * Lorenzo Bianconi <[email protected]>
> > + * Sean Wang <[email protected]>
> > + */
> > +
> > +#include <linux/iopoll.h>
> > +#include <linux/mmc/host.h>
> > +#include <linux/mmc/sdio_func.h>
> > +
> > +#include "mt76.h"
> > +#include "mt76_connac_mcu.h"
> > +#include "mt76_connac_sdio.h"
> > +
> > +static u32 mt76_connac_sdio_read_whisr(struct mt76_dev *dev)
> > +{
> > + return sdio_readl(dev->sdio.func, MCR_WHISR, NULL);
> > +}
> > +
> > +u32 mt76_connac_sdio_read_pcr(struct mt76_dev *dev)
> > +{
> > + struct mt76_sdio *sdio = &dev->sdio;
> > +
> > + return sdio_readl(sdio->func, MCR_WHLPCR, NULL);
> > +}
> > +EXPORT_SYMBOL_GPL(mt76_connac_sdio_read_pcr);
> > +
> > +u32 mt76_connac_sdio_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(mt76_connac_sdio_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;
> > +}
> > +EXPORT_SYMBOL_GPL(mt76_connac_sdio_read_mailbox);
> > +
> > +void mt76_connac_sdio_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(mt76_connac_sdio_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);
> > +}
> > +EXPORT_SYMBOL_GPL(mt76_connac_sdio_write_mailbox);
> > +
> > +u32 mt76_connac_sdio_rr(struct mt76_dev *dev, u32 offset)
> > +{
> > + if (test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state))
> > + return mt76_connac_mcu_reg_rr(dev, offset);
> > + else
> > + return mt76_connac_sdio_read_mailbox(dev, offset);
> > +}
> > +EXPORT_SYMBOL_GPL(mt76_connac_sdio_rr);
> > +
> > +void mt76_connac_sdio_wr(struct mt76_dev *dev, u32 offset, u32 val)
> > +{
> > + if (test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state))
> > + mt76_connac_mcu_reg_wr(dev, offset, val);
> > + else
> > + mt76_connac_sdio_write_mailbox(dev, offset, val);
> > +}
> > +EXPORT_SYMBOL_GPL(mt76_connac_sdio_wr);
> > +
> > +u32 mt76_connac_sdio_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val)
> > +{
> > + val |= mt76_connac_sdio_rr(dev, offset) & ~mask;
> > + mt76_connac_sdio_wr(dev, offset, val);
> > +
> > + return val;
> > +}
> > +EXPORT_SYMBOL_GPL(mt76_connac_sdio_rmw);
> > +
> > +void mt76_connac_sdio_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++) {
> > + mt76_connac_sdio_wr(dev, offset, val[i]);
> > + offset += sizeof(u32);
> > + }
> > +}
> > +EXPORT_SYMBOL_GPL(mt76_connac_sdio_write_copy);
> > +
> > +void mt76_connac_sdio_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] = mt76_connac_sdio_rr(dev, offset);
> > + offset += sizeof(u32);
> > + }
> > +}
> > +EXPORT_SYMBOL_GPL(mt76_connac_sdio_read_copy);
> > +
> > +int mt76_connac_sdio_wr_rp(struct mt76_dev *dev, u32 base,
> > + const struct mt76_reg_pair *data,
> > + int len)
> > +{
> > + int i;
> > +
> > + for (i = 0; i < len; i++) {
> > + mt76_connac_sdio_wr(dev, data->reg, data->value);
> > + data++;
> > + }
> > +
> > + return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(mt76_connac_sdio_wr_rp);
> > +
> > +int mt76_connac_sdio_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 = mt76_connac_sdio_rr(dev, data->reg);
> > + data++;
> > + }
> > +
> > + return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(mt76_connac_sdio_rd_rp);
> > +
> > +int mt76_connac_sdio_hw_init(struct mt76_dev *dev, struct sdio_func *func,
> > + sdio_irq_handler_t *irq_handler)
> > +{
> > + 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(mt76_connac_sdio_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, irq_handler);
>
> The only difference between mt7921s_irq and mt7663s_irq is the RESET check,
> right? Maybe we just need to add the same check for mt7663s_irq and move the
> routine here?

oh, I got it..the issue is the pm struct :(

Regards,
Lorenzo

>
> > + 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(mt76_connac_sdio_hw_init);
> > +
> > +int mt76_connac_sdio_init(struct mt76_dev *dev,
> > + void (*txrx_worker)(struct mt76_worker *))
> > +{
> > + int i, ret;
> > +
> > + dev->sdio.intr_data = devm_kmalloc(dev->dev,
> > + sizeof(struct mt76s_intr),
> > + GFP_KERNEL);
> > + if (!dev->sdio.intr_data)
> > + return -ENOMEM;
> > +
> > + for (i = 0; i < ARRAY_SIZE(dev->sdio.xmit_buf); i++) {
> > + dev->sdio.xmit_buf[i] = devm_kmalloc(dev->dev,
> > + MT76S_XMIT_BUF_SZ,
> > + GFP_KERNEL);
> > + if (!dev->sdio.xmit_buf[i])
> > + return -ENOMEM;
> > + }
> > +
> > + ret = mt76_worker_setup(dev->hw, &dev->sdio.txrx_worker, txrx_worker,
> > + "sdio-txrx");
>
> Same here, I guess we can move mt7921s_txrx_worker here and share it with
> mt7663s
>
> > + if (ret)
> > + return ret;
> > +
> > + sched_set_fifo_low(dev->sdio.txrx_worker.task);
> > +
> > + return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(mt76_connac_sdio_init);
> > +
> > +MODULE_AUTHOR("Sean Wang <[email protected]>");
> > +MODULE_AUTHOR("Lorenzo Bianconi <[email protected]>");
> > +MODULE_LICENSE("Dual BSD/GPL");
> > diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.h
> > new file mode 100644
> > index 000000000000..e176d6e562b2
> > --- /dev/null
> > +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio.h
> > @@ -0,0 +1,137 @@
> > +/* SPDX-License-Identifier: ISC */
> > +/* Copyright (C) 2020-2021 MediaTek Inc.
> > + *
> > + * Author: Sean Wang <[email protected]>
> > + */
> > +
> > +#ifndef __MT76_CONNAC_SDIO_H
> > +#define __MT76_CONNAC_SDIO_H
> > +
> > +#define MT_PSE_PAGE_SZ 128
> > +
> > +#define MCR_WCIR 0x0000
> > +#define MCR_WHLPCR 0x0004
> > +#define WHLPCR_FW_OWN_REQ_CLR BIT(9)
> > +#define WHLPCR_FW_OWN_REQ_SET BIT(8)
> > +#define WHLPCR_IS_DRIVER_OWN BIT(8)
> > +#define WHLPCR_INT_EN_CLR BIT(1)
> > +#define WHLPCR_INT_EN_SET BIT(0)
> > +
> > +#define MCR_WSDIOCSR 0x0008
> > +#define MCR_WHCR 0x000C
> > +#define W_INT_CLR_CTRL BIT(1)
> > +#define RECV_MAILBOX_RD_CLR_EN BIT(2)
> > +#define MAX_HIF_RX_LEN_NUM GENMASK(13, 8)
> > +#define RX_ENHANCE_MODE BIT(16)
> > +
> > +#define MCR_WHISR 0x0010
> > +#define MCR_WHIER 0x0014
> > +#define WHIER_D2H_SW_INT GENMASK(31, 8)
> > +#define WHIER_FW_OWN_BACK_INT_EN BIT(7)
> > +#define WHIER_ABNORMAL_INT_EN BIT(6)
> > +#define WHIER_RX1_DONE_INT_EN BIT(2)
> > +#define WHIER_RX0_DONE_INT_EN BIT(1)
> > +#define WHIER_TX_DONE_INT_EN BIT(0)
> > +#define WHIER_DEFAULT (WHIER_RX0_DONE_INT_EN | \
> > + WHIER_RX1_DONE_INT_EN | \
> > + WHIER_TX_DONE_INT_EN | \
> > + WHIER_ABNORMAL_INT_EN | \
> > + WHIER_D2H_SW_INT)
> > +
> > +#define MCR_WASR 0x0020
> > +#define MCR_WSICR 0x0024
> > +#define MCR_WTSR0 0x0028
> > +#define TQ0_CNT GENMASK(7, 0)
> > +#define TQ1_CNT GENMASK(15, 8)
> > +#define TQ2_CNT GENMASK(23, 16)
> > +#define TQ3_CNT GENMASK(31, 24)
> > +
> > +#define MCR_WTSR1 0x002c
> > +#define TQ4_CNT GENMASK(7, 0)
> > +#define TQ5_CNT GENMASK(15, 8)
> > +#define TQ6_CNT GENMASK(23, 16)
> > +#define TQ7_CNT GENMASK(31, 24)
> > +
> > +#define MCR_WTDR1 0x0034
> > +#define MCR_WRDR0 0x0050
> > +#define MCR_WRDR1 0x0054
> > +#define MCR_WRDR(p) (0x0050 + 4 * (p))
> > +#define MCR_H2DSM0R 0x0070
> > +#define H2D_SW_INT_READ BIT(16)
> > +#define H2D_SW_INT_WRITE BIT(17)
> > +
> > +#define MCR_H2DSM1R 0x0074
> > +#define MCR_D2HRM0R 0x0078
> > +#define MCR_D2HRM1R 0x007c
> > +#define MCR_D2HRM2R 0x0080
> > +#define MCR_WRPLR 0x0090
> > +#define RX0_PACKET_LENGTH GENMASK(15, 0)
> > +#define RX1_PACKET_LENGTH GENMASK(31, 16)
> > +
> > +#define MCR_WTMDR 0x00b0
> > +#define MCR_WTMCR 0x00b4
> > +#define MCR_WTMDPCR0 0x00b8
> > +#define MCR_WTMDPCR1 0x00bc
> > +#define MCR_WPLRCR 0x00d4
> > +#define MCR_WSR 0x00D8
> > +#define MCR_CLKIOCR 0x0100
> > +#define MCR_CMDIOCR 0x0104
> > +#define MCR_DAT0IOCR 0x0108
> > +#define MCR_DAT1IOCR 0x010C
> > +#define MCR_DAT2IOCR 0x0110
> > +#define MCR_DAT3IOCR 0x0114
> > +#define MCR_CLKDLYCR 0x0118
> > +#define MCR_CMDDLYCR 0x011C
> > +#define MCR_ODATDLYCR 0x0120
> > +#define MCR_IDATDLYCR1 0x0124
> > +#define MCR_IDATDLYCR2 0x0128
> > +#define MCR_ILCHCR 0x012C
> > +#define MCR_WTQCR0 0x0130
> > +#define MCR_WTQCR1 0x0134
> > +#define MCR_WTQCR2 0x0138
> > +#define MCR_WTQCR3 0x013C
> > +#define MCR_WTQCR4 0x0140
> > +#define MCR_WTQCR5 0x0144
> > +#define MCR_WTQCR6 0x0148
> > +#define MCR_WTQCR7 0x014C
> > +#define MCR_WTQCR(x) (0x130 + 4 * (x))
> > +#define TXQ_CNT_L GENMASK(15, 0)
> > +#define TXQ_CNT_H GENMASK(31, 16)
> > +
> > +#define MCR_SWPCDBGR 0x0154
> > +
> > +struct mt76s_intr {
> > + u32 isr;
> > + struct {
> > + u32 wtqcr[8];
> > + } tx;
> > + struct {
> > + u16 num[2];
> > + u16 len[2][16];
> > + } rx;
> > + u32 rec_mb[2];
> > +} __packed;
> > +
> > +u32 mt76_connac_sdio_read_pcr(struct mt76_dev *dev);
> > +u32 mt76_connac_sdio_read_mailbox(struct mt76_dev *dev, u32 offset);
> > +void mt76_connac_sdio_write_mailbox(struct mt76_dev *dev, u32 offset, u32 val);
> > +u32 mt76_connac_sdio_rr(struct mt76_dev *dev, u32 offset);
> > +void mt76_connac_sdio_wr(struct mt76_dev *dev, u32 offset, u32 val);
> > +u32 mt76_connac_sdio_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val);
> > +void mt76_connac_sdio_write_copy(struct mt76_dev *dev, u32 offset,
> > + const void *data, int len);
> > +void mt76_connac_sdio_read_copy(struct mt76_dev *dev, u32 offset,
> > + void *data, int len);
> > +int mt76_connac_sdio_wr_rp(struct mt76_dev *dev, u32 base,
> > + const struct mt76_reg_pair *data,
> > + int len);
> > +int mt76_connac_sdio_rd_rp(struct mt76_dev *dev, u32 base,
> > + struct mt76_reg_pair *data,
> > + int len);
> > +
> > +void mt76_connac_sdio_txrx(struct mt76_dev *dev);
> > +int mt76_connac_sdio_hw_init(struct mt76_dev *dev, struct sdio_func *func,
> > + sdio_irq_handler_t *irq_handler);
> > +int mt76_connac_sdio_init(struct mt76_dev *dev,
> > + void (*txrx_worker)(struct mt76_worker *));
> > +#endif
> > diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio_txrx.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio_txrx.c
> > new file mode 100644
> > index 000000000000..3ef42f90f3f5
> > --- /dev/null
> > +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_sdio_txrx.c
> > @@ -0,0 +1,318 @@
> > +// SPDX-License-Identifier: ISC
> > +/* Copyright (C) 2020-2021 MediaTek Inc.
> > + *
> > + * Author: Felix Fietkau <[email protected]>
> > + * Lorenzo Bianconi <[email protected]>
> > + * Sean Wang <[email protected]>
> > + */
> > +
> > +#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 "trace.h"
> > +#include "mt76.h"
> > +#include "mt76_connac_sdio.h"
> > +
> > +static int mt76_connac_sdio_refill_sched_quota(struct mt76_dev *dev, u32 *data)
> > +{
> > + u32 ple_ac_data_quota[] = {
> > + FIELD_GET(TXQ_CNT_L, data[4]), /* VO */
> > + FIELD_GET(TXQ_CNT_H, data[3]), /* VI */
> > + FIELD_GET(TXQ_CNT_L, data[3]), /* BE */
> > + FIELD_GET(TXQ_CNT_H, data[2]), /* BK */
> > + };
> > + u32 pse_ac_data_quota[] = {
> > + FIELD_GET(TXQ_CNT_H, data[1]), /* VO */
> > + FIELD_GET(TXQ_CNT_L, data[1]), /* VI */
> > + FIELD_GET(TXQ_CNT_H, data[0]), /* BE */
> > + FIELD_GET(TXQ_CNT_L, data[0]), /* BK */
> > + };
> > + u32 pse_mcu_quota = FIELD_GET(TXQ_CNT_L, data[2]);
> > + u32 pse_data_quota = 0, ple_data_quota = 0;
> > + struct mt76_sdio *sdio = &dev->sdio;
> > + int i;
> > +
> > + for (i = 0; i < ARRAY_SIZE(pse_ac_data_quota); i++) {
> > + pse_data_quota += pse_ac_data_quota[i];
> > + ple_data_quota += ple_ac_data_quota[i];
> > + }
> > +
> > + if (!pse_data_quota && !ple_data_quota && !pse_mcu_quota)
> > + return 0;
> > +
> > + sdio->sched.pse_mcu_quota += pse_mcu_quota;
> > + sdio->sched.pse_data_quota += pse_data_quota;
> > + sdio->sched.ple_data_quota += ple_data_quota;
> > +
> > + return pse_data_quota + ple_data_quota + pse_mcu_quota;
> > +}
> > +
> > +static struct sk_buff *mt76_connac_sdio_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;
> > +
> > + skb = alloc_skb(len, GFP_KERNEL);
> > + if (!skb)
> > + return NULL;
> > +
> > + skb_put_data(skb, data, len);
> > + if (data_len > len) {
> > + struct page *page;
> > +
> > + data += len;
> > + page = virt_to_head_page(data);
> > + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
> > + page, data - page_address(page),
> > + data_len - len, buf_len);
> > + get_page(page);
> > + }
> > +
> > + return skb;
> > +}
> > +
> > +static int mt76_connac_sdio_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;
> > + int len = 0, err, i;
> > + struct page *page;
> > + u8 *buf;
> > +
> > + for (i = 0; i < intr->rx.num[qid]; i++)
> > + len += round_up(intr->rx.len[qid][i] + 4, 4);
> > +
> > + if (!len)
> > + return 0;
> > +
> > + if (len > sdio->func->cur_blksize)
> > + len = roundup(len, sdio->func->cur_blksize);
> > +
> > + page = __dev_alloc_pages(GFP_KERNEL, get_order(len));
> > + if (!page)
> > + return -ENOMEM;
> > +
> > + buf = page_address(page);
> > +
> > + err = sdio_readsb(sdio->func, buf, MCR_WRDR(qid), len);
> > + if (err < 0) {
> > + dev_err(dev->dev, "sdio read data failed:%d\n", err);
> > + put_page(page);
> > + return err;
> > + }
> > +
> > + for (i = 0; i < intr->rx.num[qid]; i++) {
> > + int index = (q->head + i) % q->ndesc;
> > + struct mt76_queue_entry *e = &q->entry[index];
> > +
> > + len = intr->rx.len[qid][i];
> > + e->skb = mt76_connac_sdio_build_rx_skb(buf, len,
> > + round_up(len + 4, 4));
> > + if (!e->skb)
> > + break;
> > +
> > + buf += round_up(len + 4, 4);
> > + if (q->queued + i + 1 == q->ndesc)
> > + break;
> > + }
> > + put_page(page);
> > +
> > + spin_lock_bh(&q->lock);
> > + q->head = (q->head + i) % q->ndesc;
> > + q->queued += i;
> > + spin_unlock_bh(&q->lock);
> > +
> > + return i;
> > +}
> > +
> > +static int mt76_connac_sdio_rx_handler(struct mt76_dev *dev)
> > +{
> > + struct mt76_sdio *sdio = &dev->sdio;
> > + struct mt76s_intr *intr = sdio->intr_data;
> > + int nframes = 0, ret;
> > +
> > + ret = sdio_readsb(sdio->func, intr, MCR_WHISR, sizeof(*intr));
> > + if (ret < 0)
> > + return ret;
> > +
> > + trace_dev_irq(dev, intr->isr, 0);
> > +
> > + if (intr->isr & WHIER_RX0_DONE_INT_EN) {
> > + ret = mt76_connac_sdio_rx_run_queue(dev, 0, intr);
> > + if (ret > 0) {
> > + mt76_worker_schedule(&sdio->net_worker);
> > + nframes += ret;
> > + }
> > + }
> > +
> > + if (intr->isr & WHIER_RX1_DONE_INT_EN) {
> > + ret = mt76_connac_sdio_rx_run_queue(dev, 1, intr);
> > + if (ret > 0) {
> > + mt76_worker_schedule(&sdio->net_worker);
> > + nframes += ret;
> > + }
> > + }
> > +
> > + nframes += !!mt76_connac_sdio_refill_sched_quota(dev, intr->tx.wtqcr);
> > +
> > + return nframes;
> > +}
> > +
> > +static int mt76_connac_sdio_tx_pick_quota(struct mt76_sdio *sdio, bool mcu,
> > + int buf_sz, int *pse_size,
> > + int *ple_size)
> > +{
> > + int pse_sz;
> > +
> > + pse_sz = DIV_ROUND_UP(buf_sz + sdio->sched.deficit, MT_PSE_PAGE_SZ);
> > +
> > + if (mcu) {
> > + if (sdio->sched.pse_mcu_quota < *pse_size + pse_sz)
> > + return -EBUSY;
> > + } else {
> > + if (sdio->sched.pse_data_quota < *pse_size + pse_sz ||
> > + sdio->sched.ple_data_quota < *ple_size + 1)
> > + return -EBUSY;
> > +
> > + *ple_size = *ple_size + 1;
> > + }
> > + *pse_size = *pse_size + pse_sz;
> > +
> > + return 0;
> > +}
> > +
> > +static void mt76_connac_sdio_tx_update_quota(struct mt76_sdio *sdio, bool mcu,
> > + int pse_size, int ple_size)
> > +{
> > + if (mcu) {
> > + sdio->sched.pse_mcu_quota -= pse_size;
> > + } else {
> > + sdio->sched.pse_data_quota -= pse_size;
> > + sdio->sched.ple_data_quota -= ple_size;
> > + }
> > +}
> > +
> > +static int __mt76_connac_sdio_xmit_queue(struct mt76_dev *dev, u8 *data,
> > + int len)
> > +{
> > + struct mt76_sdio *sdio = &dev->sdio;
> > + int err;
> > +
> > + if (len > sdio->func->cur_blksize)
> > + len = roundup(len, sdio->func->cur_blksize);
> > +
> > + err = sdio_writesb(sdio->func, MCR_WTDR1, data, len);
> > + if (err)
> > + dev_err(dev->dev, "sdio write failed: %d\n", err);
> > +
> > + return err;
> > +}
> > +
> > +static int mt76_connac_sdio_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];
> > + struct mt76_sdio *sdio = &dev->sdio;
> > + u8 pad;
> > +
> > + qid = mcu ? ARRAY_SIZE(sdio->xmit_buf) - 1 : q->qid;
> > + while (q->first != q->head) {
> > + struct mt76_queue_entry *e = &q->entry[q->first];
> > + struct sk_buff *iter;
> > +
> > + smp_rmb();
> > +
> > + if (!test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state)) {
> > + __skb_put_zero(e->skb, 4);
> > + err = __mt76_connac_sdio_xmit_queue(dev, e->skb->data,
> > + e->skb->len);
> > + if (err)
> > + return err;
> > +
> > + goto next;
> > + }
> > +
> > + pad = roundup(e->skb->len, 4) - e->skb->len;
> > + if (len + e->skb->len + pad + 4 > MT76S_XMIT_BUF_SZ)
> > + break;
> > +
> > + if (mt76_connac_sdio_tx_pick_quota(sdio, mcu, e->buf_sz, &pse_sz,
> > + &ple_sz))
> > + break;
> > +
> > + memcpy(sdio->xmit_buf[qid] + len, e->skb->data,
> > + skb_headlen(e->skb));
> > + len += skb_headlen(e->skb);
> > + nframes++;
> > +
> > + skb_walk_frags(e->skb, iter) {
> > + memcpy(sdio->xmit_buf[qid] + len, iter->data,
> > + iter->len);
> > + len += iter->len;
> > + nframes++;
> > + }
> > +
> > + if (unlikely(pad)) {
> > + memset(sdio->xmit_buf[qid] + len, 0, pad);
> > + len += pad;
> > + }
> > +next:
> > + q->first = (q->first + 1) % q->ndesc;
> > + e->done = true;
> > + }
> > +
> > + if (nframes) {
> > + memset(sdio->xmit_buf[qid] + len, 0, 4);
> > + err = __mt76_connac_sdio_xmit_queue(dev, sdio->xmit_buf[qid], len + 4);
> > + if (err)
> > + return err;
> > + }
> > + mt76_connac_sdio_tx_update_quota(sdio, mcu, pse_sz, ple_sz);
> > +
> > + mt76_worker_schedule(&sdio->status_worker);
> > +
> > + return nframes;
> > +}
> > +
> > +void mt76_connac_sdio_txrx(struct mt76_dev *dev)
> > +{
> > + struct mt76_sdio *sdio = &dev->sdio;
> > + int i, nframes, ret;
> > +
> > + /* disable interrupt */
> > + sdio_claim_host(sdio->func);
> > + sdio_writel(sdio->func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, NULL);
> > +
> > + do {
> > + nframes = 0;
> > +
> > + /* tx */
> > + for (i = 0; i <= MT_TXQ_PSD; i++) {
> > + ret = mt76_connac_sdio_tx_run_queue(dev, dev->phy.q_tx[i]);
> > + if (ret > 0)
> > + nframes += ret;
> > + }
> > + ret = mt76_connac_sdio_tx_run_queue(dev, dev->q_mcu[MT_MCUQ_WM]);
> > + if (ret > 0)
> > + nframes += ret;
> > +
> > + /* rx */
> > + ret = mt76_connac_sdio_rx_handler(dev);
> > + if (ret > 0)
> > + nframes += ret;
> > + } while (nframes > 0);
> > +
> > + /* enable interrupt */
> > + sdio_writel(sdio->func, WHLPCR_INT_EN_SET, MCR_WHLPCR, NULL);
> > + sdio_release_host(sdio->func);
> > +}
> > +EXPORT_SYMBOL_GPL(mt76_connac_sdio_txrx);
> > --
> > 2.25.1
> >



Attachments:
(No filename) (27.04 kB)
signature.asc (235.00 B)
Download all attachments