Date: Fri, 5 Dec 2008 22:59:14 GMT From: Sam Leffler <sam@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 154150 for review Message-ID: <200812052259.mB5MxEQP055156@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=154150 Change 154150 by sam@sam_ebb on 2008/12/05 22:58:20 Fix bogosity in npe mailbox handling: o make ixpnpe_sendandrecvmsg synchronous and rename to ixpnpe_sendandrecvmsg_sync o rename ixpnpe_sendmsg and ixpnpe_recvmsg to ixpnpe_sendmsg_async and ixpnpe_recvmsg_async respectively to be clear they operate asynchronously o add a synchronos receive api, ixpnpe_recvmsg_sync o eliminate the sleep/wakeup dance receiving mailbox msgs; consumers that require a synchronous api must now spin/poll for a result o change if_npe to: - use synchronous receive during startup as interrupts are not working so msg from the NPE are received - listen for an initial ACK msg sent immediately after the ucode is loaded and set running - setup all 8 traffic classification bindings to the rx queue now that we have working mailbox operation: we only setup 4 before because the 5th failed with no response from the NPE; this was apparently because the CPU-NPE mailbox FIFO is 5 deep and the initial ACK+QoS setup msgs filled the queue until interrupts started working properly and we drained everything - while here disable any firewall processing (should not be needed but still looking for why NPE-A on Cambria board isn't coming up) Affected files ... .. //depot/projects/vap/sys/arm/xscale/ixp425/if_npe.c#10 edit .. //depot/projects/vap/sys/arm/xscale/ixp425/ixp425_npe.c#8 edit .. //depot/projects/vap/sys/arm/xscale/ixp425/ixp425_npevar.h#5 edit Differences ... ==== //depot/projects/vap/sys/arm/xscale/ixp425/if_npe.c#10 (text+ko) ==== @@ -250,6 +250,7 @@ static int npe_setrxqosentry(struct npe_softc *, int classix, int trafclass, int qid); +static int npe_setfirewallmode(struct npe_softc *, int onoff); static int npe_updatestats(struct npe_softc *); #if 0 static int npe_getstats(struct npe_softc *); @@ -715,7 +716,7 @@ { struct npe_softc * sc = device_get_softc(dev); int error, i, macbase, macsize, miibase, miisize; - uint32_t imageid; + uint32_t imageid, msg[2]; /* * Load NPE firmware and start it running. We assume @@ -743,6 +744,10 @@ } imageid++; } + if (ixpnpe_recvmsg_sync(sc->sc_npe, msg) != 0) { + device_printf(dev, "firmware did not respond as expected\n"); + return EIO; + } if (!override_addr(dev, "mac", &macbase, &macsize)) { macbase = npeconfig[sc->sc_npeid].macbase; @@ -832,9 +837,12 @@ * When QoS is enabled in the firmware there are * 8 traffic classes; otherwise just 4. */ - for (i = 0; i < (imageid & 0xf0000 ? 8 : 4); i++) + for (i = 0; i < 8; i++) npe_setrxqosentry(sc, i, 0, sc->rx_qid); + /* disable firewall mode just in case (should be off by default) */ + npe_setfirewallmode(sc, 0); + sc->tx_qid = npeconfig[sc->sc_npeid].tx_qid; sc->tx_doneqid = npeconfig[sc->sc_npeid].tx_doneqid; ixpqmgr_qconfig(sc->tx_qid, npe_txbuf, 0, npe_txbuf, 0, NULL, sc); @@ -976,7 +984,7 @@ * code that talks via the mailbox's (except at setup). * This likely can be handled better. */ - if (ixpnpe_recvmsg(sc->sc_npe, msg) == 0 && msg[0] == ACK) { + if (ixpnpe_recvmsg_async(sc->sc_npe, msg) == 0 && msg[0] == ACK) { bus_dmamap_sync(sc->sc_stats_tag, sc->sc_stats_map, BUS_DMASYNC_POSTREAD); npe_addstats(sc); @@ -1583,7 +1591,18 @@ msg[0] = (NPE_SETRXQOSENTRY << 24) | (sc->sc_npeid << 20) | classix; msg[1] = (trafclass << 24) | (1 << 23) | (qid << 16) | (qid << 4); - return ixpnpe_sendandrecvmsg(sc->sc_npe, msg, msg); + return ixpnpe_sendandrecvmsg_sync(sc->sc_npe, msg, msg); +} + +static int +npe_setfirewallmode(struct npe_softc *sc, int onoff) +{ + uint32_t msg[2]; + + /* XXX honor onoff */ + msg[0] = (NPE_SETFIREWALLMODE << 24) | (sc->sc_npeid << 20); + msg[1] = 0; + return ixpnpe_sendandrecvmsg_sync(sc->sc_npe, msg, msg); } /* @@ -1596,7 +1615,7 @@ msg[0] = NPE_RESETSTATS << NPE_MAC_MSGID_SHL; msg[1] = sc->sc_stats_phys; /* physical address of stat block */ - return ixpnpe_sendmsg(sc->sc_npe, msg); /* NB: no recv */ + return ixpnpe_sendmsg_async(sc->sc_npe, msg); } #if 0 @@ -1623,7 +1642,7 @@ msg[0] = NPE_GETSTATUS << NPE_MAC_MSGID_SHL; msg[1] = 0; - return ixpnpe_sendandrecvmsg(sc->sc_npe, msg, msg) == 0 ? msg[1] : 0; + return ixpnpe_sendandrecvmsg_sync(sc->sc_npe, msg, msg) == 0 ? msg[1] : 0; } /* @@ -1636,7 +1655,7 @@ msg[0] = (NPE_SETLOOPBACK << NPE_MAC_MSGID_SHL) | (ena != 0); msg[1] = 0; - return ixpnpe_sendandrecvmsg(sc->sc_npe, msg, msg); + return ixpnpe_sendandrecvmsg_sync(sc->sc_npe, msg, msg); } #endif ==== //depot/projects/vap/sys/arm/xscale/ixp425/ixp425_npe.c#8 (text+ko) ==== @@ -1317,7 +1317,7 @@ #define IX_NPEMH_MAXTRIES 100000 static int -ixpnpe_ofifo_wait(struct ixpnpe_softc *sc) +ofifo_wait(struct ixpnpe_softc *sc) { int i; @@ -1331,38 +1331,50 @@ return 0; } +static int +getmsg(struct ixpnpe_softc *sc, uint32_t msg[2]) +{ + mtx_assert(&sc->sc_mtx, MA_OWNED); + + if (!ofifo_wait(sc)) + return EAGAIN; + msg[0] = npe_reg_read(sc, IX_NPEFIFO); + DPRINTF(sc->sc_dev, "%s: msg0 0x%x\n", __func__, msg[0]); + if (!ofifo_wait(sc)) + return EAGAIN; + msg[1] = npe_reg_read(sc, IX_NPEFIFO); + DPRINTF(sc->sc_dev, "%s: msg1 0x%x\n", __func__, msg[1]); + return 0; +} + static void ixpnpe_intr(void *arg) { struct ixpnpe_softc *sc = arg; uint32_t status; + mtx_lock(&sc->sc_mtx); status = npe_reg_read(sc, IX_NPESTAT); + DPRINTF(sc->sc_dev, "%s: status 0x%x\n", __func__, status); if ((status & IX_NPESTAT_OFINT) == 0) { /* NB: should not happen */ device_printf(sc->sc_dev, "%s: status 0x%x\n", __func__, status); /* XXX must silence interrupt? */ + mtx_unlock(&sc->sc_mtx); return; } /* * A message is waiting in the output FIFO, copy it so - * the interrupt will be silenced; then signal anyone - * waiting to collect the result. + * the interrupt will be silenced. */ - sc->sc_msgwaiting = -1; /* NB: error indicator */ - if (ixpnpe_ofifo_wait(sc)) { - sc->sc_msg[0] = npe_reg_read(sc, IX_NPEFIFO); - if (ixpnpe_ofifo_wait(sc)) { - sc->sc_msg[1] = npe_reg_read(sc, IX_NPEFIFO); - sc->sc_msgwaiting = 1; /* successful fetch */ - } - } - wakeup_one(sc); + if (getmsg(sc, sc->sc_msg) == 0) + sc->sc_msgwaiting = 1; + mtx_unlock(&sc->sc_mtx); } static int -ixpnpe_ififo_wait(struct ixpnpe_softc *sc) +ififo_wait(struct ixpnpe_softc *sc) { int i; @@ -1371,91 +1383,106 @@ return 1; DELAY(10); } + device_printf(sc->sc_dev, "%s: timeout, last status 0x%x\n", + __func__, npe_reg_read(sc, IX_NPESTAT)); return 0; } static int -ixpnpe_sendmsg_locked(struct ixpnpe_softc *sc, const uint32_t msg[2]) +putmsg(struct ixpnpe_softc *sc, const uint32_t msg[2]) { - int error = 0; - mtx_assert(&sc->sc_mtx, MA_OWNED); - sc->sc_msgwaiting = 0; - if (ixpnpe_ififo_wait(sc)) { - npe_reg_write(sc, IX_NPEFIFO, msg[0]); - if (ixpnpe_ififo_wait(sc)) - npe_reg_write(sc, IX_NPEFIFO, msg[1]); - else - error = EIO; - } else - error = EIO; + DPRINTF(sc->sc_dev, "%s: msg 0x%x:0x%x\n", __func__, msg[0], msg[1]); + if (!ififo_wait(sc)) + return EIO; + npe_reg_write(sc, IX_NPEFIFO, msg[0]); + if (!ififo_wait(sc)) + return EIO; + npe_reg_write(sc, IX_NPEFIFO, msg[1]); - if (error) - device_printf(sc->sc_dev, "input FIFO timeout, " - "msg [0x%08x,0x%08x]\n", msg[0], msg[1]); - return error; + return 0; } -static int -ixpnpe_recvmsg_locked(struct ixpnpe_softc *sc, uint32_t msg[2]) +/* + * Send a msg to the NPE and wait for a reply. We spin as + * we may be called early with interrupts not properly setup. + */ +int +ixpnpe_sendandrecvmsg_sync(struct ixpnpe_softc *sc, + const uint32_t send[2], uint32_t recv[2]) { - mtx_assert(&sc->sc_mtx, MA_OWNED); + int error; + + mtx_lock(&sc->sc_mtx); + error = putmsg(sc, send); + if (error == 0) + error = getmsg(sc, recv); + mtx_unlock(&sc->sc_mtx); - if (!sc->sc_msgwaiting) - msleep(sc, &sc->sc_mtx, 0, "npemh", 0); - bcopy(sc->sc_msg, msg, sizeof(sc->sc_msg)); - /* NB: sc_msgwaiting != 1 means the ack fetch failed */ - return sc->sc_msgwaiting != 1 ? EIO : 0; + return error; } /* - * Send a msg to the NPE and wait for a reply. We use the - * private mutex and sleep until an interrupt is received - * signalling the availability of data in the output FIFO - * so the caller cannot be holding a mutex. May be better - * piggyback on the caller's mutex instead but that would - * make other locking confusing. + * Send a msg to the NPE w/o waiting for a reply. */ int -ixpnpe_sendandrecvmsg(struct ixpnpe_softc *sc, - const uint32_t send[2], uint32_t recv[2]) +ixpnpe_sendmsg_async(struct ixpnpe_softc *sc, const uint32_t msg[2]) { int error; mtx_lock(&sc->sc_mtx); - error = ixpnpe_sendmsg_locked(sc, send); - if (error == 0) - error = ixpnpe_recvmsg_locked(sc, recv); + error = putmsg(sc, msg); mtx_unlock(&sc->sc_mtx); return error; } -/* XXX temporary, not reliable */ +static int +recvmsg_locked(struct ixpnpe_softc *sc, uint32_t msg[2]) +{ + mtx_assert(&sc->sc_mtx, MA_OWNED); + + DPRINTF(sc->sc_dev, "%s: msgwaiting %d\n", __func__, sc->sc_msgwaiting); + if (sc->sc_msgwaiting) { + msg[0] = sc->sc_msg[0]; + msg[1] = sc->sc_msg[1]; + sc->sc_msgwaiting = 0; + return 0; + } + return EAGAIN; +} +/* + * Receive any msg previously received from the NPE. If nothing + * is available we return EAGAIN and the caller is required to + * do a synchronous receive or try again later. + */ int -ixpnpe_sendmsg(struct ixpnpe_softc *sc, const uint32_t msg[2]) +ixpnpe_recvmsg_async(struct ixpnpe_softc *sc, uint32_t msg[2]) { int error; mtx_lock(&sc->sc_mtx); - error = ixpnpe_sendmsg_locked(sc, msg); + error = recvmsg_locked(sc, msg); mtx_unlock(&sc->sc_mtx); return error; } +/* + * Receive a msg from the NPE. If one was received asynchronously + * then it's returned; otherwise we poll synchronously. + */ int -ixpnpe_recvmsg(struct ixpnpe_softc *sc, uint32_t msg[2]) +ixpnpe_recvmsg_sync(struct ixpnpe_softc *sc, uint32_t msg[2]) { int error; mtx_lock(&sc->sc_mtx); - if (sc->sc_msgwaiting) - bcopy(sc->sc_msg, msg, sizeof(sc->sc_msg)); - /* NB: sc_msgwaiting != 1 means the ack fetch failed */ - error = sc->sc_msgwaiting != 1 ? EIO : 0; + error = recvmsg_locked(sc, msg); + if (error == EAGAIN) + error = getmsg(sc, msg); mtx_unlock(&sc->sc_mtx); return error; ==== //depot/projects/vap/sys/arm/xscale/ixp425/ixp425_npevar.h#5 (text+ko) ==== @@ -115,8 +115,9 @@ const char *imageName, uint32_t imageId); int ixpnpe_getfunctionality(struct ixpnpe_softc *sc); -int ixpnpe_sendmsg(struct ixpnpe_softc *, const uint32_t msg[2]); -int ixpnpe_recvmsg(struct ixpnpe_softc *, uint32_t msg[2]); -int ixpnpe_sendandrecvmsg(struct ixpnpe_softc *, const uint32_t send[2], - uint32_t recv[2]); +int ixpnpe_sendmsg_async(struct ixpnpe_softc *, const uint32_t msg[2]); +int ixpnpe_recvmsg_async(struct ixpnpe_softc *, uint32_t msg[2]); +int ixpnpe_sendandrecvmsg_sync(struct ixpnpe_softc *, + const uint32_t send[2], uint32_t recv[2]); +int ixpnpe_recvmsg_sync(struct ixpnpe_softc *, uint32_t msg[2]); #endif /* _IXP425_NPEVAR_H_ */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200812052259.mB5MxEQP055156>