Message ID | 20230710154932.68377-5-andriy.shevchenko@linux.intel.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:9f45:0:b0:3ea:f831:8777 with SMTP id v5csp5125968vqx; Mon, 10 Jul 2023 09:03:23 -0700 (PDT) X-Google-Smtp-Source: APBJJlHNTYOmYZdJ2XAG2v7PODdCA50v5Xg6xcV729lGL+k66D+s8HqfEYwcUjRZwp/4btH5IYMy X-Received: by 2002:a17:902:c3c6:b0:1b8:1c9e:444e with SMTP id j6-20020a170902c3c600b001b81c9e444emr14129818plj.25.1689005003642; Mon, 10 Jul 2023 09:03:23 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1689005003; cv=none; d=google.com; s=arc-20160816; b=TZgAdUS2S+YVFYEt8IpHHhrA/mmSHH9NvMJR9bYBLNKnn1cAA77D7ZUouR5xLFg0qK 1OZNaLAZYebzev+wyBue81rm4yZiYtMFCT0MS0UCGRa29eozYXWJW1fXY9hY9sxa3V1W 5jNSje4DPnTykakuJeVlKbX2m4Tox0bvU+D8dZrLifvyULkW9mtztWfIDc0JMkhHSz/R UOptLa/k02vvwCmQZIzikx6MM69+X0v+VKmtonC6xiv3X2q16XX5wEo8OqvEoVHW72dL dwmE3DM+p9n0p+K1Y0hCX7vWWU7bPTgItfMis+UhaXL86WgtTS/8CKaAV0bBuojQsPJa QvdA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=PWA7GIOFewi2OU47McNhmbZ1Ir0zrg7xiPluBsL/qi8=; fh=CWfEt6/vd4IsHMc+T8W3bMkH4b5uOoX72TeJSijIGlU=; b=qGJgsuCPt2xeX7B0Z7golCIChVt5NR25AL4fqsnaFGxxBF16KdeoX6AqCF/ATmeefq K1NruBXIfGzBYWg28CJ5twQETdf1IEx4yuHIuSKfllI0nC6I7asxbgQuPJwz0V+gBKUD 2P+OCkEKFq3MVmB4jqrspTDZ1ZfOgV4sc2VCs/PfnNkyMKHtbRiRUFqvrdj7bmw/3Uq7 4EXVfiWkmO4WFgAEr0iluyUjs3k3XCvh0DD7DueH5fkxm/GJefX1qWaiQvo7sj/5ItMa t67qyrOQT1WWgw86O8ncgtiHSWRk/ia/rx8NhdzRJSG5qQTIrBkb7c+ldQ20fXzVLv24 wG0g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=LInZBwE6; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id b7-20020a170902650700b001b9d2982362si76513plk.36.2023.07.10.09.03.08; Mon, 10 Jul 2023 09:03:23 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=LInZBwE6; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233555AbjGJPtu (ORCPT <rfc822;ybw1215001957@gmail.com> + 99 others); Mon, 10 Jul 2023 11:49:50 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47596 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233572AbjGJPtp (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Mon, 10 Jul 2023 11:49:45 -0400 Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6492C10D; Mon, 10 Jul 2023 08:49:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1689004184; x=1720540184; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=wJa3Jmu6iVXPZMGevJvu2fkKY/Gm2mVbHm4RgDFco0c=; b=LInZBwE6tEjIur82JS/nzgbv26KmwM6gQWfbFQKHJOsA4wNR8QALYJZl Q6Avc5vn6FbysTPj0MEVXon6sFKiFlQ/qZ5tLclW+3LO0cdC367RBj2fy Cwg1EPn5oj6a6oqnBsg4FS2QgGLXvzYeA/qocHSId4B3bJtL5YilS33TQ ftYPvM58RfjdYXOxJkh2rnAi2zi28fq2kR8M/iQz5jZwDEpFnyqsDuysq oEx9d4VElghXmIN8A33hARLqTGhMWM6nvGXiBmjb1hrG1uzgWTBxSBvvA RxEtWevkBwG2SJBJAB6Uo+p8D3zPR0j+vla8cSI2r5C8e/0T3BFV1D2Zo Q==; X-IronPort-AV: E=McAfee;i="6600,9927,10767"; a="349185345" X-IronPort-AV: E=Sophos;i="6.01,194,1684825200"; d="scan'208";a="349185345" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Jul 2023 08:49:42 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10767"; a="844921834" X-IronPort-AV: E=Sophos;i="6.01,194,1684825200"; d="scan'208";a="844921834" Received: from black.fi.intel.com ([10.237.72.28]) by orsmga004.jf.intel.com with ESMTP; 10 Jul 2023 08:49:31 -0700 Received: by black.fi.intel.com (Postfix, from userid 1003) id 5A18C4BD; Mon, 10 Jul 2023 18:49:34 +0300 (EEST) From: Andy Shevchenko <andriy.shevchenko@linux.intel.com> To: Mark Brown <broonie@kernel.org>, Cristian Ciocaltea <cristian.ciocaltea@collabora.com>, Yang Yingliang <yangyingliang@huawei.com>, Andy Shevchenko <andriy.shevchenko@linux.intel.com>, Amit Kumar Mahapatra via Alsa-devel <alsa-devel@alsa-project.org>, Neil Armstrong <neil.armstrong@linaro.org>, Tharun Kumar P <tharunkumar.pasumarthi@microchip.com>, Vijaya Krishna Nivarthi <quic_vnivarth@quicinc.com>, =?utf-8?q?Uwe_Kleine-K?= =?utf-8?q?=C3=B6nig?= <u.kleine-koenig@pengutronix.de>, linux-spi@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-amlogic@lists.infradead.org, linux-mediatek@lists.infradead.org, linux-arm-msm@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-riscv@lists.infradead.org, linux-stm32@st-md-mailman.stormreply.com, linux-trace-kernel@vger.kernel.org, netdev@vger.kernel.org Cc: Sanjay R Mehta <sanju.mehta@amd.com>, Radu Pirea <radu_nicolae.pirea@upb.ro>, Nicolas Ferre <nicolas.ferre@microchip.com>, Alexandre Belloni <alexandre.belloni@bootlin.com>, Claudiu Beznea <claudiu.beznea@microchip.com>, Tudor Ambarus <tudor.ambarus@linaro.org>, Serge Semin <fancer.lancer@gmail.com>, Shawn Guo <shawnguo@kernel.org>, Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix Kernel Team <kernel@pengutronix.de>, Fabio Estevam <festevam@gmail.com>, NXP Linux Team <linux-imx@nxp.com>, Kevin Hilman <khilman@baylibre.com>, Jerome Brunet <jbrunet@baylibre.com>, Martin Blumenstingl <martin.blumenstingl@googlemail.com>, Matthias Brugger <matthias.bgg@gmail.com>, AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>, Andy Gross <agross@kernel.org>, Bjorn Andersson <andersson@kernel.org>, Konrad Dybcio <konrad.dybcio@linaro.org>, Heiko Stuebner <heiko@sntech.de>, Palmer Dabbelt <palmer@dabbelt.com>, Paul Walmsley <paul.walmsley@sifive.com>, Orson Zhai <orsonzhai@gmail.com>, Baolin Wang <baolin.wang@linux.alibaba.com>, Chunyan Zhang <zhang.lyra@gmail.com>, Alain Volmat <alain.volmat@foss.st.com>, Maxime Coquelin <mcoquelin.stm32@gmail.com>, Alexandre Torgue <alexandre.torgue@foss.st.com>, Max Filippov <jcmvbkbc@gmail.com>, Steven Rostedt <rostedt@goodmis.org>, Masami Hiramatsu <mhiramat@kernel.org>, Richard Cochran <richardcochran@gmail.com> Subject: [PATCH v2 04/15] spi: Replace open coded spi_controller_xfer_timeout() Date: Mon, 10 Jul 2023 18:49:21 +0300 Message-Id: <20230710154932.68377-5-andriy.shevchenko@linux.intel.com> X-Mailer: git-send-email 2.40.0.1.gaa8946217a0b In-Reply-To: <20230710154932.68377-1-andriy.shevchenko@linux.intel.com> References: <20230710154932.68377-1-andriy.shevchenko@linux.intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_EF,SPF_HELO_NONE,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1771050110811315954 X-GMAIL-MSGID: 1771050110811315954 |
Series |
spi: Header and core clean up and refactoring
|
|
Commit Message
Andy Shevchenko
July 10, 2023, 3:49 p.m. UTC
Since the new spi_controller_xfer_timeout() helper appeared,
we may replace open coded variant in spi_transfer_wait().
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
drivers/spi/spi.c | 25 ++-----------------------
include/linux/spi/spi.h | 6 +++++-
2 files changed, 7 insertions(+), 24 deletions(-)
Comments
On Mon, Jul 10, 2023 at 06:49:21PM +0300, Andy Shevchenko wrote: > Since the new spi_controller_xfer_timeout() helper appeared, > we may replace open coded variant in spi_transfer_wait(). > + * Assume speed to be 100 kHz if it's not defined at the time of invocation. > + * You didn't mention this bit in the changelog, and I'm not 100% convinced it was the best idea in the first place. It's going to result in some very big timeouts if it goes off, and we really should be doing validation much earlier in the process. > + u32 speed_hz = xfer->speed_hz ?: 100000; Not only the ternery operator, but the version without the second argument for extra clarity!
Il 10/07/23 17:49, Andy Shevchenko ha scritto: > Since the new spi_controller_xfer_timeout() helper appeared, > we may replace open coded variant in spi_transfer_wait(). > > Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> > --- > drivers/spi/spi.c | 25 ++----------------------- > include/linux/spi/spi.h | 6 +++++- > 2 files changed, 7 insertions(+), 24 deletions(-) > > diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c > index 125dea8fae00..c99ee4164f11 100644 > --- a/drivers/spi/spi.c > +++ b/drivers/spi/spi.c > @@ -1342,8 +1342,7 @@ static int spi_transfer_wait(struct spi_controller *ctlr, > { > struct spi_statistics __percpu *statm = ctlr->pcpu_statistics; > struct spi_statistics __percpu *stats = msg->spi->pcpu_statistics; > - u32 speed_hz = xfer->speed_hz; > - unsigned long long ms; > + unsigned long ms; > > if (spi_controller_is_slave(ctlr)) { > if (wait_for_completion_interruptible(&ctlr->xfer_completion)) { > @@ -1351,29 +1350,9 @@ static int spi_transfer_wait(struct spi_controller *ctlr, > return -EINTR; > } > } else { > - if (!speed_hz) > - speed_hz = 100000; > - > - /* > - * For each byte we wait for 8 cycles of the SPI clock. > - * Since speed is defined in Hz and we want milliseconds, > - * use respective multiplier, but before the division, > - * otherwise we may get 0 for short transfers. > - */ > - ms = 8LL * MSEC_PER_SEC * xfer->len; > - do_div(ms, speed_hz); > - > - /* > - * Increase it twice and add 200 ms tolerance, use > - * predefined maximum in case of overflow. > - */ > - ms += ms + 200; > - if (ms > UINT_MAX) > - ms = UINT_MAX; > - > + ms = spi_controller_xfer_timeout(ctlr, xfer); I agree on using helpers, but the logic is slightly changing here: yes it is unlikely (and also probably useless) to get ms == UINT_MAX, but the helper is limiting the maximum timeout value to 500mS, which may not work for some slow controllers/devices. This should get validated on more than a few platforms, and I'm not sure that this kind of validation would be "fast" to get... so, probably the best thing to do here is to add a warning in case the timeout exceeds 500mS, print the actual value, keep it like this for a kernel version or two and check reports: that would allow to understand what a safe maximum timeout value could be. Aside from that, I wouldn't drop those nice comments explaining how/why the timeout is calculated: I know how, but not everyone knows in advance. Regards, Angelo > ms = wait_for_completion_timeout(&ctlr->xfer_completion, > msecs_to_jiffies(ms)); > - > if (ms == 0) { > SPI_STATISTICS_INCREMENT_FIELD(statm, timedout); > SPI_STATISTICS_INCREMENT_FIELD(stats, timedout); > diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h > index 32c94eae8926..0ce1cb18a076 100644 > --- a/include/linux/spi/spi.h > +++ b/include/linux/spi/spi.h > @@ -1270,12 +1270,16 @@ static inline bool spi_is_bpw_supported(struct spi_device *spi, u32 bpw) > * that it would take on a single data line and take twice this amount of time > * with a minimum of 500ms to avoid false positives on loaded systems. > * > + * Assume speed to be 100 kHz if it's not defined at the time of invocation. > + * > * Returns: Transfer timeout value in milliseconds. > */ > static inline unsigned int spi_controller_xfer_timeout(struct spi_controller *ctlr, > struct spi_transfer *xfer) > { > - return max(xfer->len * 8 * 2 / (xfer->speed_hz / 1000), 500U); > + u32 speed_hz = xfer->speed_hz ?: 100000; > + > + return max(xfer->len * 8 * 2 / (speed_hz / 1000), 500U); > } > > /*---------------------------------------------------------------------------*/
On Mon, Jul 10, 2023 at 06:30:32PM +0100, Mark Brown wrote: > On Mon, Jul 10, 2023 at 06:49:21PM +0300, Andy Shevchenko wrote: > > > Since the new spi_controller_xfer_timeout() helper appeared, > > we may replace open coded variant in spi_transfer_wait(). > > > + * Assume speed to be 100 kHz if it's not defined at the time of invocation. > > + * > > You didn't mention this bit in the changelog, and I'm not 100% convinced > it was the best idea in the first place. It's going to result in some > very big timeouts if it goes off, and we really should be doing > validation much earlier in the process. Okay, let's drop this change. > > + u32 speed_hz = xfer->speed_hz ?: 100000; > > Not only the ternery operator, but the version without the second > argument for extra clarity! Elvis can be interpreted as "A _or_ B (if A is false/0)". Some pieces related to SPI use Elvis already IIRC.
On Tue, Jul 11, 2023 at 10:28:13AM +0200, AngeloGioacchino Del Regno wrote: > Il 10/07/23 17:49, Andy Shevchenko ha scritto: > > + ms = spi_controller_xfer_timeout(ctlr, xfer); > I agree on using helpers, but the logic is slightly changing here: yes it is > unlikely (and also probably useless) to get ms == UINT_MAX, but the helper is > limiting the maximum timeout value to 500mS, which may not work for some slow > controllers/devices. The helper is limiting the *minimum* timeout value to 500ms - it's using max() not min(). The idea is the other way around, that for a very fast transfer we don't want to end up with such a short timeout that it false triggers due to scheduling issues.
Il 11/07/23 15:05, Mark Brown ha scritto: > On Tue, Jul 11, 2023 at 10:28:13AM +0200, AngeloGioacchino Del Regno wrote: >> Il 10/07/23 17:49, Andy Shevchenko ha scritto: > >>> + ms = spi_controller_xfer_timeout(ctlr, xfer); > >> I agree on using helpers, but the logic is slightly changing here: yes it is >> unlikely (and also probably useless) to get ms == UINT_MAX, but the helper is >> limiting the maximum timeout value to 500mS, which may not work for some slow >> controllers/devices. > > The helper is limiting the *minimum* timeout value to 500ms - it's using > max() not min(). The idea is the other way around, that for a very fast > transfer we don't want to end up with such a short timeout that it false > triggers due to scheduling issues. After reading the code again, yeah, I've totally misread it the first time. Argh! Thanks! :-)
On Tue, Jul 11, 2023 at 02:01:13PM +0300, Andy Shevchenko wrote: > On Mon, Jul 10, 2023 at 06:30:32PM +0100, Mark Brown wrote: > > On Mon, Jul 10, 2023 at 06:49:21PM +0300, Andy Shevchenko wrote: > > > + * Assume speed to be 100 kHz if it's not defined at the time of invocation. > > You didn't mention this bit in the changelog, and I'm not 100% convinced > > it was the best idea in the first place. It's going to result in some > > very big timeouts if it goes off, and we really should be doing > > validation much earlier in the process. > Okay, let's drop this change. Like I say we *should* be fine with the refactoring without this, or at least if it's an issue we should improve the validation. > > > + u32 speed_hz = xfer->speed_hz ?: 100000; > > Not only the ternery operator, but the version without the second > > argument for extra clarity! > Elvis can be interpreted as "A _or_ B (if A is false/0)". > Some pieces related to SPI use Elvis already IIRC. I understand what it means, I just don't find it's adding clarity most of the times it's used (there's a few places where it is useful like pasting in strings in formats). There are some examples that I'd complain about in the code, most of them predating me working on SPI too much, but I'm not a fan.
On Tue, Jul 11, 2023 at 03:14:54PM +0100, Mark Brown wrote: > On Tue, Jul 11, 2023 at 02:01:13PM +0300, Andy Shevchenko wrote: > > On Mon, Jul 10, 2023 at 06:30:32PM +0100, Mark Brown wrote: > > > On Mon, Jul 10, 2023 at 06:49:21PM +0300, Andy Shevchenko wrote: > > > > > + * Assume speed to be 100 kHz if it's not defined at the time of invocation. > > > > You didn't mention this bit in the changelog, and I'm not 100% convinced > > > it was the best idea in the first place. It's going to result in some > > > very big timeouts if it goes off, and we really should be doing > > > validation much earlier in the process. > > > Okay, let's drop this change. > > Like I say we *should* be fine with the refactoring without this, or at > least if it's an issue we should improve the validation. For the speeds < 1000 Hz, this change will lead to the div by 0 crash. It seems that the current code which this one removes is better than the spi_controller_xfer_timeout() provides. If anything, the spi_controller_xfer_timeout() should be improved first. So, for now I drop this for sure. Maybe in the future we can come back to it.
On Tue, Jul 11, 2023 at 06:30:06PM +0300, Andy Shevchenko wrote: > On Tue, Jul 11, 2023 at 03:14:54PM +0100, Mark Brown wrote: > > Like I say we *should* be fine with the refactoring without this, or at > > least if it's an issue we should improve the validation. > For the speeds < 1000 Hz, this change will lead to the div by 0 crash. > It seems that the current code which this one removes is better than > the spi_controller_xfer_timeout() provides. > If anything, the spi_controller_xfer_timeout() should be improved first. > So, for now I drop this for sure. Maybe in the future we can come back > to it. I don't think this is the only thing that might fall over without a speed, what we've generally been doing (and do try to do with speeds, we already need to default in the controller's speed and so on) is to sanitise input on the way into the subsystem rather than trying to ensure that all the users are handling everything.
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 125dea8fae00..c99ee4164f11 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1342,8 +1342,7 @@ static int spi_transfer_wait(struct spi_controller *ctlr, { struct spi_statistics __percpu *statm = ctlr->pcpu_statistics; struct spi_statistics __percpu *stats = msg->spi->pcpu_statistics; - u32 speed_hz = xfer->speed_hz; - unsigned long long ms; + unsigned long ms; if (spi_controller_is_slave(ctlr)) { if (wait_for_completion_interruptible(&ctlr->xfer_completion)) { @@ -1351,29 +1350,9 @@ static int spi_transfer_wait(struct spi_controller *ctlr, return -EINTR; } } else { - if (!speed_hz) - speed_hz = 100000; - - /* - * For each byte we wait for 8 cycles of the SPI clock. - * Since speed is defined in Hz and we want milliseconds, - * use respective multiplier, but before the division, - * otherwise we may get 0 for short transfers. - */ - ms = 8LL * MSEC_PER_SEC * xfer->len; - do_div(ms, speed_hz); - - /* - * Increase it twice and add 200 ms tolerance, use - * predefined maximum in case of overflow. - */ - ms += ms + 200; - if (ms > UINT_MAX) - ms = UINT_MAX; - + ms = spi_controller_xfer_timeout(ctlr, xfer); ms = wait_for_completion_timeout(&ctlr->xfer_completion, msecs_to_jiffies(ms)); - if (ms == 0) { SPI_STATISTICS_INCREMENT_FIELD(statm, timedout); SPI_STATISTICS_INCREMENT_FIELD(stats, timedout); diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 32c94eae8926..0ce1cb18a076 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -1270,12 +1270,16 @@ static inline bool spi_is_bpw_supported(struct spi_device *spi, u32 bpw) * that it would take on a single data line and take twice this amount of time * with a minimum of 500ms to avoid false positives on loaded systems. * + * Assume speed to be 100 kHz if it's not defined at the time of invocation. + * * Returns: Transfer timeout value in milliseconds. */ static inline unsigned int spi_controller_xfer_timeout(struct spi_controller *ctlr, struct spi_transfer *xfer) { - return max(xfer->len * 8 * 2 / (xfer->speed_hz / 1000), 500U); + u32 speed_hz = xfer->speed_hz ?: 100000; + + return max(xfer->len * 8 * 2 / (speed_hz / 1000), 500U); } /*---------------------------------------------------------------------------*/