From patchwork Sat Nov 9 11:32: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: 1192397 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 (no SPF record) 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="k9oCLmWW"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 479FPc1qfPz9sPF for ; Sat, 9 Nov 2019 22:33:08 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726327AbfKILdC (ORCPT ); Sat, 9 Nov 2019 06:33:02 -0500 Received: from mail-wm1-f68.google.com ([209.85.128.68]:35697 "EHLO mail-wm1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726145AbfKILdC (ORCPT ); Sat, 9 Nov 2019 06:33:02 -0500 Received: by mail-wm1-f68.google.com with SMTP id 8so8780216wmo.0 for ; Sat, 09 Nov 2019 03:32:58 -0800 (PST) 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=cNpuFwkBot0QanqM+8oGh/xboHfp3cFPGjVYVlItv5A=; b=k9oCLmWWoGpMqZg0mp/vRtn7X2M7LPE3zrsA893GA3cyDpu9+cPw4WaPyy1GCwTudm aZBwvWMH1tGqeHf8ClyUG2/s7PFQMpSagTXkiSK9/ONxeMK0UKRxvwD4WzgQQ39yX76h PwtL8RhZYRQQ4t5ltZAQI3i9P/vTsqORB85b81Fwk3mjlgOiUCh4mQPvcbfgk3HFi4ir t7mB7M0tQkcLf7zOAnh0fdRygwiV2ruxVG/5AWHeAxSnJCogfr+qMFQOEiwF9imhnQg5 ZVIhi70eWSPj/zSdB0aoyp1oy61AFtZZSB+DO8lCboznmfbUw2aIFY+to/PoJ9xHyMP+ LgIg== 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=cNpuFwkBot0QanqM+8oGh/xboHfp3cFPGjVYVlItv5A=; b=CUuKq5sgBI7gIuNC5NJ7hc/E4dO/QHzFLWLo1JiTFq5V/EtMg/SgBrfsQ61ZwNDJIh ctUxqmexNR/qoGZ14FswnSQBbZotmkbOpMwRBmVPREfll0zjDR0lWcSvY5I0AaDtfnH5 EV9+g5fm68wcWBAskB9Fnp0JD5dR3DodueAfgZZRRavzCBwGN9L9cOe4fLwZDF/7WppN XeJC4GzUcbvOtalJyt6vd0E/jMU+kS/VjCNW63G77I+81XqgSDJ3yJoQcCzm+Pto+fIb nXnEZOr5+QU3Ms3wKLBL3hDlLAAHfGTmcHTIoE5uIioNHRCGQKVx2jLSa4NqnhN493b3 rB1Q== X-Gm-Message-State: APjAAAWnx9bqK8sGHwMR403Y+vsl3NhIXlhNILscEgVYUJd0rBEqBikR cu42RK9epTyFk1dHdyaqE3I= X-Google-Smtp-Source: APXvYqwfMN0+SudmzjzHZ3Z7Z9RM2KJ5dyZcgJdvL+Tb3+KYt72sbVCDtIPQxTqb6c7VCyZ1qMlJ+g== X-Received: by 2002:a1c:7f94:: with SMTP id a142mr11924117wmd.33.1573299178017; Sat, 09 Nov 2019 03:32:58 -0800 (PST) Received: from localhost.localdomain ([86.121.29.241]) by smtp.gmail.com with ESMTPSA id w13sm8353512wrm.8.2019.11.09.03.32.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 09 Nov 2019 03:32:57 -0800 (PST) From: Vladimir Oltean To: richardcochran@gmail.com, andrew@lunn.ch, f.fainelli@gmail.com, vivien.didelot@gmail.com, jakub.kicinski@netronome.com, davem@davemloft.net Cc: netdev@vger.kernel.org, Vladimir Oltean Subject: [PATCH net-next 1/3] net: dsa: sja1105: Implement the .gettimex64 system call for PTP Date: Sat, 9 Nov 2019 13:32:22 +0200 Message-Id: <20191109113224.6495-2-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191109113224.6495-1-olteanv@gmail.com> References: <20191109113224.6495-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. The task itself of taking the software timestamp is delegated to the SPI subsystem, through the newly introduced API in struct spi_transfer. The goal is to cross-timestamp I/O operations on the switch's PTP clock with values in the local system clock (CLOCK_REALTIME). For that we need to understand a bit of the hardware internals. The 'read PTP time' message is a 12 byte structure, first 4 bytes of which represent the SPI header, and the last 8 bytes represent the 64-bit PTP time. The switch itself starts processing the command immediately after receiving the last bit of the address, i.e. at the middle of byte 3 (last byte of header). The PTP time is shadowed to a buffer register in the switch, and retrieved atomically during the subsequent SPI frames. A similar thing goes on for the 'write PTP time' message, although in that case the switch waits until the 64-bit PTP time becomes fully available before taking any action. So the byte that needs to be software-timestamped is byte 11 (last) of the transfer. The patch creates a common (and local) sja1105_xfer implementation for the SPI I/O, and offers 3 front-ends: - sja1105_xfer_u32 and sja1105_xfer_u64: these are capable of optionally requesting a PTP timestamp - sja1105_xfer_buf: this is for large transfers (e.g. the static config buffer) and other misc data, and there is no point in giving timestamping capabilities to this. Signed-off-by: Vladimir Oltean --- drivers/net/dsa/sja1105/sja1105.h | 6 ++-- drivers/net/dsa/sja1105/sja1105_main.c | 3 +- drivers/net/dsa/sja1105/sja1105_ptp.c | 26 ++++++++------ drivers/net/dsa/sja1105/sja1105_spi.c | 48 +++++++++++++++++++++----- 4 files changed, 61 insertions(+), 22 deletions(-) diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index 91063ed3ef1b..64b3ee7b9771 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -122,9 +122,11 @@ int sja1105_xfer_buf(const struct sja1105_private *priv, sja1105_spi_rw_mode_t rw, u64 reg_addr, u8 *buf, size_t len); int sja1105_xfer_u32(const struct sja1105_private *priv, - sja1105_spi_rw_mode_t rw, u64 reg_addr, u32 *value); + sja1105_spi_rw_mode_t rw, u64 reg_addr, u32 *value, + struct ptp_system_timestamp *ptp_sts); int sja1105_xfer_u64(const struct sja1105_private *priv, - sja1105_spi_rw_mode_t rw, u64 reg_addr, u64 *value); + sja1105_spi_rw_mode_t rw, u64 reg_addr, u64 *value, + struct ptp_system_timestamp *ptp_sts); int sja1105_static_config_upload(struct sja1105_private *priv); int sja1105_inhibit_tx(const struct sja1105_private *priv, unsigned long port_bitmap, bool tx_inhibited); diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index d5dfda335aa1..d545edbbef9e 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -1973,7 +1973,8 @@ static int sja1105_check_device_id(struct sja1105_private *priv) u64 part_no; int rc; - rc = sja1105_xfer_u32(priv, SPI_READ, regs->device_id, &device_id); + rc = sja1105_xfer_u32(priv, SPI_READ, regs->device_id, &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 783100397f8a..fac72af24baf 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 @@ -335,11 +336,13 @@ static int sja1105_ptpegr_ts_poll(struct dsa_switch *ds, int port, u64 *ts) } /* Caller must hold ptp_data->lock */ -static int sja1105_ptpclkval_read(struct sja1105_private *priv, u64 *ticks) +static int sja1105_ptpclkval_read(struct sja1105_private *priv, u64 *ticks, + struct ptp_system_timestamp *ptp_sts) { const struct sja1105_regs *regs = priv->info->regs; - return sja1105_xfer_u64(priv, SPI_READ, regs->ptpclkval, ticks); + return sja1105_xfer_u64(priv, SPI_READ, regs->ptpclkval, ticks, + ptp_sts); } /* Caller must hold ptp_data->lock */ @@ -347,7 +350,8 @@ static int sja1105_ptpclkval_write(struct sja1105_private *priv, u64 ticks) { const struct sja1105_regs *regs = priv->info->regs; - return sja1105_xfer_u64(priv, SPI_WRITE, regs->ptpclkval, &ticks); + return sja1105_xfer_u64(priv, SPI_WRITE, regs->ptpclkval, &ticks, + NULL); } #define rxtstamp_to_tagger(d) \ @@ -370,7 +374,7 @@ static void sja1105_rxtstamp_work(struct work_struct *work) u64 ticks, ts; int rc; - rc = sja1105_ptpclkval_read(priv, &ticks); + rc = sja1105_ptpclkval_read(priv, &ticks, NULL); if (rc < 0) { dev_err(ds->dev, "Failed to read PTP clock: %d\n", rc); kfree_skb(skb); @@ -441,8 +445,9 @@ int sja1105_ptp_reset(struct dsa_switch *ds) 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 *ptp_sts) { struct sja1105_ptp_data *ptp_data = ptp_caps_to_data(ptp); struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data); @@ -451,7 +456,7 @@ static int sja1105_ptp_gettime(struct ptp_clock_info *ptp, mutex_lock(&ptp_data->lock); - rc = sja1105_ptpclkval_read(priv, &ticks); + rc = sja1105_ptpclkval_read(priv, &ticks, ptp_sts); *ts = ns_to_timespec64(sja1105_ticks_to_ns(ticks)); mutex_unlock(&ptp_data->lock); @@ -516,7 +521,8 @@ static int sja1105_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) mutex_lock(&ptp_data->lock); - rc = sja1105_xfer_u32(priv, SPI_WRITE, regs->ptpclkrate, &clkrate32); + rc = sja1105_xfer_u32(priv, SPI_WRITE, regs->ptpclkrate, &clkrate32, + NULL); mutex_unlock(&ptp_data->lock); @@ -558,7 +564,7 @@ int sja1105_ptp_clock_register(struct dsa_switch *ds) .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, }; @@ -604,7 +610,7 @@ void sja1105_ptp_txtstamp_skb(struct dsa_switch *ds, int slot, mutex_lock(&ptp_data->lock); - rc = sja1105_ptpclkval_read(priv, &ticks); + rc = sja1105_ptpclkval_read(priv, &ticks, NULL); if (rc < 0) { dev_err(ds->dev, "Failed to read PTP clock: %d\n", rc); kfree_skb(skb); diff --git a/drivers/net/dsa/sja1105/sja1105_spi.c b/drivers/net/dsa/sja1105/sja1105_spi.c index ed02410a9366..691cd250e50a 100644 --- a/drivers/net/dsa/sja1105/sja1105_spi.c +++ b/drivers/net/dsa/sja1105/sja1105_spi.c @@ -42,9 +42,9 @@ sja1105_spi_message_pack(void *buf, const struct sja1105_spi_message *msg) * - SPI_READ: creates and sends an SPI read message from absolute * address reg_addr, writing @len bytes into *buf */ -int sja1105_xfer_buf(const struct sja1105_private *priv, - sja1105_spi_rw_mode_t rw, u64 reg_addr, - u8 *buf, size_t len) +static int sja1105_xfer(const struct sja1105_private *priv, + sja1105_spi_rw_mode_t rw, u64 reg_addr, u8 *buf, + size_t len, struct ptp_system_timestamp *ptp_sts) { struct sja1105_chunk chunk = { .len = min_t(size_t, len, SJA1105_SIZE_SPI_MSG_MAXLEN), @@ -81,6 +81,7 @@ int sja1105_xfer_buf(const struct sja1105_private *priv, struct spi_transfer *chunk_xfer = sja1105_chunk_xfer(xfers, i); struct spi_transfer *hdr_xfer = sja1105_hdr_xfer(xfers, i); u8 *hdr_buf = sja1105_hdr_buf(hdr_bufs, i); + struct spi_transfer *ptp_sts_xfer; struct sja1105_spi_message msg; /* Populate the transfer's header buffer */ @@ -102,6 +103,26 @@ int sja1105_xfer_buf(const struct sja1105_private *priv, chunk_xfer->tx_buf = chunk.buf; chunk_xfer->len = chunk.len; + /* Request timestamping for the transfer. Instead of letting + * callers specify which byte they want to timestamp, we can + * make certain assumptions: + * - A read operation will request a software timestamp when + * what's being read is the PTP time. That is snapshotted by + * the switch hardware at the end of the command portion + * (hdr_xfer). + * - A write operation will request a software timestamp on + * actions that modify the PTP time. Taking clock stepping as + * an example, the switch writes the PTP time at the end of + * the data portion (chunk_xfer). + */ + if (rw == SPI_READ) + ptp_sts_xfer = hdr_xfer; + else + ptp_sts_xfer = chunk_xfer; + ptp_sts_xfer->ptp_sts_word_pre = ptp_sts_xfer->len - 1; + ptp_sts_xfer->ptp_sts_word_post = ptp_sts_xfer->len - 1; + ptp_sts_xfer->ptp_sts = ptp_sts; + /* Calculate next chunk */ chunk.buf += chunk.len; chunk.reg_addr += chunk.len / 4; @@ -123,6 +144,13 @@ int sja1105_xfer_buf(const struct sja1105_private *priv, return rc; } +int sja1105_xfer_buf(const struct sja1105_private *priv, + sja1105_spi_rw_mode_t rw, u64 reg_addr, + u8 *buf, size_t len) +{ + return sja1105_xfer(priv, rw, reg_addr, buf, len, NULL); +} + /* If @rw is: * - SPI_WRITE: creates and sends an SPI write message at absolute * address reg_addr @@ -133,7 +161,8 @@ int sja1105_xfer_buf(const struct sja1105_private *priv, * CPU endianness and directly usable by software running on the core. */ int sja1105_xfer_u64(const struct sja1105_private *priv, - sja1105_spi_rw_mode_t rw, u64 reg_addr, u64 *value) + sja1105_spi_rw_mode_t rw, u64 reg_addr, u64 *value, + struct ptp_system_timestamp *ptp_sts) { u8 packed_buf[8]; int rc; @@ -141,7 +170,7 @@ int sja1105_xfer_u64(const struct sja1105_private *priv, if (rw == SPI_WRITE) sja1105_pack(packed_buf, value, 63, 0, 8); - rc = sja1105_xfer_buf(priv, rw, reg_addr, packed_buf, 8); + rc = sja1105_xfer(priv, rw, reg_addr, packed_buf, 8, ptp_sts); if (rw == SPI_READ) sja1105_unpack(packed_buf, value, 63, 0, 8); @@ -151,7 +180,8 @@ int sja1105_xfer_u64(const struct sja1105_private *priv, /* Same as above, but transfers only a 4 byte word */ int sja1105_xfer_u32(const struct sja1105_private *priv, - sja1105_spi_rw_mode_t rw, u64 reg_addr, u32 *value) + sja1105_spi_rw_mode_t rw, u64 reg_addr, u32 *value, + struct ptp_system_timestamp *ptp_sts) { u8 packed_buf[4]; u64 tmp; @@ -165,7 +195,7 @@ int sja1105_xfer_u32(const struct sja1105_private *priv, sja1105_pack(packed_buf, &tmp, 31, 0, 4); } - rc = sja1105_xfer_buf(priv, rw, reg_addr, packed_buf, 4); + rc = sja1105_xfer(priv, rw, reg_addr, packed_buf, 4, ptp_sts); if (rw == SPI_READ) { sja1105_unpack(packed_buf, &tmp, 31, 0, 4); @@ -293,7 +323,7 @@ int sja1105_inhibit_tx(const struct sja1105_private *priv, int rc; rc = sja1105_xfer_u32(priv, SPI_READ, regs->port_control, - &inhibit_cmd); + &inhibit_cmd, NULL); if (rc < 0) return rc; @@ -303,7 +333,7 @@ int sja1105_inhibit_tx(const struct sja1105_private *priv, inhibit_cmd &= ~port_bitmap; return sja1105_xfer_u32(priv, SPI_WRITE, regs->port_control, - &inhibit_cmd); + &inhibit_cmd, NULL); } struct sja1105_status { From patchwork Sat Nov 9 11:32: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: 1192400 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 (no SPF record) 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="jTv0q0P2"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 479FPd3MGdz9sPV for ; Sat, 9 Nov 2019 22:33:09 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726405AbfKILdE (ORCPT ); Sat, 9 Nov 2019 06:33:04 -0500 Received: from mail-wm1-f65.google.com ([209.85.128.65]:34773 "EHLO mail-wm1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726289AbfKILdE (ORCPT ); Sat, 9 Nov 2019 06:33:04 -0500 Received: by mail-wm1-f65.google.com with SMTP id v3so9219548wmh.1 for ; Sat, 09 Nov 2019 03:33:00 -0800 (PST) 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=76I97ulel6GFS7SQHUmBknS1cMsxVD28fO1FUCW1LB4=; b=jTv0q0P23YDz5cQscs1+AULb2PGVmcDNp7MjeiMVM/C82Lz7wrnXZgVSN3pavYlcCR fHdhZTG+044m1WFmy4thw37wGCTo098bbM/pKnTjyeXhi+XNx+tlCmPLXomQog1NpWuF zCxmLn8MJ8BjUb7M7Ie3Le1Qk5kg/L8aHISxFGDc07XfMeORINJZPeBe3XJnZ+Qw8qyn en183sHYa8m7QNkCErYUgzoXAdxLHKjDkRxib4RUHFZn2T8+DlDP/NcGISrfae0xehXR AyhMfHwiLPctfa3Ek04oXsKD6CEvOTzTT9mYlFJFS825SRytMqoJJuA1deq7/ZlRfQ83 BOCw== 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=76I97ulel6GFS7SQHUmBknS1cMsxVD28fO1FUCW1LB4=; b=r2Wk/dBihhsjp93FUQo1rgheGRzP4BPgGEgDAsqOz6YrcV3r971+sNHkpoOsHTaX+2 YnsWoONK+NkrXo0f4YswvC3rrhQFs92A97ZfkPl74dnj1IXfd2HmLh7a5Pmm1lyDenjy AE2FxiuSwtzy75AAgVZf0jBFvMTnyj/AhNJYVlzDwafRyOnvdB8/ugkpCMwhDaRwpHV6 k6AxCFEjIaXTBiFRiKYAseYOrWCu0cxYvxxmu3yVuSyxewbBLQ14/tlFxBx1mioYueN7 kfsck8w8GWfT2YuDupULwLGcmiFbDdVdkm3C9WYOumCeJAKmaF3PIcZl5FQoLYPyixWq DCtg== X-Gm-Message-State: APjAAAVhXT6xnlSxQnlHtTrqewg2hx/EaTBSyVUpGMycRRpdsj5mXjiQ uY/ll/70ZZ+arpmCgilL/Tw= X-Google-Smtp-Source: APXvYqxJParjDBjB7ij+XItDUbBthfhu04hwpNBSrJCtooPooPsBWJf0otxHIgmwKG9YVknAh/aoKQ== X-Received: by 2002:a05:600c:20e:: with SMTP id 14mr11898696wmi.107.1573299179599; Sat, 09 Nov 2019 03:32:59 -0800 (PST) Received: from localhost.localdomain ([86.121.29.241]) by smtp.gmail.com with ESMTPSA id w13sm8353512wrm.8.2019.11.09.03.32.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 09 Nov 2019 03:32:59 -0800 (PST) From: Vladimir Oltean To: richardcochran@gmail.com, andrew@lunn.ch, f.fainelli@gmail.com, vivien.didelot@gmail.com, jakub.kicinski@netronome.com, davem@davemloft.net Cc: netdev@vger.kernel.org, Vladimir Oltean Subject: [PATCH net-next 2/3] net: dsa: sja1105: Restore PTP time after switch reset Date: Sat, 9 Nov 2019 13:32:23 +0200 Message-Id: <20191109113224.6495-3-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191109113224.6495-1-olteanv@gmail.com> References: <20191109113224.6495-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. Perhaps the larger implication of this patch is that the PTP .gettimex64 and .settime functions need to be exposed to sja1105_main.c, where the PTP lock needs to be held during this entire process. So their core implementation needs to move to some common functions which get exposed in sja1105_ptp.h. Signed-off-by: Vladimir Oltean --- drivers/net/dsa/sja1105/sja1105_main.c | 35 ++++++++++- drivers/net/dsa/sja1105/sja1105_ptp.c | 81 +++++++++++++++++++------- drivers/net/dsa/sja1105/sja1105_ptp.h | 24 +++++++- drivers/net/dsa/sja1105/sja1105_spi.c | 6 -- 4 files changed, 114 insertions(+), 32 deletions(-) diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index d545edbbef9e..2b8919a25392 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -1349,9 +1349,15 @@ static void sja1105_bridge_leave(struct dsa_switch *ds, int port, */ 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]; + struct dsa_switch *ds = priv->ds; + s64 t1, t2, t3, t4; + s64 t12, t34; int rc, i; + s64 now; mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries; @@ -1365,10 +1371,37 @@ 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_data.lock); + + rc = __sja1105_ptp_gettimex(ds, &now, &ptp_sts_before); + if (rc < 0) + goto out_unlock_ptp; + /* 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(ds, 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 */ + now += (t34 - t12); + + __sja1105_ptp_adjtime(ds, now); + +out_unlock_ptp: + mutex_unlock(&priv->ptp_data.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 fac72af24baf..0a35813f9328 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.c +++ b/drivers/net/dsa/sja1105/sja1105_ptp.c @@ -346,12 +346,13 @@ static int sja1105_ptpclkval_read(struct sja1105_private *priv, u64 *ticks, } /* Caller must hold ptp_data->lock */ -static int sja1105_ptpclkval_write(struct sja1105_private *priv, u64 ticks) +static int sja1105_ptpclkval_write(struct sja1105_private *priv, u64 ticks, + struct ptp_system_timestamp *ptp_sts) { const struct sja1105_regs *regs = priv->info->regs; return sja1105_xfer_u64(priv, SPI_WRITE, regs->ptpclkval, &ticks, - NULL); + ptp_sts); } #define rxtstamp_to_tagger(d) \ @@ -427,7 +428,7 @@ bool sja1105_port_txtstamp(struct dsa_switch *ds, int port, return true; } -int sja1105_ptp_reset(struct dsa_switch *ds) +static int sja1105_ptp_reset(struct dsa_switch *ds) { struct sja1105_private *priv = ds->priv; struct sja1105_ptp_data *ptp_data = &priv->ptp_data; @@ -445,19 +446,38 @@ int sja1105_ptp_reset(struct dsa_switch *ds) return rc; } +/* Caller must hold ptp_data->lock */ +int __sja1105_ptp_gettimex(struct dsa_switch *ds, u64 *ns, + struct ptp_system_timestamp *ptp_sts) +{ + struct sja1105_private *priv = ds->priv; + u64 ticks; + int rc; + + rc = sja1105_ptpclkval_read(priv, &ticks, ptp_sts); + if (rc < 0) { + dev_err(ds->dev, "Failed to read PTP clock: %d\n", rc); + return rc; + } + + *ns = sja1105_ticks_to_ns(ticks); + + return 0; +} + static int sja1105_ptp_gettimex(struct ptp_clock_info *ptp, struct timespec64 *ts, struct ptp_system_timestamp *ptp_sts) { struct sja1105_ptp_data *ptp_data = ptp_caps_to_data(ptp); struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data); - u64 ticks = 0; + u64 now = 0; int rc; mutex_lock(&ptp_data->lock); - rc = sja1105_ptpclkval_read(priv, &ticks, ptp_sts); - *ts = ns_to_timespec64(sja1105_ticks_to_ns(ticks)); + rc = __sja1105_ptp_gettimex(priv->ds, &now, ptp_sts); + *ts = ns_to_timespec64(now); mutex_unlock(&ptp_data->lock); @@ -479,24 +499,34 @@ static int sja1105_ptp_mode_set(struct sja1105_private *priv, } /* Write to PTPCLKVAL while PTPCLKADD is 0 */ +int __sja1105_ptp_settime(struct dsa_switch *ds, u64 ns, + struct ptp_system_timestamp *ptp_sts) +{ + struct sja1105_private *priv = ds->priv; + u64 ticks = ns_to_sja1105_ticks(ns); + int rc; + + 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"); + return rc; + } + + return sja1105_ptpclkval_write(priv, ticks, ptp_sts); +} + static int sja1105_ptp_settime(struct ptp_clock_info *ptp, const struct timespec64 *ts) { struct sja1105_ptp_data *ptp_data = ptp_caps_to_data(ptp); struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data); - u64 ticks = ns_to_sja1105_ticks(timespec64_to_ns(ts)); + u64 ns = timespec64_to_ns(ts); int rc; mutex_lock(&ptp_data->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; - } + rc = __sja1105_ptp_settime(priv->ds, ns, NULL); - rc = sja1105_ptpclkval_write(priv, ticks); -out: mutex_unlock(&ptp_data->lock); return rc; @@ -530,24 +560,31 @@ static int sja1105_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) } /* Write to PTPCLKVAL while PTPCLKADD is 1 */ -static int sja1105_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) +int __sja1105_ptp_adjtime(struct dsa_switch *ds, s64 delta) { - struct sja1105_ptp_data *ptp_data = ptp_caps_to_data(ptp); - struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data); + struct sja1105_private *priv = ds->priv; s64 ticks = ns_to_sja1105_ticks(delta); int rc; - mutex_lock(&ptp_data->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_ptp_data *ptp_data = ptp_caps_to_data(ptp); + struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data); + int rc; + + mutex_lock(&ptp_data->lock); + + rc = __sja1105_ptp_adjtime(priv->ds, delta); -out: mutex_unlock(&ptp_data->lock); return rc; diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.h b/drivers/net/dsa/sja1105/sja1105_ptp.h index 243f130374d2..19e707db7e8c 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.h +++ b/drivers/net/dsa/sja1105/sja1105_ptp.h @@ -51,8 +51,6 @@ int sja1105_get_ts_info(struct dsa_switch *ds, int port, void sja1105_ptp_txtstamp_skb(struct dsa_switch *ds, int slot, struct sk_buff *clone); -int sja1105_ptp_reset(struct dsa_switch *ds); - bool sja1105_port_rxtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb, unsigned int type); @@ -63,6 +61,14 @@ int sja1105_hwtstamp_get(struct dsa_switch *ds, int port, struct ifreq *ifr); int sja1105_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr); +int __sja1105_ptp_gettimex(struct dsa_switch *ds, u64 *ns, + struct ptp_system_timestamp *sts); + +int __sja1105_ptp_settime(struct dsa_switch *ds, u64 ns, + struct ptp_system_timestamp *ptp_sts); + +int __sja1105_ptp_adjtime(struct dsa_switch *ds, s64 delta); + #else struct sja1105_ptp_cmd; @@ -87,7 +93,19 @@ static inline void sja1105_ptp_txtstamp_skb(struct dsa_switch *ds, int slot, { } -static inline int sja1105_ptp_reset(struct dsa_switch *ds) +static inline int __sja1105_ptp_gettimex(struct dsa_switch *ds, u64 *ns, + struct ptp_system_timestamp *sts) +{ + return 0; +} + +static inline int __sja1105_ptp_settime(struct dsa_switch *ds, u64 ns, + struct ptp_system_timestamp *ptp_sts) +{ + return 0; +} + +static inline int __sja1105_ptp_adjtime(struct dsa_switch *ds, s64 delta) { return 0; } diff --git a/drivers/net/dsa/sja1105/sja1105_spi.c b/drivers/net/dsa/sja1105/sja1105_spi.c index 691cd250e50a..cb48e77f63fd 100644 --- a/drivers/net/dsa/sja1105/sja1105_spi.c +++ b/drivers/net/dsa/sja1105/sja1105_spi.c @@ -511,12 +511,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->ds); - 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: kfree(config_buf); return rc; From patchwork Sat Nov 9 11:32: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: 1192399 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 (no SPF record) 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="k8gpY5Cn"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 479FPd06bjz9sPT for ; Sat, 9 Nov 2019 22:33:09 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726383AbfKILdD (ORCPT ); Sat, 9 Nov 2019 06:33:03 -0500 Received: from mail-wm1-f66.google.com ([209.85.128.66]:50789 "EHLO mail-wm1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726282AbfKILdC (ORCPT ); Sat, 9 Nov 2019 06:33:02 -0500 Received: by mail-wm1-f66.google.com with SMTP id l17so7891369wmh.0 for ; Sat, 09 Nov 2019 03:33:01 -0800 (PST) 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=bjevR+W+7GyBNoKvB7ywYEXTZgBACvSScPkFXeTiERE=; b=k8gpY5CnqbHURAZqTX7nB3hPN9k95Obsv4DsaK8iK1Ooa7g9rxfpYH6lLKhjvgNS98 PvwBf+2T603zOQoQP4YE4dcmZIQ4DzHsE3+LCOidYCsUTZJCc+NRob5NQdxv2NbXu+I2 un4VHVnEhgSXQQYZow/qM22a1dF+q2rqZQSLEcim0lBKewaUkiaGIdOt2DgHueMfglYJ 5dJHKGXWq9iBOKdcGe8smHMqn5Jn5jvJ/AsZLHjJnWYKCMkIKeo0/sWDBtcBATFN0yr+ tD5HbIBF+aNbxwcOJLcJlcWTVIaDTyGnvVUgWgthOu5b1v847BlvRWTlDXhzZfFGvrRF cNkQ== 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=bjevR+W+7GyBNoKvB7ywYEXTZgBACvSScPkFXeTiERE=; b=jssOpS63LfRGRZwiNk8yQQ4UKCzYMTXnQ3ShYLjPG7rq1OMWAcZyaa0uKrKRxW4lWN wSLL56nbI/OlMj2UimdaQsiXiX8jOb2omhrBxise+OpVXNaeJGDo12RP+XHVtSoE6Zqo Bemg3lZDt2DO4TI5T/XNHnzkVBSkELuU+v//8xLA3xObeM8Up97REJBJ0F5STM1+CnLG 5GBn0XulOaaJOy0UGUCsi9JeDfE0JwJ6QvSJGbrMTO6CnI2bhNZzOmpFwIVcAywk9Z5K 33p3cvk+FU/Wqhyxm8ij7Di7UG2k9JVsmPvalQ29+z5/bAOX42WPkOWjy67xys8uoLPz fXOw== X-Gm-Message-State: APjAAAXDjACq0y5R52z+NwrwMCKcM2Ckqyj9v+/CxokZVH43fJEne/Ak yg8gq9E8HJifuc4Hmn4aBfg= X-Google-Smtp-Source: APXvYqz00WDeePWRWDxUkoS3NV5ToYub8VJsal/G/9VvYruz6o2Svl4QPOrehrADpk5VWcb8cBEOgw== X-Received: by 2002:a05:600c:218e:: with SMTP id e14mr11616443wme.22.1573299180775; Sat, 09 Nov 2019 03:33:00 -0800 (PST) Received: from localhost.localdomain ([86.121.29.241]) by smtp.gmail.com with ESMTPSA id w13sm8353512wrm.8.2019.11.09.03.32.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 09 Nov 2019 03:33:00 -0800 (PST) From: Vladimir Oltean To: richardcochran@gmail.com, andrew@lunn.ch, f.fainelli@gmail.com, vivien.didelot@gmail.com, jakub.kicinski@netronome.com, davem@davemloft.net Cc: netdev@vger.kernel.org, Vladimir Oltean Subject: [PATCH net-next 3/3] net: dsa: sja1105: Disallow management xmit during switch reset Date: Sat, 9 Nov 2019 13:32:24 +0200 Message-Id: <20191109113224.6495-4-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191109113224.6495-1-olteanv@gmail.com> References: <20191109113224.6495-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 2b8919a25392..475cc2d8b0e8 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -1359,6 +1359,8 @@ int sja1105_static_config_reload(struct sja1105_private *priv) int rc, i; s64 now; + 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 @@ -1417,6 +1419,8 @@ int sja1105_static_config_reload(struct sja1105_private *priv) goto out; } out: + mutex_unlock(&priv->mgmt_lock); + return rc; }