From patchwork Thu Sep 5 01:01:11 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 11131971 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2B0EB1398 for ; Thu, 5 Sep 2019 01:08:00 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id F14CA21881 for ; Thu, 5 Sep 2019 01:07:59 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="B1PhAvGi" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728008AbfIEBH7 (ORCPT ); Wed, 4 Sep 2019 21:07:59 -0400 Received: from mail-wm1-f67.google.com ([209.85.128.67]:35910 "EHLO mail-wm1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727789AbfIEBH7 (ORCPT ); Wed, 4 Sep 2019 21:07:59 -0400 Received: by mail-wm1-f67.google.com with SMTP id p13so761829wmh.1; Wed, 04 Sep 2019 18:07:57 -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=LHXsVk3IyN3um5OPhmjw4ruCbmDcuCM+w6HNkI9Ksdo=; b=B1PhAvGixPRVjsiW1mGbMpcULZkAy+2e9WSwPKWY7vgYXk2j5kWCGJySwSybr396/E HQkT6H8gxu2KBAaNsaXs8X+jUkaX3n3Cpa0Ff7zynceGc51MiEiNLJY4UHH+RDXQeiAD GCGPyBeS/22oecHZ+IZE3QqGYtMMEt0rjTyFpuyU4d8Rf9fq7alfzCv4+in6g3t5vx// V+3osQJOgwBGFoYshk6CzlTV6iMXepgUAJRONDQZpudxDaKE9eLQ8wF6o0OyfrZCE7TJ x4T5GDyU6KlJGX6hZmfDSgkwlDKUh6qKhaC9A7SkOgrGbS/xsybdubXCWXtMBTmefPuO QGHQ== 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=LHXsVk3IyN3um5OPhmjw4ruCbmDcuCM+w6HNkI9Ksdo=; b=Gy3xLzXnGHmzcSJ032Q0zRjfVNcDIcTS2wnGAmLR/pBnrSbL9bbQfHewnIhXR3SJUF SuQcOEURmVVdWfoqJxhh+E7OKVXqszUbW85I65qMmk5zGze46XEcwFuCt7MXRszL+zyh JxhI/TOW+KLgvnV3VRgMqq1tJJ60tLbZnNtSRJPuADyOerBX8B9KzJlOO/G8E2IIozKk 9QQsJlHArxKQRqs4sns4qwKTYYPESCn7Z0XIQL6y3aDPTR+MtJgS5o0lHckapfq9a2fM Aa/fd11Q+JHSe+WX1GVxs09zGaww9JtC5xMP/YuQ6g0fXPbdQQH1FC9HULsWEnUn6oWe ml9A== X-Gm-Message-State: APjAAAXeG3BKP4/YTwPYvSgXusgS7imbBk+AdXsxYh8/nicoSd6GrwnX VN8lK3ZE+Es243QV4pPufNGX7sDU X-Google-Smtp-Source: APXvYqyS2M3xosAjzb47lbscbO5zq6besjeiN1oZqkGZbRhQOEPJxOzscZfZYb7sxBS+hpkONl3gpA== X-Received: by 2002:a7b:c4d6:: with SMTP id g22mr681007wmk.21.1567645676931; Wed, 04 Sep 2019 18:07:56 -0700 (PDT) Received: from localhost.localdomain ([86.126.25.232]) by smtp.gmail.com with ESMTPSA id b15sm670125wmb.28.2019.09.04.18.07.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 04 Sep 2019 18:07:56 -0700 (PDT) From: Vladimir Oltean To: broonie@kernel.org, h.feurstein@gmail.com, mlichvar@redhat.com, richardcochran@gmail.com, andrew@lunn.ch, f.fainelli@gmail.com Cc: linux-spi@vger.kernel.org, netdev@vger.kernel.org, Vladimir Oltean Subject: [PATCH v2 1/4] spi: Use an abbreviated pointer to ctlr->cur_msg in __spi_pump_messages Date: Thu, 5 Sep 2019 04:01:11 +0300 Message-Id: <20190905010114.26718-2-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190905010114.26718-1-olteanv@gmail.com> References: <20190905010114.26718-1-olteanv@gmail.com> Sender: linux-spi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-spi@vger.kernel.org This helps a bit with line fitting now (the list_first_entry call) as well as during the next patch which needs to iterate through all transfers of ctlr->cur_msg so it timestamps them. Signed-off-by: Vladimir Oltean --- Changes in v2: - Renamed mesg to msg. drivers/spi/spi.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 75ac046cae52..9ce86f761763 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1265,8 +1265,9 @@ EXPORT_SYMBOL_GPL(spi_finalize_current_transfer); */ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread) { - unsigned long flags; + struct spi_message *msg; bool was_busy = false; + unsigned long flags; int ret; /* Lock queue */ @@ -1325,10 +1326,10 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread) } /* Extract head of queue */ - ctlr->cur_msg = - list_first_entry(&ctlr->queue, struct spi_message, queue); + msg = list_first_entry(&ctlr->queue, struct spi_message, queue); + ctlr->cur_msg = msg; - list_del_init(&ctlr->cur_msg->queue); + list_del_init(&msg->queue); if (ctlr->busy) was_busy = true; else @@ -1361,7 +1362,7 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread) if (ctlr->auto_runtime_pm) pm_runtime_put(ctlr->dev.parent); - ctlr->cur_msg->status = ret; + msg->status = ret; spi_finalize_current_message(ctlr); mutex_unlock(&ctlr->io_mutex); @@ -1369,28 +1370,28 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread) } } - trace_spi_message_start(ctlr->cur_msg); + trace_spi_message_start(msg); if (ctlr->prepare_message) { - ret = ctlr->prepare_message(ctlr, ctlr->cur_msg); + ret = ctlr->prepare_message(ctlr, msg); if (ret) { dev_err(&ctlr->dev, "failed to prepare message: %d\n", ret); - ctlr->cur_msg->status = ret; + msg->status = ret; spi_finalize_current_message(ctlr); goto out; } ctlr->cur_msg_prepared = true; } - ret = spi_map_msg(ctlr, ctlr->cur_msg); + ret = spi_map_msg(ctlr, msg); if (ret) { - ctlr->cur_msg->status = ret; + msg->status = ret; spi_finalize_current_message(ctlr); goto out; } - ret = ctlr->transfer_one_message(ctlr, ctlr->cur_msg); + ret = ctlr->transfer_one_message(ctlr, msg); if (ret) { dev_err(&ctlr->dev, "failed to transfer one message from queue\n"); From patchwork Thu Sep 5 01:01:12 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 11131977 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2C5221805 for ; Thu, 5 Sep 2019 01:08:09 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 0472120820 for ; Thu, 5 Sep 2019 01:08:09 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="nWsPfS8U" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730106AbfIEBIC (ORCPT ); Wed, 4 Sep 2019 21:08:02 -0400 Received: from mail-wr1-f67.google.com ([209.85.221.67]:45485 "EHLO mail-wr1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727900AbfIEBIA (ORCPT ); Wed, 4 Sep 2019 21:08:00 -0400 Received: by mail-wr1-f67.google.com with SMTP id l16so645246wrv.12; Wed, 04 Sep 2019 18:07: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=IFoCl/MgsswnRC2M32JRDOgiorNoXCIOHWB0wFwXcBw=; b=nWsPfS8UX32nRnYXA5xu0T2O5T1e247CYj8glANsnsQmqHLVx88L9Cw04jormiF33q K6nwDbDRYtLCcugJ8q6tB1OXeK8mE7x3h8PisgGGN+qJvjjNMDt4CSzxPbLMAcB9ZJKy gXuBmvOLTv2X/zM+xRJCCsAdFO1eAiCF3Ds10JkIQI02cf5nLQd629DPWStT5+X8WZtF TtkRJ3aO83pxuCyZx10TLuc9/BKNGDWHi8wvBIQBo4fjzvrlWfckpiIlOYy+lN85FoeC sZPtzQxkTgZzRd6KQu6gsPjvIH2M+8eut4jWgNbV9rsX6IwfR9Pj0YXIrwpFb6e9AV1c IFWQ== 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=IFoCl/MgsswnRC2M32JRDOgiorNoXCIOHWB0wFwXcBw=; b=slBXLbKsEve8MIf8i9Zz6daFQNZlGVxK+hldSjUyn/hJe08l7a12N3hI6TtFHMknGd FPsdVPng+8cOrTuUqTBZPAnYlfuf0BehkuKosNuIfLO1flrXTsX+zwp7b0AaZpy5obi2 nUYAORnUzI2xx4azyiSvw4arJtWeKJodrPBHHkXANwovRjIlbZrE8beIytWVaIE4GElI 5hqNEFXKprFxUbSeHrCmrZ3wSPWxknjOErkZtUjk717GUft30HLXaHhe4d6J8y+nPaMg R/Xya9qalnF1srVwXs/IeQuA8mwWZHlQIi71fuP1KWlwNaf5m17Z+D6YVuJPQRoavu0F TdvA== X-Gm-Message-State: APjAAAVKsM7qhi+bjz/QEoY7DjcAmP5j3aGostU6UqzEz6OtMlI2fE4+ xJiYk3zzLwD18g+4Vb4Jo4Q= X-Google-Smtp-Source: APXvYqziU/rF+Q/zqYcUeQnDCKd214hsky/oFcFRoibMbEwVjL6VJ/erYhQ5kSACCKWaaEnG1kV1tg== X-Received: by 2002:adf:e750:: with SMTP id c16mr332254wrn.199.1567645678030; Wed, 04 Sep 2019 18:07:58 -0700 (PDT) Received: from localhost.localdomain ([86.126.25.232]) by smtp.gmail.com with ESMTPSA id b15sm670125wmb.28.2019.09.04.18.07.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 04 Sep 2019 18:07:57 -0700 (PDT) From: Vladimir Oltean To: broonie@kernel.org, h.feurstein@gmail.com, mlichvar@redhat.com, richardcochran@gmail.com, andrew@lunn.ch, f.fainelli@gmail.com Cc: linux-spi@vger.kernel.org, netdev@vger.kernel.org, Vladimir Oltean Subject: [PATCH v2 2/4] spi: Add a PTP system timestamp to the transfer structure Date: Thu, 5 Sep 2019 04:01:12 +0300 Message-Id: <20190905010114.26718-3-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190905010114.26718-1-olteanv@gmail.com> References: <20190905010114.26718-1-olteanv@gmail.com> Sender: linux-spi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-spi@vger.kernel.org SPI is one of the interfaces used to access devices which have a POSIX clock driver (real time clocks, 1588 timers etc). The fact that the SPI bus is slow is not what the main problem is, but rather the fact that drivers don't take a constant amount of time in transferring data over SPI. When there is a high delay in the readout of time, there will be uncertainty in the value that has been read out of the peripheral. When that delay is constant, the uncertainty can at least be approximated with a certain accuracy which is fine more often than not. Timing jitter occurs all over in the kernel code, and is mainly caused by having to let go of the CPU for various reasons such as preemption, servicing interrupts, going to sleep, etc. Another major reason is CPU dynamic frequency scaling. It turns out that the problem of retrieving time from a SPI peripheral with high accuracy can be solved by the use of "PTP system timestamping" - a mechanism to correlate the time when the device has snapshotted its internal time counter with the Linux system time at that same moment. This is sufficient for having a precise time measurement - it is not necessary for the whole SPI transfer to be transmitted "as fast as possible", or "as low-jitter as possible". The system has to be low-jitter for a very short amount of time to be effective. This patch introduces a PTP system timestamping mechanism in struct spi_transfer. This is to be used by SPI device drivers when they need to know the exact time at which the underlying device's time was snapshotted. More often than not, SPI peripherals have a very exact timing for when their SPI-to-interconnect bridge issues a transaction for snapshotting and reading the time register, and that will be dependent on when the SPI-to-interconnect bridge figures out that this is what it should do, aka as soon as it sees byte N of the SPI transfer. Since spi_device drivers are the ones who'd know best how the peripheral behaves in this regard, expose a mechanism in spi_transfer which allows them to specify which word (or word range) from the transfer should be timestamped. Add a default implementation of the PTP system timestamping in the SPI core. This is not going to be satisfactory performance-wise, but should at least increase the likelihood that SPI device drivers will use PTP system timestamping in the future. There are 3 entry points from the core towards the SPI controller drivers: - transfer_one: The driver is passed individual spi_transfers to execute. This is the easiest to timestamp. - transfer_one_message: The core passes the driver an entire spi_message (a potential batch of spi_transfers). The core puts the same pre and post timestamp to all transfers within a message. This is not ideal, but nothing better can be done by default anyway, since the core has no insight into how the driver batches the transfers. - transfer: Like transfer_one_message, but for unqueued drivers (i.e. the driver implements its own queue scheduling). Signed-off-by: Vladimir Oltean --- Changes in v2: - Added even more helpful helper functions: spi_take_timestamp_pre and spi_take_timestamp_pre, that drivers can simply call without keeping any state themselves. - Updated comments and commit message. drivers/spi/spi.c | 127 ++++++++++++++++++++++++++++++++++++++++ include/linux/spi/spi.h | 61 +++++++++++++++++++ 2 files changed, 188 insertions(+) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 9ce86f761763..bfc1f1e7ae12 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1171,6 +1171,11 @@ static int spi_transfer_one_message(struct spi_controller *ctlr, spi_statistics_add_transfer_stats(statm, xfer, ctlr); spi_statistics_add_transfer_stats(stats, xfer, ctlr); + if (!ctlr->ptp_sts_supported) { + xfer->ptp_sts_word_pre = 0; + ptp_read_system_prets(xfer->ptp_sts); + } + if (xfer->tx_buf || xfer->rx_buf) { reinit_completion(&ctlr->xfer_completion); @@ -1197,6 +1202,11 @@ static int spi_transfer_one_message(struct spi_controller *ctlr, xfer->len); } + if (!ctlr->ptp_sts_supported) { + ptp_read_system_postts(xfer->ptp_sts); + xfer->ptp_sts_word_post = xfer->len; + } + trace_spi_transfer_stop(msg, xfer); if (msg->status != -EINPROGRESS) @@ -1265,6 +1275,7 @@ EXPORT_SYMBOL_GPL(spi_finalize_current_transfer); */ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread) { + struct spi_transfer *xfer; struct spi_message *msg; bool was_busy = false; unsigned long flags; @@ -1391,6 +1402,13 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread) goto out; } + if (!ctlr->ptp_sts_supported && !ctlr->transfer_one) { + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + xfer->ptp_sts_word_pre = 0; + ptp_read_system_prets(xfer->ptp_sts); + } + } + ret = ctlr->transfer_one_message(ctlr, msg); if (ret) { dev_err(&ctlr->dev, @@ -1418,6 +1436,99 @@ static void spi_pump_messages(struct kthread_work *work) __spi_pump_messages(ctlr, true); } +/** + * spi_take_timestamp_pre - helper for drivers to collect the beginning of the + * TX timestamp for the requested byte from the SPI + * transfer. The frequency with which this function + * must be called (once per word, once for the whole + * transfer, once per batch of words etc) is arbitrary + * as long as the @tx buffer offset is greater than or + * equal to the requested byte at the time of the + * call. The timestamp is only taken once, at the + * first such call. It is assumed that the driver + * advances its @tx buffer pointer monotonically. + * @ctlr: Pointer to the spi_controller structure of the driver + * @xfer: Pointer to the transfer being timestamped + * @tx: Pointer to the current word within the xfer->tx_buf that the driver is + * preparing to transmit right now. + * @irqs_off: If true, will disable IRQs and preemption for the duration of the + * transfer, for less jitter in time measurement. Only compatible + * with PIO drivers. If true, must follow up with + * spi_take_timestamp_post or otherwise system will crash. + * WARNING: for fully predictable results, the CPU frequency must + * also be under control (governor). + */ +void spi_take_timestamp_pre(struct spi_controller *ctlr, + struct spi_transfer *xfer, + const void *tx, bool irqs_off) +{ + u8 bytes_per_word = DIV_ROUND_UP(xfer->bits_per_word, 8); + + if (!xfer->ptp_sts) + return; + + if (xfer->timestamped_pre) + return; + + if (tx < (xfer->tx_buf + xfer->ptp_sts_word_pre * bytes_per_word)) + return; + + /* Capture the resolution of the timestamp */ + xfer->ptp_sts_word_pre = (tx - xfer->tx_buf) / bytes_per_word; + + xfer->timestamped_pre = true; + + if (irqs_off) { + local_irq_save(ctlr->irq_flags); + preempt_disable(); + } + + ptp_read_system_prets(xfer->ptp_sts); +} +EXPORT_SYMBOL_GPL(spi_take_timestamp_pre); + +/** + * spi_take_timestamp_post - helper for drivers to collect the end of the + * TX timestamp for the requested byte from the SPI + * transfer. Can be called with an arbitrary + * frequency: only the first call where @tx exceeds + * or is equal to the requested word will be + * timestamped. + * @ctlr: Pointer to the spi_controller structure of the driver + * @xfer: Pointer to the transfer being timestamped + * @tx: Pointer to the current word within the xfer->tx_buf that the driver has + * just transmitted. + * @irqs_off: If true, will re-enable IRQs and preemption for the local CPU. + */ +void spi_take_timestamp_post(struct spi_controller *ctlr, + struct spi_transfer *xfer, + const void *tx, bool irqs_off) +{ + u8 bytes_per_word = DIV_ROUND_UP(xfer->bits_per_word, 8); + + if (!xfer->ptp_sts) + return; + + if (xfer->timestamped_post) + return; + + if (tx < (xfer->tx_buf + xfer->ptp_sts_word_post * bytes_per_word)) + return; + + ptp_read_system_postts(xfer->ptp_sts); + + if (irqs_off) { + local_irq_restore(ctlr->irq_flags); + preempt_enable(); + } + + /* Capture the resolution of the timestamp */ + xfer->ptp_sts_word_post = (tx - xfer->tx_buf) / bytes_per_word; + + xfer->timestamped_post = true; +} +EXPORT_SYMBOL_GPL(spi_take_timestamp_post); + /** * spi_set_thread_rt - set the controller to pump at realtime priority * @ctlr: controller to boost priority of @@ -1503,6 +1614,7 @@ EXPORT_SYMBOL_GPL(spi_get_next_queued_message); */ void spi_finalize_current_message(struct spi_controller *ctlr) { + struct spi_transfer *xfer; struct spi_message *mesg; unsigned long flags; int ret; @@ -1511,6 +1623,13 @@ void spi_finalize_current_message(struct spi_controller *ctlr) mesg = ctlr->cur_msg; spin_unlock_irqrestore(&ctlr->queue_lock, flags); + if (!ctlr->ptp_sts_supported && !ctlr->transfer_one) { + list_for_each_entry(xfer, &mesg->transfers, transfer_list) { + ptp_read_system_postts(xfer->ptp_sts); + xfer->ptp_sts_word_post = xfer->len; + } + } + spi_unmap_msg(ctlr, mesg); if (ctlr->cur_msg_prepared && ctlr->unprepare_message) { @@ -3271,6 +3390,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) static int __spi_async(struct spi_device *spi, struct spi_message *message) { struct spi_controller *ctlr = spi->controller; + struct spi_transfer *xfer; /* * Some controllers do not support doing regular SPI transfers. Return @@ -3286,6 +3406,13 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message) trace_spi_message_submit(message); + if (!ctlr->ptp_sts_supported) { + list_for_each_entry(xfer, &message->transfers, transfer_list) { + xfer->ptp_sts_word_pre = 0; + ptp_read_system_prets(xfer->ptp_sts); + } + } + return ctlr->transfer(spi, message); } diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index af4f265d0f67..27f6b046cf92 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -13,6 +13,7 @@ #include #include #include +#include struct dma_chan; struct property_entry; @@ -409,6 +410,12 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * @fw_translate_cs: If the boot firmware uses different numbering scheme * what Linux expects, this optional hook can be used to translate * between the two. + * @ptp_sts_supported: If the driver sets this to true, it must provide a + * time snapshot in @spi_transfer->ptp_sts as close as possible to the + * moment in time when @spi_transfer->ptp_sts_word_pre and + * @spi_transfer->ptp_sts_word_post were transmitted. + * If the driver does not set this, the SPI core takes the snapshot as + * close to the driver hand-over as possible. * * Each SPI controller can communicate with one or more @spi_device * children. These make a small bus, sharing MOSI, MISO and SCK signals @@ -604,6 +611,15 @@ struct spi_controller { void *dummy_tx; int (*fw_translate_cs)(struct spi_controller *ctlr, unsigned cs); + + /* + * Driver sets this field to indicate it is able to snapshot SPI + * transfers (needed e.g. for reading the time of POSIX clocks) + */ + bool ptp_sts_supported; + + /* Interrupt enable state during PTP system timestamping */ + unsigned long irq_flags; }; static inline void *spi_controller_get_devdata(struct spi_controller *ctlr) @@ -644,6 +660,14 @@ extern struct spi_message *spi_get_next_queued_message(struct spi_controller *ct extern void spi_finalize_current_message(struct spi_controller *ctlr); extern void spi_finalize_current_transfer(struct spi_controller *ctlr); +/* Helper calls for driver to timestamp transfer */ +void spi_take_timestamp_pre(struct spi_controller *ctlr, + struct spi_transfer *xfer, + const void *tx, bool irqs_off); +void spi_take_timestamp_post(struct spi_controller *ctlr, + struct spi_transfer *xfer, + const void *tx, bool irqs_off); + /* the spi driver core manages memory for the spi_controller classdev */ extern struct spi_controller *__spi_alloc_controller(struct device *host, unsigned int size, bool slave); @@ -753,6 +777,35 @@ extern void spi_res_release(struct spi_controller *ctlr, * @transfer_list: transfers are sequenced through @spi_message.transfers * @tx_sg: Scatterlist for transmit, currently not for client use * @rx_sg: Scatterlist for receive, currently not for client use + * @ptp_sts_word_pre: The word (subject to bits_per_word semantics) offset + * within @tx_buf for which the SPI device is requesting that the time + * snapshot for this transfer begins. Upon completing the SPI transfer, + * this value may have changed compared to what was requested, depending + * on the available snapshotting resolution (DMA transfer, + * @ptp_sts_supported is false, etc). + * @ptp_sts_word_post: See @ptp_sts_word_post. The two can be equal (meaning + * that a single byte should be snapshotted). + * If the core takes care of the timestamp (if @ptp_sts_supported is false + * for this controller), it will set @ptp_sts_word_pre to 0, and + * @ptp_sts_word_post to the length of the transfer. This is done + * purposefully (instead of setting to spi_transfer->len - 1) to denote + * that a transfer-level snapshot taken from within the driver may still + * be of higher quality. + * @ptp_sts: Pointer to a memory location held by the SPI slave device where a + * PTP system timestamp structure may lie. If drivers use PIO or their + * hardware has some sort of assist for retrieving exact transfer timing, + * they can (and should) assert @ptp_sts_supported and populate this + * structure using the ptp_read_system_*ts helper functions. + * The timestamp must represent the time at which the SPI slave device has + * processed the word, i.e. the "pre" timestamp should be taken before + * transmitting the "pre" word, and the "post" timestamp after receiving + * transmit confirmation from the controller for the "post" word. + * @timestamped_pre: Set by the SPI controller driver to denote it has acted + * upon the @ptp_sts request. Not set when the SPI core has taken care of + * the task. SPI device drivers are free to print a warning if this comes + * back unset and they need the better resolution. + * @timestamped_post: See above. The reason why both exist is that these + * booleans are also used to keep state in the core SPI logic. * * SPI transfers always write the same number of bytes as they read. * Protocol drivers should always provide @rx_buf and/or @tx_buf. @@ -842,6 +895,14 @@ struct spi_transfer { u32 effective_speed_hz; + unsigned int ptp_sts_word_pre; + unsigned int ptp_sts_word_post; + + struct ptp_system_timestamp *ptp_sts; + + bool timestamped_pre; + bool timestamped_post; + struct list_head transfer_list; }; From patchwork Thu Sep 5 01:01:13 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 11131975 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id F00761398 for ; Thu, 5 Sep 2019 01:08:08 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id D0DC120820 for ; Thu, 5 Sep 2019 01:08:08 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="AHeiOPq5" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730122AbfIEBID (ORCPT ); Wed, 4 Sep 2019 21:08:03 -0400 Received: from mail-wm1-f66.google.com ([209.85.128.66]:56129 "EHLO mail-wm1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727789AbfIEBIA (ORCPT ); Wed, 4 Sep 2019 21:08:00 -0400 Received: by mail-wm1-f66.google.com with SMTP id g207so695579wmg.5; Wed, 04 Sep 2019 18:07: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=t5zxehNW63K06AJ8QGwgCB5nrotoKx8hpJWWf5E4I/U=; b=AHeiOPq57vVJXZjcIdfZn+F8c0ezLEImgBZUJJ3/WUqXD//+3rWx+p6Hn0Jz7fwZ0/ xALLmu6uULBAEEBDDm7q+nVop4/fcczgHt6xHqdHTzCUrKfoXgzUcgt4192kFD5Mas7H XPUCeCgQOgFpdXIUl+06H7pqGEQHeMAMxVrLP1kF5DBkJEU2qas0O7MbfgKfLatJBiH+ 2vkUTqTumcFiqGLZeQKuKpNBfU4hBlUSDZ+epyErsdIFsRh7gNQpcbTwZHvQRZWZpZ1n NbaPiLPjRd9z/iXoswGcCEVKHkm2fcFED4ntARRBnpofls5Xh5tqnlbfJDOkSVKnEHO9 sbBQ== 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=t5zxehNW63K06AJ8QGwgCB5nrotoKx8hpJWWf5E4I/U=; b=b3JjWE7ZHhr0Qsf/WP5dKdwoe9PoHAobf3M06vtfEPK7w/xmz5Zkv6r31Nc8YvSGy1 pMHxYXx/yUd0evLEJiO1G9IDGckI6cOgTswns8J31tvUzJ/7FCTx5dvcsCSAiJh3YotC YavT/oVnTJhMZ9PsAvazH870dwJO4g+q+Dx7ZentxiXo5iHdgfLnS/au3b0c9h4WNLUp svmrw6HJPm6utR+EiH3qZ9yD1uPRZjOHG6ZTlJoV2fGrY4WvNtZ3c9FmJkFtDUi9r5PS Z4UKSUImMrp2GjoZQfi1rTP1DArNL3kJnOxM5ZaHUO2o7Y9vls6dlmxuzlORFQv5kGHS ejeg== X-Gm-Message-State: APjAAAUyt2RKL2iW3S5Smg/0vbgCCP4eM148IpcIPLgP5OjJgO92Dfe8 wTv3DuxLA9ztvVirc1L+av+Jvt+4 X-Google-Smtp-Source: APXvYqyw3l8SVHEM38wn36n0JYJyN4C1Krc5UrOWZn4PC8Q0x1Q0yXdyt5hGf4cjHT8i6Ys2OFxgwQ== X-Received: by 2002:a7b:ce8f:: with SMTP id q15mr688578wmj.106.1567645679091; Wed, 04 Sep 2019 18:07:59 -0700 (PDT) Received: from localhost.localdomain ([86.126.25.232]) by smtp.gmail.com with ESMTPSA id b15sm670125wmb.28.2019.09.04.18.07.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 04 Sep 2019 18:07:58 -0700 (PDT) From: Vladimir Oltean To: broonie@kernel.org, h.feurstein@gmail.com, mlichvar@redhat.com, richardcochran@gmail.com, andrew@lunn.ch, f.fainelli@gmail.com Cc: linux-spi@vger.kernel.org, netdev@vger.kernel.org, Vladimir Oltean Subject: [PATCH v2 3/4] spi: spi-fsl-dspi: Implement the PTP system timestamping for TCFQ mode Date: Thu, 5 Sep 2019 04:01:13 +0300 Message-Id: <20190905010114.26718-4-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190905010114.26718-1-olteanv@gmail.com> References: <20190905010114.26718-1-olteanv@gmail.com> Sender: linux-spi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-spi@vger.kernel.org In this mode, the DSPI controller uses PIO to transfer word by word. In comparison, in EOQ mode the 4-word deep FIFO is being used, hence the current logic will need some adaptation for which I do not have the hardware (Coldfire) to test. It is not clear what is the timing of DMA transfers and whether timestamping in the driver brings any overall performance increase compared to regular timestamping done in the core. Short phc2sys summary after 58 minutes of running on LS1021A-TSN with interrupts disabled during the critical section: offset: min -26251 max 16416 mean -21.8672 std dev 863.416 delay: min 4720 max 57280 mean 5182.49 std dev 1607.19 lost servo lock 3 times Summary of the same phc2sys service running for 120 minutes with interrupts disabled: offset: min -378 max 381 mean -0.0083089 std dev 101.495 delay: min 4720 max 5920 mean 5129.38 std dev 154.899 lost servo lock 0 times The minimum delay (pre to post time) in nanoseconds is the same, but the maximum delay is quite a bit higher, due to interrupts getting sometimes executed and interfering with the measurement. Hence set disable_irqs whenever possible (aka when the driver runs in poll mode - otherwise it would be a contradiction in terms). Signed-off-by: Vladimir Oltean --- Changes in v2: - Adapted to the newly introduced SPI core API from 02/04. drivers/spi/spi-fsl-dspi.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index bec758e978fb..7caea2da4397 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -129,6 +129,7 @@ enum dspi_trans_mode { struct fsl_dspi_devtype_data { enum dspi_trans_mode trans_mode; u8 max_clock_factor; + bool ptp_sts_supported; bool xspi_mode; }; @@ -140,12 +141,14 @@ static const struct fsl_dspi_devtype_data vf610_data = { static const struct fsl_dspi_devtype_data ls1021a_v1_data = { .trans_mode = DSPI_TCFQ_MODE, .max_clock_factor = 8, + .ptp_sts_supported = true, .xspi_mode = true, }; static const struct fsl_dspi_devtype_data ls2085a_data = { .trans_mode = DSPI_TCFQ_MODE, .max_clock_factor = 8, + .ptp_sts_supported = true, }; static const struct fsl_dspi_devtype_data coldfire_data = { @@ -654,6 +657,9 @@ static int dspi_rxtx(struct fsl_dspi *dspi) u16 spi_tcnt; u32 spi_tcr; + spi_take_timestamp_post(dspi->ctlr, dspi->cur_transfer, + dspi->tx - dspi->bytes_per_word, !dspi->irq); + /* Get transfer counter (in number of SPI transfers). It was * reset to 0 when transfer(s) were started. */ @@ -672,6 +678,9 @@ static int dspi_rxtx(struct fsl_dspi *dspi) /* Success! */ return 0; + spi_take_timestamp_pre(dspi->ctlr, dspi->cur_transfer, + dspi->tx, !dspi->irq); + if (trans_mode == DSPI_EOQ_MODE) dspi_eoq_write(dspi); else if (trans_mode == DSPI_TCFQ_MODE) @@ -779,6 +788,9 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr, SPI_FRAME_EBITS(transfer->bits_per_word) | SPI_CTARE_DTCP(1)); + spi_take_timestamp_pre(dspi->ctlr, dspi->cur_transfer, + dspi->tx, !dspi->irq); + trans_mode = dspi->devtype_data->trans_mode; switch (trans_mode) { case DSPI_EOQ_MODE: @@ -1132,6 +1144,7 @@ static int dspi_probe(struct platform_device *pdev) init_waitqueue_head(&dspi->waitq); poll_mode: + if (dspi->devtype_data->trans_mode == DSPI_DMA_MODE) { ret = dspi_request_dma(dspi, res->start); if (ret < 0) { @@ -1143,6 +1156,8 @@ static int dspi_probe(struct platform_device *pdev) ctlr->max_speed_hz = clk_get_rate(dspi->clk) / dspi->devtype_data->max_clock_factor; + ctlr->ptp_sts_supported = dspi->devtype_data->ptp_sts_supported; + platform_set_drvdata(pdev, ctlr); ret = spi_register_controller(ctlr); From patchwork Thu Sep 5 01:01:14 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 11131973 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 611921398 for ; Thu, 5 Sep 2019 01:08:03 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 41BB620820 for ; Thu, 5 Sep 2019 01:08:03 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ZU+Sw84H" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727162AbfIEBIC (ORCPT ); Wed, 4 Sep 2019 21:08:02 -0400 Received: from mail-wm1-f68.google.com ([209.85.128.68]:56132 "EHLO mail-wm1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729919AbfIEBIB (ORCPT ); Wed, 4 Sep 2019 21:08:01 -0400 Received: by mail-wm1-f68.google.com with SMTP id g207so695604wmg.5; Wed, 04 Sep 2019 18:08: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=BtXETVKXFJe6FPHxTO9TLLqiQam7bkQepJpAF4AjFU4=; b=ZU+Sw84HT/8IphJQh6loSkm9KNVNDZ9QZvq4/msqw3ML3gPpjOCXlCtR9bz6vioEx1 LVBaeiUIngr3gxwGuyNv3DwewNExRQyDnhon7oUp4yGAIJVTU9rvtnFQ/wHC7wcE/bJd 2HGUPbJEyRAO4koqdKXyETffUMx6xiAhUwn4Pm7E7tDuF3M6ja4VWgAbQNgIJ8vdVbt4 rLqiCicnxa2KaXprJTDTUZMA0I0BrzdKTckjiEsxoklXmMbC0VgA/6OFUER6SzGnTYfp dWuG/qhyinG+ITu52jyvgHmm2x+hxA/91tKLijww7DjeAspjMhy8CBsnze46qoMZcPIf BJEw== 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=BtXETVKXFJe6FPHxTO9TLLqiQam7bkQepJpAF4AjFU4=; b=DvPyIu3mvjDF5kqd/UiVrIzG+YHrbKZwEFfa6Qa+6FxqNkpeqZB5T9D7W89TUI2gYH /Na3NvhJon/8qfNyQInFjkVZD2JJjaZMPOjrTN4NEMmkYGUl4ANqul1fVp6V33iX2+Ye yxbUNu3uLPR0aZWYNv6TnmdThilDKXiwGddi13zUc57QJ66MYtV6vE4ios7SNpu58pPd dzjUymM288tslB+E6lK58bT+ircjqvsW9BrRKafKlhabtbt3eX9WE8/igppfg14S9SjA LdQsBqkF7fPsg62tRPbId2BzUk4N6XEJsoq3mD0ICC2beObnOaGIfS67KsFA002m6SDW dOSw== X-Gm-Message-State: APjAAAVAMWngx8usg26NSRhF4CPGi+o1U6uxXQd9Twbehc6A4lrHSKA2 CPETLEt6T+tcOcKM9KW8NNI= X-Google-Smtp-Source: APXvYqwkNdnA21T9Gkqk+LdFzxj2v/Zcw/nfaiilL0gGv9t9KTapp8SYOFjemZrLHrW/97tN8K8xyg== X-Received: by 2002:a1c:1d85:: with SMTP id d127mr773378wmd.14.1567645680086; Wed, 04 Sep 2019 18:08:00 -0700 (PDT) Received: from localhost.localdomain ([86.126.25.232]) by smtp.gmail.com with ESMTPSA id b15sm670125wmb.28.2019.09.04.18.07.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 04 Sep 2019 18:07:59 -0700 (PDT) From: Vladimir Oltean To: broonie@kernel.org, h.feurstein@gmail.com, mlichvar@redhat.com, richardcochran@gmail.com, andrew@lunn.ch, f.fainelli@gmail.com Cc: linux-spi@vger.kernel.org, netdev@vger.kernel.org, Vladimir Oltean Subject: [PATCH v2 4/4] spi: spi-fsl-dspi: Always use the TCFQ devices in poll mode Date: Thu, 5 Sep 2019 04:01:14 +0300 Message-Id: <20190905010114.26718-5-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190905010114.26718-1-olteanv@gmail.com> References: <20190905010114.26718-1-olteanv@gmail.com> Sender: linux-spi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-spi@vger.kernel.org With this patch, the "interrupts" property from the device tree bindings is ignored, even if present, if the driver runs in TCFQ mode. Switching to using the DSPI in poll mode has several distinct benefits: - With interrupts, the DSPI driver in TCFQ mode raises an IRQ after each transmitted word. There is more time wasted for the "waitq" event than for actual I/O. And the DSPI IRQ count can easily get the largest in /proc/interrupts on Freescale boards with attached SPI devices. - The SPI I/O time is both lower, and more consistently so. Attached to some Freescale devices are either PTP switches, or SPI RTCs. For reading time off of a SPI slave device, it is important that all SPI transfers take a deterministic time to complete. - In poll mode there is much less time spent by the CPU in hardirq context, which helps with the response latency of the system, and at the same time there is more control over when interrupts must be disabled (to get a precise timestamp measurement): win-win. On the LS1021A-TSN board, where the SPI device is a SJA1105 PTP switch (with a bits_per_word=8 driver), I created a "benchmark" where I read its PTP time once per second, for 120 seconds. Each "read PTP time" is a 12-byte SPI transfer. I then recorded the time before putting the first byte in the TX FIFO, and the time after reading the last byte from the RX FIFO. That is the transfer delay in nanoseconds. Interrupt mode: delay: min 125120 max 168320 mean 150286 std dev 17675.3 Poll mode: delay: min 69440 max 119040 mean 70312.9 std dev 8065.34 Both the mean latency and the standard deviation are more than 50% lower in poll mode than in interrupt mode. This is with an 'ondemand' governor on an otherwise idle system - therefore running mostly at 600 MHz out of a max of 1200 MHz. Signed-off-by: Vladimir Oltean --- Changes in v2: - None. drivers/spi/spi-fsl-dspi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index 7caea2da4397..c30325faa050 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -716,7 +716,7 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id) regmap_read(dspi->regmap, SPI_SR, &spi_sr); regmap_write(dspi->regmap, SPI_SR, spi_sr); - if (!(spi_sr & (SPI_SR_EOQF | SPI_SR_TCFQF))) + if (!(spi_sr & SPI_SR_EOQF)) return IRQ_NONE; if (dspi_rxtx(dspi) == 0) { @@ -1126,6 +1126,9 @@ static int dspi_probe(struct platform_device *pdev) dspi_init(dspi); + if (dspi->devtype_data->trans_mode == DSPI_TCFQ_MODE) + goto poll_mode; + dspi->irq = platform_get_irq(pdev, 0); if (dspi->irq <= 0) { dev_info(&pdev->dev,