/* * Cache BAR0 of P2SB device functions 0 to 7. * TODO: The constant 8 is the number of functions that PCI specification * defines. Same definitions exist tree-wide. Unify this definition and * the other definitions then move to include/uapi/linux/pci.h.
*/ #define NR_P2SB_RES_CACHE 8
/* Copy resource from the first BAR of the device in question */ staticvoid p2sb_read_bar0(struct pci_dev *pdev, struct resource *mem)
{ struct resource *bar0 = pci_resource_n(pdev, 0);
/* Make sure we have no dangling pointers in the output */
memset(mem, 0, sizeof(*mem));
/* * We copy only selected fields from the original resource. * Because a PCI device will be removed soon, we may not use * any allocated data, hence we may not copy any pointers.
*/
mem->start = bar0->start;
mem->end = bar0->end;
mem->flags = bar0->flags;
mem->desc = bar0->desc;
}
staticint p2sb_scan_and_cache(struct pci_bus *bus, unsignedint devfn)
{ /* * The BIOS prevents the P2SB device from being enumerated by the PCI * subsystem, so we need to unhide and hide it back to lookup the BAR.
*/
pci_bus_write_config_dword(bus, devfn, P2SBC, 0);
/* Scan the P2SB device and cache its BAR0 */
p2sb_scan_and_cache_devfn(bus, devfn);
/* On Goldmont p2sb_bar() also gets called for the SPI controller */ if (devfn == P2SB_DEVFN_GOLDMONT)
p2sb_scan_and_cache_devfn(bus, SPI_DEVFN_GOLDMONT);
/* Assume P2SB is on the bus 0 in domain 0 */
p2sb_bus = pci_find_bus(0, 0); return p2sb_bus;
}
staticint p2sb_cache_resources(void)
{ unsignedint devfn_p2sb;
u32 value = P2SBC_HIDE; struct pci_bus *bus;
u16 class; int ret = 0;
/* Get devfn for P2SB device itself */
p2sb_get_devfn(&devfn_p2sb);
bus = p2sb_get_bus(NULL); if (!bus) return -ENODEV;
/* * When a device with same devfn exists and its device class is not * PCI_CLASS_MEMORY_OTHER for P2SB, do not touch it.
*/
pci_bus_read_config_word(bus, devfn_p2sb, PCI_CLASS_DEVICE, &class); if (!PCI_POSSIBLE_ERROR(class) && class != PCI_CLASS_MEMORY_OTHER) return -ENODEV;
/* * Prevent concurrent PCI bus scan from seeing the P2SB device and * removing via sysfs while it is temporarily exposed.
*/
pci_lock_rescan_remove();
pci_bus_read_config_dword(bus, devfn_p2sb, P2SBC, &value);
p2sb_hidden_by_bios = value & P2SBC_HIDE;
/* * If the BIOS does not hide the P2SB device then its resources * are accesilble. Cache them only if the P2SB device is hidden.
*/ if (p2sb_hidden_by_bios)
ret = p2sb_scan_and_cache(bus, devfn_p2sb);
if (cache->bus_dev_id != bus->dev.id) return -ENODEV;
if (!p2sb_valid_resource(&cache->res)) return -ENOENT;
memcpy(mem, &cache->res, sizeof(*mem));
return 0;
}
staticint p2sb_read_from_dev(struct pci_bus *bus, unsignedint devfn, struct resource *mem)
{ struct pci_dev *pdev; int ret = 0;
pdev = pci_get_slot(bus, devfn); if (!pdev) return -ENODEV;
if (p2sb_valid_resource(pci_resource_n(pdev, 0)))
p2sb_read_bar0(pdev, mem); else
ret = -ENOENT;
pci_dev_put(pdev);
return ret;
}
/** * p2sb_bar - Get Primary to Sideband (P2SB) bridge device BAR * @bus: PCI bus to communicate with * @devfn: PCI slot and function to communicate with * @mem: memory resource to be filled in * * If @bus is NULL, the bus 0 in domain 0 will be used. * If @devfn is 0, it will be replaced by devfn of the P2SB device. * * Caller must provide a valid pointer to @mem. * * Return: * 0 on success or appropriate errno value on error.
*/ int p2sb_bar(struct pci_bus *bus, unsignedint devfn, struct resource *mem)
{
bus = p2sb_get_bus(bus); if (!bus) return -ENODEV;
if (!devfn)
p2sb_get_devfn(&devfn);
if (p2sb_hidden_by_bios) return p2sb_read_from_cache(bus, devfn, mem);
/* * pci_rescan_remove_lock() can not be locked in sysfs PCI bus rescan path * because of deadlock. To avoid the deadlock, access P2SB devices with the lock * at an early step in kernel initialization and cache required resources. * * We want to run as early as possible. If the P2SB was assigned a bad BAR, * we'll need to wait on pcibios_assign_resources() to fix it. So, our list of * initcall dependencies looks something like this: * * ... * subsys_initcall (pci_subsys_init) * fs_initcall (pcibios_assign_resources)
*/
fs_initcall_sync(p2sb_fs_init);
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet am 2026-04-26)
¤
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.