cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sdio_mcu.c (4133B)


      1// SPDX-License-Identifier: ISC
      2/* Copyright (C) 2021 MediaTek Inc. */
      3
      4#include <linux/kernel.h>
      5#include <linux/mmc/sdio_func.h>
      6#include <linux/module.h>
      7#include <linux/iopoll.h>
      8
      9#include "mt7921.h"
     10#include "../sdio.h"
     11#include "mac.h"
     12#include "mcu.h"
     13#include "regs.h"
     14
     15static int
     16mt7921s_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
     17			 int cmd, int *seq)
     18{
     19	struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
     20	enum mt7921_sdio_pkt_type type = MT7921_SDIO_CMD;
     21	enum mt76_mcuq_id txq = MT_MCUQ_WM;
     22	int ret, pad;
     23
     24	/* We just return in case firmware assertion to avoid blocking the
     25	 * common workqueue to run, for example, the coredump work might be
     26	 * blocked by mt7921_mac_work that is excuting register access via sdio
     27	 * bus.
     28	 */
     29	if (dev->fw_assert)
     30		return -EBUSY;
     31
     32	ret = mt7921_mcu_fill_message(mdev, skb, cmd, seq);
     33	if (ret)
     34		return ret;
     35
     36	if (cmd == MCU_CMD(FW_SCATTER))
     37		type = MT7921_SDIO_FWDL;
     38
     39	mt7921_skb_add_usb_sdio_hdr(dev, skb, type);
     40	pad = round_up(skb->len, 4) - skb->len;
     41	__skb_put_zero(skb, pad);
     42
     43	ret = mt76_tx_queue_skb_raw(dev, mdev->q_mcu[txq], skb, 0);
     44	if (ret)
     45		return ret;
     46
     47	mt76_queue_kick(dev, mdev->q_mcu[txq]);
     48
     49	return ret;
     50}
     51
     52static u32 mt7921s_read_rm3r(struct mt7921_dev *dev)
     53{
     54	struct mt76_sdio *sdio = &dev->mt76.sdio;
     55
     56	return sdio_readl(sdio->func, MCR_D2HRM3R, NULL);
     57}
     58
     59static u32 mt7921s_clear_rm3r_drv_own(struct mt7921_dev *dev)
     60{
     61	struct mt76_sdio *sdio = &dev->mt76.sdio;
     62	u32 val;
     63
     64	val = sdio_readl(sdio->func, MCR_D2HRM3R, NULL);
     65	if (val)
     66		sdio_writel(sdio->func, H2D_SW_INT_CLEAR_MAILBOX_ACK,
     67			    MCR_WSICR, NULL);
     68
     69	return val;
     70}
     71
     72int mt7921s_mcu_init(struct mt7921_dev *dev)
     73{
     74	static const struct mt76_mcu_ops mt7921s_mcu_ops = {
     75		.headroom = MT_SDIO_HDR_SIZE + sizeof(struct mt7921_mcu_txd),
     76		.tailroom = MT_SDIO_TAIL_SIZE,
     77		.mcu_skb_send_msg = mt7921s_mcu_send_message,
     78		.mcu_parse_response = mt7921_mcu_parse_response,
     79		.mcu_rr = mt76_connac_mcu_reg_rr,
     80		.mcu_wr = mt76_connac_mcu_reg_wr,
     81	};
     82	int ret;
     83
     84	mt7921s_mcu_drv_pmctrl(dev);
     85
     86	dev->mt76.mcu_ops = &mt7921s_mcu_ops;
     87
     88	ret = mt7921_run_firmware(dev);
     89	if (ret)
     90		return ret;
     91
     92	set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
     93
     94	return 0;
     95}
     96
     97int mt7921s_mcu_drv_pmctrl(struct mt7921_dev *dev)
     98{
     99	struct sdio_func *func = dev->mt76.sdio.func;
    100	struct mt76_phy *mphy = &dev->mt76.phy;
    101	struct mt76_connac_pm *pm = &dev->pm;
    102	int err = 0;
    103	u32 status;
    104
    105	sdio_claim_host(func);
    106
    107	sdio_writel(func, WHLPCR_FW_OWN_REQ_CLR, MCR_WHLPCR, NULL);
    108
    109	err = readx_poll_timeout(mt76s_read_pcr, &dev->mt76, status,
    110				 status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000);
    111
    112	if (!err && test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state))
    113		err = readx_poll_timeout(mt7921s_read_rm3r, dev, status,
    114					 status & D2HRM3R_IS_DRIVER_OWN,
    115					 2000, 1000000);
    116
    117	sdio_release_host(func);
    118
    119	if (err < 0) {
    120		dev_err(dev->mt76.dev, "driver own failed\n");
    121		err = -EIO;
    122		goto out;
    123	}
    124
    125	clear_bit(MT76_STATE_PM, &mphy->state);
    126
    127	pm->stats.last_wake_event = jiffies;
    128	pm->stats.doze_time += pm->stats.last_wake_event -
    129			       pm->stats.last_doze_event;
    130out:
    131	return err;
    132}
    133
    134int mt7921s_mcu_fw_pmctrl(struct mt7921_dev *dev)
    135{
    136	struct sdio_func *func = dev->mt76.sdio.func;
    137	struct mt76_phy *mphy = &dev->mt76.phy;
    138	struct mt76_connac_pm *pm = &dev->pm;
    139	int err = 0;
    140	u32 status;
    141
    142	sdio_claim_host(func);
    143
    144	if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state)) {
    145		err = readx_poll_timeout(mt7921s_clear_rm3r_drv_own,
    146					 dev, status,
    147					 !(status & D2HRM3R_IS_DRIVER_OWN),
    148					 2000, 1000000);
    149		if (err < 0) {
    150			dev_err(dev->mt76.dev, "mailbox ACK not cleared\n");
    151			goto err;
    152		}
    153	}
    154
    155	sdio_writel(func, WHLPCR_FW_OWN_REQ_SET, MCR_WHLPCR, NULL);
    156
    157	err = readx_poll_timeout(mt76s_read_pcr, &dev->mt76, status,
    158				 !(status & WHLPCR_IS_DRIVER_OWN), 2000, 1000000);
    159	sdio_release_host(func);
    160
    161err:
    162	if (err < 0) {
    163		dev_err(dev->mt76.dev, "firmware own failed\n");
    164		clear_bit(MT76_STATE_PM, &mphy->state);
    165		err = -EIO;
    166	}
    167
    168	pm->stats.last_doze_event = jiffies;
    169	pm->stats.awake_time += pm->stats.last_doze_event -
    170				pm->stats.last_wake_event;
    171
    172	return err;
    173}