// SPDX-License-Identifier: GPL-2.0 /* * Purpose: PCI Express Port Bus Driver * * Copyright (C) 2004 Intel * Copyright (C) Tom Long Nguyen ([email protected]) */ #include <linux/bitfield.h> #include <linux/dmi.h> #include <linux/init.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/pm.h> #include <linux/pm_runtime.h> #include <linux/string.h> #include <linux/slab.h> #include <linux/aer.h> #include "../pci.h" #include "portdrv.h" /* * The PCIe Capability Interrupt Message Number (PCIe r3.1, sec 7.8.2) must * be one of the first 32 MSI-X entries. Per PCI r3.0, sec 6.8.3.1, MSI * supports a maximum of 32 vectors per function. */ #define PCIE_PORT_MAX_MSI_ENTRIES … #define get_descriptor_id(type, service) … struct portdrv_service_data { … }; /** * release_pcie_device - free PCI Express port service device structure * @dev: Port service device to release * * Invoked automatically when device is being removed in response to * device_unregister(dev). Release all resources being claimed. */ static void release_pcie_device(struct device *dev) { … } /* * Fill in *pme, *aer, *dpc with the relevant Interrupt Message Numbers if * services are enabled in "mask". Return the number of MSI/MSI-X vectors * required to accommodate the largest Message Number. */ static int pcie_message_numbers(struct pci_dev *dev, int mask, u32 *pme, u32 *aer, u32 *dpc) { … } /** * pcie_port_enable_irq_vec - try to set up MSI-X or MSI as interrupt mode * for given port * @dev: PCI Express port to handle * @irqs: Array of interrupt vectors to populate * @mask: Bitmask of port capabilities returned by get_port_device_capability() * * Return value: 0 on success, error code on failure */ static int pcie_port_enable_irq_vec(struct pci_dev *dev, int *irqs, int mask) { … } /** * pcie_init_service_irqs - initialize irqs for PCI Express port services * @dev: PCI Express port to handle * @irqs: Array of irqs to populate * @mask: Bitmask of port capabilities returned by get_port_device_capability() * * Return value: Interrupt mode associated with the port */ static int pcie_init_service_irqs(struct pci_dev *dev, int *irqs, int mask) { … } /** * get_port_device_capability - discover capabilities of a PCI Express port * @dev: PCI Express port to examine * * The capabilities are read from the port's PCI Express configuration registers * as described in PCI Express Base Specification 1.0a sections 7.8.2, 7.8.9 and * 7.9 - 7.11. * * Return value: Bitmask of discovered port capabilities */ static int get_port_device_capability(struct pci_dev *dev) { … } /** * pcie_device_init - allocate and initialize PCI Express port service device * @pdev: PCI Express port to associate the service device with * @service: Type of service to associate with the service device * @irq: Interrupt vector to associate with the service device */ static int pcie_device_init(struct pci_dev *pdev, int service, int irq) { … } /** * pcie_port_device_register - register PCI Express port * @dev: PCI Express port to register * * Allocate the port extension structure and register services associated with * the port. */ static int pcie_port_device_register(struct pci_dev *dev) { … } pcie_callback_t; static int pcie_port_device_iter(struct device *dev, void *data) { … } #ifdef CONFIG_PM /** * pcie_port_device_suspend - suspend port services associated with a PCIe port * @dev: PCI Express port to handle */ static int pcie_port_device_suspend(struct device *dev) { … } static int pcie_port_device_resume_noirq(struct device *dev) { … } /** * pcie_port_device_resume - resume port services associated with a PCIe port * @dev: PCI Express port to handle */ static int pcie_port_device_resume(struct device *dev) { … } /** * pcie_port_device_runtime_suspend - runtime suspend port services * @dev: PCI Express port to handle */ static int pcie_port_device_runtime_suspend(struct device *dev) { … } /** * pcie_port_device_runtime_resume - runtime resume port services * @dev: PCI Express port to handle */ static int pcie_port_device_runtime_resume(struct device *dev) { … } #endif /* PM */ static int remove_iter(struct device *dev, void *data) { … } static int find_service_iter(struct device *device, void *data) { … } /** * pcie_port_find_device - find the struct device * @dev: PCI Express port the service is associated with * @service: For the service to find * * Find the struct device associated with given service on a pci_dev */ struct device *pcie_port_find_device(struct pci_dev *dev, u32 service) { … } EXPORT_SYMBOL_GPL(…); /** * pcie_port_device_remove - unregister PCI Express port service devices * @dev: PCI Express port the service devices to unregister are associated with * * Remove PCI Express port service devices associated with given port and * disable MSI-X or MSI for the port. */ static void pcie_port_device_remove(struct pci_dev *dev) { … } /** * pcie_port_probe_service - probe driver for given PCI Express port service * @dev: PCI Express port service device to probe against * * If PCI Express port service driver is registered with * pcie_port_service_register(), this function will be called by the driver core * whenever match is found between the driver and a port service device. */ static int pcie_port_probe_service(struct device *dev) { … } /** * pcie_port_remove_service - detach driver from given PCI Express port service * @dev: PCI Express port service device to handle * * If PCI Express port service driver is registered with * pcie_port_service_register(), this function will be called by the driver core * when device_unregister() is called for the port service device associated * with the driver. */ static int pcie_port_remove_service(struct device *dev) { … } /** * pcie_port_shutdown_service - shut down given PCI Express port service * @dev: PCI Express port service device to handle * * If PCI Express port service driver is registered with * pcie_port_service_register(), this function will be called by the driver core * when device_shutdown() is called for the port service device associated * with the driver. */ static void pcie_port_shutdown_service(struct device *dev) { … } /** * pcie_port_service_register - register PCI Express port service driver * @new: PCI Express port service driver to register */ int pcie_port_service_register(struct pcie_port_service_driver *new) { … } /** * pcie_port_service_unregister - unregister PCI Express port service driver * @drv: PCI Express port service driver to unregister */ void pcie_port_service_unregister(struct pcie_port_service_driver *drv) { … } /* If this switch is set, PCIe port native services should not be enabled. */ bool pcie_ports_disabled; /* * If the user specified "pcie_ports=native", use the PCIe services regardless * of whether the platform has given us permission. On ACPI systems, this * means we ignore _OSC. */ bool pcie_ports_native; /* * If the user specified "pcie_ports=dpc-native", use the Linux DPC PCIe * service even if the platform hasn't given us permission. */ bool pcie_ports_dpc_native; static int __init pcie_port_setup(char *str) { … } __setup(…); /* global data */ #ifdef CONFIG_PM static int pcie_port_runtime_suspend(struct device *dev) { … } static int pcie_port_runtime_idle(struct device *dev) { … } static const struct dev_pm_ops pcie_portdrv_pm_ops = …; #define PCIE_PORTDRV_PM_OPS … #else /* !PM */ #define PCIE_PORTDRV_PM_OPS … #endif /* !PM */ /* * pcie_portdrv_probe - Probe PCI-Express port devices * @dev: PCI-Express port device being probed * * If detected invokes the pcie_port_device_register() method for * this port device. * */ static int pcie_portdrv_probe(struct pci_dev *dev, const struct pci_device_id *id) { … } static void pcie_portdrv_remove(struct pci_dev *dev) { … } static void pcie_portdrv_shutdown(struct pci_dev *dev) { … } static pci_ers_result_t pcie_portdrv_error_detected(struct pci_dev *dev, pci_channel_state_t error) { … } static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev) { … } static pci_ers_result_t pcie_portdrv_mmio_enabled(struct pci_dev *dev) { … } /* * LINUX Device Driver Model */ static const struct pci_device_id port_pci_ids[] = …; static const struct pci_error_handlers pcie_portdrv_err_handler = …; static struct pci_driver pcie_portdriver = …; static int __init dmi_pcie_pme_disable_msi(const struct dmi_system_id *d) { … } static const struct dmi_system_id pcie_portdrv_dmi_table[] __initconst = …; static void __init pcie_init_services(void) { … } static int __init pcie_portdrv_init(void) { … } device_initcall(pcie_portdrv_init);