Commit 5565dbd0 authored by David S. Miller's avatar David S. Miller

Merge branch 'ptp-adjfine'

Jacob Keller says:

====================
ptp: convert drivers to .adjfine

Many drivers implementing PTP have not yet migrated to the new .adjfine
frequency adjustment implementation.

A handful of these drivers use hardware with a simple increment value which
is adjusted by multiplying by the adjustment factor and then dividing by
1 billion. This calculation is very easy to convert to .adjfine, by simply
updating the divisor.

Introduce new helper functions, diff_by_scaled_ppm and adjust_by_scaled_ppm
which perform the most common calculations used by drivers for this purpose.

The adjust_by_scaled_ppm takes the base increment and scaled PPM value, and
calculates the new increment to use.

A few drivers need the difference and direction rather than a raw increment
value. The diff_by_scaled_ppm calculates the difference and returns true if
it should be a subtraction, false otherwise. This most closely aligns with
existing driver implementations.

I previously submitted v1 of this series at [1], and got some feedback only
on a handful of drivers. In the interest of merging the changes which have
received feedback, I've dropped the following drivers out of this send:

 * ptp_phc
 * ptp_ipx46x
 * tg3
 * hclge
 * stmac
 * cpts

I plan to submit those drivers changes again at a later date. As before,
there are some drivers which are not trivial to convert to the new helper
functions. While they may be able to work, their implementation is different
and I lack the hardware or datasheets to determine what the correct
implementation would be.

* drivers/net/ethernet/broadcom/bnx2x
* drivers/net/ethernet/broadcom/bnxt
* drivers/net/ethernet/cavium/liquidio
* drivers/net/ethernet/chelsio/cxgb4
* drivers/net/ethernet/freescale
* drivers/net/ethernet/qlogic/qed
* drivers/net/ethernet/qlogic/qede
* drivers/net/ethernet/sfc
* drivers/net/ethernet/sfc/siena
* drivers/net/ethernet/ti/am65-cpts.c
* drivers/ptp/ptp_dte.c

My end goal is to drop the .adjfreq implementation entirely, and to that end
I plan on modifying these drivers in the future to directly use
scaled_ppm_to_ppb as the simplest method to convert them.

Changes since v2:
* Rebased to allow landing in 6.2
* Added Richard's Acked-by

Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Haiyang Zhang <haiyangz@microsoft.com>
Cc: Stephen Hemminger <sthemmin@microsoft.com>
Cc: Wei Liu <wei.liu@kernel.org>
Cc: Dexuan Cui <decui@microsoft.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Jakub Kicinski <kuba@kernel.org>
Cc: Paolo Abeni <pabeni@redhat.com>
Cc: Siva Reddy Kallam <siva.kallam@broadcom.com>
Cc: Prashant Sreedharan <prashant@broadcom.com>
Cc: Michael Chan <mchan@broadcom.com>
Cc: Yisen Zhuang <yisen.zhuang@huawei.com>
Cc: Salil Mehta <salil.mehta@huawei.com>
Cc: Jesse Brandeburg <jesse.brandeburg@intel.com>
Cc: Tony Nguyen <anthony.l.nguyen@intel.com>
Cc: Tariq Toukan <tariqt@nvidia.com>
Cc: Saeed Mahameed <saeedm@nvidia.com>
Cc: Leon Romanovsky <leon@kernel.org>
Cc: Bryan Whitehead <bryan.whitehead@microchip.com>
Cc: Sergey Shtylyov <s.shtylyov@omp.ru>
Cc: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Cc: Alexandre Torgue <alexandre.torgue@foss.st.com>
Cc: Jose Abreu <joabreu@synopsys.com>
Cc: Maxime Coquelin <mcoquelin.stm32@gmail.com>
Cc: Richard Cochran <richardcochran@gmail.com>
Cc: Vivek Thampi <vithampi@vmware.com>
Cc: VMware PV-Drivers Reviewers <pv-drivers@vmware.com>
Cc: Jie Wang <wangjie125@huawei.com>
Cc: Jacob Keller <jacob.e.keller@intel.com>
Cc: Guangbin Huang <huangguangbin2@huawei.com>
Cc: Eran Ben Elisha <eranbe@nvidia.com>
Cc: Aya Levin <ayal@nvidia.com>
Cc: Cai Huoqing <cai.huoqing@linux.dev>
Cc: Biju Das <biju.das.jz@bp.renesas.com>
Cc: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Cc: Phil Edworthy <phil.edworthy@renesas.com>
Cc: Jiasheng Jiang <jiasheng@iscas.ac.cn>
Cc: "Gustavo A. R. Silva" <gustavoars@kernel.org>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Wan Jiabing <wanjiabing@vivo.com>
Cc: Lv Ruyi <lv.ruyi@zte.com.cn>
Cc: Arnd Bergmann <arnd@arndb.de>
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 70479a40 337ffae0
......@@ -706,7 +706,7 @@ static int hv_ptp_settime(struct ptp_clock_info *p, const struct timespec64 *ts)
return -EOPNOTSUPP;
}
static int hv_ptp_adjfreq(struct ptp_clock_info *ptp, s32 delta)
static int hv_ptp_adjfine(struct ptp_clock_info *ptp, long delta)
{
return -EOPNOTSUPP;
}
......@@ -724,7 +724,7 @@ static struct ptp_clock_info ptp_hyperv_info = {
.name = "hyperv",
.enable = hv_ptp_enable,
.adjtime = hv_ptp_adjtime,
.adjfreq = hv_ptp_adjfreq,
.adjfine = hv_ptp_adjfine,
.gettime64 = hv_ptp_gettime,
.settime64 = hv_ptp_settime,
.owner = THIS_MODULE,
......
......@@ -134,27 +134,15 @@ static u64 xgbe_cc_read(const struct cyclecounter *cc)
return nsec;
}
static int xgbe_adjfreq(struct ptp_clock_info *info, s32 delta)
static int xgbe_adjfine(struct ptp_clock_info *info, long scaled_ppm)
{
struct xgbe_prv_data *pdata = container_of(info,
struct xgbe_prv_data,
ptp_clock_info);
unsigned long flags;
u64 adjust;
u32 addend, diff;
unsigned int neg_adjust = 0;
u64 addend;
if (delta < 0) {
neg_adjust = 1;
delta = -delta;
}
adjust = pdata->tstamp_addend;
adjust *= delta;
diff = div_u64(adjust, 1000000000UL);
addend = (neg_adjust) ? pdata->tstamp_addend - diff :
pdata->tstamp_addend + diff;
addend = adjust_by_scaled_ppm(pdata->tstamp_addend, scaled_ppm);
spin_lock_irqsave(&pdata->tstamp_lock, flags);
......@@ -235,7 +223,7 @@ void xgbe_ptp_register(struct xgbe_prv_data *pdata)
netdev_name(pdata->netdev));
info->owner = THIS_MODULE;
info->max_adj = pdata->ptpclk_rate;
info->adjfreq = xgbe_adjfreq;
info->adjfine = xgbe_adjfine;
info->adjtime = xgbe_adjtime;
info->gettime64 = xgbe_gettime;
info->settime64 = xgbe_settime;
......
......@@ -29,17 +29,11 @@ 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);
struct e1000_hw *hw = &adapter->hw;
bool neg_adj = false;
unsigned long flags;
u64 adjustment;
u32 timinca, incvalue;
u64 incvalue;
u32 timinca;
s32 ret_val;
if (delta < 0) {
neg_adj = true;
delta = -delta;
}
/* Get the System Time Register SYSTIM base frequency */
ret_val = e1000e_get_base_timinca(adapter, &timinca);
if (ret_val)
......@@ -48,11 +42,7 @@ static int e1000e_phc_adjfine(struct ptp_clock_info *ptp, long delta)
spin_lock_irqsave(&adapter->systim_lock, flags);
incvalue = timinca & E1000_TIMINCA_INCVALUE_MASK;
adjustment = mul_u64_u64_div_u64(incvalue, (u64)delta,
1000000ULL << 16);
incvalue = neg_adj ? (incvalue - adjustment) : (incvalue + adjustment);
incvalue = adjust_by_scaled_ppm(incvalue, delta);
timinca &= ~E1000_TIMINCA_INCVALUE_MASK;
timinca |= incvalue;
......
......@@ -347,23 +347,12 @@ 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 (scaled_ppm < 0) {
neg_adj = 1;
scaled_ppm = -scaled_ppm;
}
u64 adj, base_adj;
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);
base_adj = I40E_PTP_40GB_INCVAL * READ_ONCE(pf->ptp_adj_mult);
if (neg_adj)
adj = I40E_PTP_40GB_INCVAL - diff;
else
adj = I40E_PTP_40GB_INCVAL + diff;
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);
......
......@@ -1444,24 +1444,10 @@ static int ice_ptp_adjfine(struct ptp_clock_info *info, long scaled_ppm)
{
struct ice_pf *pf = ptp_info_to_pf(info);
struct ice_hw *hw = &pf->hw;
u64 incval, diff;
int neg_adj = 0;
u64 incval;
int err;
incval = ice_base_incval(pf);
if (scaled_ppm < 0) {
neg_adj = 1;
scaled_ppm = -scaled_ppm;
}
diff = mul_u64_u64_div_u64(incval, (u64)scaled_ppm,
1000000ULL << 16);
if (neg_adj)
incval -= diff;
else
incval += diff;
incval = adjust_by_scaled_ppm(ice_base_incval(pf), scaled_ppm);
err = ice_ptp_write_incval_locked(hw, incval);
if (err) {
dev_err(ice_pf_to_dev(pf), "PTP failed to set incval, err %d\n",
......
......@@ -195,23 +195,9 @@ 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);
struct e1000_hw *hw = &igb->hw;
int neg_adj = 0;
u64 rate;
u32 incvalue;
if (scaled_ppm < 0) {
neg_adj = 1;
scaled_ppm = -scaled_ppm;
}
incvalue = INCVALUE_82576;
rate = mul_u64_u64_div_u64(incvalue, (u64)scaled_ppm,
1000000ULL << 16);
u64 incvalue;
if (neg_adj)
incvalue -= rate;
else
incvalue += rate;
incvalue = adjust_by_scaled_ppm(INCVALUE_82576, scaled_ppm);
wr32(E1000_TIMINCA, INCPERIOD_82576 | (incvalue & INCVALUE_82576_MASK));
......
......@@ -451,21 +451,11 @@ 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 incval, diff;
int neg_adj = 0;
if (scaled_ppm < 0) {
neg_adj = 1;
scaled_ppm = -scaled_ppm;
}
u64 incval;
smp_mb();
incval = READ_ONCE(adapter->base_incval);
diff = mul_u64_u64_div_u64(incval, scaled_ppm,
1000000ULL << 16);
incval = neg_adj ? (incval - diff) : (incval + diff);
incval = adjust_by_scaled_ppm(incval, scaled_ppm);
switch (hw->mac.type) {
case ixgbe_mac_X540:
......@@ -502,17 +492,11 @@ 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;
bool neg_adj;
u64 rate;
u32 inca;
if (scaled_ppm < 0) {
neg_adj = 1;
scaled_ppm = -scaled_ppm;
}
rate = mul_u64_u64_div_u64(IXGBE_X550_BASE_PERIOD, scaled_ppm,
1000000ULL << 16);
neg_adj = diff_by_scaled_ppm(IXGBE_X550_BASE_PERIOD, scaled_ppm, &rate);
/* warn if rate is too large */
if (rate >= INCVALUE_MASK)
......
......@@ -111,34 +111,27 @@ void mlx4_en_ptp_overflow_check(struct mlx4_en_dev *mdev)
}
/**
* mlx4_en_phc_adjfreq - adjust the frequency of the hardware clock
* mlx4_en_phc_adjfine - adjust the frequency of the hardware clock
* @ptp: ptp clock structure
* @delta: Desired frequency change in parts per billion
* @scaled_ppm: Desired frequency change in scaled parts per million
*
* Adjust the frequency of the PHC cycle counter by the indicated delta from
* the base frequency.
* Adjust the frequency of the PHC 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 mlx4_en_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta)
static int mlx4_en_phc_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
{
u64 adj;
u32 diff, mult;
int neg_adj = 0;
u32 mult;
unsigned long flags;
struct mlx4_en_dev *mdev = container_of(ptp, struct mlx4_en_dev,
ptp_clock_info);
if (delta < 0) {
neg_adj = 1;
delta = -delta;
}
mult = mdev->nominal_c_mult;
adj = mult;
adj *= delta;
diff = div_u64(adj, 1000000000ULL);
mult = (u32)adjust_by_scaled_ppm(mdev->nominal_c_mult, scaled_ppm);
write_seqlock_irqsave(&mdev->clock_lock, flags);
timecounter_read(&mdev->clock);
mdev->cycles.mult = neg_adj ? mult - diff : mult + diff;
mdev->cycles.mult = mult;
write_sequnlock_irqrestore(&mdev->clock_lock, flags);
return 0;
......@@ -237,7 +230,7 @@ static const struct ptp_clock_info mlx4_en_ptp_clock_info = {
.n_per_out = 0,
.n_pins = 0,
.pps = 0,
.adjfreq = mlx4_en_phc_adjfreq,
.adjfine = mlx4_en_phc_adjfine,
.adjtime = mlx4_en_phc_adjtime,
.gettime64 = mlx4_en_phc_gettime,
.settime64 = mlx4_en_phc_settime,
......
......@@ -339,35 +339,25 @@ static int mlx5_ptp_adjfreq_real_time(struct mlx5_core_dev *mdev, s32 freq)
return mlx5_set_mtutc(mdev, in, sizeof(in));
}
static int mlx5_ptp_adjfreq(struct ptp_clock_info *ptp, s32 delta)
static int mlx5_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
{
struct mlx5_clock *clock = container_of(ptp, struct mlx5_clock, ptp_info);
struct mlx5_timer *timer = &clock->timer;
struct mlx5_core_dev *mdev;
unsigned long flags;
int neg_adj = 0;
u32 diff;
u64 adj;
u32 mult;
int err;
mdev = container_of(clock, struct mlx5_core_dev, clock);
err = mlx5_ptp_adjfreq_real_time(mdev, delta);
err = mlx5_ptp_adjfreq_real_time(mdev, scaled_ppm_to_ppb(scaled_ppm));
if (err)
return err;
if (delta < 0) {
neg_adj = 1;
delta = -delta;
}
adj = timer->nominal_c_mult;
adj *= delta;
diff = div_u64(adj, 1000000000ULL);
mult = (u32)adjust_by_scaled_ppm(timer->nominal_c_mult, scaled_ppm);
write_seqlock_irqsave(&clock->lock, flags);
timecounter_read(&timer->tc);
timer->cycles.mult = neg_adj ? timer->nominal_c_mult - diff :
timer->nominal_c_mult + diff;
timer->cycles.mult = mult;
mlx5_update_clock_info_page(mdev);
write_sequnlock_irqrestore(&clock->lock, flags);
......@@ -697,7 +687,7 @@ static const struct ptp_clock_info mlx5_ptp_clock_info = {
.n_per_out = 0,
.n_pins = 0,
.pps = 0,
.adjfreq = mlx5_ptp_adjfreq,
.adjfine = mlx5_ptp_adjfine,
.adjtime = mlx5_ptp_adjtime,
.gettimex64 = mlx5_ptp_gettimex,
.settime64 = mlx5_ptp_settime,
......
......@@ -339,59 +339,18 @@ static int lan743x_ptpci_adjfine(struct ptp_clock_info *ptpci, long scaled_ppm)
struct lan743x_adapter *adapter =
container_of(ptp, struct lan743x_adapter, ptp);
u32 lan743x_rate_adj = 0;
bool positive = true;
u64 u64_delta = 0;
u64 u64_delta;
if ((scaled_ppm < (-LAN743X_PTP_MAX_FINE_ADJ_IN_SCALED_PPM)) ||
scaled_ppm > LAN743X_PTP_MAX_FINE_ADJ_IN_SCALED_PPM) {
return -EINVAL;
}
if (scaled_ppm > 0) {
u64_delta = (u64)scaled_ppm;
positive = true;
} else {
u64_delta = (u64)(-scaled_ppm);
positive = false;
}
u64_delta = (u64_delta << 19);
lan743x_rate_adj = div_u64(u64_delta, 1000000);
if (positive)
lan743x_rate_adj |= PTP_CLOCK_RATE_ADJ_DIR_;
lan743x_csr_write(adapter, PTP_CLOCK_RATE_ADJ,
lan743x_rate_adj);
return 0;
}
static int lan743x_ptpci_adjfreq(struct ptp_clock_info *ptpci, s32 delta_ppb)
{
struct lan743x_ptp *ptp =
container_of(ptpci, struct lan743x_ptp, ptp_clock_info);
struct lan743x_adapter *adapter =
container_of(ptp, struct lan743x_adapter, ptp);
u32 lan743x_rate_adj = 0;
bool positive = true;
u32 u32_delta = 0;
u64 u64_delta = 0;
if ((delta_ppb < (-LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB)) ||
delta_ppb > LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB) {
return -EINVAL;
}
if (delta_ppb > 0) {
u32_delta = (u32)delta_ppb;
positive = true;
} else {
u32_delta = (u32)(-delta_ppb);
positive = false;
}
u64_delta = (((u64)u32_delta) << 35);
lan743x_rate_adj = div_u64(u64_delta, 1000000000);
if (positive)
lan743x_rate_adj |= PTP_CLOCK_RATE_ADJ_DIR_;
/* diff_by_scaled_ppm returns true if the difference is negative */
if (diff_by_scaled_ppm(1ULL << 35, scaled_ppm, &u64_delta))
lan743x_rate_adj = (u32)u64_delta;
else
lan743x_rate_adj = (u32)u64_delta | PTP_CLOCK_RATE_ADJ_DIR_;
lan743x_csr_write(adapter, PTP_CLOCK_RATE_ADJ,
lan743x_rate_adj);
......@@ -1583,7 +1542,6 @@ int lan743x_ptp_open(struct lan743x_adapter *adapter)
ptp->ptp_clock_info.pps = LAN743X_PTP_N_PPS;
ptp->ptp_clock_info.pin_config = ptp->pin_config;
ptp->ptp_clock_info.adjfine = lan743x_ptpci_adjfine;
ptp->ptp_clock_info.adjfreq = lan743x_ptpci_adjfreq;
ptp->ptp_clock_info.adjtime = lan743x_ptpci_adjtime;
ptp->ptp_clock_info.gettime64 = lan743x_ptpci_gettime64;
ptp->ptp_clock_info.getcrosststamp = NULL;
......
......@@ -88,24 +88,17 @@ static int ravb_ptp_update_compare(struct ravb_private *priv, u32 ns)
}
/* PTP clock operations */
static int ravb_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
static int ravb_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
{
struct ravb_private *priv = container_of(ptp, struct ravb_private,
ptp.info);
struct net_device *ndev = priv->ndev;
unsigned long flags;
u32 diff, addend;
bool neg_adj = false;
u32 addend;
u32 gccr;
if (ppb < 0) {
neg_adj = true;
ppb = -ppb;
}
addend = priv->ptp.default_addend;
diff = div_u64((u64)addend * ppb, NSEC_PER_SEC);
addend = neg_adj ? addend - diff : addend + diff;
addend = (u32)adjust_by_scaled_ppm(priv->ptp.default_addend,
scaled_ppm);
spin_lock_irqsave(&priv->lock, flags);
......@@ -295,7 +288,7 @@ static const struct ptp_clock_info ravb_ptp_info = {
.max_adj = 50000000,
.n_ext_ts = N_EXT_TS,
.n_per_out = N_PER_OUT,
.adjfreq = ravb_ptp_adjfreq,
.adjfine = ravb_ptp_adjfine,
.adjtime = ravb_ptp_adjtime,
.gettime64 = ravb_ptp_gettime64,
.settime64 = ravb_ptp_settime64,
......
......@@ -66,7 +66,7 @@ static int ptp_kvm_getcrosststamp(struct ptp_clock_info *ptp,
* PTP clock operations
*/
static int ptp_kvm_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
static int ptp_kvm_adjfine(struct ptp_clock_info *ptp, long delta)
{
return -EOPNOTSUPP;
}
......@@ -115,7 +115,7 @@ static const struct ptp_clock_info ptp_kvm_caps = {
.n_ext_ts = 0,
.n_pins = 0,
.pps = 0,
.adjfreq = ptp_kvm_adjfreq,
.adjfine = ptp_kvm_adjfine,
.adjtime = ptp_kvm_adjtime,
.gettime64 = ptp_kvm_gettime,
.settime64 = ptp_kvm_settime,
......
......@@ -47,7 +47,7 @@ static int ptp_vmw_adjtime(struct ptp_clock_info *info, s64 delta)
return -EOPNOTSUPP;
}
static int ptp_vmw_adjfreq(struct ptp_clock_info *info, s32 delta)
static int ptp_vmw_adjfine(struct ptp_clock_info *info, long delta)
{
return -EOPNOTSUPP;
}
......@@ -79,7 +79,7 @@ static struct ptp_clock_info ptp_vmw_clock_info = {
.name = "ptp_vmw",
.max_adj = 0,
.adjtime = ptp_vmw_adjtime,
.adjfreq = ptp_vmw_adjfreq,
.adjfine = ptp_vmw_adjfine,
.gettime64 = ptp_vmw_gettime,
.settime64 = ptp_vmw_settime,
.enable = ptp_vmw_enable,
......
......@@ -45,6 +45,8 @@ struct system_device_crosststamp;
/**
* struct ptp_system_timestamp - system time corresponding to a PHC timestamp
* @pre_ts: system timestamp before capturing PHC
* @post_ts: system timestamp after capturing PHC
*/
struct ptp_system_timestamp {
struct timespec64 pre_ts;
......@@ -246,6 +248,52 @@ static inline long scaled_ppm_to_ppb(long ppm)
return (long)ppb;
}
/**
* diff_by_scaled_ppm - Calculate difference using scaled ppm
* @base: the base increment value to adjust
* @scaled_ppm: scaled parts per million to adjust by
* @diff: on return, the absolute value of calculated diff
*
* Calculate the difference to adjust the base increment using scaled parts
* per million.
*
* Use mul_u64_u64_div_u64 to perform the difference calculation in avoid
* possible overflow.
*
* Returns: true if scaled_ppm is negative, false otherwise
*/
static inline bool diff_by_scaled_ppm(u64 base, long scaled_ppm, u64 *diff)
{
bool negative = false;
if (scaled_ppm < 0) {
negative = true;
scaled_ppm = -scaled_ppm;
}
*diff = mul_u64_u64_div_u64(base, (u64)scaled_ppm, 1000000ULL << 16);
return negative;
}
/**
* adjust_by_scaled_ppm - Adjust a base increment by scaled parts per million
* @base: the base increment value to adjust
* @scaled_ppm: scaled parts per million frequency adjustment
*
* Helper function which calculates a new increment value based on the
* requested scaled parts per million adjustment.
*/
static inline u64 adjust_by_scaled_ppm(u64 base, long scaled_ppm)
{
u64 diff;
if (diff_by_scaled_ppm(base, scaled_ppm, &diff))
return base - diff;
return base + diff;
}
#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
/**
......@@ -316,6 +364,11 @@ int ptp_find_pin(struct ptp_clock *ptp,
* should most likely call ptp_find_pin() directly from their
* ptp_clock_info::enable() method.
*
* @ptp: The clock obtained from ptp_clock_register().
* @func: One of the ptp_pin_function enumerated values.
* @chan: The particular functional channel to find.
* Return: Pin index in the range of zero to ptp_clock_caps.n_pins - 1,
* or -1 if the auxiliary function cannot be found.
*/
int ptp_find_pin_unlocked(struct ptp_clock *ptp,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment