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

mt76x02_mcu.c (3946B)


      1// SPDX-License-Identifier: ISC
      2/*
      3 * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
      4 * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
      5 */
      6
      7#include <linux/kernel.h>
      8#include <linux/firmware.h>
      9#include <linux/delay.h>
     10
     11#include "mt76x02_mcu.h"
     12
     13int mt76x02_mcu_parse_response(struct mt76_dev *mdev, int cmd,
     14			       struct sk_buff *skb, int seq)
     15{
     16	struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
     17	u32 *rxfce;
     18
     19	if (!skb) {
     20		dev_err(mdev->dev, "MCU message %02x (seq %d) timed out\n",
     21			abs(cmd), seq);
     22		dev->mcu_timeout = 1;
     23		return -ETIMEDOUT;
     24	}
     25
     26	rxfce = (u32 *)skb->cb;
     27	if (seq != FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, *rxfce))
     28		return -EAGAIN;
     29
     30	return 0;
     31}
     32EXPORT_SYMBOL_GPL(mt76x02_mcu_parse_response);
     33
     34int mt76x02_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data,
     35			 int len, bool wait_resp)
     36{
     37	struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
     38	unsigned long expires = jiffies + HZ;
     39	struct sk_buff *skb;
     40	u32 tx_info;
     41	int ret;
     42	u8 seq;
     43
     44	if (dev->mcu_timeout)
     45		return -EIO;
     46
     47	skb = mt76_mcu_msg_alloc(mdev, data, len);
     48	if (!skb)
     49		return -ENOMEM;
     50
     51	mutex_lock(&mdev->mcu.mutex);
     52
     53	seq = ++mdev->mcu.msg_seq & 0xf;
     54	if (!seq)
     55		seq = ++mdev->mcu.msg_seq & 0xf;
     56
     57	tx_info = MT_MCU_MSG_TYPE_CMD |
     58		  FIELD_PREP(MT_MCU_MSG_CMD_TYPE, cmd) |
     59		  FIELD_PREP(MT_MCU_MSG_CMD_SEQ, seq) |
     60		  FIELD_PREP(MT_MCU_MSG_PORT, CPU_TX_PORT) |
     61		  FIELD_PREP(MT_MCU_MSG_LEN, skb->len);
     62
     63	ret = mt76_tx_queue_skb_raw(dev, mdev->q_mcu[MT_MCUQ_WM], skb, tx_info);
     64	if (ret)
     65		goto out;
     66
     67	while (wait_resp) {
     68		skb = mt76_mcu_get_response(&dev->mt76, expires);
     69		ret = mt76x02_mcu_parse_response(mdev, cmd, skb, seq);
     70		dev_kfree_skb(skb);
     71		if (ret != -EAGAIN)
     72			break;
     73	}
     74
     75out:
     76	mutex_unlock(&mdev->mcu.mutex);
     77
     78	return ret;
     79}
     80EXPORT_SYMBOL_GPL(mt76x02_mcu_msg_send);
     81
     82int mt76x02_mcu_function_select(struct mt76x02_dev *dev, enum mcu_function func,
     83				u32 val)
     84{
     85	struct {
     86		__le32 id;
     87		__le32 value;
     88	} __packed __aligned(4) msg = {
     89		.id = cpu_to_le32(func),
     90		.value = cpu_to_le32(val),
     91	};
     92	bool wait = false;
     93
     94	if (func != Q_SELECT)
     95		wait = true;
     96
     97	return mt76_mcu_send_msg(&dev->mt76, CMD_FUN_SET_OP, &msg,
     98				 sizeof(msg), wait);
     99}
    100EXPORT_SYMBOL_GPL(mt76x02_mcu_function_select);
    101
    102int mt76x02_mcu_set_radio_state(struct mt76x02_dev *dev, bool on)
    103{
    104	struct {
    105		__le32 mode;
    106		__le32 level;
    107	} __packed __aligned(4) msg = {
    108		.mode = cpu_to_le32(on ? RADIO_ON : RADIO_OFF),
    109		.level = cpu_to_le32(0),
    110	};
    111
    112	return mt76_mcu_send_msg(&dev->mt76, CMD_POWER_SAVING_OP, &msg,
    113				 sizeof(msg), false);
    114}
    115EXPORT_SYMBOL_GPL(mt76x02_mcu_set_radio_state);
    116
    117int mt76x02_mcu_calibrate(struct mt76x02_dev *dev, int type, u32 param)
    118{
    119	struct {
    120		__le32 id;
    121		__le32 value;
    122	} __packed __aligned(4) msg = {
    123		.id = cpu_to_le32(type),
    124		.value = cpu_to_le32(param),
    125	};
    126	bool is_mt76x2e = mt76_is_mmio(&dev->mt76) && is_mt76x2(dev);
    127	int ret;
    128
    129	if (is_mt76x2e)
    130		mt76_rmw(dev, MT_MCU_COM_REG0, BIT(31), 0);
    131
    132	ret = mt76_mcu_send_msg(&dev->mt76, CMD_CALIBRATION_OP, &msg,
    133				sizeof(msg), true);
    134	if (ret)
    135		return ret;
    136
    137	if (is_mt76x2e &&
    138	    WARN_ON(!mt76_poll_msec(dev, MT_MCU_COM_REG0,
    139				    BIT(31), BIT(31), 100)))
    140		return -ETIMEDOUT;
    141
    142	return 0;
    143}
    144EXPORT_SYMBOL_GPL(mt76x02_mcu_calibrate);
    145
    146int mt76x02_mcu_cleanup(struct mt76x02_dev *dev)
    147{
    148	struct sk_buff *skb;
    149
    150	mt76_wr(dev, MT_MCU_INT_LEVEL, 1);
    151	usleep_range(20000, 30000);
    152
    153	while ((skb = skb_dequeue(&dev->mt76.mcu.res_q)) != NULL)
    154		dev_kfree_skb(skb);
    155
    156	return 0;
    157}
    158EXPORT_SYMBOL_GPL(mt76x02_mcu_cleanup);
    159
    160void mt76x02_set_ethtool_fwver(struct mt76x02_dev *dev,
    161			       const struct mt76x02_fw_header *h)
    162{
    163	u16 bld = le16_to_cpu(h->build_ver);
    164	u16 ver = le16_to_cpu(h->fw_ver);
    165
    166	snprintf(dev->mt76.hw->wiphy->fw_version,
    167		 sizeof(dev->mt76.hw->wiphy->fw_version),
    168		 "%d.%d.%02d-b%x",
    169		 (ver >> 12) & 0xf, (ver >> 8) & 0xf, ver & 0xf, bld);
    170}
    171EXPORT_SYMBOL_GPL(mt76x02_set_ethtool_fwver);