diff mbox series

hw/ssi: imx_spi: Improve chip select handling

Message ID 20210808013406.223506-1-linux@roeck-us.net (mailing list archive)
State New, archived
Headers show
Series hw/ssi: imx_spi: Improve chip select handling | expand

Commit Message

Guenter Roeck Aug. 8, 2021, 1:34 a.m. UTC
The control register does not really have a means to deselect
all chip selects directly. As result, CS is effectively never
deselected, and connected flash chips fail to perform read
operations since they don't get the expected chip select signals
to reset their state machine.

Normally and per controller documentation one would assume that
chip select should be set whenever a transfer starts (XCH is
set or the tx fifo is written into), and that it should be disabled
whenever a transfer is complete. However, that does not work in
practice: attempts to implement this approach resulted in failures,
presumably because a single transaction can be split into multiple
transfers.

At the same time, there is no explicit signal from the host indicating
if chip select should be active or not. In the absence of such a direct
signal, use the burst length written into the control register to
determine if an access is ongoing or not. Disable all chip selects
if the burst length field in the configuration register is set to 0,
and (re-)enable chip select if a transfer is started. This is possible
because the Linux driver clears the burst length field whenever it
prepares the controller for the next transfer.
This solution  is less than perfect since it effectively only disables
chip select when initiating the next transfer, but it does work with
Linux and should otherwise do no harm.

Stop complaining if the burst length field is set to a value of 0,
since that is done by Linux for every transfer.

With this patch, a command line parameter such as "-drive
file=flash.sabre,format=raw,if=mtd" can be used to instantiate the
flash chip in the sabrelite emulation. Without this patch, the
flash instantiates, but it only reads zeroes.

Signed-off-by: Guenter Roeck <linux@roeck-us.net>
---
I am not entirely happy with this solution, but it is the best I was
able to come up with. If anyone has a better idea, I'll be happy
to give it a try.

 hw/ssi/imx_spi.c | 17 +++++++----------
 1 file changed, 7 insertions(+), 10 deletions(-)

Comments

Peter Maydell Sept. 2, 2021, 3:58 p.m. UTC | #1
On Sun, 8 Aug 2021 at 02:34, Guenter Roeck <linux@roeck-us.net> wrote:
>
> The control register does not really have a means to deselect
> all chip selects directly. As result, CS is effectively never
> deselected, and connected flash chips fail to perform read
> operations since they don't get the expected chip select signals
> to reset their state machine.
>
> Normally and per controller documentation one would assume that
> chip select should be set whenever a transfer starts (XCH is
> set or the tx fifo is written into), and that it should be disabled
> whenever a transfer is complete. However, that does not work in
> practice: attempts to implement this approach resulted in failures,
> presumably because a single transaction can be split into multiple
> transfers.
>
> At the same time, there is no explicit signal from the host indicating
> if chip select should be active or not. In the absence of such a direct
> signal, use the burst length written into the control register to
> determine if an access is ongoing or not. Disable all chip selects
> if the burst length field in the configuration register is set to 0,
> and (re-)enable chip select if a transfer is started. This is possible
> because the Linux driver clears the burst length field whenever it
> prepares the controller for the next transfer.
> This solution  is less than perfect since it effectively only disables
> chip select when initiating the next transfer, but it does work with
> Linux and should otherwise do no harm.
>
> Stop complaining if the burst length field is set to a value of 0,
> since that is done by Linux for every transfer.
>
> With this patch, a command line parameter such as "-drive
> file=flash.sabre,format=raw,if=mtd" can be used to instantiate the
> flash chip in the sabrelite emulation. Without this patch, the
> flash instantiates, but it only reads zeroes.
>
> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
> ---
> I am not entirely happy with this solution, but it is the best I was
> able to come up with. If anyone has a better idea, I'll be happy
> to give it a try.
>
>  hw/ssi/imx_spi.c | 17 +++++++----------
>  1 file changed, 7 insertions(+), 10 deletions(-)
>
> diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c
> index 189423bb3a..7a093156bd 100644
> --- a/hw/ssi/imx_spi.c
> +++ b/hw/ssi/imx_spi.c
> @@ -167,6 +167,8 @@ static void imx_spi_flush_txfifo(IMXSPIState *s)
>      DPRINTF("Begin: TX Fifo Size = %d, RX Fifo Size = %d\n",
>              fifo32_num_used(&s->tx_fifo), fifo32_num_used(&s->rx_fifo));
>
> +    qemu_set_irq(s->cs_lines[imx_spi_selected_channel(s)], 0);
> +
>      while (!fifo32_is_empty(&s->tx_fifo)) {
>          int tx_burst = 0;
>
> @@ -385,13 +387,6 @@ static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value,
>      case ECSPI_CONREG:
>          s->regs[ECSPI_CONREG] = value;
>
> -        burst = EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_BURST_LENGTH) + 1;
> -        if (burst % 8) {
> -            qemu_log_mask(LOG_UNIMP,
> -                          "[%s]%s: burst length %d not supported: rounding up to next multiple of 8\n",
> -                          TYPE_IMX_SPI, __func__, burst);
> -        }

Why has this log message been removed ?

>          if (!imx_spi_is_enabled(s)) {
>              /* device is disabled, so this is a soft reset */
>              imx_spi_soft_reset(s);

thanks
-- PMM
Guenter Roeck Sept. 2, 2021, 4:09 p.m. UTC | #2
On 9/2/21 8:58 AM, Peter Maydell wrote:
> On Sun, 8 Aug 2021 at 02:34, Guenter Roeck <linux@roeck-us.net> wrote:
>>
>> The control register does not really have a means to deselect
>> all chip selects directly. As result, CS is effectively never
>> deselected, and connected flash chips fail to perform read
>> operations since they don't get the expected chip select signals
>> to reset their state machine.
>>
>> Normally and per controller documentation one would assume that
>> chip select should be set whenever a transfer starts (XCH is
>> set or the tx fifo is written into), and that it should be disabled
>> whenever a transfer is complete. However, that does not work in
>> practice: attempts to implement this approach resulted in failures,
>> presumably because a single transaction can be split into multiple
>> transfers.
>>
>> At the same time, there is no explicit signal from the host indicating
>> if chip select should be active or not. In the absence of such a direct
>> signal, use the burst length written into the control register to
>> determine if an access is ongoing or not. Disable all chip selects
>> if the burst length field in the configuration register is set to 0,
>> and (re-)enable chip select if a transfer is started. This is possible
>> because the Linux driver clears the burst length field whenever it
>> prepares the controller for the next transfer.
>> This solution  is less than perfect since it effectively only disables
>> chip select when initiating the next transfer, but it does work with
>> Linux and should otherwise do no harm.
>>
>> Stop complaining if the burst length field is set to a value of 0,
>> since that is done by Linux for every transfer.
>>
>> With this patch, a command line parameter such as "-drive
>> file=flash.sabre,format=raw,if=mtd" can be used to instantiate the
>> flash chip in the sabrelite emulation. Without this patch, the
>> flash instantiates, but it only reads zeroes.
>>
>> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
>> ---
>> I am not entirely happy with this solution, but it is the best I was
>> able to come up with. If anyone has a better idea, I'll be happy
>> to give it a try.
>>
>>   hw/ssi/imx_spi.c | 17 +++++++----------
>>   1 file changed, 7 insertions(+), 10 deletions(-)
>>
>> diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c
>> index 189423bb3a..7a093156bd 100644
>> --- a/hw/ssi/imx_spi.c
>> +++ b/hw/ssi/imx_spi.c
>> @@ -167,6 +167,8 @@ static void imx_spi_flush_txfifo(IMXSPIState *s)
>>       DPRINTF("Begin: TX Fifo Size = %d, RX Fifo Size = %d\n",
>>               fifo32_num_used(&s->tx_fifo), fifo32_num_used(&s->rx_fifo));
>>
>> +    qemu_set_irq(s->cs_lines[imx_spi_selected_channel(s)], 0);
>> +
>>       while (!fifo32_is_empty(&s->tx_fifo)) {
>>           int tx_burst = 0;
>>
>> @@ -385,13 +387,6 @@ static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value,
>>       case ECSPI_CONREG:
>>           s->regs[ECSPI_CONREG] = value;
>>
>> -        burst = EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_BURST_LENGTH) + 1;
>> -        if (burst % 8) {
>> -            qemu_log_mask(LOG_UNIMP,
>> -                          "[%s]%s: burst length %d not supported: rounding up to next multiple of 8\n",
>> -                          TYPE_IMX_SPI, __func__, burst);
>> -        }
> 
> Why has this log message been removed ?

What I wanted to do is:

"Stop complaining if the burst length field is set to a value of 0,
  since that is done by Linux for every transfer."

What I did instead is to remove the message entirely.

How about the rest of the patch ? Is it worth a resend with the message
restored (except for burst size == 0), or is it not acceptable anyway ?

Thanks,
Guenter

> 
>>           if (!imx_spi_is_enabled(s)) {
>>               /* device is disabled, so this is a soft reset */
>>               imx_spi_soft_reset(s);
> 
> thanks
> -- PMM
>
Peter Maydell Sept. 2, 2021, 7:29 p.m. UTC | #3
On Thu, 2 Sept 2021 at 17:09, Guenter Roeck <linux@roeck-us.net> wrote:
>
> On 9/2/21 8:58 AM, Peter Maydell wrote:
> > On Sun, 8 Aug 2021 at 02:34, Guenter Roeck <linux@roeck-us.net> wrote:
> >>
> >> The control register does not really have a means to deselect
> >> all chip selects directly. As result, CS is effectively never
> >> deselected, and connected flash chips fail to perform read
> >> operations since they don't get the expected chip select signals
> >> to reset their state machine.
> >>
> >> Normally and per controller documentation one would assume that
> >> chip select should be set whenever a transfer starts (XCH is
> >> set or the tx fifo is written into), and that it should be disabled
> >> whenever a transfer is complete. However, that does not work in
> >> practice: attempts to implement this approach resulted in failures,
> >> presumably because a single transaction can be split into multiple
> >> transfers.
> >>
> >> At the same time, there is no explicit signal from the host indicating
> >> if chip select should be active or not. In the absence of such a direct
> >> signal, use the burst length written into the control register to
> >> determine if an access is ongoing or not. Disable all chip selects
> >> if the burst length field in the configuration register is set to 0,
> >> and (re-)enable chip select if a transfer is started. This is possible
> >> because the Linux driver clears the burst length field whenever it
> >> prepares the controller for the next transfer.
> >> This solution  is less than perfect since it effectively only disables
> >> chip select when initiating the next transfer, but it does work with
> >> Linux and should otherwise do no harm.
> >>
> >> Stop complaining if the burst length field is set to a value of 0,
> >> since that is done by Linux for every transfer.
> >>
> >> With this patch, a command line parameter such as "-drive
> >> file=flash.sabre,format=raw,if=mtd" can be used to instantiate the
> >> flash chip in the sabrelite emulation. Without this patch, the
> >> flash instantiates, but it only reads zeroes.
> >>
> >> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
> >> ---
> >> I am not entirely happy with this solution, but it is the best I was
> >> able to come up with. If anyone has a better idea, I'll be happy
> >> to give it a try.
> >>
> >>   hw/ssi/imx_spi.c | 17 +++++++----------
> >>   1 file changed, 7 insertions(+), 10 deletions(-)
> >>
> >> diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c
> >> index 189423bb3a..7a093156bd 100644
> >> --- a/hw/ssi/imx_spi.c
> >> +++ b/hw/ssi/imx_spi.c
> >> @@ -167,6 +167,8 @@ static void imx_spi_flush_txfifo(IMXSPIState *s)
> >>       DPRINTF("Begin: TX Fifo Size = %d, RX Fifo Size = %d\n",
> >>               fifo32_num_used(&s->tx_fifo), fifo32_num_used(&s->rx_fifo));
> >>
> >> +    qemu_set_irq(s->cs_lines[imx_spi_selected_channel(s)], 0);
> >> +
> >>       while (!fifo32_is_empty(&s->tx_fifo)) {
> >>           int tx_burst = 0;
> >>
> >> @@ -385,13 +387,6 @@ static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value,
> >>       case ECSPI_CONREG:
> >>           s->regs[ECSPI_CONREG] = value;
> >>
> >> -        burst = EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_BURST_LENGTH) + 1;
> >> -        if (burst % 8) {
> >> -            qemu_log_mask(LOG_UNIMP,
> >> -                          "[%s]%s: burst length %d not supported: rounding up to next multiple of 8\n",
> >> -                          TYPE_IMX_SPI, __func__, burst);
> >> -        }
> >
> > Why has this log message been removed ?
>
> What I wanted to do is:
>
> "Stop complaining if the burst length field is set to a value of 0,
>   since that is done by Linux for every transfer."
>
> What I did instead is to remove the message entirely.
>
> How about the rest of the patch ? Is it worth a resend with the message
> restored (except for burst size == 0), or is it not acceptable anyway ?

I did the easy bit of the code review because answering this
question is probably a multiple-hour job...this is still on my
todo list, but I'm hoping somebody who understands the MIX
SPI device gets to it first.

-- PMM
Guenter Roeck Sept. 4, 2021, 5:13 p.m. UTC | #4
On 9/2/21 12:29 PM, Peter Maydell wrote:
> On Thu, 2 Sept 2021 at 17:09, Guenter Roeck <linux@roeck-us.net> wrote:
>>
>> On 9/2/21 8:58 AM, Peter Maydell wrote:
>>> On Sun, 8 Aug 2021 at 02:34, Guenter Roeck <linux@roeck-us.net> wrote:
>>>>
>>>> The control register does not really have a means to deselect
>>>> all chip selects directly. As result, CS is effectively never
>>>> deselected, and connected flash chips fail to perform read
>>>> operations since they don't get the expected chip select signals
>>>> to reset their state machine.
>>>>
>>>> Normally and per controller documentation one would assume that
>>>> chip select should be set whenever a transfer starts (XCH is
>>>> set or the tx fifo is written into), and that it should be disabled
>>>> whenever a transfer is complete. However, that does not work in
>>>> practice: attempts to implement this approach resulted in failures,
>>>> presumably because a single transaction can be split into multiple
>>>> transfers.
>>>>
>>>> At the same time, there is no explicit signal from the host indicating
>>>> if chip select should be active or not. In the absence of such a direct
>>>> signal, use the burst length written into the control register to
>>>> determine if an access is ongoing or not. Disable all chip selects
>>>> if the burst length field in the configuration register is set to 0,
>>>> and (re-)enable chip select if a transfer is started. This is possible
>>>> because the Linux driver clears the burst length field whenever it
>>>> prepares the controller for the next transfer.
>>>> This solution  is less than perfect since it effectively only disables
>>>> chip select when initiating the next transfer, but it does work with
>>>> Linux and should otherwise do no harm.
>>>>
>>>> Stop complaining if the burst length field is set to a value of 0,
>>>> since that is done by Linux for every transfer.
>>>>
>>>> With this patch, a command line parameter such as "-drive
>>>> file=flash.sabre,format=raw,if=mtd" can be used to instantiate the
>>>> flash chip in the sabrelite emulation. Without this patch, the
>>>> flash instantiates, but it only reads zeroes.
>>>>
>>>> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
>>>> ---
>>>> I am not entirely happy with this solution, but it is the best I was
>>>> able to come up with. If anyone has a better idea, I'll be happy
>>>> to give it a try.
>>>>
>>>>    hw/ssi/imx_spi.c | 17 +++++++----------
>>>>    1 file changed, 7 insertions(+), 10 deletions(-)
>>>>
>>>> diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c
>>>> index 189423bb3a..7a093156bd 100644
>>>> --- a/hw/ssi/imx_spi.c
>>>> +++ b/hw/ssi/imx_spi.c
>>>> @@ -167,6 +167,8 @@ static void imx_spi_flush_txfifo(IMXSPIState *s)
>>>>        DPRINTF("Begin: TX Fifo Size = %d, RX Fifo Size = %d\n",
>>>>                fifo32_num_used(&s->tx_fifo), fifo32_num_used(&s->rx_fifo));
>>>>
>>>> +    qemu_set_irq(s->cs_lines[imx_spi_selected_channel(s)], 0);
>>>> +
>>>>        while (!fifo32_is_empty(&s->tx_fifo)) {
>>>>            int tx_burst = 0;
>>>>
>>>> @@ -385,13 +387,6 @@ static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value,
>>>>        case ECSPI_CONREG:
>>>>            s->regs[ECSPI_CONREG] = value;
>>>>
>>>> -        burst = EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_BURST_LENGTH) + 1;
>>>> -        if (burst % 8) {
>>>> -            qemu_log_mask(LOG_UNIMP,
>>>> -                          "[%s]%s: burst length %d not supported: rounding up to next multiple of 8\n",
>>>> -                          TYPE_IMX_SPI, __func__, burst);
>>>> -        }
>>>
>>> Why has this log message been removed ?
>>
>> What I wanted to do is:
>>
>> "Stop complaining if the burst length field is set to a value of 0,
>>    since that is done by Linux for every transfer."
>>
>> What I did instead is to remove the message entirely.
>>
>> How about the rest of the patch ? Is it worth a resend with the message
>> restored (except for burst size == 0), or is it not acceptable anyway ?
> 
> I did the easy bit of the code review because answering this
> question is probably a multiple-hour job...this is still on my
> todo list, but I'm hoping somebody who understands the MIX
> SPI device gets to it first.
> 

Makes sense. Of course, it would be even better if someone can explain
how this works on real hardware.

In this context, it would be useful to know if real SPI flash chips
reset their state to idle under some conditions which are not covered
by the current code in hw/block/m25p80.c. Maybe the real problem is
as simple as that code setting data_read_loop when it should not,
or that it doesn't reset that flag when it should (unless I am missing
something, the flag is currently only reset by disabling chip select).

Thanks,
Guenter
Bin Meng Sept. 4, 2021, 11:06 p.m. UTC | #5
On Sun, Sep 5, 2021 at 1:13 AM Guenter Roeck <linux@roeck-us.net> wrote:
>
> On 9/2/21 12:29 PM, Peter Maydell wrote:
> > On Thu, 2 Sept 2021 at 17:09, Guenter Roeck <linux@roeck-us.net> wrote:
> >>
> >> On 9/2/21 8:58 AM, Peter Maydell wrote:
> >>> On Sun, 8 Aug 2021 at 02:34, Guenter Roeck <linux@roeck-us.net> wrote:
> >>>>
> >>>> The control register does not really have a means to deselect
> >>>> all chip selects directly. As result, CS is effectively never
> >>>> deselected, and connected flash chips fail to perform read
> >>>> operations since they don't get the expected chip select signals
> >>>> to reset their state machine.
> >>>>
> >>>> Normally and per controller documentation one would assume that
> >>>> chip select should be set whenever a transfer starts (XCH is
> >>>> set or the tx fifo is written into), and that it should be disabled
> >>>> whenever a transfer is complete. However, that does not work in
> >>>> practice: attempts to implement this approach resulted in failures,
> >>>> presumably because a single transaction can be split into multiple
> >>>> transfers.
> >>>>
> >>>> At the same time, there is no explicit signal from the host indicating
> >>>> if chip select should be active or not. In the absence of such a direct
> >>>> signal, use the burst length written into the control register to
> >>>> determine if an access is ongoing or not. Disable all chip selects
> >>>> if the burst length field in the configuration register is set to 0,
> >>>> and (re-)enable chip select if a transfer is started. This is possible
> >>>> because the Linux driver clears the burst length field whenever it
> >>>> prepares the controller for the next transfer.
> >>>> This solution  is less than perfect since it effectively only disables
> >>>> chip select when initiating the next transfer, but it does work with
> >>>> Linux and should otherwise do no harm.
> >>>>
> >>>> Stop complaining if the burst length field is set to a value of 0,
> >>>> since that is done by Linux for every transfer.
> >>>>
> >>>> With this patch, a command line parameter such as "-drive
> >>>> file=flash.sabre,format=raw,if=mtd" can be used to instantiate the
> >>>> flash chip in the sabrelite emulation. Without this patch, the
> >>>> flash instantiates, but it only reads zeroes.
> >>>>
> >>>> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
> >>>> ---
> >>>> I am not entirely happy with this solution, but it is the best I was
> >>>> able to come up with. If anyone has a better idea, I'll be happy
> >>>> to give it a try.
> >>>>
> >>>>    hw/ssi/imx_spi.c | 17 +++++++----------
> >>>>    1 file changed, 7 insertions(+), 10 deletions(-)
> >>>>
> >>>> diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c
> >>>> index 189423bb3a..7a093156bd 100644
> >>>> --- a/hw/ssi/imx_spi.c
> >>>> +++ b/hw/ssi/imx_spi.c
> >>>> @@ -167,6 +167,8 @@ static void imx_spi_flush_txfifo(IMXSPIState *s)
> >>>>        DPRINTF("Begin: TX Fifo Size = %d, RX Fifo Size = %d\n",
> >>>>                fifo32_num_used(&s->tx_fifo), fifo32_num_used(&s->rx_fifo));
> >>>>
> >>>> +    qemu_set_irq(s->cs_lines[imx_spi_selected_channel(s)], 0);
> >>>> +
> >>>>        while (!fifo32_is_empty(&s->tx_fifo)) {
> >>>>            int tx_burst = 0;
> >>>>
> >>>> @@ -385,13 +387,6 @@ static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value,
> >>>>        case ECSPI_CONREG:
> >>>>            s->regs[ECSPI_CONREG] = value;
> >>>>
> >>>> -        burst = EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_BURST_LENGTH) + 1;
> >>>> -        if (burst % 8) {
> >>>> -            qemu_log_mask(LOG_UNIMP,
> >>>> -                          "[%s]%s: burst length %d not supported: rounding up to next multiple of 8\n",
> >>>> -                          TYPE_IMX_SPI, __func__, burst);
> >>>> -        }
> >>>
> >>> Why has this log message been removed ?
> >>
> >> What I wanted to do is:
> >>
> >> "Stop complaining if the burst length field is set to a value of 0,
> >>    since that is done by Linux for every transfer."
> >>
> >> What I did instead is to remove the message entirely.
> >>
> >> How about the rest of the patch ? Is it worth a resend with the message
> >> restored (except for burst size == 0), or is it not acceptable anyway ?
> >
> > I did the easy bit of the code review because answering this
> > question is probably a multiple-hour job...this is still on my
> > todo list, but I'm hoping somebody who understands the MIX
> > SPI device gets to it first.
> >
>
> Makes sense. Of course, it would be even better if someone can explain
> how this works on real hardware.
>

I happened to notice this patch today. Better to cc people who once
worked on this part from "git blame" or "git log".

> In this context, it would be useful to know if real SPI flash chips
> reset their state to idle under some conditions which are not covered
> by the current code in hw/block/m25p80.c. Maybe the real problem is
> as simple as that code setting data_read_loop when it should not,
> or that it doesn't reset that flag when it should (unless I am missing
> something, the flag is currently only reset by disabling chip select).
>

One quick question, did you test this on the latest QEMU? Is that
Linux used for testing? There have been a number of bug fixes in
imx_spi recently.

Regards,
Bin
Philippe Mathieu-Daudé Sept. 4, 2021, 11:19 p.m. UTC | #6
On 9/5/21 1:06 AM, Bin Meng wrote:
> On Sun, Sep 5, 2021 at 1:13 AM Guenter Roeck <linux@roeck-us.net> wrote:
>>
>> On 9/2/21 12:29 PM, Peter Maydell wrote:
>>> On Thu, 2 Sept 2021 at 17:09, Guenter Roeck <linux@roeck-us.net> wrote:
>>>>
>>>> On 9/2/21 8:58 AM, Peter Maydell wrote:
>>>>> On Sun, 8 Aug 2021 at 02:34, Guenter Roeck <linux@roeck-us.net> wrote:
>>>>>>
>>>>>> The control register does not really have a means to deselect
>>>>>> all chip selects directly. As result, CS is effectively never
>>>>>> deselected, and connected flash chips fail to perform read
>>>>>> operations since they don't get the expected chip select signals
>>>>>> to reset their state machine.
>>>>>>
>>>>>> Normally and per controller documentation one would assume that
>>>>>> chip select should be set whenever a transfer starts (XCH is
>>>>>> set or the tx fifo is written into), and that it should be disabled
>>>>>> whenever a transfer is complete. However, that does not work in
>>>>>> practice: attempts to implement this approach resulted in failures,
>>>>>> presumably because a single transaction can be split into multiple
>>>>>> transfers.
>>>>>>
>>>>>> At the same time, there is no explicit signal from the host indicating
>>>>>> if chip select should be active or not. In the absence of such a direct
>>>>>> signal, use the burst length written into the control register to
>>>>>> determine if an access is ongoing or not. Disable all chip selects
>>>>>> if the burst length field in the configuration register is set to 0,
>>>>>> and (re-)enable chip select if a transfer is started. This is possible
>>>>>> because the Linux driver clears the burst length field whenever it
>>>>>> prepares the controller for the next transfer.
>>>>>> This solution  is less than perfect since it effectively only disables
>>>>>> chip select when initiating the next transfer, but it does work with
>>>>>> Linux and should otherwise do no harm.
>>>>>>
>>>>>> Stop complaining if the burst length field is set to a value of 0,
>>>>>> since that is done by Linux for every transfer.
>>>>>>
>>>>>> With this patch, a command line parameter such as "-drive
>>>>>> file=flash.sabre,format=raw,if=mtd" can be used to instantiate the
>>>>>> flash chip in the sabrelite emulation. Without this patch, the
>>>>>> flash instantiates, but it only reads zeroes.
>>>>>>
>>>>>> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
>>>>>> ---
>>>>>> I am not entirely happy with this solution, but it is the best I was
>>>>>> able to come up with. If anyone has a better idea, I'll be happy
>>>>>> to give it a try.
>>>>>>
>>>>>>    hw/ssi/imx_spi.c | 17 +++++++----------
>>>>>>    1 file changed, 7 insertions(+), 10 deletions(-)
>>>>>>
>>>>>> diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c
>>>>>> index 189423bb3a..7a093156bd 100644
>>>>>> --- a/hw/ssi/imx_spi.c
>>>>>> +++ b/hw/ssi/imx_spi.c
>>>>>> @@ -167,6 +167,8 @@ static void imx_spi_flush_txfifo(IMXSPIState *s)
>>>>>>        DPRINTF("Begin: TX Fifo Size = %d, RX Fifo Size = %d\n",
>>>>>>                fifo32_num_used(&s->tx_fifo), fifo32_num_used(&s->rx_fifo));
>>>>>>
>>>>>> +    qemu_set_irq(s->cs_lines[imx_spi_selected_channel(s)], 0);
>>>>>> +
>>>>>>        while (!fifo32_is_empty(&s->tx_fifo)) {
>>>>>>            int tx_burst = 0;
>>>>>>
>>>>>> @@ -385,13 +387,6 @@ static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value,
>>>>>>        case ECSPI_CONREG:
>>>>>>            s->regs[ECSPI_CONREG] = value;
>>>>>>
>>>>>> -        burst = EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_BURST_LENGTH) + 1;
>>>>>> -        if (burst % 8) {
>>>>>> -            qemu_log_mask(LOG_UNIMP,
>>>>>> -                          "[%s]%s: burst length %d not supported: rounding up to next multiple of 8\n",
>>>>>> -                          TYPE_IMX_SPI, __func__, burst);
>>>>>> -        }
>>>>>
>>>>> Why has this log message been removed ?
>>>>
>>>> What I wanted to do is:
>>>>
>>>> "Stop complaining if the burst length field is set to a value of 0,
>>>>    since that is done by Linux for every transfer."
>>>>
>>>> What I did instead is to remove the message entirely.
>>>>
>>>> How about the rest of the patch ? Is it worth a resend with the message
>>>> restored (except for burst size == 0), or is it not acceptable anyway ?
>>>
>>> I did the easy bit of the code review because answering this
>>> question is probably a multiple-hour job...this is still on my
>>> todo list, but I'm hoping somebody who understands the MIX
>>> SPI device gets to it first.
>>>
>>
>> Makes sense. Of course, it would be even better if someone can explain
>> how this works on real hardware.
>>
> 
> I happened to notice this patch today. Better to cc people who once
> worked on this part from "git blame" or "git log".

Even better if you add yourself as designated reviewer ;)

$ ./scripts/get_maintainer.pl -f hw/ssi/imx_spi.c
Alistair Francis <alistair@alistair23.me> (maintainer:SSI)
Peter Maydell <peter.maydell@linaro.org> (odd fixer:i.MX31 (kzm))
Jean-Christophe Dubois <jcd@tribudubois.net> (reviewer:SABRELITE / i.MX6)

> 
>> In this context, it would be useful to know if real SPI flash chips
>> reset their state to idle under some conditions which are not covered
>> by the current code in hw/block/m25p80.c. Maybe the real problem is
>> as simple as that code setting data_read_loop when it should not,
>> or that it doesn't reset that flag when it should (unless I am missing
>> something, the flag is currently only reset by disabling chip select).

Plausible hypothesis.

> One quick question, did you test this on the latest QEMU? Is that
> Linux used for testing? There have been a number of bug fixes in
> imx_spi recently.

Coming from Guenter I'm almost sure the answer is "yes" to both questions.

I suppose you meant these changes?

$ git log --oneline 1da79ecc7a2..8c495d13792
8c495d13792 hw/ssi: imx_spi: Correct tx and rx fifo endianness
6ed924823c8 hw/ssi: imx_spi: Correct the burst length > 32 bit transfer
logic
24bf8ef3f53 hw/ssi: imx_spi: Round up the burst length to be multiple of 8
50dc25932eb hw/ssi: imx_spi: Disable chip selects when controller is
disabled
fb116b5456c hw/ssi: imx_spi: Rework imx_spi_write() to handle block disabled
7c87bb5333f hw/ssi: imx_spi: Rework imx_spi_read() to handle block disabled
93722b6f6a6 hw/ssi: imx_spi: Rework imx_spi_reset() to keep CONREG
register value
9c431a43a62 hw/ssi: imx_spi: Remove pointless variable initialization
3c9829e5746 hw/ssi: imx_spi: Remove imx_spi_update_irq() in imx_spi_reset()

Regards,

Phil.
Guenter Roeck Sept. 5, 2021, 2:05 a.m. UTC | #7
On 9/4/21 4:06 PM, Bin Meng wrote:
> On Sun, Sep 5, 2021 at 1:13 AM Guenter Roeck <linux@roeck-us.net> wrote:
>>
>> On 9/2/21 12:29 PM, Peter Maydell wrote:
>>> On Thu, 2 Sept 2021 at 17:09, Guenter Roeck <linux@roeck-us.net> wrote:
>>>>
>>>> On 9/2/21 8:58 AM, Peter Maydell wrote:
>>>>> On Sun, 8 Aug 2021 at 02:34, Guenter Roeck <linux@roeck-us.net> wrote:
>>>>>>
>>>>>> The control register does not really have a means to deselect
>>>>>> all chip selects directly. As result, CS is effectively never
>>>>>> deselected, and connected flash chips fail to perform read
>>>>>> operations since they don't get the expected chip select signals
>>>>>> to reset their state machine.
>>>>>>
>>>>>> Normally and per controller documentation one would assume that
>>>>>> chip select should be set whenever a transfer starts (XCH is
>>>>>> set or the tx fifo is written into), and that it should be disabled
>>>>>> whenever a transfer is complete. However, that does not work in
>>>>>> practice: attempts to implement this approach resulted in failures,
>>>>>> presumably because a single transaction can be split into multiple
>>>>>> transfers.
>>>>>>
>>>>>> At the same time, there is no explicit signal from the host indicating
>>>>>> if chip select should be active or not. In the absence of such a direct
>>>>>> signal, use the burst length written into the control register to
>>>>>> determine if an access is ongoing or not. Disable all chip selects
>>>>>> if the burst length field in the configuration register is set to 0,
>>>>>> and (re-)enable chip select if a transfer is started. This is possible
>>>>>> because the Linux driver clears the burst length field whenever it
>>>>>> prepares the controller for the next transfer.
>>>>>> This solution  is less than perfect since it effectively only disables
>>>>>> chip select when initiating the next transfer, but it does work with
>>>>>> Linux and should otherwise do no harm.
>>>>>>
>>>>>> Stop complaining if the burst length field is set to a value of 0,
>>>>>> since that is done by Linux for every transfer.
>>>>>>
>>>>>> With this patch, a command line parameter such as "-drive
>>>>>> file=flash.sabre,format=raw,if=mtd" can be used to instantiate the
>>>>>> flash chip in the sabrelite emulation. Without this patch, the
>>>>>> flash instantiates, but it only reads zeroes.
>>>>>>
>>>>>> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
>>>>>> ---
>>>>>> I am not entirely happy with this solution, but it is the best I was
>>>>>> able to come up with. If anyone has a better idea, I'll be happy
>>>>>> to give it a try.
>>>>>>
>>>>>>     hw/ssi/imx_spi.c | 17 +++++++----------
>>>>>>     1 file changed, 7 insertions(+), 10 deletions(-)
>>>>>>
>>>>>> diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c
>>>>>> index 189423bb3a..7a093156bd 100644
>>>>>> --- a/hw/ssi/imx_spi.c
>>>>>> +++ b/hw/ssi/imx_spi.c
>>>>>> @@ -167,6 +167,8 @@ static void imx_spi_flush_txfifo(IMXSPIState *s)
>>>>>>         DPRINTF("Begin: TX Fifo Size = %d, RX Fifo Size = %d\n",
>>>>>>                 fifo32_num_used(&s->tx_fifo), fifo32_num_used(&s->rx_fifo));
>>>>>>
>>>>>> +    qemu_set_irq(s->cs_lines[imx_spi_selected_channel(s)], 0);
>>>>>> +
>>>>>>         while (!fifo32_is_empty(&s->tx_fifo)) {
>>>>>>             int tx_burst = 0;
>>>>>>
>>>>>> @@ -385,13 +387,6 @@ static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value,
>>>>>>         case ECSPI_CONREG:
>>>>>>             s->regs[ECSPI_CONREG] = value;
>>>>>>
>>>>>> -        burst = EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_BURST_LENGTH) + 1;
>>>>>> -        if (burst % 8) {
>>>>>> -            qemu_log_mask(LOG_UNIMP,
>>>>>> -                          "[%s]%s: burst length %d not supported: rounding up to next multiple of 8\n",
>>>>>> -                          TYPE_IMX_SPI, __func__, burst);
>>>>>> -        }
>>>>>
>>>>> Why has this log message been removed ?
>>>>
>>>> What I wanted to do is:
>>>>
>>>> "Stop complaining if the burst length field is set to a value of 0,
>>>>     since that is done by Linux for every transfer."
>>>>
>>>> What I did instead is to remove the message entirely.
>>>>
>>>> How about the rest of the patch ? Is it worth a resend with the message
>>>> restored (except for burst size == 0), or is it not acceptable anyway ?
>>>
>>> I did the easy bit of the code review because answering this
>>> question is probably a multiple-hour job...this is still on my
>>> todo list, but I'm hoping somebody who understands the MIX
>>> SPI device gets to it first.
>>>
>>
>> Makes sense. Of course, it would be even better if someone can explain
>> how this works on real hardware.
>>
> 
> I happened to notice this patch today. Better to cc people who once
> worked on this part from "git blame" or "git log".
> 

I copy people and mailing lists as provided by scripts/get_maintainer.pl.
I don't think it would be appropriate to copy additional people; anyone
interested in patches for a specific file should be listed in
MAINTAINERS. After all, that is what it is for.

>> In this context, it would be useful to know if real SPI flash chips
>> reset their state to idle under some conditions which are not covered
>> by the current code in hw/block/m25p80.c. Maybe the real problem is
>> as simple as that code setting data_read_loop when it should not,
>> or that it doesn't reset that flag when it should (unless I am missing
>> something, the flag is currently only reset by disabling chip select).
>>
> 
> One quick question, did you test this on the latest QEMU? Is that
> Linux used for testing? There have been a number of bug fixes in
> imx_spi recently.
> 

I implemented and tested this patch on top if qemu v6.0.0, and since then
there has been no patch applied to the affected file. The patch still works
on top of qemu v6.1.0.

Guenter
Guenter Roeck Sept. 5, 2021, 2:08 a.m. UTC | #8
On 9/4/21 4:19 PM, Philippe Mathieu-Daudé wrote:
> On 9/5/21 1:06 AM, Bin Meng wrote:
>> On Sun, Sep 5, 2021 at 1:13 AM Guenter Roeck <linux@roeck-us.net> wrote:
>>>
>>> On 9/2/21 12:29 PM, Peter Maydell wrote:
>>>> On Thu, 2 Sept 2021 at 17:09, Guenter Roeck <linux@roeck-us.net> wrote:
>>>>>
>>>>> On 9/2/21 8:58 AM, Peter Maydell wrote:
>>>>>> On Sun, 8 Aug 2021 at 02:34, Guenter Roeck <linux@roeck-us.net> wrote:
>>>>>>>
>>>>>>> The control register does not really have a means to deselect
>>>>>>> all chip selects directly. As result, CS is effectively never
>>>>>>> deselected, and connected flash chips fail to perform read
>>>>>>> operations since they don't get the expected chip select signals
>>>>>>> to reset their state machine.
>>>>>>>
>>>>>>> Normally and per controller documentation one would assume that
>>>>>>> chip select should be set whenever a transfer starts (XCH is
>>>>>>> set or the tx fifo is written into), and that it should be disabled
>>>>>>> whenever a transfer is complete. However, that does not work in
>>>>>>> practice: attempts to implement this approach resulted in failures,
>>>>>>> presumably because a single transaction can be split into multiple
>>>>>>> transfers.
>>>>>>>
>>>>>>> At the same time, there is no explicit signal from the host indicating
>>>>>>> if chip select should be active or not. In the absence of such a direct
>>>>>>> signal, use the burst length written into the control register to
>>>>>>> determine if an access is ongoing or not. Disable all chip selects
>>>>>>> if the burst length field in the configuration register is set to 0,
>>>>>>> and (re-)enable chip select if a transfer is started. This is possible
>>>>>>> because the Linux driver clears the burst length field whenever it
>>>>>>> prepares the controller for the next transfer.
>>>>>>> This solution  is less than perfect since it effectively only disables
>>>>>>> chip select when initiating the next transfer, but it does work with
>>>>>>> Linux and should otherwise do no harm.
>>>>>>>
>>>>>>> Stop complaining if the burst length field is set to a value of 0,
>>>>>>> since that is done by Linux for every transfer.
>>>>>>>
>>>>>>> With this patch, a command line parameter such as "-drive
>>>>>>> file=flash.sabre,format=raw,if=mtd" can be used to instantiate the
>>>>>>> flash chip in the sabrelite emulation. Without this patch, the
>>>>>>> flash instantiates, but it only reads zeroes.
>>>>>>>
>>>>>>> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
>>>>>>> ---
>>>>>>> I am not entirely happy with this solution, but it is the best I was
>>>>>>> able to come up with. If anyone has a better idea, I'll be happy
>>>>>>> to give it a try.
>>>>>>>
>>>>>>>     hw/ssi/imx_spi.c | 17 +++++++----------
>>>>>>>     1 file changed, 7 insertions(+), 10 deletions(-)
>>>>>>>
>>>>>>> diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c
>>>>>>> index 189423bb3a..7a093156bd 100644
>>>>>>> --- a/hw/ssi/imx_spi.c
>>>>>>> +++ b/hw/ssi/imx_spi.c
>>>>>>> @@ -167,6 +167,8 @@ static void imx_spi_flush_txfifo(IMXSPIState *s)
>>>>>>>         DPRINTF("Begin: TX Fifo Size = %d, RX Fifo Size = %d\n",
>>>>>>>                 fifo32_num_used(&s->tx_fifo), fifo32_num_used(&s->rx_fifo));
>>>>>>>
>>>>>>> +    qemu_set_irq(s->cs_lines[imx_spi_selected_channel(s)], 0);
>>>>>>> +
>>>>>>>         while (!fifo32_is_empty(&s->tx_fifo)) {
>>>>>>>             int tx_burst = 0;
>>>>>>>
>>>>>>> @@ -385,13 +387,6 @@ static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value,
>>>>>>>         case ECSPI_CONREG:
>>>>>>>             s->regs[ECSPI_CONREG] = value;
>>>>>>>
>>>>>>> -        burst = EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_BURST_LENGTH) + 1;
>>>>>>> -        if (burst % 8) {
>>>>>>> -            qemu_log_mask(LOG_UNIMP,
>>>>>>> -                          "[%s]%s: burst length %d not supported: rounding up to next multiple of 8\n",
>>>>>>> -                          TYPE_IMX_SPI, __func__, burst);
>>>>>>> -        }
>>>>>>
>>>>>> Why has this log message been removed ?
>>>>>
>>>>> What I wanted to do is:
>>>>>
>>>>> "Stop complaining if the burst length field is set to a value of 0,
>>>>>     since that is done by Linux for every transfer."
>>>>>
>>>>> What I did instead is to remove the message entirely.
>>>>>
>>>>> How about the rest of the patch ? Is it worth a resend with the message
>>>>> restored (except for burst size == 0), or is it not acceptable anyway ?
>>>>
>>>> I did the easy bit of the code review because answering this
>>>> question is probably a multiple-hour job...this is still on my
>>>> todo list, but I'm hoping somebody who understands the MIX
>>>> SPI device gets to it first.
>>>>
>>>
>>> Makes sense. Of course, it would be even better if someone can explain
>>> how this works on real hardware.
>>>
>>
>> I happened to notice this patch today. Better to cc people who once
>> worked on this part from "git blame" or "git log".
> 
> Even better if you add yourself as designated reviewer ;)
> 
> $ ./scripts/get_maintainer.pl -f hw/ssi/imx_spi.c
> Alistair Francis <alistair@alistair23.me> (maintainer:SSI)
> Peter Maydell <peter.maydell@linaro.org> (odd fixer:i.MX31 (kzm))
> Jean-Christophe Dubois <jcd@tribudubois.net> (reviewer:SABRELITE / i.MX6)
> 
>>
>>> In this context, it would be useful to know if real SPI flash chips
>>> reset their state to idle under some conditions which are not covered
>>> by the current code in hw/block/m25p80.c. Maybe the real problem is
>>> as simple as that code setting data_read_loop when it should not,
>>> or that it doesn't reset that flag when it should (unless I am missing
>>> something, the flag is currently only reset by disabling chip select).
> 
> Plausible hypothesis.
> 

Possibly. Note that I did check the flash chip specification, but I don't
see a notable difference to the qemu implementation. But then, again,
I may be missing something.

Guenter
Bin Meng Sept. 8, 2021, 6:29 a.m. UTC | #9
On Sun, Sep 5, 2021 at 10:08 AM Guenter Roeck <linux@roeck-us.net> wrote:
>
> On 9/4/21 4:19 PM, Philippe Mathieu-Daudé wrote:
> > On 9/5/21 1:06 AM, Bin Meng wrote:
> >> On Sun, Sep 5, 2021 at 1:13 AM Guenter Roeck <linux@roeck-us.net> wrote:
> >>>
> >>> On 9/2/21 12:29 PM, Peter Maydell wrote:
> >>>> On Thu, 2 Sept 2021 at 17:09, Guenter Roeck <linux@roeck-us.net> wrote:
> >>>>>
> >>>>> On 9/2/21 8:58 AM, Peter Maydell wrote:
> >>>>>> On Sun, 8 Aug 2021 at 02:34, Guenter Roeck <linux@roeck-us.net> wrote:
> >>>>>>>
> >>>>>>> The control register does not really have a means to deselect
> >>>>>>> all chip selects directly. As result, CS is effectively never
> >>>>>>> deselected, and connected flash chips fail to perform read
> >>>>>>> operations since they don't get the expected chip select signals
> >>>>>>> to reset their state machine.
> >>>>>>>
> >>>>>>> Normally and per controller documentation one would assume that
> >>>>>>> chip select should be set whenever a transfer starts (XCH is
> >>>>>>> set or the tx fifo is written into), and that it should be disabled
> >>>>>>> whenever a transfer is complete. However, that does not work in
> >>>>>>> practice: attempts to implement this approach resulted in failures,
> >>>>>>> presumably because a single transaction can be split into multiple
> >>>>>>> transfers.
> >>>>>>>
> >>>>>>> At the same time, there is no explicit signal from the host indicating
> >>>>>>> if chip select should be active or not. In the absence of such a direct
> >>>>>>> signal, use the burst length written into the control register to
> >>>>>>> determine if an access is ongoing or not. Disable all chip selects
> >>>>>>> if the burst length field in the configuration register is set to 0,
> >>>>>>> and (re-)enable chip select if a transfer is started. This is possible
> >>>>>>> because the Linux driver clears the burst length field whenever it
> >>>>>>> prepares the controller for the next transfer.
> >>>>>>> This solution  is less than perfect since it effectively only disables
> >>>>>>> chip select when initiating the next transfer, but it does work with
> >>>>>>> Linux and should otherwise do no harm.
> >>>>>>>
> >>>>>>> Stop complaining if the burst length field is set to a value of 0,
> >>>>>>> since that is done by Linux for every transfer.
> >>>>>>>
> >>>>>>> With this patch, a command line parameter such as "-drive
> >>>>>>> file=flash.sabre,format=raw,if=mtd" can be used to instantiate the
> >>>>>>> flash chip in the sabrelite emulation. Without this patch, the
> >>>>>>> flash instantiates, but it only reads zeroes.
> >>>>>>>
> >>>>>>> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
> >>>>>>> ---
> >>>>>>> I am not entirely happy with this solution, but it is the best I was
> >>>>>>> able to come up with. If anyone has a better idea, I'll be happy
> >>>>>>> to give it a try.
> >>>>>>>
> >>>>>>>     hw/ssi/imx_spi.c | 17 +++++++----------
> >>>>>>>     1 file changed, 7 insertions(+), 10 deletions(-)
> >>>>>>>
> >>>>>>> diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c
> >>>>>>> index 189423bb3a..7a093156bd 100644
> >>>>>>> --- a/hw/ssi/imx_spi.c
> >>>>>>> +++ b/hw/ssi/imx_spi.c
> >>>>>>> @@ -167,6 +167,8 @@ static void imx_spi_flush_txfifo(IMXSPIState *s)
> >>>>>>>         DPRINTF("Begin: TX Fifo Size = %d, RX Fifo Size = %d\n",
> >>>>>>>                 fifo32_num_used(&s->tx_fifo), fifo32_num_used(&s->rx_fifo));
> >>>>>>>
> >>>>>>> +    qemu_set_irq(s->cs_lines[imx_spi_selected_channel(s)], 0);
> >>>>>>> +
> >>>>>>>         while (!fifo32_is_empty(&s->tx_fifo)) {
> >>>>>>>             int tx_burst = 0;
> >>>>>>>
> >>>>>>> @@ -385,13 +387,6 @@ static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value,
> >>>>>>>         case ECSPI_CONREG:
> >>>>>>>             s->regs[ECSPI_CONREG] = value;
> >>>>>>>
> >>>>>>> -        burst = EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_BURST_LENGTH) + 1;
> >>>>>>> -        if (burst % 8) {
> >>>>>>> -            qemu_log_mask(LOG_UNIMP,
> >>>>>>> -                          "[%s]%s: burst length %d not supported: rounding up to next multiple of 8\n",
> >>>>>>> -                          TYPE_IMX_SPI, __func__, burst);
> >>>>>>> -        }
> >>>>>>
> >>>>>> Why has this log message been removed ?
> >>>>>
> >>>>> What I wanted to do is:
> >>>>>
> >>>>> "Stop complaining if the burst length field is set to a value of 0,
> >>>>>     since that is done by Linux for every transfer."
> >>>>>
> >>>>> What I did instead is to remove the message entirely.
> >>>>>
> >>>>> How about the rest of the patch ? Is it worth a resend with the message
> >>>>> restored (except for burst size == 0), or is it not acceptable anyway ?
> >>>>
> >>>> I did the easy bit of the code review because answering this
> >>>> question is probably a multiple-hour job...this is still on my
> >>>> todo list, but I'm hoping somebody who understands the MIX
> >>>> SPI device gets to it first.
> >>>>
> >>>
> >>> Makes sense. Of course, it would be even better if someone can explain
> >>> how this works on real hardware.
> >>>
> >>
> >> I happened to notice this patch today. Better to cc people who once
> >> worked on this part from "git blame" or "git log".
> >
> > Even better if you add yourself as designated reviewer ;)
> >
> > $ ./scripts/get_maintainer.pl -f hw/ssi/imx_spi.c
> > Alistair Francis <alistair@alistair23.me> (maintainer:SSI)
> > Peter Maydell <peter.maydell@linaro.org> (odd fixer:i.MX31 (kzm))
> > Jean-Christophe Dubois <jcd@tribudubois.net> (reviewer:SABRELITE / i.MX6)
> >
> >>
> >>> In this context, it would be useful to know if real SPI flash chips
> >>> reset their state to idle under some conditions which are not covered
> >>> by the current code in hw/block/m25p80.c. Maybe the real problem is
> >>> as simple as that code setting data_read_loop when it should not,
> >>> or that it doesn't reset that flag when it should (unless I am missing
> >>> something, the flag is currently only reset by disabling chip select).
> >
> > Plausible hypothesis.
> >
>
> Possibly. Note that I did check the flash chip specification, but I don't
> see a notable difference to the qemu implementation. But then, again,
> I may be missing something.
>

+Xuzhou Cheng who once worked on imx_spi for some comments

Regards,
Bin
Bin Meng Sept. 8, 2021, 6:31 a.m. UTC | #10
On Wed, Sep 8, 2021 at 2:29 PM Bin Meng <bmeng.cn@gmail.com> wrote:
>
> On Sun, Sep 5, 2021 at 10:08 AM Guenter Roeck <linux@roeck-us.net> wrote:
> >
> > On 9/4/21 4:19 PM, Philippe Mathieu-Daudé wrote:
> > > On 9/5/21 1:06 AM, Bin Meng wrote:
> > >> On Sun, Sep 5, 2021 at 1:13 AM Guenter Roeck <linux@roeck-us.net> wrote:
> > >>>
> > >>> On 9/2/21 12:29 PM, Peter Maydell wrote:
> > >>>> On Thu, 2 Sept 2021 at 17:09, Guenter Roeck <linux@roeck-us.net> wrote:
> > >>>>>
> > >>>>> On 9/2/21 8:58 AM, Peter Maydell wrote:
> > >>>>>> On Sun, 8 Aug 2021 at 02:34, Guenter Roeck <linux@roeck-us.net> wrote:
> > >>>>>>>
> > >>>>>>> The control register does not really have a means to deselect
> > >>>>>>> all chip selects directly. As result, CS is effectively never
> > >>>>>>> deselected, and connected flash chips fail to perform read
> > >>>>>>> operations since they don't get the expected chip select signals
> > >>>>>>> to reset their state machine.
> > >>>>>>>
> > >>>>>>> Normally and per controller documentation one would assume that
> > >>>>>>> chip select should be set whenever a transfer starts (XCH is
> > >>>>>>> set or the tx fifo is written into), and that it should be disabled
> > >>>>>>> whenever a transfer is complete. However, that does not work in
> > >>>>>>> practice: attempts to implement this approach resulted in failures,
> > >>>>>>> presumably because a single transaction can be split into multiple
> > >>>>>>> transfers.
> > >>>>>>>
> > >>>>>>> At the same time, there is no explicit signal from the host indicating
> > >>>>>>> if chip select should be active or not. In the absence of such a direct
> > >>>>>>> signal, use the burst length written into the control register to
> > >>>>>>> determine if an access is ongoing or not. Disable all chip selects
> > >>>>>>> if the burst length field in the configuration register is set to 0,
> > >>>>>>> and (re-)enable chip select if a transfer is started. This is possible
> > >>>>>>> because the Linux driver clears the burst length field whenever it
> > >>>>>>> prepares the controller for the next transfer.
> > >>>>>>> This solution  is less than perfect since it effectively only disables
> > >>>>>>> chip select when initiating the next transfer, but it does work with
> > >>>>>>> Linux and should otherwise do no harm.
> > >>>>>>>
> > >>>>>>> Stop complaining if the burst length field is set to a value of 0,
> > >>>>>>> since that is done by Linux for every transfer.
> > >>>>>>>
> > >>>>>>> With this patch, a command line parameter such as "-drive
> > >>>>>>> file=flash.sabre,format=raw,if=mtd" can be used to instantiate the
> > >>>>>>> flash chip in the sabrelite emulation. Without this patch, the
> > >>>>>>> flash instantiates, but it only reads zeroes.
> > >>>>>>>
> > >>>>>>> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
> > >>>>>>> ---
> > >>>>>>> I am not entirely happy with this solution, but it is the best I was
> > >>>>>>> able to come up with. If anyone has a better idea, I'll be happy
> > >>>>>>> to give it a try.
> > >>>>>>>
> > >>>>>>>     hw/ssi/imx_spi.c | 17 +++++++----------
> > >>>>>>>     1 file changed, 7 insertions(+), 10 deletions(-)
> > >>>>>>>
> > >>>>>>> diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c
> > >>>>>>> index 189423bb3a..7a093156bd 100644
> > >>>>>>> --- a/hw/ssi/imx_spi.c
> > >>>>>>> +++ b/hw/ssi/imx_spi.c
> > >>>>>>> @@ -167,6 +167,8 @@ static void imx_spi_flush_txfifo(IMXSPIState *s)
> > >>>>>>>         DPRINTF("Begin: TX Fifo Size = %d, RX Fifo Size = %d\n",
> > >>>>>>>                 fifo32_num_used(&s->tx_fifo), fifo32_num_used(&s->rx_fifo));
> > >>>>>>>
> > >>>>>>> +    qemu_set_irq(s->cs_lines[imx_spi_selected_channel(s)], 0);
> > >>>>>>> +
> > >>>>>>>         while (!fifo32_is_empty(&s->tx_fifo)) {
> > >>>>>>>             int tx_burst = 0;
> > >>>>>>>
> > >>>>>>> @@ -385,13 +387,6 @@ static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value,
> > >>>>>>>         case ECSPI_CONREG:
> > >>>>>>>             s->regs[ECSPI_CONREG] = value;
> > >>>>>>>
> > >>>>>>> -        burst = EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_BURST_LENGTH) + 1;
> > >>>>>>> -        if (burst % 8) {
> > >>>>>>> -            qemu_log_mask(LOG_UNIMP,
> > >>>>>>> -                          "[%s]%s: burst length %d not supported: rounding up to next multiple of 8\n",
> > >>>>>>> -                          TYPE_IMX_SPI, __func__, burst);
> > >>>>>>> -        }
> > >>>>>>
> > >>>>>> Why has this log message been removed ?
> > >>>>>
> > >>>>> What I wanted to do is:
> > >>>>>
> > >>>>> "Stop complaining if the burst length field is set to a value of 0,
> > >>>>>     since that is done by Linux for every transfer."
> > >>>>>
> > >>>>> What I did instead is to remove the message entirely.
> > >>>>>
> > >>>>> How about the rest of the patch ? Is it worth a resend with the message
> > >>>>> restored (except for burst size == 0), or is it not acceptable anyway ?
> > >>>>
> > >>>> I did the easy bit of the code review because answering this
> > >>>> question is probably a multiple-hour job...this is still on my
> > >>>> todo list, but I'm hoping somebody who understands the MIX
> > >>>> SPI device gets to it first.
> > >>>>
> > >>>
> > >>> Makes sense. Of course, it would be even better if someone can explain
> > >>> how this works on real hardware.
> > >>>
> > >>
> > >> I happened to notice this patch today. Better to cc people who once
> > >> worked on this part from "git blame" or "git log".
> > >
> > > Even better if you add yourself as designated reviewer ;)
> > >
> > > $ ./scripts/get_maintainer.pl -f hw/ssi/imx_spi.c
> > > Alistair Francis <alistair@alistair23.me> (maintainer:SSI)
> > > Peter Maydell <peter.maydell@linaro.org> (odd fixer:i.MX31 (kzm))
> > > Jean-Christophe Dubois <jcd@tribudubois.net> (reviewer:SABRELITE / i.MX6)
> > >
> > >>
> > >>> In this context, it would be useful to know if real SPI flash chips
> > >>> reset their state to idle under some conditions which are not covered
> > >>> by the current code in hw/block/m25p80.c. Maybe the real problem is
> > >>> as simple as that code setting data_read_loop when it should not,
> > >>> or that it doesn't reset that flag when it should (unless I am missing
> > >>> something, the flag is currently only reset by disabling chip select).
> > >
> > > Plausible hypothesis.
> > >
> >
> > Possibly. Note that I did check the flash chip specification, but I don't
> > see a notable difference to the qemu implementation. But then, again,
> > I may be missing something.
> >
>
> +Xuzhou Cheng who once worked on imx_spi for some comments

Actually adding him this time :)
Cheng, Xuzhou Sept. 8, 2021, 9:05 a.m. UTC | #11
Thanks Bin added me into this loop.

Hi, Guenter

I am interested in your patch and the issue what you found. I want to reproduce your issue on Linux, but I failed, the spi-nor of sabrelite on Linux does not work.

Could you share your Linux kernel version? It would be great if you can share the detailed steps to reproduce.

My test record:
Linux version: https://github.com/torvalds/linux, the last commit is ac08b1c68d1b1ed3cebb218fc3ea2c07484eb07d.
Linux configuration: imx_v6_v7_defconfig.

QEMU command:
qemu-system-arm -nographic -M sabrelite -smp 4 -m 1G -serial null -serial /dev/pts/50 -kernel zImage -initrd rootfs.ext4 -append "root=/dev/ram rdinit=sbin/init" -dtb imx6q-sabrelite.dtb -net nic -net tap,ifname=tap_xcheng,script=no -drive file=flash.sabre,format=raw,if=mtd

Logs: there are same logs when I apply your patch or not apply. So I don't understand what this patch fixes, maybe I missed something? :(...

# cat /proc/mtd
dev:    size   erasesize  name
mtd0: 00200000 00001000 "spi0.0"
# ls /dev/mtd*
/dev/mtd0       /dev/mtd0ro     /dev/mtdblock0
# echo "01234567899876543210" > test
# dd if=test of=/dev/mtd0  /* flash.sabre is empty */
0+1 records in
0+1 records out
# dd if=/dev/mtd0 of=test_out
4096+0 records in
4096+0 records out
# cat test_out             /* test_out is empty */

Regards,
Xuzhou

-----Original Message-----
From: Bin Meng <bmeng.cn@gmail.com> 
Sent: 2021年9月8日 14:31
To: Guenter Roeck <linux@roeck-us.net>; Cheng, Xuzhou <Xuzhou.Cheng@windriver.com>
Cc: Philippe Mathieu-Daudé <f4bug@amsat.org>; Peter Maydell <peter.maydell@linaro.org>; Alistair Francis <alistair@alistair23.me>; QEMU Developers <qemu-devel@nongnu.org>; qemu-arm <qemu-arm@nongnu.org>; Jean-Christophe Dubois <jcd@tribudubois.net>
Subject: Re: [PATCH] hw/ssi: imx_spi: Improve chip select handling

[Please note: This e-mail is from an EXTERNAL e-mail address]

On Wed, Sep 8, 2021 at 2:29 PM Bin Meng <bmeng.cn@gmail.com> wrote:
>
> On Sun, Sep 5, 2021 at 10:08 AM Guenter Roeck <linux@roeck-us.net> wrote:
> >
> > On 9/4/21 4:19 PM, Philippe Mathieu-Daudé wrote:
> > > On 9/5/21 1:06 AM, Bin Meng wrote:
> > >> On Sun, Sep 5, 2021 at 1:13 AM Guenter Roeck <linux@roeck-us.net> wrote:
> > >>>
> > >>> On 9/2/21 12:29 PM, Peter Maydell wrote:
> > >>>> On Thu, 2 Sept 2021 at 17:09, Guenter Roeck <linux@roeck-us.net> wrote:
> > >>>>>
> > >>>>> On 9/2/21 8:58 AM, Peter Maydell wrote:
> > >>>>>> On Sun, 8 Aug 2021 at 02:34, Guenter Roeck <linux@roeck-us.net> wrote:
> > >>>>>>>
> > >>>>>>> The control register does not really have a means to 
> > >>>>>>> deselect all chip selects directly. As result, CS is 
> > >>>>>>> effectively never deselected, and connected flash chips fail 
> > >>>>>>> to perform read operations since they don't get the expected 
> > >>>>>>> chip select signals to reset their state machine.
> > >>>>>>>
> > >>>>>>> Normally and per controller documentation one would assume 
> > >>>>>>> that chip select should be set whenever a transfer starts 
> > >>>>>>> (XCH is set or the tx fifo is written into), and that it 
> > >>>>>>> should be disabled whenever a transfer is complete. However, 
> > >>>>>>> that does not work in
> > >>>>>>> practice: attempts to implement this approach resulted in 
> > >>>>>>> failures, presumably because a single transaction can be 
> > >>>>>>> split into multiple transfers.
> > >>>>>>>
> > >>>>>>> At the same time, there is no explicit signal from the host 
> > >>>>>>> indicating if chip select should be active or not. In the 
> > >>>>>>> absence of such a direct signal, use the burst length 
> > >>>>>>> written into the control register to determine if an access 
> > >>>>>>> is ongoing or not. Disable all chip selects if the burst 
> > >>>>>>> length field in the configuration register is set to 0, and 
> > >>>>>>> (re-)enable chip select if a transfer is started. This is 
> > >>>>>>> possible because the Linux driver clears the burst length field whenever it prepares the controller for the next transfer.
> > >>>>>>> This solution  is less than perfect since it effectively 
> > >>>>>>> only disables chip select when initiating the next transfer, 
> > >>>>>>> but it does work with Linux and should otherwise do no harm.
> > >>>>>>>
> > >>>>>>> Stop complaining if the burst length field is set to a value 
> > >>>>>>> of 0, since that is done by Linux for every transfer.
> > >>>>>>>
> > >>>>>>> With this patch, a command line parameter such as "-drive 
> > >>>>>>> file=flash.sabre,format=raw,if=mtd" can be used to 
> > >>>>>>> instantiate the flash chip in the sabrelite emulation. 
> > >>>>>>> Without this patch, the flash instantiates, but it only reads zeroes.
> > >>>>>>>
> > >>>>>>> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
> > >>>>>>> ---
> > >>>>>>> I am not entirely happy with this solution, but it is the 
> > >>>>>>> best I was able to come up with. If anyone has a better 
> > >>>>>>> idea, I'll be happy to give it a try.
> > >>>>>>>
> > >>>>>>>     hw/ssi/imx_spi.c | 17 +++++++----------
> > >>>>>>>     1 file changed, 7 insertions(+), 10 deletions(-)
> > >>>>>>>
> > >>>>>>> diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c index 
> > >>>>>>> 189423bb3a..7a093156bd 100644
> > >>>>>>> --- a/hw/ssi/imx_spi.c
> > >>>>>>> +++ b/hw/ssi/imx_spi.c
> > >>>>>>> @@ -167,6 +167,8 @@ static void imx_spi_flush_txfifo(IMXSPIState *s)
> > >>>>>>>         DPRINTF("Begin: TX Fifo Size = %d, RX Fifo Size = %d\n",
> > >>>>>>>                 fifo32_num_used(&s->tx_fifo), 
> > >>>>>>> fifo32_num_used(&s->rx_fifo));
> > >>>>>>>
> > >>>>>>> +    qemu_set_irq(s->cs_lines[imx_spi_selected_channel(s)], 
> > >>>>>>> + 0);
> > >>>>>>> +
> > >>>>>>>         while (!fifo32_is_empty(&s->tx_fifo)) {
> > >>>>>>>             int tx_burst = 0;
> > >>>>>>>
> > >>>>>>> @@ -385,13 +387,6 @@ static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value,
> > >>>>>>>         case ECSPI_CONREG:
> > >>>>>>>             s->regs[ECSPI_CONREG] = value;
> > >>>>>>>
> > >>>>>>> -        burst = EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_BURST_LENGTH) + 1;
> > >>>>>>> -        if (burst % 8) {
> > >>>>>>> -            qemu_log_mask(LOG_UNIMP,
> > >>>>>>> -                          "[%s]%s: burst length %d not supported: rounding up to next multiple of 8\n",
> > >>>>>>> -                          TYPE_IMX_SPI, __func__, burst);
> > >>>>>>> -        }
> > >>>>>>
> > >>>>>> Why has this log message been removed ?
> > >>>>>
> > >>>>> What I wanted to do is:
> > >>>>>
> > >>>>> "Stop complaining if the burst length field is set to a value of 0,
> > >>>>>     since that is done by Linux for every transfer."
> > >>>>>
> > >>>>> What I did instead is to remove the message entirely.
> > >>>>>
> > >>>>> How about the rest of the patch ? Is it worth a resend with 
> > >>>>> the message restored (except for burst size == 0), or is it not acceptable anyway ?
> > >>>>
> > >>>> I did the easy bit of the code review because answering this 
> > >>>> question is probably a multiple-hour job...this is still on my 
> > >>>> todo list, but I'm hoping somebody who understands the MIX SPI 
> > >>>> device gets to it first.
> > >>>>
> > >>>
> > >>> Makes sense. Of course, it would be even better if someone can 
> > >>> explain how this works on real hardware.
> > >>>
> > >>
> > >> I happened to notice this patch today. Better to cc people who 
> > >> once worked on this part from "git blame" or "git log".
> > >
> > > Even better if you add yourself as designated reviewer ;)
> > >
> > > $ ./scripts/get_maintainer.pl -f hw/ssi/imx_spi.c Alistair Francis 
> > > <alistair@alistair23.me> (maintainer:SSI) Peter Maydell 
> > > <peter.maydell@linaro.org> (odd fixer:i.MX31 (kzm)) 
> > > Jean-Christophe Dubois <jcd@tribudubois.net> (reviewer:SABRELITE / 
> > > i.MX6)
> > >
> > >>
> > >>> In this context, it would be useful to know if real SPI flash 
> > >>> chips reset their state to idle under some conditions which are 
> > >>> not covered by the current code in hw/block/m25p80.c. Maybe the 
> > >>> real problem is as simple as that code setting data_read_loop 
> > >>> when it should not, or that it doesn't reset that flag when it 
> > >>> should (unless I am missing something, the flag is currently only reset by disabling chip select).
> > >
> > > Plausible hypothesis.
> > >
> >
> > Possibly. Note that I did check the flash chip specification, but I 
> > don't see a notable difference to the qemu implementation. But then, 
> > again, I may be missing something.
> >
>
> +Xuzhou Cheng who once worked on imx_spi for some comments

Actually adding him this time :)
Guenter Roeck Sept. 8, 2021, 4:52 p.m. UTC | #12
On 9/8/21 2:05 AM, Cheng, Xuzhou wrote:
> Thanks Bin added me into this loop.
> 
> Hi, Guenter
> 
> I am interested in your patch and the issue what you found. I want to reproduce your issue on Linux, but I failed, the spi-nor of sabrelite on Linux does not work.
> 
> Could you share your Linux kernel version? It would be great if you can share the detailed steps to reproduce.
> 
> My test record:
> Linux version: https://github.com/torvalds/linux, the last commit is ac08b1c68d1b1ed3cebb218fc3ea2c07484eb07d.
> Linux configuration: imx_v6_v7_defconfig.
> 
> QEMU command:
> qemu-system-arm -nographic -M sabrelite -smp 4 -m 1G -serial null -serial /dev/pts/50 -kernel zImage -initrd rootfs.ext4 -append "root=/dev/ram rdinit=sbin/init" -dtb imx6q-sabrelite.dtb -net nic -net tap,ifname=tap_xcheng,script=no -drive file=flash.sabre,format=raw,if=mtd
> 
> Logs: there are same logs when I apply your patch or not apply. So I don't understand what this patch fixes, maybe I missed something? :(...
> 
> # cat /proc/mtd
> dev:    size   erasesize  name
> mtd0: 00200000 00001000 "spi0.0"
> # ls /dev/mtd*
> /dev/mtd0       /dev/mtd0ro     /dev/mtdblock0
> # echo "01234567899876543210" > test
> # dd if=test of=/dev/mtd0  /* flash.sabre is empty */
> 0+1 records in
> 0+1 records out
> # dd if=/dev/mtd0 of=test_out
> 4096+0 records in
> 4096+0 records out
> # cat test_out             /* test_out is empty */
> 

It is a flash. I don't think dd erases the flash, so unless your flash.sabre
is all-ones you probably won't see the overwritten data.

Guenter
Cheng, Xuzhou Sept. 16, 2021, 10:21 a.m. UTC | #13
> diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c
> index 189423bb3a..7a093156bd 100644
> --- a/hw/ssi/imx_spi.c
> +++ b/hw/ssi/imx_spi.c
> @@ -167,6 +167,8 @@  static void imx_spi_flush_txfifo(IMXSPIState *s)
>      DPRINTF("Begin: TX Fifo Size = %d, RX Fifo Size = %d\n",
>              fifo32_num_used(&s->tx_fifo), fifo32_num_used(&s->rx_fifo));
>  
> +    qemu_set_irq(s->cs_lines[imx_spi_selected_channel(s)], 0);
> +
>      while (!fifo32_is_empty(&s->tx_fifo)) {
>          int tx_burst = 0;
>  
> @@ -385,13 +387,6 @@  static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value,
>      case ECSPI_CONREG:
>          s->regs[ECSPI_CONREG] = value;
>  
> -        burst = EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_BURST_LENGTH) + 1;
> -        if (burst % 8) {
> -            qemu_log_mask(LOG_UNIMP,
> -                          "[%s]%s: burst length %d not supported: rounding up to next multiple of 8\n",
> -                          TYPE_IMX_SPI, __func__, burst);
> -        }
> -
>          if (!imx_spi_is_enabled(s)) {
>              /* device is disabled, so this is a soft reset */
>              imx_spi_soft_reset(s);
> @@ -404,9 +399,11 @@  static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value,
>  
>              /* We are in master mode */
>  
> -            for (i = 0; i < ECSPI_NUM_CS; i++) {
> -                qemu_set_irq(s->cs_lines[i],
> -                             i == imx_spi_selected_channel(s) ? 0 : 1);
> +            burst = EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_BURST_LENGTH);
> +            if (burst == 0) {
> +                for (i = 0; i < ECSPI_NUM_CS; i++) {
> +                    qemu_set_irq(s->cs_lines[i], 1);
> +                }
>              }

I got some free time in the past days to investigate this issue. Guenter is right, the Linux imx-spi driver does not work on QEMU.

The reason is that the state of m25p80 machine loops in STATE_READING_DATA state after receiving RDSR command, the new command is ignored. Before sending a new command, the CS line should be pulled to high, this make the state of m25p80 back to IDLE.

I have same point with Guenter, it's that set CS to 1 when burst is zero. But i don't think it is necessary to set CS to 0 in imx_spi_flush_txfifo(). I will send a new patch to fix this issue.

BTW, the Linux driver uses DMA mode when transfer length is greater than the FIFO size, But QEMU imx-spi model doesn't support DMA now.
Guenter Roeck Sept. 16, 2021, 2:21 p.m. UTC | #14
On Thu, Sep 16, 2021 at 10:21:16AM +0000, Cheng, Xuzhou wrote:
> > diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c
> > index 189423bb3a..7a093156bd 100644
> > --- a/hw/ssi/imx_spi.c
> > +++ b/hw/ssi/imx_spi.c
> > @@ -167,6 +167,8 @@  static void imx_spi_flush_txfifo(IMXSPIState *s)
> >      DPRINTF("Begin: TX Fifo Size = %d, RX Fifo Size = %d\n",
> >              fifo32_num_used(&s->tx_fifo), fifo32_num_used(&s->rx_fifo));
> >  
> > +    qemu_set_irq(s->cs_lines[imx_spi_selected_channel(s)], 0);
> > +
> >      while (!fifo32_is_empty(&s->tx_fifo)) {
> >          int tx_burst = 0;
> >  
> > @@ -385,13 +387,6 @@  static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value,
> >      case ECSPI_CONREG:
> >          s->regs[ECSPI_CONREG] = value;
> >  
> > -        burst = EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_BURST_LENGTH) + 1;
> > -        if (burst % 8) {
> > -            qemu_log_mask(LOG_UNIMP,
> > -                          "[%s]%s: burst length %d not supported: rounding up to next multiple of 8\n",
> > -                          TYPE_IMX_SPI, __func__, burst);
> > -        }
> > -
> >          if (!imx_spi_is_enabled(s)) {
> >              /* device is disabled, so this is a soft reset */
> >              imx_spi_soft_reset(s);
> > @@ -404,9 +399,11 @@  static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value,
> >  
> >              /* We are in master mode */
> >  
> > -            for (i = 0; i < ECSPI_NUM_CS; i++) {
> > -                qemu_set_irq(s->cs_lines[i],
> > -                             i == imx_spi_selected_channel(s) ? 0 : 1);
> > +            burst = EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_BURST_LENGTH);
> > +            if (burst == 0) {
> > +                for (i = 0; i < ECSPI_NUM_CS; i++) {
> > +                    qemu_set_irq(s->cs_lines[i], 1);
> > +                }
> >              }
> 
> I got some free time in the past days to investigate this issue. Guenter is right, the Linux imx-spi driver does not work on QEMU.
> 
> The reason is that the state of m25p80 machine loops in STATE_READING_DATA state after receiving RDSR command, the new command is ignored. Before sending a new command, the CS line should be pulled to high, this make the state of m25p80 back to IDLE.
> 
> I have same point with Guenter, it's that set CS to 1 when burst is zero. But i don't think it is necessary to set CS to 0 in imx_spi_flush_txfifo(). I will send a new patch to fix this issue.
> 

Thanks a lot for looking into this. If you have a better solution than mine, by
all means, please go for it. As I mentioned in my patch, I didn't really like
it, but I was unable to find a better solution.

> BTW, the Linux driver uses DMA mode when transfer length is greater than the FIFO size, But QEMU imx-spi model doesn't support DMA now.

Does it have practical impact ? Obviously my tests were somewhat limited (I was
happy to get Linux booting from flash), but I don't recall seeing a problem.

Thanks,
Guenter
Cheng, Xuzhou Sept. 18, 2021, 3:09 a.m. UTC | #15
> > I got some free time in the past days to investigate this issue. Guenter is right, the Linux imx-spi driver does not work on QEMU.
> >
> > The reason is that the state of m25p80 machine loops in STATE_READING_DATA state after receiving RDSR command, the new command is ignored. Before sending a new command, the CS line should be pulled to high, this make the state of m25p80 back to IDLE.
> >
> > I have same point with Guenter, it's that set CS to 1 when burst is zero. But i don't think it is necessary to set CS to 0 in imx_spi_flush_txfifo(). I will send a new patch to fix this issue.
> >
> 
> Thanks a lot for looking into this. If you have a better solution than mine, by all means, please go for it. As I mentioned in my patch, I didn't really like it, but I was unable to find a better solution.
I am doing some experiment to verify that the new patch is reasonable, so the new patch will be delayed few days.

> 
> > BTW, the Linux driver uses DMA mode when transfer length is greater than the FIFO size, But QEMU imx-spi model doesn't support DMA now.
> 
> Does it have practical impact ? Obviously my tests were somewhat limited (I was happy to get Linux booting from flash), but I don't recall seeing a problem.
There seem have no practical impact. :)
Guenter Roeck Sept. 18, 2021, 4:19 a.m. UTC | #16
On 9/17/21 8:09 PM, Cheng, Xuzhou wrote:
>>> I got some free time in the past days to investigate this issue. Guenter is right, the Linux imx-spi driver does not work on QEMU.
>>>
>>> The reason is that the state of m25p80 machine loops in STATE_READING_DATA state after receiving RDSR command, the new command is ignored. Before sending a new command, the CS line should be pulled to high, this make the state of m25p80 back to IDLE.
>>>
>>> I have same point with Guenter, it's that set CS to 1 when burst is zero. But i don't think it is necessary to set CS to 0 in imx_spi_flush_txfifo(). I will send a new patch to fix this issue.
>>>
>>
>> Thanks a lot for looking into this. If you have a better solution than mine, by all means, please go for it. As I mentioned in my patch, I didn't really like it, but I was unable to find a better solution.
> I am doing some experiment to verify that the new patch is reasonable, so the new patch will be delayed few days.
> 

No problem. Note that I'll be traveling for the next 2-3 weeks, and I won't be able
to test any patches during that time.

Guenter
Bin Meng Sept. 26, 2021, 2:49 a.m. UTC | #17
On Sat, Sep 18, 2021 at 12:19 PM Guenter Roeck <linux@roeck-us.net> wrote:
>
> On 9/17/21 8:09 PM, Cheng, Xuzhou wrote:
> >>> I got some free time in the past days to investigate this issue. Guenter is right, the Linux imx-spi driver does not work on QEMU.
> >>>
> >>> The reason is that the state of m25p80 machine loops in STATE_READING_DATA state after receiving RDSR command, the new command is ignored. Before sending a new command, the CS line should be pulled to high, this make the state of m25p80 back to IDLE.
> >>>
> >>> I have same point with Guenter, it's that set CS to 1 when burst is zero. But i don't think it is necessary to set CS to 0 in imx_spi_flush_txfifo(). I will send a new patch to fix this issue.
> >>>
> >>
> >> Thanks a lot for looking into this. If you have a better solution than mine, by all means, please go for it. As I mentioned in my patch, I didn't really like it, but I was unable to find a better solution.
> > I am doing some experiment to verify that the new patch is reasonable, so the new patch will be delayed few days.
> >
>
> No problem. Note that I'll be traveling for the next 2-3 weeks, and I won't be able
> to test any patches during that time.
>

I have some updates to share, as I have been working with Xuzhou
internally on this issue for the past days:

Current mods using BURST_LEN to determine the timing to pull up the CS
line in the SPI controller codes is a workaround. Hardware does not do
this. To understand what real hardware behavior is, Xuzhou used an
oscilloscope to verify our guess.

It turns out the root cause is elsewhere, and a proper fix will be
sent out soon.

Regards,
Bin
Guenter Roeck Oct. 1, 2021, 1:04 p.m. UTC | #18
On Sun, Sep 26, 2021 at 10:49:53AM +0800, Bin Meng wrote:
> On Sat, Sep 18, 2021 at 12:19 PM Guenter Roeck <linux@roeck-us.net> wrote:
> >
> > On 9/17/21 8:09 PM, Cheng, Xuzhou wrote:
> > >>> I got some free time in the past days to investigate this issue. Guenter is right, the Linux imx-spi driver does not work on QEMU.
> > >>>
> > >>> The reason is that the state of m25p80 machine loops in STATE_READING_DATA state after receiving RDSR command, the new command is ignored. Before sending a new command, the CS line should be pulled to high, this make the state of m25p80 back to IDLE.
> > >>>
> > >>> I have same point with Guenter, it's that set CS to 1 when burst is zero. But i don't think it is necessary to set CS to 0 in imx_spi_flush_txfifo(). I will send a new patch to fix this issue.
> > >>>
> > >>
> > >> Thanks a lot for looking into this. If you have a better solution than mine, by all means, please go for it. As I mentioned in my patch, I didn't really like it, but I was unable to find a better solution.
> > > I am doing some experiment to verify that the new patch is reasonable, so the new patch will be delayed few days.
> > >
> >
> > No problem. Note that I'll be traveling for the next 2-3 weeks, and I won't be able
> > to test any patches during that time.
> >
> 
> I have some updates to share, as I have been working with Xuzhou
> internally on this issue for the past days:
> 
> Current mods using BURST_LEN to determine the timing to pull up the CS
> line in the SPI controller codes is a workaround. Hardware does not do
> this. To understand what real hardware behavior is, Xuzhou used an
> oscilloscope to verify our guess.
> 
> It turns out the root cause is elsewhere, and a proper fix will be
> sent out soon.
> 

Thanks a lot for tracking this down!

Guenter
diff mbox series

Patch

diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c
index 189423bb3a..7a093156bd 100644
--- a/hw/ssi/imx_spi.c
+++ b/hw/ssi/imx_spi.c
@@ -167,6 +167,8 @@  static void imx_spi_flush_txfifo(IMXSPIState *s)
     DPRINTF("Begin: TX Fifo Size = %d, RX Fifo Size = %d\n",
             fifo32_num_used(&s->tx_fifo), fifo32_num_used(&s->rx_fifo));
 
+    qemu_set_irq(s->cs_lines[imx_spi_selected_channel(s)], 0);
+
     while (!fifo32_is_empty(&s->tx_fifo)) {
         int tx_burst = 0;
 
@@ -385,13 +387,6 @@  static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value,
     case ECSPI_CONREG:
         s->regs[ECSPI_CONREG] = value;
 
-        burst = EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_BURST_LENGTH) + 1;
-        if (burst % 8) {
-            qemu_log_mask(LOG_UNIMP,
-                          "[%s]%s: burst length %d not supported: rounding up to next multiple of 8\n",
-                          TYPE_IMX_SPI, __func__, burst);
-        }
-
         if (!imx_spi_is_enabled(s)) {
             /* device is disabled, so this is a soft reset */
             imx_spi_soft_reset(s);
@@ -404,9 +399,11 @@  static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value,
 
             /* We are in master mode */
 
-            for (i = 0; i < ECSPI_NUM_CS; i++) {
-                qemu_set_irq(s->cs_lines[i],
-                             i == imx_spi_selected_channel(s) ? 0 : 1);
+            burst = EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_BURST_LENGTH);
+            if (burst == 0) {
+                for (i = 0; i < ECSPI_NUM_CS; i++) {
+                    qemu_set_irq(s->cs_lines[i], 1);
+                }
             }
 
             if ((value & change_mask & ECSPI_CONREG_SMC) &&