drivers/bus/uniphier-system-bus.c

Source file repositories/reference/linux-study-clean/drivers/bus/uniphier-system-bus.c

File Facts

System
Linux kernel
Corpus path
drivers/bus/uniphier-system-bus.c
Extension
.c
Size
6768 bytes
Lines
252
Domain
Driver Families
Bucket
drivers/bus
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

struct uniphier_system_bus_bank {
	u32 base;
	u32 end;
};

struct uniphier_system_bus_priv {
	struct device *dev;
	void __iomem *membase;
	struct uniphier_system_bus_bank bank[UNIPHIER_SBC_NR_BANKS];
};

static int uniphier_system_bus_add_bank(struct uniphier_system_bus_priv *priv,
					int bank, u32 addr, u64 paddr, u32 size)
{
	u64 end, mask;

	dev_dbg(priv->dev,
		"range found: bank = %d, addr = %08x, paddr = %08llx, size = %08x\n",
		bank, addr, paddr, size);

	if (bank >= ARRAY_SIZE(priv->bank)) {
		dev_err(priv->dev, "unsupported bank number %d\n", bank);
		return -EINVAL;
	}

	if (priv->bank[bank].base || priv->bank[bank].end) {
		dev_err(priv->dev,
			"range for bank %d has already been specified\n", bank);
		return -EINVAL;
	}

	if (paddr > U32_MAX) {
		dev_err(priv->dev, "base address %llx is too high\n", paddr);
		return -EINVAL;
	}

	end = paddr + size;

	if (addr > paddr) {
		dev_err(priv->dev,
			"base %08x cannot be mapped to %08llx of parent\n",
			addr, paddr);
		return -EINVAL;
	}
	paddr -= addr;

	paddr = round_down(paddr, 0x00020000);
	end = round_up(end, 0x00020000);

	if (end > U32_MAX) {
		dev_err(priv->dev, "end address %08llx is too high\n", end);
		return -EINVAL;
	}
	mask = paddr ^ (end - 1);
	mask = roundup_pow_of_two(mask);

	paddr = round_down(paddr, mask);
	end = round_up(end, mask);

	priv->bank[bank].base = paddr;
	priv->bank[bank].end = end;

	dev_dbg(priv->dev, "range added: bank = %d, addr = %08x, end = %08x\n",
		bank, priv->bank[bank].base, priv->bank[bank].end);

	return 0;
}

static int uniphier_system_bus_check_overlap(
				const struct uniphier_system_bus_priv *priv)
{
	int i, j;

	for (i = 0; i < ARRAY_SIZE(priv->bank); i++) {
		for (j = i + 1; j < ARRAY_SIZE(priv->bank); j++) {
			if (priv->bank[i].end > priv->bank[j].base &&
			    priv->bank[i].base < priv->bank[j].end) {
				dev_err(priv->dev,
					"region overlap between bank%d and bank%d\n",
					i, j);
				return -EINVAL;
			}
		}
	}

	return 0;
}

static void uniphier_system_bus_check_boot_swap(
					struct uniphier_system_bus_priv *priv)

Annotation

Implementation Notes