Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 10 Dec 2006 05:54:19 GMT
From:      Warner Losh <imp@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 111376 for review
Message-ID:  <200612100554.kBA5sJUj089780@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=111376

Change 111376 by imp@imp_lighthouse on 2006/12/10 05:54:18

	MF FreeBSD-tsc-6 (by Patrick Schweiger)
	
	o Add support for reading/writing the registers via sysctl
	  to facilitate debugging
	o Make rx_buf __aligned(32) for strength!  well, to make its work.
	  I'm unsure why this is necessary.
	o Fix initialization sequence to properly reflect ordering
	  constraints.
	o tweak setup
	o fix math error in calculating length (maybe the comment here
	  could be better)
	o Simplify sc->rx_ptr computation
	o Move PREREAD dma sync into setup of RPR/RNPR rather than
	  doing it unconditionally for all buffers at startup.
	o minor locking tweak to avoid a lock leak
	o Return the data we have when we get it, rather than waiting for
	  the buffer to fill (well, and some other bogus things)

Affected files ...

.. //depot/projects/arm/src/sys/arm/at91/at91_ssc.c#19 edit

Differences ...

==== //depot/projects/arm/src/sys/arm/at91/at91_ssc.c#19 (text+ko) ====

@@ -34,6 +34,7 @@
 #include <sys/module.h>
 #include <sys/mutex.h>
 #include <sys/rman.h>
+#include <sys/sysctl.h>
 #include <sys/uio.h>
 #include <machine/bus.h>
 
@@ -58,7 +59,7 @@
 	bus_dma_tag_t tag;		/* bus dma tag  */
 	bus_dmamap_t tx_map;
 	int txdone;
-	uint8_t rx_buf[MAX_BUF];
+	uint8_t __aligned(32) rx_buf[MAX_BUF];
 	uint8_t *rx_ptr;
 	bus_dmamap_t rx_map[NRX_BUF];
 	bus_addr_t rx_pa[NRX_BUF];
@@ -68,10 +69,37 @@
 	uint8_t *rd_end;
 };
 
+struct ssc_sysctl_register_list
+{
+    char *nodename;
+    uint32_t offset;
+    char *comment;
+};
+
+static struct ssc_sysctl_register_list ssc_register_oids[] =
+{
+    { "0x00", 0x00, "Control Register"    },
+    { "0x04", 0x04, "Clock Mode Register" },
+    { "0x10", 0x10, "Receive Clock Mode Register" },
+    { "0x14", 0x14, "Receive Frame Mode Register" },
+    { "0x18", 0x18, "Transmit Clock Mode Register" },
+    { "0x1C", 0x1C, "Transmit Frame Mode Register" },
+    { "0x20", 0x20, "Receive Holding Register" },
+    { "0x24", 0x24, "Transmit Holding Register" },
+    { "0x30", 0x30, "Receive Sync. Holding Register" },
+    { "0x34", 0x34, "Transmit Sync. Holding Register" },
+    { "0x40", 0x40, "Status Register" },
+    { "0x44", 0x44, "Interrupt Enable Register" },
+    { "0x48", 0x48, "Interrupt Disable Register" },
+    { "0x4C", 0x4C, "Interrupt Mask Register" },
+    { NULL,   0xFF, NULL }
+};
+
 static void at91_ssc_loadread(void *arg, bus_dma_segment_t *segs, int nsegs,
     int error);
 static void at91_ssc_loadwrite(void *arg, bus_dma_segment_t *segs, int nsegs,
     bus_size_t size, int error);
+static int sysctl_ssc_gen_handler(SYSCTL_HANDLER_ARGS);
 
 static inline uint32_t
 RD4(struct at91_ssc_softc *sc, bus_size_t off)
@@ -144,15 +172,23 @@
 	AT91_SSC_LOCK_INIT(sc);
 
 	/*
-	 * Activate the interrupt
+	 * Register the sysctl handler.
 	 */
-	err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
-	    at91_ssc_intr, sc, &sc->intrhand);
-	if (err) {
-		AT91_SSC_LOCK_DESTROY(sc);
-		goto out;
+	for (i = 0 ; ssc_register_oids[i].nodename != NULL; i++)
+	{
+	    const struct ssc_sysctl_register_list *oid = &ssc_register_oids[i];
+
+	    SYSCTL_ADD_PROC(
+		device_get_sysctl_ctx(dev),
+		SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+		i, oid->nodename, CTLTYPE_UINT | CTLFLAG_RW,
+		sc, oid->offset, sysctl_ssc_gen_handler, "I",
+		oid->comment);
 	}
 
+	// perform software reset before DMA read buffer setup
+	WR4(sc, SSC_CR, SSC_CR_SWRST);
+
 	/*
 	 * Allocate DMA tags and maps
 	 */
@@ -165,7 +201,7 @@
 	if (err != 0)
 		goto out;
 	for (i = 0; i < NRX_BUF; i++) {
-		err = bus_dmamap_create(sc->tag, 0,  &sc->rx_map[i]);
+		err = bus_dmamap_create(sc->tag, 0, &sc->rx_map[i]);
 		if (err != 0)
 			goto out;
 		err = bus_dmamap_load(sc->tag, sc->rx_map[i], sc->rx_buf +
@@ -173,6 +209,17 @@
 		if (err != 0)
 			goto out;
 	}
+
+	/*
+	 * Activate the interrupt
+	 */
+	err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
+	    at91_ssc_intr, sc, &sc->intrhand);
+	if (err) {
+		AT91_SSC_LOCK_DESTROY(sc);
+		goto out;
+	}
+
 	// We use two buffers for read, and we bounce between them.
 
 
@@ -186,16 +233,19 @@
 	sc->rd_end = sc->rd_buf;
 
 	// Init for TSC needs
-	WR4(sc, SSC_CR, SSC_CR_SWRST);
 	WR4(sc, SSC_CMR, 0);		// clock divider unused
 	WR4(sc, SSC_RCMR,
-	    SSC_RCMR_CKS_RK | SSC_RCMR_CKO_NONE | SSC_RCMR_START_FALL_EDGE_RF);
+	    SSC_RCMR_CKS_RK | SSC_RCMR_CKO_NONE |
+	    SSC_RCMR_START_FALL_EDGE_RF | SSC_RCMR_CKI);
+
 	WR4(sc, SSC_RFMR,
-	    0x1f | SSC_RFMR_MSFBF | SSC_RFMR_FSOS_NONE);
+	    0x1f | SSC_RFMR_MSFBF | SSC_RFMR_FSOS_NONE);  // input only
+
 	WR4(sc, SSC_TCMR,
 	    SSC_TCMR_CKS_TK | SSC_TCMR_CKO_NONE |  SSC_TCMR_START_CONT);
+
 	WR4(sc, SSC_TFMR,
-	    0x1f | SSC_TFMR_DATDEF | SSC_TFMR_MSFBF | SSC_TFMR_FSOS_NEG_PULSE);
+	    0x1f | SSC_TFMR_DATDEF | SSC_TFMR_MSFBF | SSC_TFMR_FSOS_LOW);
 
 out:
 	if (err)
@@ -280,7 +330,12 @@
 		bus_dmamap_sync(sc->tag, sc->rx_map[sc->rxcur],
 		    BUS_DMASYNC_POSTREAD);
 		WR4(sc, PDC_PTCR, PDC_PTCR_RXTDIS);
-		len = ONE_BUF - RD4(sc, PDC_RCR) * 4 + 4;
+
+		// PDC_RNCR value has been moved to PDC_RCR at the time the
+		// ENDRX interrupt was triggered, its original value already
+		// accounted for the fact that RCR would receive one datum
+		len = ONE_BUF - RD4(sc, PDC_RCR) * 4;
+
 		sc->rxcur = (sc->rxcur + 1) % NRX_BUF;
 		WR4(sc, PDC_RPR, sc->rx_pa[sc->rxcur]);
 		WR4(sc, PDC_RCR, 1);
@@ -293,9 +348,7 @@
 			memcpy(sc->rd_end, sc->rx_ptr, len);
 			sc->rd_end += len;
 		}
-		sc->rx_ptr += ONE_BUF;
-		if (sc->rx_ptr >= sc->rx_buf + sizeof(sc->rx_buf))
-			sc->rx_ptr = sc->rx_buf;
+		sc->rx_ptr = sc->rx_buf + ONE_BUF * sc->rxcur;
 		sc->rxdone++;
 		wakeup(&sc->rxdone);
 	}
@@ -338,17 +391,17 @@
 	sc = arg;
 	if (error != 0)
 		return;
-	bus_dmamap_sync(sc->tag, sc->rx_map[sc->rxcur], BUS_DMASYNC_PREREAD);
 	sc->rx_pa[sc->rxcur] = segs[0].ds_addr;
 	if (sc->rx_ptr == NULL) {
 		WR4(sc, PDC_RPR, sc->rx_pa[sc->rxcur]);
 		WR4(sc, PDC_RCR, 1);
 		WR4(sc, PDC_RNPR, sc->rx_pa[sc->rxcur] + 4);
 		WR4(sc, PDC_RNCR, ONE_BUF / 4 - 1);
+		bus_dmamap_sync(sc->tag, sc->rx_map[sc->rxcur], BUS_DMASYNC_PREREAD);
 		WR4(sc, SSC_IER, SSC_SR_ENDRX);
 		WR4(sc, SSC_CR, SSC_CR_RXEN);
 		WR4(sc, PDC_PTCR, PDC_PTCR_RXTEN);
-		sc->rx_ptr = sc->rx_buf;
+		sc->rx_ptr = sc->rx_buf + ONE_BUF * sc->rxcur;
 	}
 	sc->rxcur = (sc->rxcur + 1) % NRX_BUF;
 }
@@ -377,10 +430,10 @@
 	int err, ret, len;
 
 	sc = CDEV2SOFTC(dev);
-	AT91_SSC_LOCK(sc);
 	// must read a multiple of 4 bytes
 	if ((uio->uio_resid & 0x3) != 0)
 		return (EINVAL);
+	AT91_SSC_LOCK(sc);
 	err = 0;
 	ret = 0;
 	while (uio->uio_resid) {
@@ -388,8 +441,12 @@
 		// some data, then go ahead and return what we have now.
 		if (sc->rd_end == sc->rd_buf && ret != 0)
 			break;
-		err = msleep(&sc->rxdone, &sc->sc_mtx, PCATCH | PZERO,
-		    "sscrd", 0);
+
+		if (sc->rd_end != sc->rd_buf)
+		    err = 0;
+		else
+		    err = msleep(&sc->rxdone, &sc->sc_mtx, PCATCH | PZERO,
+				 "sscrd", 0);
 		if (err != 0)
 			break;
 		if (sc->rd_end == sc->rd_buf)
@@ -466,4 +523,27 @@
 	sizeof(struct at91_ssc_softc),
 };
 
+static int 
+sysctl_ssc_gen_handler(SYSCTL_HANDLER_ARGS)
+{
+    struct at91_ssc_softc *sc = arg1;
+    int err;
+
+    uint32_t val, newval = 0;
+    val = RD4(sc, arg2);
+
+    if (req->newptr)
+    {
+	if ((err = SYSCTL_IN(req, &newval, sizeof(newval))) != 0)
+	    return err;
+	WR4(sc, arg2, newval);
+    }
+    else
+    {
+	return SYSCTL_OUT(req, &val, sizeof(val));
+    }
+
+    return 0;
+}
+
 DRIVER_MODULE(at91_ssc, atmelarm, at91_ssc_driver, at91_ssc_devclass, 0, 0);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200612100554.kBA5sJUj089780>