diff mbox series

[v3,3/3] asm-generic/io.h: Silence -Wnull-pointer-arithmetic warning on PCI_IOBASE

Message ID 20210421111759.2059976-4-schnelle@linux.ibm.com
State New
Headers show
Series asm-generic/io.h: Silence -Wnull-pointer-arithmetic warning on PCI_IOBASE | expand

Commit Message

Niklas Schnelle April 21, 2021, 11:17 a.m. UTC
When PCI_IOBASE is not defined, it is set to 0 such that it is ignored
in calls to the readX/writeX primitives. This triggers clang's
-Wnull-pointer-arithmetic warning and will result in illegal accesses on
platforms that do not support I/O ports if drivers do still attempt to
access them.

Make things explicit and silence the warning by letting inb() and
friends fail with WARN_ONCE() and a 0xff... return in case PCI_IOBASE is
not defined.

Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
---
v2 -> v3:
- Added ifdefs to ioport_map() and __pci_ioport_map() since apparently at least
  test configs enable CONFIG_HAS_IOPORT_MAP even on architectures which leave
  PCI_IOBASE unset (kernel test robot for nds32 and ARC).
v1 -> v2:
- Instead of working around the warning with a uintptr_t PCI_IOBASE make inb()
  and friends explicitly WARN_ONCE() and return 0xff... (Arnd)
 include/asm-generic/io.h | 64 +++++++++++++++++++++++++++++++++++++---
 1 file changed, 60 insertions(+), 4 deletions(-)

Comments

David Laight April 21, 2021, 11:24 a.m. UTC | #1
From: Niklas Schnelle
> Sent: 21 April 2021 12:18
> 
> When PCI_IOBASE is not defined, it is set to 0 such that it is ignored
> in calls to the readX/writeX primitives. This triggers clang's
> -Wnull-pointer-arithmetic warning and will result in illegal accesses on
> platforms that do not support I/O ports if drivers do still attempt to
> access them.
> 
> Make things explicit and silence the warning by letting inb() and
> friends fail with WARN_ONCE() and a 0xff... return in case PCI_IOBASE is
> not defined.
...
> 
> diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
> index c6af40ce03be..aabb0a8186ee 100644
> --- a/include/asm-generic/io.h
> +++ b/include/asm-generic/io.h
...
> @@ -458,12 +454,17 @@ static inline void writesq(volatile void __iomem *addr, const void *buffer,
>  #define _inb _inb
>  static inline u8 _inb(unsigned long addr)
>  {
> +#ifdef PCI_IOBASE
>  	u8 val;
> 
>  	__io_pbr();
>  	val = __raw_readb(PCI_IOBASE + addr);
>  	__io_par(val);
>  	return val;
> +#else
> +	WARN_ONCE(1, "No I/O port support\n");
> +	return ~0;
> +#endif
>  }
>  #endif

I suspect that this might be better not inlined
when PCI_IOBASE is undefined.

Otherwise you get quite a lot of bloat from all the
WARN_ONCE() calls.

	David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)
Niklas Schnelle April 21, 2021, 11:50 a.m. UTC | #2
On Wed, 2021-04-21 at 11:24 +0000, David Laight wrote:
> From: Niklas Schnelle
> > Sent: 21 April 2021 12:18
> > 
> > When PCI_IOBASE is not defined, it is set to 0 such that it is ignored
> > in calls to the readX/writeX primitives. This triggers clang's
> > -Wnull-pointer-arithmetic warning and will result in illegal accesses on
> > platforms that do not support I/O ports if drivers do still attempt to
> > access them.
> > 
> > Make things explicit and silence the warning by letting inb() and
> > friends fail with WARN_ONCE() and a 0xff... return in case PCI_IOBASE is
> > not defined.
> ...
> > diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
> > index c6af40ce03be..aabb0a8186ee 100644
> > --- a/include/asm-generic/io.h
> > +++ b/include/asm-generic/io.h
> ...
> > @@ -458,12 +454,17 @@ static inline void writesq(volatile void __iomem *addr, const void *buffer,
> >  #define _inb _inb
> >  static inline u8 _inb(unsigned long addr)
> >  {
> > +#ifdef PCI_IOBASE
> >  	u8 val;
> > 
> >  	__io_pbr();
> >  	val = __raw_readb(PCI_IOBASE + addr);
> >  	__io_par(val);
> >  	return val;
> > +#else
> > +	WARN_ONCE(1, "No I/O port support\n");
> > +	return ~0;
> > +#endif
> >  }
> >  #endif
> 
> I suspect that this might be better not inlined
> when PCI_IOBASE is undefined.
> 
> Otherwise you get quite a lot of bloat from all the
> WARN_ONCE() calls.
> 
> 	David

Hmm, I was wondering if we should rather have a large ifdef block of
all these functions stubbed to WARN_ONCE rather than in each function.
As I understand it this would be necessary if we want the inline gone.
They would still be static though so we still get a copy per
compilation unit that uses it or am I misunderstanding?

> 
> -
> Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
> Registration No: 1397386 (Wales)
>
Arnd Bergmann April 21, 2021, 11:57 a.m. UTC | #3
On Wed, Apr 21, 2021 at 1:50 PM Niklas Schnelle <schnelle@linux.ibm.com> wrote:
> On Wed, 2021-04-21 at 11:24 +0000, David Laight wrote:
> >
> > I suspect that this might be better not inlined
> > when PCI_IOBASE is undefined.
> >
> > Otherwise you get quite a lot of bloat from all the
> > WARN_ONCE() calls.
>
> Hmm, I was wondering if we should rather have a large ifdef block of
> all these functions stubbed to WARN_ONCE rather than in each function.
> As I understand it this would be necessary if we want the inline gone.
> They would still be static though so we still get a copy per
> compilation unit that uses it or am I misunderstanding?

I wouldn't worry too much about the size of known broken drivers during
compile testing. Also, since the functions are marked 'inline' and not
'__always_inline', the compiler is free to decide not to inline them if
the contents are excessively big, and since the strings are all identical,
they should be constant-folded.

If you want to make this a little smaller, using pr_warn_once()
would be a little smaller, but also give less information.

      Arnd
diff mbox series

Patch

diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
index c6af40ce03be..aabb0a8186ee 100644
--- a/include/asm-generic/io.h
+++ b/include/asm-generic/io.h
@@ -440,10 +440,6 @@  static inline void writesq(volatile void __iomem *addr, const void *buffer,
 #endif
 #endif /* CONFIG_64BIT */
 
-#ifndef PCI_IOBASE
-#define PCI_IOBASE ((void __iomem *)0)
-#endif
-
 #ifndef IO_SPACE_LIMIT
 #define IO_SPACE_LIMIT 0xffff
 #endif
@@ -458,12 +454,17 @@  static inline void writesq(volatile void __iomem *addr, const void *buffer,
 #define _inb _inb
 static inline u8 _inb(unsigned long addr)
 {
+#ifdef PCI_IOBASE
 	u8 val;
 
 	__io_pbr();
 	val = __raw_readb(PCI_IOBASE + addr);
 	__io_par(val);
 	return val;
+#else
+	WARN_ONCE(1, "No I/O port support\n");
+	return ~0;
+#endif
 }
 #endif
 
@@ -471,12 +472,17 @@  static inline u8 _inb(unsigned long addr)
 #define _inw _inw
 static inline u16 _inw(unsigned long addr)
 {
+#ifdef PCI_IOBASE
 	u16 val;
 
 	__io_pbr();
 	val = __le16_to_cpu((__le16 __force)__raw_readw(PCI_IOBASE + addr));
 	__io_par(val);
 	return val;
+#else
+	WARN_ONCE(1, "No I/O port support\n");
+	return ~0;
+#endif
 }
 #endif
 
@@ -484,12 +490,17 @@  static inline u16 _inw(unsigned long addr)
 #define _inl _inl
 static inline u32 _inl(unsigned long addr)
 {
+#ifdef PCI_IOBASE
 	u32 val;
 
 	__io_pbr();
 	val = __le32_to_cpu((__le32 __force)__raw_readl(PCI_IOBASE + addr));
 	__io_par(val);
 	return val;
+#else
+	WARN_ONCE(1, "No I/O port support\n");
+	return ~0;
+#endif
 }
 #endif
 
@@ -497,9 +508,13 @@  static inline u32 _inl(unsigned long addr)
 #define _outb _outb
 static inline void _outb(u8 value, unsigned long addr)
 {
+#ifdef PCI_IOBASE
 	__io_pbw();
 	__raw_writeb(value, PCI_IOBASE + addr);
 	__io_paw();
+#else
+	WARN_ONCE(1, "No I/O port support\n");
+#endif
 }
 #endif
 
@@ -507,9 +522,13 @@  static inline void _outb(u8 value, unsigned long addr)
 #define _outw _outw
 static inline void _outw(u16 value, unsigned long addr)
 {
+#ifdef PCI_IOBASE
 	__io_pbw();
 	__raw_writew((u16 __force)cpu_to_le16(value), PCI_IOBASE + addr);
 	__io_paw();
+#else
+	WARN_ONCE(1, "No I/O port support\n");
+#endif
 }
 #endif
 
@@ -517,9 +536,13 @@  static inline void _outw(u16 value, unsigned long addr)
 #define _outl _outl
 static inline void _outl(u32 value, unsigned long addr)
 {
+#ifdef PCI_IOBASE
 	__io_pbw();
 	__raw_writel((u32 __force)cpu_to_le32(value), PCI_IOBASE + addr);
 	__io_paw();
+#else
+	WARN_ONCE(1, "No I/O port support\n");
+#endif
 }
 #endif
 
@@ -606,7 +629,11 @@  static inline void outl_p(u32 value, unsigned long addr)
 #define insb insb
 static inline void insb(unsigned long addr, void *buffer, unsigned int count)
 {
+#ifdef PCI_IOBASE
 	readsb(PCI_IOBASE + addr, buffer, count);
+#else
+	WARN_ONCE(1, "No I/O port support\n");
+#endif
 }
 #endif
 
@@ -614,7 +641,11 @@  static inline void insb(unsigned long addr, void *buffer, unsigned int count)
 #define insw insw
 static inline void insw(unsigned long addr, void *buffer, unsigned int count)
 {
+#ifdef PCI_IOBASE
 	readsw(PCI_IOBASE + addr, buffer, count);
+#else
+	WARN_ONCE(1, "No I/O port support\n");
+#endif
 }
 #endif
 
@@ -622,7 +653,11 @@  static inline void insw(unsigned long addr, void *buffer, unsigned int count)
 #define insl insl
 static inline void insl(unsigned long addr, void *buffer, unsigned int count)
 {
+#ifdef PCI_IOBASE
 	readsl(PCI_IOBASE + addr, buffer, count);
+#else
+	WARN_ONCE(1, "No I/O port support\n");
+#endif
 }
 #endif
 
@@ -631,7 +666,11 @@  static inline void insl(unsigned long addr, void *buffer, unsigned int count)
 static inline void outsb(unsigned long addr, const void *buffer,
 			 unsigned int count)
 {
+#ifdef PCI_IOBASE
 	writesb(PCI_IOBASE + addr, buffer, count);
+#else
+	WARN_ONCE(1, "No I/O port support\n");
+#endif
 }
 #endif
 
@@ -640,7 +679,11 @@  static inline void outsb(unsigned long addr, const void *buffer,
 static inline void outsw(unsigned long addr, const void *buffer,
 			 unsigned int count)
 {
+#ifdef PCI_IOBASE
 	writesw(PCI_IOBASE + addr, buffer, count);
+#else
+	WARN_ONCE(1, "No I/O port support\n");
+#endif
 }
 #endif
 
@@ -649,7 +692,11 @@  static inline void outsw(unsigned long addr, const void *buffer,
 static inline void outsl(unsigned long addr, const void *buffer,
 			 unsigned int count)
 {
+#ifdef PCI_IOBASE
 	writesl(PCI_IOBASE + addr, buffer, count);
+#else
+	WARN_ONCE(1, "No I/O port support\n");
+#endif
 }
 #endif
 
@@ -1001,18 +1048,27 @@  static inline void __iomem *ioremap_uc(phys_addr_t offset, size_t size)
 #define ioport_map ioport_map
 static inline void __iomem *ioport_map(unsigned long port, unsigned int nr)
 {
+#ifdef PCI_IOBASE
 	port &= IO_SPACE_LIMIT;
 	return (port > MMIO_UPPER_LIMIT) ? NULL : PCI_IOBASE + port;
+#else
+	WARN_ONCE(1, "No I/O port support\n");
+	return NULL;
+#endif
 }
 #define __pci_ioport_unmap __pci_ioport_unmap
 static inline void __pci_ioport_unmap(void __iomem *p)
 {
+#ifdef PCI_IOBASE
 	uintptr_t start = (uintptr_t) PCI_IOBASE;
 	uintptr_t addr = (uintptr_t) p;
 
 	if (addr >= start && addr < start + IO_SPACE_LIMIT)
 		return;
 	iounmap(p);
+#else
+	WARN_ONCE(1, "No I/O port support\n");
+#endif
 }
 #endif