diff options
Diffstat (limited to 'drivers/net/ethernet/sfc/ptp.c')
-rw-r--r-- | drivers/net/ethernet/sfc/ptp.c | 66 |
1 files changed, 57 insertions, 9 deletions
diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c index afd4d3a50460..34b25864b121 100644 --- a/drivers/net/ethernet/sfc/ptp.c +++ b/drivers/net/ethernet/sfc/ptp.c | |||
@@ -220,6 +220,7 @@ struct efx_ptp_timeset { | |||
220 | * @evt_list: List of MC receive events awaiting packets | 220 | * @evt_list: List of MC receive events awaiting packets |
221 | * @evt_free_list: List of free events | 221 | * @evt_free_list: List of free events |
222 | * @evt_lock: Lock for manipulating evt_list and evt_free_list | 222 | * @evt_lock: Lock for manipulating evt_list and evt_free_list |
223 | * @evt_overflow: Boolean indicating that event list has overflowed | ||
223 | * @rx_evts: Instantiated events (on evt_list and evt_free_list) | 224 | * @rx_evts: Instantiated events (on evt_list and evt_free_list) |
224 | * @workwq: Work queue for processing pending PTP operations | 225 | * @workwq: Work queue for processing pending PTP operations |
225 | * @work: Work task | 226 | * @work: Work task |
@@ -270,6 +271,7 @@ struct efx_ptp_data { | |||
270 | struct list_head evt_list; | 271 | struct list_head evt_list; |
271 | struct list_head evt_free_list; | 272 | struct list_head evt_free_list; |
272 | spinlock_t evt_lock; | 273 | spinlock_t evt_lock; |
274 | bool evt_overflow; | ||
273 | struct efx_ptp_event_rx rx_evts[MAX_RECEIVE_EVENTS]; | 275 | struct efx_ptp_event_rx rx_evts[MAX_RECEIVE_EVENTS]; |
274 | struct workqueue_struct *workwq; | 276 | struct workqueue_struct *workwq; |
275 | struct work_struct work; | 277 | struct work_struct work; |
@@ -635,6 +637,11 @@ static void efx_ptp_drop_time_expired_events(struct efx_nic *efx) | |||
635 | } | 637 | } |
636 | } | 638 | } |
637 | } | 639 | } |
640 | /* If the event overflow flag is set and the event list is now empty | ||
641 | * clear the flag to re-enable the overflow warning message. | ||
642 | */ | ||
643 | if (ptp->evt_overflow && list_empty(&ptp->evt_list)) | ||
644 | ptp->evt_overflow = false; | ||
638 | spin_unlock_bh(&ptp->evt_lock); | 645 | spin_unlock_bh(&ptp->evt_lock); |
639 | } | 646 | } |
640 | 647 | ||
@@ -676,6 +683,11 @@ static enum ptp_packet_state efx_ptp_match_rx(struct efx_nic *efx, | |||
676 | break; | 683 | break; |
677 | } | 684 | } |
678 | } | 685 | } |
686 | /* If the event overflow flag is set and the event list is now empty | ||
687 | * clear the flag to re-enable the overflow warning message. | ||
688 | */ | ||
689 | if (ptp->evt_overflow && list_empty(&ptp->evt_list)) | ||
690 | ptp->evt_overflow = false; | ||
679 | spin_unlock_bh(&ptp->evt_lock); | 691 | spin_unlock_bh(&ptp->evt_lock); |
680 | 692 | ||
681 | return rc; | 693 | return rc; |
@@ -705,8 +717,9 @@ static bool efx_ptp_process_events(struct efx_nic *efx, struct sk_buff_head *q) | |||
705 | __skb_queue_tail(q, skb); | 717 | __skb_queue_tail(q, skb); |
706 | } else if (time_after(jiffies, match->expiry)) { | 718 | } else if (time_after(jiffies, match->expiry)) { |
707 | match->state = PTP_PACKET_STATE_TIMED_OUT; | 719 | match->state = PTP_PACKET_STATE_TIMED_OUT; |
708 | netif_warn(efx, rx_err, efx->net_dev, | 720 | if (net_ratelimit()) |
709 | "PTP packet - no timestamp seen\n"); | 721 | netif_warn(efx, rx_err, efx->net_dev, |
722 | "PTP packet - no timestamp seen\n"); | ||
710 | __skb_queue_tail(q, skb); | 723 | __skb_queue_tail(q, skb); |
711 | } else { | 724 | } else { |
712 | /* Replace unprocessed entry and stop */ | 725 | /* Replace unprocessed entry and stop */ |
@@ -788,9 +801,14 @@ fail: | |||
788 | static int efx_ptp_stop(struct efx_nic *efx) | 801 | static int efx_ptp_stop(struct efx_nic *efx) |
789 | { | 802 | { |
790 | struct efx_ptp_data *ptp = efx->ptp_data; | 803 | struct efx_ptp_data *ptp = efx->ptp_data; |
791 | int rc = efx_ptp_disable(efx); | ||
792 | struct list_head *cursor; | 804 | struct list_head *cursor; |
793 | struct list_head *next; | 805 | struct list_head *next; |
806 | int rc; | ||
807 | |||
808 | if (ptp == NULL) | ||
809 | return 0; | ||
810 | |||
811 | rc = efx_ptp_disable(efx); | ||
794 | 812 | ||
795 | if (ptp->rxfilter_installed) { | 813 | if (ptp->rxfilter_installed) { |
796 | efx_filter_remove_id_safe(efx, EFX_FILTER_PRI_REQUIRED, | 814 | efx_filter_remove_id_safe(efx, EFX_FILTER_PRI_REQUIRED, |
@@ -809,11 +827,19 @@ static int efx_ptp_stop(struct efx_nic *efx) | |||
809 | list_for_each_safe(cursor, next, &efx->ptp_data->evt_list) { | 827 | list_for_each_safe(cursor, next, &efx->ptp_data->evt_list) { |
810 | list_move(cursor, &efx->ptp_data->evt_free_list); | 828 | list_move(cursor, &efx->ptp_data->evt_free_list); |
811 | } | 829 | } |
830 | ptp->evt_overflow = false; | ||
812 | spin_unlock_bh(&efx->ptp_data->evt_lock); | 831 | spin_unlock_bh(&efx->ptp_data->evt_lock); |
813 | 832 | ||
814 | return rc; | 833 | return rc; |
815 | } | 834 | } |
816 | 835 | ||
836 | static int efx_ptp_restart(struct efx_nic *efx) | ||
837 | { | ||
838 | if (efx->ptp_data && efx->ptp_data->enabled) | ||
839 | return efx_ptp_start(efx); | ||
840 | return 0; | ||
841 | } | ||
842 | |||
817 | static void efx_ptp_pps_worker(struct work_struct *work) | 843 | static void efx_ptp_pps_worker(struct work_struct *work) |
818 | { | 844 | { |
819 | struct efx_ptp_data *ptp = | 845 | struct efx_ptp_data *ptp = |
@@ -901,6 +927,7 @@ static int efx_ptp_probe_channel(struct efx_channel *channel) | |||
901 | spin_lock_init(&ptp->evt_lock); | 927 | spin_lock_init(&ptp->evt_lock); |
902 | for (pos = 0; pos < MAX_RECEIVE_EVENTS; pos++) | 928 | for (pos = 0; pos < MAX_RECEIVE_EVENTS; pos++) |
903 | list_add(&ptp->rx_evts[pos].link, &ptp->evt_free_list); | 929 | list_add(&ptp->rx_evts[pos].link, &ptp->evt_free_list); |
930 | ptp->evt_overflow = false; | ||
904 | 931 | ||
905 | ptp->phc_clock_info.owner = THIS_MODULE; | 932 | ptp->phc_clock_info.owner = THIS_MODULE; |
906 | snprintf(ptp->phc_clock_info.name, | 933 | snprintf(ptp->phc_clock_info.name, |
@@ -989,7 +1016,11 @@ bool efx_ptp_is_ptp_tx(struct efx_nic *efx, struct sk_buff *skb) | |||
989 | skb->len >= PTP_MIN_LENGTH && | 1016 | skb->len >= PTP_MIN_LENGTH && |
990 | skb->len <= MC_CMD_PTP_IN_TRANSMIT_PACKET_MAXNUM && | 1017 | skb->len <= MC_CMD_PTP_IN_TRANSMIT_PACKET_MAXNUM && |
991 | likely(skb->protocol == htons(ETH_P_IP)) && | 1018 | likely(skb->protocol == htons(ETH_P_IP)) && |
1019 | skb_transport_header_was_set(skb) && | ||
1020 | skb_network_header_len(skb) >= sizeof(struct iphdr) && | ||
992 | ip_hdr(skb)->protocol == IPPROTO_UDP && | 1021 | ip_hdr(skb)->protocol == IPPROTO_UDP && |
1022 | skb_headlen(skb) >= | ||
1023 | skb_transport_offset(skb) + sizeof(struct udphdr) && | ||
993 | udp_hdr(skb)->dest == htons(PTP_EVENT_PORT); | 1024 | udp_hdr(skb)->dest == htons(PTP_EVENT_PORT); |
994 | } | 1025 | } |
995 | 1026 | ||
@@ -1106,7 +1137,7 @@ static int efx_ptp_change_mode(struct efx_nic *efx, bool enable_wanted, | |||
1106 | { | 1137 | { |
1107 | if ((enable_wanted != efx->ptp_data->enabled) || | 1138 | if ((enable_wanted != efx->ptp_data->enabled) || |
1108 | (enable_wanted && (efx->ptp_data->mode != new_mode))) { | 1139 | (enable_wanted && (efx->ptp_data->mode != new_mode))) { |
1109 | int rc; | 1140 | int rc = 0; |
1110 | 1141 | ||
1111 | if (enable_wanted) { | 1142 | if (enable_wanted) { |
1112 | /* Change of mode requires disable */ | 1143 | /* Change of mode requires disable */ |
@@ -1123,7 +1154,8 @@ static int efx_ptp_change_mode(struct efx_nic *efx, bool enable_wanted, | |||
1123 | * succeed. | 1154 | * succeed. |
1124 | */ | 1155 | */ |
1125 | efx->ptp_data->mode = new_mode; | 1156 | efx->ptp_data->mode = new_mode; |
1126 | rc = efx_ptp_start(efx); | 1157 | if (netif_running(efx->net_dev)) |
1158 | rc = efx_ptp_start(efx); | ||
1127 | if (rc == 0) { | 1159 | if (rc == 0) { |
1128 | rc = efx_ptp_synchronize(efx, | 1160 | rc = efx_ptp_synchronize(efx, |
1129 | PTP_SYNC_ATTEMPTS * 2); | 1161 | PTP_SYNC_ATTEMPTS * 2); |
@@ -1304,8 +1336,13 @@ static void ptp_event_rx(struct efx_nic *efx, struct efx_ptp_data *ptp) | |||
1304 | list_add_tail(&evt->link, &ptp->evt_list); | 1336 | list_add_tail(&evt->link, &ptp->evt_list); |
1305 | 1337 | ||
1306 | queue_work(ptp->workwq, &ptp->work); | 1338 | queue_work(ptp->workwq, &ptp->work); |
1307 | } else { | 1339 | } else if (!ptp->evt_overflow) { |
1308 | netif_err(efx, rx_err, efx->net_dev, "No free PTP event"); | 1340 | /* Log a warning message and set the event overflow flag. |
1341 | * The message won't be logged again until the event queue | ||
1342 | * becomes empty. | ||
1343 | */ | ||
1344 | netif_err(efx, rx_err, efx->net_dev, "PTP event queue overflow\n"); | ||
1345 | ptp->evt_overflow = true; | ||
1309 | } | 1346 | } |
1310 | spin_unlock_bh(&ptp->evt_lock); | 1347 | spin_unlock_bh(&ptp->evt_lock); |
1311 | } | 1348 | } |
@@ -1398,7 +1435,7 @@ static int efx_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta) | |||
1398 | if (rc != 0) | 1435 | if (rc != 0) |
1399 | return rc; | 1436 | return rc; |
1400 | 1437 | ||
1401 | ptp_data->current_adjfreq = delta; | 1438 | ptp_data->current_adjfreq = adjustment_ns; |
1402 | return 0; | 1439 | return 0; |
1403 | } | 1440 | } |
1404 | 1441 | ||
@@ -1413,7 +1450,7 @@ static int efx_phc_adjtime(struct ptp_clock_info *ptp, s64 delta) | |||
1413 | 1450 | ||
1414 | MCDI_SET_DWORD(inbuf, PTP_IN_OP, MC_CMD_PTP_OP_ADJUST); | 1451 | MCDI_SET_DWORD(inbuf, PTP_IN_OP, MC_CMD_PTP_OP_ADJUST); |
1415 | MCDI_SET_DWORD(inbuf, PTP_IN_PERIPH_ID, 0); | 1452 | MCDI_SET_DWORD(inbuf, PTP_IN_PERIPH_ID, 0); |
1416 | MCDI_SET_QWORD(inbuf, PTP_IN_ADJUST_FREQ, 0); | 1453 | MCDI_SET_QWORD(inbuf, PTP_IN_ADJUST_FREQ, ptp_data->current_adjfreq); |
1417 | MCDI_SET_DWORD(inbuf, PTP_IN_ADJUST_SECONDS, (u32)delta_ts.tv_sec); | 1454 | MCDI_SET_DWORD(inbuf, PTP_IN_ADJUST_SECONDS, (u32)delta_ts.tv_sec); |
1418 | MCDI_SET_DWORD(inbuf, PTP_IN_ADJUST_NANOSECONDS, (u32)delta_ts.tv_nsec); | 1455 | MCDI_SET_DWORD(inbuf, PTP_IN_ADJUST_NANOSECONDS, (u32)delta_ts.tv_nsec); |
1419 | return efx_mcdi_rpc(efx, MC_CMD_PTP, inbuf, sizeof(inbuf), | 1456 | return efx_mcdi_rpc(efx, MC_CMD_PTP, inbuf, sizeof(inbuf), |
@@ -1500,3 +1537,14 @@ void efx_ptp_probe(struct efx_nic *efx) | |||
1500 | efx->extra_channel_type[EFX_EXTRA_CHANNEL_PTP] = | 1537 | efx->extra_channel_type[EFX_EXTRA_CHANNEL_PTP] = |
1501 | &efx_ptp_channel_type; | 1538 | &efx_ptp_channel_type; |
1502 | } | 1539 | } |
1540 | |||
1541 | void efx_ptp_start_datapath(struct efx_nic *efx) | ||
1542 | { | ||
1543 | if (efx_ptp_restart(efx)) | ||
1544 | netif_err(efx, drv, efx->net_dev, "Failed to restart PTP.\n"); | ||
1545 | } | ||
1546 | |||
1547 | void efx_ptp_stop_datapath(struct efx_nic *efx) | ||
1548 | { | ||
1549 | efx_ptp_stop(efx); | ||
1550 | } | ||