// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2018 Marvell * * Author: Thomas Petazzoni <[email protected]> * * This file helps PCI controller drivers implement a fake root port * PCI bridge when the HW doesn't provide such a root port PCI * bridge. * * It emulates a PCI bridge by providing a fake PCI configuration * space (and optionally a PCIe capability configuration space) in * memory. By default the read/write operations simply read and update * this fake configuration space in memory. However, PCI controller * drivers can provide through the 'struct pci_sw_bridge_ops' * structure a set of operations to override or complement this * default behavior. */ #include <linux/pci.h> #include "pci-bridge-emul.h" #define PCI_BRIDGE_CONF_END … #define PCI_CAP_SSID_SIZEOF … #define PCI_CAP_PCIE_SIZEOF … /** * struct pci_bridge_reg_behavior - register bits behaviors * @ro: Read-Only bits * @rw: Read-Write bits * @w1c: Write-1-to-Clear bits * * Reads and Writes will be filtered by specified behavior. All other bits not * declared are assumed 'Reserved' and will return 0 on reads, per PCIe 5.0: * "Reserved register fields must be read only and must return 0 (all 0's for * multi-bit fields) when read". */ struct pci_bridge_reg_behavior { … }; static const struct pci_bridge_reg_behavior pci_regs_behavior[PCI_STD_HEADER_SIZEOF / 4] = …; static const struct pci_bridge_reg_behavior pcie_cap_regs_behavior[PCI_CAP_PCIE_SIZEOF / 4] = …; static pci_bridge_emul_read_status_t pci_bridge_emul_read_ssid(struct pci_bridge_emul *bridge, int reg, u32 *value) { … } /* * Initialize a pci_bridge_emul structure to represent a fake PCI * bridge configuration space. The caller needs to have initialized * the PCI configuration space with whatever values make sense * (typically at least vendor, device, revision), the ->ops pointer, * and optionally ->data and ->has_pcie. */ int pci_bridge_emul_init(struct pci_bridge_emul *bridge, unsigned int flags) { … } EXPORT_SYMBOL_GPL(…); /* * Cleanup a pci_bridge_emul structure that was previously initialized * using pci_bridge_emul_init(). */ void pci_bridge_emul_cleanup(struct pci_bridge_emul *bridge) { … } EXPORT_SYMBOL_GPL(…); /* * Should be called by the PCI controller driver when reading the PCI * configuration space of the fake bridge. It will call back the * ->ops->read_base or ->ops->read_pcie operations. */ int pci_bridge_emul_conf_read(struct pci_bridge_emul *bridge, int where, int size, u32 *value) { … } EXPORT_SYMBOL_GPL(…); /* * Should be called by the PCI controller driver when writing the PCI * configuration space of the fake bridge. It will call back the * ->ops->write_base or ->ops->write_pcie operations. */ int pci_bridge_emul_conf_write(struct pci_bridge_emul *bridge, int where, int size, u32 value) { … } EXPORT_SYMBOL_GPL(…);