.. | .. |
---|
53 | 53 | * 2^40 * 10^-9 / 60 = 18.3 minutes. |
---|
54 | 54 | * |
---|
55 | 55 | * SYSTIM is converted to real time using a timecounter. As |
---|
56 | | - * timecounter_cyc2time() allows old timestamps, the timecounter |
---|
57 | | - * needs to be updated at least once per half of the SYSTIM interval. |
---|
58 | | - * Scheduling of delayed work is not very accurate, so we aim for 8 |
---|
59 | | - * minutes to be sure the actual interval is shorter than 9.16 minutes. |
---|
| 56 | + * timecounter_cyc2time() allows old timestamps, the timecounter needs |
---|
| 57 | + * to be updated at least once per half of the SYSTIM interval. |
---|
| 58 | + * Scheduling of delayed work is not very accurate, and also the NIC |
---|
| 59 | + * clock can be adjusted to run up to 6% faster and the system clock |
---|
| 60 | + * up to 10% slower, so we aim for 6 minutes to be sure the actual |
---|
| 61 | + * interval in the NIC time is shorter than 9.16 minutes. |
---|
60 | 62 | */ |
---|
61 | 63 | |
---|
62 | | -#define IGB_SYSTIM_OVERFLOW_PERIOD (HZ * 60 * 8) |
---|
| 64 | +#define IGB_SYSTIM_OVERFLOW_PERIOD (HZ * 60 * 6) |
---|
63 | 65 | #define IGB_PTP_TX_TIMEOUT (HZ * 15) |
---|
64 | 66 | #define INCPERIOD_82576 BIT(E1000_TIMINCA_16NS_SHIFT) |
---|
65 | 67 | #define INCVALUE_82576_MASK GENMASK(E1000_TIMINCA_16NS_SHIFT - 1, 0) |
---|
.. | .. |
---|
275 | 277 | return 0; |
---|
276 | 278 | } |
---|
277 | 279 | |
---|
278 | | -static int igb_ptp_gettime_82576(struct ptp_clock_info *ptp, |
---|
279 | | - struct timespec64 *ts) |
---|
| 280 | +static int igb_ptp_gettimex_82576(struct ptp_clock_info *ptp, |
---|
| 281 | + struct timespec64 *ts, |
---|
| 282 | + struct ptp_system_timestamp *sts) |
---|
280 | 283 | { |
---|
281 | 284 | struct igb_adapter *igb = container_of(ptp, struct igb_adapter, |
---|
282 | 285 | ptp_caps); |
---|
| 286 | + struct e1000_hw *hw = &igb->hw; |
---|
283 | 287 | unsigned long flags; |
---|
| 288 | + u32 lo, hi; |
---|
284 | 289 | u64 ns; |
---|
285 | 290 | |
---|
286 | 291 | spin_lock_irqsave(&igb->tmreg_lock, flags); |
---|
287 | 292 | |
---|
288 | | - ns = timecounter_read(&igb->tc); |
---|
| 293 | + ptp_read_system_prets(sts); |
---|
| 294 | + lo = rd32(E1000_SYSTIML); |
---|
| 295 | + ptp_read_system_postts(sts); |
---|
| 296 | + hi = rd32(E1000_SYSTIMH); |
---|
| 297 | + |
---|
| 298 | + ns = timecounter_cyc2time(&igb->tc, ((u64)hi << 32) | lo); |
---|
289 | 299 | |
---|
290 | 300 | spin_unlock_irqrestore(&igb->tmreg_lock, flags); |
---|
291 | 301 | |
---|
.. | .. |
---|
294 | 304 | return 0; |
---|
295 | 305 | } |
---|
296 | 306 | |
---|
297 | | -static int igb_ptp_gettime_i210(struct ptp_clock_info *ptp, |
---|
298 | | - struct timespec64 *ts) |
---|
| 307 | +static int igb_ptp_gettimex_82580(struct ptp_clock_info *ptp, |
---|
| 308 | + struct timespec64 *ts, |
---|
| 309 | + struct ptp_system_timestamp *sts) |
---|
299 | 310 | { |
---|
300 | 311 | struct igb_adapter *igb = container_of(ptp, struct igb_adapter, |
---|
301 | 312 | ptp_caps); |
---|
| 313 | + struct e1000_hw *hw = &igb->hw; |
---|
| 314 | + unsigned long flags; |
---|
| 315 | + u32 lo, hi; |
---|
| 316 | + u64 ns; |
---|
| 317 | + |
---|
| 318 | + spin_lock_irqsave(&igb->tmreg_lock, flags); |
---|
| 319 | + |
---|
| 320 | + ptp_read_system_prets(sts); |
---|
| 321 | + rd32(E1000_SYSTIMR); |
---|
| 322 | + ptp_read_system_postts(sts); |
---|
| 323 | + lo = rd32(E1000_SYSTIML); |
---|
| 324 | + hi = rd32(E1000_SYSTIMH); |
---|
| 325 | + |
---|
| 326 | + ns = timecounter_cyc2time(&igb->tc, ((u64)hi << 32) | lo); |
---|
| 327 | + |
---|
| 328 | + spin_unlock_irqrestore(&igb->tmreg_lock, flags); |
---|
| 329 | + |
---|
| 330 | + *ts = ns_to_timespec64(ns); |
---|
| 331 | + |
---|
| 332 | + return 0; |
---|
| 333 | +} |
---|
| 334 | + |
---|
| 335 | +static int igb_ptp_gettimex_i210(struct ptp_clock_info *ptp, |
---|
| 336 | + struct timespec64 *ts, |
---|
| 337 | + struct ptp_system_timestamp *sts) |
---|
| 338 | +{ |
---|
| 339 | + struct igb_adapter *igb = container_of(ptp, struct igb_adapter, |
---|
| 340 | + ptp_caps); |
---|
| 341 | + struct e1000_hw *hw = &igb->hw; |
---|
302 | 342 | unsigned long flags; |
---|
303 | 343 | |
---|
304 | 344 | spin_lock_irqsave(&igb->tmreg_lock, flags); |
---|
305 | 345 | |
---|
306 | | - igb_ptp_read_i210(igb, ts); |
---|
| 346 | + ptp_read_system_prets(sts); |
---|
| 347 | + rd32(E1000_SYSTIMR); |
---|
| 348 | + ptp_read_system_postts(sts); |
---|
| 349 | + ts->tv_nsec = rd32(E1000_SYSTIML); |
---|
| 350 | + ts->tv_sec = rd32(E1000_SYSTIMH); |
---|
307 | 351 | |
---|
308 | 352 | spin_unlock_irqrestore(&igb->tmreg_lock, flags); |
---|
309 | 353 | |
---|
.. | .. |
---|
477 | 521 | |
---|
478 | 522 | switch (rq->type) { |
---|
479 | 523 | case PTP_CLK_REQ_EXTTS: |
---|
| 524 | + /* Reject requests with unsupported flags */ |
---|
| 525 | + if (rq->extts.flags & ~(PTP_ENABLE_FEATURE | |
---|
| 526 | + PTP_RISING_EDGE | |
---|
| 527 | + PTP_FALLING_EDGE | |
---|
| 528 | + PTP_STRICT_FLAGS)) |
---|
| 529 | + return -EOPNOTSUPP; |
---|
| 530 | + |
---|
| 531 | + /* Reject requests failing to enable both edges. */ |
---|
| 532 | + if ((rq->extts.flags & PTP_STRICT_FLAGS) && |
---|
| 533 | + (rq->extts.flags & PTP_ENABLE_FEATURE) && |
---|
| 534 | + (rq->extts.flags & PTP_EXTTS_EDGES) != PTP_EXTTS_EDGES) |
---|
| 535 | + return -EOPNOTSUPP; |
---|
| 536 | + |
---|
480 | 537 | if (on) { |
---|
481 | 538 | pin = ptp_find_pin(igb->ptp_clock, PTP_PF_EXTTS, |
---|
482 | 539 | rq->extts.index); |
---|
.. | .. |
---|
507 | 564 | return 0; |
---|
508 | 565 | |
---|
509 | 566 | case PTP_CLK_REQ_PEROUT: |
---|
| 567 | + /* Reject requests with unsupported flags */ |
---|
| 568 | + if (rq->perout.flags) |
---|
| 569 | + return -EOPNOTSUPP; |
---|
| 570 | + |
---|
510 | 571 | if (on) { |
---|
511 | 572 | pin = ptp_find_pin(igb->ptp_clock, PTP_PF_PEROUT, |
---|
512 | 573 | rq->perout.index); |
---|
.. | .. |
---|
656 | 717 | struct igb_adapter *igb = |
---|
657 | 718 | container_of(work, struct igb_adapter, ptp_overflow_work.work); |
---|
658 | 719 | struct timespec64 ts; |
---|
| 720 | + u64 ns; |
---|
659 | 721 | |
---|
660 | | - igb->ptp_caps.gettime64(&igb->ptp_caps, &ts); |
---|
| 722 | + /* Update the timecounter */ |
---|
| 723 | + ns = timecounter_read(&igb->tc); |
---|
661 | 724 | |
---|
| 725 | + ts = ns_to_timespec64(ns); |
---|
662 | 726 | pr_debug("igb overflow check at %lld.%09lu\n", |
---|
663 | 727 | (long long) ts.tv_sec, ts.tv_nsec); |
---|
664 | 728 | |
---|
.. | .. |
---|
792 | 856 | dev_kfree_skb_any(skb); |
---|
793 | 857 | } |
---|
794 | 858 | |
---|
| 859 | +#define IGB_RET_PTP_DISABLED 1 |
---|
| 860 | +#define IGB_RET_PTP_INVALID 2 |
---|
| 861 | + |
---|
795 | 862 | /** |
---|
796 | 863 | * igb_ptp_rx_pktstamp - retrieve Rx per packet timestamp |
---|
797 | 864 | * @q_vector: Pointer to interrupt specific structure |
---|
.. | .. |
---|
800 | 867 | * |
---|
801 | 868 | * This function is meant to retrieve a timestamp from the first buffer of an |
---|
802 | 869 | * incoming frame. The value is stored in little endian format starting on |
---|
803 | | - * byte 8. |
---|
| 870 | + * byte 8 |
---|
| 871 | + * |
---|
| 872 | + * Returns: 0 if success, nonzero if failure |
---|
804 | 873 | **/ |
---|
805 | | -void igb_ptp_rx_pktstamp(struct igb_q_vector *q_vector, void *va, |
---|
806 | | - struct sk_buff *skb) |
---|
| 874 | +int igb_ptp_rx_pktstamp(struct igb_q_vector *q_vector, void *va, |
---|
| 875 | + struct sk_buff *skb) |
---|
807 | 876 | { |
---|
808 | | - __le64 *regval = (__le64 *)va; |
---|
809 | 877 | struct igb_adapter *adapter = q_vector->adapter; |
---|
| 878 | + __le64 *regval = (__le64 *)va; |
---|
810 | 879 | int adjust = 0; |
---|
| 880 | + |
---|
| 881 | + if (!(adapter->ptp_flags & IGB_PTP_ENABLED)) |
---|
| 882 | + return IGB_RET_PTP_DISABLED; |
---|
811 | 883 | |
---|
812 | 884 | /* The timestamp is recorded in little endian format. |
---|
813 | 885 | * DWORD: 0 1 2 3 |
---|
814 | 886 | * Field: Reserved Reserved SYSTIML SYSTIMH |
---|
815 | 887 | */ |
---|
| 888 | + |
---|
| 889 | + /* check reserved dwords are zero, be/le doesn't matter for zero */ |
---|
| 890 | + if (regval[0]) |
---|
| 891 | + return IGB_RET_PTP_INVALID; |
---|
| 892 | + |
---|
816 | 893 | igb_ptp_systim_to_hwtstamp(adapter, skb_hwtstamps(skb), |
---|
817 | 894 | le64_to_cpu(regval[1])); |
---|
818 | 895 | |
---|
.. | .. |
---|
832 | 909 | } |
---|
833 | 910 | skb_hwtstamps(skb)->hwtstamp = |
---|
834 | 911 | ktime_sub_ns(skb_hwtstamps(skb)->hwtstamp, adjust); |
---|
| 912 | + |
---|
| 913 | + return 0; |
---|
835 | 914 | } |
---|
836 | 915 | |
---|
837 | 916 | /** |
---|
.. | .. |
---|
842 | 921 | * This function is meant to retrieve a timestamp from the internal registers |
---|
843 | 922 | * of the adapter and store it in the skb. |
---|
844 | 923 | **/ |
---|
845 | | -void igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector, |
---|
846 | | - struct sk_buff *skb) |
---|
| 924 | +void igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector, struct sk_buff *skb) |
---|
847 | 925 | { |
---|
848 | 926 | struct igb_adapter *adapter = q_vector->adapter; |
---|
849 | 927 | struct e1000_hw *hw = &adapter->hw; |
---|
850 | | - u64 regval; |
---|
851 | 928 | int adjust = 0; |
---|
| 929 | + u64 regval; |
---|
| 930 | + |
---|
| 931 | + if (!(adapter->ptp_flags & IGB_PTP_ENABLED)) |
---|
| 932 | + return; |
---|
852 | 933 | |
---|
853 | 934 | /* If this bit is set, then the RX registers contain the time stamp. No |
---|
854 | 935 | * other packet will be time stamped until we read these registers, so |
---|
.. | .. |
---|
893 | 974 | |
---|
894 | 975 | /** |
---|
895 | 976 | * igb_ptp_get_ts_config - get hardware time stamping config |
---|
896 | | - * @netdev: |
---|
897 | | - * @ifreq: |
---|
| 977 | + * @netdev: netdev struct |
---|
| 978 | + * @ifr: interface struct |
---|
898 | 979 | * |
---|
899 | 980 | * Get the hwtstamp_config settings to return to the user. Rather than attempt |
---|
900 | 981 | * to deconstruct the settings from the registers, just return a shadow copy |
---|
.. | .. |
---|
989 | 1070 | config->rx_filter = HWTSTAMP_FILTER_ALL; |
---|
990 | 1071 | break; |
---|
991 | 1072 | } |
---|
992 | | - /* fall through */ |
---|
| 1073 | + fallthrough; |
---|
993 | 1074 | default: |
---|
994 | 1075 | config->rx_filter = HWTSTAMP_FILTER_NONE; |
---|
995 | 1076 | return -ERANGE; |
---|
.. | .. |
---|
1077 | 1158 | |
---|
1078 | 1159 | /** |
---|
1079 | 1160 | * igb_ptp_set_ts_config - set hardware time stamping config |
---|
1080 | | - * @netdev: |
---|
1081 | | - * @ifreq: |
---|
| 1161 | + * @netdev: netdev struct |
---|
| 1162 | + * @ifr: interface struct |
---|
1082 | 1163 | * |
---|
1083 | 1164 | **/ |
---|
1084 | 1165 | int igb_ptp_set_ts_config(struct net_device *netdev, struct ifreq *ifr) |
---|
.. | .. |
---|
1124 | 1205 | adapter->ptp_caps.pps = 0; |
---|
1125 | 1206 | adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82576; |
---|
1126 | 1207 | adapter->ptp_caps.adjtime = igb_ptp_adjtime_82576; |
---|
1127 | | - adapter->ptp_caps.gettime64 = igb_ptp_gettime_82576; |
---|
| 1208 | + adapter->ptp_caps.gettimex64 = igb_ptp_gettimex_82576; |
---|
1128 | 1209 | adapter->ptp_caps.settime64 = igb_ptp_settime_82576; |
---|
1129 | 1210 | adapter->ptp_caps.enable = igb_ptp_feature_enable; |
---|
1130 | 1211 | adapter->cc.read = igb_ptp_read_82576; |
---|
.. | .. |
---|
1143 | 1224 | adapter->ptp_caps.pps = 0; |
---|
1144 | 1225 | adapter->ptp_caps.adjfine = igb_ptp_adjfine_82580; |
---|
1145 | 1226 | adapter->ptp_caps.adjtime = igb_ptp_adjtime_82576; |
---|
1146 | | - adapter->ptp_caps.gettime64 = igb_ptp_gettime_82576; |
---|
| 1227 | + adapter->ptp_caps.gettimex64 = igb_ptp_gettimex_82580; |
---|
1147 | 1228 | adapter->ptp_caps.settime64 = igb_ptp_settime_82576; |
---|
1148 | 1229 | adapter->ptp_caps.enable = igb_ptp_feature_enable; |
---|
1149 | 1230 | adapter->cc.read = igb_ptp_read_82580; |
---|
.. | .. |
---|
1171 | 1252 | adapter->ptp_caps.pin_config = adapter->sdp_config; |
---|
1172 | 1253 | adapter->ptp_caps.adjfine = igb_ptp_adjfine_82580; |
---|
1173 | 1254 | adapter->ptp_caps.adjtime = igb_ptp_adjtime_i210; |
---|
1174 | | - adapter->ptp_caps.gettime64 = igb_ptp_gettime_i210; |
---|
| 1255 | + adapter->ptp_caps.gettimex64 = igb_ptp_gettimex_i210; |
---|
1175 | 1256 | adapter->ptp_caps.settime64 = igb_ptp_settime_i210; |
---|
1176 | 1257 | adapter->ptp_caps.enable = igb_ptp_feature_enable_i210; |
---|
1177 | 1258 | adapter->ptp_caps.verify = igb_ptp_verify_pin; |
---|
.. | .. |
---|
1180 | 1261 | adapter->ptp_clock = NULL; |
---|
1181 | 1262 | return; |
---|
1182 | 1263 | } |
---|
1183 | | - |
---|
1184 | | - spin_lock_init(&adapter->tmreg_lock); |
---|
1185 | | - INIT_WORK(&adapter->ptp_tx_work, igb_ptp_tx_work); |
---|
1186 | | - |
---|
1187 | | - if (adapter->ptp_flags & IGB_PTP_OVERFLOW_CHECK) |
---|
1188 | | - INIT_DELAYED_WORK(&adapter->ptp_overflow_work, |
---|
1189 | | - igb_ptp_overflow_check); |
---|
1190 | | - |
---|
1191 | | - adapter->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; |
---|
1192 | | - adapter->tstamp_config.tx_type = HWTSTAMP_TX_OFF; |
---|
1193 | | - |
---|
1194 | | - igb_ptp_reset(adapter); |
---|
1195 | 1264 | |
---|
1196 | 1265 | adapter->ptp_clock = ptp_clock_register(&adapter->ptp_caps, |
---|
1197 | 1266 | &adapter->pdev->dev); |
---|
.. | .. |
---|
1202 | 1271 | dev_info(&adapter->pdev->dev, "added PHC on %s\n", |
---|
1203 | 1272 | adapter->netdev->name); |
---|
1204 | 1273 | adapter->ptp_flags |= IGB_PTP_ENABLED; |
---|
| 1274 | + |
---|
| 1275 | + spin_lock_init(&adapter->tmreg_lock); |
---|
| 1276 | + INIT_WORK(&adapter->ptp_tx_work, igb_ptp_tx_work); |
---|
| 1277 | + |
---|
| 1278 | + if (adapter->ptp_flags & IGB_PTP_OVERFLOW_CHECK) |
---|
| 1279 | + INIT_DELAYED_WORK(&adapter->ptp_overflow_work, |
---|
| 1280 | + igb_ptp_overflow_check); |
---|
| 1281 | + |
---|
| 1282 | + adapter->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; |
---|
| 1283 | + adapter->tstamp_config.tx_type = HWTSTAMP_TX_OFF; |
---|
| 1284 | + |
---|
| 1285 | + igb_ptp_reset(adapter); |
---|
1205 | 1286 | } |
---|
1206 | 1287 | } |
---|
1207 | 1288 | |
---|