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

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

File Facts

System
Linux kernel
Corpus path
drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
Extension
.c
Size
5509 bytes
Lines
216
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>
 * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl>
 */

#include "mt76x02.h"

static void mt76x02_set_beacon_offsets(struct mt76x02_dev *dev)
{
	u32 regs[4] = {};
	u16 val;
	int i;

	for (i = 0; i < dev->beacon_ops->nslots; i++) {
		val = i * dev->beacon_ops->slot_size;
		regs[i / 4] |= (val / 64) << (8 * (i % 4));
	}

	for (i = 0; i < 4; i++)
		mt76_wr(dev, MT_BCN_OFFSET(i), regs[i]);
}

static int
mt76x02_write_beacon(struct mt76x02_dev *dev, int offset, struct sk_buff *skb)
{
	int beacon_len = dev->beacon_ops->slot_size;

	if (WARN_ON_ONCE(beacon_len < skb->len + sizeof(struct mt76x02_txwi)))
		return -ENOSPC;

	/* USB devices already reserve enough skb headroom for txwi's. This
	 * helps to save slow copies over USB.
	 */
	if (mt76_is_usb(&dev->mt76)) {
		struct mt76x02_txwi *txwi;

		txwi = (struct mt76x02_txwi *)(skb->data - sizeof(*txwi));
		mt76x02_mac_write_txwi(dev, txwi, skb, NULL, NULL, skb->len);
		skb_push(skb, sizeof(*txwi));
	} else {
		struct mt76x02_txwi txwi;

		mt76x02_mac_write_txwi(dev, &txwi, skb, NULL, NULL, skb->len);
		mt76_wr_copy(dev, offset, &txwi, sizeof(txwi));
		offset += sizeof(txwi);
	}

	mt76_wr_copy(dev, offset, skb->data, skb->len);
	return 0;
}

void mt76x02_mac_set_beacon(struct mt76x02_dev *dev,
			    struct sk_buff *skb)
{
	int bcn_len = dev->beacon_ops->slot_size;
	int bcn_addr = MT_BEACON_BASE + (bcn_len * dev->beacon_data_count);

	if (!mt76x02_write_beacon(dev, bcn_addr, skb)) {
		if (!dev->beacon_data_count)
			dev->beacon_hang_check++;
		dev->beacon_data_count++;
	}
	dev_kfree_skb(skb);
}
EXPORT_SYMBOL_GPL(mt76x02_mac_set_beacon);

void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev,
				   struct ieee80211_vif *vif, bool enable)
{
	struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
	u8 old_mask = dev->mt76.beacon_mask;

	mt76x02_pre_tbtt_enable(dev, false);

	if (!dev->mt76.beacon_mask)
		dev->tbtt_count = 0;

	dev->beacon_hang_check = 0;
	if (enable) {
		dev->mt76.beacon_mask |= BIT(mvif->idx);
	} else {
		dev->mt76.beacon_mask &= ~BIT(mvif->idx);
	}

	if (!!old_mask == !!dev->mt76.beacon_mask)
		goto out;

	if (dev->mt76.beacon_mask)

Annotation

Implementation Notes