ptm.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * PCI Express Precision Time Measurement
  4. * Copyright (c) 2016, Intel Corporation.
  5. */
  6. #include <linux/module.h>
  7. #include <linux/init.h>
  8. #include <linux/pci.h>
  9. #include "../pci.h"
  10. static void pci_ptm_info(struct pci_dev *dev)
  11. {
  12. char clock_desc[8];
  13. switch (dev->ptm_granularity) {
  14. case 0:
  15. snprintf(clock_desc, sizeof(clock_desc), "unknown");
  16. break;
  17. case 255:
  18. snprintf(clock_desc, sizeof(clock_desc), ">254ns");
  19. break;
  20. default:
  21. snprintf(clock_desc, sizeof(clock_desc), "%uns",
  22. dev->ptm_granularity);
  23. break;
  24. }
  25. pci_info(dev, "PTM enabled%s, %s granularity\n",
  26. dev->ptm_root ? " (root)" : "", clock_desc);
  27. }
  28. void pci_ptm_init(struct pci_dev *dev)
  29. {
  30. int pos;
  31. u32 cap, ctrl;
  32. u8 local_clock;
  33. struct pci_dev *ups;
  34. if (!pci_is_pcie(dev))
  35. return;
  36. /*
  37. * Enable PTM only on interior devices (root ports, switch ports,
  38. * etc.) on the assumption that it causes no link traffic until an
  39. * endpoint enables it.
  40. */
  41. if ((pci_pcie_type(dev) == PCI_EXP_TYPE_ENDPOINT ||
  42. pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END))
  43. return;
  44. /*
  45. * Switch Downstream Ports are not permitted to have a PTM
  46. * capability; their PTM behavior is controlled by the Upstream
  47. * Port (PCIe r5.0, sec 7.9.16).
  48. */
  49. ups = pci_upstream_bridge(dev);
  50. if (pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM &&
  51. ups && ups->ptm_enabled) {
  52. dev->ptm_granularity = ups->ptm_granularity;
  53. dev->ptm_enabled = 1;
  54. return;
  55. }
  56. pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PTM);
  57. if (!pos)
  58. return;
  59. pci_read_config_dword(dev, pos + PCI_PTM_CAP, &cap);
  60. local_clock = (cap & PCI_PTM_GRANULARITY_MASK) >> 8;
  61. /*
  62. * There's no point in enabling PTM unless it's enabled in the
  63. * upstream device or this device can be a PTM Root itself. Per
  64. * the spec recommendation (PCIe r3.1, sec 7.32.3), select the
  65. * furthest upstream Time Source as the PTM Root.
  66. */
  67. if (ups && ups->ptm_enabled) {
  68. ctrl = PCI_PTM_CTRL_ENABLE;
  69. if (ups->ptm_granularity == 0)
  70. dev->ptm_granularity = 0;
  71. else if (ups->ptm_granularity > local_clock)
  72. dev->ptm_granularity = ups->ptm_granularity;
  73. } else {
  74. if (cap & PCI_PTM_CAP_ROOT) {
  75. ctrl = PCI_PTM_CTRL_ENABLE | PCI_PTM_CTRL_ROOT;
  76. dev->ptm_root = 1;
  77. dev->ptm_granularity = local_clock;
  78. } else
  79. return;
  80. }
  81. ctrl |= dev->ptm_granularity << 8;
  82. pci_write_config_dword(dev, pos + PCI_PTM_CTRL, ctrl);
  83. dev->ptm_enabled = 1;
  84. pci_ptm_info(dev);
  85. }
  86. int pci_enable_ptm(struct pci_dev *dev, u8 *granularity)
  87. {
  88. int pos;
  89. u32 cap, ctrl;
  90. struct pci_dev *ups;
  91. if (!pci_is_pcie(dev))
  92. return -EINVAL;
  93. pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PTM);
  94. if (!pos)
  95. return -EINVAL;
  96. pci_read_config_dword(dev, pos + PCI_PTM_CAP, &cap);
  97. if (!(cap & PCI_PTM_CAP_REQ))
  98. return -EINVAL;
  99. /*
  100. * For a PCIe Endpoint, PTM is only useful if the endpoint can
  101. * issue PTM requests to upstream devices that have PTM enabled.
  102. *
  103. * For Root Complex Integrated Endpoints, there is no upstream
  104. * device, so there must be some implementation-specific way to
  105. * associate the endpoint with a time source.
  106. */
  107. if (pci_pcie_type(dev) == PCI_EXP_TYPE_ENDPOINT) {
  108. ups = pci_upstream_bridge(dev);
  109. if (!ups || !ups->ptm_enabled)
  110. return -EINVAL;
  111. dev->ptm_granularity = ups->ptm_granularity;
  112. } else if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END) {
  113. dev->ptm_granularity = 0;
  114. } else
  115. return -EINVAL;
  116. ctrl = PCI_PTM_CTRL_ENABLE;
  117. ctrl |= dev->ptm_granularity << 8;
  118. pci_write_config_dword(dev, pos + PCI_PTM_CTRL, ctrl);
  119. dev->ptm_enabled = 1;
  120. pci_ptm_info(dev);
  121. if (granularity)
  122. *granularity = dev->ptm_granularity;
  123. return 0;
  124. }
  125. EXPORT_SYMBOL(pci_enable_ptm);