Re: [Linuxptp-devel] Issues with mutex locking and ptp_find_pin
PTP IEEE 1588 stack for Linux
Brought to you by:
rcochran
From: Andrew S. <and...@gm...> - 2016-01-15 01:39:37
|
Hi Richard Thanks for verifying the behavior on your side. Having just looked more closely at the igb driver code, I notice that the *ptp_find_pin* is only ever called when enabling a pin (the "on" argument must be true). This explains why my code hangs while their code doesn't. As a temporary measure I have now changed my code to simply lock the pin number to a channel with the same number, negating the need to call *ptp_find_pin.* My original problematic code follow below. Regards Andrew ---------- --- KERNEL-CLEAN/drivers/net/ethernet/ti/cpts.c 2015-11-13 12:56:51.000000000 -0800 +++ KERNEL/drivers/net/ethernet/ti/cpts.c 2016-01-14 17:10:10.507652309 -0800 @@ -46,6 +46,11 @@ return (event->high >> EVENT_TYPE_SHIFT) & EVENT_TYPE_MASK; } +static int event_port(struct cpts_event *event) +{ + return (event->high >> PORT_NUMBER_SHIFT) & PORT_NUMBER_MASK; +} + static int cpts_fifo_pop(struct cpts *cpts, u32 *high, u32 *low) { u32 r = cpts_read32(cpts, intstat_raw); @@ -67,7 +72,7 @@ int i, type = -1; u32 hi, lo; struct cpts_event *event; - + struct ptp_clock_event pevent; for (i = 0; i < CPTS_FIFO_DEPTH; i++) { if (cpts_fifo_pop(cpts, &hi, &lo)) break; @@ -81,6 +86,12 @@ event->low = lo; type = event_type(event); switch (type) { + case CPTS_EV_HW: + pevent.timestamp = timecounter_cyc2time(&cpts->tc, event->low); + pevent.type = PTP_CLOCK_EXTTS; + pevent.index = event_port(event) - 1; + ptp_clock_event(cpts->clock, &pevent); + break; case CPTS_EV_PUSH: case CPTS_EV_RX: case CPTS_EV_TX: @@ -89,7 +100,6 @@ break; case CPTS_EV_ROLL: case CPTS_EV_HALF: - case CPTS_EV_HW: break; default: pr_err("cpts: unknown event type\n"); @@ -183,7 +193,7 @@ } static int cpts_ptp_settime(struct ptp_clock_info *ptp, - const struct timespec64 *ts) + const struct timespec64 *ts) { u64 ns; unsigned long flags; @@ -198,32 +208,113 @@ return 0; } +static int cpts_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin, + enum ptp_pin_function func, unsigned int chan) +{ + /* Check number of pins */ + if (pin >= ptp->n_pins || !ptp->pin_config) + return -EINVAL; + + /* Lock the channel */ + if (chan != ptp->pin_config[pin].chan) + return -EINVAL; + + /* Check function */ + switch (func) { + case PTP_PF_NONE: + case PTP_PF_EXTTS: + break; + default: + return -EINVAL; + } + + return 0; +} + static int cpts_ptp_enable(struct ptp_clock_info *ptp, - struct ptp_clock_request *rq, int on) + struct ptp_clock_request *rq, int on) { + int pin; + u32 ctrl, mask; + struct cpts *cpts = container_of(ptp, struct cpts, info); + switch(rq->type) { + case PTP_CLK_REQ_EXTTS: + pin = ptp_find_pin(cpts->clock, PTP_PF_EXTTS, rq->extts.index); + if (pin < 0) + return -EBUSY; + switch (pin) { + case 0: mask = HW1_TS_PUSH_EN; break; + case 1: mask = HW2_TS_PUSH_EN; break; + case 2: mask = HW3_TS_PUSH_EN; break; + case 3: mask = HW4_TS_PUSH_EN; break; + default: + return -EINVAL; + } + ctrl = cpts_read32(cpts, control); + if (on) + ctrl |= mask; + else + ctrl &= ~mask; + cpts_write32(cpts, ctrl, control); + return 0; + default: + break; + } return -EOPNOTSUPP; } +static struct ptp_pin_desc cpts_pins[4] = { + { + .name = "HW1_TS_PUSH", + .index = 0, + .func = PTP_PF_NONE, + .chan = 0 + }, + { + .name = "HW2_TS_PUSH", + .index = 1, + .func = PTP_PF_NONE, + .chan = 1 + }, + { + .name = "HW3_TS_PUSH", + .index = 2, + .func = PTP_PF_NONE, + .chan = 2 + }, + { + .name = "HW4_TS_PUSH", + .index = 3, + .func = PTP_PF_NONE, + .chan = 3 + } +}; + static struct ptp_clock_info cpts_info = { .owner = THIS_MODULE, .name = "CTPS timer", .max_adj = 1000000, - .n_ext_ts = 0, - .n_pins = 0, + .n_alarm = 0, + .n_ext_ts = 4, + .n_pins = 4, .pps = 0, + .pin_config = cpts_pins, .adjfreq = cpts_ptp_adjfreq, .adjtime = cpts_ptp_adjtime, .gettime64 = cpts_ptp_gettime, .settime64 = cpts_ptp_settime, .enable = cpts_ptp_enable, + .verify = cpts_ptp_verify, }; static void cpts_overflow_check(struct work_struct *work) { + u32 ctrl; struct timespec64 ts; struct cpts *cpts = container_of(work, struct cpts, overflow_work.work); - - cpts_write32(cpts, CPTS_EN, control); + ctrl = cpts_read32(cpts, control); + ctrl |= CPTS_EN; + cpts_write32(cpts, ctrl, control); cpts_write32(cpts, TS_PEND_EN, int_enable); cpts_ptp_gettime(&cpts->info, &ts); pr_debug("cpts overflow check at %lld.%09lu\n", ts.tv_sec, ts.tv_nsec); @@ -247,7 +338,7 @@ } static int cpts_match(struct sk_buff *skb, unsigned int ptp_class, - u16 ts_seqid, u8 ts_msgtype) + u16 ts_seqid, u8 ts_msgtype) { u16 *seqid; unsigned int offset = 0; @@ -308,7 +399,7 @@ mtype = (event->high >> MESSAGE_TYPE_SHIFT) & MESSAGE_TYPE_MASK; seqid = (event->high >> SEQUENCE_ID_SHIFT) & SEQUENCE_ID_MASK; if (ev_type == event_type(event) && - cpts_match(skb, class, seqid, mtype)) { + cpts_match(skb, class, seqid, mtype)) { ns = timecounter_cyc2time(&cpts->tc, event->low); list_del_init(&event->list); list_add(&event->list, &cpts->pool); @@ -353,7 +444,7 @@ #endif /*CONFIG_TI_CPTS*/ int cpts_register(struct device *dev, struct cpts *cpts, - u32 mult, u32 shift) + u32 mult, u32 shift) { #ifdef CONFIG_TI_CPTS int err, i; @@ -405,4 +496,4 @@ if (cpts->refclk) cpts_clk_release(cpts); #endif -} +} \ No newline at end of file On Thu, Jan 14, 2016 at 3:01 PM, Richard Cochran <ric...@gm...> wrote: > On Thu, Jan 14, 2016 at 01:57:02PM -0800, Andrew Symington wrote: > > I just modified the Linux TI CPTS driver to support external hardware > time > > stamping. In my driver's .enable function callback on the > *ptp_clock_info* > > struct I made use of the *ptp_find_pin* to map a (function,channel) to a > > (pin). Using the testptp.c app I am able to successfully switch to func=1 > > (EXTTS) mode and time stamping works. However, when I try and switch back > > to func=0 (NONE) the testptp application hangs, and I get a kernel panic > > (slow mutex). > > It is hard to figure out what went wrong without seeing the code. > Please show us your diff. > > > Perhaps it isn't a good practice to call *ptp_find_pin *from within the > > enable function callback in driver code, as done in > > /drivers/net/ethernet/intel/igb/igb_ptp.c. > > I think igb is working just fine: > > # testptp -l > name SDP0 index 0 func 0 chan 0 > name SDP1 index 1 func 0 chan 0 > name SDP2 index 2 func 0 chan 0 > name SDP3 index 3 func 0 chan 0 > > # testptp -L 0,1 > set pin function okay > > # testptp -l > name SDP0 index 0 func 1 chan 0 > name SDP1 index 1 func 0 chan 0 > name SDP2 index 2 func 0 chan 0 > name SDP3 index 3 func 0 chan 0 > > # testptp -L 0,0 > set pin function okay > > # testptp -l > name SDP0 index 0 func 0 chan 0 > name SDP1 index 1 func 0 chan 0 > name SDP2 index 2 func 0 chan 0 > name SDP3 index 3 func 0 chan 0 > > Thanks, > Richard > |