Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756653AbcKWVFz (ORCPT ); Wed, 23 Nov 2016 16:05:55 -0500 Received: from mail-wm0-f65.google.com ([74.125.82.65]:33302 "EHLO mail-wm0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754335AbcKWVFy (ORCPT ); Wed, 23 Nov 2016 16:05:54 -0500 Date: Wed, 23 Nov 2016 22:03:18 +0100 From: Richard Cochran To: Andrei Pistirica Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, davem@davemloft.net, nicolas.ferre@atmel.com, harinikatakamlinux@gmail.com, harini.katakam@xilinx.com, punnaia@xilinx.com, michals@xilinx.com, anirudh@xilinx.com, boris.brezillon@free-electrons.com, alexandre.belloni@free-electrons.com, tbultel@pixelsurmer.com Subject: Re: [RFC PATCH v2 1/2] macb: Add 1588 support in Cadence GEM. Message-ID: <20161123210318.GB2845@localhost.localdomain> References: <1479478912-14067-1-git-send-email-andrei.pistirica@microchip.com> <20161120191823.GA6950@localhost.localdomain> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.23 (2014-03-12) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 2162 Lines: 89 On Wed, Nov 23, 2016 at 02:34:03PM +0100, Andrei Pistirica wrote: > From what I understand, your suggestion is: > (ns | frac) * ppb = (total_ns | total_frac) > (total_ns | total_frac) / 10^9 = (adj_ns | adj_frac) > This is correct iff total_ns/10^9 >= 1, but the problem is that there are > missed fractions due to the following approximation: > frac*ppb =~ (ns*ppb+frac*ppb*2^16)*2^16-10^9*2^16*flor(ns*ppb+frac*ppb*2^16, > 10^9). -ENOPARSE; > An example which uses values from a real test: > let ppb=4891, ns=12 and frac=3158 That is a very strange example for nominal frequency. The clock period is 12.048187255859375 nanoseconds, and so the frequency is 83000037.99 Hz. But hey, let's go with it... > - using suggested algorithm, yields: adj_ns = 0 and adj_frac = 0 > - using in-place algorithm, yields: adj_ns = 0, adj_frac = 4 > You can check the calculus. The test program, below, shows you what I meant. (Of course, you should adjust this to fit the adjfine() method.) Unfortunately, this device has a very coarse frequency resolution. Using a nominal period of ns=12 as an example, the resolution is 2^-16 / 12 or 1.27 ppm. The 24 bit device is much better in this repect. The output using your example numbers is: $ ./a.out 12 3158 4891 ns=12 frac=3158 ns=12 frac=3162 $ ./a.out 12 3158 -4891 ns=12 frac=3158 ns=12 frac=3154 See how you get a result of +/- 4 with just one division? Thanks, Richard --- #include #include #include static void adjfreq(uint32_t ns, uint32_t frac, int32_t ppb) { uint64_t adj; uint32_t diff, word; int neg_adj = 0; printf("ns=%u frac=%u\n", ns, frac); if (ppb < 0) { neg_adj = 1; ppb = -ppb; } word = (ns << 16) + frac; adj = word; adj *= ppb; adj += 500000000UL; diff = adj / 1000000000UL; word = neg_adj ? word - diff : word + diff; printf("ns=%u frac=%u\n", word >> 16, word & 0xffff); } int main(int argc, char *argv[]) { uint32_t ns, frac; int32_t ppb; if (argc != 4) { puts("need ns, frac, and ppb"); return -1; } ns = atoi(argv[1]); frac = atoi(argv[2]); ppb = atoi(argv[3]); adjfreq(ns, frac, ppb); return 0; }