Date: Tue, 5 Aug 2014 06:34:00 +0000 (UTC) From: Hans Petter Selasky <hselasky@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r269564 - head/sys/dev/usb/controller Message-ID: <53e07ad8.5f3e.1a10c6a4@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: hselasky Date: Tue Aug 5 06:33:59 2014 New Revision: 269564 URL: http://svnweb.freebsd.org/changeset/base/269564 Log: - Implement fast interrupt handler to save CPU usage. - Add support for striding register offsets. - Cleanup some register reads and writes to use existing register access macros. Modified: head/sys/dev/usb/controller/uss820dci.c head/sys/dev/usb/controller/uss820dci.h head/sys/dev/usb/controller/uss820dci_atmelarm.c Modified: head/sys/dev/usb/controller/uss820dci.c ============================================================================== --- head/sys/dev/usb/controller/uss820dci.c Tue Aug 5 06:31:09 2014 (r269563) +++ head/sys/dev/usb/controller/uss820dci.c Tue Aug 5 06:33:59 2014 (r269564) @@ -81,6 +81,9 @@ #define USS820_DCI_PC2SC(pc) \ USS820_DCI_BUS2SC(USB_DMATAG_TO_XROOT((pc)->tag_parent)->bus) +#define USS820_DCI_THREAD_IRQ \ + (USS820_SSR_SUSPEND | USS820_SSR_RESUME | USS820_SSR_RESET) + #ifdef USB_DEBUG static int uss820dcidebug = 0; @@ -243,24 +246,18 @@ uss820dci_set_address(struct uss820dci_s } static uint8_t -uss820dci_setup_rx(struct uss820dci_td *td) +uss820dci_setup_rx(struct uss820dci_softc *sc, struct uss820dci_td *td) { - struct uss820dci_softc *sc; struct usb_device_request req; uint16_t count; uint8_t rx_stat; uint8_t temp; /* select the correct endpoint */ - bus_space_write_1(td->io_tag, td->io_hdl, - USS820_EPINDEX, td->ep_index); + USS820_WRITE_1(sc, USS820_EPINDEX, td->ep_index); /* read out FIFO status */ - rx_stat = bus_space_read_1(td->io_tag, td->io_hdl, - USS820_RXSTAT); - - /* get pointer to softc */ - sc = USS820_DCI_PC2SC(td->pc); + rx_stat = USS820_READ_1(sc, USS820_RXSTAT); DPRINTFN(5, "rx_stat=0x%02x rem=%u\n", rx_stat, td->remainder); @@ -282,10 +279,8 @@ uss820dci_setup_rx(struct uss820dci_td * 0xFF ^ USS820_RXSTAT_EDOVW, 0); /* get the packet byte count */ - count = bus_space_read_1(td->io_tag, td->io_hdl, - USS820_RXCNTL); - count |= (bus_space_read_1(td->io_tag, td->io_hdl, - USS820_RXCNTH) << 8); + count = USS820_READ_1(sc, USS820_RXCNTL); + count |= (USS820_READ_1(sc, USS820_RXCNTH) << 8); count &= 0x3FF; /* verify data length */ @@ -300,12 +295,11 @@ uss820dci_setup_rx(struct uss820dci_td * goto setup_not_complete; } /* receive data */ - bus_space_read_multi_1(td->io_tag, td->io_hdl, - USS820_RXDAT, (void *)&req, sizeof(req)); + bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl, + USS820_RXDAT * USS820_REG_STRIDE, (void *)&req, sizeof(req)); /* read out FIFO status */ - rx_stat = bus_space_read_1(td->io_tag, td->io_hdl, - USS820_RXSTAT); + rx_stat = USS820_READ_1(sc, USS820_RXSTAT); if (rx_stat & (USS820_RXSTAT_EDOVW | USS820_RXSTAT_STOVW)) { @@ -319,11 +313,9 @@ uss820dci_setup_rx(struct uss820dci_td * USS820_RXSTAT_STOVW), 0); /* set RXFFRC bit */ - temp = bus_space_read_1(td->io_tag, td->io_hdl, - USS820_RXCON); + temp = USS820_READ_1(sc, USS820_RXCON); temp |= USS820_RXCON_RXFFRC; - bus_space_write_1(td->io_tag, td->io_hdl, - USS820_RXCON, temp); + USS820_WRITE_1(sc, USS820_RXCON, temp); /* copy data into real buffer */ usbd_copy_in(td->pc, 0, &req, sizeof(req)); @@ -351,11 +343,9 @@ uss820dci_setup_rx(struct uss820dci_td * setup_not_complete: /* set RXFFRC bit */ - temp = bus_space_read_1(td->io_tag, td->io_hdl, - USS820_RXCON); + temp = USS820_READ_1(sc, USS820_RXCON); temp |= USS820_RXCON_RXFFRC; - bus_space_write_1(td->io_tag, td->io_hdl, - USS820_RXCON, temp); + USS820_WRITE_1(sc, USS820_RXCON, temp); /* FALLTHROUGH */ @@ -378,11 +368,10 @@ not_complete: USS820_RXSTAT_RXSETUP), 0); } return (1); /* not complete */ - } static uint8_t -uss820dci_data_rx(struct uss820dci_td *td) +uss820dci_data_rx(struct uss820dci_softc *sc, struct uss820dci_td *td) { struct usb_page_search buf_res; uint16_t count; @@ -396,16 +385,14 @@ uss820dci_data_rx(struct uss820dci_td *t got_short = 0; /* select the correct endpoint */ - bus_space_write_1(td->io_tag, td->io_hdl, USS820_EPINDEX, td->ep_index); + USS820_WRITE_1(sc, USS820_EPINDEX, td->ep_index); /* check if any of the FIFO banks have data */ repeat: /* read out FIFO flag */ - rx_flag = bus_space_read_1(td->io_tag, td->io_hdl, - USS820_RXFLG); + rx_flag = USS820_READ_1(sc, USS820_RXFLG); /* read out FIFO status */ - rx_stat = bus_space_read_1(td->io_tag, td->io_hdl, - USS820_RXSTAT); + rx_stat = USS820_READ_1(sc, USS820_RXSTAT); DPRINTFN(5, "rx_stat=0x%02x rx_flag=0x%02x rem=%u\n", rx_stat, rx_flag, td->remainder); @@ -449,11 +436,8 @@ repeat: return (1); /* not complete */ } /* get the packet byte count */ - count = bus_space_read_1(td->io_tag, td->io_hdl, - USS820_RXCNTL); - - count |= (bus_space_read_1(td->io_tag, td->io_hdl, - USS820_RXCNTH) << 8); + count = USS820_READ_1(sc, USS820_RXCNTL); + count |= (USS820_READ_1(sc, USS820_RXCNTH) << 8); count &= 0x3FF; DPRINTFN(5, "count=0x%04x\n", count); @@ -484,8 +468,8 @@ repeat: buf_res.length = count; } /* receive data */ - bus_space_read_multi_1(td->io_tag, td->io_hdl, - USS820_RXDAT, buf_res.buffer, buf_res.length); + bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl, + USS820_RXDAT * USS820_REG_STRIDE, buf_res.buffer, buf_res.length); /* update counters */ count -= buf_res.length; @@ -494,11 +478,9 @@ repeat: } /* set RXFFRC bit */ - rx_cntl = bus_space_read_1(td->io_tag, td->io_hdl, - USS820_RXCON); + rx_cntl = USS820_READ_1(sc, USS820_RXCON); rx_cntl |= USS820_RXCON_RXFFRC; - bus_space_write_1(td->io_tag, td->io_hdl, - USS820_RXCON, rx_cntl); + USS820_WRITE_1(sc, USS820_RXCON, rx_cntl); /* check if we are complete */ if ((td->remainder == 0) || got_short) { @@ -515,7 +497,7 @@ repeat: } static uint8_t -uss820dci_data_tx(struct uss820dci_td *td) +uss820dci_data_tx(struct uss820dci_softc *sc, struct uss820dci_td *td) { struct usb_page_search buf_res; uint16_t count; @@ -525,19 +507,16 @@ uss820dci_data_tx(struct uss820dci_td *t uint8_t to; /* select the correct endpoint */ - bus_space_write_1(td->io_tag, td->io_hdl, - USS820_EPINDEX, td->ep_index); + USS820_WRITE_1(sc, USS820_EPINDEX, td->ep_index); to = 2; /* don't loop forever! */ repeat: /* read out TX FIFO flags */ - tx_flag = bus_space_read_1(td->io_tag, td->io_hdl, - USS820_TXFLG); + tx_flag = USS820_READ_1(sc, USS820_TXFLG); /* read out RX FIFO status last */ - rx_stat = bus_space_read_1(td->io_tag, td->io_hdl, - USS820_RXSTAT); + rx_stat = USS820_READ_1(sc, USS820_RXSTAT); DPRINTFN(5, "rx_stat=0x%02x tx_flag=0x%02x rem=%u\n", rx_stat, tx_flag, td->remainder); @@ -583,8 +562,8 @@ repeat: buf_res.length = count; } /* transmit data */ - bus_space_write_multi_1(td->io_tag, td->io_hdl, - USS820_TXDAT, buf_res.buffer, buf_res.length); + bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl, + USS820_TXDAT * USS820_REG_STRIDE, buf_res.buffer, buf_res.length); /* update counters */ count -= buf_res.length; @@ -593,12 +572,10 @@ repeat: } /* post-write high packet byte count first */ - bus_space_write_1(td->io_tag, td->io_hdl, - USS820_TXCNTH, count_copy >> 8); + USS820_WRITE_1(sc, USS820_TXCNTH, count_copy >> 8); /* post-write low packet byte count last */ - bus_space_write_1(td->io_tag, td->io_hdl, - USS820_TXCNTL, count_copy); + USS820_WRITE_1(sc, USS820_TXCNTL, count_copy); /* * Enable TX output, which must happen after that we have written @@ -623,23 +600,19 @@ repeat: } static uint8_t -uss820dci_data_tx_sync(struct uss820dci_td *td) +uss820dci_data_tx_sync(struct uss820dci_softc *sc, struct uss820dci_td *td) { - struct uss820dci_softc *sc; uint8_t rx_stat; uint8_t tx_flag; /* select the correct endpoint */ - bus_space_write_1(td->io_tag, td->io_hdl, - USS820_EPINDEX, td->ep_index); + USS820_WRITE_1(sc, USS820_EPINDEX, td->ep_index); /* read out TX FIFO flag */ - tx_flag = bus_space_read_1(td->io_tag, td->io_hdl, - USS820_TXFLG); + tx_flag = USS820_READ_1(sc, USS820_TXFLG); /* read out RX FIFO status last */ - rx_stat = bus_space_read_1(td->io_tag, td->io_hdl, - USS820_RXSTAT); + rx_stat = USS820_READ_1(sc, USS820_RXSTAT); DPRINTFN(5, "rx_stat=0x%02x rem=%u\n", rx_stat, td->remainder); @@ -662,7 +635,6 @@ uss820dci_data_tx_sync(struct uss820dci_ USS820_TXFLG_TXFIF1)) { return (1); /* not complete */ } - sc = USS820_DCI_PC2SC(td->pc); if (sc->sc_dv_addr != 0xFF) { /* write function address */ uss820dci_set_address(sc, sc->sc_dv_addr); @@ -670,16 +642,20 @@ uss820dci_data_tx_sync(struct uss820dci_ return (0); /* complete */ } -static uint8_t +static void uss820dci_xfer_do_fifo(struct usb_xfer *xfer) { + struct uss820dci_softc *sc = USS820_DCI_BUS2SC(xfer->xroot->bus); struct uss820dci_td *td; DPRINTFN(9, "\n"); td = xfer->td_transfer_cache; + if (td == NULL) + return; + while (1) { - if ((td->func) (td)) { + if ((td->func) (sc, td)) { /* operation in progress */ break; } @@ -703,27 +679,47 @@ uss820dci_xfer_do_fifo(struct usb_xfer * td = td->obj_next; xfer->td_transfer_cache = td; } - return (1); /* not complete */ + return; done: /* compute all actual lengths */ + xfer->td_transfer_cache = NULL; + sc->sc_xfer_complete = 1; +} - uss820dci_standard_done(xfer); +static uint8_t +uss820dci_xfer_do_complete(struct usb_xfer *xfer) +{ + struct uss820dci_td *td; - return (0); /* complete */ + DPRINTFN(9, "\n"); + + td = xfer->td_transfer_cache; + if (td == NULL) { + /* compute all actual lengths */ + uss820dci_standard_done(xfer); + return(1); + } + return (0); } static void -uss820dci_interrupt_poll(struct uss820dci_softc *sc) +uss820dci_interrupt_poll_locked(struct uss820dci_softc *sc) { struct usb_xfer *xfer; + TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) + uss820dci_xfer_do_fifo(xfer); +} + +static void +uss820dci_interrupt_complete_locked(struct uss820dci_softc *sc) +{ + struct usb_xfer *xfer; repeat: TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { - if (!uss820dci_xfer_do_fifo(xfer)) { - /* queue has been modified */ + if (uss820dci_xfer_do_complete(xfer)) goto repeat; - } } } @@ -748,27 +744,51 @@ uss820dci_wait_suspend(struct uss820dci_ USS820_WRITE_1(sc, USS820_SCRATCH, scratch); } +int +uss820dci_filter_interrupt(void *arg) +{ + struct uss820dci_softc *sc = arg; + int retval = FILTER_HANDLED; + uint8_t ssr; + + USB_BUS_SPIN_LOCK(&sc->sc_bus); + + ssr = USS820_READ_1(sc, USS820_SSR); + uss820dci_update_shared_1(sc, USS820_SSR, USS820_DCI_THREAD_IRQ, 0); + + if (ssr & USS820_DCI_THREAD_IRQ) + retval = FILTER_SCHEDULE_THREAD; + + /* poll FIFOs, if any */ + uss820dci_interrupt_poll_locked(sc); + + if (sc->sc_xfer_complete != 0) + retval = FILTER_SCHEDULE_THREAD; + + USB_BUS_SPIN_UNLOCK(&sc->sc_bus); + + return (retval); +} + void -uss820dci_interrupt(struct uss820dci_softc *sc) +uss820dci_interrupt(void *arg) { + struct uss820dci_softc *sc = arg; uint8_t ssr; uint8_t event; USB_BUS_LOCK(&sc->sc_bus); + USB_BUS_SPIN_LOCK(&sc->sc_bus); ssr = USS820_READ_1(sc, USS820_SSR); - ssr &= (USS820_SSR_SUSPEND | - USS820_SSR_RESUME | - USS820_SSR_RESET); - /* acknowledge all interrupts */ - uss820dci_update_shared_1(sc, USS820_SSR, 0, 0); + uss820dci_update_shared_1(sc, USS820_SSR, ~USS820_DCI_THREAD_IRQ, 0); /* check for any bus state change interrupts */ - if (ssr) { + if (ssr & USS820_DCI_THREAD_IRQ) { event = 0; @@ -820,9 +840,13 @@ uss820dci_interrupt(struct uss820dci_sof /* acknowledge all SBI1 interrupts */ uss820dci_update_shared_1(sc, USS820_SBI1, 0, 0); - /* poll all active transfers */ - uss820dci_interrupt_poll(sc); + if (sc->sc_xfer_complete != 0) { + sc->sc_xfer_complete = 0; + /* complete FIFOs, if any */ + uss820dci_interrupt_complete_locked(sc); + } + USB_BUS_SPIN_UNLOCK(&sc->sc_bus); USB_BUS_UNLOCK(&sc->sc_bus); } @@ -1050,11 +1074,16 @@ uss820dci_intr_set(struct usb_xfer *xfer static void uss820dci_start_standard_chain(struct usb_xfer *xfer) { + struct uss820dci_softc *sc = USS820_DCI_BUS2SC(xfer->xroot->bus); + DPRINTFN(9, "\n"); + USB_BUS_SPIN_LOCK(&sc->sc_bus); + /* poll one time */ - if (uss820dci_xfer_do_fifo(xfer)) { + uss820dci_xfer_do_fifo(xfer); + if (uss820dci_xfer_do_complete(xfer) == 0) { /* * Only enable the endpoint interrupt when we are * actually waiting for data, hence we are dealing @@ -1071,6 +1100,7 @@ uss820dci_start_standard_chain(struct us &uss820dci_timeout, xfer->timeout); } } + USB_BUS_SPIN_UNLOCK(&sc->sc_bus); } static void @@ -1204,16 +1234,22 @@ done: static void uss820dci_device_done(struct usb_xfer *xfer, usb_error_t error) { + struct uss820dci_softc *sc = USS820_DCI_BUS2SC(xfer->xroot->bus); + USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); DPRINTFN(2, "xfer=%p, endpoint=%p, error=%d\n", xfer, xfer->endpoint, error); + USB_BUS_SPIN_LOCK(&sc->sc_bus); + if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) { uss820dci_intr_set(xfer, 0); } /* dequeue transfer and start next transfer */ usbd_transfer_done(xfer, error); + + USB_BUS_SPIN_UNLOCK(&sc->sc_bus); } static void @@ -1246,6 +1282,7 @@ uss820dci_set_stall(struct usb_device *u /* should not happen */ return; } + USB_BUS_SPIN_LOCK(&sc->sc_bus); USS820_WRITE_1(sc, USS820_EPINDEX, ep_no); if (ep_dir == UE_DIR_IN) { @@ -1254,6 +1291,7 @@ uss820dci_set_stall(struct usb_device *u temp = USS820_EPCON_RXSTL; } uss820dci_update_shared_1(sc, USS820_EPCON, 0xFF, temp); + USB_BUS_SPIN_UNLOCK(&sc->sc_bus); } static void @@ -1266,6 +1304,8 @@ uss820dci_clear_stall_sub(struct uss820d /* clearing stall is not needed */ return; } + USB_BUS_SPIN_LOCK(&sc->sc_bus); + /* select endpoint index */ USS820_WRITE_1(sc, USS820_EPINDEX, ep_no); @@ -1304,6 +1344,7 @@ uss820dci_clear_stall_sub(struct uss820d temp &= ~USS820_RXCON_RXCLR; USS820_WRITE_1(sc, USS820_RXCON, temp); } + USB_BUS_SPIN_UNLOCK(&sc->sc_bus); } static void @@ -1540,7 +1581,10 @@ uss820dci_do_poll(struct usb_bus *bus) struct uss820dci_softc *sc = USS820_DCI_BUS2SC(bus); USB_BUS_LOCK(&sc->sc_bus); - uss820dci_interrupt_poll(sc); + USB_BUS_SPIN_LOCK(&sc->sc_bus); + uss820dci_interrupt_poll_locked(sc); + uss820dci_interrupt_complete_locked(sc); + USB_BUS_SPIN_UNLOCK(&sc->sc_bus); USB_BUS_UNLOCK(&sc->sc_bus); } @@ -2304,8 +2348,6 @@ uss820dci_xfer_setup(struct usb_setup_pa td = USB_ADD_BYTES(parm->buf, parm->size[0]); /* init TD */ - td->io_tag = sc->sc_io_tag; - td->io_hdl = sc->sc_io_hdl; td->max_packet_size = xfer->max_packet_size; td->ep_index = ep_no; if (pf->support_multi_buffer && Modified: head/sys/dev/usb/controller/uss820dci.h ============================================================================== --- head/sys/dev/usb/controller/uss820dci.h Tue Aug 5 06:31:09 2014 (r269563) +++ head/sys/dev/usb/controller/uss820dci.h Tue Aug 5 06:33:59 2014 (r269564) @@ -255,19 +255,22 @@ #define USS820_UNK1 0x1f /* Unknown */ #define USS820_UNK1_UNKNOWN 0xFF +#ifndef USS820_REG_STRIDE +#define USS820_REG_STRIDE 1 +#endif + #define USS820_READ_1(sc, reg) \ - bus_space_read_1((sc)->sc_io_tag, (sc)->sc_io_hdl, reg) + bus_space_read_1((sc)->sc_io_tag, (sc)->sc_io_hdl, (reg) * USS820_REG_STRIDE) #define USS820_WRITE_1(sc, reg, data) \ - bus_space_write_1((sc)->sc_io_tag, (sc)->sc_io_hdl, reg, data) + bus_space_write_1((sc)->sc_io_tag, (sc)->sc_io_hdl, (reg) * USS820_REG_STRIDE, (data)) struct uss820dci_td; +struct uss820dci_softc; -typedef uint8_t (uss820dci_cmd_t)(struct uss820dci_td *td); +typedef uint8_t (uss820dci_cmd_t)(struct uss820dci_softc *, struct uss820dci_td *td); struct uss820dci_td { - bus_space_tag_t io_tag; - bus_space_handle_t io_hdl; struct uss820dci_td *obj_next; uss820dci_cmd_t *func; struct usb_page_cache *pc; @@ -336,6 +339,8 @@ struct uss820dci_softc { bus_space_tag_t sc_io_tag; bus_space_handle_t sc_io_hdl; + uint32_t sc_xfer_complete; + uint8_t sc_rt_addr; /* root HUB address */ uint8_t sc_dv_addr; /* device address */ uint8_t sc_conf; /* root HUB config */ @@ -349,6 +354,7 @@ struct uss820dci_softc { usb_error_t uss820dci_init(struct uss820dci_softc *sc); void uss820dci_uninit(struct uss820dci_softc *sc); -void uss820dci_interrupt(struct uss820dci_softc *sc); +driver_filter_t uss820dci_filter_interrupt; +driver_intr_t uss820dci_interrupt; #endif /* _USS820_DCI_H_ */ Modified: head/sys/dev/usb/controller/uss820dci_atmelarm.c ============================================================================== --- head/sys/dev/usb/controller/uss820dci_atmelarm.c Tue Aug 5 06:31:09 2014 (r269563) +++ head/sys/dev/usb/controller/uss820dci_atmelarm.c Tue Aug 5 06:33:59 2014 (r269564) @@ -136,13 +136,8 @@ uss820_atmelarm_attach(device_t dev) } device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); -#if (__FreeBSD_version >= 700031) - err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - NULL, (driver_intr_t *)uss820dci_interrupt, sc, &sc->sc_intr_hdl); -#else - err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - (driver_intr_t *)uss820dci_interrupt, sc, &sc->sc_intr_hdl); -#endif + err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_TTY | INTR_MPSAFE, + uss820dci_filter_interrupt, uss820dci_interrupt, sc, &sc->sc_intr_hdl); if (err) { sc->sc_intr_hdl = NULL; goto error;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?53e07ad8.5f3e.1a10c6a4>