Re: `io{re,un}map()` build error in s390 under `!CONFIG_HAS_IOMEM`

"Arnd Bergmann" <[email protected]> Tue, 04 Aug 2026 12:36:55 +0200
Newsgroups org.kernel.vger.rust-for-linux,dev.linux.lists.driver-core,org.kernel.vger.linux-arch,org.kernel.vger.linux-s390
Message-ID <[email protected]>
On Tue, Aug 4, 2026, at 09:13, Heiko Carstens wrote:
> On Mon, Aug 03, 2026 at 10:09:08PM +0200, Danilo Krummrich wrote:
>> On Mon Aug 3, 2026 at 9:56 PM CEST, Arnd Bergmann wrote:
>> > In theory you should be able to use rust code without PCI MMIO
>> > support, but I can't see any practical downsides to making rust
>> > 'depends on HAS_MMIO' to avoid having to add those #ifdef.
>> 
>> I think the implications should be minor without making Rust depend on
>> CONFIG_HAS_IOMEM.
>> 
>> I just sent out a fix [1]; the only annoying part is [2], but we should change
>> those doc-tests anyway. For the one in rust/kernel/io.rs we already did in
>> driver-core-next.
>> 
>> [1] https://lore.kernel.org/driver-core/[email protected]/

This looks like you still provide the rust version of ioremap(),
turning what is supposed to be a link failure into a runtime
error.

> I'm wondering if it would make sense to make HAS_IOMEM always available
> on s390, even though it doesn't make too much sense without PCI.
> But at least it would make s390 again a bit less special.

I see that with CONFIG_PCI=y, s390 already falls back to
generic_ioremap_prot() and just maps any phys_addr_t into the
page table as PAGE_KERNEL, regardless of whether this is an MMIO
address or not.

The simple change below would just extend that behavior to !PCI
and make that consistent with CONFIG_PCI=y on machines without
actual PCI hardware. Of course any code that might rely on this
is now a bug that likely never gets caught at build time.

This still relies on implementing the __raw_* helpers as nop
to have the same behavior as the PCI=y version, as the generic
version would just end up dereferencing the invalid pointers.

     Arnd

diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 84404e6778d5..806782acf6f6 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -173,7 +173,7 @@ config S390
 	select GENERIC_ENTRY
 	select GENERIC_GETTIMEOFDAY
 	select GENERIC_SMP_IDLE_THREAD
-	select GENERIC_IOREMAP if PCI
+	select GENERIC_IOREMAP
 	select GLOB
 	select HAVE_ALIGNED_STRUCT_PAGE
 	select HAVE_ARCH_AUDITSYSCALL
@@ -756,9 +756,6 @@ config PCI_NR_FUNCTIONS
 
 endif # PCI
 
-config HAS_IOMEM
-	def_bool PCI
-
 config CHSC_SCH
 	def_tristate m
 	prompt "Support for CHSC subchannels"
diff --git a/arch/s390/include/asm/io.h b/arch/s390/include/asm/io.h
index faddb9aef3b8..fa5a9dd1c47f 100644
--- a/arch/s390/include/asm/io.h
+++ b/arch/s390/include/asm/io.h
@@ -22,30 +22,16 @@ void *xlate_dev_mem_ptr(phys_addr_t phys);
 #define kc_unxlate_dev_mem_ptr unxlate_dev_mem_ptr
 void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr);
 
-#define IO_SPACE_LIMIT 0
-
-/*
- * I/O memory mapping functions.
- */
-#define ioremap_prot ioremap_prot
-#define iounmap iounmap
-
 #define _PAGE_IOREMAP pgprot_val(PAGE_KERNEL)
 
 #define ioremap_wc(addr, size)  \
 	ioremap_prot((addr), (size), pgprot_writecombine(PAGE_KERNEL))
 
-static inline void __iomem *ioport_map(unsigned long port, unsigned int nr)
-{
-	return NULL;
-}
-
-static inline void ioport_unmap(void __iomem *p)
-{
-}
-
 #ifdef CONFIG_PCI
 
+#define ioremap_prot ioremap_prot
+#define iounmap iounmap
+
 /*
  * s390 needs a private implementation of pci_iomap since ioremap with its
  * offset parameter isn't sufficient. That's because BAR spaces are not
@@ -88,6 +74,49 @@ static inline void __iowrite64_copy(void __iomem *to, const void *from,
 }
 #define __iowrite64_copy __iowrite64_copy
 
+#else
+/*
+ * ioremap_prot() without PCI behaves like memremap(),
+ * MMIO accessors do nothing
+ */
+#define ioremap_prot generic_ioremap_prot
+#define iounmap generic_iounmap
+static inline u8 __raw_readb(const volatile void __iomem *addr)
+{
+	return 0xff;
+}
+#define __raw_readb __raw_readb
+static inline u16 __raw_readw(const volatile void __iomem *addr)
+{
+	return 0xffff;
+}
+#define __raw_readw __raw_readw
+static inline u32 __raw_readl(const volatile void __iomem *addr)
+{
+	return 0xffffffffu;
+}
+#define __raw_readl __raw_readl
+static inline u64 __raw_readq(const volatile void __iomem *addr)
+{
+	return 0xffffffffffffffffull;
+}
+#define __raw_readq __raw_readq
+static inline void __raw_writeb(u8 val, volatile void __iomem *addr)
+{
+}
+#define __raw_writeb __raw_writeb
+static inline void __raw_writew(u16 val, volatile void __iomem *addr)
+{
+}
+#define __raw_writew __raw_writew
+static inline void __raw_writel(u32 val, volatile void __iomem *addr)
+{
+}
+#define __raw_writel __raw_writel
+static inline void __raw_writeq(u64 val, volatile void __iomem *addr)
+{
+}
+#define __raw_writeq __raw_writeq
 #endif /* CONFIG_PCI */
 
 #include <asm-generic/io.h>
diff --git a/init/Kconfig b/init/Kconfig
index 5230d4879b1c..2a4e3ecbfddd 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -237,7 +237,6 @@ config INIT_ENV_ARG_LIMIT
 
 config COMPILE_TEST
 	bool "Compile also drivers which will not load"
-	depends on HAS_IOMEM
 	help
 	  Some drivers can be compiled on a different platform than they are
 	  intended to be run on. Despite they cannot be loaded there (or even