drivers/net/ethernet/freescale/enetc/enetc_cbdr.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
Extension
.c
Size
7321 bytes
Lines
309
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: (GPL-2.0+ OR BSD-3-Clause)
/* Copyright 2017-2019 NXP */

#include "enetc.h"

int enetc_setup_cbdr(struct enetc_si *si)
{
	int size = ENETC_CBDR_DEFAULT_SIZE * sizeof(struct enetc_cbd);
	struct enetc_cbdr *cbdr = &si->cbd_ring;
	struct device *dev = &si->pdev->dev;
	struct enetc_hw *hw = &si->hw;

	cbdr->bd_base = dma_alloc_coherent(dev, size, &cbdr->bd_dma_base,
					   GFP_KERNEL);
	if (!cbdr->bd_base)
		return -ENOMEM;

	/* h/w requires 128B alignment */
	if (!IS_ALIGNED(cbdr->bd_dma_base, 128)) {
		dma_free_coherent(dev, size, cbdr->bd_base,
				  cbdr->bd_dma_base);
		return -EINVAL;
	}

	cbdr->next_to_clean = 0;
	cbdr->next_to_use = 0;
	cbdr->dma_dev = dev;
	cbdr->bd_count = ENETC_CBDR_DEFAULT_SIZE;

	cbdr->pir = hw->reg + ENETC_SICBDRPIR;
	cbdr->cir = hw->reg + ENETC_SICBDRCIR;
	cbdr->mr = hw->reg + ENETC_SICBDRMR;

	/* set CBDR cache attributes */
	enetc_wr(hw, ENETC_SICAR2,
		 ENETC_SICAR_RD_COHERENT | ENETC_SICAR_WR_COHERENT);

	enetc_wr(hw, ENETC_SICBDRBAR0, lower_32_bits(cbdr->bd_dma_base));
	enetc_wr(hw, ENETC_SICBDRBAR1, upper_32_bits(cbdr->bd_dma_base));
	enetc_wr(hw, ENETC_SICBDRLENR, ENETC_RTBLENR_LEN(cbdr->bd_count));

	enetc_wr_reg(cbdr->pir, cbdr->next_to_clean);
	enetc_wr_reg(cbdr->cir, cbdr->next_to_use);
	/* enable ring */
	enetc_wr_reg(cbdr->mr, BIT(31));

	return 0;
}
EXPORT_SYMBOL_GPL(enetc_setup_cbdr);

void enetc_teardown_cbdr(struct enetc_si *si)
{
	struct enetc_cbdr *cbdr = &si->cbd_ring;
	int size;

	/* disable ring */
	enetc_wr_reg(cbdr->mr, 0);

	size = cbdr->bd_count * sizeof(struct enetc_cbd);
	dma_free_coherent(cbdr->dma_dev, size, cbdr->bd_base,
			  cbdr->bd_dma_base);
	cbdr->bd_base = NULL;
	cbdr->dma_dev = NULL;
}
EXPORT_SYMBOL_GPL(enetc_teardown_cbdr);

int enetc4_setup_cbdr(struct enetc_si *si)
{
	struct ntmp_user *user = &si->ntmp_user;
	struct device *dev = &si->pdev->dev;
	struct enetc_hw *hw = &si->hw;
	struct netc_cbdr_regs regs;

	user->cbdr_num = 1;
	user->dev = dev;
	user->ring = devm_kcalloc(dev, user->cbdr_num,
				  sizeof(struct netc_cbdr), GFP_KERNEL);
	if (!user->ring)
		return -ENOMEM;

	regs.pir = hw->reg + ENETC_SICBDRPIR;
	regs.cir = hw->reg + ENETC_SICBDRCIR;
	regs.mr = hw->reg + ENETC_SICBDRMR;
	regs.bar0 = hw->reg + ENETC_SICBDRBAR0;
	regs.bar1 = hw->reg + ENETC_SICBDRBAR1;
	regs.lenr = hw->reg + ENETC_SICBDRLENR;

	return ntmp_init_cbdr(user->ring, dev, &regs);
}
EXPORT_SYMBOL_GPL(enetc4_setup_cbdr);

Annotation

Implementation Notes