cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

portdrv_pci.c (6371B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Purpose:	PCI Express Port Bus Driver
      4 * Author:	Tom Nguyen <tom.l.nguyen@intel.com>
      5 *
      6 * Copyright (C) 2004 Intel
      7 * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
      8 */
      9
     10#include <linux/pci.h>
     11#include <linux/kernel.h>
     12#include <linux/errno.h>
     13#include <linux/pm.h>
     14#include <linux/pm_runtime.h>
     15#include <linux/init.h>
     16#include <linux/aer.h>
     17#include <linux/dmi.h>
     18
     19#include "../pci.h"
     20#include "portdrv.h"
     21
     22/* If this switch is set, PCIe port native services should not be enabled. */
     23bool pcie_ports_disabled;
     24
     25/*
     26 * If the user specified "pcie_ports=native", use the PCIe services regardless
     27 * of whether the platform has given us permission.  On ACPI systems, this
     28 * means we ignore _OSC.
     29 */
     30bool pcie_ports_native;
     31
     32/*
     33 * If the user specified "pcie_ports=dpc-native", use the Linux DPC PCIe
     34 * service even if the platform hasn't given us permission.
     35 */
     36bool pcie_ports_dpc_native;
     37
     38static int __init pcie_port_setup(char *str)
     39{
     40	if (!strncmp(str, "compat", 6))
     41		pcie_ports_disabled = true;
     42	else if (!strncmp(str, "native", 6))
     43		pcie_ports_native = true;
     44	else if (!strncmp(str, "dpc-native", 10))
     45		pcie_ports_dpc_native = true;
     46
     47	return 1;
     48}
     49__setup("pcie_ports=", pcie_port_setup);
     50
     51/* global data */
     52
     53#ifdef CONFIG_PM
     54static int pcie_port_runtime_suspend(struct device *dev)
     55{
     56	if (!to_pci_dev(dev)->bridge_d3)
     57		return -EBUSY;
     58
     59	return pcie_port_device_runtime_suspend(dev);
     60}
     61
     62static int pcie_port_runtime_idle(struct device *dev)
     63{
     64	/*
     65	 * Assume the PCI core has set bridge_d3 whenever it thinks the port
     66	 * should be good to go to D3.  Everything else, including moving
     67	 * the port to D3, is handled by the PCI core.
     68	 */
     69	return to_pci_dev(dev)->bridge_d3 ? 0 : -EBUSY;
     70}
     71
     72static const struct dev_pm_ops pcie_portdrv_pm_ops = {
     73	.suspend	= pcie_port_device_suspend,
     74	.resume_noirq	= pcie_port_device_resume_noirq,
     75	.resume		= pcie_port_device_resume,
     76	.freeze		= pcie_port_device_suspend,
     77	.thaw		= pcie_port_device_resume,
     78	.poweroff	= pcie_port_device_suspend,
     79	.restore_noirq	= pcie_port_device_resume_noirq,
     80	.restore	= pcie_port_device_resume,
     81	.runtime_suspend = pcie_port_runtime_suspend,
     82	.runtime_resume	= pcie_port_device_runtime_resume,
     83	.runtime_idle	= pcie_port_runtime_idle,
     84};
     85
     86#define PCIE_PORTDRV_PM_OPS	(&pcie_portdrv_pm_ops)
     87
     88#else /* !PM */
     89
     90#define PCIE_PORTDRV_PM_OPS	NULL
     91#endif /* !PM */
     92
     93/*
     94 * pcie_portdrv_probe - Probe PCI-Express port devices
     95 * @dev: PCI-Express port device being probed
     96 *
     97 * If detected invokes the pcie_port_device_register() method for
     98 * this port device.
     99 *
    100 */
    101static int pcie_portdrv_probe(struct pci_dev *dev,
    102					const struct pci_device_id *id)
    103{
    104	int type = pci_pcie_type(dev);
    105	int status;
    106
    107	if (!pci_is_pcie(dev) ||
    108	    ((type != PCI_EXP_TYPE_ROOT_PORT) &&
    109	     (type != PCI_EXP_TYPE_UPSTREAM) &&
    110	     (type != PCI_EXP_TYPE_DOWNSTREAM) &&
    111	     (type != PCI_EXP_TYPE_RC_EC)))
    112		return -ENODEV;
    113
    114	if (type == PCI_EXP_TYPE_RC_EC)
    115		pcie_link_rcec(dev);
    116
    117	status = pcie_port_device_register(dev);
    118	if (status)
    119		return status;
    120
    121	pci_save_state(dev);
    122
    123	dev_pm_set_driver_flags(&dev->dev, DPM_FLAG_NO_DIRECT_COMPLETE |
    124					   DPM_FLAG_SMART_SUSPEND);
    125
    126	if (pci_bridge_d3_possible(dev)) {
    127		/*
    128		 * Keep the port resumed 100ms to make sure things like
    129		 * config space accesses from userspace (lspci) will not
    130		 * cause the port to repeatedly suspend and resume.
    131		 */
    132		pm_runtime_set_autosuspend_delay(&dev->dev, 100);
    133		pm_runtime_use_autosuspend(&dev->dev);
    134		pm_runtime_mark_last_busy(&dev->dev);
    135		pm_runtime_put_autosuspend(&dev->dev);
    136		pm_runtime_allow(&dev->dev);
    137	}
    138
    139	return 0;
    140}
    141
    142static void pcie_portdrv_remove(struct pci_dev *dev)
    143{
    144	if (pci_bridge_d3_possible(dev)) {
    145		pm_runtime_forbid(&dev->dev);
    146		pm_runtime_get_noresume(&dev->dev);
    147		pm_runtime_dont_use_autosuspend(&dev->dev);
    148	}
    149
    150	pcie_port_device_remove(dev);
    151}
    152
    153static pci_ers_result_t pcie_portdrv_error_detected(struct pci_dev *dev,
    154					pci_channel_state_t error)
    155{
    156	if (error == pci_channel_io_frozen)
    157		return PCI_ERS_RESULT_NEED_RESET;
    158	return PCI_ERS_RESULT_CAN_RECOVER;
    159}
    160
    161static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev)
    162{
    163	size_t off = offsetof(struct pcie_port_service_driver, slot_reset);
    164	device_for_each_child(&dev->dev, &off, pcie_port_device_iter);
    165
    166	pci_restore_state(dev);
    167	pci_save_state(dev);
    168	return PCI_ERS_RESULT_RECOVERED;
    169}
    170
    171static pci_ers_result_t pcie_portdrv_mmio_enabled(struct pci_dev *dev)
    172{
    173	return PCI_ERS_RESULT_RECOVERED;
    174}
    175
    176/*
    177 * LINUX Device Driver Model
    178 */
    179static const struct pci_device_id port_pci_ids[] = {
    180	/* handle any PCI-Express port */
    181	{ PCI_DEVICE_CLASS(PCI_CLASS_BRIDGE_PCI_NORMAL, ~0) },
    182	/* subtractive decode PCI-to-PCI bridge, class type is 060401h */
    183	{ PCI_DEVICE_CLASS(PCI_CLASS_BRIDGE_PCI_SUBTRACTIVE, ~0) },
    184	/* handle any Root Complex Event Collector */
    185	{ PCI_DEVICE_CLASS(((PCI_CLASS_SYSTEM_RCEC << 8) | 0x00), ~0) },
    186	{ },
    187};
    188
    189static const struct pci_error_handlers pcie_portdrv_err_handler = {
    190	.error_detected = pcie_portdrv_error_detected,
    191	.slot_reset = pcie_portdrv_slot_reset,
    192	.mmio_enabled = pcie_portdrv_mmio_enabled,
    193};
    194
    195static struct pci_driver pcie_portdriver = {
    196	.name		= "pcieport",
    197	.id_table	= &port_pci_ids[0],
    198
    199	.probe		= pcie_portdrv_probe,
    200	.remove		= pcie_portdrv_remove,
    201	.shutdown	= pcie_portdrv_remove,
    202
    203	.err_handler	= &pcie_portdrv_err_handler,
    204
    205	.driver_managed_dma = true,
    206
    207	.driver.pm	= PCIE_PORTDRV_PM_OPS,
    208};
    209
    210static int __init dmi_pcie_pme_disable_msi(const struct dmi_system_id *d)
    211{
    212	pr_notice("%s detected: will not use MSI for PCIe PME signaling\n",
    213		  d->ident);
    214	pcie_pme_disable_msi();
    215	return 0;
    216}
    217
    218static const struct dmi_system_id pcie_portdrv_dmi_table[] __initconst = {
    219	/*
    220	 * Boxes that should not use MSI for PCIe PME signaling.
    221	 */
    222	{
    223	 .callback = dmi_pcie_pme_disable_msi,
    224	 .ident = "MSI Wind U-100",
    225	 .matches = {
    226		     DMI_MATCH(DMI_SYS_VENDOR,
    227				"MICRO-STAR INTERNATIONAL CO., LTD"),
    228		     DMI_MATCH(DMI_PRODUCT_NAME, "U-100"),
    229		     },
    230	 },
    231	 {}
    232};
    233
    234static void __init pcie_init_services(void)
    235{
    236	pcie_aer_init();
    237	pcie_pme_init();
    238	pcie_dpc_init();
    239	pcie_hp_init();
    240}
    241
    242static int __init pcie_portdrv_init(void)
    243{
    244	if (pcie_ports_disabled)
    245		return -EACCES;
    246
    247	pcie_init_services();
    248	dmi_check_system(pcie_portdrv_dmi_table);
    249
    250	return pci_register_driver(&pcie_portdriver);
    251}
    252device_initcall(pcie_portdrv_init);