diff options
Diffstat (limited to 'drivers/net/ethernet/intel/i40e/i40e_ptp.c')
| -rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_ptp.c | 137 |
1 files changed, 62 insertions, 75 deletions
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index 61e5789d78db..33535418178b 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -1,9 +1,10 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright(c) 2013 - 2018 Intel Corporation. */ -#include "i40e.h" #include <linux/ptp_classify.h> #include <linux/posix-clock.h> +#include "i40e.h" +#include "i40e_devids.h" /* The XL710 timesync is very much like Intel's 82599 design when it comes to * the fundamental clock design. However, the clock operations are much simpler @@ -27,7 +28,6 @@ #define I40E_PRTTSYN_CTL1_TSYNTYPE_V2 (2 << \ I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT) #define I40E_SUBDEV_ID_25G_PTP_PIN 0xB -#define to_dev(obj) container_of(obj, struct device, kobj) enum i40e_ptp_pin { SDP3_2 = 0, @@ -35,7 +35,7 @@ enum i40e_ptp_pin { GPIO_4 }; -enum i40e_can_set_pins_t { +enum i40e_can_set_pins { CANT_DO_PINS = -1, CAN_SET_PINS, CAN_DO_PINS @@ -193,7 +193,7 @@ static bool i40e_is_ptp_pin_dev(struct i40e_hw *hw) * return CAN_DO_PINS if pins can be manipulated within a NIC or * return CANT_DO_PINS otherwise. **/ -static enum i40e_can_set_pins_t i40e_can_set_pins(struct i40e_pf *pf) +static enum i40e_can_set_pins i40e_can_set_pins(struct i40e_pf *pf) { if (!i40e_is_ptp_pin_dev(&pf->hw)) { dev_warn(&pf->pdev->dev, @@ -335,43 +335,25 @@ static void i40e_ptp_convert_to_hwtstamp(struct skb_shared_hwtstamps *hwtstamps, } /** - * i40e_ptp_adjfreq - Adjust the PHC frequency + * i40e_ptp_adjfine - Adjust the PHC frequency * @ptp: The PTP clock structure - * @ppb: Parts per billion adjustment from the base + * @scaled_ppm: Scaled parts per million adjustment from base * - * Adjust the frequency of the PHC by the indicated parts per billion from the - * base frequency. + * Adjust the frequency of the PHC by the indicated delta from the base + * frequency. + * + * Scaled parts per million is ppm with a 16 bit binary fractional field. **/ -static int i40e_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb) +static int i40e_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) { struct i40e_pf *pf = container_of(ptp, struct i40e_pf, ptp_caps); struct i40e_hw *hw = &pf->hw; - u64 adj, freq, diff; - int neg_adj = 0; - - if (ppb < 0) { - neg_adj = 1; - ppb = -ppb; - } - - freq = I40E_PTP_40GB_INCVAL; - freq *= ppb; - diff = div_u64(freq, 1000000000ULL); + u64 adj, base_adj; - if (neg_adj) - adj = I40E_PTP_40GB_INCVAL - diff; - else - adj = I40E_PTP_40GB_INCVAL + diff; - - /* At some link speeds, the base incval is so large that directly - * multiplying by ppb would result in arithmetic overflow even when - * using a u64. Avoid this by instead calculating the new incval - * always in terms of the 40GbE clock rate and then multiplying by the - * link speed factor afterwards. This does result in slightly lower - * precision at lower link speeds, but it is fairly minor. - */ smp_mb(); /* Force any pending update before accessing. */ - adj *= READ_ONCE(pf->ptp_adj_mult); + base_adj = I40E_PTP_40GB_INCVAL * READ_ONCE(pf->ptp_adj_mult); + + adj = adjust_by_scaled_ppm(base_adj, scaled_ppm); wr32(hw, I40E_PRTTSYN_INC_L, adj & 0xFFFFFFFF); wr32(hw, I40E_PRTTSYN_INC_H, adj >> 32); @@ -568,7 +550,7 @@ static int i40e_ptp_enable_pin(struct i40e_pf *pf, unsigned int chan, pins.gpio_4 = pf->ptp_pins->gpio_4; /* To turn on the pin - find the corresponding one based on - * the given index. To to turn the function off - find + * the given index. To turn the function off - find * which pin had it assigned. Don't use ptp_find_pin here * because it tries to lock the pincfg_mux which is locked by * ptp_pin_store() that calls here. @@ -698,7 +680,7 @@ void i40e_ptp_rx_hang(struct i40e_pf *pf) * configured. We don't want to spuriously warn about Rx timestamp * hangs if we don't care about the timestamps. */ - if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_rx) + if (!test_bit(I40E_FLAG_PTP_ENA, pf->flags) || !pf->ptp_rx) return; spin_lock_bh(&pf->ptp_rx_lock); @@ -751,7 +733,7 @@ void i40e_ptp_tx_hang(struct i40e_pf *pf) { struct sk_buff *skb; - if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_tx) + if (!test_bit(I40E_FLAG_PTP_ENA, pf->flags) || !pf->ptp_tx) return; /* Nothing to do if we're not already waiting for a timestamp */ @@ -789,7 +771,7 @@ void i40e_ptp_tx_hwtstamp(struct i40e_pf *pf) u32 hi, lo; u64 ns; - if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_tx) + if (!test_bit(I40E_FLAG_PTP_ENA, pf->flags) || !pf->ptp_tx) return; /* don't attempt to timestamp if we don't have an skb */ @@ -836,7 +818,7 @@ void i40e_ptp_rx_hwtstamp(struct i40e_pf *pf, struct sk_buff *skb, u8 index) /* Since we cannot turn off the Rx timestamp logic if the device is * doing Tx timestamping, check if Rx timestamping is configured. */ - if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_rx) + if (!test_bit(I40E_FLAG_PTP_ENA, pf->flags) || !pf->ptp_rx) return; hw = &pf->hw; @@ -930,23 +912,26 @@ void i40e_ptp_set_increment(struct i40e_pf *pf) } /** - * i40e_ptp_get_ts_config - ioctl interface to read the HW timestamping - * @pf: Board private structure - * @ifr: ioctl data + * i40e_ptp_hwtstamp_get - interface to read the HW timestamping + * @netdev: Network device structure + * @config: Timestamping configuration structure * * Obtain the current hardware timestamping settigs as requested. To do this, * keep a shadow copy of the timestamp settings rather than attempting to * deconstruct it from the registers. **/ -int i40e_ptp_get_ts_config(struct i40e_pf *pf, struct ifreq *ifr) +int i40e_ptp_hwtstamp_get(struct net_device *netdev, + struct kernel_hwtstamp_config *config) { - struct hwtstamp_config *config = &pf->tstamp_config; + struct i40e_netdev_priv *np = netdev_priv(netdev); + struct i40e_pf *pf = np->vsi->back; - if (!(pf->flags & I40E_FLAG_PTP)) + if (!test_bit(I40E_FLAG_PTP_ENA, pf->flags)) return -EOPNOTSUPP; - return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ? - -EFAULT : 0; + *config = pf->tstamp_config; + + return 0; } /** @@ -1089,7 +1074,7 @@ static void i40e_ptp_set_pins_hw(struct i40e_pf *pf) static int i40e_ptp_set_pins(struct i40e_pf *pf, struct i40e_ptp_pins_settings *pins) { - enum i40e_can_set_pins_t pin_caps = i40e_can_set_pins(pf); + enum i40e_can_set_pins pin_caps = i40e_can_set_pins(pf); int i = 0; if (pin_caps == CANT_DO_PINS) @@ -1151,7 +1136,7 @@ int i40e_ptp_alloc_pins(struct i40e_pf *pf) if (!pf->ptp_pins) { dev_warn(&pf->pdev->dev, "Cannot allocate memory for PTP pins structure.\n"); - return -I40E_ERR_NO_MEMORY; + return -ENOMEM; } pf->ptp_pins->sdp3_2 = off; @@ -1185,7 +1170,7 @@ int i40e_ptp_alloc_pins(struct i40e_pf *pf) * more broad if the specific filter is not directly supported. **/ static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf, - struct hwtstamp_config *config) + struct kernel_hwtstamp_config *config) { struct i40e_hw *hw = &pf->hw; u32 tsyntype, regval; @@ -1229,7 +1214,7 @@ static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf, case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: - if (!(pf->hw_features & I40E_HW_PTP_L4_CAPABLE)) + if (!test_bit(I40E_HW_CAP_PTP_L4, pf->hw.caps)) return -ERANGE; pf->ptp_rx = true; tsyntype = I40E_PRTTSYN_CTL1_V1MESSTYPE0_MASK | @@ -1243,7 +1228,7 @@ static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf, case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: - if (!(pf->hw_features & I40E_HW_PTP_L4_CAPABLE)) + if (!test_bit(I40E_HW_CAP_PTP_L4, pf->hw.caps)) return -ERANGE; fallthrough; case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: @@ -1252,7 +1237,7 @@ static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf, pf->ptp_rx = true; tsyntype = I40E_PRTTSYN_CTL1_V2MESSTYPE0_MASK | I40E_PRTTSYN_CTL1_TSYNTYPE_V2; - if (pf->hw_features & I40E_HW_PTP_L4_CAPABLE) { + if (test_bit(I40E_HW_CAP_PTP_L4, pf->hw.caps)) { tsyntype |= I40E_PRTTSYN_CTL1_UDP_ENA_MASK; config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; } else { @@ -1308,9 +1293,10 @@ static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf, } /** - * i40e_ptp_set_ts_config - ioctl interface to control the HW timestamping - * @pf: Board private structure - * @ifr: ioctl data + * i40e_ptp_hwtstamp_set - interface to control the HW timestamping + * @netdev: Network device structure + * @config: Timestamping configuration structure + * @extack: Netlink extended ack structure for error reporting * * Respond to the user filter requests and make the appropriate hardware * changes here. The XL710 cannot support splitting of the Tx/Rx timestamping @@ -1321,26 +1307,25 @@ static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf, * as the user receives the timestamps they care about and the user is notified * the filter has been broadened. **/ -int i40e_ptp_set_ts_config(struct i40e_pf *pf, struct ifreq *ifr) +int i40e_ptp_hwtstamp_set(struct net_device *netdev, + struct kernel_hwtstamp_config *config, + struct netlink_ext_ack *extack) { - struct hwtstamp_config config; + struct i40e_netdev_priv *np = netdev_priv(netdev); + struct i40e_pf *pf = np->vsi->back; int err; - if (!(pf->flags & I40E_FLAG_PTP)) + if (!test_bit(I40E_FLAG_PTP_ENA, pf->flags)) return -EOPNOTSUPP; - if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) - return -EFAULT; - - err = i40e_ptp_set_timestamp_mode(pf, &config); + err = i40e_ptp_set_timestamp_mode(pf, config); if (err) return err; /* save these settings for future reference */ - pf->tstamp_config = config; + pf->tstamp_config = *config; - return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? - -EFAULT : 0; + return 0; } /** @@ -1398,11 +1383,11 @@ static long i40e_ptp_create_clock(struct i40e_pf *pf) if (!IS_ERR_OR_NULL(pf->ptp_clock)) return 0; - strlcpy(pf->ptp_caps.name, i40e_driver_name, + strscpy(pf->ptp_caps.name, i40e_driver_name, sizeof(pf->ptp_caps.name) - 1); pf->ptp_caps.owner = THIS_MODULE; pf->ptp_caps.max_adj = 999999999; - pf->ptp_caps.adjfreq = i40e_ptp_adjfreq; + pf->ptp_caps.adjfine = i40e_ptp_adjfine; pf->ptp_caps.adjtime = i40e_ptp_adjtime; pf->ptp_caps.gettimex64 = i40e_ptp_gettimex; pf->ptp_caps.settime64 = i40e_ptp_settime; @@ -1444,7 +1429,7 @@ static long i40e_ptp_create_clock(struct i40e_pf *pf) void i40e_ptp_save_hw_time(struct i40e_pf *pf) { /* don't try to access the PTP clock if it's not enabled */ - if (!(pf->flags & I40E_FLAG_PTP)) + if (!test_bit(I40E_FLAG_PTP_ENA, pf->flags)) return; i40e_ptp_gettimex(&pf->ptp_caps, &pf->ptp_prev_hw_time, NULL); @@ -1490,7 +1475,8 @@ void i40e_ptp_restore_hw_time(struct i40e_pf *pf) **/ void i40e_ptp_init(struct i40e_pf *pf) { - struct net_device *netdev = pf->vsi[pf->lan_vsi]->netdev; + struct i40e_vsi *vsi = i40e_pf_get_main_vsi(pf); + struct net_device *netdev = vsi->netdev; struct i40e_hw *hw = &pf->hw; u32 pf_id; long err; @@ -1498,10 +1484,10 @@ void i40e_ptp_init(struct i40e_pf *pf) /* Only one PF is assigned to control 1588 logic per port. Do not * enable any support for PFs not assigned via PRTTSYN_CTL0.PF_ID */ - pf_id = (rd32(hw, I40E_PRTTSYN_CTL0) & I40E_PRTTSYN_CTL0_PF_ID_MASK) >> - I40E_PRTTSYN_CTL0_PF_ID_SHIFT; + pf_id = FIELD_GET(I40E_PRTTSYN_CTL0_PF_ID_MASK, + rd32(hw, I40E_PRTTSYN_CTL0)); if (hw->pf_id != pf_id) { - pf->flags &= ~I40E_FLAG_PTP; + clear_bit(I40E_FLAG_PTP_ENA, pf->flags); dev_info(&pf->pdev->dev, "%s: PTP not supported on %s\n", __func__, netdev->name); @@ -1522,7 +1508,7 @@ void i40e_ptp_init(struct i40e_pf *pf) if (pf->hw.debug_mask & I40E_DEBUG_LAN) dev_info(&pf->pdev->dev, "PHC enabled\n"); - pf->flags |= I40E_FLAG_PTP; + set_bit(I40E_FLAG_PTP_ENA, pf->flags); /* Ensure the clocks are running. */ regval = rd32(hw, I40E_PRTTSYN_CTL0); @@ -1554,10 +1540,11 @@ void i40e_ptp_init(struct i40e_pf *pf) **/ void i40e_ptp_stop(struct i40e_pf *pf) { + struct i40e_vsi *main_vsi = i40e_pf_get_main_vsi(pf); struct i40e_hw *hw = &pf->hw; u32 regval; - pf->flags &= ~I40E_FLAG_PTP; + clear_bit(I40E_FLAG_PTP_ENA, pf->flags); pf->ptp_tx = false; pf->ptp_rx = false; @@ -1573,7 +1560,7 @@ void i40e_ptp_stop(struct i40e_pf *pf) ptp_clock_unregister(pf->ptp_clock); pf->ptp_clock = NULL; dev_info(&pf->pdev->dev, "%s: removed PHC on %s\n", __func__, - pf->vsi[pf->lan_vsi]->netdev->name); + main_vsi->netdev->name); } if (i40e_is_ptp_pin_dev(&pf->hw)) { |
