]> git.dujemihanovic.xyz Git - linux.git/commit
EDAC/synopsys: Fix ECC status and IRQ control race condition
authorSerge Semin <fancer.lancer@gmail.com>
Thu, 22 Feb 2024 18:12:46 +0000 (21:12 +0300)
committerBorislav Petkov (AMD) <bp@alien8.de>
Mon, 6 May 2024 12:19:07 +0000 (14:19 +0200)
commit591c946675d88dcc0ae9ff54be9d5caaee8ce1e3
tree5accb498e0fb80e0abf3e46f1f92d6275aa37a0a
parentdd5a440a31fae6e459c0d6271dddd62825505361
EDAC/synopsys: Fix ECC status and IRQ control race condition

The race condition around the ECCCLR register access happens in the IRQ
disable method called in the device remove() procedure and in the ECC IRQ
handler:

  1. Enable IRQ:
     a. ECCCLR = EN_CE | EN_UE
  2. Disable IRQ:
     a. ECCCLR = 0
  3. IRQ handler:
     a. ECCCLR = CLR_CE | CLR_CE_CNT | CLR_CE | CLR_CE_CNT
     b. ECCCLR = 0
     c. ECCCLR = EN_CE | EN_UE

So if the IRQ disabling procedure is called concurrently with the IRQ
handler method the IRQ might be actually left enabled due to the
statement 3c.

The root cause of the problem is that ECCCLR register (which since
v3.10a has been called as ECCCTL) has intermixed ECC status data clear
flags and the IRQ enable/disable flags. Thus the IRQ disabling (clear EN
flags) and handling (write 1 to clear ECC status data) procedures must
be serialised around the ECCCTL register modification to prevent the
race.

So fix the problem described above by adding the spin-lock around the
ECCCLR modifications and preventing the IRQ-handler from modifying the
IRQs enable flags (there is no point in disabling the IRQ and then
re-enabling it again within a single IRQ handler call, see the
statements 3a/3b and 3c above).

Fixes: f7824ded4149 ("EDAC/synopsys: Add support for version 3 of the Synopsys EDAC DDR")
Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Link: https://lore.kernel.org/r/20240222181324.28242-2-fancer.lancer@gmail.com
drivers/edac/synopsys_edac.c