From 82719d0e7584bf78aebf66fd94f12aa437c94031 Mon Sep 17 00:00:00 2001 From: Sherry Sun Date: Wed, 12 Mar 2025 10:39:02 +0800 Subject: [PATCH 01/45] tty: serial: fsl_lpuart: Use u32 and u8 for register variables [ Upstream commit b6a8f6ab2c53e5ea3c7f2a3978db378a89bb7595 ] Use u32 and u8 rather than unsigned long or unsigned char for register variables for clarity and consistency. Signed-off-by: Sherry Sun Link: https://lore.kernel.org/r/20250312023904.1343351-2-sherry.sun@nxp.com Signed-off-by: Greg Kroah-Hartman Stable-dep-of: e98ab45ec518 ("tty: serial: lpuart: only disable CTS instead of overwriting the whole UARTMODIR register") Signed-off-by: Sasha Levin --- drivers/tty/serial/fsl_lpuart.c | 93 ++++++++++++++++----------------- 1 file changed, 46 insertions(+), 47 deletions(-) diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 9f9fc733eb2c..e86fb9c60f1c 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -440,7 +440,7 @@ static unsigned int lpuart_get_baud_clk_rate(struct lpuart_port *sport) static void lpuart_stop_tx(struct uart_port *port) { - unsigned char temp; + u8 temp; temp = readb(port->membase + UARTCR2); temp &= ~(UARTCR2_TIE | UARTCR2_TCIE); @@ -449,7 +449,7 @@ static void lpuart_stop_tx(struct uart_port *port) static void lpuart32_stop_tx(struct uart_port *port) { - unsigned long temp; + u32 temp; temp = lpuart32_read(port, UARTCTRL); temp &= ~(UARTCTRL_TIE | UARTCTRL_TCIE); @@ -458,7 +458,7 @@ static void lpuart32_stop_tx(struct uart_port *port) static void lpuart_stop_rx(struct uart_port *port) { - unsigned char temp; + u8 temp; temp = readb(port->membase + UARTCR2); writeb(temp & ~UARTCR2_RE, port->membase + UARTCR2); @@ -466,7 +466,7 @@ static void lpuart_stop_rx(struct uart_port *port) static void lpuart32_stop_rx(struct uart_port *port) { - unsigned long temp; + u32 temp; temp = lpuart32_read(port, UARTCTRL); lpuart32_write(port, temp & ~UARTCTRL_RE, UARTCTRL); @@ -641,7 +641,7 @@ static int lpuart_poll_init(struct uart_port *port) struct lpuart_port *sport = container_of(port, struct lpuart_port, port); unsigned long flags; - unsigned char temp; + u8 temp; sport->port.fifosize = 0; @@ -751,7 +751,7 @@ static inline void lpuart_transmit_buffer(struct lpuart_port *sport) static inline void lpuart32_transmit_buffer(struct lpuart_port *sport) { struct tty_port *tport = &sport->port.state->port; - unsigned long txcnt; + u32 txcnt; unsigned char c; if (sport->port.x_char) { @@ -788,7 +788,7 @@ static void lpuart_start_tx(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); - unsigned char temp; + u8 temp; temp = readb(port->membase + UARTCR2); writeb(temp | UARTCR2_TIE, port->membase + UARTCR2); @@ -805,7 +805,7 @@ static void lpuart_start_tx(struct uart_port *port) static void lpuart32_start_tx(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); - unsigned long temp; + u32 temp; if (sport->lpuart_dma_tx_use) { if (!lpuart_stopped_or_empty(port)) @@ -838,8 +838,8 @@ static unsigned int lpuart_tx_empty(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); - unsigned char sr1 = readb(port->membase + UARTSR1); - unsigned char sfifo = readb(port->membase + UARTSFIFO); + u8 sr1 = readb(port->membase + UARTSR1); + u8 sfifo = readb(port->membase + UARTSFIFO); if (sport->dma_tx_in_progress) return 0; @@ -854,9 +854,9 @@ static unsigned int lpuart32_tx_empty(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); - unsigned long stat = lpuart32_read(port, UARTSTAT); - unsigned long sfifo = lpuart32_read(port, UARTFIFO); - unsigned long ctrl = lpuart32_read(port, UARTCTRL); + u32 stat = lpuart32_read(port, UARTSTAT); + u32 sfifo = lpuart32_read(port, UARTFIFO); + u32 ctrl = lpuart32_read(port, UARTCTRL); if (sport->dma_tx_in_progress) return 0; @@ -883,7 +883,7 @@ static void lpuart_rxint(struct lpuart_port *sport) { unsigned int flg, ignored = 0, overrun = 0; struct tty_port *port = &sport->port.state->port; - unsigned char rx, sr; + u8 rx, sr; uart_port_lock(&sport->port); @@ -960,7 +960,7 @@ static void lpuart32_rxint(struct lpuart_port *sport) { unsigned int flg, ignored = 0; struct tty_port *port = &sport->port.state->port; - unsigned long rx, sr; + u32 rx, sr; bool is_break; uart_port_lock(&sport->port); @@ -1038,7 +1038,7 @@ out: static irqreturn_t lpuart_int(int irq, void *dev_id) { struct lpuart_port *sport = dev_id; - unsigned char sts; + u8 sts; sts = readb(sport->port.membase + UARTSR1); @@ -1112,7 +1112,7 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) int count, copied; if (lpuart_is_32(sport)) { - unsigned long sr = lpuart32_read(&sport->port, UARTSTAT); + u32 sr = lpuart32_read(&sport->port, UARTSTAT); if (sr & (UARTSTAT_PE | UARTSTAT_FE)) { /* Clear the error flags */ @@ -1124,10 +1124,10 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) sport->port.icount.frame++; } } else { - unsigned char sr = readb(sport->port.membase + UARTSR1); + u8 sr = readb(sport->port.membase + UARTSR1); if (sr & (UARTSR1_PE | UARTSR1_FE)) { - unsigned char cr2; + u8 cr2; /* Disable receiver during this operation... */ cr2 = readb(sport->port.membase + UARTCR2); @@ -1278,7 +1278,7 @@ static void lpuart32_dma_idleint(struct lpuart_port *sport) static irqreturn_t lpuart32_int(int irq, void *dev_id) { struct lpuart_port *sport = dev_id; - unsigned long sts, rxcount; + u32 sts, rxcount; sts = lpuart32_read(&sport->port, UARTSTAT); rxcount = lpuart32_read(&sport->port, UARTWATER); @@ -1410,12 +1410,12 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport) dma_async_issue_pending(chan); if (lpuart_is_32(sport)) { - unsigned long temp = lpuart32_read(&sport->port, UARTBAUD); + u32 temp = lpuart32_read(&sport->port, UARTBAUD); lpuart32_write(&sport->port, temp | UARTBAUD_RDMAE, UARTBAUD); if (sport->dma_idle_int) { - unsigned long ctrl = lpuart32_read(&sport->port, UARTCTRL); + u32 ctrl = lpuart32_read(&sport->port, UARTCTRL); lpuart32_write(&sport->port, ctrl | UARTCTRL_ILIE, UARTCTRL); } @@ -1481,7 +1481,7 @@ static int lpuart32_config_rs485(struct uart_port *port, struct ktermios *termio struct lpuart_port *sport = container_of(port, struct lpuart_port, port); - unsigned long modem = lpuart32_read(&sport->port, UARTMODIR) + u32 modem = lpuart32_read(&sport->port, UARTMODIR) & ~(UARTMODIR_TXRTSPOL | UARTMODIR_TXRTSE); u32 ctrl; @@ -1576,7 +1576,7 @@ static void lpuart32_set_mctrl(struct uart_port *port, unsigned int mctrl) static void lpuart_break_ctl(struct uart_port *port, int break_state) { - unsigned char temp; + u8 temp; temp = readb(port->membase + UARTCR2) & ~UARTCR2_SBK; @@ -1588,7 +1588,7 @@ static void lpuart_break_ctl(struct uart_port *port, int break_state) static void lpuart32_break_ctl(struct uart_port *port, int break_state) { - unsigned long temp; + u32 temp; temp = lpuart32_read(port, UARTCTRL); @@ -1622,8 +1622,7 @@ static void lpuart32_break_ctl(struct uart_port *port, int break_state) static void lpuart_setup_watermark(struct lpuart_port *sport) { - unsigned char val, cr2; - unsigned char cr2_saved; + u8 val, cr2, cr2_saved; cr2 = readb(sport->port.membase + UARTCR2); cr2_saved = cr2; @@ -1656,7 +1655,7 @@ static void lpuart_setup_watermark(struct lpuart_port *sport) static void lpuart_setup_watermark_enable(struct lpuart_port *sport) { - unsigned char cr2; + u8 cr2; lpuart_setup_watermark(sport); @@ -1667,8 +1666,7 @@ static void lpuart_setup_watermark_enable(struct lpuart_port *sport) static void lpuart32_setup_watermark(struct lpuart_port *sport) { - unsigned long val, ctrl; - unsigned long ctrl_saved; + u32 val, ctrl, ctrl_saved; ctrl = lpuart32_read(&sport->port, UARTCTRL); ctrl_saved = ctrl; @@ -1777,7 +1775,7 @@ err: static void lpuart_rx_dma_startup(struct lpuart_port *sport) { int ret; - unsigned char cr3; + u8 cr3; if (uart_console(&sport->port)) goto err; @@ -1827,7 +1825,7 @@ static void lpuart_hw_setup(struct lpuart_port *sport) static int lpuart_startup(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); - unsigned char temp; + u8 temp; /* determine FIFO size and enable FIFO mode */ temp = readb(sport->port.membase + UARTPFIFO); @@ -1847,7 +1845,7 @@ static int lpuart_startup(struct uart_port *port) static void lpuart32_hw_disable(struct lpuart_port *sport) { - unsigned long temp; + u32 temp; temp = lpuart32_read(&sport->port, UARTCTRL); temp &= ~(UARTCTRL_RIE | UARTCTRL_ILIE | UARTCTRL_RE | @@ -1857,7 +1855,7 @@ static void lpuart32_hw_disable(struct lpuart_port *sport) static void lpuart32_configure(struct lpuart_port *sport) { - unsigned long temp; + u32 temp; temp = lpuart32_read(&sport->port, UARTCTRL); if (!sport->lpuart_dma_rx_use) @@ -1887,7 +1885,7 @@ static void lpuart32_hw_setup(struct lpuart_port *sport) static int lpuart32_startup(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); - unsigned long temp; + u32 temp; /* determine FIFO size */ temp = lpuart32_read(&sport->port, UARTFIFO); @@ -1941,7 +1939,7 @@ static void lpuart_dma_shutdown(struct lpuart_port *sport) static void lpuart_shutdown(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); - unsigned char temp; + u8 temp; unsigned long flags; uart_port_lock_irqsave(port, &flags); @@ -1961,7 +1959,7 @@ static void lpuart32_shutdown(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); - unsigned long temp; + u32 temp; unsigned long flags; uart_port_lock_irqsave(port, &flags); @@ -1992,7 +1990,7 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); unsigned long flags; - unsigned char cr1, old_cr1, old_cr2, cr3, cr4, bdh, modem; + u8 cr1, old_cr1, old_cr2, cr3, cr4, bdh, modem; unsigned int baud; unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; unsigned int sbr, brfa; @@ -2230,7 +2228,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); unsigned long flags; - unsigned long ctrl, old_ctrl, bd, modem; + u32 ctrl, old_ctrl, bd, modem; unsigned int baud; unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; @@ -2487,7 +2485,7 @@ static void lpuart_console_write(struct console *co, const char *s, unsigned int count) { struct lpuart_port *sport = lpuart_ports[co->index]; - unsigned char old_cr2, cr2; + u8 old_cr2, cr2; unsigned long flags; int locked = 1; @@ -2517,7 +2515,7 @@ static void lpuart32_console_write(struct console *co, const char *s, unsigned int count) { struct lpuart_port *sport = lpuart_ports[co->index]; - unsigned long old_cr, cr; + u32 old_cr, cr; unsigned long flags; int locked = 1; @@ -2551,7 +2549,7 @@ static void __init lpuart_console_get_options(struct lpuart_port *sport, int *baud, int *parity, int *bits) { - unsigned char cr, bdh, bdl, brfa; + u8 cr, bdh, bdl, brfa; unsigned int sbr, uartclk, baud_raw; cr = readb(sport->port.membase + UARTCR2); @@ -2600,7 +2598,7 @@ static void __init lpuart32_console_get_options(struct lpuart_port *sport, int *baud, int *parity, int *bits) { - unsigned long cr, bd; + u32 cr, bd; unsigned int sbr, uartclk, baud_raw; cr = lpuart32_read(&sport->port, UARTCTRL); @@ -2806,7 +2804,7 @@ static int lpuart_global_reset(struct lpuart_port *sport) { struct uart_port *port = &sport->port; void __iomem *global_addr; - unsigned long ctrl, bd; + u32 ctrl, bd; unsigned int val = 0; int ret; @@ -3012,7 +3010,7 @@ static int lpuart_runtime_resume(struct device *dev) static void serial_lpuart_enable_wakeup(struct lpuart_port *sport, bool on) { - unsigned int val, baud; + u32 val, baud; if (lpuart_is_32(sport)) { val = lpuart32_read(&sport->port, UARTCTRL); @@ -3077,7 +3075,7 @@ static int lpuart_suspend_noirq(struct device *dev) static int lpuart_resume_noirq(struct device *dev) { struct lpuart_port *sport = dev_get_drvdata(dev); - unsigned int val; + u32 val; pinctrl_pm_select_default_state(dev); @@ -3097,7 +3095,8 @@ static int lpuart_resume_noirq(struct device *dev) static int lpuart_suspend(struct device *dev) { struct lpuart_port *sport = dev_get_drvdata(dev); - unsigned long temp, flags; + u32 temp; + unsigned long flags; uart_suspend_port(&lpuart_reg, &sport->port); From ac08fa36d8cbcdbe39eb490fc2dd4345d50a433c Mon Sep 17 00:00:00 2001 From: Sherry Sun Date: Wed, 12 Mar 2025 10:39:03 +0800 Subject: [PATCH 02/45] tty: serial: fsl_lpuart: use port struct directly to simply code commit 3cc16ae096f164ae0c6b98416c25a01db5f3a529 upstream. Most lpuart functions have the parameter struct uart_port *port, but still use the &sport->port to get the uart_port instead of use it directly, let's simply the code logic, directly use this struct instead of covert it from struct sport. Signed-off-by: Sherry Sun Link: https://lore.kernel.org/r/20250312023904.1343351-3-sherry.sun@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 210 ++++++++++++++++---------------- 1 file changed, 102 insertions(+), 108 deletions(-) diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index e86fb9c60f1c..029f49a4a00c 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -580,7 +580,7 @@ static int lpuart_dma_tx_request(struct uart_port *port) ret = dmaengine_slave_config(sport->dma_tx_chan, &dma_tx_sconfig); if (ret) { - dev_err(sport->port.dev, + dev_err(port->dev, "DMA slave config failed, err = %d\n", ret); return ret; } @@ -610,13 +610,13 @@ static void lpuart_flush_buffer(struct uart_port *port) } if (lpuart_is_32(sport)) { - val = lpuart32_read(&sport->port, UARTFIFO); + val = lpuart32_read(port, UARTFIFO); val |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH; - lpuart32_write(&sport->port, val, UARTFIFO); + lpuart32_write(port, val, UARTFIFO); } else { - val = readb(sport->port.membase + UARTCFIFO); + val = readb(port->membase + UARTCFIFO); val |= UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH; - writeb(val, sport->port.membase + UARTCFIFO); + writeb(val, port->membase + UARTCFIFO); } } @@ -643,33 +643,33 @@ static int lpuart_poll_init(struct uart_port *port) unsigned long flags; u8 temp; - sport->port.fifosize = 0; + port->fifosize = 0; - uart_port_lock_irqsave(&sport->port, &flags); + uart_port_lock_irqsave(port, &flags); /* Disable Rx & Tx */ - writeb(0, sport->port.membase + UARTCR2); + writeb(0, port->membase + UARTCR2); - temp = readb(sport->port.membase + UARTPFIFO); + temp = readb(port->membase + UARTPFIFO); /* Enable Rx and Tx FIFO */ writeb(temp | UARTPFIFO_RXFE | UARTPFIFO_TXFE, - sport->port.membase + UARTPFIFO); + port->membase + UARTPFIFO); /* flush Tx and Rx FIFO */ writeb(UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH, - sport->port.membase + UARTCFIFO); + port->membase + UARTCFIFO); /* explicitly clear RDRF */ - if (readb(sport->port.membase + UARTSR1) & UARTSR1_RDRF) { - readb(sport->port.membase + UARTDR); - writeb(UARTSFIFO_RXUF, sport->port.membase + UARTSFIFO); + if (readb(port->membase + UARTSR1) & UARTSR1_RDRF) { + readb(port->membase + UARTDR); + writeb(UARTSFIFO_RXUF, port->membase + UARTSFIFO); } - writeb(0, sport->port.membase + UARTTWFIFO); - writeb(1, sport->port.membase + UARTRWFIFO); + writeb(0, port->membase + UARTTWFIFO); + writeb(1, port->membase + UARTRWFIFO); /* Enable Rx and Tx */ - writeb(UARTCR2_RE | UARTCR2_TE, sport->port.membase + UARTCR2); - uart_port_unlock_irqrestore(&sport->port, flags); + writeb(UARTCR2_RE | UARTCR2_TE, port->membase + UARTCR2); + uart_port_unlock_irqrestore(port, flags); return 0; } @@ -695,30 +695,30 @@ static int lpuart32_poll_init(struct uart_port *port) struct lpuart_port *sport = container_of(port, struct lpuart_port, port); u32 temp; - sport->port.fifosize = 0; + port->fifosize = 0; - uart_port_lock_irqsave(&sport->port, &flags); + uart_port_lock_irqsave(port, &flags); /* Disable Rx & Tx */ - lpuart32_write(&sport->port, 0, UARTCTRL); + lpuart32_write(port, 0, UARTCTRL); - temp = lpuart32_read(&sport->port, UARTFIFO); + temp = lpuart32_read(port, UARTFIFO); /* Enable Rx and Tx FIFO */ - lpuart32_write(&sport->port, temp | UARTFIFO_RXFE | UARTFIFO_TXFE, UARTFIFO); + lpuart32_write(port, temp | UARTFIFO_RXFE | UARTFIFO_TXFE, UARTFIFO); /* flush Tx and Rx FIFO */ - lpuart32_write(&sport->port, UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH, UARTFIFO); + lpuart32_write(port, UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH, UARTFIFO); /* explicitly clear RDRF */ - if (lpuart32_read(&sport->port, UARTSTAT) & UARTSTAT_RDRF) { - lpuart32_read(&sport->port, UARTDATA); - lpuart32_write(&sport->port, UARTFIFO_RXUF, UARTFIFO); + if (lpuart32_read(port, UARTSTAT) & UARTSTAT_RDRF) { + lpuart32_read(port, UARTDATA); + lpuart32_write(port, UARTFIFO_RXUF, UARTFIFO); } /* Enable Rx and Tx */ - lpuart32_write(&sport->port, UARTCTRL_RE | UARTCTRL_TE, UARTCTRL); - uart_port_unlock_irqrestore(&sport->port, flags); + lpuart32_write(port, UARTCTRL_RE | UARTCTRL_TE, UARTCTRL); + uart_port_unlock_irqrestore(port, flags); return 0; } @@ -1448,12 +1448,9 @@ static void lpuart_dma_rx_free(struct uart_port *port) static int lpuart_config_rs485(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485) { - struct lpuart_port *sport = container_of(port, - struct lpuart_port, port); - - u8 modem = readb(sport->port.membase + UARTMODEM) & + u8 modem = readb(port->membase + UARTMODEM) & ~(UARTMODEM_TXRTSPOL | UARTMODEM_TXRTSE); - writeb(modem, sport->port.membase + UARTMODEM); + writeb(modem, port->membase + UARTMODEM); if (rs485->flags & SER_RS485_ENABLED) { /* Enable auto RS-485 RTS mode */ @@ -1471,32 +1468,29 @@ static int lpuart_config_rs485(struct uart_port *port, struct ktermios *termios, modem &= ~UARTMODEM_TXRTSPOL; } - writeb(modem, sport->port.membase + UARTMODEM); + writeb(modem, port->membase + UARTMODEM); return 0; } static int lpuart32_config_rs485(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485) { - struct lpuart_port *sport = container_of(port, - struct lpuart_port, port); - - u32 modem = lpuart32_read(&sport->port, UARTMODIR) + u32 modem = lpuart32_read(port, UARTMODIR) & ~(UARTMODIR_TXRTSPOL | UARTMODIR_TXRTSE); u32 ctrl; /* TXRTSE and TXRTSPOL only can be changed when transmitter is disabled. */ - ctrl = lpuart32_read(&sport->port, UARTCTRL); + ctrl = lpuart32_read(port, UARTCTRL); if (ctrl & UARTCTRL_TE) { /* wait for the transmit engine to complete */ - lpuart32_wait_bit_set(&sport->port, UARTSTAT, UARTSTAT_TC); - lpuart32_write(&sport->port, ctrl & ~UARTCTRL_TE, UARTCTRL); + lpuart32_wait_bit_set(port, UARTSTAT, UARTSTAT_TC); + lpuart32_write(port, ctrl & ~UARTCTRL_TE, UARTCTRL); - while (lpuart32_read(&sport->port, UARTCTRL) & UARTCTRL_TE) + while (lpuart32_read(port, UARTCTRL) & UARTCTRL_TE) cpu_relax(); } - lpuart32_write(&sport->port, modem, UARTMODIR); + lpuart32_write(port, modem, UARTMODIR); if (rs485->flags & SER_RS485_ENABLED) { /* Enable auto RS-485 RTS mode */ @@ -1514,10 +1508,10 @@ static int lpuart32_config_rs485(struct uart_port *port, struct ktermios *termio modem &= ~UARTMODIR_TXRTSPOL; } - lpuart32_write(&sport->port, modem, UARTMODIR); + lpuart32_write(port, modem, UARTMODIR); if (ctrl & UARTCTRL_TE) - lpuart32_write(&sport->port, ctrl, UARTCTRL); + lpuart32_write(port, ctrl, UARTCTRL); return 0; } @@ -1828,11 +1822,11 @@ static int lpuart_startup(struct uart_port *port) u8 temp; /* determine FIFO size and enable FIFO mode */ - temp = readb(sport->port.membase + UARTPFIFO); + temp = readb(port->membase + UARTPFIFO); sport->txfifo_size = UARTFIFO_DEPTH((temp >> UARTPFIFO_TXSIZE_OFF) & UARTPFIFO_FIFOSIZE_MASK); - sport->port.fifosize = sport->txfifo_size; + port->fifosize = sport->txfifo_size; sport->rxfifo_size = UARTFIFO_DEPTH((temp >> UARTPFIFO_RXSIZE_OFF) & UARTPFIFO_FIFOSIZE_MASK); @@ -1888,11 +1882,11 @@ static int lpuart32_startup(struct uart_port *port) u32 temp; /* determine FIFO size */ - temp = lpuart32_read(&sport->port, UARTFIFO); + temp = lpuart32_read(port, UARTFIFO); sport->txfifo_size = UARTFIFO_DEPTH((temp >> UARTFIFO_TXSIZE_OFF) & UARTFIFO_FIFOSIZE_MASK); - sport->port.fifosize = sport->txfifo_size; + port->fifosize = sport->txfifo_size; sport->rxfifo_size = UARTFIFO_DEPTH((temp >> UARTFIFO_RXSIZE_OFF) & UARTFIFO_FIFOSIZE_MASK); @@ -1905,7 +1899,7 @@ static int lpuart32_startup(struct uart_port *port) if (is_layerscape_lpuart(sport)) { sport->rxfifo_size = 16; sport->txfifo_size = 16; - sport->port.fifosize = sport->txfifo_size; + port->fifosize = sport->txfifo_size; } lpuart_request_dma(sport); @@ -1965,8 +1959,8 @@ static void lpuart32_shutdown(struct uart_port *port) uart_port_lock_irqsave(port, &flags); /* clear status */ - temp = lpuart32_read(&sport->port, UARTSTAT); - lpuart32_write(&sport->port, temp, UARTSTAT); + temp = lpuart32_read(port, UARTSTAT); + lpuart32_write(port, temp, UARTSTAT); /* disable Rx/Tx DMA */ temp = lpuart32_read(port, UARTBAUD); @@ -1995,12 +1989,12 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; unsigned int sbr, brfa; - cr1 = old_cr1 = readb(sport->port.membase + UARTCR1); - old_cr2 = readb(sport->port.membase + UARTCR2); - cr3 = readb(sport->port.membase + UARTCR3); - cr4 = readb(sport->port.membase + UARTCR4); - bdh = readb(sport->port.membase + UARTBDH); - modem = readb(sport->port.membase + UARTMODEM); + cr1 = old_cr1 = readb(port->membase + UARTCR1); + old_cr2 = readb(port->membase + UARTCR2); + cr3 = readb(port->membase + UARTCR3); + cr4 = readb(port->membase + UARTCR4); + bdh = readb(port->membase + UARTBDH); + modem = readb(port->membase + UARTMODEM); /* * only support CS8 and CS7, and for CS7 must enable PE. * supported mode: @@ -2032,7 +2026,7 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, * When auto RS-485 RTS mode is enabled, * hardware flow control need to be disabled. */ - if (sport->port.rs485.flags & SER_RS485_ENABLED) + if (port->rs485.flags & SER_RS485_ENABLED) termios->c_cflag &= ~CRTSCTS; if (termios->c_cflag & CRTSCTS) @@ -2073,59 +2067,59 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, * Need to update the Ring buffer length according to the selected * baud rate and restart Rx DMA path. * - * Since timer function acqures sport->port.lock, need to stop before + * Since timer function acqures port->lock, need to stop before * acquring same lock because otherwise del_timer_sync() can deadlock. */ if (old && sport->lpuart_dma_rx_use) - lpuart_dma_rx_free(&sport->port); + lpuart_dma_rx_free(port); - uart_port_lock_irqsave(&sport->port, &flags); + uart_port_lock_irqsave(port, &flags); - sport->port.read_status_mask = 0; + port->read_status_mask = 0; if (termios->c_iflag & INPCK) - sport->port.read_status_mask |= UARTSR1_FE | UARTSR1_PE; + port->read_status_mask |= UARTSR1_FE | UARTSR1_PE; if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) - sport->port.read_status_mask |= UARTSR1_FE; + port->read_status_mask |= UARTSR1_FE; /* characters to ignore */ - sport->port.ignore_status_mask = 0; + port->ignore_status_mask = 0; if (termios->c_iflag & IGNPAR) - sport->port.ignore_status_mask |= UARTSR1_PE; + port->ignore_status_mask |= UARTSR1_PE; if (termios->c_iflag & IGNBRK) { - sport->port.ignore_status_mask |= UARTSR1_FE; + port->ignore_status_mask |= UARTSR1_FE; /* * if we're ignoring parity and break indicators, * ignore overruns too (for real raw support). */ if (termios->c_iflag & IGNPAR) - sport->port.ignore_status_mask |= UARTSR1_OR; + port->ignore_status_mask |= UARTSR1_OR; } /* update the per-port timeout */ uart_update_timeout(port, termios->c_cflag, baud); /* wait transmit engin complete */ - lpuart_wait_bit_set(&sport->port, UARTSR1, UARTSR1_TC); + lpuart_wait_bit_set(port, UARTSR1, UARTSR1_TC); /* disable transmit and receive */ writeb(old_cr2 & ~(UARTCR2_TE | UARTCR2_RE), - sport->port.membase + UARTCR2); + port->membase + UARTCR2); - sbr = sport->port.uartclk / (16 * baud); - brfa = ((sport->port.uartclk - (16 * sbr * baud)) * 2) / baud; + sbr = port->uartclk / (16 * baud); + brfa = ((port->uartclk - (16 * sbr * baud)) * 2) / baud; bdh &= ~UARTBDH_SBR_MASK; bdh |= (sbr >> 8) & 0x1F; cr4 &= ~UARTCR4_BRFA_MASK; brfa &= UARTCR4_BRFA_MASK; - writeb(cr4 | brfa, sport->port.membase + UARTCR4); - writeb(bdh, sport->port.membase + UARTBDH); - writeb(sbr & 0xFF, sport->port.membase + UARTBDL); - writeb(cr3, sport->port.membase + UARTCR3); - writeb(cr1, sport->port.membase + UARTCR1); - writeb(modem, sport->port.membase + UARTMODEM); + writeb(cr4 | brfa, port->membase + UARTCR4); + writeb(bdh, port->membase + UARTBDH); + writeb(sbr & 0xFF, port->membase + UARTBDL); + writeb(cr3, port->membase + UARTCR3); + writeb(cr1, port->membase + UARTCR1); + writeb(modem, port->membase + UARTMODEM); /* restore control register */ - writeb(old_cr2, sport->port.membase + UARTCR2); + writeb(old_cr2, port->membase + UARTCR2); if (old && sport->lpuart_dma_rx_use) { if (!lpuart_start_rx_dma(sport)) @@ -2134,7 +2128,7 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, sport->lpuart_dma_rx_use = false; } - uart_port_unlock_irqrestore(&sport->port, flags); + uart_port_unlock_irqrestore(port, flags); } static void __lpuart32_serial_setbrg(struct uart_port *port, @@ -2232,9 +2226,9 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, unsigned int baud; unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; - ctrl = old_ctrl = lpuart32_read(&sport->port, UARTCTRL); - bd = lpuart32_read(&sport->port, UARTBAUD); - modem = lpuart32_read(&sport->port, UARTMODIR); + ctrl = old_ctrl = lpuart32_read(port, UARTCTRL); + bd = lpuart32_read(port, UARTBAUD); + modem = lpuart32_read(port, UARTMODIR); sport->is_cs7 = false; /* * only support CS8 and CS7, and for CS7 must enable PE. @@ -2267,7 +2261,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, * When auto RS-485 RTS mode is enabled, * hardware flow control need to be disabled. */ - if (sport->port.rs485.flags & SER_RS485_ENABLED) + if (port->rs485.flags & SER_RS485_ENABLED) termios->c_cflag &= ~CRTSCTS; if (termios->c_cflag & CRTSCTS) @@ -2308,32 +2302,32 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, * Need to update the Ring buffer length according to the selected * baud rate and restart Rx DMA path. * - * Since timer function acqures sport->port.lock, need to stop before + * Since timer function acqures port->lock, need to stop before * acquring same lock because otherwise del_timer_sync() can deadlock. */ if (old && sport->lpuart_dma_rx_use) - lpuart_dma_rx_free(&sport->port); + lpuart_dma_rx_free(port); - uart_port_lock_irqsave(&sport->port, &flags); + uart_port_lock_irqsave(port, &flags); - sport->port.read_status_mask = 0; + port->read_status_mask = 0; if (termios->c_iflag & INPCK) - sport->port.read_status_mask |= UARTSTAT_FE | UARTSTAT_PE; + port->read_status_mask |= UARTSTAT_FE | UARTSTAT_PE; if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) - sport->port.read_status_mask |= UARTSTAT_FE; + port->read_status_mask |= UARTSTAT_FE; /* characters to ignore */ - sport->port.ignore_status_mask = 0; + port->ignore_status_mask = 0; if (termios->c_iflag & IGNPAR) - sport->port.ignore_status_mask |= UARTSTAT_PE; + port->ignore_status_mask |= UARTSTAT_PE; if (termios->c_iflag & IGNBRK) { - sport->port.ignore_status_mask |= UARTSTAT_FE; + port->ignore_status_mask |= UARTSTAT_FE; /* * if we're ignoring parity and break indicators, * ignore overruns too (for real raw support). */ if (termios->c_iflag & IGNPAR) - sport->port.ignore_status_mask |= UARTSTAT_OR; + port->ignore_status_mask |= UARTSTAT_OR; } /* update the per-port timeout */ @@ -2345,22 +2339,22 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, * asserted. */ if (!(old_ctrl & UARTCTRL_SBK)) { - lpuart32_write(&sport->port, 0, UARTMODIR); - lpuart32_wait_bit_set(&sport->port, UARTSTAT, UARTSTAT_TC); + lpuart32_write(port, 0, UARTMODIR); + lpuart32_wait_bit_set(port, UARTSTAT, UARTSTAT_TC); } /* disable transmit and receive */ - lpuart32_write(&sport->port, old_ctrl & ~(UARTCTRL_TE | UARTCTRL_RE), + lpuart32_write(port, old_ctrl & ~(UARTCTRL_TE | UARTCTRL_RE), UARTCTRL); - lpuart32_write(&sport->port, bd, UARTBAUD); + lpuart32_write(port, bd, UARTBAUD); lpuart32_serial_setbrg(sport, baud); /* disable CTS before enabling UARTCTRL_TE to avoid pending idle preamble */ - lpuart32_write(&sport->port, modem & ~UARTMODIR_TXCTSE, UARTMODIR); + lpuart32_write(port, modem & ~UARTMODIR_TXCTSE, UARTMODIR); /* restore control register */ - lpuart32_write(&sport->port, ctrl, UARTCTRL); + lpuart32_write(port, ctrl, UARTCTRL); /* re-enable the CTS if needed */ - lpuart32_write(&sport->port, modem, UARTMODIR); + lpuart32_write(port, modem, UARTMODIR); if ((ctrl & (UARTCTRL_PE | UARTCTRL_M)) == UARTCTRL_PE) sport->is_cs7 = true; @@ -2372,7 +2366,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, sport->lpuart_dma_rx_use = false; } - uart_port_unlock_irqrestore(&sport->port, flags); + uart_port_unlock_irqrestore(port, flags); } static const char *lpuart_type(struct uart_port *port) @@ -2810,7 +2804,7 @@ static int lpuart_global_reset(struct lpuart_port *sport) ret = clk_prepare_enable(sport->ipg_clk); if (ret) { - dev_err(sport->port.dev, "failed to enable uart ipg clk: %d\n", ret); + dev_err(port->dev, "failed to enable uart ipg clk: %d\n", ret); return ret; } @@ -2821,10 +2815,10 @@ static int lpuart_global_reset(struct lpuart_port *sport) */ ctrl = lpuart32_read(port, UARTCTRL); if (ctrl & UARTCTRL_TE) { - bd = lpuart32_read(&sport->port, UARTBAUD); + bd = lpuart32_read(port, UARTBAUD); if (read_poll_timeout(lpuart32_tx_empty, val, val, 1, 100000, false, port)) { - dev_warn(sport->port.dev, + dev_warn(port->dev, "timeout waiting for transmit engine to complete\n"); clk_disable_unprepare(sport->ipg_clk); return 0; @@ -3176,7 +3170,7 @@ static void lpuart_console_fixup(struct lpuart_port *sport) * in VLLS mode, or restore console setting here. */ if (is_imx7ulp_lpuart(sport) && lpuart_uport_is_active(sport) && - console_suspend_enabled && uart_console(&sport->port)) { + console_suspend_enabled && uart_console(uport)) { mutex_lock(&port->mutex); memset(&termios, 0, sizeof(struct ktermios)); From b09ff334c168e99e09ff86b91a30f5270f87a733 Mon Sep 17 00:00:00 2001 From: Sherry Sun Date: Mon, 24 Mar 2025 10:10:51 +0800 Subject: [PATCH 03/45] tty: serial: fsl_lpuart: Fix unused variable 'sport' build warning commit 9f8fe348ac9544f6855f82565e754bf085d81f88 upstream. Remove the unused variable 'sport' to avoid the kernel build warning. Fixes: 3cc16ae096f1 ("tty: serial: fsl_lpuart: use port struct directly to simply code") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202503210614.2qGlnbIq-lkp@intel.com/ Signed-off-by: Sherry Sun Link: https://lore.kernel.org/r/20250324021051.162676-1-sherry.sun@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 029f49a4a00c..c2b522843b72 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -638,8 +638,6 @@ static void lpuart32_wait_bit_set(struct uart_port *port, unsigned int offset, static int lpuart_poll_init(struct uart_port *port) { - struct lpuart_port *sport = container_of(port, - struct lpuart_port, port); unsigned long flags; u8 temp; @@ -692,7 +690,6 @@ static int lpuart_poll_get_char(struct uart_port *port) static int lpuart32_poll_init(struct uart_port *port) { unsigned long flags; - struct lpuart_port *sport = container_of(port, struct lpuart_port, port); u32 temp; port->fifosize = 0; From 96fa2608296da9ce5d519d9741ef59e17ceb0e43 Mon Sep 17 00:00:00 2001 From: Sherry Sun Date: Fri, 7 Mar 2025 14:54:46 +0800 Subject: [PATCH 04/45] tty: serial: lpuart: only disable CTS instead of overwriting the whole UARTMODIR register [ Upstream commit e98ab45ec5182605d2e00114cba3bbf46b0ea27f ] No need to overwrite the whole UARTMODIR register before waiting the transmit engine complete, actually our target here is only to disable CTS flow control to avoid the dirty data in TX FIFO may block the transmit engine complete. Also delete the following duplicate CTS disable configuration. Fixes: d5a2e0834364 ("tty: serial: lpuart: disable flow control while waiting for the transmit engine to complete") Cc: stable Signed-off-by: Sherry Sun Link: https://lore.kernel.org/r/20250307065446.1122482-1-sherry.sun@nxp.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/tty/serial/fsl_lpuart.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index c2b522843b72..951c3cdac3b9 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -2330,15 +2330,19 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, /* update the per-port timeout */ uart_update_timeout(port, termios->c_cflag, baud); + /* + * disable CTS to ensure the transmit engine is not blocked by the flow + * control when there is dirty data in TX FIFO + */ + lpuart32_write(port, modem & ~UARTMODIR_TXCTSE, UARTMODIR); + /* * LPUART Transmission Complete Flag may never be set while queuing a break * character, so skip waiting for transmission complete when UARTCTRL_SBK is * asserted. */ - if (!(old_ctrl & UARTCTRL_SBK)) { - lpuart32_write(port, 0, UARTMODIR); + if (!(old_ctrl & UARTCTRL_SBK)) lpuart32_wait_bit_set(port, UARTSTAT, UARTSTAT_TC); - } /* disable transmit and receive */ lpuart32_write(port, old_ctrl & ~(UARTCTRL_TE | UARTCTRL_RE), @@ -2346,8 +2350,6 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, lpuart32_write(port, bd, UARTBAUD); lpuart32_serial_setbrg(sport, baud); - /* disable CTS before enabling UARTCTRL_TE to avoid pending idle preamble */ - lpuart32_write(port, modem & ~UARTMODIR_TXCTSE, UARTMODIR); /* restore control register */ lpuart32_write(port, ctrl, UARTCTRL); /* re-enable the CTS if needed */ From 86f327305ed4bb5caa95fba368cfc6f040dd7917 Mon Sep 17 00:00:00 2001 From: Alexander Wetzel Date: Thu, 13 Feb 2025 22:43:30 +0100 Subject: [PATCH 05/45] wifi: mac80211: Fix sparse warning for monitor_sdata commit 861d0445e72e9e33797f2ceef882c74decb16a87 upstream. Use rcu_access_pointer() to avoid sparse warning in drv_remove_interface(). Signed-off-by: Alexander Wetzel Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202502130534.bVrZZBK0-lkp@intel.com/ Fixes: 646262c71aca ("wifi: mac80211: remove debugfs dir for virtual monitor") Link: https://patch.msgid.link/20250213214330.6113-1-Alexander@wetzel-home.de Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/mac80211/driver-ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/driver-ops.c b/net/mac80211/driver-ops.c index 9b7d09994820..4243f8ee5ab6 100644 --- a/net/mac80211/driver-ops.c +++ b/net/mac80211/driver-ops.c @@ -120,7 +120,7 @@ void drv_remove_interface(struct ieee80211_local *local, * The virtual monitor interface doesn't get a debugfs * entry, so it's exempt here. */ - if (sdata != local->monitor_sdata) + if (sdata != rcu_access_pointer(local->monitor_sdata)) ieee80211_debugfs_recreate_netdev(sdata, sdata->vif.valid_links); From d689645cd1594ea1d13cb0c404f8ad1011353e0e Mon Sep 17 00:00:00 2001 From: Ying Lu Date: Wed, 2 Apr 2025 16:58:59 +0800 Subject: [PATCH 06/45] usbnet:fix NPE during rx_complete MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 51de3600093429e3b712e5f091d767babc5dd6df upstream. Missing usbnet_going_away Check in Critical Path. The usb_submit_urb function lacks a usbnet_going_away validation, whereas __usbnet_queue_skb includes this check. This inconsistency creates a race condition where: A URB request may succeed, but the corresponding SKB data fails to be queued. Subsequent processes: (e.g., rx_complete → defer_bh → __skb_unlink(skb, list)) attempt to access skb->next, triggering a NULL pointer dereference (Kernel Panic). Fixes: 04e906839a05 ("usbnet: fix cyclical race on disconnect with work queue") Cc: stable@vger.kernel.org Signed-off-by: Ying Lu Link: https://patch.msgid.link/4c9ef2efaa07eb7f9a5042b74348a67e5a3a7aea.1743584159.git.luying1@xiaomi.com Signed-off-by: Jakub Kicinski Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/usbnet.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index aeab2308b150..724b93aa4f7e 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -530,7 +530,8 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) netif_device_present (dev->net) && test_bit(EVENT_DEV_OPEN, &dev->flags) && !test_bit (EVENT_RX_HALT, &dev->flags) && - !test_bit (EVENT_DEV_ASLEEP, &dev->flags)) { + !test_bit (EVENT_DEV_ASLEEP, &dev->flags) && + !usbnet_going_away(dev)) { switch (retval = usb_submit_urb (urb, GFP_ATOMIC)) { case -EPIPE: usbnet_defer_kevent (dev, EVENT_RX_HALT); @@ -551,8 +552,7 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) tasklet_schedule (&dev->bh); break; case 0: - if (!usbnet_going_away(dev)) - __usbnet_queue_skb(&dev->rxq, skb, rx_start); + __usbnet_queue_skb(&dev->rxq, skb, rx_start); } } else { netif_dbg(dev, ifdown, dev->net, "rx: stopped\n"); From dc07c4698587bc9e1040a24d9a4e739c4f2caa75 Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Sun, 30 Mar 2025 16:30:20 +0800 Subject: [PATCH 07/45] rust: Fix enabling Rust and building with GCC for LoongArch commit 13c23cb4ed09466d73f1beae8956810b95add6ef upstream. This patch fixes a build issue on LoongArch when Rust is enabled and compiled with GCC by explicitly setting the bindgen target and skipping C flags that Clang doesn't support. Cc: stable@vger.kernel.org Acked-by: Miguel Ojeda Signed-off-by: WANG Rui Signed-off-by: Huacai Chen Signed-off-by: Greg Kroah-Hartman --- rust/Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rust/Makefile b/rust/Makefile index 09521fc449dc..1b00e16951ee 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -227,7 +227,8 @@ bindgen_skip_c_flags := -mno-fp-ret-in-387 -mpreferred-stack-boundary=% \ -mfunction-return=thunk-extern -mrecord-mcount -mabi=lp64 \ -mindirect-branch-cs-prefix -mstack-protector-guard% -mtraceback=no \ -mno-pointers-to-nested-functions -mno-string \ - -mno-strict-align -mstrict-align \ + -mno-strict-align -mstrict-align -mdirect-extern-access \ + -mexplicit-relocs -mno-check-zero-division \ -fconserve-stack -falign-jumps=% -falign-loops=% \ -femit-struct-debug-baseonly -fno-ipa-cp-clone -fno-ipa-sra \ -fno-partial-inlining -fplugin-arg-arm_ssp_per_task_plugin-% \ @@ -241,6 +242,7 @@ bindgen_skip_c_flags := -mno-fp-ret-in-387 -mpreferred-stack-boundary=% \ # Derived from `scripts/Makefile.clang`. BINDGEN_TARGET_x86 := x86_64-linux-gnu BINDGEN_TARGET_arm64 := aarch64-linux-gnu +BINDGEN_TARGET_loongarch := loongarch64-linux-gnusf BINDGEN_TARGET := $(BINDGEN_TARGET_$(SRCARCH)) # All warnings are inhibited since GCC builds are very experimental, From 1d0def2d1658666ec1f32c9495df60e7411e3c82 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Sun, 30 Mar 2025 16:31:09 +0800 Subject: [PATCH 08/45] LoongArch: Increase ARCH_DMA_MINALIGN up to 16 commit 4103cfe9dcb88010ae4911d3ff417457d1b6a720 upstream. ARCH_DMA_MINALIGN is 1 by default, but some LoongArch-specific devices (such as APBDMA) require 16 bytes alignment. When the data buffer length is too small, the hardware may make an error writing cacheline. Thus, it is dangerous to allocate a small memory buffer for DMA. It's always safe to define ARCH_DMA_MINALIGN as L1_CACHE_BYTES but unnecessary (kmalloc() need small memory objects). Therefore, just increase it to 16. Cc: stable@vger.kernel.org Tested-by: Binbin Zhou Signed-off-by: Huacai Chen Signed-off-by: Greg Kroah-Hartman --- arch/loongarch/include/asm/cache.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/loongarch/include/asm/cache.h b/arch/loongarch/include/asm/cache.h index 1b6d09617199..aa622c754414 100644 --- a/arch/loongarch/include/asm/cache.h +++ b/arch/loongarch/include/asm/cache.h @@ -8,6 +8,8 @@ #define L1_CACHE_SHIFT CONFIG_L1_CACHE_SHIFT #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) +#define ARCH_DMA_MINALIGN (16) + #define __read_mostly __section(".data..read_mostly") #endif /* _ASM_CACHE_H */ From 0aa5d4370b5b667bb2d9f7224da46dfdb76a396f Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Sun, 30 Mar 2025 16:31:09 +0800 Subject: [PATCH 09/45] LoongArch: Increase MAX_IO_PICS up to 8 commit ec105cadff5d8c0a029a3dc1084cae46cf3f799d upstream. Begin with Loongson-3C6000, the number of PCI host can be as many as 8 for multi-chip machines, and this number should be the same for I/O interrupt controllers. To support these machines we also increase the MAX_IO_PICS up to 8. Cc: stable@vger.kernel.org Tested-by: Mingcong Bai Signed-off-by: Huacai Chen Signed-off-by: Greg Kroah-Hartman --- arch/loongarch/include/asm/irq.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/loongarch/include/asm/irq.h b/arch/loongarch/include/asm/irq.h index 9c2ca785faa9..b2915fd53862 100644 --- a/arch/loongarch/include/asm/irq.h +++ b/arch/loongarch/include/asm/irq.h @@ -53,7 +53,7 @@ void spurious_interrupt(void); #define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace void arch_trigger_cpumask_backtrace(const struct cpumask *mask, int exclude_cpu); -#define MAX_IO_PICS 2 +#define MAX_IO_PICS 8 #define NR_IRQS (64 + NR_VECTORS * (NR_CPUS + MAX_IO_PICS)) struct acpi_vector_group { From 205a2182c51ffebaef54d643e3745e720cded08b Mon Sep 17 00:00:00 2001 From: Hengqi Chen Date: Sun, 30 Mar 2025 16:31:09 +0800 Subject: [PATCH 10/45] LoongArch: BPF: Fix off-by-one error in build_prologue() commit 7e2586991e36663c9bc48c828b83eab180ad30a9 upstream. Vincent reported that running BPF progs with tailcalls on LoongArch causes kernel hard lockup. Debugging the issues shows that the JITed image missing a jirl instruction at the end of the epilogue. There are two passes in JIT compiling, the first pass set the flags and the second pass generates JIT code based on those flags. With BPF progs mixing bpf2bpf and tailcalls, build_prologue() generates N insns in the first pass and then generates N+1 insns in the second pass. This makes epilogue_offset off by one and we will jump to some unexpected insn and cause lockup. Fix this by inserting a nop insn. Cc: stable@vger.kernel.org Fixes: 5dc615520c4d ("LoongArch: Add BPF JIT support") Fixes: bb035ef0cc91 ("LoongArch: BPF: Support mixing bpf2bpf and tailcalls") Reported-by: Vincent Li Tested-by: Vincent Li Closes: https://lore.kernel.org/loongarch/CAK3+h2w6WESdBN3UCr3WKHByD7D6Q_Ve1EDAjotVrnx6Or_c8g@mail.gmail.com/ Closes: https://lore.kernel.org/bpf/CAK3+h2woEjG_N=-XzqEGaAeCmgu2eTCUc7p6bP4u8Q+DFHm-7g@mail.gmail.com/ Signed-off-by: Hengqi Chen Signed-off-by: Huacai Chen Signed-off-by: Greg Kroah-Hartman --- arch/loongarch/net/bpf_jit.c | 2 ++ arch/loongarch/net/bpf_jit.h | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c index ea357a3edc09..2346c0b55043 100644 --- a/arch/loongarch/net/bpf_jit.c +++ b/arch/loongarch/net/bpf_jit.c @@ -142,6 +142,8 @@ static void build_prologue(struct jit_ctx *ctx) */ if (seen_tail_call(ctx) && seen_call(ctx)) move_reg(ctx, TCC_SAVED, REG_TCC); + else + emit_insn(ctx, nop); ctx->stack_size = stack_adjust; } diff --git a/arch/loongarch/net/bpf_jit.h b/arch/loongarch/net/bpf_jit.h index 68586338ecf8..f9c569f53949 100644 --- a/arch/loongarch/net/bpf_jit.h +++ b/arch/loongarch/net/bpf_jit.h @@ -27,6 +27,11 @@ struct jit_data { struct jit_ctx ctx; }; +static inline void emit_nop(union loongarch_instruction *insn) +{ + insn->word = INSN_NOP; +} + #define emit_insn(ctx, func, ...) \ do { \ if (ctx->image != NULL) { \ From 223d565d8892481684091cfbaf3466f2b0e289d3 Mon Sep 17 00:00:00 2001 From: Hengqi Chen Date: Sun, 30 Mar 2025 16:31:09 +0800 Subject: [PATCH 11/45] LoongArch: BPF: Don't override subprog's return value commit 60f3caff1492e5b8616b9578c4bedb5c0a88ed14 upstream. The verifier test `calls: div by 0 in subprog` triggers a panic at the ld.bu instruction. The ld.bu insn is trying to load byte from memory address returned by the subprog. The subprog actually set the correct address at the a5 register (dedicated register for BPF return values). But at commit 73c359d1d356 ("LoongArch: BPF: Sign-extend return values") we also sign extended a5 to the a0 register (return value in LoongArch). For function call insn, we later propagate the a0 register back to a5 register. This is right for native calls but wrong for bpf2bpf calls which expect zero-extended return value in a5 register. So only move a0 to a5 for native calls (i.e. non-BPF_PSEUDO_CALL). Cc: stable@vger.kernel.org Fixes: 73c359d1d356 ("LoongArch: BPF: Sign-extend return values") Signed-off-by: Hengqi Chen Signed-off-by: Huacai Chen Signed-off-by: Greg Kroah-Hartman --- arch/loongarch/net/bpf_jit.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c index 2346c0b55043..f532d6ef16e5 100644 --- a/arch/loongarch/net/bpf_jit.c +++ b/arch/loongarch/net/bpf_jit.c @@ -907,7 +907,10 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext move_addr(ctx, t1, func_addr); emit_insn(ctx, jirl, LOONGARCH_GPR_RA, t1, 0); - move_reg(ctx, regmap[BPF_REG_0], LOONGARCH_GPR_A0); + + if (insn->src_reg != BPF_PSEUDO_CALL) + move_reg(ctx, regmap[BPF_REG_0], LOONGARCH_GPR_A0); + break; /* tail call */ From add72c418d0a3c4531f0664aa758868f598542dd Mon Sep 17 00:00:00 2001 From: Hengqi Chen Date: Sun, 30 Mar 2025 16:31:09 +0800 Subject: [PATCH 12/45] LoongArch: BPF: Use move_addr() for BPF_PSEUDO_FUNC commit 52266f1015a8b5aabec7d127f83d105f702b388e upstream. Vincent reported that running XDP synproxy program on LoongArch results in the following error: JIT doesn't support bpf-to-bpf calls With dmesg: multi-func JIT bug 1391 != 1390 The root cause is that verifier will refill the imm with the correct addresses of bpf_calls for BPF_PSEUDO_FUNC instructions and then run the last pass of JIT. So we generate different JIT code for the same instruction in two passes (one for placeholder and the other for the real address). Let's use move_addr() instead. See commit 64f50f6575721ef0 ("LoongArch, bpf: Use 4 instructions for function address in JIT") for a similar fix. Cc: stable@vger.kernel.org Fixes: 69c087ba6225 ("bpf: Add bpf_for_each_map_elem() helper") Fixes: bb035ef0cc91 ("LoongArch: BPF: Support mixing bpf2bpf and tailcalls") Reported-by: Vincent Li Tested-by: Vincent Li Closes: https://lore.kernel.org/loongarch/CAK3+h2yfM9FTNiXvEQBkvtuoJrvzmN4c_NZsFXqEk4Cj1tsBNA@mail.gmail.com/T/#u Signed-off-by: Hengqi Chen Signed-off-by: Huacai Chen Signed-off-by: Greg Kroah-Hartman --- arch/loongarch/net/bpf_jit.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c index f532d6ef16e5..fa1500d4aa3e 100644 --- a/arch/loongarch/net/bpf_jit.c +++ b/arch/loongarch/net/bpf_jit.c @@ -935,7 +935,10 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext { const u64 imm64 = (u64)(insn + 1)->imm << 32 | (u32)insn->imm; - move_imm(ctx, dst, imm64, is32); + if (bpf_pseudo_func(insn)) + move_addr(ctx, dst, imm64); + else + move_imm(ctx, dst, imm64, is32); return 1; } From a54247efbc73131def0d5cd3ac35ef89629f2c13 Mon Sep 17 00:00:00 2001 From: Tianyu Lan Date: Thu, 13 Mar 2025 04:52:17 -0400 Subject: [PATCH 13/45] x86/hyperv: Fix check of return value from snp_set_vmsa() commit e792d843aa3c9d039074cdce728d5803262e57a7 upstream. snp_set_vmsa() returns 0 as success result and so fix it. Cc: stable@vger.kernel.org Fixes: 44676bb9d566 ("x86/hyperv: Add smp support for SEV-SNP guest") Signed-off-by: Tianyu Lan Reviewed-by: Michael Kelley Link: https://lore.kernel.org/r/20250313085217.45483-1-ltykernel@gmail.com Signed-off-by: Wei Liu Message-ID: <20250313085217.45483-1-ltykernel@gmail.com> Signed-off-by: Greg Kroah-Hartman --- arch/x86/hyperv/ivm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/hyperv/ivm.c b/arch/x86/hyperv/ivm.c index aa8befc4d901..4065f5ef3ae0 100644 --- a/arch/x86/hyperv/ivm.c +++ b/arch/x86/hyperv/ivm.c @@ -339,7 +339,7 @@ int hv_snp_boot_ap(u32 cpu, unsigned long start_ip) vmsa->sev_features = sev_status >> 2; ret = snp_set_vmsa(vmsa, true); - if (!ret) { + if (ret) { pr_err("RMPADJUST(%llx) failed: %llx\n", (u64)vmsa, ret); free_page((u64)vmsa); return ret; From d39838da59bda11b5b292f46db5a52201cef107a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 6 Mar 2025 21:29:22 +0100 Subject: [PATCH 14/45] KVM: x86: block KVM_CAP_SYNC_REGS if guest state is protected commit 74c1807f6c4feddb3c3cb1056c54531d4adbaea6 upstream. KVM_CAP_SYNC_REGS does not make sense for VMs with protected guest state, since the register values cannot actually be written. Return 0 when using the VM-level KVM_CHECK_EXTENSION ioctl, and accordingly return -EINVAL from KVM_RUN if the valid/dirty fields are nonzero. However, on exit from KVM_RUN userspace could have placed a nonzero value into kvm_run->kvm_valid_regs, so check guest_state_protected again and skip store_regs() in that case. Cc: stable@vger.kernel.org Fixes: 517987e3fb19 ("KVM: x86: add fields to struct kvm_arch for CoCo features") Signed-off-by: Paolo Bonzini Message-ID: <20250306202923.646075-1-pbonzini@redhat.com> Reviewed-by: Pankaj Gupta Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/x86.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 8794c0a8a2e4..45337a3fc03c 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4590,6 +4590,11 @@ static bool kvm_is_vm_type_supported(unsigned long type) return type < 32 && (kvm_caps.supported_vm_types & BIT(type)); } +static inline u32 kvm_sync_valid_fields(struct kvm *kvm) +{ + return kvm && kvm->arch.has_protected_state ? 0 : KVM_SYNC_X86_VALID_FIELDS; +} + int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) { int r = 0; @@ -4698,7 +4703,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) break; #endif case KVM_CAP_SYNC_REGS: - r = KVM_SYNC_X86_VALID_FIELDS; + r = kvm_sync_valid_fields(kvm); break; case KVM_CAP_ADJUST_CLOCK: r = KVM_CLOCK_VALID_FLAGS; @@ -11470,6 +11475,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) { struct kvm_queued_exception *ex = &vcpu->arch.exception; struct kvm_run *kvm_run = vcpu->run; + u32 sync_valid_fields; int r; r = kvm_mmu_post_init_vm(vcpu->kvm); @@ -11515,8 +11521,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) goto out; } - if ((kvm_run->kvm_valid_regs & ~KVM_SYNC_X86_VALID_FIELDS) || - (kvm_run->kvm_dirty_regs & ~KVM_SYNC_X86_VALID_FIELDS)) { + sync_valid_fields = kvm_sync_valid_fields(vcpu->kvm); + if ((kvm_run->kvm_valid_regs & ~sync_valid_fields) || + (kvm_run->kvm_dirty_regs & ~sync_valid_fields)) { r = -EINVAL; goto out; } @@ -11574,7 +11581,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) out: kvm_put_guest_fpu(vcpu); - if (kvm_run->kvm_valid_regs) + if (kvm_run->kvm_valid_regs && likely(!vcpu->arch.guest_state_protected)) store_regs(vcpu); post_kvm_run_save(vcpu); kvm_vcpu_srcu_read_unlock(vcpu); From ada88219d5315fc13f2910fe278c7112d8d68889 Mon Sep 17 00:00:00 2001 From: Boris Ostrovsky Date: Thu, 27 Mar 2025 19:05:02 -0400 Subject: [PATCH 15/45] x86/microcode/AMD: Fix __apply_microcode_amd()'s return value commit 31ab12df723543047c3fc19cb8f8c4498ec6267f upstream. When verify_sha256_digest() fails, __apply_microcode_amd() should propagate the failure by returning false (and not -1 which is promoted to true). Fixes: 50cef76d5cb0 ("x86/microcode/AMD: Load only SHA256-checksummed patches") Signed-off-by: Boris Ostrovsky Signed-off-by: Borislav Petkov (AMD) Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20250327230503.1850368-2-boris.ostrovsky@oracle.com Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/microcode/amd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c index 07fc145f3531..5cd735728fa0 100644 --- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c @@ -600,7 +600,7 @@ static bool __apply_microcode_amd(struct microcode_amd *mc, u32 *cur_rev, unsigned long p_addr = (unsigned long)&mc->hdr.data_code; if (!verify_sha256_digest(mc->hdr.patch_id, *cur_rev, (const u8 *)p_addr, psize)) - return -1; + return false; native_wrmsrl(MSR_AMD64_PATCH_LOADER, p_addr); From 3e3d8169c0950a0b3cd5105f6403a78350dcac80 Mon Sep 17 00:00:00 2001 From: Shuai Xue Date: Wed, 12 Mar 2025 19:28:50 +0800 Subject: [PATCH 16/45] x86/mce: use is_copy_from_user() to determine copy-from-user context commit 1a15bb8303b6b104e78028b6c68f76a0d4562134 upstream. Patch series "mm/hwpoison: Fix regressions in memory failure handling", v4. ## 1. What am I trying to do: This patchset resolves two critical regressions related to memory failure handling that have appeared in the upstream kernel since version 5.17, as compared to 5.10 LTS. - copyin case: poison found in user page while kernel copying from user space - instr case: poison found while instruction fetching in user space ## 2. What is the expected outcome and why - For copyin case: Kernel can recover from poison found where kernel is doing get_user() or copy_from_user() if those places get an error return and the kernel return -EFAULT to the process instead of crashing. More specifily, MCE handler checks the fixup handler type to decide whether an in kernel #MC can be recovered. When EX_TYPE_UACCESS is found, the PC jumps to recovery code specified in _ASM_EXTABLE_FAULT() and return a -EFAULT to user space. - For instr case: If a poison found while instruction fetching in user space, full recovery is possible. User process takes #PF, Linux allocates a new page and fills by reading from storage. ## 3. What actually happens and why - For copyin case: kernel panic since v5.17 Commit 4c132d1d844a ("x86/futex: Remove .fixup usage") introduced a new extable fixup type, EX_TYPE_EFAULT_REG, and later patches updated the extable fixup type for copy-from-user operations, changing it from EX_TYPE_UACCESS to EX_TYPE_EFAULT_REG. It breaks previous EX_TYPE_UACCESS handling when posion found in get_user() or copy_from_user(). - For instr case: user process is killed by a SIGBUS signal due to #CMCI and #MCE race When an uncorrected memory error is consumed there is a race between the CMCI from the memory controller reporting an uncorrected error with a UCNA signature, and the core reporting and SRAR signature machine check when the data is about to be consumed. ### Background: why *UN*corrected errors tied to *C*MCI in Intel platform [1] Prior to Icelake memory controllers reported patrol scrub events that detected a previously unseen uncorrected error in memory by signaling a broadcast machine check with an SRAO (Software Recoverable Action Optional) signature in the machine check bank. This was overkill because it's not an urgent problem that no core is on the verge of consuming that bad data. It's also found that multi SRAO UCE may cause nested MCE interrupts and finally become an IERR. Hence, Intel downgrades the machine check bank signature of patrol scrub from SRAO to UCNA (Uncorrected, No Action required), and signal changed to #CMCI. Just to add to the confusion, Linux does take an action (in uc_decode_notifier()) to try to offline the page despite the UC*NA* signature name. ### Background: why #CMCI and #MCE race when poison is consuming in Intel platform [1] Having decided that CMCI/UCNA is the best action for patrol scrub errors, the memory controller uses it for reads too. But the memory controller is executing asynchronously from the core, and can't tell the difference between a "real" read and a speculative read. So it will do CMCI/UCNA if an error is found in any read. Thus: 1) Core is clever and thinks address A is needed soon, issues a speculative read. 2) Core finds it is going to use address A soon after sending the read request 3) The CMCI from the memory controller is in a race with MCE from the core that will soon try to retire the load from address A. Quite often (because speculation has got better) the CMCI from the memory controller is delivered before the core is committed to the instruction reading address A, so the interrupt is taken, and Linux offlines the page (marking it as poison). ## Why user process is killed for instr case Commit 046545a661af ("mm/hwpoison: fix error page recovered but reported "not recovered"") tries to fix noise message "Memory error not recovered" and skips duplicate SIGBUSs due to the race. But it also introduced a bug that kill_accessing_process() return -EHWPOISON for instr case, as result, kill_me_maybe() send a SIGBUS to user process. # 4. The fix, in my opinion, should be: - For copyin case: The key point is whether the error context is in a read from user memory. We do not care about the ex-type if we know its a MOV reading from userspace. is_copy_from_user() return true when both of the following two checks are true: - the current instruction is copy - source address is user memory If copy_user is true, we set m->kflags |= MCE_IN_KERNEL_COPYIN | MCE_IN_KERNEL_RECOV; Then do_machine_check() will try fixup_exception() first. - For instr case: let kill_accessing_process() return 0 to prevent a SIGBUS. - For patch 3: The return value of memory_failure() is quite important while discussed instr case regression with Tony and Miaohe for patch 2, so add comment about the return value. This patch (of 3): Commit 4c132d1d844a ("x86/futex: Remove .fixup usage") introduced a new extable fixup type, EX_TYPE_EFAULT_REG, and commit 4c132d1d844a ("x86/futex: Remove .fixup usage") updated the extable fixup type for copy-from-user operations, changing it from EX_TYPE_UACCESS to EX_TYPE_EFAULT_REG. The error context for copy-from-user operations no longer functions as an in-kernel recovery context. Consequently, the error context for copy-from-user operations no longer functions as an in-kernel recovery context, resulting in kernel panics with the message: "Machine check: Data load in unrecoverable area of kernel." To address this, it is crucial to identify if an error context involves a read operation from user memory. The function is_copy_from_user() can be utilized to determine: - the current operation is copy - when reading user memory When these conditions are met, is_copy_from_user() will return true, confirming that it is indeed a direct copy from user memory. This check is essential for correctly handling the context of errors in these operations without relying on the extable fixup types that previously allowed for in-kernel recovery. So, use is_copy_from_user() to determine if a context is copy user directly. Link: https://lkml.kernel.org/r/20250312112852.82415-1-xueshuai@linux.alibaba.com Link: https://lkml.kernel.org/r/20250312112852.82415-2-xueshuai@linux.alibaba.com Fixes: 4c132d1d844a ("x86/futex: Remove .fixup usage") Signed-off-by: Shuai Xue Suggested-by: Peter Zijlstra Acked-by: Borislav Petkov (AMD) Tested-by: Tony Luck Cc: Baolin Wang Cc: Borislav Betkov Cc: Catalin Marinas Cc: Dave Hansen Cc: "H. Peter Anvin" Cc: Ingo Molnar Cc: Josh Poimboeuf Cc: Miaohe Lin Cc: Naoya Horiguchi Cc: Ruidong Tian Cc: Thomas Gleinxer Cc: Yazen Ghannam Cc: Jane Chu Cc: Jarkko Sakkinen Cc: Jonathan Cameron Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/mce/severity.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/arch/x86/kernel/cpu/mce/severity.c b/arch/x86/kernel/cpu/mce/severity.c index dac4d64dfb2a..2235a7477436 100644 --- a/arch/x86/kernel/cpu/mce/severity.c +++ b/arch/x86/kernel/cpu/mce/severity.c @@ -300,13 +300,12 @@ static noinstr int error_context(struct mce *m, struct pt_regs *regs) copy_user = is_copy_from_user(regs); instrumentation_end(); - switch (fixup_type) { - case EX_TYPE_UACCESS: - if (!copy_user) - return IN_KERNEL; - m->kflags |= MCE_IN_KERNEL_COPYIN; - fallthrough; + if (copy_user) { + m->kflags |= MCE_IN_KERNEL_COPYIN | MCE_IN_KERNEL_RECOV; + return IN_KERNEL_RECOV; + } + switch (fixup_type) { case EX_TYPE_FAULT_MCE_SAFE: case EX_TYPE_DEFAULT_MCE_SAFE: m->kflags |= MCE_IN_KERNEL_RECOV; From 805e3ce5e0e32b31dcecc0774c57c17a1f13cef6 Mon Sep 17 00:00:00 2001 From: Vishal Annapurve Date: Fri, 28 Feb 2025 01:44:15 +0000 Subject: [PATCH 17/45] x86/tdx: Fix arch_safe_halt() execution for TDX VMs commit 9f98a4f4e7216dbe366010b4cdcab6b220f229c4 upstream. Direct HLT instruction execution causes #VEs for TDX VMs which is routed to hypervisor via TDCALL. If HLT is executed in STI-shadow, resulting #VE handler will enable interrupts before TDCALL is routed to hypervisor leading to missed wakeup events, as current TDX spec doesn't expose interruptibility state information to allow #VE handler to selectively enable interrupts. Commit bfe6ed0c6727 ("x86/tdx: Add HLT support for TDX guests") prevented the idle routines from executing HLT instruction in STI-shadow. But it missed the paravirt routine which can be reached via this path as an example: kvm_wait() => safe_halt() => raw_safe_halt() => arch_safe_halt() => irq.safe_halt() => pv_native_safe_halt() To reliably handle arch_safe_halt() for TDX VMs, introduce explicit dependency on CONFIG_PARAVIRT and override paravirt halt()/safe_halt() routines with TDX-safe versions that execute direct TDCALL and needed interrupt flag updates. Executing direct TDCALL brings in additional benefit of avoiding HLT related #VEs altogether. As tested by Ryan Afranji: "Tested with the specjbb2015 benchmark. It has heavy lock contention which leads to many halt calls. TDX VMs suffered a poor score before this patchset. Verified the major performance improvement with this patchset applied." Fixes: bfe6ed0c6727 ("x86/tdx: Add HLT support for TDX guests") Signed-off-by: Vishal Annapurve Signed-off-by: Ingo Molnar Reviewed-by: Kirill A. Shutemov Tested-by: Ryan Afranji Cc: Andy Lutomirski Cc: Brian Gerst Cc: Juergen Gross Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Josh Poimboeuf Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20250228014416.3925664-3-vannapurve@google.com Signed-off-by: Greg Kroah-Hartman --- arch/x86/Kconfig | 1 + arch/x86/coco/tdx/tdx.c | 26 +++++++++++++++++++++++++- arch/x86/include/asm/tdx.h | 4 ++-- arch/x86/kernel/process.c | 2 +- 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index c915097d3b73..db38d2b9b788 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -894,6 +894,7 @@ config INTEL_TDX_GUEST depends on X86_64 && CPU_SUP_INTEL depends on X86_X2APIC depends on EFI_STUB + depends on PARAVIRT select ARCH_HAS_CC_PLATFORM select X86_MEM_ENCRYPT select X86_MCE diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c index 2f85ed005c42..b8aeb3ac7d28 100644 --- a/arch/x86/coco/tdx/tdx.c +++ b/arch/x86/coco/tdx/tdx.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -359,7 +360,7 @@ static int handle_halt(struct ve_info *ve) return ve_instr_len(ve); } -void __cpuidle tdx_safe_halt(void) +void __cpuidle tdx_halt(void) { const bool irq_disabled = false; @@ -370,6 +371,16 @@ void __cpuidle tdx_safe_halt(void) WARN_ONCE(1, "HLT instruction emulation failed\n"); } +static void __cpuidle tdx_safe_halt(void) +{ + tdx_halt(); + /* + * "__cpuidle" section doesn't support instrumentation, so stick + * with raw_* variant that avoids tracing hooks. + */ + raw_local_irq_enable(); +} + static int read_msr(struct pt_regs *regs, struct ve_info *ve) { struct tdx_module_args args = { @@ -1056,6 +1067,19 @@ void __init tdx_early_init(void) x86_platform.guest.enc_kexec_begin = tdx_kexec_begin; x86_platform.guest.enc_kexec_finish = tdx_kexec_finish; + /* + * Avoid "sti;hlt" execution in TDX guests as HLT induces a #VE that + * will enable interrupts before HLT TDCALL invocation if executed + * in STI-shadow, possibly resulting in missed wakeup events. + * + * Modify all possible HLT execution paths to use TDX specific routines + * that directly execute TDCALL and toggle the interrupt state as + * needed after TDCALL completion. This also reduces HLT related #VEs + * in addition to having a reliable halt logic execution. + */ + pv_ops.irq.safe_halt = tdx_safe_halt; + pv_ops.irq.halt = tdx_halt; + /* * TDX intercepts the RDMSR to read the X2APIC ID in the parallel * bringup low level code. That raises #VE which cannot be handled diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h index eba178996d84..b5b633294061 100644 --- a/arch/x86/include/asm/tdx.h +++ b/arch/x86/include/asm/tdx.h @@ -58,7 +58,7 @@ void tdx_get_ve_info(struct ve_info *ve); bool tdx_handle_virt_exception(struct pt_regs *regs, struct ve_info *ve); -void tdx_safe_halt(void); +void tdx_halt(void); bool tdx_early_handle_ve(struct pt_regs *regs); @@ -69,7 +69,7 @@ u64 tdx_hcall_get_quote(u8 *buf, size_t size); #else static inline void tdx_early_init(void) { }; -static inline void tdx_safe_halt(void) { }; +static inline void tdx_halt(void) { }; static inline bool tdx_early_handle_ve(struct pt_regs *regs) { return false; } diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index e42db0de0292..c7ce3655b707 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -938,7 +938,7 @@ void __init select_idle_routine(void) static_call_update(x86_idle, mwait_idle); } else if (cpu_feature_enabled(X86_FEATURE_TDX_GUEST)) { pr_info("using TDX aware idle routine\n"); - static_call_update(x86_idle, tdx_safe_halt); + static_call_update(x86_idle, tdx_halt); } else { static_call_update(x86_idle, default_idle); } From 35c1834dd630919e50414250fcc573d13bae2f78 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 25 Mar 2025 22:04:50 +0100 Subject: [PATCH 18/45] ACPI: x86: Extend Lenovo Yoga Tab 3 quirk with skip GPIO event-handlers commit 2fa87c71d2adb4b82c105f9191e6120340feff00 upstream. Depending on the secureboot signature on EFI\BOOT\BOOTX86.EFI the Lenovo Yoga Tab 3 UEFI will switch its OSID ACPI variable between 1 (Windows) and 4 (Android(GMIN)). In Windows mode a GPIO event handler gets installed for GPO1 pin 5, causing Linux' x86-android-tables code which deals with the general brokenness of this device's ACPI tables to fail to probe with: [ 17.853705] x86_android_tablets: error -16 getting GPIO INT33FF:01 5 [ 17.859623] x86_android_tablets x86_android_tablets: probe with driver which renders sound, the touchscreen, charging-management, battery-monitoring and more non functional. Add ACPI_QUIRK_SKIP_GPIO_EVENT_HANDLERS to the existing quirks for this device to fix this. Reported-by: Agoston Lorincz Closes: https://lore.kernel.org/platform-driver-x86/CAMEzqD+DNXrAvUOHviB2O2bjtcbmo3xH=kunKr4nubuMLbb_0A@mail.gmail.com/ Cc: All applicable Fixes: fe820db35275 ("ACPI: x86: Add skip i2c clients quirk for Lenovo Yoga Tab 3 Pro (YT3-X90F)") Signed-off-by: Hans de Goede Link: https://patch.msgid.link/20250325210450.358506-1-hdegoede@redhat.com Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/x86/utils.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c index 068c1612660b..4ee30c2897a2 100644 --- a/drivers/acpi/x86/utils.c +++ b/drivers/acpi/x86/utils.c @@ -374,7 +374,8 @@ static const struct dmi_system_id acpi_quirk_skip_dmi_ids[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "Blade3-10A-001"), }, .driver_data = (void *)(ACPI_QUIRK_SKIP_I2C_CLIENTS | - ACPI_QUIRK_SKIP_ACPI_AC_AND_BATTERY), + ACPI_QUIRK_SKIP_ACPI_AC_AND_BATTERY | + ACPI_QUIRK_SKIP_GPIO_EVENT_HANDLERS), }, { /* Medion Lifetab S10346 */ From 48792ab445529e2d929035456051bb4fd9e42fbe Mon Sep 17 00:00:00 2001 From: Eduard Christian Dumitrescu Date: Mon, 24 Mar 2025 11:24:42 -0400 Subject: [PATCH 19/45] platform/x86: thinkpad_acpi: disable ACPI fan access for T495* and E560 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 2b9f84e7dc863afd63357b867cea246aeedda036 upstream. T495, T495s, and E560 laptops have the FANG+FANW ACPI methods (therefore fang_handle and fanw_handle are not NULL) but they do not actually work, which results in a "No such device or address" error. The DSDT table code for the FANG+FANW methods doesn't seem to do anything special regarding the fan being secondary. The bug was introduced in commit 57d0557dfa49 ("platform/x86: thinkpad_acpi: Add Thinkpad Edge E531 fan support"), which added a new fan control method via the FANG+FANW ACPI methods. Add a quirk for T495, T495s, and E560 to avoid the FANG+FANW methods. Fan access and control is restored after forcing the legacy non-ACPI fan control method by setting both fang_handle and fanw_handle to NULL. Reported-by: Vlastimil Holer Fixes: 57d0557dfa49 ("platform/x86: thinkpad_acpi: Add Thinkpad Edge E531 fan support") Closes: https://bugzilla.kernel.org/show_bug.cgi?id=219643 Cc: stable@vger.kernel.org Tested-by: Alireza Elikahi Reviewed-by: Kurt Borja Signed-off-by: Eduard Christian Dumitrescu Co-developed-by: Seyediman Seyedarab Signed-off-by: Seyediman Seyedarab Link: https://lore.kernel.org/r/20250324152442.106113-1-ImanDevel@gmail.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen Signed-off-by: Greg Kroah-Hartman --- drivers/platform/x86/thinkpad_acpi.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index a3c73abb00f2..dea40da86755 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -8795,6 +8795,7 @@ static const struct attribute_group fan_driver_attr_group = { #define TPACPI_FAN_NS 0x0010 /* For EC with non-Standard register addresses */ #define TPACPI_FAN_DECRPM 0x0020 /* For ECFW's with RPM in register as decimal */ #define TPACPI_FAN_TPR 0x0040 /* Fan speed is in Ticks Per Revolution */ +#define TPACPI_FAN_NOACPI 0x0080 /* Don't use ACPI methods even if detected */ static const struct tpacpi_quirk fan_quirk_table[] __initconst = { TPACPI_QEC_IBM('1', 'Y', TPACPI_FAN_Q1), @@ -8825,6 +8826,9 @@ static const struct tpacpi_quirk fan_quirk_table[] __initconst = { TPACPI_Q_LNV3('N', '1', 'O', TPACPI_FAN_NOFAN), /* X1 Tablet (2nd gen) */ TPACPI_Q_LNV3('R', '0', 'Q', TPACPI_FAN_DECRPM),/* L480 */ TPACPI_Q_LNV('8', 'F', TPACPI_FAN_TPR), /* ThinkPad x120e */ + TPACPI_Q_LNV3('R', '0', '0', TPACPI_FAN_NOACPI),/* E560 */ + TPACPI_Q_LNV3('R', '1', '2', TPACPI_FAN_NOACPI),/* T495 */ + TPACPI_Q_LNV3('R', '1', '3', TPACPI_FAN_NOACPI),/* T495s */ }; static int __init fan_init(struct ibm_init_struct *iibm) @@ -8876,6 +8880,13 @@ static int __init fan_init(struct ibm_init_struct *iibm) tp_features.fan_ctrl_status_undef = 1; } + if (quirks & TPACPI_FAN_NOACPI) { + /* E560, T495, T495s */ + pr_info("Ignoring buggy ACPI fan access method\n"); + fang_handle = NULL; + fanw_handle = NULL; + } + if (gfan_handle) { /* 570, 600e/x, 770e, 770x */ fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN; From 1a85281415fbe6509a30c347d14214b63f990870 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Fri, 28 Mar 2025 15:47:49 -0700 Subject: [PATCH 20/45] platform/x86: ISST: Correct command storage data length MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 9462e74c5c983cce34019bfb27f734552bebe59f upstream. After resume/online turbo limit ratio (TRL) is restored partially if the admin explicitly changed TRL from user space. A hash table is used to store SST mail box and MSR settings when modified to restore those settings after resume or online. This uses a struct isst_cmd field "data" to store these settings. This is a 64 bit field. But isst_store_new_cmd() is only assigning as u32. This results in truncation of 32 bits. Change the argument to u64 from u32. Fixes: f607874f35cb ("platform/x86: ISST: Restore state on resume") Signed-off-by: Srinivas Pandruvada Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20250328224749.2691272-1-srinivas.pandruvada@linux.intel.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen Signed-off-by: Greg Kroah-Hartman --- drivers/platform/x86/intel/speed_select_if/isst_if_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel/speed_select_if/isst_if_common.c b/drivers/platform/x86/intel/speed_select_if/isst_if_common.c index dbcd3087aaa4..31239a93dd71 100644 --- a/drivers/platform/x86/intel/speed_select_if/isst_if_common.c +++ b/drivers/platform/x86/intel/speed_select_if/isst_if_common.c @@ -84,7 +84,7 @@ static DECLARE_HASHTABLE(isst_hash, 8); static DEFINE_MUTEX(isst_hash_lock); static int isst_store_new_cmd(int cmd, u32 cpu, int mbox_cmd_type, u32 param, - u32 data) + u64 data) { struct isst_cmd *sst_cmd; From 854b6764be33d0b37eb91acf7b8b89a1e45ee868 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 23 Sep 2024 10:38:11 +0200 Subject: [PATCH 21/45] ntb_perf: Delete duplicate dmaengine_unmap_put() call in perf_copy_chunk() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 4279e72cab31dd3eb8c89591eb9d2affa90ab6aa upstream. The function call “dmaengine_unmap_put(unmap)” was used in an if branch. The same call was immediately triggered by a subsequent goto statement. Thus avoid such a call repetition. This issue was detected by using the Coccinelle software. Fixes: 5648e56d03fa ("NTB: ntb_perf: Add full multi-port NTB API support") Cc: stable@vger.kernel.org Signed-off-by: Markus Elfring Signed-off-by: Jon Mason Signed-off-by: Greg Kroah-Hartman --- drivers/ntb/test/ntb_perf.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/ntb/test/ntb_perf.c b/drivers/ntb/test/ntb_perf.c index 72bc1d017a46..dfd175f79e8f 100644 --- a/drivers/ntb/test/ntb_perf.c +++ b/drivers/ntb/test/ntb_perf.c @@ -839,10 +839,8 @@ static int perf_copy_chunk(struct perf_thread *pthr, dma_set_unmap(tx, unmap); ret = dma_submit_error(dmaengine_submit(tx)); - if (ret) { - dmaengine_unmap_put(unmap); + if (ret) goto err_free_resource; - } dmaengine_unmap_put(unmap); From e853bb7d6aec34d91dfae639254892bd5721fc7b Mon Sep 17 00:00:00 2001 From: "Peter Zijlstra (Intel)" Date: Tue, 21 Jan 2025 07:23:00 -0800 Subject: [PATCH 22/45] perf/x86/intel: Apply static call for drain_pebs commit 314dfe10576912e1d786b13c5d4eee8c51b63caa upstream. The x86_pmu_drain_pebs static call was introduced in commit 7c9903c9bf71 ("x86/perf, static_call: Optimize x86_pmu methods"), but it's not really used to replace the old method. Apply the static call for drain_pebs. Fixes: 7c9903c9bf71 ("x86/perf, static_call: Optimize x86_pmu methods") Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Kan Liang Signed-off-by: Peter Zijlstra (Intel) Cc: stable@vger.kernel.org Link: https://lkml.kernel.org/r/20250121152303.3128733-1-kan.liang@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- arch/x86/events/intel/core.c | 2 +- arch/x86/events/intel/ds.c | 2 +- arch/x86/events/perf_event.h | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 3a68b3e0b7a3..6ad22e187b06 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -3067,7 +3067,7 @@ static int handle_pmi_common(struct pt_regs *regs, u64 status) handled++; x86_pmu_handle_guest_pebs(regs, &data); - x86_pmu.drain_pebs(regs, &data); + static_call(x86_pmu_drain_pebs)(regs, &data); status &= intel_ctrl | GLOBAL_STATUS_TRACE_TOPAPMI; /* diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c index c07ca43e67e7..80cb7a9bd854 100644 --- a/arch/x86/events/intel/ds.c +++ b/arch/x86/events/intel/ds.c @@ -936,7 +936,7 @@ static inline void intel_pmu_drain_pebs_buffer(void) { struct perf_sample_data data; - x86_pmu.drain_pebs(NULL, &data); + static_call(x86_pmu_drain_pebs)(NULL, &data); } /* diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h index ac1182141bf6..b440f7295f1f 100644 --- a/arch/x86/events/perf_event.h +++ b/arch/x86/events/perf_event.h @@ -1092,6 +1092,7 @@ extern struct x86_pmu x86_pmu __read_mostly; DECLARE_STATIC_CALL(x86_pmu_set_period, *x86_pmu.set_period); DECLARE_STATIC_CALL(x86_pmu_update, *x86_pmu.update); +DECLARE_STATIC_CALL(x86_pmu_drain_pebs, *x86_pmu.drain_pebs); static __always_inline struct x86_perf_task_context_opt *task_context_opt(void *ctx) { From 3a8bec6583e5239de3bd597ab382dc6c2b0c29a1 Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Tue, 21 Jan 2025 07:23:01 -0800 Subject: [PATCH 23/45] perf/x86/intel: Avoid disable PMU if !cpuc->enabled in sample read commit f9bdf1f953392c9edd69a7f884f78c0390127029 upstream. The WARN_ON(this_cpu_read(cpu_hw_events.enabled)) in the intel_pmu_save_and_restart_reload() is triggered, when sampling read topdown events. In a NMI handler, the cpu_hw_events.enabled is set and used to indicate the status of core PMU. The generic pmu->pmu_disable_count, updated in the perf_pmu_disable/enable pair, is not touched. However, the perf_pmu_disable/enable pair is invoked when sampling read in a NMI handler. The cpuc->enabled is mistakenly set by the perf_pmu_enable(). Avoid disabling PMU if the core PMU is already disabled. Merge the logic together. Fixes: 7b2c05a15d29 ("perf/x86/intel: Generic support for hardware TopDown metrics") Suggested-by: Peter Zijlstra (Intel) Signed-off-by: Kan Liang Signed-off-by: Peter Zijlstra (Intel) Cc: stable@vger.kernel.org Link: https://lkml.kernel.org/r/20250121152303.3128733-2-kan.liang@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- arch/x86/events/intel/core.c | 45 ++++++++++++++++++++---------------- arch/x86/events/intel/ds.c | 11 +-------- arch/x86/events/perf_event.h | 2 +- 3 files changed, 27 insertions(+), 31 deletions(-) diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 6ad22e187b06..f86e47afd560 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -2779,28 +2779,33 @@ static u64 icl_update_topdown_event(struct perf_event *event) DEFINE_STATIC_CALL(intel_pmu_update_topdown_event, x86_perf_event_update); -static void intel_pmu_read_topdown_event(struct perf_event *event) -{ - struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); - - /* Only need to call update_topdown_event() once for group read. */ - if ((cpuc->txn_flags & PERF_PMU_TXN_READ) && - !is_slots_event(event)) - return; - - perf_pmu_disable(event->pmu); - static_call(intel_pmu_update_topdown_event)(event); - perf_pmu_enable(event->pmu); -} - static void intel_pmu_read_event(struct perf_event *event) { - if (event->hw.flags & PERF_X86_EVENT_AUTO_RELOAD) - intel_pmu_auto_reload_read(event); - else if (is_topdown_count(event)) - intel_pmu_read_topdown_event(event); - else - x86_perf_event_update(event); + if (event->hw.flags & (PERF_X86_EVENT_AUTO_RELOAD | PERF_X86_EVENT_TOPDOWN)) { + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); + bool pmu_enabled = cpuc->enabled; + + /* Only need to call update_topdown_event() once for group read. */ + if (is_metric_event(event) && (cpuc->txn_flags & PERF_PMU_TXN_READ)) + return; + + cpuc->enabled = 0; + if (pmu_enabled) + intel_pmu_disable_all(); + + if (is_topdown_event(event)) + static_call(intel_pmu_update_topdown_event)(event); + else + intel_pmu_drain_pebs_buffer(); + + cpuc->enabled = pmu_enabled; + if (pmu_enabled) + intel_pmu_enable_all(0); + + return; + } + + x86_perf_event_update(event); } static void intel_pmu_enable_fixed(struct perf_event *event) diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c index 80cb7a9bd854..1617aa3efd68 100644 --- a/arch/x86/events/intel/ds.c +++ b/arch/x86/events/intel/ds.c @@ -932,7 +932,7 @@ unlock: return 1; } -static inline void intel_pmu_drain_pebs_buffer(void) +void intel_pmu_drain_pebs_buffer(void) { struct perf_sample_data data; @@ -2079,15 +2079,6 @@ get_next_pebs_record_by_bit(void *base, void *top, int bit) return NULL; } -void intel_pmu_auto_reload_read(struct perf_event *event) -{ - WARN_ON(!(event->hw.flags & PERF_X86_EVENT_AUTO_RELOAD)); - - perf_pmu_disable(event->pmu); - intel_pmu_drain_pebs_buffer(); - perf_pmu_enable(event->pmu); -} - /* * Special variant of intel_pmu_save_and_restart() for auto-reload. */ diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h index b440f7295f1f..8c616656391e 100644 --- a/arch/x86/events/perf_event.h +++ b/arch/x86/events/perf_event.h @@ -1627,7 +1627,7 @@ void intel_pmu_pebs_disable_all(void); void intel_pmu_pebs_sched_task(struct perf_event_pmu_context *pmu_ctx, bool sched_in); -void intel_pmu_auto_reload_read(struct perf_event *event); +void intel_pmu_drain_pebs_buffer(void); void intel_pmu_store_pebs_lbrs(struct lbr_entry *lbr); From c35771342e47d58ab9433f3be1c3c30f2c5fa4f3 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 12 Feb 2025 23:04:33 +0100 Subject: [PATCH 24/45] uprobes/x86: Harden uretprobe syscall trampoline check commit fa6192adc32f4fdfe5b74edd5b210e12afd6ecc0 upstream. Jann reported a possible issue when trampoline_check_ip returns address near the bottom of the address space that is allowed to call into the syscall if uretprobes are not set up: https://lore.kernel.org/bpf/202502081235.5A6F352985@keescook/T/#m9d416df341b8fbc11737dacbcd29f0054413cbbf Though the mmap minimum address restrictions will typically prevent creating mappings there, let's make sure uretprobe syscall checks for that. Fixes: ff474a78cef5 ("uprobe: Add uretprobe syscall to speed up return probe") Reported-by: Jann Horn Signed-off-by: Jiri Olsa Signed-off-by: Ingo Molnar Reviewed-by: Oleg Nesterov Reviewed-by: Kees Cook Acked-by: Andrii Nakryiko Acked-by: Masami Hiramatsu (Google) Acked-by: Alexei Starovoitov Cc: Andy Lutomirski Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20250212220433.3624297-1-jolsa@kernel.org Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/uprobes.c | 14 +++++++++----- include/linux/uprobes.h | 2 ++ kernel/events/uprobes.c | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c index 5a952c5ea66b..9194695662b2 100644 --- a/arch/x86/kernel/uprobes.c +++ b/arch/x86/kernel/uprobes.c @@ -357,19 +357,23 @@ void *arch_uprobe_trampoline(unsigned long *psize) return &insn; } -static unsigned long trampoline_check_ip(void) +static unsigned long trampoline_check_ip(unsigned long tramp) { - unsigned long tramp = uprobe_get_trampoline_vaddr(); - return tramp + (uretprobe_syscall_check - uretprobe_trampoline_entry); } SYSCALL_DEFINE0(uretprobe) { struct pt_regs *regs = task_pt_regs(current); - unsigned long err, ip, sp, r11_cx_ax[3]; + unsigned long err, ip, sp, r11_cx_ax[3], tramp; - if (regs->ip != trampoline_check_ip()) + /* If there's no trampoline, we are called from wrong place. */ + tramp = uprobe_get_trampoline_vaddr(); + if (unlikely(tramp == UPROBE_NO_TRAMPOLINE_VADDR)) + goto sigill; + + /* Make sure the ip matches the only allowed sys_uretprobe caller. */ + if (unlikely(regs->ip != trampoline_check_ip(tramp))) goto sigill; err = copy_from_user(r11_cx_ax, (void __user *)regs->sp, sizeof(r11_cx_ax)); diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h index 2b294bf1881f..d0cb0e02cd6a 100644 --- a/include/linux/uprobes.h +++ b/include/linux/uprobes.h @@ -28,6 +28,8 @@ struct page; #define MAX_URETPROBE_DEPTH 64 +#define UPROBE_NO_TRAMPOLINE_VADDR (~0UL) + struct uprobe_consumer { /* * handler() can return UPROBE_HANDLER_REMOVE to signal the need to diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index b0909c3839fd..e60f5e71e35d 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -1898,8 +1898,8 @@ void uprobe_copy_process(struct task_struct *t, unsigned long flags) */ unsigned long uprobe_get_trampoline_vaddr(void) { + unsigned long trampoline_vaddr = UPROBE_NO_TRAMPOLINE_VADDR; struct xol_area *area; - unsigned long trampoline_vaddr = -1; /* Pairs with xol_add_vma() smp_store_release() */ area = READ_ONCE(current->mm->uprobes_state.xol_area); /* ^^^ */ From e8bba7ced03ef9a8de546ba2f79945aa13a0e9e6 Mon Sep 17 00:00:00 2001 From: Joe Damato Date: Fri, 4 Oct 2024 10:54:07 +0000 Subject: [PATCH 25/45] idpf: Don't hard code napi_struct size commit 49717ef01ce1b6dbe4cd12bee0fc25e086c555df upstream. The sizeof(struct napi_struct) can change. Don't hardcode the size to 400 bytes and instead use "sizeof(struct napi_struct)". Suggested-by: Alexander Lobakin Signed-off-by: Joe Damato Acked-by: Alexander Lobakin Link: https://patch.msgid.link/20241004105407.73585-1-jdamato@fastly.com Signed-off-by: Jakub Kicinski [Yifei: In Linux-6.12.y, it still hard code the size of napi_struct, adding a member will lead the entire build failed] Signed-off-by: Yifei Liu Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/idpf/idpf_txrx.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h index f0537826f840..9c1fe84108ed 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h @@ -438,7 +438,8 @@ struct idpf_q_vector { __cacheline_group_end_aligned(cold); }; libeth_cacheline_set_assert(struct idpf_q_vector, 112, - 424 + 2 * sizeof(struct dim), + 24 + sizeof(struct napi_struct) + + 2 * sizeof(struct dim), 8 + sizeof(cpumask_var_t)); struct idpf_rx_queue_stats { From e3d54decc75c40ec76fff5b60ee6d4152e2bb22e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 26 Feb 2025 22:37:05 +0100 Subject: [PATCH 26/45] x86/Kconfig: Add cmpxchg8b support back to Geode CPUs commit 6ac43f2be982ea54b75206dccd33f4cf81bfdc39 upstream. An older cleanup of mine inadvertently removed geode-gx1 and geode-lx from the list of CPUs that are known to support a working cmpxchg8b. Fixes: 88a2b4edda3d ("x86/Kconfig: Rework CONFIG_X86_PAE dependency") Signed-off-by: Arnd Bergmann Signed-off-by: Ingo Molnar Cc: Linus Torvalds Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20250226213714.4040853-2-arnd@kernel.org Signed-off-by: Greg Kroah-Hartman --- arch/x86/Kconfig.cpu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu index 2a7279d80460..42e6a40876ea 100644 --- a/arch/x86/Kconfig.cpu +++ b/arch/x86/Kconfig.cpu @@ -368,7 +368,7 @@ config X86_HAVE_PAE config X86_CMPXCHG64 def_bool y - depends on X86_HAVE_PAE || M586TSC || M586MMX || MK6 || MK7 + depends on X86_HAVE_PAE || M586TSC || M586MMX || MK6 || MK7 || MGEODEGX1 || MGEODE_LX # this should be set for all -march=.. options where the compiler # generates cmov. From 70a2fa13d4a9e782ee342354202fd4190e075108 Mon Sep 17 00:00:00 2001 From: "Guilherme G. Piccoli" Date: Sat, 15 Feb 2025 17:58:16 -0300 Subject: [PATCH 27/45] x86/tsc: Always save/restore TSC sched_clock() on suspend/resume commit d90c9de9de2f1712df56de6e4f7d6982d358cabe upstream. TSC could be reset in deep ACPI sleep states, even with invariant TSC. That's the reason we have sched_clock() save/restore functions, to deal with this situation. But what happens is that such functions are guarded with a check for the stability of sched_clock - if not considered stable, the save/restore routines aren't executed. On top of that, we have a clear comment in native_sched_clock() saying that *even* with TSC unstable, we continue using TSC for sched_clock due to its speed. In other words, if we have a situation of TSC getting detected as unstable, it marks the sched_clock as unstable as well, so subsequent S3 sleep cycles could bring bogus sched_clock values due to the lack of the save/restore mechanism, causing warnings like this: [22.954918] ------------[ cut here ]------------ [22.954923] Delta way too big! 18446743750843854390 ts=18446744072977390405 before=322133536015 after=322133536015 write stamp=18446744072977390405 [22.954923] If you just came from a suspend/resume, [22.954923] please switch to the trace global clock: [22.954923] echo global > /sys/kernel/tracing/trace_clock [22.954923] or add trace_clock=global to the kernel command line [22.954937] WARNING: CPU: 2 PID: 5728 at kernel/trace/ring_buffer.c:2890 rb_add_timestamp+0x193/0x1c0 Notice that the above was reproduced even with "trace_clock=global". The fix for that is to _always_ save/restore the sched_clock on suspend cycle _if TSC is used_ as sched_clock - only if we fallback to jiffies the sched_clock_stable() check becomes relevant to save/restore the sched_clock. Debugged-by: Thadeu Lima de Souza Cascardo Signed-off-by: Guilherme G. Piccoli Signed-off-by: Ingo Molnar Cc: stable@vger.kernel.org Cc: Thomas Gleixner Cc: Peter Zijlstra Cc: Linus Torvalds Link: https://lore.kernel.org/r/20250215210314.351480-1-gpiccoli@igalia.com Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/tsc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index dfe6847fd99e..310d8cdf7ca3 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -956,7 +956,7 @@ static unsigned long long cyc2ns_suspend; void tsc_save_sched_clock_state(void) { - if (!sched_clock_stable()) + if (!static_branch_likely(&__use_tsc) && !sched_clock_stable()) return; cyc2ns_suspend = sched_clock(); @@ -976,7 +976,7 @@ void tsc_restore_sched_clock_state(void) unsigned long flags; int cpu; - if (!sched_clock_stable()) + if (!static_branch_likely(&__use_tsc) && !sched_clock_stable()) return; local_irq_save(flags); From 93224deb50a8d20df3884f3672ce9f982129aa50 Mon Sep 17 00:00:00 2001 From: Jann Horn Date: Fri, 3 Jan 2025 19:39:38 +0100 Subject: [PATCH 28/45] x86/mm: Fix flush_tlb_range() when used for zapping normal PMDs commit 3ef938c3503563bfc2ac15083557f880d29c2e64 upstream. On the following path, flush_tlb_range() can be used for zapping normal PMD entries (PMD entries that point to page tables) together with the PTE entries in the pointed-to page table: collapse_pte_mapped_thp pmdp_collapse_flush flush_tlb_range The arm64 version of flush_tlb_range() has a comment describing that it can be used for page table removal, and does not use any last-level invalidation optimizations. Fix the X86 version by making it behave the same way. Currently, X86 only uses this information for the following two purposes, which I think means the issue doesn't have much impact: - In native_flush_tlb_multi() for checking if lazy TLB CPUs need to be IPI'd to avoid issues with speculative page table walks. - In Hyper-V TLB paravirtualization, again for lazy TLB stuff. The patch "x86/mm: only invalidate final translations with INVLPGB" which is currently under review (see ) would probably be making the impact of this a lot worse. Fixes: 016c4d92cd16 ("x86/mm/tlb: Add freed_tables argument to flush_tlb_mm_range") Signed-off-by: Jann Horn Signed-off-by: Peter Zijlstra (Intel) Cc: stable@vger.kernel.org Link: https://lkml.kernel.org/r/20250103-x86-collapse-flush-fix-v1-1-3c521856cfa6@google.com Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/tlbflush.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h index 02fc2aa06e9e..3da645139748 100644 --- a/arch/x86/include/asm/tlbflush.h +++ b/arch/x86/include/asm/tlbflush.h @@ -242,7 +242,7 @@ void flush_tlb_multi(const struct cpumask *cpumask, flush_tlb_mm_range((vma)->vm_mm, start, end, \ ((vma)->vm_flags & VM_HUGETLB) \ ? huge_page_shift(hstate_vma(vma)) \ - : PAGE_SHIFT, false) + : PAGE_SHIFT, true) extern void flush_tlb_all(void); extern void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, From 339d6c965f207eecf273cf684677d27d9466e932 Mon Sep 17 00:00:00 2001 From: Ming Yen Hsieh Date: Tue, 4 Mar 2025 19:36:47 +0800 Subject: [PATCH 29/45] wifi: mt76: mt7925: remove unused acpi function for clc commit b4ea6fdfc08375aae59c7e7059653b9877171fe4 upstream. The code for handling ACPI configuration in CLC was copied from the mt7921 driver but is not utilized in the mt7925 implementation. So removes the unused functionality to clean up the codebase. Cc: stable@vger.kernel.org Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips") Signed-off-by: Ming Yen Hsieh Link: https://patch.msgid.link/20250304113649.867387-4-mingyen.hsieh@mediatek.com Signed-off-by: Felix Fietkau Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index ce3d8197b026..c7eba60897d2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -3117,7 +3117,6 @@ __mt7925_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, .idx = idx, .env = env_cap, - .acpi_conf = mt792x_acpi_get_flags(&dev->phy), }; int ret, valid_cnt = 0; u8 i, *pos; From e71a57c5aaa389d4c3c82f920761262efdd18d38 Mon Sep 17 00:00:00 2001 From: Murad Masimov Date: Thu, 23 Jan 2025 19:39:45 +0300 Subject: [PATCH 30/45] acpi: nfit: fix narrowing conversion in acpi_nfit_ctl commit 2ff0e408db36c21ed3fa5e3c1e0e687c82cf132f upstream. Syzkaller has reported a warning in to_nfit_bus_uuid(): "only secondary bus families can be translated". This warning is emited if the argument is equal to NVDIMM_BUS_FAMILY_NFIT == 0. Function acpi_nfit_ctl() first verifies that a user-provided value call_pkg->nd_family of type u64 is not equal to 0. Then the value is converted to int, and only after that is compared to NVDIMM_BUS_FAMILY_MAX. This can lead to passing an invalid argument to acpi_nfit_ctl(), if call_pkg->nd_family is non-zero, while the lower 32 bits are zero. Furthermore, it is best to return EINVAL immediately upon seeing the invalid user input. The WARNING is insufficient to prevent further undefined behavior based on other invalid user input. All checks of the input value should be applied to the original variable call_pkg->nd_family. [iweiny: update commit message] Fixes: 6450ddbd5d8e ("ACPI: NFIT: Define runtime firmware activation commands") Cc: stable@vger.kernel.org Reported-by: syzbot+c80d8dc0d9fa81a3cd8c@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=c80d8dc0d9fa81a3cd8c Signed-off-by: Murad Masimov Link: https://patch.msgid.link/20250123163945.251-1-m.masimov@mt-integration.ru Signed-off-by: Ira Weiny Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/nfit/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index a5d47819b3a4..ae035b93da08 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -485,7 +485,7 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, cmd_mask = nd_desc->cmd_mask; if (cmd == ND_CMD_CALL && call_pkg->nd_family) { family = call_pkg->nd_family; - if (family > NVDIMM_BUS_FAMILY_MAX || + if (call_pkg->nd_family > NVDIMM_BUS_FAMILY_MAX || !test_bit(family, &nd_desc->bus_family_mask)) return -EINVAL; family = array_index_nospec(family, From 498edda23f7e643ad2b100e47c3257ac21a83a47 Mon Sep 17 00:00:00 2001 From: Paul Menzel Date: Tue, 18 Mar 2025 17:09:02 +0100 Subject: [PATCH 31/45] ACPI: resource: Skip IRQ override on ASUS Vivobook 14 X1404VAP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 2da31ea2a085cd189857f2db0f7b78d0162db87a upstream. Like the ASUS Vivobook X1504VAP and Vivobook X1704VAP, the ASUS Vivobook 14 X1404VAP has its keyboard IRQ (1) described as ActiveLow in the DSDT, which the kernel overrides to EdgeHigh breaking the keyboard. $ sudo dmidecode […] System Information Manufacturer: ASUSTeK COMPUTER INC. Product Name: ASUS Vivobook 14 X1404VAP_X1404VA […] $ grep -A 30 PS2K dsdt.dsl | grep IRQ -A 1 IRQ (Level, ActiveLow, Exclusive, ) {1} Add the X1404VAP to the irq1_level_low_skip_override[] quirk table to fix this. Closes: https://bugzilla.kernel.org/show_bug.cgi?id=219224 Cc: All applicable Signed-off-by: Paul Menzel Reviewed-by: Hans de Goede Tested-by: Anton Shyndin Link: https://patch.msgid.link/20250318160903.77107-1-pmenzel@molgen.mpg.de Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/resource.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index b4cd14e7fa76..14c7bac4100b 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -440,6 +440,13 @@ static const struct dmi_system_id irq1_level_low_skip_override[] = { DMI_MATCH(DMI_BOARD_NAME, "S5602ZA"), }, }, + { + /* Asus Vivobook X1404VAP */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_BOARD_NAME, "X1404VAP"), + }, + }, { /* Asus Vivobook X1504VAP */ .matches = { From 9f7ae45f0c615d0c26ce6d42f712f525764699ed Mon Sep 17 00:00:00 2001 From: Christian Eggers Date: Thu, 20 Mar 2025 22:33:51 +0100 Subject: [PATCH 32/45] ARM: 9444/1: add KEEP() keyword to ARM_VECTORS commit c3d944a367c0d9e4e125c7006e52f352e75776dc upstream. Without this, the vectors are removed if LD_DEAD_CODE_DATA_ELIMINATION is enabled. At startup, the CPU (silently) hangs in the undefined instruction exception as soon as the first timer interrupt arrives. On my setup, the system also boots fine without the 2nd and 3rd KEEP() statements, so I cannot tell whether these are actually required. [nathan: Use OVERLAY_KEEP() to avoid breaking old ld.lld versions] Cc: stable@vger.kernel.org Fixes: ed0f94102251 ("ARM: 9404/1: arm32: enable HAVE_LD_DEAD_CODE_DATA_ELIMINATION") Signed-off-by: Christian Eggers Reviewed-by: Linus Walleij Signed-off-by: Nathan Chancellor Signed-off-by: Russell King (Oracle) Signed-off-by: Greg Kroah-Hartman --- arch/arm/include/asm/vmlinux.lds.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/include/asm/vmlinux.lds.h b/arch/arm/include/asm/vmlinux.lds.h index d60f6e83a9f7..f6623fc6cc39 100644 --- a/arch/arm/include/asm/vmlinux.lds.h +++ b/arch/arm/include/asm/vmlinux.lds.h @@ -125,13 +125,13 @@ __vectors_lma = .; \ OVERLAY 0xffff0000 : NOCROSSREFS AT(__vectors_lma) { \ .vectors { \ - *(.vectors) \ + OVERLAY_KEEP(*(.vectors)) \ } \ .vectors.bhb.loop8 { \ - *(.vectors.bhb.loop8) \ + OVERLAY_KEEP(*(.vectors.bhb.loop8)) \ } \ .vectors.bhb.bpiall { \ - *(.vectors.bhb.bpiall) \ + OVERLAY_KEEP(*(.vectors.bhb.bpiall)) \ } \ } \ ARM_LMA(__vectors, .vectors); \ From 6b9ddc4f5f2e2698ac83e9d0824c0c91d7bb447c Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Mon, 28 Oct 2024 17:58:36 +0000 Subject: [PATCH 33/45] media: omap3isp: Handle ARM dma_iommu_mapping commit 6bc076eec6f85f778f33a8242b438e1bd9fcdd59 upstream. It's no longer practical for the OMAP IOMMU driver to trick arm_setup_iommu_dma_ops() into ignoring its presence, so let's use the same tactic as other IOMMU API users on 32-bit ARM and explicitly kick the arch code's dma_iommu_mapping out of the way to avoid problems. Fixes: 4720287c7bf7 ("iommu: Remove struct iommu_ops *iommu from arch_setup_dma_ops()") Cc: stable@vger.kernel.org Signed-off-by: Robin Murphy Tested-by: Sicelo A. Mhlongo Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil Signed-off-by: Greg Kroah-Hartman --- drivers/media/platform/ti/omap3isp/isp.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/media/platform/ti/omap3isp/isp.c b/drivers/media/platform/ti/omap3isp/isp.c index 91101ba88ef0..b2210841a320 100644 --- a/drivers/media/platform/ti/omap3isp/isp.c +++ b/drivers/media/platform/ti/omap3isp/isp.c @@ -1961,6 +1961,13 @@ static int isp_attach_iommu(struct isp_device *isp) struct dma_iommu_mapping *mapping; int ret; + /* We always want to replace any default mapping from the arch code */ + mapping = to_dma_iommu_mapping(isp->dev); + if (mapping) { + arm_iommu_detach_device(isp->dev); + arm_iommu_release_mapping(mapping); + } + /* * Create the ARM mapping, used by the ARM DMA mapping core to allocate * VAs. This will allocate a corresponding IOMMU domain. From 0c121f2065e44ae055e2661f05b4cfe6f6d6c500 Mon Sep 17 00:00:00 2001 From: Candice Li Date: Wed, 26 Mar 2025 13:41:01 +0800 Subject: [PATCH 34/45] Remove unnecessary firmware version check for gc v9_4_2 commit 5b3c08ae9ed324743f5f7286940d45caeb656e6e upstream. GC v9_4_2 uses a new versioning scheme for CP firmware, making the warning ("CP firmware version too old, please update!") irrelevant. Signed-off-by: Candice Li Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index 05d1ae2ef84b..114653a0b570 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -1269,6 +1269,7 @@ static void gfx_v9_0_check_fw_write_wait(struct amdgpu_device *adev) adev->gfx.mec_fw_write_wait = false; if ((amdgpu_ip_version(adev, GC_HWIP, 0) != IP_VERSION(9, 4, 1)) && + (amdgpu_ip_version(adev, GC_HWIP, 0) != IP_VERSION(9, 4, 2)) && ((adev->gfx.mec_fw_version < 0x000001a5) || (adev->gfx.mec_feature_version < 46) || (adev->gfx.pfp_fw_version < 0x000000b7) || From b548a448993ac2b8cb0ec64e9353cfdf6d2f79a9 Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Tue, 18 Mar 2025 22:02:25 +0800 Subject: [PATCH 35/45] mmc: omap: Fix memory leak in mmc_omap_new_slot commit 3834a759afb817e23a7a2f09c2c9911b0ce5c588 upstream. Add err_free_host label to properly pair mmc_alloc_host() with mmc_free_host() in GPIO error paths. The allocated host memory was leaked when GPIO lookups failed. Fixes: e519f0bb64ef ("ARM/mmc: Convert old mmci-omap to GPIO descriptors") Signed-off-by: Miaoqian Lin Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20250318140226.19650-1-linmq006@gmail.com Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/omap.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 335350a4e99a..ee0940d96feb 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -1272,19 +1272,25 @@ static int mmc_omap_new_slot(struct mmc_omap_host *host, int id) /* Check for some optional GPIO controls */ slot->vsd = devm_gpiod_get_index_optional(host->dev, "vsd", id, GPIOD_OUT_LOW); - if (IS_ERR(slot->vsd)) - return dev_err_probe(host->dev, PTR_ERR(slot->vsd), + if (IS_ERR(slot->vsd)) { + r = dev_err_probe(host->dev, PTR_ERR(slot->vsd), "error looking up VSD GPIO\n"); + goto err_free_host; + } slot->vio = devm_gpiod_get_index_optional(host->dev, "vio", id, GPIOD_OUT_LOW); - if (IS_ERR(slot->vio)) - return dev_err_probe(host->dev, PTR_ERR(slot->vio), + if (IS_ERR(slot->vio)) { + r = dev_err_probe(host->dev, PTR_ERR(slot->vio), "error looking up VIO GPIO\n"); + goto err_free_host; + } slot->cover = devm_gpiod_get_index_optional(host->dev, "cover", id, GPIOD_IN); - if (IS_ERR(slot->cover)) - return dev_err_probe(host->dev, PTR_ERR(slot->cover), + if (IS_ERR(slot->cover)) { + r = dev_err_probe(host->dev, PTR_ERR(slot->cover), "error looking up cover switch GPIO\n"); + goto err_free_host; + } host->slots[id] = slot; @@ -1344,6 +1350,7 @@ err_remove_slot_name: device_remove_file(&mmc->class_dev, &dev_attr_slot_name); err_remove_host: mmc_remove_host(mmc); +err_free_host: mmc_free_host(mmc); return r; } From 1209241a6b40c8fff985a32fcaa75e174d37ff5f Mon Sep 17 00:00:00 2001 From: Karel Balej Date: Mon, 10 Mar 2025 15:07:04 +0100 Subject: [PATCH 36/45] mmc: sdhci-pxav3: set NEED_RSP_BUSY capability MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit a41fcca4b342811b473bbaa4b44f1d34d87fcce6 upstream. Set the MMC_CAP_NEED_RSP_BUSY capability for the sdhci-pxav3 host to prevent conversion of R1B responses to R1. Without this, the eMMC card in the samsung,coreprimevelte smartphone using the Marvell PXA1908 SoC with this mmc host doesn't probe with the ETIMEDOUT error originating in __mmc_poll_for_busy. Note that the other issues reported for this phone and host, namely floods of "Tuning failed, falling back to fixed sampling clock" dmesg messages for the eMMC and unstable SDIO are not mitigated by this change. Link: https://lore.kernel.org/r/20200310153340.5593-1-ulf.hansson@linaro.org/ Link: https://lore.kernel.org/r/D7204PWIGQGI.1FRFQPPIEE2P9@matfyz.cz/ Link: https://lore.kernel.org/r/20250115-pxa1908-lkml-v14-0-847d24f3665a@skole.hr/ Cc: stable@vger.kernel.org Signed-off-by: Karel Balej Acked-by: Adrian Hunter Tested-by: Duje Mihanović Link: https://lore.kernel.org/r/20250310140707.23459-1-balejk@matfyz.cz Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/sdhci-pxav3.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index 3af43ac05825..376fd927ae73 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -399,6 +399,7 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) if (!IS_ERR(pxa->clk_core)) clk_prepare_enable(pxa->clk_core); + host->mmc->caps |= MMC_CAP_NEED_RSP_BUSY; /* enable 1/8V DDR capable */ host->mmc->caps |= MMC_CAP_1_8V_DDR; From a31fa24813a770dc3389e5174a7757e74b96ac0f Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 12 Mar 2025 13:17:12 +0100 Subject: [PATCH 37/45] mmc: sdhci-omap: Disable MMC_CAP_AGGRESSIVE_PM for eMMC/SD commit 49d162635151d0dd04935070d7cf67137ab863aa upstream. We have received reports about cards can become corrupt related to the aggressive PM support. Let's make a partial revert of the change that enabled the feature. Reported-by: David Owens Reported-by: Romain Naour Reported-by: Robert Nelson Tested-by: Robert Nelson Fixes: 3edf588e7fe0 ("mmc: sdhci-omap: Allow SDIO card power off and enable aggressive PM") Cc: stable@vger.kernel.org Signed-off-by: Ulf Hansson Acked-by: Adrian Hunter Reviewed-by: Tony Lindgren Link: https://lore.kernel.org/r/20250312121712.1168007-1-ulf.hansson@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/sdhci-omap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index 5841a9afeb9f..ea4a801c9ace 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -1339,8 +1339,8 @@ static int sdhci_omap_probe(struct platform_device *pdev) /* R1B responses is required to properly manage HW busy detection. */ mmc->caps |= MMC_CAP_NEED_RSP_BUSY; - /* Allow card power off and runtime PM for eMMC/SD card devices */ - mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_AGGRESSIVE_PM; + /* Enable SDIO card power off. */ + mmc->caps |= MMC_CAP_POWER_OFF_CARD; ret = sdhci_setup_host(host); if (ret) From 9bc3299039d2c10d4fff7650ac17e415e87a862c Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 26 Feb 2025 17:25:35 -0800 Subject: [PATCH 38/45] KVM: SVM: Don't change target vCPU state on AP Creation VMGEXIT error commit d26638bfcdfc5c8c4e085dc3f5976a0443abab3c upstream. If KVM rejects an AP Creation event, leave the target vCPU state as-is. Nothing in the GHCB suggests the hypervisor is *allowed* to muck with vCPU state on failure, let alone required to do so. Furthermore, kicking only in the !ON_INIT case leads to divergent behavior, and even the "kick" case is non-deterministic. E.g. if an ON_INIT request fails, the guest can successfully retry if the fixed AP Creation request is made prior to sending INIT. And if a !ON_INIT fails, the guest can successfully retry if the fixed AP Creation request is handled before the target vCPU processes KVM's KVM_REQ_UPDATE_PROTECTED_GUEST_STATE. Fixes: e366f92ea99e ("KVM: SEV: Support SEV-SNP AP Creation NAE event") Cc: stable@vger.kernel.org Reviewed-by: Tom Lendacky Reviewed-by: Pankaj Gupta Link: https://lore.kernel.org/r/20250227012541.3234589-5-seanjc@google.com Signed-off-by: Sean Christopherson Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/svm/sev.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 3ec56bf76ef1..6154cb450b44 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -3957,16 +3957,12 @@ static int sev_snp_ap_creation(struct vcpu_svm *svm) /* * The target vCPU is valid, so the vCPU will be kicked unless the - * request is for CREATE_ON_INIT. For any errors at this stage, the - * kick will place the vCPU in an non-runnable state. + * request is for CREATE_ON_INIT. */ kick = true; mutex_lock(&target_svm->sev_es.snp_vmsa_mutex); - target_svm->sev_es.snp_vmsa_gpa = INVALID_PAGE; - target_svm->sev_es.snp_ap_waiting_for_reset = true; - /* Interrupt injection mode shouldn't change for AP creation */ if (request < SVM_VMGEXIT_AP_DESTROY) { u64 sev_features; @@ -4012,20 +4008,23 @@ static int sev_snp_ap_creation(struct vcpu_svm *svm) target_svm->sev_es.snp_vmsa_gpa = svm->vmcb->control.exit_info_2; break; case SVM_VMGEXIT_AP_DESTROY: + target_svm->sev_es.snp_vmsa_gpa = INVALID_PAGE; break; default: vcpu_unimpl(vcpu, "vmgexit: invalid AP creation request [%#x] from guest\n", request); ret = -EINVAL; - break; + goto out; } -out: + target_svm->sev_es.snp_ap_waiting_for_reset = true; + if (kick) { kvm_make_request(KVM_REQ_UPDATE_PROTECTED_GUEST_STATE, target_vcpu); kvm_vcpu_kick(target_vcpu); } +out: mutex_unlock(&target_svm->sev_es.snp_vmsa_mutex); return ret; From 29b946714d6aa77de54c71243bba39469ac43ef2 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Fri, 14 Mar 2025 18:21:47 +0900 Subject: [PATCH 39/45] ksmbd: add bounds check for durable handle context commit 542027e123fc0bfd61dd59e21ae0ee4ef2101b29 upstream. Add missing bounds check for durable handle context. Cc: stable@vger.kernel.org Reported-by: Norbert Szetei Tested-by: Norbert Szetei Signed-off-by: Namjae Jeon Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/smb/server/smb2pdu.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 5b94d90870b0..1c7433aaad29 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -2699,6 +2699,13 @@ static int parse_durable_handle_context(struct ksmbd_work *work, goto out; } + if (le16_to_cpu(context->DataOffset) + + le32_to_cpu(context->DataLength) < + sizeof(struct create_durable_reconn_v2_req)) { + err = -EINVAL; + goto out; + } + recon_v2 = (struct create_durable_reconn_v2_req *)context; persistent_id = recon_v2->Fid.PersistentFileId; dh_info->fp = ksmbd_lookup_durable_fd(persistent_id); @@ -2732,6 +2739,13 @@ static int parse_durable_handle_context(struct ksmbd_work *work, goto out; } + if (le16_to_cpu(context->DataOffset) + + le32_to_cpu(context->DataLength) < + sizeof(struct create_durable_reconn_req)) { + err = -EINVAL; + goto out; + } + recon = (struct create_durable_reconn_req *)context; persistent_id = recon->Data.Fid.PersistentFileId; dh_info->fp = ksmbd_lookup_durable_fd(persistent_id); @@ -2757,6 +2771,13 @@ static int parse_durable_handle_context(struct ksmbd_work *work, goto out; } + if (le16_to_cpu(context->DataOffset) + + le32_to_cpu(context->DataLength) < + sizeof(struct create_durable_req_v2)) { + err = -EINVAL; + goto out; + } + durable_v2_blob = (struct create_durable_req_v2 *)context; ksmbd_debug(SMB, "Request for durable v2 open\n"); From 800c482c9ef5910f05e3a713943c67cc6c1d4939 Mon Sep 17 00:00:00 2001 From: Norbert Szetei Date: Sat, 15 Mar 2025 12:19:28 +0900 Subject: [PATCH 40/45] ksmbd: add bounds check for create lease context commit bab703ed8472aa9d109c5f8c1863921533363dae upstream. Add missing bounds check for create lease context. Cc: stable@vger.kernel.org Reported-by: Norbert Szetei Tested-by: Norbert Szetei Signed-off-by: Norbert Szetei Signed-off-by: Namjae Jeon Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/smb/server/oplock.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c index 304aefecaaaf..deacf78b4400 100644 --- a/fs/smb/server/oplock.c +++ b/fs/smb/server/oplock.c @@ -1505,6 +1505,10 @@ struct lease_ctx_info *parse_lease_state(void *open_req) if (sizeof(struct lease_context_v2) == le32_to_cpu(cc->DataLength)) { struct create_lease_v2 *lc = (struct create_lease_v2 *)cc; + if (le16_to_cpu(cc->DataOffset) + le32_to_cpu(cc->DataLength) < + sizeof(struct create_lease_v2) - 4) + return NULL; + memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE); lreq->req_state = lc->lcontext.LeaseState; lreq->flags = lc->lcontext.LeaseFlags; @@ -1517,6 +1521,10 @@ struct lease_ctx_info *parse_lease_state(void *open_req) } else { struct create_lease *lc = (struct create_lease *)cc; + if (le16_to_cpu(cc->DataOffset) + le32_to_cpu(cc->DataLength) < + sizeof(struct create_lease)) + return NULL; + memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE); lreq->req_state = lc->lcontext.LeaseState; lreq->flags = lc->lcontext.LeaseFlags; From ca042cc0e4f9e0d2c8f86dd67e4b22f30a516a9b Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sat, 22 Mar 2025 09:20:19 +0900 Subject: [PATCH 41/45] ksmbd: fix use-after-free in ksmbd_sessions_deregister() commit 15a9605f8d69dc85005b1a00c31a050b8625e1aa upstream. In multichannel mode, UAF issue can occur in session_deregister when the second channel sets up a session through the connection of the first channel. session that is freed through the global session table can be accessed again through ->sessions of connection. Cc: stable@vger.kernel.org Reported-by: Norbert Szetei Tested-by: Norbert Szetei Signed-off-by: Namjae Jeon Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/smb/server/mgmt/user_session.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c index 3d47da9c18c4..16d15f0a72b8 100644 --- a/fs/smb/server/mgmt/user_session.c +++ b/fs/smb/server/mgmt/user_session.c @@ -230,6 +230,9 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn) if (!ksmbd_chann_del(conn, sess) && xa_empty(&sess->ksmbd_chann_list)) { hash_del(&sess->hlist); + down_write(&conn->session_lock); + xa_erase(&conn->sessions, sess->id); + up_write(&conn->session_lock); ksmbd_session_destroy(sess); } } From 9069939d762138e232a6f79e3e1462682ed6a17d Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Thu, 27 Mar 2025 21:22:51 +0900 Subject: [PATCH 42/45] ksmbd: fix session use-after-free in multichannel connection commit fa4cdb8cbca7d6cb6aa13e4d8d83d1103f6345db upstream. There is a race condition between session setup and ksmbd_sessions_deregister. The session can be freed before the connection is added to channel list of session. This patch check reference count of session before freeing it. Cc: stable@vger.kernel.org Reported-by: Sean Heelan Signed-off-by: Namjae Jeon Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/smb/server/auth.c | 4 ++-- fs/smb/server/mgmt/user_session.c | 14 ++++++++------ fs/smb/server/smb2pdu.c | 7 ++++--- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c index 0d458742b707..954497513683 100644 --- a/fs/smb/server/auth.c +++ b/fs/smb/server/auth.c @@ -1016,9 +1016,9 @@ static int ksmbd_get_encryption_key(struct ksmbd_work *work, __u64 ses_id, ses_enc_key = enc ? sess->smb3encryptionkey : sess->smb3decryptionkey; - if (enc) - ksmbd_user_session_get(sess); memcpy(key, ses_enc_key, SMB3_ENC_DEC_KEY_SIZE); + if (!enc) + ksmbd_user_session_put(sess); return 0; } diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c index 16d15f0a72b8..0963693015ee 100644 --- a/fs/smb/server/mgmt/user_session.c +++ b/fs/smb/server/mgmt/user_session.c @@ -181,7 +181,7 @@ static void ksmbd_expire_session(struct ksmbd_conn *conn) down_write(&sessions_table_lock); down_write(&conn->session_lock); xa_for_each(&conn->sessions, id, sess) { - if (atomic_read(&sess->refcnt) == 0 && + if (atomic_read(&sess->refcnt) <= 1 && (sess->state != SMB2_SESSION_VALID || time_after(jiffies, sess->last_active + SMB2_SESSION_TIMEOUT))) { @@ -233,7 +233,8 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn) down_write(&conn->session_lock); xa_erase(&conn->sessions, sess->id); up_write(&conn->session_lock); - ksmbd_session_destroy(sess); + if (atomic_dec_and_test(&sess->refcnt)) + ksmbd_session_destroy(sess); } } } @@ -252,7 +253,8 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn) if (xa_empty(&sess->ksmbd_chann_list)) { xa_erase(&conn->sessions, sess->id); hash_del(&sess->hlist); - ksmbd_session_destroy(sess); + if (atomic_dec_and_test(&sess->refcnt)) + ksmbd_session_destroy(sess); } } up_write(&conn->session_lock); @@ -328,8 +330,8 @@ void ksmbd_user_session_put(struct ksmbd_session *sess) if (atomic_read(&sess->refcnt) <= 0) WARN_ON(1); - else - atomic_dec(&sess->refcnt); + else if (atomic_dec_and_test(&sess->refcnt)) + ksmbd_session_destroy(sess); } struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn, @@ -436,7 +438,7 @@ static struct ksmbd_session *__session_create(int protocol) xa_init(&sess->rpc_handle_list); sess->sequence_number = 1; rwlock_init(&sess->tree_conns_lock); - atomic_set(&sess->refcnt, 1); + atomic_set(&sess->refcnt, 2); ret = __init_smb2_session(sess); if (ret) diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 1c7433aaad29..3a3c0a99eb04 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -2230,13 +2230,14 @@ int smb2_session_logoff(struct ksmbd_work *work) return -ENOENT; } - ksmbd_destroy_file_table(&sess->file_table); down_write(&conn->session_lock); sess->state = SMB2_SESSION_EXPIRED; up_write(&conn->session_lock); - ksmbd_free_user(sess->user); - sess->user = NULL; + if (sess->user) { + ksmbd_free_user(sess->user); + sess->user = NULL; + } ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_NEGOTIATE); rsp->StructureSize = cpu_to_le16(4); From 6a9cd9ff0fa2bcc30b2bfb8bdb161eb20e44b9dc Mon Sep 17 00:00:00 2001 From: Norbert Szetei Date: Sat, 29 Mar 2025 06:58:15 +0000 Subject: [PATCH 43/45] ksmbd: fix overflow in dacloffset bounds check commit beff0bc9d69bc8e733f9bca28e2d3df5b3e10e42 upstream. The dacloffset field was originally typed as int and used in an unchecked addition, which could overflow and bypass the existing bounds check in both smb_check_perm_dacl() and smb_inherit_dacl(). This could result in out-of-bounds memory access and a kernel crash when dereferencing the DACL pointer. This patch converts dacloffset to unsigned int and uses check_add_overflow() to validate access to the DACL. Cc: stable@vger.kernel.org Signed-off-by: Norbert Szetei Acked-by: Namjae Jeon Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/smb/server/smbacl.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c index 5e6ffb821f6f..9e590c70e3a4 100644 --- a/fs/smb/server/smbacl.c +++ b/fs/smb/server/smbacl.c @@ -1026,7 +1026,9 @@ int smb_inherit_dacl(struct ksmbd_conn *conn, struct dentry *parent = path->dentry->d_parent; struct mnt_idmap *idmap = mnt_idmap(path->mnt); int inherited_flags = 0, flags = 0, i, nt_size = 0, pdacl_size; - int rc = 0, dacloffset, pntsd_type, pntsd_size, acl_len, aces_size; + int rc = 0, pntsd_type, pntsd_size, acl_len, aces_size; + unsigned int dacloffset; + size_t dacl_struct_end; u16 num_aces, ace_cnt = 0; char *aces_base; bool is_dir = S_ISDIR(d_inode(path->dentry)->i_mode); @@ -1035,8 +1037,11 @@ int smb_inherit_dacl(struct ksmbd_conn *conn, parent, &parent_pntsd); if (pntsd_size <= 0) return -ENOENT; + dacloffset = le32_to_cpu(parent_pntsd->dacloffset); - if (!dacloffset || (dacloffset + sizeof(struct smb_acl) > pntsd_size)) { + if (!dacloffset || + check_add_overflow(dacloffset, sizeof(struct smb_acl), &dacl_struct_end) || + dacl_struct_end > (size_t)pntsd_size) { rc = -EINVAL; goto free_parent_pntsd; } @@ -1239,7 +1244,9 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path, struct smb_ntsd *pntsd = NULL; struct smb_acl *pdacl; struct posix_acl *posix_acls; - int rc = 0, pntsd_size, acl_size, aces_size, pdacl_size, dacl_offset; + int rc = 0, pntsd_size, acl_size, aces_size, pdacl_size; + unsigned int dacl_offset; + size_t dacl_struct_end; struct smb_sid sid; int granted = le32_to_cpu(*pdaccess & ~FILE_MAXIMAL_ACCESS_LE); struct smb_ace *ace; @@ -1258,7 +1265,8 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path, dacl_offset = le32_to_cpu(pntsd->dacloffset); if (!dacl_offset || - (dacl_offset + sizeof(struct smb_acl) > pntsd_size)) + check_add_overflow(dacl_offset, sizeof(struct smb_acl), &dacl_struct_end) || + dacl_struct_end > (size_t)pntsd_size) goto err_out; pdacl = (struct smb_acl *)((char *)pntsd + le32_to_cpu(pntsd->dacloffset)); From 56de7778a48560278c334077ace7b9ac4bfb2fd1 Mon Sep 17 00:00:00 2001 From: Norbert Szetei Date: Sat, 29 Mar 2025 16:06:01 +0000 Subject: [PATCH 44/45] ksmbd: validate zero num_subauth before sub_auth is accessed commit bf21e29d78cd2c2371023953d9c82dfef82ebb36 upstream. Access psid->sub_auth[psid->num_subauth - 1] without checking if num_subauth is non-zero leads to an out-of-bounds read. This patch adds a validation step to ensure num_subauth != 0 before sub_auth is accessed. Cc: stable@vger.kernel.org Signed-off-by: Norbert Szetei Acked-by: Namjae Jeon Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/smb/server/smbacl.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c index 9e590c70e3a4..376ae68144af 100644 --- a/fs/smb/server/smbacl.c +++ b/fs/smb/server/smbacl.c @@ -270,6 +270,11 @@ static int sid_to_id(struct mnt_idmap *idmap, return -EIO; } + if (psid->num_subauth == 0) { + pr_err("%s: zero subauthorities!\n", __func__); + return -EIO; + } + if (sidtype == SIDOWNER) { kuid_t uid; uid_t id; From ca8bed31edf728a662ef9d6f39f50e7a7dc2b5ad Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Wed, 2 Apr 2025 09:11:23 +0900 Subject: [PATCH 45/45] ksmbd: fix null pointer dereference in alloc_preauth_hash() commit c8b5b7c5da7d0c31c9b7190b4a7bba5281fc4780 upstream. The Client send malformed smb2 negotiate request. ksmbd return error response. Subsequently, the client can send smb2 session setup even thought conn->preauth_info is not allocated. This patch add KSMBD_SESS_NEED_SETUP status of connection to ignore session setup request if smb2 negotiate phase is not complete. Cc: stable@vger.kernel.org Tested-by: Steve French Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-26505 Signed-off-by: Namjae Jeon Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/smb/server/connection.h | 11 +++++++++++ fs/smb/server/mgmt/user_session.c | 4 ++-- fs/smb/server/smb2pdu.c | 14 +++++++++++--- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/fs/smb/server/connection.h b/fs/smb/server/connection.h index 91c2318639e7..14620e147dda 100644 --- a/fs/smb/server/connection.h +++ b/fs/smb/server/connection.h @@ -27,6 +27,7 @@ enum { KSMBD_SESS_EXITING, KSMBD_SESS_NEED_RECONNECT, KSMBD_SESS_NEED_NEGOTIATE, + KSMBD_SESS_NEED_SETUP, KSMBD_SESS_RELEASING }; @@ -187,6 +188,11 @@ static inline bool ksmbd_conn_need_negotiate(struct ksmbd_conn *conn) return READ_ONCE(conn->status) == KSMBD_SESS_NEED_NEGOTIATE; } +static inline bool ksmbd_conn_need_setup(struct ksmbd_conn *conn) +{ + return READ_ONCE(conn->status) == KSMBD_SESS_NEED_SETUP; +} + static inline bool ksmbd_conn_need_reconnect(struct ksmbd_conn *conn) { return READ_ONCE(conn->status) == KSMBD_SESS_NEED_RECONNECT; @@ -217,6 +223,11 @@ static inline void ksmbd_conn_set_need_negotiate(struct ksmbd_conn *conn) WRITE_ONCE(conn->status, KSMBD_SESS_NEED_NEGOTIATE); } +static inline void ksmbd_conn_set_need_setup(struct ksmbd_conn *conn) +{ + WRITE_ONCE(conn->status, KSMBD_SESS_NEED_SETUP); +} + static inline void ksmbd_conn_set_need_reconnect(struct ksmbd_conn *conn) { WRITE_ONCE(conn->status, KSMBD_SESS_NEED_RECONNECT); diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c index 0963693015ee..f83daf72f877 100644 --- a/fs/smb/server/mgmt/user_session.c +++ b/fs/smb/server/mgmt/user_session.c @@ -374,13 +374,13 @@ void destroy_previous_session(struct ksmbd_conn *conn, ksmbd_all_conn_set_status(id, KSMBD_SESS_NEED_RECONNECT); err = ksmbd_conn_wait_idle_sess_id(conn, id); if (err) { - ksmbd_all_conn_set_status(id, KSMBD_SESS_NEED_NEGOTIATE); + ksmbd_all_conn_set_status(id, KSMBD_SESS_NEED_SETUP); goto out; } ksmbd_destroy_file_table(&prev_sess->file_table); prev_sess->state = SMB2_SESSION_EXPIRED; - ksmbd_all_conn_set_status(id, KSMBD_SESS_NEED_NEGOTIATE); + ksmbd_all_conn_set_status(id, KSMBD_SESS_NEED_SETUP); ksmbd_launch_ksmbd_durable_scavenger(); out: up_write(&conn->session_lock); diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 3a3c0a99eb04..7fea86edc717 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -1247,7 +1247,7 @@ int smb2_handle_negotiate(struct ksmbd_work *work) } conn->srv_sec_mode = le16_to_cpu(rsp->SecurityMode); - ksmbd_conn_set_need_negotiate(conn); + ksmbd_conn_set_need_setup(conn); err_out: if (rc) @@ -1268,6 +1268,9 @@ static int alloc_preauth_hash(struct ksmbd_session *sess, if (sess->Preauth_HashValue) return 0; + if (!conn->preauth_info) + return -ENOMEM; + sess->Preauth_HashValue = kmemdup(conn->preauth_info->Preauth_HashValue, PREAUTH_HASHVALUE_SIZE, GFP_KERNEL); if (!sess->Preauth_HashValue) @@ -1671,6 +1674,11 @@ int smb2_sess_setup(struct ksmbd_work *work) ksmbd_debug(SMB, "Received request for session setup\n"); + if (!ksmbd_conn_need_setup(conn) && !ksmbd_conn_good(conn)) { + work->send_no_response = 1; + return rc; + } + WORK_BUFFERS(work, req, rsp); rsp->StructureSize = cpu_to_le16(9); @@ -1906,7 +1914,7 @@ out_err: if (try_delay) { ksmbd_conn_set_need_reconnect(conn); ssleep(5); - ksmbd_conn_set_need_negotiate(conn); + ksmbd_conn_set_need_setup(conn); } } smb2_set_err_rsp(work); @@ -2238,7 +2246,7 @@ int smb2_session_logoff(struct ksmbd_work *work) ksmbd_free_user(sess->user); sess->user = NULL; } - ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_NEGOTIATE); + ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_SETUP); rsp->StructureSize = cpu_to_le16(4); err = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_logoff_rsp));