Author: hselasky
Date: Wed Sep 12 07:34:09 2012
New Revision: 240381
URL: http://svn.freebsd.org/changeset/base/240381

Log:
  Reduce DWC OTG polling rate by using the SOF interrupt.

Modified:
  head/sys/dev/usb/controller/dwc_otg.c
  head/sys/dev/usb/controller/dwc_otg.h

Modified: head/sys/dev/usb/controller/dwc_otg.c
==============================================================================
--- head/sys/dev/usb/controller/dwc_otg.c       Wed Sep 12 04:29:11 2012        
(r240380)
+++ head/sys/dev/usb/controller/dwc_otg.c       Wed Sep 12 07:34:09 2012        
(r240381)
@@ -160,6 +160,23 @@ dwc_otg_get_hw_ep_profile(struct usb_dev
                *ppf = NULL;
 }
 
+static void
+dwc_otg_request_sof(struct dwc_otg_softc *sc)
+{
+       sc->sc_sof_refs++;
+       sc->sc_irq_mask |= GINTMSK_SOFMSK;
+       DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask);
+}
+
+static void
+dwc_otg_release_sof(struct dwc_otg_softc *sc)
+{
+       if (--(sc->sc_sof_refs) == 0) {
+               sc->sc_irq_mask &= ~GINTMSK_SOFMSK;
+               DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask);
+       }
+}
+
 static int
 dwc_otg_init_fifo(struct dwc_otg_softc *sc, uint8_t mode)
 {
@@ -523,6 +540,9 @@ dwc_otg_host_channel_alloc(struct dwc_ot
                        /* set active EP */
                        sc->sc_active_rx_ep |= (1 << x);
 
+                       /* request SOF's */
+                       dwc_otg_request_sof(sc);
+
                        return (0);     /* allocated */
                }
        }
@@ -576,6 +596,10 @@ dwc_otg_host_setup_tx(struct dwc_otg_td 
                        td->remainder -= td->tx_bytes;
                        td->toggle = 1;
                        return (0);     /* complete */
+               } else {
+                       if ((sc->sc_sof_val & 1) != (td->sof_val & 1))
+                               return (1);     /* busy */
+                       td->sof_val += 1;
                }
        } else {
                return (1);     /* busy */
@@ -882,12 +906,19 @@ not_complete:
                /* DATA 0 */
                td->toggle = 0;
        } else if (ep_type == UE_INTERRUPT) {
-               if ((sc->sc_interrupt_val & 0xFF) != td->sof_val)
+               if ((sc->sc_sof_val & 0xFF) != td->sof_val)
                        return (1);     /* busy */
                td->sof_val += td->sof_res;
-       } else if (td->set_toggle) {
-               td->set_toggle = 0;
-               td->toggle = 1;
+       } else {
+               if (td->did_nak) {
+                       if ((sc->sc_sof_val & 1) != (td->sof_val & 1))
+                               return (1);     /* busy */
+                       td->sof_val += 1;
+               }
+               if (td->set_toggle) {
+                       td->set_toggle = 0;
+                       td->toggle = 1;
+               }
        }
 
        /* receive one packet */
@@ -1078,7 +1109,11 @@ dwc_otg_host_data_tx(struct dwc_otg_td *
 
                                /* else we need to transmit a short packet */
                        }
-               }
+               } else {
+                       if ((sc->sc_sof_val & 1) != (td->sof_val & 1))
+                               return (1);     /* busy */
+                       td->sof_val += 1;
+               }
        } else {
                return (1);     /* busy */
        }
@@ -1098,7 +1133,7 @@ dwc_otg_host_data_tx(struct dwc_otg_td *
                td->toggle = 0;
 
        } else if (ep_type == UE_INTERRUPT) {
-               if ((sc->sc_interrupt_val & 0xFF) != td->sof_val)
+               if ((sc->sc_sof_val & 0xFF) != td->sof_val)
                        return (1);     /* busy */
                td->sof_val += td->sof_res;
        } else if (td->set_toggle) {
@@ -1775,21 +1810,8 @@ dwc_otg_interrupt(struct dwc_otg_softc *
        }
 
        /* check for Start Of Frame IRQ */
-       if (status & GINTMSK_SOFMSK) {
-
-               uint32_t temp;
-
-               temp = DWC_OTG_READ_4(sc, DOTG_HFNUM);
-               temp &= HFNUM_FRNUM_MASK;
-
-               if (sc->sc_flags.status_high_speed) {
-                       if ((temp & 7) == (sc->sc_sof_val & 7))
-                               sc->sc_sof_val++;
-               } else {
-                       if ((temp & 1) == (sc->sc_sof_val & 1))
-                               sc->sc_sof_val++;
-               }
-       }
+       if (status & GINTMSK_SOFMSK)
+               sc->sc_sof_val++;
 
        /* poll FIFO(s) */
        dwc_otg_interrupt_poll(sc);
@@ -2058,6 +2080,16 @@ dwc_otg_setup_standard_chain(struct usb_
                        } else {
                                td->hcsplt = 0;
                        }
+                       if (xfer_type == UE_INTERRUPT) {
+                               uint32_t ival;
+                               ival = xfer->interval;
+                               if (ival == 0)
+                                       ival = 1;
+                               else if (ival > 255)
+                                       ival = 255;
+                               td->sof_val = sc->sc_sof_val + ival;
+                               td->sof_res = ival;
+                       }
                        break;
                case USB_SPEED_HIGH:
                        td->hcsplt = 0;
@@ -2066,6 +2098,16 @@ dwc_otg_setup_standard_chain(struct usb_
                                td->hcchar |= ((xfer->max_packet_count & 3)
                                    << HCCHAR_MC_SHIFT);
                        }
+                       if (xfer_type == UE_INTERRUPT) {
+                               uint32_t ival;
+                               ival = xfer->interval * 8;
+                               if (ival == 0)
+                                       ival = 1;
+                               else if (ival > 255)
+                                       ival = 255;
+                               td->sof_val = sc->sc_sof_val + ival;
+                               td->sof_res = ival;
+                       }
                        break;
                default:
                        td->hcsplt = 0;
@@ -2075,9 +2117,9 @@ dwc_otg_setup_standard_chain(struct usb_
                if (xfer_type == UE_ISOCHRONOUS) {
                        td->sof_val = xfer->endpoint->isoc_next & 0xFF;
                        td->sof_res = 1 << usbd_xfer_get_fps_shift(xfer);
-               } else if (xfer_type == UE_INTERRUPT) {
-                       td->sof_val = sc->sc_interrupt_val;
-                       td->sof_res = 0;        /* TODO */
+               } else if (xfer_type != UE_INTERRUPT) {
+                       td->sof_val = sc->sc_sof_val + 1;
+                       td->sof_res = 1;
                }
        }
 }
@@ -2269,6 +2311,9 @@ dwc_otg_device_done(struct usb_xfer *xfe
                        sc->sc_active_rx_ep &= ~(1 << td->channel);
 
                        td->channel = DWC_OTG_MAX_CHANNELS;
+
+                       /* release SOF's */
+                       dwc_otg_release_sof(sc);
                }
        }
        /* dequeue transfer and start next transfer */
@@ -2742,32 +2787,22 @@ struct usb_pipe_methods dwc_otg_device_n
 static void
 dwc_otg_device_isoc_open(struct usb_xfer *xfer)
 {
-       struct dwc_otg_softc *sc = DWC_OTG_BUS2SC(xfer->xroot->bus);
-
        if (xfer->xroot->udev->flags.usb_mode == USB_MODE_HOST) {
-               xfer->qh_pos = 1;
-               sc->sc_sof_refs++;
-               sc->sc_irq_mask |= GINTMSK_SOFMSK;
-               DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask);
+               struct dwc_otg_softc *sc = DWC_OTG_BUS2SC(xfer->xroot->bus);
 
-               usb_hs_bandwidth_alloc(xfer);
+               xfer->qh_pos = 1;
+               dwc_otg_request_sof(sc);
        }
 }
 
 static void
 dwc_otg_device_isoc_close(struct usb_xfer *xfer)
 {
-       struct dwc_otg_softc *sc = DWC_OTG_BUS2SC(xfer->xroot->bus);
-
        if (xfer->qh_pos != 0) {
+               struct dwc_otg_softc *sc = DWC_OTG_BUS2SC(xfer->xroot->bus);
+
                xfer->qh_pos = 0;
-               if (--(sc->sc_sof_refs) == 0) {
-                       sc->sc_irq_mask &= ~GINTMSK_SOFMSK;
-                       DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask);
-               }
-       }
-       if (xfer->xroot->udev->flags.usb_mode == USB_MODE_HOST) {
-               usb_hs_bandwidth_free(xfer);
+               dwc_otg_release_sof(sc);
        }
        dwc_otg_device_done(xfer, USB_ERR_CANCELLED);
 }

Modified: head/sys/dev/usb/controller/dwc_otg.h
==============================================================================
--- head/sys/dev/usb/controller/dwc_otg.h       Wed Sep 12 04:29:11 2012        
(r240380)
+++ head/sys/dev/usb/controller/dwc_otg.h       Wed Sep 12 07:34:09 2012        
(r240381)
@@ -151,8 +151,6 @@ struct dwc_otg_softc {
        uint32_t sc_hcchar[DWC_OTG_MAX_CHANNELS];
        uint32_t sc_sof_refs;
        uint32_t sc_sof_val;
-       uint32_t sc_interrupt_refs;
-       uint32_t sc_interrupt_val;
        uint32_t sc_hprt_val;
 
        uint16_t sc_active_rx_ep;
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to