Message ID | 20240730091509.18846-14-mateusz.polchlopek@intel.com (mailing list archive) |
---|---|
State | Awaiting Upstream |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | Add support for Rx timestamping for both ice and iavf drivers. | expand |
Context | Check | Description |
---|---|---|
netdev/tree_selection | success | Guessing tree name failed - patch did not apply |
From: Mateusz Polchlopek <mateusz.polchlopek@intel.com> Date: Tue, 30 Jul 2024 05:15:08 -0400 > From: Jacob Keller <jacob.e.keller@intel.com> > > Add handlers for the .ndo_hwtstamp_get and .ndo_hwtstamp_set ops which allow > userspace to request timestamp enablement for the device. This support allows > standard Linux applications to request the timestamping desired. [...] > diff --git a/drivers/net/ethernet/intel/iavf/iavf_ptp.c b/drivers/net/ethernet/intel/iavf/iavf_ptp.c > index 9eb3161575d5..7754f4f24052 100644 > --- a/drivers/net/ethernet/intel/iavf/iavf_ptp.c > +++ b/drivers/net/ethernet/intel/iavf/iavf_ptp.c > @@ -3,6 +3,136 @@ > > #include "iavf.h" > > +/** > + * iavf_ptp_disable_rx_tstamp - Disable timestamping in Rx rings > + * @adapter: private adapter structure > + * > + * Disable timestamp reporting for all Rx rings. > + */ > +static void iavf_ptp_disable_rx_tstamp(struct iavf_adapter *adapter) > +{ > + unsigned int i; > + > + for (i = 0; i < adapter->num_active_queues; i++) for (u32 i = 0; ...) > + adapter->rx_rings[i].flags &= ~IAVF_TXRX_FLAGS_HW_TSTAMP; > +} > + > +/** > + * iavf_ptp_enable_rx_tstamp - Enable timestamping in Rx rings > + * @adapter: private adapter structure > + * > + * Enable timestamp reporting for all Rx rings. > + */ > +static void iavf_ptp_enable_rx_tstamp(struct iavf_adapter *adapter) > +{ > + unsigned int i; > + > + for (i = 0; i < adapter->num_active_queues; i++) (same) > + adapter->rx_rings[i].flags |= IAVF_TXRX_FLAGS_HW_TSTAMP; > +} > + > +/** > + * iavf_ptp_set_timestamp_mode - Set device timestamping mode > + * @adapter: private adapter structure > + * @config: pointer to kernel_hwtstamp_config > + * > + * Set the timestamping mode requested from the userspace. > + * > + * Note: this function always translates Rx timestamp requests for any packet > + * category into HWTSTAMP_FILTER_ALL. > + * > + * Return: zero. > + */ > +static int iavf_ptp_set_timestamp_mode(struct iavf_adapter *adapter, > + struct kernel_hwtstamp_config *config) > +{ > + /* Reserved for future extensions. */ > + if (config->flags) > + return -EINVAL; > + > + switch (config->tx_type) { > + case HWTSTAMP_TX_OFF: > + break; > + case HWTSTAMP_TX_ON: > + return -EOPNOTSUPP; > + default: > + return -ERANGE; > + } > + > + switch (config->rx_filter) { > + case HWTSTAMP_FILTER_NONE: > + iavf_ptp_disable_rx_tstamp(adapter); > + break; > + case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: > + case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: > + case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: > + case HWTSTAMP_FILTER_PTP_V2_EVENT: > + case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: > + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: > + case HWTSTAMP_FILTER_PTP_V2_SYNC: > + case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: > + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: > + case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: > + case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: > + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: > + case HWTSTAMP_FILTER_NTP_ALL: > + case HWTSTAMP_FILTER_ALL: Since these definitions are uAPI, their values can't change, only new ones can be added. So, you can use case range: case FILTER_ALL: case V1_L4_EVENT ... NTP_ALL: > + if (!(iavf_ptp_cap_supported(adapter, > + VIRTCHNL_1588_PTP_CAP_RX_TSTAMP))) > + return -EOPNOTSUPP; > + config->rx_filter = HWTSTAMP_FILTER_ALL; > + iavf_ptp_enable_rx_tstamp(adapter); > + break; > + default: > + return -ERANGE; > + } or even simpler: if (rx_filter == NONE) // disable return; if (rx_filter == FILTER_SOME || rx_filter > NTP_ALL) return -ERANGE; // here you will have your 14 supported cases from above, // proceed with configuration > + > + return 0; > +} > + > +/** > + * iavf_ptp_get_ts_config - Get timestamping configuration > + * @adapter: private adapter structure > + * @config: pointer to kernel_hwtstamp_config > + * > + * Return the current hardware timestamping configuration back to userspace. > + * > + * Return: zero. > + */ > +int iavf_ptp_get_ts_config(struct iavf_adapter *adapter, > + struct kernel_hwtstamp_config *config) > +{ > + *config = adapter->ptp.hwtstamp_config; > + > + return 0; If it always returns 0, void then? > +} > + > +/** > + * iavf_ptp_set_ts_config - Set timestamping configuration > + * @adapter: private adapter structure > + * @config: pointer to kernel_hwtstamp_config structure > + * @extack: pointer to netlink_ext_ack structure > + * > + * Program the requested timestamping configuration to the device. > + * > + * Return: zero. But it can also return @err... > + */ > +int iavf_ptp_set_ts_config(struct iavf_adapter *adapter, > + struct kernel_hwtstamp_config *config, > + struct netlink_ext_ack *extack) > +{ > + int err; > + > + err = iavf_ptp_set_timestamp_mode(adapter, config); > + if (err) > + return err; > + > + /* Save successful settings for future reference */ > + adapter->ptp.hwtstamp_config = *config; > + > + return 0; > +} [...] Thanks, Olek
diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index dc1908690e2d..61720b27c8f1 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -5067,6 +5067,23 @@ static netdev_features_t iavf_fix_features(struct net_device *netdev, return iavf_fix_strip_features(adapter, features); } +static int iavf_hwstamp_get(struct net_device *netdev, + struct kernel_hwtstamp_config *config) +{ + struct iavf_adapter *adapter = netdev_priv(netdev); + + return iavf_ptp_get_ts_config(adapter, config); +} + +static int iavf_hwstamp_set(struct net_device *netdev, + struct kernel_hwtstamp_config *config, + struct netlink_ext_ack *extack) +{ + struct iavf_adapter *adapter = netdev_priv(netdev); + + return iavf_ptp_set_ts_config(adapter, config, extack); +} + static const struct net_device_ops iavf_netdev_ops = { .ndo_open = iavf_open, .ndo_stop = iavf_close, @@ -5082,6 +5099,8 @@ static const struct net_device_ops iavf_netdev_ops = { .ndo_fix_features = iavf_fix_features, .ndo_set_features = iavf_set_features, .ndo_setup_tc = iavf_setup_tc, + .ndo_hwtstamp_get = iavf_hwstamp_get, + .ndo_hwtstamp_set = iavf_hwstamp_set, }; /** diff --git a/drivers/net/ethernet/intel/iavf/iavf_ptp.c b/drivers/net/ethernet/intel/iavf/iavf_ptp.c index 9eb3161575d5..7754f4f24052 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_ptp.c +++ b/drivers/net/ethernet/intel/iavf/iavf_ptp.c @@ -3,6 +3,136 @@ #include "iavf.h" +/** + * iavf_ptp_disable_rx_tstamp - Disable timestamping in Rx rings + * @adapter: private adapter structure + * + * Disable timestamp reporting for all Rx rings. + */ +static void iavf_ptp_disable_rx_tstamp(struct iavf_adapter *adapter) +{ + unsigned int i; + + for (i = 0; i < adapter->num_active_queues; i++) + adapter->rx_rings[i].flags &= ~IAVF_TXRX_FLAGS_HW_TSTAMP; +} + +/** + * iavf_ptp_enable_rx_tstamp - Enable timestamping in Rx rings + * @adapter: private adapter structure + * + * Enable timestamp reporting for all Rx rings. + */ +static void iavf_ptp_enable_rx_tstamp(struct iavf_adapter *adapter) +{ + unsigned int i; + + for (i = 0; i < adapter->num_active_queues; i++) + adapter->rx_rings[i].flags |= IAVF_TXRX_FLAGS_HW_TSTAMP; +} + +/** + * iavf_ptp_set_timestamp_mode - Set device timestamping mode + * @adapter: private adapter structure + * @config: pointer to kernel_hwtstamp_config + * + * Set the timestamping mode requested from the userspace. + * + * Note: this function always translates Rx timestamp requests for any packet + * category into HWTSTAMP_FILTER_ALL. + * + * Return: zero. + */ +static int iavf_ptp_set_timestamp_mode(struct iavf_adapter *adapter, + struct kernel_hwtstamp_config *config) +{ + /* Reserved for future extensions. */ + if (config->flags) + return -EINVAL; + + switch (config->tx_type) { + case HWTSTAMP_TX_OFF: + break; + case HWTSTAMP_TX_ON: + return -EOPNOTSUPP; + default: + return -ERANGE; + } + + switch (config->rx_filter) { + case HWTSTAMP_FILTER_NONE: + iavf_ptp_disable_rx_tstamp(adapter); + break; + case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: + case HWTSTAMP_FILTER_NTP_ALL: + case HWTSTAMP_FILTER_ALL: + if (!(iavf_ptp_cap_supported(adapter, + VIRTCHNL_1588_PTP_CAP_RX_TSTAMP))) + return -EOPNOTSUPP; + config->rx_filter = HWTSTAMP_FILTER_ALL; + iavf_ptp_enable_rx_tstamp(adapter); + break; + default: + return -ERANGE; + } + + return 0; +} + +/** + * iavf_ptp_get_ts_config - Get timestamping configuration + * @adapter: private adapter structure + * @config: pointer to kernel_hwtstamp_config + * + * Return the current hardware timestamping configuration back to userspace. + * + * Return: zero. + */ +int iavf_ptp_get_ts_config(struct iavf_adapter *adapter, + struct kernel_hwtstamp_config *config) +{ + *config = adapter->ptp.hwtstamp_config; + + return 0; +} + +/** + * iavf_ptp_set_ts_config - Set timestamping configuration + * @adapter: private adapter structure + * @config: pointer to kernel_hwtstamp_config structure + * @extack: pointer to netlink_ext_ack structure + * + * Program the requested timestamping configuration to the device. + * + * Return: zero. + */ +int iavf_ptp_set_ts_config(struct iavf_adapter *adapter, + struct kernel_hwtstamp_config *config, + struct netlink_ext_ack *extack) +{ + int err; + + err = iavf_ptp_set_timestamp_mode(adapter, config); + if (err) + return err; + + /* Save successful settings for future reference */ + adapter->ptp.hwtstamp_config = *config; + + return 0; +} + /** * clock_to_adapter - Convert clock info pointer to adapter pointer * @ptp_info: PTP info structure @@ -336,4 +466,10 @@ void iavf_ptp_process_caps(struct iavf_adapter *adapter) iavf_ptp_cap_supported(adapter, VIRTCHNL_1588_PTP_CAP_READ_PHC)) iavf_ptp_init(adapter); + + /* Check if the device lost access to Rx timestamp incoming packets */ + if (!iavf_ptp_cap_supported(adapter, VIRTCHNL_1588_PTP_CAP_RX_TSTAMP)) { + adapter->ptp.hwtstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; + iavf_ptp_disable_rx_tstamp(adapter); + } } diff --git a/drivers/net/ethernet/intel/iavf/iavf_ptp.h b/drivers/net/ethernet/intel/iavf/iavf_ptp.h index 5f0efc5fbad1..656d360d2bb4 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_ptp.h +++ b/drivers/net/ethernet/intel/iavf/iavf_ptp.h @@ -21,6 +21,7 @@ struct iavf_ptp { struct list_head aq_cmds; /* Lock protecting access to the AQ command list */ struct mutex aq_cmd_lock; + struct kernel_hwtstamp_config hwtstamp_config; u64 cached_phc_time; unsigned long cached_phc_updated; bool initialized; @@ -35,5 +36,10 @@ void iavf_ptp_process_caps(struct iavf_adapter *adapter); bool iavf_ptp_cap_supported(struct iavf_adapter *adapter, u32 cap); void iavf_virtchnl_send_ptp_cmd(struct iavf_adapter *adapter); long iavf_ptp_do_aux_work(struct ptp_clock_info *ptp); +int iavf_ptp_get_ts_config(struct iavf_adapter *adapter, + struct kernel_hwtstamp_config *config); +int iavf_ptp_set_ts_config(struct iavf_adapter *adapter, + struct kernel_hwtstamp_config *config, + struct netlink_ext_ack *extack); #endif /* _IAVF_PTP_H_ */ diff --git a/drivers/net/ethernet/intel/iavf/iavf_txrx.h b/drivers/net/ethernet/intel/iavf/iavf_txrx.h index 94023873cb36..fd3444241a45 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_txrx.h +++ b/drivers/net/ethernet/intel/iavf/iavf_txrx.h @@ -252,6 +252,7 @@ struct iavf_ring { #define IAVF_TXRX_FLAGS_VLAN_TAG_LOC_L2TAG1 BIT(3) #define IAVF_TXR_FLAGS_VLAN_TAG_LOC_L2TAG2 BIT(4) #define IAVF_RXR_FLAGS_VLAN_TAG_LOC_L2TAG2_2 BIT(5) +#define IAVF_TXRX_FLAGS_HW_TSTAMP BIT(6) /* stats structs */ struct iavf_queue_stats stats;