]> www.infradead.org Git - users/hch/misc.git/commitdiff
iavf: add initial framework for registering PTP clock
authorJacob Keller <jacob.e.keller@intel.com>
Wed, 6 Nov 2024 17:37:23 +0000 (12:37 -0500)
committerTony Nguyen <anthony.l.nguyen@intel.com>
Fri, 14 Feb 2025 18:58:07 +0000 (10:58 -0800)
Add the iavf_ptp.c file and fill it in with a skeleton framework to
allow registering the PTP clock device.
Add implementation of helper functions to check if a PTP capability
is supported and handle change in PTP capabilities.
Enabling virtual clock would be possible, though it would probably
perform poorly due to the lack of direct time access.

Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Reviewed-by: Sai Krishna <saikrishnag@marvell.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Co-developed-by: Ahmed Zaki <ahmed.zaki@intel.com>
Signed-off-by: Ahmed Zaki <ahmed.zaki@intel.com>
Tested-by: Rafal Romanowski <rafal.romanowski@intel.com>
Co-developed-by: Mateusz Polchlopek <mateusz.polchlopek@intel.com>
Signed-off-by: Mateusz Polchlopek <mateusz.polchlopek@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
drivers/net/ethernet/intel/Kconfig
drivers/net/ethernet/intel/iavf/Makefile
drivers/net/ethernet/intel/iavf/iavf_main.c
drivers/net/ethernet/intel/iavf/iavf_ptp.c [new file with mode: 0644]
drivers/net/ethernet/intel/iavf/iavf_ptp.h
drivers/net/ethernet/intel/iavf/iavf_txrx.h
drivers/net/ethernet/intel/iavf/iavf_virtchnl.c

index 26b9938bc38d6b2ad20c833b2b1afcc18619efd2..1640d2f27833073c13a41e6070b6ae0dd8f99aa7 100644 (file)
@@ -264,6 +264,7 @@ config I40EVF
        tristate "Intel(R) Ethernet Adaptive Virtual Function support"
        select IAVF
        depends on PCI_MSI
+       depends on PTP_1588_CLOCK_OPTIONAL
        help
          This driver supports virtual functions for Intel XL710,
          X710, X722, XXV710, and all devices advertising support for
index 356ac9faa5bf9de6c386b4828fdd32fae381ee50..e13720a728ff3bf2a73117f4980bab8e4f7f0b6a 100644 (file)
@@ -13,3 +13,5 @@ obj-$(CONFIG_IAVF) += iavf.o
 
 iavf-y := iavf_main.o iavf_ethtool.o iavf_virtchnl.o iavf_fdir.o \
          iavf_adv_rss.o iavf_txrx.o iavf_common.o iavf_adminq.o
+
+iavf-$(CONFIG_PTP_1588_CLOCK) += iavf_ptp.o
index edb9679cbad4772b72ab52609880d29bdc9b4c18..8d652ab72e195b72ea1775f026cf6ae00ddf85d2 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/net/intel/libie/rx.h>
 
 #include "iavf.h"
+#include "iavf_ptp.h"
 #include "iavf_prototype.h"
 /* All iavf tracepoints are defined by the include below, which must
  * be included exactly once across the whole kernel with
@@ -2878,6 +2879,9 @@ static void iavf_init_config_adapter(struct iavf_adapter *adapter)
        if (QOS_ALLOWED(adapter))
                adapter->aq_required |= IAVF_FLAG_AQ_GET_QOS_CAPS;
 
+       /* Setup initial PTP configuration */
+       iavf_ptp_init(adapter);
+
        iavf_schedule_finish_config(adapter);
        return;
 
@@ -5681,6 +5685,8 @@ static void iavf_remove(struct pci_dev *pdev)
                msleep(50);
        }
 
+       iavf_ptp_release(adapter);
+
        iavf_misc_irq_disable(adapter);
        /* Shut down all the garbage mashers on the detention level */
        cancel_work_sync(&adapter->reset_task);
diff --git a/drivers/net/ethernet/intel/iavf/iavf_ptp.c b/drivers/net/ethernet/intel/iavf/iavf_ptp.c
new file mode 100644 (file)
index 0000000..5a1b5f8
--- /dev/null
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2024 Intel Corporation. */
+
+#include "iavf.h"
+#include "iavf_ptp.h"
+
+/**
+ * iavf_ptp_cap_supported - Check if a PTP capability is supported
+ * @adapter: private adapter structure
+ * @cap: the capability bitmask to check
+ *
+ * Return: true if every capability set in cap is also set in the enabled
+ *         capabilities reported by the PF, false otherwise.
+ */
+bool iavf_ptp_cap_supported(const struct iavf_adapter *adapter, u32 cap)
+{
+       if (!IAVF_PTP_ALLOWED(adapter))
+               return false;
+
+       /* Only return true if every bit in cap is set in hw_caps.caps */
+       return (adapter->ptp.hw_caps.caps & cap) == cap;
+}
+
+/**
+ * iavf_ptp_register_clock - Register a new PTP for userspace
+ * @adapter: private adapter structure
+ *
+ * Allocate and register a new PTP clock device if necessary.
+ *
+ * Return: 0 if success, error otherwise.
+ */
+static int iavf_ptp_register_clock(struct iavf_adapter *adapter)
+{
+       struct ptp_clock_info *ptp_info = &adapter->ptp.info;
+       struct device *dev = &adapter->pdev->dev;
+       struct ptp_clock *clock;
+
+       snprintf(ptp_info->name, sizeof(ptp_info->name), "%s-%s-clk",
+                KBUILD_MODNAME, dev_name(dev));
+       ptp_info->owner = THIS_MODULE;
+
+       clock = ptp_clock_register(ptp_info, dev);
+       if (IS_ERR(clock))
+               return PTR_ERR(clock);
+
+       adapter->ptp.clock = clock;
+
+       dev_dbg(&adapter->pdev->dev, "PTP clock %s registered\n",
+               adapter->ptp.info.name);
+
+       return 0;
+}
+
+/**
+ * iavf_ptp_init - Initialize PTP support if capability was negotiated
+ * @adapter: private adapter structure
+ *
+ * Initialize PTP functionality, based on the capabilities that the PF has
+ * enabled for this VF.
+ */
+void iavf_ptp_init(struct iavf_adapter *adapter)
+{
+       int err;
+
+       if (!iavf_ptp_cap_supported(adapter, VIRTCHNL_1588_PTP_CAP_READ_PHC)) {
+               pci_notice(adapter->pdev,
+                          "Device does not have PTP clock support\n");
+               return;
+       }
+
+       err = iavf_ptp_register_clock(adapter);
+       if (err) {
+               pci_err(adapter->pdev,
+                       "Failed to register PTP clock device (%p)\n",
+                       ERR_PTR(err));
+               return;
+       }
+
+       for (int i = 0; i < adapter->num_active_queues; i++) {
+               struct iavf_ring *rx_ring = &adapter->rx_rings[i];
+
+               rx_ring->ptp = &adapter->ptp;
+       }
+}
+
+/**
+ * iavf_ptp_release - Disable PTP support
+ * @adapter: private adapter structure
+ *
+ * Release all PTP resources that were previously initialized.
+ */
+void iavf_ptp_release(struct iavf_adapter *adapter)
+{
+       if (!adapter->ptp.clock)
+               return;
+
+       pci_dbg(adapter->pdev, "removing PTP clock %s\n",
+               adapter->ptp.info.name);
+       ptp_clock_unregister(adapter->ptp.clock);
+       adapter->ptp.clock = NULL;
+}
+
+/**
+ * iavf_ptp_process_caps - Handle change in PTP capabilities
+ * @adapter: private adapter structure
+ *
+ * Handle any state changes necessary due to change in PTP capabilities, such
+ * as after a device reset or change in configuration from the PF.
+ */
+void iavf_ptp_process_caps(struct iavf_adapter *adapter)
+{
+       bool phc = iavf_ptp_cap_supported(adapter, VIRTCHNL_1588_PTP_CAP_READ_PHC);
+
+       /* Check if the device gained or lost necessary access to support the
+        * PTP hardware clock. If so, driver must respond appropriately by
+        * creating or destroying the PTP clock device.
+        */
+       if (adapter->ptp.clock && !phc)
+               iavf_ptp_release(adapter);
+       else if (!adapter->ptp.clock && phc)
+               iavf_ptp_init(adapter);
+}
index 65678e76c34f0a898b7ef880d9115725eff3d66a..b63aea323f86a10272af639b3021b47c74f7de90 100644 (file)
@@ -6,4 +6,18 @@
 
 #include "iavf_types.h"
 
+#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
+void iavf_ptp_init(struct iavf_adapter *adapter);
+void iavf_ptp_release(struct iavf_adapter *adapter);
+void iavf_ptp_process_caps(struct iavf_adapter *adapter);
+bool iavf_ptp_cap_supported(const struct iavf_adapter *adapter, u32 cap);
+#else /* IS_ENABLED(CONFIG_PTP_1588_CLOCK) */
+static inline void iavf_ptp_init(struct iavf_adapter *adapter) { }
+static inline void iavf_ptp_release(struct iavf_adapter *adapter) { }
+static inline void iavf_ptp_process_caps(struct iavf_adapter *adapter) { }
+static inline bool iavf_ptp_cap_supported(struct iavf_adapter *adapter, u32 cap)
+{
+       return false;
+}
+#endif /* IS_ENABLED(CONFIG_PTP_1588_CLOCK) */
 #endif /* _IAVF_PTP_H_ */
index 15a05e30434de30949984f7d16c47dfeaf62fd40..c38b4ec2eaea10239d0d88bbaaac2898894b36e1 100644 (file)
@@ -297,6 +297,8 @@ struct iavf_ring {
                                         * for this ring.
                                         */
 
+       struct iavf_ptp *ptp;
+
        u32 rx_buf_len;
        struct net_shaper q_shaper;
        bool q_shaper_update;
index 65b0028bb968bce086506d84d5127f0812411c26..d009171e5f8a30236704b20caf3d61b65456ce88 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/net/intel/libie/rx.h>
 
 #include "iavf.h"
+#include "iavf_ptp.h"
 #include "iavf_prototype.h"
 
 /**
@@ -359,6 +360,7 @@ void iavf_configure_queues(struct iavf_adapter *adapter)
        int pairs = adapter->num_active_queues;
        struct virtchnl_queue_pair_info *vqpi;
        u32 i, max_frame;
+       u8 rx_flags = 0;
        size_t len;
 
        max_frame = LIBIE_MAX_RX_FRM_LEN(adapter->rx_rings->pp->p.offset);
@@ -376,6 +378,9 @@ void iavf_configure_queues(struct iavf_adapter *adapter)
        if (!vqci)
                return;
 
+       if (iavf_ptp_cap_supported(adapter, VIRTCHNL_1588_PTP_CAP_RX_TSTAMP))
+               rx_flags |= VIRTCHNL_PTP_RX_TSTAMP;
+
        vqci->vsi_id = adapter->vsi_res->vsi_id;
        vqci->num_queue_pairs = pairs;
        vqpi = vqci->qpair;
@@ -398,6 +403,7 @@ void iavf_configure_queues(struct iavf_adapter *adapter)
                if (CRC_OFFLOAD_ALLOWED(adapter))
                        vqpi->rxq.crc_disable = !!(adapter->netdev->features &
                                                   NETIF_F_RXFCS);
+               vqpi->rxq.flags = rx_flags;
                vqpi++;
        }
 
@@ -2608,6 +2614,8 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
 
                adapter->ptp.hw_caps = *(struct virtchnl_ptp_caps *)msg;
 
+               /* process any state change needed due to new capabilities */
+               iavf_ptp_process_caps(adapter);
                break;
        case VIRTCHNL_OP_ENABLE_QUEUES:
                /* enable transmits */