dwc_otg: make periodic scheduling behave properly for FS buses
authorP33M <p33m@github.com>
Thu, 25 May 2017 15:04:53 +0000 (16:04 +0100)
committerRaspbian kernel package updater <root@raspbian.org>
Sun, 8 Oct 2017 01:08:10 +0000 (01:08 +0000)
If the root port is in full-speed mode, transfer times at 12mbit/s
would be calculated but matched against high-speed quotas.

Reinitialise hcd->frame_usecs[i] on each port enable event so that
full-speed bandwidth can be tracked sensibly.

Also, don't bother using the FIQ for transfers when in full-speed
mode - at the slower bus speed, interrupt frequency is reduced by
an order of magnitude.

Related issue: https://github.com/raspberrypi/linux/issues/2020

drivers/usb/host/dwc_otg/dwc_otg_hcd.c
drivers/usb/host/dwc_otg/dwc_otg_hcd.h
drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c

index a2dc6337836b2719f4c954edeeb2a71301931b04..38bf5fc792d32352f9e208e0e90f968599b9bc31 100644 (file)
@@ -926,8 +926,6 @@ static void dwc_otg_hcd_free(dwc_otg_hcd_t * dwc_otg_hcd)
        DWC_FREE(dwc_otg_hcd);
 }
 
-int init_hcd_usecs(dwc_otg_hcd_t *_hcd);
-
 int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if)
 {
        struct device *dev = dwc_otg_hcd_to_dev(hcd);
@@ -1429,6 +1427,7 @@ static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
 
 /**
  * fiq_fsm_transaction_suitable() - Test a QH for compatibility with the FIQ
+ * @hcd:       Pointer to the dwc_otg_hcd struct
  * @qh:        pointer to the endpoint's queue head
  *
  * Transaction start/end control flow is grafted onto the existing dwc_otg
@@ -1438,8 +1437,14 @@ static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
  * Returns: 0 for unsuitable, 1 implies the FIQ can be enabled for this transaction.
  */
 
-int fiq_fsm_transaction_suitable(dwc_otg_qh_t *qh)
+int fiq_fsm_transaction_suitable(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
 {
+       /* There is little benefit in using the FIQ to perform transfers if
+        * the root port is not in high-speed mode.
+        */
+       if (hcd->flags.b.port_speed != DWC_HPRT0_PRTSPD_HIGH_SPEED)
+               return 0;
+
        if (qh->do_split) {
                switch (qh->ep_type) {
                case UE_CONTROL:
@@ -2218,7 +2223,7 @@ static void process_periodic_channels(dwc_otg_hcd_t * hcd)
                        continue;
                }
 
-               if (fiq_fsm_enable && fiq_fsm_transaction_suitable(qh)) {
+               if (fiq_fsm_enable && fiq_fsm_transaction_suitable(hcd, qh)) {
                        if (qh->do_split)
                                fiq_fsm_queue_split_transaction(hcd, qh);
                        else
@@ -2355,7 +2360,7 @@ static void process_non_periodic_channels(dwc_otg_hcd_t * hcd)
                qh = DWC_LIST_ENTRY(hcd->non_periodic_qh_ptr, dwc_otg_qh_t,
                                    qh_list_entry);
 
-               if(fiq_fsm_enable && fiq_fsm_transaction_suitable(qh)) {
+               if(fiq_fsm_enable && fiq_fsm_transaction_suitable(hcd, qh)) {
                        fiq_fsm_queue_split_transaction(hcd, qh);
                } else {
                        status = queue_transaction(hcd, qh->channel,
index 7f7e9eaffd6a3c3d898855562fbec11289f77f53..5ed8dccf03959a610849aa6c8946ca745dbae207 100644 (file)
@@ -410,7 +410,8 @@ struct dwc_otg_hcd {
                        unsigned port_suspend_change:1;
                        unsigned port_over_current_change:1;
                        unsigned port_l1_change:1;
-                       unsigned reserved:26;
+                       unsigned port_speed:2;
+                       unsigned reserved:24;
                } b;
        } flags;
 
@@ -629,7 +630,7 @@ int dwc_otg_hcd_allocate_port(dwc_otg_hcd_t * hcd, dwc_otg_qh_t *qh);
 void dwc_otg_hcd_release_port(dwc_otg_hcd_t * dwc_otg_hcd, dwc_otg_qh_t *qh);
 
 extern int fiq_fsm_queue_transaction(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh);
-extern int fiq_fsm_transaction_suitable(dwc_otg_qh_t *qh);
+extern int fiq_fsm_transaction_suitable(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh);
 extern void dwc_otg_cleanup_fiq_channel(dwc_otg_hcd_t *hcd, uint32_t num);
 
 /** @} */
@@ -823,6 +824,8 @@ static inline uint16_t dwc_micro_frame_num(uint16_t frame)
        return frame & 0x7;
 }
 
+extern void init_hcd_usecs(dwc_otg_hcd_t *_hcd);
+
 void dwc_otg_hcd_save_data_toggle(dwc_hc_t * hc,
                                  dwc_otg_hc_regs_t * hc_regs,
                                  dwc_otg_qtd_t * qtd);
index a4355afc77b68718fdaba6c5d4be257dadc75036..c8f52709a7d24974c0a38dcf1708f91073e96b0e 100644 (file)
@@ -515,6 +515,10 @@ int32_t dwc_otg_hcd_handle_port_intr(dwc_otg_hcd_t * dwc_otg_hcd)
                        dwc_otg_host_if_t *host_if =
                            dwc_otg_hcd->core_if->host_if;
 
+                       dwc_otg_hcd->flags.b.port_speed = hprt0.b.prtspd;
+                       if (microframe_schedule)
+                               init_hcd_usecs(dwc_otg_hcd);
+
                        /* Every time when port enables calculate
                         * HFIR.FrInterval
                         */
index 85a6d431ca54b47dc10573aa72d1ad69d06f2e36..4b1dd9de99e9e08b2e006fb5f8a7ef92f20c2553 100644 (file)
@@ -408,13 +408,17 @@ const unsigned short max_uframe_usecs[]={ 100, 100, 100, 100, 100, 100, 30, 0 };
 /*
  * called from dwc_otg_hcd.c:dwc_otg_hcd_init
  */
-int init_hcd_usecs(dwc_otg_hcd_t *_hcd)
+void init_hcd_usecs(dwc_otg_hcd_t *_hcd)
 {
        int i;
-       for (i=0; i<8; i++) {
-               _hcd->frame_usecs[i] = max_uframe_usecs[i];
+       if (_hcd->flags.b.port_speed == DWC_HPRT0_PRTSPD_FULL_SPEED) {
+               _hcd->frame_usecs[0] = 900;
+               for (i = 1; i < 8; i++)
+                       _hcd->frame_usecs[i] = 0;
+       } else {
+               for (i = 0; i < 8; i++)
+                       _hcd->frame_usecs[i] = max_uframe_usecs[i];
        }
-       return 0;
 }
 
 static int find_single_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh)
@@ -541,8 +545,9 @@ static int find_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh)
        int ret;
        ret = -1;
 
-       if (_qh->speed == USB_SPEED_HIGH) {
-               /* if this is a hs transaction we need a full frame */
+       if (_qh->speed == USB_SPEED_HIGH ||
+               _hcd->flags.b.port_speed == DWC_HPRT0_PRTSPD_FULL_SPEED) {
+               /* if this is a hs transaction we need a full frame - or account for FS usecs */
                ret = find_single_uframe(_hcd, _qh);
        } else {
                /* if this is a fs transaction we may need a sequence of frames */
@@ -627,7 +632,7 @@ static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
        if (status) {
                DWC_INFO("%s: Insufficient periodic bandwidth for "
                            "periodic transfer.\n", __func__);
-               return status;
+               return -DWC_E_NO_SPACE;
        }
        status = check_max_xfer_size(hcd, qh);
        if (status) {