diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2010-07-09 22:33:22 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2010-07-09 22:33:22 +0000 |
commit | 39a01e6a9fabc042f5f0cbc690235e62446158a9 (patch) | |
tree | 7a317ec0d8eb1d1116048976324b06c131a0b9bc /sys/dev/pci | |
parent | bde66da2738d9e8292c0f830a2d34d4d8bc231dd (diff) |
rewrite the polling codepath in mpii.
it basically has the poll code swap the ccb completion path out for
something that clears the flag the poll code is looping on. it just
runs the interrupt handler to try and get that ccb back off the
hardware.
the reply queue is now protected by a semaphore, meaning that if
one cpu is already pulling stuff off the chip, another cpu may try
to also pull stuff off, but will return immediately cos the first
cpu will end up doing the work it wants anyway.
i did it this way so the ccb completion paths wouldnt be run while
a mutex was held, and to avoid reordering of ccb completions and
updates to the reply queue consumer that could be caused by allowing
concurrent runs of the interrupt handler to step on each other.
there is a big change here in that polling doesnt time out anymore.
it keeps trying until it succeeds, or it keeps trying. i think it
is dangerous to complete a ccb until th echip has returned it.
the only safe alternative is to do a full reset of the chip, but
that is a massive amount of work.
reviewed by mikeb
ok krw@
testing by me on real and logical disks
Diffstat (limited to 'sys/dev/pci')
-rw-r--r-- | sys/dev/pci/mpii.c | 184 |
1 files changed, 98 insertions, 86 deletions
diff --git a/sys/dev/pci/mpii.c b/sys/dev/pci/mpii.c index cdedf0e198b..c04c585dacf 100644 --- a/sys/dev/pci/mpii.c +++ b/sys/dev/pci/mpii.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mpii.c,v 1.31 2010/07/07 10:29:17 dlg Exp $ */ +/* $OpenBSD: mpii.c,v 1.32 2010/07/09 22:33:21 dlg Exp $ */ /* * Copyright (c) 2010 Mike Belopuhov <mkb@crypt.org.ru> * Copyright (c) 2009 James Giannoules @@ -1788,6 +1788,8 @@ struct mpii_softc { bus_dma_tag_t sc_dmat; struct mutex sc_req_mtx; + struct mutex sc_rep_mtx; + u_int sc_rep_sem; u_int8_t sc_porttype; int sc_request_depth; @@ -1893,13 +1895,16 @@ int mpii_remove_dev(struct mpii_softc *, struct mpii_device *); struct mpii_device *mpii_find_dev(struct mpii_softc *, u_int16_t); void mpii_start(struct mpii_softc *, struct mpii_ccb *); -int mpii_complete(struct mpii_softc *, struct mpii_ccb *, int); -int mpii_poll(struct mpii_softc *, struct mpii_ccb *, int); +int mpii_poll(struct mpii_softc *, struct mpii_ccb *); +void mpii_poll_done(struct mpii_ccb *); int mpii_reply(struct mpii_softc *, struct mpii_reply_descr *); void mpii_wait(struct mpii_softc *, struct mpii_ccb *); void mpii_wait_done(struct mpii_ccb *); +int mpii_sem_enter(struct mpii_softc *); +int mpii_sem_leave(struct mpii_softc *); + void mpii_init_queues(struct mpii_softc *); int mpii_load_xs(struct mpii_ccb *); @@ -2037,6 +2042,7 @@ mpii_attach(struct device *parent, struct device *self, void *aux) sc->sc_dmat = pa->pa_dmat; mtx_init(&sc->sc_req_mtx, IPL_BIO); + mtx_init(&sc->sc_rep_mtx, IPL_BIO); /* find the appropriate memory base */ for (r = PCI_MAPREG_START; r < PCI_MAPREG_END; r += sizeof(memtype)) { @@ -2240,41 +2246,75 @@ mpii_detach(struct device *self, int flags) return (0); } +int +mpii_sem_enter(struct mpii_softc *sc) +{ + int rv = 1; + + mtx_enter(&sc->sc_rep_mtx); + sc->sc_rep_sem++; + if (sc->sc_rep_sem > 1) + rv = 0; + mtx_leave(&sc->sc_rep_mtx); + + return (rv); +} + +int +mpii_sem_leave(struct mpii_softc *sc) +{ + int rv = 1; + + mtx_enter(&sc->sc_rep_mtx); + sc->sc_rep_sem--; + if (sc->sc_rep_sem > 0) + rv = 0; + mtx_leave(&sc->sc_rep_mtx); + + return (rv); +} int mpii_intr(void *arg) { struct mpii_softc *sc = arg; - struct mpii_reply_descr *rdp; + struct mpii_reply_descr *postq = sc->sc_reply_postq_kva, *rdp; int rv = 0; + if (!mpii_sem_enter(sc)) + return (0); do { - bus_dmamap_sync(sc->sc_dmat, MPII_DMA_MAP(sc->sc_reply_postq), - 0, 8 * sc->sc_reply_post_qdepth, BUS_DMASYNC_POSTWRITE); - rdp = &sc->sc_reply_postq_kva[sc->sc_reply_post_host_index]; - if ((rdp->reply_flags & MPII_REPLY_DESCR_TYPE_MASK) == - MPII_REPLY_DESCR_UNUSED) - break; - if (rdp->data == 0xffffffff) { - /* - * ioc is still writing to the reply post queue - * race condition - bail! - */ - printf("%s: ioc is writing a reply @ %d/%d (kva %p)\n", - DEVNAME(sc), sc->sc_reply_post_host_index, - sc->sc_reply_post_qdepth, rdp); - break; + for (;;) { + bus_dmamap_sync(sc->sc_dmat, + MPII_DMA_MAP(sc->sc_reply_postq), + 0, 8 * sc->sc_reply_post_qdepth, + BUS_DMASYNC_POSTWRITE); + + rdp = &postq[sc->sc_reply_post_host_index]; + if ((rdp->reply_flags & MPII_REPLY_DESCR_TYPE_MASK) == + MPII_REPLY_DESCR_UNUSED) + break; + if (rdp->data == 0xffffffff) { + /* + * ioc is still writing to the reply post queue + * race condition - bail! + */ + break; + } + + mpii_reply(sc, rdp); + + sc->sc_reply_post_host_index = + (sc->sc_reply_post_host_index + 1) % + sc->sc_reply_post_qdepth; + + rv = 1; } - mpii_reply(sc, rdp); - sc->sc_reply_post_host_index = - (sc->sc_reply_post_host_index + 1) % - sc->sc_reply_post_qdepth; - rv |= 1; - } while (1); + if (rv) + mpii_write_reply_post(sc, sc->sc_reply_post_host_index); - if (rv) - mpii_write_reply_post(sc, sc->sc_reply_post_host_index); + } while (!mpii_sem_leave(sc)); return (rv); } @@ -2980,7 +3020,7 @@ mpii_portfacts(struct mpii_softc *sc) pfq->vp_id = 0; pfq->vf_id = 0; - if (mpii_poll(sc, ccb, 50000) != 0) { + if (mpii_poll(sc, ccb) != 0) { DNPRINTF(MPII_D_MISC, "%s: mpii_portfacts poll\n", DEVNAME(sc)); goto err; @@ -3078,7 +3118,7 @@ mpii_portenable(struct mpii_softc *sc) peq->function = MPII_FUNCTION_PORT_ENABLE; peq->vf_id = sc->sc_vf_id; - if (mpii_poll(sc, ccb, 80000) != 0) { + if (mpii_poll(sc, ccb) != 0) { DNPRINTF(MPII_D_MISC, "%s: mpii_portenable poll\n", DEVNAME(sc)); return (1); @@ -3639,7 +3679,7 @@ mpii_req_cfg_header(struct mpii_softc *sc, u_int8_t type, u_int8_t number, ccb->ccb_done = mpii_empty_done; if (ISSET(flags, MPII_PG_POLL)) { - if (mpii_poll(sc, ccb, 5000) != 0) { + if (mpii_poll(sc, ccb) != 0) { DNPRINTF(MPII_D_MISC, "%s: mpii_cfg_header poll\n", DEVNAME(sc)); return (1); @@ -3759,7 +3799,7 @@ mpii_req_cfg_page(struct mpii_softc *sc, u_int32_t address, int flags, ccb->ccb_done = mpii_empty_done; if (ISSET(flags, MPII_PG_POLL)) { - if (mpii_poll(sc, ccb, 5000) != 0) { + if (mpii_poll(sc, ccb) != 0) { DNPRINTF(MPII_D_MISC, "%s: mpii_cfg_header poll\n", DEVNAME(sc)); return (1); @@ -4163,53 +4203,42 @@ mpii_start(struct mpii_softc *sc, struct mpii_ccb *ccb) } int -mpii_complete(struct mpii_softc *sc, struct mpii_ccb *ccb, int timeout) +mpii_poll(struct mpii_softc *sc, struct mpii_ccb *ccb) { - struct mpii_reply_descr *rdp; - int smid = -1; + void (*done)(struct mpii_ccb *); + void *cookie; + int rv = 1; - DNPRINTF(MPII_D_INTR, "%s: mpii_complete timeout %d\n", DEVNAME(sc), - timeout); + DNPRINTF(MPII_D_INTR, "%s: mpii_complete %d\n", DEVNAME(sc)); - timeout *= 100; + done = ccb->ccb_done; + cookie = ccb->ccb_cookie; - do { - /* avoid excessive polling */ - if (!mpii_reply_waiting(sc)) { - if (timeout-- == 0) - return (1); - delay(10); - continue; - } + ccb->ccb_done = mpii_poll_done; + ccb->ccb_cookie = &rv; - bus_dmamap_sync(sc->sc_dmat, MPII_DMA_MAP(sc->sc_reply_postq), - 0, 8 * sc->sc_reply_post_qdepth, BUS_DMASYNC_POSTWRITE); + mpii_start(sc, ccb); - rdp = &sc->sc_reply_postq_kva[sc->sc_reply_post_host_index]; - if ((rdp->reply_flags & MPII_REPLY_DESCR_TYPE_MASK) == - MPII_REPLY_DESCR_UNUSED) - continue; - if (rdp->data == 0xffffffff) { - /* - * ioc is still writing to the reply post queue - * race condition - bail! - */ - printf("%s: ioc is writing a reply\n", DEVNAME(sc)); - continue; - } + while (rv == 1) { + /* avoid excessive polling */ + if (mpii_reply_waiting(sc)) + mpii_intr(sc); + else + delay(10); + } - smid = mpii_reply(sc, rdp); + ccb->ccb_cookie = cookie; + done(ccb); - DNPRINTF(MPII_D_INTR, "%s: mpii_complete call to mpii_reply" - "returned: %d\n", DEVNAME(sc), smid); + return (0); +} - sc->sc_reply_post_host_index = - (sc->sc_reply_post_host_index + 1) % - sc->sc_reply_post_qdepth; - mpii_write_reply_post(sc, sc->sc_reply_post_host_index); - } while (ccb->ccb_smid != smid); +void +mpii_poll_done(struct mpii_ccb *ccb) +{ + int *rv = ccb->ccb_cookie; - return (0); + *rv = 0; } int @@ -4271,23 +4300,6 @@ mpii_init_queues(struct mpii_softc *sc) mpii_write_reply_post(sc, sc->sc_reply_post_host_index); } -int -mpii_poll(struct mpii_softc *sc, struct mpii_ccb *ccb, int timeout) -{ - int error; - int s; - - DNPRINTF(MPII_D_CMD, "%s: mpii_poll: ccb %p cmd 0x%08x\n", - DEVNAME(sc), ccb, ccb->ccb_cmd); - - s = splbio(); - mpii_start(sc, ccb); - error = mpii_complete(sc, ccb, timeout); - splx(s); - - return (error); -} - void mpii_wait(struct mpii_softc *sc, struct mpii_ccb *ccb) { @@ -4413,7 +4425,7 @@ mpii_scsi_cmd(struct scsi_xfer *xs) io->sgl_offset0); if (xs->flags & SCSI_POLL) { - if (mpii_poll(sc, ccb, xs->timeout) != 0) { + if (mpii_poll(sc, ccb) != 0) { xs->error = XS_DRIVER_STUFFUP; scsi_done(xs); } |