ptp: dynamic pin control
Subsystems (14)
Richard Cochran
maintainercover ptp: dynamic pin control
This patch series introduces a way of changing the auxiliary PTP Hardware Clock functions (periodic output signals and time stamping external signals) at run time. In the past on the netdev list, we have discussed other ways to handle this, such as module parameters and ethtool. This series implements a new PHC ioctl because that is the most natural way. Users already activate the auxiliary functions via the ioctls. The sysfs interface has also been expanded so that the pin configuration can be programmed using shell scripts.
The first patch adds the new ioctls. The PHC subsystem does most of the work of maintaining the function-to-pin mapping. Drivers will only need to allocate and initialize a pin configuration table and also provide a new method that validates a particular assignment.
Patches 5 and 6 just clean up a couple of issues in the phyter driver, and the remaining patches actually hook the phyter's pins into the new system.
Comments and questions are most welcome.
Thanks,
Richard
Richard Cochran (9):
ptp: introduce programmable pins.
ptp: add the pin GET/SETFUNC ioctls to the testptp program.
ptp: expose the programmable pins via sysfs
ptp: drivers: set the number of programmable pins.
dp83640: trivial fixes
dp83640: correct the periodic output frequency
dp83640: implement programmable pin functions.
dp83640: let external input pins from the module parameters be
defaults.
dp83640: let the periodic pin from the module parameter be a default.
Documentation/ABI/testing/sysfs-ptp | 20 ++++ Documentation/ptp/testptp.c | 58 +++++++++- drivers/net/ethernet/adi/bfin_mac.c | 1 + drivers/net/ethernet/broadcom/tg3.c | 1 + drivers/net/ethernet/freescale/fec_ptp.c | 1 + drivers/net/ethernet/freescale/gianfar_ptp.c | 1 + drivers/net/ethernet/intel/e1000e/ptp.c | 1 + drivers/net/ethernet/mellanox/mlx4/en_clock.c | 1 + drivers/net/ethernet/sfc/ptp.c | 1 + drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c | 1 + drivers/net/ethernet/ti/cpts.c | 1 + drivers/net/ethernet/tile/tilegx.c | 1 + drivers/net/phy/dp83640.c | 93 ++++++++++++--- drivers/ptp/ptp_chardev.c | 133 +++++++++++++++++++++- drivers/ptp/ptp_clock.c | 23 ++++ drivers/ptp/ptp_ixp46x.c | 1 + drivers/ptp/ptp_pch.c | 1 + drivers/ptp/ptp_private.h | 7 ++ drivers/ptp/ptp_sysfs.c | 109 ++++++++++++++++++ include/linux/ptp_clock_kernel.h | 33 ++++++ include/uapi/linux/ptp_clock.h | 39 ++++++- 21 files changed, 507 insertions(+), 20 deletions(-)
Signature · 1 line
1.7.10.4
Richard Cochran
maintainerRFC PATCH 1/9 ptp: introduce programmable pins.
This patch adds a pair of new ioctls to the PTP Hardware Clock device interface. Using the ioctls, user space programs can query each pin to find out its current function and also reprogram a different function if desired.
--- drivers/ptp/ptp_chardev.c | 133 +++++++++++++++++++++++++++++++++++++- drivers/ptp/ptp_clock.c | 23 +++++++ drivers/ptp/ptp_private.h | 4 ++ include/linux/ptp_clock_kernel.h | 33 ++++++++++ include/uapi/linux/ptp_clock.h | 39 ++++++++++- 5 files changed, 230 insertions(+), 2 deletions(-)
drivers/ptp/ptp_chardev.c +132 -1
@@ -25,6 +25,104 @@#include "ptp_private.h" +static int ptp_disable_pinfunc (struct ptp_clock_info *ops, +enum ptp_pin_function func,unsigned int chan) +{ +struct ptp_clock_request rq; +int err =0 ; + +memset (&rq,0 ,sizeof (rq)); + +switch (func) { +case PTP_PF_NONE : +break ; +case PTP_PF_EXTTS : + rq.type =PTP_CLK_REQ_EXTTS ; + rq.extts.index = chan; + err = ops->enable (ops, &rq,0 ); +break ; +case PTP_PF_PEROUT : + rq.type =PTP_CLK_REQ_PEROUT ; + rq.perout.index = chan; + err = ops->enable (ops, &rq,0 ); +break ; +case PTP_PF_PHYSYNC : +break ; +default : +return -EINVAL ; + } + +return err; +} + +int ptp_setpin (struct ptp_clock *ptp,unsigned int pin, +enum ptp_pin_function func,unsigned int chan) +{ +struct ptp_clock_info *info = ptp->info; +struct ptp_pin_desc *pin1 =NULL , *pin2 = &info->pin_config[pin]; +unsigned int i; + +/* Check to see if any other pin previously had this function. */ +if (mutex_lock_interruptible (&ptp->pincfg_mux)) +return -ERESTARTSYS ; +for (i =0 ; i < info->n_pins; i++) { +if (info->pin_config[i].func == func && + info->pin_config[i].chan == chan) { + pin1 = &info->pin_config[i]; +break ; + } + } +mutex_unlock (&ptp->pincfg_mux); +if (pin1 && i == pin) +return 0 ; + +/* Check the desired function and channel. */ +switch (func) { +case PTP_PF_NONE : +break ; +case PTP_PF_EXTTS : +if (chan >= info->n_ext_ts) +return -EINVAL ; +break ; +case PTP_PF_PEROUT : +if (chan >= info->n_per_out) +return -EINVAL ; +break ; +case PTP_PF_PHYSYNC : +pr_err ("sorry, cannot reassign the calibration pin\n" ); +return -EINVAL ; +default : +return -EINVAL ; + } + +if (pin1 && pin1->func ==PTP_PF_PHYSYNC ) { +pr_err ("sorry, cannot reprogram the calibration pin\n" ); +return -EINVAL ; + } + +if (info->setpin (info, pin, func, chan)) { +pr_err ("driver cannot use function %u on pin %u\n" , func, chan); +return -EOPNOTSUPP ; + } + +/* Disable whatever function was previously assigned. */ +ptp_disable_pinfunc (info, pin2->func, pin2->chan); +if (pin1) +ptp_disable_pinfunc (info, func, chan); + +if (mutex_lock_interruptible (&ptp->pincfg_mux)) +return -ERESTARTSYS ; + pin2->func = func; + pin2->chan = chan; +if (pin1) { + pin1->func =PTP_PF_NONE ; + pin1->chan =0 ; + } +mutex_unlock (&ptp->pincfg_mux); + +return 0 ; +} +int ptp_open (struct posix_clock *pc,fmode_t fmode) {return 0 ;
@@ -35,12 +133,13 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg)struct ptp_clock_caps caps;struct ptp_clock_request req;struct ptp_sys_offset *sysoff =NULL ; +struct ptp_pin_desc pd; struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);struct ptp_clock_info *ops = ptp->info;struct ptp_clock_time *pct;struct timespec ts;int enable, err =0 ; -unsigned int i; +unsigned int i, pin_index;switch (cmd) {
@@ -51,6 +150,7 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg) caps.n_ext_ts = ptp->info->n_ext_ts; caps.n_per_out = ptp->info->n_per_out; caps.pps = ptp->info->pps; + caps.n_pins = ptp->info->n_pins;if (copy_to_user ((void __user *)arg, &caps,sizeof (caps))) err = -EFAULT ;break ;
@@ -126,6 +226,37 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg) err = -EFAULT ;break ; +case PTP_PIN_GETFUNC : +if (copy_from_user (&pd, (void __user *)arg,sizeof (pd))) { + err = -EFAULT ; +break ; + } + pin_index = pd.index; +if (pin_index >= ops->n_pins) { + err = -EINVAL ; +break ; + } +if (mutex_lock_interruptible (&ptp->pincfg_mux)) +return -ERESTARTSYS ; + pd = ops->pin_config[pin_index]; +mutex_unlock (&ptp->pincfg_mux); +if (!err &©_to_user ((void __user *)arg, &pd,sizeof (pd))) + err = -EFAULT ; +break ; + +case PTP_PIN_SETFUNC : +if (copy_from_user (&pd, (void __user *)arg,sizeof (pd))) { + err = -EFAULT ; +break ; + } + pin_index = pd.index; +if (pin_index >= ops->n_pins) { + err = -EINVAL ; +break ; + } + err =ptp_setpin (ptp, pin_index, pd.func, pd.chan); +break ; +default : err = -ENOTTY ;break ;
drivers/ptp/ptp_clock.c +23 -0
@@ -169,6 +169,7 @@ static void delete_ptp_clock(struct posix_clock *pc) struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);mutex_destroy (&ptp->tsevq_mux); +mutex_destroy (&ptp->pincfg_mux);ida_simple_remove (&ptp_clocks_map, ptp->index);kfree (ptp); }
@@ -203,6 +204,7 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info, ptp->index = index;spin_lock_init (&ptp->tsevq.lock);mutex_init (&ptp->tsevq_mux); +mutex_init (&ptp->pincfg_mux);init_waitqueue_head (&ptp->tsev_wq);/* Create a new device in our class. */
@@ -249,6 +251,7 @@ no_sysfs:device_destroy (ptp_class, ptp->devid); no_device:mutex_destroy (&ptp->tsevq_mux); +mutex_destroy (&ptp->pincfg_mux); no_slot:kfree (ptp); no_memory:
@@ -305,6 +308,26 @@ int ptp_clock_index(struct ptp_clock *ptp) }EXPORT_SYMBOL (ptp_clock_index); +int ptp_find_pin (struct ptp_clock *ptp, +enum ptp_pin_function func,unsigned int chan) +{ +struct ptp_pin_desc *pin =NULL ; +int i; + +mutex_lock (&ptp->pincfg_mux); +for (i =0 ; i < ptp->info->n_pins; i++) { +if (ptp->info->pin_config[i].func == func && + ptp->info->pin_config[i].chan == chan) { + pin = &ptp->info->pin_config[i]; +break ; + } + } +mutex_unlock (&ptp->pincfg_mux); + +return pin ? pin - ptp->info->pin_config :-1 ; +} +EXPORT_SYMBOL (ptp_find_pin); +/* module operations */ static void __exit ptp_exit(void)
drivers/ptp/ptp_private.h +4 -0
@@ -48,6 +48,7 @@ struct ptp_clock {long dialed_frequency;/* remembers the frequency adjustment */ struct timestamp_event_queue tsevq;/* simple fifo for time stamps */ struct mutex tsevq_mux;/* one process at a time reading the fifo */ +struct mutex pincfg_mux;/* protect concurrent info->pin_config access */ wait_queue_head_t tsev_wq;int defunct;/* tells readers to go away when clock is being removed */ };
@@ -69,6 +70,9 @@ static inline int queue_cnt(struct timestamp_event_queue *q)* see ptp_chardev.c */ +int ptp_setpin (struct ptp_clock *ptp,unsigned int pin, +enum ptp_pin_function func,unsigned int chan); +long ptp_ioctl (struct posix_clock *pc,unsigned int cmd,unsigned long arg);
include/linux/ptp_clock_kernel.h +33 -0
@@ -49,7 +49,11 @@ struct ptp_clock_request {* @n_alarm: The number of programmable alarms. * @n_ext_ts: The number of external time stamp channels. * @n_per_out: The number of programmable periodic signals. +* @n_pins: The number of programmable pins. * @pps: Indicates whether the clock supports a PPS callback. +* @pin_config: Array of length 'n_pins'. If the number of +* programmable pins is nonzero, then drivers must +* allocate and initialize this array. * * clock operations *
@@ -70,6 +74,18 @@ struct ptp_clock_request {* parameter request: Desired resource to enable or disable. * parameter on: Caller passes one to enable or zero to disable. * +* @setpin: Confirm that a pin can perform a given function. The PTP +* Hardware Clock subsystem maintains the 'pin_config' +* array on behalf of the drivers, but the PHC subsystem +* assumes that every pin can perform every function. This +* hook gives drivers a way of telling the core about +* limitations on specific pins. This function must return +* zero if the function can be assigned to this pin, and +* nonzero otherwise. +* parameter pin: index of the pin in question. +* parameter func: the desired function to use. +* parameter chan: the function channel index to use. +* * Drivers should embed their ptp_clock_info within a private * structure, obtaining a reference to it using container_of(). *
@@ -83,13 +99,17 @@ struct ptp_clock_info {int n_alarm;int n_ext_ts;int n_per_out; +int n_pins;int pps; +struct ptp_pin_desc *pin_config;int (*adjfreq)(struct ptp_clock_info *ptp,s32 delta);int (*adjtime)(struct ptp_clock_info *ptp,s64 delta);int (*gettime)(struct ptp_clock_info *ptp,struct timespec *ts);int (*settime)(struct ptp_clock_info *ptp,const struct timespec *ts);int (*enable)(struct ptp_clock_info *ptp,struct ptp_clock_request *request,int on); +int (*setpin)(struct ptp_clock_info *ptp,unsigned int pin, +enum ptp_pin_function func,unsigned int chan); };struct ptp_clock ;
@@ -156,4 +176,17 @@ extern void ptp_clock_event(struct ptp_clock *ptp,extern int ptp_clock_index (struct ptp_clock *ptp); +/** +* ptp_find_pin() - obtain the pin index of a given auxiliary function +* +* @ptp: The clock obtained from ptp_clock_register(). +* @func: One of the ptp_pin_function enumerated values. +* @chan: The particular functional channel to find. +* Return: Pin index in the range of zero to ptp_clock_caps.n_pins - 1, +* or -1 if the auxiliary function cannot be found. +*/ + +int ptp_find_pin (struct ptp_clock *ptp, +enum ptp_pin_function func,unsigned int chan); +#endif
include/uapi/linux/ptp_clock.h +38 -1
@@ -50,7 +50,8 @@ struct ptp_clock_caps {int n_ext_ts;/* Number of external time stamp channels. */ int n_per_out;/* Number of programmable periodic signals. */ int pps;/* Whether the clock supports a PPS callback. */ -int rsv[15 ];/* Reserved for future use. */ +int n_pins;/* Number of input/output pins. */ +int rsv[14 ];/* Reserved for future use. */ };struct ptp_extts_request {
@@ -80,6 +81,40 @@ struct ptp_sys_offset {struct ptp_clock_time ts[2 *PTP_MAX_SAMPLES +1 ]; }; +enum ptp_pin_function { +PTP_PF_NONE , +PTP_PF_EXTTS , +PTP_PF_PEROUT , +PTP_PF_PHYSYNC , +}; + +struct ptp_pin_desc { +/* +* Hardware specific human readable pin name. This field is +* set by the kernel during the PTP_PIN_GETFUNC ioctl and is +* ignored for the PTP_PIN_SETFUNC ioctl. +*/ +char name[64 ]; +/* +* Pin index in the range of zero to ptp_clock_caps.n_pins - 1. +*/ +unsigned int index; +/* +* Which of the PTP_PF_xxx functions to use on this pin. +*/ +unsigned int func; +/* +* The specific channel to use for this function. +* This corresponds to the 'index' field of the +* PTP_EXTTS_REQUEST and PTP_PEROUT_REQUEST ioctls. +*/ +unsigned int chan; +/* +* Reserved for future use. +*/ +unsigned int rsv[5 ]; +}; +#define PTP_CLK_MAGIC '='#define PTP_CLOCK_GETCAPS _IOR(PTP_CLK_MAGIC, 1, struct ptp_clock_caps)
@@ -87,6 +122,8 @@ struct ptp_sys_offset {#define PTP_PEROUT_REQUEST _IOW(PTP_CLK_MAGIC, 3, struct ptp_perout_request)#define PTP_ENABLE_PPS _IOW(PTP_CLK_MAGIC, 4, int)#define PTP_SYS_OFFSET _IOW(PTP_CLK_MAGIC, 5, struct ptp_sys_offset) +#define PTP_PIN_GETFUNC _IOWR(PTP_CLK_MAGIC, 6, struct ptp_pin_desc) +#define PTP_PIN_SETFUNC _IOW(PTP_CLK_MAGIC, 7, struct ptp_pin_desc)struct ptp_extts_event {struct ptp_clock_time t;/* Time event occured. */
Signature · 1 line
1.7.10.4
Richard Cochran
maintainerRFC PATCH 2/9 ptp: add the pin GET/SETFUNC ioctls to the testptp program.
In reply to Richard CochranThis patch adds a option to the test program that lists the programmable pins on a PTP Hardware Clock device, assuming there are any such pins. A second option lets the user reprogram the auxiliary function of a single pin.
--- Documentation/ptp/testptp.c | 58 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 3 deletions(-)
Documentation/ptp/testptp.c +55 -3
@@ -120,6 +120,13 @@ static void usage(char *progname)" -i val index for event/trigger\n" " -k val measure the time offset between system and phc clock\n" " for 'val' times (Maximum 25)\n" +" -l list the current pin configuration\n" +" -L pin,val configure pin index 'pin' with function 'val'\n" +" the channel index is taken from the '-i' option\n" +" 'val' specifies the auxiliary function:\n" +" 0 - none\n" +" 1 - external time stamp\n" +" 2 - periodic output\n" " -p val enable output with a period of 'val' nanoseconds\n" " -P val enable or disable (val=1|0) the system clock PPS\n" " -s set the ptp clock time from the system time\n"
@@ -134,6 +141,7 @@ int main(int argc, char *argv[])struct ptp_extts_event event;struct ptp_extts_request extts_request;struct ptp_perout_request perout_request; +struct ptp_pin_desc desc;struct timespec ts;struct timex tx;
@@ -156,11 +164,13 @@ int main(int argc, char *argv[])int extts =0 ;int gettime =0 ;int index =0 ; +int list_pins =0 ;int oneshot =0 ;int pct_offset =0 ;int n_samples =0 ;int periodic =0 ;int perout =-1 ; +int pin_index =-1 , pin_func;int pps =-1 ;int settime =0 ;
@@ -169,7 +179,7 @@ int main(int argc, char *argv[]) progname =strrchr (argv[0 ],'/' ); progname = progname ?1 +progname : argv[0 ]; -while (EOF != (c =getopt (argc, argv,"a:A:cd:e:f:ghi:k:p:P:sSt:v" ))) { +while (EOF != (c =getopt (argc, argv,"a:A:cd:e:f:ghi:k:lL:p:P:sSt:v" ))) {switch (c) {case 'a' : oneshot =atoi (optarg);
@@ -199,6 +209,16 @@ int main(int argc, char *argv[]) pct_offset =1 ; n_samples =atoi (optarg);break ; +case 'l' : + list_pins =1 ; +break ; +case 'L' : + cnt =sscanf (optarg,"%d,%d" , &pin_index, &pin_func); +if (cnt !=2 ) { +usage (progname); +return -1 ; + } +break ;case 'p' : perout =atoi (optarg);break ;
@@ -245,12 +265,14 @@ int main(int argc, char *argv[])" %d programmable alarms\n" " %d external time stamp channels\n" " %d programmable periodic signals\n" -" %d pulse per second\n" , +" %d pulse per second\n" +" %d programmable pins\n" , caps.max_adj, caps.n_alarm, caps.n_ext_ts, caps.n_per_out, - caps.pps); + caps.pps, + caps.n_pins); } }
@@ -331,6 +353,24 @@ int main(int argc, char *argv[]) } } +if (list_pins) { +int n_pins =0 ; +if (ioctl (fd,PTP_CLOCK_GETCAPS , &caps)) { +perror ("PTP_CLOCK_GETCAPS" ); + }else { + n_pins = caps.n_pins; + } +for (i =0 ; i < n_pins; i++) { + desc.index = i; +if (ioctl (fd,PTP_PIN_GETFUNC , &desc)) { +perror ("PTP_PIN_GETFUNC" ); +break ; + } +printf ("name %s index %u func %u chan %u\n" , + desc.name, desc.index, desc.func, desc.chan); + } + } +if (oneshot) {install_handler (SIGALRM , handle_alarm);/* Create a timer. */
@@ -392,6 +432,18 @@ int main(int argc, char *argv[]) } } +if (pin_index >=0 ) { +memset (&desc,0 ,sizeof (desc)); + desc.index = pin_index; + desc.func = pin_func; + desc.chan = index; +if (ioctl (fd,PTP_PIN_SETFUNC , &desc)) { +perror ("PTP_PIN_SETFUNC" ); + }else { +puts ("set pin function okay" ); + } + } +if (pps !=-1 ) {int enable = pps ?1 :0 ;if (ioctl (fd,PTP_ENABLE_PPS , enable)) {
Signature · 1 line
1.7.10.4
Richard Cochran
maintainerRFC PATCH 3/9 ptp: expose the programmable pins via sysfs
In reply to Richard CochranThis patch adds the sysfs hooks needed in order to get and set the programmable pin settings.
--- Documentation/ABI/testing/sysfs-ptp | 20 +++++++ drivers/ptp/ptp_private.h | 3 + drivers/ptp/ptp_sysfs.c | 109 +++++++++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+)
Documentation/ABI/testing/sysfs-ptp +20 -0
@@ -54,6 +54,26 @@ Description: This file contains the number of programmable periodic output channels offered by the PTP hardware clock. +What: /sys/class/ptp/ptpN/n_pins +Date: March 2014 +Contact: Richard Cochran <[email protected]> +Description: + This file contains the number of programmable pins + offered by the PTP hardware clock. + +What: /sys/class/ptp/ptpN/pins +Date: March 2014 +Contact: Richard Cochran <[email protected]> +Description: + This directory contains one file for each programmable + pin offered by the PTP hardware clock. The file name + is the hardware dependent pin name. Reading from this + file produces two numbers, the assigned function (see + the PTP_PF_ enumeration values in linux/ptp_clock.h) + and the channel number. The function and channel + assignment may be changed by two writing numbers into + the file. + What: /sys/class/ptp/ptpN/pps_avaiable Date: September 2010 Contact: Richard Cochran <[email protected]>
drivers/ptp/ptp_private.h +3 -0
@@ -51,6 +51,9 @@ struct ptp_clock {struct mutex pincfg_mux;/* protect concurrent info->pin_config access */ wait_queue_head_t tsev_wq;int defunct;/* tells readers to go away when clock is being removed */ +struct device_attribute *pin_dev_attr; +struct attribute **pin_attr; +struct attribute_group pin_attr_group; };/*
drivers/ptp/ptp_sysfs.c +109 -0
146 lines not on this page · raw message
Signature · 1 line
1.7.10.4
Richard Cochran
maintainerRFC PATCH 4/9 ptp: drivers: set the number of programmable pins.
In reply to Richard CochranThis patch updates the many PTP Hardware Clock drivers with the newly introduced field that advertises the number of programmable pins. Some of these devices do have programmable pins, but the implementation will have to wait for follow on patches.
--- drivers/net/ethernet/adi/bfin_mac.c | 1 + drivers/net/ethernet/broadcom/tg3.c | 1 + drivers/net/ethernet/freescale/fec_ptp.c | 1 + drivers/net/ethernet/freescale/gianfar_ptp.c | 1 + drivers/net/ethernet/intel/e1000e/ptp.c | 1 + drivers/net/ethernet/mellanox/mlx4/en_clock.c | 1 + drivers/net/ethernet/sfc/ptp.c | 1 + drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c | 1 + drivers/net/ethernet/ti/cpts.c | 1 + drivers/net/ethernet/tile/tilegx.c | 1 + drivers/ptp/ptp_ixp46x.c | 1 + drivers/ptp/ptp_pch.c | 1 + 12 files changed, 12 insertions(+)
drivers/net/ethernet/adi/bfin_mac.c +1 -0
@@ -1040,6 +1040,7 @@ static struct ptp_clock_info bfin_ptp_caps = { .n_alarm = 0, .n_ext_ts = 0, .n_per_out = 0, + .n_pins = 0, .pps = 0, .adjfreq = bfin_ptp_adjfreq, .adjtime = bfin_ptp_adjtime,
drivers/net/ethernet/broadcom/tg3.c +1 -0
@@ -6322,6 +6322,7 @@ static const struct ptp_clock_info tg3_ptp_caps = { .n_alarm = 0, .n_ext_ts = 0, .n_per_out = 1, + .n_pins = 0, .pps = 0, .adjfreq = tg3_ptp_adjfreq, .adjtime = tg3_ptp_adjtime,
drivers/net/ethernet/freescale/fec_ptp.c +1 -0
@@ -372,6 +372,7 @@ void fec_ptp_init(struct platform_device *pdev) fep->ptp_caps.n_alarm =0 ; fep->ptp_caps.n_ext_ts =0 ; fep->ptp_caps.n_per_out =0 ; + fep->ptp_caps.n_pins =0 ; fep->ptp_caps.pps =0 ; fep->ptp_caps.adjfreq = fec_ptp_adjfreq; fep->ptp_caps.adjtime = fec_ptp_adjtime;
drivers/net/ethernet/freescale/gianfar_ptp.c +1 -0
@@ -414,6 +414,7 @@ static struct ptp_clock_info ptp_gianfar_caps = { .n_alarm = 0, .n_ext_ts = N_EXT_TS, .n_per_out = 0, + .n_pins = 0, .pps = 1, .adjfreq = ptp_gianfar_adjfreq, .adjtime = ptp_gianfar_adjtime,
drivers/net/ethernet/intel/e1000e/ptp.c +1 -0
@@ -191,6 +191,7 @@ static const struct ptp_clock_info e1000e_ptp_clock_info = { .n_alarm = 0, .n_ext_ts = 0, .n_per_out = 0, + .n_pins = 0, .pps = 0, .adjfreq = e1000e_phc_adjfreq, .adjtime = e1000e_phc_adjtime,
drivers/net/ethernet/mellanox/mlx4/en_clock.c +1 -0
@@ -276,6 +276,7 @@ static const struct ptp_clock_info mlx4_en_ptp_clock_info = { .n_alarm = 0, .n_ext_ts = 0, .n_per_out = 0, + .n_pins = 0, .pps = 0, .adjfreq = mlx4_en_phc_adjfreq, .adjtime = mlx4_en_phc_adjtime,
drivers/net/ethernet/sfc/ptp.c +1 -0
@@ -1194,6 +1194,7 @@ static const struct ptp_clock_info efx_phc_clock_info = { .n_alarm = 0, .n_ext_ts = 0, .n_per_out = 0, + .n_pins = 0, .pps = 1, .adjfreq = efx_phc_adjfreq, .adjtime = efx_phc_adjtime,
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c +1 -0
@@ -164,6 +164,7 @@ static struct ptp_clock_info stmmac_ptp_clock_ops = { .n_alarm = 0, .n_ext_ts = 0, .n_per_out = 0, + .n_pins = 0, .pps = 0, .adjfreq = stmmac_adjust_freq, .adjtime = stmmac_adjust_time,
drivers/net/ethernet/ti/cpts.c +1 -0
@@ -217,6 +217,7 @@ static struct ptp_clock_info cpts_info = { .name = "CTPS timer", .max_adj = 1000000, .n_ext_ts = 0, + .n_pins = 0, .pps = 0, .adjfreq = cpts_ptp_adjfreq, .adjtime = cpts_ptp_adjtime,
drivers/net/ethernet/tile/tilegx.c +1 -0
@@ -870,6 +870,7 @@ static struct ptp_clock_info ptp_mpipe_caps = { .name = "mPIPE clock", .max_adj = 999999999, .n_ext_ts = 0, + .n_pins = 0, .pps = 0, .adjfreq = ptp_mpipe_adjfreq, .adjtime = ptp_mpipe_adjtime,
drivers/ptp/ptp_ixp46x.c +1 -0
@@ -244,6 +244,7 @@ static struct ptp_clock_info ptp_ixp_caps = { .name = "IXP46X timer", .max_adj = 66666655, .n_ext_ts = N_EXT_TS, + .n_pins = 0, .pps = 0, .adjfreq = ptp_ixp_adjfreq, .adjtime = ptp_ixp_adjtime,
drivers/ptp/ptp_pch.c +1 -0
@@ -514,6 +514,7 @@ static struct ptp_clock_info ptp_pch_caps = { .name = "PCH timer", .max_adj = 50000000, .n_ext_ts = N_EXT_TS, + .n_pins = 0, .pps = 0, .adjfreq = ptp_pch_adjfreq, .adjtime = ptp_pch_adjtime,
Signature · 1 line
1.7.10.4
Richard Cochran
maintainerRFC PATCH 5/9 dp83640: trivial fixes
In reply to Richard CochranThis patch cleans up the input checking code on the external time stamp function by using an unsigned rather than a signed channel index.
Also, this patch corrects the author's email address. When this macro was last changed, the top level domain part of the email address was left behind.
--- drivers/net/phy/dp83640.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/net/phy/dp83640.c +3 -3
@@ -424,13 +424,13 @@ static int ptp_dp83640_enable(struct ptp_clock_info *ptp,struct dp83640_clock *clock = container_of(ptp, struct dp83640_clock, caps);struct phy_device *phydev = clock->chosen->phydev; -int index; +unsigned int index;u16 evnt, event_num, gpio_num;switch (rq->type) {case PTP_CLK_REQ_EXTTS : index = rq->extts.index; -if (index <0 || index >=N_EXT_TS ) +if (index >=N_EXT_TS )return -EINVAL ; event_num =EXT_EVENT + index; evnt =EVNT_WR | (event_num &EVNT_SEL_MASK ) <<EVNT_SEL_SHIFT ;
@@ -1363,7 +1363,7 @@ static void __exit dp83640_exit(void) }MODULE_DESCRIPTION ("National Semiconductor DP83640 PHY driver" ); -MODULE_AUTHOR ("Richard Cochran <[email protected]>" ); +MODULE_AUTHOR ("Richard Cochran <[email protected]>" );MODULE_LICENSE ("GPL" );module_init (dp83640_init);
Signature · 1 line
1.7.10.4
Richard Cochran
maintainerRFC PATCH 6/9 dp83640: correct the periodic output frequency
In reply to Richard CochranThe phyter driver incorrectly feeds the value of the period into what is in fact a pulse width register, resulting in the actual period being twice the dialed value. This patch fixes the issue and renames a variable to make the code at bit more clear.
--- drivers/net/phy/dp83640.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
drivers/net/phy/dp83640.c +6 -5
@@ -271,7 +271,7 @@ static void periodic_output(struct dp83640_clock *clock, {struct dp83640_private *dp83640 = clock->chosen;struct phy_device *phydev = dp83640->phydev; -u32 sec, nsec, period; +u32 sec, nsec, pwidth;u16 gpio, ptp_trig, trigger, val; gpio = on ? gpio_tab[PEROUT_GPIO ] :0 ;
@@ -296,8 +296,9 @@ static void periodic_output(struct dp83640_clock *clock, sec = clkreq->perout.start.sec; nsec = clkreq->perout.start.nsec; - period = clkreq->perout.period.sec *1000000000UL ; - period += clkreq->perout.period.nsec; + pwidth = clkreq->perout.period.sec *1000000000UL ; + pwidth += clkreq->perout.period.nsec; + pwidth /=2 ;mutex_lock (&clock->extreg_lock);
@@ -310,8 +311,8 @@ static void periodic_output(struct dp83640_clock *clock,ext_write (0 , phydev,PAGE4 ,PTP_TDR , nsec >>16 );/* ns[31:16] */ ext_write (0 , phydev,PAGE4 ,PTP_TDR , sec &0xffff );/* sec[15:0] */ ext_write (0 , phydev,PAGE4 ,PTP_TDR , sec >>16 );/* sec[31:16] */ -ext_write (0 , phydev,PAGE4 ,PTP_TDR , period &0xffff );/* ns[15:0] */ -ext_write (0 , phydev,PAGE4 ,PTP_TDR , period >>16 );/* ns[31:16] */ +ext_write (0 , phydev,PAGE4 ,PTP_TDR , pwidth &0xffff );/* ns[15:0] */ +ext_write (0 , phydev,PAGE4 ,PTP_TDR , pwidth >>16 );/* ns[31:16] */ /*enable trigger*/ val &= ~TRIG_LOAD ;
Signature · 1 line
1.7.10.4
Richard Cochran
maintainerRFC PATCH 7/9 dp83640: implement programmable pin functions.
In reply to Richard CochranThis patch adapts the dp83640 driver to allow reconfiguration of which auxiliary function goes on which pin. The functions may be reassigned freely with the one exception of the calibration function.
--- drivers/net/phy/dp83640.c | 52 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+)
drivers/net/phy/dp83640.c +52 -0
@@ -47,6 +47,7 @@#define CAL_EVENT 7#define CAL_TRIGGER 7#define PER_TRIGGER 6 +#define DP83640_N_PINS 12#define MII_DP83640_MICR 0x11#define MII_DP83640_MISR 0x12
@@ -173,6 +174,37 @@ MODULE_PARM_DESC(chosen_phy, \MODULE_PARM_DESC (gpio_tab, \"Which GPIO line to use for which purpose: cal,perout,extts1,...,extts6" ); +static void dp83640_gpio_defaults (struct ptp_pin_desc *pd) +{ +int i, index; + +for (i =0 ; i <DP83640_N_PINS ; i++) { +snprintf (pd[i].name,sizeof (pd[i].name),"GPIO%d" ,1 + i); + pd[i].index = i; + } + +for (i =0 ; i <GPIO_TABLE_SIZE ; i++) { +if (gpio_tab[i] <1 || gpio_tab[i] >DP83640_N_PINS ) { +pr_err ("gpio_tab[%d]=%hu out of range" , i, gpio_tab[i]); +return ; + } + } + + index = gpio_tab[CALIBRATE_GPIO ] -1 ; + pd[index].func =PTP_PF_PHYSYNC ; + pd[index].chan =0 ; + + index = gpio_tab[PEROUT_GPIO ] -1 ; + pd[index].func =PTP_PF_PEROUT ; + pd[index].chan =0 ; + +for (i =EXTTS0_GPIO ; i <GPIO_TABLE_SIZE ; i++) { + index = gpio_tab[i] -1 ; + pd[index].func =PTP_PF_EXTTS ; + pd[index].chan = i -EXTTS0_GPIO ; + } +} +/* a list of clocks and a mutex to protect it */ static LIST_HEAD (phyter_clocks);static DEFINE_MUTEX (phyter_clocks_lock);
@@ -459,6 +491,12 @@ static int ptp_dp83640_enable(struct ptp_clock_info *ptp,return -EOPNOTSUPP ; } +static int ptp_dp83640_setpin (struct ptp_clock_info *ptp,unsigned int pin, +enum ptp_pin_function func,unsigned int chan) +{ +return 0 ; +} +static u8 status_frame_dst[6 ] = {0x01 ,0x1B ,0x19 ,0x00 ,0x00 ,0x00 };static u8 status_frame_src[6 ] = {0x08 ,0x00 ,0x17 ,0x0B ,0x6B ,0x0F };
@@ -876,6 +914,7 @@ static void dp83640_free_clocks(void)mutex_destroy (&clock->extreg_lock);mutex_destroy (&clock->clock_lock);put_device (&clock->bus->dev); +kfree (clock->caps.pin_config);kfree (clock); }
@@ -895,12 +934,18 @@ static void dp83640_clock_init(struct dp83640_clock *clock, struct mii_bus *bus) clock->caps.n_alarm =0 ; clock->caps.n_ext_ts =N_EXT_TS ; clock->caps.n_per_out =1 ; + clock->caps.n_pins =DP83640_N_PINS ; clock->caps.pps =0 ; clock->caps.adjfreq = ptp_dp83640_adjfreq; clock->caps.adjtime = ptp_dp83640_adjtime; clock->caps.gettime = ptp_dp83640_gettime; clock->caps.settime = ptp_dp83640_settime; clock->caps.enable = ptp_dp83640_enable; + clock->caps.setpin = ptp_dp83640_setpin; +/* +* Convert the module param defaults into a dynamic pin configuration. +*/ +dp83640_gpio_defaults (clock->caps.pin_config);/* * Get a reference to this bus instance. */
@@ -951,6 +996,13 @@ static struct dp83640_clock *dp83640_clock_get_bus(struct mii_bus *bus)if (!clock) goto out; + clock->caps.pin_config =kzalloc (sizeof (struct ptp_pin_desc ) * +DP83640_N_PINS ,GFP_KERNEL ); +if (!clock->caps.pin_config) { +kfree (clock); + clock =NULL ; + goto out; + }dp83640_clock_init (clock, bus);list_add_tail (&phyter_clocks, &clock->list); out:
Signature · 1 line
1.7.10.4
Richard Cochran
maintainerRFC PATCH 8/9 dp83640: let external input pins from the module parameters be defaults.
In reply to Richard CochranThis patch changes the driver to use the new pin configuration method when programming the external time stamp input signals.
--- drivers/net/phy/dp83640.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/net/phy/dp83640.c +4 -1
@@ -468,7 +468,10 @@ static int ptp_dp83640_enable(struct ptp_clock_info *ptp, event_num =EXT_EVENT + index; evnt =EVNT_WR | (event_num &EVNT_SEL_MASK ) <<EVNT_SEL_SHIFT ;if (on) { - gpio_num = gpio_tab[EXTTS0_GPIO + index]; + gpio_num =1 +ptp_find_pin (clock->ptp_clock, +PTP_PF_EXTTS , index); +if (gpio_num <1 ) +return -EINVAL ; evnt |= (gpio_num &EVNT_GPIO_MASK ) <<EVNT_GPIO_SHIFT ;if (rq->extts.flags &PTP_FALLING_EDGE ) evnt |=EVNT_FALL ;
Signature · 1 line
1.7.10.4
Richard Cochran
maintainerRFC PATCH 9/9 dp83640: let the periodic pin from the module parameter be a default.
In reply to Richard CochranThis patch changes the driver use the new pin configuration method when programming the periodic output signal.
--- drivers/net/phy/dp83640.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-)
drivers/net/phy/dp83640.c +13 -6
@@ -298,15 +298,22 @@ static u64 phy2txts(struct phy_txts *p)return ns; } -static void periodic_output (struct dp83640_clock *clock, -struct ptp_clock_request *clkreq,bool on) +static int periodic_output (struct dp83640_clock *clock, +struct ptp_clock_request *clkreq,bool on) {struct dp83640_private *dp83640 = clock->chosen;struct phy_device *phydev = dp83640->phydev;u32 sec, nsec, pwidth;u16 gpio, ptp_trig, trigger, val; - gpio = on ? gpio_tab[PEROUT_GPIO ] :0 ; +if (on) { + gpio =1 +ptp_find_pin (clock->ptp_clock,PTP_PF_PEROUT ,0 ); +if (gpio <1 ) +return -EINVAL ; + }else { + gpio =0 ; + } + trigger =PER_TRIGGER ; ptp_trig = TRIG_WR |
@@ -323,7 +330,7 @@ static void periodic_output(struct dp83640_clock *clock,ext_write (0 , phydev,PAGE5 ,PTP_TRIG , ptp_trig);ext_write (0 , phydev,PAGE4 ,PTP_CTL , val);mutex_unlock (&clock->extreg_lock); -return ; +return 0 ; } sec = clkreq->perout.start.sec;
@@ -352,6 +359,7 @@ static void periodic_output(struct dp83640_clock *clock,ext_write (0 , phydev,PAGE4 ,PTP_CTL , val);mutex_unlock (&clock->extreg_lock); +return 0 ; }/* ptp clock methods */
@@ -484,8 +492,7 @@ static int ptp_dp83640_enable(struct ptp_clock_info *ptp,case PTP_CLK_REQ_PEROUT :if (rq->perout.index !=0 )return -EINVAL ; -periodic_output (clock, rq, on); -return 0 ; +return periodic_output (clock, rq, on);default :break ;
Signature · 1 line
1.7.10.4
Quoted 8 lines · Richard Cochran
This patch series introduces a way of changing the auxiliary PTP Hardware Clock functions (periodic output signals and time stamping external signals) at run time. In the past on the netdev list, we have discussed other ways to handle this, such as module parameters and ethtool. This series implements a new PHC ioctl because that is the most natural way. Users already activate the auxiliary functions via the ioctls. The sysfs interface has also been expanded so that the pin configuration can be programmed using shell scripts.
A few general questions / thoughts:
What are the n_ext_ts and n_per_out supposed to be set to now? The number of pins configured for the relevant function or the number of channels that are available for the function?
The implementation is limited to a single function for each pin - the dp83640 supports an ext_ts and several periodic outputs on the same pin, but I do not see that many real-world uses.
I have done a few short run-time tests, and so far everything is working as expected.
Stefan
Re: [PATCH RFC net-next v1 1/9] ptp: introduce programmable pins.
In reply to Richard Cochrandrivers/ptp/ptp_chardev.c line 59
Quoted 2 lines · Richard Cochran
drivers/ptp/ptp_chardev.c +2
-0+int ptp_setpin (struct ptp_clock *ptp,unsigned int pin, +enum ptp_pin_function func,unsigned int chan)
From the name I would think that this would set the state of the pin. Rename to ptp_set_pinfunc?
Quoted 8 lines
drivers/ptp/ptp_clock.c +8
-0+int ptp_find_pin (struct ptp_clock *ptp, +enum ptp_pin_function func,unsigned int chan) +{ +struct ptp_pin_desc *pin =NULL ; +int i; + +mutex_lock (&ptp->pincfg_mux); +for (i =0 ; i < ptp->info->n_pins; i++) {
drivers/ptp/ptp_clock.c int ptp_clock_index(struct ptp_clock *ptp) · line 328
Quoted 10 lines
drivers/ptp/ptp_clock.c +10
-0+if (ptp->info->pin_config[i].func == func && + ptp->info->pin_config[i].chan == chan) { + pin = &ptp->info->pin_config[i]; +break ; + } + } +mutex_unlock (&ptp->pincfg_mux); + +return pin ? pin - ptp->info->pin_config :-1 ; +}
Maybe replace 'pin - ptp->info->pin_config' with 'i'?
drivers/ptp/ptp_private.h struct ptp_clock { · line 51
Quoted 6 lines
+++
b/drivers/ptp/ptp_private.hdrivers/ptp/ptp_private.h +1
-0@@ -48,6 +48,7 @@ struct ptp_clock {long dialed_frequency;/* remembers the frequency adjustment */ struct timestamp_event_queue tsevq;/* simple fifo for time stamps */ struct mutex tsevq_mux;/* one process at a time reading the fifo */ +struct mutex pincfg_mux;/* protect concurrent info->pin_config access */
Line over 80 chars.
include/linux/ptp_clock_kernel.h struct ptp_clock_request { · line 84
Quoted 8 lines
include/linux/ptp_clock_kernel.h +8
-0+* @setpin: Confirm that a pin can perform a given function. The PTP +* Hardware Clock subsystem maintains the 'pin_config' +* array on behalf of the drivers, but the PHC subsystem +* assumes that every pin can perform every function. This +* hook gives drivers a way of telling the core about +* limitations on specific pins. This function must return +* zero if the function can be assigned to this pin, and +* nonzero otherwise.
The function does not actually set the pin. Rename to verify_pinfunc?
Stefan
Richard Cochran
maintainerRe: [PATCH RFC net-next v1 1/9] ptp: introduce programmable pins.
Quoted 14 lines · Stefan
Quoted 12 lines · Richard Cochran
drivers/ptp/ptp_clock.c +12
-0+int ptp_find_pin (struct ptp_clock *ptp, +enum ptp_pin_function func,unsigned int chan) +{ +struct ptp_pin_desc *pin =NULL ; +int i; + +mutex_lock (&ptp->pincfg_mux); +for (i =0 ; i < ptp->info->n_pins; i++) { +if (ptp->info->pin_config[i].func == func && + ptp->info->pin_config[i].chan == chan) { + pin = &ptp->info->pin_config[i]; +break ;
Quoted 8 lines
drivers/ptp/ptp_clock.c int ptp_clock_index(struct ptp_clock *ptp) · line 328
Quoted 6 lines
drivers/ptp/ptp_clock.c +6
-0+ } + } +mutex_unlock (&ptp->pincfg_mux); + +return pin ? pin - ptp->info->pin_config :-1 ; +}Maybe replace 'pin -
ptp->info->pin_config' with 'i'?
Yes, of course.
Thanks,
Richard
Richard Cochran
maintainerQuoted 4 lines · Stefan
What are the
n_ext_tsandn_per_outsupposed to be set to now? The number of pins configured for the relevant function or the number of channels that are available for the function?
They are the number of available functions. This is not necessarily the same as the number of pins. Many chips have more functions than pins.
Quoted 3 lines
The implementation is limited to a single function for each pin - the dp83640 supports an
ext_tsand several periodic outputs on the same pin, but I do not see that many real-world uses.
Yes, it does support different functions on a single pin, but not at the same time. You have to choose what function you want on each pin, and that is what the new ioctl lets you do.
I did not change the n_per_out in this series, but once this basic support gets merged, then you will be able to increase n_per_out for the dp83640 with little extra effort.
Thanks,
Richard
Richard Cochran
maintainerQuoted 3 lines · Stefan
The implementation is limited to a single function for each pin - the dp83640 supports an
ext_tsand several periodic outputs on the same pin, but I do not see that many real-world uses.
So the main use case is to allow users to configure the auxiliary functions according to their needs. This series provides this without relying on DT, ACPI, etc. The sysfs control lets you put this into a boot script, for example.
In addition, there are also less common use cases for re-configuring pins at run time. One use would be to switch from a PPS output to a time stamping input during automated PTP testing.
Thanks,
Richard
Re: [PATCH RFC net-next v1 1/9] ptp: introduce programmable pins.
In reply to Richard CochranHi Richard,
Quoted 19 lines · --On March 08, 2014 20:42 +0100 Richard Cochran <[email protected]>…
This patch adds a pair of new ioctls to the PTP Hardware Clock device interface. Using the ioctls, user space programs can query each pin to find out its current function and also reprogram a different function if desired.
Signed-off-by Richard Cochran <[email protected]>--- drivers/ptp/ptp_chardev.c | 133 +++++++++++++++++++++++++++++++++++++- drivers/ptp/ptp_clock.c | 23 +++++++ drivers/ptp/ptp_private.h | 4 ++ include/linux/ptp_clock_kernel.h | 33 ++++++++++ include/uapi/linux/ptp_clock.h | 39 ++++++++++- 5 files changed, 230 insertions(+), 2 deletions(-)drivers/ptp/ptp_chardev.c +0
-0
[...]
Quoted 33 lines
drivers/ptp/ptp_chardev.c +33
-0+int ptp_setpin (struct ptp_clock *ptp,unsigned int pin, +enum ptp_pin_function func,unsigned int chan) +{ +struct ptp_clock_info *info = ptp->info; +struct ptp_pin_desc *pin1 =NULL , *pin2 = &info->pin_config[pin]; +unsigned int i; + +/* Check to see if any other pin previously had this function. */ +if (mutex_lock_interruptible (&ptp->pincfg_mux)) +return -ERESTARTSYS ; +for (i =0 ; i < info->n_pins; i++) { +if (info->pin_config[i].func == func && + info->pin_config[i].chan == chan) { + pin1 = &info->pin_config[i]; +break ; + } + } +mutex_unlock (&ptp->pincfg_mux); +if (pin1 && i == pin) +return 0 ; + +/* Check the desired function and channel. */ +switch (func) { +case PTP_PF_NONE : +break ; +case PTP_PF_EXTTS : +if (chan >= info->n_ext_ts) +return -EINVAL ; +break ; +case PTP_PF_PEROUT : +if (chan >= info->n_per_out) +return -EINVAL ; +break ;
drivers/ptp/ptp_chardev.c line 100
Quoted 10 lines
drivers/ptp/ptp_chardev.c +10
-0+case PTP_PF_PHYSYNC : +pr_err ("sorry, cannot reassign the calibration pin\n" ); +return -EINVAL ; +default : +return -EINVAL ; + } + +if (pin1 && pin1->func ==PTP_PF_PHYSYNC ) { +pr_err ("sorry, cannot reprogram the calibration pin\n" ); +return -EINVAL ;
^^^^
Will this ever happen? pin1 && pin1->func == PTP_PF_PHYSYNC means that func == PTP_PF_PHYSYNC, but in this case you already return -EINVAL a few lines above.
Christian
Richard Cochran
maintainerRe: [PATCH RFC net-next v1 1/9] ptp: introduce programmable pins.
Quoted 8 lines · Christian Riesch
drivers/ptp/ptp_chardev.c line 100
Quoted 3 lines
drivers/ptp/ptp_chardev.c +3
-0+if (pin1 && pin1->func ==PTP_PF_PHYSYNC ) { +pr_err ("sorry, cannot reprogram the calibration pin\n" ); +return -EINVAL ;^^^^Will this ever happen? pin1 &&
pin1->func==PTP_PF_PHYSYNCmeans that func ==PTP_PF_PHYSYNC, but in this case you already return-EINVALa few lines above.
This a bug. I really meant to test (pin2->func == PTP_PF_PHYSYNC) to prevent clobbering the calibration function with some other function. I'll fix it for v2.
Thanks,
Richard
Hi Richard,
Quoted 13 lines · --On March 10, 2014 14:42 +0100 Richard Cochran <[email protected]>…
Quoted 4 lines · Stefan
What are the
n_ext_tsandn_per_outsupposed to be set to now? The number of pins configured for the relevant function or the number of channels that are available for the function?They are the number of available functions. This is not necessarily the same as the number of pins. Many chips have more functions than pins.
Quoted 3 lines
The implementation is limited to a single function for each pin - the dp83640 supports an
ext_tsand several periodic outputs on the same pin, but I do not see that many real-world uses.
Quoted 5 lines
Yes, it does support different functions on a single pin, but not at the same time. You have to choose what function you want on each pin, and that is what the new ioctl lets you do.
I did not change the
n_per_outin this series,
Why not? I think it would be a good idea to set both n_ext_ts and n_per_out to the correct value right from the start (8, right?). Christian
Quoted 3 lines
but once this basic
support gets merged, then you will be able to increasen_per_outfor the dp83640 with little extra effort.
Hi Richard,
Quoted 8 lines · --On March 08, 2014 20:42 +0100 Richard Cochran <[email protected]>…
This patch series introduces a way of changing the auxiliary PTP Hardware Clock functions (periodic output signals and time stamping external signals) at run time. In the past on the netdev list, we have discussed other ways to handle this, such as module parameters and ethtool. This series implements a new PHC ioctl because that is the most natural way. Users already activate the auxiliary functions via the ioctls. The sysfs interface has also been expanded so that the pin configuration can be programmed using shell scripts.
I did a few tests on one of my boards, everything works so far! Thanks for the patchset, I like it!
Quoted 10 lines
The first patch adds the new ioctls. The PHC subsystem does most of the work of maintaining the function-to-pin mapping. Drivers will only need to allocate and initialize a pin configuration table and also provide a new method that validates a particular assignment.
Patches 5 and 6 just clean up a couple of issues in the phyter driver, and the remaining patches actually hook the phyter's pins into the new system.
Comments and questions are most welcome.
Do you think it is possible to extend this in the future, e.g. for selecting the polarity of periodic output signals or for time stamping of external signals (rising edge/falling edge), or duty cycles of the periodic signal other than 50%? How could this be done? Using the reserved fields in struct ptp_pin_desc?
Do you think the concept allows an extension for single pulse output, e.g. programming a pin to output a single pulse at a given time, as supported by the DP83640?
If several DP83640 are connected together with the calibration function, only the GPIOs of the master device can be used, right? I guess this could also be extended in the future to use the GPIOs of all DP83640, right? Or do you see a problem with your concept here?
Best regards,
Christian
Richard Cochran
maintainerQuoted 5 lines · Christian Riesch
Quoted 1 line
I did not change the
n_per_outin this series,Why not? I think it would be a good idea to set both
n_ext_tsandn_per_outto the correct value right from the start (8, right?). Christian
Yes, it is a good idea, but it is a little extra work, especially testing it. Channels 0 and 1 must be programmed differently, IIRC.
Right now, I am focusing on:
1. getting the new ioctl interface right
2. making it work for the phyter while keeping the module params.
After that, as I said before:
Quoted 3 lines
Quoted 3 lines
but once this basic
support gets merged, then you will be able to increasen_per_outfor the dp83640 with little extra effort.
Thanks,
Richard
Richard Cochran
maintainerQuoted 6 lines · Christian Riesch
Do you think it is possible to extend this in the future, e.g. for selecting the polarity of periodic output signals or for time stamping of external signals (rising edge/falling edge), or duty cycles of the periodic signal other than 50%? How could this be done? Using the reserved fields in struct
ptp_pin_desc?
Yes, this can be done, but this relates to the ptp_xyz_request ioctls and not to the ptp_pin_desc. You asked for three things. Here is how one might implement them.
1. selecting the polarity of periodic output signals
ptp_perout_request.flags (new flag)
2. time stamping of external signals (rising edge/falling edge)
This is already supported in the ptp_extts_request.flags field. The drivers just need to implement it.
3. duty cycles of the periodic signal other than 50%?
Maybe using one of the ptp_perout_request.rsv fields.
Quoted 3 lines
Do you think the concept allows an extension for single pulse output, e.g. programming a pin to output a single pulse at a given time, as supported by the DP83640?
Yes, either a new ioctl or maybe ptp_perout_request.flags with a ONE-SHOT flag.
Quoted 4 lines
If several DP83640 are connected together with the calibration function, only the GPIOs of the master device can be used, right? I guess this could also be extended in the future to use the GPIOs of all DP83640, right? Or do you see a problem with your concept here?
If the driver would combine all of the pins and functions over all the devices, that would be best. I think it would be tricky to implement, since the driver probe() function doesn't know how many more phyters to expect.
Thanks,
Richard