From: Rengarajan S rengarajan.s@microchip.com
[ Upstream commit c40b91e38eb8d4489def095d62ab476d45871323 ]
Systems that issue PCIe hot reset requests during a suspend/resume cycle cause PCI1XXXX device revisions prior to C0 to get its UART configuration registers reset to hardware default values. This results in device inaccessibility and data transfer failures. Starting with Revision C0, support was added in the device hardware (via the Hot Reset Disable Bit) to allow resetting only the PCIe interface and its associated logic, but preserving the UART configuration during a hot reset. This patch enables the hot reset disable feature during suspend/ resume for C0 and later revisions of the device.
Signed-off-by: Rengarajan S rengarajan.s@microchip.com Reviewed-by: Jiri Slaby jirislaby@kernel.org Link: https://lore.kernel.org/r/20250425145500.29036-1-rengarajan.s@microchip.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Sasha Levin sashal@kernel.org ---
**YES**
This commit should be backported to stable kernel trees based on the following analysis:
## Bug Fix Analysis
**This commit fixes a significant user-facing bug**: Systems that issue PCIe hot reset requests during suspend/resume cycles cause PCI1XXXX device revisions prior to C0 to lose their UART configuration registers, resulting in: - Device inaccessibility - Data transfer failures - Complete loss of UART functionality after suspend/resume
This is exactly the type of critical hardware functionality bug that stable backports are designed to address.
## Code Changes Assessment
**The changes are minimal and well-contained**:
1. **Single bit definition added** (line 118): ```c #define UART_RESET_HOT_RESET_DISABLE BIT(17) ```
2. **Revision-gated logic in suspend** (lines 625-626): ```c if (priv->dev_rev >= 0xC0) data |= UART_RESET_HOT_RESET_DISABLE; ```
3. **Corresponding logic in resume** (lines 656-657): ```c if (priv->dev_rev >= 0xC0) data &= ~UART_RESET_HOT_RESET_DISABLE; ```
**Risk Assessment**: - **Very low risk** - Only affects C0 and later hardware revisions (>= 0xC0) - **Hardware-specific** - Only impacts Microchip PCI1XXXX UART devices - **Well-tested functionality** - Uses existing hardware feature designed for this purpose - **No architectural changes** - Simple register bit manipulation in existing suspend/resume paths
## Comparison with Similar Commits
Looking at the reference examples, this commit aligns with **Similar Commit #3** which was marked for backporting ("Backport Status: YES"). That commit also: - Fixed a hardware-specific bug (RTS pin toggle issue) - Made minimal, contained changes - Addressed device functionality problems - Was revision-specific (B0 hardware only)
Unlike the "NO" examples which added new features (suspend/resume support, RS485 support, burst mode), this commit purely fixes existing broken functionality.
## Stable Tree Criteria Met
✅ **Fixes important bug** - Complete UART failure after suspend/resume ✅ **Minimal risk** - Small, contained changes to single driver ✅ **No new features** - Just enables existing hardware capability ✅ **No architectural changes** - Uses existing suspend/resume framework ✅ **Critical subsystem impact** - Serial communication is essential functionality
The commit message explicitly states this addresses "device inaccessibility and data transfer failures" which are exactly the types of regressions stable trees exist to prevent.
drivers/tty/serial/8250/8250_pci1xxxx.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/drivers/tty/serial/8250/8250_pci1xxxx.c b/drivers/tty/serial/8250/8250_pci1xxxx.c index f462b3d1c104c..d6b01e015a96b 100644 --- a/drivers/tty/serial/8250/8250_pci1xxxx.c +++ b/drivers/tty/serial/8250/8250_pci1xxxx.c @@ -115,6 +115,7 @@
#define UART_RESET_REG 0x94 #define UART_RESET_D3_RESET_DISABLE BIT(16) +#define UART_RESET_HOT_RESET_DISABLE BIT(17)
#define UART_BURST_STATUS_REG 0x9C #define UART_TX_BURST_FIFO 0xA0 @@ -620,6 +621,10 @@ static int pci1xxxx_suspend(struct device *dev) }
data = readl(p + UART_RESET_REG); + + if (priv->dev_rev >= 0xC0) + data |= UART_RESET_HOT_RESET_DISABLE; + writel(data | UART_RESET_D3_RESET_DISABLE, p + UART_RESET_REG);
if (wakeup) @@ -647,7 +652,12 @@ static int pci1xxxx_resume(struct device *dev) }
data = readl(p + UART_RESET_REG); + + if (priv->dev_rev >= 0xC0) + data &= ~UART_RESET_HOT_RESET_DISABLE; + writel(data & ~UART_RESET_D3_RESET_DISABLE, p + UART_RESET_REG); + iounmap(p);
for (i = 0; i < priv->nr; i++) {