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