struct ethtool_ts_info;
 int efx_ptp_probe(struct efx_nic *efx, struct efx_channel *channel);
 void efx_ptp_defer_probe_with_channel(struct efx_nic *efx);
+struct efx_channel *efx_ptp_channel(struct efx_nic *efx);
 void efx_ptp_remove(struct efx_nic *efx);
 int efx_ptp_set_ts_config(struct efx_nic *efx, struct ifreq *ifr);
 int efx_ptp_get_ts_config(struct efx_nic *efx, struct ifreq *ifr);
 
        return efx_ptp_s27_to_ktime(nic_major, nic_minor);
 }
 
+struct efx_channel *efx_ptp_channel(struct efx_nic *efx)
+{
+       return efx->ptp_data ? efx->ptp_data->channel : NULL;
+}
+
+static u32 last_sync_timestamp_major(struct efx_nic *efx)
+{
+       struct efx_channel *channel = efx_ptp_channel(efx);
+       u32 major = 0;
+
+       if (channel)
+               major = channel->sync_timestamp_major;
+       return major;
+}
+
+/* The 8000 series and later can provide the time from the MAC, which is only
+ * 48 bits long and provides meta-information in the top 2 bits.
+ */
+static ktime_t
+efx_ptp_mac_s27_to_ktime_correction(struct efx_nic *efx,
+                                   u32 nic_major, u32 nic_minor,
+                                   s32 correction)
+{
+       ktime_t kt = { 0 };
+
+       if (!(nic_major & 0x80000000)) {
+               WARN_ON_ONCE(nic_major >> 16);
+               /* Use the top bits from the latest sync event. */
+               nic_major &= 0xffff;
+               nic_major |= (last_sync_timestamp_major(efx) & 0xffff0000);
+
+               kt = efx_ptp_s27_to_ktime_correction(nic_major, nic_minor,
+                                                    correction);
+       }
+       return kt;
+}
+
 ktime_t efx_ptp_nic_to_kernel_time(struct efx_tx_queue *tx_queue)
 {
        struct efx_nic *efx = tx_queue->efx;
        struct efx_ptp_data *ptp = efx->ptp_data;
        ktime_t kt;
 
-       kt = ptp->nic_to_kernel_time(tx_queue->completed_timestamp_major,
-                                    tx_queue->completed_timestamp_minor, 0);
+       if (efx_ptp_use_mac_tx_timestamps(efx))
+               kt = efx_ptp_mac_s27_to_ktime_correction(efx,
+                               tx_queue->completed_timestamp_major,
+                               tx_queue->completed_timestamp_minor, 0);
+       else
+               kt = ptp->nic_to_kernel_time(
+                               tx_queue->completed_timestamp_major,
+                               tx_queue->completed_timestamp_minor, 0);
        return kt;
 }