aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2013-12-10 21:36:08 -0500
committerBen Hutchings <bhutchings@solarflare.com>2013-12-12 17:07:30 -0500
commit99691c4ac112666fe8aef30cffef1cc9f6f94f79 (patch)
tree43fe421c4ca59224489109723d2c96fbadd024e7
parent79ac47ae74c1e905c204c2eeb090c8098d570ef2 (diff)
sfc: Add PTP counters to ethtool stats
These were implemented by Andrew Jackson and Laurence Evans but not previously included in-tree. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
-rw-r--r--drivers/net/ethernet/sfc/ethtool.c8
-rw-r--r--drivers/net/ethernet/sfc/nic.h2
-rw-r--r--drivers/net/ethernet/sfc/ptp.c126
3 files changed, 127 insertions, 9 deletions
diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c
index bb2af8045281..f181522688b2 100644
--- a/drivers/net/ethernet/sfc/ethtool.c
+++ b/drivers/net/ethernet/sfc/ethtool.c
@@ -359,7 +359,8 @@ static int efx_ethtool_get_sset_count(struct net_device *net_dev,
359 switch (string_set) { 359 switch (string_set) {
360 case ETH_SS_STATS: 360 case ETH_SS_STATS:
361 return efx->type->describe_stats(efx, NULL) + 361 return efx->type->describe_stats(efx, NULL) +
362 EFX_ETHTOOL_SW_STAT_COUNT; 362 EFX_ETHTOOL_SW_STAT_COUNT +
363 efx_ptp_describe_stats(efx, NULL);
363 case ETH_SS_TEST: 364 case ETH_SS_TEST:
364 return efx_ethtool_fill_self_tests(efx, NULL, NULL, NULL); 365 return efx_ethtool_fill_self_tests(efx, NULL, NULL, NULL);
365 default: 366 default:
@@ -380,6 +381,8 @@ static void efx_ethtool_get_strings(struct net_device *net_dev,
380 for (i = 0; i < EFX_ETHTOOL_SW_STAT_COUNT; i++) 381 for (i = 0; i < EFX_ETHTOOL_SW_STAT_COUNT; i++)
381 strlcpy(strings + i * ETH_GSTRING_LEN, 382 strlcpy(strings + i * ETH_GSTRING_LEN,
382 efx_sw_stat_desc[i].name, ETH_GSTRING_LEN); 383 efx_sw_stat_desc[i].name, ETH_GSTRING_LEN);
384 strings += EFX_ETHTOOL_SW_STAT_COUNT * ETH_GSTRING_LEN;
385 efx_ptp_describe_stats(efx, strings);
383 break; 386 break;
384 case ETH_SS_TEST: 387 case ETH_SS_TEST:
385 efx_ethtool_fill_self_tests(efx, NULL, strings, NULL); 388 efx_ethtool_fill_self_tests(efx, NULL, strings, NULL);
@@ -429,8 +432,11 @@ static void efx_ethtool_get_stats(struct net_device *net_dev,
429 break; 432 break;
430 } 433 }
431 } 434 }
435 data += EFX_ETHTOOL_SW_STAT_COUNT;
432 436
433 spin_unlock_bh(&efx->stats_lock); 437 spin_unlock_bh(&efx->stats_lock);
438
439 efx_ptp_update_stats(efx, data);
434} 440}
435 441
436static void efx_ethtool_self_test(struct net_device *net_dev, 442static void efx_ethtool_self_test(struct net_device *net_dev,
diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h
index 170ac6ee3ab2..a001fae1a8d7 100644
--- a/drivers/net/ethernet/sfc/nic.h
+++ b/drivers/net/ethernet/sfc/nic.h
@@ -566,6 +566,8 @@ int efx_ptp_change_mode(struct efx_nic *efx, bool enable_wanted,
566 unsigned int new_mode); 566 unsigned int new_mode);
567int efx_ptp_tx(struct efx_nic *efx, struct sk_buff *skb); 567int efx_ptp_tx(struct efx_nic *efx, struct sk_buff *skb);
568void efx_ptp_event(struct efx_nic *efx, efx_qword_t *ev); 568void efx_ptp_event(struct efx_nic *efx, efx_qword_t *ev);
569size_t efx_ptp_describe_stats(struct efx_nic *efx, u8 *strings);
570size_t efx_ptp_update_stats(struct efx_nic *efx, u64 *stats);
569void efx_time_sync_event(struct efx_channel *channel, efx_qword_t *ev); 571void efx_time_sync_event(struct efx_channel *channel, efx_qword_t *ev);
570void __efx_rx_skb_attach_timestamp(struct efx_channel *channel, 572void __efx_rx_skb_attach_timestamp(struct efx_channel *channel,
571 struct sk_buff *skb); 573 struct sk_buff *skb);
diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c
index 084e2d44790f..7aa070813960 100644
--- a/drivers/net/ethernet/sfc/ptp.c
+++ b/drivers/net/ethernet/sfc/ptp.c
@@ -255,6 +255,15 @@ struct efx_ptp_timeset {
255 * @nic_ts_enabled: Flag indicating if NIC generated TS events are handled 255 * @nic_ts_enabled: Flag indicating if NIC generated TS events are handled
256 * @txbuf: Buffer for use when transmitting (PTP) packets to MC (avoids 256 * @txbuf: Buffer for use when transmitting (PTP) packets to MC (avoids
257 * allocations in main data path). 257 * allocations in main data path).
258 * @good_syncs: Number of successful synchronisations.
259 * @fast_syncs: Number of synchronisations requiring short delay
260 * @bad_syncs: Number of failed synchronisations.
261 * @sync_timeouts: Number of synchronisation timeouts
262 * @no_time_syncs: Number of synchronisations with no good times.
263 * @invalid_sync_windows: Number of sync windows with bad durations.
264 * @undersize_sync_windows: Number of corrected sync windows that are too small
265 * @oversize_sync_windows: Number of corrected sync windows that are too large
266 * @rx_no_timestamp: Number of packets received without a timestamp.
258 * @timeset: Last set of synchronisation statistics. 267 * @timeset: Last set of synchronisation statistics.
259 */ 268 */
260struct efx_ptp_data { 269struct efx_ptp_data {
@@ -300,6 +309,16 @@ struct efx_ptp_data {
300 struct workqueue_struct *pps_workwq; 309 struct workqueue_struct *pps_workwq;
301 bool nic_ts_enabled; 310 bool nic_ts_enabled;
302 MCDI_DECLARE_BUF(txbuf, MC_CMD_PTP_IN_TRANSMIT_LENMAX); 311 MCDI_DECLARE_BUF(txbuf, MC_CMD_PTP_IN_TRANSMIT_LENMAX);
312
313 unsigned int good_syncs;
314 unsigned int fast_syncs;
315 unsigned int bad_syncs;
316 unsigned int sync_timeouts;
317 unsigned int no_time_syncs;
318 unsigned int invalid_sync_windows;
319 unsigned int undersize_sync_windows;
320 unsigned int oversize_sync_windows;
321 unsigned int rx_no_timestamp;
303 struct efx_ptp_timeset 322 struct efx_ptp_timeset
304 timeset[MC_CMD_PTP_OUT_SYNCHRONIZE_TIMESET_MAXNUM]; 323 timeset[MC_CMD_PTP_OUT_SYNCHRONIZE_TIMESET_MAXNUM];
305}; 324};
@@ -312,6 +331,78 @@ static int efx_phc_settime(struct ptp_clock_info *ptp,
312static int efx_phc_enable(struct ptp_clock_info *ptp, 331static int efx_phc_enable(struct ptp_clock_info *ptp,
313 struct ptp_clock_request *request, int on); 332 struct ptp_clock_request *request, int on);
314 333
334#define PTP_SW_STAT(ext_name, field_name) \
335 { #ext_name, 0, offsetof(struct efx_ptp_data, field_name) }
336#define PTP_MC_STAT(ext_name, mcdi_name) \
337 { #ext_name, 32, MC_CMD_PTP_OUT_STATUS_STATS_ ## mcdi_name ## _OFST }
338static const struct efx_hw_stat_desc efx_ptp_stat_desc[] = {
339 PTP_SW_STAT(ptp_good_syncs, good_syncs),
340 PTP_SW_STAT(ptp_fast_syncs, fast_syncs),
341 PTP_SW_STAT(ptp_bad_syncs, bad_syncs),
342 PTP_SW_STAT(ptp_sync_timeouts, sync_timeouts),
343 PTP_SW_STAT(ptp_no_time_syncs, no_time_syncs),
344 PTP_SW_STAT(ptp_invalid_sync_windows, invalid_sync_windows),
345 PTP_SW_STAT(ptp_undersize_sync_windows, undersize_sync_windows),
346 PTP_SW_STAT(ptp_oversize_sync_windows, oversize_sync_windows),
347 PTP_SW_STAT(ptp_rx_no_timestamp, rx_no_timestamp),
348 PTP_MC_STAT(ptp_tx_timestamp_packets, TX),
349 PTP_MC_STAT(ptp_rx_timestamp_packets, RX),
350 PTP_MC_STAT(ptp_timestamp_packets, TS),
351 PTP_MC_STAT(ptp_filter_matches, FM),
352 PTP_MC_STAT(ptp_non_filter_matches, NFM),
353};
354#define PTP_STAT_COUNT ARRAY_SIZE(efx_ptp_stat_desc)
355static const unsigned long efx_ptp_stat_mask[] = {
356 [0 ... BITS_TO_LONGS(PTP_STAT_COUNT) - 1] = ~0UL,
357};
358
359size_t efx_ptp_describe_stats(struct efx_nic *efx, u8 *strings)
360{
361 if (!efx->ptp_data)
362 return 0;
363
364 return efx_nic_describe_stats(efx_ptp_stat_desc, PTP_STAT_COUNT,
365 efx_ptp_stat_mask, strings);
366}
367
368size_t efx_ptp_update_stats(struct efx_nic *efx, u64 *stats)
369{
370 MCDI_DECLARE_BUF(inbuf, MC_CMD_PTP_IN_STATUS_LEN);
371 MCDI_DECLARE_BUF(outbuf, MC_CMD_PTP_OUT_STATUS_LEN);
372 size_t i;
373 int rc;
374
375 if (!efx->ptp_data)
376 return 0;
377
378 /* Copy software statistics */
379 for (i = 0; i < PTP_STAT_COUNT; i++) {
380 if (efx_ptp_stat_desc[i].dma_width)
381 continue;
382 stats[i] = *(unsigned int *)((char *)efx->ptp_data +
383 efx_ptp_stat_desc[i].offset);
384 }
385
386 /* Fetch MC statistics. We *must* fill in all statistics or
387 * risk leaking kernel memory to userland, so if the MCDI
388 * request fails we pretend we got zeroes.
389 */
390 MCDI_SET_DWORD(inbuf, PTP_IN_OP, MC_CMD_PTP_OP_STATUS);
391 MCDI_SET_DWORD(inbuf, PTP_IN_PERIPH_ID, 0);
392 rc = efx_mcdi_rpc(efx, MC_CMD_PTP, inbuf, sizeof(inbuf),
393 outbuf, sizeof(outbuf), NULL);
394 if (rc) {
395 netif_err(efx, hw, efx->net_dev,
396 "MC_CMD_PTP_OP_STATUS failed (%d)\n", rc);
397 memset(outbuf, 0, sizeof(outbuf));
398 }
399 efx_nic_update_stats(efx_ptp_stat_desc, PTP_STAT_COUNT,
400 efx_ptp_stat_mask,
401 stats, _MCDI_PTR(outbuf, 0), false);
402
403 return PTP_STAT_COUNT;
404}
405
315/* For Siena platforms NIC time is s and ns */ 406/* For Siena platforms NIC time is s and ns */
316static void efx_ptp_ns_to_s_ns(s64 ns, u32 *nic_major, u32 *nic_minor) 407static void efx_ptp_ns_to_s_ns(s64 ns, u32 *nic_major, u32 *nic_minor)
317{ 408{
@@ -633,7 +724,8 @@ efx_ptp_process_times(struct efx_nic *efx, MCDI_DECLARE_STRUCT_PTR(synch_buf),
633 /* Read the set of results and find the last good host-MC 724 /* Read the set of results and find the last good host-MC
634 * synchronization result. The MC times when it finishes reading the 725 * synchronization result. The MC times when it finishes reading the
635 * host time so the corrected window time should be fairly constant 726 * host time so the corrected window time should be fairly constant
636 * for a given platform. 727 * for a given platform. Increment stats for any results that appear
728 * to be erroneous.
637 */ 729 */
638 for (i = 0; i < number_readings; i++) { 730 for (i = 0; i < number_readings; i++) {
639 s32 window, corrected; 731 s32 window, corrected;
@@ -658,9 +750,13 @@ efx_ptp_process_times(struct efx_nic *efx, MCDI_DECLARE_STRUCT_PTR(synch_buf),
658 * interrupt or other delay occurred between reading the system 750 * interrupt or other delay occurred between reading the system
659 * time and writing it to MC memory. 751 * time and writing it to MC memory.
660 */ 752 */
661 if (window >= SYNCHRONISATION_GRANULARITY_NS && 753 if (window < SYNCHRONISATION_GRANULARITY_NS) {
662 corrected < MAX_SYNCHRONISATION_NS && 754 ++ptp->invalid_sync_windows;
663 corrected >= ptp->min_synchronisation_ns) { 755 } else if (corrected >= MAX_SYNCHRONISATION_NS) {
756 ++ptp->undersize_sync_windows;
757 } else if (corrected < ptp->min_synchronisation_ns) {
758 ++ptp->oversize_sync_windows;
759 } else {
664 ngood++; 760 ngood++;
665 last_good = i; 761 last_good = i;
666 } 762 }
@@ -741,6 +837,11 @@ static int efx_ptp_synchronize(struct efx_nic *efx, unsigned int num_readings)
741 loops++; 837 loops++;
742 } 838 }
743 839
840 if (loops <= 1)
841 ++ptp->fast_syncs;
842 if (!time_before(jiffies, timeout))
843 ++ptp->sync_timeouts;
844
744 if (ACCESS_ONCE(*start)) 845 if (ACCESS_ONCE(*start))
745 efx_ptp_send_times(efx, &last_time); 846 efx_ptp_send_times(efx, &last_time);
746 847
@@ -749,9 +850,20 @@ static int efx_ptp_synchronize(struct efx_nic *efx, unsigned int num_readings)
749 MC_CMD_PTP_IN_SYNCHRONIZE_LEN, 850 MC_CMD_PTP_IN_SYNCHRONIZE_LEN,
750 synch_buf, sizeof(synch_buf), 851 synch_buf, sizeof(synch_buf),
751 &response_length); 852 &response_length);
752 if (rc == 0) 853 if (rc == 0) {
753 rc = efx_ptp_process_times(efx, synch_buf, response_length, 854 rc = efx_ptp_process_times(efx, synch_buf, response_length,
754 &last_time); 855 &last_time);
856 if (rc == 0)
857 ++ptp->good_syncs;
858 else
859 ++ptp->no_time_syncs;
860 }
861
862 /* Increment the bad syncs counter if the synchronize fails, whatever
863 * the reason.
864 */
865 if (rc != 0)
866 ++ptp->bad_syncs;
755 867
756 return rc; 868 return rc;
757} 869}
@@ -907,9 +1019,7 @@ static void efx_ptp_process_events(struct efx_nic *efx, struct sk_buff_head *q)
907 __skb_queue_tail(q, skb); 1019 __skb_queue_tail(q, skb);
908 } else if (time_after(jiffies, match->expiry)) { 1020 } else if (time_after(jiffies, match->expiry)) {
909 match->state = PTP_PACKET_STATE_TIMED_OUT; 1021 match->state = PTP_PACKET_STATE_TIMED_OUT;
910 if (net_ratelimit()) 1022 ++ptp->rx_no_timestamp;
911 netif_warn(efx, rx_err, efx->net_dev,
912 "PTP packet - no timestamp seen\n");
913 __skb_queue_tail(q, skb); 1023 __skb_queue_tail(q, skb);
914 } else { 1024 } else {
915 /* Replace unprocessed entry and stop */ 1025 /* Replace unprocessed entry and stop */