diff mbox series

ASoC: fsi: Stop using __raw_*() I/O accessors

Message ID 20201119125318.4066097-1-geert+renesas@glider.be (mailing list archive)
State New, archived
Headers show
Series ASoC: fsi: Stop using __raw_*() I/O accessors | expand

Commit Message

Geert Uytterhoeven Nov. 19, 2020, 12:53 p.m. UTC
There is no reason to keep on using the __raw_{read,write}l() I/O
accessors in Renesas ARM or SuperH driver code.  Switch to using the
plain {read,write}l() I/O accessors, to have a chance that this works on
big-endian.

Suggested-by: Arnd Bergmann <arnd@kernel.org>
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
Assembler output difference on SuperH checked.
---
 sound/soc/sh/fsi.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

Comments

Arnd Bergmann Nov. 19, 2020, 3:54 p.m. UTC | #1
On Thu, Nov 19, 2020 at 1:53 PM Geert Uytterhoeven
<geert+renesas@glider.be> wrote:
>
> There is no reason to keep on using the __raw_{read,write}l() I/O
> accessors in Renesas ARM or SuperH driver code.  Switch to using the
> plain {read,write}l() I/O accessors, to have a chance that this works on
> big-endian.
>
> Suggested-by: Arnd Bergmann <arnd@kernel.org>
> Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>

I don't think this one is correct, as based on

static void fsi_pio_push16(struct fsi_priv *fsi, u8 *_buf, int samples)
{
        int i;

        if (fsi_is_enable_stream(fsi)) {
                /*
                 * stream mode
                 * see
                 *      fsi_pio_push_init()
                 */
                u32 *buf = (u32 *)_buf;

                for (i = 0; i < samples / 2; i++)
                        fsi_reg_write(fsi, DODT, buf[i]);
        } else {
                /* normal mode */
                u16 *buf = (u16 *)_buf;

                for (i = 0; i < samples; i++)
                        fsi_reg_write(fsi, DODT, ((u32)*(buf + i) << 8));
        }
}

the same helper is used for both accessing endianness-sensitive
register values (which need the converrsion in writel()) and
possibly in-memory byte streams that need the __raw_writel()
behavior of copying the input bytes in sequence rather than sets of
native-endian 16-bit or 32-bit samples.

> ---
> Assembler output difference on SuperH checked.

I'm also not sure whether changing this breaks big-endian SuperH,
which defines the accessors differently from Arm and most other
architectures.

Maybe better just mark the driver as 'depends on SH || !CPU_BIG_ENDIAN'
as it is clearly broken on big-endian Arm.

     Arnd
Geert Uytterhoeven Nov. 19, 2020, 4:13 p.m. UTC | #2
Hi Arnd,

On Thu, Nov 19, 2020 at 4:54 PM Arnd Bergmann <arnd@kernel.org> wrote:
> On Thu, Nov 19, 2020 at 1:53 PM Geert Uytterhoeven
> <geert+renesas@glider.be> wrote:
> > There is no reason to keep on using the __raw_{read,write}l() I/O
> > accessors in Renesas ARM or SuperH driver code.  Switch to using the
> > plain {read,write}l() I/O accessors, to have a chance that this works on
> > big-endian.
> >
> > Suggested-by: Arnd Bergmann <arnd@kernel.org>
> > Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
>
> I don't think this one is correct, as based on
>
> static void fsi_pio_push16(struct fsi_priv *fsi, u8 *_buf, int samples)
> {
>         int i;
>
>         if (fsi_is_enable_stream(fsi)) {
>                 /*
>                  * stream mode
>                  * see
>                  *      fsi_pio_push_init()
>                  */
>                 u32 *buf = (u32 *)_buf;
>
>                 for (i = 0; i < samples / 2; i++)
>                         fsi_reg_write(fsi, DODT, buf[i]);
>         } else {
>                 /* normal mode */
>                 u16 *buf = (u16 *)_buf;
>
>                 for (i = 0; i < samples; i++)
>                         fsi_reg_write(fsi, DODT, ((u32)*(buf + i) << 8));
>         }
> }
>
> the same helper is used for both accessing endianness-sensitive
> register values (which need the converrsion in writel()) and
> possibly in-memory byte streams that need the __raw_writel()
> behavior of copying the input bytes in sequence rather than sets of
> native-endian 16-bit or 32-bit samples.

Thanks, good catch!

> > ---
> > Assembler output difference on SuperH checked.
>
> I'm also not sure whether changing this breaks big-endian SuperH,
> which defines the accessors differently from Arm and most other
> architectures.

On SH, this driver is only used on SH7724 systems.
Compiling an ecovec24_defconfig kernel with CONFIG_CPU_BIG_ENDIAN=y
shows that the same code (native 32-bit access) is generated for
big-endian as for little-endian, which means that it indeed must be
broken for one of them. But this is not changed by my patch.

> Maybe better just mark the driver as 'depends on SH || !CPU_BIG_ENDIAN'
> as it is clearly broken on big-endian Arm.

"depends on !CPU_BIG_ENDIAN"?

Gr{oetje,eeting}s,

                        Geert
Arnd Bergmann Nov. 19, 2020, 4:22 p.m. UTC | #3
On Thu, Nov 19, 2020 at 5:13 PM Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> On Thu, Nov 19, 2020 at 4:54 PM Arnd Bergmann <arnd@kernel.org> wrote:
> > On Thu, Nov 19, 2020 at 1:53 PM Geert Uytterhoeven
> > <geert+renesas@glider.be> wrote:
> >
> > I'm also not sure whether changing this breaks big-endian SuperH,
> > which defines the accessors differently from Arm and most other
> > architectures.
>
> On SH, this driver is only used on SH7724 systems.
> Compiling an ecovec24_defconfig kernel with CONFIG_CPU_BIG_ENDIAN=y
> shows that the same code (native 32-bit access) is generated for
> big-endian as for little-endian, which means that it indeed must be
> broken for one of them. But this is not changed by my patch.

Not necessarily: I think superh is more like the old 'BE32' variant of Arm
big-endian, in that on-chip registers are accessed in CPU-endian byte order,
while access to external RAM is byte-swapped.

> > Maybe better just mark the driver as 'depends on SH || !CPU_BIG_ENDIAN'
> > as it is clearly broken on big-endian Arm.
>
> "depends on !CPU_BIG_ENDIAN"?

I think I'd just leave it as it is. Unless someone wants to try out this
board in both big-endian and little-endian configurations and also
listen to the audio output, it's impossible to know whether it is actually
broken. sound/soc/sh/dma-sh7760.c does have a comment from 2007
saying "// FIXME: little-endian only for now".

      Arnd
Geert Uytterhoeven Nov. 19, 2020, 5:20 p.m. UTC | #4
Hi Arnd,

On Thu, Nov 19, 2020 at 5:22 PM Arnd Bergmann <arnd@kernel.org> wrote:
> On Thu, Nov 19, 2020 at 5:13 PM Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> > On Thu, Nov 19, 2020 at 4:54 PM Arnd Bergmann <arnd@kernel.org> wrote:
> > > On Thu, Nov 19, 2020 at 1:53 PM Geert Uytterhoeven
> > > <geert+renesas@glider.be> wrote:
> > >
> > > I'm also not sure whether changing this breaks big-endian SuperH,
> > > which defines the accessors differently from Arm and most other
> > > architectures.
> >
> > On SH, this driver is only used on SH7724 systems.
> > Compiling an ecovec24_defconfig kernel with CONFIG_CPU_BIG_ENDIAN=y
> > shows that the same code (native 32-bit access) is generated for
> > big-endian as for little-endian, which means that it indeed must be
> > broken for one of them. But this is not changed by my patch.
>
> Not necessarily: I think superh is more like the old 'BE32' variant of Arm
> big-endian, in that on-chip registers are accessed in CPU-endian byte order,
> while access to external RAM is byte-swapped.

That's indeed quite likely: according to the SH7724 docs, the endianness
of "the system" is configured by an external pin at power-on reset time,
and cannot be changed dynamically.  Hence testing this would require a
big-endian boot loader, too.

> > > Maybe better just mark the driver as 'depends on SH || !CPU_BIG_ENDIAN'
> > > as it is clearly broken on big-endian Arm.
> >
> > "depends on !CPU_BIG_ENDIAN"?
>
> I think I'd just leave it as it is. Unless someone wants to try out this

OK.

> board in both big-endian and little-endian configurations and also
> listen to the audio output, it's impossible to know whether it is actually
> broken. sound/soc/sh/dma-sh7760.c does have a comment from 2007
> saying "// FIXME: little-endian only for now".

SH7760 does not use the FSI driver.
A few SH defconfig files have CONFIG_CPU_BIG_ENDIAN=y, but
the later SH4A parts all seem to be used in little-endian mode.

Gr{oetje,eeting}s,

                        Geert
Mark Brown Dec. 1, 2020, 1:57 p.m. UTC | #5
On Thu, 19 Nov 2020 13:53:18 +0100, Geert Uytterhoeven wrote:
> There is no reason to keep on using the __raw_{read,write}l() I/O
> accessors in Renesas ARM or SuperH driver code.  Switch to using the
> plain {read,write}l() I/O accessors, to have a chance that this works on
> big-endian.

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next

Thanks!

[1/1] ASoC: fsi: Stop using __raw_*() I/O accessors
      (no commit info)

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark
diff mbox series

Patch

diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 3c574792231bc5c3..518d4b0c4b8b99fa 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -313,12 +313,12 @@  static void __fsi_reg_write(u32 __iomem *reg, u32 data)
 	/* valid data area is 24bit */
 	data &= 0x00ffffff;
 
-	__raw_writel(data, reg);
+	writel(data, reg);
 }
 
 static u32 __fsi_reg_read(u32 __iomem *reg)
 {
-	return __raw_readl(reg);
+	return readl(reg);
 }
 
 static void __fsi_reg_mask_set(u32 __iomem *reg, u32 mask, u32 data)