[PATCH 4/4] Revert "drivers: convert sbd_duart.map_guard from atomic_t to refcount_t"

From: Maciej W. Rozycki

Date: Sun Apr 12 2026 - 23:32:00 EST


Revert commit 22a33651a56f ("drivers: convert sbd_duart.map_guard from
atomic_t to refcount_t"), which broke perfectly valid code:

------------[ cut here ]------------
WARNING: CPU: 1 PID: 1 at lib/refcount.c:114 sbd_request_port+0x54/0x140
refcount_t: increment on 0; use-after-free.
CPU: 1 PID: 1 Comm: swapper/0 Not tainted 4.11.0-rc2+ #34
Stack : 0000000014001fe0 0000000000000000 ffffffff80830000 0000000000000000
ffffffff8127bc7a ffffffff8016fe08 ffffffff808d0000 ffffffff808d0000
ffffffff807aa828 ffffffff80822337 ffffffff808ce188 a8000001860b0000
0000000000000001 0000000000000001 00000000000001c8 ffffffff808a3090
00000000000000bb ffffffff801b09d4 a80000018609bb68 ffffffff801231cc
ffffffff812a0000 ffffffff80171388 0000000000001000 ffffffff807aa828
0000000000000001 0000000000000001 0000000000000000 0000000000000000
0000000000000000 a80000018609bab0 0000000000000000 ffffffff803c47cc
0000000000000000 0000000000000000 0000000000000000 0000000000000000
ffffffff807cb648 ffffffff8010bff8 0000000014001fe1 ffffffff803c47cc
...
Call Trace:
[<ffffffff8010bff8>] show_stack+0x28/0x88
[<ffffffff803c47cc>] dump_stack+0x8c/0xc0
[<ffffffff801aff5c>] __warn+0xe0/0x114
[<ffffffff801233f0>] warn_slowpath_fmt+0x40/0x50
[<ffffffff80455bcc>] sbd_request_port+0x54/0x140
[<ffffffff804563a4>] sbd_config_port+0x2c/0x68
---[ end trace f666d696412caa3e ]---

(report at the offending commit) -- sbd_request_port() is called twice
per DUART instance, to reserve a resource holding the control register
block shared between the two channels, so there's no slightest chance
for an overflow. Also this doesn't stop the driver from working and
it's just the reservation that is missing as a result, i.e.:

10060100-100601ff : sb1250-duart
10060200-100602ff : sb1250-duart

as from the offending change, vs:

10060100-100601ff : sb1250-duart
10060200-100602ff : sb1250-duart
10060300-100603ff : sb1250-duart

beforehand, which is surely why the breakage has gone so long unnoticed.

"If it ain't broke, don't fix it," so just revert the broken commit.

Fixes: 22a33651a56f ("drivers: convert sbd_duart.map_guard from atomic_t to refcount_t")
Signed-off-by: Maciej W. Rozycki <macro@xxxxxxxxxxx>
---
drivers/tty/serial/sb1250-duart.c | 20 ++++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)

linux-serial-sb1250-duart-map-guard-atomic.diff
Index: linux-macro/drivers/tty/serial/sb1250-duart.c
===================================================================
--- linux-macro.orig/drivers/tty/serial/sb1250-duart.c
+++ linux-macro/drivers/tty/serial/sb1250-duart.c
@@ -34,8 +34,8 @@
#include <linux/tty_flip.h>
#include <linux/types.h>

-#include <linux/refcount.h>
-#include <linux/io.h>
+#include <linux/atomic.h>
+#include <asm/io.h>

#include <asm/sibyte/sb1250.h>
#include <asm/sibyte/sb1250_uart.h>
@@ -86,7 +86,7 @@ struct sbd_port {
struct sbd_duart {
struct sbd_port sport[2];
unsigned long mapctrl;
- refcount_t map_guard;
+ atomic_t map_guard;
};

#define to_sport(uport) container_of(uport, struct sbd_port, port)
@@ -662,13 +662,15 @@ static void sbd_release_port(struct uart
{
struct sbd_port *sport = to_sport(uport);
struct sbd_duart *duart = sport->duart;
+ int map_guard;

iounmap(sport->memctrl);
sport->memctrl = NULL;
iounmap(uport->membase);
uport->membase = NULL;

- if(refcount_dec_and_test(&duart->map_guard))
+ map_guard = atomic_add_return(-1, &duart->map_guard);
+ if (!map_guard)
release_mem_region(duart->mapctrl, DUART_CHANREG_SPACING);
release_mem_region(uport->mapbase, DUART_CHANREG_SPACING);
}
@@ -704,6 +706,7 @@ static int sbd_request_port(struct uart_
{
const char *err = KERN_ERR "sbd: Unable to reserve MMIO resource\n";
struct sbd_duart *duart = to_sport(uport)->duart;
+ int map_guard;
int ret = 0;

if (!request_mem_region(uport->mapbase, DUART_CHANREG_SPACING,
@@ -711,11 +714,11 @@ static int sbd_request_port(struct uart_
printk(err);
return -EBUSY;
}
- refcount_inc(&duart->map_guard);
- if (refcount_read(&duart->map_guard) == 1) {
+ map_guard = atomic_add_return(1, &duart->map_guard);
+ if (map_guard == 1) {
if (!request_mem_region(duart->mapctrl, DUART_CHANREG_SPACING,
"sb1250-duart")) {
- refcount_dec(&duart->map_guard);
+ atomic_add(-1, &duart->map_guard);
printk(err);
ret = -EBUSY;
}
@@ -723,7 +726,8 @@ static int sbd_request_port(struct uart_
if (!ret) {
ret = sbd_map_port(uport);
if (ret) {
- if (refcount_dec_and_test(&duart->map_guard))
+ map_guard = atomic_add_return(-1, &duart->map_guard);
+ if (!map_guard)
release_mem_region(duart->mapctrl,
DUART_CHANREG_SPACING);
}