Re: [PATCH v3] ata: ahci: work around lost interrupts on Marvell 88SE61xx
From: Hajo Noerenberg
Date: Sat Sep 05 2026 - 08:30:53 EST
On 04.09.2026 at 16:45 Niklas Cassel wrote:
> On Mon, Aug 31, 2026 at 04:27:24PM +0200, Niklas Cassel wrote:
>> On Mon, 31 Aug 2026 14:43:03 +0200, Hajo Noerenberg wrote:
>>> ahci_single_level_irq_intr() services the ports first and clears the
>>> global HOST_IRQ_STAT afterwards, as recommended by AHCI 1.1 section
>>> 10.6.2. The Marvell 88SE6111/6121/6145 family stops reporting interrupts
>>> for a port when HOST_IRQ_STAT is cleared while PxIS still holds bits:
>>> PxIS keeps its content, HOST_IRQ_STAT reads back as 0, the port is never
>>> looked at again, and the command in flight only ends in a timeout.
>>>
>>> [...]
>>
>> Applied to libata/linux.git (for-7.4), thanks!
>>
>> [1/1] ata: ahci: work around lost interrupts on Marvell 88SE61xx
>> https://git.kernel.org/libata/linux/c/22f2ba34
>
> Decided to send this for 7.3-rc2 instead:
> https://lore.kernel.org/linux-ide/20260904144228.1473602-1-cassel@xxxxxxxxxx/T/#u
>
Niklas,
thanks for moving it to 7.3-rc2.
I spent a lot of time on this bug, mostly because I did not know what I was
looking for. Now that it has a name, searching for it actually works - and
out of idle curiosity I went looking a moment ago, only to find that FreeBSD
has been carrying the same workaround for years.
In FreeBSD's sys/dev/ahci/ahci_pci.c all four chips of the family are tagged
AHCI_Q_EDGEIS:
{0x611111ab, ... "Marvell 88SE6111", ... AHCI_Q_1CH | AHCI_Q_EDGEIS},
{0x612111ab, ... "Marvell 88SE6121", ... AHCI_Q_2CH | AHCI_Q_EDGEIS | ...},
{0x614111ab, ... "Marvell 88SE6141", ... AHCI_Q_4CH | AHCI_Q_EDGEIS | ...},
{0x614511ab, ... "Marvell 88SE6145", ... AHCI_Q_4CH | AHCI_Q_EDGEIS | ...},
and in ahci_intr() the quirk does precisely what this patch does:
/* Some controllers have edge triggered IS. */
if (ctlr->quirks & AHCI_Q_EDGEIS)
ise |= is;
if (ise != 0)
ATA_OUTL(ctlr->r_mem, AHCI_IS, ise);
for (...)
ctlr->interrupt[unit].function(arg);
/* AHCI declares level triggered IS. */
if (!(ctlr->quirks & AHCI_Q_EDGEIS))
ATA_OUTL(ctlr->r_mem, AHCI_IS, is);
That is an independent confirmation of both the diagnosis and the fix, by
people who knew nothing about this bug report.
It also suggests Linux covers less of the family than it could. board_ahci_mv
lists 0x6121 and 0x6145 only, FreeBSD tags 0x6111 and 0x6141 as well, and
Marvell's own driver for these chips knows 6101, 6111, 6121, 6122, 6141 and
6145. A 88SE6111 or 88SE6141 in AHCI mode therefore ends up on the generic
class entry and plain board_ahci - not only without the new handler, but also
without AHCI_HFLAG_NO_NCQ and AHCI_HFLAG_NO_PMP that the two listed siblings
get. I have neither chip and no report of one failing, so this is a remark,
not a patch proposal.
FreeBSD does make a silicon revision distinction, but only for the 88SE912x:
1b4b:9123 gets AHCI_Q_EDGEIS below revision 0x11 and AHCI_Q_ALTSIG from 0x11
on, so Marvell appears to have fixed it there in later silicon. Linux has no
special handling for either of those - 1b4b:9120 is not in ahci.c at all, and
1b4b:9123 gets board_ahci_yes_fbs. I have none of that hardware either, so
again, an observation and nothing more.
For the 6111/6121/6141/6145 family there is no such silicon revision
distinction anywhere. FreeBSD sets AHCI_Q_EDGEIS for every revision of all
four, and Marvell's own driver does the reordering unconditionally at all
three places it acknowledges interrupts, with no revision check near any of
them - the only revision-dependent branch in that whole driver is for an
unrelated chip. Applying the fix unconditionally, as this patch does, is
therefore in line with both.
Unrelated to the interrupt problem: FreeBSD also tags these chips
AHCI_Q_NOCOUNT, which makes it ignore the command header's bytecount field
when computing the transfer residual. I have seen no symptom of that on Linux
and have not checked whether libata uses that field at all; mentioning it for
completeness.
Thanks again,
Hajo