| .. | .. |
|---|
| 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 | |
|---|