drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c

Source file repositories/reference/linux-study-clean/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c

File Facts

System
Linux kernel
Corpus path
drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c
Extension
.c
Size
3961 bytes
Lines
172
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
 * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
 * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
 */

#include <linux/kernel.h>
#include <linux/firmware.h>
#include <linux/delay.h>

#include "mt76x02_mcu.h"

int mt76x02_mcu_parse_response(struct mt76_dev *mdev, int cmd,
			       struct sk_buff *skb, int seq)
{
	struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
	u32 *rxfce;

	if (!skb) {
		dev_err(mdev->dev, "MCU message %02x (seq %d) timed out\n",
			abs(cmd), seq);
		dev->mcu_timeout = 1;
		return -ETIMEDOUT;
	}

	rxfce = (u32 *)skb->cb;
	if (seq != FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, *rxfce))
		return -EAGAIN;

	return 0;
}
EXPORT_SYMBOL_GPL(mt76x02_mcu_parse_response);

int mt76x02_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data,
			 int len, bool wait_resp)
{
	struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
	unsigned long expires = jiffies + HZ;
	struct sk_buff *skb;
	u32 tx_info;
	int ret;
	u8 seq;

	if (dev->mcu_timeout)
		return -EIO;

	skb = mt76_mcu_msg_alloc(mdev, data, len);
	if (!skb)
		return -ENOMEM;

	mutex_lock(&mdev->mcu.mutex);

	seq = ++mdev->mcu.msg_seq & 0xf;
	if (!seq)
		seq = ++mdev->mcu.msg_seq & 0xf;

	tx_info = MT_MCU_MSG_TYPE_CMD |
		  FIELD_PREP(MT_MCU_MSG_CMD_TYPE, cmd) |
		  FIELD_PREP(MT_MCU_MSG_CMD_SEQ, seq) |
		  FIELD_PREP(MT_MCU_MSG_PORT, CPU_TX_PORT) |
		  FIELD_PREP(MT_MCU_MSG_LEN, skb->len);

	ret = mt76_tx_queue_skb_raw(dev, mdev->q_mcu[MT_MCUQ_WM], skb, tx_info);
	if (ret)
		goto out;

	while (wait_resp) {
		skb = mt76_mcu_get_response(&dev->mt76, expires);
		ret = mt76x02_mcu_parse_response(mdev, cmd, skb, seq);
		dev_kfree_skb(skb);
		if (ret != -EAGAIN)
			break;
	}

out:
	mutex_unlock(&mdev->mcu.mutex);

	return ret;
}
EXPORT_SYMBOL_GPL(mt76x02_mcu_msg_send);

int mt76x02_mcu_function_select(struct mt76x02_dev *dev, enum mcu_function func,
				u32 val)
{
	struct {
		__le32 id;
		__le32 value;
	} __packed __aligned(4) msg = {
		.id = cpu_to_le32(func),
		.value = cpu_to_le32(val),

Annotation

Implementation Notes