root/drivers/pci/pcie/ptm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pci_ptm_info
  2. pci_ptm_init
  3. pci_enable_ptm

   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 
  12 static 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 
  32 void pci_ptm_init(struct pci_dev *dev)
  33 {
  34         int pos;
  35         u32 cap, ctrl;
  36         u8 local_clock;
  37         struct pci_dev *ups;
  38 
  39         if (!pci_is_pcie(dev))
  40                 return;
  41 
  42         pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PTM);
  43         if (!pos)
  44                 return;
  45 
  46         /*
  47          * Enable PTM only on interior devices (root ports, switch ports,
  48          * etc.) on the assumption that it causes no link traffic until an
  49          * endpoint enables it.
  50          */
  51         if ((pci_pcie_type(dev) == PCI_EXP_TYPE_ENDPOINT ||
  52              pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END))
  53                 return;
  54 
  55         pci_read_config_dword(dev, pos + PCI_PTM_CAP, &cap);
  56         local_clock = (cap & PCI_PTM_GRANULARITY_MASK) >> 8;
  57 
  58         /*
  59          * There's no point in enabling PTM unless it's enabled in the
  60          * upstream device or this device can be a PTM Root itself.  Per
  61          * the spec recommendation (PCIe r3.1, sec 7.32.3), select the
  62          * furthest upstream Time Source as the PTM Root.
  63          */
  64         ups = pci_upstream_bridge(dev);
  65         if (ups && ups->ptm_enabled) {
  66                 ctrl = PCI_PTM_CTRL_ENABLE;
  67                 if (ups->ptm_granularity == 0)
  68                         dev->ptm_granularity = 0;
  69                 else if (ups->ptm_granularity > local_clock)
  70                         dev->ptm_granularity = ups->ptm_granularity;
  71         } else {
  72                 if (cap & PCI_PTM_CAP_ROOT) {
  73                         ctrl = PCI_PTM_CTRL_ENABLE | PCI_PTM_CTRL_ROOT;
  74                         dev->ptm_root = 1;
  75                         dev->ptm_granularity = local_clock;
  76                 } else
  77                         return;
  78         }
  79 
  80         ctrl |= dev->ptm_granularity << 8;
  81         pci_write_config_dword(dev, pos + PCI_PTM_CTRL, ctrl);
  82         dev->ptm_enabled = 1;
  83 
  84         pci_ptm_info(dev);
  85 }
  86 
  87 int pci_enable_ptm(struct pci_dev *dev, u8 *granularity)
  88 {
  89         int pos;
  90         u32 cap, ctrl;
  91         struct pci_dev *ups;
  92 
  93         if (!pci_is_pcie(dev))
  94                 return -EINVAL;
  95 
  96         pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PTM);
  97         if (!pos)
  98                 return -EINVAL;
  99 
 100         pci_read_config_dword(dev, pos + PCI_PTM_CAP, &cap);
 101         if (!(cap & PCI_PTM_CAP_REQ))
 102                 return -EINVAL;
 103 
 104         /*
 105          * For a PCIe Endpoint, PTM is only useful if the endpoint can
 106          * issue PTM requests to upstream devices that have PTM enabled.
 107          *
 108          * For Root Complex Integrated Endpoints, there is no upstream
 109          * device, so there must be some implementation-specific way to
 110          * associate the endpoint with a time source.
 111          */
 112         if (pci_pcie_type(dev) == PCI_EXP_TYPE_ENDPOINT) {
 113                 ups = pci_upstream_bridge(dev);
 114                 if (!ups || !ups->ptm_enabled)
 115                         return -EINVAL;
 116 
 117                 dev->ptm_granularity = ups->ptm_granularity;
 118         } else if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END) {
 119                 dev->ptm_granularity = 0;
 120         } else
 121                 return -EINVAL;
 122 
 123         ctrl = PCI_PTM_CTRL_ENABLE;
 124         ctrl |= dev->ptm_granularity << 8;
 125         pci_write_config_dword(dev, pos + PCI_PTM_CTRL, ctrl);
 126         dev->ptm_enabled = 1;
 127 
 128         pci_ptm_info(dev);
 129 
 130         if (granularity)
 131                 *granularity = dev->ptm_granularity;
 132         return 0;
 133 }
 134 EXPORT_SYMBOL(pci_enable_ptm);

/* [<][>][^][v][top][bottom][index][help] */