diff options
-rw-r--r-- | drivers/net/ethernet/sfc/ef10.c | 123 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/efx.c | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/mcdi.c | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/net_driver.h | 22 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/nic.h | 9 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/ptp.c | 131 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/rx.c | 2 |
7 files changed, 277 insertions, 15 deletions
diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index ca922b958a2e..a3d891764030 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c | |||
@@ -1469,8 +1469,9 @@ static void efx_ef10_rx_init(struct efx_rx_queue *rx_queue) | |||
1469 | MCDI_SET_DWORD(inbuf, INIT_RXQ_IN_LABEL, efx_rx_queue_index(rx_queue)); | 1469 | MCDI_SET_DWORD(inbuf, INIT_RXQ_IN_LABEL, efx_rx_queue_index(rx_queue)); |
1470 | MCDI_SET_DWORD(inbuf, INIT_RXQ_IN_INSTANCE, | 1470 | MCDI_SET_DWORD(inbuf, INIT_RXQ_IN_INSTANCE, |
1471 | efx_rx_queue_index(rx_queue)); | 1471 | efx_rx_queue_index(rx_queue)); |
1472 | MCDI_POPULATE_DWORD_1(inbuf, INIT_RXQ_IN_FLAGS, | 1472 | MCDI_POPULATE_DWORD_2(inbuf, INIT_RXQ_IN_FLAGS, |
1473 | INIT_RXQ_IN_FLAG_PREFIX, 1); | 1473 | INIT_RXQ_IN_FLAG_PREFIX, 1, |
1474 | INIT_RXQ_IN_FLAG_TIMESTAMP, 1); | ||
1474 | MCDI_SET_DWORD(inbuf, INIT_RXQ_IN_OWNER_ID, 0); | 1475 | MCDI_SET_DWORD(inbuf, INIT_RXQ_IN_OWNER_ID, 0); |
1475 | MCDI_SET_DWORD(inbuf, INIT_RXQ_IN_PORT_ID, EVB_PORT_ID_ASSIGNED); | 1476 | MCDI_SET_DWORD(inbuf, INIT_RXQ_IN_PORT_ID, EVB_PORT_ID_ASSIGNED); |
1476 | 1477 | ||
@@ -3406,6 +3407,119 @@ static void efx_ef10_ptp_write_host_time(struct efx_nic *efx, u32 host_time) | |||
3406 | _efx_writed(efx, cpu_to_le32(host_time), ER_DZ_MC_DB_LWRD); | 3407 | _efx_writed(efx, cpu_to_le32(host_time), ER_DZ_MC_DB_LWRD); |
3407 | } | 3408 | } |
3408 | 3409 | ||
3410 | static int efx_ef10_rx_enable_timestamping(struct efx_channel *channel, | ||
3411 | bool temp) | ||
3412 | { | ||
3413 | MCDI_DECLARE_BUF(inbuf, MC_CMD_PTP_IN_TIME_EVENT_SUBSCRIBE_LEN); | ||
3414 | int rc; | ||
3415 | |||
3416 | if (channel->sync_events_state == SYNC_EVENTS_REQUESTED || | ||
3417 | channel->sync_events_state == SYNC_EVENTS_VALID || | ||
3418 | (temp && channel->sync_events_state == SYNC_EVENTS_DISABLED)) | ||
3419 | return 0; | ||
3420 | channel->sync_events_state = SYNC_EVENTS_REQUESTED; | ||
3421 | |||
3422 | MCDI_SET_DWORD(inbuf, PTP_IN_OP, MC_CMD_PTP_OP_TIME_EVENT_SUBSCRIBE); | ||
3423 | MCDI_SET_DWORD(inbuf, PTP_IN_PERIPH_ID, 0); | ||
3424 | MCDI_SET_DWORD(inbuf, PTP_IN_TIME_EVENT_SUBSCRIBE_QUEUE, | ||
3425 | channel->channel); | ||
3426 | |||
3427 | rc = efx_mcdi_rpc(channel->efx, MC_CMD_PTP, | ||
3428 | inbuf, sizeof(inbuf), NULL, 0, NULL); | ||
3429 | |||
3430 | if (rc != 0) | ||
3431 | channel->sync_events_state = temp ? SYNC_EVENTS_QUIESCENT : | ||
3432 | SYNC_EVENTS_DISABLED; | ||
3433 | |||
3434 | return rc; | ||
3435 | } | ||
3436 | |||
3437 | static int efx_ef10_rx_disable_timestamping(struct efx_channel *channel, | ||
3438 | bool temp) | ||
3439 | { | ||
3440 | MCDI_DECLARE_BUF(inbuf, MC_CMD_PTP_IN_TIME_EVENT_UNSUBSCRIBE_LEN); | ||
3441 | int rc; | ||
3442 | |||
3443 | if (channel->sync_events_state == SYNC_EVENTS_DISABLED || | ||
3444 | (temp && channel->sync_events_state == SYNC_EVENTS_QUIESCENT)) | ||
3445 | return 0; | ||
3446 | if (channel->sync_events_state == SYNC_EVENTS_QUIESCENT) { | ||
3447 | channel->sync_events_state = SYNC_EVENTS_DISABLED; | ||
3448 | return 0; | ||
3449 | } | ||
3450 | channel->sync_events_state = temp ? SYNC_EVENTS_QUIESCENT : | ||
3451 | SYNC_EVENTS_DISABLED; | ||
3452 | |||
3453 | MCDI_SET_DWORD(inbuf, PTP_IN_OP, MC_CMD_PTP_OP_TIME_EVENT_UNSUBSCRIBE); | ||
3454 | MCDI_SET_DWORD(inbuf, PTP_IN_PERIPH_ID, 0); | ||
3455 | MCDI_SET_DWORD(inbuf, PTP_IN_TIME_EVENT_UNSUBSCRIBE_CONTROL, | ||
3456 | MC_CMD_PTP_IN_TIME_EVENT_UNSUBSCRIBE_SINGLE); | ||
3457 | MCDI_SET_DWORD(inbuf, PTP_IN_TIME_EVENT_UNSUBSCRIBE_QUEUE, | ||
3458 | channel->channel); | ||
3459 | |||
3460 | rc = efx_mcdi_rpc(channel->efx, MC_CMD_PTP, | ||
3461 | inbuf, sizeof(inbuf), NULL, 0, NULL); | ||
3462 | |||
3463 | return rc; | ||
3464 | } | ||
3465 | |||
3466 | static int efx_ef10_ptp_set_ts_sync_events(struct efx_nic *efx, bool en, | ||
3467 | bool temp) | ||
3468 | { | ||
3469 | int (*set)(struct efx_channel *channel, bool temp); | ||
3470 | struct efx_channel *channel; | ||
3471 | |||
3472 | set = en ? | ||
3473 | efx_ef10_rx_enable_timestamping : | ||
3474 | efx_ef10_rx_disable_timestamping; | ||
3475 | |||
3476 | efx_for_each_channel(channel, efx) { | ||
3477 | int rc = set(channel, temp); | ||
3478 | if (en && rc != 0) { | ||
3479 | efx_ef10_ptp_set_ts_sync_events(efx, false, temp); | ||
3480 | return rc; | ||
3481 | } | ||
3482 | } | ||
3483 | |||
3484 | return 0; | ||
3485 | } | ||
3486 | |||
3487 | static int efx_ef10_ptp_set_ts_config(struct efx_nic *efx, | ||
3488 | struct hwtstamp_config *init) | ||
3489 | { | ||
3490 | int rc; | ||
3491 | |||
3492 | switch (init->rx_filter) { | ||
3493 | case HWTSTAMP_FILTER_NONE: | ||
3494 | efx_ef10_ptp_set_ts_sync_events(efx, false, false); | ||
3495 | /* if TX timestamping is still requested then leave PTP on */ | ||
3496 | return efx_ptp_change_mode(efx, | ||
3497 | init->tx_type != HWTSTAMP_TX_OFF, 0); | ||
3498 | case HWTSTAMP_FILTER_ALL: | ||
3499 | case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: | ||
3500 | case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: | ||
3501 | case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: | ||
3502 | case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: | ||
3503 | case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: | ||
3504 | case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: | ||
3505 | case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: | ||
3506 | case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: | ||
3507 | case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: | ||
3508 | case HWTSTAMP_FILTER_PTP_V2_EVENT: | ||
3509 | case HWTSTAMP_FILTER_PTP_V2_SYNC: | ||
3510 | case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: | ||
3511 | init->rx_filter = HWTSTAMP_FILTER_ALL; | ||
3512 | rc = efx_ptp_change_mode(efx, true, 0); | ||
3513 | if (!rc) | ||
3514 | rc = efx_ef10_ptp_set_ts_sync_events(efx, true, false); | ||
3515 | if (rc) | ||
3516 | efx_ptp_change_mode(efx, false, 0); | ||
3517 | return rc; | ||
3518 | default: | ||
3519 | return -ERANGE; | ||
3520 | } | ||
3521 | } | ||
3522 | |||
3409 | const struct efx_nic_type efx_hunt_a0_nic_type = { | 3523 | const struct efx_nic_type efx_hunt_a0_nic_type = { |
3410 | .mem_map_size = efx_ef10_mem_map_size, | 3524 | .mem_map_size = efx_ef10_mem_map_size, |
3411 | .probe = efx_ef10_probe, | 3525 | .probe = efx_ef10_probe, |
@@ -3484,11 +3598,14 @@ const struct efx_nic_type efx_hunt_a0_nic_type = { | |||
3484 | .mtd_sync = efx_mcdi_mtd_sync, | 3598 | .mtd_sync = efx_mcdi_mtd_sync, |
3485 | #endif | 3599 | #endif |
3486 | .ptp_write_host_time = efx_ef10_ptp_write_host_time, | 3600 | .ptp_write_host_time = efx_ef10_ptp_write_host_time, |
3601 | .ptp_set_ts_sync_events = efx_ef10_ptp_set_ts_sync_events, | ||
3602 | .ptp_set_ts_config = efx_ef10_ptp_set_ts_config, | ||
3487 | 3603 | ||
3488 | .revision = EFX_REV_HUNT_A0, | 3604 | .revision = EFX_REV_HUNT_A0, |
3489 | .max_dma_mask = DMA_BIT_MASK(ESF_DZ_TX_KER_BUF_ADDR_WIDTH), | 3605 | .max_dma_mask = DMA_BIT_MASK(ESF_DZ_TX_KER_BUF_ADDR_WIDTH), |
3490 | .rx_prefix_size = ES_DZ_RX_PREFIX_SIZE, | 3606 | .rx_prefix_size = ES_DZ_RX_PREFIX_SIZE, |
3491 | .rx_hash_offset = ES_DZ_RX_PREFIX_HASH_OFST, | 3607 | .rx_hash_offset = ES_DZ_RX_PREFIX_HASH_OFST, |
3608 | .rx_ts_offset = ES_DZ_RX_PREFIX_TSTAMP_OFST, | ||
3492 | .can_rx_scatter = true, | 3609 | .can_rx_scatter = true, |
3493 | .always_rx_scatter = true, | 3610 | .always_rx_scatter = true, |
3494 | .max_interrupt_mode = EFX_INT_MODE_MSIX, | 3611 | .max_interrupt_mode = EFX_INT_MODE_MSIX, |
@@ -3497,4 +3614,6 @@ const struct efx_nic_type efx_hunt_a0_nic_type = { | |||
3497 | NETIF_F_RXHASH | NETIF_F_NTUPLE), | 3614 | NETIF_F_RXHASH | NETIF_F_NTUPLE), |
3498 | .mcdi_max_ver = 2, | 3615 | .mcdi_max_ver = 2, |
3499 | .max_rx_ip_filters = HUNT_FILTER_TBL_ROWS, | 3616 | .max_rx_ip_filters = HUNT_FILTER_TBL_ROWS, |
3617 | .hwtstamp_filters = 1 << HWTSTAMP_FILTER_NONE | | ||
3618 | 1 << HWTSTAMP_FILTER_ALL, | ||
3500 | }; | 3619 | }; |
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 893cd78c3a6c..b9929d9ed69d 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c | |||
@@ -2586,6 +2586,8 @@ static int efx_init_struct(struct efx_nic *efx, | |||
2586 | NET_IP_ALIGN ? (efx->rx_prefix_size + NET_IP_ALIGN) % 4 : 0; | 2586 | NET_IP_ALIGN ? (efx->rx_prefix_size + NET_IP_ALIGN) % 4 : 0; |
2587 | efx->rx_packet_hash_offset = | 2587 | efx->rx_packet_hash_offset = |
2588 | efx->type->rx_hash_offset - efx->type->rx_prefix_size; | 2588 | efx->type->rx_hash_offset - efx->type->rx_prefix_size; |
2589 | efx->rx_packet_ts_offset = | ||
2590 | efx->type->rx_ts_offset - efx->type->rx_prefix_size; | ||
2589 | spin_lock_init(&efx->stats_lock); | 2591 | spin_lock_init(&efx->stats_lock); |
2590 | mutex_init(&efx->mac_lock); | 2592 | mutex_init(&efx->mac_lock); |
2591 | efx->phy_op = &efx_dummy_phy_operations; | 2593 | efx->phy_op = &efx_dummy_phy_operations; |
diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c index d608838f6729..540f57915d6f 100644 --- a/drivers/net/ethernet/sfc/mcdi.c +++ b/drivers/net/ethernet/sfc/mcdi.c | |||
@@ -1018,6 +1018,9 @@ void efx_mcdi_process_event(struct efx_channel *channel, | |||
1018 | case MCDI_EVENT_CODE_PTP_PPS: | 1018 | case MCDI_EVENT_CODE_PTP_PPS: |
1019 | efx_ptp_event(efx, event); | 1019 | efx_ptp_event(efx, event); |
1020 | break; | 1020 | break; |
1021 | case MCDI_EVENT_CODE_PTP_TIME: | ||
1022 | efx_time_sync_event(channel, event); | ||
1023 | break; | ||
1021 | case MCDI_EVENT_CODE_TX_FLUSH: | 1024 | case MCDI_EVENT_CODE_TX_FLUSH: |
1022 | case MCDI_EVENT_CODE_RX_FLUSH: | 1025 | case MCDI_EVENT_CODE_RX_FLUSH: |
1023 | /* Two flush events will be sent: one to the same event | 1026 | /* Two flush events will be sent: one to the same event |
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 1a3e4972c68f..0d0e8eb88332 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h | |||
@@ -369,6 +369,13 @@ enum efx_rx_alloc_method { | |||
369 | RX_ALLOC_METHOD_PAGE = 2, | 369 | RX_ALLOC_METHOD_PAGE = 2, |
370 | }; | 370 | }; |
371 | 371 | ||
372 | enum efx_sync_events_state { | ||
373 | SYNC_EVENTS_DISABLED = 0, | ||
374 | SYNC_EVENTS_QUIESCENT, | ||
375 | SYNC_EVENTS_REQUESTED, | ||
376 | SYNC_EVENTS_VALID, | ||
377 | }; | ||
378 | |||
372 | /** | 379 | /** |
373 | * struct efx_channel - An Efx channel | 380 | * struct efx_channel - An Efx channel |
374 | * | 381 | * |
@@ -408,6 +415,9 @@ enum efx_rx_alloc_method { | |||
408 | * by __efx_rx_packet(), if @rx_pkt_n_frags != 0 | 415 | * by __efx_rx_packet(), if @rx_pkt_n_frags != 0 |
409 | * @rx_queue: RX queue for this channel | 416 | * @rx_queue: RX queue for this channel |
410 | * @tx_queue: TX queues for this channel | 417 | * @tx_queue: TX queues for this channel |
418 | * @sync_events_state: Current state of sync events on this channel | ||
419 | * @sync_timestamp_major: Major part of the last ptp sync event | ||
420 | * @sync_timestamp_minor: Minor part of the last ptp sync event | ||
411 | */ | 421 | */ |
412 | struct efx_channel { | 422 | struct efx_channel { |
413 | struct efx_nic *efx; | 423 | struct efx_nic *efx; |
@@ -446,6 +456,10 @@ struct efx_channel { | |||
446 | 456 | ||
447 | struct efx_rx_queue rx_queue; | 457 | struct efx_rx_queue rx_queue; |
448 | struct efx_tx_queue tx_queue[EFX_TXQ_TYPES]; | 458 | struct efx_tx_queue tx_queue[EFX_TXQ_TYPES]; |
459 | |||
460 | enum efx_sync_events_state sync_events_state; | ||
461 | u32 sync_timestamp_major; | ||
462 | u32 sync_timestamp_minor; | ||
449 | }; | 463 | }; |
450 | 464 | ||
451 | /** | 465 | /** |
@@ -686,6 +700,8 @@ struct vfdi_status; | |||
686 | * (valid only if @rx_prefix_size != 0; always negative) | 700 | * (valid only if @rx_prefix_size != 0; always negative) |
687 | * @rx_packet_len_offset: Offset of RX packet length from start of packet data | 701 | * @rx_packet_len_offset: Offset of RX packet length from start of packet data |
688 | * (valid only for NICs that set %EFX_RX_PKT_PREFIX_LEN; always negative) | 702 | * (valid only for NICs that set %EFX_RX_PKT_PREFIX_LEN; always negative) |
703 | * @rx_packet_ts_offset: Offset of timestamp from start of packet data | ||
704 | * (valid only if channel->sync_timestamps_enabled; always negative) | ||
689 | * @rx_hash_key: Toeplitz hash key for RSS | 705 | * @rx_hash_key: Toeplitz hash key for RSS |
690 | * @rx_indir_table: Indirection table for RSS | 706 | * @rx_indir_table: Indirection table for RSS |
691 | * @rx_scatter: Scatter mode enabled for receives | 707 | * @rx_scatter: Scatter mode enabled for receives |
@@ -820,6 +836,7 @@ struct efx_nic { | |||
820 | unsigned int rx_prefix_size; | 836 | unsigned int rx_prefix_size; |
821 | int rx_packet_hash_offset; | 837 | int rx_packet_hash_offset; |
822 | int rx_packet_len_offset; | 838 | int rx_packet_len_offset; |
839 | int rx_packet_ts_offset; | ||
823 | u8 rx_hash_key[40]; | 840 | u8 rx_hash_key[40]; |
824 | u32 rx_indir_table[128]; | 841 | u32 rx_indir_table[128]; |
825 | bool rx_scatter; | 842 | bool rx_scatter; |
@@ -1035,6 +1052,8 @@ struct efx_mtd_partition { | |||
1035 | * also notifies the driver that a writer has finished using this | 1052 | * also notifies the driver that a writer has finished using this |
1036 | * partition. | 1053 | * partition. |
1037 | * @ptp_write_host_time: Send host time to MC as part of sync protocol | 1054 | * @ptp_write_host_time: Send host time to MC as part of sync protocol |
1055 | * @ptp_set_ts_sync_events: Enable or disable sync events for inline RX | ||
1056 | * timestamping, possibly only temporarily for the purposes of a reset. | ||
1038 | * @ptp_set_ts_config: Set hardware timestamp configuration. The flags | 1057 | * @ptp_set_ts_config: Set hardware timestamp configuration. The flags |
1039 | * and tx_type will already have been validated but this operation | 1058 | * and tx_type will already have been validated but this operation |
1040 | * must validate and update rx_filter. | 1059 | * must validate and update rx_filter. |
@@ -1047,6 +1066,7 @@ struct efx_mtd_partition { | |||
1047 | * @max_dma_mask: Maximum possible DMA mask | 1066 | * @max_dma_mask: Maximum possible DMA mask |
1048 | * @rx_prefix_size: Size of RX prefix before packet data | 1067 | * @rx_prefix_size: Size of RX prefix before packet data |
1049 | * @rx_hash_offset: Offset of RX flow hash within prefix | 1068 | * @rx_hash_offset: Offset of RX flow hash within prefix |
1069 | * @rx_ts_offset: Offset of timestamp within prefix | ||
1050 | * @rx_buffer_padding: Size of padding at end of RX packet | 1070 | * @rx_buffer_padding: Size of padding at end of RX packet |
1051 | * @can_rx_scatter: NIC is able to scatter packets to multiple buffers | 1071 | * @can_rx_scatter: NIC is able to scatter packets to multiple buffers |
1052 | * @always_rx_scatter: NIC will always scatter packets to multiple buffers | 1072 | * @always_rx_scatter: NIC will always scatter packets to multiple buffers |
@@ -1158,6 +1178,7 @@ struct efx_nic_type { | |||
1158 | int (*mtd_sync)(struct mtd_info *mtd); | 1178 | int (*mtd_sync)(struct mtd_info *mtd); |
1159 | #endif | 1179 | #endif |
1160 | void (*ptp_write_host_time)(struct efx_nic *efx, u32 host_time); | 1180 | void (*ptp_write_host_time)(struct efx_nic *efx, u32 host_time); |
1181 | int (*ptp_set_ts_sync_events)(struct efx_nic *efx, bool en, bool temp); | ||
1161 | int (*ptp_set_ts_config)(struct efx_nic *efx, | 1182 | int (*ptp_set_ts_config)(struct efx_nic *efx, |
1162 | struct hwtstamp_config *init); | 1183 | struct hwtstamp_config *init); |
1163 | 1184 | ||
@@ -1170,6 +1191,7 @@ struct efx_nic_type { | |||
1170 | u64 max_dma_mask; | 1191 | u64 max_dma_mask; |
1171 | unsigned int rx_prefix_size; | 1192 | unsigned int rx_prefix_size; |
1172 | unsigned int rx_hash_offset; | 1193 | unsigned int rx_hash_offset; |
1194 | unsigned int rx_ts_offset; | ||
1173 | unsigned int rx_buffer_padding; | 1195 | unsigned int rx_buffer_padding; |
1174 | bool can_rx_scatter; | 1196 | bool can_rx_scatter; |
1175 | bool always_rx_scatter; | 1197 | bool always_rx_scatter; |
diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h index 999ef285662d..5d9e2dc121f7 100644 --- a/drivers/net/ethernet/sfc/nic.h +++ b/drivers/net/ethernet/sfc/nic.h | |||
@@ -566,6 +566,15 @@ int efx_ptp_change_mode(struct efx_nic *efx, bool enable_wanted, | |||
566 | unsigned int new_mode); | 566 | unsigned int new_mode); |
567 | int efx_ptp_tx(struct efx_nic *efx, struct sk_buff *skb); | 567 | int efx_ptp_tx(struct efx_nic *efx, struct sk_buff *skb); |
568 | void efx_ptp_event(struct efx_nic *efx, efx_qword_t *ev); | 568 | void efx_ptp_event(struct efx_nic *efx, efx_qword_t *ev); |
569 | void efx_time_sync_event(struct efx_channel *channel, efx_qword_t *ev); | ||
570 | void __efx_rx_skb_attach_timestamp(struct efx_channel *channel, | ||
571 | struct sk_buff *skb); | ||
572 | static inline void efx_rx_skb_attach_timestamp(struct efx_channel *channel, | ||
573 | struct sk_buff *skb) | ||
574 | { | ||
575 | if (channel->sync_events_state == SYNC_EVENTS_VALID) | ||
576 | __efx_rx_skb_attach_timestamp(channel, skb); | ||
577 | } | ||
569 | void efx_ptp_start_datapath(struct efx_nic *efx); | 578 | void efx_ptp_start_datapath(struct efx_nic *efx); |
570 | void efx_ptp_stop_datapath(struct efx_nic *efx); | 579 | void efx_ptp_stop_datapath(struct efx_nic *efx); |
571 | 580 | ||
diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c index 1d1a6f7325da..843e98dfb1b2 100644 --- a/drivers/net/ethernet/sfc/ptp.c +++ b/drivers/net/ethernet/sfc/ptp.c | |||
@@ -216,6 +216,8 @@ struct efx_ptp_timeset { | |||
216 | * struct efx_ptp_data - Precision Time Protocol (PTP) state | 216 | * struct efx_ptp_data - Precision Time Protocol (PTP) state |
217 | * @efx: The NIC context | 217 | * @efx: The NIC context |
218 | * @channel: The PTP channel (Siena only) | 218 | * @channel: The PTP channel (Siena only) |
219 | * @rx_ts_inline: Flag for whether RX timestamps are inline (else they are | ||
220 | * separate events) | ||
219 | * @rxq: Receive queue (awaiting timestamps) | 221 | * @rxq: Receive queue (awaiting timestamps) |
220 | * @txq: Transmit queue | 222 | * @txq: Transmit queue |
221 | * @evt_list: List of MC receive events awaiting packets | 223 | * @evt_list: List of MC receive events awaiting packets |
@@ -258,6 +260,7 @@ struct efx_ptp_timeset { | |||
258 | struct efx_ptp_data { | 260 | struct efx_ptp_data { |
259 | struct efx_nic *efx; | 261 | struct efx_nic *efx; |
260 | struct efx_channel *channel; | 262 | struct efx_channel *channel; |
263 | bool rx_ts_inline; | ||
261 | struct sk_buff_head rxq; | 264 | struct sk_buff_head rxq; |
262 | struct sk_buff_head txq; | 265 | struct sk_buff_head txq; |
263 | struct list_head evt_list; | 266 | struct list_head evt_list; |
@@ -317,8 +320,8 @@ static void efx_ptp_ns_to_s_ns(s64 ns, u32 *nic_major, u32 *nic_minor) | |||
317 | *nic_minor = ts.tv_nsec; | 320 | *nic_minor = ts.tv_nsec; |
318 | } | 321 | } |
319 | 322 | ||
320 | static ktime_t efx_ptp_s_ns_to_ktime(u32 nic_major, u32 nic_minor, | 323 | static ktime_t efx_ptp_s_ns_to_ktime_correction(u32 nic_major, u32 nic_minor, |
321 | s32 correction) | 324 | s32 correction) |
322 | { | 325 | { |
323 | ktime_t kt = ktime_set(nic_major, nic_minor); | 326 | ktime_t kt = ktime_set(nic_major, nic_minor); |
324 | if (correction >= 0) | 327 | if (correction >= 0) |
@@ -359,11 +362,16 @@ static void efx_ptp_ns_to_s27(s64 ns, u32 *nic_major, u32 *nic_minor) | |||
359 | *nic_minor = min; | 362 | *nic_minor = min; |
360 | } | 363 | } |
361 | 364 | ||
362 | static ktime_t efx_ptp_s27_to_ktime(u32 nic_major, u32 nic_minor, | 365 | static inline ktime_t efx_ptp_s27_to_ktime(u32 nic_major, u32 nic_minor) |
363 | s32 correction) | ||
364 | { | 366 | { |
365 | u32 ns; | 367 | u32 ns = (u32)(((u64)nic_minor * NSEC_PER_SEC + |
368 | (1ULL << (S27_TO_NS_SHIFT - 1))) >> S27_TO_NS_SHIFT); | ||
369 | return ktime_set(nic_major, ns); | ||
370 | } | ||
366 | 371 | ||
372 | static ktime_t efx_ptp_s27_to_ktime_correction(u32 nic_major, u32 nic_minor, | ||
373 | s32 correction) | ||
374 | { | ||
367 | /* Apply the correction and deal with carry */ | 375 | /* Apply the correction and deal with carry */ |
368 | nic_minor += correction; | 376 | nic_minor += correction; |
369 | if ((s32)nic_minor < 0) { | 377 | if ((s32)nic_minor < 0) { |
@@ -374,10 +382,7 @@ static ktime_t efx_ptp_s27_to_ktime(u32 nic_major, u32 nic_minor, | |||
374 | nic_major++; | 382 | nic_major++; |
375 | } | 383 | } |
376 | 384 | ||
377 | ns = (u32)(((u64)nic_minor * NSEC_PER_SEC + | 385 | return efx_ptp_s27_to_ktime(nic_major, nic_minor); |
378 | (1ULL << (S27_TO_NS_SHIFT - 1))) >> S27_TO_NS_SHIFT); | ||
379 | |||
380 | return ktime_set(nic_major, ns); | ||
381 | } | 386 | } |
382 | 387 | ||
383 | /* Get PTP attributes and set up time conversions */ | 388 | /* Get PTP attributes and set up time conversions */ |
@@ -407,10 +412,10 @@ static int efx_ptp_get_attributes(struct efx_nic *efx) | |||
407 | 412 | ||
408 | if (fmt == MC_CMD_PTP_OUT_GET_ATTRIBUTES_SECONDS_27FRACTION) { | 413 | if (fmt == MC_CMD_PTP_OUT_GET_ATTRIBUTES_SECONDS_27FRACTION) { |
409 | ptp->ns_to_nic_time = efx_ptp_ns_to_s27; | 414 | ptp->ns_to_nic_time = efx_ptp_ns_to_s27; |
410 | ptp->nic_to_kernel_time = efx_ptp_s27_to_ktime; | 415 | ptp->nic_to_kernel_time = efx_ptp_s27_to_ktime_correction; |
411 | } else if (fmt == MC_CMD_PTP_OUT_GET_ATTRIBUTES_SECONDS_NANOSECONDS) { | 416 | } else if (fmt == MC_CMD_PTP_OUT_GET_ATTRIBUTES_SECONDS_NANOSECONDS) { |
412 | ptp->ns_to_nic_time = efx_ptp_ns_to_s_ns; | 417 | ptp->ns_to_nic_time = efx_ptp_ns_to_s_ns; |
413 | ptp->nic_to_kernel_time = efx_ptp_s_ns_to_ktime; | 418 | ptp->nic_to_kernel_time = efx_ptp_s_ns_to_ktime_correction; |
414 | } else { | 419 | } else { |
415 | return -ERANGE; | 420 | return -ERANGE; |
416 | } | 421 | } |
@@ -806,6 +811,9 @@ static void efx_ptp_drop_time_expired_events(struct efx_nic *efx) | |||
806 | struct list_head *cursor; | 811 | struct list_head *cursor; |
807 | struct list_head *next; | 812 | struct list_head *next; |
808 | 813 | ||
814 | if (ptp->rx_ts_inline) | ||
815 | return; | ||
816 | |||
809 | /* Drop time-expired events */ | 817 | /* Drop time-expired events */ |
810 | spin_lock_bh(&ptp->evt_lock); | 818 | spin_lock_bh(&ptp->evt_lock); |
811 | if (!list_empty(&ptp->evt_list)) { | 819 | if (!list_empty(&ptp->evt_list)) { |
@@ -839,6 +847,8 @@ static enum ptp_packet_state efx_ptp_match_rx(struct efx_nic *efx, | |||
839 | struct efx_ptp_match *match; | 847 | struct efx_ptp_match *match; |
840 | enum ptp_packet_state rc = PTP_PACKET_STATE_UNMATCHED; | 848 | enum ptp_packet_state rc = PTP_PACKET_STATE_UNMATCHED; |
841 | 849 | ||
850 | WARN_ON_ONCE(ptp->rx_ts_inline); | ||
851 | |||
842 | spin_lock_bh(&ptp->evt_lock); | 852 | spin_lock_bh(&ptp->evt_lock); |
843 | evts_waiting = !list_empty(&ptp->evt_list); | 853 | evts_waiting = !list_empty(&ptp->evt_list); |
844 | spin_unlock_bh(&ptp->evt_lock); | 854 | spin_unlock_bh(&ptp->evt_lock); |
@@ -1061,8 +1071,6 @@ static void efx_ptp_pps_worker(struct work_struct *work) | |||
1061 | ptp_clock_event(ptp->phc_clock, &ptp_evt); | 1071 | ptp_clock_event(ptp->phc_clock, &ptp_evt); |
1062 | } | 1072 | } |
1063 | 1073 | ||
1064 | /* Process any pending transmissions and timestamp any received packets. | ||
1065 | */ | ||
1066 | static void efx_ptp_worker(struct work_struct *work) | 1074 | static void efx_ptp_worker(struct work_struct *work) |
1067 | { | 1075 | { |
1068 | struct efx_ptp_data *ptp_data = | 1076 | struct efx_ptp_data *ptp_data = |
@@ -1120,6 +1128,7 @@ int efx_ptp_probe(struct efx_nic *efx, struct efx_channel *channel) | |||
1120 | 1128 | ||
1121 | ptp->efx = efx; | 1129 | ptp->efx = efx; |
1122 | ptp->channel = channel; | 1130 | ptp->channel = channel; |
1131 | ptp->rx_ts_inline = efx_nic_rev(efx) >= EFX_REV_HUNT_A0; | ||
1123 | 1132 | ||
1124 | rc = efx_nic_alloc_buffer(efx, &ptp->start, sizeof(int), GFP_KERNEL); | 1133 | rc = efx_nic_alloc_buffer(efx, &ptp->start, sizeof(int), GFP_KERNEL); |
1125 | if (rc != 0) | 1134 | if (rc != 0) |
@@ -1491,6 +1500,9 @@ static void ptp_event_rx(struct efx_nic *efx, struct efx_ptp_data *ptp) | |||
1491 | { | 1500 | { |
1492 | struct efx_ptp_event_rx *evt = NULL; | 1501 | struct efx_ptp_event_rx *evt = NULL; |
1493 | 1502 | ||
1503 | if (WARN_ON_ONCE(ptp->rx_ts_inline)) | ||
1504 | return; | ||
1505 | |||
1494 | if (ptp->evt_frag_idx != 3) { | 1506 | if (ptp->evt_frag_idx != 3) { |
1495 | ptp_event_failure(efx, 3); | 1507 | ptp_event_failure(efx, 3); |
1496 | return; | 1508 | return; |
@@ -1587,6 +1599,93 @@ void efx_ptp_event(struct efx_nic *efx, efx_qword_t *ev) | |||
1587 | } | 1599 | } |
1588 | } | 1600 | } |
1589 | 1601 | ||
1602 | void efx_time_sync_event(struct efx_channel *channel, efx_qword_t *ev) | ||
1603 | { | ||
1604 | channel->sync_timestamp_major = MCDI_EVENT_FIELD(*ev, PTP_TIME_MAJOR); | ||
1605 | channel->sync_timestamp_minor = | ||
1606 | MCDI_EVENT_FIELD(*ev, PTP_TIME_MINOR_26_19) << 19; | ||
1607 | /* if sync events have been disabled then we want to silently ignore | ||
1608 | * this event, so throw away result. | ||
1609 | */ | ||
1610 | (void) cmpxchg(&channel->sync_events_state, SYNC_EVENTS_REQUESTED, | ||
1611 | SYNC_EVENTS_VALID); | ||
1612 | } | ||
1613 | |||
1614 | /* make some assumptions about the time representation rather than abstract it, | ||
1615 | * since we currently only support one type of inline timestamping and only on | ||
1616 | * EF10. | ||
1617 | */ | ||
1618 | #define MINOR_TICKS_PER_SECOND 0x8000000 | ||
1619 | /* Fuzz factor for sync events to be out of order with RX events */ | ||
1620 | #define FUZZ (MINOR_TICKS_PER_SECOND / 10) | ||
1621 | #define EXPECTED_SYNC_EVENTS_PER_SECOND 4 | ||
1622 | |||
1623 | static inline u32 efx_rx_buf_timestamp_minor(struct efx_nic *efx, const u8 *eh) | ||
1624 | { | ||
1625 | #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) | ||
1626 | return __le32_to_cpup((const __le32 *)(eh + efx->rx_packet_ts_offset)); | ||
1627 | #else | ||
1628 | const u8 *data = eh + efx->rx_packet_ts_offset; | ||
1629 | return (u32)data[0] | | ||
1630 | (u32)data[1] << 8 | | ||
1631 | (u32)data[2] << 16 | | ||
1632 | (u32)data[3] << 24; | ||
1633 | #endif | ||
1634 | } | ||
1635 | |||
1636 | void __efx_rx_skb_attach_timestamp(struct efx_channel *channel, | ||
1637 | struct sk_buff *skb) | ||
1638 | { | ||
1639 | struct efx_nic *efx = channel->efx; | ||
1640 | u32 pkt_timestamp_major, pkt_timestamp_minor; | ||
1641 | u32 diff, carry; | ||
1642 | struct skb_shared_hwtstamps *timestamps; | ||
1643 | |||
1644 | pkt_timestamp_minor = (efx_rx_buf_timestamp_minor(efx, | ||
1645 | skb_mac_header(skb)) + | ||
1646 | (u32) efx->ptp_data->ts_corrections.rx) & | ||
1647 | (MINOR_TICKS_PER_SECOND - 1); | ||
1648 | |||
1649 | /* get the difference between the packet and sync timestamps, | ||
1650 | * modulo one second | ||
1651 | */ | ||
1652 | diff = (pkt_timestamp_minor - channel->sync_timestamp_minor) & | ||
1653 | (MINOR_TICKS_PER_SECOND - 1); | ||
1654 | /* do we roll over a second boundary and need to carry the one? */ | ||
1655 | carry = channel->sync_timestamp_minor + diff > MINOR_TICKS_PER_SECOND ? | ||
1656 | 1 : 0; | ||
1657 | |||
1658 | if (diff <= MINOR_TICKS_PER_SECOND / EXPECTED_SYNC_EVENTS_PER_SECOND + | ||
1659 | FUZZ) { | ||
1660 | /* packet is ahead of the sync event by a quarter of a second or | ||
1661 | * less (allowing for fuzz) | ||
1662 | */ | ||
1663 | pkt_timestamp_major = channel->sync_timestamp_major + carry; | ||
1664 | } else if (diff >= MINOR_TICKS_PER_SECOND - FUZZ) { | ||
1665 | /* packet is behind the sync event but within the fuzz factor. | ||
1666 | * This means the RX packet and sync event crossed as they were | ||
1667 | * placed on the event queue, which can sometimes happen. | ||
1668 | */ | ||
1669 | pkt_timestamp_major = channel->sync_timestamp_major - 1 + carry; | ||
1670 | } else { | ||
1671 | /* it's outside tolerance in both directions. this might be | ||
1672 | * indicative of us missing sync events for some reason, so | ||
1673 | * we'll call it an error rather than risk giving a bogus | ||
1674 | * timestamp. | ||
1675 | */ | ||
1676 | netif_vdbg(efx, drv, efx->net_dev, | ||
1677 | "packet timestamp %x too far from sync event %x:%x\n", | ||
1678 | pkt_timestamp_minor, channel->sync_timestamp_major, | ||
1679 | channel->sync_timestamp_minor); | ||
1680 | return; | ||
1681 | } | ||
1682 | |||
1683 | /* attach the timestamps to the skb */ | ||
1684 | timestamps = skb_hwtstamps(skb); | ||
1685 | timestamps->hwtstamp = | ||
1686 | efx_ptp_s27_to_ktime(pkt_timestamp_major, pkt_timestamp_minor); | ||
1687 | } | ||
1688 | |||
1590 | static int efx_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta) | 1689 | static int efx_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta) |
1591 | { | 1690 | { |
1592 | struct efx_ptp_data *ptp_data = container_of(ptp, | 1691 | struct efx_ptp_data *ptp_data = container_of(ptp, |
@@ -1728,9 +1827,15 @@ void efx_ptp_start_datapath(struct efx_nic *efx) | |||
1728 | { | 1827 | { |
1729 | if (efx_ptp_restart(efx)) | 1828 | if (efx_ptp_restart(efx)) |
1730 | netif_err(efx, drv, efx->net_dev, "Failed to restart PTP.\n"); | 1829 | netif_err(efx, drv, efx->net_dev, "Failed to restart PTP.\n"); |
1830 | /* re-enable timestamping if it was previously enabled */ | ||
1831 | if (efx->type->ptp_set_ts_sync_events) | ||
1832 | efx->type->ptp_set_ts_sync_events(efx, true, true); | ||
1731 | } | 1833 | } |
1732 | 1834 | ||
1733 | void efx_ptp_stop_datapath(struct efx_nic *efx) | 1835 | void efx_ptp_stop_datapath(struct efx_nic *efx) |
1734 | { | 1836 | { |
1837 | /* temporarily disable timestamping */ | ||
1838 | if (efx->type->ptp_set_ts_sync_events) | ||
1839 | efx->type->ptp_set_ts_sync_events(efx, false, true); | ||
1735 | efx_ptp_stop(efx); | 1840 | efx_ptp_stop(efx); |
1736 | } | 1841 | } |
diff --git a/drivers/net/ethernet/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c index d12abc543975..1fde9b8ac456 100644 --- a/drivers/net/ethernet/sfc/rx.c +++ b/drivers/net/ethernet/sfc/rx.c | |||
@@ -624,6 +624,8 @@ static void efx_rx_deliver(struct efx_channel *channel, u8 *eh, | |||
624 | if (likely(rx_buf->flags & EFX_RX_PKT_CSUMMED)) | 624 | if (likely(rx_buf->flags & EFX_RX_PKT_CSUMMED)) |
625 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 625 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
626 | 626 | ||
627 | efx_rx_skb_attach_timestamp(channel, skb); | ||
628 | |||
627 | if (channel->type->receive_skb) | 629 | if (channel->type->receive_skb) |
628 | if (channel->type->receive_skb(channel, skb)) | 630 | if (channel->type->receive_skb(channel, skb)) |
629 | return; | 631 | return; |