// SPDX-License-Identifier: GPL-2.0-only /* * Helper routines to scan the device tree for PCI devices and busses * * Migrated out of PowerPC architecture pci_64.c file by Grant Likely * <grant.likely@secretlab.ca> so that these routines are available for * 32 bit also. * * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM * Rework, based on alpha PCI code. * Copyright (c) 2009 Secret Lab Technologies Ltd.
*/
/** * get_int_prop - Decode a u32 from a device tree property
*/ static u32 get_int_prop(struct device_node *np, constchar *name, u32 def)
{ const __be32 *prop; int len;
prop = of_get_property(np, name, &len); if (prop && len >= 4) return of_read_number(prop, 1); return def;
}
/** * pci_parse_of_flags - Parse the flags cell of a device tree PCI address * @addr0: value of 1st cell of a device tree PCI address. * @bridge: Set this flag if the address is from a bridge 'ranges' property * * PCI Bus Binding to IEEE Std 1275-1994 * * Bit# 33222222 22221111 11111100 00000000 * 10987654 32109876 54321098 76543210 * phys.hi cell: npt000ss bbbbbbbb dddddfff rrrrrrrr * phys.mid cell: hhhhhhhh hhhhhhhh hhhhhhhh hhhhhhhh * phys.lo cell: llllllll llllllll llllllll llllllll * * where: * n is 0 if the address is relocatable, 1 otherwise * p is 1 if the addressable region is "prefetchable", 0 otherwise * t is 1 if the address is aliased (for non-relocatable I/O), * below 1 MB (for Memory),or below 64 KB (for relocatable I/O). * ss is the space code, denoting the address space: * 00 denotes Configuration Space * 01 denotes I/O Space * 10 denotes 32-bit-address Memory Space * 11 denotes 64-bit-address Memory Space * bbbbbbbb is the 8-bit Bus Number * ddddd is the 5-bit Device Number * fff is the 3-bit Function Number * rrrrrrrr is the 8-bit Register Number
*/ #define OF_PCI_ADDR0_SPACE(ss) (((ss)&3)<<24) #define OF_PCI_ADDR0_SPACE_CFG OF_PCI_ADDR0_SPACE(0) #define OF_PCI_ADDR0_SPACE_IO OF_PCI_ADDR0_SPACE(1) #define OF_PCI_ADDR0_SPACE_MMIO32 OF_PCI_ADDR0_SPACE(2) #define OF_PCI_ADDR0_SPACE_MMIO64 OF_PCI_ADDR0_SPACE(3) #define OF_PCI_ADDR0_SPACE_MASK OF_PCI_ADDR0_SPACE(3) #define OF_PCI_ADDR0_RELOC (1UL<<31) #define OF_PCI_ADDR0_PREFETCH (1UL<<30) #define OF_PCI_ADDR0_ALIAS (1UL<<29) #define OF_PCI_ADDR0_BUS 0x00FF0000UL #define OF_PCI_ADDR0_DEV 0x0000F800UL #define OF_PCI_ADDR0_FN 0x00000700UL #define OF_PCI_ADDR0_BARREG 0x000000FFUL
unsignedint pci_parse_of_flags(u32 addr0, int bridge)
{ unsignedint flags = 0, as = addr0 & OF_PCI_ADDR0_SPACE_MASK;
if (as == OF_PCI_ADDR0_SPACE_MMIO32 || as == OF_PCI_ADDR0_SPACE_MMIO64) {
flags = IORESOURCE_MEM | PCI_BASE_ADDRESS_SPACE_MEMORY;
if (as == OF_PCI_ADDR0_SPACE_MMIO64)
flags |= PCI_BASE_ADDRESS_MEM_TYPE_64 | IORESOURCE_MEM_64;
if (addr0 & OF_PCI_ADDR0_ALIAS)
flags |= PCI_BASE_ADDRESS_MEM_TYPE_1M;
if (addr0 & OF_PCI_ADDR0_PREFETCH)
flags |= IORESOURCE_PREFETCH |
PCI_BASE_ADDRESS_MEM_PREFETCH;
/* Note: We don't know whether the ROM has been left enabled * by the firmware or not. We mark it as disabled (ie, we do * not set the IORESOURCE_ROM_ENABLE flag) for now rather than * do a config space read, it will be force-enabled if needed
*/ if (!bridge && (addr0 & OF_PCI_ADDR0_BARREG) == PCI_ROM_ADDRESS)
flags |= IORESOURCE_READONLY;
/** * of_pci_parse_addrs - Parse PCI addresses assigned in the device tree node * @node: device tree node for the PCI device * @dev: pci_dev structure for the device * * This function parses the 'assigned-addresses' property of a PCI devices' * device tree node and writes them into the associated pci_dev structure.
*/ staticvoid of_pci_parse_addrs(struct device_node *node, struct pci_dev *dev)
{
u64 base, size; unsignedint flags; struct pci_bus_region region; struct resource *res; const __be32 *addrs;
u32 i; int proplen; bool mark_unset = false;
if (PCI_BASE_ADDRESS_0 <= i && i <= PCI_BASE_ADDRESS_5) {
res = &dev->resource[(i - PCI_BASE_ADDRESS_0) >> 2];
} elseif (i == dev->rom_base_reg) {
res = &dev->resource[PCI_ROM_RESOURCE];
flags |= IORESOURCE_READONLY;
} else {
printk(KERN_ERR "PCI: bad cfg reg num 0x%x\n", i); continue;
}
res->flags = flags; if (mark_unset)
res->flags |= IORESOURCE_UNSET;
res->name = pci_name(dev);
region.start = base;
region.end = base + size - 1;
pcibios_bus_to_resource(dev->bus, res, ®ion);
}
}
/** * of_create_pci_dev - Given a device tree node on a pci bus, create a pci_dev * @node: device tree node pointer * @bus: bus the device is sitting on * @devfn: PCI function number, extracted from device tree by caller.
*/ struct pci_dev *of_create_pci_dev(struct device_node *node, struct pci_bus *bus, int devfn)
{ struct pci_dev *dev;
dev->current_state = PCI_UNKNOWN; /* unknown power state */
dev->error_state = pci_channel_io_normal;
dev->dma_mask = 0xffffffff;
/* Early fixups, before probing the BARs */
pci_fixup_device(pci_fixup_early, dev);
if (of_node_is_type(node, "pci") || of_node_is_type(node, "pciex")) { /* a PCI-PCI bridge */
dev->hdr_type = PCI_HEADER_TYPE_BRIDGE;
dev->rom_base_reg = PCI_ROM_ADDRESS1;
set_pcie_hotplug_bridge(dev);
} elseif (of_node_is_type(node, "cardbus")) {
dev->hdr_type = PCI_HEADER_TYPE_CARDBUS;
} else {
dev->hdr_type = PCI_HEADER_TYPE_NORMAL;
dev->rom_base_reg = PCI_ROM_ADDRESS; /* Maybe do a default OF mapping here */
dev->irq = 0;
}
of_pci_parse_addrs(node, dev);
pr_debug(" adding to system ...\n");
pci_device_add(dev, bus);
return dev;
}
EXPORT_SYMBOL(of_create_pci_dev);
/** * of_scan_pci_bridge - Set up a PCI bridge and scan for child nodes * @dev: pci_dev structure for the bridge * * of_scan_bus() calls this routine for each PCI bridge that it finds, and * this routine in turn call of_scan_bus() recursively to scan for more child * devices.
*/ void of_scan_pci_bridge(struct pci_dev *dev)
{ struct device_node *node = dev->dev.of_node; struct pci_bus *bus; struct pci_controller *phb; const __be32 *busrange, *ranges; int len, i, mode; struct pci_bus_region region; struct resource *res; unsignedint flags;
u64 size;
pr_debug("of_scan_pci_bridge(%pOF)\n", node);
/* parse bus-range property */
busrange = of_get_property(node, "bus-range", &len); if (busrange == NULL || len != 8) {
printk(KERN_DEBUG "Can't get bus-range for PCI-PCI bridge %pOF\n",
node); return;
}
ranges = of_get_property(node, "ranges", &len); if (ranges == NULL) {
printk(KERN_DEBUG "Can't get ranges for PCI-PCI bridge %pOF\n",
node); return;
}
bus = pci_find_bus(pci_domain_nr(dev->bus),
of_read_number(busrange, 1)); if (!bus) {
bus = pci_add_new_bus(dev->bus, dev,
of_read_number(busrange, 1)); if (!bus) {
printk(KERN_ERR "Failed to create pci bus for %pOF\n",
node); return;
}
}
/* create a new pci_dev for this device */
dev = of_create_pci_dev(dn, bus, devfn); if (!dev) return NULL;
pr_debug(" dev header type: %x\n", dev->hdr_type); return dev;
}
/** * __of_scan_bus - given a PCI bus node, setup bus and scan for child devices * @node: device tree node for the PCI bus * @bus: pci_bus structure for the PCI bus * @rescan_existing: Flag indicating bus has already been set up
*/ staticvoid __of_scan_bus(struct device_node *node, struct pci_bus *bus, int rescan_existing)
{ struct device_node *child; struct pci_dev *dev;
pr_debug("of_scan_bus(%pOF) bus no %d...\n",
node, bus->number);
/* Scan direct children */
for_each_child_of_node(node, child) {
dev = of_scan_pci_dev(bus, child); if (!dev) continue;
pr_debug(" dev header type: %x\n", dev->hdr_type);
}
/* Apply all fixups necessary. We don't fixup the bus "self" * for an existing bridge that is being rescanned
*/ if (!rescan_existing)
pcibios_setup_bus_self(bus);
/* Now scan child busses */
for_each_pci_bridge(dev, bus)
of_scan_pci_bridge(dev);
}
/** * of_scan_bus - given a PCI bus node, setup bus and scan for child devices * @node: device tree node for the PCI bus * @bus: pci_bus structure for the PCI bus
*/ void of_scan_bus(struct device_node *node, struct pci_bus *bus)
{
__of_scan_bus(node, bus, 0);
}
EXPORT_SYMBOL_GPL(of_scan_bus);
/** * of_rescan_bus - given a PCI bus node, scan for child devices * @node: device tree node for the PCI bus * @bus: pci_bus structure for the PCI bus * * Same as of_scan_bus, but for a pci_bus structure that has already been * setup.
*/ void of_rescan_bus(struct device_node *node, struct pci_bus *bus)
{
__of_scan_bus(node, bus, 1);
}
EXPORT_SYMBOL_GPL(of_rescan_bus);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.