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

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

File Facts

System
Linux kernel
Corpus path
drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c
Extension
.c
Size
6744 bytes
Lines
298
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) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
 */

#include <linux/module.h>
#include <linux/firmware.h>

#include "mt76x02.h"
#include "mt76x02_mcu.h"
#include "mt76x02_usb.h"

#define MT_CMD_HDR_LEN			4

#define MT_FCE_DMA_ADDR			0x0230
#define MT_FCE_DMA_LEN			0x0234

#define MT_TX_CPU_FROM_FCE_CPU_DESC_IDX	0x09a8

static void
mt76x02u_multiple_mcu_reads(struct mt76_dev *dev, u8 *data, int len)
{
	struct mt76_usb *usb = &dev->usb;
	int i;

	WARN_ON_ONCE(len / 8 != usb->mcu.rp_len);

	for (i = 0; i < usb->mcu.rp_len; i++) {
		u32 reg = get_unaligned_le32(data + 8 * i) - usb->mcu.base;
		u32 val = get_unaligned_le32(data + 8 * i + 4);

		WARN_ON_ONCE(usb->mcu.rp[i].reg != reg);
		usb->mcu.rp[i].value = val;
	}
}

static int mt76x02u_mcu_wait_resp(struct mt76_dev *dev, u8 seq)
{
	struct mt76_usb *usb = &dev->usb;
	u8 *data = usb->mcu.data;
	int i, len, ret;
	u32 rxfce;

	for (i = 0; i < 5; i++) {
		ret = mt76u_bulk_msg(dev, data, MCU_RESP_URB_SIZE, &len,
				     300, MT_EP_IN_CMD_RESP);
		if (ret == -ETIMEDOUT)
			continue;
		if (ret)
			goto out;

		if (usb->mcu.rp)
			mt76x02u_multiple_mcu_reads(dev, data + 4, len - 8);

		rxfce = get_unaligned_le32(data);
		if (seq == FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, rxfce) &&
		    FIELD_GET(MT_RX_FCE_INFO_EVT_TYPE, rxfce) == EVT_CMD_DONE)
			return 0;

		dev_err(dev->dev, "error: MCU resp evt:%lx seq:%hhx-%lx\n",
			FIELD_GET(MT_RX_FCE_INFO_EVT_TYPE, rxfce),
			seq, FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, rxfce));
	}
out:
	dev_err(dev->dev, "error: %s failed with %d\n", __func__, ret);
	return ret;
}

static int
__mt76x02u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb,
			int cmd, bool wait_resp)
{
	u8 seq = 0;
	u32 info;
	int ret;

	if (test_bit(MT76_REMOVED, &dev->phy.state)) {
		ret = 0;
		goto out;
	}

	if (wait_resp) {
		seq = ++dev->mcu.msg_seq & 0xf;
		if (!seq)
			seq = ++dev->mcu.msg_seq & 0xf;
	}

	info = FIELD_PREP(MT_MCU_MSG_CMD_SEQ, seq) |
	       FIELD_PREP(MT_MCU_MSG_CMD_TYPE, cmd) |
	       MT_MCU_MSG_TYPE_CMD;

Annotation

Implementation Notes