diff options
| author | Bjorn Helgaas <bhelgaas@google.com> | 2016-09-01 10:04:55 -0400 |
|---|---|---|
| committer | Bjorn Helgaas <bhelgaas@google.com> | 2016-09-01 10:04:55 -0400 |
| commit | 9e18ad98ca71ca0cfcadf633547409829773f36a (patch) | |
| tree | 66a761b8f3db00623fc112e32af55d909c628dcf | |
| parent | a4589a660662d16336353b1c66ad18e0a0a3eb1e (diff) | |
| parent | 8b2ec318eece89be5e33d5313a25461a55a3177a (diff) | |
Merge branch 'pci/ptm' into next
* pci/ptm:
PCI: Add PTM clock granularity information
PCI: Add pci_enable_ptm() for drivers to enable PTM on endpoints
PCI: Add Precision Time Measurement (PTM) support
| -rw-r--r-- | drivers/pci/pci.h | 6 | ||||
| -rw-r--r-- | drivers/pci/pcie/Kconfig | 11 | ||||
| -rw-r--r-- | drivers/pci/pcie/Makefile | 1 | ||||
| -rw-r--r-- | drivers/pci/pcie/ptm.c | 142 | ||||
| -rw-r--r-- | drivers/pci/probe.c | 3 | ||||
| -rw-r--r-- | include/linux/pci.h | 13 | ||||
| -rw-r--r-- | include/uapi/linux/pci_regs.h | 12 |
7 files changed, 187 insertions, 1 deletions
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 9730c474b016..194521bfb1a3 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h | |||
| @@ -332,6 +332,12 @@ static inline resource_size_t pci_resource_alignment(struct pci_dev *dev, | |||
| 332 | 332 | ||
| 333 | void pci_enable_acs(struct pci_dev *dev); | 333 | void pci_enable_acs(struct pci_dev *dev); |
| 334 | 334 | ||
| 335 | #ifdef CONFIG_PCIE_PTM | ||
| 336 | void pci_ptm_init(struct pci_dev *dev); | ||
| 337 | #else | ||
| 338 | static inline void pci_ptm_init(struct pci_dev *dev) { } | ||
| 339 | #endif | ||
| 340 | |||
| 335 | struct pci_dev_reset_methods { | 341 | struct pci_dev_reset_methods { |
| 336 | u16 vendor; | 342 | u16 vendor; |
| 337 | u16 device; | 343 | u16 device; |
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig index 7fcea75afa4c..7ce77635e5ad 100644 --- a/drivers/pci/pcie/Kconfig +++ b/drivers/pci/pcie/Kconfig | |||
| @@ -92,3 +92,14 @@ config PCIE_DPC | |||
| 92 | will be handled by the DPC driver. If your system doesn't | 92 | will be handled by the DPC driver. If your system doesn't |
| 93 | have this capability or you do not want to use this feature, | 93 | have this capability or you do not want to use this feature, |
| 94 | it is safe to answer N. | 94 | it is safe to answer N. |
| 95 | |||
| 96 | config PCIE_PTM | ||
| 97 | bool "PCIe Precision Time Measurement support" | ||
| 98 | default n | ||
| 99 | depends on PCIEPORTBUS | ||
| 100 | help | ||
| 101 | This enables PCI Express Precision Time Measurement (PTM) | ||
| 102 | support. | ||
| 103 | |||
| 104 | This is only useful if you have devices that support PTM, but it | ||
| 105 | is safe to enable even if you don't. | ||
diff --git a/drivers/pci/pcie/Makefile b/drivers/pci/pcie/Makefile index b24525b3dec1..36e35ea8fde7 100644 --- a/drivers/pci/pcie/Makefile +++ b/drivers/pci/pcie/Makefile | |||
| @@ -16,3 +16,4 @@ obj-$(CONFIG_PCIEAER) += aer/ | |||
| 16 | obj-$(CONFIG_PCIE_PME) += pme.o | 16 | obj-$(CONFIG_PCIE_PME) += pme.o |
| 17 | 17 | ||
| 18 | obj-$(CONFIG_PCIE_DPC) += pcie-dpc.o | 18 | obj-$(CONFIG_PCIE_DPC) += pcie-dpc.o |
| 19 | obj-$(CONFIG_PCIE_PTM) += ptm.o | ||
diff --git a/drivers/pci/pcie/ptm.c b/drivers/pci/pcie/ptm.c new file mode 100644 index 000000000000..bab8ac63c4f3 --- /dev/null +++ b/drivers/pci/pcie/ptm.c | |||
| @@ -0,0 +1,142 @@ | |||
| 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 | char clock_desc[8]; | ||
| 23 | |||
| 24 | switch (dev->ptm_granularity) { | ||
| 25 | case 0: | ||
| 26 | snprintf(clock_desc, sizeof(clock_desc), "unknown"); | ||
| 27 | break; | ||
| 28 | case 255: | ||
| 29 | snprintf(clock_desc, sizeof(clock_desc), ">254ns"); | ||
| 30 | break; | ||
| 31 | default: | ||
| 32 | snprintf(clock_desc, sizeof(clock_desc), "%udns", | ||
| 33 | dev->ptm_granularity); | ||
| 34 | break; | ||
| 35 | } | ||
| 36 | dev_info(&dev->dev, "PTM enabled%s, %s granularity\n", | ||
| 37 | dev->ptm_root ? " (root)" : "", clock_desc); | ||
| 38 | } | ||
| 39 | |||
| 40 | void pci_ptm_init(struct pci_dev *dev) | ||
| 41 | { | ||
| 42 | int pos; | ||
| 43 | u32 cap, ctrl; | ||
| 44 | u8 local_clock; | ||
| 45 | struct pci_dev *ups; | ||
| 46 | |||
| 47 | if (!pci_is_pcie(dev)) | ||
| 48 | return; | ||
| 49 | |||
| 50 | pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PTM); | ||
| 51 | if (!pos) | ||
| 52 | return; | ||
| 53 | |||
| 54 | /* | ||
| 55 | * Enable PTM only on interior devices (root ports, switch ports, | ||
| 56 | * etc.) on the assumption that it causes no link traffic until an | ||
| 57 | * endpoint enables it. | ||
| 58 | */ | ||
| 59 | if ((pci_pcie_type(dev) == PCI_EXP_TYPE_ENDPOINT || | ||
| 60 | pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END)) | ||
| 61 | return; | ||
| 62 | |||
| 63 | pci_read_config_dword(dev, pos + PCI_PTM_CAP, &cap); | ||
| 64 | local_clock = (cap & PCI_PTM_GRANULARITY_MASK) >> 8; | ||
| 65 | |||
| 66 | /* | ||
| 67 | * There's no point in enabling PTM unless it's enabled in the | ||
| 68 | * upstream device or this device can be a PTM Root itself. Per | ||
| 69 | * the spec recommendation (PCIe r3.1, sec 7.32.3), select the | ||
| 70 | * furthest upstream Time Source as the PTM Root. | ||
| 71 | */ | ||
| 72 | ups = pci_upstream_bridge(dev); | ||
| 73 | if (ups && ups->ptm_enabled) { | ||
| 74 | ctrl = PCI_PTM_CTRL_ENABLE; | ||
| 75 | if (ups->ptm_granularity == 0) | ||
| 76 | dev->ptm_granularity = 0; | ||
| 77 | else if (ups->ptm_granularity > local_clock) | ||
| 78 | dev->ptm_granularity = ups->ptm_granularity; | ||
| 79 | } else { | ||
| 80 | if (cap & PCI_PTM_CAP_ROOT) { | ||
| 81 | ctrl = PCI_PTM_CTRL_ENABLE | PCI_PTM_CTRL_ROOT; | ||
| 82 | dev->ptm_root = 1; | ||
| 83 | dev->ptm_granularity = local_clock; | ||
| 84 | } else | ||
| 85 | return; | ||
| 86 | } | ||
| 87 | |||
| 88 | ctrl |= dev->ptm_granularity << 8; | ||
| 89 | pci_write_config_dword(dev, pos + PCI_PTM_CTRL, ctrl); | ||
| 90 | dev->ptm_enabled = 1; | ||
| 91 | |||
| 92 | pci_ptm_info(dev); | ||
| 93 | } | ||
| 94 | |||
| 95 | int pci_enable_ptm(struct pci_dev *dev, u8 *granularity) | ||
| 96 | { | ||
| 97 | int pos; | ||
| 98 | u32 cap, ctrl; | ||
| 99 | struct pci_dev *ups; | ||
| 100 | |||
| 101 | if (!pci_is_pcie(dev)) | ||
| 102 | return -EINVAL; | ||
| 103 | |||
| 104 | pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PTM); | ||
| 105 | if (!pos) | ||
| 106 | return -EINVAL; | ||
| 107 | |||
| 108 | pci_read_config_dword(dev, pos + PCI_PTM_CAP, &cap); | ||
| 109 | if (!(cap & PCI_PTM_CAP_REQ)) | ||
| 110 | return -EINVAL; | ||
| 111 | |||
| 112 | /* | ||
| 113 | * For a PCIe Endpoint, PTM is only useful if the endpoint can | ||
| 114 | * issue PTM requests to upstream devices that have PTM enabled. | ||
| 115 | * | ||
| 116 | * For Root Complex Integrated Endpoints, there is no upstream | ||
| 117 | * device, so there must be some implementation-specific way to | ||
| 118 | * associate the endpoint with a time source. | ||
| 119 | */ | ||
| 120 | if (pci_pcie_type(dev) == PCI_EXP_TYPE_ENDPOINT) { | ||
| 121 | ups = pci_upstream_bridge(dev); | ||
| 122 | if (!ups || !ups->ptm_enabled) | ||
| 123 | return -EINVAL; | ||
| 124 | |||
| 125 | dev->ptm_granularity = ups->ptm_granularity; | ||
| 126 | } else if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END) { | ||
| 127 | dev->ptm_granularity = 0; | ||
| 128 | } else | ||
| 129 | return -EINVAL; | ||
| 130 | |||
| 131 | ctrl = PCI_PTM_CTRL_ENABLE; | ||
| 132 | ctrl |= dev->ptm_granularity << 8; | ||
| 133 | pci_write_config_dword(dev, pos + PCI_PTM_CTRL, ctrl); | ||
| 134 | dev->ptm_enabled = 1; | ||
| 135 | |||
| 136 | pci_ptm_info(dev); | ||
| 137 | |||
| 138 | if (granularity) | ||
| 139 | *granularity = dev->ptm_granularity; | ||
| 140 | return 0; | ||
| 141 | } | ||
| 142 | EXPORT_SYMBOL(pci_enable_ptm); | ||
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 93f280df3428..e2e424472058 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
| @@ -1667,6 +1667,9 @@ static void pci_init_capabilities(struct pci_dev *dev) | |||
| 1667 | pci_enable_acs(dev); | 1667 | pci_enable_acs(dev); |
| 1668 | 1668 | ||
| 1669 | pci_cleanup_aer_error_status_regs(dev); | 1669 | pci_cleanup_aer_error_status_regs(dev); |
| 1670 | |||
| 1671 | /* Precision Time Measurement */ | ||
| 1672 | pci_ptm_init(dev); | ||
| 1670 | } | 1673 | } |
| 1671 | 1674 | ||
| 1672 | /* | 1675 | /* |
diff --git a/include/linux/pci.h b/include/linux/pci.h index 2599a980340f..7256f33b6a15 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
| @@ -367,6 +367,12 @@ struct pci_dev { | |||
| 367 | int rom_attr_enabled; /* has display of the rom attribute been enabled? */ | 367 | int rom_attr_enabled; /* has display of the rom attribute been enabled? */ |
| 368 | struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */ | ||
