linux-spi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Looking for a solution for CPM FSL SPI driver that swaps 16 bits words
@ 2023-03-07 18:21 Christophe Leroy
  2023-03-07 18:35 ` Mark Brown
  0 siblings, 1 reply; 12+ messages in thread
From: Christophe Leroy @ 2023-03-07 18:21 UTC (permalink / raw)
  To: Mark Brown, linux-spi

Hello,

I'm wondering how to solve the following issue:

On powerpc CPM soc, SPI handles words in reversed byte order. Therefore 
when some drivers like the GPIO max7301 driver request 16 bits data, 
data is sent in wrong byte order.

$ git grep bits_per_word gpio-max7301.c
gpio-max7301.c: /* bits_per_word cannot be configured in platform data */
gpio-max7301.c:         spi->bits_per_word = 16;

We could do as in spi-fsl-spi.c SPI driver for the QE soc and force 8 
bits transfer at all time:

static int mspi_apply_qe_mode_quirks(struct spi_mpc8xxx_cs *cs,
				struct spi_device *spi,
				int bits_per_word)
{
	/* QE uses Little Endian for words > 8
	 * so transform all words > 8 into 8 bits
	 * Unfortnatly that doesn't work for LSB so
	 * reject these for now */
	/* Note: 32 bits word, LSB works iff
	 * tfcr/rfcr is set to CPMFCR_GBL */
	if (spi->mode & SPI_LSB_FIRST &&
	    bits_per_word > 8)
		return -EINVAL;
	if (bits_per_word > 8)
		return 8; /* pretend its 8 bits */
	return bits_per_word;
}



But this would be a pitty because 8 bits mode is far less efficient and 
requires much lower transfer speed on powerpc CPM soc.

I have some (out of tree for now) driver that is used to load a FPGA 
through SPI and has to transfer as much as 300 kbytes data. That driver 
knows that words have to be submitted in reversed byte order and is able 
to use the SPI driver at full speed in 16 bits transfer mode, but when I 
use max7301 GPIO driver it is a problem.

What could be the best solution to force 8 bits transfer on generic 
drivers like GPIO max7301 while still allowing aware drivers like my 
FPGA loader to use 16 bits mode by reversing words by itself ?

Thanks
Christophe

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Looking for a solution for CPM FSL SPI driver that swaps 16 bits words
  2023-03-07 18:21 Looking for a solution for CPM FSL SPI driver that swaps 16 bits words Christophe Leroy
@ 2023-03-07 18:35 ` Mark Brown
  2023-03-07 19:01   ` Christophe Leroy
  0 siblings, 1 reply; 12+ messages in thread
From: Mark Brown @ 2023-03-07 18:35 UTC (permalink / raw)
  To: Christophe Leroy; +Cc: linux-spi

[-- Attachment #1: Type: text/plain, Size: 956 bytes --]

On Tue, Mar 07, 2023 at 06:21:36PM +0000, Christophe Leroy wrote:
> 
> On powerpc CPM soc, SPI handles words in reversed byte order. Therefore 
> when some drivers like the GPIO max7301 driver request 16 bits data, 
> data is sent in wrong byte order.

Clearly if the device is byte swapping the data incorrectly then you'll
need to do an extra swap in the CPU before sending to the device, or get
the DMA controller to do it if that's a feature it has, when using the
16 bit mode.

> We could do as in spi-fsl-spi.c SPI driver for the QE soc and force 8 
> bits transfer at all time:

Right, that's the simplest thing.

> What could be the best solution to force 8 bits transfer on generic 
> drivers like GPIO max7301 while still allowing aware drivers like my 
> FPGA loader to use 16 bits mode by reversing words by itself ?

If your FPGA loader is already reversing words you may as well just move
it into the controller driver.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Looking for a solution for CPM FSL SPI driver that swaps 16 bits words
  2023-03-07 18:35 ` Mark Brown
@ 2023-03-07 19:01   ` Christophe Leroy
  2023-03-07 19:19     ` Mark Brown
  0 siblings, 1 reply; 12+ messages in thread
From: Christophe Leroy @ 2023-03-07 19:01 UTC (permalink / raw)
  To: Mark Brown; +Cc: linux-spi



Le 07/03/2023 à 19:35, Mark Brown a écrit :
> On Tue, Mar 07, 2023 at 06:21:36PM +0000, Christophe Leroy wrote:
>>
>> On powerpc CPM soc, SPI handles words in reversed byte order. Therefore
>> when some drivers like the GPIO max7301 driver request 16 bits data,
>> data is sent in wrong byte order.
> 
> Clearly if the device is byte swapping the data incorrectly then you'll
> need to do an extra swap in the CPU before sending to the device, or get
> the DMA controller to do it if that's a feature it has, when using the
> 16 bit mode.
> 
>> We could do as in spi-fsl-spi.c SPI driver for the QE soc and force 8
>> bits transfer at all time:
> 
> Right, that's the simplest thing.

Yes it is for the general case, but I need to be able to continue using 
that reverting 16 bits mode for some special cases like my FPGA loader.

> 
>> What could be the best solution to force 8 bits transfer on generic
>> drivers like GPIO max7301 while still allowing aware drivers like my
>> FPGA loader to use 16 bits mode by reversing words by itself ?
> 
> If your FPGA loader is already reversing words you may as well just move
> it into the controller driver.

Well, my loader reverts words "in place" because it is the one who has 
allocated and prepared the DMA buffer. But if we move that swaping into 
the SPI controller driver, it won't be possible to do it "in place" 
because the controller cannot know it the caller plans to re-use data 
after. And I'm not sure about the performance if we start having the 
controler to start kmallocing new DMA buffers on the fly.

What about a new flag at SPI device registration to tell the SPI 
subsystem that this SPI device driver wants "raw/native 16 bits" data 
being sent as-is, that my loader would set in order to tell the 
controler "I have prepared the data, send it in your native 16 bits 
order mode" ?
And for all devices not setting that flags, the controller would 
fallback to 8 bits mode.

Thanks
Christophe

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Looking for a solution for CPM FSL SPI driver that swaps 16 bits words
  2023-03-07 19:01   ` Christophe Leroy
@ 2023-03-07 19:19     ` Mark Brown
  2023-03-07 19:43       ` Christophe Leroy
  0 siblings, 1 reply; 12+ messages in thread
From: Mark Brown @ 2023-03-07 19:19 UTC (permalink / raw)
  To: Christophe Leroy; +Cc: linux-spi

[-- Attachment #1: Type: text/plain, Size: 1209 bytes --]

On Tue, Mar 07, 2023 at 07:01:54PM +0000, Christophe Leroy wrote:

> What about a new flag at SPI device registration to tell the SPI 
> subsystem that this SPI device driver wants "raw/native 16 bits" data 
> being sent as-is, that my loader would set in order to tell the 
> controler "I have prepared the data, send it in your native 16 bits 
> order mode" ?
> And for all devices not setting that flags, the controller would 
> fallback to 8 bits mode.

Oh, so the issue is that your controller is *not* swapping data?  In
that case if 16 bit transfers are more efficient and a buffer formatted
for 8 bit transfers is already in the correct format then why not just
tell the controller to use 16 bit words where possible?  Nothing outside
the controller cares about anything other than the memory and wire
formats, if the controller correctly performs an 8 bit transfer when
programmed for 16 bit words and it's faster then just do that.  That
will work a lot better in general, drivers just sending a byte stream
aren't going to (and shouldn't) ask for anything other than 8 bit words.

Word size configuration should only be used by a client driver when it
wants things rewriting.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Looking for a solution for CPM FSL SPI driver that swaps 16 bits words
  2023-03-07 19:19     ` Mark Brown
@ 2023-03-07 19:43       ` Christophe Leroy
  2023-03-07 21:10         ` Mark Brown
  0 siblings, 1 reply; 12+ messages in thread
From: Christophe Leroy @ 2023-03-07 19:43 UTC (permalink / raw)
  To: Mark Brown; +Cc: linux-spi



Le 07/03/2023 à 20:19, Mark Brown a écrit :
> On Tue, Mar 07, 2023 at 07:01:54PM +0000, Christophe Leroy wrote:
> 
>> What about a new flag at SPI device registration to tell the SPI
>> subsystem that this SPI device driver wants "raw/native 16 bits" data
>> being sent as-is, that my loader would set in order to tell the
>> controler "I have prepared the data, send it in your native 16 bits
>> order mode" ?
>> And for all devices not setting that flags, the controller would
>> fallback to 8 bits mode.
> 
> Oh, so the issue is that your controller is *not* swapping data?  In
> that case if 16 bit transfers are more efficient and a buffer formatted
> for 8 bit transfers is already in the correct format then why not just
> tell the controller to use 16 bit words where possible?  Nothing outside
> the controller cares about anything other than the memory and wire
> formats, if the controller correctly performs an 8 bit transfer when
> programmed for 16 bit words and it's faster then just do that.  That
> will work a lot better in general, drivers just sending a byte stream
> aren't going to (and shouldn't) ask for anything other than 8 bit words.
> 
> Word size configuration should only be used by a client driver when it
> wants things rewriting.

No no, 8 bits mode is slower, or should I say it consumes more CPU for 
the same clock rate, which means we have to use slower rate in order to 
not saturate the RISC controller of the Communication Processor.

Well I not sure what you mean by swapping / not swapping data. Powerpc 
8xx is natively a big endian processor like all PPC32. But its 
Communication Processor (CPM) is apparently fetching data as little 
endian when told to perform transfer of 16 bits word on SPI.

So, my problem really is the GPIO MAX7301 driver which requests 16 bits 
transfers, because then the SPI controller sends the 2 bytes in reversed 
order. Do I understand correctly that from your point of view, that 
driver shouldn't request a 16 bits tranfer ? It is done here, in the 
max7301_probe() function, 
https://elixir.bootlin.com/linux/v6.3-rc1/source/drivers/gpio/gpio-max7301.c#L50

Because if I clamp the CPM SPI driver to 8 bits transfers, then I cannot 
anymore perform 16 bits transfer for loading my FPGA, then it means I 
must reduce data rate then loading the FPGA takes ages.

Christophe

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Looking for a solution for CPM FSL SPI driver that swaps 16 bits words
  2023-03-07 19:43       ` Christophe Leroy
@ 2023-03-07 21:10         ` Mark Brown
  2023-03-07 21:40           ` Christophe Leroy
  0 siblings, 1 reply; 12+ messages in thread
From: Mark Brown @ 2023-03-07 21:10 UTC (permalink / raw)
  To: Christophe Leroy; +Cc: linux-spi

[-- Attachment #1: Type: text/plain, Size: 2445 bytes --]

On Tue, Mar 07, 2023 at 07:43:42PM +0000, Christophe Leroy wrote:
> Le 07/03/2023 à 20:19, Mark Brown a écrit :

> > Oh, so the issue is that your controller is *not* swapping data?  In
> > that case if 16 bit transfers are more efficient and a buffer formatted
> > for 8 bit transfers is already in the correct format then why not just
> > tell the controller to use 16 bit words where possible?  Nothing outside

...

> No no, 8 bits mode is slower, or should I say it consumes more CPU for 
> the same clock rate, which means we have to use slower rate in order to 
> not saturate the RISC controller of the Communication Processor.

Please read what I wrote above.

> Well I not sure what you mean by swapping / not swapping data. Powerpc 
> 8xx is natively a big endian processor like all PPC32. But its 
> Communication Processor (CPM) is apparently fetching data as little 
> endian when told to perform transfer of 16 bits word on SPI.

The default wire format for SPI is big endian (MSB first), as covered in
spi.h:

 * In-memory data values are always in native CPU byte order, translated
 * from the wire byte order (big-endian except with SPI_LSB_FIRST).  So
 * for example when bits_per_word is sixteen, buffers are 2N bytes long
 * (@len = 2N) and hold N sixteen bit words in CPU byte order.

LSB_FIRST has only one in tree user other than spidev so I'd question
how often it's correctly implemented.

> So, my problem really is the GPIO MAX7301 driver which requests 16 bits 
> transfers, because then the SPI controller sends the 2 bytes in reversed 
> order. Do I understand correctly that from your point of view, that 
> driver shouldn't request a 16 bits tranfer ? It is done here, in the 
> max7301_probe() function, 
> https://elixir.bootlin.com/linux/v6.3-rc1/source/drivers/gpio/gpio-max7301.c#L50

It would certainly improve interoperability with controllers to request
8 bit, but so long as the driver is reading and writing data in the
expected format it should work perfectly well.  Looking at the lack of
any endianness handling in the driver that doesn't seem to be the case
though, it's just handling data in CPU endian format which isn't
portable.

> Because if I clamp the CPM SPI driver to 8 bits transfers, then I cannot 
> anymore perform 16 bits transfer for loading my FPGA, then it means I 
> must reduce data rate then loading the FPGA takes ages.

Why?

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Looking for a solution for CPM FSL SPI driver that swaps 16 bits words
  2023-03-07 21:10         ` Mark Brown
@ 2023-03-07 21:40           ` Christophe Leroy
  2023-03-07 22:16             ` Mark Brown
  0 siblings, 1 reply; 12+ messages in thread
From: Christophe Leroy @ 2023-03-07 21:40 UTC (permalink / raw)
  To: Mark Brown; +Cc: linux-spi



Le 07/03/2023 à 22:10, Mark Brown a écrit :
> On Tue, Mar 07, 2023 at 07:43:42PM +0000, Christophe Leroy wrote:
>> Le 07/03/2023 à 20:19, Mark Brown a écrit :
> 
>>> Oh, so the issue is that your controller is *not* swapping data?  In
>>> that case if 16 bit transfers are more efficient and a buffer formatted
>>> for 8 bit transfers is already in the correct format then why not just
>>> tell the controller to use 16 bit words where possible?  Nothing outside
> 
> ...
> 
>> No no, 8 bits mode is slower, or should I say it consumes more CPU for
>> the same clock rate, which means we have to use slower rate in order to
>> not saturate the RISC controller of the Communication Processor.
> 
> Please read what I wrote above.

Ah sorry, I mis-read your text.

So yes, the problem is that the controller *is* swapping data: if I 
format the buffer to have 0x12 0x34 and tells the controller to send it 
as a 16 bits word, it will send 0x3412 whereas if I tell it to send as 8 
bits words, it will send 0x12 then 0x34.

So a driver like MAX7301 which wants to send 0x1234 as a 16-bits word 
will write 0x1234 into the buffer. The powerpc 8xx being big endian, I 
get 0x12 0x34 into the buffer then the controller sends word 0x3412.

> 
>> Well I not sure what you mean by swapping / not swapping data. Powerpc
>> 8xx is natively a big endian processor like all PPC32. But its
>> Communication Processor (CPM) is apparently fetching data as little
>> endian when told to perform transfer of 16 bits word on SPI.
> 
> The default wire format for SPI is big endian (MSB first), as covered in
> spi.h:
> 
>   * In-memory data values are always in native CPU byte order, translated
>   * from the wire byte order (big-endian except with SPI_LSB_FIRST).  So
>   * for example when bits_per_word is sixteen, buffers are 2N bytes long
>   * (@len = 2N) and hold N sixteen bit words in CPU byte order.
> 
> LSB_FIRST has only one in tree user other than spidev so I'd question
> how often it's correctly implemented.

Well, ok, I have no problem with the wire byte order, only with how the 
controller fetches the data from the DMA buffer. I'm not sure what I 
write is clear, is it ?

> 
>> So, my problem really is the GPIO MAX7301 driver which requests 16 bits
>> transfers, because then the SPI controller sends the 2 bytes in reversed
>> order. Do I understand correctly that from your point of view, that
>> driver shouldn't request a 16 bits tranfer ? It is done here, in the
>> max7301_probe() function,
>> https://elixir.bootlin.com/linux/v6.3-rc1/source/drivers/gpio/gpio-max7301.c#L50
> 
> It would certainly improve interoperability with controllers to request
> 8 bit, but so long as the driver is reading and writing data in the
> expected format it should work perfectly well.  Looking at the lack of
> any endianness handling in the driver that doesn't seem to be the case
> though, it's just handling data in CPU endian format which isn't
> portable.

I agree, it should work but it doesn't.
When I change max7301_probe() to set bits_per_word to 8 instead of 16 it 
works.

> 
>> Because if I clamp the CPM SPI driver to 8 bits transfers, then I cannot
>> anymore perform 16 bits transfer for loading my FPGA, then it means I
>> must reduce data rate then loading the FPGA takes ages.
> 
> Why?

Maybe what I wrote here isn't clear. What I mean is that if I modify CPM 
SPI controller driver to always use 8 bits mode (as done for the QE SPI 
controller via function mspi_apply_qe_mode_quirks() ), then it will work 
but I will not be able to use the same speed as in 16 bits transfer mode.

So, to sum up, the solutions I see:
A/ Force CPM SPI controller to always use 8 bits mode.
B/ Implement a flag to allow a SPI consumer to say "please perform 
tranfer with your bogus but performant 16 bits mode, I have worked 
around the data order for you"
C/ Implement a byte-swapping in the CPM SPI controller when a consumer 
asks for a 16-bits data transfer
D/ Modify MAX7301 GPIO driver to use 8 bits words instead of 16 bits words.

Solution A will degrade performance by forcing transfer rate reduction.
Solution B looks like a "home made" solution.
Solution C means copy-and-swap into a newly allocated DMA buffer.
Solution D is .... the best one ?

Any other idea ?

Which solution would you prefer ?

Thanks
Christophe

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Looking for a solution for CPM FSL SPI driver that swaps 16 bits words
  2023-03-07 21:40           ` Christophe Leroy
@ 2023-03-07 22:16             ` Mark Brown
  2023-03-13  9:55               ` Christophe Leroy
  2023-03-13 22:33               ` Christophe Leroy
  0 siblings, 2 replies; 12+ messages in thread
From: Mark Brown @ 2023-03-07 22:16 UTC (permalink / raw)
  To: Christophe Leroy; +Cc: linux-spi

[-- Attachment #1: Type: text/plain, Size: 6370 bytes --]

On Tue, Mar 07, 2023 at 09:40:09PM +0000, Christophe Leroy wrote:
> Le 07/03/2023 à 22:10, Mark Brown a écrit :
> > On Tue, Mar 07, 2023 at 07:43:42PM +0000, Christophe Leroy wrote:
> >> Le 07/03/2023 à 20:19, Mark Brown a écrit :

> So yes, the problem is that the controller *is* swapping data: if I 
> format the buffer to have 0x12 0x34 and tells the controller to send it 
> as a 16 bits word, it will send 0x3412 whereas if I tell it to send as 8 
> bits words, it will send 0x12 then 0x34.

> So a driver like MAX7301 which wants to send 0x1234 as a 16-bits word 
> will write 0x1234 into the buffer. The powerpc 8xx being big endian, I 
> get 0x12 0x34 into the buffer then the controller sends word 0x3412.

So the CPU is big endian, memory has a big endian word in it and the
controller is then sending as little endian?  That would mean that the
driver for the controller is implementing SPI_LSB_FIRST mode without
being asked (IIRC there is an option to run these systems LE, I don't
know if the controller is just always little endian or always byte
swapping).  That seems like a bug in the driver for the controller.

> >> Well I not sure what you mean by swapping / not swapping data. Powerpc
> >> 8xx is natively a big endian processor like all PPC32. But its
> >> Communication Processor (CPM) is apparently fetching data as little
> >> endian when told to perform transfer of 16 bits word on SPI.

> > The default wire format for SPI is big endian (MSB first), as covered in
> > spi.h:

> >   * In-memory data values are always in native CPU byte order, translated
> >   * from the wire byte order (big-endian except with SPI_LSB_FIRST).  So
> >   * for example when bits_per_word is sixteen, buffers are 2N bytes long
> >   * (@len = 2N) and hold N sixteen bit words in CPU byte order.

> > LSB_FIRST has only one in tree user other than spidev so I'd question
> > how often it's correctly implemented.

> Well, ok, I have no problem with the wire byte order, only with how the 
> controller fetches the data from the DMA buffer. I'm not sure what I 
> write is clear, is it ?

You have a problem with the wire byte order not being what was
requested - the data should always be big endian unless otherwise
specified.

> >> So, my problem really is the GPIO MAX7301 driver which requests 16 bits
> >> transfers, because then the SPI controller sends the 2 bytes in reversed
> >> order. Do I understand correctly that from your point of view, that
> >> driver shouldn't request a 16 bits tranfer ? It is done here, in the
> >> max7301_probe() function,
> >> https://elixir.bootlin.com/linux/v6.3-rc1/source/drivers/gpio/gpio-max7301.c#L50

> > It would certainly improve interoperability with controllers to request
> > 8 bit, but so long as the driver is reading and writing data in the
> > expected format it should work perfectly well.  Looking at the lack of
> > any endianness handling in the driver that doesn't seem to be the case
> > though, it's just handling data in CPU endian format which isn't
> > portable.

> I agree, it should work but it doesn't.
> When I change max7301_probe() to set bits_per_word to 8 instead of 16 it 
> works.

So the driver should also work on a little endian system configured for
16 bit words - looking at the code I would only expect it to work on
one endianness of system.

> >> Because if I clamp the CPM SPI driver to 8 bits transfers, then I cannot
> >> anymore perform 16 bits transfer for loading my FPGA, then it means I
> >> must reduce data rate then loading the FPGA takes ages.

> > Why?

> Maybe what I wrote here isn't clear. What I mean is that if I modify CPM 
> SPI controller driver to always use 8 bits mode (as done for the QE SPI 
> controller via function mspi_apply_qe_mode_quirks() ), then it will work 
> but I will not be able to use the same speed as in 16 bits transfer mode.

Why would we tell the controller to run in 8 bit mode when you don't
need to?  What the driver tells the controller just needs to produce the
correct results given the request from the client driver, it doesn't
need to be what the client driver asked for.

> So, to sum up, the solutions I see:
> A/ Force CPM SPI controller to always use 8 bits mode.

SPI controller driver should do whatever is the most efficient thing
for the transfers it was asked to perform.

> B/ Implement a flag to allow a SPI consumer to say "please perform 
> tranfer with your bogus but performant 16 bits mode, I have worked 
> around the data order for you"

SPI_LSB_FIRST already exists, however unless a device really is
operating with words I'd really suggest not using this since it just
adds confusion and portability problems. 

> C/ Implement a byte-swapping in the CPM SPI controller when a consumer 
> asks for a 16-bits data transfer

If the device doesn't request SPI_LSB_FIRST.

> D/ Modify MAX7301 GPIO driver to use 8 bits words instead of 16 bits words.

That seems like it's needed anyway AFAICT, the driver is assuming a
particular endianness.  It could also be modified to format data in a
way that'll work with either endianness but that seems more confusing.

If your FPGA image is just a byte stream then I'd expect the driver for
it to be using 8 bit mode.  It is unclear to me if something has pre
swapped the image to contort it through whatever set of endianness
assumptions are going on here, you seem to want it to be byte swapped
but that seems like a surprising format for a FPGA image to be generated
in which makes me think something swapped the image earlier on?  AFAICT
what you're describing is a FPGA image which is a sequence of little
endian 16 bit words which need to be sent to the FPGA as a sequence of
big endian 16 bit words.

> Solution A will degrade performance by forcing transfer rate reduction.
> Solution B looks like a "home made" solution.
> Solution C means copy-and-swap into a newly allocated DMA buffer.
> Solution D is .... the best one ?

> Any other idea ?

> Which solution would you prefer ?

It seems like it'd be a lot clearer if the FPGA driver worked with a
byte stream, then the controller driver can work out the most efficient
way to actually perform that transfer.  At the minute I'm not clear what
it's actually doing here.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Looking for a solution for CPM FSL SPI driver that swaps 16 bits words
  2023-03-07 22:16             ` Mark Brown
@ 2023-03-13  9:55               ` Christophe Leroy
  2023-03-14 18:58                 ` Mark Brown
  2023-03-13 22:33               ` Christophe Leroy
  1 sibling, 1 reply; 12+ messages in thread
From: Christophe Leroy @ 2023-03-13  9:55 UTC (permalink / raw)
  To: Mark Brown; +Cc: linux-spi

[-- Attachment #1: Type: text/plain, Size: 7391 bytes --]



Le 07/03/2023 à 23:16, Mark Brown a écrit :
> On Tue, Mar 07, 2023 at 09:40:09PM +0000, Christophe Leroy wrote:
>> Le 07/03/2023 à 22:10, Mark Brown a écrit :
>>> On Tue, Mar 07, 2023 at 07:43:42PM +0000, Christophe Leroy wrote:
>>>> Le 07/03/2023 à 20:19, Mark Brown a écrit :
> 
>> So yes, the problem is that the controller *is* swapping data: if I
>> format the buffer to have 0x12 0x34 and tells the controller to send it
>> as a 16 bits word, it will send 0x3412 whereas if I tell it to send as 8
>> bits words, it will send 0x12 then 0x34.
> 
>> So a driver like MAX7301 which wants to send 0x1234 as a 16-bits word
>> will write 0x1234 into the buffer. The powerpc 8xx being big endian, I
>> get 0x12 0x34 into the buffer then the controller sends word 0x3412.
> 
> So the CPU is big endian, memory has a big endian word in it and the
> controller is then sending as little endian?  That would mean that the
> driver for the controller is implementing SPI_LSB_FIRST mode without
> being asked (IIRC there is an option to run these systems LE, I don't
> know if the controller is just always little endian or always byte
> swapping).  That seems like a bug in the driver for the controller.

What does SPI_LSB_FIRST stands for ? From what you say, shall I 
understand that it means Least Significant _Byte_ first ?

I'm asking because as far as I can see, for the controller SPI_LSB_FIRST 
means Least Significant _bit_ first. Is that wrong ?

> 
>>>> Well I not sure what you mean by swapping / not swapping data. Powerpc
>>>> 8xx is natively a big endian processor like all PPC32. But its
>>>> Communication Processor (CPM) is apparently fetching data as little
>>>> endian when told to perform transfer of 16 bits word on SPI.
> 
>>> The default wire format for SPI is big endian (MSB first), as covered in
>>> spi.h:
> 
>>>    * In-memory data values are always in native CPU byte order, translated
>>>    * from the wire byte order (big-endian except with SPI_LSB_FIRST).  So
>>>    * for example when bits_per_word is sixteen, buffers are 2N bytes long
>>>    * (@len = 2N) and hold N sixteen bit words in CPU byte order.
> 
>>> LSB_FIRST has only one in tree user other than spidev so I'd question
>>> how often it's correctly implemented.
> 
>> Well, ok, I have no problem with the wire byte order, only with how the
>> controller fetches the data from the DMA buffer. I'm not sure what I
>> write is clear, is it ?
> 
> You have a problem with the wire byte order not being what was
> requested - the data should always be big endian unless otherwise
> specified.

The attached screen capture is an extract of the controller reference 
manual. When SPI_LSB_FIRST is requested, REV bit is set to 0. Otherwise 
REV bit is set to 1.

Hope it helps clarify how the controller works.

> 
>>>> So, my problem really is the GPIO MAX7301 driver which requests 16 bits
>>>> transfers, because then the SPI controller sends the 2 bytes in reversed
>>>> order. Do I understand correctly that from your point of view, that
>>>> driver shouldn't request a 16 bits tranfer ? It is done here, in the
>>>> max7301_probe() function,
>>>> https://elixir.bootlin.com/linux/v6.3-rc1/source/drivers/gpio/gpio-max7301.c#L50
> 
>>> It would certainly improve interoperability with controllers to request
>>> 8 bit, but so long as the driver is reading and writing data in the
>>> expected format it should work perfectly well.  Looking at the lack of
>>> any endianness handling in the driver that doesn't seem to be the case
>>> though, it's just handling data in CPU endian format which isn't
>>> portable.
> 
>> I agree, it should work but it doesn't.
>> When I change max7301_probe() to set bits_per_word to 8 instead of 16 it
>> works.
> 
> So the driver should also work on a little endian system configured for
> 16 bit words - looking at the code I would only expect it to work on
> one endianness of system.
> 
>>>> Because if I clamp the CPM SPI driver to 8 bits transfers, then I cannot
>>>> anymore perform 16 bits transfer for loading my FPGA, then it means I
>>>> must reduce data rate then loading the FPGA takes ages.
> 
>>> Why?
> 
>> Maybe what I wrote here isn't clear. What I mean is that if I modify CPM
>> SPI controller driver to always use 8 bits mode (as done for the QE SPI
>> controller via function mspi_apply_qe_mode_quirks() ), then it will work
>> but I will not be able to use the same speed as in 16 bits transfer mode.
> 
> Why would we tell the controller to run in 8 bit mode when you don't
> need to?  What the driver tells the controller just needs to produce the
> correct results given the request from the client driver, it doesn't
> need to be what the client driver asked for.
> 
>> So, to sum up, the solutions I see:
>> A/ Force CPM SPI controller to always use 8 bits mode.
> 
> SPI controller driver should do whatever is the most efficient thing
> for the transfers it was asked to perform.
> 
>> B/ Implement a flag to allow a SPI consumer to say "please perform
>> tranfer with your bogus but performant 16 bits mode, I have worked
>> around the data order for you"
> 
> SPI_LSB_FIRST already exists, however unless a device really is
> operating with words I'd really suggest not using this since it just
> adds confusion and portability problems.
> 
>> C/ Implement a byte-swapping in the CPM SPI controller when a consumer
>> asks for a 16-bits data transfer
> 
> If the device doesn't request SPI_LSB_FIRST.
> 
>> D/ Modify MAX7301 GPIO driver to use 8 bits words instead of 16 bits words.
> 
> That seems like it's needed anyway AFAICT, the driver is assuming a
> particular endianness.  It could also be modified to format data in a
> way that'll work with either endianness but that seems more confusing.
> 
> If your FPGA image is just a byte stream then I'd expect the driver for
> it to be using 8 bit mode.  It is unclear to me if something has pre
> swapped the image to contort it through whatever set of endianness
> assumptions are going on here, you seem to want it to be byte swapped
> but that seems like a surprising format for a FPGA image to be generated
> in which makes me think something swapped the image earlier on?  AFAICT
> what you're describing is a FPGA image which is a sequence of little
> endian 16 bit words which need to be sent to the FPGA as a sequence of
> big endian 16 bit words.

My FPGA image is a byte stream, you are right it could/should use 8 bit 
more. Using 16 bit mode was a trick to be able to send faster as the 
controler is more efficient in 16 bits mode.

> 
>> Solution A will degrade performance by forcing transfer rate reduction.
>> Solution B looks like a "home made" solution.
>> Solution C means copy-and-swap into a newly allocated DMA buffer.
>> Solution D is .... the best one ?
> 
>> Any other idea ?
> 
>> Which solution would you prefer ?
> 
> It seems like it'd be a lot clearer if the FPGA driver worked with a
> byte stream, then the controller driver can work out the most efficient
> way to actually perform that transfer.  At the minute I'm not clear what
> it's actually doing here.

Yes I agree, let's see if I can implement byte swapping in the SPI 
controller driver.

Thanks for your help,
Christophe

[-- Attachment #2: spi_fsl_examples.png --]
[-- Type: image/png, Size: 138646 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Looking for a solution for CPM FSL SPI driver that swaps 16 bits words
  2023-03-07 22:16             ` Mark Brown
  2023-03-13  9:55               ` Christophe Leroy
@ 2023-03-13 22:33               ` Christophe Leroy
  2023-03-14 13:00                 ` Mark Brown
  1 sibling, 1 reply; 12+ messages in thread
From: Christophe Leroy @ 2023-03-13 22:33 UTC (permalink / raw)
  To: Mark Brown; +Cc: linux-spi

Hi Mark,

Le 07/03/2023 à 23:16, Mark Brown a écrit :
> On Tue, Mar 07, 2023 at 09:40:09PM +0000, Christophe Leroy wrote:
>>>    * In-memory data values are always in native CPU byte order, translated
>>>    * from the wire byte order (big-endian except with SPI_LSB_FIRST).  So
>>>    * for example when bits_per_word is sixteen, buffers are 2N bytes long
>>>    * (@len = 2N) and hold N sixteen bit words in CPU byte order.
> 
>>> LSB_FIRST has only one in tree user other than spidev so I'd question
>>> how often it's correctly implemented.
> 
>> Well, ok, I have no problem with the wire byte order, only with how the
>> controller fetches the data from the DMA buffer. I'm not sure what I
>> write is clear, is it ?
> 
> You have a problem with the wire byte order not being what was
> requested - the data should always be big endian unless otherwise
> specified.
> 

Looking at another driver I'm even more puzzled. That's driver 
drivers/leds/leds-dac124s085.c

It also sets spi->bits_per_word = 16 , but is uses cpu_to_le16() to 
prepare that data. So this one should then work with any host 
endianness, but why the hell is it doing cpu_to_le16() if the data 
should be big endian ?

To be honnest, I'm really not sure anymore what is the way to go.

Christophe

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Looking for a solution for CPM FSL SPI driver that swaps 16 bits words
  2023-03-13 22:33               ` Christophe Leroy
@ 2023-03-14 13:00                 ` Mark Brown
  0 siblings, 0 replies; 12+ messages in thread
From: Mark Brown @ 2023-03-14 13:00 UTC (permalink / raw)
  To: Christophe Leroy; +Cc: linux-spi

[-- Attachment #1: Type: text/plain, Size: 1091 bytes --]

On Mon, Mar 13, 2023 at 10:33:10PM +0000, Christophe Leroy wrote:

> Looking at another driver I'm even more puzzled. That's driver 
> drivers/leds/leds-dac124s085.c

> It also sets spi->bits_per_word = 16 , but is uses cpu_to_le16() to 
> prepare that data. So this one should then work with any host 
> endianness, but why the hell is it doing cpu_to_le16() if the data 
> should be big endian ?

I wouldn't take some random client driver as being particulary
meaningful - people often abuse APIs.  I wouldn't be sure that that
endianness conversion was doing anything on the system that the driver
was developed on.

> To be honnest, I'm really not sure anymore what is the way to go.

The expected behaviour is very clearly documented, I've quoted that
documentation at you and recommended that anything being done for
performance reasons be done in the controller driver.  I'm really not
sure what else to tell you, especially given that if the client driver
uses a byte stream (which is what it wants) this all becomes purely
internal to the controller
driver.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Looking for a solution for CPM FSL SPI driver that swaps 16 bits words
  2023-03-13  9:55               ` Christophe Leroy
@ 2023-03-14 18:58                 ` Mark Brown
  0 siblings, 0 replies; 12+ messages in thread
From: Mark Brown @ 2023-03-14 18:58 UTC (permalink / raw)
  To: Christophe Leroy; +Cc: linux-spi

[-- Attachment #1: Type: text/plain, Size: 875 bytes --]

On Mon, Mar 13, 2023 at 09:55:25AM +0000, Christophe Leroy wrote:
> Le 07/03/2023 à 23:16, Mark Brown a écrit :

> > So the CPU is big endian, memory has a big endian word in it and the
> > controller is then sending as little endian?  That would mean that the
> > driver for the controller is implementing SPI_LSB_FIRST mode without
> > being asked (IIRC there is an option to run these systems LE, I don't
> > know if the controller is just always little endian or always byte
> > swapping).  That seems like a bug in the driver for the controller.

> What does SPI_LSB_FIRST stands for ? From what you say, shall I 
> understand that it means Least Significant _Byte_ first ?

> I'm asking because as far as I can see, for the controller SPI_LSB_FIRST 
> means Least Significant _bit_ first. Is that wrong ?

Ah, you're right - it's bit rather than byte.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2023-03-14 18:58 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-03-07 18:21 Looking for a solution for CPM FSL SPI driver that swaps 16 bits words Christophe Leroy
2023-03-07 18:35 ` Mark Brown
2023-03-07 19:01   ` Christophe Leroy
2023-03-07 19:19     ` Mark Brown
2023-03-07 19:43       ` Christophe Leroy
2023-03-07 21:10         ` Mark Brown
2023-03-07 21:40           ` Christophe Leroy
2023-03-07 22:16             ` Mark Brown
2023-03-13  9:55               ` Christophe Leroy
2023-03-14 18:58                 ` Mark Brown
2023-03-13 22:33               ` Christophe Leroy
2023-03-14 13:00                 ` Mark Brown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).