Module Name: src Committed By: macallan Date: Fri Jun 1 16:12:01 UTC 2018
Modified Files: src/sys/dev/pci: svwsata.c Log Message: another G5-specific fix - do a 32bit read of the status register before checking for channel interrupts. No more interrupt storms. Adapted from FreeBSD To generate a diff of this commit: cvs rdiff -u -r1.20 -r1.21 src/sys/dev/pci/svwsata.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/pci/svwsata.c diff -u src/sys/dev/pci/svwsata.c:1.20 src/sys/dev/pci/svwsata.c:1.21 --- src/sys/dev/pci/svwsata.c:1.20 Sat Oct 7 16:05:33 2017 +++ src/sys/dev/pci/svwsata.c Fri Jun 1 16:12:01 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: svwsata.c,v 1.20 2017/10/07 16:05:33 jdolecek Exp $ */ +/* $NetBSD: svwsata.c,v 1.21 2018/06/01 16:12:01 macallan Exp $ */ /* * Copyright (c) 2005 Mark Kettenis @@ -17,7 +17,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: svwsata.c,v 1.20 2017/10/07 16:05:33 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: svwsata.c,v 1.21 2018/06/01 16:12:01 macallan Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -39,6 +39,7 @@ static void svwsata_chip_map(struct pcii static void svwsata_mapreg_dma(struct pciide_softc *, const struct pci_attach_args *); static void svwsata_mapchan(struct pciide_channel *); +int svwsata_intr(void *); CFATTACH_DECL_NEW(svwsata, sizeof(struct pciide_softc), svwsata_match, svwsata_attach, pciide_detach, NULL); @@ -161,7 +162,7 @@ svwsata_chip_map(struct pciide_softc *sc } intrstr = pci_intr_string(pa->pa_pc, intrhandle, intrbuf, sizeof(intrbuf)); sc->sc_pci_ih = pci_intr_establish(pa->pa_pc, intrhandle, IPL_BIO, - pciide_pci_intr, sc); + svwsata_intr, sc); if (sc->sc_pci_ih != NULL) { aprint_normal_dev(sc->sc_wdcdev.sc_atac.atac_dev, "using %s for native-PCI interrupt\n", @@ -178,7 +179,6 @@ svwsata_chip_map(struct pciide_softc *sc interface = PCIIDE_INTERFACE_BUS_MASTER_DMA | PCIIDE_INTERFACE_PCI(0) | PCIIDE_INTERFACE_PCI(1); - for (channel = 0; channel < sc->sc_wdcdev.sc_atac.atac_nchannels; channel++) { cp = &sc->pciide_channels[channel]; @@ -322,9 +322,62 @@ svwsata_mapchan(struct pciide_channel *c bus_space_write_4(sc->sc_ba5_st, sc->sc_ba5_sh, (wdc_cp->ch_channel << 8) + SVWSATA_SIM, 0); +#ifndef notyet + cp->ata_channel.ch_flags |= ATACH_DMA_BEFORE_CMD; +#endif wdcattach(wdc_cp); return; bad: cp->ata_channel.ch_flags |= ATACH_DISABLED; } + +int +svwsata_intr(void *arg) +{ + struct pciide_softc *sc = arg; + struct pciide_channel *cp; + struct ata_channel *wdc_cp; + struct wdc_regs *wdr; + int i, rv, crv; + uint8_t dmastat; + + rv = 0; + for (i = 0; i < sc->sc_wdcdev.sc_atac.atac_nchannels; i++) { + volatile uint32_t status; + cp = &sc->pciide_channels[i]; + wdc_cp = &cp->ata_channel; + wdr = CHAN_TO_WDC_REGS(wdc_cp); + + /* + * from FreeBSD's ata-serverworks.c: + * We need to do a 4-byte read on the status reg before the + * values will report correctly + */ + bus_space_read_4(wdr->cmd_iot, + wdr->cmd_iohs[wd_status], 0); + __USE(status); + + dmastat = bus_space_read_1(sc->sc_dma_iot, + cp->dma_iohs[IDEDMA_CTL], 0); + + /* If a compat channel skip. */ + if (cp->compat) + continue; + + /* if this channel not waiting for intr, skip */ + if ((wdc_cp->ch_flags & ATACH_IRQ_WAIT) == 0) { + continue; + } + crv = wdcintr(wdc_cp); + if ((crv == 0)) { + bus_space_write_1(sc->sc_dma_iot, + cp->dma_iohs[IDEDMA_CTL], 0, dmastat); + } + else if (crv == 1) + rv = 1; /* claim the intr */ + else if (rv == 0) /* crv should be -1 in this case */ + rv = crv; /* if we've done no better, take it */ + } + return (rv); +}