From patchwork Fri Aug 30 00:46:21 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1155583 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="Qd/4PsDP"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 46KLQj74r4z9sNC for ; Fri, 30 Aug 2019 10:46:53 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727398AbfH3Aqw (ORCPT ); Thu, 29 Aug 2019 20:46:52 -0400 Received: from mail-wm1-f65.google.com ([209.85.128.65]:53175 "EHLO mail-wm1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727041AbfH3Aqv (ORCPT ); Thu, 29 Aug 2019 20:46:51 -0400 Received: by mail-wm1-f65.google.com with SMTP id t17so5496032wmi.2 for ; Thu, 29 Aug 2019 17:46:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=o7Uoqn7wDIBSyY2TE0cNLF6RFruoF5TerjP42Rz6Uf4=; b=Qd/4PsDPeUv+dZoCdFelmiLjsz4fZBtLpCF4Cx8mddPP8OJlO1+t+2mI6FpYSG9dvA VcQbaxpA7XLHmURfpXADD9ja5O5q8twqsKPgqD2iESZk2CVm3eWnPb1WJ9dTbRgUaQNb pLSZ6YEEB1iBp9H6hGD6XdbRY+lMeCUfeIDVXZBqbTMB4alF9DR4nt00XaGDCUGKm5f8 j0TM2wcR8F3WChBifpm7CWV0BljZsxKbbKnGCtAAhKCjezX6qEQMVMD7vbXdL4BNV/Yt yeVipeYoSQuQ2GyvoluBcydDebpov2BKWNt5l39ysqep1cdxkEESQg/3VCIIanBuWWO6 RswQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=o7Uoqn7wDIBSyY2TE0cNLF6RFruoF5TerjP42Rz6Uf4=; b=UsJf8g0XyADGgc54ltNeGorNsn3lW6U/NcMs5hz2RCBIiMj24IzBq+SOqrN5hsxDDs vQbhsB478kfMH1aUdDVAoBNt/ge6OBNpEfuFakmgVT6KxiDQ/uHuBpnuPf7AxHjBtD9F N3mFGhUpWu7s2eM2lp271QCHn6Ka8bkb8hzCd2i5tUxfADMwydlWfN8DfsU5O496AgqL TezRQNUrWlS9CjomCqlx52mSe6oCZpPTkTzBAboi1O5EFHKu6ICVEOVhYbhOliMBSD4s qBksF9sjbdUc7T57HJPFhhIuuv6WJDxDJwAM8uyo7NyQreiS6AcTeSw8u6z7/Gmkhcvu Lp1Q== X-Gm-Message-State: APjAAAUG0crtIhTYHh00KPHBfaBjjiCFb1ILtXw7eRs5UlrNq96LgFGu rAP/wxlgkXqi+Z/yIOvvjkQUC5mqtY8= X-Google-Smtp-Source: APXvYqysdOparD2kENGOGXSA8kdq19pIrnIq4kh0f0O+IMv9vcs9MsVNTERnjLCgVZtiCpjI8bAW2Q== X-Received: by 2002:a1c:eb06:: with SMTP id j6mr15356522wmh.76.1567126009275; Thu, 29 Aug 2019 17:46:49 -0700 (PDT) Received: from localhost.localdomain ([86.126.25.232]) by smtp.gmail.com with ESMTPSA id y3sm9298442wmg.2.2019.08.29.17.46.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Aug 2019 17:46:48 -0700 (PDT) From: Vladimir Oltean To: f.fainelli@gmail.com, vivien.didelot@gmail.com, andrew@lunn.ch, davem@davemloft.net, vinicius.gomes@intel.com, vedang.patel@intel.com, richardcochran@gmail.com Cc: weifeng.voon@intel.com, jiri@mellanox.com, m-karicheri2@ti.com, Jose.Abreu@synopsys.com, ilias.apalodimas@linaro.org, --to=jhs@mojatatu.com, --to=xiyou.wangcong@gmail.com, netdev@vger.kernel.org, Vladimir Oltean Subject: [RFC PATCH v2 net-next 01/15] net: dsa: sja1105: Change the PTP command access pattern Date: Fri, 30 Aug 2019 03:46:21 +0300 Message-Id: <20190830004635.24863-2-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190830004635.24863-1-olteanv@gmail.com> References: <20190830004635.24863-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org The PTP command register contains enable bits for: - Putting the 64-bit PTPCLKVAL register in add/subtract or write mode - Taking timestamps off of the corrected vs free-running clock - Starting/stopping the TTEthernet scheduling - Starting/stopping PPS output - Resetting the switch When a command needs to be issued (e.g. "change the PTPCLKVAL from write mode to add/subtract mode"), one cannot simply write to the command register setting the PTPCLKADD bit to 1, because that would zeroize the other settings. One also cannot do a read-modify-write (that would be too easy for this hardware) because not all bits of the command register are readable over SPI. So this leaves us with the only option of keeping the value of the PTP command register in the driver, and operating on that. Signed-off-by: Vladimir Oltean --- drivers/net/dsa/sja1105/sja1105.h | 5 +++++ drivers/net/dsa/sja1105/sja1105_ptp.c | 6 +----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index 78094db32622..d8a92646e80a 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -50,6 +50,10 @@ struct sja1105_regs { u64 qlevel[SJA1105_NUM_PORTS]; }; +struct sja1105_ptp_cmd { + u64 resptp; /* reset */ +}; + struct sja1105_info { u64 device_id; /* Needed for distinction between P and R, and between Q and S @@ -89,6 +93,7 @@ struct sja1105_private { struct spi_device *spidev; struct dsa_switch *ds; struct sja1105_port ports[SJA1105_NUM_PORTS]; + struct sja1105_ptp_cmd ptp_cmd; struct ptp_clock_info ptp_caps; struct ptp_clock *clock; /* The cycle counter translates the PTP timestamps (based on diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.c b/drivers/net/dsa/sja1105/sja1105_ptp.c index d8e8dd59f3d1..07374ba6b9be 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.c +++ b/drivers/net/dsa/sja1105/sja1105_ptp.c @@ -54,10 +54,6 @@ #define cc_to_sja1105(d) container_of((d), struct sja1105_private, tstamp_cc) #define dw_to_sja1105(d) container_of((d), struct sja1105_private, refresh_work) -struct sja1105_ptp_cmd { - u64 resptp; /* reset */ -}; - int sja1105_get_ts_info(struct dsa_switch *ds, int port, struct ethtool_ts_info *info) { @@ -218,8 +214,8 @@ int sja1105_ptpegr_ts_poll(struct sja1105_private *priv, int port, u64 *ts) int sja1105_ptp_reset(struct sja1105_private *priv) { + struct sja1105_ptp_cmd cmd = priv->ptp_cmd; struct dsa_switch *ds = priv->ds; - struct sja1105_ptp_cmd cmd = {0}; int rc; mutex_lock(&priv->ptp_lock); From patchwork Fri Aug 30 00:46:22 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1155584 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="pJes8jHo"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 46KLQm2rMSz9sN6 for ; Fri, 30 Aug 2019 10:46:56 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727486AbfH3Aqz (ORCPT ); Thu, 29 Aug 2019 20:46:55 -0400 Received: from mail-wr1-f67.google.com ([209.85.221.67]:38481 "EHLO mail-wr1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727318AbfH3Aqw (ORCPT ); Thu, 29 Aug 2019 20:46:52 -0400 Received: by mail-wr1-f67.google.com with SMTP id e16so5207755wro.5 for ; Thu, 29 Aug 2019 17:46:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=L/28Tt0OL3o5o3i1aVj6mT3MYze2NgArhQFp6Loydec=; b=pJes8jHo51ZQdUaDTmqyD/qLu+4dAid00I/1nyRGwtIeGCAcPUiDKrzlJNZyt86wCn 69yq3vFSTxe9CzO5230Jp4JlrrR/hpzEt1n56x3MknMq/2fYM+Rr0eIdxiFUVZhgAywW /BGga2R2yzZ0K+kzZ1esveP4mMaL9a/NC+/5PqYUbXvTrUvXN5RLe6izlvCti9iIer0M rAM5Pr5plohIH2eGJR/5jCY7p3ESoOHR5TODArV7CzEqsTWortwws1zfWJrmYNmA0GS4 +oNYorMn8b7AtKQq2AgOjnNbIbXp4B4Ul44B4qUnkBm7VSYIazq1E9X1BdPb/vOzUvgj fDIg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=L/28Tt0OL3o5o3i1aVj6mT3MYze2NgArhQFp6Loydec=; b=eQYSNNToLHI0WDmrCPcb35l/yF72pMskPEKVizbfVfzcfzBMap1cV4ZLWdLqxWmGS6 gGpYwz5vOThTjcxXe5x6fGHqWQb/5bF+WyzcWz1d7xDWIu3jv1FXuTnOVdEso6uSY5yC HFxYyClQ499DTGYiJ8tWenJGHCvLgaznCUVxE7c6khPedI2Cb6iiOAzppuCrTG6MSMBb nSOWcHDp6Awaby5ff0BtG2i/IaJd5fbYW/92WqyDFJY6HvMJ31MxcGYPLjzbsTAyoOAw UjGhlMurIusYFYbYDG2tbfgcg3xaQknWF8VObWNqb4mW6ir/+WFZHR95sTlx6RlrblsV /ZrQ== X-Gm-Message-State: APjAAAWZH2lVaAPWBofwmX9Ubi+w+DVgUuDFHz8xFgAhx+oCddpPuPDt MSJdOuacgTGTkJ5yOzPjMbk= X-Google-Smtp-Source: APXvYqyEl+2gcbsmX1yJFHeH5wN+SlAxpaskmDw6zijNjGJS80g1crjIl7IDHAxs1cvsCkv+yRM9HQ== X-Received: by 2002:adf:eb8c:: with SMTP id t12mr13866127wrn.84.1567126010633; Thu, 29 Aug 2019 17:46:50 -0700 (PDT) Received: from localhost.localdomain ([86.126.25.232]) by smtp.gmail.com with ESMTPSA id y3sm9298442wmg.2.2019.08.29.17.46.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Aug 2019 17:46:50 -0700 (PDT) From: Vladimir Oltean To: f.fainelli@gmail.com, vivien.didelot@gmail.com, andrew@lunn.ch, davem@davemloft.net, vinicius.gomes@intel.com, vedang.patel@intel.com, richardcochran@gmail.com Cc: weifeng.voon@intel.com, jiri@mellanox.com, m-karicheri2@ti.com, Jose.Abreu@synopsys.com, ilias.apalodimas@linaro.org, --to=jhs@mojatatu.com, --to=xiyou.wangcong@gmail.com, netdev@vger.kernel.org, Vladimir Oltean Subject: [RFC PATCH v2 net-next 02/15] net: dsa: sja1105: Get rid of global declaration of struct ptp_clock_info Date: Fri, 30 Aug 2019 03:46:22 +0300 Message-Id: <20190830004635.24863-3-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190830004635.24863-1-olteanv@gmail.com> References: <20190830004635.24863-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org We need priv->ptp_caps to hold a structure and not just a pointer, because we use container_of in the various PTP callbacks. Therefore, the sja1105_ptp_caps structure declared in the global memory of the driver serves no further purpose after copying it into priv->ptp_caps. So just populate priv->ptp_caps with the needed operations and remove sja1105_ptp_caps. Signed-off-by: Vladimir Oltean --- drivers/net/dsa/sja1105/sja1105_ptp.c | 29 +++++++++++++-------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.c b/drivers/net/dsa/sja1105/sja1105_ptp.c index 07374ba6b9be..13f9f5799e46 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.c +++ b/drivers/net/dsa/sja1105/sja1105_ptp.c @@ -343,29 +343,28 @@ static void sja1105_ptp_overflow_check(struct work_struct *work) schedule_delayed_work(&priv->refresh_work, SJA1105_REFRESH_INTERVAL); } -static const struct ptp_clock_info sja1105_ptp_caps = { - .owner = THIS_MODULE, - .name = "SJA1105 PHC", - .adjfine = sja1105_ptp_adjfine, - .adjtime = sja1105_ptp_adjtime, - .gettime64 = sja1105_ptp_gettime, - .settime64 = sja1105_ptp_settime, - .max_adj = SJA1105_MAX_ADJ_PPB, -}; - int sja1105_ptp_clock_register(struct sja1105_private *priv) { struct dsa_switch *ds = priv->ds; /* Set up the cycle counter */ priv->tstamp_cc = (struct cyclecounter) { - .read = sja1105_ptptsclk_read, - .mask = CYCLECOUNTER_MASK(64), - .shift = SJA1105_CC_SHIFT, - .mult = SJA1105_CC_MULT, + .read = sja1105_ptptsclk_read, + .mask = CYCLECOUNTER_MASK(64), + .shift = SJA1105_CC_SHIFT, + .mult = SJA1105_CC_MULT, + }; + priv->ptp_caps = (struct ptp_clock_info) { + .owner = THIS_MODULE, + .name = "SJA1105 PHC", + .adjfine = sja1105_ptp_adjfine, + .adjtime = sja1105_ptp_adjtime, + .gettime64 = sja1105_ptp_gettime, + .settime64 = sja1105_ptp_settime, + .max_adj = SJA1105_MAX_ADJ_PPB, }; + mutex_init(&priv->ptp_lock); - priv->ptp_caps = sja1105_ptp_caps; priv->clock = ptp_clock_register(&priv->ptp_caps, ds->dev); if (IS_ERR_OR_NULL(priv->clock)) From patchwork Fri Aug 30 00:46:23 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1155585 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="fuU9YGrJ"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 46KLQp1XSQz9sN6 for ; Fri, 30 Aug 2019 10:46:58 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727544AbfH3Aq5 (ORCPT ); Thu, 29 Aug 2019 20:46:57 -0400 Received: from mail-wm1-f68.google.com ([209.85.128.68]:54772 "EHLO mail-wm1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727401AbfH3Aqy (ORCPT ); Thu, 29 Aug 2019 20:46:54 -0400 Received: by mail-wm1-f68.google.com with SMTP id k2so4056879wmj.4 for ; Thu, 29 Aug 2019 17:46:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=hGWyi0Od8Y1ErBJF0hpItNPFaZTbueW2FEapaslMToY=; b=fuU9YGrJfPd8iGLL5RjHtx856Ys9usHh6VUm1TVXbmU+W4ZDPRp9m/vjcyc8OVxiOA 5ZNs2v3/WK2L6r+cFIaJAMFYzPvvbRi2vDt84Ih+MIqC3zMBPCXNIjrfsxAAZdYXfv7Y GmN1Tox3QX8KJno8MlSPKQaztfE15IA7hAYrn8y3/67lp1k1M5cE7D116/HdDsDO7sa8 bTnnJI594u74bSR0GJkDhy5blCPDKwwrZW8oPBCJiJ1qNZsTWmt90vZfxfIpZx+xyiCt mTjpV4n5pVLN/S7eyGTn95tkIw+jtGReDGP+AXst4SvwCJqT2gp7ZfPFZJf0+IkdI5kH JvnQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=hGWyi0Od8Y1ErBJF0hpItNPFaZTbueW2FEapaslMToY=; b=O63azhKRJat5U3ko5lo7tat3SAp1a5gxnLQrc02kEf/3cEGgOPZxCPlJolCeNcQUp4 gUfw0GZaKHP6rkLasHQvelxKMgnJC8FJIufAfKEnj25WY8h19QkUX4TNzCHc6RjjDs5e +BzDOGgX84D1o9tVD30xAUbIjNCocFyqG5f+PmcvvQw3AUdlh7W3wsyz3+ha4Cn5zz19 phFHvbTO2HQsoSszaxNUI/0+bNGccWXfBcSM/Y1wM55KYHpEvbgOn57QV2vbhjVxeAFQ dByygtwvr4CHITIHkYNZ92CG8/ft3FSUbrq5V0y13Hb91oQifl1b9I5Tsj0/POKlGnNl vP8A== X-Gm-Message-State: APjAAAUmjXi2QwjPdvXaBqrjcjZnag58M4lif0ysKtFUjGDOZCt3BaO/ MNUsr8Z2IHJZ/gGEav8PBktfXeaBo/c= X-Google-Smtp-Source: APXvYqypM85EdovMGJ94o2esm0rz8eyzZntgLZQuMYUg1ShgX+FLMxZq27mZR3gpe62DmQGy8y2vNw== X-Received: by 2002:a7b:c952:: with SMTP id i18mr15473194wml.44.1567126011893; Thu, 29 Aug 2019 17:46:51 -0700 (PDT) Received: from localhost.localdomain ([86.126.25.232]) by smtp.gmail.com with ESMTPSA id y3sm9298442wmg.2.2019.08.29.17.46.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Aug 2019 17:46:51 -0700 (PDT) From: Vladimir Oltean To: f.fainelli@gmail.com, vivien.didelot@gmail.com, andrew@lunn.ch, davem@davemloft.net, vinicius.gomes@intel.com, vedang.patel@intel.com, richardcochran@gmail.com Cc: weifeng.voon@intel.com, jiri@mellanox.com, m-karicheri2@ti.com, Jose.Abreu@synopsys.com, ilias.apalodimas@linaro.org, --to=jhs@mojatatu.com, --to=xiyou.wangcong@gmail.com, netdev@vger.kernel.org, Vladimir Oltean Subject: [RFC PATCH v2 net-next 03/15] net: dsa: sja1105: Switch to hardware operations for PTP Date: Fri, 30 Aug 2019 03:46:23 +0300 Message-Id: <20190830004635.24863-4-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190830004635.24863-1-olteanv@gmail.com> References: <20190830004635.24863-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Adjusting the hardware clock (PTPCLKVAL, PTPCLKADD, PTPCLKRATE) is a requirement for the auxiliary PTP functionality of the switch (TTEthernet, PPS input, PPS output). Now that the sync precision issues have been identified (and fixed in the spi-fsl-dspi driver), we can get rid of the timecounter/cyclecounter implementation, which is reliant on the free-running PTPTSCLK. Signed-off-by: Vladimir Oltean --- drivers/net/dsa/sja1105/sja1105.h | 16 +-- drivers/net/dsa/sja1105/sja1105_main.c | 18 ++- drivers/net/dsa/sja1105/sja1105_ptp.c | 181 ++++++++++++------------- drivers/net/dsa/sja1105/sja1105_ptp.h | 22 +++ drivers/net/dsa/sja1105/sja1105_spi.c | 2 - 5 files changed, 122 insertions(+), 117 deletions(-) diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index d8a92646e80a..e4955a025e46 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -32,7 +32,6 @@ struct sja1105_regs { u64 ptp_control; u64 ptpclk; u64 ptpclkrate; - u64 ptptsclk; u64 ptpegr_ts[SJA1105_NUM_PORTS]; u64 pad_mii_tx[SJA1105_NUM_PORTS]; u64 pad_mii_id[SJA1105_NUM_PORTS]; @@ -50,8 +49,15 @@ struct sja1105_regs { u64 qlevel[SJA1105_NUM_PORTS]; }; +enum sja1105_ptp_clk_mode { + PTP_ADD_MODE = 1, + PTP_SET_MODE = 0, +}; + struct sja1105_ptp_cmd { u64 resptp; /* reset */ + u64 corrclk4ts; /* use the corrected clock for timestamps */ + u64 ptpclkadd; /* enum sja1105_ptp_clk_mode */ }; struct sja1105_info { @@ -96,13 +102,7 @@ struct sja1105_private { struct sja1105_ptp_cmd ptp_cmd; struct ptp_clock_info ptp_caps; struct ptp_clock *clock; - /* The cycle counter translates the PTP timestamps (based on - * a free-running counter) into a software time domain. - */ - struct cyclecounter tstamp_cc; - struct timecounter tstamp_tc; - struct delayed_work refresh_work; - /* Serializes all operations on the cycle counter */ + /* Serializes all operations on the PTP hardware clock */ struct mutex ptp_lock; /* Serializes transmission of management frames so that * the switch doesn't confuse them with one another. diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index d8cff0107ec4..630f7e337fe9 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -1813,7 +1813,7 @@ static netdev_tx_t sja1105_port_deferred_xmit(struct dsa_switch *ds, int port, struct skb_shared_hwtstamps shwt = {0}; int slot = sp->mgmt_slot; struct sk_buff *clone; - u64 now, ts; + u64 ticks, ts; int rc; /* The tragic fact about the switch having 4x2 slots for installing @@ -1844,7 +1844,7 @@ static netdev_tx_t sja1105_port_deferred_xmit(struct dsa_switch *ds, int port, mutex_lock(&priv->ptp_lock); - now = priv->tstamp_cc.read(&priv->tstamp_cc); + ticks = sja1105_ptpclkval_read(priv); rc = sja1105_ptpegr_ts_poll(priv, slot, &ts); if (rc < 0) { @@ -1853,10 +1853,9 @@ static netdev_tx_t sja1105_port_deferred_xmit(struct dsa_switch *ds, int port, goto out_unlock_ptp; } - ts = sja1105_tstamp_reconstruct(priv, now, ts); - ts = timecounter_cyc2time(&priv->tstamp_tc, ts); + ts = sja1105_tstamp_reconstruct(priv, ticks, ts); - shwt.hwtstamp = ns_to_ktime(ts); + shwt.hwtstamp = ns_to_ktime(sja1105_ticks_to_ns(ts)); skb_complete_tx_timestamp(clone, &shwt); out_unlock_ptp: @@ -1994,11 +1993,11 @@ static void sja1105_rxtstamp_work(struct work_struct *work) struct sja1105_tagger_data *data = to_tagger(work); struct sja1105_private *priv = to_sja1105(data); struct sk_buff *skb; - u64 now; + u64 ticks; mutex_lock(&priv->ptp_lock); - now = priv->tstamp_cc.read(&priv->tstamp_cc); + ticks = sja1105_ptpclkval_read(priv); while ((skb = skb_dequeue(&data->skb_rxtstamp_queue)) != NULL) { struct skb_shared_hwtstamps *shwt = skb_hwtstamps(skb); @@ -2007,10 +2006,9 @@ static void sja1105_rxtstamp_work(struct work_struct *work) *shwt = (struct skb_shared_hwtstamps) {0}; ts = SJA1105_SKB_CB(skb)->meta_tstamp; - ts = sja1105_tstamp_reconstruct(priv, now, ts); - ts = timecounter_cyc2time(&priv->tstamp_tc, ts); + ts = sja1105_tstamp_reconstruct(priv, ticks, ts); - shwt->hwtstamp = ns_to_ktime(ts); + shwt->hwtstamp = ns_to_ktime(sja1105_ticks_to_ns(ts)); netif_rx_ni(skb); } diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.c b/drivers/net/dsa/sja1105/sja1105_ptp.c index 13f9f5799e46..bcdfdda46b9c 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.c +++ b/drivers/net/dsa/sja1105/sja1105_ptp.c @@ -13,24 +13,6 @@ #define SJA1105_MAX_ADJ_PPB 32000000 #define SJA1105_SIZE_PTP_CMD 4 -/* Timestamps are in units of 8 ns clock ticks (equivalent to a fixed - * 125 MHz clock) so the scale factor (MULT / SHIFT) needs to be 8. - * Furthermore, wisely pick SHIFT as 28 bits, which translates - * MULT into 2^31 (0x80000000). This is the same value around which - * the hardware PTPCLKRATE is centered, so the same ppb conversion - * arithmetic can be reused. - */ -#define SJA1105_CC_SHIFT 28 -#define SJA1105_CC_MULT (8 << SJA1105_CC_SHIFT) - -/* Having 33 bits of cycle counter left until a 64-bit overflow during delta - * conversion, we multiply this by the 8 ns counter resolution and arrive at - * a comfortable 68.71 second refresh interval until the delta would cause - * an integer overflow, in absence of any other readout. - * Approximate to 1 minute. - */ -#define SJA1105_REFRESH_INTERVAL (HZ * 60) - /* This range is actually +/- SJA1105_MAX_ADJ_PPB * divided by 1000 (ppb -> ppm) and with a 16-bit * "fractional" part (actually fixed point). @@ -41,7 +23,7 @@ * * This forgoes a "ppb" numeric representation (up to NSEC_PER_SEC) * and defines the scaling factor between scaled_ppm and the actual - * frequency adjustments (both cycle counter and hardware). + * frequency adjustments of the PHC. * * ptpclkrate = scaled_ppm * 2^31 / (10^6 * 2^16) * simplifies to @@ -49,10 +31,9 @@ */ #define SJA1105_CC_MULT_NUM (1 << 9) #define SJA1105_CC_MULT_DEM 15625 +#define SJA1105_CC_MULT 0x80000000 #define ptp_to_sja1105(d) container_of((d), struct sja1105_private, ptp_caps) -#define cc_to_sja1105(d) container_of((d), struct sja1105_private, tstamp_cc) -#define dw_to_sja1105(d) container_of((d), struct sja1105_private, refresh_work) int sja1105_get_ts_info(struct dsa_switch *ds, int port, struct ethtool_ts_info *info) @@ -86,6 +67,8 @@ int sja1105et_ptp_cmd(const void *ctx, const void *data) sja1105_pack(buf, &valid, 31, 31, size); sja1105_pack(buf, &cmd->resptp, 2, 2, size); + sja1105_pack(buf, &cmd->corrclk4ts, 1, 1, size); + sja1105_pack(buf, &cmd->ptpclkadd, 0, 0, size); return sja1105_spi_send_packed_buf(priv, SPI_WRITE, regs->ptp_control, buf, SJA1105_SIZE_PTP_CMD); @@ -103,6 +86,8 @@ int sja1105pqrs_ptp_cmd(const void *ctx, const void *data) sja1105_pack(buf, &valid, 31, 31, size); sja1105_pack(buf, &cmd->resptp, 3, 3, size); + sja1105_pack(buf, &cmd->corrclk4ts, 2, 2, size); + sja1105_pack(buf, &cmd->ptpclkadd, 0, 0, size); return sja1105_spi_send_packed_buf(priv, SPI_WRITE, regs->ptp_control, buf, SJA1105_SIZE_PTP_CMD); @@ -215,17 +200,14 @@ int sja1105_ptpegr_ts_poll(struct sja1105_private *priv, int port, u64 *ts) int sja1105_ptp_reset(struct sja1105_private *priv) { struct sja1105_ptp_cmd cmd = priv->ptp_cmd; - struct dsa_switch *ds = priv->ds; int rc; mutex_lock(&priv->ptp_lock); cmd.resptp = 1; - dev_dbg(ds->dev, "Resetting PTP clock\n"); - rc = priv->info->ptp_cmd(priv, &cmd); - timecounter_init(&priv->tstamp_tc, &priv->tstamp_cc, - ktime_to_ns(ktime_get_real())); + dev_dbg(priv->ds->dev, "Resetting PTP clock\n"); + rc = priv->info->ptp_cmd(priv, &cmd); mutex_unlock(&priv->ptp_lock); @@ -236,124 +218,130 @@ static int sja1105_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) { struct sja1105_private *priv = ptp_to_sja1105(ptp); - u64 ns; + u64 ticks; mutex_lock(&priv->ptp_lock); - ns = timecounter_read(&priv->tstamp_tc); - mutex_unlock(&priv->ptp_lock); - *ts = ns_to_timespec64(ns); + ticks = sja1105_ptpclkval_read(priv); + *ts = ns_to_timespec64(sja1105_ticks_to_ns(ticks)); + + mutex_unlock(&priv->ptp_lock); return 0; } +/* Caller must hold priv->ptp_lock */ +static int sja1105_ptp_mode_set(struct sja1105_private *priv, + enum sja1105_ptp_clk_mode mode) +{ + if (priv->ptp_cmd.ptpclkadd == mode) + return 0; + + priv->ptp_cmd.ptpclkadd = mode; + + return priv->info->ptp_cmd(priv, &priv->ptp_cmd); +} + +/* Caller must hold priv->ptp_lock */ +static int sja1105_ptpclkval_write(struct sja1105_private *priv, u64 val) +{ + const struct sja1105_regs *regs = priv->info->regs; + + return sja1105_spi_send_int(priv, SPI_WRITE, regs->ptpclk, &val, 8); +} + +/* Write to PTPCLKVAL while PTPCLKADD is 0 */ static int sja1105_ptp_settime(struct ptp_clock_info *ptp, const struct timespec64 *ts) { + u64 ticks = ns_to_sja1105_ticks(timespec64_to_ns(ts)); struct sja1105_private *priv = ptp_to_sja1105(ptp); - u64 ns = timespec64_to_ns(ts); + int rc; mutex_lock(&priv->ptp_lock); - timecounter_init(&priv->tstamp_tc, &priv->tstamp_cc, ns); + + rc = sja1105_ptp_mode_set(priv, PTP_SET_MODE); + if (rc < 0) { + dev_err(priv->ds->dev, "Failed to put PTPCLK in set mode\n"); + goto out; + } + + rc = sja1105_ptpclkval_write(priv, ticks); + +out: mutex_unlock(&priv->ptp_lock); - return 0; + return rc; } static int sja1105_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) { struct sja1105_private *priv = ptp_to_sja1105(ptp); + const struct sja1105_regs *regs = priv->info->regs; s64 clkrate; + int rc; clkrate = (s64)scaled_ppm * SJA1105_CC_MULT_NUM; clkrate = div_s64(clkrate, SJA1105_CC_MULT_DEM); - mutex_lock(&priv->ptp_lock); - - /* Force a readout to update the timer *before* changing its frequency. - * - * This way, its corrected time curve can at all times be modeled - * as a linear "A * x + B" function, where: - * - * - B are past frequency adjustments and offset shifts, all - * accumulated into the cycle_last variable. - * - * - A is the new frequency adjustments we're just about to set. - * - * Reading now makes B accumulate the correct amount of time, - * corrected at the old rate, before changing it. - * - * Hardware timestamps then become simple points on the curve and - * are approximated using the above function. This is still better - * than letting the switch take the timestamps using the hardware - * rate-corrected clock (PTPCLKVAL) - the comparison in this case would - * be that we're shifting the ruler at the same time as we're taking - * measurements with it. - * - * The disadvantage is that it's possible to receive timestamps when - * a frequency adjustment took place in the near past. - * In this case they will be approximated using the new ppb value - * instead of a compound function made of two segments (one at the old - * and the other at the new rate) - introducing some inaccuracy. - */ - timecounter_read(&priv->tstamp_tc); - - priv->tstamp_cc.mult = SJA1105_CC_MULT + clkrate; + /* Take a +/- value and re-center it around 2^31. */ + clkrate = SJA1105_CC_MULT + clkrate; + clkrate &= GENMASK_ULL(31, 0); - mutex_unlock(&priv->ptp_lock); - - return 0; -} + mutex_lock(&priv->ptp_lock); -static int sja1105_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) -{ - struct sja1105_private *priv = ptp_to_sja1105(ptp); + rc = sja1105_spi_send_int(priv, SPI_WRITE, regs->ptpclkrate, + &clkrate, 4); - mutex_lock(&priv->ptp_lock); - timecounter_adjtime(&priv->tstamp_tc, delta); mutex_unlock(&priv->ptp_lock); - return 0; + return rc; } -static u64 sja1105_ptptsclk_read(const struct cyclecounter *cc) +/* Caller must hold priv->ptp_lock */ +u64 sja1105_ptpclkval_read(struct sja1105_private *priv) { - struct sja1105_private *priv = cc_to_sja1105(cc); const struct sja1105_regs *regs = priv->info->regs; - u64 ptptsclk = 0; + u64 ptpclkval = 0; int rc; - rc = sja1105_spi_send_int(priv, SPI_READ, regs->ptptsclk, - &ptptsclk, 8); + rc = sja1105_spi_send_int(priv, SPI_READ, regs->ptpclk, + &ptpclkval, 8); if (rc < 0) dev_err_ratelimited(priv->ds->dev, - "failed to read ptp cycle counter: %d\n", + "failed to read ptp time: %d\n", rc); - return ptptsclk; + + return ptpclkval; } -static void sja1105_ptp_overflow_check(struct work_struct *work) +/* Write to PTPCLKVAL while PTPCLKADD is 1 */ +static int sja1105_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) { - struct delayed_work *dw = to_delayed_work(work); - struct sja1105_private *priv = dw_to_sja1105(dw); - struct timespec64 ts; + struct sja1105_private *priv = ptp_to_sja1105(ptp); + s64 ticks = ns_to_sja1105_ticks(delta); + int rc; - sja1105_ptp_gettime(&priv->ptp_caps, &ts); + mutex_lock(&priv->ptp_lock); - schedule_delayed_work(&priv->refresh_work, SJA1105_REFRESH_INTERVAL); + rc = sja1105_ptp_mode_set(priv, PTP_ADD_MODE); + if (rc < 0) { + dev_err(priv->ds->dev, "Failed to put PTPCLK in add mode\n"); + goto out; + } + + rc = sja1105_ptpclkval_write(priv, ticks); + +out: + mutex_unlock(&priv->ptp_lock); + + return rc; } int sja1105_ptp_clock_register(struct sja1105_private *priv) { struct dsa_switch *ds = priv->ds; - /* Set up the cycle counter */ - priv->tstamp_cc = (struct cyclecounter) { - .read = sja1105_ptptsclk_read, - .mask = CYCLECOUNTER_MASK(64), - .shift = SJA1105_CC_SHIFT, - .mult = SJA1105_CC_MULT, - }; priv->ptp_caps = (struct ptp_clock_info) { .owner = THIS_MODULE, .name = "SJA1105 PHC", @@ -370,8 +358,8 @@ int sja1105_ptp_clock_register(struct sja1105_private *priv) if (IS_ERR_OR_NULL(priv->clock)) return PTR_ERR(priv->clock); - INIT_DELAYED_WORK(&priv->refresh_work, sja1105_ptp_overflow_check); - schedule_delayed_work(&priv->refresh_work, SJA1105_REFRESH_INTERVAL); + priv->ptp_cmd.corrclk4ts = true; + priv->ptp_cmd.ptpclkadd = PTP_SET_MODE; return sja1105_ptp_reset(priv); } @@ -381,7 +369,6 @@ void sja1105_ptp_clock_unregister(struct sja1105_private *priv) if (IS_ERR_OR_NULL(priv->clock)) return; - cancel_delayed_work_sync(&priv->refresh_work); ptp_clock_unregister(priv->clock); priv->clock = NULL; } diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.h b/drivers/net/dsa/sja1105/sja1105_ptp.h index af456b0a4d27..51e21d951548 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.h +++ b/drivers/net/dsa/sja1105/sja1105_ptp.h @@ -4,6 +4,21 @@ #ifndef _SJA1105_PTP_H #define _SJA1105_PTP_H +/* Timestamps are in units of 8 ns clock ticks (equivalent to + * a fixed 125 MHz clock). + */ +#define SJA1105_TICK_NS 8 + +static inline s64 ns_to_sja1105_ticks(s64 ns) +{ + return ns / SJA1105_TICK_NS; +} + +static inline s64 sja1105_ticks_to_ns(s64 ticks) +{ + return ticks * SJA1105_TICK_NS; +} + #if IS_ENABLED(CONFIG_NET_DSA_SJA1105_PTP) int sja1105_ptp_clock_register(struct sja1105_private *priv); @@ -24,6 +39,8 @@ u64 sja1105_tstamp_reconstruct(struct sja1105_private *priv, u64 now, int sja1105_ptp_reset(struct sja1105_private *priv); +u64 sja1105_ptpclkval_read(struct sja1105_private *priv); + #else static inline int sja1105_ptp_clock_register(struct sja1105_private *priv) @@ -53,6 +70,11 @@ static inline int sja1105_ptp_reset(struct sja1105_private *priv) return 0; } +static inline u64 sja1105_ptpclkval_read(struct sja1105_private *priv) +{ + return 0; +} + #define sja1105et_ptp_cmd NULL #define sja1105pqrs_ptp_cmd NULL diff --git a/drivers/net/dsa/sja1105/sja1105_spi.c b/drivers/net/dsa/sja1105/sja1105_spi.c index 84dc603138cf..1953d8c54af6 100644 --- a/drivers/net/dsa/sja1105/sja1105_spi.c +++ b/drivers/net/dsa/sja1105/sja1105_spi.c @@ -517,7 +517,6 @@ static struct sja1105_regs sja1105et_regs = { .ptp_control = 0x17, .ptpclk = 0x18, /* Spans 0x18 to 0x19 */ .ptpclkrate = 0x1A, - .ptptsclk = 0x1B, /* Spans 0x1B to 0x1C */ }; static struct sja1105_regs sja1105pqrs_regs = { @@ -548,7 +547,6 @@ static struct sja1105_regs sja1105pqrs_regs = { .ptp_control = 0x18, .ptpclk = 0x19, .ptpclkrate = 0x1B, - .ptptsclk = 0x1C, }; struct sja1105_info sja1105e_info = { From patchwork Fri Aug 30 00:46:24 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1155588 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="e51Exq1F"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 46KLQt6HYnz9sN6 for ; Fri, 30 Aug 2019 10:47:02 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727635AbfH3ArC (ORCPT ); Thu, 29 Aug 2019 20:47:02 -0400 Received: from mail-wr1-f65.google.com ([209.85.221.65]:46005 "EHLO mail-wr1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727434AbfH3Aq4 (ORCPT ); Thu, 29 Aug 2019 20:46:56 -0400 Received: by mail-wr1-f65.google.com with SMTP id q12so5158329wrj.12 for ; Thu, 29 Aug 2019 17:46:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=L+CufA23+UP0A0dMOttVkrRwGGC/uK1Jo64bJFqsvfQ=; b=e51Exq1Fo4XGq5LA7UiqLNPn9IQeLgclYqY2vqSh79W/hklW2UBB51hd5XEg7HM9j/ CHtUdGKMqdLDO2PlB5VmOiggwgpDbz0NduJNz3GX0aYu9JCN8Npky0kmCYuBKgjvQAmU ng3F6nswwf+8Bbw8QCBPzKAACUv8UEkMsyhY1HIzqwVmm4ydsqDAdaatsxskUoGmggpW K8ZmjYeEIbzuhE9E3iNo94AXmMkpdcgRw5rmf5jMBhuLLdH7oQWvUh0MQ8YzIXSCtZUe yrthe5Kcu7of8mLBb1t7cl/M2fn2rojXNeOGpITm8HeGNrCj0EEyUT2ZF7zDqosX02nq nA3w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=L+CufA23+UP0A0dMOttVkrRwGGC/uK1Jo64bJFqsvfQ=; b=OXdkrI9ESPVkZZFqIFciH6PAFKtlK5OFvdWuR3o8DQFkb3C8b1+WEKe1/SQFkWt67n h/3pOrU0LKY2ALClNaz7w2WDMGtU3xQIYiONu6mJ6ixSNTTGM8grNZ1DsLxmxbBXuIkH c5iSu31ZEEwU/BIhH4pxgV4w9zo4CEE/PBAU8Ei5vH2xUpnyNAIZkLZrd/CX8vyfRp+b k7CWxNFOKRTnuK3r3Hjm1Ufi6XJXdw603/Sy00cFrgLJ+UQEqioDEOdThTSMNGLkpnau ZM6BZMZ3P18lE8OXR4w0BijAziS5MmGztxr7IfAjFUDahMx3H2gdhW3CVH0z8mLq9r0N 5S5g== X-Gm-Message-State: APjAAAUqVUy0+3SI+VgZppOoYd+/Yoro/HoGPUWwzvc5xy3dUxsOHxxS g9Fy0b2J4gl5dcg7+vR6E4a0o/B1Sjw= X-Google-Smtp-Source: APXvYqxjsL0fUJAGibJUnIq7YJbDCIKsK6sm1EN++O0y2F80eeH2TUFf76mTIRw2PJgjsLkxk+l5Kw== X-Received: by 2002:adf:c613:: with SMTP id n19mr3983711wrg.109.1567126013189; Thu, 29 Aug 2019 17:46:53 -0700 (PDT) Received: from localhost.localdomain ([86.126.25.232]) by smtp.gmail.com with ESMTPSA id y3sm9298442wmg.2.2019.08.29.17.46.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Aug 2019 17:46:52 -0700 (PDT) From: Vladimir Oltean To: f.fainelli@gmail.com, vivien.didelot@gmail.com, andrew@lunn.ch, davem@davemloft.net, vinicius.gomes@intel.com, vedang.patel@intel.com, richardcochran@gmail.com Cc: weifeng.voon@intel.com, jiri@mellanox.com, m-karicheri2@ti.com, Jose.Abreu@synopsys.com, ilias.apalodimas@linaro.org, --to=jhs@mojatatu.com, --to=xiyou.wangcong@gmail.com, netdev@vger.kernel.org, Vladimir Oltean Subject: [RFC PATCH v2 net-next 04/15] net: dsa: sja1105: Implement the .gettimex64 system call for PTP Date: Fri, 30 Aug 2019 03:46:24 +0300 Message-Id: <20190830004635.24863-5-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190830004635.24863-1-olteanv@gmail.com> References: <20190830004635.24863-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Through the PTP_SYS_OFFSET_EXTENDED ioctl, it is possible for userspace applications (i.e. phc2sys) to compensate for the delays incurred while reading the PHC's time. For now implement this ioctl in the driver, although the performance improvements are minimal. The goal with this patch is to rework the infrastructure in the driver for SPI transfers to be timestamped. Other patches depend on this change. The "performance" implementation of this ioctl will come later, once the API in the SPI subsystem is agreed upon. The change in the sja1105 driver will be minimal then. Signed-off-by: Vladimir Oltean --- drivers/net/dsa/sja1105/sja1105.h | 3 ++- drivers/net/dsa/sja1105/sja1105_main.c | 8 +++--- drivers/net/dsa/sja1105/sja1105_ptp.c | 20 ++++++++------ drivers/net/dsa/sja1105/sja1105_ptp.h | 6 +++-- drivers/net/dsa/sja1105/sja1105_spi.c | 36 +++++++++++++++++++------- 5 files changed, 48 insertions(+), 25 deletions(-) diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index e4955a025e46..c80be59dafbd 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -131,7 +131,8 @@ int sja1105_spi_send_packed_buf(const struct sja1105_private *priv, void *packed_buf, size_t size_bytes); int sja1105_spi_send_int(const struct sja1105_private *priv, sja1105_spi_rw_mode_t rw, u64 reg_addr, - u64 *value, u64 size_bytes); + u64 *value, u64 size_bytes, + struct ptp_system_timestamp *ptp_sts); int sja1105_spi_send_long_packed_buf(const struct sja1105_private *priv, sja1105_spi_rw_mode_t rw, u64 base_addr, void *packed_buf, u64 buf_len); diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index 630f7e337fe9..f7f03d486499 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -1844,7 +1844,7 @@ static netdev_tx_t sja1105_port_deferred_xmit(struct dsa_switch *ds, int port, mutex_lock(&priv->ptp_lock); - ticks = sja1105_ptpclkval_read(priv); + ticks = sja1105_ptpclkval_read(priv, NULL); rc = sja1105_ptpegr_ts_poll(priv, slot, &ts); if (rc < 0) { @@ -1997,7 +1997,7 @@ static void sja1105_rxtstamp_work(struct work_struct *work) mutex_lock(&priv->ptp_lock); - ticks = sja1105_ptpclkval_read(priv); + ticks = sja1105_ptpclkval_read(priv, NULL); while ((skb = skb_dequeue(&data->skb_rxtstamp_queue)) != NULL) { struct skb_shared_hwtstamps *shwt = skb_hwtstamps(skb); @@ -2092,8 +2092,8 @@ static int sja1105_check_device_id(struct sja1105_private *priv) u64 part_no; int rc; - rc = sja1105_spi_send_int(priv, SPI_READ, regs->device_id, - &device_id, SJA1105_SIZE_DEVICE_ID); + rc = sja1105_spi_send_int(priv, SPI_READ, regs->device_id, &device_id, + SJA1105_SIZE_DEVICE_ID, NULL); if (rc < 0) return rc; diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.c b/drivers/net/dsa/sja1105/sja1105_ptp.c index bcdfdda46b9c..04693c702b09 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.c +++ b/drivers/net/dsa/sja1105/sja1105_ptp.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2019, Vladimir Oltean */ +#include #include "sja1105.h" /* The adjfine API clamps ppb between [-32,768,000, 32,768,000], and @@ -214,15 +215,16 @@ int sja1105_ptp_reset(struct sja1105_private *priv) return rc; } -static int sja1105_ptp_gettime(struct ptp_clock_info *ptp, - struct timespec64 *ts) +static int sja1105_ptp_gettimex(struct ptp_clock_info *ptp, + struct timespec64 *ts, + struct ptp_system_timestamp *sts) { struct sja1105_private *priv = ptp_to_sja1105(ptp); u64 ticks; mutex_lock(&priv->ptp_lock); - ticks = sja1105_ptpclkval_read(priv); + ticks = sja1105_ptpclkval_read(priv, sts); *ts = ns_to_timespec64(sja1105_ticks_to_ns(ticks)); mutex_unlock(&priv->ptp_lock); @@ -247,7 +249,8 @@ static int sja1105_ptpclkval_write(struct sja1105_private *priv, u64 val) { const struct sja1105_regs *regs = priv->info->regs; - return sja1105_spi_send_int(priv, SPI_WRITE, regs->ptpclk, &val, 8); + return sja1105_spi_send_int(priv, SPI_WRITE, regs->ptpclk, &val, 8, + NULL); } /* Write to PTPCLKVAL while PTPCLKADD is 0 */ @@ -291,7 +294,7 @@ static int sja1105_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) mutex_lock(&priv->ptp_lock); rc = sja1105_spi_send_int(priv, SPI_WRITE, regs->ptpclkrate, - &clkrate, 4); + &clkrate, 4, NULL); mutex_unlock(&priv->ptp_lock); @@ -299,14 +302,15 @@ static int sja1105_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) } /* Caller must hold priv->ptp_lock */ -u64 sja1105_ptpclkval_read(struct sja1105_private *priv) +u64 sja1105_ptpclkval_read(struct sja1105_private *priv, + struct ptp_system_timestamp *sts) { const struct sja1105_regs *regs = priv->info->regs; u64 ptpclkval = 0; int rc; rc = sja1105_spi_send_int(priv, SPI_READ, regs->ptpclk, - &ptpclkval, 8); + &ptpclkval, 8, sts); if (rc < 0) dev_err_ratelimited(priv->ds->dev, "failed to read ptp time: %d\n", @@ -347,7 +351,7 @@ int sja1105_ptp_clock_register(struct sja1105_private *priv) .name = "SJA1105 PHC", .adjfine = sja1105_ptp_adjfine, .adjtime = sja1105_ptp_adjtime, - .gettime64 = sja1105_ptp_gettime, + .gettimex64 = sja1105_ptp_gettimex, .settime64 = sja1105_ptp_settime, .max_adj = SJA1105_MAX_ADJ_PPB, }; diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.h b/drivers/net/dsa/sja1105/sja1105_ptp.h index 51e21d951548..80c33e5e4503 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.h +++ b/drivers/net/dsa/sja1105/sja1105_ptp.h @@ -39,7 +39,8 @@ u64 sja1105_tstamp_reconstruct(struct sja1105_private *priv, u64 now, int sja1105_ptp_reset(struct sja1105_private *priv); -u64 sja1105_ptpclkval_read(struct sja1105_private *priv); +u64 sja1105_ptpclkval_read(struct sja1105_private *priv, + struct ptp_system_timestamp *sts); #else @@ -70,7 +71,8 @@ static inline int sja1105_ptp_reset(struct sja1105_private *priv) return 0; } -static inline u64 sja1105_ptpclkval_read(struct sja1105_private *priv) +static inline u64 sja1105_ptpclkval_read(struct sja1105_private *priv, + struct ptp_system_timestamp *sts) { return 0; } diff --git a/drivers/net/dsa/sja1105/sja1105_spi.c b/drivers/net/dsa/sja1105/sja1105_spi.c index 1953d8c54af6..26985f1209ad 100644 --- a/drivers/net/dsa/sja1105/sja1105_spi.c +++ b/drivers/net/dsa/sja1105/sja1105_spi.c @@ -15,7 +15,8 @@ (SJA1105_SIZE_SPI_MSG_HEADER + SJA1105_SIZE_SPI_MSG_MAXLEN) static int sja1105_spi_transfer(const struct sja1105_private *priv, - const void *tx, void *rx, int size) + const void *tx, void *rx, int size, + struct ptp_system_timestamp *ptp_sts) { struct spi_device *spi = priv->spidev; struct spi_transfer transfer = { @@ -35,12 +36,16 @@ static int sja1105_spi_transfer(const struct sja1105_private *priv, spi_message_init(&msg); spi_message_add_tail(&transfer, &msg); + ptp_read_system_prets(ptp_sts); + rc = spi_sync(spi, &msg); if (rc < 0) { dev_err(&spi->dev, "SPI transfer failed: %d\n", rc); return rc; } + ptp_read_system_postts(ptp_sts); + return rc; } @@ -66,9 +71,11 @@ sja1105_spi_message_pack(void *buf, const struct sja1105_spi_message *msg) * @size_bytes is smaller than SIZE_SPI_MSG_MAXLEN. Larger packed buffers * are chunked in smaller pieces by sja1105_spi_send_long_packed_buf below. */ -int sja1105_spi_send_packed_buf(const struct sja1105_private *priv, - sja1105_spi_rw_mode_t rw, u64 reg_addr, - void *packed_buf, size_t size_bytes) +static int +__sja1105_spi_send_packed_buf(const struct sja1105_private *priv, + sja1105_spi_rw_mode_t rw, u64 reg_addr, + void *packed_buf, size_t size_bytes, + struct ptp_system_timestamp *ptp_sts) { u8 tx_buf[SJA1105_SIZE_SPI_TRANSFER_MAX] = {0}; u8 rx_buf[SJA1105_SIZE_SPI_TRANSFER_MAX] = {0}; @@ -90,7 +97,7 @@ int sja1105_spi_send_packed_buf(const struct sja1105_private *priv, memcpy(tx_buf + SJA1105_SIZE_SPI_MSG_HEADER, packed_buf, size_bytes); - rc = sja1105_spi_transfer(priv, tx_buf, rx_buf, msg_len); + rc = sja1105_spi_transfer(priv, tx_buf, rx_buf, msg_len, ptp_sts); if (rc < 0) return rc; @@ -101,6 +108,14 @@ int sja1105_spi_send_packed_buf(const struct sja1105_private *priv, return 0; } +int sja1105_spi_send_packed_buf(const struct sja1105_private *priv, + sja1105_spi_rw_mode_t rw, u64 reg_addr, + void *packed_buf, size_t size_bytes) +{ + return __sja1105_spi_send_packed_buf(priv, rw, reg_addr, packed_buf, + size_bytes, NULL); +} + /* If @rw is: * - SPI_WRITE: creates and sends an SPI write message at absolute * address reg_addr, taking size_bytes from *packed_buf @@ -114,7 +129,8 @@ int sja1105_spi_send_packed_buf(const struct sja1105_private *priv, */ int sja1105_spi_send_int(const struct sja1105_private *priv, sja1105_spi_rw_mode_t rw, u64 reg_addr, - u64 *value, u64 size_bytes) + u64 *value, u64 size_bytes, + struct ptp_system_timestamp *ptp_sts) { u8 packed_buf[SJA1105_SIZE_SPI_MSG_MAXLEN]; int rc; @@ -126,8 +142,8 @@ int sja1105_spi_send_int(const struct sja1105_private *priv, sja1105_pack(packed_buf, value, 8 * size_bytes - 1, 0, size_bytes); - rc = sja1105_spi_send_packed_buf(priv, rw, reg_addr, packed_buf, - size_bytes); + rc = __sja1105_spi_send_packed_buf(priv, rw, reg_addr, packed_buf, + size_bytes, ptp_sts); if (rw == SPI_READ) sja1105_unpack(packed_buf, value, 8 * size_bytes - 1, 0, @@ -291,7 +307,7 @@ int sja1105_inhibit_tx(const struct sja1105_private *priv, int rc; rc = sja1105_spi_send_int(priv, SPI_READ, regs->port_control, - &inhibit_cmd, SJA1105_SIZE_PORT_CTRL); + &inhibit_cmd, SJA1105_SIZE_PORT_CTRL, NULL); if (rc < 0) return rc; @@ -301,7 +317,7 @@ int sja1105_inhibit_tx(const struct sja1105_private *priv, inhibit_cmd &= ~port_bitmap; return sja1105_spi_send_int(priv, SPI_WRITE, regs->port_control, - &inhibit_cmd, SJA1105_SIZE_PORT_CTRL); + &inhibit_cmd, SJA1105_SIZE_PORT_CTRL, NULL); } struct sja1105_status { From patchwork Fri Aug 30 00:46:25 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1155587 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="P41xQBrc"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 46KLQs49wTz9sNC for ; Fri, 30 Aug 2019 10:47:01 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727608AbfH3ArA (ORCPT ); Thu, 29 Aug 2019 20:47:00 -0400 Received: from mail-wr1-f67.google.com ([209.85.221.67]:46853 "EHLO mail-wr1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727476AbfH3Aq5 (ORCPT ); Thu, 29 Aug 2019 20:46:57 -0400 Received: by mail-wr1-f67.google.com with SMTP id h7so3867725wrt.13 for ; Thu, 29 Aug 2019 17:46:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=bHjssYXNt7YExpDa379zkscq2PtpufAIzUFeKm02Xec=; b=P41xQBrc5LE6KRxFAbQQ9knw64u99udZm28FYlT69HJlitUkusB8RrOmeGNZfwxiqJ TaHbPw8fMaMN7tZGTlU6AyUyvaUTQcqJjKEPMpFHd2v1VW0xB/FWgaZVaOu7AWLb5yvc ZqB4+SEPzTeYTqqb6oU/8QHDTqQcbhtcAqU+vr8MP1MtVPbbsyiGxBJGg0TNdMUnNLKE Gdmz3cid6k/JxnLeeybLemhZoaL4A1q4tJxpSz0B1TpBmbhp7FGypvyMpOk3gNIL9j9S tq6LkrDJJ1lezQJqtjypIrsAmOSKQeG6a/UUfmx53ErPOevmzen71vnlZwhUsVMmWi8q BKpg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=bHjssYXNt7YExpDa379zkscq2PtpufAIzUFeKm02Xec=; b=Un/X1FhyMEOfaaL/HGL03fv3cALyKc64ydlgTBb76hJpQ1j5vrn+d/zvf0s/XZTbBa G0ElXkLRniz5SIZFs+8Z+li5RTvGVAC8m4IuJMUj58MevqYClkya/vHQfdzfmcShQqmL +9+8w8UjBHSaGlLz8jDgpbasQZoX7PeSvHLIl1pnlxa3kog7ezedDRri+MueI8/CilK1 5WPy8BxRomYcvh5N3NpNyh7KxVvyRCf1eStJ8pO0mchQDwYxatb8yKyTJ0l0QKS7iBtf XqFuIWnyvcIIAjWEckwz/+pVaym824OsCopPCyiMrL1CaT/VnYxEi1NgKCzD/jEKXO46 UPxg== X-Gm-Message-State: APjAAAU6hazWDGtep3hFthDTbvM+EbHakIdxLzzfTVSbRQ7jeY8fPmY8 FjFa3HiMcSp+KTM1CoIRHsU= X-Google-Smtp-Source: APXvYqyyQzEilZbRkitzgBJTzaIui//LmVdddLAoKjQ8Ezok5b6jXWTXYjw5avE+DgqJTgvhX8+yDg== X-Received: by 2002:adf:b612:: with SMTP id f18mr12926315wre.97.1567126014440; Thu, 29 Aug 2019 17:46:54 -0700 (PDT) Received: from localhost.localdomain ([86.126.25.232]) by smtp.gmail.com with ESMTPSA id y3sm9298442wmg.2.2019.08.29.17.46.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Aug 2019 17:46:54 -0700 (PDT) From: Vladimir Oltean To: f.fainelli@gmail.com, vivien.didelot@gmail.com, andrew@lunn.ch, davem@davemloft.net, vinicius.gomes@intel.com, vedang.patel@intel.com, richardcochran@gmail.com Cc: weifeng.voon@intel.com, jiri@mellanox.com, m-karicheri2@ti.com, Jose.Abreu@synopsys.com, ilias.apalodimas@linaro.org, --to=jhs@mojatatu.com, --to=xiyou.wangcong@gmail.com, netdev@vger.kernel.org, Vladimir Oltean Subject: [RFC PATCH v2 net-next 05/15] net: dsa: sja1105: Restore PTP time after switch reset Date: Fri, 30 Aug 2019 03:46:25 +0300 Message-Id: <20190830004635.24863-6-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190830004635.24863-1-olteanv@gmail.com> References: <20190830004635.24863-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org The PTP time of the switch is not preserved when uploading a new static configuration. Work around this hardware oddity by reading its PTP time before a static config upload, and restoring it afterwards. Static config changes are expected to occur at runtime even in scenarios directly related to PTP, i.e. the Time-Aware Scheduler of the switch is programmed in this way. Signed-off-by: Vladimir Oltean --- drivers/net/dsa/sja1105/sja1105_main.c | 32 ++++++++++++- drivers/net/dsa/sja1105/sja1105_ptp.c | 66 ++++++++++++++++++-------- drivers/net/dsa/sja1105/sja1105_ptp.h | 25 ++++++++++ drivers/net/dsa/sja1105/sja1105_spi.c | 4 -- 4 files changed, 101 insertions(+), 26 deletions(-) diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index f7f03d486499..abb22f0a9884 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -1382,8 +1382,13 @@ static void sja1105_bridge_leave(struct dsa_switch *ds, int port, */ static int sja1105_static_config_reload(struct sja1105_private *priv) { + struct ptp_system_timestamp ptp_sts_before; + struct ptp_system_timestamp ptp_sts_after; struct sja1105_mac_config_entry *mac; int speed_mbps[SJA1105_NUM_PORTS]; + s64 t1, t2, t3, t4; + s64 ptpclkval; + s64 t12, t34; int rc, i; mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries; @@ -1398,10 +1403,35 @@ static int sja1105_static_config_reload(struct sja1105_private *priv) mac[i].speed = SJA1105_SPEED_AUTO; } + /* No PTP operations can run right now */ + mutex_lock(&priv->ptp_lock); + + ptpclkval = __sja1105_ptp_gettimex(priv, &ptp_sts_before); + /* Reset switch and send updated static configuration */ rc = sja1105_static_config_upload(priv); if (rc < 0) - goto out; + goto out_unlock_ptp; + + rc = __sja1105_ptp_settime(priv, 0, &ptp_sts_after); + if (rc < 0) + goto out_unlock_ptp; + + t1 = timespec64_to_ns(&ptp_sts_before.pre_ts); + t2 = timespec64_to_ns(&ptp_sts_before.post_ts); + t3 = timespec64_to_ns(&ptp_sts_after.pre_ts); + t4 = timespec64_to_ns(&ptp_sts_after.post_ts); + /* Mid point, corresponds to pre-reset PTPCLKVAL */ + t12 = t1 + (t2 - t1) / 2; + /* Mid point, corresponds to post-reset PTPCLKVAL, aka 0 */ + t34 = t3 + (t4 - t3) / 2; + /* Advance PTPCLKVAL by the time it took since its readout */ + ptpclkval += (t34 - t12); + + __sja1105_ptp_adjtime(priv, ptpclkval); + +out_unlock_ptp: + mutex_unlock(&priv->ptp_lock); /* Configure the CGU (PLLs) for MII and RMII PHYs. * For these interfaces there is no dynamic configuration diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.c b/drivers/net/dsa/sja1105/sja1105_ptp.c index 04693c702b09..a7722c0944fb 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.c +++ b/drivers/net/dsa/sja1105/sja1105_ptp.c @@ -215,17 +215,26 @@ int sja1105_ptp_reset(struct sja1105_private *priv) return rc; } +/* Caller must hold priv->ptp_lock */ +u64 __sja1105_ptp_gettimex(struct sja1105_private *priv, + struct ptp_system_timestamp *sts) +{ + u64 ticks; + + ticks = sja1105_ptpclkval_read(priv, sts); + + return sja1105_ticks_to_ns(ticks); +} + static int sja1105_ptp_gettimex(struct ptp_clock_info *ptp, struct timespec64 *ts, struct ptp_system_timestamp *sts) { struct sja1105_private *priv = ptp_to_sja1105(ptp); - u64 ticks; mutex_lock(&priv->ptp_lock); - ticks = sja1105_ptpclkval_read(priv, sts); - *ts = ns_to_timespec64(sja1105_ticks_to_ns(ticks)); + *ts = ns_to_timespec64(__sja1105_ptp_gettimex(priv, sts)); mutex_unlock(&priv->ptp_lock); @@ -245,33 +254,42 @@ static int sja1105_ptp_mode_set(struct sja1105_private *priv, } /* Caller must hold priv->ptp_lock */ -static int sja1105_ptpclkval_write(struct sja1105_private *priv, u64 val) +static int sja1105_ptpclkval_write(struct sja1105_private *priv, u64 val, + struct ptp_system_timestamp *ptp_sts) { const struct sja1105_regs *regs = priv->info->regs; return sja1105_spi_send_int(priv, SPI_WRITE, regs->ptpclk, &val, 8, - NULL); + ptp_sts); } /* Write to PTPCLKVAL while PTPCLKADD is 0 */ -static int sja1105_ptp_settime(struct ptp_clock_info *ptp, - const struct timespec64 *ts) +int __sja1105_ptp_settime(struct sja1105_private *priv, u64 ns, + struct ptp_system_timestamp *ptp_sts) { - u64 ticks = ns_to_sja1105_ticks(timespec64_to_ns(ts)); - struct sja1105_private *priv = ptp_to_sja1105(ptp); + u64 ticks = ns_to_sja1105_ticks(ns); int rc; - mutex_lock(&priv->ptp_lock); - rc = sja1105_ptp_mode_set(priv, PTP_SET_MODE); if (rc < 0) { dev_err(priv->ds->dev, "Failed to put PTPCLK in set mode\n"); - goto out; + return rc; } - rc = sja1105_ptpclkval_write(priv, ticks); + return sja1105_ptpclkval_write(priv, ticks, ptp_sts); +} + +static int sja1105_ptp_settime(struct ptp_clock_info *ptp, + const struct timespec64 *ts) +{ + struct sja1105_private *priv = ptp_to_sja1105(ptp); + u64 ns = timespec64_to_ns(ts); + int rc; + + mutex_lock(&priv->ptp_lock); + + rc = __sja1105_ptp_settime(priv, ns, NULL); -out: mutex_unlock(&priv->ptp_lock); return rc; @@ -320,23 +338,29 @@ u64 sja1105_ptpclkval_read(struct sja1105_private *priv, } /* Write to PTPCLKVAL while PTPCLKADD is 1 */ -static int sja1105_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) +int __sja1105_ptp_adjtime(struct sja1105_private *priv, s64 delta) { - struct sja1105_private *priv = ptp_to_sja1105(ptp); s64 ticks = ns_to_sja1105_ticks(delta); int rc; - mutex_lock(&priv->ptp_lock); - rc = sja1105_ptp_mode_set(priv, PTP_ADD_MODE); if (rc < 0) { dev_err(priv->ds->dev, "Failed to put PTPCLK in add mode\n"); - goto out; + return rc; } - rc = sja1105_ptpclkval_write(priv, ticks); + return sja1105_ptpclkval_write(priv, ticks, NULL); +} + +static int sja1105_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) +{ + struct sja1105_private *priv = ptp_to_sja1105(ptp); + int rc; + + mutex_lock(&priv->ptp_lock); + + rc = __sja1105_ptp_adjtime(priv, delta); -out: mutex_unlock(&priv->ptp_lock); return rc; diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.h b/drivers/net/dsa/sja1105/sja1105_ptp.h index 80c33e5e4503..c699611e585d 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.h +++ b/drivers/net/dsa/sja1105/sja1105_ptp.h @@ -42,6 +42,14 @@ int sja1105_ptp_reset(struct sja1105_private *priv); u64 sja1105_ptpclkval_read(struct sja1105_private *priv, struct ptp_system_timestamp *sts); +u64 __sja1105_ptp_gettimex(struct sja1105_private *priv, + struct ptp_system_timestamp *sts); + +int __sja1105_ptp_settime(struct sja1105_private *priv, u64 ns, + struct ptp_system_timestamp *ptp_sts); + +int __sja1105_ptp_adjtime(struct sja1105_private *priv, s64 delta); + #else static inline int sja1105_ptp_clock_register(struct sja1105_private *priv) @@ -77,6 +85,23 @@ static inline u64 sja1105_ptpclkval_read(struct sja1105_private *priv, return 0; } +static inline u64 __sja1105_ptp_gettimex(struct sja1105_private *priv, + struct ptp_system_timestamp *sts) +{ + return 0; +} + +static inline int __sja1105_ptp_settime(struct sja1105_private *priv, u64 ns, + struct ptp_system_timestamp *ptp_sts) +{ + return 0; +} + +static inline int __sja1105_ptp_adjtime(struct sja1105_private *priv, s64 delta) +{ + return 0; +} + #define sja1105et_ptp_cmd NULL #define sja1105pqrs_ptp_cmd NULL diff --git a/drivers/net/dsa/sja1105/sja1105_spi.c b/drivers/net/dsa/sja1105/sja1105_spi.c index 26985f1209ad..eae9c9baa189 100644 --- a/drivers/net/dsa/sja1105/sja1105_spi.c +++ b/drivers/net/dsa/sja1105/sja1105_spi.c @@ -496,10 +496,6 @@ int sja1105_static_config_upload(struct sja1105_private *priv) dev_info(dev, "Succeeded after %d tried\n", RETRIES - retries); } - rc = sja1105_ptp_reset(priv); - if (rc < 0) - dev_err(dev, "Failed to reset PTP clock: %d\n", rc); - dev_info(dev, "Reset switch and programmed static config\n"); out: From patchwork Fri Aug 30 00:46:26 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1155589 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="uFB8t/T/"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 46KLQw0sLjz9sNC for ; Fri, 30 Aug 2019 10:47:04 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727648AbfH3ArC (ORCPT ); Thu, 29 Aug 2019 20:47:02 -0400 Received: from mail-wm1-f68.google.com ([209.85.128.68]:40573 "EHLO mail-wm1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727500AbfH3Aq5 (ORCPT ); Thu, 29 Aug 2019 20:46:57 -0400 Received: by mail-wm1-f68.google.com with SMTP id t9so5573915wmi.5 for ; Thu, 29 Aug 2019 17:46:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=byOve4hK9MD9IaKQiPRozkAVI6p2OHZpeb9FYCyxWzo=; b=uFB8t/T/tAidqe01wunpd4FmCb/n3VU6NewGCprHfzwl9F9xC71Uy9FdSE0VDcqlAR zhRVXHtfaxH9NfiMFPShic7WoF1F/nUdf/wORLosy8XVFtMe/AOhmnQY3HueW+hpMbQO WKnx5yCECsBj7mCdl8QB2LWgqNIzI92Lai+X+dCRYRPnn5qDEm4/SvVU0umcIkGToebA yodKfOZFd5/Dg8P8EaG6OnyzI2Kpq1kZEsYgXhVTEIIkcH12aPLwVAChS+qh6tn6TYIZ mF0g/WA9D02f7R9NvyrxGAkRt64mqw0CsLg2GoDU+k6u0NtHiTzE1cjURr3NsgXPXJXP XTyA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=byOve4hK9MD9IaKQiPRozkAVI6p2OHZpeb9FYCyxWzo=; b=L2puGT+apfkA80UzMKt7geTYomc7omRtan9jX8GdUxcJLttErCTagSo9M8TkNfsBDe bV2Q8U9ny339B+7aQnmPiB0aKrtVCxG8oUOropTE5Q9J6YbAoAoJ1s/gp1zoNqkHsKY1 Qpm2SQixstOgxHqHFlGUA26+mnXaDy2AnsVnBM7PLDrnlCvrw4rtiOegnc9OIQNuSb7/ 3qhU35KLcjkmIgLaf0LkIoE6IPxvT4/N6renoaudkVjh/Dn/tcrsvXO4bC5mbc8YDtlV B49kNDVue2Z8CFbQjP0Sb7ujE4f0IVsZ+DiOPPqLO8kcOACDOxLie+krnjTrJHscANXK QrBg== X-Gm-Message-State: APjAAAV/ugxmpw7fpQZv7TIqRh5XKEiBeigTwfuF6d3dbyF0/RZ5FO80 5+yg+q8TH/k96hzaNJlVM4Y= X-Google-Smtp-Source: APXvYqyu2Od/xLv0ZXlD7Z1LVDk+CAUjr9MmhOUBo4R1bZjpMoFLQGRB4kWvhmduWQB/o5kXvz4OqQ== X-Received: by 2002:a7b:cd17:: with SMTP id f23mr15001392wmj.177.1567126015673; Thu, 29 Aug 2019 17:46:55 -0700 (PDT) Received: from localhost.localdomain ([86.126.25.232]) by smtp.gmail.com with ESMTPSA id y3sm9298442wmg.2.2019.08.29.17.46.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Aug 2019 17:46:55 -0700 (PDT) From: Vladimir Oltean To: f.fainelli@gmail.com, vivien.didelot@gmail.com, andrew@lunn.ch, davem@davemloft.net, vinicius.gomes@intel.com, vedang.patel@intel.com, richardcochran@gmail.com Cc: weifeng.voon@intel.com, jiri@mellanox.com, m-karicheri2@ti.com, Jose.Abreu@synopsys.com, ilias.apalodimas@linaro.org, --to=jhs@mojatatu.com, --to=xiyou.wangcong@gmail.com, netdev@vger.kernel.org, Vladimir Oltean Subject: [RFC PATCH v2 net-next 06/15] net: dsa: sja1105: Disallow management xmit during switch reset Date: Fri, 30 Aug 2019 03:46:26 +0300 Message-Id: <20190830004635.24863-7-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190830004635.24863-1-olteanv@gmail.com> References: <20190830004635.24863-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org The purpose here is to avoid ptp4l fail due to this condition: timed out while polling for tx timestamp increasing tx_timestamp_timeout may correct this issue, but it is likely caused by a driver bug port 1: send peer delay request failed So either reset the switch before the management frame was sent, or after it was timestamped as well, but not in the middle. The condition may arise either due to a true timeout (i.e. because re-uploading the static config takes time), or due to the TX timestamp actually getting lost due to reset. For the former we can increase tx_timestamp_timeout in userspace, for the latter we need this patch. Locking all traffic during switch reset does not make sense at all, though. Forcing all CPU-originated traffic to potentially block waiting for a sleepable context to send > 800 bytes over SPI is not a good idea. Flows that are autonomously forwarded by the switch will get dropped anyway during switch reset no matter what. So just let all other CPU-originated traffic be dropped as well. Signed-off-by: Vladimir Oltean --- drivers/net/dsa/sja1105/sja1105_main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index abb22f0a9884..d92f15b3aea9 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -1391,6 +1391,8 @@ static int sja1105_static_config_reload(struct sja1105_private *priv) s64 t12, t34; int rc, i; + mutex_lock(&priv->mgmt_lock); + mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries; /* Back up the dynamic link speed changed by sja1105_adjust_port_config @@ -1447,6 +1449,8 @@ static int sja1105_static_config_reload(struct sja1105_private *priv) goto out; } out: + mutex_unlock(&priv->mgmt_lock); + return rc; } From patchwork Fri Aug 30 00:46:27 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1155586 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="QwCw97wI"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 46KLQr5VTQz9sN6 for ; Fri, 30 Aug 2019 10:47:00 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727578AbfH3Aq7 (ORCPT ); Thu, 29 Aug 2019 20:46:59 -0400 Received: from mail-wr1-f67.google.com ([209.85.221.67]:42762 "EHLO mail-wr1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727401AbfH3Aq6 (ORCPT ); Thu, 29 Aug 2019 20:46:58 -0400 Received: by mail-wr1-f67.google.com with SMTP id b16so5178951wrq.9 for ; Thu, 29 Aug 2019 17:46:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=4KM1VoqrfvMIwtYD1uU4m6otb3Yxko8K5pGuKaNKqIM=; b=QwCw97wIzyJnb5SWEib83WdZ0eL7dXFl4b0rrEeiNkIYMy5xgf7q9NOt6w7H/OvRSQ OkDk4XnhSij0g/+C75Mgks7rQNSk9D0RZF8riIdnxRuh9AYxNoH0ibwcH6GXmw8Ex5sP mkNztepvv+sZRENRCyb9Mvs4O3b903W/xBxvIYrFcYNNYcFyJaqzAacOTLTxIHddaiwN nAdIlHj+9eW48VT7RaKt2uC8ssQuKpo75JghJ2VYVQ7unMT4Fvo3sLtsRnrwkPIYA+1j xniauNwsgJQ6Bi8ufjOFhYskOUthA2bIjRLa+HzsYs+ENgsw0EDgODxv243A8JJFFjRB PpuQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=4KM1VoqrfvMIwtYD1uU4m6otb3Yxko8K5pGuKaNKqIM=; b=LPrUhfElulB5EhbEytgb7qIxwGHNFI22t2/Yb+M6icOkIoOjukPtjPWbzCYqlju8UP 1QDqXbtLijlDeWb2NKNcem8i/Dl3Av8udHim7MRy1ZpEE6EpyTUc8HIrY6OYgBw6tMo+ z7+Rq1ROblI8AaiFWqNHTo7pL5JoWzVzc8UKZa7Y/3TcWgXaIO4jQZKgqgeKuBJkemz9 NLNb9CZ5xWN3ElaJ2Xh6QPUWreiDroCxlfAPthlo09jkquaQWSPA7JBflxPAgftSwP8m eEabX6M3GsiCqBjxHHxNq7xUDKkr+FCu5XA+yxjBcqCgOR1l25W2AYgZglCrPeJjvuq+ uNZg== X-Gm-Message-State: APjAAAUnel173471WK4ZS2L0ArhsNwUgDoysA4TsEIi5Kng6TRYbulOD wYRn1eNBeLl3EnioDalef1g= X-Google-Smtp-Source: APXvYqwdrnRDKer/eclSfWaEW3xygD4Tlb1HABNhlnnxfsnwUSw8IM376wttNO2agG3NLsnZ7i+P1Q== X-Received: by 2002:a5d:63c8:: with SMTP id c8mr9375394wrw.21.1567126017213; Thu, 29 Aug 2019 17:46:57 -0700 (PDT) Received: from localhost.localdomain ([86.126.25.232]) by smtp.gmail.com with ESMTPSA id y3sm9298442wmg.2.2019.08.29.17.46.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Aug 2019 17:46:56 -0700 (PDT) From: Vladimir Oltean To: f.fainelli@gmail.com, vivien.didelot@gmail.com, andrew@lunn.ch, davem@davemloft.net, vinicius.gomes@intel.com, vedang.patel@intel.com, richardcochran@gmail.com Cc: weifeng.voon@intel.com, jiri@mellanox.com, m-karicheri2@ti.com, Jose.Abreu@synopsys.com, ilias.apalodimas@linaro.org, --to=jhs@mojatatu.com, --to=xiyou.wangcong@gmail.com, netdev@vger.kernel.org, Vladimir Oltean Subject: [RFC PATCH v2 net-next 07/15] net: dsa: sja1105: Move PTP data to its own private structure Date: Fri, 30 Aug 2019 03:46:27 +0300 Message-Id: <20190830004635.24863-8-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190830004635.24863-1-olteanv@gmail.com> References: <20190830004635.24863-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Reduce the size of the sja1105_private structure when CONFIG_NET_DSA_SJA1105_PTP is not enabled. Also make the PTP code a little bit more self-contained. Signed-off-by: Vladimir Oltean --- drivers/net/dsa/sja1105/sja1105.h | 20 +------ drivers/net/dsa/sja1105/sja1105_main.c | 12 ++-- drivers/net/dsa/sja1105/sja1105_ptp.c | 81 +++++++++++++++----------- drivers/net/dsa/sja1105/sja1105_ptp.h | 29 +++++++++ 4 files changed, 84 insertions(+), 58 deletions(-) diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index c80be59dafbd..3ca0b87aa3e4 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -20,6 +20,8 @@ */ #define SJA1105_AGEING_TIME_MS(ms) ((ms) / 10) +#include "sja1105_ptp.h" + /* Keeps the different addresses between E/T and P/Q/R/S */ struct sja1105_regs { u64 device_id; @@ -49,17 +51,6 @@ struct sja1105_regs { u64 qlevel[SJA1105_NUM_PORTS]; }; -enum sja1105_ptp_clk_mode { - PTP_ADD_MODE = 1, - PTP_SET_MODE = 0, -}; - -struct sja1105_ptp_cmd { - u64 resptp; /* reset */ - u64 corrclk4ts; /* use the corrected clock for timestamps */ - u64 ptpclkadd; /* enum sja1105_ptp_clk_mode */ -}; - struct sja1105_info { u64 device_id; /* Needed for distinction between P and R, and between Q and S @@ -99,20 +90,15 @@ struct sja1105_private { struct spi_device *spidev; struct dsa_switch *ds; struct sja1105_port ports[SJA1105_NUM_PORTS]; - struct sja1105_ptp_cmd ptp_cmd; - struct ptp_clock_info ptp_caps; - struct ptp_clock *clock; - /* Serializes all operations on the PTP hardware clock */ - struct mutex ptp_lock; /* Serializes transmission of management frames so that * the switch doesn't confuse them with one another. */ struct mutex mgmt_lock; struct sja1105_tagger_data tagger_data; + struct sja1105_ptp_data ptp_data; }; #include "sja1105_dynamic_config.h" -#include "sja1105_ptp.h" struct sja1105_spi_message { u64 access; diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index d92f15b3aea9..670c069722d5 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -1406,7 +1406,7 @@ static int sja1105_static_config_reload(struct sja1105_private *priv) } /* No PTP operations can run right now */ - mutex_lock(&priv->ptp_lock); + mutex_lock(&priv->ptp_data.lock); ptpclkval = __sja1105_ptp_gettimex(priv, &ptp_sts_before); @@ -1433,7 +1433,7 @@ static int sja1105_static_config_reload(struct sja1105_private *priv) __sja1105_ptp_adjtime(priv, ptpclkval); out_unlock_ptp: - mutex_unlock(&priv->ptp_lock); + mutex_unlock(&priv->ptp_data.lock); /* Configure the CGU (PLLs) for MII and RMII PHYs. * For these interfaces there is no dynamic configuration @@ -1876,7 +1876,7 @@ static netdev_tx_t sja1105_port_deferred_xmit(struct dsa_switch *ds, int port, skb_shinfo(clone)->tx_flags |= SKBTX_IN_PROGRESS; - mutex_lock(&priv->ptp_lock); + mutex_lock(&priv->ptp_data.lock); ticks = sja1105_ptpclkval_read(priv, NULL); @@ -1893,7 +1893,7 @@ static netdev_tx_t sja1105_port_deferred_xmit(struct dsa_switch *ds, int port, skb_complete_tx_timestamp(clone, &shwt); out_unlock_ptp: - mutex_unlock(&priv->ptp_lock); + mutex_unlock(&priv->ptp_data.lock); out: mutex_unlock(&priv->mgmt_lock); return NETDEV_TX_OK; @@ -2029,7 +2029,7 @@ static void sja1105_rxtstamp_work(struct work_struct *work) struct sk_buff *skb; u64 ticks; - mutex_lock(&priv->ptp_lock); + mutex_lock(&priv->ptp_data.lock); ticks = sja1105_ptpclkval_read(priv, NULL); @@ -2046,7 +2046,7 @@ static void sja1105_rxtstamp_work(struct work_struct *work) netif_rx_ni(skb); } - mutex_unlock(&priv->ptp_lock); + mutex_unlock(&priv->ptp_data.lock); } /* Called from dsa_skb_defer_rx_timestamp */ diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.c b/drivers/net/dsa/sja1105/sja1105_ptp.c index a7722c0944fb..f85f44bdab31 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.c +++ b/drivers/net/dsa/sja1105/sja1105_ptp.c @@ -34,7 +34,10 @@ #define SJA1105_CC_MULT_DEM 15625 #define SJA1105_CC_MULT 0x80000000 -#define ptp_to_sja1105(d) container_of((d), struct sja1105_private, ptp_caps) +#define ptp_to_sja1105_data(d) \ + container_of((d), struct sja1105_ptp_data, caps) +#define ptp_data_to_sja1105(d) \ + container_of((d), struct sja1105_private, ptp_data) int sja1105_get_ts_info(struct dsa_switch *ds, int port, struct ethtool_ts_info *info) @@ -42,7 +45,7 @@ int sja1105_get_ts_info(struct dsa_switch *ds, int port, struct sja1105_private *priv = ds->priv; /* Called during cleanup */ - if (!priv->clock) + if (!priv->ptp_data.clock) return -ENODEV; info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE | @@ -52,7 +55,7 @@ int sja1105_get_ts_info(struct dsa_switch *ds, int port, (1 << HWTSTAMP_TX_ON); info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT); - info->phc_index = ptp_clock_index(priv->clock); + info->phc_index = ptp_clock_index(priv->ptp_data.clock); return 0; } @@ -200,22 +203,23 @@ int sja1105_ptpegr_ts_poll(struct sja1105_private *priv, int port, u64 *ts) int sja1105_ptp_reset(struct sja1105_private *priv) { - struct sja1105_ptp_cmd cmd = priv->ptp_cmd; + struct sja1105_ptp_data *ptp_data = &priv->ptp_data; + struct sja1105_ptp_cmd cmd = ptp_data->cmd; int rc; - mutex_lock(&priv->ptp_lock); + mutex_lock(&ptp_data->lock); cmd.resptp = 1; dev_dbg(priv->ds->dev, "Resetting PTP clock\n"); rc = priv->info->ptp_cmd(priv, &cmd); - mutex_unlock(&priv->ptp_lock); + mutex_unlock(&ptp_data->lock); return rc; } -/* Caller must hold priv->ptp_lock */ +/* Caller must hold priv->ptp_data.lock */ u64 __sja1105_ptp_gettimex(struct sja1105_private *priv, struct ptp_system_timestamp *sts) { @@ -230,30 +234,31 @@ static int sja1105_ptp_gettimex(struct ptp_clock_info *ptp, struct timespec64 *ts, struct ptp_system_timestamp *sts) { - struct sja1105_private *priv = ptp_to_sja1105(ptp); + struct sja1105_ptp_data *ptp_data = ptp_to_sja1105_data(ptp); + struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data); - mutex_lock(&priv->ptp_lock); + mutex_lock(&ptp_data->lock); *ts = ns_to_timespec64(__sja1105_ptp_gettimex(priv, sts)); - mutex_unlock(&priv->ptp_lock); + mutex_unlock(&ptp_data->lock); return 0; } -/* Caller must hold priv->ptp_lock */ +/* Caller must hold priv->ptp_data.lock */ static int sja1105_ptp_mode_set(struct sja1105_private *priv, enum sja1105_ptp_clk_mode mode) { - if (priv->ptp_cmd.ptpclkadd == mode) + if (priv->ptp_data.cmd.ptpclkadd == mode) return 0; - priv->ptp_cmd.ptpclkadd = mode; + priv->ptp_data.cmd.ptpclkadd = mode; - return priv->info->ptp_cmd(priv, &priv->ptp_cmd); + return priv->info->ptp_cmd(priv, &priv->ptp_data.cmd); } -/* Caller must hold priv->ptp_lock */ +/* Caller must hold priv->ptp_data.lock */ static int sja1105_ptpclkval_write(struct sja1105_private *priv, u64 val, struct ptp_system_timestamp *ptp_sts) { @@ -282,22 +287,24 @@ int __sja1105_ptp_settime(struct sja1105_private *priv, u64 ns, static int sja1105_ptp_settime(struct ptp_clock_info *ptp, const struct timespec64 *ts) { - struct sja1105_private *priv = ptp_to_sja1105(ptp); + struct sja1105_ptp_data *ptp_data = ptp_to_sja1105_data(ptp); + struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data); u64 ns = timespec64_to_ns(ts); int rc; - mutex_lock(&priv->ptp_lock); + mutex_lock(&ptp_data->lock); rc = __sja1105_ptp_settime(priv, ns, NULL); - mutex_unlock(&priv->ptp_lock); + mutex_unlock(&ptp_data->lock); return rc; } static int sja1105_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) { - struct sja1105_private *priv = ptp_to_sja1105(ptp); + struct sja1105_ptp_data *ptp_data = ptp_to_sja1105_data(ptp); + struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data); const struct sja1105_regs *regs = priv->info->regs; s64 clkrate; int rc; @@ -309,17 +316,17 @@ static int sja1105_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) clkrate = SJA1105_CC_MULT + clkrate; clkrate &= GENMASK_ULL(31, 0); - mutex_lock(&priv->ptp_lock); + mutex_lock(&priv->ptp_data.lock); rc = sja1105_spi_send_int(priv, SPI_WRITE, regs->ptpclkrate, &clkrate, 4, NULL); - mutex_unlock(&priv->ptp_lock); + mutex_unlock(&priv->ptp_data.lock); return rc; } -/* Caller must hold priv->ptp_lock */ +/* Caller must hold priv->ptp_data.lock */ u64 sja1105_ptpclkval_read(struct sja1105_private *priv, struct ptp_system_timestamp *sts) { @@ -354,23 +361,25 @@ int __sja1105_ptp_adjtime(struct sja1105_private *priv, s64 delta) static int sja1105_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) { - struct sja1105_private *priv = ptp_to_sja1105(ptp); + struct sja1105_ptp_data *ptp_data = ptp_to_sja1105_data(ptp); + struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data); int rc; - mutex_lock(&priv->ptp_lock); + mutex_lock(&ptp_data->lock); rc = __sja1105_ptp_adjtime(priv, delta); - mutex_unlock(&priv->ptp_lock); + mutex_unlock(&ptp_data->lock); return rc; } int sja1105_ptp_clock_register(struct sja1105_private *priv) { + struct sja1105_ptp_data *ptp_data = &priv->ptp_data; struct dsa_switch *ds = priv->ds; - priv->ptp_caps = (struct ptp_clock_info) { + ptp_data->caps = (struct ptp_clock_info) { .owner = THIS_MODULE, .name = "SJA1105 PHC", .adjfine = sja1105_ptp_adjfine, @@ -380,23 +389,25 @@ int sja1105_ptp_clock_register(struct sja1105_private *priv) .max_adj = SJA1105_MAX_ADJ_PPB, }; - mutex_init(&priv->ptp_lock); + mutex_init(&ptp_data->lock); - priv->clock = ptp_clock_register(&priv->ptp_caps, ds->dev); - if (IS_ERR_OR_NULL(priv->clock)) - return PTR_ERR(priv->clock); + ptp_data->clock = ptp_clock_register(&ptp_data->caps, ds->dev); + if (IS_ERR_OR_NULL(ptp_data->clock)) + return PTR_ERR(ptp_data->clock); - priv->ptp_cmd.corrclk4ts = true; - priv->ptp_cmd.ptpclkadd = PTP_SET_MODE; + ptp_data->cmd.corrclk4ts = true; + ptp_data->cmd.ptpclkadd = PTP_SET_MODE; return sja1105_ptp_reset(priv); } void sja1105_ptp_clock_unregister(struct sja1105_private *priv) { - if (IS_ERR_OR_NULL(priv->clock)) + struct sja1105_ptp_data *ptp_data = &priv->ptp_data; + + if (IS_ERR_OR_NULL(ptp_data->clock)) return; - ptp_clock_unregister(priv->clock); - priv->clock = NULL; + ptp_clock_unregister(ptp_data->clock); + ptp_data->clock = NULL; } diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.h b/drivers/net/dsa/sja1105/sja1105_ptp.h index c699611e585d..dfe856200394 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.h +++ b/drivers/net/dsa/sja1105/sja1105_ptp.h @@ -19,8 +19,29 @@ static inline s64 sja1105_ticks_to_ns(s64 ticks) return ticks * SJA1105_TICK_NS; } +struct sja1105_private; + #if IS_ENABLED(CONFIG_NET_DSA_SJA1105_PTP) +enum sja1105_ptp_clk_mode { + PTP_ADD_MODE = 1, + PTP_SET_MODE = 0, +}; + +struct sja1105_ptp_cmd { + u64 resptp; /* reset */ + u64 corrclk4ts; /* use the corrected clock for timestamps */ + u64 ptpclkadd; /* enum sja1105_ptp_clk_mode */ +}; + +struct sja1105_ptp_data { + struct sja1105_ptp_cmd cmd; + struct ptp_clock_info caps; + struct ptp_clock *clock; + /* Serializes all operations on the PTP hardware clock */ + struct mutex lock; +}; + int sja1105_ptp_clock_register(struct sja1105_private *priv); void sja1105_ptp_clock_unregister(struct sja1105_private *priv); @@ -52,6 +73,14 @@ int __sja1105_ptp_adjtime(struct sja1105_private *priv, s64 delta); #else +/* Structures cannot be empty in C. Bah! + * Keep the mutex as the only element, which is a bit more difficult to + * refactor out of sja1105_main.c anyway. + */ +struct sja1105_ptp_data { + struct mutex lock; +}; + static inline int sja1105_ptp_clock_register(struct sja1105_private *priv) { return 0; From patchwork Fri Aug 30 00:46:28 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1155596 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="jj2Uq9yO"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 46KLRC0kRyz9sNC for ; Fri, 30 Aug 2019 10:47:19 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727753AbfH3ArS (ORCPT ); Thu, 29 Aug 2019 20:47:18 -0400 Received: from mail-wr1-f68.google.com ([209.85.221.68]:32866 "EHLO mail-wr1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727548AbfH3ArA (ORCPT ); Thu, 29 Aug 2019 20:47:00 -0400 Received: by mail-wr1-f68.google.com with SMTP id u16so5239347wrr.0 for ; Thu, 29 Aug 2019 17:46:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=okvCbJRGSBW0afYBgPHs06MKr4GY4K4DnCbOWgAvAbY=; b=jj2Uq9yO27vHSCL9gSIIT7Dbh/eBniMdfAl51DoC1RBWAk91zPx73vlWkvts3H5P7l DapgyxCP06gYFFeX31DOjhLAGTy+X8UeC1+SfFohPcQJvryJo5hMK7+6FGgllzU/R5+Y 77wN8sDaggizW7Dkk9WsgGjJkIeusQ3Wl/ipA5pXI6OveVxFnw1emKmCHWcOn9tXVwPL YUwBU+G6Gb+a1V6Q+3HcQawuraelfLVFxI6N4/Qn6vowILxzm0A9HaqUJ0searTihzce BbVMhkRuithfgyfn4I60+Yehr6xfJwBaEP3uHq0rzeRYQWrg+l0UI9Y24OV7D5uyFig0 aBrA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=okvCbJRGSBW0afYBgPHs06MKr4GY4K4DnCbOWgAvAbY=; b=ZG2mRUDqBiOBNqdTCpOX6wfDjScD+BvbjKvYFAGiCwORTvnZwo/MbxejwI6ojx5Q23 m2A6i5SYnCfvimKAu6FYConl2FGGnuy+95Tx9CacCv81Elk3KkGTVtB3G7gbfeaQ7C4D LhtMwQ8P3eZKhH//itvX43/z9gQFdkh4H7SEHfTp+qxQXtOWWXkGFRCy21dAy6yMYRNj ai6VPocaFmwWFCSMkq6vWjPBLk+vR1KAp1vPTI5SRWvBzwmvkQ8duFoxfhk7K8yJSETC KzHX+oPjKv7HAY+9z7BgHabTMBXCwMjC6p8P5jQpEL31T2J/EhDJlHR5FWPh7kcAiGHw e9Wg== X-Gm-Message-State: APjAAAVt10qdcPAjB912wVHZpuWsGOKtfrT++bKjTUg/oc3cSsZ2Yxf2 Ucx9XvbQCwYMAHx5hQkFGgc= X-Google-Smtp-Source: APXvYqxDq4phU+cZIvBCICDJP8ACzBvm4hRiFcKVdHiGySYePHBWh8sIs7Pg3yJe9PpWJNh1ZkxAcg== X-Received: by 2002:a5d:4d81:: with SMTP id b1mr15666885wru.27.1567126018463; Thu, 29 Aug 2019 17:46:58 -0700 (PDT) Received: from localhost.localdomain ([86.126.25.232]) by smtp.gmail.com with ESMTPSA id y3sm9298442wmg.2.2019.08.29.17.46.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Aug 2019 17:46:58 -0700 (PDT) From: Vladimir Oltean To: f.fainelli@gmail.com, vivien.didelot@gmail.com, andrew@lunn.ch, davem@davemloft.net, vinicius.gomes@intel.com, vedang.patel@intel.com, richardcochran@gmail.com Cc: weifeng.voon@intel.com, jiri@mellanox.com, m-karicheri2@ti.com, Jose.Abreu@synopsys.com, ilias.apalodimas@linaro.org, --to=jhs@mojatatu.com, --to=xiyou.wangcong@gmail.com, netdev@vger.kernel.org, Vladimir Oltean Subject: [RFC PATCH v2 net-next 08/15] net: dsa: sja1105: Advertise the 8 TX queues Date: Fri, 30 Aug 2019 03:46:28 +0300 Message-Id: <20190830004635.24863-9-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190830004635.24863-1-olteanv@gmail.com> References: <20190830004635.24863-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This is a preparation patch for the tc-taprio offload (and potentially for other future offloads such as tc-mqprio). Instead of looking directly at skb->priority during xmit, let's get the netdev queue and the queue-to-traffic-class mapping, and put the resulting traffic class into the dsa_8021q PCP field. The switch is configured with a 1-to-1 PCP-to-ingress-queue-to-egress-queue mapping (see vlan_pmap in sja1105_main.c), so the effect is that we can inject into a front-panel's egress traffic class through VLAN tagging from Linux, completely transparently. Unfortunately the switch doesn't look at the VLAN PCP in the case of management traffic to/from the CPU (link-local frames at 01-80-C2-xx-xx-xx or 01-1B-19-xx-xx-xx) so we can't alter the transmission queue of this type of traffic on a frame-by-frame basis. It is only selected through the "hostprio" setting which ATM is harcoded in the driver to 7. Signed-off-by: Vladimir Oltean --- drivers/net/dsa/sja1105/sja1105_main.c | 7 ++++++- net/dsa/tag_sja1105.c | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index 670c069722d5..8b930cc2dabc 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -384,7 +384,9 @@ static int sja1105_init_general_params(struct sja1105_private *priv) /* Disallow dynamic changing of the mirror port */ .mirr_ptacu = 0, .switchid = priv->ds->index, - /* Priority queue for link-local frames trapped to CPU */ + /* Priority queue for link-local management frames + * (both ingress to and egress from CPU - PTP, STP etc) + */ .hostprio = 7, .mac_fltres1 = SJA1105_LINKLOCAL_FILTER_A, .mac_flt1 = SJA1105_LINKLOCAL_FILTER_A_MASK, @@ -1745,6 +1747,9 @@ static int sja1105_setup(struct dsa_switch *ds) */ ds->vlan_filtering_is_global = true; + /* Advertise the 8 egress queues */ + ds->num_tx_queues = SJA1105_NUM_TC; + /* The DSA/switchdev model brings up switch ports in standalone mode by * default, and that means vlan_filtering is 0 since they're not under * a bridge, so it's safe to set up switch tagging at this time. diff --git a/net/dsa/tag_sja1105.c b/net/dsa/tag_sja1105.c index 47ee88163a9d..9c9aff3e52cf 100644 --- a/net/dsa/tag_sja1105.c +++ b/net/dsa/tag_sja1105.c @@ -89,7 +89,8 @@ static struct sk_buff *sja1105_xmit(struct sk_buff *skb, struct dsa_port *dp = dsa_slave_to_port(netdev); struct dsa_switch *ds = dp->ds; u16 tx_vid = dsa_8021q_tx_vid(ds, dp->index); - u8 pcp = skb->priority; + u16 queue_mapping = skb_get_queue_mapping(skb); + u8 pcp = netdev_txq_to_tc(netdev, queue_mapping); /* Transmitting management traffic does not rely upon switch tagging, * but instead SPI-installed management routes. Part 2 of this From patchwork Fri Aug 30 00:46:29 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1155592 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="K68gMon0"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 46KLR22Jljz9sNC for ; Fri, 30 Aug 2019 10:47:10 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727681AbfH3ArH (ORCPT ); Thu, 29 Aug 2019 20:47:07 -0400 Received: from mail-wm1-f65.google.com ([209.85.128.65]:51361 "EHLO mail-wm1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727604AbfH3ArB (ORCPT ); Thu, 29 Aug 2019 20:47:01 -0400 Received: by mail-wm1-f65.google.com with SMTP id k1so5496811wmi.1 for ; Thu, 29 Aug 2019 17:47:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=jkB/fQrumz+D8ijtPzdGU5sUKjYl9rcJNuttAQ1GgOo=; b=K68gMon0zJyTYCLlYDJzpeiQm1D38jLSyMzMAzm2dL/o+Slb0hFqiZPymF2krR39tY /22DZ3l/5YeyMunVTWq+cmXPR8dHTvHGFjKbPP1LxdYwtBLXyAeiTCJMI7bfNtzqkWWK 7dNl6STL7M4Bp0GfSTs4nXK/t3KcxyVRIrccTbT5KbYwq2aMo3hCDw9sBrzlHkJYakff oXAgG4DIGx4HcCj66K7ymJPly6z3pbcAhTps9YiS1xNSpZOeVZUZYou9T5xF8Jt3N8C5 P4XlHNwV1K1OFTonwFZU12UTGt8a2gIKy9t/saEbnVQvoagxVQyHm6O3bdt70XqWLnlS NXkw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=jkB/fQrumz+D8ijtPzdGU5sUKjYl9rcJNuttAQ1GgOo=; b=tQ4gcULgVK5EInNdDKQ2DIv3L5Vjwu4vOkLkubphtt9B4H5PcWgAjYzsNUQgy9hjC5 VGDpE9y8f3iQdtITEvMvTkaqCdFiR2Qa3S+qXejxxOW6WyNTl68g+v2DCygX/nTBsmu4 Y6eI7sKWRKRp4qsERV0Fte6mr6lDoekr0qrCcULJ5yUyoHTi3Df4KrkdDT34rJfBHmXv tomd2SsN4aHT+LsqoQDnvbrFbqwlk8b6CKi/bzXOEY+4KIiuIcF1lb+31HLjmMWUIxgG B2GPqqXG5tT3QszXoc+2du61R/Nm/jd9mW0fCEYY/U0ky+2cdhbFdgCTVrADcXDxe2CW T1Ng== X-Gm-Message-State: APjAAAU6XVDVbxo0WCgFBnxJ212cNyV420tKZWBR4KQoyBwW9pvcuW0s QmUEJggr/IcxYbnxrPiwSiw= X-Google-Smtp-Source: APXvYqy8kdRoSMUY+1uRLjufKmHFv/h942bQ1sMeF8/PBVTrRGEx6anZv40frQQwuYAb8zEDL5jcDA== X-Received: by 2002:a1c:18d:: with SMTP id 135mr14601477wmb.171.1567126019871; Thu, 29 Aug 2019 17:46:59 -0700 (PDT) Received: from localhost.localdomain ([86.126.25.232]) by smtp.gmail.com with ESMTPSA id y3sm9298442wmg.2.2019.08.29.17.46.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Aug 2019 17:46:59 -0700 (PDT) From: Vladimir Oltean To: f.fainelli@gmail.com, vivien.didelot@gmail.com, andrew@lunn.ch, davem@davemloft.net, vinicius.gomes@intel.com, vedang.patel@intel.com, richardcochran@gmail.com Cc: weifeng.voon@intel.com, jiri@mellanox.com, m-karicheri2@ti.com, Jose.Abreu@synopsys.com, ilias.apalodimas@linaro.org, --to=jhs@mojatatu.com, --to=xiyou.wangcong@gmail.com, netdev@vger.kernel.org, Vladimir Oltean Subject: [RFC PATCH v2 net-next 09/15] taprio: Add support for hardware offloading Date: Fri, 30 Aug 2019 03:46:29 +0300 Message-Id: <20190830004635.24863-10-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190830004635.24863-1-olteanv@gmail.com> References: <20190830004635.24863-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Vinicius Costa Gomes This allows taprio to offload the schedule enforcement to capable network cards, resulting in more precise windows and less CPU usage. The important detail here is the difference between the gate_mask in taprio and gate_mask for the network driver. For the driver, each bit in gate_mask references a transmission queue: bit 0 for queue 0, bit 1 for queue 1, and so on. This is done so the driver doesn't need to know about traffic classes. Two reference counting API helpers are also added to support the use case where Ethernet drivers need to keep the taprio offload structure locally (i.e. they are a multi-port switch driver, and configuring a port depends on the settings of other ports as well). Signed-off-by: Vinicius Costa Gomes Signed-off-by: Voon Weifeng Signed-off-by: Vladimir Oltean --- include/linux/netdevice.h | 1 + include/net/pkt_sched.h | 33 +++++ include/uapi/linux/pkt_sched.h | 3 +- net/sched/sch_taprio.c | 246 ++++++++++++++++++++++++++++++++- 4 files changed, 279 insertions(+), 4 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index b5d28dadf964..8225631b9315 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -847,6 +847,7 @@ enum tc_setup_type { TC_SETUP_QDISC_ETF, TC_SETUP_ROOT_QDISC, TC_SETUP_QDISC_GRED, + TC_SETUP_QDISC_TAPRIO, }; /* These structures hold the attributes of bpf state that are being passed diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index a16fbe9a2a67..bba288f9c98b 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -161,4 +161,37 @@ struct tc_etf_qopt_offload { s32 queue; }; +struct tc_taprio_sched_entry { + u8 command; /* TC_TAPRIO_CMD_* */ + + /* The gate_mask in the offloading side refers to HW queues */ + u32 gate_mask; + u32 interval; +}; + +struct tc_taprio_qopt_offload { + refcount_t users; + u8 enable; + ktime_t base_time; + u64 cycle_time; + u64 cycle_time_extension; + + size_t num_entries; + struct tc_taprio_sched_entry entries[0]; +}; + +static inline struct tc_taprio_qopt_offload * +taprio_get(struct tc_taprio_qopt_offload *taprio) +{ + refcount_inc(&taprio->users); + return taprio; +} + +static inline void taprio_free(struct tc_taprio_qopt_offload *taprio) +{ + if (!refcount_dec_and_test(&taprio->users)) + return; + kfree(taprio); +} + #endif diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h index 18f185299f47..5011259b8f67 100644 --- a/include/uapi/linux/pkt_sched.h +++ b/include/uapi/linux/pkt_sched.h @@ -1160,7 +1160,8 @@ enum { * [TCA_TAPRIO_ATTR_SCHED_ENTRY_INTERVAL] */ -#define TCA_TAPRIO_ATTR_FLAG_TXTIME_ASSIST 0x1 +#define TCA_TAPRIO_ATTR_FLAG_TXTIME_ASSIST BIT(0) +#define TCA_TAPRIO_ATTR_FLAG_FULL_OFFLOAD BIT(1) enum { TCA_TAPRIO_ATTR_UNSPEC, diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c index 645ae744390b..219a4611b202 100644 --- a/net/sched/sch_taprio.c +++ b/net/sched/sch_taprio.c @@ -29,8 +29,10 @@ static DEFINE_SPINLOCK(taprio_list_lock); #define TAPRIO_ALL_GATES_OPEN -1 -#define FLAGS_VALID(flags) (!((flags) & ~TCA_TAPRIO_ATTR_FLAG_TXTIME_ASSIST)) +#define FLAGS_VALID(flags) (!((flags) & ~(TCA_TAPRIO_ATTR_FLAG_TXTIME_ASSIST | \ + TCA_TAPRIO_ATTR_FLAG_FULL_OFFLOAD))) #define TXTIME_ASSIST_IS_ENABLED(flags) ((flags) & TCA_TAPRIO_ATTR_FLAG_TXTIME_ASSIST) +#define FULL_OFFLOAD_IS_ENABLED(flags) ((flags) & TCA_TAPRIO_ATTR_FLAG_FULL_OFFLOAD) struct sched_entry { struct list_head list; @@ -75,6 +77,8 @@ struct taprio_sched { struct sched_gate_list __rcu *admin_sched; struct hrtimer advance_timer; struct list_head taprio_list; + struct sk_buff *(*dequeue)(struct Qdisc *sch); + struct sk_buff *(*peek)(struct Qdisc *sch); u32 txtime_delay; }; @@ -417,7 +421,7 @@ static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch, return qdisc_enqueue(skb, child, to_free); } -static struct sk_buff *taprio_peek(struct Qdisc *sch) +static struct sk_buff *taprio_peek_soft(struct Qdisc *sch) { struct taprio_sched *q = qdisc_priv(sch); struct net_device *dev = qdisc_dev(sch); @@ -461,6 +465,36 @@ static struct sk_buff *taprio_peek(struct Qdisc *sch) return NULL; } +static struct sk_buff *taprio_peek_offload(struct Qdisc *sch) +{ + struct taprio_sched *q = qdisc_priv(sch); + struct net_device *dev = qdisc_dev(sch); + struct sk_buff *skb; + int i; + + for (i = 0; i < dev->num_tx_queues; i++) { + struct Qdisc *child = q->qdiscs[i]; + + if (unlikely(!child)) + continue; + + skb = child->ops->peek(child); + if (!skb) + continue; + + return skb; + } + + return NULL; +} + +static struct sk_buff *taprio_peek(struct Qdisc *sch) +{ + struct taprio_sched *q = qdisc_priv(sch); + + return q->peek(sch); +} + static void taprio_set_budget(struct taprio_sched *q, struct sched_entry *entry) { atomic_set(&entry->budget, @@ -468,7 +502,7 @@ static void taprio_set_budget(struct taprio_sched *q, struct sched_entry *entry) atomic64_read(&q->picos_per_byte))); } -static struct sk_buff *taprio_dequeue(struct Qdisc *sch) +static struct sk_buff *taprio_dequeue_soft(struct Qdisc *sch) { struct taprio_sched *q = qdisc_priv(sch); struct net_device *dev = qdisc_dev(sch); @@ -550,6 +584,40 @@ static struct sk_buff *taprio_dequeue(struct Qdisc *sch) return skb; } +static struct sk_buff *taprio_dequeue_offload(struct Qdisc *sch) +{ + struct taprio_sched *q = qdisc_priv(sch); + struct net_device *dev = qdisc_dev(sch); + struct sk_buff *skb; + int i; + + for (i = 0; i < dev->num_tx_queues; i++) { + struct Qdisc *child = q->qdiscs[i]; + + if (unlikely(!child)) + continue; + + skb = child->ops->dequeue(child); + if (unlikely(!skb)) + continue; + + qdisc_bstats_update(sch, skb); + qdisc_qstats_backlog_dec(sch, skb); + sch->q.qlen--; + + return skb; + } + + return NULL; +} + +static struct sk_buff *taprio_dequeue(struct Qdisc *sch) +{ + struct taprio_sched *q = qdisc_priv(sch); + + return q->dequeue(sch); +} + static bool should_restart_cycle(const struct sched_gate_list *oper, const struct sched_entry *entry) { @@ -1011,6 +1079,166 @@ static void setup_txtime(struct taprio_sched *q, } } +static u32 tc_mask_to_queue_mask(const struct tc_mqprio_qopt *mqprio, + u32 tc_mask) +{ + u32 i, queue_mask = 0; + + for (i = 0; i < mqprio->num_tc; i++) { + u32 offset, count; + + if (!(tc_mask & BIT(i))) + continue; + + offset = mqprio->offset[i]; + count = mqprio->count[i]; + + queue_mask |= GENMASK(offset + count - 1, offset); + } + + return queue_mask; +} + +static void taprio_sched_to_offload(struct taprio_sched *q, + struct sched_gate_list *sched, + const struct tc_mqprio_qopt *mqprio, + struct tc_taprio_qopt_offload *taprio) +{ + struct sched_entry *entry; + int i = 0; + + taprio->base_time = sched->base_time; + taprio->cycle_time = sched->cycle_time; + taprio->cycle_time_extension = sched->cycle_time_extension; + + list_for_each_entry(entry, &sched->entries, list) { + struct tc_taprio_sched_entry *e = &taprio->entries[i]; + + e->command = entry->command; + e->interval = entry->interval; + + /* We do this transformation because the NIC + * has no knowledge of traffic classes, but it + * knows about queues. + */ + e->gate_mask = tc_mask_to_queue_mask(mqprio, entry->gate_mask); + i++; + } + + taprio->num_entries = i; +} + +static int taprio_disable_offload(struct net_device *dev, + struct taprio_sched *q) +{ + const struct net_device_ops *ops = dev->netdev_ops; + struct tc_taprio_qopt_offload taprio = { }; + int err; + + if (!FULL_OFFLOAD_IS_ENABLED(q->flags)) + return 0; + + if (!ops->ndo_setup_tc) + return -EOPNOTSUPP; + + taprio.enable = 0; + + err = ops->ndo_setup_tc(dev, TC_SETUP_QDISC_TAPRIO, &taprio); + if (err < 0) + return err; + + /* Just to be sure to keep the function pointers in a + * consistent state always. + */ + q->dequeue = taprio_dequeue_soft; + q->peek = taprio_peek_soft; + + q->advance_timer.function = advance_sched; + + q->flags &= ~TCA_TAPRIO_ATTR_FLAG_FULL_OFFLOAD; + + return 0; +} + +static enum hrtimer_restart next_sched(struct hrtimer *timer) +{ + struct taprio_sched *q = container_of(timer, struct taprio_sched, + advance_timer); + struct sched_gate_list *oper, *admin; + bool cond; + + spin_lock(&q->current_entry_lock); + + cond = lockdep_is_held(&q->current_entry_lock); + + oper = rcu_dereference_protected(q->oper_sched, cond); + admin = rcu_dereference_protected(q->admin_sched, cond); + + rcu_assign_pointer(q->oper_sched, admin); + rcu_assign_pointer(q->admin_sched, NULL); + + if (oper) + call_rcu(&oper->rcu, taprio_free_sched_cb); + + spin_unlock(&q->current_entry_lock); + + return HRTIMER_NORESTART; +} + +static int taprio_enable_offload(struct net_device *dev, + struct tc_mqprio_qopt *mqprio, + struct taprio_sched *q, + struct sched_gate_list *sched, + struct netlink_ext_ack *extack) +{ + const struct net_device_ops *ops = dev->netdev_ops; + struct tc_taprio_qopt_offload *taprio; + size_t size; + int err = 0; + + if (!ops->ndo_setup_tc) { + NL_SET_ERR_MSG(extack, + "Device does not support taprio offload"); + return -EOPNOTSUPP; + } + + size = sizeof(*taprio) + + sched->num_entries * sizeof(struct tc_taprio_sched_entry); + + taprio = kzalloc(size, GFP_ATOMIC); + if (!taprio) { + NL_SET_ERR_MSG(extack, + "Not enough memory for enabling offload mode"); + return -ENOMEM; + } + + refcount_set(&taprio->users, 1); + taprio->enable = 1; + taprio_sched_to_offload(q, sched, mqprio, taprio); + + err = ops->ndo_setup_tc(dev, TC_SETUP_QDISC_TAPRIO, taprio); + if (err < 0) { + NL_SET_ERR_MSG(extack, + "Device failed to setup taprio offload"); + goto done; + } + + q->dequeue = taprio_dequeue_offload; + q->peek = taprio_peek_offload; + + /* This function will only serve to keep the pointers to the + * "oper" and "admin" schedules valid in relation to their + * base times, so when calling dump() the users looks at the + * right schedules. + */ + q->advance_timer.function = next_sched; + +done: + taprio_free(taprio); + + return err; +} + static int taprio_change(struct Qdisc *sch, struct nlattr *opt, struct netlink_ext_ack *extack) { @@ -1153,6 +1381,13 @@ static int taprio_change(struct Qdisc *sch, struct nlattr *opt, goto unlock; } + if (FULL_OFFLOAD_IS_ENABLED(taprio_flags)) + err = taprio_enable_offload(dev, mqprio, q, new_admin, extack); + else + err = taprio_disable_offload(dev, q); + if (err) + goto unlock; + err = taprio_get_start_time(sch, new_admin, &start); if (err < 0) { NL_SET_ERR_MSG(extack, "Internal error: failed get start time"); @@ -1217,6 +1452,8 @@ static void taprio_destroy(struct Qdisc *sch) hrtimer_cancel(&q->advance_timer); + taprio_disable_offload(dev, q); + if (q->qdiscs) { for (i = 0; i < dev->num_tx_queues && q->qdiscs[i]; i++) qdisc_put(q->qdiscs[i]); @@ -1246,6 +1483,9 @@ static int taprio_init(struct Qdisc *sch, struct nlattr *opt, hrtimer_init(&q->advance_timer, CLOCK_TAI, HRTIMER_MODE_ABS); q->advance_timer.function = advance_sched; + q->dequeue = taprio_dequeue_soft; + q->peek = taprio_peek_soft; + q->root = sch; /* We only support static clockids. Use an invalid value as default From patchwork Fri Aug 30 00:46:30 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1155590 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="uSNj2Zfh"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 46KLQy3rBpz9sN6 for ; Fri, 30 Aug 2019 10:47:06 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727663AbfH3ArF (ORCPT ); Thu, 29 Aug 2019 20:47:05 -0400 Received: from mail-wm1-f66.google.com ([209.85.128.66]:51363 "EHLO mail-wm1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727174AbfH3ArC (ORCPT ); Thu, 29 Aug 2019 20:47:02 -0400 Received: by mail-wm1-f66.google.com with SMTP id k1so5496827wmi.1 for ; Thu, 29 Aug 2019 17:47:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=DoxoK+E7bV8EyL0Za1CahweAzSzRuPAoZfR/YFCzTo4=; b=uSNj2ZfhTWPs/Wx9NI9fx9UoOTcInR18tJuBYO3nv/SvG/rXHlU/SaHBAn+TubDH2v uNvjz9Tk+I1s0C0HGXjA8Nbc0qKGAn6rJ42wCu3DzHEi0AHV6Y3iNC6D9emmlIHOlDb9 jPn9xC2NCEPm+ncKyaJ+unv52bOw+JQsG5r8Y+NAgvrnOc4G6Ol43I1lzwrbZtE70N5O xel76YP8vxnNPCGM2jaVVNtG+ZlgHv/eZlnyq5tvhjGhhZdQ+gDUO50eu5J6BPunlIUI /1hEnJAt6iB5vosRMzf4Dau5fQhuVBlnAvhK1agsS3w1NcTedFnj4qhJMQAcO8JMRmfZ IjRQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=DoxoK+E7bV8EyL0Za1CahweAzSzRuPAoZfR/YFCzTo4=; b=agmHU1m9Db3IjxdPgnGka91qGq4sbYIA0YdyK0Ban8EV9MAZM81hMOmA4RmeOoqazg e8QOmM5w97FPma/5y6TIJ4n20e/wKhLOO9ePtwmWBYARWZVWHsy1wm8p9WLdE3qmBJOZ pNbJqLbs4YV5ndiBzZbGTVYQ/ilp1Xor7iQnGvgzjDsLvFW9BEv7zQ0nWWiiHrzJvf0C gbB6c0WbtmiMztaROV4WkDFy6U9lRKpAAx7zdxwIV6ZZHlgVAUqiS46BoKJZ/jEjdS2L yyn3RjhGj0cJBkbQLHii5xwe3WTFurs8Q99+fZEFybpB8DKyeydje4HocMeZaohmwsPD IMbg== X-Gm-Message-State: APjAAAWfFUk+x1b5UG24RCZ58eGTuAKf7XdoweRC3+1v9Mb2nnUtq9QZ 0e0ZhnKHXK9vzk9DMlFpypjvAswz+Hw= X-Google-Smtp-Source: APXvYqyH10Duyyx8/U7ZfCBXMSWXBQ67M3hfjtcedBdZxe7wsIKgweGMfMkEGemJL/2iSdKQTGQ8jg== X-Received: by 2002:a7b:c019:: with SMTP id c25mr15284369wmb.116.1567126021118; Thu, 29 Aug 2019 17:47:01 -0700 (PDT) Received: from localhost.localdomain ([86.126.25.232]) by smtp.gmail.com with ESMTPSA id y3sm9298442wmg.2.2019.08.29.17.46.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Aug 2019 17:47:00 -0700 (PDT) From: Vladimir Oltean To: f.fainelli@gmail.com, vivien.didelot@gmail.com, andrew@lunn.ch, davem@davemloft.net, vinicius.gomes@intel.com, vedang.patel@intel.com, richardcochran@gmail.com Cc: weifeng.voon@intel.com, jiri@mellanox.com, m-karicheri2@ti.com, Jose.Abreu@synopsys.com, ilias.apalodimas@linaro.org, --to=jhs@mojatatu.com, --to=xiyou.wangcong@gmail.com, netdev@vger.kernel.org, Vladimir Oltean Subject: [RFC PATCH v2 net-next 10/15] net: dsa: Pass ndo_setup_tc slave callback to drivers Date: Fri, 30 Aug 2019 03:46:30 +0300 Message-Id: <20190830004635.24863-11-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190830004635.24863-1-olteanv@gmail.com> References: <20190830004635.24863-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org DSA currently handles shared block filters (for the classifier-action qdisc) in the core due to what I believe are simply pragmatic reasons - hiding the complexity from drivers and offerring a simple API for port mirroring. Extend the dsa_slave_setup_tc function by passing all other qdisc offloads to the driver layer, where the driver may choose what it implements and how. DSA is simply a pass-through in this case. There is an open question related to the drivers potentially needing to do work in process context, but .ndo_setup_tc is called in atomic context. At the moment the drivers are left to handle this on their own. The risk is that once accepting the offload callback right away in the DSA core, then the driver would have no way to signal an error back. So right now the driver has to do as much error checking as possible in the atomic context and only defer (probably) the actual configuring of the offload. Signed-off-by: Vladimir Oltean --- include/net/dsa.h | 3 +++ net/dsa/slave.c | 12 ++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/include/net/dsa.h b/include/net/dsa.h index 96acb14ec1a8..232b5d36815d 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -154,6 +154,7 @@ struct dsa_mall_tc_entry { }; }; +struct tc_taprio_qopt_offload; struct dsa_port { /* A CPU port is physically connected to a master device. @@ -515,6 +516,8 @@ struct dsa_switch_ops { bool ingress); void (*port_mirror_del)(struct dsa_switch *ds, int port, struct dsa_mall_mirror_tc_entry *mirror); + int (*port_setup_tc)(struct dsa_switch *ds, int port, + enum tc_setup_type type, void *type_data); /* * Cross-chip operations diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 9a88035517a6..75d58229a4bd 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -1035,12 +1035,16 @@ static int dsa_slave_setup_tc_block(struct net_device *dev, static int dsa_slave_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data) { - switch (type) { - case TC_SETUP_BLOCK: + struct dsa_port *dp = dsa_slave_to_port(dev); + struct dsa_switch *ds = dp->ds; + + if (type == TC_SETUP_BLOCK) return dsa_slave_setup_tc_block(dev, type_data); - default: + + if (!ds->ops->port_setup_tc) return -EOPNOTSUPP; - } + + return ds->ops->port_setup_tc(ds, dp->index, type, type_data); } static void dsa_slave_get_stats64(struct net_device *dev, From patchwork Fri Aug 30 00:46:31 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1155591 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="LUc6sFNB"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 46KLR13nKBz9sN6 for ; Fri, 30 Aug 2019 10:47:09 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727708AbfH3ArI (ORCPT ); Thu, 29 Aug 2019 20:47:08 -0400 Received: from mail-wr1-f65.google.com ([209.85.221.65]:46864 "EHLO mail-wr1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727500AbfH3ArF (ORCPT ); Thu, 29 Aug 2019 20:47:05 -0400 Received: by mail-wr1-f65.google.com with SMTP id h7so3867900wrt.13 for ; Thu, 29 Aug 2019 17:47:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=dvFi5mx45b37+pGtmgRj4eItTZ6iaE9A0Ucx9Pj6C6s=; b=LUc6sFNBovKVBnBCtxsQMCKWyR0QlEQmSYHWMle2fXbKI9zIyH06srhJ2a79SV0NY0 78RtzPqLKSaeTSqnPbeP813Aie9ZRcj3dsCYqmasm64hASLJIT39rY2HzMvSDvKAIeok VTy+DZUz9Gm4Yq2Mc+D6Fnxle+6fzLexE+NDdlsN74kFTgOTSwHm1ctP+j8dkgrDe+G/ qVOMJX6HVjZcyKtMjfAq8+BOWzbsN63UcundV5IHImn94ItpQo5P/Y4EdDShejYs3Don fjLGJIOnQD4/U8JzLHy0uQmkAHlEFk7U8mEuy5n/JnlrkK+dXdTQOi/UAR3JbAMssd/q JlYw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=dvFi5mx45b37+pGtmgRj4eItTZ6iaE9A0Ucx9Pj6C6s=; b=HHC/R0F6TzjL1JywhD/DMUtlmFgUPhG4WdazfiVpFROYUQR+TFtY24ww0c2HnZN1Bs sP/f873fYZB+Pi6cKTkbQ89DO+u48BPoH+mqRSDBCeRWMEgo4VcZ8QlMmgiy3BE/qCQz yXHSHW/sMI/tG4q8rKfhZ5r4Pffd/2Fp1q9TA5A+QfZUDb41oyC3m8zS4df18MF8GQqb y3fNnCjVwklkc1lfhlagoGxk4Mq2eegWsO4PRIzWutdQp8P+5SUvGPnKOyxv/1OJ10Ny j/cRCPBhx26YUdaSmLcN68k3dl1bPPXE3BX9+99cCCtY6q5qgx66HkclaX7T6l001CIO uUjg== X-Gm-Message-State: APjAAAV2yxMP2jaOAgCQ/O1SLtZ5s93CXSFkow+V+wEdH45+227if6y0 /g03m/lQfC2WEJVyYKIVOns= X-Google-Smtp-Source: APXvYqyiM+UHOPJeWyk5qrHFAcYrzXbGO1+wxEYa4yK57iWY60CSi4nuBRoNzDFgtnRHAQpdQiaTXw== X-Received: by 2002:adf:d852:: with SMTP id k18mr5882382wrl.88.1567126022546; Thu, 29 Aug 2019 17:47:02 -0700 (PDT) Received: from localhost.localdomain ([86.126.25.232]) by smtp.gmail.com with ESMTPSA id y3sm9298442wmg.2.2019.08.29.17.47.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Aug 2019 17:47:01 -0700 (PDT) From: Vladimir Oltean To: f.fainelli@gmail.com, vivien.didelot@gmail.com, andrew@lunn.ch, davem@davemloft.net, vinicius.gomes@intel.com, vedang.patel@intel.com, richardcochran@gmail.com Cc: weifeng.voon@intel.com, jiri@mellanox.com, m-karicheri2@ti.com, Jose.Abreu@synopsys.com, ilias.apalodimas@linaro.org, --to=jhs@mojatatu.com, --to=xiyou.wangcong@gmail.com, netdev@vger.kernel.org, Vladimir Oltean Subject: [RFC PATCH v2 net-next 11/15] net: dsa: sja1105: Add static config tables for scheduling Date: Fri, 30 Aug 2019 03:46:31 +0300 Message-Id: <20190830004635.24863-12-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190830004635.24863-1-olteanv@gmail.com> References: <20190830004635.24863-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org In order to support tc-taprio offload, the TTEthernet egress scheduling core registers must be made visible through the static interface. Signed-off-by: Vladimir Oltean --- .../net/dsa/sja1105/sja1105_dynamic_config.c | 8 + .../net/dsa/sja1105/sja1105_static_config.c | 167 ++++++++++++++++++ .../net/dsa/sja1105/sja1105_static_config.h | 48 ++++- 3 files changed, 222 insertions(+), 1 deletion(-) diff --git a/drivers/net/dsa/sja1105/sja1105_dynamic_config.c b/drivers/net/dsa/sja1105/sja1105_dynamic_config.c index 9988c9d18567..91da430045ff 100644 --- a/drivers/net/dsa/sja1105/sja1105_dynamic_config.c +++ b/drivers/net/dsa/sja1105/sja1105_dynamic_config.c @@ -488,6 +488,8 @@ sja1105et_general_params_entry_packing(void *buf, void *entry_ptr, /* SJA1105E/T: First generation */ struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = { + [BLK_IDX_SCHEDULE] = {0}, + [BLK_IDX_SCHEDULE_ENTRY_POINTS] = {0}, [BLK_IDX_L2_LOOKUP] = { .entry_packing = sja1105et_dyn_l2_lookup_entry_packing, .cmd_packing = sja1105et_l2_lookup_cmd_packing, @@ -529,6 +531,8 @@ struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = { .packed_size = SJA1105ET_SIZE_MAC_CONFIG_DYN_CMD, .addr = 0x36, }, + [BLK_IDX_SCHEDULE_PARAMS] = {0}, + [BLK_IDX_SCHEDULE_ENTRY_POINTS_PARAMS] = {0}, [BLK_IDX_L2_LOOKUP_PARAMS] = { .entry_packing = sja1105et_l2_lookup_params_entry_packing, .cmd_packing = sja1105et_l2_lookup_params_cmd_packing, @@ -552,6 +556,8 @@ struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = { /* SJA1105P/Q/R/S: Second generation */ struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = { + [BLK_IDX_SCHEDULE] = {0}, + [BLK_IDX_SCHEDULE_ENTRY_POINTS] = {0}, [BLK_IDX_L2_LOOKUP] = { .entry_packing = sja1105pqrs_dyn_l2_lookup_entry_packing, .cmd_packing = sja1105pqrs_l2_lookup_cmd_packing, @@ -593,6 +599,8 @@ struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = { .packed_size = SJA1105PQRS_SIZE_MAC_CONFIG_DYN_CMD, .addr = 0x4B, }, + [BLK_IDX_SCHEDULE_PARAMS] = {0}, + [BLK_IDX_SCHEDULE_ENTRY_POINTS_PARAMS] = {0}, [BLK_IDX_L2_LOOKUP_PARAMS] = { .entry_packing = sja1105et_l2_lookup_params_entry_packing, .cmd_packing = sja1105et_l2_lookup_params_cmd_packing, diff --git a/drivers/net/dsa/sja1105/sja1105_static_config.c b/drivers/net/dsa/sja1105/sja1105_static_config.c index b31c737dc560..0d03e13e9909 100644 --- a/drivers/net/dsa/sja1105/sja1105_static_config.c +++ b/drivers/net/dsa/sja1105/sja1105_static_config.c @@ -371,6 +371,63 @@ size_t sja1105pqrs_mac_config_entry_packing(void *buf, void *entry_ptr, return size; } +static size_t +sja1105_schedule_entry_points_params_entry_packing(void *buf, void *entry_ptr, + enum packing_op op) +{ + struct sja1105_schedule_entry_points_params_entry *entry = entry_ptr; + const size_t size = SJA1105_SIZE_SCHEDULE_ENTRY_POINTS_PARAMS_ENTRY; + + sja1105_packing(buf, &entry->clksrc, 31, 30, size, op); + sja1105_packing(buf, &entry->actsubsch, 29, 27, size, op); + return size; +} + +static size_t +sja1105_schedule_entry_points_entry_packing(void *buf, void *entry_ptr, + enum packing_op op) +{ + struct sja1105_schedule_entry_points_entry *entry = entry_ptr; + const size_t size = SJA1105_SIZE_SCHEDULE_ENTRY_POINTS_ENTRY; + + sja1105_packing(buf, &entry->subschindx, 31, 29, size, op); + sja1105_packing(buf, &entry->delta, 28, 11, size, op); + sja1105_packing(buf, &entry->address, 10, 1, size, op); + return size; +} + +static size_t sja1105_schedule_params_entry_packing(void *buf, void *entry_ptr, + enum packing_op op) +{ + const size_t size = SJA1105_SIZE_SCHEDULE_PARAMS_ENTRY; + struct sja1105_schedule_params_entry *entry = entry_ptr; + int offset, i; + + for (i = 0, offset = 16; i < 8; i++, offset += 10) + sja1105_packing(buf, &entry->subscheind[i], + offset + 9, offset + 0, size, op); + return size; +} + +static size_t sja1105_schedule_entry_packing(void *buf, void *entry_ptr, + enum packing_op op) +{ + const size_t size = SJA1105_SIZE_SCHEDULE_ENTRY; + struct sja1105_schedule_entry *entry = entry_ptr; + + sja1105_packing(buf, &entry->winstindex, 63, 54, size, op); + sja1105_packing(buf, &entry->winend, 53, 53, size, op); + sja1105_packing(buf, &entry->winst, 52, 52, size, op); + sja1105_packing(buf, &entry->destports, 51, 47, size, op); + sja1105_packing(buf, &entry->setvalid, 46, 46, size, op); + sja1105_packing(buf, &entry->txen, 45, 45, size, op); + sja1105_packing(buf, &entry->resmedia_en, 44, 44, size, op); + sja1105_packing(buf, &entry->resmedia, 43, 36, size, op); + sja1105_packing(buf, &entry->vlindex, 35, 26, size, op); + sja1105_packing(buf, &entry->delta, 25, 8, size, op); + return size; +} + size_t sja1105_vlan_lookup_entry_packing(void *buf, void *entry_ptr, enum packing_op op) { @@ -447,11 +504,15 @@ static void sja1105_table_write_crc(u8 *table_start, u8 *crc_ptr) * before blindly indexing kernel memory with the blk_idx. */ static u64 blk_id_map[BLK_IDX_MAX] = { + [BLK_IDX_SCHEDULE] = BLKID_SCHEDULE, + [BLK_IDX_SCHEDULE_ENTRY_POINTS] = BLKID_SCHEDULE_ENTRY_POINTS, [BLK_IDX_L2_LOOKUP] = BLKID_L2_LOOKUP, [BLK_IDX_L2_POLICING] = BLKID_L2_POLICING, [BLK_IDX_VLAN_LOOKUP] = BLKID_VLAN_LOOKUP, [BLK_IDX_L2_FORWARDING] = BLKID_L2_FORWARDING, [BLK_IDX_MAC_CONFIG] = BLKID_MAC_CONFIG, + [BLK_IDX_SCHEDULE_PARAMS] = BLKID_SCHEDULE_PARAMS, + [BLK_IDX_SCHEDULE_ENTRY_POINTS_PARAMS] = BLKID_SCHEDULE_ENTRY_POINTS_PARAMS, [BLK_IDX_L2_LOOKUP_PARAMS] = BLKID_L2_LOOKUP_PARAMS, [BLK_IDX_L2_FORWARDING_PARAMS] = BLKID_L2_FORWARDING_PARAMS, [BLK_IDX_AVB_PARAMS] = BLKID_AVB_PARAMS, @@ -461,6 +522,13 @@ static u64 blk_id_map[BLK_IDX_MAX] = { const char *sja1105_static_config_error_msg[] = { [SJA1105_CONFIG_OK] = "", + [SJA1105_TTETHERNET_NOT_SUPPORTED] = + "schedule-table present, but TTEthernet is " + "only supported on T and Q/S", + [SJA1105_INCORRECT_TTETHERNET_CONFIGURATION] = + "schedule-table present, but one of " + "schedule-entry-points-table, schedule-parameters-table or " + "schedule-entry-points-parameters table is empty", [SJA1105_MISSING_L2_POLICING_TABLE] = "l2-policing-table needs to have at least one entry", [SJA1105_MISSING_L2_FORWARDING_TABLE] = @@ -508,6 +576,21 @@ sja1105_static_config_check_valid(const struct sja1105_static_config *config) #define IS_FULL(blk_idx) \ (tables[blk_idx].entry_count == tables[blk_idx].ops->max_entry_count) + if (tables[BLK_IDX_SCHEDULE].entry_count) { + if (config->device_id != SJA1105T_DEVICE_ID && + config->device_id != SJA1105QS_DEVICE_ID) + return SJA1105_TTETHERNET_NOT_SUPPORTED; + + if (tables[BLK_IDX_SCHEDULE_ENTRY_POINTS].entry_count == 0) + return SJA1105_INCORRECT_TTETHERNET_CONFIGURATION; + + if (!IS_FULL(BLK_IDX_SCHEDULE_PARAMS)) + return SJA1105_INCORRECT_TTETHERNET_CONFIGURATION; + + if (!IS_FULL(BLK_IDX_SCHEDULE_ENTRY_POINTS_PARAMS)) + return SJA1105_INCORRECT_TTETHERNET_CONFIGURATION; + } + if (tables[BLK_IDX_L2_POLICING].entry_count == 0) return SJA1105_MISSING_L2_POLICING_TABLE; @@ -614,6 +697,8 @@ sja1105_static_config_get_length(const struct sja1105_static_config *config) /* SJA1105E: First generation, no TTEthernet */ struct sja1105_table_ops sja1105e_table_ops[BLK_IDX_MAX] = { + [BLK_IDX_SCHEDULE] = {0}, + [BLK_IDX_SCHEDULE_ENTRY_POINTS] = {0}, [BLK_IDX_L2_LOOKUP] = { .packing = sja1105et_l2_lookup_entry_packing, .unpacked_entry_size = sizeof(struct sja1105_l2_lookup_entry), @@ -644,6 +729,8 @@ struct sja1105_table_ops sja1105e_table_ops[BLK_IDX_MAX] = { .packed_entry_size = SJA1105ET_SIZE_MAC_CONFIG_ENTRY, .max_entry_count = SJA1105_MAX_MAC_CONFIG_COUNT, }, + [BLK_IDX_SCHEDULE_PARAMS] = {0}, + [BLK_IDX_SCHEDULE_ENTRY_POINTS_PARAMS] = {0}, [BLK_IDX_L2_LOOKUP_PARAMS] = { .packing = sja1105et_l2_lookup_params_entry_packing, .unpacked_entry_size = sizeof(struct sja1105_l2_lookup_params_entry), @@ -678,6 +765,18 @@ struct sja1105_table_ops sja1105e_table_ops[BLK_IDX_MAX] = { /* SJA1105T: First generation, TTEthernet */ struct sja1105_table_ops sja1105t_table_ops[BLK_IDX_MAX] = { + [BLK_IDX_SCHEDULE] = { + .packing = sja1105_schedule_entry_packing, + .unpacked_entry_size = sizeof(struct sja1105_schedule_entry), + .packed_entry_size = SJA1105_SIZE_SCHEDULE_ENTRY, + .max_entry_count = SJA1105_MAX_SCHEDULE_COUNT, + }, + [BLK_IDX_SCHEDULE_ENTRY_POINTS] = { + .packing = sja1105_schedule_entry_points_entry_packing, + .unpacked_entry_size = sizeof(struct sja1105_schedule_entry_points_entry), + .packed_entry_size = SJA1105_SIZE_SCHEDULE_ENTRY_POINTS_ENTRY, + .max_entry_count = SJA1105_MAX_SCHEDULE_ENTRY_POINTS_COUNT, + }, [BLK_IDX_L2_LOOKUP] = { .packing = sja1105et_l2_lookup_entry_packing, .unpacked_entry_size = sizeof(struct sja1105_l2_lookup_entry), @@ -708,6 +807,18 @@ struct sja1105_table_ops sja1105t_table_ops[BLK_IDX_MAX] = { .packed_entry_size = SJA1105ET_SIZE_MAC_CONFIG_ENTRY, .max_entry_count = SJA1105_MAX_MAC_CONFIG_COUNT, }, + [BLK_IDX_SCHEDULE_PARAMS] = { + .packing = sja1105_schedule_params_entry_packing, + .unpacked_entry_size = sizeof(struct sja1105_schedule_params_entry), + .packed_entry_size = SJA1105_SIZE_SCHEDULE_PARAMS_ENTRY, + .max_entry_count = SJA1105_MAX_SCHEDULE_PARAMS_COUNT, + }, + [BLK_IDX_SCHEDULE_ENTRY_POINTS_PARAMS] = { + .packing = sja1105_schedule_entry_points_params_entry_packing, + .unpacked_entry_size = sizeof(struct sja1105_schedule_entry_points_params_entry), + .packed_entry_size = SJA1105_SIZE_SCHEDULE_ENTRY_POINTS_PARAMS_ENTRY, + .max_entry_count = SJA1105_MAX_SCHEDULE_ENTRY_POINTS_PARAMS_COUNT, + }, [BLK_IDX_L2_LOOKUP_PARAMS] = { .packing = sja1105et_l2_lookup_params_entry_packing, .unpacked_entry_size = sizeof(struct sja1105_l2_lookup_params_entry), @@ -742,6 +853,8 @@ struct sja1105_table_ops sja1105t_table_ops[BLK_IDX_MAX] = { /* SJA1105P: Second generation, no TTEthernet, no SGMII */ struct sja1105_table_ops sja1105p_table_ops[BLK_IDX_MAX] = { + [BLK_IDX_SCHEDULE] = {0}, + [BLK_IDX_SCHEDULE_ENTRY_POINTS] = {0}, [BLK_IDX_L2_LOOKUP] = { .packing = sja1105pqrs_l2_lookup_entry_packing, .unpacked_entry_size = sizeof(struct sja1105_l2_lookup_entry), @@ -772,6 +885,8 @@ struct sja1105_table_ops sja1105p_table_ops[BLK_IDX_MAX] = { .packed_entry_size = SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY, .max_entry_count = SJA1105_MAX_MAC_CONFIG_COUNT, }, + [BLK_IDX_SCHEDULE_PARAMS] = {0}, + [BLK_IDX_SCHEDULE_ENTRY_POINTS_PARAMS] = {0}, [BLK_IDX_L2_LOOKUP_PARAMS] = { .packing = sja1105pqrs_l2_lookup_params_entry_packing, .unpacked_entry_size = sizeof(struct sja1105_l2_lookup_params_entry), @@ -806,6 +921,18 @@ struct sja1105_table_ops sja1105p_table_ops[BLK_IDX_MAX] = { /* SJA1105Q: Second generation, TTEthernet, no SGMII */ struct sja1105_table_ops sja1105q_table_ops[BLK_IDX_MAX] = { + [BLK_IDX_SCHEDULE] = { + .packing = sja1105_schedule_entry_packing, + .unpacked_entry_size = sizeof(struct sja1105_schedule_entry), + .packed_entry_size = SJA1105_SIZE_SCHEDULE_ENTRY, + .max_entry_count = SJA1105_MAX_SCHEDULE_COUNT, + }, + [BLK_IDX_SCHEDULE_ENTRY_POINTS] = { + .packing = sja1105_schedule_entry_points_entry_packing, + .unpacked_entry_size = sizeof(struct sja1105_schedule_entry_points_entry), + .packed_entry_size = SJA1105_SIZE_SCHEDULE_ENTRY_POINTS_ENTRY, + .max_entry_count = SJA1105_MAX_SCHEDULE_ENTRY_POINTS_COUNT, + }, [BLK_IDX_L2_LOOKUP] = { .packing = sja1105pqrs_l2_lookup_entry_packing, .unpacked_entry_size = sizeof(struct sja1105_l2_lookup_entry), @@ -836,6 +963,18 @@ struct sja1105_table_ops sja1105q_table_ops[BLK_IDX_MAX] = { .packed_entry_size = SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY, .max_entry_count = SJA1105_MAX_MAC_CONFIG_COUNT, }, + [BLK_IDX_SCHEDULE_PARAMS] = { + .packing = sja1105_schedule_params_entry_packing, + .unpacked_entry_size = sizeof(struct sja1105_schedule_params_entry), + .packed_entry_size = SJA1105_SIZE_SCHEDULE_PARAMS_ENTRY, + .max_entry_count = SJA1105_MAX_SCHEDULE_PARAMS_COUNT, + }, + [BLK_IDX_SCHEDULE_ENTRY_POINTS_PARAMS] = { + .packing = sja1105_schedule_entry_points_params_entry_packing, + .unpacked_entry_size = sizeof(struct sja1105_schedule_entry_points_params_entry), + .packed_entry_size = SJA1105_SIZE_SCHEDULE_ENTRY_POINTS_PARAMS_ENTRY, + .max_entry_count = SJA1105_MAX_SCHEDULE_ENTRY_POINTS_PARAMS_COUNT, + }, [BLK_IDX_L2_LOOKUP_PARAMS] = { .packing = sja1105pqrs_l2_lookup_params_entry_packing, .unpacked_entry_size = sizeof(struct sja1105_l2_lookup_params_entry), @@ -870,6 +1009,8 @@ struct sja1105_table_ops sja1105q_table_ops[BLK_IDX_MAX] = { /* SJA1105R: Second generation, no TTEthernet, SGMII */ struct sja1105_table_ops sja1105r_table_ops[BLK_IDX_MAX] = { + [BLK_IDX_SCHEDULE] = {0}, + [BLK_IDX_SCHEDULE_ENTRY_POINTS] = {0}, [BLK_IDX_L2_LOOKUP] = { .packing = sja1105pqrs_l2_lookup_entry_packing, .unpacked_entry_size = sizeof(struct sja1105_l2_lookup_entry), @@ -900,6 +1041,8 @@ struct sja1105_table_ops sja1105r_table_ops[BLK_IDX_MAX] = { .packed_entry_size = SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY, .max_entry_count = SJA1105_MAX_MAC_CONFIG_COUNT, }, + [BLK_IDX_SCHEDULE_PARAMS] = {0}, + [BLK_IDX_SCHEDULE_ENTRY_POINTS_PARAMS] = {0}, [BLK_IDX_L2_LOOKUP_PARAMS] = { .packing = sja1105pqrs_l2_lookup_params_entry_packing, .unpacked_entry_size = sizeof(struct sja1105_l2_lookup_params_entry), @@ -934,6 +1077,18 @@ struct sja1105_table_ops sja1105r_table_ops[BLK_IDX_MAX] = { /* SJA1105S: Second generation, TTEthernet, SGMII */ struct sja1105_table_ops sja1105s_table_ops[BLK_IDX_MAX] = { + [BLK_IDX_SCHEDULE] = { + .packing = sja1105_schedule_entry_packing, + .unpacked_entry_size = sizeof(struct sja1105_schedule_entry), + .packed_entry_size = SJA1105_SIZE_SCHEDULE_ENTRY, + .max_entry_count = SJA1105_MAX_SCHEDULE_COUNT, + }, + [BLK_IDX_SCHEDULE_ENTRY_POINTS] = { + .packing = sja1105_schedule_entry_points_entry_packing, + .unpacked_entry_size = sizeof(struct sja1105_schedule_entry_points_entry), + .packed_entry_size = SJA1105_SIZE_SCHEDULE_ENTRY_POINTS_ENTRY, + .max_entry_count = SJA1105_MAX_SCHEDULE_ENTRY_POINTS_COUNT, + }, [BLK_IDX_L2_LOOKUP] = { .packing = sja1105pqrs_l2_lookup_entry_packing, .unpacked_entry_size = sizeof(struct sja1105_l2_lookup_entry), @@ -964,6 +1119,18 @@ struct sja1105_table_ops sja1105s_table_ops[BLK_IDX_MAX] = { .packed_entry_size = SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY, .max_entry_count = SJA1105_MAX_MAC_CONFIG_COUNT, }, + [BLK_IDX_SCHEDULE_PARAMS] = { + .packing = sja1105_schedule_params_entry_packing, + .unpacked_entry_size = sizeof(struct sja1105_schedule_params_entry), + .packed_entry_size = SJA1105_SIZE_SCHEDULE_PARAMS_ENTRY, + .max_entry_count = SJA1105_MAX_SCHEDULE_PARAMS_COUNT, + }, + [BLK_IDX_SCHEDULE_ENTRY_POINTS_PARAMS] = { + .packing = sja1105_schedule_entry_points_params_entry_packing, + .unpacked_entry_size = sizeof(struct sja1105_schedule_entry_points_params_entry), + .packed_entry_size = SJA1105_SIZE_SCHEDULE_ENTRY_POINTS_PARAMS_ENTRY, + .max_entry_count = SJA1105_MAX_SCHEDULE_ENTRY_POINTS_PARAMS_COUNT, + }, [BLK_IDX_L2_LOOKUP_PARAMS] = { .packing = sja1105pqrs_l2_lookup_params_entry_packing, .unpacked_entry_size = sizeof(struct sja1105_l2_lookup_params_entry), diff --git a/drivers/net/dsa/sja1105/sja1105_static_config.h b/drivers/net/dsa/sja1105/sja1105_static_config.h index 684465fc0882..7f87022a2d61 100644 --- a/drivers/net/dsa/sja1105/sja1105_static_config.h +++ b/drivers/net/dsa/sja1105/sja1105_static_config.h @@ -11,11 +11,15 @@ #define SJA1105_SIZE_DEVICE_ID 4 #define SJA1105_SIZE_TABLE_HEADER 12 +#define SJA1105_SIZE_SCHEDULE_ENTRY 8 +#define SJA1105_SIZE_SCHEDULE_ENTRY_POINTS_ENTRY 4 #define SJA1105_SIZE_L2_POLICING_ENTRY 8 #define SJA1105_SIZE_VLAN_LOOKUP_ENTRY 8 #define SJA1105_SIZE_L2_FORWARDING_ENTRY 8 #define SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY 12 #define SJA1105_SIZE_XMII_PARAMS_ENTRY 4 +#define SJA1105_SIZE_SCHEDULE_PARAMS_ENTRY 12 +#define SJA1105_SIZE_SCHEDULE_ENTRY_POINTS_PARAMS_ENTRY 4 #define SJA1105ET_SIZE_L2_LOOKUP_ENTRY 12 #define SJA1105ET_SIZE_MAC_CONFIG_ENTRY 28 #define SJA1105ET_SIZE_L2_LOOKUP_PARAMS_ENTRY 4 @@ -29,11 +33,15 @@ /* UM10944.pdf Page 11, Table 2. Configuration Blocks */ enum { + BLKID_SCHEDULE = 0x00, + BLKID_SCHEDULE_ENTRY_POINTS = 0x01, BLKID_L2_LOOKUP = 0x05, BLKID_L2_POLICING = 0x06, BLKID_VLAN_LOOKUP = 0x07, BLKID_L2_FORWARDING = 0x08, BLKID_MAC_CONFIG = 0x09, + BLKID_SCHEDULE_PARAMS = 0x0A, + BLKID_SCHEDULE_ENTRY_POINTS_PARAMS = 0x0B, BLKID_L2_LOOKUP_PARAMS = 0x0D, BLKID_L2_FORWARDING_PARAMS = 0x0E, BLKID_AVB_PARAMS = 0x10, @@ -42,11 +50,15 @@ enum { }; enum sja1105_blk_idx { - BLK_IDX_L2_LOOKUP = 0, + BLK_IDX_SCHEDULE = 0, + BLK_IDX_SCHEDULE_ENTRY_POINTS, + BLK_IDX_L2_LOOKUP, BLK_IDX_L2_POLICING, BLK_IDX_VLAN_LOOKUP, BLK_IDX_L2_FORWARDING, BLK_IDX_MAC_CONFIG, + BLK_IDX_SCHEDULE_PARAMS, + BLK_IDX_SCHEDULE_ENTRY_POINTS_PARAMS, BLK_IDX_L2_LOOKUP_PARAMS, BLK_IDX_L2_FORWARDING_PARAMS, BLK_IDX_AVB_PARAMS, @@ -59,11 +71,15 @@ enum sja1105_blk_idx { BLK_IDX_INVAL = -1, }; +#define SJA1105_MAX_SCHEDULE_COUNT 1024 +#define SJA1105_MAX_SCHEDULE_ENTRY_POINTS_COUNT 2048 #define SJA1105_MAX_L2_LOOKUP_COUNT 1024 #define SJA1105_MAX_L2_POLICING_COUNT 45 #define SJA1105_MAX_VLAN_LOOKUP_COUNT 4096 #define SJA1105_MAX_L2_FORWARDING_COUNT 13 #define SJA1105_MAX_MAC_CONFIG_COUNT 5 +#define SJA1105_MAX_SCHEDULE_PARAMS_COUNT 1 +#define SJA1105_MAX_SCHEDULE_ENTRY_POINTS_PARAMS_COUNT 1 #define SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT 1 #define SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT 1 #define SJA1105_MAX_GENERAL_PARAMS_COUNT 1 @@ -83,6 +99,23 @@ enum sja1105_blk_idx { #define SJA1105R_PART_NO 0x9A86 #define SJA1105S_PART_NO 0x9A87 +struct sja1105_schedule_entry { + u64 winstindex; + u64 winend; + u64 winst; + u64 destports; + u64 setvalid; + u64 txen; + u64 resmedia_en; + u64 resmedia; + u64 vlindex; + u64 delta; +}; + +struct sja1105_schedule_params_entry { + u64 subscheind[8]; +}; + struct sja1105_general_params_entry { u64 vllupformat; u64 mirr_ptacu; @@ -112,6 +145,17 @@ struct sja1105_general_params_entry { u64 replay_port; }; +struct sja1105_schedule_entry_points_entry { + u64 subschindx; + u64 delta; + u64 address; +}; + +struct sja1105_schedule_entry_points_params_entry { + u64 clksrc; + u64 actsubsch; +}; + struct sja1105_vlan_lookup_entry { u64 ving_mirr; u64 vegr_mirr; @@ -256,6 +300,8 @@ sja1105_static_config_get_length(const struct sja1105_static_config *config); typedef enum { SJA1105_CONFIG_OK = 0, + SJA1105_TTETHERNET_NOT_SUPPORTED, + SJA1105_INCORRECT_TTETHERNET_CONFIGURATION, SJA1105_MISSING_L2_POLICING_TABLE, SJA1105_MISSING_L2_FORWARDING_TABLE, SJA1105_MISSING_L2_FORWARDING_PARAMS_TABLE, From patchwork Fri Aug 30 00:46:32 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1155595 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="nuFUxtVh"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 46KLR65n28z9sN6 for ; Fri, 30 Aug 2019 10:47:14 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727747AbfH3ArN (ORCPT ); Thu, 29 Aug 2019 20:47:13 -0400 Received: from mail-wr1-f65.google.com ([209.85.221.65]:38496 "EHLO mail-wr1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727658AbfH3ArH (ORCPT ); Thu, 29 Aug 2019 20:47:07 -0400 Received: by mail-wr1-f65.google.com with SMTP id e16so5208047wro.5 for ; Thu, 29 Aug 2019 17:47:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=gBu+Z0kpeIIVY2J23gGKWd+J3LOAZAzKI50m7BCV0WI=; b=nuFUxtVhe1OQ2RmhaxslHaI4+o0jCwBBtz7S2KPgxysRm0AcX95je1adXX/mUc8bEf dcZyMYnx+AgtxF5IH1wJyJq4t2pmiqPQTlQG8aI/XLhFKHpVla7jJzgLDFA3rDgHbMee 0Oo5H8r9Qw1PcN2ILYiE1IdhguyC3pkkHfC1giVesf9Xz8SzDk/pmcH05Cj4OsbFCsa4 Qy20o2G9OT5EhNDpjRzZwUioXfSqHw3HujmWgQx62LIBvjOVvrmFhMtc8jorbn1gF0fw CS9i0sTdxdFI91EWg0DVWUmA04kMM4MwHjuewbkMj6oHOOY/L/KWciaOXPs+Iz/yTNp9 ASQg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=gBu+Z0kpeIIVY2J23gGKWd+J3LOAZAzKI50m7BCV0WI=; b=O7cBZQSf0N6wOT1VpP24IHppk3nEnU08/W2I3ZA72g7HZ133Ghu3uj9sM2kABATp1J b1Bf3vMSElcz12s6OGyUQYg3BhJDa3QGzD1ECLIVkgAuIaUAUg8zc/eCXJUIw9gLnw3m xRQ3sdloh7uHV9+ofaC3mrZGuSA69bny5kfA6wEH5V55LAg5iZmWgx9bAvh/UC/AcL5C YPzmjWDleEN5DvsFaDWGCszTTKZan85IIKPy4Z3ZDT8PuYd0G+WSfPp0sNFSztFDxhqh qEKhpuBBm0M61ey6LFCJU1qikP5VYHRYmOnJzCgwr14pZXINgSb/NuBKQDH+6rvHUUym j7NQ== X-Gm-Message-State: APjAAAWEAOkqyfLs8o/8nhNQbZodA7aR9KfCxXZb8TTVNTwzwaSqVzfr fVM8ZebkPIwAHFNWdQF5l/k= X-Google-Smtp-Source: APXvYqwtPYCsa6nt9hkXC/4b/Hj/qpmfJnLUtPdZi0qdgwcAlxcgV9Jyy03q+0vpVJyoo4YhqpgtEA== X-Received: by 2002:adf:eac5:: with SMTP id o5mr15495932wrn.140.1567126024192; Thu, 29 Aug 2019 17:47:04 -0700 (PDT) Received: from localhost.localdomain ([86.126.25.232]) by smtp.gmail.com with ESMTPSA id y3sm9298442wmg.2.2019.08.29.17.47.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Aug 2019 17:47:03 -0700 (PDT) From: Vladimir Oltean To: f.fainelli@gmail.com, vivien.didelot@gmail.com, andrew@lunn.ch, davem@davemloft.net, vinicius.gomes@intel.com, vedang.patel@intel.com, richardcochran@gmail.com Cc: weifeng.voon@intel.com, jiri@mellanox.com, m-karicheri2@ti.com, Jose.Abreu@synopsys.com, ilias.apalodimas@linaro.org, --to=jhs@mojatatu.com, --to=xiyou.wangcong@gmail.com, netdev@vger.kernel.org, Vladimir Oltean Subject: [RFC PATCH v2 net-next 12/15] net: dsa: sja1105: Configure the Time-Aware Scheduler via tc-taprio offload Date: Fri, 30 Aug 2019 03:46:32 +0300 Message-Id: <20190830004635.24863-13-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190830004635.24863-1-olteanv@gmail.com> References: <20190830004635.24863-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This qdisc offload is the closest thing to what the SJA1105 supports in hardware for time-based egress shaping. The switch core really is built around SAE AS6802/TTEthernet (a TTTech standard) but can be made to operate similarly to IEEE 802.1Qbv with some constraints: - The gate control list is a global list for all ports. There are 8 execution threads that iterate through this global list in parallel. I don't know why 8, there are only 4 front-panel ports. - Care must be taken by the user to make sure that two execution threads never get to execute a GCL entry simultaneously. I created a O(n^4) checker for this hardware limitation, prior to accepting a taprio offload configuration as valid. - The spec says that if a GCL entry's interval is shorter than the frame length, you shouldn't send it (and end up in head-of-line blocking). Well, this switch does anyway. - The switch has no concept of ADMIN and OPER configurations. Because it's so simple, the TAS settings are loaded through the static config tables interface, so there isn't even place for any discussion about 'graceful switchover between ADMIN and OPER'. You just reset the switch and upload a new OPER config. - The switch accepts multiple time sources for the gate events. Right now I am using the standalone clock source as opposed to PTP. So the base time parameter doesn't really do much. Support for the PTP clock source will be added in the next patch. Signed-off-by: Vladimir Oltean --- drivers/net/dsa/sja1105/Kconfig | 8 + drivers/net/dsa/sja1105/Makefile | 4 + drivers/net/dsa/sja1105/sja1105.h | 5 + drivers/net/dsa/sja1105/sja1105_main.c | 19 +- drivers/net/dsa/sja1105/sja1105_tas.c | 447 +++++++++++++++++++++++++ drivers/net/dsa/sja1105/sja1105_tas.h | 47 +++ 6 files changed, 529 insertions(+), 1 deletion(-) create mode 100644 drivers/net/dsa/sja1105/sja1105_tas.c create mode 100644 drivers/net/dsa/sja1105/sja1105_tas.h diff --git a/drivers/net/dsa/sja1105/Kconfig b/drivers/net/dsa/sja1105/Kconfig index 770134a66e48..55424f39cb0d 100644 --- a/drivers/net/dsa/sja1105/Kconfig +++ b/drivers/net/dsa/sja1105/Kconfig @@ -23,3 +23,11 @@ config NET_DSA_SJA1105_PTP help This enables support for timestamping and PTP clock manipulations in the SJA1105 DSA driver. + +config NET_DSA_SJA1105_TAS + bool "Support for the Time-Aware Scheduler on NXP SJA1105" + depends on NET_DSA_SJA1105 + help + This enables support for the TTEthernet-based egress scheduling + engine in the SJA1105 DSA driver, which is controlled using a + hardware offload of the tc-tqprio qdisc. diff --git a/drivers/net/dsa/sja1105/Makefile b/drivers/net/dsa/sja1105/Makefile index 4483113e6259..66161e874344 100644 --- a/drivers/net/dsa/sja1105/Makefile +++ b/drivers/net/dsa/sja1105/Makefile @@ -12,3 +12,7 @@ sja1105-objs := \ ifdef CONFIG_NET_DSA_SJA1105_PTP sja1105-objs += sja1105_ptp.o endif + +ifdef CONFIG_NET_DSA_SJA1105_TAS +sja1105-objs += sja1105_tas.o +endif diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index 3ca0b87aa3e4..d95f9ce3b4f9 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -21,6 +21,7 @@ #define SJA1105_AGEING_TIME_MS(ms) ((ms) / 10) #include "sja1105_ptp.h" +#include "sja1105_tas.h" /* Keeps the different addresses between E/T and P/Q/R/S */ struct sja1105_regs { @@ -96,6 +97,7 @@ struct sja1105_private { struct mutex mgmt_lock; struct sja1105_tagger_data tagger_data; struct sja1105_ptp_data ptp_data; + struct sja1105_tas_data tas_data; }; #include "sja1105_dynamic_config.h" @@ -111,6 +113,9 @@ typedef enum { SPI_WRITE = 1, } sja1105_spi_rw_mode_t; +/* From sja1105_main.c */ +int sja1105_static_config_reload(struct sja1105_private *priv); + /* From sja1105_spi.c */ int sja1105_spi_send_packed_buf(const struct sja1105_private *priv, sja1105_spi_rw_mode_t rw, u64 reg_addr, diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index 8b930cc2dabc..4b393782cc84 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -22,6 +22,7 @@ #include #include #include "sja1105.h" +#include "sja1105_tas.h" static void sja1105_hw_reset(struct gpio_desc *gpio, unsigned int pulse_len, unsigned int startup_delay) @@ -1382,7 +1383,7 @@ static void sja1105_bridge_leave(struct dsa_switch *ds, int port, * modify at runtime (currently only MAC) and restore them after uploading, * such that this operation is relatively seamless. */ -static int sja1105_static_config_reload(struct sja1105_private *priv) +int sja1105_static_config_reload(struct sja1105_private *priv) { struct ptp_system_timestamp ptp_sts_before; struct ptp_system_timestamp ptp_sts_after; @@ -1761,6 +1762,7 @@ static void sja1105_teardown(struct dsa_switch *ds) { struct sja1105_private *priv = ds->priv; + sja1105_tas_teardown(priv); cancel_work_sync(&priv->tagger_data.rxtstamp_work); skb_queue_purge(&priv->tagger_data.skb_rxtstamp_queue); sja1105_ptp_clock_unregister(priv); @@ -2088,6 +2090,18 @@ static bool sja1105_port_txtstamp(struct dsa_switch *ds, int port, return true; } +static int sja1105_port_setup_tc(struct dsa_switch *ds, int port, + enum tc_setup_type type, + void *type_data) +{ + switch (type) { + case TC_SETUP_QDISC_TAPRIO: + return sja1105_setup_tc_taprio(ds, port, type_data); + default: + return -EOPNOTSUPP; + } +} + static const struct dsa_switch_ops sja1105_switch_ops = { .get_tag_protocol = sja1105_get_tag_protocol, .setup = sja1105_setup, @@ -2120,6 +2134,7 @@ static const struct dsa_switch_ops sja1105_switch_ops = { .port_hwtstamp_set = sja1105_hwtstamp_set, .port_rxtstamp = sja1105_port_rxtstamp, .port_txtstamp = sja1105_port_txtstamp, + .port_setup_tc = sja1105_port_setup_tc, }; static int sja1105_check_device_id(struct sja1105_private *priv) @@ -2229,6 +2244,8 @@ static int sja1105_probe(struct spi_device *spi) } mutex_init(&priv->mgmt_lock); + sja1105_tas_setup(priv); + return dsa_register_switch(priv->ds); } diff --git a/drivers/net/dsa/sja1105/sja1105_tas.c b/drivers/net/dsa/sja1105/sja1105_tas.c new file mode 100644 index 000000000000..e316008246f6 --- /dev/null +++ b/drivers/net/dsa/sja1105/sja1105_tas.c @@ -0,0 +1,447 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2019, Vladimir Oltean + */ +#include "sja1105.h" + +#define SJA1105_TAS_CLKSRC_DISABLED 0 +#define SJA1105_TAS_CLKSRC_STANDALONE 1 +#define SJA1105_TAS_CLKSRC_AS6802 2 +#define SJA1105_TAS_CLKSRC_PTP 3 +#define SJA1105_GATE_MASK GENMASK_ULL(SJA1105_NUM_TC - 1, 0) +#define SJA1105_TAS_MAX_DELTA BIT(19) + +#define config_work_to_sja1105_tas(d) \ + container_of((d), struct sja1105_tas_data, config_work) +#define tas_to_sja1105(d) \ + container_of((d), struct sja1105_private, tas_data) + +/* This is not a preprocessor macro because the "ns" argument may or may not be + * u64 at caller side. This ensures it is properly type-cast before div_u64. + */ +static u64 ns_to_sja1105_delta(u64 ns) +{ + return div_u64(ns, 200); +} + +/* Lo and behold: the egress scheduler from hell. + * + * At the hardware level, the Time-Aware Shaper holds a global linear arrray of + * all schedule entries for all ports. These are the Gate Control List (GCL) + * entries, let's call them "timeslots" for short. This linear array of + * timeslots is held in BLK_IDX_SCHEDULE. + * + * Then there are a maximum of 8 "execution threads" inside the switch, which + * iterate cyclically through the "schedule". Each "cycle" has an entry point + * and an exit point, both being timeslot indices in the schedule table. The + * hardware calls each cycle a "subschedule". + * + * Subschedule (cycle) i starts when PTPCLKVAL >= BLK_IDX_SCHEDULE_ENTRY_POINTS[i].delta. + * The hardware scheduler iterates BLK_IDX_SCHEDULE with a k ranging from + * k = BLK_IDX_SCHEDULE_ENTRY_POINTS[i].address to + * k = BLK_IDX_SCHEDULE_PARAMS.subscheind[i] + * For each schedule entry (timeslot) k, the engine executes the gate control + * list entry for the duration of BLK_IDX_SCHEDULE[k].delta. + * + * +---------+ + * | | BLK_IDX_SCHEDULE_ENTRY_POINTS_PARAMS + * +---------+ + * | + * | .actsubsch + * +-----------------+ + * | + * | + * | + * BLK_IDX_SCHEDULE_ENTRY_POINTS v + * +---------+---------+ + * | cycle 0 | cycle 1 | + * +---------+---------+ + * | | | | + * +----------------+ | | +-----------------------------------------------+ + * | .subschindx | | .subschindx | + * | | +-------------------+ | + * | .address | .address | | + * | | | | + * | | | | + * | BLK_IDX_SCHEDULE v v | + * | +---------+---------+---------+---------+---------+---------+ | + * | | entry 0 | entry 1 | entry 2 | entry 3 | entry 4 | entry 5 | | + * | +---------+---------+---------+---------+---------+---------+ | + * | ^ ^ ^ ^ | + * | | | | | | + * | +-----------------------------+ | | | | + * | | | | | | + * | | +--------------------------------------+ | | | + * | | | | | | + * | | | +-----------------------+ | | + * | | | | | | + * | | | | BLK_IDX_SCHEDULE_PARAMS | | + * | +----------------------------------------------------------------------------+ | + * | | .subscheind[0] <= .subscheind[1] <= .subscheind[2] <= ... <= subscheind[7] | | + * | +----------------------------------------------------------------------------+ | + * | ^ ^ | + * | | | | + * +---------+ +---------------------------------------------------+ + * + * In the above picture there are two subschedules (cycles): + * + * - cycle 0: iterates the schedule table from 0 to 2 (and back) + * - cycle 1: iterates the schedule table from 3 to 5 (and back) + * + * All other possible execution threads must be marked as unused by making + * their "subschedule end index" (subscheind) equal to the last valid + * subschedule's end index (in this case 5). + */ +static int sja1105_init_scheduling(struct sja1105_private *priv) +{ + struct sja1105_schedule_entry_points_entry *schedule_entry_points; + struct sja1105_schedule_entry_points_params_entry + *schedule_entry_points_params; + struct sja1105_schedule_params_entry *schedule_params; + struct sja1105_tas_data *tas_data = &priv->tas_data; + struct sja1105_schedule_entry *schedule; + struct sja1105_table *table; + int subscheind[8] = {0}; + int schedule_start_idx; + u64 entry_point_delta; + int schedule_end_idx; + int num_entries = 0; + int num_cycles = 0; + int cycle = 0; + int i, k = 0; + int port; + + /* Discard previous Schedule Table */ + table = &priv->static_config.tables[BLK_IDX_SCHEDULE]; + if (table->entry_count) { + kfree(table->entries); + table->entry_count = 0; + } + + /* Discard previous Schedule Entry Points Parameters Table */ + table = &priv->static_config.tables[BLK_IDX_SCHEDULE_ENTRY_POINTS_PARAMS]; + if (table->entry_count) { + kfree(table->entries); + table->entry_count = 0; + } + + /* Discard previous Schedule Parameters Table */ + table = &priv->static_config.tables[BLK_IDX_SCHEDULE_PARAMS]; + if (table->entry_count) { + kfree(table->entries); + table->entry_count = 0; + } + + /* Discard previous Schedule Entry Points Table */ + table = &priv->static_config.tables[BLK_IDX_SCHEDULE_ENTRY_POINTS]; + if (table->entry_count) { + kfree(table->entries); + table->entry_count = 0; + } + + /* Figure out the dimensioning of the problem */ + for (port = 0; port < SJA1105_NUM_PORTS; port++) { + if (tas_data->config[port]) { + num_entries += tas_data->config[port]->num_entries; + num_cycles++; + } + } + + /* Nothing to do */ + if (!num_cycles) + return 0; + + /* Pre-allocate space in the static config tables */ + + /* Schedule Table */ + table = &priv->static_config.tables[BLK_IDX_SCHEDULE]; + table->entries = kcalloc(num_entries, table->ops->unpacked_entry_size, + GFP_ATOMIC); + if (!table->entries) + return -ENOMEM; + table->entry_count = num_entries; + schedule = table->entries; + + /* Schedule Points Parameters Table */ + table = &priv->static_config.tables[BLK_IDX_SCHEDULE_ENTRY_POINTS_PARAMS]; + table->entries = kcalloc(SJA1105_MAX_SCHEDULE_ENTRY_POINTS_PARAMS_COUNT, + table->ops->unpacked_entry_size, GFP_ATOMIC); + if (!table->entries) + return -ENOMEM; + table->entry_count = SJA1105_MAX_SCHEDULE_ENTRY_POINTS_PARAMS_COUNT; + schedule_entry_points_params = table->entries; + + /* Schedule Parameters Table */ + table = &priv->static_config.tables[BLK_IDX_SCHEDULE_PARAMS]; + table->entries = kcalloc(SJA1105_MAX_SCHEDULE_PARAMS_COUNT, + table->ops->unpacked_entry_size, GFP_ATOMIC); + if (!table->entries) + return -ENOMEM; + table->entry_count = SJA1105_MAX_SCHEDULE_PARAMS_COUNT; + schedule_params = table->entries; + + /* Schedule Entry Points Table */ + table = &priv->static_config.tables[BLK_IDX_SCHEDULE_ENTRY_POINTS]; + table->entries = kcalloc(num_cycles, table->ops->unpacked_entry_size, + GFP_ATOMIC); + if (!table->entries) + return -ENOMEM; + table->entry_count = num_cycles; + schedule_entry_points = table->entries; + + /* Finally start populating the static config tables */ + schedule_entry_points_params->clksrc = SJA1105_TAS_CLKSRC_STANDALONE; + schedule_entry_points_params->actsubsch = num_cycles - 1; + + for (port = 0; port < SJA1105_NUM_PORTS; port++) { + const struct tc_taprio_qopt_offload *tas_config; + + tas_config = tas_data->config[port]; + if (!tas_config) + continue; + + schedule_start_idx = k; + schedule_end_idx = k + tas_config->num_entries - 1; + /* TODO this is only a relative base time for the subschedule + * (relative to PTPSCHTM). But as we're using standalone and + * not PTP clock as time reference, leave it like this for now. + * Later we'll have to enforce that all ports' base times are + * within SJA1105_TAS_MAX_DELTA 200ns cycles of one another. + */ + entry_point_delta = ns_to_sja1105_delta(tas_config->base_time); + + schedule_entry_points[cycle].subschindx = cycle; + schedule_entry_points[cycle].delta = entry_point_delta; + schedule_entry_points[cycle].address = schedule_start_idx; + + for (i = cycle; i < 8; i++) + subscheind[i] = schedule_end_idx; + + for (i = 0; i < tas_config->num_entries; i++, k++) { + u64 delta_ns = tas_config->entries[i].interval; + + schedule[k].delta = ns_to_sja1105_delta(delta_ns); + schedule[k].destports = BIT(port); + schedule[k].resmedia_en = true; + schedule[k].resmedia = SJA1105_GATE_MASK & + ~tas_config->entries[i].gate_mask; + } + cycle++; + } + + for (i = 0; i < 8; i++) + schedule_params->subscheind[i] = subscheind[i]; + + return 0; +} + +/* Be there 2 port subschedules, each executing an arbitrary number of gate + * open/close events cyclically. + * None of those gate events must ever occur at the exact same time, otherwise + * the switch is known to act in exotically strange ways. + * However the hardware doesn't bother performing these integrity checks - the + * designers probably said "nah, let's leave that to the experts" - oh well, + * now we're the experts. + * So here we are with the task of validating whether the new @qopt has any + * conflict with the already established TAS configuration in tas_data->config. + * We already know the other ports are in harmony with one another, otherwise + * we wouldn't have saved them. + * Each gate event executes periodically, with a period of @cycle_time and a + * phase given by its cycle's @base_time plus its offset within the cycle + * (which in turn is given by the length of the events prior to it). + * There are two aspects to possible collisions: + * - Collisions within one cycle's (actually the longest cycle's) time frame. + * For that, we need to compare the cartesian product of each possible + * occurrence of each event within one cycle time. + * - Collisions in the future. Events may not collide within one cycle time, + * but if two port schedules don't have the same periodicity (aka the cycle + * times aren't multiples of one another), they surely will some time in the + * future (actually they will collide an infinite amount of times). + */ +static bool +sja1105_tas_check_conflicts(struct sja1105_private *priv, + const struct tc_taprio_qopt_offload *qopt) +{ + struct sja1105_tas_data *tas_data = &priv->tas_data; + int port; + + for (port = 0; port < SJA1105_NUM_PORTS; port++) { + const struct tc_taprio_qopt_offload *tas_config; + u64 max_cycle_time, min_cycle_time; + u64 delta1, delta2; + u64 rbt1, rbt2; + u64 stop_time; + u64 t1, t2; + int i, j; + s32 rem; + + tas_config = tas_data->config[port]; + + if (!tas_config) + continue; + + /* Check if the two cycle times are multiples of one another. + * If they aren't, then they will surely collide. + */ + max_cycle_time = max(tas_config->cycle_time, qopt->cycle_time); + min_cycle_time = min(tas_config->cycle_time, qopt->cycle_time); + div_u64_rem(max_cycle_time, min_cycle_time, &rem); + if (rem) + return true; + + /* Calculate the "reduced" base time of each of the two cycles + * (transposed back as close to 0 as possible) by dividing to + * the cycle time. + */ + div_u64_rem(tas_config->base_time, tas_config->cycle_time, + &rem); + rbt1 = rem; + + div_u64_rem(qopt->base_time, qopt->cycle_time, &rem); + rbt2 = rem; + + stop_time = max_cycle_time + max(rbt1, rbt2); + + /* delta1 is the relative base time of each GCL entry within + * the established ports' TAS config. + */ + for (i = 0, delta1 = 0; + i < tas_config->num_entries; + delta1 += tas_config->entries[i].interval, i++) { + + /* delta2 is the relative base time of each GCL entry + * within the newly added TAS config. + */ + for (j = 0, delta2 = 0; + j < qopt->num_entries; + delta2 += qopt->entries[j].interval, j++) { + + /* t1 follows all possible occurrences of the + * established ports' GCL entry i within the + * first cycle time. + */ + for (t1 = rbt1 + delta1; + t1 <= stop_time; + t1 += tas_config->cycle_time) { + + /* t2 follows all possible occurrences + * of the newly added GCL entry j + * within the first cycle time. + */ + for (t2 = rbt2 + delta2; + t2 <= stop_time; + t2 += qopt->cycle_time) { + + if (t1 == t2) { + dev_warn(priv->ds->dev, + "GCL entry %d collides with entry %d of port %d\n", + j, i, port); + return true; + } + } + } + } + } + } + + return false; +} + +void sja1105_tas_config_work(struct work_struct *work) +{ + struct sja1105_tas_data *tas_data = config_work_to_sja1105_tas(work); + struct sja1105_private *priv = tas_to_sja1105(tas_data); + struct dsa_switch *ds = priv->ds; + int rc; + + rc = sja1105_static_config_reload(priv); + if (rc) + dev_err(ds->dev, "Failed to change scheduling settings\n"); +} + +int sja1105_setup_tc_taprio(struct dsa_switch *ds, int port, + struct tc_taprio_qopt_offload *tas_config) +{ + struct sja1105_private *priv = ds->priv; + struct sja1105_tas_data *tas_data = &priv->tas_data; + int rc, i; + + /* Can't change an already configured port (must delete qdisc first). + * Can't delete the qdisc from an unconfigured port. + */ + if (!!tas_data->config[port] == tas_config->enable) + return -EINVAL; + + if (!tas_config->enable) { + taprio_free(tas_data->config[port]); + tas_data->config[port] = NULL; + + rc = sja1105_init_scheduling(priv); + if (rc < 0) + return rc; + + schedule_work(&tas_data->config_work); + + return 0; + } + + /* The cycle time extension is the amount of time the last cycle from + * the old OPER needs to be extended in order to phase-align with the + * base time of the ADMIN when that becomes the new OPER. + * But of course our switch needs to be reset to switch-over between + * the ADMIN and the OPER configs - so much for a seamless transition. + * So don't add insult over injury and just say we don't support cycle + * time extension. + */ + if (tas_config->cycle_time_extension) + return -ENOTSUPP; + + if (!ns_to_sja1105_delta(tas_config->base_time)) { + dev_err(ds->dev, "A base time of zero is not hardware-allowed\n"); + return -ERANGE; + } + + for (i = 0; i < tas_config->num_entries; i++) { + u64 delta_ns = tas_config->entries[i].interval; + u64 delta_cycles = ns_to_sja1105_delta(delta_ns); + bool too_long, too_short; + + too_long = (delta_cycles >= SJA1105_TAS_MAX_DELTA); + too_short = (delta_cycles == 0); + if (too_long || too_short) { + dev_err(priv->ds->dev, + "Interval %llu too %s for GCL entry %d\n", + delta_ns, too_long ? "long" : "short", i); + return -ERANGE; + } + } + + if (sja1105_tas_check_conflicts(priv, tas_config)) + return -ERANGE; + + tas_data->config[port] = taprio_get(tas_config); + + rc = sja1105_init_scheduling(priv); + if (rc < 0) + return rc; + + schedule_work(&tas_data->config_work); + + return 0; +} + +void sja1105_tas_setup(struct sja1105_private *priv) +{ + INIT_WORK(&priv->tas_data.config_work, sja1105_tas_config_work); +} + +void sja1105_tas_teardown(struct sja1105_private *priv) +{ + struct sja1105_tas_data *tas_data = &priv->tas_data; + int port; + + cancel_work_sync(&tas_data->config_work); + + for (port = 0; port < SJA1105_NUM_PORTS; port++) + if (tas_data->config[port]) + taprio_free(tas_data->config[port]); +} diff --git a/drivers/net/dsa/sja1105/sja1105_tas.h b/drivers/net/dsa/sja1105/sja1105_tas.h new file mode 100644 index 000000000000..1629492e20ab --- /dev/null +++ b/drivers/net/dsa/sja1105/sja1105_tas.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0 + * Copyright (c) 2019, Vladimir Oltean + */ +#ifndef _SJA1105_TAS_H +#define _SJA1105_TAS_H + +#include + +#if IS_ENABLED(CONFIG_NET_DSA_SJA1105_TAS) + +struct sja1105_tas_data { + struct tc_taprio_qopt_offload *config[SJA1105_NUM_PORTS]; + struct work_struct config_work; +}; + +void sja1105_tas_config_work(struct work_struct *work); + +int sja1105_setup_tc_taprio(struct dsa_switch *ds, int port, + struct tc_taprio_qopt_offload *qopt); + +void sja1105_tas_setup(struct sja1105_private *priv); + +void sja1105_tas_teardown(struct sja1105_private *priv); + +#else + +/* C doesn't allow empty structures, bah! */ +struct sja1105_tas_data { + u8 dummy; +}; + +#define sja1105_tas_config_work NULL + +static inline int +sja1105_setup_tc_taprio(struct dsa_switch *ds, int port, + struct tc_taprio_qopt_offload *qopt) +{ + return -EOPNOTSUPP; +} + +static inline void sja1105_tas_setup(struct sja1105_private *priv) { } + +static inline void sja1105_tas_teardown(struct sja1105_private *priv) { } + +#endif /* IS_ENABLED(CONFIG_NET_DSA_SJA1105_TAS) */ + +#endif /* _SJA1105_TAS_H */ From patchwork Fri Aug 30 00:46:33 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1155593 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="Jxgb5feB"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 46KLR35CwBz9sN6 for ; Fri, 30 Aug 2019 10:47:11 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727738AbfH3ArL (ORCPT ); Thu, 29 Aug 2019 20:47:11 -0400 Received: from mail-wm1-f68.google.com ([209.85.128.68]:53203 "EHLO mail-wm1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727671AbfH3ArH (ORCPT ); Thu, 29 Aug 2019 20:47:07 -0400 Received: by mail-wm1-f68.google.com with SMTP id t17so5496468wmi.2 for ; Thu, 29 Aug 2019 17:47:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=WMwdBlNOrBWO77HHiyJpkgNTQOv44nXnUcl235N4nNU=; b=Jxgb5feBM1Raul6HIHT7MWMLP3rcvDZy/IP+Dfx7pz+dfGlW3D/eXX4pjoKckRazPj GBe9nSglovNaMNNjy+FQdMhU9LhbDa9HZ3DL/toOj1//q2ItCYeCKoQl0snlts1zhujh +k0TPhNU4R4P5yaIa52gQNZvwa0uZpIigix088pUc4DQnv10PcZhiw4/w/Pg7kBPQejV qKHD15pWZwKIHqJKcGemB9sxvqXIDj74ZHxubMRLIH6u0RbvInIcGwvEo8bY7IYjmE/X r5CIwBIGkZ3PxODzdT8TpstHpcnOiReW+vvgfCUKp1WGUYkb8rKk+FXI1PRRk4sNCfYY owTw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=WMwdBlNOrBWO77HHiyJpkgNTQOv44nXnUcl235N4nNU=; b=inhgjR4z5oQecsOT/41Xsc1OjtxOf+jEgSknxTVy18r7oUAg0qgzTOfwZTy9eio6Oh 2g5KuRRMdeoepFoq8+qRwcsw1ApBQCB2Sxzy1P4JXquVLDk2f2Wg0zbcOKGkRt0pY/Up oU0cv3SBSbOcXZm0ca1EvMKD4ksgMqtB0rkOamPAlLR0q6d0hkXFsf0DhfkBBf2g4qv3 1hINGapwmxvzrrfM3B6CcI1Z7QeYL99fiVvH1KdRRU9NnToo8bbUTgqlQw0P+M5c4Jvq 40aLPGSt4nBL0LBxugqLiTeKiw3CNeAauMl7Ml+ignPAM+IZAKyFqSI9xmYeTXkKu2gS hVJA== X-Gm-Message-State: APjAAAXcJzDQ4SDbC5N3SHcJV9vVE+wxzNYC5dXlV+HefMQBJAP0ROYU xbmw2oGXxvzzn6tZ3jLF/po= X-Google-Smtp-Source: APXvYqxNnypntZ2Sj6sHvwKdzyq/dDnJhsrsq0Xe3sgzIcH3Io/0eDkh2VjNA3xwREPEKMHGEw9JBA== X-Received: by 2002:a7b:c775:: with SMTP id x21mr14615592wmk.97.1567126025428; Thu, 29 Aug 2019 17:47:05 -0700 (PDT) Received: from localhost.localdomain ([86.126.25.232]) by smtp.gmail.com with ESMTPSA id y3sm9298442wmg.2.2019.08.29.17.47.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Aug 2019 17:47:05 -0700 (PDT) From: Vladimir Oltean To: f.fainelli@gmail.com, vivien.didelot@gmail.com, andrew@lunn.ch, davem@davemloft.net, vinicius.gomes@intel.com, vedang.patel@intel.com, richardcochran@gmail.com Cc: weifeng.voon@intel.com, jiri@mellanox.com, m-karicheri2@ti.com, Jose.Abreu@synopsys.com, ilias.apalodimas@linaro.org, --to=jhs@mojatatu.com, --to=xiyou.wangcong@gmail.com, netdev@vger.kernel.org, Vladimir Oltean Subject: [RFC PATCH v2 net-next 13/15] net: dsa: sja1105: Make HOSTPRIO a kernel config Date: Fri, 30 Aug 2019 03:46:33 +0300 Message-Id: <20190830004635.24863-14-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190830004635.24863-1-olteanv@gmail.com> References: <20190830004635.24863-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Unfortunately with this hardware, there is no way to transmit in-band QoS hints with management frames (i.e. VLAN PCP is ignored). The traffic class for these is fixed in the static config (which in turn requires a reset to change). With the new ability to add time gates for individual traffic classes, there is a real danger that the user might unknowingly turn off the traffic class for PTP, BPDUs, LLDP etc. So we need to manage this situation the best we can. There isn't any knob in Linux for this, and changing it at runtime probably isn't worth it either. So just make the setting loud enough by promoting it to a Kconfig, which the user can customize to their particular setup. Signed-off-by: Vladimir Oltean --- drivers/net/dsa/sja1105/Kconfig | 9 +++++++++ drivers/net/dsa/sja1105/sja1105_main.c | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/net/dsa/sja1105/Kconfig b/drivers/net/dsa/sja1105/Kconfig index 55424f39cb0d..4dc873e985e6 100644 --- a/drivers/net/dsa/sja1105/Kconfig +++ b/drivers/net/dsa/sja1105/Kconfig @@ -17,6 +17,15 @@ tristate "NXP SJA1105 Ethernet switch family support" - SJA1105R (Gen. 2, SGMII, No TT-Ethernet) - SJA1105S (Gen. 2, SGMII, TT-Ethernet) +config NET_DSA_SJA1105_HOSTPRIO + int "Traffic class for management traffic" + range 0 7 + default 7 + depends on NET_DSA_SJA1105 + help + Configure the traffic class which will be used for management + (link-local) traffic sent and received over switch ports. + config NET_DSA_SJA1105_PTP bool "Support for the PTP clock on the NXP SJA1105 Ethernet switch" depends on NET_DSA_SJA1105 diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index 4b393782cc84..0c03347b6429 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -388,7 +388,7 @@ static int sja1105_init_general_params(struct sja1105_private *priv) /* Priority queue for link-local management frames * (both ingress to and egress from CPU - PTP, STP etc) */ - .hostprio = 7, + .hostprio = CONFIG_NET_DSA_SJA1105_HOSTPRIO, .mac_fltres1 = SJA1105_LINKLOCAL_FILTER_A, .mac_flt1 = SJA1105_LINKLOCAL_FILTER_A_MASK, .incl_srcpt1 = false, From patchwork Fri Aug 30 00:46:34 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1155594 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="SZSjbnCV"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 46KLR4548Bz9sNC for ; Fri, 30 Aug 2019 10:47:12 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727726AbfH3ArK (ORCPT ); Thu, 29 Aug 2019 20:47:10 -0400 Received: from mail-wm1-f65.google.com ([209.85.128.65]:40587 "EHLO mail-wm1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727604AbfH3ArJ (ORCPT ); Thu, 29 Aug 2019 20:47:09 -0400 Received: by mail-wm1-f65.google.com with SMTP id t9so5574173wmi.5 for ; Thu, 29 Aug 2019 17:47:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=n6MDv1cVh94kAqR6xYW3m+NuBDmtWX/Ey0XYlMKRbgg=; b=SZSjbnCVsBotBrUNXwWT7YUsnH5KMOr13rb0eJLZECuIAxo0mdLBBDG3vhwEQTXHX4 sz+CrSMd8iQM+RcaGmzHf455McS51sJSbzT4MU3npLxbH2mCAX+Ef7AiJO83S2JLWnCX pEwEV54TcivCAusyEos5YVNI5fI2RgNQjio5/Py4HhN7/ln+u7JK/T0QhoBVTb8Pa4TR FEcINTD6STrZwee1f3zWwjU8pvjTeuN5OXLrHEYmOy8N076mWaX67b17MmZ9GBvEuZEP OgZf2swwj2nKBeFSxfEzy3GIVCr1AF/y8uT5UoavpqqWHgVD3mzHT0lB/I5AWk5zQAsv 0T9w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=n6MDv1cVh94kAqR6xYW3m+NuBDmtWX/Ey0XYlMKRbgg=; b=EhISz8SrhqjMDTcg7vAmXDnLVzaCN3FR18h3nKw/2mdsb6iPSuaNNsdrojOkuidi1Z 9uJ5p8DIVS/NvUNoN8T68JjMAf7G0Gsad+6gOyl/9o2Rcc8szXbD826bKxmLAAdPtI98 JeV9DapfagDPnZTtdGojB52fkLdaR7qB8QQFwgFCSlNLiY+84sEr57Y9lWl/yPQBQ/sI Q8WwyXVEvKJmYsL1QnZ9xXdyux781A3BIBCIjFcNHkwzHM6UqU+ztDW/ivHPSlWyAKpy /12jw27/NUI2B4wsIfeKeO4k8zWpZNXWxZHabNH9SRRLQbctvZ31W8X6gL8zpgrQVOOS ra6A== X-Gm-Message-State: APjAAAXB3T0VLydeVgV9ro+7Uyn6FYvgdtEbScebMaIzpT+nzv/e9ywk Os7Ztdg+BspCT5rBzg5G52k= X-Google-Smtp-Source: APXvYqyIEnyf3McSiwdYXRNArMBNcLMHSYEW9Me226XX8Ads6cRX6OtZbOf4sg4eisWd4C/56Om1vQ== X-Received: by 2002:a7b:c246:: with SMTP id b6mr15068626wmj.13.1567126026688; Thu, 29 Aug 2019 17:47:06 -0700 (PDT) Received: from localhost.localdomain ([86.126.25.232]) by smtp.gmail.com with ESMTPSA id y3sm9298442wmg.2.2019.08.29.17.47.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Aug 2019 17:47:06 -0700 (PDT) From: Vladimir Oltean To: f.fainelli@gmail.com, vivien.didelot@gmail.com, andrew@lunn.ch, davem@davemloft.net, vinicius.gomes@intel.com, vedang.patel@intel.com, richardcochran@gmail.com Cc: weifeng.voon@intel.com, jiri@mellanox.com, m-karicheri2@ti.com, Jose.Abreu@synopsys.com, ilias.apalodimas@linaro.org, --to=jhs@mojatatu.com, --to=xiyou.wangcong@gmail.com, netdev@vger.kernel.org, Vladimir Oltean Subject: [RFC PATCH v2 net-next 14/15] net: dsa: sja1105: Make the PTP command read-write Date: Fri, 30 Aug 2019 03:46:34 +0300 Message-Id: <20190830004635.24863-15-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190830004635.24863-1-olteanv@gmail.com> References: <20190830004635.24863-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org The PTPSTRTSCH and PTPSTOPSCH bits are actually readable and indicate whether the time-aware scheduler is running or not. We will be using that for monitoring the scheduler in the next patch, so refactor the PTP command API in order to allow that. Signed-off-by: Vladimir Oltean --- drivers/net/dsa/sja1105/sja1105.h | 13 +++--- drivers/net/dsa/sja1105/sja1105_ptp.c | 64 ++++++++++++++++----------- drivers/net/dsa/sja1105/sja1105_ptp.h | 12 +++-- drivers/net/dsa/sja1105/sja1105_spi.c | 12 ++--- 4 files changed, 58 insertions(+), 43 deletions(-) diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index d95f9ce3b4f9..44f7385c51b5 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -20,6 +20,11 @@ */ #define SJA1105_AGEING_TIME_MS(ms) ((ms) / 10) +typedef enum { + SPI_READ = 0, + SPI_WRITE = 1, +} sja1105_spi_rw_mode_t; + #include "sja1105_ptp.h" #include "sja1105_tas.h" @@ -71,7 +76,6 @@ struct sja1105_info { const struct sja1105_dynamic_table_ops *dyn_ops; const struct sja1105_table_ops *static_ops; const struct sja1105_regs *regs; - int (*ptp_cmd)(const void *ctx, const void *data); int (*reset_cmd)(const void *ctx, const void *data); int (*setup_rgmii_delay)(const void *ctx, int port); /* Prototypes from include/net/dsa.h */ @@ -79,6 +83,8 @@ struct sja1105_info { const unsigned char *addr, u16 vid); int (*fdb_del_cmd)(struct dsa_switch *ds, int port, const unsigned char *addr, u16 vid); + void (*ptp_cmd_packing)(u8 *buf, struct sja1105_ptp_cmd *cmd, + enum packing_op op); const char *name; }; @@ -108,11 +114,6 @@ struct sja1105_spi_message { u64 address; }; -typedef enum { - SPI_READ = 0, - SPI_WRITE = 1, -} sja1105_spi_rw_mode_t; - /* From sja1105_main.c */ int sja1105_static_config_reload(struct sja1105_private *priv); diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.c b/drivers/net/dsa/sja1105/sja1105_ptp.c index f85f44bdab31..ed80278a3521 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.c +++ b/drivers/net/dsa/sja1105/sja1105_ptp.c @@ -59,42 +59,50 @@ int sja1105_get_ts_info(struct dsa_switch *ds, int port, return 0; } -int sja1105et_ptp_cmd(const void *ctx, const void *data) +void sja1105et_ptp_cmd_packing(u8 *buf, struct sja1105_ptp_cmd *cmd, + enum packing_op op) { - const struct sja1105_ptp_cmd *cmd = data; - const struct sja1105_private *priv = ctx; - const struct sja1105_regs *regs = priv->info->regs; const int size = SJA1105_SIZE_PTP_CMD; - u8 buf[SJA1105_SIZE_PTP_CMD] = {0}; /* No need to keep this as part of the structure */ u64 valid = 1; - sja1105_pack(buf, &valid, 31, 31, size); - sja1105_pack(buf, &cmd->resptp, 2, 2, size); - sja1105_pack(buf, &cmd->corrclk4ts, 1, 1, size); - sja1105_pack(buf, &cmd->ptpclkadd, 0, 0, size); - - return sja1105_spi_send_packed_buf(priv, SPI_WRITE, regs->ptp_control, - buf, SJA1105_SIZE_PTP_CMD); + sja1105_packing(buf, &valid, 31, 31, size, op); + sja1105_packing(buf, &cmd->resptp, 2, 2, size, op); + sja1105_packing(buf, &cmd->corrclk4ts, 1, 1, size, op); + sja1105_packing(buf, &cmd->ptpclkadd, 0, 0, size, op); } -int sja1105pqrs_ptp_cmd(const void *ctx, const void *data) +void sja1105pqrs_ptp_cmd_packing(u8 *buf, struct sja1105_ptp_cmd *cmd, + enum packing_op op) { - const struct sja1105_ptp_cmd *cmd = data; - const struct sja1105_private *priv = ctx; - const struct sja1105_regs *regs = priv->info->regs; const int size = SJA1105_SIZE_PTP_CMD; - u8 buf[SJA1105_SIZE_PTP_CMD] = {0}; /* No need to keep this as part of the structure */ u64 valid = 1; - sja1105_pack(buf, &valid, 31, 31, size); - sja1105_pack(buf, &cmd->resptp, 3, 3, size); - sja1105_pack(buf, &cmd->corrclk4ts, 2, 2, size); - sja1105_pack(buf, &cmd->ptpclkadd, 0, 0, size); + sja1105_packing(buf, &valid, 31, 31, size, op); + sja1105_packing(buf, &cmd->resptp, 3, 3, size, op); + sja1105_packing(buf, &cmd->corrclk4ts, 2, 2, size, op); + sja1105_packing(buf, &cmd->ptpclkadd, 0, 0, size, op); +} - return sja1105_spi_send_packed_buf(priv, SPI_WRITE, regs->ptp_control, - buf, SJA1105_SIZE_PTP_CMD); +static int sja1105_ptp_commit(struct sja1105_private *priv, + struct sja1105_ptp_cmd *cmd, + sja1105_spi_rw_mode_t rw) +{ + const struct sja1105_regs *regs = priv->info->regs; + u8 buf[SJA1105_SIZE_PTP_CMD] = {0}; + int rc; + + if (rw == SPI_WRITE) + priv->info->ptp_cmd_packing(buf, cmd, PACK); + + rc = sja1105_spi_send_packed_buf(priv, rw, regs->ptp_control, + buf, SJA1105_SIZE_PTP_CMD); + + if (rw == SPI_READ) + priv->info->ptp_cmd_packing(buf, cmd, UNPACK); + + return rc; } /* The switch returns partial timestamps (24 bits for SJA1105 E/T, which wrap @@ -212,7 +220,7 @@ int sja1105_ptp_reset(struct sja1105_private *priv) cmd.resptp = 1; dev_dbg(priv->ds->dev, "Resetting PTP clock\n"); - rc = priv->info->ptp_cmd(priv, &cmd); + rc = sja1105_ptp_commit(priv, &cmd, SPI_WRITE); mutex_unlock(&ptp_data->lock); @@ -250,12 +258,14 @@ static int sja1105_ptp_gettimex(struct ptp_clock_info *ptp, static int sja1105_ptp_mode_set(struct sja1105_private *priv, enum sja1105_ptp_clk_mode mode) { - if (priv->ptp_data.cmd.ptpclkadd == mode) + struct sja1105_ptp_data *ptp_data = &priv->ptp_data; + + if (ptp_data->cmd.ptpclkadd == mode) return 0; - priv->ptp_data.cmd.ptpclkadd = mode; + ptp_data->cmd.ptpclkadd = mode; - return priv->info->ptp_cmd(priv, &priv->ptp_data.cmd); + return sja1105_ptp_commit(priv, &ptp_data->cmd, SPI_WRITE); } /* Caller must hold priv->ptp_data.lock */ diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.h b/drivers/net/dsa/sja1105/sja1105_ptp.h index dfe856200394..c24c40115650 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.h +++ b/drivers/net/dsa/sja1105/sja1105_ptp.h @@ -48,9 +48,11 @@ void sja1105_ptp_clock_unregister(struct sja1105_private *priv); int sja1105_ptpegr_ts_poll(struct sja1105_private *priv, int port, u64 *ts); -int sja1105et_ptp_cmd(const void *ctx, const void *data); +void sja1105et_ptp_cmd_packing(u8 *buf, struct sja1105_ptp_cmd *cmd, + enum packing_op op); -int sja1105pqrs_ptp_cmd(const void *ctx, const void *data); +void sja1105pqrs_ptp_cmd_packing(u8 *buf, struct sja1105_ptp_cmd *cmd, + enum packing_op op); int sja1105_get_ts_info(struct dsa_switch *ds, int port, struct ethtool_ts_info *ts); @@ -73,6 +75,8 @@ int __sja1105_ptp_adjtime(struct sja1105_private *priv, s64 delta); #else +struct sja1105_ptp_cmd; + /* Structures cannot be empty in C. Bah! * Keep the mutex as the only element, which is a bit more difficult to * refactor out of sja1105_main.c anyway. @@ -131,9 +135,9 @@ static inline int __sja1105_ptp_adjtime(struct sja1105_private *priv, s64 delta) return 0; } -#define sja1105et_ptp_cmd NULL +#define sja1105et_ptp_cmd_packing NULL -#define sja1105pqrs_ptp_cmd NULL +#define sja1105pqrs_ptp_cmd_packing NULL #define sja1105_get_ts_info NULL diff --git a/drivers/net/dsa/sja1105/sja1105_spi.c b/drivers/net/dsa/sja1105/sja1105_spi.c index eae9c9baa189..794cc5077565 100644 --- a/drivers/net/dsa/sja1105/sja1105_spi.c +++ b/drivers/net/dsa/sja1105/sja1105_spi.c @@ -571,7 +571,7 @@ struct sja1105_info sja1105e_info = { .reset_cmd = sja1105et_reset_cmd, .fdb_add_cmd = sja1105et_fdb_add, .fdb_del_cmd = sja1105et_fdb_del, - .ptp_cmd = sja1105et_ptp_cmd, + .ptp_cmd_packing = sja1105et_ptp_cmd_packing, .regs = &sja1105et_regs, .name = "SJA1105E", }; @@ -585,7 +585,7 @@ struct sja1105_info sja1105t_info = { .reset_cmd = sja1105et_reset_cmd, .fdb_add_cmd = sja1105et_fdb_add, .fdb_del_cmd = sja1105et_fdb_del, - .ptp_cmd = sja1105et_ptp_cmd, + .ptp_cmd_packing = sja1105et_ptp_cmd_packing, .regs = &sja1105et_regs, .name = "SJA1105T", }; @@ -600,7 +600,7 @@ struct sja1105_info sja1105p_info = { .reset_cmd = sja1105pqrs_reset_cmd, .fdb_add_cmd = sja1105pqrs_fdb_add, .fdb_del_cmd = sja1105pqrs_fdb_del, - .ptp_cmd = sja1105pqrs_ptp_cmd, + .ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing, .regs = &sja1105pqrs_regs, .name = "SJA1105P", }; @@ -615,7 +615,7 @@ struct sja1105_info sja1105q_info = { .reset_cmd = sja1105pqrs_reset_cmd, .fdb_add_cmd = sja1105pqrs_fdb_add, .fdb_del_cmd = sja1105pqrs_fdb_del, - .ptp_cmd = sja1105pqrs_ptp_cmd, + .ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing, .regs = &sja1105pqrs_regs, .name = "SJA1105Q", }; @@ -630,7 +630,7 @@ struct sja1105_info sja1105r_info = { .reset_cmd = sja1105pqrs_reset_cmd, .fdb_add_cmd = sja1105pqrs_fdb_add, .fdb_del_cmd = sja1105pqrs_fdb_del, - .ptp_cmd = sja1105pqrs_ptp_cmd, + .ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing, .regs = &sja1105pqrs_regs, .name = "SJA1105R", }; @@ -646,6 +646,6 @@ struct sja1105_info sja1105s_info = { .reset_cmd = sja1105pqrs_reset_cmd, .fdb_add_cmd = sja1105pqrs_fdb_add, .fdb_del_cmd = sja1105pqrs_fdb_del, - .ptp_cmd = sja1105pqrs_ptp_cmd, + .ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing, .name = "SJA1105S", }; From patchwork Fri Aug 30 00:46:35 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1155597 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="Sv2Ay4H1"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 46KLRF1DMnz9sN6 for ; Fri, 30 Aug 2019 10:47:21 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727768AbfH3ArU (ORCPT ); Thu, 29 Aug 2019 20:47:20 -0400 Received: from mail-wm1-f67.google.com ([209.85.128.67]:53209 "EHLO mail-wm1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727731AbfH3ArO (ORCPT ); Thu, 29 Aug 2019 20:47:14 -0400 Received: by mail-wm1-f67.google.com with SMTP id t17so5496578wmi.2 for ; Thu, 29 Aug 2019 17:47:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=8QMFISiQjz0hREIh8mIIF5ovLu505oRHUDBNINKJUpE=; b=Sv2Ay4H1AW/BS2SKUG9WQDSeIhif8zNfCHv5gALgNpRG6OMgighDLxqG3qsCTnDur6 LNgtNHwFnJBGzub/uUYj+Jo14CWCMdaG9LPNublpM0AV2SLfbzj9cuCrBby54Rd1dUD+ HO+vr1Z1LykqkhR5JuyMk93425K14/ORExAJUWYd2hPOqVtGMpFMfcHWehVXo7DyVhDi brQlfrcrn1HBodfN7zAtad+sK3hl+3cXcq0BNBcFqibiTIqZnXT5ZaYAhixIhbO69ks3 SbVesfpWCG6jX/1k1/Yn/ZvczNFQ5qAx/vCOzzLM2b89b+BLMZ6VtmriLEx5qrg970ZY LFHQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=8QMFISiQjz0hREIh8mIIF5ovLu505oRHUDBNINKJUpE=; b=jvkZy8XPMGX2U+UnvURqe2GcuDZMl+N0PpEz/Yr379pvmULYsB8oocdL8mWtPxhpAA zNGHuKr6YSvPyH+HJJYS9fTrv7jINwHcE23bYJbTrqoQTdm+7Yv/xVBkuSw25qsTrX9F 9F3/6btQMa1IY/aN7JW1fKetQUcMZkcMPzqRZu5HAlOfUVvwO/XDLp9/TmNL5YEc89J3 HyaX3kyQ1NKIkKUdEigSOCMVGzX3Y4zBBIjrt/Kooeeqen6Du8CxRA641J75TZByLqQ+ Y1XeDimje5mA0mB4zQrlW7jXaL4mMU34UmqoIIvk8x9iLC4gpW+vqo02Do3/6Emyu9Cz RyYQ== X-Gm-Message-State: APjAAAWwdKvEjx0aB0NkrJjnKtkkMr7QdsKO0roxvd+M8yZbJXSjkt1q NXDC7BFO0iYFvtL7wCzpr/w= X-Google-Smtp-Source: APXvYqyyK4FdscfnC68GXA7dQq7K1IdZkmbth7kJqqwFdnRyQiQaMKmlJ9bhDVVIQdDnZbs+IAgFXA== X-Received: by 2002:a1c:3944:: with SMTP id g65mr15205926wma.68.1567126027987; Thu, 29 Aug 2019 17:47:07 -0700 (PDT) Received: from localhost.localdomain ([86.126.25.232]) by smtp.gmail.com with ESMTPSA id y3sm9298442wmg.2.2019.08.29.17.47.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Aug 2019 17:47:07 -0700 (PDT) From: Vladimir Oltean To: f.fainelli@gmail.com, vivien.didelot@gmail.com, andrew@lunn.ch, davem@davemloft.net, vinicius.gomes@intel.com, vedang.patel@intel.com, richardcochran@gmail.com Cc: weifeng.voon@intel.com, jiri@mellanox.com, m-karicheri2@ti.com, Jose.Abreu@synopsys.com, ilias.apalodimas@linaro.org, --to=jhs@mojatatu.com, --to=xiyou.wangcong@gmail.com, netdev@vger.kernel.org, Vladimir Oltean Subject: [RFC PATCH v2 net-next 15/15] net: dsa: sja1105: Implement state machine for TAS with PTP clock source Date: Fri, 30 Aug 2019 03:46:35 +0300 Message-Id: <20190830004635.24863-16-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190830004635.24863-1-olteanv@gmail.com> References: <20190830004635.24863-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Tested using the following bash script and the tc from iproute2-next: #!/bin/bash set -e -u -o pipefail NSEC_PER_SEC="1000000000" gatemask() { local tc_list="$1" local mask=0 for tc in ${tc_list}; do mask=$((${mask} | (1 << ${tc}))) done printf "%02x" ${mask} } if ! systemctl is-active --quiet ptp4l; then echo "Please start the ptp4l service" exit fi now=$(phc_ctl /dev/ptp1 get | gawk '/clock time is/ { print $5; }') # Phase-align the base time to the start of the next second. sec=$(echo "${now}" | gawk -F. '{ print $1; }') base_time="$(((${sec} + 1) * ${NSEC_PER_SEC}))" echo 'file drivers/net/dsa/sja1105/sja1105_tas.c +plm' | \ sudo tee /sys/kernel/debug/dynamic_debug/control tc qdisc add dev swp5 parent root handle 100 taprio \ num_tc 8 \ map 0 1 2 3 5 6 7 \ queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 \ base-time ${base_time} \ sched-entry S $(gatemask 7) 100000 \ sched-entry S $(gatemask "0 1 2 3 4 5 6") 400000 \ clockid CLOCK_TAI flags 2 The "state machine" is a workqueue invoked after each manipulation command on the PTP clock (reset, adjust time, set time, adjust frequency) which checks over the state of the time-aware scheduler. So it is not monitored periodically, only in reaction to a PTP command typically triggered from a userspace daemon (linuxptp). Otherwise there is no reason for things to go wrong. Now that the timecounter/cyclecounter has been replaced with hardware operations on the PTP clock, the TAS Kconfig now depends upon PTP and the standalone clocksource operating mode has been removed. Signed-off-by: Vladimir Oltean --- drivers/net/dsa/sja1105/Kconfig | 2 +- drivers/net/dsa/sja1105/sja1105.h | 2 + drivers/net/dsa/sja1105/sja1105_ptp.c | 26 +- drivers/net/dsa/sja1105/sja1105_ptp.h | 13 + drivers/net/dsa/sja1105/sja1105_spi.c | 4 + drivers/net/dsa/sja1105/sja1105_tas.c | 420 +++++++++++++++++++++++++- drivers/net/dsa/sja1105/sja1105_tas.h | 27 ++ 7 files changed, 480 insertions(+), 14 deletions(-) diff --git a/drivers/net/dsa/sja1105/Kconfig b/drivers/net/dsa/sja1105/Kconfig index 4dc873e985e6..9316a23b7c30 100644 --- a/drivers/net/dsa/sja1105/Kconfig +++ b/drivers/net/dsa/sja1105/Kconfig @@ -35,7 +35,7 @@ config NET_DSA_SJA1105_PTP config NET_DSA_SJA1105_TAS bool "Support for the Time-Aware Scheduler on NXP SJA1105" - depends on NET_DSA_SJA1105 + depends on NET_DSA_SJA1105_PTP help This enables support for the TTEthernet-based egress scheduling engine in the SJA1105 DSA driver, which is controlled using a diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index 44f7385c51b5..e8f95b6fadfa 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -40,6 +40,8 @@ struct sja1105_regs { u64 ptp_control; u64 ptpclk; u64 ptpclkrate; + u64 ptpclkcorp; + u64 ptpschtm; u64 ptpegr_ts[SJA1105_NUM_PORTS]; u64 pad_mii_tx[SJA1105_NUM_PORTS]; u64 pad_mii_id[SJA1105_NUM_PORTS]; diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.c b/drivers/net/dsa/sja1105/sja1105_ptp.c index ed80278a3521..b037834ff820 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.c +++ b/drivers/net/dsa/sja1105/sja1105_ptp.c @@ -67,6 +67,8 @@ void sja1105et_ptp_cmd_packing(u8 *buf, struct sja1105_ptp_cmd *cmd, u64 valid = 1; sja1105_packing(buf, &valid, 31, 31, size, op); + sja1105_packing(buf, &cmd->ptpstrtsch, 30, 30, size, op); + sja1105_packing(buf, &cmd->ptpstopsch, 29, 29, size, op); sja1105_packing(buf, &cmd->resptp, 2, 2, size, op); sja1105_packing(buf, &cmd->corrclk4ts, 1, 1, size, op); sja1105_packing(buf, &cmd->ptpclkadd, 0, 0, size, op); @@ -80,14 +82,16 @@ void sja1105pqrs_ptp_cmd_packing(u8 *buf, struct sja1105_ptp_cmd *cmd, u64 valid = 1; sja1105_packing(buf, &valid, 31, 31, size, op); + sja1105_packing(buf, &cmd->ptpstrtsch, 30, 30, size, op); + sja1105_packing(buf, &cmd->ptpstopsch, 29, 29, size, op); sja1105_packing(buf, &cmd->resptp, 3, 3, size, op); sja1105_packing(buf, &cmd->corrclk4ts, 2, 2, size, op); sja1105_packing(buf, &cmd->ptpclkadd, 0, 0, size, op); } -static int sja1105_ptp_commit(struct sja1105_private *priv, - struct sja1105_ptp_cmd *cmd, - sja1105_spi_rw_mode_t rw) +int sja1105_ptp_commit(struct sja1105_private *priv, + struct sja1105_ptp_cmd *cmd, + sja1105_spi_rw_mode_t rw) { const struct sja1105_regs *regs = priv->info->regs; u8 buf[SJA1105_SIZE_PTP_CMD] = {0}; @@ -222,6 +226,8 @@ int sja1105_ptp_reset(struct sja1105_private *priv) dev_dbg(priv->ds->dev, "Resetting PTP clock\n"); rc = sja1105_ptp_commit(priv, &cmd, SPI_WRITE); + sja1105_tas_clockstep(priv); + mutex_unlock(&ptp_data->lock); return rc; @@ -291,7 +297,11 @@ int __sja1105_ptp_settime(struct sja1105_private *priv, u64 ns, return rc; } - return sja1105_ptpclkval_write(priv, ticks, ptp_sts); + rc = sja1105_ptpclkval_write(priv, ticks, ptp_sts); + + sja1105_tas_clockstep(priv); + + return rc; } static int sja1105_ptp_settime(struct ptp_clock_info *ptp, @@ -331,6 +341,8 @@ static int sja1105_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) rc = sja1105_spi_send_int(priv, SPI_WRITE, regs->ptpclkrate, &clkrate, 4, NULL); + sja1105_tas_adjfreq(priv); + mutex_unlock(&priv->ptp_data.lock); return rc; @@ -366,7 +378,11 @@ int __sja1105_ptp_adjtime(struct sja1105_private *priv, s64 delta) return rc; } - return sja1105_ptpclkval_write(priv, ticks, NULL); + rc = sja1105_ptpclkval_write(priv, ticks, NULL); + + sja1105_tas_clockstep(priv); + + return rc; } static int sja1105_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.h b/drivers/net/dsa/sja1105/sja1105_ptp.h index c24c40115650..da68e5881e5f 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.h +++ b/drivers/net/dsa/sja1105/sja1105_ptp.h @@ -29,6 +29,8 @@ enum sja1105_ptp_clk_mode { }; struct sja1105_ptp_cmd { + u64 ptpstrtsch; /* start schedule */ + u64 ptpstopsch; /* stop schedule */ u64 resptp; /* reset */ u64 corrclk4ts; /* use the corrected clock for timestamps */ u64 ptpclkadd; /* enum sja1105_ptp_clk_mode */ @@ -73,6 +75,10 @@ int __sja1105_ptp_settime(struct sja1105_private *priv, u64 ns, int __sja1105_ptp_adjtime(struct sja1105_private *priv, s64 delta); +int sja1105_ptp_commit(struct sja1105_private *priv, + struct sja1105_ptp_cmd *cmd, + sja1105_spi_rw_mode_t rw); + #else struct sja1105_ptp_cmd; @@ -135,6 +141,13 @@ static inline int __sja1105_ptp_adjtime(struct sja1105_private *priv, s64 delta) return 0; } +static inline int sja1105_ptp_commit(struct sja1105_private *priv, + struct sja1105_ptp_cmd *cmd, + sja1105_spi_rw_mode_t rw) +{ + return 0; +} + #define sja1105et_ptp_cmd_packing NULL #define sja1105pqrs_ptp_cmd_packing NULL diff --git a/drivers/net/dsa/sja1105/sja1105_spi.c b/drivers/net/dsa/sja1105/sja1105_spi.c index 794cc5077565..f6df050c15ec 100644 --- a/drivers/net/dsa/sja1105/sja1105_spi.c +++ b/drivers/net/dsa/sja1105/sja1105_spi.c @@ -526,9 +526,11 @@ static struct sja1105_regs sja1105et_regs = { .rmii_ref_clk = {0x100015, 0x10001C, 0x100023, 0x10002A, 0x100031}, .rmii_ext_tx_clk = {0x100018, 0x10001F, 0x100026, 0x10002D, 0x100034}, .ptpegr_ts = {0xC0, 0xC2, 0xC4, 0xC6, 0xC8}, + .ptpschtm = 0x12, /* Spans 0x12 to 0x13 */ .ptp_control = 0x17, .ptpclk = 0x18, /* Spans 0x18 to 0x19 */ .ptpclkrate = 0x1A, + .ptpclkcorp = 0x1D, }; static struct sja1105_regs sja1105pqrs_regs = { @@ -556,9 +558,11 @@ static struct sja1105_regs sja1105pqrs_regs = { .rmii_ext_tx_clk = {0x100017, 0x10001D, 0x100023, 0x100029, 0x10002F}, .qlevel = {0x604, 0x614, 0x624, 0x634, 0x644}, .ptpegr_ts = {0xC0, 0xC4, 0xC8, 0xCC, 0xD0}, + .ptpschtm = 0x13, /* Spans 0x13 to 0x14 */ .ptp_control = 0x18, .ptpclk = 0x19, .ptpclkrate = 0x1B, + .ptpclkcorp = 0x1E, }; struct sja1105_info sja1105e_info = { diff --git a/drivers/net/dsa/sja1105/sja1105_tas.c b/drivers/net/dsa/sja1105/sja1105_tas.c index e316008246f6..d19c8c62812c 100644 --- a/drivers/net/dsa/sja1105/sja1105_tas.c +++ b/drivers/net/dsa/sja1105/sja1105_tas.c @@ -12,6 +12,8 @@ #define config_work_to_sja1105_tas(d) \ container_of((d), struct sja1105_tas_data, config_work) +#define tas_work_to_sja1105_tas(d) \ + container_of((d), struct sja1105_tas_data, tas_work) #define tas_to_sja1105(d) \ container_of((d), struct sja1105_private, tas_data) @@ -23,6 +25,100 @@ static u64 ns_to_sja1105_delta(u64 ns) return div_u64(ns, 200); } +static u64 sja1105_delta_to_ns(u64 tas_cycles) +{ + return tas_cycles * 200; +} + +/* Calculate the first base_time in the future that satisfies this + * relationship: + * + * future_base_time = base_time + N x cycle_time >= now, or + * + * now - base_time + * N >= --------------- + * cycle_time + * + * Because N is an integer, the ceiling value of the above "a / b" ratio + * is in fact precisely the floor value of "(a + b - 1) / b", which is + * easier to calculate only having integer division tools. + */ +static u64 future_base_time(u64 base_time, u64 cycle_time, u64 now) +{ + u64 a, b, n; + + if (base_time >= now) + return base_time; + + a = now - base_time; + b = cycle_time; + n = div_u64(a + b - 1, b); + + return base_time + n * cycle_time; +} + +static int sja1105_tas_set_runtime_params(struct sja1105_private *priv) +{ + struct sja1105_tas_data *tas_data = &priv->tas_data; + s64 earliest_base_time = S64_MAX; + s64 latest_base_time = 0; + s64 its_cycle_time = 0; + s64 max_cycle_time = 0; + int port; + + tas_data->enabled = false; + + for (port = 0; port < SJA1105_NUM_PORTS; port++) { + const struct tc_taprio_qopt_offload *tas_config; + + tas_config = tas_data->config[port]; + if (!tas_config) + continue; + + tas_data->enabled = true; + + if (max_cycle_time < tas_config->cycle_time) + max_cycle_time = tas_config->cycle_time; + if (latest_base_time < tas_config->base_time) + latest_base_time = tas_config->base_time; + if (earliest_base_time > tas_config->base_time) { + earliest_base_time = tas_config->base_time; + its_cycle_time = tas_config->cycle_time; + } + } + + if (!tas_data->enabled) + return 0; + + /* Roll the earliest base time over until it is in a comparable + * time base with the latest, then compare their deltas. + * We want to enforce that all ports' base times are within + * SJA1105_TAS_MAX_DELTA 200ns cycles of one another. + */ + earliest_base_time = future_base_time(earliest_base_time, + its_cycle_time, + latest_base_time); + if (latest_base_time - earliest_base_time > + sja1105_delta_to_ns(SJA1105_TAS_MAX_DELTA)) { + dev_err(priv->ds->dev, + "Base times too far apart: min %llu max %llu\n", + earliest_base_time, latest_base_time); + return -ERANGE; + } + + tas_data->earliest_base_time = earliest_base_time; + tas_data->max_cycle_time = max_cycle_time; + + dev_dbg(priv->ds->dev, "earliest base time %llu\n", + tas_data->earliest_base_time); + dev_dbg(priv->ds->dev, "latest base time %llu\n", + tas_data->earliest_base_time); + dev_dbg(priv->ds->dev, "max cycle time %llu\n", + tas_data->max_cycle_time); + + return 0; +} + /* Lo and behold: the egress scheduler from hell. * * At the hardware level, the Time-Aware Shaper holds a global linear arrray of @@ -108,7 +204,11 @@ static int sja1105_init_scheduling(struct sja1105_private *priv) int num_cycles = 0; int cycle = 0; int i, k = 0; - int port; + int port, rc; + + rc = sja1105_tas_set_runtime_params(priv); + if (rc < 0) + return rc; /* Discard previous Schedule Table */ table = &priv->static_config.tables[BLK_IDX_SCHEDULE]; @@ -189,11 +289,13 @@ static int sja1105_init_scheduling(struct sja1105_private *priv) schedule_entry_points = table->entries; /* Finally start populating the static config tables */ - schedule_entry_points_params->clksrc = SJA1105_TAS_CLKSRC_STANDALONE; + schedule_entry_points_params->clksrc = SJA1105_TAS_CLKSRC_PTP; schedule_entry_points_params->actsubsch = num_cycles - 1; for (port = 0; port < SJA1105_NUM_PORTS; port++) { const struct tc_taprio_qopt_offload *tas_config; + /* Relative base time */ + u64 rbt; tas_config = tas_data->config[port]; if (!tas_config) @@ -201,13 +303,20 @@ static int sja1105_init_scheduling(struct sja1105_private *priv) schedule_start_idx = k; schedule_end_idx = k + tas_config->num_entries - 1; - /* TODO this is only a relative base time for the subschedule - * (relative to PTPSCHTM). But as we're using standalone and - * not PTP clock as time reference, leave it like this for now. - * Later we'll have to enforce that all ports' base times are - * within SJA1105_TAS_MAX_DELTA 200ns cycles of one another. + /* This is only a relative base time for the subschedule + * (relative to PTPSCHTM - aka the operational base time). */ - entry_point_delta = ns_to_sja1105_delta(tas_config->base_time); + rbt = future_base_time(tas_config->base_time, + tas_config->cycle_time, + tas_data->earliest_base_time); + rbt -= tas_data->earliest_base_time; + /* UM10944.pdf 4.2.2. Schedule Entry Points table says that + * delta cannot be zero, which is shitty. Advance all relative + * base times by 1 TAS cycle, so that even the earliest base + * time becomes 1 in relative terms. Then start the operational + * base time (PTPSCHTM) one TAS cycle earlier than planned. + */ + entry_point_delta = ns_to_sja1105_delta(rbt) + 1; schedule_entry_points[cycle].subschindx = cycle; schedule_entry_points[cycle].delta = entry_point_delta; @@ -429,9 +538,303 @@ int sja1105_setup_tc_taprio(struct dsa_switch *ds, int port, return 0; } +static int sja1105_tas_check_running(struct sja1105_private *priv) +{ + struct sja1105_tas_data *tas_data = &priv->tas_data; + struct sja1105_ptp_cmd cmd = {0}; + int rc; + + rc = sja1105_ptp_commit(priv, &cmd, SPI_READ); + if (rc < 0) + return rc; + + if (cmd.ptpstrtsch == 1) + /* Schedule successfully started */ + tas_data->state = SJA1105_TAS_STATE_RUNNING; + else if (cmd.ptpstopsch == 1) + /* Schedule is stopped */ + tas_data->state = SJA1105_TAS_STATE_DISABLED; + else + /* Schedule is probably not configured with PTP clock source */ + rc = -EINVAL; + + return rc; +} + +/* Write to PTPCLKCORP */ +static int sja1105_tas_adjust_drift(struct sja1105_private *priv, + u64 correction) +{ + const struct sja1105_regs *regs = priv->info->regs; + u64 ptpclkcorp = ns_to_sja1105_ticks(correction); + + return sja1105_spi_send_int(priv, SPI_WRITE, regs->ptpclkcorp, + &ptpclkcorp, 4, NULL); +} + +/* Write to PTPSCHTM */ +static int sja1105_tas_set_base_time(struct sja1105_private *priv, + u64 base_time) +{ + const struct sja1105_regs *regs = priv->info->regs; + u64 ptpschtm = ns_to_sja1105_ticks(base_time); + + return sja1105_spi_send_int(priv, SPI_WRITE, regs->ptpschtm, + &ptpschtm, 8, NULL); +} + +static int sja1105_tas_start(struct sja1105_private *priv) +{ + struct sja1105_tas_data *tas_data = &priv->tas_data; + struct sja1105_ptp_cmd *cmd = &priv->ptp_data.cmd; + int rc; + + dev_dbg(priv->ds->dev, "Starting the TAS\n"); + + if (tas_data->state == SJA1105_TAS_STATE_ENABLED_NOT_RUNNING || + tas_data->state == SJA1105_TAS_STATE_RUNNING) { + dev_err(priv->ds->dev, "TAS already started\n"); + return -EINVAL; + } + + cmd->ptpstrtsch = 1; + cmd->ptpstopsch = 0; + + rc = sja1105_ptp_commit(priv, cmd, SPI_WRITE); + if (rc < 0) + return rc; + + tas_data->state = SJA1105_TAS_STATE_ENABLED_NOT_RUNNING; + + return 0; +} + +static int sja1105_tas_stop(struct sja1105_private *priv) +{ + struct sja1105_tas_data *tas_data = &priv->tas_data; + struct sja1105_ptp_cmd *cmd = &priv->ptp_data.cmd; + int rc; + + dev_dbg(priv->ds->dev, "Stopping the TAS\n"); + + if (tas_data->state == SJA1105_TAS_STATE_DISABLED) { + dev_err(priv->ds->dev, "TAS already disabled\n"); + return -EINVAL; + } + + cmd->ptpstopsch = 1; + cmd->ptpstrtsch = 0; + + rc = sja1105_ptp_commit(priv, cmd, SPI_WRITE); + if (rc < 0) + return rc; + + tas_data->state = SJA1105_TAS_STATE_DISABLED; + + return 0; +} + +/* The schedule engine and the PTP clock are driven by the same oscillator, and + * they run in parallel. But whilst the PTP clock can keep an absolute + * time-of-day, the schedule engine is only running in 'ticks' (25 ticks make + * up a delta, which is 200ns), and wrapping around at the end of each cycle. + * The schedule engine is started when the PTP clock reaches the PTPSCHTM time + * (in PTP domain). + * Because the PTP clock can be rate-corrected (accelerated or slowed down) by + * a software servo, and the schedule engine clock runs in parallel to the PTP + * clock, there is logic internal to the switch that periodically keeps the + * schedule engine from drifting away. The frequency with which this internal + * syntonization happens is the PTP clock correction period (PTPCLKCORP). It is + * a value also in the PTP clock domain, and is also rate-corrected. + * To be precise, during a correction period, there is logic to determine by + * how many scheduler clock ticks has the PTP clock drifted. At the end of each + * correction period/beginning of new one, the length of a delta is shrunk or + * expanded with an integer number of ticks, compared with the typical 25. + * So a delta lasts for 200ns (or 25 ticks) only on average. + * Sometimes it is longer, sometimes it is shorter. The internal syntonization + * logic can adjust for at most 5 ticks each 20 ticks. + * + * The first implication is that you should choose your schedule correction + * period to be an integer multiple of the schedule length. Preferably one. + * In case there are schedules of multiple ports active, then the correction + * period needs to be a multiple of them all. Given the restriction that the + * cycle times have to be multiples of one another anyway, this means the + * correction period can simply be the largest cycle time, hence the current + * choice. This way, the updates are always synchronous to the transmission + * cycle, and therefore predictable. + * + * The second implication is that at the beginning of a correction period, the + * first few deltas will be modulated in time, until the schedule engine is + * properly phase-aligned with the PTP clock. For this reason, you should place + * your best-effort traffic at the beginning of a cycle, and your + * time-triggered traffic afterwards. + * + * The third implication is that once the schedule engine is started, it can + * only adjust for so much drift within a correction period. In the servo you + * can only change the PTPCLKRATE, but not step the clock (PTPCLKADD). If you + * want to do the latter, you need to stop and restart the schedule engine, + * which is what the state machine handles. + */ +static void sja1105_tas_state_machine(struct work_struct *work) +{ + struct sja1105_tas_data *tas_data = tas_work_to_sja1105_tas(work); + struct sja1105_private *priv = tas_to_sja1105(tas_data); + struct sja1105_ptp_data *ptp_data = &priv->ptp_data; + struct timespec64 base_time_ts, now_ts; + struct dsa_switch *ds = priv->ds; + struct timespec64 diff; + s64 base_time, now; + int rc = 0; + + mutex_lock(&ptp_data->lock); + + switch (tas_data->state) { + case SJA1105_TAS_STATE_DISABLED: + + dev_dbg(ds->dev, "TAS state: disabled\n"); + /* Can't do anything at all if clock is still being stepped */ + if (tas_data->last_op != SJA1105_PTP_ADJUSTFREQ) + break; + + rc = sja1105_tas_adjust_drift(priv, tas_data->max_cycle_time); + if (rc < 0) + break; + + now = __sja1105_ptp_gettimex(priv, NULL); + + /* Plan to start the earliest schedule first. The others + * will be started in hardware, by way of their respective + * entry points delta. + * Try our best to avoid fringe cases (race condition between + * ptpschtm and ptpstrtsch) by pushing the oper_base_time at + * least one second in the future from now. This is not ideal, + * but this only needs to buy us time until the + * sja1105_tas_start command below gets executed. + */ + base_time = future_base_time(tas_data->earliest_base_time, + tas_data->max_cycle_time, + now + 1ull * NSEC_PER_SEC); + base_time -= sja1105_delta_to_ns(1); + + rc = sja1105_tas_set_base_time(priv, base_time); + if (rc < 0) + break; + + tas_data->oper_base_time = base_time; + + rc = sja1105_tas_start(priv); + if (rc < 0) + break; + + base_time_ts = ns_to_timespec64(base_time); + now_ts = ns_to_timespec64(now); + + dev_dbg(ds->dev, "OPER base time %lld.%09ld (now %lld.%09ld)\n", + base_time_ts.tv_sec, base_time_ts.tv_nsec, + now_ts.tv_sec, now_ts.tv_nsec); + + break; + + case SJA1105_TAS_STATE_ENABLED_NOT_RUNNING: + /* Check if TAS has actually started, by comparing the + * scheduled start time with the SJA1105 PTP clock + */ + dev_dbg(ds->dev, "TAS state: enabled but not running\n"); + + /* Clock was stepped.. bad news for TAS */ + if (tas_data->last_op != SJA1105_PTP_ADJUSTFREQ) { + sja1105_tas_stop(priv); + break; + } + + now = __sja1105_ptp_gettimex(priv, NULL); + + if (now < tas_data->oper_base_time) { + /* TAS has not started yet */ + diff = ns_to_timespec64(tas_data->oper_base_time - now); + dev_dbg(ds->dev, "time to start: [%lld.%09ld]", + diff.tv_sec, diff.tv_nsec); + break; + } + + /* Time elapsed, what happened? */ + rc = sja1105_tas_check_running(priv); + if (rc < 0) + break; + + if (tas_data->state == SJA1105_TAS_STATE_RUNNING) + /* TAS has started */ + dev_dbg(ds->dev, "TAS state: transitioned to running\n"); + else + dev_err(ds->dev, "TAS state: not started despite time elapsed\n"); + + break; + + case SJA1105_TAS_STATE_RUNNING: + dev_dbg(ds->dev, "TAS state: running\n"); + + /* Clock was stepped.. bad news for TAS */ + if (tas_data->last_op != SJA1105_PTP_ADJUSTFREQ) { + sja1105_tas_stop(priv); + break; + } + + rc = sja1105_tas_check_running(priv); + if (rc < 0) + break; + + if (tas_data->state != SJA1105_TAS_STATE_RUNNING) { + dev_err(ds->dev, "TAS surprisingly stopped\n"); + break; + } + + now = __sja1105_ptp_gettimex(priv, NULL); + + diff = ns_to_timespec64(now - tas_data->oper_base_time); + + dev_dbg(ds->dev, "Time since TAS started: [%lld.%09ld]\n", + diff.tv_sec, diff.tv_nsec); + break; + + default: + if (net_ratelimit()) + dev_err(ds->dev, "TAS in an invalid state (incorrect use of API)!\n"); + } + + if (rc && net_ratelimit()) + dev_err(ds->dev, "An operation returned %d\n", rc); + + mutex_unlock(&ptp_data->lock); +} + +void sja1105_tas_clockstep(struct sja1105_private *priv) +{ + struct sja1105_tas_data *tas_data = &priv->tas_data; + + if (!tas_data->enabled) + return; + + tas_data->last_op = SJA1105_PTP_CLOCKSTEP; + schedule_work(&tas_data->tas_work); +} + +void sja1105_tas_adjfreq(struct sja1105_private *priv) +{ + struct sja1105_tas_data *tas_data = &priv->tas_data; + + if (!tas_data->enabled) + return; + + tas_data->last_op = SJA1105_PTP_ADJUSTFREQ; + schedule_work(&tas_data->tas_work); +} + void sja1105_tas_setup(struct sja1105_private *priv) { INIT_WORK(&priv->tas_data.config_work, sja1105_tas_config_work); + INIT_WORK(&priv->tas_data.tas_work, sja1105_tas_state_machine); + priv->tas_data.state = SJA1105_TAS_STATE_DISABLED; + priv->tas_data.last_op = SJA1105_PTP_NONE; } void sja1105_tas_teardown(struct sja1105_private *priv) @@ -440,6 +843,7 @@ void sja1105_tas_teardown(struct sja1105_private *priv) int port; cancel_work_sync(&tas_data->config_work); + cancel_work_sync(&tas_data->tas_work); for (port = 0; port < SJA1105_NUM_PORTS; port++) if (tas_data->config[port]) diff --git a/drivers/net/dsa/sja1105/sja1105_tas.h b/drivers/net/dsa/sja1105/sja1105_tas.h index 1629492e20ab..942be6945058 100644 --- a/drivers/net/dsa/sja1105/sja1105_tas.h +++ b/drivers/net/dsa/sja1105/sja1105_tas.h @@ -8,9 +8,28 @@ #if IS_ENABLED(CONFIG_NET_DSA_SJA1105_TAS) +enum sja1105_tas_state { + SJA1105_TAS_STATE_DISABLED, + SJA1105_TAS_STATE_ENABLED_NOT_RUNNING, + SJA1105_TAS_STATE_RUNNING, +}; + +enum sja1105_ptp_op { + SJA1105_PTP_NONE, + SJA1105_PTP_CLOCKSTEP, + SJA1105_PTP_ADJUSTFREQ, +}; + struct sja1105_tas_data { struct tc_taprio_qopt_offload *config[SJA1105_NUM_PORTS]; struct work_struct config_work; + enum sja1105_tas_state state; + enum sja1105_ptp_op last_op; + struct work_struct tas_work; + s64 earliest_base_time; + s64 oper_base_time; + u64 max_cycle_time; + bool enabled; }; void sja1105_tas_config_work(struct work_struct *work); @@ -22,6 +41,10 @@ void sja1105_tas_setup(struct sja1105_private *priv); void sja1105_tas_teardown(struct sja1105_private *priv); +void sja1105_tas_clockstep(struct sja1105_private *priv); + +void sja1105_tas_adjfreq(struct sja1105_private *priv); + #else /* C doesn't allow empty structures, bah! */ @@ -42,6 +65,10 @@ static inline void sja1105_tas_setup(struct sja1105_private *priv) { } static inline void sja1105_tas_teardown(struct sja1105_private *priv) { } +static inline void sja1105_tas_clockstep(struct sja1105_private *priv) { } + +static inline void sja1105_tas_adjfreq(struct sja1105_private *priv) { } + #endif /* IS_ENABLED(CONFIG_NET_DSA_SJA1105_TAS) */ #endif /* _SJA1105_TAS_H */