]>
Commit | Line | Data |
---|---|---|
9bb04a0c JY |
1 | /* |
2 | * PCI Express Precision Time Measurement | |
3 | * Copyright (c) 2016, Intel Corporation. | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms and conditions of the GNU General Public License, | |
7 | * version 2, as published by the Free Software Foundation. | |
8 | * | |
9 | * This program is distributed in the hope it will be useful, but WITHOUT | |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
12 | * more details. | |
13 | */ | |
14 | ||
15 | #include <linux/module.h> | |
16 | #include <linux/init.h> | |
17 | #include <linux/pci.h> | |
18 | #include "../pci.h" | |
19 | ||
20 | static void pci_ptm_info(struct pci_dev *dev) | |
21 | { | |
22 | dev_info(&dev->dev, "PTM enabled%s\n", dev->ptm_root ? " (root)" : ""); | |
23 | } | |
24 | ||
25 | void pci_ptm_init(struct pci_dev *dev) | |
26 | { | |
27 | int pos; | |
28 | u32 cap, ctrl; | |
29 | struct pci_dev *ups; | |
30 | ||
31 | if (!pci_is_pcie(dev)) | |
32 | return; | |
33 | ||
34 | pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PTM); | |
35 | if (!pos) | |
36 | return; | |
37 | ||
38 | /* | |
39 | * Enable PTM only on interior devices (root ports, switch ports, | |
40 | * etc.) on the assumption that it causes no link traffic until an | |
41 | * endpoint enables it. | |
42 | */ | |
43 | if ((pci_pcie_type(dev) == PCI_EXP_TYPE_ENDPOINT || | |
44 | pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END)) | |
45 | return; | |
46 | ||
47 | pci_read_config_dword(dev, pos + PCI_PTM_CAP, &cap); | |
48 | ||
49 | /* | |
50 | * There's no point in enabling PTM unless it's enabled in the | |
51 | * upstream device or this device can be a PTM Root itself. Per | |
52 | * the spec recommendation (PCIe r3.1, sec 7.32.3), select the | |
53 | * furthest upstream Time Source as the PTM Root. | |
54 | */ | |
55 | ups = pci_upstream_bridge(dev); | |
56 | if (ups && ups->ptm_enabled) { | |
57 | ctrl = PCI_PTM_CTRL_ENABLE; | |
58 | } else { | |
59 | if (cap & PCI_PTM_CAP_ROOT) { | |
60 | ctrl = PCI_PTM_CTRL_ENABLE | PCI_PTM_CTRL_ROOT; | |
61 | dev->ptm_root = 1; | |
62 | } else | |
63 | return; | |
64 | } | |
65 | ||
66 | pci_write_config_dword(dev, pos + PCI_PTM_CTRL, ctrl); | |
67 | dev->ptm_enabled = 1; | |
68 | ||
69 | pci_ptm_info(dev); | |
70 | } |