From: Shao Mingyin seattle_transmit_led_message() updates a controller-wide SGPIO register before taking ap->lock. Concurrent LED updates for different ports can therefore read the same register value and overwrite each other's changes, leaving activity, locate or fault LEDs in the wrong state. The lock currently protects only the saved LED state. Take the shared host lock before reading the SGPIO register and hold it through the write and the saved-state update, so that each update preserves the other ports' LED bits. Fixes: 535dac4ab5f4 ("ata: add AMD Seattle platform driver") Signed-off-by: Shao Mingyin --- Tested on next-20261105 in an x86-64 QEMU/KVM guest with KASAN and lock checking. Two kernel threads on separate CPUs call the original LED callback for synthetic libata ports verified to share the host lock, using a RAM-backed SGPIO register and TEST-ONLY MMIO observers. The observer waits only when unlocked, with IRQs enabled; it never waits for another thread while holding the callback's spinlock. In 1025 controlled update pairs, the unpatched kernel loses register bits 897 times (including expected 0x900, actual 0x100); the patched kernel loses none. Another 256 pairs with IRQ-disabled entry preserve all updates after the fix. Saved PMP LED states and entry IRQ state are correct in both kernels; 482 invalid-PMP calls return -EINVAL. This tests callback synchronization, not Seattle hardware or LED I/O. drivers/ata/ahci_seattle.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ata/ahci_seattle.c b/drivers/ata/ahci_seattle.c index 9758fa0260..a398778ebf 100644 --- a/drivers/ata/ahci_seattle.c +++ b/drivers/ata/ahci_seattle.c @@ -92,6 +92,8 @@ static ssize_t seattle_transmit_led_message(struct ata_port *ap, u32 state, return -EINVAL; emp = &pp->em_priv[pmp]; + spin_lock_irqsave(ap->lock, flags); + val = ioread32(plat_data->sgpio_ctrl); if (state & ACTIVITY_MASK) val |= 1 << ACTIVITY_BIT_POS((ap->port_no)); @@ -110,8 +112,6 @@ static ssize_t seattle_transmit_led_message(struct ata_port *ap, u32 state, iowrite32(val, plat_data->sgpio_ctrl); - spin_lock_irqsave(ap->lock, flags); - /* save off new led state for port/slot */ emp->led_state = state; -- 2.27.0