--- /dev/null
+From 614a19b89ca43449196a8af1afac7d55c6781687 Mon Sep 17 00:00:00 2001
+From: Doug Berger <opendmb@gmail.com>
+Date: Wed, 24 Apr 2024 15:25:59 -0700
+Subject: serial: 8250_bcm7271: use default_mux_rate if possible
+
+From: Doug Berger <opendmb@gmail.com>
+
+commit 614a19b89ca43449196a8af1afac7d55c6781687 upstream.
+
+There is a scenario when resuming from some power saving states
+with no_console_suspend where console output can be generated
+before the 8250_bcm7271 driver gets the opportunity to restore
+the baud_mux_clk frequency. Since the baud_mux_clk is at its
+default frequency at this time the output can be garbled until
+the driver gets the opportunity to resume.
+
+Since this is only an issue with console use of the serial port
+during that window and the console isn't likely to use baud
+rates that require alternate baud_mux_clk frequencies, allow the
+driver to select the default_mux_rate if it is accurate enough.
+
+Fixes: 41a469482de2 ("serial: 8250: Add new 8250-core based Broadcom STB driver")
+Cc: stable@vger.kernel.org
+Signed-off-by: Doug Berger <opendmb@gmail.com>
+Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Tested-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Link: https://lore.kernel.org/r/20240424222559.1844045-1-opendmb@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/8250/8250_bcm7271.c | 101 +++++++++++++++++++--------------
+ 1 file changed, 60 insertions(+), 41 deletions(-)
+
+--- a/drivers/tty/serial/8250/8250_bcm7271.c
++++ b/drivers/tty/serial/8250/8250_bcm7271.c
+@@ -674,18 +674,46 @@ static void init_real_clk_rates(struct d
+ clk_set_rate(priv->baud_mux_clk, priv->default_mux_rate);
+ }
+
++static u32 find_quot(struct device *dev, u32 freq, u32 baud, u32 *percent)
++{
++ u32 quot;
++ u32 rate;
++ u64 hires_rate;
++ u64 hires_baud;
++ u64 hires_err;
++
++ rate = freq / 16;
++ quot = DIV_ROUND_CLOSEST(rate, baud);
++ if (!quot)
++ return 0;
++
++ /* increase resolution to get xx.xx percent */
++ hires_rate = div_u64((u64)rate * 10000, (u64)quot);
++ hires_baud = (u64)baud * 10000;
++
++ /* get the delta */
++ if (hires_rate > hires_baud)
++ hires_err = (hires_rate - hires_baud);
++ else
++ hires_err = (hires_baud - hires_rate);
++
++ *percent = (unsigned long)DIV_ROUND_CLOSEST_ULL(hires_err, baud);
++
++ dev_dbg(dev, "Baud rate: %u, MUX Clk: %u, Error: %u.%u%%\n",
++ baud, freq, *percent / 100, *percent % 100);
++
++ return quot;
++}
++
+ static void set_clock_mux(struct uart_port *up, struct brcmuart_priv *priv,
+ u32 baud)
+ {
+ u32 percent;
+ u32 best_percent = UINT_MAX;
+ u32 quot;
++ u32 freq;
+ u32 best_quot = 1;
+- u32 rate;
+- int best_index = -1;
+- u64 hires_rate;
+- u64 hires_baud;
+- u64 hires_err;
++ u32 best_freq = 0;
+ int rc;
+ int i;
+ int real_baud;
+@@ -694,44 +722,35 @@ static void set_clock_mux(struct uart_po
+ if (priv->baud_mux_clk == NULL)
+ return;
+
+- /* Find the closest match for specified baud */
+- for (i = 0; i < ARRAY_SIZE(priv->real_rates); i++) {
+- if (priv->real_rates[i] == 0)
+- continue;
+- rate = priv->real_rates[i] / 16;
+- quot = DIV_ROUND_CLOSEST(rate, baud);
+- if (!quot)
+- continue;
+-
+- /* increase resolution to get xx.xx percent */
+- hires_rate = (u64)rate * 10000;
+- hires_baud = (u64)baud * 10000;
+-
+- hires_err = div_u64(hires_rate, (u64)quot);
+-
+- /* get the delta */
+- if (hires_err > hires_baud)
+- hires_err = (hires_err - hires_baud);
+- else
+- hires_err = (hires_baud - hires_err);
+-
+- percent = (unsigned long)DIV_ROUND_CLOSEST_ULL(hires_err, baud);
+- dev_dbg(up->dev,
+- "Baud rate: %u, MUX Clk: %u, Error: %u.%u%%\n",
+- baud, priv->real_rates[i], percent / 100,
+- percent % 100);
+- if (percent < best_percent) {
+- best_percent = percent;
+- best_index = i;
+- best_quot = quot;
++ /* Try default_mux_rate first */
++ quot = find_quot(up->dev, priv->default_mux_rate, baud, &percent);
++ if (quot) {
++ best_percent = percent;
++ best_freq = priv->default_mux_rate;
++ best_quot = quot;
++ }
++ /* If more than 1% error, find the closest match for specified baud */
++ if (best_percent > 100) {
++ for (i = 0; i < ARRAY_SIZE(priv->real_rates); i++) {
++ freq = priv->real_rates[i];
++ if (freq == 0 || freq == priv->default_mux_rate)
++ continue;
++ quot = find_quot(up->dev, freq, baud, &percent);
++ if (!quot)
++ continue;
++
++ if (percent < best_percent) {
++ best_percent = percent;
++ best_freq = freq;
++ best_quot = quot;
++ }
+ }
+ }
+- if (best_index == -1) {
++ if (!best_freq) {
+ dev_err(up->dev, "Error, %d BAUD rate is too fast.\n", baud);
+ return;
+ }
+- rate = priv->real_rates[best_index];
+- rc = clk_set_rate(priv->baud_mux_clk, rate);
++ rc = clk_set_rate(priv->baud_mux_clk, best_freq);
+ if (rc)
+ dev_err(up->dev, "Error selecting BAUD MUX clock\n");
+
+@@ -740,8 +759,8 @@ static void set_clock_mux(struct uart_po
+ dev_err(up->dev, "Error, baud: %d has %u.%u%% error\n",
+ baud, percent / 100, percent % 100);
+
+- real_baud = rate / 16 / best_quot;
+- dev_dbg(up->dev, "Selecting BAUD MUX rate: %u\n", rate);
++ real_baud = best_freq / 16 / best_quot;
++ dev_dbg(up->dev, "Selecting BAUD MUX rate: %u\n", best_freq);
+ dev_dbg(up->dev, "Requested baud: %u, Actual baud: %u\n",
+ baud, real_baud);
+
+@@ -750,7 +769,7 @@ static void set_clock_mux(struct uart_po
+ i += (i / 2);
+ priv->char_wait = ns_to_ktime(i);
+
+- up->uartclk = rate;
++ up->uartclk = best_freq;
+ }
+
+ static void brcmstb_set_termios(struct uart_port *up,
--- /dev/null
+From 4244f830a56058ee0670d80e7ac9fd7c982eb480 Mon Sep 17 00:00:00 2001
+From: Pin-yen Lin <treapking@chromium.org>
+Date: Wed, 24 Apr 2024 20:58:08 +0800
+Subject: serial: 8520_mtk: Set RTS on shutdown for Rx in-band wakeup
+
+From: Pin-yen Lin <treapking@chromium.org>
+
+commit 4244f830a56058ee0670d80e7ac9fd7c982eb480 upstream.
+
+When Rx in-band wakeup is enabled, set RTS to true in mtk8250_shutdown()
+so the connected device can still send message and trigger IRQ when the
+system is suspended.
+
+Fixes: 18c9d4a3c249 ("serial: When UART is suspended, set RTS to false")
+Cc: stable <stable@kernel.org>
+Signed-off-by: Pin-yen Lin <treapking@chromium.org>
+Link: https://lore.kernel.org/r/20240424130619.2924456-1-treapking@chromium.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/8250/8250_mtk.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+--- a/drivers/tty/serial/8250/8250_mtk.c
++++ b/drivers/tty/serial/8250/8250_mtk.c
+@@ -209,15 +209,19 @@ static int mtk8250_startup(struct uart_p
+
+ static void mtk8250_shutdown(struct uart_port *port)
+ {
+-#ifdef CONFIG_SERIAL_8250_DMA
+ struct uart_8250_port *up = up_to_u8250p(port);
+ struct mtk8250_data *data = port->private_data;
++ int irq = data->rx_wakeup_irq;
+
++#ifdef CONFIG_SERIAL_8250_DMA
+ if (up->dma)
+ data->rx_status = DMA_RX_SHUTDOWN;
+ #endif
+
+- return serial8250_do_shutdown(port);
++ serial8250_do_shutdown(port);
++
++ if (irq >= 0)
++ serial8250_do_set_mctrl(&up->port, TIOCM_RTS);
+ }
+
+ static void mtk8250_disable_intrs(struct uart_8250_port *up, int mask)
tty-n_gsm-fix-possible-out-of-bounds-in-gsm0_receive.patch
+tty-n_gsm-fix-missing-receive-state-reset-after-mode-switch.patch
+speakup-fix-sizeof-vs-array_size-bug.patch
+serial-8250_bcm7271-use-default_mux_rate-if-possible.patch
+serial-8520_mtk-set-rts-on-shutdown-for-rx-in-band-wakeup.patch
--- /dev/null
+From 008ab3c53bc4f0b2f20013c8f6c204a3203d0b8b Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <dan.carpenter@linaro.org>
+Date: Mon, 15 Apr 2024 14:02:23 +0300
+Subject: speakup: Fix sizeof() vs ARRAY_SIZE() bug
+
+From: Dan Carpenter <dan.carpenter@linaro.org>
+
+commit 008ab3c53bc4f0b2f20013c8f6c204a3203d0b8b upstream.
+
+The "buf" pointer is an array of u16 values. This code should be
+using ARRAY_SIZE() (which is 256) instead of sizeof() (which is 512),
+otherwise it can the still got out of bounds.
+
+Fixes: c8d2f34ea96e ("speakup: Avoid crash on very long word")
+Cc: stable@vger.kernel.org
+Signed-off-by: Dan Carpenter <dan.carpenter@linaro.org>
+Reviewed-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
+Link: https://lore.kernel.org/r/d16f67d2-fd0a-4d45-adac-75ddd11001aa@moroto.mountain
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/accessibility/speakup/main.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/accessibility/speakup/main.c
++++ b/drivers/accessibility/speakup/main.c
+@@ -573,7 +573,7 @@ static u_long get_word(struct vc_data *v
+ }
+ attr_ch = get_char(vc, (u_short *)tmp_pos, &spk_attr);
+ buf[cnt++] = attr_ch;
+- while (tmpx < vc->vc_cols - 1 && cnt < sizeof(buf) - 1) {
++ while (tmpx < vc->vc_cols - 1 && cnt < ARRAY_SIZE(buf) - 1) {
+ tmp_pos += 2;
+ tmpx++;
+ ch = get_char(vc, (u_short *)tmp_pos, &temp);
--- /dev/null
+From 70d7f1427afcf7fa2d21cb5a04c6f3555d5b9357 Mon Sep 17 00:00:00 2001
+From: Daniel Starke <daniel.starke@siemens.com>
+Date: Wed, 24 Apr 2024 07:48:42 +0200
+Subject: tty: n_gsm: fix missing receive state reset after mode switch
+
+From: Daniel Starke <daniel.starke@siemens.com>
+
+commit 70d7f1427afcf7fa2d21cb5a04c6f3555d5b9357 upstream.
+
+The current implementation uses either gsm0_receive() or gsm1_receive()
+depending on whether the user configured the mux in basic or advanced
+option mode. Both functions share some state values over the same logical
+elements of the frame. However, both frame types differ in their nature.
+gsm0_receive() uses non-transparency framing, whereas gsm1_receive() uses
+transparency mechanism. Switching between both modes leaves the receive
+function in an undefined state when done during frame reception.
+
+Fix this by splitting both states. Add gsm0_receive_state_check_and_fix()
+and gsm1_receive_state_check_and_fix() to ensure that gsm->state is reset
+after a change of gsm->receive.
+
+Note that gsm->state is only accessed in:
+- gsm0_receive()
+- gsm1_receive()
+- gsm_error()
+
+Fixes: e1eaea46bb40 ("tty: n_gsm line discipline")
+Cc: stable@vger.kernel.org
+Signed-off-by: Daniel Starke <daniel.starke@siemens.com>
+Link: https://lore.kernel.org/r/20240424054842.7741-2-daniel.starke@siemens.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/n_gsm.c | 133 +++++++++++++++++++++++++++++++++++-----------------
+ 1 file changed, 92 insertions(+), 41 deletions(-)
+
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -202,16 +202,18 @@ enum gsm_encoding {
+
+ enum gsm_mux_state {
+ GSM_SEARCH,
+- GSM_START,
+- GSM_ADDRESS,
+- GSM_CONTROL,
+- GSM_LEN,
+- GSM_DATA,
+- GSM_FCS,
+- GSM_OVERRUN,
+- GSM_LEN0,
+- GSM_LEN1,
+- GSM_SSOF,
++ GSM0_ADDRESS,
++ GSM0_CONTROL,
++ GSM0_LEN0,
++ GSM0_LEN1,
++ GSM0_DATA,
++ GSM0_FCS,
++ GSM0_SSOF,
++ GSM1_START,
++ GSM1_ADDRESS,
++ GSM1_CONTROL,
++ GSM1_DATA,
++ GSM1_OVERRUN,
+ };
+
+ /*
+@@ -2259,6 +2261,30 @@ invalid:
+ return;
+ }
+
++/**
++ * gsm0_receive_state_check_and_fix - check and correct receive state
++ * @gsm: gsm data for this ldisc instance
++ *
++ * Ensures that the current receive state is valid for basic option mode.
++ */
++
++static void gsm0_receive_state_check_and_fix(struct gsm_mux *gsm)
++{
++ switch (gsm->state) {
++ case GSM_SEARCH:
++ case GSM0_ADDRESS:
++ case GSM0_CONTROL:
++ case GSM0_LEN0:
++ case GSM0_LEN1:
++ case GSM0_DATA:
++ case GSM0_FCS:
++ case GSM0_SSOF:
++ break;
++ default:
++ gsm->state = GSM_SEARCH;
++ break;
++ }
++}
+
+ /**
+ * gsm0_receive - perform processing for non-transparency
+@@ -2272,26 +2298,27 @@ static void gsm0_receive(struct gsm_mux
+ {
+ unsigned int len;
+
++ gsm0_receive_state_check_and_fix(gsm);
+ switch (gsm->state) {
+ case GSM_SEARCH: /* SOF marker */
+ if (c == GSM0_SOF) {
+- gsm->state = GSM_ADDRESS;
++ gsm->state = GSM0_ADDRESS;
+ gsm->address = 0;
+ gsm->len = 0;
+ gsm->fcs = INIT_FCS;
+ }
+ break;
+- case GSM_ADDRESS: /* Address EA */
++ case GSM0_ADDRESS: /* Address EA */
+ gsm->fcs = gsm_fcs_add(gsm->fcs, c);
+ if (gsm_read_ea(&gsm->address, c))
+- gsm->state = GSM_CONTROL;
++ gsm->state = GSM0_CONTROL;
+ break;
+- case GSM_CONTROL: /* Control Byte */
++ case GSM0_CONTROL: /* Control Byte */
+ gsm->fcs = gsm_fcs_add(gsm->fcs, c);
+ gsm->control = c;
+- gsm->state = GSM_LEN0;
++ gsm->state = GSM0_LEN0;
+ break;
+- case GSM_LEN0: /* Length EA */
++ case GSM0_LEN0: /* Length EA */
+ gsm->fcs = gsm_fcs_add(gsm->fcs, c);
+ if (gsm_read_ea(&gsm->len, c)) {
+ if (gsm->len > gsm->mru) {
+@@ -2301,14 +2328,14 @@ static void gsm0_receive(struct gsm_mux
+ }
+ gsm->count = 0;
+ if (!gsm->len)
+- gsm->state = GSM_FCS;
++ gsm->state = GSM0_FCS;
+ else
+- gsm->state = GSM_DATA;
++ gsm->state = GSM0_DATA;
+ break;
+ }
+- gsm->state = GSM_LEN1;
++ gsm->state = GSM0_LEN1;
+ break;
+- case GSM_LEN1:
++ case GSM0_LEN1:
+ gsm->fcs = gsm_fcs_add(gsm->fcs, c);
+ len = c;
+ gsm->len |= len << 7;
+@@ -2319,11 +2346,11 @@ static void gsm0_receive(struct gsm_mux
+ }
+ gsm->count = 0;
+ if (!gsm->len)
+- gsm->state = GSM_FCS;
++ gsm->state = GSM0_FCS;
+ else
+- gsm->state = GSM_DATA;
++ gsm->state = GSM0_DATA;
+ break;
+- case GSM_DATA: /* Data */
++ case GSM0_DATA: /* Data */
+ gsm->buf[gsm->count++] = c;
+ if (gsm->count >= MAX_MRU) {
+ gsm->bad_size++;
+@@ -2334,14 +2361,14 @@ static void gsm0_receive(struct gsm_mux
+ gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf,
+ gsm->count);
+ }
+- gsm->state = GSM_FCS;
++ gsm->state = GSM0_FCS;
+ }
+ break;
+- case GSM_FCS: /* FCS follows the packet */
++ case GSM0_FCS: /* FCS follows the packet */
+ gsm->fcs = gsm_fcs_add(gsm->fcs, c);
+- gsm->state = GSM_SSOF;
++ gsm->state = GSM0_SSOF;
+ break;
+- case GSM_SSOF:
++ case GSM0_SSOF:
+ gsm->state = GSM_SEARCH;
+ if (c == GSM0_SOF)
+ gsm_queue(gsm);
+@@ -2355,6 +2382,29 @@ static void gsm0_receive(struct gsm_mux
+ }
+
+ /**
++ * gsm1_receive_state_check_and_fix - check and correct receive state
++ * @gsm: gsm data for this ldisc instance
++ *
++ * Ensures that the current receive state is valid for advanced option mode.
++ */
++
++static void gsm1_receive_state_check_and_fix(struct gsm_mux *gsm)
++{
++ switch (gsm->state) {
++ case GSM_SEARCH:
++ case GSM1_START:
++ case GSM1_ADDRESS:
++ case GSM1_CONTROL:
++ case GSM1_DATA:
++ case GSM1_OVERRUN:
++ break;
++ default:
++ gsm->state = GSM_SEARCH;
++ break;
++ }
++}
++
++/**
+ * gsm1_receive - perform processing for non-transparency
+ * @gsm: gsm data for this ldisc instance
+ * @c: character
+@@ -2364,6 +2414,7 @@ static void gsm0_receive(struct gsm_mux
+
+ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c)
+ {
++ gsm1_receive_state_check_and_fix(gsm);
+ /* handle XON/XOFF */
+ if ((c & ISO_IEC_646_MASK) == XON) {
+ gsm->constipated = true;
+@@ -2376,11 +2427,11 @@ static void gsm1_receive(struct gsm_mux
+ }
+ if (c == GSM1_SOF) {
+ /* EOF is only valid in frame if we have got to the data state */
+- if (gsm->state == GSM_DATA) {
++ if (gsm->state == GSM1_DATA) {
+ if (gsm->count < 1) {
+ /* Missing FSC */
+ gsm->malformed++;
+- gsm->state = GSM_START;
++ gsm->state = GSM1_START;
+ return;
+ }
+ /* Remove the FCS from data */
+@@ -2396,14 +2447,14 @@ static void gsm1_receive(struct gsm_mux
+ gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->buf[gsm->count]);
+ gsm->len = gsm->count;
+ gsm_queue(gsm);
+- gsm->state = GSM_START;
++ gsm->state = GSM1_START;
+ return;
+ }
+ /* Any partial frame was a runt so go back to start */
+- if (gsm->state != GSM_START) {
++ if (gsm->state != GSM1_START) {
+ if (gsm->state != GSM_SEARCH)
+ gsm->malformed++;
+- gsm->state = GSM_START;
++ gsm->state = GSM1_START;
+ }
+ /* A SOF in GSM_START means we are still reading idling or
+ framing bytes */
+@@ -2424,30 +2475,30 @@ static void gsm1_receive(struct gsm_mux
+ gsm->escape = false;
+ }
+ switch (gsm->state) {
+- case GSM_START: /* First byte after SOF */
++ case GSM1_START: /* First byte after SOF */
+ gsm->address = 0;
+- gsm->state = GSM_ADDRESS;
++ gsm->state = GSM1_ADDRESS;
+ gsm->fcs = INIT_FCS;
+ fallthrough;
+- case GSM_ADDRESS: /* Address continuation */
++ case GSM1_ADDRESS: /* Address continuation */
+ gsm->fcs = gsm_fcs_add(gsm->fcs, c);
+ if (gsm_read_ea(&gsm->address, c))
+- gsm->state = GSM_CONTROL;
++ gsm->state = GSM1_CONTROL;
+ break;
+- case GSM_CONTROL: /* Control Byte */
++ case GSM1_CONTROL: /* Control Byte */
+ gsm->fcs = gsm_fcs_add(gsm->fcs, c);
+ gsm->control = c;
+ gsm->count = 0;
+- gsm->state = GSM_DATA;
++ gsm->state = GSM1_DATA;
+ break;
+- case GSM_DATA: /* Data */
++ case GSM1_DATA: /* Data */
+ if (gsm->count > gsm->mru || gsm->count > MAX_MRU) { /* Allow one for the FCS */
+- gsm->state = GSM_OVERRUN;
++ gsm->state = GSM1_OVERRUN;
+ gsm->bad_size++;
+ } else
+ gsm->buf[gsm->count++] = c;
+ break;
+- case GSM_OVERRUN: /* Over-long - eg a dropped SOF */
++ case GSM1_OVERRUN: /* Over-long - eg a dropped SOF */
+ break;
+ default:
+ pr_debug("%s: unhandled state: %d\n", __func__, gsm->state);