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 <[email protected]>
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
>
------------------------------------------------------------------------------
Site24x7 APM Insight: Get Deep Visibility into Application Performance
APM + Mobile APM + RUM: Monitor 3 App instances at just $35/Month
Monitor end-to-end web transactions and take corrective actions now
Troubleshoot faster and improve end-user experience. Signup Now!
http://pubads.g.doubleclick.net/gampad/clk?id=267308311&iu=/4140
_______________________________________________
Linuxptp-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/linuxptp-devel

Reply via email to