From 6d89ead19946181df1e41d38917fddc951dbd95b Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 12 Jul 2024 11:35:23 +0200 Subject: UAPI/ioctl: Improve parameter name of ioctl request definition helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The third parameter to _IOR et al is a type name, not a size. So the parameter being named "size" is irritating. Rename it to "argtype" instead to reduce confusion. There is a very minor chance that this breaks stuff. It only hurts however if there is a variable (or macro) in userspace that is called "argtype" *and* it's used in the parameters of _IOR and friends. IMHO this is negligible because usually definitions making use of these macros are provided by kernel headers (i.e. us) or if they are replicated in userspace code, they are replicated and so supposed to match the kernel definitions (e.g. to make them usable by programs without the need to update the kernel headers used to compile the program). Signed-off-by: Uwe Kleine-König Signed-off-by: Arnd Bergmann --- include/uapi/asm-generic/ioctl.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/uapi/asm-generic/ioctl.h b/include/uapi/asm-generic/ioctl.h index a84f4db8a250..e3290a5824c9 100644 --- a/include/uapi/asm-generic/ioctl.h +++ b/include/uapi/asm-generic/ioctl.h @@ -82,13 +82,13 @@ * NOTE: _IOW means userland is writing and kernel is reading. _IOR * means userland is reading and kernel is writing. */ -#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0) -#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size))) -#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size))) -#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size))) -#define _IOR_BAD(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size)) -#define _IOW_BAD(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size)) -#define _IOWR_BAD(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size)) +#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0) +#define _IOR(type,nr,argtype) _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(argtype))) +#define _IOW(type,nr,argtype) _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(argtype))) +#define _IOWR(type,nr,argtype) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(argtype))) +#define _IOR_BAD(type,nr,argtype) _IOC(_IOC_READ,(type),(nr),sizeof(argtype)) +#define _IOW_BAD(type,nr,argtype) _IOC(_IOC_WRITE,(type),(nr),sizeof(argtype)) +#define _IOWR_BAD(type,nr,argtype) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(argtype)) /* used to decode ioctl numbers.. */ #define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) -- cgit v1.2.3 From 7c7e6c8924e7bf98db4e5b2edb202842003c00c2 Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Thu, 24 Oct 2024 19:54:43 +0200 Subject: tty: serial: handle HAS_IOPORT dependencies In a future patch HAS_IOPORT=n will disable inb()/outb() and friends at compile time. We thus need to add HAS_IOPORT as dependency for those drivers using them unconditionally. Some 8250 serial drivers support MMIO only use, so fence only the parts requiring I/O ports and print an error message if a device can't be supported with the current configuration. Co-developed-by: Arnd Bergmann Signed-off-by: Arnd Bergmann Acked-by: Greg Kroah-Hartman Reviewed-by: Maciej W. Rozycki Signed-off-by: Niklas Schnelle Signed-off-by: Arnd Bergmann --- drivers/tty/Kconfig | 4 ++-- drivers/tty/serial/8250/8250_early.c | 4 ++++ drivers/tty/serial/8250/8250_pci.c | 40 +++++++++++++++++++++++++++++++++++ drivers/tty/serial/8250/8250_pcilib.c | 12 ++++++++++- drivers/tty/serial/8250/8250_pcilib.h | 2 ++ drivers/tty/serial/8250/8250_port.c | 27 +++++++++++++++++++---- drivers/tty/serial/8250/Kconfig | 4 ++-- drivers/tty/serial/Kconfig | 2 +- include/linux/serial_core.h | 4 ++++ 9 files changed, 89 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index a45d423ad10f..63a494d36a1f 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -220,7 +220,7 @@ config MOXA_INTELLIO config MOXA_SMARTIO tristate "Moxa SmartIO support v. 2.0" - depends on SERIAL_NONSTANDARD && PCI + depends on SERIAL_NONSTANDARD && PCI && HAS_IOPORT help Say Y here if you have a Moxa SmartIO multiport serial card and/or want to help develop a new version of this driver. @@ -302,7 +302,7 @@ config GOLDFISH_TTY_EARLY_CONSOLE config IPWIRELESS tristate "IPWireless 3G UMTS PCMCIA card support" - depends on PCMCIA && NETDEVICES + depends on PCMCIA && NETDEVICES && HAS_IOPORT select PPP help This is a driver for 3G UMTS PCMCIA card from IPWireless company. In diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index 6176083d0341..842422921765 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -46,8 +46,10 @@ static unsigned int serial8250_early_in(struct uart_port *port, int offset) return readl(port->membase + offset); case UPIO_MEM32BE: return ioread32be(port->membase + offset); +#ifdef CONFIG_HAS_IOPORT case UPIO_PORT: return inb(port->iobase + offset); +#endif default: return 0; } @@ -70,9 +72,11 @@ static void serial8250_early_out(struct uart_port *port, int offset, int value) case UPIO_MEM32BE: iowrite32be(value, port->membase + offset); break; +#ifdef CONFIG_HAS_IOPORT case UPIO_PORT: outb(value, port->iobase + offset); break; +#endif } } diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 6709b6a5f301..7d7a6d62c09c 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -964,6 +964,9 @@ static int pci_ite887x_init(struct pci_dev *dev) struct resource *iobase = NULL; u32 miscr, uartbar, ioport; + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(dev); + /* search for the base-ioport */ for (i = 0; i < ARRAY_SIZE(inta_addr); i++) { iobase = request_region(inta_addr[i], ITE_887x_IOSIZE, @@ -1514,6 +1517,9 @@ static int pci_quatech_init(struct pci_dev *dev) const struct pci_device_id *match; bool amcc = false; + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(dev); + match = pci_match_id(quatech_cards, dev); if (match) amcc = match->driver_data; @@ -1538,6 +1544,9 @@ static int pci_quatech_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) { + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(priv->dev); + /* Needed by pci_quatech calls below */ port->port.iobase = pci_resource_start(priv->dev, FL_GET_BASE(board->flags)); /* Set up the clocking */ @@ -1655,6 +1664,9 @@ static int pci_fintek_setup(struct serial_private *priv, u8 config_base; u16 iobase; + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(pdev); + config_base = 0x40 + 0x08 * idx; /* Get the io address from configuration space */ @@ -1686,6 +1698,9 @@ static int pci_fintek_init(struct pci_dev *dev) u8 config_base; struct serial_private *priv = pci_get_drvdata(dev); + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(dev); + if (!(pci_resource_flags(dev, 5) & IORESOURCE_IO) || !(pci_resource_flags(dev, 4) & IORESOURCE_IO) || !(pci_resource_flags(dev, 3) & IORESOURCE_IO)) @@ -1864,6 +1879,9 @@ static int kt_serial_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) { + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(priv->dev); + port->port.flags |= UPF_BUG_THRE; port->port.serial_in = kt_serial_in; port->port.handle_break = kt_handle_break; @@ -1884,6 +1902,9 @@ pci_wch_ch353_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) { + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(priv->dev); + port->port.flags |= UPF_FIXED_TYPE; port->port.type = PORT_16550A; return pci_default_setup(priv, board, port, idx); @@ -1894,6 +1915,9 @@ pci_wch_ch355_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) { + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(priv->dev); + port->port.flags |= UPF_FIXED_TYPE; port->port.type = PORT_16550A; return pci_default_setup(priv, board, port, idx); @@ -1904,6 +1928,9 @@ pci_wch_ch38x_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) { + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(priv->dev); + port->port.flags |= UPF_FIXED_TYPE; port->port.type = PORT_16850; return pci_default_setup(priv, board, port, idx); @@ -1918,6 +1945,8 @@ static int pci_wch_ch38x_init(struct pci_dev *dev) int max_port; unsigned long iobase; + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(dev); switch (dev->device) { case 0x3853: /* 8 ports */ @@ -1937,6 +1966,11 @@ static void pci_wch_ch38x_exit(struct pci_dev *dev) { unsigned long iobase; + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) { + serial_8250_warn_need_ioport(dev); + return; + } + iobase = pci_resource_start(dev, 0); outb(0x0, iobase + CH384_XINT_ENABLE_REG); } @@ -2052,6 +2086,9 @@ static int pci_moxa_init(struct pci_dev *dev) unsigned int i, num_ports = moxa_get_nports(device); u8 val, init_mode = MOXA_RS232; + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(dev); + if (!(pci_moxa_supported_rs(dev) & MOXA_SUPP_RS232)) { init_mode = MOXA_RS422; } @@ -2084,6 +2121,9 @@ pci_moxa_setup(struct serial_private *priv, unsigned int bar = FL_GET_BASE(board->flags); int offset; + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(priv->dev); + if (board->num_ports == 4 && idx == 3) offset = 7 * board->uart_offset; else diff --git a/drivers/tty/serial/8250/8250_pcilib.c b/drivers/tty/serial/8250/8250_pcilib.c index ea906d721b2c..ec4d04177802 100644 --- a/drivers/tty/serial/8250/8250_pcilib.c +++ b/drivers/tty/serial/8250/8250_pcilib.c @@ -12,6 +12,14 @@ #include "8250.h" #include "8250_pcilib.h" +int serial_8250_warn_need_ioport(struct pci_dev *dev) +{ + dev_warn(&dev->dev, + "Serial port not supported because of missing I/O resource\n"); + + return -ENXIO; +} + int serial8250_pci_setup_port(struct pci_dev *dev, struct uart_8250_port *port, u8 bar, unsigned int offset, int regshift) { @@ -27,12 +35,14 @@ int serial8250_pci_setup_port(struct pci_dev *dev, struct uart_8250_port *port, port->port.mapbase = pci_resource_start(dev, bar) + offset; port->port.membase = pcim_iomap_table(dev)[bar] + offset; port->port.regshift = regshift; - } else { + } else if (IS_ENABLED(CONFIG_HAS_IOPORT)) { port->port.iotype = UPIO_PORT; port->port.iobase = pci_resource_start(dev, bar) + offset; port->port.mapbase = 0; port->port.membase = NULL; port->port.regshift = 0; + } else { + return serial_8250_warn_need_ioport(dev); } return 0; } diff --git a/drivers/tty/serial/8250/8250_pcilib.h b/drivers/tty/serial/8250/8250_pcilib.h index 1aaf1b50ce9c..16a274574cde 100644 --- a/drivers/tty/serial/8250/8250_pcilib.h +++ b/drivers/tty/serial/8250/8250_pcilib.h @@ -13,3 +13,5 @@ struct uart_8250_port; int serial8250_pci_setup_port(struct pci_dev *dev, struct uart_8250_port *port, u8 bar, unsigned int offset, int regshift); + +int serial_8250_warn_need_ioport(struct pci_dev *dev); diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 3509af7dc52b..91369f542b0b 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -338,6 +338,7 @@ static void default_serial_dl_write(struct uart_8250_port *up, u32 value) serial_out(up, UART_DLM, value >> 8 & 0xff); } +#ifdef CONFIG_HAS_IOPORT static unsigned int hub6_serial_in(struct uart_port *p, int offset) { offset = offset << p->regshift; @@ -351,6 +352,7 @@ static void hub6_serial_out(struct uart_port *p, int offset, int value) outb(p->hub6 - 1 + offset, p->iobase); outb(value, p->iobase + 1); } +#endif /* CONFIG_HAS_IOPORT */ static unsigned int mem_serial_in(struct uart_port *p, int offset) { @@ -400,6 +402,7 @@ static unsigned int mem32be_serial_in(struct uart_port *p, int offset) return ioread32be(p->membase + offset); } +#ifdef CONFIG_HAS_IOPORT static unsigned int io_serial_in(struct uart_port *p, int offset) { offset = offset << p->regshift; @@ -411,6 +414,15 @@ static void io_serial_out(struct uart_port *p, int offset, int value) offset = offset << p->regshift; outb(value, p->iobase + offset); } +#endif +static unsigned int no_serial_in(struct uart_port *p, int offset) +{ + return (unsigned int)-1; +} + +static void no_serial_out(struct uart_port *p, int offset, int value) +{ +} static int serial8250_default_handle_irq(struct uart_port *port); @@ -422,10 +434,12 @@ static void set_io_from_upio(struct uart_port *p) up->dl_write = default_serial_dl_write; switch (p->iotype) { +#ifdef CONFIG_HAS_IOPORT case UPIO_HUB6: p->serial_in = hub6_serial_in; p->serial_out = hub6_serial_out; break; +#endif case UPIO_MEM: p->serial_in = mem_serial_in; @@ -446,11 +460,16 @@ static void set_io_from_upio(struct uart_port *p) p->serial_in = mem32be_serial_in; p->serial_out = mem32be_serial_out; break; - - default: +#ifdef CONFIG_HAS_IOPORT + case UPIO_PORT: p->serial_in = io_serial_in; p->serial_out = io_serial_out; break; +#endif + default: + WARN(1, "Unsupported UART type %x\n", p->iotype); + p->serial_in = no_serial_in; + p->serial_out = no_serial_out; } /* Remember loaded iotype */ up->cur_iotype = p->iotype; @@ -1174,7 +1193,7 @@ static void autoconfig(struct uart_8250_port *up) */ scratch = serial_in(up, UART_IER); serial_out(up, UART_IER, 0); -#ifdef __i386__ +#if defined(__i386__) && defined(CONFIG_HAS_IOPORT) outb(0xff, 0x080); #endif /* @@ -1183,7 +1202,7 @@ static void autoconfig(struct uart_8250_port *up) */ scratch2 = serial_in(up, UART_IER) & UART_IER_ALL_INTR; serial_out(up, UART_IER, UART_IER_ALL_INTR); -#ifdef __i386__ +#if defined(__i386__) && defined(CONFIG_HAS_IOPORT) outb(0, 0x080); #endif scratch3 = serial_in(up, UART_IER) & UART_IER_ALL_INTR; diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index 47ff50763c04..1eb20350fcf4 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -72,7 +72,7 @@ config SERIAL_8250_16550A_VARIANTS config SERIAL_8250_FINTEK bool "Support for Fintek variants" - depends on SERIAL_8250 + depends on SERIAL_8250 && HAS_IOPORT help Selecting this option will add support for the RS232 and RS485 capabilities of the Fintek F81216A LPC to 4 UART as well similar @@ -163,7 +163,7 @@ config SERIAL_8250_HP300 config SERIAL_8250_CS tristate "8250/16550 PCMCIA device support" - depends on PCMCIA && SERIAL_8250 + depends on PCMCIA && SERIAL_8250 && HAS_IOPORT help Say Y here to enable support for 16-bit PCMCIA serial devices, including serial port cards, modems, and the modem functions of diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 28e4beeabf8f..45f0f779fbf9 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -877,7 +877,7 @@ config SERIAL_TXX9_STDSERIAL config SERIAL_JSM tristate "Digi International NEO and Classic PCI Support" - depends on PCI + depends on PCI && HAS_IOPORT select SERIAL_CORE help This is a driver for Digi International's Neo and Classic series diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 4ab65874a850..743b4afaad4c 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -505,7 +505,11 @@ struct uart_port { * The remaining bits are serial-core specific and not modifiable by * userspace. */ +#ifdef CONFIG_HAS_IOPORT #define UPF_FOURPORT ((__force upf_t) ASYNC_FOURPORT /* 1 */ ) +#else +#define UPF_FOURPORT 0 +#endif #define UPF_SAK ((__force upf_t) ASYNC_SAK /* 2 */ ) #define UPF_SPD_HI ((__force upf_t) ASYNC_SPD_HI /* 4 */ ) #define UPF_SPD_VHI ((__force upf_t) ASYNC_SPD_VHI /* 5 */ ) -- cgit v1.2.3 From 6f043e75744596968b6547c4bd43e4d30bbb6d6e Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Thu, 24 Oct 2024 19:54:44 +0200 Subject: asm-generic/io.h: Remove I/O port accessors for HAS_IOPORT=n MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With all subsystems and drivers either declaring their dependence on HAS_IOPORT or fencing I/O port specific code sections we can finally make inb()/outb() and friends compile-time dependent on HAS_IOPORT as suggested by Linus in the linked mail. The main benefit of this is that on platforms such as s390 which have no meaningful way of implementing inb()/outb() their use without the proper HAS_IOPORT dependency will result in easy to catch and fix compile-time errors instead of compiling code that can never work. Link: https://lore.kernel.org/lkml/CAHk-=wg80je=K7madF4e7WrRNp37e3qh6y10Svhdc7O8SZ_-8g@mail.gmail.com/ Co-developed-by: Arnd Bergmann Signed-off-by: Arnd Bergmann Signed-off-by: Niklas Schnelle Reviewed-by: Takashi Iwai Reviewed-by: Ville Syrjälä Reviewed-by: Jarkko Sakkinen Acked-by: Lucas De Marchi Acked-by: Maciej W. Rozycki Acked-by: Damien Le Moal Acked-by: Jaroslav Kysela Acked-by: Greg Kroah-Hartman Acked-by: Rafael J. Wysocki Acked-by: Johannes Berg # for ARCH=um Acked-by: Geert Uytterhoeven Acked-by: Kalle Valo Acked-by: Jakub Kicinski Acked-by: Corey Minyard Acked-by: Guenter Roeck Acked-by: Damien Le Moal Acked-by: Sebastian Reichel Signed-off-by: Arnd Bergmann --- include/asm-generic/io.h | 60 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) (limited to 'include') diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h index 80de699bf6af..1027be6a62bc 100644 --- a/include/asm-generic/io.h +++ b/include/asm-generic/io.h @@ -540,6 +540,7 @@ static inline void writesq(volatile void __iomem *addr, const void *buffer, #if !defined(inb) && !defined(_inb) #define _inb _inb +#ifdef CONFIG_HAS_IOPORT static inline u8 _inb(unsigned long addr) { u8 val; @@ -549,10 +550,15 @@ static inline u8 _inb(unsigned long addr) __io_par(val); return val; } +#else +u8 _inb(unsigned long addr) + __compiletime_error("inb()) requires CONFIG_HAS_IOPORT"); +#endif #endif #if !defined(inw) && !defined(_inw) #define _inw _inw +#ifdef CONFIG_HAS_IOPORT static inline u16 _inw(unsigned long addr) { u16 val; @@ -562,10 +568,15 @@ static inline u16 _inw(unsigned long addr) __io_par(val); return val; } +#else +u16 _inw(unsigned long addr) + __compiletime_error("inw() requires CONFIG_HAS_IOPORT"); +#endif #endif #if !defined(inl) && !defined(_inl) #define _inl _inl +#ifdef CONFIG_HAS_IOPORT static inline u32 _inl(unsigned long addr) { u32 val; @@ -575,36 +586,55 @@ static inline u32 _inl(unsigned long addr) __io_par(val); return val; } +#else +u32 _inl(unsigned long addr) + __compiletime_error("inl() requires CONFIG_HAS_IOPORT"); +#endif #endif #if !defined(outb) && !defined(_outb) #define _outb _outb +#ifdef CONFIG_HAS_IOPORT static inline void _outb(u8 value, unsigned long addr) { __io_pbw(); __raw_writeb(value, PCI_IOBASE + addr); __io_paw(); } +#else +void _outb(u8 value, unsigned long addr) + __compiletime_error("outb() requires CONFIG_HAS_IOPORT"); +#endif #endif #if !defined(outw) && !defined(_outw) #define _outw _outw +#ifdef CONFIG_HAS_IOPORT static inline void _outw(u16 value, unsigned long addr) { __io_pbw(); __raw_writew((u16 __force)cpu_to_le16(value), PCI_IOBASE + addr); __io_paw(); } +#else +void _outw(u16 value, unsigned long addr) + __compiletime_error("outw() requires CONFIG_HAS_IOPORT"); +#endif #endif #if !defined(outl) && !defined(_outl) #define _outl _outl +#ifdef CONFIG_HAS_IOPORT static inline void _outl(u32 value, unsigned long addr) { __io_pbw(); __raw_writel((u32 __force)cpu_to_le32(value), PCI_IOBASE + addr); __io_paw(); } +#else +void _outl(u32 value, unsigned long addr) + __compiletime_error("outl() requires CONFIG_HAS_IOPORT"); +#endif #endif #include @@ -688,53 +718,83 @@ static inline void outl_p(u32 value, unsigned long addr) #ifndef insb #define insb insb +#ifdef CONFIG_HAS_IOPORT static inline void insb(unsigned long addr, void *buffer, unsigned int count) { readsb(PCI_IOBASE + addr, buffer, count); } +#else +void insb(unsigned long addr, void *buffer, unsigned int count) + __compiletime_error("insb() requires HAS_IOPORT"); +#endif #endif #ifndef insw #define insw insw +#ifdef CONFIG_HAS_IOPORT static inline void insw(unsigned long addr, void *buffer, unsigned int count) { readsw(PCI_IOBASE + addr, buffer, count); } +#else +void insw(unsigned long addr, void *buffer, unsigned int count) + __compiletime_error("insw() requires HAS_IOPORT"); +#endif #endif #ifndef insl #define insl insl +#ifdef CONFIG_HAS_IOPORT static inline void insl(unsigned long addr, void *buffer, unsigned int count) { readsl(PCI_IOBASE + addr, buffer, count); } +#else +void insl(unsigned long addr, void *buffer, unsigned int count) + __compiletime_error("insl() requires HAS_IOPORT"); +#endif #endif #ifndef outsb #define outsb outsb +#ifdef CONFIG_HAS_IOPORT static inline void outsb(unsigned long addr, const void *buffer, unsigned int count) { writesb(PCI_IOBASE + addr, buffer, count); } +#else +void outsb(unsigned long addr, const void *buffer, unsigned int count) + __compiletime_error("outsb() requires HAS_IOPORT"); +#endif #endif #ifndef outsw #define outsw outsw +#ifdef CONFIG_HAS_IOPORT static inline void outsw(unsigned long addr, const void *buffer, unsigned int count) { writesw(PCI_IOBASE + addr, buffer, count); } +#else +void outsw(unsigned long addr, const void *buffer, unsigned int count) + __compiletime_error("outsw() requires HAS_IOPORT"); +#endif #endif #ifndef outsl #define outsl outsl +#ifdef CONFIG_HAS_IOPORT static inline void outsl(unsigned long addr, const void *buffer, unsigned int count) { writesl(PCI_IOBASE + addr, buffer, count); } +#else +void outsl(unsigned long addr, const void *buffer, unsigned int count) + __compiletime_error("outsl() requires HAS_IOPORT"); +#endif #endif #ifndef insb_p -- cgit v1.2.3 From c5c3238d9b8cee58cd4b08bbbe9347a94a566390 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 23 Oct 2024 07:36:36 +0200 Subject: asm-generic: provide generic page_to_phys and phys_to_page implementations page_to_phys is duplicated by all architectures, and from some strange reason placed in where it doesn't fit at all. phys_to_page is only provided by a few architectures despite having a lot of open coded users. Provide generic versions in to make these helpers more easily usable. Note with this patch powerpc loses the CONFIG_DEBUG_VIRTUAL pfn_valid check. It will be added back in a generic version later. Signed-off-by: Christoph Hellwig Signed-off-by: Arnd Bergmann --- arch/alpha/include/asm/io.h | 1 - arch/arc/include/asm/io.h | 3 --- arch/arm/include/asm/memory.h | 6 ------ arch/arm64/include/asm/memory.h | 6 ------ arch/csky/include/asm/page.h | 3 --- arch/hexagon/include/asm/page.h | 6 ------ arch/loongarch/include/asm/page.h | 3 --- arch/m68k/include/asm/virtconvert.h | 3 --- arch/microblaze/include/asm/page.h | 1 - arch/mips/include/asm/io.h | 5 ----- arch/nios2/include/asm/io.h | 3 --- arch/openrisc/include/asm/page.h | 2 -- arch/parisc/include/asm/page.h | 1 - arch/powerpc/include/asm/io.h | 12 ------------ arch/riscv/include/asm/page.h | 3 --- arch/s390/include/asm/page.h | 2 -- arch/sh/include/asm/page.h | 1 - arch/sparc/include/asm/page.h | 2 -- arch/um/include/asm/pgtable.h | 2 -- arch/x86/include/asm/io.h | 5 ----- arch/xtensa/include/asm/page.h | 1 - include/asm-generic/memory_model.h | 3 +++ 22 files changed, 3 insertions(+), 71 deletions(-) (limited to 'include') diff --git a/arch/alpha/include/asm/io.h b/arch/alpha/include/asm/io.h index b191d87f89c4..65fe1e54c6da 100644 --- a/arch/alpha/include/asm/io.h +++ b/arch/alpha/include/asm/io.h @@ -88,7 +88,6 @@ static inline void * phys_to_virt(unsigned long address) #define virt_to_phys virt_to_phys #define phys_to_virt phys_to_virt -#define page_to_phys(page) page_to_pa(page) /* Maximum PIO space address supported? */ #define IO_SPACE_LIMIT 0xffff diff --git a/arch/arc/include/asm/io.h b/arch/arc/include/asm/io.h index f57cb5a6b624..00171a212b3c 100644 --- a/arch/arc/include/asm/io.h +++ b/arch/arc/include/asm/io.h @@ -42,9 +42,6 @@ static inline void ioport_unmap(void __iomem *addr) #define iowrite16be(v,p) ({ __iowmb(); __raw_writew((__force u16)cpu_to_be16(v), p); }) #define iowrite32be(v,p) ({ __iowmb(); __raw_writel((__force u32)cpu_to_be32(v), p); }) -/* Change struct page to physical address */ -#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) - #define __raw_readb __raw_readb static inline u8 __raw_readb(const volatile void __iomem *addr) { diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h index ef2aa79ece5a..7c2fa7dcec6d 100644 --- a/arch/arm/include/asm/memory.h +++ b/arch/arm/include/asm/memory.h @@ -147,12 +147,6 @@ extern unsigned long vectors_base; #define DTCM_OFFSET UL(0xfffe8000) #endif -/* - * Convert a page to/from a physical address - */ -#define page_to_phys(page) (__pfn_to_phys(page_to_pfn(page))) -#define phys_to_page(phys) (pfn_to_page(__phys_to_pfn(phys))) - /* * PLAT_PHYS_OFFSET is the offset (from zero) of the start of physical * memory. This is used for XIP and NoMMU kernels, and on platforms that don't diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h index 0480c61dbb4f..b9b992908a56 100644 --- a/arch/arm64/include/asm/memory.h +++ b/arch/arm64/include/asm/memory.h @@ -353,12 +353,6 @@ extern phys_addr_t __phys_addr_symbol(unsigned long x); #define __phys_to_virt(x) ((unsigned long)((x) - PHYS_OFFSET) | PAGE_OFFSET) #define __phys_to_kimg(x) ((unsigned long)((x) + kimage_voffset)) -/* - * Convert a page to/from a physical address - */ -#define page_to_phys(page) (__pfn_to_phys(page_to_pfn(page))) -#define phys_to_page(phys) (pfn_to_page(__phys_to_pfn(phys))) - /* * Note: Drivers should NOT use these. They are the wrong * translation for translating DMA addresses. Use the driver diff --git a/arch/csky/include/asm/page.h b/arch/csky/include/asm/page.h index 0ca6c408c07f..a5afdfe27dc6 100644 --- a/arch/csky/include/asm/page.h +++ b/arch/csky/include/asm/page.h @@ -43,9 +43,6 @@ extern void *memcpy(void *to, const void *from, size_t l); #define clear_page(page) memset((page), 0, PAGE_SIZE) #define copy_page(to, from) memcpy((to), (from), PAGE_SIZE) -#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) -#define phys_to_page(paddr) (pfn_to_page(PFN_DOWN(paddr))) - struct page; #include diff --git a/arch/hexagon/include/asm/page.h b/arch/hexagon/include/asm/page.h index 8a6af57274c2..aba4d7901305 100644 --- a/arch/hexagon/include/asm/page.h +++ b/arch/hexagon/include/asm/page.h @@ -118,12 +118,6 @@ static inline void clear_page(void *page) #define clear_user_page(page, vaddr, pg) clear_page(page) #define copy_user_page(to, from, vaddr, pg) copy_page(to, from) -/* - * page_to_phys - convert page to physical address - * @page - pointer to page entry in mem_map - */ -#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) - static inline unsigned long virt_to_pfn(const void *kaddr) { return __pa(kaddr) >> PAGE_SHIFT; diff --git a/arch/loongarch/include/asm/page.h b/arch/loongarch/include/asm/page.h index e85df33f11c7..8b4e6b280f2b 100644 --- a/arch/loongarch/include/asm/page.h +++ b/arch/loongarch/include/asm/page.h @@ -81,9 +81,6 @@ struct page *tlb_virt_to_page(unsigned long kaddr); #define pfn_to_phys(pfn) __pfn_to_phys(pfn) #define phys_to_pfn(paddr) __phys_to_pfn(paddr) -#define page_to_phys(page) pfn_to_phys(page_to_pfn(page)) -#define phys_to_page(paddr) pfn_to_page(phys_to_pfn(paddr)) - #ifndef CONFIG_KFENCE #define page_to_virt(page) __va(page_to_phys(page)) diff --git a/arch/m68k/include/asm/virtconvert.h b/arch/m68k/include/asm/virtconvert.h index 0a27905b0036..32e27bddb7d4 100644 --- a/arch/m68k/include/asm/virtconvert.h +++ b/arch/m68k/include/asm/virtconvert.h @@ -28,9 +28,6 @@ static inline void *phys_to_virt(unsigned long address) return __va(address); } -/* Permanent address of a page. */ -#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) - /* * IO bus memory addresses are 1:1 with the physical address, * deprecated globally but still used on two machines. diff --git a/arch/microblaze/include/asm/page.h b/arch/microblaze/include/asm/page.h index 8810f4f1c3b0..ecd4bf2779a0 100644 --- a/arch/microblaze/include/asm/page.h +++ b/arch/microblaze/include/asm/page.h @@ -101,7 +101,6 @@ extern int page_is_ram(unsigned long pfn); # define virt_to_page(kaddr) (pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)) # define page_to_virt(page) __va(page_to_pfn(page) << PAGE_SHIFT) -# define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) # define ARCH_PFN_OFFSET (memory_start >> PAGE_SHIFT) # endif /* __ASSEMBLY__ */ diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index af58d6ae06b8..0bddb568af7c 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -125,11 +125,6 @@ static inline unsigned long isa_virt_to_bus(volatile void *address) return virt_to_phys(address); } -/* - * Change "struct page" to physical address. - */ -#define page_to_phys(page) ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT) - void __iomem *ioremap_prot(phys_addr_t offset, unsigned long size, unsigned long prot_val); void iounmap(const volatile void __iomem *addr); diff --git a/arch/nios2/include/asm/io.h b/arch/nios2/include/asm/io.h index 746853ac7d8d..36e3550673b3 100644 --- a/arch/nios2/include/asm/io.h +++ b/arch/nios2/include/asm/io.h @@ -28,9 +28,6 @@ void __iomem *ioremap(unsigned long physaddr, unsigned long size); void iounmap(void __iomem *addr); -/* Pages to physical address... */ -#define page_to_phys(page) virt_to_phys(page_to_virt(page)) - /* Macros used for converting between virtual and physical mappings. */ #define phys_to_virt(vaddr) \ ((void *)((unsigned long)(vaddr) | CONFIG_NIOS2_KERNEL_REGION_BASE)) diff --git a/arch/openrisc/include/asm/page.h b/arch/openrisc/include/asm/page.h index 1d5913f67c31..45d6c440729c 100644 --- a/arch/openrisc/include/asm/page.h +++ b/arch/openrisc/include/asm/page.h @@ -80,8 +80,6 @@ static inline unsigned long virt_to_pfn(const void *kaddr) #define virt_to_page(addr) \ (mem_map + (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT)) -#define page_to_phys(page) ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT) - #define virt_addr_valid(kaddr) (pfn_valid(virt_to_pfn(kaddr))) #endif /* __ASSEMBLY__ */ diff --git a/arch/parisc/include/asm/page.h b/arch/parisc/include/asm/page.h index 4bea2e95798f..6cb5b02aca9a 100644 --- a/arch/parisc/include/asm/page.h +++ b/arch/parisc/include/asm/page.h @@ -168,7 +168,6 @@ extern int npmem_ranges; #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) -#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) #include diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h index 52e1b1d15ff6..fd92ac450169 100644 --- a/arch/powerpc/include/asm/io.h +++ b/arch/powerpc/include/asm/io.h @@ -969,18 +969,6 @@ static inline void * phys_to_virt(unsigned long address) } #define phys_to_virt phys_to_virt -/* - * Change "struct page" to physical address. - */ -static inline phys_addr_t page_to_phys(struct page *page) -{ - unsigned long pfn = page_to_pfn(page); - - WARN_ON(IS_ENABLED(CONFIG_DEBUG_VIRTUAL) && !pfn_valid(pfn)); - - return PFN_PHYS(pfn); -} - /* * 32 bits still uses virt_to_bus() for its implementation of DMA * mappings se we have to keep it defined here. We also have some old diff --git a/arch/riscv/include/asm/page.h b/arch/riscv/include/asm/page.h index 32d308a3355f..16f4141f0055 100644 --- a/arch/riscv/include/asm/page.h +++ b/arch/riscv/include/asm/page.h @@ -194,9 +194,6 @@ extern phys_addr_t __phys_addr_symbol(unsigned long x); #define virt_to_page(vaddr) (pfn_to_page(virt_to_pfn(vaddr))) #define page_to_virt(page) (pfn_to_virt(page_to_pfn(page))) -#define page_to_phys(page) (pfn_to_phys(page_to_pfn(page))) -#define phys_to_page(paddr) (pfn_to_page(phys_to_pfn(paddr))) - #define sym_to_pfn(x) __phys_to_pfn(__pa_symbol(x)) unsigned long kaslr_offset(void); diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h index 73e1e03317b4..16d62a4ecccc 100644 --- a/arch/s390/include/asm/page.h +++ b/arch/s390/include/asm/page.h @@ -245,9 +245,7 @@ static inline unsigned long __phys_addr(unsigned long x, bool is_31bit) #define phys_to_pfn(phys) ((phys) >> PAGE_SHIFT) #define pfn_to_phys(pfn) ((pfn) << PAGE_SHIFT) -#define phys_to_page(phys) pfn_to_page(phys_to_pfn(phys)) #define phys_to_folio(phys) page_folio(phys_to_page(phys)) -#define page_to_phys(page) pfn_to_phys(page_to_pfn(page)) #define folio_to_phys(page) pfn_to_phys(folio_pfn(folio)) static inline void *pfn_to_virt(unsigned long pfn) diff --git a/arch/sh/include/asm/page.h b/arch/sh/include/asm/page.h index f780b467e75d..4e82ea84a06f 100644 --- a/arch/sh/include/asm/page.h +++ b/arch/sh/include/asm/page.h @@ -147,7 +147,6 @@ typedef struct page *pgtable_t; #endif #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) -#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) /* * PFN = physical frame number (ie PFN 0 == physical address 0) diff --git a/arch/sparc/include/asm/page.h b/arch/sparc/include/asm/page.h index 5e44cdf2a8f2..1a00cc0a1893 100644 --- a/arch/sparc/include/asm/page.h +++ b/arch/sparc/include/asm/page.h @@ -2,8 +2,6 @@ #ifndef ___ASM_SPARC_PAGE_H #define ___ASM_SPARC_PAGE_H -#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) - #if defined(__sparc__) && defined(__arch64__) #include #else diff --git a/arch/um/include/asm/pgtable.h b/arch/um/include/asm/pgtable.h index 83373c9963e7..faab5a2a4b06 100644 --- a/arch/um/include/asm/pgtable.h +++ b/arch/um/include/asm/pgtable.h @@ -287,9 +287,7 @@ static inline int pte_same(pte_t pte_a, pte_t pte_b) * and a page entry and page directory to the page they refer to. */ -#define phys_to_page(phys) pfn_to_page(phys_to_pfn(phys)) #define __virt_to_page(virt) phys_to_page(__pa(virt)) -#define page_to_phys(page) pfn_to_phys(page_to_pfn(page)) #define virt_to_page(addr) __virt_to_page((const unsigned long) addr) #define mk_pte(page, pgprot) \ diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h index 1d60427379c9..ed580c7f9d0a 100644 --- a/arch/x86/include/asm/io.h +++ b/arch/x86/include/asm/io.h @@ -151,11 +151,6 @@ static inline void *phys_to_virt(phys_addr_t address) } #define phys_to_virt phys_to_virt -/* - * Change "struct page" to physical address. - */ -#define page_to_phys(page) ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT) - /* * ISA I/O bus memory addresses are 1:1 with the physical address. * However, we truncate the address to unsigned int to avoid undesirable diff --git a/arch/xtensa/include/asm/page.h b/arch/xtensa/include/asm/page.h index 4db56ef052d2..dc3d5b094ecd 100644 --- a/arch/xtensa/include/asm/page.h +++ b/arch/xtensa/include/asm/page.h @@ -195,7 +195,6 @@ static inline unsigned long ___pa(unsigned long va) #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) #define page_to_virt(page) __va(page_to_pfn(page) << PAGE_SHIFT) #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) -#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) #endif /* __ASSEMBLY__ */ diff --git a/include/asm-generic/memory_model.h b/include/asm-generic/memory_model.h index 6796abe1900e..a73a140cbecd 100644 --- a/include/asm-generic/memory_model.h +++ b/include/asm-generic/memory_model.h @@ -64,6 +64,9 @@ static inline int pfn_valid(unsigned long pfn) #define page_to_pfn __page_to_pfn #define pfn_to_page __pfn_to_page +#define page_to_phys(page) PFN_PHYS(page_to_pfn(page)) +#define phys_to_page(phys) pfn_to_page(PHYS_PFN(phys)) + #endif /* __ASSEMBLY__ */ #endif -- cgit v1.2.3 From 3e25d5a49f99b75be2c6cfb165e4f77dc6d739a2 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 23 Oct 2024 07:36:37 +0200 Subject: asm-generic: add an optional pfn_valid check to page_to_phys page_to_pfn is usually implemented by pointer arithmetics on the memory map, which means that bogus input can lead to even more bogus output. Powerpc had a pfn_valid check on the intermediate pfn in the page_to_phys implementation when CONFIG_DEBUG_VIRTUAL is defined, which seems generally useful, so add that to the generic version. Signed-off-by: Christoph Hellwig Reviewed-by: Thomas Huth Signed-off-by: Arnd Bergmann --- include/asm-generic/memory_model.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'include') diff --git a/include/asm-generic/memory_model.h b/include/asm-generic/memory_model.h index a73a140cbecd..6d1fb6162ac1 100644 --- a/include/asm-generic/memory_model.h +++ b/include/asm-generic/memory_model.h @@ -64,7 +64,17 @@ static inline int pfn_valid(unsigned long pfn) #define page_to_pfn __page_to_pfn #define pfn_to_page __pfn_to_page +#ifdef CONFIG_DEBUG_VIRTUAL +#define page_to_phys(page) \ +({ \ + unsigned long __pfn = page_to_pfn(page); \ + \ + WARN_ON_ONCE(!pfn_valid(__pfn)); \ + PFN_PHYS(__pfn); \ +}) +#else #define page_to_phys(page) PFN_PHYS(page_to_pfn(page)) +#endif /* CONFIG_DEBUG_VIRTUAL */ #define phys_to_page(phys) pfn_to_page(PHYS_PFN(phys)) #endif /* __ASSEMBLY__ */ -- cgit v1.2.3 From 00a31dd3acea0f88f947fc71e268ebb34b59f218 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 3 Oct 2024 17:16:14 -0400 Subject: asm-generic/div64: optimize/simplify __div64_const32() Several years later I just realized that this code could be greatly simplified. First, let's formalize the need for overflow handling in __arch_xprod64(). Assuming n = UINT64_MAX, there are 2 cases where an overflow may occur: 1) If a bias must be added, we have m_lo * n_lo + m or m_lo * 0xffffffff + ((m_hi << 32) + m_lo) or ((m_lo << 32) - m_lo) + ((m_hi << 32) + m_lo) or (m_lo + m_hi) << 32 which must be < (1 << 64). So the criteria for no overflow is m_lo + m_hi < (1 << 32). 2) The cross product m_lo * n_hi + m_hi * n_lo or m_lo * 0xffffffff + m_hi * 0xffffffff or ((m_lo << 32) - m_lo) + ((m_hi << 32) - m_hi). Assuming the top result from the previous step (m_lo + m_hi) that must be added to this, we get (m_lo + m_hi) << 32 again. So let's have a straight and simpler version when this is true. Otherwise some reordering allows for taking care of possible overflows without any actual conditionals. And prevent from generating both code variants by making sure this is considered only if m is perceived as constant by the compiler. This, in turn, allows for greatly simplifying __div64_const32(). The "special case" may go as well as the regular case works just fine without needing a bias. Then reduction should be applied all the time as minimizing m is the key. Signed-off-by: Nicolas Pitre Signed-off-by: Arnd Bergmann --- include/asm-generic/div64.h | 114 ++++++++++++++------------------------------ 1 file changed, 35 insertions(+), 79 deletions(-) (limited to 'include') diff --git a/include/asm-generic/div64.h b/include/asm-generic/div64.h index 13f5aa68a455..5d59cf7e73d9 100644 --- a/include/asm-generic/div64.h +++ b/include/asm-generic/div64.h @@ -74,7 +74,8 @@ * do the trick here). \ */ \ uint64_t ___res, ___x, ___t, ___m, ___n = (n); \ - uint32_t ___p, ___bias; \ + uint32_t ___p; \ + bool ___bias = false; \ \ /* determine MSB of b */ \ ___p = 1 << ilog2(___b); \ @@ -87,22 +88,14 @@ ___x = ~0ULL / ___b * ___b - 1; \ \ /* test our ___m with res = m * x / (p << 64) */ \ - ___res = ((___m & 0xffffffff) * (___x & 0xffffffff)) >> 32; \ - ___t = ___res += (___m & 0xffffffff) * (___x >> 32); \ - ___res += (___x & 0xffffffff) * (___m >> 32); \ - ___t = (___res < ___t) ? (1ULL << 32) : 0; \ - ___res = (___res >> 32) + ___t; \ - ___res += (___m >> 32) * (___x >> 32); \ - ___res /= ___p; \ + ___res = (___m & 0xffffffff) * (___x & 0xffffffff); \ + ___t = (___m & 0xffffffff) * (___x >> 32) + (___res >> 32); \ + ___res = (___m >> 32) * (___x >> 32) + (___t >> 32); \ + ___t = (___m >> 32) * (___x & 0xffffffff) + (___t & 0xffffffff);\ + ___res = (___res + (___t >> 32)) / ___p; \ \ - /* Now sanitize and optimize what we've got. */ \ - if (~0ULL % (___b / (___b & -___b)) == 0) { \ - /* special case, can be simplified to ... */ \ - ___n /= (___b & -___b); \ - ___m = ~0ULL / (___b / (___b & -___b)); \ - ___p = 1; \ - ___bias = 1; \ - } else if (___res != ___x / ___b) { \ + /* Now validate what we've got. */ \ + if (___res != ___x / ___b) { \ /* \ * We can't get away without a bias to compensate \ * for bit truncation errors. To avoid it we'd need an \ @@ -111,45 +104,18 @@ * \ * Instead we do m = p / b and n / b = (n * m + m) / p. \ */ \ - ___bias = 1; \ + ___bias = true; \ /* Compute m = (p << 64) / b */ \ ___m = (~0ULL / ___b) * ___p; \ ___m += ((~0ULL % ___b + 1) * ___p) / ___b; \ - } else { \ - /* \ - * Reduce m / p, and try to clear bit 31 of m when \ - * possible, otherwise that'll need extra overflow \ - * handling later. \ - */ \ - uint32_t ___bits = -(___m & -___m); \ - ___bits |= ___m >> 32; \ - ___bits = (~___bits) << 1; \ - /* \ - * If ___bits == 0 then setting bit 31 is unavoidable. \ - * Simply apply the maximum possible reduction in that \ - * case. Otherwise the MSB of ___bits indicates the \ - * best reduction we should apply. \ - */ \ - if (!___bits) { \ - ___p /= (___m & -___m); \ - ___m /= (___m & -___m); \ - } else { \ - ___p >>= ilog2(___bits); \ - ___m >>= ilog2(___bits); \ - } \ - /* No bias needed. */ \ - ___bias = 0; \ } \ \ + /* Reduce m / p to help avoid overflow handling later. */ \ + ___p /= (___m & -___m); \ + ___m /= (___m & -___m); \ + \ /* \ - * Now we have a combination of 2 conditions: \ - * \ - * 1) whether or not we need to apply a bias, and \ - * \ - * 2) whether or not there might be an overflow in the cross \ - * product determined by (___m & ((1 << 63) | (1 << 31))). \ - * \ - * Select the best way to do (m_bias + m * n) / (1 << 64). \ + * Perform (m_bias + m * n) / (1 << 64). \ * From now on there will be actual runtime code generated. \ */ \ ___res = __arch_xprod_64(___m, ___n, ___bias); \ @@ -165,7 +131,7 @@ * Semantic: retval = ((bias ? m : 0) + m * n) >> 64 * * The product is a 128-bit value, scaled down to 64 bits. - * Assuming constant propagation to optimize away unused conditional code. + * Hoping for compile-time optimization of conditional code. * Architectures may provide their own optimized assembly implementation. */ static inline uint64_t __arch_xprod_64(const uint64_t m, uint64_t n, bool bias) @@ -174,38 +140,28 @@ static inline uint64_t __arch_xprod_64(const uint64_t m, uint64_t n, bool bias) uint32_t m_hi = m >> 32; uint32_t n_lo = n; uint32_t n_hi = n >> 32; - uint64_t res; - uint32_t res_lo, res_hi, tmp; - - if (!bias) { - res = ((uint64_t)m_lo * n_lo) >> 32; - } else if (!(m & ((1ULL << 63) | (1ULL << 31)))) { - /* there can't be any overflow here */ - res = (m + (uint64_t)m_lo * n_lo) >> 32; - } else { - res = m + (uint64_t)m_lo * n_lo; - res_lo = res >> 32; - res_hi = (res_lo < m_hi); - res = res_lo | ((uint64_t)res_hi << 32); - } - - if (!(m & ((1ULL << 63) | (1ULL << 31)))) { - /* there can't be any overflow here */ - res += (uint64_t)m_lo * n_hi; - res += (uint64_t)m_hi * n_lo; - res >>= 32; + uint64_t x, y; + + /* Determine if overflow handling can be dispensed with. */ + bool no_ovf = __builtin_constant_p(m) && + ((m >> 32) + (m & 0xffffffff) < 0x100000000); + + if (no_ovf) { + x = (uint64_t)m_lo * n_lo + (bias ? m : 0); + x >>= 32; + x += (uint64_t)m_lo * n_hi; + x += (uint64_t)m_hi * n_lo; + x >>= 32; + x += (uint64_t)m_hi * n_hi; } else { - res += (uint64_t)m_lo * n_hi; - tmp = res >> 32; - res += (uint64_t)m_hi * n_lo; - res_lo = res >> 32; - res_hi = (res_lo < tmp); - res = res_lo | ((uint64_t)res_hi << 32); + x = (uint64_t)m_lo * n_lo + (bias ? m_lo : 0); + y = (uint64_t)m_lo * n_hi + (uint32_t)(x >> 32) + (bias ? m_hi : 0); + x = (uint64_t)m_hi * n_hi + (uint32_t)(y >> 32); + y = (uint64_t)m_hi * n_lo + (uint32_t)y; + x += (uint32_t)(y >> 32); } - res += (uint64_t)m_hi * n_hi; - - return res; + return x; } #endif -- cgit v1.2.3 From d533cb2d2af400f4689d8c5ca41db6d83ff173be Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 3 Oct 2024 17:16:16 -0400 Subject: __arch_xprod64(): make __always_inline when optimizing for performance Recent gcc versions started not systematically inline __arch_xprod64() and that has performance implications. Give the compiler the freedom to decide only when optimizing for size. Here's some timing numbers from lib/math/test_div64.c Using __always_inline: ``` test_div64: Starting 64bit/32bit division and modulo test test_div64: Completed 64bit/32bit division and modulo test, 0.048285584s elapsed ``` Without __always_inline: ``` test_div64: Starting 64bit/32bit division and modulo test test_div64: Completed 64bit/32bit division and modulo test, 0.053023584s elapsed ``` Forcing constant base through the non-constant base code path: ``` test_div64: Starting 64bit/32bit division and modulo test test_div64: Completed 64bit/32bit division and modulo test, 0.103263776s elapsed ``` It is worth noting that test_div64 does half the test with non constant divisors already so the impact is greater than what those numbers show. And for what it is worth, those numbers were obtained using QEMU. The gcc version is 14.1.0. Signed-off-by: Nicolas Pitre Signed-off-by: Arnd Bergmann --- arch/arm/include/asm/div64.h | 7 ++++++- include/asm-generic/div64.h | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/arch/arm/include/asm/div64.h b/arch/arm/include/asm/div64.h index 562d5376ae7a..d3ef8e416b27 100644 --- a/arch/arm/include/asm/div64.h +++ b/arch/arm/include/asm/div64.h @@ -52,7 +52,12 @@ static inline uint32_t __div64_32(uint64_t *n, uint32_t base) #else -static inline uint64_t __arch_xprod_64(uint64_t m, uint64_t n, bool bias) +#ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE +static __always_inline +#else +static inline +#endif +uint64_t __arch_xprod_64(uint64_t m, uint64_t n, bool bias) { unsigned long long res; register unsigned int tmp asm("ip") = 0; diff --git a/include/asm-generic/div64.h b/include/asm-generic/div64.h index 5d59cf7e73d9..25e7b4b58dcf 100644 --- a/include/asm-generic/div64.h +++ b/include/asm-generic/div64.h @@ -134,7 +134,12 @@ * Hoping for compile-time optimization of conditional code. * Architectures may provide their own optimized assembly implementation. */ -static inline uint64_t __arch_xprod_64(const uint64_t m, uint64_t n, bool bias) +#ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE +static __always_inline +#else +static inline +#endif +uint64_t __arch_xprod_64(const uint64_t m, uint64_t n, bool bias) { uint32_t m_lo = m; uint32_t m_hi = m >> 32; -- cgit v1.2.3 From b660d0a2acb9053d627befbb259a397d26aa9582 Mon Sep 17 00:00:00 2001 From: Julian Vetter Date: Mon, 28 Oct 2024 14:42:24 +0100 Subject: New implementation for IO memcpy and IO memset The IO memcpy and IO memset functions in asm-generic/io.h simply call memcpy and memset. This can lead to alignment problems or faults on architectures that do not define their own version and fall back to these defaults. This patch introduces new implementations for IO memcpy and IO memset, that use read{l,q} accessor functions, align accesses to machine word size, and resort to byte accesses when the target memory is not aligned. For new architectures and existing ones that were using the old fallbacks these functions are save to use, because IO memory constraints are taken into account. Moreover, architectures with similar implementations can now use these new versions, not needing to implement their own. Reviewed-by: Yann Sionneau Signed-off-by: Julian Vetter Signed-off-by: Arnd Bergmann --- include/asm-generic/io.h | 22 ++------ lib/Makefile | 2 +- lib/iomem_copy.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 140 insertions(+), 20 deletions(-) create mode 100644 lib/iomem_copy.c (limited to 'include') diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h index 1027be6a62bc..a5cbbf3e26ec 100644 --- a/include/asm-generic/io.h +++ b/include/asm-generic/io.h @@ -1211,7 +1211,6 @@ static inline void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr) #endif #ifndef memset_io -#define memset_io memset_io /** * memset_io Set a range of I/O memory to a constant value * @addr: The beginning of the I/O-memory range to set @@ -1220,15 +1219,10 @@ static inline void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr) * * Set a range of I/O memory to a given value. */ -static inline void memset_io(volatile void __iomem *addr, int value, - size_t size) -{ - memset(__io_virt(addr), value, size); -} +void memset_io(volatile void __iomem *addr, int val, size_t count); #endif #ifndef memcpy_fromio -#define memcpy_fromio memcpy_fromio /** * memcpy_fromio Copy a block of data from I/O memory * @dst: The (RAM) destination for the copy @@ -1237,16 +1231,10 @@ static inline void memset_io(volatile void __iomem *addr, int value, * * Copy a block of data from I/O memory. */ -static inline void memcpy_fromio(void *buffer, - const volatile void __iomem *addr, - size_t size) -{ - memcpy(buffer, __io_virt(addr), size); -} +void memcpy_fromio(void *dst, const volatile void __iomem *src, size_t count); #endif #ifndef memcpy_toio -#define memcpy_toio memcpy_toio /** * memcpy_toio Copy a block of data into I/O memory * @dst: The (I/O memory) destination for the copy @@ -1255,11 +1243,7 @@ static inline void memcpy_fromio(void *buffer, * * Copy a block of data to I/O memory. */ -static inline void memcpy_toio(volatile void __iomem *addr, const void *buffer, - size_t size) -{ - memcpy(__io_virt(addr), buffer, size); -} +void memcpy_toio(volatile void __iomem *dst, const void *src, size_t count); #endif extern int devmem_is_allowed(unsigned long pfn); diff --git a/lib/Makefile b/lib/Makefile index 773adf88af41..db4717538fad 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -35,7 +35,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \ is_single_threaded.o plist.o decompress.o kobject_uevent.o \ earlycpio.o seq_buf.o siphash.o dec_and_lock.o \ nmi_backtrace.o win_minmax.o memcat_p.o \ - buildid.o objpool.o union_find.o + buildid.o objpool.o union_find.o iomem_copy.o lib-$(CONFIG_PRINTK) += dump_stack.o lib-$(CONFIG_SMP) += cpumask.o diff --git a/lib/iomem_copy.c b/lib/iomem_copy.c new file mode 100644 index 000000000000..24c2b59a0ad2 --- /dev/null +++ b/lib/iomem_copy.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright 2024 Kalray, Inc. All Rights Reserved. + */ + +#include +#include +#include +#include +#include + +#ifndef memset_io +/** + * memset_io Set a range of I/O memory to a constant value + * @addr: The beginning of the I/O-memory range to set + * @val: The value to set the memory to + * @count: The number of bytes to set + * + * Set a range of I/O memory to a given value. + */ +void memset_io(volatile void __iomem *addr, int val, size_t count) +{ + long qc = (u8)val; + + qc *= ~0UL / 0xff; + + while (count && !IS_ALIGNED((long)addr, sizeof(long))) { + __raw_writeb(val, addr); + addr++; + count--; + } + + while (count >= sizeof(long)) { +#ifdef CONFIG_64BIT + __raw_writeq(qc, addr); +#else + __raw_writel(qc, addr); +#endif + + addr += sizeof(long); + count -= sizeof(long); + } + + while (count) { + __raw_writeb(val, addr); + addr++; + count--; + } +} +EXPORT_SYMBOL(memset_io); +#endif + +#ifndef memcpy_fromio +/** + * memcpy_fromio Copy a block of data from I/O memory + * @dst: The (RAM) destination for the copy + * @src: The (I/O memory) source for the data + * @count: The number of bytes to copy + * + * Copy a block of data from I/O memory. + */ +void memcpy_fromio(void *dst, const volatile void __iomem *src, size_t count) +{ + while (count && !IS_ALIGNED((long)src, sizeof(long))) { + *(u8 *)dst = __raw_readb(src); + src++; + dst++; + count--; + } + + while (count >= sizeof(long)) { +#ifdef CONFIG_64BIT + long val = __raw_readq(src); +#else + long val = __raw_readl(src); +#endif + put_unaligned(val, (long *)dst); + + + src += sizeof(long); + dst += sizeof(long); + count -= sizeof(long); + } + + while (count) { + *(u8 *)dst = __raw_readb(src); + src++; + dst++; + count--; + } +} +EXPORT_SYMBOL(memcpy_fromio); +#endif + +#ifndef memcpy_toio +/** + * memcpy_toio Copy a block of data into I/O memory + * @dst: The (I/O memory) destination for the copy + * @src: The (RAM) source for the data + * @count: The number of bytes to copy + * + * Copy a block of data to I/O memory. + */ +void memcpy_toio(volatile void __iomem *dst, const void *src, size_t count) +{ + while (count && !IS_ALIGNED((long)dst, sizeof(long))) { + __raw_writeb(*(u8 *)src, dst); + src++; + dst++; + count--; + } + + while (count >= sizeof(long)) { + long val = get_unaligned((long *)src); +#ifdef CONFIG_64BIT + __raw_writeq(val, dst); +#else + __raw_writel(val, dst); +#endif + + src += sizeof(long); + dst += sizeof(long); + count -= sizeof(long); + } + + while (count) { + __raw_writeb(*(u8 *)src, dst); + src++; + dst++; + count--; + } +} +EXPORT_SYMBOL(memcpy_toio); +#endif + + -- cgit v1.2.3 From fb56007c9bc38550755a53f7afd71a287340b724 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 6 Nov 2024 06:10:19 +0000 Subject: vt_buffer.h: get rid of dead code in default scr_...() instances Only 4 architectures define VT_BUF_HAVE_RW (alpha, mips, powerpc, sparc) and all of them define VT_BUF_HAVE_MEM{SET,CPY,MOVE}W. In other words, the code under #ifdef VT_BUF_HAVE_RW in default scr_mem...w() instances won't be compiled anyway. Signed-off-by: Al Viro Signed-off-by: Arnd Bergmann --- include/linux/vt_buffer.h | 24 ------------------------ 1 file changed, 24 deletions(-) (limited to 'include') diff --git a/include/linux/vt_buffer.h b/include/linux/vt_buffer.h index 919d999a8c1d..b6eeb8cb6070 100644 --- a/include/linux/vt_buffer.h +++ b/include/linux/vt_buffer.h @@ -28,45 +28,21 @@ #ifndef VT_BUF_HAVE_MEMSETW static inline void scr_memsetw(u16 *s, u16 c, unsigned int count) { -#ifdef VT_BUF_HAVE_RW - count /= 2; - while (count--) - scr_writew(c, s++); -#else memset16(s, c, count / 2); -#endif } #endif #ifndef VT_BUF_HAVE_MEMCPYW static inline void scr_memcpyw(u16 *d, const u16 *s, unsigned int count) { -#ifdef VT_BUF_HAVE_RW - count /= 2; - while (count--) - scr_writew(scr_readw(s++), d++); -#else memcpy(d, s, count); -#endif } #endif #ifndef VT_BUF_HAVE_MEMMOVEW static inline void scr_memmovew(u16 *d, const u16 *s, unsigned int count) { -#ifdef VT_BUF_HAVE_RW - if (d < s) - scr_memcpyw(d, s, count); - else { - count /= 2; - d += count; - s += count; - while (count--) - scr_writew(scr_readw(--s), --d); - } -#else memmove(d, s, count); -#endif } #endif -- cgit v1.2.3 From 0af8e32343f8d0db31f593464fc140eaef25a281 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 6 Nov 2024 06:11:47 +0000 Subject: empty include/asm-generic/vga.h all places that use anything defined in it (vgacon, mdacon and vga16fb) are built only on architectures that have all that stuff in their native asm/vga.h allows to kill stub asm/vga.h on sh, while we are at it... Signed-off-by: Al Viro Signed-off-by: Arnd Bergmann --- arch/sh/include/asm/vga.h | 7 ------- include/asm-generic/vga.h | 23 +---------------------- 2 files changed, 1 insertion(+), 29 deletions(-) delete mode 100644 arch/sh/include/asm/vga.h (limited to 'include') diff --git a/arch/sh/include/asm/vga.h b/arch/sh/include/asm/vga.h deleted file mode 100644 index 089fbdc6c0b1..000000000000 --- a/arch/sh/include/asm/vga.h +++ /dev/null @@ -1,7 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __ASM_SH_VGA_H -#define __ASM_SH_VGA_H - -/* Stupid drivers. */ - -#endif /* __ASM_SH_VGA_H */ diff --git a/include/asm-generic/vga.h b/include/asm-generic/vga.h index adf91a783b5c..5dcaf4ae904a 100644 --- a/include/asm-generic/vga.h +++ b/include/asm-generic/vga.h @@ -1,25 +1,4 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/* - * Access to VGA videoram - * - * (c) 1998 Martin Mares - */ #ifndef __ASM_GENERIC_VGA_H #define __ASM_GENERIC_VGA_H - -/* - * On most architectures that support VGA, we can just - * recalculate addresses and then access the videoram - * directly without any black magic. - * - * Everyone else needs to ioremap the address and use - * proper I/O accesses. - */ -#ifndef VGA_MAP_MEM -#define VGA_MAP_MEM(x, s) (unsigned long)phys_to_virt(x) -#endif - -#define vga_readb(x) (*(x)) -#define vga_writeb(x, y) (*(y) = (x)) - -#endif /* _ASM_GENERIC_VGA_H */ +#endif /* __ASM_GENERIC_VGA_H */ -- cgit v1.2.3