From d3214e8d6dc187fbf627f15cdd5749825f82eb6f Mon Sep 17 00:00:00 2001 From: Michal Meloun Date: Sun, 29 Nov 2015 11:28:04 +0000 Subject: [PATCH] AHCI: Fix AHCI driver for ARM. On ARM, we must ensure proper interdevice write ordering. The AHCI interrupt status register must be updated in HW before registers in interrupt controller. Unfortunately, only way how we can do it is readback. Discussed with: mav Approved by: kib (mentor) Differential Revision: https://reviews.freebsd.org/D4240 --- sys/dev/ahci/ahci.c | 3 +++ sys/dev/ahci/ahci.h | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/sys/dev/ahci/ahci.c b/sys/dev/ahci/ahci.c index 7e512c222af..7fe3da88057 100644 --- a/sys/dev/ahci/ahci.c +++ b/sys/dev/ahci/ahci.c @@ -483,6 +483,7 @@ ahci_intr(void *data) /* AHCI declares level triggered IS. */ if (!(ctlr->quirks & AHCI_Q_EDGEIS)) ATA_OUTL(ctlr->r_mem, AHCI_IS, is); + ATA_RBL(ctlr->r_mem, AHCI_IS); } /* @@ -501,6 +502,7 @@ ahci_intr_one(void *data) ctlr->interrupt[unit].function(arg); /* AHCI declares level triggered IS. */ ATA_OUTL(ctlr->r_mem, AHCI_IS, 1 << unit); + ATA_RBL(ctlr->r_mem, AHCI_IS); } static void @@ -516,6 +518,7 @@ ahci_intr_one_edge(void *data) ATA_OUTL(ctlr->r_mem, AHCI_IS, 1 << unit); if ((arg = ctlr->interrupt[unit].argument)) ctlr->interrupt[unit].function(arg); + ATA_RBL(ctlr->r_mem, AHCI_IS); } struct resource * diff --git a/sys/dev/ahci/ahci.h b/sys/dev/ahci/ahci.h index 0461953940f..5953425e2d9 100644 --- a/sys/dev/ahci/ahci.h +++ b/sys/dev/ahci/ahci.h @@ -562,6 +562,20 @@ enum ahci_err_type { #define ATA_OUTSL_STRM(res, offset, addr, count) \ bus_write_multi_stream_4((res), (offset), (addr), (count)) +/* + * On some platforms, we must ensure proper interdevice write ordering. + * The AHCI interrupt status register must be updated in HW before + * registers in interrupt controller. + * Unfortunately, only way how we can do it is readback. + * + * Currently, only ARM is known to have this issue. + */ +#if defined(__arm__) +#define ATA_RBL(res, offset) \ + bus_read_4((res), (offset)) +#else +#define ATA_RBL(res, offset) +#endif #define AHCI_Q_NOFORCE 0x00000001 #define AHCI_Q_NOPMP 0x00000002