drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c

Source file repositories/reference/linux-study-clean/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c

File Facts

System
Linux kernel
Corpus path
drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c
Extension
.c
Size
11278 bytes
Lines
502
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source 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

if ((flow->rings[i]) && (i != flowid)) {
			ring = flow->rings[i];
			if ((ring->status == RING_OPEN) &&
			    (brcmf_flowring_ifidx_get(flow, i) == ifidx)) {
				if (ring->blocked) {
					currently_blocked = true;
					break;
				}
			}
		}
	}
	flow->rings[flowid]->blocked = blocked;
	if (currently_blocked) {
		spin_unlock_irqrestore(&flow->block_lock, flags);
		return;
	}

	bus_if = dev_get_drvdata(flow->dev);
	drvr = bus_if->drvr;
	ifp = brcmf_get_ifp(drvr, ifidx);
	brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_FLOW, blocked);

	spin_unlock_irqrestore(&flow->block_lock, flags);
}


void brcmf_flowring_delete(struct brcmf_flowring *flow, u16 flowid)
{
	struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev);
	struct brcmf_flowring_ring *ring;
	struct brcmf_if *ifp;
	u16 hash_idx;
	u8 ifidx;
	struct sk_buff *skb;

	ring = flow->rings[flowid];
	if (!ring)
		return;

	ifidx = brcmf_flowring_ifidx_get(flow, flowid);
	ifp = brcmf_get_ifp(bus_if->drvr, ifidx);

	brcmf_flowring_block(flow, flowid, false);
	hash_idx = ring->hash_id;
	flow->hash[hash_idx].ifidx = BRCMF_FLOWRING_INVALID_IFIDX;
	eth_zero_addr(flow->hash[hash_idx].mac);
	flow->rings[flowid] = NULL;

	skb = skb_dequeue(&ring->skblist);
	while (skb) {
		brcmf_txfinalize(ifp, skb, false);
		skb = skb_dequeue(&ring->skblist);
	}

	kfree(ring);
}


u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u16 flowid,
			   struct sk_buff *skb)
{
	struct brcmf_flowring_ring *ring;

	ring = flow->rings[flowid];

	skb_queue_tail(&ring->skblist, skb);

	if (!ring->blocked &&
	    (skb_queue_len(&ring->skblist) > BRCMF_FLOWRING_HIGH)) {
		brcmf_flowring_block(flow, flowid, true);
		brcmf_dbg(MSGBUF, "Flowcontrol: BLOCK for ring %d\n", flowid);
		/* To prevent (work around) possible race condition, check
		 * queue len again. It is also possible to use locking to
		 * protect, but that is undesirable for every enqueue and
		 * dequeue. This simple check will solve a possible race
		 * condition if it occurs.
		 */
		if (skb_queue_len(&ring->skblist) < BRCMF_FLOWRING_LOW)
			brcmf_flowring_block(flow, flowid, false);
	}
	return skb_queue_len(&ring->skblist);
}


struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u16 flowid)
{
	struct brcmf_flowring_ring *ring;
	struct sk_buff *skb;

	ring = flow->rings[flowid];

Annotation

Implementation Notes