[PATCH] dwc_otg: Reduce interrupt load
Sebastian Huber
sebastian.huber at embedded-brains.de
Fri Oct 30 13:47:30 UTC 2015
Tested on an Altera Cyclone V development kit. Here the controller has
16 host channels. This change significantly reduced the time spent in
the dwc_otg_interrupt_poll_locked() function.
---
sys/dev/usb/controller/dwc_otg.c | 21 ++++++++++++---------
sys/dev/usb/controller/dwc_otg.h | 1 +
2 files changed, 13 insertions(+), 9 deletions(-)
diff --git a/sys/dev/usb/controller/dwc_otg.c b/sys/dev/usb/controller/dwc_otg.c
index e018ab5..a57e064 100644
--- a/sys/dev/usb/controller/dwc_otg.c
+++ b/sys/dev/usb/controller/dwc_otg.c
@@ -270,8 +270,7 @@ dwc_otg_init_fifo(struct dwc_otg_softc *sc, uint8_t mode)
memset(sc->sc_chan_state, 0, sizeof(sc->sc_chan_state));
/* enable all host channel interrupts */
- DWC_OTG_WRITE_4(sc, DOTG_HAINTMSK,
- (1U << sc->sc_host_ch_max) - 1U);
+ DWC_OTG_WRITE_4(sc, DOTG_HAINTMSK, sc->sc_host_ch_mask);
}
if (mode == DWC_MODE_DEVICE) {
@@ -2559,7 +2558,8 @@ dwc_otg_interrupt_poll_locked(struct dwc_otg_softc *sc)
uint32_t count;
uint32_t temp;
uint8_t got_rx_status;
- uint8_t x;
+ uint32_t haint;
+ int x;
if (sc->sc_flags.status_device_mode == 0) {
/*
@@ -2576,13 +2576,14 @@ repeat:
return;
}
/* get all host channel interrupts */
- for (x = 0; x != sc->sc_host_ch_max; x++) {
+ haint = DWC_OTG_READ_4(sc, DOTG_HAINT) & sc->sc_host_ch_mask;
+ while (haint != 0) {
+ x = ffs((int)haint) - 1;
temp = DWC_OTG_READ_4(sc, DOTG_HCINT(x));
- if (temp != 0) {
- DWC_OTG_WRITE_4(sc, DOTG_HCINT(x), temp);
- temp &= ~HCINT_SOFTWARE_ONLY;
- sc->sc_chan_state[x].hcint |= temp;
- }
+ DWC_OTG_WRITE_4(sc, DOTG_HCINT(x), temp);
+ temp &= ~HCINT_SOFTWARE_ONLY;
+ sc->sc_chan_state[x].hcint |= temp;
+ haint &= ~(1U << x);
}
if (sc->sc_last_rx_status == 0) {
@@ -3845,6 +3846,8 @@ dwc_otg_init(struct dwc_otg_softc *sc)
if (sc->sc_host_ch_max > DWC_OTG_MAX_CHANNELS)
sc->sc_host_ch_max = DWC_OTG_MAX_CHANNELS;
+ sc->sc_host_ch_mask = (1U << sc->sc_host_ch_max) - 1U;
+
temp = DWC_OTG_READ_4(sc, DOTG_GHWCFG4);
sc->sc_dev_in_ep_max = GHWCFG4_NUM_IN_EP_GET(temp);
diff --git a/sys/dev/usb/controller/dwc_otg.h b/sys/dev/usb/controller/dwc_otg.h
index f5e9887..6882e40 100644
--- a/sys/dev/usb/controller/dwc_otg.h
+++ b/sys/dev/usb/controller/dwc_otg.h
@@ -185,6 +185,7 @@ struct dwc_otg_softc {
uint32_t sc_tmr_val;
uint32_t sc_hprt_val;
uint32_t sc_xfer_complete;
+ uint32_t sc_host_ch_mask;
uint16_t sc_active_rx_ep;
uint16_t sc_last_frame_num;
--
1.8.4.5
More information about the freebsd-usb
mailing list