Lines Matching +full:clock +full:- +full:error +full:- +full:detect

1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd. */
3 /* Copyright (c) 1999 - 2025 Intel Corporation. */
38 seq = read_seqbegin(&wx->hw_tc_lock); in wx_ptp_timecounter_cyc2time()
39 ns = timecounter_cyc2time(&wx->hw_tc, timestamp); in wx_ptp_timecounter_cyc2time()
40 } while (read_seqretry(&wx->hw_tc_lock, seq)); in wx_ptp_timecounter_cyc2time()
69 incval = READ_ONCE(wx->base_incval); in wx_ptp_adjfine()
72 mask = (wx->mac.type == wx_mac_em) ? 0x7FFFFFF : 0xFFFFFF; in wx_ptp_adjfine()
74 if (wx->mac.type != wx_mac_em) in wx_ptp_adjfine()
87 write_seqlock_irqsave(&wx->hw_tc_lock, flags); in wx_ptp_adjtime()
88 timecounter_adjtime(&wx->hw_tc, delta); in wx_ptp_adjtime()
89 write_sequnlock_irqrestore(&wx->hw_tc_lock, flags); in wx_ptp_adjtime()
91 if (wx->ptp_setup_sdp) in wx_ptp_adjtime()
92 wx->ptp_setup_sdp(wx); in wx_ptp_adjtime()
120 write_seqlock_irqsave(&wx->hw_tc_lock, flags); in wx_ptp_settime64()
121 timecounter_init(&wx->hw_tc, &wx->hw_cc, ns); in wx_ptp_settime64()
122 write_sequnlock_irqrestore(&wx->hw_tc_lock, flags); in wx_ptp_settime64()
124 if (wx->ptp_setup_sdp) in wx_ptp_settime64()
125 wx->ptp_setup_sdp(wx); in wx_ptp_settime64()
131 * wx_ptp_clear_tx_timestamp - utility function to clear Tx timestamp state
141 if (wx->ptp_tx_skb) { in wx_ptp_clear_tx_timestamp()
142 dev_kfree_skb_any(wx->ptp_tx_skb); in wx_ptp_clear_tx_timestamp()
143 wx->ptp_tx_skb = NULL; in wx_ptp_clear_tx_timestamp()
145 clear_bit_unlock(WX_STATE_PTP_TX_IN_PROGRESS, wx->state); in wx_ptp_clear_tx_timestamp()
149 * wx_ptp_convert_to_hwtstamp - convert register value to hw timestamp
172 hwtstamp->hwtstamp = ns_to_ktime(ns); in wx_ptp_convert_to_hwtstamp()
176 * wx_ptp_tx_hwtstamp - utility function which checks for TX time stamp
186 struct sk_buff *skb = wx->ptp_tx_skb; in wx_ptp_tx_hwtstamp()
194 wx->ptp_tx_skb = NULL; in wx_ptp_tx_hwtstamp()
195 clear_bit_unlock(WX_STATE_PTP_TX_IN_PROGRESS, wx->state); in wx_ptp_tx_hwtstamp()
198 wx->tx_hwtstamp_pkts++; in wx_ptp_tx_hwtstamp()
206 if (!wx->ptp_tx_skb) { in wx_ptp_tx_hwtstamp_work()
218 return -1; in wx_ptp_tx_hwtstamp_work()
222 * wx_ptp_overflow_check - watchdog task to detect SYSTIME overflow
233 bool timeout = time_is_before_jiffies(wx->last_overflow_check + in wx_ptp_overflow_check()
239 write_seqlock_irqsave(&wx->hw_tc_lock, flags); in wx_ptp_overflow_check()
240 timecounter_read(&wx->hw_tc); in wx_ptp_overflow_check()
241 write_sequnlock_irqrestore(&wx->hw_tc_lock, flags); in wx_ptp_overflow_check()
243 wx->last_overflow_check = jiffies; in wx_ptp_overflow_check()
248 * wx_ptp_rx_hang - detect error case when Rx timestamp registers latched
251 * this watchdog task is scheduled to detect error case where hardware has
253 * particular error is rare but leaves the device in a state unable to
269 wx->last_rx_ptp_check = jiffies; in wx_ptp_rx_hang()
274 rx_event = wx->last_rx_ptp_check; in wx_ptp_rx_hang()
275 for (n = 0; n < wx->num_rx_queues; n++) { in wx_ptp_rx_hang()
276 rx_ring = wx->rx_ring[n]; in wx_ptp_rx_hang()
277 if (time_after(rx_ring->last_rx_timestamp, rx_event)) in wx_ptp_rx_hang()
278 rx_event = rx_ring->last_rx_timestamp; in wx_ptp_rx_hang()
284 wx->last_rx_ptp_check = jiffies; in wx_ptp_rx_hang()
286 wx->rx_hwtstamp_cleared++; in wx_ptp_rx_hang()
287 dev_warn(&wx->pdev->dev, "clearing RX Timestamp hang"); in wx_ptp_rx_hang()
292 * wx_ptp_tx_hang - detect error case where Tx timestamp never finishes
297 bool timeout = time_is_before_jiffies(wx->ptp_tx_start + in wx_ptp_tx_hang()
300 if (!wx->ptp_tx_skb) in wx_ptp_tx_hang()
303 if (!test_bit(WX_STATE_PTP_TX_IN_PROGRESS, wx->state)) in wx_ptp_tx_hang()
312 wx->tx_hwtstamp_timeouts++; in wx_ptp_tx_hang()
313 dev_warn(&wx->pdev->dev, "clearing Tx timestamp hang\n"); in wx_ptp_tx_hang()
326 wx->flags))) in wx_ptp_do_aux_work()
335 struct cyclecounter *cc = &wx->hw_cc; in wx_ptp_trigger_calc()
340 /* Read the current clock time, and save the cycle counter value */ in wx_ptp_trigger_calc()
341 write_seqlock_irqsave(&wx->hw_tc_lock, flags); in wx_ptp_trigger_calc()
342 ns = timecounter_read(&wx->hw_tc); in wx_ptp_trigger_calc()
343 wx->pps_edge_start = wx->hw_tc.cycle_last; in wx_ptp_trigger_calc()
344 write_sequnlock_irqrestore(&wx->hw_tc_lock, flags); in wx_ptp_trigger_calc()
345 wx->pps_edge_end = wx->pps_edge_start; in wx_ptp_trigger_calc()
350 /* Figure out how many nanoseconds to add to round the clock edge up in wx_ptp_trigger_calc()
353 rem = (WX_NS_PER_SEC - rem); in wx_ptp_trigger_calc()
355 /* Adjust the clock edge to align with the next full second. */ in wx_ptp_trigger_calc()
356 wx->pps_edge_start += div_u64(((u64)rem << cc->shift), cc->mult); in wx_ptp_trigger_calc()
357 wx->pps_edge_end += div_u64(((u64)(rem + wx->pps_width) << in wx_ptp_trigger_calc()
358 cc->shift), cc->mult); in wx_ptp_trigger_calc()
365 struct cyclecounter *cc = &wx->hw_cc; in wx_ptp_setup_sdp()
369 if (wx->pps_width >= WX_NS_PER_SEC) { in wx_ptp_setup_sdp()
371 return -EINVAL; in wx_ptp_setup_sdp()
378 if (!test_bit(WX_FLAG_PTP_PPS_ENABLED, wx->flags)) { in wx_ptp_setup_sdp()
379 if (wx->pps_enabled) { in wx_ptp_setup_sdp()
380 wx->pps_enabled = false; in wx_ptp_setup_sdp()
386 wx->pps_enabled = true; in wx_ptp_setup_sdp()
388 wx_set_pps(wx, wx->pps_enabled, nsec, wx->pps_edge_start); in wx_ptp_setup_sdp()
392 wr32ptp(wx, WX_TSC_1588_TRGT_L(0), (u32)wx->pps_edge_start); in wx_ptp_setup_sdp()
393 wr32ptp(wx, WX_TSC_1588_TRGT_H(0), (u32)(wx->pps_edge_start >> 32)); in wx_ptp_setup_sdp()
394 wr32ptp(wx, WX_TSC_1588_TRGT_L(1), (u32)wx->pps_edge_end); in wx_ptp_setup_sdp()
395 wr32ptp(wx, WX_TSC_1588_TRGT_H(1), (u32)(wx->pps_edge_end >> 32)); in wx_ptp_setup_sdp()
403 /* Adjust the clock edge to align with the next full second. */ in wx_ptp_setup_sdp()
404 wx->sec_to_cc = div_u64(((u64)WX_NS_PER_SEC << cc->shift), cc->mult); in wx_ptp_setup_sdp()
417 * event when the clock SDP triggers. Clear mask when PPS is in wx_ptp_feature_enable()
420 if (rq->type != PTP_CLK_REQ_PEROUT || !wx->ptp_setup_sdp) in wx_ptp_feature_enable()
421 return -EOPNOTSUPP; in wx_ptp_feature_enable()
424 if (rq->perout.flags & ~(PTP_PEROUT_DUTY_CYCLE | in wx_ptp_feature_enable()
426 return -EOPNOTSUPP; in wx_ptp_feature_enable()
428 if (rq->perout.phase.sec || rq->perout.phase.nsec) { in wx_ptp_feature_enable()
430 return -EINVAL; in wx_ptp_feature_enable()
433 if (rq->perout.period.sec != 1 || rq->perout.period.nsec) { in wx_ptp_feature_enable()
435 return -EINVAL; in wx_ptp_feature_enable()
438 if (rq->perout.flags & PTP_PEROUT_DUTY_CYCLE) { in wx_ptp_feature_enable()
441 ts_on.tv_sec = rq->perout.on.sec; in wx_ptp_feature_enable()
442 ts_on.tv_nsec = rq->perout.on.nsec; in wx_ptp_feature_enable()
443 wx->pps_width = timespec64_to_ns(&ts_on); in wx_ptp_feature_enable()
445 wx->pps_width = 120000000; in wx_ptp_feature_enable()
449 set_bit(WX_FLAG_PTP_PPS_ENABLED, wx->flags); in wx_ptp_feature_enable()
451 clear_bit(WX_FLAG_PTP_PPS_ENABLED, wx->flags); in wx_ptp_feature_enable()
453 return wx->ptp_setup_sdp(wx); in wx_ptp_feature_enable()
464 if (!wx->ptp_clock) in wx_ptp_check_pps_event()
477 wr32ptp(wx, WX_TSC_1588_TRGT_L(0), (u32)wx->pps_edge_start); in wx_ptp_check_pps_event()
478 wr32ptp(wx, WX_TSC_1588_TRGT_H(0), (u32)(wx->pps_edge_start >> 32)); in wx_ptp_check_pps_event()
479 wr32ptp(wx, WX_TSC_1588_TRGT_L(1), (u32)wx->pps_edge_end); in wx_ptp_check_pps_event()
480 wr32ptp(wx, WX_TSC_1588_TRGT_H(1), (u32)(wx->pps_edge_end >> 32)); in wx_ptp_check_pps_event()
489 struct net_device *netdev = wx->netdev; in wx_ptp_create_clock()
492 /* do nothing if we already have a clock device */ in wx_ptp_create_clock()
493 if (!IS_ERR_OR_NULL(wx->ptp_clock)) in wx_ptp_create_clock()
496 snprintf(wx->ptp_caps.name, sizeof(wx->ptp_caps.name), in wx_ptp_create_clock()
497 "%s", netdev->name); in wx_ptp_create_clock()
498 wx->ptp_caps.owner = THIS_MODULE; in wx_ptp_create_clock()
499 wx->ptp_caps.n_alarm = 0; in wx_ptp_create_clock()
500 wx->ptp_caps.n_ext_ts = 0; in wx_ptp_create_clock()
501 wx->ptp_caps.pps = 0; in wx_ptp_create_clock()
502 wx->ptp_caps.adjfine = wx_ptp_adjfine; in wx_ptp_create_clock()
503 wx->ptp_caps.adjtime = wx_ptp_adjtime; in wx_ptp_create_clock()
504 wx->ptp_caps.gettimex64 = wx_ptp_gettimex64; in wx_ptp_create_clock()
505 wx->ptp_caps.settime64 = wx_ptp_settime64; in wx_ptp_create_clock()
506 wx->ptp_caps.do_aux_work = wx_ptp_do_aux_work; in wx_ptp_create_clock()
507 if (wx->mac.type == wx_mac_em) { in wx_ptp_create_clock()
508 wx->ptp_caps.max_adj = 500000000; in wx_ptp_create_clock()
509 wx->ptp_caps.n_per_out = 1; in wx_ptp_create_clock()
510 wx->ptp_setup_sdp = wx_ptp_setup_sdp; in wx_ptp_create_clock()
511 wx->ptp_caps.enable = wx_ptp_feature_enable; in wx_ptp_create_clock()
513 wx->ptp_caps.max_adj = 250000000; in wx_ptp_create_clock()
514 wx->ptp_caps.n_per_out = 0; in wx_ptp_create_clock()
515 wx->ptp_setup_sdp = NULL; in wx_ptp_create_clock()
518 wx->ptp_clock = ptp_clock_register(&wx->ptp_caps, &wx->pdev->dev); in wx_ptp_create_clock()
519 if (IS_ERR(wx->ptp_clock)) { in wx_ptp_create_clock()
520 err = PTR_ERR(wx->ptp_clock); in wx_ptp_create_clock()
521 wx->ptp_clock = NULL; in wx_ptp_create_clock()
522 wx_err(wx, "ptp clock register failed\n"); in wx_ptp_create_clock()
524 } else if (wx->ptp_clock) { in wx_ptp_create_clock()
525 dev_info(&wx->pdev->dev, "registered PHC device on %s\n", in wx_ptp_create_clock()
526 netdev->name); in wx_ptp_create_clock()
533 wx->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; in wx_ptp_create_clock()
534 wx->tstamp_config.tx_type = HWTSTAMP_TX_OFF; in wx_ptp_create_clock()
549 memcpy(flags, wx->flags, sizeof(wx->flags)); in wx_ptp_set_timestamp_mode()
551 switch (config->tx_type) { in wx_ptp_set_timestamp_mode()
558 return -ERANGE; in wx_ptp_set_timestamp_mode()
561 switch (config->rx_filter) { in wx_ptp_set_timestamp_mode()
591 config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; in wx_ptp_set_timestamp_mode()
599 * packets => return error in wx_ptp_set_timestamp_mode()
601 config->rx_filter = HWTSTAMP_FILTER_NONE; in wx_ptp_set_timestamp_mode()
602 return -ERANGE; in wx_ptp_set_timestamp_mode()
632 memcpy(wx->flags, flags, sizeof(wx->flags)); in wx_ptp_set_timestamp_mode()
650 if (wx->mac.type == wx_mac_em) { in wx_ptp_link_speed_adjust()
656 switch (wx->speed) { in wx_ptp_link_speed_adjust()
678 * wx_ptp_reset_cyclecounter - create the cycle counter from hw
698 * they do not properly function if the overflow point isn't 2^N-1. in wx_ptp_reset_cyclecounter()
712 WRITE_ONCE(wx->base_incval, incval); in wx_ptp_reset_cyclecounter()
714 mask = (wx->mac.type == wx_mac_em) ? 0x7FFFFFF : 0xFFFFFF; in wx_ptp_reset_cyclecounter()
716 if (wx->mac.type != wx_mac_em) in wx_ptp_reset_cyclecounter()
723 write_seqlock_irqsave(&wx->hw_tc_lock, flags); in wx_ptp_reset_cyclecounter()
724 memcpy(&wx->hw_cc, &cc, sizeof(wx->hw_cc)); in wx_ptp_reset_cyclecounter()
725 write_sequnlock_irqrestore(&wx->hw_tc_lock, flags); in wx_ptp_reset_cyclecounter()
734 wx_ptp_set_timestamp_mode(wx, &wx->tstamp_config); in wx_ptp_reset()
741 write_seqlock_irqsave(&wx->hw_tc_lock, flags); in wx_ptp_reset()
742 timecounter_init(&wx->hw_tc, &wx->hw_cc, in wx_ptp_reset()
744 write_sequnlock_irqrestore(&wx->hw_tc_lock, flags); in wx_ptp_reset()
746 wx->last_overflow_check = jiffies; in wx_ptp_reset()
747 ptp_schedule_worker(wx->ptp_clock, HZ); in wx_ptp_reset()
750 * registers reset, (re-)enable the Clock out feature in wx_ptp_reset()
752 if (wx->ptp_setup_sdp) in wx_ptp_reset()
753 wx->ptp_setup_sdp(wx); in wx_ptp_reset()
759 /* Initialize the seqlock_t first, since the user might call the clock in wx_ptp_init()
760 * functions any time after we've initialized the ptp clock device. in wx_ptp_init()
762 seqlock_init(&wx->hw_tc_lock); in wx_ptp_init()
764 /* obtain a ptp clock device, or re-use an existing device */ in wx_ptp_init()
768 wx->tx_hwtstamp_pkts = 0; in wx_ptp_init()
769 wx->tx_hwtstamp_timeouts = 0; in wx_ptp_init()
770 wx->tx_hwtstamp_skipped = 0; in wx_ptp_init()
771 wx->tx_hwtstamp_errors = 0; in wx_ptp_init()
772 wx->rx_hwtstamp_cleared = 0; in wx_ptp_init()
777 set_bit(WX_STATE_PTP_RUNNING, wx->state); in wx_ptp_init()
782 * wx_ptp_suspend - stop ptp work items
786 * generated, but does not destroy the clock device.
791 if (!test_and_clear_bit(WX_STATE_PTP_RUNNING, wx->state)) in wx_ptp_suspend()
794 clear_bit(WX_FLAG_PTP_PPS_ENABLED, wx->flags); in wx_ptp_suspend()
795 if (wx->ptp_setup_sdp) in wx_ptp_suspend()
796 wx->ptp_setup_sdp(wx); in wx_ptp_suspend()
803 * wx_ptp_stop - destroy the ptp_clock device
814 /* now destroy the ptp clock device */ in wx_ptp_stop()
815 if (wx->ptp_clock) { in wx_ptp_stop()
816 ptp_clock_unregister(wx->ptp_clock); in wx_ptp_stop()
817 wx->ptp_clock = NULL; in wx_ptp_stop()
818 dev_info(&wx->pdev->dev, "removed PHC on %s\n", wx->netdev->name); in wx_ptp_stop()
824 * wx_ptp_rx_hwtstamp - utility function which checks for RX time stamp
856 return -EINVAL; in wx_hwtstamp_get()
858 *cfg = wx->tstamp_config; in wx_hwtstamp_get()
872 return -EINVAL; in wx_hwtstamp_set()
879 memcpy(&wx->tstamp_config, cfg, sizeof(wx->tstamp_config)); in wx_hwtstamp_set()