diff mbox series

spi: imx: mx51-ecspi: Fix low-speed CONFIGREG delay calculation

Message ID 20210718211143.143557-1-marex@denx.de (mailing list archive)
State Superseded
Headers show
Series spi: imx: mx51-ecspi: Fix low-speed CONFIGREG delay calculation | expand

Commit Message

Marek Vasut July 18, 2021, 9:11 p.m. UTC
The spi_imx->spi_bus_clk may be uninitialized and thus also zero in
mx51_ecspi_prepare_message(), which would lead to division by zero
in kernel. Since bitbang .setup_transfer callback which initializes
the spi_imx->spi_bus_clk is called after bitbang prepare_message
callback, iterate over all the transfers in spi_message, find the
one with lowest bus frequency, and use that bus frequency for the
delay calculation.

Note that it is not possible to move this CONFIGREG delay back into
the .setup_transfer callback, because that is invoked too late, after
the GPIO chipselects were already configured.

Fixes: 135cbd378eab ("spi: imx: mx51-ecspi: Reinstate low-speed CONFIGREG delay")
Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Cc: Mark Brown <broonie@kernel.org>
---
Sigh ...
---
 drivers/spi/spi-imx.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

Comments

Uwe Kleine-König July 19, 2021, 8:20 a.m. UTC | #1
On Sun, Jul 18, 2021 at 11:11:43PM +0200, Marek Vasut wrote:
> The spi_imx->spi_bus_clk may be uninitialized and thus also zero in
> mx51_ecspi_prepare_message(), which would lead to division by zero
> in kernel. Since bitbang .setup_transfer callback which initializes
> the spi_imx->spi_bus_clk is called after bitbang prepare_message
> callback, iterate over all the transfers in spi_message, find the
> one with lowest bus frequency, and use that bus frequency for the
> delay calculation.
> 
> Note that it is not possible to move this CONFIGREG delay back into
> the .setup_transfer callback, because that is invoked too late, after
> the GPIO chipselects were already configured.
> 
> Fixes: 135cbd378eab ("spi: imx: mx51-ecspi: Reinstate low-speed CONFIGREG delay")
> Signed-off-by: Marek Vasut <marex@denx.de>
> Cc: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> Cc: Mark Brown <broonie@kernel.org>
> ---
> Sigh ...
> ---
>  drivers/spi/spi-imx.c | 10 +++++++++-
>  1 file changed, 9 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
> index 4aee3db6d6df..e18338fc3108 100644
> --- a/drivers/spi/spi-imx.c
> +++ b/drivers/spi/spi-imx.c
> @@ -505,7 +505,9 @@ static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx,
>  				      struct spi_message *msg)
>  {
>  	struct spi_device *spi = msg->spi;
> +	struct spi_transfer *xfer;
>  	u32 ctrl = MX51_ECSPI_CTRL_ENABLE;
> +	u32 min_speed_hz = ~0U;
>  	u32 testreg, delay;
>  	u32 cfg = readl(spi_imx->base + MX51_ECSPI_CONFIG);
>  
> @@ -578,7 +580,13 @@ static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx,
>  	 * the SPI communication as the device on the other end would consider
>  	 * the change of SCLK polarity as a clock tick already.
>  	 */
> -	delay = (2 * 1000000) / spi_imx->spi_bus_clk;
> +	list_for_each_entry(xfer, &msg->transfers, transfer_list) {
> +		if (!xfer->speed_hz)
> +			continue;
> +		min_speed_hz = min(xfer->speed_hz, min_speed_hz);
> +	}

Can it happen that all transfer's spped_hz are zero?

> +
> +	delay = (2 * 1000000) / min_speed_hz;

Orthogonal to your change: I wonder if we need to round up the division
here.

>  	if (likely(delay < 10))	/* SCLK is faster than 100 kHz */
>  		udelay(delay);
>  	else			/* SCLK is _very_ slow */

Also the comments are wrong here. Is SCLK is 150 kHz we have
min_speed_hz = 150000, right? Then delay becomes 13 and the slow freq
path is entered. The right comment (when keeping delay = (2 * 1000000) /
min_speed_hz) would be

	if (likely(delay < 10)) /* SCLK is faster than 181.818 kHz */

Best regards
Uwe
Marek Vasut July 19, 2021, 1:38 p.m. UTC | #2
On 7/19/21 10:20 AM, Uwe Kleine-König wrote:

[...]

>> @@ -505,7 +505,9 @@ static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx,
>>   				      struct spi_message *msg)
>>   {
>>   	struct spi_device *spi = msg->spi;
>> +	struct spi_transfer *xfer;
>>   	u32 ctrl = MX51_ECSPI_CTRL_ENABLE;
>> +	u32 min_speed_hz = ~0U;
>>   	u32 testreg, delay;
>>   	u32 cfg = readl(spi_imx->base + MX51_ECSPI_CONFIG);
>>   
>> @@ -578,7 +580,13 @@ static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx,
>>   	 * the SPI communication as the device on the other end would consider
>>   	 * the change of SCLK polarity as a clock tick already.
>>   	 */
>> -	delay = (2 * 1000000) / spi_imx->spi_bus_clk;
>> +	list_for_each_entry(xfer, &msg->transfers, transfer_list) {
>> +		if (!xfer->speed_hz)
>> +			continue;
>> +		min_speed_hz = min(xfer->speed_hz, min_speed_hz);
>> +	}
> 
> Can it happen that all transfer's spped_hz are zero?

I don't think so, what kind of spi_message would that be ?

And even if it was zero, the delay would be 2000000/~0U , so zero as 
well, which I suppose is the best we can do in such a case.

>> +
>> +	delay = (2 * 1000000) / min_speed_hz;
> 
> Orthogonal to your change: I wonder if we need to round up the division
> here.

That is not necessary, since the delay here is twice what it needs to be 
(because we really do not know what happens in the hardware internally).

>>   	if (likely(delay < 10))	/* SCLK is faster than 100 kHz */
>>   		udelay(delay);
>>   	else			/* SCLK is _very_ slow */
> 
> Also the comments are wrong here. Is SCLK is 150 kHz we have
> min_speed_hz = 150000, right? Then delay becomes 13 and the slow freq
> path is entered. The right comment (when keeping delay = (2 * 1000000) /
> min_speed_hz) would be
> 
> 	if (likely(delay < 10)) /* SCLK is faster than 181.818 kHz */

This whole if/else is in fact based on 
Documentation/timers/timers-howto.rst , which says use usleep_range() 
for delays above 10uS or so.

The comment should be updated, but that's a separate patch.
Mark Brown July 19, 2021, 9:12 p.m. UTC | #3
On Mon, Jul 19, 2021 at 03:38:55PM +0200, Marek Vasut wrote:
> On 7/19/21 10:20 AM, Uwe Kleine-König wrote:

> > Can it happen that all transfer's spped_hz are zero?

> I don't think so, what kind of spi_message would that be ?

> And even if it was zero, the delay would be 2000000/~0U , so zero as well,
> which I suppose is the best we can do in such a case.

I can see that happening for a controller that didn't set any speed
information with a driver that also didn't set any speed information,
everything is just hoping that the default is fine but only the hardware
is actually setting something.  I've not gone and checked if anything
ever insists there absolutely must be something specified in software.
Marek Vasut July 21, 2021, 8:18 p.m. UTC | #4
On 7/19/21 11:12 PM, Mark Brown wrote:
> On Mon, Jul 19, 2021 at 03:38:55PM +0200, Marek Vasut wrote:
>> On 7/19/21 10:20 AM, Uwe Kleine-König wrote:
> 
>>> Can it happen that all transfer's spped_hz are zero?
> 
>> I don't think so, what kind of spi_message would that be ?
> 
>> And even if it was zero, the delay would be 2000000/~0U , so zero as well,
>> which I suppose is the best we can do in such a case.
> 
> I can see that happening for a controller that didn't set any speed
> information with a driver that also didn't set any speed information,
> everything is just hoping that the default is fine but only the hardware
> is actually setting something.  I've not gone and checked if anything
> ever insists there absolutely must be something specified in software.

So, should I send a V2 here with any changes or is this one OK as-is ?
Mark Brown July 26, 2021, 1:46 a.m. UTC | #5
On Wed, Jul 21, 2021 at 10:18:35PM +0200, Marek Vasut wrote:

> So, should I send a V2 here with any changes or is this one OK as-is ?

It wasn't clear that Uwe was OK with the current version, I don't mind.
Uwe Kleine-König July 26, 2021, 6:25 a.m. UTC | #6
On Mon, Jul 26, 2021 at 02:46:06AM +0100, Mark Brown wrote:
> On Wed, Jul 21, 2021 at 10:18:35PM +0200, Marek Vasut wrote:
> 
> > So, should I send a V2 here with any changes or is this one OK as-is ?
> 
> It wasn't clear that Uwe was OK with the current version, I don't mind.

My concerns were mostly orthogonal to Marek's patch. The only (little
critical) thing is: Can it happen that all transfer's speed_hz are zero?
What happens with the code change is ok, when reading the code this
looks this is by chance howver. So I would have added a comment
describing that.

But all in all I'm convinced that the change is an improvement, so no
further concerns from my side.

Best regards
Uwe
diff mbox series

Patch

diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 4aee3db6d6df..e18338fc3108 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -505,7 +505,9 @@  static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx,
 				      struct spi_message *msg)
 {
 	struct spi_device *spi = msg->spi;
+	struct spi_transfer *xfer;
 	u32 ctrl = MX51_ECSPI_CTRL_ENABLE;
+	u32 min_speed_hz = ~0U;
 	u32 testreg, delay;
 	u32 cfg = readl(spi_imx->base + MX51_ECSPI_CONFIG);
 
@@ -578,7 +580,13 @@  static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx,
 	 * the SPI communication as the device on the other end would consider
 	 * the change of SCLK polarity as a clock tick already.
 	 */
-	delay = (2 * 1000000) / spi_imx->spi_bus_clk;
+	list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+		if (!xfer->speed_hz)
+			continue;
+		min_speed_hz = min(xfer->speed_hz, min_speed_hz);
+	}
+
+	delay = (2 * 1000000) / min_speed_hz;
 	if (likely(delay < 10))	/* SCLK is faster than 100 kHz */
 		udelay(delay);
 	else			/* SCLK is _very_ slow */