diff options
author | Sunil Goutham <sgoutham@cavium.com> | 2018-01-15 07:44:57 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-01-16 14:31:14 -0500 |
commit | 4a8755096466d1002236ac7293eae821b6de87ba (patch) | |
tree | 8eaf366be7af579511c08ba91d1f991d155f7ec7 | |
parent | 8c56df372bc1371504bf3cc29fbb3c09967cafff (diff) |
net: thunderx: add timestamping support
This adds timestamping support for both receive and transmit
paths. On the receive side no filters are supported i.e either
all pkts will get a timestamp appended infront of the packet or none.
On the transmit side HW doesn't support timestamp insertion but
only generates a separate CQE with transmitted packet's timestamp.
Also HW supports only one packet at a time for timestamping on the
transmit side.
Signed-off-by: Sunil Goutham <sgoutham@cavium.com>
Signed-off-by: Aleksey Makarov <aleksey.makarov@cavium.com>
Acked-by: Philippe Ombredanne <pombredanne@nexb.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/cavium/Kconfig | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/cavium/thunder/nic.h | 36 | ||||
-rw-r--r-- | drivers/net/ethernet/cavium/thunder/nic_main.c | 56 | ||||
-rw-r--r-- | drivers/net/ethernet/cavium/thunder/nic_reg.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c | 29 | ||||
-rw-r--r-- | drivers/net/ethernet/cavium/thunder/nicvf_main.c | 169 | ||||
-rw-r--r-- | drivers/net/ethernet/cavium/thunder/nicvf_queues.c | 26 | ||||
-rw-r--r-- | drivers/net/ethernet/cavium/thunder/thunder_bgx.c | 29 | ||||
-rw-r--r-- | drivers/net/ethernet/cavium/thunder/thunder_bgx.h | 4 |
9 files changed, 345 insertions, 6 deletions
diff --git a/drivers/net/ethernet/cavium/Kconfig b/drivers/net/ethernet/cavium/Kconfig index 96586c0b4490..043e3c11c42b 100644 --- a/drivers/net/ethernet/cavium/Kconfig +++ b/drivers/net/ethernet/cavium/Kconfig | |||
@@ -27,6 +27,7 @@ config THUNDER_NIC_PF | |||
27 | 27 | ||
28 | config THUNDER_NIC_VF | 28 | config THUNDER_NIC_VF |
29 | tristate "Thunder Virtual function driver" | 29 | tristate "Thunder Virtual function driver" |
30 | imply CAVIUM_PTP | ||
30 | depends on 64BIT | 31 | depends on 64BIT |
31 | ---help--- | 32 | ---help--- |
32 | This driver supports Thunder's NIC virtual function | 33 | This driver supports Thunder's NIC virtual function |
diff --git a/drivers/net/ethernet/cavium/thunder/nic.h b/drivers/net/ethernet/cavium/thunder/nic.h index 4a02e618e318..4cacce5d2b16 100644 --- a/drivers/net/ethernet/cavium/thunder/nic.h +++ b/drivers/net/ethernet/cavium/thunder/nic.h | |||
@@ -263,6 +263,8 @@ struct nicvf_drv_stats { | |||
263 | struct u64_stats_sync syncp; | 263 | struct u64_stats_sync syncp; |
264 | }; | 264 | }; |
265 | 265 | ||
266 | struct cavium_ptp; | ||
267 | |||
266 | struct nicvf { | 268 | struct nicvf { |
267 | struct nicvf *pnicvf; | 269 | struct nicvf *pnicvf; |
268 | struct net_device *netdev; | 270 | struct net_device *netdev; |
@@ -312,6 +314,33 @@ struct nicvf { | |||
312 | struct tasklet_struct qs_err_task; | 314 | struct tasklet_struct qs_err_task; |
313 | struct work_struct reset_task; | 315 | struct work_struct reset_task; |
314 | 316 | ||
317 | /* PTP timestamp */ | ||
318 | struct cavium_ptp *ptp_clock; | ||
319 | /* Inbound timestamping is on */ | ||
320 | bool hw_rx_tstamp; | ||
321 | /* When the packet that requires timestamping is sent, hardware inserts | ||
322 | * two entries to the completion queue. First is the regular | ||
323 | * CQE_TYPE_SEND entry that signals that the packet was sent. | ||
324 | * The second is CQE_TYPE_SEND_PTP that contains the actual timestamp | ||
325 | * for that packet. | ||
326 | * `ptp_skb` is initialized in the handler for the CQE_TYPE_SEND | ||
327 | * entry and is used and zeroed in the handler for the CQE_TYPE_SEND_PTP | ||
328 | * entry. | ||
329 | * So `ptp_skb` is used to hold the pointer to the packet between | ||
330 | * the calls to CQE_TYPE_SEND and CQE_TYPE_SEND_PTP handlers. | ||
331 | */ | ||
332 | struct sk_buff *ptp_skb; | ||
333 | /* `tx_ptp_skbs` is set when the hardware is sending a packet that | ||
334 | * requires timestamping. Cavium hardware can not process more than one | ||
335 | * such packet at once so this is set each time the driver submits | ||
336 | * a packet that requires timestamping to the send queue and clears | ||
337 | * each time it receives the entry on the completion queue saying | ||
338 | * that such packet was sent. | ||
339 | * So `tx_ptp_skbs` prevents driver from submitting more than one | ||
340 | * packet that requires timestamping to the hardware for transmitting. | ||
341 | */ | ||
342 | atomic_t tx_ptp_skbs; | ||
343 | |||
315 | /* Interrupt coalescing settings */ | 344 | /* Interrupt coalescing settings */ |
316 | u32 cq_coalesce_usecs; | 345 | u32 cq_coalesce_usecs; |
317 | u32 msg_enable; | 346 | u32 msg_enable; |
@@ -371,6 +400,7 @@ struct nicvf { | |||
371 | #define NIC_MBOX_MSG_LOOPBACK 0x16 /* Set interface in loopback */ | 400 | #define NIC_MBOX_MSG_LOOPBACK 0x16 /* Set interface in loopback */ |
372 | #define NIC_MBOX_MSG_RESET_STAT_COUNTER 0x17 /* Reset statistics counters */ | 401 | #define NIC_MBOX_MSG_RESET_STAT_COUNTER 0x17 /* Reset statistics counters */ |
373 | #define NIC_MBOX_MSG_PFC 0x18 /* Pause frame control */ | 402 | #define NIC_MBOX_MSG_PFC 0x18 /* Pause frame control */ |
403 | #define NIC_MBOX_MSG_PTP_CFG 0x19 /* HW packet timestamp */ | ||
374 | #define NIC_MBOX_MSG_CFG_DONE 0xF0 /* VF configuration done */ | 404 | #define NIC_MBOX_MSG_CFG_DONE 0xF0 /* VF configuration done */ |
375 | #define NIC_MBOX_MSG_SHUTDOWN 0xF1 /* VF is being shutdown */ | 405 | #define NIC_MBOX_MSG_SHUTDOWN 0xF1 /* VF is being shutdown */ |
376 | 406 | ||
@@ -521,6 +551,11 @@ struct pfc { | |||
521 | u8 fc_tx; | 551 | u8 fc_tx; |
522 | }; | 552 | }; |
523 | 553 | ||
554 | struct set_ptp { | ||
555 | u8 msg; | ||
556 | bool enable; | ||
557 | }; | ||
558 | |||
524 | /* 128 bit shared memory between PF and each VF */ | 559 | /* 128 bit shared memory between PF and each VF */ |
525 | union nic_mbx { | 560 | union nic_mbx { |
526 | struct { u8 msg; } msg; | 561 | struct { u8 msg; } msg; |
@@ -540,6 +575,7 @@ union nic_mbx { | |||
540 | struct set_loopback lbk; | 575 | struct set_loopback lbk; |
541 | struct reset_stat_cfg reset_stat; | 576 | struct reset_stat_cfg reset_stat; |
542 | struct pfc pfc; | 577 | struct pfc pfc; |
578 | struct set_ptp ptp; | ||
543 | }; | 579 | }; |
544 | 580 | ||
545 | #define NIC_NODE_ID_MASK 0x03 | 581 | #define NIC_NODE_ID_MASK 0x03 |
diff --git a/drivers/net/ethernet/cavium/thunder/nic_main.c b/drivers/net/ethernet/cavium/thunder/nic_main.c index 8f1dd55b3e08..8325577d7442 100644 --- a/drivers/net/ethernet/cavium/thunder/nic_main.c +++ b/drivers/net/ethernet/cavium/thunder/nic_main.c | |||
@@ -426,13 +426,22 @@ static void nic_init_hw(struct nicpf *nic) | |||
426 | /* Enable backpressure */ | 426 | /* Enable backpressure */ |
427 | nic_reg_write(nic, NIC_PF_BP_CFG, (1ULL << 6) | 0x03); | 427 | nic_reg_write(nic, NIC_PF_BP_CFG, (1ULL << 6) | 0x03); |
428 | 428 | ||
429 | /* TNS and TNS bypass modes are present only on 88xx */ | 429 | /* TNS and TNS bypass modes are present only on 88xx |
430 | * Also offset of this CSR has changed in 81xx and 83xx. | ||
431 | */ | ||
430 | if (nic->pdev->subsystem_device == PCI_SUBSYS_DEVID_88XX_NIC_PF) { | 432 | if (nic->pdev->subsystem_device == PCI_SUBSYS_DEVID_88XX_NIC_PF) { |
431 | /* Disable TNS mode on both interfaces */ | 433 | /* Disable TNS mode on both interfaces */ |
432 | nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG, | 434 | nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG, |
433 | (NIC_TNS_BYPASS_MODE << 7) | BGX0_BLOCK); | 435 | (NIC_TNS_BYPASS_MODE << 7) | |
436 | BGX0_BLOCK | (1ULL << 16)); | ||
434 | nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG | (1 << 8), | 437 | nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG | (1 << 8), |
435 | (NIC_TNS_BYPASS_MODE << 7) | BGX1_BLOCK); | 438 | (NIC_TNS_BYPASS_MODE << 7) | |
439 | BGX1_BLOCK | (1ULL << 16)); | ||
440 | } else { | ||
441 | /* Configure timestamp generation timeout to 10us */ | ||
442 | for (i = 0; i < nic->hw->bgx_cnt; i++) | ||
443 | nic_reg_write(nic, NIC_PF_INTFX_SEND_CFG | (i << 3), | ||
444 | (1ULL << 16)); | ||
436 | } | 445 | } |
437 | 446 | ||
438 | nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG, | 447 | nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG, |
@@ -880,6 +889,44 @@ static void nic_pause_frame(struct nicpf *nic, int vf, struct pfc *cfg) | |||
880 | } | 889 | } |
881 | } | 890 | } |
882 | 891 | ||
892 | /* Enable or disable HW timestamping by BGX for pkts received on a LMAC */ | ||
893 | static void nic_config_timestamp(struct nicpf *nic, int vf, struct set_ptp *ptp) | ||
894 | { | ||
895 | struct pkind_cfg *pkind; | ||
896 | u8 lmac, bgx_idx; | ||
897 | u64 pkind_val, pkind_idx; | ||
898 | |||
899 | if (vf >= nic->num_vf_en) | ||
900 | return; | ||
901 | |||
902 | bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); | ||
903 | lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); | ||
904 | |||
905 | pkind_idx = lmac + bgx_idx * MAX_LMAC_PER_BGX; | ||
906 | pkind_val = nic_reg_read(nic, NIC_PF_PKIND_0_15_CFG | (pkind_idx << 3)); | ||
907 | pkind = (struct pkind_cfg *)&pkind_val; | ||
908 | |||
909 | if (ptp->enable && !pkind->hdr_sl) { | ||
910 | /* Skiplen to exclude 8byte timestamp while parsing pkt | ||
911 | * If not configured, will result in L2 errors. | ||
912 | */ | ||
913 | pkind->hdr_sl = 4; | ||
914 | /* Adjust max packet length allowed */ | ||
915 | pkind->maxlen += (pkind->hdr_sl * 2); | ||
916 | bgx_config_timestamping(nic->node, bgx_idx, lmac, true); | ||
917 | nic_reg_write(nic, NIC_PF_RX_ETYPE_0_7 | (1 << 3), | ||
918 | (ETYPE_ALG_ENDPARSE << 16) | ETH_P_1588); | ||
919 | } else if (!ptp->enable && pkind->hdr_sl) { | ||
920 | pkind->maxlen -= (pkind->hdr_sl * 2); | ||
921 | pkind->hdr_sl = 0; | ||
922 | bgx_config_timestamping(nic->node, bgx_idx, lmac, false); | ||
923 | nic_reg_write(nic, NIC_PF_RX_ETYPE_0_7 | (1 << 3), | ||
924 | (ETYPE_ALG_SKIP << 16) | ETH_P_8021Q); | ||
925 | } | ||
926 | |||
927 | nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG | (pkind_idx << 3), pkind_val); | ||
928 | } | ||
929 | |||
883 | /* Interrupt handler to handle mailbox messages from VFs */ | 930 | /* Interrupt handler to handle mailbox messages from VFs */ |
884 | static void nic_handle_mbx_intr(struct nicpf *nic, int vf) | 931 | static void nic_handle_mbx_intr(struct nicpf *nic, int vf) |
885 | { | 932 | { |
@@ -1022,6 +1069,9 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf) | |||
1022 | case NIC_MBOX_MSG_PFC: | 1069 | case NIC_MBOX_MSG_PFC: |
1023 | nic_pause_frame(nic, vf, &mbx.pfc); | 1070 | nic_pause_frame(nic, vf, &mbx.pfc); |
1024 | goto unlock; | 1071 | goto unlock; |
1072 | case NIC_MBOX_MSG_PTP_CFG: | ||
1073 | nic_config_timestamp(nic, vf, &mbx.ptp); | ||
1074 | break; | ||
1025 | default: | 1075 | default: |
1026 | dev_err(&nic->pdev->dev, | 1076 | dev_err(&nic->pdev->dev, |
1027 | "Invalid msg from VF%d, msg 0x%x\n", vf, mbx.msg.msg); | 1077 | "Invalid msg from VF%d, msg 0x%x\n", vf, mbx.msg.msg); |
diff --git a/drivers/net/ethernet/cavium/thunder/nic_reg.h b/drivers/net/ethernet/cavium/thunder/nic_reg.h index 80d46337cf29..a16c48a1ebb2 100644 --- a/drivers/net/ethernet/cavium/thunder/nic_reg.h +++ b/drivers/net/ethernet/cavium/thunder/nic_reg.h | |||
@@ -99,6 +99,7 @@ | |||
99 | #define NIC_PF_ECC3_DBE_INT_W1S (0x2708) | 99 | #define NIC_PF_ECC3_DBE_INT_W1S (0x2708) |
100 | #define NIC_PF_ECC3_DBE_ENA_W1C (0x2710) | 100 | #define NIC_PF_ECC3_DBE_ENA_W1C (0x2710) |
101 | #define NIC_PF_ECC3_DBE_ENA_W1S (0x2718) | 101 | #define NIC_PF_ECC3_DBE_ENA_W1S (0x2718) |
102 | #define NIC_PF_INTFX_SEND_CFG (0x4000) | ||
102 | #define NIC_PF_MCAM_0_191_ENA (0x100000) | 103 | #define NIC_PF_MCAM_0_191_ENA (0x100000) |
103 | #define NIC_PF_MCAM_0_191_M_0_5_DATA (0x110000) | 104 | #define NIC_PF_MCAM_0_191_M_0_5_DATA (0x110000) |
104 | #define NIC_PF_MCAM_CTRL (0x120000) | 105 | #define NIC_PF_MCAM_CTRL (0x120000) |
diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c b/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c index b9ece9cbf98b..ed9f10bdf41e 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c | |||
@@ -9,12 +9,14 @@ | |||
9 | /* ETHTOOL Support for VNIC_VF Device*/ | 9 | /* ETHTOOL Support for VNIC_VF Device*/ |
10 | 10 | ||
11 | #include <linux/pci.h> | 11 | #include <linux/pci.h> |
12 | #include <linux/net_tstamp.h> | ||
12 | 13 | ||
13 | #include "nic_reg.h" | 14 | #include "nic_reg.h" |
14 | #include "nic.h" | 15 | #include "nic.h" |
15 | #include "nicvf_queues.h" | 16 | #include "nicvf_queues.h" |
16 | #include "q_struct.h" | 17 | #include "q_struct.h" |
17 | #include "thunder_bgx.h" | 18 | #include "thunder_bgx.h" |
19 | #include "../common/cavium_ptp.h" | ||
18 | 20 | ||
19 | #define DRV_NAME "thunder-nicvf" | 21 | #define DRV_NAME "thunder-nicvf" |
20 | #define DRV_VERSION "1.0" | 22 | #define DRV_VERSION "1.0" |
@@ -824,6 +826,31 @@ static int nicvf_set_pauseparam(struct net_device *dev, | |||
824 | return 0; | 826 | return 0; |
825 | } | 827 | } |
826 | 828 | ||
829 | static int nicvf_get_ts_info(struct net_device *netdev, | ||
830 | struct ethtool_ts_info *info) | ||
831 | { | ||
832 | struct nicvf *nic = netdev_priv(netdev); | ||
833 | |||
834 | if (!nic->ptp_clock) | ||
835 | return ethtool_op_get_ts_info(netdev, info); | ||
836 | |||
837 | info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | | ||
838 | SOF_TIMESTAMPING_RX_SOFTWARE | | ||
839 | SOF_TIMESTAMPING_SOFTWARE | | ||
840 | SOF_TIMESTAMPING_TX_HARDWARE | | ||
841 | SOF_TIMESTAMPING_RX_HARDWARE | | ||
842 | SOF_TIMESTAMPING_RAW_HARDWARE; | ||
843 | |||
844 | info->phc_index = cavium_ptp_clock_index(nic->ptp_clock); | ||
845 | |||
846 | info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); | ||
847 | |||
848 | info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | | ||
849 | (1 << HWTSTAMP_FILTER_ALL); | ||
850 | |||
851 | return 0; | ||
852 | } | ||
853 | |||
827 | static const struct ethtool_ops nicvf_ethtool_ops = { | 854 | static const struct ethtool_ops nicvf_ethtool_ops = { |
828 | .get_link = nicvf_get_link, | 855 | .get_link = nicvf_get_link, |
829 | .get_drvinfo = nicvf_get_drvinfo, | 856 | .get_drvinfo = nicvf_get_drvinfo, |
@@ -847,7 +874,7 @@ static const struct ethtool_ops nicvf_ethtool_ops = { | |||
847 | .set_channels = nicvf_set_channels, | 874 | .set_channels = nicvf_set_channels, |
848 | .get_pauseparam = nicvf_get_pauseparam, | 875 | .get_pauseparam = nicvf_get_pauseparam, |
849 | .set_pauseparam = nicvf_set_pauseparam, | 876 | .set_pauseparam = nicvf_set_pauseparam, |
850 | .get_ts_info = ethtool_op_get_ts_info, | 877 | .get_ts_info = nicvf_get_ts_info, |
851 | .get_link_ksettings = nicvf_get_link_ksettings, | 878 | .get_link_ksettings = nicvf_get_link_ksettings, |
852 | }; | 879 | }; |
853 | 880 | ||
diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c index 21618d0d694f..881af8a120f5 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c | |||
@@ -20,11 +20,13 @@ | |||
20 | #include <linux/bpf.h> | 20 | #include <linux/bpf.h> |
21 | #include <linux/bpf_trace.h> | 21 | #include <linux/bpf_trace.h> |
22 | #include <linux/filter.h> | 22 | #include <linux/filter.h> |
23 | #include <linux/net_tstamp.h> | ||
23 | 24 | ||
24 | #include "nic_reg.h" | 25 | #include "nic_reg.h" |
25 | #include "nic.h" | 26 | #include "nic.h" |
26 | #include "nicvf_queues.h" | 27 | #include "nicvf_queues.h" |
27 | #include "thunder_bgx.h" | 28 | #include "thunder_bgx.h" |
29 | #include "../common/cavium_ptp.h" | ||
28 | 30 | ||
29 | #define DRV_NAME "thunder-nicvf" | 31 | #define DRV_NAME "thunder-nicvf" |
30 | #define DRV_VERSION "1.0" | 32 | #define DRV_VERSION "1.0" |
@@ -602,6 +604,44 @@ static inline bool nicvf_xdp_rx(struct nicvf *nic, struct bpf_prog *prog, | |||
602 | return false; | 604 | return false; |
603 | } | 605 | } |
604 | 606 | ||
607 | static void nicvf_snd_ptp_handler(struct net_device *netdev, | ||
608 | struct cqe_send_t *cqe_tx) | ||
609 | { | ||
610 | struct nicvf *nic = netdev_priv(netdev); | ||
611 | struct skb_shared_hwtstamps ts; | ||
612 | u64 ns; | ||
613 | |||
614 | nic = nic->pnicvf; | ||
615 | |||
616 | /* Sync for 'ptp_skb' */ | ||
617 | smp_rmb(); | ||
618 | |||
619 | /* New timestamp request can be queued now */ | ||
620 | atomic_set(&nic->tx_ptp_skbs, 0); | ||
621 | |||
622 | /* Check for timestamp requested skb */ | ||
623 | if (!nic->ptp_skb) | ||
624 | return; | ||
625 | |||
626 | /* Check if timestamping is timedout, which is set to 10us */ | ||
627 | if (cqe_tx->send_status == CQ_TX_ERROP_TSTMP_TIMEOUT || | ||
628 | cqe_tx->send_status == CQ_TX_ERROP_TSTMP_CONFLICT) | ||
629 | goto no_tstamp; | ||
630 | |||
631 | /* Get the timestamp */ | ||
632 | memset(&ts, 0, sizeof(ts)); | ||
633 | ns = cavium_ptp_tstamp2time(nic->ptp_clock, cqe_tx->ptp_timestamp); | ||
634 | ts.hwtstamp = ns_to_ktime(ns); | ||
635 | skb_tstamp_tx(nic->ptp_skb, &ts); | ||
636 | |||
637 | no_tstamp: | ||
638 | /* Free the original skb */ | ||
639 | dev_kfree_skb_any(nic->ptp_skb); | ||
640 | nic->ptp_skb = NULL; | ||
641 | /* Sync 'ptp_skb' */ | ||
642 | smp_wmb(); | ||
643 | } | ||
644 | |||
605 | static void nicvf_snd_pkt_handler(struct net_device *netdev, | 645 | static void nicvf_snd_pkt_handler(struct net_device *netdev, |
606 | struct cqe_send_t *cqe_tx, | 646 | struct cqe_send_t *cqe_tx, |
607 | int budget, int *subdesc_cnt, | 647 | int budget, int *subdesc_cnt, |
@@ -658,7 +698,12 @@ static void nicvf_snd_pkt_handler(struct net_device *netdev, | |||
658 | prefetch(skb); | 698 | prefetch(skb); |
659 | (*tx_pkts)++; | 699 | (*tx_pkts)++; |
660 | *tx_bytes += skb->len; | 700 | *tx_bytes += skb->len; |
661 | napi_consume_skb(skb, budget); | 701 | /* If timestamp is requested for this skb, don't free it */ |
702 | if (skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS && | ||
703 | !nic->pnicvf->ptp_skb) | ||
704 | nic->pnicvf->ptp_skb = skb; | ||
705 | else | ||
706 | napi_consume_skb(skb, budget); | ||
662 | sq->skbuff[cqe_tx->sqe_ptr] = (u64)NULL; | 707 | sq->skbuff[cqe_tx->sqe_ptr] = (u64)NULL; |
663 | } else { | 708 | } else { |
664 | /* In case of SW TSO on 88xx, only last segment will have | 709 | /* In case of SW TSO on 88xx, only last segment will have |
@@ -697,6 +742,21 @@ static inline void nicvf_set_rxhash(struct net_device *netdev, | |||
697 | skb_set_hash(skb, hash, hash_type); | 742 | skb_set_hash(skb, hash, hash_type); |
698 | } | 743 | } |
699 | 744 | ||
745 | static inline void nicvf_set_rxtstamp(struct nicvf *nic, struct sk_buff *skb) | ||
746 | { | ||
747 | u64 ns; | ||
748 | |||
749 | if (!nic->ptp_clock || !nic->hw_rx_tstamp) | ||
750 | return; | ||
751 | |||
752 | /* The first 8 bytes is the timestamp */ | ||
753 | ns = cavium_ptp_tstamp2time(nic->ptp_clock, | ||
754 | be64_to_cpu(*(__be64 *)skb->data)); | ||
755 | skb_hwtstamps(skb)->hwtstamp = ns_to_ktime(ns); | ||
756 | |||
757 | __skb_pull(skb, 8); | ||
758 | } | ||
759 | |||
700 | static void nicvf_rcv_pkt_handler(struct net_device *netdev, | 760 | static void nicvf_rcv_pkt_handler(struct net_device *netdev, |
701 | struct napi_struct *napi, | 761 | struct napi_struct *napi, |
702 | struct cqe_rx_t *cqe_rx, | 762 | struct cqe_rx_t *cqe_rx, |
@@ -748,6 +808,7 @@ static void nicvf_rcv_pkt_handler(struct net_device *netdev, | |||
748 | return; | 808 | return; |
749 | } | 809 | } |
750 | 810 | ||
811 | nicvf_set_rxtstamp(nic, skb); | ||
751 | nicvf_set_rxhash(netdev, cqe_rx, skb); | 812 | nicvf_set_rxhash(netdev, cqe_rx, skb); |
752 | 813 | ||
753 | skb_record_rx_queue(skb, rq_idx); | 814 | skb_record_rx_queue(skb, rq_idx); |
@@ -823,10 +884,12 @@ loop: | |||
823 | &tx_pkts, &tx_bytes); | 884 | &tx_pkts, &tx_bytes); |
824 | tx_done++; | 885 | tx_done++; |
825 | break; | 886 | break; |
887 | case CQE_TYPE_SEND_PTP: | ||
888 | nicvf_snd_ptp_handler(netdev, (void *)cq_desc); | ||
889 | break; | ||
826 | case CQE_TYPE_INVALID: | 890 | case CQE_TYPE_INVALID: |
827 | case CQE_TYPE_RX_SPLIT: | 891 | case CQE_TYPE_RX_SPLIT: |
828 | case CQE_TYPE_RX_TCP: | 892 | case CQE_TYPE_RX_TCP: |
829 | case CQE_TYPE_SEND_PTP: | ||
830 | /* Ignore for now */ | 893 | /* Ignore for now */ |
831 | break; | 894 | break; |
832 | } | 895 | } |
@@ -1322,12 +1385,28 @@ int nicvf_stop(struct net_device *netdev) | |||
1322 | 1385 | ||
1323 | nicvf_free_cq_poll(nic); | 1386 | nicvf_free_cq_poll(nic); |
1324 | 1387 | ||
1388 | /* Free any pending SKB saved to receive timestamp */ | ||
1389 | if (nic->ptp_skb) { | ||
1390 | dev_kfree_skb_any(nic->ptp_skb); | ||
1391 | nic->ptp_skb = NULL; | ||
1392 | } | ||
1393 | |||
1325 | /* Clear multiqset info */ | 1394 | /* Clear multiqset info */ |
1326 | nic->pnicvf = nic; | 1395 | nic->pnicvf = nic; |
1327 | 1396 | ||
1328 | return 0; | 1397 | return 0; |
1329 | } | 1398 | } |
1330 | 1399 | ||
1400 | static int nicvf_config_hw_rx_tstamp(struct nicvf *nic, bool enable) | ||
1401 | { | ||
1402 | union nic_mbx mbx = {}; | ||
1403 | |||
1404 | mbx.ptp.msg = NIC_MBOX_MSG_PTP_CFG; | ||
1405 | mbx.ptp.enable = enable; | ||
1406 | |||
1407 | return nicvf_send_msg_to_pf(nic, &mbx); | ||
1408 | } | ||
1409 | |||
1331 | static int nicvf_update_hw_max_frs(struct nicvf *nic, int mtu) | 1410 | static int nicvf_update_hw_max_frs(struct nicvf *nic, int mtu) |
1332 | { | 1411 | { |
1333 | union nic_mbx mbx = {}; | 1412 | union nic_mbx mbx = {}; |
@@ -1397,6 +1476,12 @@ int nicvf_open(struct net_device *netdev) | |||
1397 | if (nic->sqs_mode) | 1476 | if (nic->sqs_mode) |
1398 | nicvf_get_primary_vf_struct(nic); | 1477 | nicvf_get_primary_vf_struct(nic); |
1399 | 1478 | ||
1479 | /* Configure PTP timestamp */ | ||
1480 | if (nic->ptp_clock) | ||
1481 | nicvf_config_hw_rx_tstamp(nic, nic->hw_rx_tstamp); | ||
1482 | atomic_set(&nic->tx_ptp_skbs, 0); | ||
1483 | nic->ptp_skb = NULL; | ||
1484 | |||
1400 | /* Configure receive side scaling and MTU */ | 1485 | /* Configure receive side scaling and MTU */ |
1401 | if (!nic->sqs_mode) { | 1486 | if (!nic->sqs_mode) { |
1402 | nicvf_rss_init(nic); | 1487 | nicvf_rss_init(nic); |
@@ -1823,6 +1908,73 @@ static void nicvf_xdp_flush(struct net_device *dev) | |||
1823 | return; | 1908 | return; |
1824 | } | 1909 | } |
1825 | 1910 | ||
1911 | static int nicvf_config_hwtstamp(struct net_device *netdev, struct ifreq *ifr) | ||
1912 | { | ||
1913 | struct hwtstamp_config config; | ||
1914 | struct nicvf *nic = netdev_priv(netdev); | ||
1915 | |||
1916 | if (!nic->ptp_clock) | ||
1917 | return -ENODEV; | ||
1918 | |||
1919 | if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) | ||
1920 | return -EFAULT; | ||
1921 | |||
1922 | /* reserved for future extensions */ | ||
1923 | if (config.flags) | ||
1924 | return -EINVAL; | ||
1925 | |||
1926 | switch (config.tx_type) { | ||
1927 | case HWTSTAMP_TX_OFF: | ||
1928 | case HWTSTAMP_TX_ON: | ||
1929 | break; | ||
1930 | default: | ||
1931 | return -ERANGE; | ||
1932 | } | ||
1933 | |||
1934 | switch (config.rx_filter) { | ||
1935 | case HWTSTAMP_FILTER_NONE: | ||
1936 | nic->hw_rx_tstamp = false; | ||
1937 | break; | ||
1938 | case HWTSTAMP_FILTER_ALL: | ||
1939 | case HWTSTAMP_FILTER_SOME: | ||
1940 | case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: | ||
1941 | case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: | ||
1942 | case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: | ||
1943 | case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: | ||
1944 | case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: | ||
1945 | case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: | ||
1946 | case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: | ||
1947 | case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: | ||
1948 | case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: | ||
1949 | case HWTSTAMP_FILTER_PTP_V2_EVENT: | ||
1950 | case HWTSTAMP_FILTER_PTP_V2_SYNC: | ||
1951 | case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: | ||
1952 | nic->hw_rx_tstamp = true; | ||
1953 | config.rx_filter = HWTSTAMP_FILTER_ALL; | ||
1954 | break; | ||
1955 | default: | ||
1956 | return -ERANGE; | ||
1957 | } | ||
1958 | |||
1959 | if (netif_running(netdev)) | ||
1960 | nicvf_config_hw_rx_tstamp(nic, nic->hw_rx_tstamp); | ||
1961 | |||
1962 | if (copy_to_user(ifr->ifr_data, &config, sizeof(config))) | ||
1963 | return -EFAULT; | ||
1964 | |||
1965 | return 0; | ||
1966 | } | ||
1967 | |||
1968 | static int nicvf_ioctl(struct net_device *netdev, struct ifreq *req, int cmd) | ||
1969 | { | ||
1970 | switch (cmd) { | ||
1971 | case SIOCSHWTSTAMP: | ||
1972 | return nicvf_config_hwtstamp(netdev, req); | ||
1973 | default: | ||
1974 | return -EOPNOTSUPP; | ||
1975 | } | ||
1976 | } | ||
1977 | |||
1826 | static const struct net_device_ops nicvf_netdev_ops = { | 1978 | static const struct net_device_ops nicvf_netdev_ops = { |
1827 | .ndo_open = nicvf_open, | 1979 | .ndo_open = nicvf_open, |
1828 | .ndo_stop = nicvf_stop, | 1980 | .ndo_stop = nicvf_stop, |
@@ -1836,6 +1988,7 @@ static const struct net_device_ops nicvf_netdev_ops = { | |||
1836 | .ndo_bpf = nicvf_xdp, | 1988 | .ndo_bpf = nicvf_xdp, |
1837 | .ndo_xdp_xmit = nicvf_xdp_xmit, | 1989 | .ndo_xdp_xmit = nicvf_xdp_xmit, |
1838 | .ndo_xdp_flush = nicvf_xdp_flush, | 1990 | .ndo_xdp_flush = nicvf_xdp_flush, |
1991 | .ndo_do_ioctl = nicvf_ioctl, | ||
1839 | }; | 1992 | }; |
1840 | 1993 | ||
1841 | static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | 1994 | static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
@@ -1845,6 +1998,16 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1845 | struct nicvf *nic; | 1998 | struct nicvf *nic; |
1846 | int err, qcount; | 1999 | int err, qcount; |
1847 | u16 sdevid; | 2000 | u16 sdevid; |
2001 | struct cavium_ptp *ptp_clock; | ||
2002 | |||
2003 | ptp_clock = cavium_ptp_get(); | ||
2004 | if (IS_ERR(ptp_clock)) { | ||
2005 | if (PTR_ERR(ptp_clock) == -ENODEV) | ||
2006 | /* In virtualized environment we proceed without ptp */ | ||
2007 | ptp_clock = NULL; | ||
2008 | else | ||
2009 | return PTR_ERR(ptp_clock); | ||
2010 | } | ||
1848 | 2011 | ||
1849 | err = pci_enable_device(pdev); | 2012 | err = pci_enable_device(pdev); |
1850 | if (err) { | 2013 | if (err) { |
@@ -1899,6 +2062,7 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1899 | */ | 2062 | */ |
1900 | if (!nic->t88) | 2063 | if (!nic->t88) |
1901 | nic->max_queues *= 2; | 2064 | nic->max_queues *= 2; |
2065 | nic->ptp_clock = ptp_clock; | ||
1902 | 2066 | ||
1903 | /* MAP VF's configuration registers */ | 2067 | /* MAP VF's configuration registers */ |
1904 | nic->reg_base = pcim_iomap(pdev, PCI_CFG_REG_BAR_NUM, 0); | 2068 | nic->reg_base = pcim_iomap(pdev, PCI_CFG_REG_BAR_NUM, 0); |
@@ -2012,6 +2176,7 @@ static void nicvf_remove(struct pci_dev *pdev) | |||
2012 | pci_set_drvdata(pdev, NULL); | 2176 | pci_set_drvdata(pdev, NULL); |
2013 | if (nic->drv_stats) | 2177 | if (nic->drv_stats) |
2014 | free_percpu(nic->drv_stats); | 2178 | free_percpu(nic->drv_stats); |
2179 | cavium_ptp_put(nic->ptp_clock); | ||
2015 | free_netdev(netdev); | 2180 | free_netdev(netdev); |
2016 | pci_release_regions(pdev); | 2181 | pci_release_regions(pdev); |
2017 | pci_disable_device(pdev); | 2182 | pci_disable_device(pdev); |
diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c index 14e62c6ac342..3eae9ff9b53a 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c | |||
@@ -982,6 +982,9 @@ void nicvf_qset_config(struct nicvf *nic, bool enable) | |||
982 | qs_cfg->be = 1; | 982 | qs_cfg->be = 1; |
983 | #endif | 983 | #endif |
984 | qs_cfg->vnic = qs->vnic_id; | 984 | qs_cfg->vnic = qs->vnic_id; |
985 | /* Enable Tx timestamping capability */ | ||
986 | if (nic->ptp_clock) | ||
987 | qs_cfg->send_tstmp_ena = 1; | ||
985 | } | 988 | } |
986 | nicvf_send_msg_to_pf(nic, &mbx); | 989 | nicvf_send_msg_to_pf(nic, &mbx); |
987 | } | 990 | } |
@@ -1389,6 +1392,29 @@ nicvf_sq_add_hdr_subdesc(struct nicvf *nic, struct snd_queue *sq, int qentry, | |||
1389 | hdr->inner_l3_offset = skb_network_offset(skb) - 2; | 1392 | hdr->inner_l3_offset = skb_network_offset(skb) - 2; |
1390 | this_cpu_inc(nic->pnicvf->drv_stats->tx_tso); | 1393 | this_cpu_inc(nic->pnicvf->drv_stats->tx_tso); |
1391 | } | 1394 | } |
1395 | |||
1396 | /* Check if timestamp is requested */ | ||
1397 | if (!(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) { | ||
1398 | skb_tx_timestamp(skb); | ||
1399 | return; | ||
1400 | } | ||
1401 | |||
1402 | /* Tx timestamping not supported along with TSO, so ignore request */ | ||
1403 | if (skb_shinfo(skb)->gso_size) | ||
1404 | return; | ||
1405 | |||
1406 | /* HW supports only a single outstanding packet to timestamp */ | ||
1407 | if (!atomic_add_unless(&nic->pnicvf->tx_ptp_skbs, 1, 1)) | ||
1408 | return; | ||
1409 | |||
1410 | /* Mark the SKB for later reference */ | ||
1411 | skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; | ||
1412 | |||
1413 | /* Finally enable timestamp generation | ||
1414 | * Since 'post_cqe' is also set, two CQEs will be posted | ||
1415 | * for this packet i.e CQE_TYPE_SEND and CQE_TYPE_SEND_PTP. | ||
1416 | */ | ||
1417 | hdr->tstmp = 1; | ||
1392 | } | 1418 | } |
1393 | 1419 | ||
1394 | /* SQ GATHER subdescriptor | 1420 | /* SQ GATHER subdescriptor |
diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c index 5e5c4d7796b8..0f23999c5bcf 100644 --- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c +++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c | |||
@@ -245,6 +245,35 @@ void bgx_lmac_rx_tx_enable(int node, int bgx_idx, int lmacid, bool enable) | |||
245 | } | 245 | } |
246 | EXPORT_SYMBOL(bgx_lmac_rx_tx_enable); | 246 | EXPORT_SYMBOL(bgx_lmac_rx_tx_enable); |
247 | 247 | ||
248 | /* Enables or disables timestamp insertion by BGX for Rx packets */ | ||
249 | void bgx_config_timestamping(int node, int bgx_idx, int lmacid, bool enable) | ||
250 | { | ||
251 | struct bgx *bgx = get_bgx(node, bgx_idx); | ||
252 | struct lmac *lmac; | ||
253 | u64 csr_offset, cfg; | ||
254 | |||
255 | if (!bgx) | ||
256 | return; | ||
257 | |||
258 | lmac = &bgx->lmac[lmacid]; | ||
259 | |||
260 | if (lmac->lmac_type == BGX_MODE_SGMII || | ||
261 | lmac->lmac_type == BGX_MODE_QSGMII || | ||
262 | lmac->lmac_type == BGX_MODE_RGMII) | ||
263 | csr_offset = BGX_GMP_GMI_RXX_FRM_CTL; | ||
264 | else | ||
265 | csr_offset = BGX_SMUX_RX_FRM_CTL; | ||
266 | |||
267 | cfg = bgx_reg_read(bgx, lmacid, csr_offset); | ||
268 | |||
269 | if (enable) | ||
270 | cfg |= BGX_PKT_RX_PTP_EN; | ||
271 | else | ||
272 | cfg &= ~BGX_PKT_RX_PTP_EN; | ||
273 | bgx_reg_write(bgx, lmacid, csr_offset, cfg); | ||
274 | } | ||
275 | EXPORT_SYMBOL(bgx_config_timestamping); | ||
276 | |||
248 | void bgx_lmac_get_pfc(int node, int bgx_idx, int lmacid, void *pause) | 277 | void bgx_lmac_get_pfc(int node, int bgx_idx, int lmacid, void *pause) |
249 | { | 278 | { |
250 | struct pfc *pfc = (struct pfc *)pause; | 279 | struct pfc *pfc = (struct pfc *)pause; |
diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.h b/drivers/net/ethernet/cavium/thunder/thunder_bgx.h index 23acdc5ab896..5a7567d31138 100644 --- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.h +++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.h | |||
@@ -122,6 +122,8 @@ | |||
122 | #define SPU_DBG_CTL_AN_NONCE_MCT_DIS BIT_ULL(29) | 122 | #define SPU_DBG_CTL_AN_NONCE_MCT_DIS BIT_ULL(29) |
123 | 123 | ||
124 | #define BGX_SMUX_RX_INT 0x20000 | 124 | #define BGX_SMUX_RX_INT 0x20000 |
125 | #define BGX_SMUX_RX_FRM_CTL 0x20020 | ||
126 | #define BGX_PKT_RX_PTP_EN BIT_ULL(12) | ||
125 | #define BGX_SMUX_RX_JABBER 0x20030 | 127 | #define BGX_SMUX_RX_JABBER 0x20030 |
126 | #define BGX_SMUX_RX_CTL 0x20048 | 128 | #define BGX_SMUX_RX_CTL 0x20048 |
127 | #define SMU_RX_CTL_STATUS (3ull << 0) | 129 | #define SMU_RX_CTL_STATUS (3ull << 0) |
@@ -172,6 +174,7 @@ | |||
172 | #define GMI_PORT_CFG_SPEED_MSB BIT_ULL(8) | 174 | #define GMI_PORT_CFG_SPEED_MSB BIT_ULL(8) |
173 | #define GMI_PORT_CFG_RX_IDLE BIT_ULL(12) | 175 | #define GMI_PORT_CFG_RX_IDLE BIT_ULL(12) |
174 | #define GMI_PORT_CFG_TX_IDLE BIT_ULL(13) | 176 | #define GMI_PORT_CFG_TX_IDLE BIT_ULL(13) |
177 | #define BGX_GMP_GMI_RXX_FRM_CTL 0x38028 | ||
175 | #define BGX_GMP_GMI_RXX_JABBER 0x38038 | 178 | #define BGX_GMP_GMI_RXX_JABBER 0x38038 |
176 | #define BGX_GMP_GMI_TXX_THRESH 0x38210 | 179 | #define BGX_GMP_GMI_TXX_THRESH 0x38210 |
177 | #define BGX_GMP_GMI_TXX_APPEND 0x38218 | 180 | #define BGX_GMP_GMI_TXX_APPEND 0x38218 |
@@ -223,6 +226,7 @@ void bgx_set_lmac_mac(int node, int bgx_idx, int lmacid, const u8 *mac); | |||
223 | void bgx_get_lmac_link_state(int node, int bgx_idx, int lmacid, void *status); | 226 | void bgx_get_lmac_link_state(int node, int bgx_idx, int lmacid, void *status); |
224 | void bgx_lmac_internal_loopback(int node, int bgx_idx, | 227 | void bgx_lmac_internal_loopback(int node, int bgx_idx, |
225 | int lmac_idx, bool enable); | 228 | int lmac_idx, bool enable); |
229 | void bgx_config_timestamping(int node, int bgx_idx, int lmacid, bool enable); | ||
226 | void bgx_lmac_get_pfc(int node, int bgx_idx, int lmacid, void *pause); | 230 | void bgx_lmac_get_pfc(int node, int bgx_idx, int lmacid, void *pause); |
227 | void bgx_lmac_set_pfc(int node, int bgx_idx, int lmacid, void *pause); | 231 | void bgx_lmac_set_pfc(int node, int bgx_idx, int lmacid, void *pause); |
228 | 232 | ||