summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2026-04-13 12:50:04 -0500
committerBjorn Helgaas <bhelgaas@google.com>2026-04-13 12:50:04 -0500
commit7d7c6ebd46d952335ff33e21f77fdd761ac2b573 (patch)
tree2f268aeab9141687a0c8d23838828ea6b153ad66
parenta735a513ff2c219f3dc4f9c159f3a328bfb41834 (diff)
parente1092d5e15e6a9b168bf830af9a26d7ea17cd57d (diff)
downloadlwn-7d7c6ebd46d952335ff33e21f77fdd761ac2b573.tar.gz
lwn-7d7c6ebd46d952335ff33e21f77fdd761ac2b573.zip
Merge branch 'pci/ptm'
- Leave Precision Time Measurement disabled until a driver enables it to avoid PCIe errors (Mika Westerberg) * pci/ptm: PCI/PTM: Do not enable PTM automatically for Root and Switch Upstream Ports PCI/PTM: Drop pci_enable_ptm() granularity parameter
-rw-r--r--drivers/net/ethernet/intel/ice/ice_main.c2
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_main.c2
-rw-r--r--drivers/net/ethernet/intel/igc/igc_main.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/main.c2
-rw-r--r--drivers/pci/pcie/ptm.c77
-rw-r--r--include/linux/pci.h6
6 files changed, 48 insertions, 43 deletions
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index ebf48feffb30..b35c4e4ecd2a 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -5028,7 +5028,7 @@ static int ice_init(struct ice_pf *pf)
}
if (pf->hw.mac_type == ICE_MAC_E830) {
- err = pci_enable_ptm(pf->pdev, NULL);
+ err = pci_enable_ptm(pf->pdev);
if (err)
dev_dbg(dev, "PCIe PTM not supported by PCIe bus/controller\n");
}
diff --git a/drivers/net/ethernet/intel/idpf/idpf_main.c b/drivers/net/ethernet/intel/idpf/idpf_main.c
index 0dd741dcfcdb..ab3c409e587b 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_main.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_main.c
@@ -257,7 +257,7 @@ static int idpf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_free;
}
- err = pci_enable_ptm(pdev, NULL);
+ err = pci_enable_ptm(pdev);
if (err)
pci_dbg(pdev, "PCIe PTM is not supported by PCIe bus/controller\n");
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index 27e5c2109138..b030acf94ac4 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -7123,7 +7123,7 @@ static int igc_probe(struct pci_dev *pdev,
if (err)
goto err_pci_reg;
- err = pci_enable_ptm(pdev, NULL);
+ err = pci_enable_ptm(pdev);
if (err < 0)
dev_info(&pdev->dev, "PCIe PTM not supported by PCIe bus/controller\n");
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index fdc3ba20912e..0b94d4ed0ef6 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -960,7 +960,7 @@ static int mlx5_pci_init(struct mlx5_core_dev *dev, struct pci_dev *pdev,
mlx5_pci_vsc_init(dev);
- pci_enable_ptm(pdev, NULL);
+ pci_enable_ptm(pdev);
return 0;
diff --git a/drivers/pci/pcie/ptm.c b/drivers/pci/pcie/ptm.c
index 91a598ed534c..a41ffd1914de 100644
--- a/drivers/pci/pcie/ptm.c
+++ b/drivers/pci/pcie/ptm.c
@@ -52,6 +52,7 @@ void pci_ptm_init(struct pci_dev *dev)
return;
dev->ptm_cap = ptm;
+ atomic_set(&dev->ptm_enable_cnt, 0);
pci_add_ext_cap_save_buffer(dev, PCI_EXT_CAP_ID_PTM, sizeof(u32));
pci_read_config_dword(dev, ptm + PCI_PTM_CAP, &cap);
@@ -85,10 +86,6 @@ void pci_ptm_init(struct pci_dev *dev)
dev->ptm_responder = 1;
if (cap & PCI_PTM_CAP_REQ)
dev->ptm_requester = 1;
-
- if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT ||
- pci_pcie_type(dev) == PCI_EXP_TYPE_UPSTREAM)
- pci_enable_ptm(dev, NULL);
}
void pci_save_ptm_state(struct pci_dev *dev)
@@ -129,26 +126,11 @@ void pci_restore_ptm_state(struct pci_dev *dev)
static int __pci_enable_ptm(struct pci_dev *dev)
{
u16 ptm = dev->ptm_cap;
- struct pci_dev *ups;
u32 ctrl;
if (!ptm)
return -EINVAL;
- /*
- * A device uses local PTM Messages to request time information
- * from a PTM Root that's farther upstream. Every device along the
- * path must support PTM and have it enabled so it can handle the
- * messages. Therefore, if this device is not a PTM Root, the
- * upstream link partner must have PTM enabled before we can enable
- * PTM.
- */
- if (!dev->ptm_root) {
- ups = pci_upstream_ptm(dev);
- if (!ups || !ups->ptm_enabled)
- return -EINVAL;
- }
-
switch (pci_pcie_type(dev)) {
case PCI_EXP_TYPE_ROOT_PORT:
if (!dev->ptm_root)
@@ -182,27 +164,46 @@ static int __pci_enable_ptm(struct pci_dev *dev)
/**
* pci_enable_ptm() - Enable Precision Time Measurement
* @dev: PCI device
- * @granularity: pointer to return granularity
*
- * Enable Precision Time Measurement for @dev. If successful and
- * @granularity is non-NULL, return the Effective Granularity.
+ * Enable Precision Time Measurement for @dev.
*
* Return: zero if successful, or -EINVAL if @dev lacks a PTM Capability or
* is not a PTM Root and lacks an upstream path of PTM-enabled devices.
*/
-int pci_enable_ptm(struct pci_dev *dev, u8 *granularity)
+int pci_enable_ptm(struct pci_dev *dev)
{
int rc;
char clock_desc[8];
- rc = __pci_enable_ptm(dev);
- if (rc)
- return rc;
+ /*
+ * A device uses local PTM Messages to request time information
+ * from a PTM Root that's farther upstream. Every device along
+ * the path must support PTM and have it enabled so it can
+ * handle the messages. Therefore, if this device is not a PTM
+ * Root, the upstream link partner must have PTM enabled before
+ * we can enable PTM.
+ */
+ if (!dev->ptm_root) {
+ struct pci_dev *parent;
+
+ parent = pci_upstream_ptm(dev);
+ if (!parent)
+ return -EINVAL;
+ /* Enable PTM for the parent */
+ rc = pci_enable_ptm(parent);
+ if (rc)
+ return rc;
+ }
- dev->ptm_enabled = 1;
+ /* Already enabled? */
+ if (atomic_inc_return(&dev->ptm_enable_cnt) > 1)
+ return 0;
- if (granularity)
- *granularity = dev->ptm_granularity;
+ rc = __pci_enable_ptm(dev);
+ if (rc) {
+ atomic_dec(&dev->ptm_enable_cnt);
+ return rc;
+ }
switch (dev->ptm_granularity) {
case 0:
@@ -244,27 +245,31 @@ static void __pci_disable_ptm(struct pci_dev *dev)
*/
void pci_disable_ptm(struct pci_dev *dev)
{
- if (dev->ptm_enabled) {
+ struct pci_dev *parent;
+
+ if (atomic_dec_and_test(&dev->ptm_enable_cnt))
__pci_disable_ptm(dev);
- dev->ptm_enabled = 0;
- }
+
+ parent = pci_upstream_ptm(dev);
+ if (parent)
+ pci_disable_ptm(parent);
}
EXPORT_SYMBOL(pci_disable_ptm);
/*
- * Disable PTM, but preserve dev->ptm_enabled so we silently re-enable it on
+ * Disable PTM, but preserve dev->ptm_enable_cnt so we silently re-enable it on
* resume if necessary.
*/
void pci_suspend_ptm(struct pci_dev *dev)
{
- if (dev->ptm_enabled)
+ if (atomic_read(&dev->ptm_enable_cnt))
__pci_disable_ptm(dev);
}
/* If PTM was enabled before suspend, re-enable it when resuming */
void pci_resume_ptm(struct pci_dev *dev)
{
- if (dev->ptm_enabled)
+ if (atomic_read(&dev->ptm_enable_cnt))
__pci_enable_ptm(dev);
}
@@ -273,7 +278,7 @@ bool pcie_ptm_enabled(struct pci_dev *dev)
if (!dev)
return false;
- return dev->ptm_enabled;
+ return atomic_read(&dev->ptm_enable_cnt);
}
EXPORT_SYMBOL(pcie_ptm_enabled);
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 482dd8460dd9..47c5b0c09ffb 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -518,7 +518,7 @@ struct pci_dev {
unsigned int ptm_root:1;
unsigned int ptm_responder:1;
unsigned int ptm_requester:1;
- unsigned int ptm_enabled:1;
+ atomic_t ptm_enable_cnt;
u8 ptm_granularity;
#endif
#ifdef CONFIG_PCI_MSI
@@ -1973,11 +1973,11 @@ struct pci_ptm_debugfs {
};
#ifdef CONFIG_PCIE_PTM
-int pci_enable_ptm(struct pci_dev *dev, u8 *granularity);
+int pci_enable_ptm(struct pci_dev *dev);
void pci_disable_ptm(struct pci_dev *dev);
bool pcie_ptm_enabled(struct pci_dev *dev);
#else
-static inline int pci_enable_ptm(struct pci_dev *dev, u8 *granularity)
+static inline int pci_enable_ptm(struct pci_dev *dev)
{ return -EINVAL; }
static inline void pci_disable_ptm(struct pci_dev *dev) { }
static inline bool pcie_ptm_enabled(struct pci_dev *dev)