All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3] usb: dwc2: fix regression on big-endian PowerPC/ARM systems
@ 2016-05-12 20:56 Arnd Bergmann
  2016-05-13  6:32 ` John Youn
  0 siblings, 1 reply; 3+ messages in thread
From: Arnd Bergmann @ 2016-05-12 20:56 UTC (permalink / raw)
  To: Christian Lamparter, Benjamin Herrenschmidt, Felipe Balbi
  Cc: linux-mips, johnyoun, gregkh, linux-usb, linux-kernel, a.seppala,
	linuxppc-dev, Arnd Bergmann, Felipe Balbi, Douglas Anderson,
	Gregory Herrero, Mian Yousaf Kaukab, Marek Szyprowski

A patch that went into Linux-4.4 to fix big-endian mode on a Lantiq
MIPS system unfortunately broke big-endian operation on PowerPC
APM82181 as reported by Christian Lamparter, and likely other
systems.

It actually introduced multiple issues:

- it broke big-endian ARM kernels: any machine that was working
  correctly with a little-endian kernel is no longer using byteswaps
  on big-endian kernels, which clearly breaks them.
- On PowerPC the same thing must be true: if it was working before,
  using big-endian kernels is now broken. Unlike ARM, 32-bit PowerPC
  usually uses big-endian kernels, so they are likely all broken.
- The barrier for dwc2_writel is on the wrong side of the __raw_writel(),
  so the MMIO no longer synchronizes with DMA operations.
- On architectures that require specific CPU instructions for MMIO
  access, using the __raw_ variant may turn this into a pointer
  dereference that does not have the same effect as the readl/writel.

This patch is a simple revert for all architectures other than MIPS,
in the hope that we can more easily backport it to fix the regression
on PowerPC and ARM systems without breaking the Lantiq system again.

We should follow this up with a more elaborate change to add runtime
detection of endianess, to make sure it also works on all other
combinations of architectures and implementations of the usb-dwc2
device. That patch however will be fairly large and not appropriate
for backports to stable kernels.

Felipe suggested a different approach, using an endianess switching
register to always put the device into LE mode, but unfortunately
the dwc2 hardware does not provide a generic way to do that. Also,
I see no practical way of addressing the problem more generally by
patching architecture specific code on MIPS.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Fixes: 95c8bc360944 ("usb: dwc2: Use platform endianness when accessing registers")
---
v3: reverted the accidental changes that slipped into the patch,
    resending as requested by Christian.

 drivers/usb/dwc2/core.h | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index 3c58d633ce80..74ed2ee881cd 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -64,6 +64,18 @@
 	DWC2_TRACE_SCHEDULER_VB(pr_fmt("%s: SCH: " fmt),		\
 				dev_name(hsotg->dev), ##__VA_ARGS__)
 
+
+#ifdef CONFIG_MIPS
+/*
+ * There are some MIPS machines that can run in either big-endian
+ * or little-endian mode and that use the dwc2 register without
+ * a byteswap in both ways.
+ * Unlike other architectures, MIPS does not require a barrier
+ * before the __raw_writel() to synchronize with DMA but does
+ * require the barrier after the writel() to serialize a series
+ * of writes. This set of operations was added specifically for
+ * MIPS and should only be used there.
+ */
 static inline u32 dwc2_readl(const void __iomem *addr)
 {
 	u32 value = __raw_readl(addr);
@@ -90,6 +102,23 @@ static inline void dwc2_writel(u32 value, void __iomem *addr)
 	pr_info("INFO:: wrote %08x to %p\n", value, addr);
 #endif
 }
+#else
+/* Normal architectures just use readl/write */
+static inline u32 dwc2_readl(const void __iomem *addr)
+{
+	u32 value = readl(addr);
+	return value;
+}
+
+static inline void dwc2_writel(u32 value, void __iomem *addr)
+{
+	writel(value, addr);
+
+#ifdef dwc2_log_writes
+	pr_info("info:: wrote %08x to %p\n", value, addr);
+#endif
+}
+#endif
 
 /* Maximum number of Endpoints/HostChannels */
 #define MAX_EPS_CHANNELS	16
-- 
2.7.0

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

* Re: [PATCH v3] usb: dwc2: fix regression on big-endian PowerPC/ARM systems
  2016-05-12 20:56 [PATCH v3] usb: dwc2: fix regression on big-endian PowerPC/ARM systems Arnd Bergmann
@ 2016-05-13  6:32 ` John Youn
  2016-05-13 13:48   ` Arnd Bergmann
  0 siblings, 1 reply; 3+ messages in thread
From: John Youn @ 2016-05-13  6:32 UTC (permalink / raw)
  To: Arnd Bergmann, Christian Lamparter, Benjamin Herrenschmidt, Felipe Balbi
  Cc: linux-mips, John.Youn, gregkh, linux-usb, linux-kernel,
	a.seppala, linuxppc-dev, Felipe Balbi, Douglas Anderson,
	Gregory Herrero, Mian Yousaf Kaukab, Marek Szyprowski

On 5/12/2016 1:56 PM, Arnd Bergmann wrote:
> A patch that went into Linux-4.4 to fix big-endian mode on a Lantiq
> MIPS system unfortunately broke big-endian operation on PowerPC
> APM82181 as reported by Christian Lamparter, and likely other
> systems.
> 
> It actually introduced multiple issues:
> 
> - it broke big-endian ARM kernels: any machine that was working
>   correctly with a little-endian kernel is no longer using byteswaps
>   on big-endian kernels, which clearly breaks them.
> - On PowerPC the same thing must be true: if it was working before,
>   using big-endian kernels is now broken. Unlike ARM, 32-bit PowerPC
>   usually uses big-endian kernels, so they are likely all broken.
> - The barrier for dwc2_writel is on the wrong side of the __raw_writel(),
>   so the MMIO no longer synchronizes with DMA operations.
> - On architectures that require specific CPU instructions for MMIO
>   access, using the __raw_ variant may turn this into a pointer
>   dereference that does not have the same effect as the readl/writel.
> 
> This patch is a simple revert for all architectures other than MIPS,
> in the hope that we can more easily backport it to fix the regression
> on PowerPC and ARM systems without breaking the Lantiq system again.
> 
> We should follow this up with a more elaborate change to add runtime
> detection of endianess, to make sure it also works on all other
> combinations of architectures and implementations of the usb-dwc2
> device. That patch however will be fairly large and not appropriate
> for backports to stable kernels.
> 
> Felipe suggested a different approach, using an endianess switching
> register to always put the device into LE mode, but unfortunately
> the dwc2 hardware does not provide a generic way to do that. Also,
> I see no practical way of addressing the problem more generally by
> patching architecture specific code on MIPS.
> 
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> Fixes: 95c8bc360944 ("usb: dwc2: Use platform endianness when accessing registers")
> ---
> v3: reverted the accidental changes that slipped into the patch,
>     resending as requested by Christian.
> 
>  drivers/usb/dwc2/core.h | 29 +++++++++++++++++++++++++++++
>  1 file changed, 29 insertions(+)
> 
> diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
> index 3c58d633ce80..74ed2ee881cd 100644
> --- a/drivers/usb/dwc2/core.h
> +++ b/drivers/usb/dwc2/core.h
> @@ -64,6 +64,18 @@
>  	DWC2_TRACE_SCHEDULER_VB(pr_fmt("%s: SCH: " fmt),		\
>  				dev_name(hsotg->dev), ##__VA_ARGS__)
>  
> +
> +#ifdef CONFIG_MIPS
> +/*
> + * There are some MIPS machines that can run in either big-endian
> + * or little-endian mode and that use the dwc2 register without
> + * a byteswap in both ways.
> + * Unlike other architectures, MIPS does not require a barrier
> + * before the __raw_writel() to synchronize with DMA but does
> + * require the barrier after the writel() to serialize a series
> + * of writes. This set of operations was added specifically for
> + * MIPS and should only be used there.
> + */
>  static inline u32 dwc2_readl(const void __iomem *addr)
>  {
>  	u32 value = __raw_readl(addr);
> @@ -90,6 +102,23 @@ static inline void dwc2_writel(u32 value, void __iomem *addr)
>  	pr_info("INFO:: wrote %08x to %p\n", value, addr);
>  #endif
>  }
> +#else
> +/* Normal architectures just use readl/write */
> +static inline u32 dwc2_readl(const void __iomem *addr)
> +{
> +	u32 value = readl(addr);
> +	return value;
> +}
> +
> +static inline void dwc2_writel(u32 value, void __iomem *addr)
> +{
> +	writel(value, addr);
> +
> +#ifdef dwc2_log_writes

Hi Arnd,

The capitalization issue is still there in this patch.

There's also a few checkpatch issues.

And should the barrier be moved after the write like it says in the
comment? That seems to have been removed since earlier versions of
the patch.

Regards,
John

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

* Re: [PATCH v3] usb: dwc2: fix regression on big-endian PowerPC/ARM systems
  2016-05-13  6:32 ` John Youn
@ 2016-05-13 13:48   ` Arnd Bergmann
  0 siblings, 0 replies; 3+ messages in thread
From: Arnd Bergmann @ 2016-05-13 13:48 UTC (permalink / raw)
  To: John Youn
  Cc: Christian Lamparter, Benjamin Herrenschmidt, Felipe Balbi,
	linux-mips, gregkh, linux-usb, linux-kernel, a.seppala,
	linuxppc-dev, Felipe Balbi, Douglas Anderson, Gregory Herrero,
	Mian Yousaf Kaukab, Marek Szyprowski

On Thursday 12 May 2016 23:32:18 John Youn wrote:
> 
> Hi Arnd,
> 
> The capitalization issue is still there in this patch.
> 
> There's also a few checkpatch issues.

Fixed now, thanks. I'll send a v4 in a bit.

> And should the barrier be moved after the write like it says in the
> comment? That seems to have been removed since earlier versions of
> the patch.

I've clarified the comment, so we refer to the __raw_writel
not the writel. It's also possible that this was just another
bug in the patch that broke powerpc, but I don't know anything
about MIPS barrier semantics, so I prefer not to touch that.

	Arnd

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

end of thread, other threads:[~2016-05-13 13:48 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-05-12 20:56 [PATCH v3] usb: dwc2: fix regression on big-endian PowerPC/ARM systems Arnd Bergmann
2016-05-13  6:32 ` John Youn
2016-05-13 13:48   ` Arnd Bergmann

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.