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

ptm.c (5039B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * PCI Express Precision Time Measurement
      4 * Copyright (c) 2016, Intel Corporation.
      5 */
      6
      7#include <linux/module.h>
      8#include <linux/init.h>
      9#include <linux/pci.h>
     10#include "../pci.h"
     11
     12static void pci_ptm_info(struct pci_dev *dev)
     13{
     14	char clock_desc[8];
     15
     16	switch (dev->ptm_granularity) {
     17	case 0:
     18		snprintf(clock_desc, sizeof(clock_desc), "unknown");
     19		break;
     20	case 255:
     21		snprintf(clock_desc, sizeof(clock_desc), ">254ns");
     22		break;
     23	default:
     24		snprintf(clock_desc, sizeof(clock_desc), "%uns",
     25			 dev->ptm_granularity);
     26		break;
     27	}
     28	pci_info(dev, "PTM enabled%s, %s granularity\n",
     29		 dev->ptm_root ? " (root)" : "", clock_desc);
     30}
     31
     32void pci_disable_ptm(struct pci_dev *dev)
     33{
     34	int ptm;
     35	u16 ctrl;
     36
     37	if (!pci_is_pcie(dev))
     38		return;
     39
     40	ptm = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PTM);
     41	if (!ptm)
     42		return;
     43
     44	pci_read_config_word(dev, ptm + PCI_PTM_CTRL, &ctrl);
     45	ctrl &= ~(PCI_PTM_CTRL_ENABLE | PCI_PTM_CTRL_ROOT);
     46	pci_write_config_word(dev, ptm + PCI_PTM_CTRL, ctrl);
     47}
     48
     49void pci_save_ptm_state(struct pci_dev *dev)
     50{
     51	int ptm;
     52	struct pci_cap_saved_state *save_state;
     53	u16 *cap;
     54
     55	if (!pci_is_pcie(dev))
     56		return;
     57
     58	ptm = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PTM);
     59	if (!ptm)
     60		return;
     61
     62	save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_PTM);
     63	if (!save_state)
     64		return;
     65
     66	cap = (u16 *)&save_state->cap.data[0];
     67	pci_read_config_word(dev, ptm + PCI_PTM_CTRL, cap);
     68}
     69
     70void pci_restore_ptm_state(struct pci_dev *dev)
     71{
     72	struct pci_cap_saved_state *save_state;
     73	int ptm;
     74	u16 *cap;
     75
     76	if (!pci_is_pcie(dev))
     77		return;
     78
     79	save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_PTM);
     80	ptm = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PTM);
     81	if (!save_state || !ptm)
     82		return;
     83
     84	cap = (u16 *)&save_state->cap.data[0];
     85	pci_write_config_word(dev, ptm + PCI_PTM_CTRL, *cap);
     86}
     87
     88void pci_ptm_init(struct pci_dev *dev)
     89{
     90	int pos;
     91	u32 cap, ctrl;
     92	u8 local_clock;
     93	struct pci_dev *ups;
     94
     95	if (!pci_is_pcie(dev))
     96		return;
     97
     98	/*
     99	 * Enable PTM only on interior devices (root ports, switch ports,
    100	 * etc.) on the assumption that it causes no link traffic until an
    101	 * endpoint enables it.
    102	 */
    103	if ((pci_pcie_type(dev) == PCI_EXP_TYPE_ENDPOINT ||
    104	     pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END))
    105		return;
    106
    107	/*
    108	 * Switch Downstream Ports are not permitted to have a PTM
    109	 * capability; their PTM behavior is controlled by the Upstream
    110	 * Port (PCIe r5.0, sec 7.9.16).
    111	 */
    112	ups = pci_upstream_bridge(dev);
    113	if (pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM &&
    114	    ups && ups->ptm_enabled) {
    115		dev->ptm_granularity = ups->ptm_granularity;
    116		dev->ptm_enabled = 1;
    117		return;
    118	}
    119
    120	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PTM);
    121	if (!pos)
    122		return;
    123
    124	pci_add_ext_cap_save_buffer(dev, PCI_EXT_CAP_ID_PTM, sizeof(u16));
    125
    126	pci_read_config_dword(dev, pos + PCI_PTM_CAP, &cap);
    127	local_clock = (cap & PCI_PTM_GRANULARITY_MASK) >> 8;
    128
    129	/*
    130	 * There's no point in enabling PTM unless it's enabled in the
    131	 * upstream device or this device can be a PTM Root itself.  Per
    132	 * the spec recommendation (PCIe r3.1, sec 7.32.3), select the
    133	 * furthest upstream Time Source as the PTM Root.
    134	 */
    135	if (ups && ups->ptm_enabled) {
    136		ctrl = PCI_PTM_CTRL_ENABLE;
    137		if (ups->ptm_granularity == 0)
    138			dev->ptm_granularity = 0;
    139		else if (ups->ptm_granularity > local_clock)
    140			dev->ptm_granularity = ups->ptm_granularity;
    141	} else {
    142		if (cap & PCI_PTM_CAP_ROOT) {
    143			ctrl = PCI_PTM_CTRL_ENABLE | PCI_PTM_CTRL_ROOT;
    144			dev->ptm_root = 1;
    145			dev->ptm_granularity = local_clock;
    146		} else
    147			return;
    148	}
    149
    150	ctrl |= dev->ptm_granularity << 8;
    151	pci_write_config_dword(dev, pos + PCI_PTM_CTRL, ctrl);
    152	dev->ptm_enabled = 1;
    153
    154	pci_ptm_info(dev);
    155}
    156
    157int pci_enable_ptm(struct pci_dev *dev, u8 *granularity)
    158{
    159	int pos;
    160	u32 cap, ctrl;
    161	struct pci_dev *ups;
    162
    163	if (!pci_is_pcie(dev))
    164		return -EINVAL;
    165
    166	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PTM);
    167	if (!pos)
    168		return -EINVAL;
    169
    170	pci_read_config_dword(dev, pos + PCI_PTM_CAP, &cap);
    171	if (!(cap & PCI_PTM_CAP_REQ))
    172		return -EINVAL;
    173
    174	/*
    175	 * For a PCIe Endpoint, PTM is only useful if the endpoint can
    176	 * issue PTM requests to upstream devices that have PTM enabled.
    177	 *
    178	 * For Root Complex Integrated Endpoints, there is no upstream
    179	 * device, so there must be some implementation-specific way to
    180	 * associate the endpoint with a time source.
    181	 */
    182	if (pci_pcie_type(dev) == PCI_EXP_TYPE_ENDPOINT) {
    183		ups = pci_upstream_bridge(dev);
    184		if (!ups || !ups->ptm_enabled)
    185			return -EINVAL;
    186
    187		dev->ptm_granularity = ups->ptm_granularity;
    188	} else if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END) {
    189		dev->ptm_granularity = 0;
    190	} else
    191		return -EINVAL;
    192
    193	ctrl = PCI_PTM_CTRL_ENABLE;
    194	ctrl |= dev->ptm_granularity << 8;
    195	pci_write_config_dword(dev, pos + PCI_PTM_CTRL, ctrl);
    196	dev->ptm_enabled = 1;
    197
    198	pci_ptm_info(dev);
    199
    200	if (granularity)
    201		*granularity = dev->ptm_granularity;
    202	return 0;
    203}
    204EXPORT_SYMBOL(pci_enable_ptm);
    205
    206bool pcie_ptm_enabled(struct pci_dev *dev)
    207{
    208	if (!dev)
    209		return false;
    210
    211	return dev->ptm_enabled;
    212}
    213EXPORT_SYMBOL(pcie_ptm_enabled);