Merge branch '1GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue

Tony Nguyen says:

====================
1GbE Intel Wired LAN Driver Updates 2022-07-28

Jacob Keller says:

Convert all of the Intel drivers with PTP support to the newer .adjfine
implementation which uses scaled parts per million.

This improves the precision of the frequency adjustments by taking advantage
of the full scaled parts per million input coming from user space.

In addition, all implementations are converted to using the
mul_u64_u64_div_u64 function which better handles the intermediate value.
This function supports architecture specific instructions where possible to
avoid loss of precision if the normal 64-bit multiplication would overflow.

Of note, the i40e implementation is now able to avoid loss of precision on
slower link speeds by taking advantage of this to multiply by the link speed
factor first. This results in a significantly more precise adjustment by
allowing the calculation to impact the lower bits.

This also gets us a step closer to being able to remove the .adjfreq
entirely by removing its use from many drivers.

I plan to follow this up with a series to update the drivers from other
vendors and drop the .adjfreq implementation entirely.

* '1GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue:
  igb: convert .adjfreq to .adjfine
  ixgbe: convert .adjfreq to .adjfine
  i40e: convert .adjfreq to .adjfine
  i40e: use mul_u64_u64_div_u64 for PTP frequency calculation
  e1000e: convert .adjfreq to .adjfine
  e1000e: remove unnecessary range check in e1000e_phc_adjfreq
  ice: implement adjfine with mul_u64_u64_div_u64
====================

Link: https://lore.kernel.org/r/20220728181836.3387862-1-anthony.l.nguyen@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2022-08-01 11:15:39 -07:00
commit 9936e07eaf
7 changed files with 75 additions and 88 deletions

View File

@ -329,7 +329,7 @@ struct e1000_adapter {
struct ptp_clock *ptp_clock;
struct ptp_clock_info ptp_clock_info;
struct pm_qos_request pm_qos_req;
s32 ptp_delta;
long ptp_delta;
u16 eee_advert;
};

View File

@ -3922,9 +3922,9 @@ static void e1000e_systim_reset(struct e1000_adapter *adapter)
if (!(adapter->flags & FLAG_HAS_HW_TIMESTAMP))
return;
if (info->adjfreq) {
if (info->adjfine) {
/* restore the previous ptp frequency delta */
ret_val = info->adjfreq(info, adapter->ptp_delta);
ret_val = info->adjfine(info, adapter->ptp_delta);
} else {
/* set the default base frequency if no adjustment possible */
ret_val = e1000e_get_base_timinca(adapter, &timinca);

View File

@ -15,14 +15,16 @@
#endif
/**
* e1000e_phc_adjfreq - adjust the frequency of the hardware clock
* e1000e_phc_adjfine - adjust the frequency of the hardware clock
* @ptp: ptp clock structure
* @delta: Desired frequency change in parts per billion
* @delta: Desired frequency chance in scaled parts per million
*
* Adjust the frequency of the PHC cycle counter by the indicated delta from
* the base frequency.
*
* Scaled parts per million is ppm but with a 16 bit binary fractional field.
**/
static int e1000e_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta)
static int e1000e_phc_adjfine(struct ptp_clock_info *ptp, long delta)
{
struct e1000_adapter *adapter = container_of(ptp, struct e1000_adapter,
ptp_clock_info);
@ -33,9 +35,6 @@ static int e1000e_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta)
u32 timinca, incvalue;
s32 ret_val;
if ((delta > ptp->max_adj) || (delta <= -1000000000))
return -EINVAL;
if (delta < 0) {
neg_adj = true;
delta = -delta;
@ -50,9 +49,8 @@ static int e1000e_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta)
incvalue = timinca & E1000_TIMINCA_INCVALUE_MASK;
adjustment = incvalue;
adjustment *= delta;
adjustment = div_u64(adjustment, 1000000000);
adjustment = mul_u64_u64_div_u64(incvalue, (u64)delta,
1000000ULL << 16);
incvalue = neg_adj ? (incvalue - adjustment) : (incvalue + adjustment);
@ -260,7 +258,7 @@ static const struct ptp_clock_info e1000e_ptp_clock_info = {
.n_per_out = 0,
.n_pins = 0,
.pps = 0,
.adjfreq = e1000e_phc_adjfreq,
.adjfine = e1000e_phc_adjfine,
.adjtime = e1000e_phc_adjtime,
.gettimex64 = e1000e_phc_gettimex,
.settime64 = e1000e_phc_settime,

View File

@ -334,44 +334,37 @@ 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) {
if (scaled_ppm < 0) {
neg_adj = 1;
ppb = -ppb;
scaled_ppm = -scaled_ppm;
}
freq = I40E_PTP_40GB_INCVAL;
freq *= ppb;
diff = div_u64(freq, 1000000000ULL);
smp_mb(); /* Force any pending update before accessing. */
freq = I40E_PTP_40GB_INCVAL * READ_ONCE(pf->ptp_adj_mult);
diff = mul_u64_u64_div_u64(freq, (u64)scaled_ppm,
1000000ULL << 16);
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);
wr32(hw, I40E_PRTTSYN_INC_L, adj & 0xFFFFFFFF);
wr32(hw, I40E_PRTTSYN_INC_H, adj >> 32);
@ -1401,7 +1394,7 @@ static long i40e_ptp_create_clock(struct i40e_pf *pf)
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;

View File

@ -1102,9 +1102,8 @@ static void ice_ptp_reset_phy_timestamping(struct ice_pf *pf)
static int ice_ptp_adjfine(struct ptp_clock_info *info, long scaled_ppm)
{
struct ice_pf *pf = ptp_info_to_pf(info);
u64 freq, divisor = 1000000ULL;
struct ice_hw *hw = &pf->hw;
s64 incval, diff;
u64 incval, diff;
int neg_adj = 0;
int err;
@ -1115,17 +1114,8 @@ static int ice_ptp_adjfine(struct ptp_clock_info *info, long scaled_ppm)
scaled_ppm = -scaled_ppm;
}
while ((u64)scaled_ppm > div64_u64(U64_MAX, incval)) {
/* handle overflow by scaling down the scaled_ppm and
* the divisor, losing some precision
*/
scaled_ppm >>= 2;
divisor >>= 2;
}
freq = (incval * (u64)scaled_ppm) >> 16;
diff = div_u64(freq, divisor);
diff = mul_u64_u64_div_u64(incval, (u64)scaled_ppm,
1000000ULL << 16);
if (neg_adj)
incval -= diff;
else

View File

@ -190,7 +190,7 @@ static void igb_ptp_systim_to_hwtstamp(struct igb_adapter *adapter,
}
/* PTP clock operations */
static int igb_ptp_adjfreq_82576(struct ptp_clock_info *ptp, s32 ppb)
static int igb_ptp_adjfine_82576(struct ptp_clock_info *ptp, long scaled_ppm)
{
struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
ptp_caps);
@ -199,15 +199,14 @@ static int igb_ptp_adjfreq_82576(struct ptp_clock_info *ptp, s32 ppb)
u64 rate;
u32 incvalue;
if (ppb < 0) {
if (scaled_ppm < 0) {
neg_adj = 1;
ppb = -ppb;
scaled_ppm = -scaled_ppm;
}
rate = ppb;
rate <<= 14;
rate = div_u64(rate, 1953125);
incvalue = 16 << IGB_82576_TSYNC_SHIFT;
incvalue = INCVALUE_82576;
rate = mul_u64_u64_div_u64(incvalue, (u64)scaled_ppm,
1000000ULL << 16);
if (neg_adj)
incvalue -= rate;
@ -1347,7 +1346,7 @@ void igb_ptp_init(struct igb_adapter *adapter)
adapter->ptp_caps.max_adj = 999999881;
adapter->ptp_caps.n_ext_ts = 0;
adapter->ptp_caps.pps = 0;
adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82576;
adapter->ptp_caps.adjfine = igb_ptp_adjfine_82576;
adapter->ptp_caps.adjtime = igb_ptp_adjtime_82576;
adapter->ptp_caps.gettimex64 = igb_ptp_gettimex_82576;
adapter->ptp_caps.settime64 = igb_ptp_settime_82576;

View File

@ -113,12 +113,16 @@
* the sign bit. This register enables software to calculate frequency
* adjustments and apply them directly to the clock rate.
*
* The math for converting ppb into TIMINCA values is fairly straightforward.
* TIMINCA value = ( Base_Frequency * ppb ) / 1000000000ULL
* The math for converting scaled_ppm into TIMINCA values is fairly
* straightforward.
*
* This assumes that ppb is never high enough to create a value bigger than
* TIMINCA's 31 bits can store. This is ensured by the stack. Calculating this
* value is also simple.
* TIMINCA value = ( Base_Frequency * scaled_ppm ) / 1000000ULL << 16
*
* To avoid overflow, we simply use mul_u64_u64_div_u64.
*
* This assumes that scaled_ppm is never high enough to create a value bigger
* than TIMINCA's 31 bits can store. This is ensured by the stack, and is
* measured in parts per billion. Calculating this value is also simple.
* Max ppb = ( Max Adjustment / Base Frequency ) / 1000000000ULL
*
* For the X550, the Max adjustment is +/- 0.5 ns, and the base frequency is
@ -433,45 +437,45 @@ static void ixgbe_ptp_convert_to_hwtstamp(struct ixgbe_adapter *adapter,
}
/**
* ixgbe_ptp_adjfreq_82599
* ixgbe_ptp_adjfine_82599
* @ptp: the ptp clock structure
* @ppb: parts per billion adjustment from base
* @scaled_ppm: scaled parts per million adjustment from base
*
* adjust the frequency of the ptp cycle counter by the
* indicated ppb from the base frequency.
* Adjust the frequency of the ptp cycle counter by the
* indicated scaled_ppm from the base frequency.
*
* Scaled parts per million is ppm with a 16-bit binary fractional field.
*/
static int ixgbe_ptp_adjfreq_82599(struct ptp_clock_info *ptp, s32 ppb)
static int ixgbe_ptp_adjfine_82599(struct ptp_clock_info *ptp, long scaled_ppm)
{
struct ixgbe_adapter *adapter =
container_of(ptp, struct ixgbe_adapter, ptp_caps);
struct ixgbe_hw *hw = &adapter->hw;
u64 freq, incval;
u32 diff;
u64 incval, diff;
int neg_adj = 0;
if (ppb < 0) {
if (scaled_ppm < 0) {
neg_adj = 1;
ppb = -ppb;
scaled_ppm = -scaled_ppm;
}
smp_mb();
incval = READ_ONCE(adapter->base_incval);
freq = incval;
freq *= ppb;
diff = div_u64(freq, 1000000000ULL);
diff = mul_u64_u64_div_u64(incval, scaled_ppm,
1000000ULL << 16);
incval = neg_adj ? (incval - diff) : (incval + diff);
switch (hw->mac.type) {
case ixgbe_mac_X540:
if (incval > 0xFFFFFFFFULL)
e_dev_warn("PTP ppb adjusted SYSTIME rate overflowed!\n");
e_dev_warn("PTP scaled_ppm adjusted SYSTIME rate overflowed!\n");
IXGBE_WRITE_REG(hw, IXGBE_TIMINCA, (u32)incval);
break;
case ixgbe_mac_82599EB:
if (incval > 0x00FFFFFFULL)
e_dev_warn("PTP ppb adjusted SYSTIME rate overflowed!\n");
e_dev_warn("PTP scaled_ppm adjusted SYSTIME rate overflowed!\n");
IXGBE_WRITE_REG(hw, IXGBE_TIMINCA,
BIT(IXGBE_INCPER_SHIFT_82599) |
((u32)incval & 0x00FFFFFFUL));
@ -484,32 +488,35 @@ static int ixgbe_ptp_adjfreq_82599(struct ptp_clock_info *ptp, s32 ppb)
}
/**
* ixgbe_ptp_adjfreq_X550
* ixgbe_ptp_adjfine_X550
* @ptp: the ptp clock structure
* @ppb: parts per billion adjustment from base
* @scaled_ppm: scaled parts per million adjustment from base
*
* adjust the frequency of the SYSTIME registers by the indicated ppb from base
* frequency
* Adjust the frequency of the SYSTIME registers by the indicated scaled_ppm
* from base frequency.
*
* Scaled parts per million is ppm with a 16-bit binary fractional field.
*/
static int ixgbe_ptp_adjfreq_X550(struct ptp_clock_info *ptp, s32 ppb)
static int ixgbe_ptp_adjfine_X550(struct ptp_clock_info *ptp, long scaled_ppm)
{
struct ixgbe_adapter *adapter =
container_of(ptp, struct ixgbe_adapter, ptp_caps);
struct ixgbe_hw *hw = &adapter->hw;
int neg_adj = 0;
u64 rate = IXGBE_X550_BASE_PERIOD;
u64 rate;
u32 inca;
if (ppb < 0) {
if (scaled_ppm < 0) {
neg_adj = 1;
ppb = -ppb;
scaled_ppm = -scaled_ppm;
}
rate *= ppb;
rate = div_u64(rate, 1000000000ULL);
rate = mul_u64_u64_div_u64(IXGBE_X550_BASE_PERIOD, scaled_ppm,
1000000ULL << 16);
/* warn if rate is too large */
if (rate >= INCVALUE_MASK)
e_dev_warn("PTP ppb adjusted SYSTIME rate overflowed!\n");
e_dev_warn("PTP scaled_ppm adjusted SYSTIME rate overflowed!\n");
inca = rate & INCVALUE_MASK;
if (neg_adj)
@ -1355,7 +1362,7 @@ static long ixgbe_ptp_create_clock(struct ixgbe_adapter *adapter)
adapter->ptp_caps.n_ext_ts = 0;
adapter->ptp_caps.n_per_out = 0;
adapter->ptp_caps.pps = 1;
adapter->ptp_caps.adjfreq = ixgbe_ptp_adjfreq_82599;
adapter->ptp_caps.adjfine = ixgbe_ptp_adjfine_82599;
adapter->ptp_caps.adjtime = ixgbe_ptp_adjtime;
adapter->ptp_caps.gettimex64 = ixgbe_ptp_gettimex;
adapter->ptp_caps.settime64 = ixgbe_ptp_settime;
@ -1372,7 +1379,7 @@ static long ixgbe_ptp_create_clock(struct ixgbe_adapter *adapter)
adapter->ptp_caps.n_ext_ts = 0;
adapter->ptp_caps.n_per_out = 0;
adapter->ptp_caps.pps = 0;
adapter->ptp_caps.adjfreq = ixgbe_ptp_adjfreq_82599;
adapter->ptp_caps.adjfine = ixgbe_ptp_adjfine_82599;
adapter->ptp_caps.adjtime = ixgbe_ptp_adjtime;
adapter->ptp_caps.gettimex64 = ixgbe_ptp_gettimex;
adapter->ptp_caps.settime64 = ixgbe_ptp_settime;
@ -1388,7 +1395,7 @@ static long ixgbe_ptp_create_clock(struct ixgbe_adapter *adapter)
adapter->ptp_caps.n_ext_ts = 0;
adapter->ptp_caps.n_per_out = 0;
adapter->ptp_caps.pps = 1;
adapter->ptp_caps.adjfreq = ixgbe_ptp_adjfreq_X550;
adapter->ptp_caps.adjfine = ixgbe_ptp_adjfine_X550;
adapter->ptp_caps.adjtime = ixgbe_ptp_adjtime;
adapter->ptp_caps.gettimex64 = ixgbe_ptp_gettimex;
adapter->ptp_caps.settime64 = ixgbe_ptp_settime;