Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'timers-ptp-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip

* 'timers-ptp-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
ptp: Fix dp83640 build warning when building statically
ptp: Added a clock driver for the National Semiconductor PHYTER.
ptp: Added a clock driver for the IXP46x.
ptp: Added a clock that uses the eTSEC found on the MPC85xx.
ptp: Added a brand new class driver for ptp clocks.

+4406 -3
+98
Documentation/ABI/testing/sysfs-ptp
··· 1 + What: /sys/class/ptp/ 2 + Date: September 2010 3 + Contact: Richard Cochran <richardcochran@gmail.com> 4 + Description: 5 + This directory contains files and directories 6 + providing a standardized interface to the ancillary 7 + features of PTP hardware clocks. 8 + 9 + What: /sys/class/ptp/ptpN/ 10 + Date: September 2010 11 + Contact: Richard Cochran <richardcochran@gmail.com> 12 + Description: 13 + This directory contains the attributes of the Nth PTP 14 + hardware clock registered into the PTP class driver 15 + subsystem. 16 + 17 + What: /sys/class/ptp/ptpN/clock_name 18 + Date: September 2010 19 + Contact: Richard Cochran <richardcochran@gmail.com> 20 + Description: 21 + This file contains the name of the PTP hardware clock 22 + as a human readable string. 23 + 24 + What: /sys/class/ptp/ptpN/max_adjustment 25 + Date: September 2010 26 + Contact: Richard Cochran <richardcochran@gmail.com> 27 + Description: 28 + This file contains the PTP hardware clock's maximum 29 + frequency adjustment value (a positive integer) in 30 + parts per billion. 31 + 32 + What: /sys/class/ptp/ptpN/n_alarms 33 + Date: September 2010 34 + Contact: Richard Cochran <richardcochran@gmail.com> 35 + Description: 36 + This file contains the number of periodic or one shot 37 + alarms offer by the PTP hardware clock. 38 + 39 + What: /sys/class/ptp/ptpN/n_external_timestamps 40 + Date: September 2010 41 + Contact: Richard Cochran <richardcochran@gmail.com> 42 + Description: 43 + This file contains the number of external timestamp 44 + channels offered by the PTP hardware clock. 45 + 46 + What: /sys/class/ptp/ptpN/n_periodic_outputs 47 + Date: September 2010 48 + Contact: Richard Cochran <richardcochran@gmail.com> 49 + Description: 50 + This file contains the number of programmable periodic 51 + output channels offered by the PTP hardware clock. 52 + 53 + What: /sys/class/ptp/ptpN/pps_avaiable 54 + Date: September 2010 55 + Contact: Richard Cochran <richardcochran@gmail.com> 56 + Description: 57 + This file indicates whether the PTP hardware clock 58 + supports a Pulse Per Second to the host CPU. Reading 59 + "1" means that the PPS is supported, while "0" means 60 + not supported. 61 + 62 + What: /sys/class/ptp/ptpN/extts_enable 63 + Date: September 2010 64 + Contact: Richard Cochran <richardcochran@gmail.com> 65 + Description: 66 + This write-only file enables or disables external 67 + timestamps. To enable external timestamps, write the 68 + channel index followed by a "1" into the file. 69 + To disable external timestamps, write the channel 70 + index followed by a "0" into the file. 71 + 72 + What: /sys/class/ptp/ptpN/fifo 73 + Date: September 2010 74 + Contact: Richard Cochran <richardcochran@gmail.com> 75 + Description: 76 + This file provides timestamps on external events, in 77 + the form of three integers: channel index, seconds, 78 + and nanoseconds. 79 + 80 + What: /sys/class/ptp/ptpN/period 81 + Date: September 2010 82 + Contact: Richard Cochran <richardcochran@gmail.com> 83 + Description: 84 + This write-only file enables or disables periodic 85 + outputs. To enable a periodic output, write five 86 + integers into the file: channel index, start time 87 + seconds, start time nanoseconds, period seconds, and 88 + period nanoseconds. To disable a periodic output, set 89 + all the seconds and nanoseconds values to zero. 90 + 91 + What: /sys/class/ptp/ptpN/pps_enable 92 + Date: September 2010 93 + Contact: Richard Cochran <richardcochran@gmail.com> 94 + Description: 95 + This write-only file enables or disables delivery of 96 + PPS events to the Linux PPS subsystem. To enable PPS 97 + events, write a "1" into the file. To disable events, 98 + write a "0" into the file.
+54
Documentation/devicetree/bindings/net/fsl-tsec-phy.txt
··· 74 74 interrupt-parent = <&mpic>; 75 75 phy-handle = <&phy0> 76 76 }; 77 + 78 + * Gianfar PTP clock nodes 79 + 80 + General Properties: 81 + 82 + - compatible Should be "fsl,etsec-ptp" 83 + - reg Offset and length of the register set for the device 84 + - interrupts There should be at least two interrupts. Some devices 85 + have as many as four PTP related interrupts. 86 + 87 + Clock Properties: 88 + 89 + - fsl,tclk-period Timer reference clock period in nanoseconds. 90 + - fsl,tmr-prsc Prescaler, divides the output clock. 91 + - fsl,tmr-add Frequency compensation value. 92 + - fsl,tmr-fiper1 Fixed interval period pulse generator. 93 + - fsl,tmr-fiper2 Fixed interval period pulse generator. 94 + - fsl,max-adj Maximum frequency adjustment in parts per billion. 95 + 96 + These properties set the operational parameters for the PTP 97 + clock. You must choose these carefully for the clock to work right. 98 + Here is how to figure good values: 99 + 100 + TimerOsc = system clock MHz 101 + tclk_period = desired clock period nanoseconds 102 + NominalFreq = 1000 / tclk_period MHz 103 + FreqDivRatio = TimerOsc / NominalFreq (must be greater that 1.0) 104 + tmr_add = ceil(2^32 / FreqDivRatio) 105 + OutputClock = NominalFreq / tmr_prsc MHz 106 + PulseWidth = 1 / OutputClock microseconds 107 + FiperFreq1 = desired frequency in Hz 108 + FiperDiv1 = 1000000 * OutputClock / FiperFreq1 109 + tmr_fiper1 = tmr_prsc * tclk_period * FiperDiv1 - tclk_period 110 + max_adj = 1000000000 * (FreqDivRatio - 1.0) - 1 111 + 112 + The calculation for tmr_fiper2 is the same as for tmr_fiper1. The 113 + driver expects that tmr_fiper1 will be correctly set to produce a 1 114 + Pulse Per Second (PPS) signal, since this will be offered to the PPS 115 + subsystem to synchronize the Linux clock. 116 + 117 + Example: 118 + 119 + ptp_clock@24E00 { 120 + compatible = "fsl,etsec-ptp"; 121 + reg = <0x24E00 0xB0>; 122 + interrupts = <12 0x8 13 0x8>; 123 + interrupt-parent = < &ipic >; 124 + fsl,tclk-period = <10>; 125 + fsl,tmr-prsc = <100>; 126 + fsl,tmr-add = <0x999999A4>; 127 + fsl,tmr-fiper1 = <0x3B9AC9F6>; 128 + fsl,tmr-fiper2 = <0x00018696>; 129 + fsl,max-adj = <659999998>; 130 + };
+89
Documentation/ptp/ptp.txt
··· 1 + 2 + * PTP hardware clock infrastructure for Linux 3 + 4 + This patch set introduces support for IEEE 1588 PTP clocks in 5 + Linux. Together with the SO_TIMESTAMPING socket options, this 6 + presents a standardized method for developing PTP user space 7 + programs, synchronizing Linux with external clocks, and using the 8 + ancillary features of PTP hardware clocks. 9 + 10 + A new class driver exports a kernel interface for specific clock 11 + drivers and a user space interface. The infrastructure supports a 12 + complete set of PTP hardware clock functionality. 13 + 14 + + Basic clock operations 15 + - Set time 16 + - Get time 17 + - Shift the clock by a given offset atomically 18 + - Adjust clock frequency 19 + 20 + + Ancillary clock features 21 + - One short or periodic alarms, with signal delivery to user program 22 + - Time stamp external events 23 + - Period output signals configurable from user space 24 + - Synchronization of the Linux system time via the PPS subsystem 25 + 26 + ** PTP hardware clock kernel API 27 + 28 + A PTP clock driver registers itself with the class driver. The 29 + class driver handles all of the dealings with user space. The 30 + author of a clock driver need only implement the details of 31 + programming the clock hardware. The clock driver notifies the class 32 + driver of asynchronous events (alarms and external time stamps) via 33 + a simple message passing interface. 34 + 35 + The class driver supports multiple PTP clock drivers. In normal use 36 + cases, only one PTP clock is needed. However, for testing and 37 + development, it can be useful to have more than one clock in a 38 + single system, in order to allow performance comparisons. 39 + 40 + ** PTP hardware clock user space API 41 + 42 + The class driver also creates a character device for each 43 + registered clock. User space can use an open file descriptor from 44 + the character device as a POSIX clock id and may call 45 + clock_gettime, clock_settime, and clock_adjtime. These calls 46 + implement the basic clock operations. 47 + 48 + User space programs may control the clock using standardized 49 + ioctls. A program may query, enable, configure, and disable the 50 + ancillary clock features. User space can receive time stamped 51 + events via blocking read() and poll(). One shot and periodic 52 + signals may be configured via the POSIX timer_settime() system 53 + call. 54 + 55 + ** Writing clock drivers 56 + 57 + Clock drivers include include/linux/ptp_clock_kernel.h and register 58 + themselves by presenting a 'struct ptp_clock_info' to the 59 + registration method. Clock drivers must implement all of the 60 + functions in the interface. If a clock does not offer a particular 61 + ancillary feature, then the driver should just return -EOPNOTSUPP 62 + from those functions. 63 + 64 + Drivers must ensure that all of the methods in interface are 65 + reentrant. Since most hardware implementations treat the time value 66 + as a 64 bit integer accessed as two 32 bit registers, drivers 67 + should use spin_lock_irqsave/spin_unlock_irqrestore to protect 68 + against concurrent access. This locking cannot be accomplished in 69 + class driver, since the lock may also be needed by the clock 70 + driver's interrupt service routine. 71 + 72 + ** Supported hardware 73 + 74 + + Freescale eTSEC gianfar 75 + - 2 Time stamp external triggers, programmable polarity (opt. interrupt) 76 + - 2 Alarm registers (optional interrupt) 77 + - 3 Periodic signals (optional interrupt) 78 + 79 + + National DP83640 80 + - 6 GPIOs programmable as inputs or outputs 81 + - 6 GPIOs with dedicated functions (LED/JTAG/clock) can also be 82 + used as general inputs or outputs 83 + - GPIO inputs can time stamp external triggers 84 + - GPIO outputs can produce periodic signals 85 + - 1 interrupt pin 86 + 87 + + Intel IXP465 88 + - Auxiliary Slave/Master Mode Snapshot (optional interrupt) 89 + - Target Time (optional interrupt)
+381
Documentation/ptp/testptp.c
··· 1 + /* 2 + * PTP 1588 clock support - User space test program 3 + * 4 + * Copyright (C) 2010 OMICRON electronics GmbH 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program; if not, write to the Free Software 18 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 + */ 20 + #include <errno.h> 21 + #include <fcntl.h> 22 + #include <math.h> 23 + #include <signal.h> 24 + #include <stdio.h> 25 + #include <stdlib.h> 26 + #include <string.h> 27 + #include <sys/ioctl.h> 28 + #include <sys/mman.h> 29 + #include <sys/stat.h> 30 + #include <sys/time.h> 31 + #include <sys/timex.h> 32 + #include <sys/types.h> 33 + #include <time.h> 34 + #include <unistd.h> 35 + 36 + #include <linux/ptp_clock.h> 37 + 38 + #define DEVICE "/dev/ptp0" 39 + 40 + #ifndef ADJ_SETOFFSET 41 + #define ADJ_SETOFFSET 0x0100 42 + #endif 43 + 44 + #ifndef CLOCK_INVALID 45 + #define CLOCK_INVALID -1 46 + #endif 47 + 48 + /* When glibc offers the syscall, this will go away. */ 49 + #include <sys/syscall.h> 50 + static int clock_adjtime(clockid_t id, struct timex *tx) 51 + { 52 + return syscall(__NR_clock_adjtime, id, tx); 53 + } 54 + 55 + static clockid_t get_clockid(int fd) 56 + { 57 + #define CLOCKFD 3 58 + #define FD_TO_CLOCKID(fd) ((~(clockid_t) (fd) << 3) | CLOCKFD) 59 + 60 + return FD_TO_CLOCKID(fd); 61 + } 62 + 63 + static void handle_alarm(int s) 64 + { 65 + printf("received signal %d\n", s); 66 + } 67 + 68 + static int install_handler(int signum, void (*handler)(int)) 69 + { 70 + struct sigaction action; 71 + sigset_t mask; 72 + 73 + /* Unblock the signal. */ 74 + sigemptyset(&mask); 75 + sigaddset(&mask, signum); 76 + sigprocmask(SIG_UNBLOCK, &mask, NULL); 77 + 78 + /* Install the signal handler. */ 79 + action.sa_handler = handler; 80 + action.sa_flags = 0; 81 + sigemptyset(&action.sa_mask); 82 + sigaction(signum, &action, NULL); 83 + 84 + return 0; 85 + } 86 + 87 + static long ppb_to_scaled_ppm(int ppb) 88 + { 89 + /* 90 + * The 'freq' field in the 'struct timex' is in parts per 91 + * million, but with a 16 bit binary fractional field. 92 + * Instead of calculating either one of 93 + * 94 + * scaled_ppm = (ppb / 1000) << 16 [1] 95 + * scaled_ppm = (ppb << 16) / 1000 [2] 96 + * 97 + * we simply use double precision math, in order to avoid the 98 + * truncation in [1] and the possible overflow in [2]. 99 + */ 100 + return (long) (ppb * 65.536); 101 + } 102 + 103 + static void usage(char *progname) 104 + { 105 + fprintf(stderr, 106 + "usage: %s [options]\n" 107 + " -a val request a one-shot alarm after 'val' seconds\n" 108 + " -A val request a periodic alarm every 'val' seconds\n" 109 + " -c query the ptp clock's capabilities\n" 110 + " -d name device to open\n" 111 + " -e val read 'val' external time stamp events\n" 112 + " -f val adjust the ptp clock frequency by 'val' ppb\n" 113 + " -g get the ptp clock time\n" 114 + " -h prints this message\n" 115 + " -p val enable output with a period of 'val' nanoseconds\n" 116 + " -P val enable or disable (val=1|0) the system clock PPS\n" 117 + " -s set the ptp clock time from the system time\n" 118 + " -S set the system time from the ptp clock time\n" 119 + " -t val shift the ptp clock time by 'val' seconds\n", 120 + progname); 121 + } 122 + 123 + int main(int argc, char *argv[]) 124 + { 125 + struct ptp_clock_caps caps; 126 + struct ptp_extts_event event; 127 + struct ptp_extts_request extts_request; 128 + struct ptp_perout_request perout_request; 129 + struct timespec ts; 130 + struct timex tx; 131 + 132 + static timer_t timerid; 133 + struct itimerspec timeout; 134 + struct sigevent sigevent; 135 + 136 + char *progname; 137 + int c, cnt, fd; 138 + 139 + char *device = DEVICE; 140 + clockid_t clkid; 141 + int adjfreq = 0x7fffffff; 142 + int adjtime = 0; 143 + int capabilities = 0; 144 + int extts = 0; 145 + int gettime = 0; 146 + int oneshot = 0; 147 + int periodic = 0; 148 + int perout = -1; 149 + int pps = -1; 150 + int settime = 0; 151 + 152 + progname = strrchr(argv[0], '/'); 153 + progname = progname ? 1+progname : argv[0]; 154 + while (EOF != (c = getopt(argc, argv, "a:A:cd:e:f:ghp:P:sSt:v"))) { 155 + switch (c) { 156 + case 'a': 157 + oneshot = atoi(optarg); 158 + break; 159 + case 'A': 160 + periodic = atoi(optarg); 161 + break; 162 + case 'c': 163 + capabilities = 1; 164 + break; 165 + case 'd': 166 + device = optarg; 167 + break; 168 + case 'e': 169 + extts = atoi(optarg); 170 + break; 171 + case 'f': 172 + adjfreq = atoi(optarg); 173 + break; 174 + case 'g': 175 + gettime = 1; 176 + break; 177 + case 'p': 178 + perout = atoi(optarg); 179 + break; 180 + case 'P': 181 + pps = atoi(optarg); 182 + break; 183 + case 's': 184 + settime = 1; 185 + break; 186 + case 'S': 187 + settime = 2; 188 + break; 189 + case 't': 190 + adjtime = atoi(optarg); 191 + break; 192 + case 'h': 193 + usage(progname); 194 + return 0; 195 + case '?': 196 + default: 197 + usage(progname); 198 + return -1; 199 + } 200 + } 201 + 202 + fd = open(device, O_RDWR); 203 + if (fd < 0) { 204 + fprintf(stderr, "opening %s: %s\n", device, strerror(errno)); 205 + return -1; 206 + } 207 + 208 + clkid = get_clockid(fd); 209 + if (CLOCK_INVALID == clkid) { 210 + fprintf(stderr, "failed to read clock id\n"); 211 + return -1; 212 + } 213 + 214 + if (capabilities) { 215 + if (ioctl(fd, PTP_CLOCK_GETCAPS, &caps)) { 216 + perror("PTP_CLOCK_GETCAPS"); 217 + } else { 218 + printf("capabilities:\n" 219 + " %d maximum frequency adjustment (ppb)\n" 220 + " %d programmable alarms\n" 221 + " %d external time stamp channels\n" 222 + " %d programmable periodic signals\n" 223 + " %d pulse per second\n", 224 + caps.max_adj, 225 + caps.n_alarm, 226 + caps.n_ext_ts, 227 + caps.n_per_out, 228 + caps.pps); 229 + } 230 + } 231 + 232 + if (0x7fffffff != adjfreq) { 233 + memset(&tx, 0, sizeof(tx)); 234 + tx.modes = ADJ_FREQUENCY; 235 + tx.freq = ppb_to_scaled_ppm(adjfreq); 236 + if (clock_adjtime(clkid, &tx)) { 237 + perror("clock_adjtime"); 238 + } else { 239 + puts("frequency adjustment okay"); 240 + } 241 + } 242 + 243 + if (adjtime) { 244 + memset(&tx, 0, sizeof(tx)); 245 + tx.modes = ADJ_SETOFFSET; 246 + tx.time.tv_sec = adjtime; 247 + tx.time.tv_usec = 0; 248 + if (clock_adjtime(clkid, &tx) < 0) { 249 + perror("clock_adjtime"); 250 + } else { 251 + puts("time shift okay"); 252 + } 253 + } 254 + 255 + if (gettime) { 256 + if (clock_gettime(clkid, &ts)) { 257 + perror("clock_gettime"); 258 + } else { 259 + printf("clock time: %ld.%09ld or %s", 260 + ts.tv_sec, ts.tv_nsec, ctime(&ts.tv_sec)); 261 + } 262 + } 263 + 264 + if (settime == 1) { 265 + clock_gettime(CLOCK_REALTIME, &ts); 266 + if (clock_settime(clkid, &ts)) { 267 + perror("clock_settime"); 268 + } else { 269 + puts("set time okay"); 270 + } 271 + } 272 + 273 + if (settime == 2) { 274 + clock_gettime(clkid, &ts); 275 + if (clock_settime(CLOCK_REALTIME, &ts)) { 276 + perror("clock_settime"); 277 + } else { 278 + puts("set time okay"); 279 + } 280 + } 281 + 282 + if (extts) { 283 + memset(&extts_request, 0, sizeof(extts_request)); 284 + extts_request.index = 0; 285 + extts_request.flags = PTP_ENABLE_FEATURE; 286 + if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) { 287 + perror("PTP_EXTTS_REQUEST"); 288 + extts = 0; 289 + } else { 290 + puts("external time stamp request okay"); 291 + } 292 + for (; extts; extts--) { 293 + cnt = read(fd, &event, sizeof(event)); 294 + if (cnt != sizeof(event)) { 295 + perror("read"); 296 + break; 297 + } 298 + printf("event index %u at %lld.%09u\n", event.index, 299 + event.t.sec, event.t.nsec); 300 + fflush(stdout); 301 + } 302 + /* Disable the feature again. */ 303 + extts_request.flags = 0; 304 + if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) { 305 + perror("PTP_EXTTS_REQUEST"); 306 + } 307 + } 308 + 309 + if (oneshot) { 310 + install_handler(SIGALRM, handle_alarm); 311 + /* Create a timer. */ 312 + sigevent.sigev_notify = SIGEV_SIGNAL; 313 + sigevent.sigev_signo = SIGALRM; 314 + if (timer_create(clkid, &sigevent, &timerid)) { 315 + perror("timer_create"); 316 + return -1; 317 + } 318 + /* Start the timer. */ 319 + memset(&timeout, 0, sizeof(timeout)); 320 + timeout.it_value.tv_sec = oneshot; 321 + if (timer_settime(timerid, 0, &timeout, NULL)) { 322 + perror("timer_settime"); 323 + return -1; 324 + } 325 + pause(); 326 + timer_delete(timerid); 327 + } 328 + 329 + if (periodic) { 330 + install_handler(SIGALRM, handle_alarm); 331 + /* Create a timer. */ 332 + sigevent.sigev_notify = SIGEV_SIGNAL; 333 + sigevent.sigev_signo = SIGALRM; 334 + if (timer_create(clkid, &sigevent, &timerid)) { 335 + perror("timer_create"); 336 + return -1; 337 + } 338 + /* Start the timer. */ 339 + memset(&timeout, 0, sizeof(timeout)); 340 + timeout.it_interval.tv_sec = periodic; 341 + timeout.it_value.tv_sec = periodic; 342 + if (timer_settime(timerid, 0, &timeout, NULL)) { 343 + perror("timer_settime"); 344 + return -1; 345 + } 346 + while (1) { 347 + pause(); 348 + } 349 + timer_delete(timerid); 350 + } 351 + 352 + if (perout >= 0) { 353 + if (clock_gettime(clkid, &ts)) { 354 + perror("clock_gettime"); 355 + return -1; 356 + } 357 + memset(&perout_request, 0, sizeof(perout_request)); 358 + perout_request.index = 0; 359 + perout_request.start.sec = ts.tv_sec + 2; 360 + perout_request.start.nsec = 0; 361 + perout_request.period.sec = 0; 362 + perout_request.period.nsec = perout; 363 + if (ioctl(fd, PTP_PEROUT_REQUEST, &perout_request)) { 364 + perror("PTP_PEROUT_REQUEST"); 365 + } else { 366 + puts("periodic output request okay"); 367 + } 368 + } 369 + 370 + if (pps != -1) { 371 + int enable = pps ? 1 : 0; 372 + if (ioctl(fd, PTP_ENABLE_PPS, enable)) { 373 + perror("PTP_ENABLE_PPS"); 374 + } else { 375 + puts("pps for system time request okay"); 376 + } 377 + } 378 + 379 + close(fd); 380 + return 0; 381 + }
+33
Documentation/ptp/testptp.mk
··· 1 + # PTP 1588 clock support - User space test program 2 + # 3 + # Copyright (C) 2010 OMICRON electronics GmbH 4 + # 5 + # This program is free software; you can redistribute it and/or modify 6 + # it under the terms of the GNU General Public License as published by 7 + # the Free Software Foundation; either version 2 of the License, or 8 + # (at your option) any later version. 9 + # 10 + # This program is distributed in the hope that it will be useful, 11 + # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 + # GNU General Public License for more details. 14 + # 15 + # You should have received a copy of the GNU General Public License 16 + # along with this program; if not, write to the Free Software 17 + # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 + 19 + CC = $(CROSS_COMPILE)gcc 20 + INC = -I$(KBUILD_OUTPUT)/usr/include 21 + CFLAGS = -Wall $(INC) 22 + LDLIBS = -lrt 23 + PROGS = testptp 24 + 25 + all: $(PROGS) 26 + 27 + testptp: testptp.o 28 + 29 + clean: 30 + rm -f testptp.o 31 + 32 + distclean: clean 33 + rm -f $(PROGS)
+78
arch/arm/mach-ixp4xx/include/mach/ixp46x_ts.h
··· 1 + /* 2 + * PTP 1588 clock using the IXP46X 3 + * 4 + * Copyright (C) 2010 OMICRON electronics GmbH 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program; if not, write to the Free Software 18 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 + */ 20 + 21 + #ifndef _IXP46X_TS_H_ 22 + #define _IXP46X_TS_H_ 23 + 24 + #define DEFAULT_ADDEND 0xF0000029 25 + #define TICKS_NS_SHIFT 4 26 + 27 + struct ixp46x_channel_ctl { 28 + u32 ch_control; /* 0x40 Time Synchronization Channel Control */ 29 + u32 ch_event; /* 0x44 Time Synchronization Channel Event */ 30 + u32 tx_snap_lo; /* 0x48 Transmit Snapshot Low Register */ 31 + u32 tx_snap_hi; /* 0x4C Transmit Snapshot High Register */ 32 + u32 rx_snap_lo; /* 0x50 Receive Snapshot Low Register */ 33 + u32 rx_snap_hi; /* 0x54 Receive Snapshot High Register */ 34 + u32 src_uuid_lo; /* 0x58 Source UUID0 Low Register */ 35 + u32 src_uuid_hi; /* 0x5C Sequence Identifier/Source UUID0 High */ 36 + }; 37 + 38 + struct ixp46x_ts_regs { 39 + u32 control; /* 0x00 Time Sync Control Register */ 40 + u32 event; /* 0x04 Time Sync Event Register */ 41 + u32 addend; /* 0x08 Time Sync Addend Register */ 42 + u32 accum; /* 0x0C Time Sync Accumulator Register */ 43 + u32 test; /* 0x10 Time Sync Test Register */ 44 + u32 unused; /* 0x14 */ 45 + u32 rsystime_lo; /* 0x18 RawSystemTime_Low Register */ 46 + u32 rsystime_hi; /* 0x1C RawSystemTime_High Register */ 47 + u32 systime_lo; /* 0x20 SystemTime_Low Register */ 48 + u32 systime_hi; /* 0x24 SystemTime_High Register */ 49 + u32 trgt_lo; /* 0x28 TargetTime_Low Register */ 50 + u32 trgt_hi; /* 0x2C TargetTime_High Register */ 51 + u32 asms_lo; /* 0x30 Auxiliary Slave Mode Snapshot Low */ 52 + u32 asms_hi; /* 0x34 Auxiliary Slave Mode Snapshot High */ 53 + u32 amms_lo; /* 0x38 Auxiliary Master Mode Snapshot Low */ 54 + u32 amms_hi; /* 0x3C Auxiliary Master Mode Snapshot High */ 55 + 56 + struct ixp46x_channel_ctl channel[3]; 57 + }; 58 + 59 + /* 0x00 Time Sync Control Register Bits */ 60 + #define TSCR_AMM (1<<3) 61 + #define TSCR_ASM (1<<2) 62 + #define TSCR_TTM (1<<1) 63 + #define TSCR_RST (1<<0) 64 + 65 + /* 0x04 Time Sync Event Register Bits */ 66 + #define TSER_SNM (1<<3) 67 + #define TSER_SNS (1<<2) 68 + #define TTIPEND (1<<1) 69 + 70 + /* 0x40 Time Synchronization Channel Control Register Bits */ 71 + #define MASTER_MODE (1<<0) 72 + #define TIMESTAMP_ALL (1<<1) 73 + 74 + /* 0x44 Time Synchronization Channel Event Register Bits */ 75 + #define TX_SNAPSHOT_LOCKED (1<<0) 76 + #define RX_SNAPSHOT_LOCKED (1<<1) 77 + 78 + #endif
+13
arch/powerpc/boot/dts/mpc8313erdb.dts
··· 176 176 sleep = <&pmc 0x00300000>; 177 177 }; 178 178 179 + ptp_clock@24E00 { 180 + compatible = "fsl,etsec-ptp"; 181 + reg = <0x24E00 0xB0>; 182 + interrupts = <12 0x8 13 0x8>; 183 + interrupt-parent = < &ipic >; 184 + fsl,tclk-period = <10>; 185 + fsl,tmr-prsc = <100>; 186 + fsl,tmr-add = <0x999999A4>; 187 + fsl,tmr-fiper1 = <0x3B9AC9F6>; 188 + fsl,tmr-fiper2 = <0x00018696>; 189 + fsl,max-adj = <659999998>; 190 + }; 191 + 179 192 enet0: ethernet@24000 { 180 193 #address-cells = <1>; 181 194 #size-cells = <1>;
+13
arch/powerpc/boot/dts/mpc8572ds.dts
··· 324 324 }; 325 325 }; 326 326 327 + ptp_clock@24E00 { 328 + compatible = "fsl,etsec-ptp"; 329 + reg = <0x24E00 0xB0>; 330 + interrupts = <68 2 69 2 70 2 71 2>; 331 + interrupt-parent = < &mpic >; 332 + fsl,tclk-period = <5>; 333 + fsl,tmr-prsc = <200>; 334 + fsl,tmr-add = <0xAAAAAAAB>; 335 + fsl,tmr-fiper1 = <0x3B9AC9FB>; 336 + fsl,tmr-fiper2 = <0x3B9AC9FB>; 337 + fsl,max-adj = <499999999>; 338 + }; 339 + 327 340 enet0: ethernet@24000 { 328 341 #address-cells = <1>; 329 342 #size-cells = <1>;
+13
arch/powerpc/boot/dts/p2020ds.dts
··· 178 178 179 179 }; 180 180 181 + ptp_clock@24E00 { 182 + compatible = "fsl,etsec-ptp"; 183 + reg = <0x24E00 0xB0>; 184 + interrupts = <68 2 69 2 70 2>; 185 + interrupt-parent = < &mpic >; 186 + fsl,tclk-period = <5>; 187 + fsl,tmr-prsc = <200>; 188 + fsl,tmr-add = <0xCCCCCCCD>; 189 + fsl,tmr-fiper1 = <0x3B9AC9FB>; 190 + fsl,tmr-fiper2 = <0x0001869B>; 191 + fsl,max-adj = <249999999>; 192 + }; 193 + 181 194 enet0: ethernet@24000 { 182 195 tbi-handle = <&tbi0>; 183 196 phy-handle = <&phy0>;
+13
arch/powerpc/boot/dts/p2020rdb.dts
··· 224 224 status = "disabled"; 225 225 }; 226 226 227 + ptp_clock@24E00 { 228 + compatible = "fsl,etsec-ptp"; 229 + reg = <0x24E00 0xB0>; 230 + interrupts = <68 2 69 2 70 2>; 231 + interrupt-parent = < &mpic >; 232 + fsl,tclk-period = <5>; 233 + fsl,tmr-prsc = <200>; 234 + fsl,tmr-add = <0xCCCCCCCD>; 235 + fsl,tmr-fiper1 = <0x3B9AC9FB>; 236 + fsl,tmr-fiper2 = <0x0001869B>; 237 + fsl,max-adj = <249999999>; 238 + }; 239 + 227 240 enet0: ethernet@24000 { 228 241 fixed-link = <1 1 1000 0 0>; 229 242 phy-connection-type = "rgmii-id";
+2
drivers/Kconfig
··· 54 54 55 55 source "drivers/pps/Kconfig" 56 56 57 + source "drivers/ptp/Kconfig" 58 + 57 59 source "drivers/gpio/Kconfig" 58 60 59 61 source "drivers/w1/Kconfig"
+1
drivers/Makefile
··· 75 75 obj-$(CONFIG_RTC_LIB) += rtc/ 76 76 obj-y += i2c/ media/ 77 77 obj-$(CONFIG_PPS) += pps/ 78 + obj-$(CONFIG_PTP_1588_CLOCK) += ptp/ 78 79 obj-$(CONFIG_W1) += w1/ 79 80 obj-$(CONFIG_POWER_SUPPLY) += power/ 80 81 obj-$(CONFIG_HWMON) += hwmon/
+1
drivers/net/Makefile
··· 31 31 obj-$(CONFIG_ATL1E) += atl1e/ 32 32 obj-$(CONFIG_ATL1C) += atl1c/ 33 33 obj-$(CONFIG_GIANFAR) += gianfar_driver.o 34 + obj-$(CONFIG_PTP_1588_CLOCK_GIANFAR) += gianfar_ptp.o 34 35 obj-$(CONFIG_TEHUTI) += tehuti.o 35 36 obj-$(CONFIG_ENIC) += enic/ 36 37 obj-$(CONFIG_JME) += jme.o
+192 -3
drivers/net/arm/ixp4xx_eth.c
··· 30 30 #include <linux/etherdevice.h> 31 31 #include <linux/io.h> 32 32 #include <linux/kernel.h> 33 + #include <linux/net_tstamp.h> 33 34 #include <linux/phy.h> 34 35 #include <linux/platform_device.h> 36 + #include <linux/ptp_classify.h> 35 37 #include <linux/slab.h> 38 + #include <mach/ixp46x_ts.h> 36 39 #include <mach/npe.h> 37 40 #include <mach/qmgr.h> 38 41 ··· 69 66 #define TX_QUEUE(port_id) (NPE_ID(port_id) + 23) 70 67 #define RXFREE_QUEUE(port_id) (NPE_ID(port_id) + 26) 71 68 #define TXDONE_QUEUE 31 69 + 70 + #define PTP_SLAVE_MODE 1 71 + #define PTP_MASTER_MODE 2 72 + #define PORT2CHANNEL(p) NPE_ID(p->id) 72 73 73 74 /* TX Control Registers */ 74 75 #define TX_CNTRL0_TX_EN 0x01 ··· 178 171 int id; /* logical port ID */ 179 172 int speed, duplex; 180 173 u8 firmware[4]; 174 + int hwts_tx_en; 175 + int hwts_rx_en; 181 176 }; 182 177 183 178 /* NPE message structure */ ··· 255 246 static struct port *npe_port_tab[MAX_NPES]; 256 247 static struct dma_pool *dma_pool; 257 248 249 + static struct sock_filter ptp_filter[] = { 250 + PTP_FILTER 251 + }; 252 + 253 + static int ixp_ptp_match(struct sk_buff *skb, u16 uid_hi, u32 uid_lo, u16 seqid) 254 + { 255 + u8 *data = skb->data; 256 + unsigned int offset; 257 + u16 *hi, *id; 258 + u32 lo; 259 + 260 + if (sk_run_filter(skb, ptp_filter) != PTP_CLASS_V1_IPV4) 261 + return 0; 262 + 263 + offset = ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN; 264 + 265 + if (skb->len < offset + OFF_PTP_SEQUENCE_ID + sizeof(seqid)) 266 + return 0; 267 + 268 + hi = (u16 *)(data + offset + OFF_PTP_SOURCE_UUID); 269 + id = (u16 *)(data + offset + OFF_PTP_SEQUENCE_ID); 270 + 271 + memcpy(&lo, &hi[1], sizeof(lo)); 272 + 273 + return (uid_hi == ntohs(*hi) && 274 + uid_lo == ntohl(lo) && 275 + seqid == ntohs(*id)); 276 + } 277 + 278 + static void ixp_rx_timestamp(struct port *port, struct sk_buff *skb) 279 + { 280 + struct skb_shared_hwtstamps *shhwtstamps; 281 + struct ixp46x_ts_regs *regs; 282 + u64 ns; 283 + u32 ch, hi, lo, val; 284 + u16 uid, seq; 285 + 286 + if (!port->hwts_rx_en) 287 + return; 288 + 289 + ch = PORT2CHANNEL(port); 290 + 291 + regs = (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT; 292 + 293 + val = __raw_readl(&regs->channel[ch].ch_event); 294 + 295 + if (!(val & RX_SNAPSHOT_LOCKED)) 296 + return; 297 + 298 + lo = __raw_readl(&regs->channel[ch].src_uuid_lo); 299 + hi = __raw_readl(&regs->channel[ch].src_uuid_hi); 300 + 301 + uid = hi & 0xffff; 302 + seq = (hi >> 16) & 0xffff; 303 + 304 + if (!ixp_ptp_match(skb, htons(uid), htonl(lo), htons(seq))) 305 + goto out; 306 + 307 + lo = __raw_readl(&regs->channel[ch].rx_snap_lo); 308 + hi = __raw_readl(&regs->channel[ch].rx_snap_hi); 309 + ns = ((u64) hi) << 32; 310 + ns |= lo; 311 + ns <<= TICKS_NS_SHIFT; 312 + 313 + shhwtstamps = skb_hwtstamps(skb); 314 + memset(shhwtstamps, 0, sizeof(*shhwtstamps)); 315 + shhwtstamps->hwtstamp = ns_to_ktime(ns); 316 + out: 317 + __raw_writel(RX_SNAPSHOT_LOCKED, &regs->channel[ch].ch_event); 318 + } 319 + 320 + static void ixp_tx_timestamp(struct port *port, struct sk_buff *skb) 321 + { 322 + struct skb_shared_hwtstamps shhwtstamps; 323 + struct ixp46x_ts_regs *regs; 324 + struct skb_shared_info *shtx; 325 + u64 ns; 326 + u32 ch, cnt, hi, lo, val; 327 + 328 + shtx = skb_shinfo(skb); 329 + if (unlikely(shtx->tx_flags & SKBTX_HW_TSTAMP && port->hwts_tx_en)) 330 + shtx->tx_flags |= SKBTX_IN_PROGRESS; 331 + else 332 + return; 333 + 334 + ch = PORT2CHANNEL(port); 335 + 336 + regs = (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT; 337 + 338 + /* 339 + * This really stinks, but we have to poll for the Tx time stamp. 340 + * Usually, the time stamp is ready after 4 to 6 microseconds. 341 + */ 342 + for (cnt = 0; cnt < 100; cnt++) { 343 + val = __raw_readl(&regs->channel[ch].ch_event); 344 + if (val & TX_SNAPSHOT_LOCKED) 345 + break; 346 + udelay(1); 347 + } 348 + if (!(val & TX_SNAPSHOT_LOCKED)) { 349 + shtx->tx_flags &= ~SKBTX_IN_PROGRESS; 350 + return; 351 + } 352 + 353 + lo = __raw_readl(&regs->channel[ch].tx_snap_lo); 354 + hi = __raw_readl(&regs->channel[ch].tx_snap_hi); 355 + ns = ((u64) hi) << 32; 356 + ns |= lo; 357 + ns <<= TICKS_NS_SHIFT; 358 + 359 + memset(&shhwtstamps, 0, sizeof(shhwtstamps)); 360 + shhwtstamps.hwtstamp = ns_to_ktime(ns); 361 + skb_tstamp_tx(skb, &shhwtstamps); 362 + 363 + __raw_writel(TX_SNAPSHOT_LOCKED, &regs->channel[ch].ch_event); 364 + } 365 + 366 + static int hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) 367 + { 368 + struct hwtstamp_config cfg; 369 + struct ixp46x_ts_regs *regs; 370 + struct port *port = netdev_priv(netdev); 371 + int ch; 372 + 373 + if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg))) 374 + return -EFAULT; 375 + 376 + if (cfg.flags) /* reserved for future extensions */ 377 + return -EINVAL; 378 + 379 + ch = PORT2CHANNEL(port); 380 + regs = (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT; 381 + 382 + switch (cfg.tx_type) { 383 + case HWTSTAMP_TX_OFF: 384 + port->hwts_tx_en = 0; 385 + break; 386 + case HWTSTAMP_TX_ON: 387 + port->hwts_tx_en = 1; 388 + break; 389 + default: 390 + return -ERANGE; 391 + } 392 + 393 + switch (cfg.rx_filter) { 394 + case HWTSTAMP_FILTER_NONE: 395 + port->hwts_rx_en = 0; 396 + break; 397 + case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: 398 + port->hwts_rx_en = PTP_SLAVE_MODE; 399 + __raw_writel(0, &regs->channel[ch].ch_control); 400 + break; 401 + case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: 402 + port->hwts_rx_en = PTP_MASTER_MODE; 403 + __raw_writel(MASTER_MODE, &regs->channel[ch].ch_control); 404 + break; 405 + default: 406 + return -ERANGE; 407 + } 408 + 409 + /* Clear out any old time stamps. */ 410 + __raw_writel(TX_SNAPSHOT_LOCKED | RX_SNAPSHOT_LOCKED, 411 + &regs->channel[ch].ch_event); 412 + 413 + return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; 414 + } 258 415 259 416 static int ixp4xx_mdio_cmd(struct mii_bus *bus, int phy_id, int location, 260 417 int write, u16 cmd) ··· 748 573 749 574 debug_pkt(dev, "eth_poll", skb->data, skb->len); 750 575 576 + ixp_rx_timestamp(port, skb); 751 577 skb->protocol = eth_type_trans(skb, dev); 752 578 dev->stats.rx_packets++; 753 579 dev->stats.rx_bytes += skb->len; ··· 855 679 return NETDEV_TX_OK; 856 680 } 857 681 memcpy_swab32(mem, (u32 *)((int)skb->data & ~3), bytes / 4); 858 - dev_kfree_skb(skb); 859 682 #endif 860 683 861 684 phys = dma_map_single(&dev->dev, mem, bytes, DMA_TO_DEVICE); 862 685 if (dma_mapping_error(&dev->dev, phys)) { 863 - #ifdef __ARMEB__ 864 686 dev_kfree_skb(skb); 865 - #else 687 + #ifndef __ARMEB__ 866 688 kfree(mem); 867 689 #endif 868 690 dev->stats.tx_dropped++; ··· 901 727 902 728 #if DEBUG_TX 903 729 printk(KERN_DEBUG "%s: eth_xmit end\n", dev->name); 730 + #endif 731 + 732 + ixp_tx_timestamp(port, skb); 733 + skb_tx_timestamp(skb); 734 + 735 + #ifndef __ARMEB__ 736 + dev_kfree_skb(skb); 904 737 #endif 905 738 return NETDEV_TX_OK; 906 739 } ··· 963 782 964 783 if (!netif_running(dev)) 965 784 return -EINVAL; 785 + 786 + if (cpu_is_ixp46x() && cmd == SIOCSHWTSTAMP) 787 + return hwtstamp_ioctl(dev, req, cmd); 966 788 967 789 return phy_mii_ioctl(port->phydev, req, cmd); 968 790 } ··· 1354 1170 u32 regs_phys; 1355 1171 char phy_id[MII_BUS_ID_SIZE + 3]; 1356 1172 int err; 1173 + 1174 + if (ptp_filter_init(ptp_filter, ARRAY_SIZE(ptp_filter))) { 1175 + pr_err("ixp4xx_eth: bad ptp filter\n"); 1176 + return -EINVAL; 1177 + } 1357 1178 1358 1179 if (!(dev = alloc_etherdev(sizeof(struct port)))) 1359 1180 return -ENOMEM;
+588
drivers/net/gianfar_ptp.c
··· 1 + /* 2 + * PTP 1588 clock using the eTSEC 3 + * 4 + * Copyright (C) 2010 OMICRON electronics GmbH 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program; if not, write to the Free Software 18 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 + */ 20 + #include <linux/device.h> 21 + #include <linux/hrtimer.h> 22 + #include <linux/init.h> 23 + #include <linux/interrupt.h> 24 + #include <linux/kernel.h> 25 + #include <linux/module.h> 26 + #include <linux/of.h> 27 + #include <linux/of_platform.h> 28 + #include <linux/timex.h> 29 + #include <linux/io.h> 30 + 31 + #include <linux/ptp_clock_kernel.h> 32 + 33 + #include "gianfar.h" 34 + 35 + /* 36 + * gianfar ptp registers 37 + * Generated by regen.tcl on Thu May 13 01:38:57 PM CEST 2010 38 + */ 39 + struct gianfar_ptp_registers { 40 + u32 tmr_ctrl; /* Timer control register */ 41 + u32 tmr_tevent; /* Timestamp event register */ 42 + u32 tmr_temask; /* Timer event mask register */ 43 + u32 tmr_pevent; /* Timestamp event register */ 44 + u32 tmr_pemask; /* Timer event mask register */ 45 + u32 tmr_stat; /* Timestamp status register */ 46 + u32 tmr_cnt_h; /* Timer counter high register */ 47 + u32 tmr_cnt_l; /* Timer counter low register */ 48 + u32 tmr_add; /* Timer drift compensation addend register */ 49 + u32 tmr_acc; /* Timer accumulator register */ 50 + u32 tmr_prsc; /* Timer prescale */ 51 + u8 res1[4]; 52 + u32 tmroff_h; /* Timer offset high */ 53 + u32 tmroff_l; /* Timer offset low */ 54 + u8 res2[8]; 55 + u32 tmr_alarm1_h; /* Timer alarm 1 high register */ 56 + u32 tmr_alarm1_l; /* Timer alarm 1 high register */ 57 + u32 tmr_alarm2_h; /* Timer alarm 2 high register */ 58 + u32 tmr_alarm2_l; /* Timer alarm 2 high register */ 59 + u8 res3[48]; 60 + u32 tmr_fiper1; /* Timer fixed period interval */ 61 + u32 tmr_fiper2; /* Timer fixed period interval */ 62 + u32 tmr_fiper3; /* Timer fixed period interval */ 63 + u8 res4[20]; 64 + u32 tmr_etts1_h; /* Timestamp of general purpose external trigger */ 65 + u32 tmr_etts1_l; /* Timestamp of general purpose external trigger */ 66 + u32 tmr_etts2_h; /* Timestamp of general purpose external trigger */ 67 + u32 tmr_etts2_l; /* Timestamp of general purpose external trigger */ 68 + }; 69 + 70 + /* Bit definitions for the TMR_CTRL register */ 71 + #define ALM1P (1<<31) /* Alarm1 output polarity */ 72 + #define ALM2P (1<<30) /* Alarm2 output polarity */ 73 + #define FS (1<<28) /* FIPER start indication */ 74 + #define PP1L (1<<27) /* Fiper1 pulse loopback mode enabled. */ 75 + #define PP2L (1<<26) /* Fiper2 pulse loopback mode enabled. */ 76 + #define TCLK_PERIOD_SHIFT (16) /* 1588 timer reference clock period. */ 77 + #define TCLK_PERIOD_MASK (0x3ff) 78 + #define RTPE (1<<15) /* Record Tx Timestamp to PAL Enable. */ 79 + #define FRD (1<<14) /* FIPER Realignment Disable */ 80 + #define ESFDP (1<<11) /* External Tx/Rx SFD Polarity. */ 81 + #define ESFDE (1<<10) /* External Tx/Rx SFD Enable. */ 82 + #define ETEP2 (1<<9) /* External trigger 2 edge polarity */ 83 + #define ETEP1 (1<<8) /* External trigger 1 edge polarity */ 84 + #define COPH (1<<7) /* Generated clock output phase. */ 85 + #define CIPH (1<<6) /* External oscillator input clock phase */ 86 + #define TMSR (1<<5) /* Timer soft reset. */ 87 + #define BYP (1<<3) /* Bypass drift compensated clock */ 88 + #define TE (1<<2) /* 1588 timer enable. */ 89 + #define CKSEL_SHIFT (0) /* 1588 Timer reference clock source */ 90 + #define CKSEL_MASK (0x3) 91 + 92 + /* Bit definitions for the TMR_TEVENT register */ 93 + #define ETS2 (1<<25) /* External trigger 2 timestamp sampled */ 94 + #define ETS1 (1<<24) /* External trigger 1 timestamp sampled */ 95 + #define ALM2 (1<<17) /* Current time = alarm time register 2 */ 96 + #define ALM1 (1<<16) /* Current time = alarm time register 1 */ 97 + #define PP1 (1<<7) /* periodic pulse generated on FIPER1 */ 98 + #define PP2 (1<<6) /* periodic pulse generated on FIPER2 */ 99 + #define PP3 (1<<5) /* periodic pulse generated on FIPER3 */ 100 + 101 + /* Bit definitions for the TMR_TEMASK register */ 102 + #define ETS2EN (1<<25) /* External trigger 2 timestamp enable */ 103 + #define ETS1EN (1<<24) /* External trigger 1 timestamp enable */ 104 + #define ALM2EN (1<<17) /* Timer ALM2 event enable */ 105 + #define ALM1EN (1<<16) /* Timer ALM1 event enable */ 106 + #define PP1EN (1<<7) /* Periodic pulse event 1 enable */ 107 + #define PP2EN (1<<6) /* Periodic pulse event 2 enable */ 108 + 109 + /* Bit definitions for the TMR_PEVENT register */ 110 + #define TXP2 (1<<9) /* PTP transmitted timestamp im TXTS2 */ 111 + #define TXP1 (1<<8) /* PTP transmitted timestamp in TXTS1 */ 112 + #define RXP (1<<0) /* PTP frame has been received */ 113 + 114 + /* Bit definitions for the TMR_PEMASK register */ 115 + #define TXP2EN (1<<9) /* Transmit PTP packet event 2 enable */ 116 + #define TXP1EN (1<<8) /* Transmit PTP packet event 1 enable */ 117 + #define RXPEN (1<<0) /* Receive PTP packet event enable */ 118 + 119 + /* Bit definitions for the TMR_STAT register */ 120 + #define STAT_VEC_SHIFT (0) /* Timer general purpose status vector */ 121 + #define STAT_VEC_MASK (0x3f) 122 + 123 + /* Bit definitions for the TMR_PRSC register */ 124 + #define PRSC_OCK_SHIFT (0) /* Output clock division/prescale factor. */ 125 + #define PRSC_OCK_MASK (0xffff) 126 + 127 + 128 + #define DRIVER "gianfar_ptp" 129 + #define DEFAULT_CKSEL 1 130 + #define N_ALARM 1 /* first alarm is used internally to reset fipers */ 131 + #define N_EXT_TS 2 132 + #define REG_SIZE sizeof(struct gianfar_ptp_registers) 133 + 134 + struct etsects { 135 + struct gianfar_ptp_registers *regs; 136 + spinlock_t lock; /* protects regs */ 137 + struct ptp_clock *clock; 138 + struct ptp_clock_info caps; 139 + struct resource *rsrc; 140 + int irq; 141 + u64 alarm_interval; /* for periodic alarm */ 142 + u64 alarm_value; 143 + u32 tclk_period; /* nanoseconds */ 144 + u32 tmr_prsc; 145 + u32 tmr_add; 146 + u32 cksel; 147 + u32 tmr_fiper1; 148 + u32 tmr_fiper2; 149 + }; 150 + 151 + /* 152 + * Register access functions 153 + */ 154 + 155 + /* Caller must hold etsects->lock. */ 156 + static u64 tmr_cnt_read(struct etsects *etsects) 157 + { 158 + u64 ns; 159 + u32 lo, hi; 160 + 161 + lo = gfar_read(&etsects->regs->tmr_cnt_l); 162 + hi = gfar_read(&etsects->regs->tmr_cnt_h); 163 + ns = ((u64) hi) << 32; 164 + ns |= lo; 165 + return ns; 166 + } 167 + 168 + /* Caller must hold etsects->lock. */ 169 + static void tmr_cnt_write(struct etsects *etsects, u64 ns) 170 + { 171 + u32 hi = ns >> 32; 172 + u32 lo = ns & 0xffffffff; 173 + 174 + gfar_write(&etsects->regs->tmr_cnt_l, lo); 175 + gfar_write(&etsects->regs->tmr_cnt_h, hi); 176 + } 177 + 178 + /* Caller must hold etsects->lock. */ 179 + static void set_alarm(struct etsects *etsects) 180 + { 181 + u64 ns; 182 + u32 lo, hi; 183 + 184 + ns = tmr_cnt_read(etsects) + 1500000000ULL; 185 + ns = div_u64(ns, 1000000000UL) * 1000000000ULL; 186 + ns -= etsects->tclk_period; 187 + hi = ns >> 32; 188 + lo = ns & 0xffffffff; 189 + gfar_write(&etsects->regs->tmr_alarm1_l, lo); 190 + gfar_write(&etsects->regs->tmr_alarm1_h, hi); 191 + } 192 + 193 + /* Caller must hold etsects->lock. */ 194 + static void set_fipers(struct etsects *etsects) 195 + { 196 + u32 tmr_ctrl = gfar_read(&etsects->regs->tmr_ctrl); 197 + 198 + gfar_write(&etsects->regs->tmr_ctrl, tmr_ctrl & (~TE)); 199 + gfar_write(&etsects->regs->tmr_prsc, etsects->tmr_prsc); 200 + gfar_write(&etsects->regs->tmr_fiper1, etsects->tmr_fiper1); 201 + gfar_write(&etsects->regs->tmr_fiper2, etsects->tmr_fiper2); 202 + set_alarm(etsects); 203 + gfar_write(&etsects->regs->tmr_ctrl, tmr_ctrl|TE); 204 + } 205 + 206 + /* 207 + * Interrupt service routine 208 + */ 209 + 210 + static irqreturn_t isr(int irq, void *priv) 211 + { 212 + struct etsects *etsects = priv; 213 + struct ptp_clock_event event; 214 + u64 ns; 215 + u32 ack = 0, lo, hi, mask, val; 216 + 217 + val = gfar_read(&etsects->regs->tmr_tevent); 218 + 219 + if (val & ETS1) { 220 + ack |= ETS1; 221 + hi = gfar_read(&etsects->regs->tmr_etts1_h); 222 + lo = gfar_read(&etsects->regs->tmr_etts1_l); 223 + event.type = PTP_CLOCK_EXTTS; 224 + event.index = 0; 225 + event.timestamp = ((u64) hi) << 32; 226 + event.timestamp |= lo; 227 + ptp_clock_event(etsects->clock, &event); 228 + } 229 + 230 + if (val & ETS2) { 231 + ack |= ETS2; 232 + hi = gfar_read(&etsects->regs->tmr_etts2_h); 233 + lo = gfar_read(&etsects->regs->tmr_etts2_l); 234 + event.type = PTP_CLOCK_EXTTS; 235 + event.index = 1; 236 + event.timestamp = ((u64) hi) << 32; 237 + event.timestamp |= lo; 238 + ptp_clock_event(etsects->clock, &event); 239 + } 240 + 241 + if (val & ALM2) { 242 + ack |= ALM2; 243 + if (etsects->alarm_value) { 244 + event.type = PTP_CLOCK_ALARM; 245 + event.index = 0; 246 + event.timestamp = etsects->alarm_value; 247 + ptp_clock_event(etsects->clock, &event); 248 + } 249 + if (etsects->alarm_interval) { 250 + ns = etsects->alarm_value + etsects->alarm_interval; 251 + hi = ns >> 32; 252 + lo = ns & 0xffffffff; 253 + spin_lock(&etsects->lock); 254 + gfar_write(&etsects->regs->tmr_alarm2_l, lo); 255 + gfar_write(&etsects->regs->tmr_alarm2_h, hi); 256 + spin_unlock(&etsects->lock); 257 + etsects->alarm_value = ns; 258 + } else { 259 + gfar_write(&etsects->regs->tmr_tevent, ALM2); 260 + spin_lock(&etsects->lock); 261 + mask = gfar_read(&etsects->regs->tmr_temask); 262 + mask &= ~ALM2EN; 263 + gfar_write(&etsects->regs->tmr_temask, mask); 264 + spin_unlock(&etsects->lock); 265 + etsects->alarm_value = 0; 266 + etsects->alarm_interval = 0; 267 + } 268 + } 269 + 270 + if (val & PP1) { 271 + ack |= PP1; 272 + event.type = PTP_CLOCK_PPS; 273 + ptp_clock_event(etsects->clock, &event); 274 + } 275 + 276 + if (ack) { 277 + gfar_write(&etsects->regs->tmr_tevent, ack); 278 + return IRQ_HANDLED; 279 + } else 280 + return IRQ_NONE; 281 + } 282 + 283 + /* 284 + * PTP clock operations 285 + */ 286 + 287 + static int ptp_gianfar_adjfreq(struct ptp_clock_info *ptp, s32 ppb) 288 + { 289 + u64 adj; 290 + u32 diff, tmr_add; 291 + int neg_adj = 0; 292 + struct etsects *etsects = container_of(ptp, struct etsects, caps); 293 + 294 + if (ppb < 0) { 295 + neg_adj = 1; 296 + ppb = -ppb; 297 + } 298 + tmr_add = etsects->tmr_add; 299 + adj = tmr_add; 300 + adj *= ppb; 301 + diff = div_u64(adj, 1000000000ULL); 302 + 303 + tmr_add = neg_adj ? tmr_add - diff : tmr_add + diff; 304 + 305 + gfar_write(&etsects->regs->tmr_add, tmr_add); 306 + 307 + return 0; 308 + } 309 + 310 + static int ptp_gianfar_adjtime(struct ptp_clock_info *ptp, s64 delta) 311 + { 312 + s64 now; 313 + unsigned long flags; 314 + struct etsects *etsects = container_of(ptp, struct etsects, caps); 315 + 316 + spin_lock_irqsave(&etsects->lock, flags); 317 + 318 + now = tmr_cnt_read(etsects); 319 + now += delta; 320 + tmr_cnt_write(etsects, now); 321 + 322 + spin_unlock_irqrestore(&etsects->lock, flags); 323 + 324 + set_fipers(etsects); 325 + 326 + return 0; 327 + } 328 + 329 + static int ptp_gianfar_gettime(struct ptp_clock_info *ptp, struct timespec *ts) 330 + { 331 + u64 ns; 332 + u32 remainder; 333 + unsigned long flags; 334 + struct etsects *etsects = container_of(ptp, struct etsects, caps); 335 + 336 + spin_lock_irqsave(&etsects->lock, flags); 337 + 338 + ns = tmr_cnt_read(etsects); 339 + 340 + spin_unlock_irqrestore(&etsects->lock, flags); 341 + 342 + ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder); 343 + ts->tv_nsec = remainder; 344 + return 0; 345 + } 346 + 347 + static int ptp_gianfar_settime(struct ptp_clock_info *ptp, 348 + const struct timespec *ts) 349 + { 350 + u64 ns; 351 + unsigned long flags; 352 + struct etsects *etsects = container_of(ptp, struct etsects, caps); 353 + 354 + ns = ts->tv_sec * 1000000000ULL; 355 + ns += ts->tv_nsec; 356 + 357 + spin_lock_irqsave(&etsects->lock, flags); 358 + 359 + tmr_cnt_write(etsects, ns); 360 + set_fipers(etsects); 361 + 362 + spin_unlock_irqrestore(&etsects->lock, flags); 363 + 364 + return 0; 365 + } 366 + 367 + static int ptp_gianfar_enable(struct ptp_clock_info *ptp, 368 + struct ptp_clock_request *rq, int on) 369 + { 370 + struct etsects *etsects = container_of(ptp, struct etsects, caps); 371 + unsigned long flags; 372 + u32 bit, mask; 373 + 374 + switch (rq->type) { 375 + case PTP_CLK_REQ_EXTTS: 376 + switch (rq->extts.index) { 377 + case 0: 378 + bit = ETS1EN; 379 + break; 380 + case 1: 381 + bit = ETS2EN; 382 + break; 383 + default: 384 + return -EINVAL; 385 + } 386 + spin_lock_irqsave(&etsects->lock, flags); 387 + mask = gfar_read(&etsects->regs->tmr_temask); 388 + if (on) 389 + mask |= bit; 390 + else 391 + mask &= ~bit; 392 + gfar_write(&etsects->regs->tmr_temask, mask); 393 + spin_unlock_irqrestore(&etsects->lock, flags); 394 + return 0; 395 + 396 + case PTP_CLK_REQ_PPS: 397 + spin_lock_irqsave(&etsects->lock, flags); 398 + mask = gfar_read(&etsects->regs->tmr_temask); 399 + if (on) 400 + mask |= PP1EN; 401 + else 402 + mask &= ~PP1EN; 403 + gfar_write(&etsects->regs->tmr_temask, mask); 404 + spin_unlock_irqrestore(&etsects->lock, flags); 405 + return 0; 406 + 407 + default: 408 + break; 409 + } 410 + 411 + return -EOPNOTSUPP; 412 + } 413 + 414 + static struct ptp_clock_info ptp_gianfar_caps = { 415 + .owner = THIS_MODULE, 416 + .name = "gianfar clock", 417 + .max_adj = 512000, 418 + .n_alarm = N_ALARM, 419 + .n_ext_ts = N_EXT_TS, 420 + .n_per_out = 0, 421 + .pps = 1, 422 + .adjfreq = ptp_gianfar_adjfreq, 423 + .adjtime = ptp_gianfar_adjtime, 424 + .gettime = ptp_gianfar_gettime, 425 + .settime = ptp_gianfar_settime, 426 + .enable = ptp_gianfar_enable, 427 + }; 428 + 429 + /* OF device tree */ 430 + 431 + static int get_of_u32(struct device_node *node, char *str, u32 *val) 432 + { 433 + int plen; 434 + const u32 *prop = of_get_property(node, str, &plen); 435 + 436 + if (!prop || plen != sizeof(*prop)) 437 + return -1; 438 + *val = *prop; 439 + return 0; 440 + } 441 + 442 + static int gianfar_ptp_probe(struct platform_device *dev) 443 + { 444 + struct device_node *node = dev->dev.of_node; 445 + struct etsects *etsects; 446 + struct timespec now; 447 + int err = -ENOMEM; 448 + u32 tmr_ctrl; 449 + unsigned long flags; 450 + 451 + etsects = kzalloc(sizeof(*etsects), GFP_KERNEL); 452 + if (!etsects) 453 + goto no_memory; 454 + 455 + err = -ENODEV; 456 + 457 + etsects->caps = ptp_gianfar_caps; 458 + etsects->cksel = DEFAULT_CKSEL; 459 + 460 + if (get_of_u32(node, "fsl,tclk-period", &etsects->tclk_period) || 461 + get_of_u32(node, "fsl,tmr-prsc", &etsects->tmr_prsc) || 462 + get_of_u32(node, "fsl,tmr-add", &etsects->tmr_add) || 463 + get_of_u32(node, "fsl,tmr-fiper1", &etsects->tmr_fiper1) || 464 + get_of_u32(node, "fsl,tmr-fiper2", &etsects->tmr_fiper2) || 465 + get_of_u32(node, "fsl,max-adj", &etsects->caps.max_adj)) { 466 + pr_err("device tree node missing required elements\n"); 467 + goto no_node; 468 + } 469 + 470 + etsects->irq = platform_get_irq(dev, 0); 471 + 472 + if (etsects->irq == NO_IRQ) { 473 + pr_err("irq not in device tree\n"); 474 + goto no_node; 475 + } 476 + if (request_irq(etsects->irq, isr, 0, DRIVER, etsects)) { 477 + pr_err("request_irq failed\n"); 478 + goto no_node; 479 + } 480 + 481 + etsects->rsrc = platform_get_resource(dev, IORESOURCE_MEM, 0); 482 + if (!etsects->rsrc) { 483 + pr_err("no resource\n"); 484 + goto no_resource; 485 + } 486 + if (request_resource(&ioport_resource, etsects->rsrc)) { 487 + pr_err("resource busy\n"); 488 + goto no_resource; 489 + } 490 + 491 + spin_lock_init(&etsects->lock); 492 + 493 + etsects->regs = ioremap(etsects->rsrc->start, 494 + 1 + etsects->rsrc->end - etsects->rsrc->start); 495 + if (!etsects->regs) { 496 + pr_err("ioremap ptp registers failed\n"); 497 + goto no_ioremap; 498 + } 499 + getnstimeofday(&now); 500 + ptp_gianfar_settime(&etsects->caps, &now); 501 + 502 + tmr_ctrl = 503 + (etsects->tclk_period & TCLK_PERIOD_MASK) << TCLK_PERIOD_SHIFT | 504 + (etsects->cksel & CKSEL_MASK) << CKSEL_SHIFT; 505 + 506 + spin_lock_irqsave(&etsects->lock, flags); 507 + 508 + gfar_write(&etsects->regs->tmr_ctrl, tmr_ctrl); 509 + gfar_write(&etsects->regs->tmr_add, etsects->tmr_add); 510 + gfar_write(&etsects->regs->tmr_prsc, etsects->tmr_prsc); 511 + gfar_write(&etsects->regs->tmr_fiper1, etsects->tmr_fiper1); 512 + gfar_write(&etsects->regs->tmr_fiper2, etsects->tmr_fiper2); 513 + set_alarm(etsects); 514 + gfar_write(&etsects->regs->tmr_ctrl, tmr_ctrl|FS|RTPE|TE); 515 + 516 + spin_unlock_irqrestore(&etsects->lock, flags); 517 + 518 + etsects->clock = ptp_clock_register(&etsects->caps); 519 + if (IS_ERR(etsects->clock)) { 520 + err = PTR_ERR(etsects->clock); 521 + goto no_clock; 522 + } 523 + 524 + dev_set_drvdata(&dev->dev, etsects); 525 + 526 + return 0; 527 + 528 + no_clock: 529 + no_ioremap: 530 + release_resource(etsects->rsrc); 531 + no_resource: 532 + free_irq(etsects->irq, etsects); 533 + no_node: 534 + kfree(etsects); 535 + no_memory: 536 + return err; 537 + } 538 + 539 + static int gianfar_ptp_remove(struct platform_device *dev) 540 + { 541 + struct etsects *etsects = dev_get_drvdata(&dev->dev); 542 + 543 + gfar_write(&etsects->regs->tmr_temask, 0); 544 + gfar_write(&etsects->regs->tmr_ctrl, 0); 545 + 546 + ptp_clock_unregister(etsects->clock); 547 + iounmap(etsects->regs); 548 + release_resource(etsects->rsrc); 549 + free_irq(etsects->irq, etsects); 550 + kfree(etsects); 551 + 552 + return 0; 553 + } 554 + 555 + static struct of_device_id match_table[] = { 556 + { .compatible = "fsl,etsec-ptp" }, 557 + {}, 558 + }; 559 + 560 + static struct platform_driver gianfar_ptp_driver = { 561 + .driver = { 562 + .name = "gianfar_ptp", 563 + .of_match_table = match_table, 564 + .owner = THIS_MODULE, 565 + }, 566 + .probe = gianfar_ptp_probe, 567 + .remove = gianfar_ptp_remove, 568 + }; 569 + 570 + /* module operations */ 571 + 572 + static int __init ptp_gianfar_init(void) 573 + { 574 + return platform_driver_register(&gianfar_ptp_driver); 575 + } 576 + 577 + module_init(ptp_gianfar_init); 578 + 579 + static void __exit ptp_gianfar_exit(void) 580 + { 581 + platform_driver_unregister(&gianfar_ptp_driver); 582 + } 583 + 584 + module_exit(ptp_gianfar_exit); 585 + 586 + MODULE_AUTHOR("Richard Cochran <richard.cochran@omicron.at>"); 587 + MODULE_DESCRIPTION("PTP clock using the eTSEC"); 588 + MODULE_LICENSE("GPL");
+1
drivers/net/phy/Makefile
··· 19 19 obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o 20 20 obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o 21 21 obj-$(CONFIG_NATIONAL_PHY) += national.o 22 + obj-$(CONFIG_DP83640_PHY) += dp83640.o 22 23 obj-$(CONFIG_STE10XP) += ste10Xp.o 23 24 obj-$(CONFIG_MICREL_PHY) += micrel.o 24 25 obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o
+1100
drivers/net/phy/dp83640.c
··· 1 + /* 2 + * Driver for the National Semiconductor DP83640 PHYTER 3 + * 4 + * Copyright (C) 2010 OMICRON electronics GmbH 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program; if not, write to the Free Software 18 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 + */ 20 + #include <linux/ethtool.h> 21 + #include <linux/kernel.h> 22 + #include <linux/list.h> 23 + #include <linux/mii.h> 24 + #include <linux/module.h> 25 + #include <linux/net_tstamp.h> 26 + #include <linux/netdevice.h> 27 + #include <linux/phy.h> 28 + #include <linux/ptp_classify.h> 29 + #include <linux/ptp_clock_kernel.h> 30 + 31 + #include "dp83640_reg.h" 32 + 33 + #define DP83640_PHY_ID 0x20005ce1 34 + #define PAGESEL 0x13 35 + #define LAYER4 0x02 36 + #define LAYER2 0x01 37 + #define MAX_RXTS 4 38 + #define MAX_TXTS 4 39 + #define N_EXT_TS 1 40 + #define PSF_PTPVER 2 41 + #define PSF_EVNT 0x4000 42 + #define PSF_RX 0x2000 43 + #define PSF_TX 0x1000 44 + #define EXT_EVENT 1 45 + #define EXT_GPIO 1 46 + #define CAL_EVENT 2 47 + #define CAL_GPIO 9 48 + #define CAL_TRIGGER 2 49 + 50 + /* phyter seems to miss the mark by 16 ns */ 51 + #define ADJTIME_FIX 16 52 + 53 + #if defined(__BIG_ENDIAN) 54 + #define ENDIAN_FLAG 0 55 + #elif defined(__LITTLE_ENDIAN) 56 + #define ENDIAN_FLAG PSF_ENDIAN 57 + #endif 58 + 59 + #define SKB_PTP_TYPE(__skb) (*(unsigned int *)((__skb)->cb)) 60 + 61 + struct phy_rxts { 62 + u16 ns_lo; /* ns[15:0] */ 63 + u16 ns_hi; /* overflow[1:0], ns[29:16] */ 64 + u16 sec_lo; /* sec[15:0] */ 65 + u16 sec_hi; /* sec[31:16] */ 66 + u16 seqid; /* sequenceId[15:0] */ 67 + u16 msgtype; /* messageType[3:0], hash[11:0] */ 68 + }; 69 + 70 + struct phy_txts { 71 + u16 ns_lo; /* ns[15:0] */ 72 + u16 ns_hi; /* overflow[1:0], ns[29:16] */ 73 + u16 sec_lo; /* sec[15:0] */ 74 + u16 sec_hi; /* sec[31:16] */ 75 + }; 76 + 77 + struct rxts { 78 + struct list_head list; 79 + unsigned long tmo; 80 + u64 ns; 81 + u16 seqid; 82 + u8 msgtype; 83 + u16 hash; 84 + }; 85 + 86 + struct dp83640_clock; 87 + 88 + struct dp83640_private { 89 + struct list_head list; 90 + struct dp83640_clock *clock; 91 + struct phy_device *phydev; 92 + struct work_struct ts_work; 93 + int hwts_tx_en; 94 + int hwts_rx_en; 95 + int layer; 96 + int version; 97 + /* remember state of cfg0 during calibration */ 98 + int cfg0; 99 + /* remember the last event time stamp */ 100 + struct phy_txts edata; 101 + /* list of rx timestamps */ 102 + struct list_head rxts; 103 + struct list_head rxpool; 104 + struct rxts rx_pool_data[MAX_RXTS]; 105 + /* protects above three fields from concurrent access */ 106 + spinlock_t rx_lock; 107 + /* queues of incoming and outgoing packets */ 108 + struct sk_buff_head rx_queue; 109 + struct sk_buff_head tx_queue; 110 + }; 111 + 112 + struct dp83640_clock { 113 + /* keeps the instance in the 'phyter_clocks' list */ 114 + struct list_head list; 115 + /* we create one clock instance per MII bus */ 116 + struct mii_bus *bus; 117 + /* protects extended registers from concurrent access */ 118 + struct mutex extreg_lock; 119 + /* remembers which page was last selected */ 120 + int page; 121 + /* our advertised capabilities */ 122 + struct ptp_clock_info caps; 123 + /* protects the three fields below from concurrent access */ 124 + struct mutex clock_lock; 125 + /* the one phyter from which we shall read */ 126 + struct dp83640_private *chosen; 127 + /* list of the other attached phyters, not chosen */ 128 + struct list_head phylist; 129 + /* reference to our PTP hardware clock */ 130 + struct ptp_clock *ptp_clock; 131 + }; 132 + 133 + /* globals */ 134 + 135 + static int chosen_phy = -1; 136 + static ushort cal_gpio = 4; 137 + 138 + module_param(chosen_phy, int, 0444); 139 + module_param(cal_gpio, ushort, 0444); 140 + 141 + MODULE_PARM_DESC(chosen_phy, \ 142 + "The address of the PHY to use for the ancillary clock features"); 143 + MODULE_PARM_DESC(cal_gpio, \ 144 + "Which GPIO line to use for synchronizing multiple PHYs"); 145 + 146 + /* a list of clocks and a mutex to protect it */ 147 + static LIST_HEAD(phyter_clocks); 148 + static DEFINE_MUTEX(phyter_clocks_lock); 149 + 150 + static void rx_timestamp_work(struct work_struct *work); 151 + 152 + /* extended register access functions */ 153 + 154 + #define BROADCAST_ADDR 31 155 + 156 + static inline int broadcast_write(struct mii_bus *bus, u32 regnum, u16 val) 157 + { 158 + return mdiobus_write(bus, BROADCAST_ADDR, regnum, val); 159 + } 160 + 161 + /* Caller must hold extreg_lock. */ 162 + static int ext_read(struct phy_device *phydev, int page, u32 regnum) 163 + { 164 + struct dp83640_private *dp83640 = phydev->priv; 165 + int val; 166 + 167 + if (dp83640->clock->page != page) { 168 + broadcast_write(phydev->bus, PAGESEL, page); 169 + dp83640->clock->page = page; 170 + } 171 + val = phy_read(phydev, regnum); 172 + 173 + return val; 174 + } 175 + 176 + /* Caller must hold extreg_lock. */ 177 + static void ext_write(int broadcast, struct phy_device *phydev, 178 + int page, u32 regnum, u16 val) 179 + { 180 + struct dp83640_private *dp83640 = phydev->priv; 181 + 182 + if (dp83640->clock->page != page) { 183 + broadcast_write(phydev->bus, PAGESEL, page); 184 + dp83640->clock->page = page; 185 + } 186 + if (broadcast) 187 + broadcast_write(phydev->bus, regnum, val); 188 + else 189 + phy_write(phydev, regnum, val); 190 + } 191 + 192 + /* Caller must hold extreg_lock. */ 193 + static int tdr_write(int bc, struct phy_device *dev, 194 + const struct timespec *ts, u16 cmd) 195 + { 196 + ext_write(bc, dev, PAGE4, PTP_TDR, ts->tv_nsec & 0xffff);/* ns[15:0] */ 197 + ext_write(bc, dev, PAGE4, PTP_TDR, ts->tv_nsec >> 16); /* ns[31:16] */ 198 + ext_write(bc, dev, PAGE4, PTP_TDR, ts->tv_sec & 0xffff); /* sec[15:0] */ 199 + ext_write(bc, dev, PAGE4, PTP_TDR, ts->tv_sec >> 16); /* sec[31:16]*/ 200 + 201 + ext_write(bc, dev, PAGE4, PTP_CTL, cmd); 202 + 203 + return 0; 204 + } 205 + 206 + /* convert phy timestamps into driver timestamps */ 207 + 208 + static void phy2rxts(struct phy_rxts *p, struct rxts *rxts) 209 + { 210 + u32 sec; 211 + 212 + sec = p->sec_lo; 213 + sec |= p->sec_hi << 16; 214 + 215 + rxts->ns = p->ns_lo; 216 + rxts->ns |= (p->ns_hi & 0x3fff) << 16; 217 + rxts->ns += ((u64)sec) * 1000000000ULL; 218 + rxts->seqid = p->seqid; 219 + rxts->msgtype = (p->msgtype >> 12) & 0xf; 220 + rxts->hash = p->msgtype & 0x0fff; 221 + rxts->tmo = jiffies + HZ; 222 + } 223 + 224 + static u64 phy2txts(struct phy_txts *p) 225 + { 226 + u64 ns; 227 + u32 sec; 228 + 229 + sec = p->sec_lo; 230 + sec |= p->sec_hi << 16; 231 + 232 + ns = p->ns_lo; 233 + ns |= (p->ns_hi & 0x3fff) << 16; 234 + ns += ((u64)sec) * 1000000000ULL; 235 + 236 + return ns; 237 + } 238 + 239 + /* ptp clock methods */ 240 + 241 + static int ptp_dp83640_adjfreq(struct ptp_clock_info *ptp, s32 ppb) 242 + { 243 + struct dp83640_clock *clock = 244 + container_of(ptp, struct dp83640_clock, caps); 245 + struct phy_device *phydev = clock->chosen->phydev; 246 + u64 rate; 247 + int neg_adj = 0; 248 + u16 hi, lo; 249 + 250 + if (ppb < 0) { 251 + neg_adj = 1; 252 + ppb = -ppb; 253 + } 254 + rate = ppb; 255 + rate <<= 26; 256 + rate = div_u64(rate, 1953125); 257 + 258 + hi = (rate >> 16) & PTP_RATE_HI_MASK; 259 + if (neg_adj) 260 + hi |= PTP_RATE_DIR; 261 + 262 + lo = rate & 0xffff; 263 + 264 + mutex_lock(&clock->extreg_lock); 265 + 266 + ext_write(1, phydev, PAGE4, PTP_RATEH, hi); 267 + ext_write(1, phydev, PAGE4, PTP_RATEL, lo); 268 + 269 + mutex_unlock(&clock->extreg_lock); 270 + 271 + return 0; 272 + } 273 + 274 + static int ptp_dp83640_adjtime(struct ptp_clock_info *ptp, s64 delta) 275 + { 276 + struct dp83640_clock *clock = 277 + container_of(ptp, struct dp83640_clock, caps); 278 + struct phy_device *phydev = clock->chosen->phydev; 279 + struct timespec ts; 280 + int err; 281 + 282 + delta += ADJTIME_FIX; 283 + 284 + ts = ns_to_timespec(delta); 285 + 286 + mutex_lock(&clock->extreg_lock); 287 + 288 + err = tdr_write(1, phydev, &ts, PTP_STEP_CLK); 289 + 290 + mutex_unlock(&clock->extreg_lock); 291 + 292 + return err; 293 + } 294 + 295 + static int ptp_dp83640_gettime(struct ptp_clock_info *ptp, struct timespec *ts) 296 + { 297 + struct dp83640_clock *clock = 298 + container_of(ptp, struct dp83640_clock, caps); 299 + struct phy_device *phydev = clock->chosen->phydev; 300 + unsigned int val[4]; 301 + 302 + mutex_lock(&clock->extreg_lock); 303 + 304 + ext_write(0, phydev, PAGE4, PTP_CTL, PTP_RD_CLK); 305 + 306 + val[0] = ext_read(phydev, PAGE4, PTP_TDR); /* ns[15:0] */ 307 + val[1] = ext_read(phydev, PAGE4, PTP_TDR); /* ns[31:16] */ 308 + val[2] = ext_read(phydev, PAGE4, PTP_TDR); /* sec[15:0] */ 309 + val[3] = ext_read(phydev, PAGE4, PTP_TDR); /* sec[31:16] */ 310 + 311 + mutex_unlock(&clock->extreg_lock); 312 + 313 + ts->tv_nsec = val[0] | (val[1] << 16); 314 + ts->tv_sec = val[2] | (val[3] << 16); 315 + 316 + return 0; 317 + } 318 + 319 + static int ptp_dp83640_settime(struct ptp_clock_info *ptp, 320 + const struct timespec *ts) 321 + { 322 + struct dp83640_clock *clock = 323 + container_of(ptp, struct dp83640_clock, caps); 324 + struct phy_device *phydev = clock->chosen->phydev; 325 + int err; 326 + 327 + mutex_lock(&clock->extreg_lock); 328 + 329 + err = tdr_write(1, phydev, ts, PTP_LOAD_CLK); 330 + 331 + mutex_unlock(&clock->extreg_lock); 332 + 333 + return err; 334 + } 335 + 336 + static int ptp_dp83640_enable(struct ptp_clock_info *ptp, 337 + struct ptp_clock_request *rq, int on) 338 + { 339 + struct dp83640_clock *clock = 340 + container_of(ptp, struct dp83640_clock, caps); 341 + struct phy_device *phydev = clock->chosen->phydev; 342 + u16 evnt; 343 + 344 + switch (rq->type) { 345 + case PTP_CLK_REQ_EXTTS: 346 + if (rq->extts.index != 0) 347 + return -EINVAL; 348 + evnt = EVNT_WR | (EXT_EVENT & EVNT_SEL_MASK) << EVNT_SEL_SHIFT; 349 + if (on) { 350 + evnt |= (EXT_GPIO & EVNT_GPIO_MASK) << EVNT_GPIO_SHIFT; 351 + evnt |= EVNT_RISE; 352 + } 353 + ext_write(0, phydev, PAGE5, PTP_EVNT, evnt); 354 + return 0; 355 + default: 356 + break; 357 + } 358 + 359 + return -EOPNOTSUPP; 360 + } 361 + 362 + static u8 status_frame_dst[6] = { 0x01, 0x1B, 0x19, 0x00, 0x00, 0x00 }; 363 + static u8 status_frame_src[6] = { 0x08, 0x00, 0x17, 0x0B, 0x6B, 0x0F }; 364 + 365 + static void enable_status_frames(struct phy_device *phydev, bool on) 366 + { 367 + u16 cfg0 = 0, ver; 368 + 369 + if (on) 370 + cfg0 = PSF_EVNT_EN | PSF_RXTS_EN | PSF_TXTS_EN | ENDIAN_FLAG; 371 + 372 + ver = (PSF_PTPVER & VERSIONPTP_MASK) << VERSIONPTP_SHIFT; 373 + 374 + ext_write(0, phydev, PAGE5, PSF_CFG0, cfg0); 375 + ext_write(0, phydev, PAGE6, PSF_CFG1, ver); 376 + 377 + if (!phydev->attached_dev) { 378 + pr_warning("dp83640: expected to find an attached netdevice\n"); 379 + return; 380 + } 381 + 382 + if (on) { 383 + if (dev_mc_add(phydev->attached_dev, status_frame_dst)) 384 + pr_warning("dp83640: failed to add mc address\n"); 385 + } else { 386 + if (dev_mc_del(phydev->attached_dev, status_frame_dst)) 387 + pr_warning("dp83640: failed to delete mc address\n"); 388 + } 389 + } 390 + 391 + static bool is_status_frame(struct sk_buff *skb, int type) 392 + { 393 + struct ethhdr *h = eth_hdr(skb); 394 + 395 + if (PTP_CLASS_V2_L2 == type && 396 + !memcmp(h->h_source, status_frame_src, sizeof(status_frame_src))) 397 + return true; 398 + else 399 + return false; 400 + } 401 + 402 + static int expired(struct rxts *rxts) 403 + { 404 + return time_after(jiffies, rxts->tmo); 405 + } 406 + 407 + /* Caller must hold rx_lock. */ 408 + static void prune_rx_ts(struct dp83640_private *dp83640) 409 + { 410 + struct list_head *this, *next; 411 + struct rxts *rxts; 412 + 413 + list_for_each_safe(this, next, &dp83640->rxts) { 414 + rxts = list_entry(this, struct rxts, list); 415 + if (expired(rxts)) { 416 + list_del_init(&rxts->list); 417 + list_add(&rxts->list, &dp83640->rxpool); 418 + } 419 + } 420 + } 421 + 422 + /* synchronize the phyters so they act as one clock */ 423 + 424 + static void enable_broadcast(struct phy_device *phydev, int init_page, int on) 425 + { 426 + int val; 427 + phy_write(phydev, PAGESEL, 0); 428 + val = phy_read(phydev, PHYCR2); 429 + if (on) 430 + val |= BC_WRITE; 431 + else 432 + val &= ~BC_WRITE; 433 + phy_write(phydev, PHYCR2, val); 434 + phy_write(phydev, PAGESEL, init_page); 435 + } 436 + 437 + static void recalibrate(struct dp83640_clock *clock) 438 + { 439 + s64 now, diff; 440 + struct phy_txts event_ts; 441 + struct timespec ts; 442 + struct list_head *this; 443 + struct dp83640_private *tmp; 444 + struct phy_device *master = clock->chosen->phydev; 445 + u16 cfg0, evnt, ptp_trig, trigger, val; 446 + 447 + trigger = CAL_TRIGGER; 448 + 449 + mutex_lock(&clock->extreg_lock); 450 + 451 + /* 452 + * enable broadcast, disable status frames, enable ptp clock 453 + */ 454 + list_for_each(this, &clock->phylist) { 455 + tmp = list_entry(this, struct dp83640_private, list); 456 + enable_broadcast(tmp->phydev, clock->page, 1); 457 + tmp->cfg0 = ext_read(tmp->phydev, PAGE5, PSF_CFG0); 458 + ext_write(0, tmp->phydev, PAGE5, PSF_CFG0, 0); 459 + ext_write(0, tmp->phydev, PAGE4, PTP_CTL, PTP_ENABLE); 460 + } 461 + enable_broadcast(master, clock->page, 1); 462 + cfg0 = ext_read(master, PAGE5, PSF_CFG0); 463 + ext_write(0, master, PAGE5, PSF_CFG0, 0); 464 + ext_write(0, master, PAGE4, PTP_CTL, PTP_ENABLE); 465 + 466 + /* 467 + * enable an event timestamp 468 + */ 469 + evnt = EVNT_WR | EVNT_RISE | EVNT_SINGLE; 470 + evnt |= (CAL_EVENT & EVNT_SEL_MASK) << EVNT_SEL_SHIFT; 471 + evnt |= (cal_gpio & EVNT_GPIO_MASK) << EVNT_GPIO_SHIFT; 472 + 473 + list_for_each(this, &clock->phylist) { 474 + tmp = list_entry(this, struct dp83640_private, list); 475 + ext_write(0, tmp->phydev, PAGE5, PTP_EVNT, evnt); 476 + } 477 + ext_write(0, master, PAGE5, PTP_EVNT, evnt); 478 + 479 + /* 480 + * configure a trigger 481 + */ 482 + ptp_trig = TRIG_WR | TRIG_IF_LATE | TRIG_PULSE; 483 + ptp_trig |= (trigger & TRIG_CSEL_MASK) << TRIG_CSEL_SHIFT; 484 + ptp_trig |= (cal_gpio & TRIG_GPIO_MASK) << TRIG_GPIO_SHIFT; 485 + ext_write(0, master, PAGE5, PTP_TRIG, ptp_trig); 486 + 487 + /* load trigger */ 488 + val = (trigger & TRIG_SEL_MASK) << TRIG_SEL_SHIFT; 489 + val |= TRIG_LOAD; 490 + ext_write(0, master, PAGE4, PTP_CTL, val); 491 + 492 + /* enable trigger */ 493 + val &= ~TRIG_LOAD; 494 + val |= TRIG_EN; 495 + ext_write(0, master, PAGE4, PTP_CTL, val); 496 + 497 + /* disable trigger */ 498 + val = (trigger & TRIG_SEL_MASK) << TRIG_SEL_SHIFT; 499 + val |= TRIG_DIS; 500 + ext_write(0, master, PAGE4, PTP_CTL, val); 501 + 502 + /* 503 + * read out and correct offsets 504 + */ 505 + val = ext_read(master, PAGE4, PTP_STS); 506 + pr_info("master PTP_STS 0x%04hx", val); 507 + val = ext_read(master, PAGE4, PTP_ESTS); 508 + pr_info("master PTP_ESTS 0x%04hx", val); 509 + event_ts.ns_lo = ext_read(master, PAGE4, PTP_EDATA); 510 + event_ts.ns_hi = ext_read(master, PAGE4, PTP_EDATA); 511 + event_ts.sec_lo = ext_read(master, PAGE4, PTP_EDATA); 512 + event_ts.sec_hi = ext_read(master, PAGE4, PTP_EDATA); 513 + now = phy2txts(&event_ts); 514 + 515 + list_for_each(this, &clock->phylist) { 516 + tmp = list_entry(this, struct dp83640_private, list); 517 + val = ext_read(tmp->phydev, PAGE4, PTP_STS); 518 + pr_info("slave PTP_STS 0x%04hx", val); 519 + val = ext_read(tmp->phydev, PAGE4, PTP_ESTS); 520 + pr_info("slave PTP_ESTS 0x%04hx", val); 521 + event_ts.ns_lo = ext_read(tmp->phydev, PAGE4, PTP_EDATA); 522 + event_ts.ns_hi = ext_read(tmp->phydev, PAGE4, PTP_EDATA); 523 + event_ts.sec_lo = ext_read(tmp->phydev, PAGE4, PTP_EDATA); 524 + event_ts.sec_hi = ext_read(tmp->phydev, PAGE4, PTP_EDATA); 525 + diff = now - (s64) phy2txts(&event_ts); 526 + pr_info("slave offset %lld nanoseconds\n", diff); 527 + diff += ADJTIME_FIX; 528 + ts = ns_to_timespec(diff); 529 + tdr_write(0, tmp->phydev, &ts, PTP_STEP_CLK); 530 + } 531 + 532 + /* 533 + * restore status frames 534 + */ 535 + list_for_each(this, &clock->phylist) { 536 + tmp = list_entry(this, struct dp83640_private, list); 537 + ext_write(0, tmp->phydev, PAGE5, PSF_CFG0, tmp->cfg0); 538 + } 539 + ext_write(0, master, PAGE5, PSF_CFG0, cfg0); 540 + 541 + mutex_unlock(&clock->extreg_lock); 542 + } 543 + 544 + /* time stamping methods */ 545 + 546 + static void decode_evnt(struct dp83640_private *dp83640, 547 + struct phy_txts *phy_txts, u16 ests) 548 + { 549 + struct ptp_clock_event event; 550 + int words = (ests >> EVNT_TS_LEN_SHIFT) & EVNT_TS_LEN_MASK; 551 + 552 + switch (words) { /* fall through in every case */ 553 + case 3: 554 + dp83640->edata.sec_hi = phy_txts->sec_hi; 555 + case 2: 556 + dp83640->edata.sec_lo = phy_txts->sec_lo; 557 + case 1: 558 + dp83640->edata.ns_hi = phy_txts->ns_hi; 559 + case 0: 560 + dp83640->edata.ns_lo = phy_txts->ns_lo; 561 + } 562 + 563 + event.type = PTP_CLOCK_EXTTS; 564 + event.index = 0; 565 + event.timestamp = phy2txts(&dp83640->edata); 566 + 567 + ptp_clock_event(dp83640->clock->ptp_clock, &event); 568 + } 569 + 570 + static void decode_rxts(struct dp83640_private *dp83640, 571 + struct phy_rxts *phy_rxts) 572 + { 573 + struct rxts *rxts; 574 + unsigned long flags; 575 + 576 + spin_lock_irqsave(&dp83640->rx_lock, flags); 577 + 578 + prune_rx_ts(dp83640); 579 + 580 + if (list_empty(&dp83640->rxpool)) { 581 + pr_warning("dp83640: rx timestamp pool is empty\n"); 582 + goto out; 583 + } 584 + rxts = list_first_entry(&dp83640->rxpool, struct rxts, list); 585 + list_del_init(&rxts->list); 586 + phy2rxts(phy_rxts, rxts); 587 + list_add_tail(&rxts->list, &dp83640->rxts); 588 + out: 589 + spin_unlock_irqrestore(&dp83640->rx_lock, flags); 590 + } 591 + 592 + static void decode_txts(struct dp83640_private *dp83640, 593 + struct phy_txts *phy_txts) 594 + { 595 + struct skb_shared_hwtstamps shhwtstamps; 596 + struct sk_buff *skb; 597 + u64 ns; 598 + 599 + /* We must already have the skb that triggered this. */ 600 + 601 + skb = skb_dequeue(&dp83640->tx_queue); 602 + 603 + if (!skb) { 604 + pr_warning("dp83640: have timestamp but tx_queue empty\n"); 605 + return; 606 + } 607 + ns = phy2txts(phy_txts); 608 + memset(&shhwtstamps, 0, sizeof(shhwtstamps)); 609 + shhwtstamps.hwtstamp = ns_to_ktime(ns); 610 + skb_complete_tx_timestamp(skb, &shhwtstamps); 611 + } 612 + 613 + static void decode_status_frame(struct dp83640_private *dp83640, 614 + struct sk_buff *skb) 615 + { 616 + struct phy_rxts *phy_rxts; 617 + struct phy_txts *phy_txts; 618 + u8 *ptr; 619 + int len, size; 620 + u16 ests, type; 621 + 622 + ptr = skb->data + 2; 623 + 624 + for (len = skb_headlen(skb) - 2; len > sizeof(type); len -= size) { 625 + 626 + type = *(u16 *)ptr; 627 + ests = type & 0x0fff; 628 + type = type & 0xf000; 629 + len -= sizeof(type); 630 + ptr += sizeof(type); 631 + 632 + if (PSF_RX == type && len >= sizeof(*phy_rxts)) { 633 + 634 + phy_rxts = (struct phy_rxts *) ptr; 635 + decode_rxts(dp83640, phy_rxts); 636 + size = sizeof(*phy_rxts); 637 + 638 + } else if (PSF_TX == type && len >= sizeof(*phy_txts)) { 639 + 640 + phy_txts = (struct phy_txts *) ptr; 641 + decode_txts(dp83640, phy_txts); 642 + size = sizeof(*phy_txts); 643 + 644 + } else if (PSF_EVNT == type && len >= sizeof(*phy_txts)) { 645 + 646 + phy_txts = (struct phy_txts *) ptr; 647 + decode_evnt(dp83640, phy_txts, ests); 648 + size = sizeof(*phy_txts); 649 + 650 + } else { 651 + size = 0; 652 + break; 653 + } 654 + ptr += size; 655 + } 656 + } 657 + 658 + static int match(struct sk_buff *skb, unsigned int type, struct rxts *rxts) 659 + { 660 + u16 *seqid; 661 + unsigned int offset; 662 + u8 *msgtype, *data = skb_mac_header(skb); 663 + 664 + /* check sequenceID, messageType, 12 bit hash of offset 20-29 */ 665 + 666 + switch (type) { 667 + case PTP_CLASS_V1_IPV4: 668 + case PTP_CLASS_V2_IPV4: 669 + offset = ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN; 670 + break; 671 + case PTP_CLASS_V1_IPV6: 672 + case PTP_CLASS_V2_IPV6: 673 + offset = OFF_PTP6; 674 + break; 675 + case PTP_CLASS_V2_L2: 676 + offset = ETH_HLEN; 677 + break; 678 + case PTP_CLASS_V2_VLAN: 679 + offset = ETH_HLEN + VLAN_HLEN; 680 + break; 681 + default: 682 + return 0; 683 + } 684 + 685 + if (skb->len + ETH_HLEN < offset + OFF_PTP_SEQUENCE_ID + sizeof(*seqid)) 686 + return 0; 687 + 688 + if (unlikely(type & PTP_CLASS_V1)) 689 + msgtype = data + offset + OFF_PTP_CONTROL; 690 + else 691 + msgtype = data + offset; 692 + 693 + seqid = (u16 *)(data + offset + OFF_PTP_SEQUENCE_ID); 694 + 695 + return (rxts->msgtype == (*msgtype & 0xf) && 696 + rxts->seqid == ntohs(*seqid)); 697 + } 698 + 699 + static void dp83640_free_clocks(void) 700 + { 701 + struct dp83640_clock *clock; 702 + struct list_head *this, *next; 703 + 704 + mutex_lock(&phyter_clocks_lock); 705 + 706 + list_for_each_safe(this, next, &phyter_clocks) { 707 + clock = list_entry(this, struct dp83640_clock, list); 708 + if (!list_empty(&clock->phylist)) { 709 + pr_warning("phy list non-empty while unloading"); 710 + BUG(); 711 + } 712 + list_del(&clock->list); 713 + mutex_destroy(&clock->extreg_lock); 714 + mutex_destroy(&clock->clock_lock); 715 + put_device(&clock->bus->dev); 716 + kfree(clock); 717 + } 718 + 719 + mutex_unlock(&phyter_clocks_lock); 720 + } 721 + 722 + static void dp83640_clock_init(struct dp83640_clock *clock, struct mii_bus *bus) 723 + { 724 + INIT_LIST_HEAD(&clock->list); 725 + clock->bus = bus; 726 + mutex_init(&clock->extreg_lock); 727 + mutex_init(&clock->clock_lock); 728 + INIT_LIST_HEAD(&clock->phylist); 729 + clock->caps.owner = THIS_MODULE; 730 + sprintf(clock->caps.name, "dp83640 timer"); 731 + clock->caps.max_adj = 1953124; 732 + clock->caps.n_alarm = 0; 733 + clock->caps.n_ext_ts = N_EXT_TS; 734 + clock->caps.n_per_out = 0; 735 + clock->caps.pps = 0; 736 + clock->caps.adjfreq = ptp_dp83640_adjfreq; 737 + clock->caps.adjtime = ptp_dp83640_adjtime; 738 + clock->caps.gettime = ptp_dp83640_gettime; 739 + clock->caps.settime = ptp_dp83640_settime; 740 + clock->caps.enable = ptp_dp83640_enable; 741 + /* 742 + * Get a reference to this bus instance. 743 + */ 744 + get_device(&bus->dev); 745 + } 746 + 747 + static int choose_this_phy(struct dp83640_clock *clock, 748 + struct phy_device *phydev) 749 + { 750 + if (chosen_phy == -1 && !clock->chosen) 751 + return 1; 752 + 753 + if (chosen_phy == phydev->addr) 754 + return 1; 755 + 756 + return 0; 757 + } 758 + 759 + static struct dp83640_clock *dp83640_clock_get(struct dp83640_clock *clock) 760 + { 761 + if (clock) 762 + mutex_lock(&clock->clock_lock); 763 + return clock; 764 + } 765 + 766 + /* 767 + * Look up and lock a clock by bus instance. 768 + * If there is no clock for this bus, then create it first. 769 + */ 770 + static struct dp83640_clock *dp83640_clock_get_bus(struct mii_bus *bus) 771 + { 772 + struct dp83640_clock *clock = NULL, *tmp; 773 + struct list_head *this; 774 + 775 + mutex_lock(&phyter_clocks_lock); 776 + 777 + list_for_each(this, &phyter_clocks) { 778 + tmp = list_entry(this, struct dp83640_clock, list); 779 + if (tmp->bus == bus) { 780 + clock = tmp; 781 + break; 782 + } 783 + } 784 + if (clock) 785 + goto out; 786 + 787 + clock = kzalloc(sizeof(struct dp83640_clock), GFP_KERNEL); 788 + if (!clock) 789 + goto out; 790 + 791 + dp83640_clock_init(clock, bus); 792 + list_add_tail(&phyter_clocks, &clock->list); 793 + out: 794 + mutex_unlock(&phyter_clocks_lock); 795 + 796 + return dp83640_clock_get(clock); 797 + } 798 + 799 + static void dp83640_clock_put(struct dp83640_clock *clock) 800 + { 801 + mutex_unlock(&clock->clock_lock); 802 + } 803 + 804 + static int dp83640_probe(struct phy_device *phydev) 805 + { 806 + struct dp83640_clock *clock; 807 + struct dp83640_private *dp83640; 808 + int err = -ENOMEM, i; 809 + 810 + if (phydev->addr == BROADCAST_ADDR) 811 + return 0; 812 + 813 + clock = dp83640_clock_get_bus(phydev->bus); 814 + if (!clock) 815 + goto no_clock; 816 + 817 + dp83640 = kzalloc(sizeof(struct dp83640_private), GFP_KERNEL); 818 + if (!dp83640) 819 + goto no_memory; 820 + 821 + dp83640->phydev = phydev; 822 + INIT_WORK(&dp83640->ts_work, rx_timestamp_work); 823 + 824 + INIT_LIST_HEAD(&dp83640->rxts); 825 + INIT_LIST_HEAD(&dp83640->rxpool); 826 + for (i = 0; i < MAX_RXTS; i++) 827 + list_add(&dp83640->rx_pool_data[i].list, &dp83640->rxpool); 828 + 829 + phydev->priv = dp83640; 830 + 831 + spin_lock_init(&dp83640->rx_lock); 832 + skb_queue_head_init(&dp83640->rx_queue); 833 + skb_queue_head_init(&dp83640->tx_queue); 834 + 835 + dp83640->clock = clock; 836 + 837 + if (choose_this_phy(clock, phydev)) { 838 + clock->chosen = dp83640; 839 + clock->ptp_clock = ptp_clock_register(&clock->caps); 840 + if (IS_ERR(clock->ptp_clock)) { 841 + err = PTR_ERR(clock->ptp_clock); 842 + goto no_register; 843 + } 844 + } else 845 + list_add_tail(&dp83640->list, &clock->phylist); 846 + 847 + if (clock->chosen && !list_empty(&clock->phylist)) 848 + recalibrate(clock); 849 + else 850 + enable_broadcast(dp83640->phydev, clock->page, 1); 851 + 852 + dp83640_clock_put(clock); 853 + return 0; 854 + 855 + no_register: 856 + clock->chosen = NULL; 857 + kfree(dp83640); 858 + no_memory: 859 + dp83640_clock_put(clock); 860 + no_clock: 861 + return err; 862 + } 863 + 864 + static void dp83640_remove(struct phy_device *phydev) 865 + { 866 + struct dp83640_clock *clock; 867 + struct list_head *this, *next; 868 + struct dp83640_private *tmp, *dp83640 = phydev->priv; 869 + 870 + if (phydev->addr == BROADCAST_ADDR) 871 + return; 872 + 873 + enable_status_frames(phydev, false); 874 + cancel_work_sync(&dp83640->ts_work); 875 + 876 + clock = dp83640_clock_get(dp83640->clock); 877 + 878 + if (dp83640 == clock->chosen) { 879 + ptp_clock_unregister(clock->ptp_clock); 880 + clock->chosen = NULL; 881 + } else { 882 + list_for_each_safe(this, next, &clock->phylist) { 883 + tmp = list_entry(this, struct dp83640_private, list); 884 + if (tmp == dp83640) { 885 + list_del_init(&tmp->list); 886 + break; 887 + } 888 + } 889 + } 890 + 891 + dp83640_clock_put(clock); 892 + kfree(dp83640); 893 + } 894 + 895 + static int dp83640_hwtstamp(struct phy_device *phydev, struct ifreq *ifr) 896 + { 897 + struct dp83640_private *dp83640 = phydev->priv; 898 + struct hwtstamp_config cfg; 899 + u16 txcfg0, rxcfg0; 900 + 901 + if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg))) 902 + return -EFAULT; 903 + 904 + if (cfg.flags) /* reserved for future extensions */ 905 + return -EINVAL; 906 + 907 + switch (cfg.tx_type) { 908 + case HWTSTAMP_TX_OFF: 909 + dp83640->hwts_tx_en = 0; 910 + break; 911 + case HWTSTAMP_TX_ON: 912 + dp83640->hwts_tx_en = 1; 913 + break; 914 + default: 915 + return -ERANGE; 916 + } 917 + 918 + switch (cfg.rx_filter) { 919 + case HWTSTAMP_FILTER_NONE: 920 + dp83640->hwts_rx_en = 0; 921 + dp83640->layer = 0; 922 + dp83640->version = 0; 923 + break; 924 + case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: 925 + case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: 926 + case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: 927 + dp83640->hwts_rx_en = 1; 928 + dp83640->layer = LAYER4; 929 + dp83640->version = 1; 930 + break; 931 + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: 932 + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: 933 + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: 934 + dp83640->hwts_rx_en = 1; 935 + dp83640->layer = LAYER4; 936 + dp83640->version = 2; 937 + break; 938 + case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: 939 + case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: 940 + case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: 941 + dp83640->hwts_rx_en = 1; 942 + dp83640->layer = LAYER2; 943 + dp83640->version = 2; 944 + break; 945 + case HWTSTAMP_FILTER_PTP_V2_EVENT: 946 + case HWTSTAMP_FILTER_PTP_V2_SYNC: 947 + case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: 948 + dp83640->hwts_rx_en = 1; 949 + dp83640->layer = LAYER4|LAYER2; 950 + dp83640->version = 2; 951 + break; 952 + default: 953 + return -ERANGE; 954 + } 955 + 956 + txcfg0 = (dp83640->version & TX_PTP_VER_MASK) << TX_PTP_VER_SHIFT; 957 + rxcfg0 = (dp83640->version & TX_PTP_VER_MASK) << TX_PTP_VER_SHIFT; 958 + 959 + if (dp83640->layer & LAYER2) { 960 + txcfg0 |= TX_L2_EN; 961 + rxcfg0 |= RX_L2_EN; 962 + } 963 + if (dp83640->layer & LAYER4) { 964 + txcfg0 |= TX_IPV6_EN | TX_IPV4_EN; 965 + rxcfg0 |= RX_IPV6_EN | RX_IPV4_EN; 966 + } 967 + 968 + if (dp83640->hwts_tx_en) 969 + txcfg0 |= TX_TS_EN; 970 + 971 + if (dp83640->hwts_rx_en) 972 + rxcfg0 |= RX_TS_EN; 973 + 974 + mutex_lock(&dp83640->clock->extreg_lock); 975 + 976 + if (dp83640->hwts_tx_en || dp83640->hwts_rx_en) { 977 + enable_status_frames(phydev, true); 978 + ext_write(0, phydev, PAGE4, PTP_CTL, PTP_ENABLE); 979 + } 980 + 981 + ext_write(0, phydev, PAGE5, PTP_TXCFG0, txcfg0); 982 + ext_write(0, phydev, PAGE5, PTP_RXCFG0, rxcfg0); 983 + 984 + mutex_unlock(&dp83640->clock->extreg_lock); 985 + 986 + return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; 987 + } 988 + 989 + static void rx_timestamp_work(struct work_struct *work) 990 + { 991 + struct dp83640_private *dp83640 = 992 + container_of(work, struct dp83640_private, ts_work); 993 + struct list_head *this, *next; 994 + struct rxts *rxts; 995 + struct skb_shared_hwtstamps *shhwtstamps; 996 + struct sk_buff *skb; 997 + unsigned int type; 998 + unsigned long flags; 999 + 1000 + /* Deliver each deferred packet, with or without a time stamp. */ 1001 + 1002 + while ((skb = skb_dequeue(&dp83640->rx_queue)) != NULL) { 1003 + type = SKB_PTP_TYPE(skb); 1004 + spin_lock_irqsave(&dp83640->rx_lock, flags); 1005 + list_for_each_safe(this, next, &dp83640->rxts) { 1006 + rxts = list_entry(this, struct rxts, list); 1007 + if (match(skb, type, rxts)) { 1008 + shhwtstamps = skb_hwtstamps(skb); 1009 + memset(shhwtstamps, 0, sizeof(*shhwtstamps)); 1010 + shhwtstamps->hwtstamp = ns_to_ktime(rxts->ns); 1011 + list_del_init(&rxts->list); 1012 + list_add(&rxts->list, &dp83640->rxpool); 1013 + break; 1014 + } 1015 + } 1016 + spin_unlock_irqrestore(&dp83640->rx_lock, flags); 1017 + netif_rx(skb); 1018 + } 1019 + 1020 + /* Clear out expired time stamps. */ 1021 + 1022 + spin_lock_irqsave(&dp83640->rx_lock, flags); 1023 + prune_rx_ts(dp83640); 1024 + spin_unlock_irqrestore(&dp83640->rx_lock, flags); 1025 + } 1026 + 1027 + static bool dp83640_rxtstamp(struct phy_device *phydev, 1028 + struct sk_buff *skb, int type) 1029 + { 1030 + struct dp83640_private *dp83640 = phydev->priv; 1031 + 1032 + if (!dp83640->hwts_rx_en) 1033 + return false; 1034 + 1035 + if (is_status_frame(skb, type)) { 1036 + decode_status_frame(dp83640, skb); 1037 + /* Let the stack drop this frame. */ 1038 + return false; 1039 + } 1040 + 1041 + SKB_PTP_TYPE(skb) = type; 1042 + skb_queue_tail(&dp83640->rx_queue, skb); 1043 + schedule_work(&dp83640->ts_work); 1044 + 1045 + return true; 1046 + } 1047 + 1048 + static void dp83640_txtstamp(struct phy_device *phydev, 1049 + struct sk_buff *skb, int type) 1050 + { 1051 + struct dp83640_private *dp83640 = phydev->priv; 1052 + 1053 + if (!dp83640->hwts_tx_en) { 1054 + kfree_skb(skb); 1055 + return; 1056 + } 1057 + skb_queue_tail(&dp83640->tx_queue, skb); 1058 + schedule_work(&dp83640->ts_work); 1059 + } 1060 + 1061 + static struct phy_driver dp83640_driver = { 1062 + .phy_id = DP83640_PHY_ID, 1063 + .phy_id_mask = 0xfffffff0, 1064 + .name = "NatSemi DP83640", 1065 + .features = PHY_BASIC_FEATURES, 1066 + .flags = 0, 1067 + .probe = dp83640_probe, 1068 + .remove = dp83640_remove, 1069 + .config_aneg = genphy_config_aneg, 1070 + .read_status = genphy_read_status, 1071 + .hwtstamp = dp83640_hwtstamp, 1072 + .rxtstamp = dp83640_rxtstamp, 1073 + .txtstamp = dp83640_txtstamp, 1074 + .driver = {.owner = THIS_MODULE,} 1075 + }; 1076 + 1077 + static int __init dp83640_init(void) 1078 + { 1079 + return phy_driver_register(&dp83640_driver); 1080 + } 1081 + 1082 + static void __exit dp83640_exit(void) 1083 + { 1084 + dp83640_free_clocks(); 1085 + phy_driver_unregister(&dp83640_driver); 1086 + } 1087 + 1088 + MODULE_DESCRIPTION("National Semiconductor DP83640 PHY driver"); 1089 + MODULE_AUTHOR("Richard Cochran <richard.cochran@omicron.at>"); 1090 + MODULE_LICENSE("GPL"); 1091 + 1092 + module_init(dp83640_init); 1093 + module_exit(dp83640_exit); 1094 + 1095 + static struct mdio_device_id __maybe_unused dp83640_tbl[] = { 1096 + { DP83640_PHY_ID, 0xfffffff0 }, 1097 + { } 1098 + }; 1099 + 1100 + MODULE_DEVICE_TABLE(mdio, dp83640_tbl);
+267
drivers/net/phy/dp83640_reg.h
··· 1 + /* dp83640_reg.h 2 + * Generated by regen.tcl on Thu Feb 17 10:02:48 AM CET 2011 3 + */ 4 + #ifndef HAVE_DP83640_REGISTERS 5 + #define HAVE_DP83640_REGISTERS 6 + 7 + #define PAGE0 0x0000 8 + #define PHYCR2 0x001c /* PHY Control Register 2 */ 9 + 10 + #define PAGE4 0x0004 11 + #define PTP_CTL 0x0014 /* PTP Control Register */ 12 + #define PTP_TDR 0x0015 /* PTP Time Data Register */ 13 + #define PTP_STS 0x0016 /* PTP Status Register */ 14 + #define PTP_TSTS 0x0017 /* PTP Trigger Status Register */ 15 + #define PTP_RATEL 0x0018 /* PTP Rate Low Register */ 16 + #define PTP_RATEH 0x0019 /* PTP Rate High Register */ 17 + #define PTP_RDCKSUM 0x001a /* PTP Read Checksum */ 18 + #define PTP_WRCKSUM 0x001b /* PTP Write Checksum */ 19 + #define PTP_TXTS 0x001c /* PTP Transmit Timestamp Register, in four 16-bit reads */ 20 + #define PTP_RXTS 0x001d /* PTP Receive Timestamp Register, in six? 16-bit reads */ 21 + #define PTP_ESTS 0x001e /* PTP Event Status Register */ 22 + #define PTP_EDATA 0x001f /* PTP Event Data Register */ 23 + 24 + #define PAGE5 0x0005 25 + #define PTP_TRIG 0x0014 /* PTP Trigger Configuration Register */ 26 + #define PTP_EVNT 0x0015 /* PTP Event Configuration Register */ 27 + #define PTP_TXCFG0 0x0016 /* PTP Transmit Configuration Register 0 */ 28 + #define PTP_TXCFG1 0x0017 /* PTP Transmit Configuration Register 1 */ 29 + #define PSF_CFG0 0x0018 /* PHY Status Frame Configuration Register 0 */ 30 + #define PTP_RXCFG0 0x0019 /* PTP Receive Configuration Register 0 */ 31 + #define PTP_RXCFG1 0x001a /* PTP Receive Configuration Register 1 */ 32 + #define PTP_RXCFG2 0x001b /* PTP Receive Configuration Register 2 */ 33 + #define PTP_RXCFG3 0x001c /* PTP Receive Configuration Register 3 */ 34 + #define PTP_RXCFG4 0x001d /* PTP Receive Configuration Register 4 */ 35 + #define PTP_TRDL 0x001e /* PTP Temporary Rate Duration Low Register */ 36 + #define PTP_TRDH 0x001f /* PTP Temporary Rate Duration High Register */ 37 + 38 + #define PAGE6 0x0006 39 + #define PTP_COC 0x0014 /* PTP Clock Output Control Register */ 40 + #define PSF_CFG1 0x0015 /* PHY Status Frame Configuration Register 1 */ 41 + #define PSF_CFG2 0x0016 /* PHY Status Frame Configuration Register 2 */ 42 + #define PSF_CFG3 0x0017 /* PHY Status Frame Configuration Register 3 */ 43 + #define PSF_CFG4 0x0018 /* PHY Status Frame Configuration Register 4 */ 44 + #define PTP_SFDCFG 0x0019 /* PTP SFD Configuration Register */ 45 + #define PTP_INTCTL 0x001a /* PTP Interrupt Control Register */ 46 + #define PTP_CLKSRC 0x001b /* PTP Clock Source Register */ 47 + #define PTP_ETR 0x001c /* PTP Ethernet Type Register */ 48 + #define PTP_OFF 0x001d /* PTP Offset Register */ 49 + #define PTP_GPIOMON 0x001e /* PTP GPIO Monitor Register */ 50 + #define PTP_RXHASH 0x001f /* PTP Receive Hash Register */ 51 + 52 + /* Bit definitions for the PHYCR2 register */ 53 + #define BC_WRITE (1<<11) /* Broadcast Write Enable */ 54 + 55 + /* Bit definitions for the PTP_CTL register */ 56 + #define TRIG_SEL_SHIFT (10) /* PTP Trigger Select */ 57 + #define TRIG_SEL_MASK (0x7) 58 + #define TRIG_DIS (1<<9) /* Disable PTP Trigger */ 59 + #define TRIG_EN (1<<8) /* Enable PTP Trigger */ 60 + #define TRIG_READ (1<<7) /* Read PTP Trigger */ 61 + #define TRIG_LOAD (1<<6) /* Load PTP Trigger */ 62 + #define PTP_RD_CLK (1<<5) /* Read PTP Clock */ 63 + #define PTP_LOAD_CLK (1<<4) /* Load PTP Clock */ 64 + #define PTP_STEP_CLK (1<<3) /* Step PTP Clock */ 65 + #define PTP_ENABLE (1<<2) /* Enable PTP Clock */ 66 + #define PTP_DISABLE (1<<1) /* Disable PTP Clock */ 67 + #define PTP_RESET (1<<0) /* Reset PTP Clock */ 68 + 69 + /* Bit definitions for the PTP_STS register */ 70 + #define TXTS_RDY (1<<11) /* Transmit Timestamp Ready */ 71 + #define RXTS_RDY (1<<10) /* Receive Timestamp Ready */ 72 + #define TRIG_DONE (1<<9) /* PTP Trigger Done */ 73 + #define EVENT_RDY (1<<8) /* PTP Event Timestamp Ready */ 74 + #define TXTS_IE (1<<3) /* Transmit Timestamp Interrupt Enable */ 75 + #define RXTS_IE (1<<2) /* Receive Timestamp Interrupt Enable */ 76 + #define TRIG_IE (1<<1) /* Trigger Interrupt Enable */ 77 + #define EVENT_IE (1<<0) /* Event Interrupt Enable */ 78 + 79 + /* Bit definitions for the PTP_TSTS register */ 80 + #define TRIG7_ERROR (1<<15) /* Trigger 7 Error */ 81 + #define TRIG7_ACTIVE (1<<14) /* Trigger 7 Active */ 82 + #define TRIG6_ERROR (1<<13) /* Trigger 6 Error */ 83 + #define TRIG6_ACTIVE (1<<12) /* Trigger 6 Active */ 84 + #define TRIG5_ERROR (1<<11) /* Trigger 5 Error */ 85 + #define TRIG5_ACTIVE (1<<10) /* Trigger 5 Active */ 86 + #define TRIG4_ERROR (1<<9) /* Trigger 4 Error */ 87 + #define TRIG4_ACTIVE (1<<8) /* Trigger 4 Active */ 88 + #define TRIG3_ERROR (1<<7) /* Trigger 3 Error */ 89 + #define TRIG3_ACTIVE (1<<6) /* Trigger 3 Active */ 90 + #define TRIG2_ERROR (1<<5) /* Trigger 2 Error */ 91 + #define TRIG2_ACTIVE (1<<4) /* Trigger 2 Active */ 92 + #define TRIG1_ERROR (1<<3) /* Trigger 1 Error */ 93 + #define TRIG1_ACTIVE (1<<2) /* Trigger 1 Active */ 94 + #define TRIG0_ERROR (1<<1) /* Trigger 0 Error */ 95 + #define TRIG0_ACTIVE (1<<0) /* Trigger 0 Active */ 96 + 97 + /* Bit definitions for the PTP_RATEH register */ 98 + #define PTP_RATE_DIR (1<<15) /* PTP Rate Direction */ 99 + #define PTP_TMP_RATE (1<<14) /* PTP Temporary Rate */ 100 + #define PTP_RATE_HI_SHIFT (0) /* PTP Rate High 10-bits */ 101 + #define PTP_RATE_HI_MASK (0x3ff) 102 + 103 + /* Bit definitions for the PTP_ESTS register */ 104 + #define EVNTS_MISSED_SHIFT (8) /* Indicates number of events missed */ 105 + #define EVNTS_MISSED_MASK (0x7) 106 + #define EVNT_TS_LEN_SHIFT (6) /* Indicates length of the Timestamp field in 16-bit words minus 1 */ 107 + #define EVNT_TS_LEN_MASK (0x3) 108 + #define EVNT_RF (1<<5) /* Indicates whether the event is a rise or falling event */ 109 + #define EVNT_NUM_SHIFT (2) /* Indicates Event Timestamp Unit which detected an event */ 110 + #define EVNT_NUM_MASK (0x7) 111 + #define MULT_EVNT (1<<1) /* Indicates multiple events were detected at the same time */ 112 + #define EVENT_DET (1<<0) /* PTP Event Detected */ 113 + 114 + /* Bit definitions for the PTP_EDATA register */ 115 + #define E7_RISE (1<<15) /* Indicates direction of Event 7 */ 116 + #define E7_DET (1<<14) /* Indicates Event 7 detected */ 117 + #define E6_RISE (1<<13) /* Indicates direction of Event 6 */ 118 + #define E6_DET (1<<12) /* Indicates Event 6 detected */ 119 + #define E5_RISE (1<<11) /* Indicates direction of Event 5 */ 120 + #define E5_DET (1<<10) /* Indicates Event 5 detected */ 121 + #define E4_RISE (1<<9) /* Indicates direction of Event 4 */ 122 + #define E4_DET (1<<8) /* Indicates Event 4 detected */ 123 + #define E3_RISE (1<<7) /* Indicates direction of Event 3 */ 124 + #define E3_DET (1<<6) /* Indicates Event 3 detected */ 125 + #define E2_RISE (1<<5) /* Indicates direction of Event 2 */ 126 + #define E2_DET (1<<4) /* Indicates Event 2 detected */ 127 + #define E1_RISE (1<<3) /* Indicates direction of Event 1 */ 128 + #define E1_DET (1<<2) /* Indicates Event 1 detected */ 129 + #define E0_RISE (1<<1) /* Indicates direction of Event 0 */ 130 + #define E0_DET (1<<0) /* Indicates Event 0 detected */ 131 + 132 + /* Bit definitions for the PTP_TRIG register */ 133 + #define TRIG_PULSE (1<<15) /* generate a Pulse rather than a single edge */ 134 + #define TRIG_PER (1<<14) /* generate a periodic signal */ 135 + #define TRIG_IF_LATE (1<<13) /* trigger immediately if already past */ 136 + #define TRIG_NOTIFY (1<<12) /* Trigger Notification Enable */ 137 + #define TRIG_GPIO_SHIFT (8) /* Trigger GPIO Connection, value 1-12 */ 138 + #define TRIG_GPIO_MASK (0xf) 139 + #define TRIG_TOGGLE (1<<7) /* Trigger Toggle Mode Enable */ 140 + #define TRIG_CSEL_SHIFT (1) /* Trigger Configuration Select */ 141 + #define TRIG_CSEL_MASK (0x7) 142 + #define TRIG_WR (1<<0) /* Trigger Configuration Write */ 143 + 144 + /* Bit definitions for the PTP_EVNT register */ 145 + #define EVNT_RISE (1<<14) /* Event Rise Detect Enable */ 146 + #define EVNT_FALL (1<<13) /* Event Fall Detect Enable */ 147 + #define EVNT_SINGLE (1<<12) /* enable single event capture operation */ 148 + #define EVNT_GPIO_SHIFT (8) /* Event GPIO Connection, value 1-12 */ 149 + #define EVNT_GPIO_MASK (0xf) 150 + #define EVNT_SEL_SHIFT (1) /* Event Select */ 151 + #define EVNT_SEL_MASK (0x7) 152 + #define EVNT_WR (1<<0) /* Event Configuration Write */ 153 + 154 + /* Bit definitions for the PTP_TXCFG0 register */ 155 + #define SYNC_1STEP (1<<15) /* insert timestamp into transmit Sync Messages */ 156 + #define DR_INSERT (1<<13) /* Insert Delay_Req Timestamp in Delay_Resp (dangerous) */ 157 + #define NTP_TS_EN (1<<12) /* Enable Timestamping of NTP Packets */ 158 + #define IGNORE_2STEP (1<<11) /* Ignore Two_Step flag for One-Step operation */ 159 + #define CRC_1STEP (1<<10) /* Disable checking of CRC for One-Step operation */ 160 + #define CHK_1STEP (1<<9) /* Enable UDP Checksum correction for One-Step Operation */ 161 + #define IP1588_EN (1<<8) /* Enable IEEE 1588 defined IP address filter */ 162 + #define TX_L2_EN (1<<7) /* Layer2 Timestamp Enable */ 163 + #define TX_IPV6_EN (1<<6) /* IPv6 Timestamp Enable */ 164 + #define TX_IPV4_EN (1<<5) /* IPv4 Timestamp Enable */ 165 + #define TX_PTP_VER_SHIFT (1) /* Enable Timestamp capture for IEEE 1588 version X */ 166 + #define TX_PTP_VER_MASK (0xf) 167 + #define TX_TS_EN (1<<0) /* Transmit Timestamp Enable */ 168 + 169 + /* Bit definitions for the PTP_TXCFG1 register */ 170 + #define BYTE0_MASK_SHIFT (8) /* Bit mask to be used for matching Byte0 of the PTP Message */ 171 + #define BYTE0_MASK_MASK (0xff) 172 + #define BYTE0_DATA_SHIFT (0) /* Data to be used for matching Byte0 of the PTP Message */ 173 + #define BYTE0_DATA_MASK (0xff) 174 + 175 + /* Bit definitions for the PSF_CFG0 register */ 176 + #define MAC_SRC_ADD_SHIFT (11) /* Status Frame Mac Source Address */ 177 + #define MAC_SRC_ADD_MASK (0x3) 178 + #define MIN_PRE_SHIFT (8) /* Status Frame Minimum Preamble */ 179 + #define MIN_PRE_MASK (0x7) 180 + #define PSF_ENDIAN (1<<7) /* Status Frame Endian Control */ 181 + #define PSF_IPV4 (1<<6) /* Status Frame IPv4 Enable */ 182 + #define PSF_PCF_RD (1<<5) /* Control Frame Read PHY Status Frame Enable */ 183 + #define PSF_ERR_EN (1<<4) /* Error PHY Status Frame Enable */ 184 + #define PSF_TXTS_EN (1<<3) /* Transmit Timestamp PHY Status Frame Enable */ 185 + #define PSF_RXTS_EN (1<<2) /* Receive Timestamp PHY Status Frame Enable */ 186 + #define PSF_TRIG_EN (1<<1) /* Trigger PHY Status Frame Enable */ 187 + #define PSF_EVNT_EN (1<<0) /* Event PHY Status Frame Enable */ 188 + 189 + /* Bit definitions for the PTP_RXCFG0 register */ 190 + #define DOMAIN_EN (1<<15) /* Domain Match Enable */ 191 + #define ALT_MAST_DIS (1<<14) /* Alternate Master Timestamp Disable */ 192 + #define USER_IP_SEL (1<<13) /* Selects portion of IP address accessible thru PTP_RXCFG2 */ 193 + #define USER_IP_EN (1<<12) /* Enable User-programmed IP address filter */ 194 + #define RX_SLAVE (1<<11) /* Receive Slave Only */ 195 + #define IP1588_EN_SHIFT (8) /* Enable IEEE 1588 defined IP address filters */ 196 + #define IP1588_EN_MASK (0xf) 197 + #define RX_L2_EN (1<<7) /* Layer2 Timestamp Enable */ 198 + #define RX_IPV6_EN (1<<6) /* IPv6 Timestamp Enable */ 199 + #define RX_IPV4_EN (1<<5) /* IPv4 Timestamp Enable */ 200 + #define RX_PTP_VER_SHIFT (1) /* Enable Timestamp capture for IEEE 1588 version X */ 201 + #define RX_PTP_VER_MASK (0xf) 202 + #define RX_TS_EN (1<<0) /* Receive Timestamp Enable */ 203 + 204 + /* Bit definitions for the PTP_RXCFG1 register */ 205 + #define BYTE0_MASK_SHIFT (8) /* Bit mask to be used for matching Byte0 of the PTP Message */ 206 + #define BYTE0_MASK_MASK (0xff) 207 + #define BYTE0_DATA_SHIFT (0) /* Data to be used for matching Byte0 of the PTP Message */ 208 + #define BYTE0_DATA_MASK (0xff) 209 + 210 + /* Bit definitions for the PTP_RXCFG3 register */ 211 + #define TS_MIN_IFG_SHIFT (12) /* Minimum Inter-frame Gap */ 212 + #define TS_MIN_IFG_MASK (0xf) 213 + #define ACC_UDP (1<<11) /* Record Timestamp if UDP Checksum Error */ 214 + #define ACC_CRC (1<<10) /* Record Timestamp if CRC Error */ 215 + #define TS_APPEND (1<<9) /* Append Timestamp for L2 */ 216 + #define TS_INSERT (1<<8) /* Enable Timestamp Insertion */ 217 + #define PTP_DOMAIN_SHIFT (0) /* PTP Message domainNumber field */ 218 + #define PTP_DOMAIN_MASK (0xff) 219 + 220 + /* Bit definitions for the PTP_RXCFG4 register */ 221 + #define IPV4_UDP_MOD (1<<15) /* Enable IPV4 UDP Modification */ 222 + #define TS_SEC_EN (1<<14) /* Enable Timestamp Seconds */ 223 + #define TS_SEC_LEN_SHIFT (12) /* Inserted Timestamp Seconds Length */ 224 + #define TS_SEC_LEN_MASK (0x3) 225 + #define RXTS_NS_OFF_SHIFT (6) /* Receive Timestamp Nanoseconds offset */ 226 + #define RXTS_NS_OFF_MASK (0x3f) 227 + #define RXTS_SEC_OFF_SHIFT (0) /* Receive Timestamp Seconds offset */ 228 + #define RXTS_SEC_OFF_MASK (0x3f) 229 + 230 + /* Bit definitions for the PTP_COC register */ 231 + #define PTP_CLKOUT_EN (1<<15) /* PTP Clock Output Enable */ 232 + #define PTP_CLKOUT_SEL (1<<14) /* PTP Clock Output Source Select */ 233 + #define PTP_CLKOUT_SPEEDSEL (1<<13) /* PTP Clock Output I/O Speed Select */ 234 + #define PTP_CLKDIV_SHIFT (0) /* PTP Clock Divide-by Value */ 235 + #define PTP_CLKDIV_MASK (0xff) 236 + 237 + /* Bit definitions for the PSF_CFG1 register */ 238 + #define PTPRESERVED_SHIFT (12) /* PTP v2 reserved field */ 239 + #define PTPRESERVED_MASK (0xf) 240 + #define VERSIONPTP_SHIFT (8) /* PTP v2 versionPTP field */ 241 + #define VERSIONPTP_MASK (0xf) 242 + #define TRANSPORT_SPECIFIC_SHIFT (4) /* PTP v2 Header transportSpecific field */ 243 + #define TRANSPORT_SPECIFIC_MASK (0xf) 244 + #define MESSAGETYPE_SHIFT (0) /* PTP v2 messageType field */ 245 + #define MESSAGETYPE_MASK (0xf) 246 + 247 + /* Bit definitions for the PTP_SFDCFG register */ 248 + #define TX_SFD_GPIO_SHIFT (4) /* TX SFD GPIO Select, value 1-12 */ 249 + #define TX_SFD_GPIO_MASK (0xf) 250 + #define RX_SFD_GPIO_SHIFT (0) /* RX SFD GPIO Select, value 1-12 */ 251 + #define RX_SFD_GPIO_MASK (0xf) 252 + 253 + /* Bit definitions for the PTP_INTCTL register */ 254 + #define PTP_INT_GPIO_SHIFT (0) /* PTP Interrupt GPIO Select */ 255 + #define PTP_INT_GPIO_MASK (0xf) 256 + 257 + /* Bit definitions for the PTP_CLKSRC register */ 258 + #define CLK_SRC_SHIFT (14) /* PTP Clock Source Select */ 259 + #define CLK_SRC_MASK (0x3) 260 + #define CLK_SRC_PER_SHIFT (0) /* PTP Clock Source Period */ 261 + #define CLK_SRC_PER_MASK (0x7f) 262 + 263 + /* Bit definitions for the PTP_OFF register */ 264 + #define PTP_OFFSET_SHIFT (0) /* PTP Message offset from preceding header */ 265 + #define PTP_OFFSET_MASK (0xff) 266 + 267 + #endif
+75
drivers/ptp/Kconfig
··· 1 + # 2 + # PTP clock support configuration 3 + # 4 + 5 + menu "PTP clock support" 6 + 7 + comment "Enable Device Drivers -> PPS to see the PTP clock options." 8 + depends on PPS=n 9 + 10 + config PTP_1588_CLOCK 11 + tristate "PTP clock support" 12 + depends on EXPERIMENTAL 13 + depends on PPS 14 + help 15 + The IEEE 1588 standard defines a method to precisely 16 + synchronize distributed clocks over Ethernet networks. The 17 + standard defines a Precision Time Protocol (PTP), which can 18 + be used to achieve synchronization within a few dozen 19 + microseconds. In addition, with the help of special hardware 20 + time stamping units, it can be possible to achieve 21 + synchronization to within a few hundred nanoseconds. 22 + 23 + This driver adds support for PTP clocks as character 24 + devices. If you want to use a PTP clock, then you should 25 + also enable at least one clock driver as well. 26 + 27 + To compile this driver as a module, choose M here: the module 28 + will be called ptp. 29 + 30 + config PTP_1588_CLOCK_GIANFAR 31 + tristate "Freescale eTSEC as PTP clock" 32 + depends on PTP_1588_CLOCK 33 + depends on GIANFAR 34 + help 35 + This driver adds support for using the eTSEC as a PTP 36 + clock. This clock is only useful if your PTP programs are 37 + getting hardware time stamps on the PTP Ethernet packets 38 + using the SO_TIMESTAMPING API. 39 + 40 + To compile this driver as a module, choose M here: the module 41 + will be called gianfar_ptp. 42 + 43 + config PTP_1588_CLOCK_IXP46X 44 + tristate "Intel IXP46x as PTP clock" 45 + depends on PTP_1588_CLOCK 46 + depends on IXP4XX_ETH 47 + help 48 + This driver adds support for using the IXP46X as a PTP 49 + clock. This clock is only useful if your PTP programs are 50 + getting hardware time stamps on the PTP Ethernet packets 51 + using the SO_TIMESTAMPING API. 52 + 53 + To compile this driver as a module, choose M here: the module 54 + will be called ptp_ixp46x. 55 + 56 + comment "Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks." 57 + depends on PTP_1588_CLOCK && (PHYLIB=n || NETWORK_PHY_TIMESTAMPING=n) 58 + 59 + config DP83640_PHY 60 + tristate "Driver for the National Semiconductor DP83640 PHYTER" 61 + depends on PTP_1588_CLOCK 62 + depends on NETWORK_PHY_TIMESTAMPING 63 + depends on PHYLIB 64 + ---help--- 65 + Supports the DP83640 PHYTER with IEEE 1588 features. 66 + 67 + This driver adds support for using the DP83640 as a PTP 68 + clock. This clock is only useful if your PTP programs are 69 + getting hardware time stamps on the PTP Ethernet packets 70 + using the SO_TIMESTAMPING API. 71 + 72 + In order for this to work, your MAC driver must also 73 + implement the skb_tx_timetamp() function. 74 + 75 + endmenu
+7
drivers/ptp/Makefile
··· 1 + # 2 + # Makefile for PTP 1588 clock support. 3 + # 4 + 5 + ptp-y := ptp_clock.o ptp_chardev.o ptp_sysfs.o 6 + obj-$(CONFIG_PTP_1588_CLOCK) += ptp.o 7 + obj-$(CONFIG_PTP_1588_CLOCK_IXP46X) += ptp_ixp46x.o
+159
drivers/ptp/ptp_chardev.c
··· 1 + /* 2 + * PTP 1588 clock support - character device implementation. 3 + * 4 + * Copyright (C) 2010 OMICRON electronics GmbH 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program; if not, write to the Free Software 18 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 + */ 20 + #include <linux/module.h> 21 + #include <linux/posix-clock.h> 22 + #include <linux/poll.h> 23 + #include <linux/sched.h> 24 + 25 + #include "ptp_private.h" 26 + 27 + int ptp_open(struct posix_clock *pc, fmode_t fmode) 28 + { 29 + return 0; 30 + } 31 + 32 + long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg) 33 + { 34 + struct ptp_clock_caps caps; 35 + struct ptp_clock_request req; 36 + struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); 37 + struct ptp_clock_info *ops = ptp->info; 38 + int enable, err = 0; 39 + 40 + switch (cmd) { 41 + 42 + case PTP_CLOCK_GETCAPS: 43 + memset(&caps, 0, sizeof(caps)); 44 + caps.max_adj = ptp->info->max_adj; 45 + caps.n_alarm = ptp->info->n_alarm; 46 + caps.n_ext_ts = ptp->info->n_ext_ts; 47 + caps.n_per_out = ptp->info->n_per_out; 48 + caps.pps = ptp->info->pps; 49 + err = copy_to_user((void __user *)arg, &caps, sizeof(caps)); 50 + break; 51 + 52 + case PTP_EXTTS_REQUEST: 53 + if (copy_from_user(&req.extts, (void __user *)arg, 54 + sizeof(req.extts))) { 55 + err = -EFAULT; 56 + break; 57 + } 58 + if (req.extts.index >= ops->n_ext_ts) { 59 + err = -EINVAL; 60 + break; 61 + } 62 + req.type = PTP_CLK_REQ_EXTTS; 63 + enable = req.extts.flags & PTP_ENABLE_FEATURE ? 1 : 0; 64 + err = ops->enable(ops, &req, enable); 65 + break; 66 + 67 + case PTP_PEROUT_REQUEST: 68 + if (copy_from_user(&req.perout, (void __user *)arg, 69 + sizeof(req.perout))) { 70 + err = -EFAULT; 71 + break; 72 + } 73 + if (req.perout.index >= ops->n_per_out) { 74 + err = -EINVAL; 75 + break; 76 + } 77 + req.type = PTP_CLK_REQ_PEROUT; 78 + enable = req.perout.period.sec || req.perout.period.nsec; 79 + err = ops->enable(ops, &req, enable); 80 + break; 81 + 82 + case PTP_ENABLE_PPS: 83 + if (!capable(CAP_SYS_TIME)) 84 + return -EPERM; 85 + req.type = PTP_CLK_REQ_PPS; 86 + enable = arg ? 1 : 0; 87 + err = ops->enable(ops, &req, enable); 88 + break; 89 + 90 + default: 91 + err = -ENOTTY; 92 + break; 93 + } 94 + return err; 95 + } 96 + 97 + unsigned int ptp_poll(struct posix_clock *pc, struct file *fp, poll_table *wait) 98 + { 99 + struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); 100 + 101 + poll_wait(fp, &ptp->tsev_wq, wait); 102 + 103 + return queue_cnt(&ptp->tsevq) ? POLLIN : 0; 104 + } 105 + 106 + ssize_t ptp_read(struct posix_clock *pc, 107 + uint rdflags, char __user *buf, size_t cnt) 108 + { 109 + struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); 110 + struct timestamp_event_queue *queue = &ptp->tsevq; 111 + struct ptp_extts_event event[PTP_BUF_TIMESTAMPS]; 112 + unsigned long flags; 113 + size_t qcnt, i; 114 + 115 + if (cnt % sizeof(struct ptp_extts_event) != 0) 116 + return -EINVAL; 117 + 118 + if (cnt > sizeof(event)) 119 + cnt = sizeof(event); 120 + 121 + cnt = cnt / sizeof(struct ptp_extts_event); 122 + 123 + if (mutex_lock_interruptible(&ptp->tsevq_mux)) 124 + return -ERESTARTSYS; 125 + 126 + if (wait_event_interruptible(ptp->tsev_wq, 127 + ptp->defunct || queue_cnt(queue))) { 128 + mutex_unlock(&ptp->tsevq_mux); 129 + return -ERESTARTSYS; 130 + } 131 + 132 + if (ptp->defunct) 133 + return -ENODEV; 134 + 135 + spin_lock_irqsave(&queue->lock, flags); 136 + 137 + qcnt = queue_cnt(queue); 138 + 139 + if (cnt > qcnt) 140 + cnt = qcnt; 141 + 142 + for (i = 0; i < cnt; i++) { 143 + event[i] = queue->buf[queue->head]; 144 + queue->head = (queue->head + 1) % PTP_MAX_TIMESTAMPS; 145 + } 146 + 147 + spin_unlock_irqrestore(&queue->lock, flags); 148 + 149 + cnt = cnt * sizeof(struct ptp_extts_event); 150 + 151 + mutex_unlock(&ptp->tsevq_mux); 152 + 153 + if (copy_to_user(buf, event, cnt)) { 154 + mutex_unlock(&ptp->tsevq_mux); 155 + return -EFAULT; 156 + } 157 + 158 + return cnt; 159 + }
+343
drivers/ptp/ptp_clock.c
··· 1 + /* 2 + * PTP 1588 clock support 3 + * 4 + * Copyright (C) 2010 OMICRON electronics GmbH 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program; if not, write to the Free Software 18 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 + */ 20 + #include <linux/bitops.h> 21 + #include <linux/device.h> 22 + #include <linux/err.h> 23 + #include <linux/init.h> 24 + #include <linux/kernel.h> 25 + #include <linux/module.h> 26 + #include <linux/posix-clock.h> 27 + #include <linux/pps_kernel.h> 28 + #include <linux/slab.h> 29 + #include <linux/syscalls.h> 30 + #include <linux/uaccess.h> 31 + 32 + #include "ptp_private.h" 33 + 34 + #define PTP_MAX_ALARMS 4 35 + #define PTP_MAX_CLOCKS 8 36 + #define PTP_PPS_DEFAULTS (PPS_CAPTUREASSERT | PPS_OFFSETASSERT) 37 + #define PTP_PPS_EVENT PPS_CAPTUREASSERT 38 + #define PTP_PPS_MODE (PTP_PPS_DEFAULTS | PPS_CANWAIT | PPS_TSFMT_TSPEC) 39 + 40 + /* private globals */ 41 + 42 + static dev_t ptp_devt; 43 + static struct class *ptp_class; 44 + 45 + static DECLARE_BITMAP(ptp_clocks_map, PTP_MAX_CLOCKS); 46 + static DEFINE_MUTEX(ptp_clocks_mutex); /* protects 'ptp_clocks_map' */ 47 + 48 + /* time stamp event queue operations */ 49 + 50 + static inline int queue_free(struct timestamp_event_queue *q) 51 + { 52 + return PTP_MAX_TIMESTAMPS - queue_cnt(q) - 1; 53 + } 54 + 55 + static void enqueue_external_timestamp(struct timestamp_event_queue *queue, 56 + struct ptp_clock_event *src) 57 + { 58 + struct ptp_extts_event *dst; 59 + unsigned long flags; 60 + s64 seconds; 61 + u32 remainder; 62 + 63 + seconds = div_u64_rem(src->timestamp, 1000000000, &remainder); 64 + 65 + spin_lock_irqsave(&queue->lock, flags); 66 + 67 + dst = &queue->buf[queue->tail]; 68 + dst->index = src->index; 69 + dst->t.sec = seconds; 70 + dst->t.nsec = remainder; 71 + 72 + if (!queue_free(queue)) 73 + queue->head = (queue->head + 1) % PTP_MAX_TIMESTAMPS; 74 + 75 + queue->tail = (queue->tail + 1) % PTP_MAX_TIMESTAMPS; 76 + 77 + spin_unlock_irqrestore(&queue->lock, flags); 78 + } 79 + 80 + static s32 scaled_ppm_to_ppb(long ppm) 81 + { 82 + /* 83 + * The 'freq' field in the 'struct timex' is in parts per 84 + * million, but with a 16 bit binary fractional field. 85 + * 86 + * We want to calculate 87 + * 88 + * ppb = scaled_ppm * 1000 / 2^16 89 + * 90 + * which simplifies to 91 + * 92 + * ppb = scaled_ppm * 125 / 2^13 93 + */ 94 + s64 ppb = 1 + ppm; 95 + ppb *= 125; 96 + ppb >>= 13; 97 + return (s32) ppb; 98 + } 99 + 100 + /* posix clock implementation */ 101 + 102 + static int ptp_clock_getres(struct posix_clock *pc, struct timespec *tp) 103 + { 104 + return 1; /* always round timer functions to one nanosecond */ 105 + } 106 + 107 + static int ptp_clock_settime(struct posix_clock *pc, const struct timespec *tp) 108 + { 109 + struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); 110 + return ptp->info->settime(ptp->info, tp); 111 + } 112 + 113 + static int ptp_clock_gettime(struct posix_clock *pc, struct timespec *tp) 114 + { 115 + struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); 116 + return ptp->info->gettime(ptp->info, tp); 117 + } 118 + 119 + static int ptp_clock_adjtime(struct posix_clock *pc, struct timex *tx) 120 + { 121 + struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); 122 + struct ptp_clock_info *ops; 123 + int err = -EOPNOTSUPP; 124 + 125 + ops = ptp->info; 126 + 127 + if (tx->modes & ADJ_SETOFFSET) { 128 + struct timespec ts; 129 + ktime_t kt; 130 + s64 delta; 131 + 132 + ts.tv_sec = tx->time.tv_sec; 133 + ts.tv_nsec = tx->time.tv_usec; 134 + 135 + if (!(tx->modes & ADJ_NANO)) 136 + ts.tv_nsec *= 1000; 137 + 138 + if ((unsigned long) ts.tv_nsec >= NSEC_PER_SEC) 139 + return -EINVAL; 140 + 141 + kt = timespec_to_ktime(ts); 142 + delta = ktime_to_ns(kt); 143 + err = ops->adjtime(ops, delta); 144 + 145 + } else if (tx->modes & ADJ_FREQUENCY) { 146 + 147 + err = ops->adjfreq(ops, scaled_ppm_to_ppb(tx->freq)); 148 + } 149 + 150 + return err; 151 + } 152 + 153 + static struct posix_clock_operations ptp_clock_ops = { 154 + .owner = THIS_MODULE, 155 + .clock_adjtime = ptp_clock_adjtime, 156 + .clock_gettime = ptp_clock_gettime, 157 + .clock_getres = ptp_clock_getres, 158 + .clock_settime = ptp_clock_settime, 159 + .ioctl = ptp_ioctl, 160 + .open = ptp_open, 161 + .poll = ptp_poll, 162 + .read = ptp_read, 163 + }; 164 + 165 + static void delete_ptp_clock(struct posix_clock *pc) 166 + { 167 + struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); 168 + 169 + mutex_destroy(&ptp->tsevq_mux); 170 + 171 + /* Remove the clock from the bit map. */ 172 + mutex_lock(&ptp_clocks_mutex); 173 + clear_bit(ptp->index, ptp_clocks_map); 174 + mutex_unlock(&ptp_clocks_mutex); 175 + 176 + kfree(ptp); 177 + } 178 + 179 + /* public interface */ 180 + 181 + struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info) 182 + { 183 + struct ptp_clock *ptp; 184 + int err = 0, index, major = MAJOR(ptp_devt); 185 + 186 + if (info->n_alarm > PTP_MAX_ALARMS) 187 + return ERR_PTR(-EINVAL); 188 + 189 + /* Find a free clock slot and reserve it. */ 190 + err = -EBUSY; 191 + mutex_lock(&ptp_clocks_mutex); 192 + index = find_first_zero_bit(ptp_clocks_map, PTP_MAX_CLOCKS); 193 + if (index < PTP_MAX_CLOCKS) 194 + set_bit(index, ptp_clocks_map); 195 + else 196 + goto no_slot; 197 + 198 + /* Initialize a clock structure. */ 199 + err = -ENOMEM; 200 + ptp = kzalloc(sizeof(struct ptp_clock), GFP_KERNEL); 201 + if (ptp == NULL) 202 + goto no_memory; 203 + 204 + ptp->clock.ops = ptp_clock_ops; 205 + ptp->clock.release = delete_ptp_clock; 206 + ptp->info = info; 207 + ptp->devid = MKDEV(major, index); 208 + ptp->index = index; 209 + spin_lock_init(&ptp->tsevq.lock); 210 + mutex_init(&ptp->tsevq_mux); 211 + init_waitqueue_head(&ptp->tsev_wq); 212 + 213 + /* Create a new device in our class. */ 214 + ptp->dev = device_create(ptp_class, NULL, ptp->devid, ptp, 215 + "ptp%d", ptp->index); 216 + if (IS_ERR(ptp->dev)) 217 + goto no_device; 218 + 219 + dev_set_drvdata(ptp->dev, ptp); 220 + 221 + err = ptp_populate_sysfs(ptp); 222 + if (err) 223 + goto no_sysfs; 224 + 225 + /* Register a new PPS source. */ 226 + if (info->pps) { 227 + struct pps_source_info pps; 228 + memset(&pps, 0, sizeof(pps)); 229 + snprintf(pps.name, PPS_MAX_NAME_LEN, "ptp%d", index); 230 + pps.mode = PTP_PPS_MODE; 231 + pps.owner = info->owner; 232 + ptp->pps_source = pps_register_source(&pps, PTP_PPS_DEFAULTS); 233 + if (!ptp->pps_source) { 234 + pr_err("failed to register pps source\n"); 235 + goto no_pps; 236 + } 237 + } 238 + 239 + /* Create a posix clock. */ 240 + err = posix_clock_register(&ptp->clock, ptp->devid); 241 + if (err) { 242 + pr_err("failed to create posix clock\n"); 243 + goto no_clock; 244 + } 245 + 246 + mutex_unlock(&ptp_clocks_mutex); 247 + return ptp; 248 + 249 + no_clock: 250 + if (ptp->pps_source) 251 + pps_unregister_source(ptp->pps_source); 252 + no_pps: 253 + ptp_cleanup_sysfs(ptp); 254 + no_sysfs: 255 + device_destroy(ptp_class, ptp->devid); 256 + no_device: 257 + mutex_destroy(&ptp->tsevq_mux); 258 + kfree(ptp); 259 + no_memory: 260 + clear_bit(index, ptp_clocks_map); 261 + no_slot: 262 + mutex_unlock(&ptp_clocks_mutex); 263 + return ERR_PTR(err); 264 + } 265 + EXPORT_SYMBOL(ptp_clock_register); 266 + 267 + int ptp_clock_unregister(struct ptp_clock *ptp) 268 + { 269 + ptp->defunct = 1; 270 + wake_up_interruptible(&ptp->tsev_wq); 271 + 272 + /* Release the clock's resources. */ 273 + if (ptp->pps_source) 274 + pps_unregister_source(ptp->pps_source); 275 + ptp_cleanup_sysfs(ptp); 276 + device_destroy(ptp_class, ptp->devid); 277 + 278 + posix_clock_unregister(&ptp->clock); 279 + return 0; 280 + } 281 + EXPORT_SYMBOL(ptp_clock_unregister); 282 + 283 + void ptp_clock_event(struct ptp_clock *ptp, struct ptp_clock_event *event) 284 + { 285 + struct pps_event_time evt; 286 + 287 + switch (event->type) { 288 + 289 + case PTP_CLOCK_ALARM: 290 + break; 291 + 292 + case PTP_CLOCK_EXTTS: 293 + enqueue_external_timestamp(&ptp->tsevq, event); 294 + wake_up_interruptible(&ptp->tsev_wq); 295 + break; 296 + 297 + case PTP_CLOCK_PPS: 298 + pps_get_ts(&evt); 299 + pps_event(ptp->pps_source, &evt, PTP_PPS_EVENT, NULL); 300 + break; 301 + } 302 + } 303 + EXPORT_SYMBOL(ptp_clock_event); 304 + 305 + /* module operations */ 306 + 307 + static void __exit ptp_exit(void) 308 + { 309 + class_destroy(ptp_class); 310 + unregister_chrdev_region(ptp_devt, PTP_MAX_CLOCKS); 311 + } 312 + 313 + static int __init ptp_init(void) 314 + { 315 + int err; 316 + 317 + ptp_class = class_create(THIS_MODULE, "ptp"); 318 + if (IS_ERR(ptp_class)) { 319 + pr_err("ptp: failed to allocate class\n"); 320 + return PTR_ERR(ptp_class); 321 + } 322 + 323 + err = alloc_chrdev_region(&ptp_devt, 0, PTP_MAX_CLOCKS, "ptp"); 324 + if (err < 0) { 325 + pr_err("ptp: failed to allocate device region\n"); 326 + goto no_region; 327 + } 328 + 329 + ptp_class->dev_attrs = ptp_dev_attrs; 330 + pr_info("PTP clock support registered\n"); 331 + return 0; 332 + 333 + no_region: 334 + class_destroy(ptp_class); 335 + return err; 336 + } 337 + 338 + subsys_initcall(ptp_init); 339 + module_exit(ptp_exit); 340 + 341 + MODULE_AUTHOR("Richard Cochran <richard.cochran@omicron.at>"); 342 + MODULE_DESCRIPTION("PTP clocks support"); 343 + MODULE_LICENSE("GPL");
+332
drivers/ptp/ptp_ixp46x.c
··· 1 + /* 2 + * PTP 1588 clock using the IXP46X 3 + * 4 + * Copyright (C) 2010 OMICRON electronics GmbH 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program; if not, write to the Free Software 18 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 + */ 20 + #include <linux/device.h> 21 + #include <linux/err.h> 22 + #include <linux/gpio.h> 23 + #include <linux/init.h> 24 + #include <linux/interrupt.h> 25 + #include <linux/io.h> 26 + #include <linux/irq.h> 27 + #include <linux/kernel.h> 28 + #include <linux/module.h> 29 + 30 + #include <linux/ptp_clock_kernel.h> 31 + #include <mach/ixp46x_ts.h> 32 + 33 + #define DRIVER "ptp_ixp46x" 34 + #define N_EXT_TS 2 35 + #define MASTER_GPIO 8 36 + #define MASTER_IRQ 25 37 + #define SLAVE_GPIO 7 38 + #define SLAVE_IRQ 24 39 + 40 + struct ixp_clock { 41 + struct ixp46x_ts_regs *regs; 42 + struct ptp_clock *ptp_clock; 43 + struct ptp_clock_info caps; 44 + int exts0_enabled; 45 + int exts1_enabled; 46 + }; 47 + 48 + DEFINE_SPINLOCK(register_lock); 49 + 50 + /* 51 + * Register access functions 52 + */ 53 + 54 + static u64 ixp_systime_read(struct ixp46x_ts_regs *regs) 55 + { 56 + u64 ns; 57 + u32 lo, hi; 58 + 59 + lo = __raw_readl(&regs->systime_lo); 60 + hi = __raw_readl(&regs->systime_hi); 61 + 62 + ns = ((u64) hi) << 32; 63 + ns |= lo; 64 + ns <<= TICKS_NS_SHIFT; 65 + 66 + return ns; 67 + } 68 + 69 + static void ixp_systime_write(struct ixp46x_ts_regs *regs, u64 ns) 70 + { 71 + u32 hi, lo; 72 + 73 + ns >>= TICKS_NS_SHIFT; 74 + hi = ns >> 32; 75 + lo = ns & 0xffffffff; 76 + 77 + __raw_writel(lo, &regs->systime_lo); 78 + __raw_writel(hi, &regs->systime_hi); 79 + } 80 + 81 + /* 82 + * Interrupt service routine 83 + */ 84 + 85 + static irqreturn_t isr(int irq, void *priv) 86 + { 87 + struct ixp_clock *ixp_clock = priv; 88 + struct ixp46x_ts_regs *regs = ixp_clock->regs; 89 + struct ptp_clock_event event; 90 + u32 ack = 0, lo, hi, val; 91 + 92 + val = __raw_readl(&regs->event); 93 + 94 + if (val & TSER_SNS) { 95 + ack |= TSER_SNS; 96 + if (ixp_clock->exts0_enabled) { 97 + hi = __raw_readl(&regs->asms_hi); 98 + lo = __raw_readl(&regs->asms_lo); 99 + event.type = PTP_CLOCK_EXTTS; 100 + event.index = 0; 101 + event.timestamp = ((u64) hi) << 32; 102 + event.timestamp |= lo; 103 + event.timestamp <<= TICKS_NS_SHIFT; 104 + ptp_clock_event(ixp_clock->ptp_clock, &event); 105 + } 106 + } 107 + 108 + if (val & TSER_SNM) { 109 + ack |= TSER_SNM; 110 + if (ixp_clock->exts1_enabled) { 111 + hi = __raw_readl(&regs->amms_hi); 112 + lo = __raw_readl(&regs->amms_lo); 113 + event.type = PTP_CLOCK_EXTTS; 114 + event.index = 1; 115 + event.timestamp = ((u64) hi) << 32; 116 + event.timestamp |= lo; 117 + event.timestamp <<= TICKS_NS_SHIFT; 118 + ptp_clock_event(ixp_clock->ptp_clock, &event); 119 + } 120 + } 121 + 122 + if (val & TTIPEND) 123 + ack |= TTIPEND; /* this bit seems to be always set */ 124 + 125 + if (ack) { 126 + __raw_writel(ack, &regs->event); 127 + return IRQ_HANDLED; 128 + } else 129 + return IRQ_NONE; 130 + } 131 + 132 + /* 133 + * PTP clock operations 134 + */ 135 + 136 + static int ptp_ixp_adjfreq(struct ptp_clock_info *ptp, s32 ppb) 137 + { 138 + u64 adj; 139 + u32 diff, addend; 140 + int neg_adj = 0; 141 + struct ixp_clock *ixp_clock = container_of(ptp, struct ixp_clock, caps); 142 + struct ixp46x_ts_regs *regs = ixp_clock->regs; 143 + 144 + if (ppb < 0) { 145 + neg_adj = 1; 146 + ppb = -ppb; 147 + } 148 + addend = DEFAULT_ADDEND; 149 + adj = addend; 150 + adj *= ppb; 151 + diff = div_u64(adj, 1000000000ULL); 152 + 153 + addend = neg_adj ? addend - diff : addend + diff; 154 + 155 + __raw_writel(addend, &regs->addend); 156 + 157 + return 0; 158 + } 159 + 160 + static int ptp_ixp_adjtime(struct ptp_clock_info *ptp, s64 delta) 161 + { 162 + s64 now; 163 + unsigned long flags; 164 + struct ixp_clock *ixp_clock = container_of(ptp, struct ixp_clock, caps); 165 + struct ixp46x_ts_regs *regs = ixp_clock->regs; 166 + 167 + spin_lock_irqsave(&register_lock, flags); 168 + 169 + now = ixp_systime_read(regs); 170 + now += delta; 171 + ixp_systime_write(regs, now); 172 + 173 + spin_unlock_irqrestore(&register_lock, flags); 174 + 175 + return 0; 176 + } 177 + 178 + static int ptp_ixp_gettime(struct ptp_clock_info *ptp, struct timespec *ts) 179 + { 180 + u64 ns; 181 + u32 remainder; 182 + unsigned long flags; 183 + struct ixp_clock *ixp_clock = container_of(ptp, struct ixp_clock, caps); 184 + struct ixp46x_ts_regs *regs = ixp_clock->regs; 185 + 186 + spin_lock_irqsave(&register_lock, flags); 187 + 188 + ns = ixp_systime_read(regs); 189 + 190 + spin_unlock_irqrestore(&register_lock, flags); 191 + 192 + ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder); 193 + ts->tv_nsec = remainder; 194 + return 0; 195 + } 196 + 197 + static int ptp_ixp_settime(struct ptp_clock_info *ptp, 198 + const struct timespec *ts) 199 + { 200 + u64 ns; 201 + unsigned long flags; 202 + struct ixp_clock *ixp_clock = container_of(ptp, struct ixp_clock, caps); 203 + struct ixp46x_ts_regs *regs = ixp_clock->regs; 204 + 205 + ns = ts->tv_sec * 1000000000ULL; 206 + ns += ts->tv_nsec; 207 + 208 + spin_lock_irqsave(&register_lock, flags); 209 + 210 + ixp_systime_write(regs, ns); 211 + 212 + spin_unlock_irqrestore(&register_lock, flags); 213 + 214 + return 0; 215 + } 216 + 217 + static int ptp_ixp_enable(struct ptp_clock_info *ptp, 218 + struct ptp_clock_request *rq, int on) 219 + { 220 + struct ixp_clock *ixp_clock = container_of(ptp, struct ixp_clock, caps); 221 + 222 + switch (rq->type) { 223 + case PTP_CLK_REQ_EXTTS: 224 + switch (rq->extts.index) { 225 + case 0: 226 + ixp_clock->exts0_enabled = on ? 1 : 0; 227 + break; 228 + case 1: 229 + ixp_clock->exts1_enabled = on ? 1 : 0; 230 + break; 231 + default: 232 + return -EINVAL; 233 + } 234 + return 0; 235 + default: 236 + break; 237 + } 238 + 239 + return -EOPNOTSUPP; 240 + } 241 + 242 + static struct ptp_clock_info ptp_ixp_caps = { 243 + .owner = THIS_MODULE, 244 + .name = "IXP46X timer", 245 + .max_adj = 66666655, 246 + .n_ext_ts = N_EXT_TS, 247 + .pps = 0, 248 + .adjfreq = ptp_ixp_adjfreq, 249 + .adjtime = ptp_ixp_adjtime, 250 + .gettime = ptp_ixp_gettime, 251 + .settime = ptp_ixp_settime, 252 + .enable = ptp_ixp_enable, 253 + }; 254 + 255 + /* module operations */ 256 + 257 + static struct ixp_clock ixp_clock; 258 + 259 + static int setup_interrupt(int gpio) 260 + { 261 + int irq; 262 + 263 + gpio_line_config(gpio, IXP4XX_GPIO_IN); 264 + 265 + irq = gpio_to_irq(gpio); 266 + 267 + if (NO_IRQ == irq) 268 + return NO_IRQ; 269 + 270 + if (irq_set_irq_type(irq, IRQF_TRIGGER_FALLING)) { 271 + pr_err("cannot set trigger type for irq %d\n", irq); 272 + return NO_IRQ; 273 + } 274 + 275 + if (request_irq(irq, isr, 0, DRIVER, &ixp_clock)) { 276 + pr_err("request_irq failed for irq %d\n", irq); 277 + return NO_IRQ; 278 + } 279 + 280 + return irq; 281 + } 282 + 283 + static void __exit ptp_ixp_exit(void) 284 + { 285 + free_irq(MASTER_IRQ, &ixp_clock); 286 + free_irq(SLAVE_IRQ, &ixp_clock); 287 + ptp_clock_unregister(ixp_clock.ptp_clock); 288 + } 289 + 290 + static int __init ptp_ixp_init(void) 291 + { 292 + if (!cpu_is_ixp46x()) 293 + return -ENODEV; 294 + 295 + ixp_clock.regs = 296 + (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT; 297 + 298 + ixp_clock.caps = ptp_ixp_caps; 299 + 300 + ixp_clock.ptp_clock = ptp_clock_register(&ixp_clock.caps); 301 + 302 + if (IS_ERR(ixp_clock.ptp_clock)) 303 + return PTR_ERR(ixp_clock.ptp_clock); 304 + 305 + __raw_writel(DEFAULT_ADDEND, &ixp_clock.regs->addend); 306 + __raw_writel(1, &ixp_clock.regs->trgt_lo); 307 + __raw_writel(0, &ixp_clock.regs->trgt_hi); 308 + __raw_writel(TTIPEND, &ixp_clock.regs->event); 309 + 310 + if (MASTER_IRQ != setup_interrupt(MASTER_GPIO)) { 311 + pr_err("failed to setup gpio %d as irq\n", MASTER_GPIO); 312 + goto no_master; 313 + } 314 + if (SLAVE_IRQ != setup_interrupt(SLAVE_GPIO)) { 315 + pr_err("failed to setup gpio %d as irq\n", SLAVE_GPIO); 316 + goto no_slave; 317 + } 318 + 319 + return 0; 320 + no_slave: 321 + free_irq(MASTER_IRQ, &ixp_clock); 322 + no_master: 323 + ptp_clock_unregister(ixp_clock.ptp_clock); 324 + return -ENODEV; 325 + } 326 + 327 + module_init(ptp_ixp_init); 328 + module_exit(ptp_ixp_exit); 329 + 330 + MODULE_AUTHOR("Richard Cochran <richard.cochran@omicron.at>"); 331 + MODULE_DESCRIPTION("PTP clock using the IXP46X timer"); 332 + MODULE_LICENSE("GPL");
+92
drivers/ptp/ptp_private.h
··· 1 + /* 2 + * PTP 1588 clock support - private declarations for the core module. 3 + * 4 + * Copyright (C) 2010 OMICRON electronics GmbH 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program; if not, write to the Free Software 18 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 + */ 20 + #ifndef _PTP_PRIVATE_H_ 21 + #define _PTP_PRIVATE_H_ 22 + 23 + #include <linux/cdev.h> 24 + #include <linux/device.h> 25 + #include <linux/mutex.h> 26 + #include <linux/posix-clock.h> 27 + #include <linux/ptp_clock.h> 28 + #include <linux/ptp_clock_kernel.h> 29 + #include <linux/time.h> 30 + 31 + #define PTP_MAX_TIMESTAMPS 128 32 + #define PTP_BUF_TIMESTAMPS 30 33 + 34 + struct timestamp_event_queue { 35 + struct ptp_extts_event buf[PTP_MAX_TIMESTAMPS]; 36 + int head; 37 + int tail; 38 + spinlock_t lock; 39 + }; 40 + 41 + struct ptp_clock { 42 + struct posix_clock clock; 43 + struct device *dev; 44 + struct ptp_clock_info *info; 45 + dev_t devid; 46 + int index; /* index into clocks.map */ 47 + struct pps_device *pps_source; 48 + struct timestamp_event_queue tsevq; /* simple fifo for time stamps */ 49 + struct mutex tsevq_mux; /* one process at a time reading the fifo */ 50 + wait_queue_head_t tsev_wq; 51 + int defunct; /* tells readers to go away when clock is being removed */ 52 + }; 53 + 54 + /* 55 + * The function queue_cnt() is safe for readers to call without 56 + * holding q->lock. Readers use this function to verify that the queue 57 + * is nonempty before proceeding with a dequeue operation. The fact 58 + * that a writer might concurrently increment the tail does not 59 + * matter, since the queue remains nonempty nonetheless. 60 + */ 61 + static inline int queue_cnt(struct timestamp_event_queue *q) 62 + { 63 + int cnt = q->tail - q->head; 64 + return cnt < 0 ? PTP_MAX_TIMESTAMPS + cnt : cnt; 65 + } 66 + 67 + /* 68 + * see ptp_chardev.c 69 + */ 70 + 71 + long ptp_ioctl(struct posix_clock *pc, 72 + unsigned int cmd, unsigned long arg); 73 + 74 + int ptp_open(struct posix_clock *pc, fmode_t fmode); 75 + 76 + ssize_t ptp_read(struct posix_clock *pc, 77 + uint flags, char __user *buf, size_t cnt); 78 + 79 + uint ptp_poll(struct posix_clock *pc, 80 + struct file *fp, poll_table *wait); 81 + 82 + /* 83 + * see ptp_sysfs.c 84 + */ 85 + 86 + extern struct device_attribute ptp_dev_attrs[]; 87 + 88 + int ptp_cleanup_sysfs(struct ptp_clock *ptp); 89 + 90 + int ptp_populate_sysfs(struct ptp_clock *ptp); 91 + 92 + #endif
+230
drivers/ptp/ptp_sysfs.c
··· 1 + /* 2 + * PTP 1588 clock support - sysfs interface. 3 + * 4 + * Copyright (C) 2010 OMICRON electronics GmbH 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program; if not, write to the Free Software 18 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 + */ 20 + #include <linux/capability.h> 21 + 22 + #include "ptp_private.h" 23 + 24 + static ssize_t clock_name_show(struct device *dev, 25 + struct device_attribute *attr, char *page) 26 + { 27 + struct ptp_clock *ptp = dev_get_drvdata(dev); 28 + return snprintf(page, PAGE_SIZE-1, "%s\n", ptp->info->name); 29 + } 30 + 31 + #define PTP_SHOW_INT(name) \ 32 + static ssize_t name##_show(struct device *dev, \ 33 + struct device_attribute *attr, char *page) \ 34 + { \ 35 + struct ptp_clock *ptp = dev_get_drvdata(dev); \ 36 + return snprintf(page, PAGE_SIZE-1, "%d\n", ptp->info->name); \ 37 + } 38 + 39 + PTP_SHOW_INT(max_adj); 40 + PTP_SHOW_INT(n_alarm); 41 + PTP_SHOW_INT(n_ext_ts); 42 + PTP_SHOW_INT(n_per_out); 43 + PTP_SHOW_INT(pps); 44 + 45 + #define PTP_RO_ATTR(_var, _name) { \ 46 + .attr = { .name = __stringify(_name), .mode = 0444 }, \ 47 + .show = _var##_show, \ 48 + } 49 + 50 + struct device_attribute ptp_dev_attrs[] = { 51 + PTP_RO_ATTR(clock_name, clock_name), 52 + PTP_RO_ATTR(max_adj, max_adjustment), 53 + PTP_RO_ATTR(n_alarm, n_alarms), 54 + PTP_RO_ATTR(n_ext_ts, n_external_timestamps), 55 + PTP_RO_ATTR(n_per_out, n_periodic_outputs), 56 + PTP_RO_ATTR(pps, pps_available), 57 + __ATTR_NULL, 58 + }; 59 + 60 + static ssize_t extts_enable_store(struct device *dev, 61 + struct device_attribute *attr, 62 + const char *buf, size_t count) 63 + { 64 + struct ptp_clock *ptp = dev_get_drvdata(dev); 65 + struct ptp_clock_info *ops = ptp->info; 66 + struct ptp_clock_request req = { .type = PTP_CLK_REQ_EXTTS }; 67 + int cnt, enable; 68 + int err = -EINVAL; 69 + 70 + cnt = sscanf(buf, "%u %d", &req.extts.index, &enable); 71 + if (cnt != 2) 72 + goto out; 73 + if (req.extts.index >= ops->n_ext_ts) 74 + goto out; 75 + 76 + err = ops->enable(ops, &req, enable ? 1 : 0); 77 + if (err) 78 + goto out; 79 + 80 + return count; 81 + out: 82 + return err; 83 + } 84 + 85 + static ssize_t extts_fifo_show(struct device *dev, 86 + struct device_attribute *attr, char *page) 87 + { 88 + struct ptp_clock *ptp = dev_get_drvdata(dev); 89 + struct timestamp_event_queue *queue = &ptp->tsevq; 90 + struct ptp_extts_event event; 91 + unsigned long flags; 92 + size_t qcnt; 93 + int cnt = 0; 94 + 95 + memset(&event, 0, sizeof(event)); 96 + 97 + if (mutex_lock_interruptible(&ptp->tsevq_mux)) 98 + return -ERESTARTSYS; 99 + 100 + spin_lock_irqsave(&queue->lock, flags); 101 + qcnt = queue_cnt(queue); 102 + if (qcnt) { 103 + event = queue->buf[queue->head]; 104 + queue->head = (queue->head + 1) % PTP_MAX_TIMESTAMPS; 105 + } 106 + spin_unlock_irqrestore(&queue->lock, flags); 107 + 108 + if (!qcnt) 109 + goto out; 110 + 111 + cnt = snprintf(page, PAGE_SIZE, "%u %lld %u\n", 112 + event.index, event.t.sec, event.t.nsec); 113 + out: 114 + mutex_unlock(&ptp->tsevq_mux); 115 + return cnt; 116 + } 117 + 118 + static ssize_t period_store(struct device *dev, 119 + struct device_attribute *attr, 120 + const char *buf, size_t count) 121 + { 122 + struct ptp_clock *ptp = dev_get_drvdata(dev); 123 + struct ptp_clock_info *ops = ptp->info; 124 + struct ptp_clock_request req = { .type = PTP_CLK_REQ_PEROUT }; 125 + int cnt, enable, err = -EINVAL; 126 + 127 + cnt = sscanf(buf, "%u %lld %u %lld %u", &req.perout.index, 128 + &req.perout.start.sec, &req.perout.start.nsec, 129 + &req.perout.period.sec, &req.perout.period.nsec); 130 + if (cnt != 5) 131 + goto out; 132 + if (req.perout.index >= ops->n_per_out) 133 + goto out; 134 + 135 + enable = req.perout.period.sec || req.perout.period.nsec; 136 + err = ops->enable(ops, &req, enable); 137 + if (err) 138 + goto out; 139 + 140 + return count; 141 + out: 142 + return err; 143 + } 144 + 145 + static ssize_t pps_enable_store(struct device *dev, 146 + struct device_attribute *attr, 147 + const char *buf, size_t count) 148 + { 149 + struct ptp_clock *ptp = dev_get_drvdata(dev); 150 + struct ptp_clock_info *ops = ptp->info; 151 + struct ptp_clock_request req = { .type = PTP_CLK_REQ_PPS }; 152 + int cnt, enable; 153 + int err = -EINVAL; 154 + 155 + if (!capable(CAP_SYS_TIME)) 156 + return -EPERM; 157 + 158 + cnt = sscanf(buf, "%d", &enable); 159 + if (cnt != 1) 160 + goto out; 161 + 162 + err = ops->enable(ops, &req, enable ? 1 : 0); 163 + if (err) 164 + goto out; 165 + 166 + return count; 167 + out: 168 + return err; 169 + } 170 + 171 + static DEVICE_ATTR(extts_enable, 0220, NULL, extts_enable_store); 172 + static DEVICE_ATTR(fifo, 0444, extts_fifo_show, NULL); 173 + static DEVICE_ATTR(period, 0220, NULL, period_store); 174 + static DEVICE_ATTR(pps_enable, 0220, NULL, pps_enable_store); 175 + 176 + int ptp_cleanup_sysfs(struct ptp_clock *ptp) 177 + { 178 + struct device *dev = ptp->dev; 179 + struct ptp_clock_info *info = ptp->info; 180 + 181 + if (info->n_ext_ts) { 182 + device_remove_file(dev, &dev_attr_extts_enable); 183 + device_remove_file(dev, &dev_attr_fifo); 184 + } 185 + if (info->n_per_out) 186 + device_remove_file(dev, &dev_attr_period); 187 + 188 + if (info->pps) 189 + device_remove_file(dev, &dev_attr_pps_enable); 190 + 191 + return 0; 192 + } 193 + 194 + int ptp_populate_sysfs(struct ptp_clock *ptp) 195 + { 196 + struct device *dev = ptp->dev; 197 + struct ptp_clock_info *info = ptp->info; 198 + int err; 199 + 200 + if (info->n_ext_ts) { 201 + err = device_create_file(dev, &dev_attr_extts_enable); 202 + if (err) 203 + goto out1; 204 + err = device_create_file(dev, &dev_attr_fifo); 205 + if (err) 206 + goto out2; 207 + } 208 + if (info->n_per_out) { 209 + err = device_create_file(dev, &dev_attr_period); 210 + if (err) 211 + goto out3; 212 + } 213 + if (info->pps) { 214 + err = device_create_file(dev, &dev_attr_pps_enable); 215 + if (err) 216 + goto out4; 217 + } 218 + return 0; 219 + out4: 220 + if (info->n_per_out) 221 + device_remove_file(dev, &dev_attr_period); 222 + out3: 223 + if (info->n_ext_ts) 224 + device_remove_file(dev, &dev_attr_fifo); 225 + out2: 226 + if (info->n_ext_ts) 227 + device_remove_file(dev, &dev_attr_extts_enable); 228 + out1: 229 + return err; 230 + }
+1
include/linux/Kbuild
··· 302 302 header-y += ppp_defs.h 303 303 header-y += pps.h 304 304 header-y += prctl.h 305 + header-y += ptp_clock.h 305 306 header-y += ptrace.h 306 307 header-y += qnx4_fs.h 307 308 header-y += qnxtypes.h
+7
include/linux/ptp_classify.h
··· 25 25 26 26 #include <linux/if_ether.h> 27 27 #include <linux/if_vlan.h> 28 + #include <linux/ip.h> 28 29 #include <linux/filter.h> 29 30 #ifdef __KERNEL__ 30 31 #include <linux/in.h> ··· 58 57 #define OFF_PROTO4 23 59 58 #define OFF_NEXT 6 60 59 #define OFF_UDP_DST 2 60 + 61 + #define OFF_PTP_SOURCE_UUID 22 /* PTPv1 only */ 62 + #define OFF_PTP_SEQUENCE_ID 30 63 + #define OFF_PTP_CONTROL 32 /* PTPv1 only */ 64 + 65 + #define IPV4_HLEN(data) (((struct iphdr *)(data + OFF_IHL))->ihl << 2) 61 66 62 67 #define IP6_HLEN 40 63 68 #define UDP_HLEN 8
+84
include/linux/ptp_clock.h
··· 1 + /* 2 + * PTP 1588 clock support - user space interface 3 + * 4 + * Copyright (C) 2010 OMICRON electronics GmbH 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program; if not, write to the Free Software 18 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 + */ 20 + 21 + #ifndef _PTP_CLOCK_H_ 22 + #define _PTP_CLOCK_H_ 23 + 24 + #include <linux/ioctl.h> 25 + #include <linux/types.h> 26 + 27 + /* PTP_xxx bits, for the flags field within the request structures. */ 28 + #define PTP_ENABLE_FEATURE (1<<0) 29 + #define PTP_RISING_EDGE (1<<1) 30 + #define PTP_FALLING_EDGE (1<<2) 31 + 32 + /* 33 + * struct ptp_clock_time - represents a time value 34 + * 35 + * The sign of the seconds field applies to the whole value. The 36 + * nanoseconds field is always unsigned. The reserved field is 37 + * included for sub-nanosecond resolution, should the demand for 38 + * this ever appear. 39 + * 40 + */ 41 + struct ptp_clock_time { 42 + __s64 sec; /* seconds */ 43 + __u32 nsec; /* nanoseconds */ 44 + __u32 reserved; 45 + }; 46 + 47 + struct ptp_clock_caps { 48 + int max_adj; /* Maximum frequency adjustment in parts per billon. */ 49 + int n_alarm; /* Number of programmable alarms. */ 50 + int n_ext_ts; /* Number of external time stamp channels. */ 51 + int n_per_out; /* Number of programmable periodic signals. */ 52 + int pps; /* Whether the clock supports a PPS callback. */ 53 + int rsv[15]; /* Reserved for future use. */ 54 + }; 55 + 56 + struct ptp_extts_request { 57 + unsigned int index; /* Which channel to configure. */ 58 + unsigned int flags; /* Bit field for PTP_xxx flags. */ 59 + unsigned int rsv[2]; /* Reserved for future use. */ 60 + }; 61 + 62 + struct ptp_perout_request { 63 + struct ptp_clock_time start; /* Absolute start time. */ 64 + struct ptp_clock_time period; /* Desired period, zero means disable. */ 65 + unsigned int index; /* Which channel to configure. */ 66 + unsigned int flags; /* Reserved for future use. */ 67 + unsigned int rsv[4]; /* Reserved for future use. */ 68 + }; 69 + 70 + #define PTP_CLK_MAGIC '=' 71 + 72 + #define PTP_CLOCK_GETCAPS _IOR(PTP_CLK_MAGIC, 1, struct ptp_clock_caps) 73 + #define PTP_EXTTS_REQUEST _IOW(PTP_CLK_MAGIC, 2, struct ptp_extts_request) 74 + #define PTP_PEROUT_REQUEST _IOW(PTP_CLK_MAGIC, 3, struct ptp_perout_request) 75 + #define PTP_ENABLE_PPS _IOW(PTP_CLK_MAGIC, 4, int) 76 + 77 + struct ptp_extts_event { 78 + struct ptp_clock_time t; /* Time event occured. */ 79 + unsigned int index; /* Which channel produced the event. */ 80 + unsigned int flags; /* Reserved for future use. */ 81 + unsigned int rsv[2]; /* Reserved for future use. */ 82 + }; 83 + 84 + #endif
+139
include/linux/ptp_clock_kernel.h
··· 1 + /* 2 + * PTP 1588 clock support 3 + * 4 + * Copyright (C) 2010 OMICRON electronics GmbH 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program; if not, write to the Free Software 18 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 + */ 20 + 21 + #ifndef _PTP_CLOCK_KERNEL_H_ 22 + #define _PTP_CLOCK_KERNEL_H_ 23 + 24 + #include <linux/ptp_clock.h> 25 + 26 + 27 + struct ptp_clock_request { 28 + enum { 29 + PTP_CLK_REQ_EXTTS, 30 + PTP_CLK_REQ_PEROUT, 31 + PTP_CLK_REQ_PPS, 32 + } type; 33 + union { 34 + struct ptp_extts_request extts; 35 + struct ptp_perout_request perout; 36 + }; 37 + }; 38 + 39 + /** 40 + * struct ptp_clock_info - decribes a PTP hardware clock 41 + * 42 + * @owner: The clock driver should set to THIS_MODULE. 43 + * @name: A short name to identify the clock. 44 + * @max_adj: The maximum possible frequency adjustment, in parts per billon. 45 + * @n_alarm: The number of programmable alarms. 46 + * @n_ext_ts: The number of external time stamp channels. 47 + * @n_per_out: The number of programmable periodic signals. 48 + * @pps: Indicates whether the clock supports a PPS callback. 49 + * 50 + * clock operations 51 + * 52 + * @adjfreq: Adjusts the frequency of the hardware clock. 53 + * parameter delta: Desired period change in parts per billion. 54 + * 55 + * @adjtime: Shifts the time of the hardware clock. 56 + * parameter delta: Desired change in nanoseconds. 57 + * 58 + * @gettime: Reads the current time from the hardware clock. 59 + * parameter ts: Holds the result. 60 + * 61 + * @settime: Set the current time on the hardware clock. 62 + * parameter ts: Time value to set. 63 + * 64 + * @enable: Request driver to enable or disable an ancillary feature. 65 + * parameter request: Desired resource to enable or disable. 66 + * parameter on: Caller passes one to enable or zero to disable. 67 + * 68 + * Drivers should embed their ptp_clock_info within a private 69 + * structure, obtaining a reference to it using container_of(). 70 + * 71 + * The callbacks must all return zero on success, non-zero otherwise. 72 + */ 73 + 74 + struct ptp_clock_info { 75 + struct module *owner; 76 + char name[16]; 77 + s32 max_adj; 78 + int n_alarm; 79 + int n_ext_ts; 80 + int n_per_out; 81 + int pps; 82 + int (*adjfreq)(struct ptp_clock_info *ptp, s32 delta); 83 + int (*adjtime)(struct ptp_clock_info *ptp, s64 delta); 84 + int (*gettime)(struct ptp_clock_info *ptp, struct timespec *ts); 85 + int (*settime)(struct ptp_clock_info *ptp, const struct timespec *ts); 86 + int (*enable)(struct ptp_clock_info *ptp, 87 + struct ptp_clock_request *request, int on); 88 + }; 89 + 90 + struct ptp_clock; 91 + 92 + /** 93 + * ptp_clock_register() - register a PTP hardware clock driver 94 + * 95 + * @info: Structure describing the new clock. 96 + */ 97 + 98 + extern struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info); 99 + 100 + /** 101 + * ptp_clock_unregister() - unregister a PTP hardware clock driver 102 + * 103 + * @ptp: The clock to remove from service. 104 + */ 105 + 106 + extern int ptp_clock_unregister(struct ptp_clock *ptp); 107 + 108 + 109 + enum ptp_clock_events { 110 + PTP_CLOCK_ALARM, 111 + PTP_CLOCK_EXTTS, 112 + PTP_CLOCK_PPS, 113 + }; 114 + 115 + /** 116 + * struct ptp_clock_event - decribes a PTP hardware clock event 117 + * 118 + * @type: One of the ptp_clock_events enumeration values. 119 + * @index: Identifies the source of the event. 120 + * @timestamp: When the event occured. 121 + */ 122 + 123 + struct ptp_clock_event { 124 + int type; 125 + int index; 126 + u64 timestamp; 127 + }; 128 + 129 + /** 130 + * ptp_clock_event() - notify the PTP layer about an event 131 + * 132 + * @ptp: The clock obtained from ptp_clock_register(). 133 + * @event: Message structure describing the event. 134 + */ 135 + 136 + extern void ptp_clock_event(struct ptp_clock *ptp, 137 + struct ptp_clock_event *event); 138 + 139 + #endif