From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752413AbdLFNby (ORCPT ); Wed, 6 Dec 2017 08:31:54 -0500 Received: from mail-sn1nam02on0074.outbound.protection.outlook.com ([104.47.36.74]:25088 "EHLO NAM02-SN1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1752292AbdLFNbp (ORCPT ); Wed, 6 Dec 2017 08:31:45 -0500 Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=Aleksey.Makarov@cavium.com; From: Aleksey Makarov To: netdev@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, "Goutham, Sunil" , Radoslaw Biernacki , Aleksey Makarov , Robert Richter , David Daney , Sunil Goutham Subject: [PATCH net-next v3 2/2] net: thunderx: add timestamping support Date: Wed, 6 Dec 2017 16:30:58 +0300 Message-Id: <20171206133100.26436-3-aleksey.makarov@cavium.com> X-Mailer: git-send-email 2.15.1 In-Reply-To: <20171206133100.26436-1-aleksey.makarov@cavium.com> References: <20171206133100.26436-1-aleksey.makarov@cavium.com> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [46.242.8.171] X-ClientProxiedBy: HE1P191CA0021.EURP191.PROD.OUTLOOK.COM (10.172.132.159) To BN3PR07MB2482.namprd07.prod.outlook.com (10.167.4.23) X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 01b2495d-c72e-4c2f-3f31-08d53cadb0ce X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:(4534020)(4602075)(4627115)(201703031133081)(201702281549075)(5600026)(4604075)(2017052603286);SRVR:BN3PR07MB2482; X-Microsoft-Exchange-Diagnostics: 1;BN3PR07MB2482;3:fjG06N4bm1QbZlTwPJJLr0LudJwW01MI2zCGfvLGuKXjgmumXCGqSAKjheodhjAHOObPXQcu94LIHeG/MPWriw82lDjdbhPVEJqTSlt4MnRwJ1ka2JA4SI708qK/SqBIMrzRq8soQxoesfssh7+P9eQAd/b/+8IflXeSEAKYjllzzaqn7+IXtHYe0ch2uMKnzPfRfm+Wo4fvBV2FZYg0iJ6Ehc5AixRBPughsjJCriuQka0Top6HakX8o8JXaGid;25:5gPtrepIn0C66ZfN58e3PUU7SHnprAqU9Xe8y55b8bIkyjyaN5urJlvx07z+uwzlubX2q+LJXt4VfQGjT9+0Sl+Gc+3TIPn4iQoTu691pTrMH91i8vofk02i888FiISW+Rc87Btx1o9B5LAk4GsOoyfV2XmbYk88+09dCnpF81xoS2exkykqLpzRASEn5UqY8NFUY/t5n1ruEPmlSo5xfpCx4K5ZSBMu7fwclzdo00YcfLcG6SCeLwqDfUUBEmVsEGqquMJvHTcdIJ0MQ7Ao3WbZNmouux3Ei9eXWdTklVAYqU/i5rx20Lyq6iNQMhF8/AmjtDy3DPKqpBFsbCDkig==;31:AfqHku18ezY6Bt2rpajHkXoPBN91EGY/yPanVfe+821yGSASqUkDIDp0mi4b1DGVTF9Z6yy4Lzl5mt/qLWnnJefpaMWvzyhEmWy6KknKhVExGxBP3fe++fk7CkixzT22dOsiZP+Q5NOCuTEB2A/gFpbIVkm4/myFcOc5xVD9/FkPwzxbybnYVpG+zsYM0zeac9JbYVkMgeadXXpy/K9/hrRdKlfxVVMYBLB1hIWP/aw= X-MS-TrafficTypeDiagnostic: BN3PR07MB2482: X-Microsoft-Exchange-Diagnostics: 1;BN3PR07MB2482;20:19IY0xpQ5u8cZ91Khvg094zWdj2tsbBCdKAaiRI53tOU39TDflae/1XWvBgt+GaqRNvsW1mSTYLTjx4tMx4+Yk9QhD7aFrx98K2bmLJvAMq/QMj5dd0GSDYs9m/5t4WjH6lf77pNXbReO/OB0y2Bc3eVlCyfKKoWuQAg9vLnYg0I36ljV0oRB6DPxUwJaA/z1j5ZFGnmqiSyJ60xFzYoYisNF/W7jY+3atkBsgou+K028NquzgrSNT5yQoXxZdzHcZcbpDq5Qc4ws3hwcOsBgTHOCMsqdd1pkz2OAhPJcmIAsDHZsvgH0WNamsr5MMZuPBBmIHB5E3woKFhqC4pP6D99FsRfyFbv86tWVBhclsoDUMsuNMwHa7amEfUneMFt1ojfbrwak0w6XBxXmWiUkBBBCGboZ4m9mlja+QhbufxTKb3eTkTVwDolsPsNwQaTzpoCfGLFooOmUfPtHKRV7bAaJVct6AcH7RNFcgR7QgNgbugS15KH4juzha+nNhY8;4:xDyGAij/3dYvzUtZLODB4todkfR4AYRv6FELzCexIypSt9s8+oplMojmUXcyXB9XNCquIb3gywSE3yytNUXMGtEkWzogbw0bCG0/nPRDHauyqcExmCwy2vfA1by26wkoa9N2xplBVPrQgw2aBJrDjiYPOyZ4lk3SXwV6uOPlh8pDQQT5HgSQoJZeHy7pgHb919Oh0dEVq07GbEPkfAYR8f+b6Tk8cHV2TJUyARSHGYhrVznlIKFy+fD515qxH+Zljp8U1kwME8YKfzLjkUMCjQ== X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(6040450)(2401047)(8121501046)(5005006)(93006095)(93001095)(10201501046)(3231022)(3002001)(6041248)(201703131423075)(201702281528075)(201703061421075)(201703061406153)(20161123564025)(20161123562025)(20161123558100)(20161123560025)(20161123555025)(6072148)(201708071742011);SRVR:BN3PR07MB2482;BCL:0;PCL:0;RULEID:(100000803101)(100110400095);SRVR:BN3PR07MB2482; X-Forefront-PRVS: 05134F8B4F X-Forefront-Antispam-Report: SFV:NSPM;SFS:(10009020)(6069001)(376002)(346002)(366004)(189003)(199004)(25786009)(6666003)(50226002)(305945005)(2950100002)(6916009)(3846002)(8936002)(7736002)(478600001)(72206003)(68736007)(8676002)(81166006)(81156014)(54906003)(86362001)(36756003)(2906002)(6116002)(33646002)(1076002)(575784001)(6486002)(16526018)(6512007)(107886003)(51416003)(52116002)(76176011)(6506006)(106356001)(2361001)(53936002)(316002)(16586007)(105586002)(2351001)(5660300001)(48376002)(101416001)(97736004)(50466002)(4326008)(66066001)(47776003);DIR:OUT;SFP:1101;SCL:1;SRVR:BN3PR07MB2482;H:localhost.localdomain;FPR:;SPF:None;PTR:InfoNoRecords;MX:1;A:1;LANG:en; X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1;BN3PR07MB2482;23:Bf5TAQiTuLBgOxGlfh/s9fw0m4l+1n40PaCL5NB4P?= =?us-ascii?Q?1PGs5dcMw7zKEjCGco7XT7URupPgdToWdUMQ8mt6VrBd9qB7w+c/a1fO01Vl?= =?us-ascii?Q?bPgDrSzXwUBrlG6iLix7jAkKzxmNBR81bQgSaQk6kFB1YANSG5xKozrNoHNG?= =?us-ascii?Q?aOA/M+4jhW+XycZ2/v6loTP/sx52ry3anw0nasm6H6b9Q38uoO7Hf249hlVs?= =?us-ascii?Q?8/72XZTZJXPJvDMjyVRophSl4oqGbbVgBQxpnmAF6XN/RFISIt4/p1nlGsYk?= =?us-ascii?Q?ormvm8o8IScKoDgHGfXtYxLNtaM8d5704BNQeXoXHzIL5l8+c1N5p7/47CTj?= =?us-ascii?Q?bvmd/l4n1dlzsdovYpAu25rSK8IttbtwPm22etpzasYft+zfUCrIfJGyVBXr?= =?us-ascii?Q?OTU7vMWiWyPMWBvPUt5ZHyMld+dnD9IIgyd3YIOmPR6SPhY4YR5DHCGH0JjN?= =?us-ascii?Q?YEqcagi1CXxg0EddG9bAtTFEsJqfLMcxvZ1ICtxbuAkGUVXUlaqn9PN3SYiS?= =?us-ascii?Q?WjMNQZZu5cwva2jEQeq3vOPetTeJCd30zr6z5rr9A7S8Oo69rwIau5UbxqUZ?= =?us-ascii?Q?TDvam0TQ5CD69EKf/+BbN+Ih0MsXr/i6F4sDajmIACMW61nM5RvqEOlL2Zut?= =?us-ascii?Q?p1UYp5OB5rrQkUbsQdNLBMQgKUZjRD0LffkJP49X/u5gpiUdrxy1BIDvEw+i?= =?us-ascii?Q?j8sXEqb6vi1VNz8TJaSY/QyCBZJq1/VjqWJCsCrKF8wKcSMLnvpr+8bsq14v?= =?us-ascii?Q?ZGsl1Ss8jeBiBQrkayN7P/KNN3x4SxIj7Mjhz1MWLo/pbBH5kWsPw9NMxD3g?= =?us-ascii?Q?DkNMVVqMihiFsjQQUsbqEPAw0o+RaDSuYArrxyP/yiE3sdKFK9Y/PUAI9/xV?= =?us-ascii?Q?WQNw8NnlMa2IU/YTnakUdRRbLjhfIlRLMdB3XlkKvcCB9XZDNhKmldtVv5P4?= =?us-ascii?Q?oTrxJiuy30ZvqMyScu1MWcmHoJmNS9sf94ks2mAiJEkMrT3Bd6hZxmwwQ/Wb?= =?us-ascii?Q?ziWoSZPwRmiRUGe+XzC9+dZw4y5+dYFZnMrC14X6Tlwl5L7fSvaF8XvNpGzh?= =?us-ascii?Q?tUgj9lxnQsgPyAztGYNuB5QoP3orEopHxz4qBinl/EFhEv+cWicejIJJuJsK?= =?us-ascii?Q?3i45zUYUDzqxJOBK7m8RM5vdhQcKnQHZpi1GKK+XXel80SzqmmbYysnh5TIS?= =?us-ascii?Q?Yux6ZQL/++eaSc=3D?= X-Microsoft-Exchange-Diagnostics: 1;BN3PR07MB2482;6:O/Qu61MxgBOpwTY/N9rfmMnfEoIH2DWo4HLk0UnkZQtkoSboXoGwaQPe9VEbHtQxqbNtsOIfdaBzKUGUA3WPeKLDom31WqlZ4yY5dj/ZsEQy/GfuqMahFEnHV+maBsUHWxDH/OgSYEdgifkUHdK/Xi/yw2DF9cZ7UU2y5VB5IbOIsRdrXqcBdlhXf0KGOcLU0kZcIe6C9gkQY3o3Tz8crCuxaoNwCueFJ6/L2men06ySTiapy0PW1tv+2Cmp5xm0XGR5wF/bJRLyu2AHbMlJAVEhGrtVSq99QyUm25tvc+Bprl/FBX8x+/Wu5EgkPBBx7AVC3gI1XPQxHkj3JAV+OPrxoQ1KKlnwgRYW5xrIJ+0=;5:Hy5XPjO/Xfupq9m62RSmB/dM8GKf+BnLFbbnQETrtWOcFCBfAg2mNPa4t6mzm0Z4WyLyfyOhe5d+uV2O2KDYe3kcfiksSIyt4kBoI9DC884u9V3YfHbmEq0DU+OltXvO/H0xeavbtJam3Jx2RZicu6XHc45zWLiANaThqGAizFQ=;24:5Hajwgey6ZwBQNlV/mYb053kebMQzPaRYDsds5/zIMGGtVnvWvR56hme2SYBpn3mJWs9qh+ocqme6BZf4u21aLcmOz67jjBNHEr7knY6wU0=;7:CXl1iM22fn3kCV0K7eD3EQ0OG6bQSu8wG+6IO+Q0s+na5iUCnwBIshmRIp9OkolOHX0gODvQ+8nuLIrtn4IJKX3uQfOztQcvXHsvcLTiNgK+E1TQylx+ZQ14qBgU7B6DScGxTKZainN3MAAJbR6Hp0qubr7IZoeQvTrvkubSlAxLVS0G6WoJ3cW3AZVRIXRLPePOUuSordjJK7MJhyI2t6qCtBYj+6OVUjqZIE+JFB+4NBK4hkb+6wlA+A7No8oN SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: cavium.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 06 Dec 2017 13:31:40.6073 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 01b2495d-c72e-4c2f-3f31-08d53cadb0ce X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 711e4ccf-2e9b-4bcf-a551-4094005b6194 X-MS-Exchange-Transport-CrossTenantHeadersStamped: BN3PR07MB2482 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Sunil Goutham 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 Signed-off-by: Aleksey Makarov --- drivers/net/ethernet/cavium/Kconfig | 1 + drivers/net/ethernet/cavium/thunder/nic.h | 15 ++ drivers/net/ethernet/cavium/thunder/nic_main.c | 58 ++++++- drivers/net/ethernet/cavium/thunder/nic_reg.h | 1 + .../net/ethernet/cavium/thunder/nicvf_ethtool.c | 29 +++- drivers/net/ethernet/cavium/thunder/nicvf_main.c | 173 ++++++++++++++++++++- drivers/net/ethernet/cavium/thunder/nicvf_queues.c | 26 ++++ drivers/net/ethernet/cavium/thunder/thunder_bgx.c | 29 ++++ drivers/net/ethernet/cavium/thunder/thunder_bgx.h | 4 + 9 files changed, 330 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/cavium/Kconfig b/drivers/net/ethernet/cavium/Kconfig index fabe0ffcc2d4..6d003cbe197c 100644 --- a/drivers/net/ethernet/cavium/Kconfig +++ b/drivers/net/ethernet/cavium/Kconfig @@ -27,6 +27,7 @@ config THUNDER_NIC_PF config THUNDER_NIC_VF tristate "Thunder Virtual function driver" + select CAVIUM_PTP depends on 64BIT ---help--- 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..204b234beb9d 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 { struct u64_stats_sync syncp; }; +struct cavium_ptp; + struct nicvf { struct nicvf *pnicvf; struct net_device *netdev; @@ -312,6 +314,12 @@ struct nicvf { struct tasklet_struct qs_err_task; struct work_struct reset_task; + /* PTP timestamp */ + struct cavium_ptp *ptp_clock; + bool hw_rx_tstamp; + struct sk_buff *ptp_skb; + atomic_t tx_ptp_skbs; + /* Interrupt coalescing settings */ u32 cq_coalesce_usecs; u32 msg_enable; @@ -371,6 +379,7 @@ struct nicvf { #define NIC_MBOX_MSG_LOOPBACK 0x16 /* Set interface in loopback */ #define NIC_MBOX_MSG_RESET_STAT_COUNTER 0x17 /* Reset statistics counters */ #define NIC_MBOX_MSG_PFC 0x18 /* Pause frame control */ +#define NIC_MBOX_MSG_PTP_CFG 0x19 /* HW packet timestamp */ #define NIC_MBOX_MSG_CFG_DONE 0xF0 /* VF configuration done */ #define NIC_MBOX_MSG_SHUTDOWN 0xF1 /* VF is being shutdown */ @@ -521,6 +530,11 @@ struct pfc { u8 fc_tx; }; +struct set_ptp { + u8 msg; + bool enable; +}; + /* 128 bit shared memory between PF and each VF */ union nic_mbx { struct { u8 msg; } msg; @@ -540,6 +554,7 @@ union nic_mbx { struct set_loopback lbk; struct reset_stat_cfg reset_stat; struct pfc pfc; + struct set_ptp ptp; }; #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..4c1c5414a162 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) /* Enable backpressure */ nic_reg_write(nic, NIC_PF_BP_CFG, (1ULL << 6) | 0x03); - /* TNS and TNS bypass modes are present only on 88xx */ + /* TNS and TNS bypass modes are present only on 88xx + * Also offset of this CSR has changed in 81xx and 83xx. + */ if (nic->pdev->subsystem_device == PCI_SUBSYS_DEVID_88XX_NIC_PF) { /* Disable TNS mode on both interfaces */ nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG, - (NIC_TNS_BYPASS_MODE << 7) | BGX0_BLOCK); + (NIC_TNS_BYPASS_MODE << 7) | + BGX0_BLOCK | (1ULL << 16)); nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG | (1 << 8), - (NIC_TNS_BYPASS_MODE << 7) | BGX1_BLOCK); + (NIC_TNS_BYPASS_MODE << 7) | + BGX1_BLOCK | (1ULL << 16)); + } else { + /* Configure timestamp generation timeout to 10us */ + for (i = 0; i < nic->hw->bgx_cnt; i++) + nic_reg_write(nic, NIC_PF_INTFX_SEND_CFG | (i << 3), + (1ULL << 16)); } nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG, @@ -880,6 +889,46 @@ static void nic_pause_frame(struct nicpf *nic, int vf, struct pfc *cfg) } } +/* Enable or disable HW timestamping by BGX for pkts received on a LMAC */ +static void nic_config_timestamp(struct nicpf *nic, int vf, struct set_ptp *ptp) +{ + struct pkind_cfg *pkind; + u8 lmac, bgx_idx; + u64 pkind_val, pkind_idx; + + if (vf >= nic->num_vf_en) + return; + + bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); + lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); + + pkind_idx = lmac + bgx_idx * MAX_LMAC_PER_BGX; + pkind_val = nic_reg_read(nic, NIC_PF_PKIND_0_15_CFG | (pkind_idx << 3)); + pkind = (struct pkind_cfg *)&pkind_val; + + if (ptp->enable && !pkind->hdr_sl) { + /* Skiplen to exclude 8byte timestamp while parsing pkt + * If not configured, will result in L2 errors. + */ + pkind->hdr_sl = 4; + /* Adjust max packet length allowed */ + pkind->maxlen += (pkind->hdr_sl * 2); + bgx_config_timestamping(nic->node, bgx_idx, lmac, true); + nic_reg_write(nic, + NIC_PF_RX_ETYPE_0_7 | (1 << 3), + (ETYPE_ALG_ENDPARSE << 16) | ETH_P_1588); + } else if (!ptp->enable && pkind->hdr_sl) { + pkind->maxlen -= (pkind->hdr_sl * 2); + pkind->hdr_sl = 0; + bgx_config_timestamping(nic->node, bgx_idx, lmac, false); + nic_reg_write(nic, + NIC_PF_RX_ETYPE_0_7 | (1 << 3), + (1ULL << 16) | ETH_P_8021Q); /* reset value */ + } + + nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG | (pkind_idx << 3), pkind_val); +} + /* Interrupt handler to handle mailbox messages from VFs */ static void nic_handle_mbx_intr(struct nicpf *nic, int vf) { @@ -1022,6 +1071,9 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf) case NIC_MBOX_MSG_PFC: nic_pause_frame(nic, vf, &mbx.pfc); goto unlock; + case NIC_MBOX_MSG_PTP_CFG: + nic_config_timestamp(nic, vf, &mbx.ptp); + break; default: dev_err(&nic->pdev->dev, "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 @@ #define NIC_PF_ECC3_DBE_INT_W1S (0x2708) #define NIC_PF_ECC3_DBE_ENA_W1C (0x2710) #define NIC_PF_ECC3_DBE_ENA_W1S (0x2718) +#define NIC_PF_INTFX_SEND_CFG (0x4000) #define NIC_PF_MCAM_0_191_ENA (0x100000) #define NIC_PF_MCAM_0_191_M_0_5_DATA (0x110000) #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 @@ /* ETHTOOL Support for VNIC_VF Device*/ #include +#include #include "nic_reg.h" #include "nic.h" #include "nicvf_queues.h" #include "q_struct.h" #include "thunder_bgx.h" +#include "../common/cavium_ptp.h" #define DRV_NAME "thunder-nicvf" #define DRV_VERSION "1.0" @@ -824,6 +826,31 @@ static int nicvf_set_pauseparam(struct net_device *dev, return 0; } +static int nicvf_get_ts_info(struct net_device *netdev, + struct ethtool_ts_info *info) +{ + struct nicvf *nic = netdev_priv(netdev); + + if (!nic->ptp_clock) + return ethtool_op_get_ts_info(netdev, info); + + info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_RX_SOFTWARE | + SOF_TIMESTAMPING_SOFTWARE | + SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; + + info->phc_index = cavium_ptp_clock_index(nic->ptp_clock); + + info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); + + info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | + (1 << HWTSTAMP_FILTER_ALL); + + return 0; +} + static const struct ethtool_ops nicvf_ethtool_ops = { .get_link = nicvf_get_link, .get_drvinfo = nicvf_get_drvinfo, @@ -847,7 +874,7 @@ static const struct ethtool_ops nicvf_ethtool_ops = { .set_channels = nicvf_set_channels, .get_pauseparam = nicvf_get_pauseparam, .set_pauseparam = nicvf_set_pauseparam, - .get_ts_info = ethtool_op_get_ts_info, + .get_ts_info = nicvf_get_ts_info, .get_link_ksettings = nicvf_get_link_ksettings, }; diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c index 52b3a6044f85..487d09a32b6d 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c @@ -20,11 +20,13 @@ #include #include #include +#include #include "nic_reg.h" #include "nic.h" #include "nicvf_queues.h" #include "thunder_bgx.h" +#include "../common/cavium_ptp.h" #define DRV_NAME "thunder-nicvf" #define DRV_VERSION "1.0" @@ -601,6 +603,44 @@ static inline bool nicvf_xdp_rx(struct nicvf *nic, struct bpf_prog *prog, return false; } +static void nicvf_snd_ptp_handler(struct net_device *netdev, + struct cqe_send_t *cqe_tx) +{ + struct nicvf *nic = netdev_priv(netdev); + struct skb_shared_hwtstamps ts; + u64 ns; + + nic = nic->pnicvf; + + /* Sync for 'ptp_skb' */ + smp_rmb(); + + /* New timestamp request can be queued now */ + atomic_set(&nic->tx_ptp_skbs, 0); + + /* Check for timestamp requested skb */ + if (!nic->ptp_skb) + return; + + /* Check if timestamping is timedout, which is set to 10us */ + if (cqe_tx->send_status == CQ_TX_ERROP_TSTMP_TIMEOUT || + cqe_tx->send_status == CQ_TX_ERROP_TSTMP_CONFLICT) + goto no_tstamp; + + /* Get the timestamp */ + memset(&ts, 0, sizeof(ts)); + ns = cavium_ptp_tstamp2time(nic->ptp_clock, cqe_tx->ptp_timestamp); + ts.hwtstamp = ns_to_ktime(ns); + skb_tstamp_tx(nic->ptp_skb, &ts); + +no_tstamp: + /* Free the original skb */ + dev_kfree_skb_any(nic->ptp_skb); + nic->ptp_skb = NULL; + /* Sync 'ptp_skb' */ + smp_wmb(); +} + static void nicvf_snd_pkt_handler(struct net_device *netdev, struct cqe_send_t *cqe_tx, int budget, int *subdesc_cnt, @@ -657,7 +697,12 @@ static void nicvf_snd_pkt_handler(struct net_device *netdev, prefetch(skb); (*tx_pkts)++; *tx_bytes += skb->len; - napi_consume_skb(skb, budget); + /* If timestamp is requested for this skb, don't free it */ + if (skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS && + !nic->pnicvf->ptp_skb) + nic->pnicvf->ptp_skb = skb; + else + napi_consume_skb(skb, budget); sq->skbuff[cqe_tx->sqe_ptr] = (u64)NULL; } else { /* In case of SW TSO on 88xx, only last segment will have @@ -696,6 +741,21 @@ static inline void nicvf_set_rxhash(struct net_device *netdev, skb_set_hash(skb, hash, hash_type); } +static inline void nicvf_set_rxtstamp(struct nicvf *nic, struct sk_buff *skb) +{ + u64 ns; + + if (!nic->ptp_clock || !nic->hw_rx_tstamp) + return; + + /* The first 8 bytes is the timestamp */ + ns = cavium_ptp_tstamp2time(nic->ptp_clock, + be64_to_cpu(*(u64 *)skb->data)); + skb_hwtstamps(skb)->hwtstamp = ns_to_ktime(ns); + + __skb_pull(skb, 8); +} + static void nicvf_rcv_pkt_handler(struct net_device *netdev, struct napi_struct *napi, struct cqe_rx_t *cqe_rx, struct snd_queue *sq) @@ -746,6 +806,7 @@ static void nicvf_rcv_pkt_handler(struct net_device *netdev, return; } + nicvf_set_rxtstamp(nic, skb); nicvf_set_rxhash(netdev, cqe_rx, skb); skb_record_rx_queue(skb, rq_idx); @@ -820,10 +881,12 @@ static int nicvf_cq_intr_handler(struct net_device *netdev, u8 cq_idx, &tx_pkts, &tx_bytes); tx_done++; break; + case CQE_TYPE_SEND_PTP: + nicvf_snd_ptp_handler(netdev, (void *)cq_desc); + break; case CQE_TYPE_INVALID: case CQE_TYPE_RX_SPLIT: case CQE_TYPE_RX_TCP: - case CQE_TYPE_SEND_PTP: /* Ignore for now */ break; } @@ -1319,12 +1382,28 @@ int nicvf_stop(struct net_device *netdev) nicvf_free_cq_poll(nic); + /* Free any pending SKB saved to receive timestamp */ + if (nic->ptp_skb) { + dev_kfree_skb_any(nic->ptp_skb); + nic->ptp_skb = NULL; + } + /* Clear multiqset info */ nic->pnicvf = nic; return 0; } +static int nicvf_config_hw_rx_tstamp(struct nicvf *nic, bool enable) +{ + union nic_mbx mbx = {}; + + mbx.ptp.msg = NIC_MBOX_MSG_PTP_CFG; + mbx.ptp.enable = enable; + + return nicvf_send_msg_to_pf(nic, &mbx); +} + static int nicvf_update_hw_max_frs(struct nicvf *nic, int mtu) { union nic_mbx mbx = {}; @@ -1394,6 +1473,12 @@ int nicvf_open(struct net_device *netdev) if (nic->sqs_mode) nicvf_get_primary_vf_struct(nic); + /* Configure PTP timestamp */ + if (nic->ptp_clock) + nicvf_config_hw_rx_tstamp(nic, nic->hw_rx_tstamp); + atomic_set(&nic->tx_ptp_skbs, 0); + nic->ptp_skb = NULL; + /* Configure receive side scaling and MTU */ if (!nic->sqs_mode) { nicvf_rss_init(nic); @@ -1820,6 +1905,77 @@ static void nicvf_xdp_flush(struct net_device *dev) return; } +int nicvf_config_hwtstamp(struct net_device *netdev, struct ifreq *ifr) +{ + struct hwtstamp_config config; + struct nicvf *nic = netdev_priv(netdev); + + if (!nic->ptp_clock) + return -ENODEV; + + if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) + return -EFAULT; + + /* reserved for future extensions */ + if (config.flags) + return -EINVAL; + + switch (config.tx_type) { + case HWTSTAMP_TX_OFF: + case HWTSTAMP_TX_ON: + break; + default: + return -ERANGE; + } + + switch (config.rx_filter) { + case HWTSTAMP_FILTER_NONE: + nic->hw_rx_tstamp = false; + break; + case HWTSTAMP_FILTER_ALL: + case HWTSTAMP_FILTER_SOME: + case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + nic->hw_rx_tstamp = true; + config.rx_filter = HWTSTAMP_FILTER_ALL; + break; + default: + return -ERANGE; + } + + if (netif_running(netdev)) { + if (nic->hw_rx_tstamp) + nicvf_config_hw_rx_tstamp(nic, true); + else + nicvf_config_hw_rx_tstamp(nic, false); + } + + if (copy_to_user(ifr->ifr_data, &config, sizeof(config))) + return -EFAULT; + + return 0; +} + +static int nicvf_ioctl(struct net_device *netdev, struct ifreq *req, int cmd) +{ + switch (cmd) { + case SIOCSHWTSTAMP: + return nicvf_config_hwtstamp(netdev, req); + default: + return -EOPNOTSUPP; + } +} + static const struct net_device_ops nicvf_netdev_ops = { .ndo_open = nicvf_open, .ndo_stop = nicvf_stop, @@ -1833,6 +1989,7 @@ static const struct net_device_ops nicvf_netdev_ops = { .ndo_bpf = nicvf_xdp, .ndo_xdp_xmit = nicvf_xdp_xmit, .ndo_xdp_flush = nicvf_xdp_flush, + .ndo_do_ioctl = nicvf_ioctl, }; static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -1842,6 +1999,16 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct nicvf *nic; int err, qcount; u16 sdevid; + struct cavium_ptp *ptp_clock; + + ptp_clock = cavium_ptp_get(); + if (IS_ERR(ptp_clock)) { + if (PTR_ERR(ptp_clock) == -ENODEV) + /* In virtualized environment we proceed without ptp */ + ptp_clock = NULL; + else + return PTR_ERR(ptp_clock); + } err = pci_enable_device(pdev); if (err) { @@ -1896,6 +2063,7 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) */ if (!nic->t88) nic->max_queues *= 2; + nic->ptp_clock = ptp_clock; /* MAP VF's configuration registers */ nic->reg_base = pcim_iomap(pdev, PCI_CFG_REG_BAR_NUM, 0); @@ -2009,6 +2177,7 @@ static void nicvf_remove(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); if (nic->drv_stats) free_percpu(nic->drv_stats); + cavium_ptp_put(nic->ptp_clock); free_netdev(netdev); pci_release_regions(pdev); 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 095c18aeb8d5..9a999c62d6ba 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c @@ -978,6 +978,9 @@ void nicvf_qset_config(struct nicvf *nic, bool enable) qs_cfg->be = 1; #endif qs_cfg->vnic = qs->vnic_id; + /* Enable Tx timestamping capability */ + if (nic->ptp_clock) + qs_cfg->send_tstmp_ena = 1; } nicvf_send_msg_to_pf(nic, &mbx); } @@ -1383,6 +1386,29 @@ nicvf_sq_add_hdr_subdesc(struct nicvf *nic, struct snd_queue *sq, int qentry, hdr->inner_l3_offset = skb_network_offset(skb) - 2; this_cpu_inc(nic->pnicvf->drv_stats->tx_tso); } + + /* Check if timestamp is requested */ + if (!(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) { + skb_tx_timestamp(skb); + return; + } + + /* Tx timestamping not supported along with TSO, so ignore request */ + if (skb_shinfo(skb)->gso_size) + return; + + /* HW supports only a single outstanding packet to timestamp */ + if (!atomic_add_unless(&nic->pnicvf->tx_ptp_skbs, 1, 1)) + return; + + /* Mark the SKB for later reference */ + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; + + /* Finally enable timestamp generation + * Since 'post_cqe' is also set, two CQEs will be posted + * for this packet i.e CQE_TYPE_SEND and CQE_TYPE_SEND_PTP. + */ + hdr->tstmp = 1; } /* 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) } EXPORT_SYMBOL(bgx_lmac_rx_tx_enable); +/* Enables or disables timestamp insertion by BGX for Rx packets */ +void bgx_config_timestamping(int node, int bgx_idx, int lmacid, bool enable) +{ + struct bgx *bgx = get_bgx(node, bgx_idx); + struct lmac *lmac; + u64 csr_offset, cfg; + + if (!bgx) + return; + + lmac = &bgx->lmac[lmacid]; + + if (lmac->lmac_type == BGX_MODE_SGMII || + lmac->lmac_type == BGX_MODE_QSGMII || + lmac->lmac_type == BGX_MODE_RGMII) + csr_offset = BGX_GMP_GMI_RXX_FRM_CTL; + else + csr_offset = BGX_SMUX_RX_FRM_CTL; + + cfg = bgx_reg_read(bgx, lmacid, csr_offset); + + if (enable) + cfg |= BGX_PKT_RX_PTP_EN; + else + cfg &= ~BGX_PKT_RX_PTP_EN; + bgx_reg_write(bgx, lmacid, csr_offset, cfg); +} +EXPORT_SYMBOL(bgx_config_timestamping); + void bgx_lmac_get_pfc(int node, int bgx_idx, int lmacid, void *pause) { 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 @@ #define SPU_DBG_CTL_AN_NONCE_MCT_DIS BIT_ULL(29) #define BGX_SMUX_RX_INT 0x20000 +#define BGX_SMUX_RX_FRM_CTL 0x20020 +#define BGX_PKT_RX_PTP_EN BIT_ULL(12) #define BGX_SMUX_RX_JABBER 0x20030 #define BGX_SMUX_RX_CTL 0x20048 #define SMU_RX_CTL_STATUS (3ull << 0) @@ -172,6 +174,7 @@ #define GMI_PORT_CFG_SPEED_MSB BIT_ULL(8) #define GMI_PORT_CFG_RX_IDLE BIT_ULL(12) #define GMI_PORT_CFG_TX_IDLE BIT_ULL(13) +#define BGX_GMP_GMI_RXX_FRM_CTL 0x38028 #define BGX_GMP_GMI_RXX_JABBER 0x38038 #define BGX_GMP_GMI_TXX_THRESH 0x38210 #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); void bgx_get_lmac_link_state(int node, int bgx_idx, int lmacid, void *status); void bgx_lmac_internal_loopback(int node, int bgx_idx, int lmac_idx, bool enable); +void bgx_config_timestamping(int node, int bgx_idx, int lmacid, bool enable); void bgx_lmac_get_pfc(int node, int bgx_idx, int lmacid, void *pause); void bgx_lmac_set_pfc(int node, int bgx_idx, int lmacid, void *pause); -- 2.15.1 From mboxrd@z Thu Jan 1 00:00:00 1970 From: aleksey.makarov@cavium.com (Aleksey Makarov) Date: Wed, 6 Dec 2017 16:30:58 +0300 Subject: [PATCH net-next v3 2/2] net: thunderx: add timestamping support In-Reply-To: <20171206133100.26436-1-aleksey.makarov@cavium.com> References: <20171206133100.26436-1-aleksey.makarov@cavium.com> Message-ID: <20171206133100.26436-3-aleksey.makarov@cavium.com> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org From: Sunil Goutham 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 Signed-off-by: Aleksey Makarov --- drivers/net/ethernet/cavium/Kconfig | 1 + drivers/net/ethernet/cavium/thunder/nic.h | 15 ++ drivers/net/ethernet/cavium/thunder/nic_main.c | 58 ++++++- drivers/net/ethernet/cavium/thunder/nic_reg.h | 1 + .../net/ethernet/cavium/thunder/nicvf_ethtool.c | 29 +++- drivers/net/ethernet/cavium/thunder/nicvf_main.c | 173 ++++++++++++++++++++- drivers/net/ethernet/cavium/thunder/nicvf_queues.c | 26 ++++ drivers/net/ethernet/cavium/thunder/thunder_bgx.c | 29 ++++ drivers/net/ethernet/cavium/thunder/thunder_bgx.h | 4 + 9 files changed, 330 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/cavium/Kconfig b/drivers/net/ethernet/cavium/Kconfig index fabe0ffcc2d4..6d003cbe197c 100644 --- a/drivers/net/ethernet/cavium/Kconfig +++ b/drivers/net/ethernet/cavium/Kconfig @@ -27,6 +27,7 @@ config THUNDER_NIC_PF config THUNDER_NIC_VF tristate "Thunder Virtual function driver" + select CAVIUM_PTP depends on 64BIT ---help--- 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..204b234beb9d 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 { struct u64_stats_sync syncp; }; +struct cavium_ptp; + struct nicvf { struct nicvf *pnicvf; struct net_device *netdev; @@ -312,6 +314,12 @@ struct nicvf { struct tasklet_struct qs_err_task; struct work_struct reset_task; + /* PTP timestamp */ + struct cavium_ptp *ptp_clock; + bool hw_rx_tstamp; + struct sk_buff *ptp_skb; + atomic_t tx_ptp_skbs; + /* Interrupt coalescing settings */ u32 cq_coalesce_usecs; u32 msg_enable; @@ -371,6 +379,7 @@ struct nicvf { #define NIC_MBOX_MSG_LOOPBACK 0x16 /* Set interface in loopback */ #define NIC_MBOX_MSG_RESET_STAT_COUNTER 0x17 /* Reset statistics counters */ #define NIC_MBOX_MSG_PFC 0x18 /* Pause frame control */ +#define NIC_MBOX_MSG_PTP_CFG 0x19 /* HW packet timestamp */ #define NIC_MBOX_MSG_CFG_DONE 0xF0 /* VF configuration done */ #define NIC_MBOX_MSG_SHUTDOWN 0xF1 /* VF is being shutdown */ @@ -521,6 +530,11 @@ struct pfc { u8 fc_tx; }; +struct set_ptp { + u8 msg; + bool enable; +}; + /* 128 bit shared memory between PF and each VF */ union nic_mbx { struct { u8 msg; } msg; @@ -540,6 +554,7 @@ union nic_mbx { struct set_loopback lbk; struct reset_stat_cfg reset_stat; struct pfc pfc; + struct set_ptp ptp; }; #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..4c1c5414a162 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) /* Enable backpressure */ nic_reg_write(nic, NIC_PF_BP_CFG, (1ULL << 6) | 0x03); - /* TNS and TNS bypass modes are present only on 88xx */ + /* TNS and TNS bypass modes are present only on 88xx + * Also offset of this CSR has changed in 81xx and 83xx. + */ if (nic->pdev->subsystem_device == PCI_SUBSYS_DEVID_88XX_NIC_PF) { /* Disable TNS mode on both interfaces */ nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG, - (NIC_TNS_BYPASS_MODE << 7) | BGX0_BLOCK); + (NIC_TNS_BYPASS_MODE << 7) | + BGX0_BLOCK | (1ULL << 16)); nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG | (1 << 8), - (NIC_TNS_BYPASS_MODE << 7) | BGX1_BLOCK); + (NIC_TNS_BYPASS_MODE << 7) | + BGX1_BLOCK | (1ULL << 16)); + } else { + /* Configure timestamp generation timeout to 10us */ + for (i = 0; i < nic->hw->bgx_cnt; i++) + nic_reg_write(nic, NIC_PF_INTFX_SEND_CFG | (i << 3), + (1ULL << 16)); } nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG, @@ -880,6 +889,46 @@ static void nic_pause_frame(struct nicpf *nic, int vf, struct pfc *cfg) } } +/* Enable or disable HW timestamping by BGX for pkts received on a LMAC */ +static void nic_config_timestamp(struct nicpf *nic, int vf, struct set_ptp *ptp) +{ + struct pkind_cfg *pkind; + u8 lmac, bgx_idx; + u64 pkind_val, pkind_idx; + + if (vf >= nic->num_vf_en) + return; + + bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); + lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); + + pkind_idx = lmac + bgx_idx * MAX_LMAC_PER_BGX; + pkind_val = nic_reg_read(nic, NIC_PF_PKIND_0_15_CFG | (pkind_idx << 3)); + pkind = (struct pkind_cfg *)&pkind_val; + + if (ptp->enable && !pkind->hdr_sl) { + /* Skiplen to exclude 8byte timestamp while parsing pkt + * If not configured, will result in L2 errors. + */ + pkind->hdr_sl = 4; + /* Adjust max packet length allowed */ + pkind->maxlen += (pkind->hdr_sl * 2); + bgx_config_timestamping(nic->node, bgx_idx, lmac, true); + nic_reg_write(nic, + NIC_PF_RX_ETYPE_0_7 | (1 << 3), + (ETYPE_ALG_ENDPARSE << 16) | ETH_P_1588); + } else if (!ptp->enable && pkind->hdr_sl) { + pkind->maxlen -= (pkind->hdr_sl * 2); + pkind->hdr_sl = 0; + bgx_config_timestamping(nic->node, bgx_idx, lmac, false); + nic_reg_write(nic, + NIC_PF_RX_ETYPE_0_7 | (1 << 3), + (1ULL << 16) | ETH_P_8021Q); /* reset value */ + } + + nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG | (pkind_idx << 3), pkind_val); +} + /* Interrupt handler to handle mailbox messages from VFs */ static void nic_handle_mbx_intr(struct nicpf *nic, int vf) { @@ -1022,6 +1071,9 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf) case NIC_MBOX_MSG_PFC: nic_pause_frame(nic, vf, &mbx.pfc); goto unlock; + case NIC_MBOX_MSG_PTP_CFG: + nic_config_timestamp(nic, vf, &mbx.ptp); + break; default: dev_err(&nic->pdev->dev, "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 @@ #define NIC_PF_ECC3_DBE_INT_W1S (0x2708) #define NIC_PF_ECC3_DBE_ENA_W1C (0x2710) #define NIC_PF_ECC3_DBE_ENA_W1S (0x2718) +#define NIC_PF_INTFX_SEND_CFG (0x4000) #define NIC_PF_MCAM_0_191_ENA (0x100000) #define NIC_PF_MCAM_0_191_M_0_5_DATA (0x110000) #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 @@ /* ETHTOOL Support for VNIC_VF Device*/ #include +#include #include "nic_reg.h" #include "nic.h" #include "nicvf_queues.h" #include "q_struct.h" #include "thunder_bgx.h" +#include "../common/cavium_ptp.h" #define DRV_NAME "thunder-nicvf" #define DRV_VERSION "1.0" @@ -824,6 +826,31 @@ static int nicvf_set_pauseparam(struct net_device *dev, return 0; } +static int nicvf_get_ts_info(struct net_device *netdev, + struct ethtool_ts_info *info) +{ + struct nicvf *nic = netdev_priv(netdev); + + if (!nic->ptp_clock) + return ethtool_op_get_ts_info(netdev, info); + + info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_RX_SOFTWARE | + SOF_TIMESTAMPING_SOFTWARE | + SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; + + info->phc_index = cavium_ptp_clock_index(nic->ptp_clock); + + info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); + + info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | + (1 << HWTSTAMP_FILTER_ALL); + + return 0; +} + static const struct ethtool_ops nicvf_ethtool_ops = { .get_link = nicvf_get_link, .get_drvinfo = nicvf_get_drvinfo, @@ -847,7 +874,7 @@ static const struct ethtool_ops nicvf_ethtool_ops = { .set_channels = nicvf_set_channels, .get_pauseparam = nicvf_get_pauseparam, .set_pauseparam = nicvf_set_pauseparam, - .get_ts_info = ethtool_op_get_ts_info, + .get_ts_info = nicvf_get_ts_info, .get_link_ksettings = nicvf_get_link_ksettings, }; diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c index 52b3a6044f85..487d09a32b6d 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c @@ -20,11 +20,13 @@ #include #include #include +#include #include "nic_reg.h" #include "nic.h" #include "nicvf_queues.h" #include "thunder_bgx.h" +#include "../common/cavium_ptp.h" #define DRV_NAME "thunder-nicvf" #define DRV_VERSION "1.0" @@ -601,6 +603,44 @@ static inline bool nicvf_xdp_rx(struct nicvf *nic, struct bpf_prog *prog, return false; } +static void nicvf_snd_ptp_handler(struct net_device *netdev, + struct cqe_send_t *cqe_tx) +{ + struct nicvf *nic = netdev_priv(netdev); + struct skb_shared_hwtstamps ts; + u64 ns; + + nic = nic->pnicvf; + + /* Sync for 'ptp_skb' */ + smp_rmb(); + + /* New timestamp request can be queued now */ + atomic_set(&nic->tx_ptp_skbs, 0); + + /* Check for timestamp requested skb */ + if (!nic->ptp_skb) + return; + + /* Check if timestamping is timedout, which is set to 10us */ + if (cqe_tx->send_status == CQ_TX_ERROP_TSTMP_TIMEOUT || + cqe_tx->send_status == CQ_TX_ERROP_TSTMP_CONFLICT) + goto no_tstamp; + + /* Get the timestamp */ + memset(&ts, 0, sizeof(ts)); + ns = cavium_ptp_tstamp2time(nic->ptp_clock, cqe_tx->ptp_timestamp); + ts.hwtstamp = ns_to_ktime(ns); + skb_tstamp_tx(nic->ptp_skb, &ts); + +no_tstamp: + /* Free the original skb */ + dev_kfree_skb_any(nic->ptp_skb); + nic->ptp_skb = NULL; + /* Sync 'ptp_skb' */ + smp_wmb(); +} + static void nicvf_snd_pkt_handler(struct net_device *netdev, struct cqe_send_t *cqe_tx, int budget, int *subdesc_cnt, @@ -657,7 +697,12 @@ static void nicvf_snd_pkt_handler(struct net_device *netdev, prefetch(skb); (*tx_pkts)++; *tx_bytes += skb->len; - napi_consume_skb(skb, budget); + /* If timestamp is requested for this skb, don't free it */ + if (skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS && + !nic->pnicvf->ptp_skb) + nic->pnicvf->ptp_skb = skb; + else + napi_consume_skb(skb, budget); sq->skbuff[cqe_tx->sqe_ptr] = (u64)NULL; } else { /* In case of SW TSO on 88xx, only last segment will have @@ -696,6 +741,21 @@ static inline void nicvf_set_rxhash(struct net_device *netdev, skb_set_hash(skb, hash, hash_type); } +static inline void nicvf_set_rxtstamp(struct nicvf *nic, struct sk_buff *skb) +{ + u64 ns; + + if (!nic->ptp_clock || !nic->hw_rx_tstamp) + return; + + /* The first 8 bytes is the timestamp */ + ns = cavium_ptp_tstamp2time(nic->ptp_clock, + be64_to_cpu(*(u64 *)skb->data)); + skb_hwtstamps(skb)->hwtstamp = ns_to_ktime(ns); + + __skb_pull(skb, 8); +} + static void nicvf_rcv_pkt_handler(struct net_device *netdev, struct napi_struct *napi, struct cqe_rx_t *cqe_rx, struct snd_queue *sq) @@ -746,6 +806,7 @@ static void nicvf_rcv_pkt_handler(struct net_device *netdev, return; } + nicvf_set_rxtstamp(nic, skb); nicvf_set_rxhash(netdev, cqe_rx, skb); skb_record_rx_queue(skb, rq_idx); @@ -820,10 +881,12 @@ static int nicvf_cq_intr_handler(struct net_device *netdev, u8 cq_idx, &tx_pkts, &tx_bytes); tx_done++; break; + case CQE_TYPE_SEND_PTP: + nicvf_snd_ptp_handler(netdev, (void *)cq_desc); + break; case CQE_TYPE_INVALID: case CQE_TYPE_RX_SPLIT: case CQE_TYPE_RX_TCP: - case CQE_TYPE_SEND_PTP: /* Ignore for now */ break; } @@ -1319,12 +1382,28 @@ int nicvf_stop(struct net_device *netdev) nicvf_free_cq_poll(nic); + /* Free any pending SKB saved to receive timestamp */ + if (nic->ptp_skb) { + dev_kfree_skb_any(nic->ptp_skb); + nic->ptp_skb = NULL; + } + /* Clear multiqset info */ nic->pnicvf = nic; return 0; } +static int nicvf_config_hw_rx_tstamp(struct nicvf *nic, bool enable) +{ + union nic_mbx mbx = {}; + + mbx.ptp.msg = NIC_MBOX_MSG_PTP_CFG; + mbx.ptp.enable = enable; + + return nicvf_send_msg_to_pf(nic, &mbx); +} + static int nicvf_update_hw_max_frs(struct nicvf *nic, int mtu) { union nic_mbx mbx = {}; @@ -1394,6 +1473,12 @@ int nicvf_open(struct net_device *netdev) if (nic->sqs_mode) nicvf_get_primary_vf_struct(nic); + /* Configure PTP timestamp */ + if (nic->ptp_clock) + nicvf_config_hw_rx_tstamp(nic, nic->hw_rx_tstamp); + atomic_set(&nic->tx_ptp_skbs, 0); + nic->ptp_skb = NULL; + /* Configure receive side scaling and MTU */ if (!nic->sqs_mode) { nicvf_rss_init(nic); @@ -1820,6 +1905,77 @@ static void nicvf_xdp_flush(struct net_device *dev) return; } +int nicvf_config_hwtstamp(struct net_device *netdev, struct ifreq *ifr) +{ + struct hwtstamp_config config; + struct nicvf *nic = netdev_priv(netdev); + + if (!nic->ptp_clock) + return -ENODEV; + + if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) + return -EFAULT; + + /* reserved for future extensions */ + if (config.flags) + return -EINVAL; + + switch (config.tx_type) { + case HWTSTAMP_TX_OFF: + case HWTSTAMP_TX_ON: + break; + default: + return -ERANGE; + } + + switch (config.rx_filter) { + case HWTSTAMP_FILTER_NONE: + nic->hw_rx_tstamp = false; + break; + case HWTSTAMP_FILTER_ALL: + case HWTSTAMP_FILTER_SOME: + case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + nic->hw_rx_tstamp = true; + config.rx_filter = HWTSTAMP_FILTER_ALL; + break; + default: + return -ERANGE; + } + + if (netif_running(netdev)) { + if (nic->hw_rx_tstamp) + nicvf_config_hw_rx_tstamp(nic, true); + else + nicvf_config_hw_rx_tstamp(nic, false); + } + + if (copy_to_user(ifr->ifr_data, &config, sizeof(config))) + return -EFAULT; + + return 0; +} + +static int nicvf_ioctl(struct net_device *netdev, struct ifreq *req, int cmd) +{ + switch (cmd) { + case SIOCSHWTSTAMP: + return nicvf_config_hwtstamp(netdev, req); + default: + return -EOPNOTSUPP; + } +} + static const struct net_device_ops nicvf_netdev_ops = { .ndo_open = nicvf_open, .ndo_stop = nicvf_stop, @@ -1833,6 +1989,7 @@ static const struct net_device_ops nicvf_netdev_ops = { .ndo_bpf = nicvf_xdp, .ndo_xdp_xmit = nicvf_xdp_xmit, .ndo_xdp_flush = nicvf_xdp_flush, + .ndo_do_ioctl = nicvf_ioctl, }; static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -1842,6 +1999,16 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct nicvf *nic; int err, qcount; u16 sdevid; + struct cavium_ptp *ptp_clock; + + ptp_clock = cavium_ptp_get(); + if (IS_ERR(ptp_clock)) { + if (PTR_ERR(ptp_clock) == -ENODEV) + /* In virtualized environment we proceed without ptp */ + ptp_clock = NULL; + else + return PTR_ERR(ptp_clock); + } err = pci_enable_device(pdev); if (err) { @@ -1896,6 +2063,7 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) */ if (!nic->t88) nic->max_queues *= 2; + nic->ptp_clock = ptp_clock; /* MAP VF's configuration registers */ nic->reg_base = pcim_iomap(pdev, PCI_CFG_REG_BAR_NUM, 0); @@ -2009,6 +2177,7 @@ static void nicvf_remove(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); if (nic->drv_stats) free_percpu(nic->drv_stats); + cavium_ptp_put(nic->ptp_clock); free_netdev(netdev); pci_release_regions(pdev); 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 095c18aeb8d5..9a999c62d6ba 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c @@ -978,6 +978,9 @@ void nicvf_qset_config(struct nicvf *nic, bool enable) qs_cfg->be = 1; #endif qs_cfg->vnic = qs->vnic_id; + /* Enable Tx timestamping capability */ + if (nic->ptp_clock) + qs_cfg->send_tstmp_ena = 1; } nicvf_send_msg_to_pf(nic, &mbx); } @@ -1383,6 +1386,29 @@ nicvf_sq_add_hdr_subdesc(struct nicvf *nic, struct snd_queue *sq, int qentry, hdr->inner_l3_offset = skb_network_offset(skb) - 2; this_cpu_inc(nic->pnicvf->drv_stats->tx_tso); } + + /* Check if timestamp is requested */ + if (!(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) { + skb_tx_timestamp(skb); + return; + } + + /* Tx timestamping not supported along with TSO, so ignore request */ + if (skb_shinfo(skb)->gso_size) + return; + + /* HW supports only a single outstanding packet to timestamp */ + if (!atomic_add_unless(&nic->pnicvf->tx_ptp_skbs, 1, 1)) + return; + + /* Mark the SKB for later reference */ + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; + + /* Finally enable timestamp generation + * Since 'post_cqe' is also set, two CQEs will be posted + * for this packet i.e CQE_TYPE_SEND and CQE_TYPE_SEND_PTP. + */ + hdr->tstmp = 1; } /* 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) } EXPORT_SYMBOL(bgx_lmac_rx_tx_enable); +/* Enables or disables timestamp insertion by BGX for Rx packets */ +void bgx_config_timestamping(int node, int bgx_idx, int lmacid, bool enable) +{ + struct bgx *bgx = get_bgx(node, bgx_idx); + struct lmac *lmac; + u64 csr_offset, cfg; + + if (!bgx) + return; + + lmac = &bgx->lmac[lmacid]; + + if (lmac->lmac_type == BGX_MODE_SGMII || + lmac->lmac_type == BGX_MODE_QSGMII || + lmac->lmac_type == BGX_MODE_RGMII) + csr_offset = BGX_GMP_GMI_RXX_FRM_CTL; + else + csr_offset = BGX_SMUX_RX_FRM_CTL; + + cfg = bgx_reg_read(bgx, lmacid, csr_offset); + + if (enable) + cfg |= BGX_PKT_RX_PTP_EN; + else + cfg &= ~BGX_PKT_RX_PTP_EN; + bgx_reg_write(bgx, lmacid, csr_offset, cfg); +} +EXPORT_SYMBOL(bgx_config_timestamping); + void bgx_lmac_get_pfc(int node, int bgx_idx, int lmacid, void *pause) { 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 @@ #define SPU_DBG_CTL_AN_NONCE_MCT_DIS BIT_ULL(29) #define BGX_SMUX_RX_INT 0x20000 +#define BGX_SMUX_RX_FRM_CTL 0x20020 +#define BGX_PKT_RX_PTP_EN BIT_ULL(12) #define BGX_SMUX_RX_JABBER 0x20030 #define BGX_SMUX_RX_CTL 0x20048 #define SMU_RX_CTL_STATUS (3ull << 0) @@ -172,6 +174,7 @@ #define GMI_PORT_CFG_SPEED_MSB BIT_ULL(8) #define GMI_PORT_CFG_RX_IDLE BIT_ULL(12) #define GMI_PORT_CFG_TX_IDLE BIT_ULL(13) +#define BGX_GMP_GMI_RXX_FRM_CTL 0x38028 #define BGX_GMP_GMI_RXX_JABBER 0x38038 #define BGX_GMP_GMI_TXX_THRESH 0x38210 #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); void bgx_get_lmac_link_state(int node, int bgx_idx, int lmacid, void *status); void bgx_lmac_internal_loopback(int node, int bgx_idx, int lmac_idx, bool enable); +void bgx_config_timestamping(int node, int bgx_idx, int lmacid, bool enable); void bgx_lmac_get_pfc(int node, int bgx_idx, int lmacid, void *pause); void bgx_lmac_set_pfc(int node, int bgx_idx, int lmacid, void *pause); -- 2.15.1