drivers/pci/ecam.c

Source file repositories/reference/linux-study-clean/drivers/pci/ecam.c

File Facts

System
Linux kernel
Corpus path
drivers/pci/ecam.c
Extension
.c
Size
5731 bytes
Lines
234
Domain
Representative Device Path
Bucket
PCIe NVMe Storage Path
Inferred role
Representative Device Path: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Part of the selected hardware vertical slice: PCI discovery, driver binding, NVMe queues, block requests, DMA, interrupts, and completion.

Dependency Surface

Detected Declarations

Annotated Snippet

if (cfg->winp) {
			for (i = 0; i < resource_size(&cfg->busr); i++)
				if (cfg->winp[i])
					iounmap(cfg->winp[i]);
			kfree(cfg->winp);
		}
	} else {
		if (cfg->win)
			iounmap(cfg->win);
	}
	if (cfg->res.parent)
		release_resource(&cfg->res);
	kfree(cfg);
}
EXPORT_SYMBOL_GPL(pci_ecam_free);

static int pci_ecam_add_bus(struct pci_bus *bus)
{
	struct pci_config_window *cfg = bus->sysdata;
	unsigned int bsz = 1 << cfg->bus_shift;
	unsigned int busn = bus->number;
	phys_addr_t start;

	if (!per_bus_mapping)
		return 0;

	if (busn < cfg->busr.start || busn > cfg->busr.end)
		return -EINVAL;

	busn -= cfg->busr.start;
	start = cfg->res.start + busn * bsz;

	cfg->winp[busn] = pci_remap_cfgspace(start, bsz);
	if (!cfg->winp[busn])
		return -ENOMEM;

	return 0;
}

static void pci_ecam_remove_bus(struct pci_bus *bus)
{
	struct pci_config_window *cfg = bus->sysdata;
	unsigned int busn = bus->number;

	if (!per_bus_mapping || busn < cfg->busr.start || busn > cfg->busr.end)
		return;

	busn -= cfg->busr.start;
	if (cfg->winp[busn]) {
		iounmap(cfg->winp[busn]);
		cfg->winp[busn] = NULL;
	}
}

/*
 * Function to implement the pci_ops ->map_bus method
 */
void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn,
			       int where)
{
	struct pci_config_window *cfg = bus->sysdata;
	unsigned int bus_shift = cfg->ops->bus_shift;
	unsigned int devfn_shift = cfg->ops->bus_shift - 8;
	unsigned int busn = bus->number;
	void __iomem *base;
	u32 bus_offset, devfn_offset;

	if (busn < cfg->busr.start || busn > cfg->busr.end)
		return NULL;

	busn -= cfg->busr.start;
	if (per_bus_mapping) {
		base = cfg->winp[busn];
		busn = 0;
	} else
		base = cfg->win;

	if (cfg->ops->bus_shift) {
		bus_offset = (busn & PCIE_ECAM_BUS_MASK) << bus_shift;
		devfn_offset = (devfn & PCIE_ECAM_DEVFN_MASK) << devfn_shift;
		where &= PCIE_ECAM_REG_MASK;

		return base + (bus_offset | devfn_offset | where);
	}

	return base + PCIE_ECAM_OFFSET(busn, devfn, where);
}
EXPORT_SYMBOL_GPL(pci_ecam_map_bus);

/* ECAM ops */

Annotation

Implementation Notes