diff options
author | grehan <grehan@FreeBSD.org> | 2014-04-28 18:41:25 +0000 |
---|---|---|
committer | grehan <grehan@FreeBSD.org> | 2014-04-28 18:41:25 +0000 |
commit | 165205a04192087fdd51c5b4d5b6470ab372ba06 (patch) | |
tree | 5ff74e9fc6030d5d2a74563b95a5e6cf5fe0aabf /usr.sbin | |
parent | a977fd0d7bc7ec14bbcf9ebfc402bf1be4e45505 (diff) | |
download | FreeBSD-src-165205a04192087fdd51c5b4d5b6470ab372ba06.zip FreeBSD-src-165205a04192087fdd51c5b4d5b6470ab372ba06.tar.gz |
Implement legacy interrupts for the AHCI device emulation
according to the method outlined in the AHCI spec.
Tested with FreeBSD 9/10/11 with MSI disabled,
and also NetBSD/amd64 (lightly).
Reviewed by: neel, tychon
MFC after: 3 weeks
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/bhyve/pci_ahci.c | 36 |
1 files changed, 34 insertions, 2 deletions
diff --git a/usr.sbin/bhyve/pci_ahci.c b/usr.sbin/bhyve/pci_ahci.c index 3f9fc7f..9f61107 100644 --- a/usr.sbin/bhyve/pci_ahci.c +++ b/usr.sbin/bhyve/pci_ahci.c @@ -192,6 +192,7 @@ struct pci_ahci_softc { uint32_t em_ctl; uint32_t cap2; uint32_t bohc; + uint32_t lintr; struct ahci_port port[MAX_PORTS]; }; #define ahci_ctx(sc) ((sc)->asc_pi->pi_vmctx) @@ -211,8 +212,11 @@ static inline void lba_to_msf(uint8_t *buf, int lba) static void ahci_generate_intr(struct pci_ahci_softc *sc) { + struct pci_devinst *pi; int i; + pi = sc->asc_pi; + for (i = 0; i < sc->ports; i++) { struct ahci_port *pr; pr = &sc->port[i]; @@ -222,8 +226,28 @@ ahci_generate_intr(struct pci_ahci_softc *sc) DPRINTF("%s %x\n", __func__, sc->is); - if (sc->is && (sc->ghc & AHCI_GHC_IE)) - pci_generate_msi(sc->asc_pi, 0); + if (sc->is && (sc->ghc & AHCI_GHC_IE)) { + if (pci_msi_enabled(pi)) { + /* + * Generate an MSI interrupt on every edge + */ + pci_generate_msi(pi, 0); + } else if (!sc->lintr) { + /* + * Only generate a pin-based interrupt if one wasn't + * in progress + */ + sc->lintr = 1; + pci_lintr_assert(pi); + } + } else if (sc->lintr) { + /* + * No interrupts: deassert pin-based signal if it had + * been asserted + */ + pci_lintr_deassert(pi); + sc->lintr = 0; + } } static void @@ -367,6 +391,12 @@ ahci_reset(struct pci_ahci_softc *sc) sc->ghc = AHCI_GHC_AE; sc->is = 0; + + if (sc->lintr) { + pci_lintr_deassert(sc->asc_pi); + sc->lintr = 0; + } + for (i = 0; i < sc->ports; i++) { sc->port[i].ie = 0; sc->port[i].is = 0; @@ -1814,6 +1844,8 @@ pci_ahci_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts, int atapi) pci_emul_alloc_bar(pi, 5, PCIBAR_MEM32, AHCI_OFFSET + sc->ports * AHCI_STEP); + pci_lintr_request(pi); + open_fail: if (ret) { blockif_close(sc->port[0].bctx); |