PERFORCE change 109409 for review

Sam Leffler sam at FreeBSD.org
Tue Nov 7 01:33:48 UTC 2006


http://perforce.freebsd.org/chv.cgi?CH=109409

Change 109409 by sam at sam_ebb on 2006/11/07 01:33:10

	lots of cleanups:
	o single-thread access to the mailbox registers
	o eliminate spinning waiting for a message reply; instead
	  enable interrupts and do sleep/wakeup to get the msg
	  response from the NPE
	o remove ixpnpe_sendmsg and ipxnpe_recvmsg; they are now
	  dangerous to use and are otherwise we really need clients
	  to use the send+recv api
	o be pedantic and cleanup resources on detach

Affected files ...

.. //depot/projects/arm/src/sys/arm/xscale/ixp425/ixp425_npe.c#3 edit
.. //depot/projects/arm/src/sys/arm/xscale/ixp425/ixp425_npevar.h#3 edit

Differences ...

==== //depot/projects/arm/src/sys/arm/xscale/ixp425/ixp425_npe.c#3 (text+ko) ====

@@ -69,6 +69,9 @@
  * for loading microcode images and the associated NPE CPU
  * manipulations (start, stop, reset).
  *
+ * The code here basically replaces the npeDl and npeMh classes
+ * in the Intel Access Library (IAL).
+ *
  * NB: Microcode images are loaded with firmware(9).  To
  *     include microcode in a static kernel include the
  *     ixpnpe_fw device.  Otherwise the firmware will be
@@ -103,8 +106,12 @@
     device_t		sc_dev;
     bus_space_tag_t	sc_iot;
     bus_space_handle_t	sc_ioh;
+    bus_size_t		sc_size;	/* size of mapped register window */
     struct resource	*sc_irq;	/* IRQ resource */
     void		*sc_ih;		/* interrupt handler */
+    struct mtx		sc_mtx;		/* mailbox lock */
+    uint32_t		sc_msg[2];	/* reply msg collected in ixpnpe_intr */
+    int			sc_msgwaiting;	/* sc_msg holds valid data */
 
     int			validImage;	/* valid ucode image loaded */
     int			started;	/* NPE is started */
@@ -221,9 +228,7 @@
 static int npe_ctx_reg_write(struct ixpnpe_softc *, uint32_t ctxtNum,
 		uint32_t ctxtReg, uint32_t ctxtRegVal, int verify);
 
-#if 0
 static void ixpnpe_intr(void *arg);
-#endif
 
 static uint32_t
 npe_reg_read(struct ixpnpe_softc *sc, bus_size_t off)
@@ -246,16 +251,17 @@
     struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
     struct ixpnpe_softc *sc;
     bus_addr_t base;
-    bus_size_t size;
     int rid, irq;
 
     /* XXX M_BUS */
     sc = malloc(sizeof(struct ixpnpe_softc), M_TEMP, M_WAITOK | M_ZERO);
     sc->sc_dev = dev;
     sc->sc_iot = sa->sc_iot;
+    mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF);
+
     if (device_get_unit(dev) == 0) {
 	base = IXP425_NPE_B_HWBASE;
-	size = IXP425_NPE_B_SIZE;
+	sc->sc_size = IXP425_NPE_B_SIZE;
 	irq = IXP425_INT_NPE_B;
 
 	/* size of instruction memory */
@@ -264,7 +270,7 @@
 	sc->dataMemSize = IX_NPEDL_DATA_MEMSIZE_WORDS_NPEB;
     } else {
 	base = IXP425_NPE_C_HWBASE;
-	size = IXP425_NPE_C_SIZE;
+	sc->sc_size = IXP425_NPE_C_SIZE;
 	irq = IXP425_INT_NPE_C;
 
 	/* size of instruction memory */
@@ -272,7 +278,7 @@
 	/* size of data memory */
 	sc->dataMemSize = IX_NPEDL_DATA_MEMSIZE_WORDS_NPEC;
     }
-    if (bus_space_map(sc->sc_iot, base, size, 0, &sc->sc_ioh))
+    if (bus_space_map(sc->sc_iot, base, sc->sc_size, 0, &sc->sc_ioh))
 	panic("%s: Cannot map registers", device_get_name(dev));
 
     /*
@@ -284,10 +290,11 @@
     if (!sc->sc_irq)
 	panic("%s: Unable to allocate irq %u", device_get_name(dev), irq);
     /* XXX could be a source of entropy */
-#if 0
     bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_NET | INTR_MPSAFE,
 	ixpnpe_intr, sc, &sc->sc_ih);
-#endif
+    /* enable output fifo interrupts (NB: must also set OFIFO Write Enable) */ 
+    npe_reg_write(sc, IX_NPECTL,
+	npe_reg_read(sc, IX_NPECTL) | (IX_NPECTL_OFE | IX_NPECTL_OFWE));
 
     return sc;
 }
@@ -295,8 +302,13 @@
 void
 ixpnpe_detach(struct ixpnpe_softc *sc)
 {
-    /* XXX release irq */
-    /* XXX unmap memory */
+    /* disable output fifo interrupts */ 
+    npe_reg_write(sc, IX_NPECTL,
+	npe_reg_read(sc, IX_NPECTL) &~ (IX_NPECTL_OFE | IX_NPECTL_OFWE));
+
+    bus_teardown_intr(sc->sc_dev, sc->sc_irq, sc->sc_ih);
+    bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size);
+    mtx_destroy(&sc->sc_mtx);
     free(sc, M_TEMP);
 }
 
@@ -305,11 +317,14 @@
 {
     int error;
 
-    error = npe_cpu_stop(sc);	/* stop NPE */
+    mtx_lock(&sc->sc_mtx);
+    error = npe_cpu_stop(sc);		/* stop NPE */
     if (error == 0)
 	error = npe_cpu_reset(sc);	/* reset it */
     if (error == 0)
-	sc->started = 0;	/* mark stopped */
+	sc->started = 0;		/* mark stopped */
+    mtx_unlock(&sc->sc_mtx);
+
     DPRINTF(sc->sc_dev, "%s: error %d\n", __func__, error);
     return error;
 }
@@ -319,12 +334,15 @@
 {
     int error;
 
+    mtx_lock(&sc->sc_mtx);
     if (!sc->started) {
 	error = npe_cpu_start(sc);
 	if (error == 0)
 	    sc->started = 1;
     } else
 	error = 0;
+    mtx_unlock(&sc->sc_mtx);
+
     DPRINTF(sc->sc_dev, "%s: error %d\n", __func__, error);
     return error;
 }
@@ -334,9 +352,12 @@
 {
     int error;
 
+    mtx_lock(&sc->sc_mtx);
     error = npe_cpu_stop(sc);
     if (error == 0)
 	sc->started = 0;
+    mtx_unlock(&sc->sc_mtx);
+
     DPRINTF(sc->sc_dev, "%s: error %d\n", __func__, error);
     return error;
 }
@@ -425,6 +446,7 @@
      * currently loaded images. If a critical error occured
      * during download, record that the NPE has an invalid image
      */
+    mtx_lock(&sc->sc_mtx);
     error = npe_load_image(sc, imageCodePtr, 1 /*VERIFY*/);
     if (error == 0) {
 	sc->validImage = 1;
@@ -433,6 +455,7 @@
 	sc->validImage = 0;
     }
     sc->functionalityId = IX_NPEDL_FUNCTIONID_FROM_IMAGEID_GET(imageId);
+    mtx_unlock(&sc->sc_mtx);
 done:
     firmware_put(fw, FIRMWARE_UNLOAD);
     DPRINTF(sc->sc_dev, "%s: error %d\n", __func__, error);
@@ -808,7 +831,7 @@
 #undef N
 }
 
-int
+static int
 npe_cpu_start(struct ixpnpe_softc *sc)
 {
     uint32_t ecsRegVal;
@@ -1214,27 +1237,18 @@
     }
 }
 
-#if 0
-static void
-ixpnpe_intr(void *arg)
-{
-    struct ixpnpe_softc *sc = arg;
-    uint32_t status;
-
-    status = npe_reg_read(sc, IX_NPESTAT);
-    device_printf(sc->sc_dev, "%s: status 0x%x\n", __func__, status);
-}
-#endif
-
+/*
+ * NPE Mailbox support.
+ */
 #define	IX_NPEMH_MAXTRIES	100000
 
 static int
-ixpnpe_ififo_wait(struct ixpnpe_softc *sc)
+ixpnpe_ofifo_wait(struct ixpnpe_softc *sc)
 {
     int i;
 
     for (i = 0; i < IX_NPEMH_MAXTRIES; i++) {
-	if (npe_reg_read(sc, IX_NPESTAT) & IX_NPESTAT_IFNF)
+        if (npe_reg_read(sc, IX_NPESTAT) & IX_NPESTAT_OFNE)
 	    return 1;
 	DELAY(10);
     }
@@ -1243,54 +1257,102 @@
     return 0;
 }
 
-int
-ixpnpe_sendmsg(struct ixpnpe_softc *sc, const uint32_t msg[2])
+static void
+ixpnpe_intr(void *arg)
 {
+    struct ixpnpe_softc *sc = arg;
+    uint32_t status;
 
-    if (!ixpnpe_ififo_wait(sc))
-	return EIO;
-    npe_reg_write(sc, IX_NPEFIFO, msg[0]);
-    if (!ixpnpe_ififo_wait(sc))
-	return EIO;
-    npe_reg_write(sc, IX_NPEFIFO, msg[1]);
-    return 0;
+    status = npe_reg_read(sc, IX_NPESTAT);
+    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? */
+	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.
+     */
+    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);
 }
 
 static int
-ixpnpe_ofifo_wait(struct ixpnpe_softc *sc)
+ixpnpe_ififo_wait(struct ixpnpe_softc *sc)
 {
     int i;
 
     for (i = 0; i < IX_NPEMH_MAXTRIES; i++) {
-        if (npe_reg_read(sc, IX_NPESTAT) & IX_NPESTAT_OFNE)
+	if (npe_reg_read(sc, IX_NPESTAT) & IX_NPESTAT_IFNF)
 	    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;
 }
 
-int
-ixpnpe_recvmsg(struct ixpnpe_softc *sc, uint32_t msg[2])
+static int
+ixpnpe_sendmsg_locked(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;
+
+    if (error)
+	device_printf(sc->sc_dev, "input FIFO timeout, msg [0x%x,0x%x]\n",
+	    msg[0], msg[1]);
+    return error;
+}
+
+static int
+ixpnpe_recvmsg_locked(struct ixpnpe_softc *sc, uint32_t msg[2])
 {
-    if (!ixpnpe_ofifo_wait(sc))
-	return EIO;
-    msg[0] = npe_reg_read(sc, IX_NPEFIFO);
-    if (!ixpnpe_ofifo_wait(sc))
-	return EIO;
-    msg[1] = npe_reg_read(sc, IX_NPEFIFO);
-    return 0;
+    mtx_assert(&sc->sc_mtx, MA_OWNED);
+
+    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;
 }
 
+/*
+ * 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.
+ */
 int
 ixpnpe_sendandrecvmsg(struct ixpnpe_softc *sc,
 	const uint32_t send[2], uint32_t recv[2])
 {
-    int status;
+    int error;
+
+    mtx_lock(&sc->sc_mtx);
+    error = ixpnpe_sendmsg_locked(sc, send);
+    if (error == 0)
+	error = ixpnpe_recvmsg_locked(sc, recv);
+    mtx_unlock(&sc->sc_mtx);
 
-    status = ixpnpe_sendmsg(sc, send);
-    if (status == 0)
-	status = ixpnpe_recvmsg(sc, recv);
-    return status;
+    return error;
 }

==== //depot/projects/arm/src/sys/arm/xscale/ixp425/ixp425_npevar.h#3 (text+ko) ====

@@ -87,8 +87,6 @@
 		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]);
 #endif /* _IXP425_NPEVAR_H_ */


More information about the p4-projects mailing list