Skip site navigation (1)Skip section navigation (2)
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>