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>