On Fri, Nov 18, 2016 at 03:21:51PM +0100, Andrei Pistirica wrote:
> - Frequency adjustment is not directly supported by this IP.

This statement still makes no sense.  Doesn't the following text...

>   addend is the initial value ns increment and similarly addendesub.
>   The ppb (parts per billion) provided is used as
>   ns_incr = addend +/- (ppb/rate).
>   Similarly the remainder of the above is used to populate subns increment.

describe how frequency adjustment is in fact supported?

> +config MACB_USE_HWSTAMP
> +     bool "Use IEEE 1588 hwstamp"
> +     depends on MACB
> +     default y
> +     select PTP_1588_CLOCK

This "select" pattern is going to be replaced with "imply" soon.

   http://www.mail-archive.com/linux-kernel@vger.kernel.org/msg1269181.html

You should use the new "imply" key word and reference that series in
your change log.

> diff --git a/drivers/net/ethernet/cadence/macb.h 
> b/drivers/net/ethernet/cadence/macb.h
> index 3f385ab..2ee9af8 100644
> --- a/drivers/net/ethernet/cadence/macb.h
> +++ b/drivers/net/ethernet/cadence/macb.h
> @@ -10,6 +10,10 @@
>  #ifndef _MACB_H
>  #define _MACB_H
>  
> +#include <linux/net_tstamp.h>
> +#include <linux/ptp_clock.h>
> +#include <linux/ptp_clock_kernel.h>

Don't need net_tstamp.h here.  Move it into the .c file please.

> @@ -840,8 +902,26 @@ struct macb {
>  
>       unsigned int            rx_frm_len_mask;
>       unsigned int            jumbo_max_len;
> +
> +#ifdef CONFIG_MACB_USE_HWSTAMP
> +     unsigned int            hwts_tx_en;
> +     unsigned int            hwts_rx_en;

These two can be bool'eans.

> +     spinlock_t              tsu_clk_lock;
> +     unsigned int            tsu_rate;
> +
> +     struct ptp_clock        *ptp_clock;
> +     struct ptp_clock_info   ptp_caps;
> +     unsigned int            ns_incr;
> +     unsigned int            subns_incr;

These two are 32 bit register values, right?  Then use the u32 type.

> +#endif
>  };

> +static inline void macb_tsu_set_time(struct macb *bp,
> +                                  const struct timespec64 *ts)
> +{
> +     u32 ns, sech, secl;
> +     s64 word_mask = 0xffffffff;
> +
> +     sech = (u32)ts->tv_sec;
> +     secl = (u32)ts->tv_sec;
> +     ns = ts->tv_nsec;
> +     if (ts->tv_sec > word_mask)
> +             sech = (ts->tv_sec >> 32);
> +
> +     spin_lock(&bp->tsu_clk_lock);
> +
> +     /* TSH doesn't latch the time and no atomicity! */
> +     gem_writel(bp, TSH, sech);
> +     gem_writel(bp, TSL, secl);

If TN overflows here then the clock will be off by one whole second!
Why not clear TN first?

> +     gem_writel(bp, TN, ns);
> +
> +     spin_unlock(&bp->tsu_clk_lock);
> +}
> +
> +static int macb_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
> +{
> +     struct macb *bp = container_of(ptp, struct macb, ptp_caps);
> +     u32 addend, addend_frac, rem;
> +     u64 drift_tmr, diff, diff_frac = 0;
> +     int neg_adj = 0;
> +
> +     if (ppb < 0) {
> +             neg_adj = 1;
> +             ppb = -ppb;
> +     }
> +
> +     /* drift/period */
> +     drift_tmr = (bp->ns_incr * ppb) +
> +                 ((bp->subns_incr * ppb) >> 16);

What?  Why the 16 bit shift?  Last time your said it was 24 bits.

> +     /* drift/cycle */
> +     diff = div_u64_rem(drift_tmr, 1000000000ULL, &rem);
> +
> +     /* drift fraction/cycle, if necessary */
> +     if (rem) {
> +             u64 fraction = rem;
> +             fraction = fraction << 16;
> +
> +             diff_frac = div_u64(fraction, 1000000000ULL);

If you use a combined tuning word like I explained last time, then you
will not need a second division.

Also, please use the new adjfine() PHC method, as adjfreq() is now deprecated.

> +     }
> +
> +     /* adjustmets */
> +     addend = neg_adj ? (bp->ns_incr - diff) : (bp->ns_incr + diff);
> +     addend_frac = neg_adj ? (bp->subns_incr - diff_frac) :
> +                             (bp->subns_incr + diff_frac);
> +
> +     spin_lock(&bp->tsu_clk_lock);
> +
> +     gem_writel(bp, TISUBN, GEM_BF(SUBNSINCR, addend_frac));
> +     gem_writel(bp, TI, GEM_BF(NSINCR, addend));
> +
> +     spin_unlock(&bp->tsu_clk_lock);
> +     return 0;
> +}

> +void macb_ptp_init(struct net_device *ndev)
> +{
> +     struct macb *bp = netdev_priv(ndev);
> +     struct timespec64 now;
> +     u32 rem = 0;
> +
> +     if (!(bp->caps | MACB_CAPS_GEM_HAS_PTP)){
> +             netdev_vdbg(bp->dev, "Platform does not support PTP!\n");
> +             return;
> +     }
> +
> +     spin_lock_init(&bp->tsu_clk_lock);
> +
> +     bp->ptp_caps = macb_ptp_caps;
> +     bp->tsu_rate = clk_get_rate(bp->pclk);
> +
> +     getnstimeofday64(&now);
> +     macb_tsu_set_time(bp, (const struct timespec64 *)&now);
> +
> +     bp->ns_incr = div_u64_rem(NSEC_PER_SEC, bp->tsu_rate, &rem);
> +     if (rem) {
> +             u64 adj = rem;
> +             /* Multiply by 2^16 as subns register is 16 bits */

Last time you said:
> +             /* Multiple by 2^24 as subns field is 24 bits */

> +             adj <<= 16;
> +             bp->subns_incr = div_u64(adj, bp->tsu_rate);
> +     } else {
> +             bp->subns_incr = 0;
> +     }
> +
> +     gem_writel(bp, TISUBN, GEM_BF(SUBNSINCR, bp->subns_incr));
> +     gem_writel(bp, TI, GEM_BF(NSINCR, bp->ns_incr));
> +     gem_writel(bp, TA, 0);
> +
> +     bp->ptp_clock = ptp_clock_register(&bp->ptp_caps, NULL);

You call regsiter, but you never call unregister!

> +     if (IS_ERR(&bp->ptp_clock)) {
> +             bp->ptp_clock = NULL;
> +             pr_err("ptp clock register failed\n");
> +             return;
> +     }
> +
> +     dev_info(&bp->pdev->dev, "%s ptp clock registered.\n", GMAC_TIMER_NAME);
> +}
> +
> -- 
> 1.9.1
> 

Thanks,
Richard

Reply via email to