]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Better estimate the maximum USB transfer size.
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Tue, 19 Mar 2013 07:17:51 +0000 (08:17 +0100)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Tue, 19 Mar 2013 07:17:51 +0000 (08:17 +0100)
ChangeLog
grub-core/bus/usb/ehci.c
grub-core/bus/usb/ohci.c
grub-core/bus/usb/uhci.c
grub-core/bus/usb/usbtrans.c
include/grub/usb.h

index ad84d27f757f7d67e0058db5f86883a3918a1f19..d331cb4ed8057271d2bf763c0020aebd7f6f21e2 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2013-03-19  Aleš Nesrsta  <starous@volny.cz>
+
+       Better estimate the maximum USB transfer size.
+
 2013-03-17  Vladimir Serbinenko  <phcoder@gmail.com>
 
        Resend a packet if we got the wrong buffer in status.
index 92158665a727b69e835de13a9e5f301b33ca848f..c60873d606a10f39a2e7c65410df7cb6ded32fcb 100644 (file)
@@ -1902,7 +1902,9 @@ static struct grub_usb_controller_dev usb_controller = {
   .cancel_transfer = grub_ehci_cancel_transfer,
   .hubports = grub_ehci_hubports,
   .portstatus = grub_ehci_portstatus,
-  .detect_dev = grub_ehci_detect_dev
+  .detect_dev = grub_ehci_detect_dev,
+  /* estimated max. count of TDs for one bulk transfer */
+  .max_bulk_tds = GRUB_EHCI_N_TD * 3 / 4 
 };
 
 GRUB_MOD_INIT (ehci)
index 835bb15b4de1d5ce769c83e4158f22907b499239..2f3fd91fbab1bd4782441b77025db4af923db453 100644 (file)
@@ -1431,7 +1431,9 @@ static struct grub_usb_controller_dev usb_controller =
   .cancel_transfer = grub_ohci_cancel_transfer,
   .hubports = grub_ohci_hubports,
   .portstatus = grub_ohci_portstatus,
-  .detect_dev = grub_ohci_detect_dev
+  .detect_dev = grub_ohci_detect_dev,
+  /* estimated max. count of TDs for one bulk transfer */
+  .max_bulk_tds = GRUB_OHCI_TDS * 3 / 4
 };
 
 static struct grub_preboot *fini_hnd;
index 74de392a7088d5746c0ecb696f579a752eb77eb6..3639c425805dbdcd0006e90fa97dd723780b6e15 100644 (file)
@@ -823,7 +823,9 @@ static struct grub_usb_controller_dev usb_controller =
   .cancel_transfer = grub_uhci_cancel_transfer,
   .hubports = grub_uhci_hubports,
   .portstatus = grub_uhci_portstatus,
-  .detect_dev = grub_uhci_detect_dev
+  .detect_dev = grub_uhci_detect_dev,
+  /* estimated max. count of TDs for one bulk transfer */
+  .max_bulk_tds = N_TD * 3 / 4
 };
 
 GRUB_MOD_INIT(uhci)
index 154c72d55f9ac33d8cba71ca31f88afcfeb80e55..4c4d8b4742f07528b9c011ae61ae9e7187f86c08 100644 (file)
 #include <grub/usbtrans.h>
 #include <grub/time.h>
 
+
+static inline unsigned int
+grub_usb_bulk_maxpacket (grub_usb_device_t dev, int endpoint)
+{
+  unsigned int max = 64;
+
+  /* Use the maximum packet size given in the endpoint descriptor.  */
+  if (dev->initialized)
+    {
+      struct grub_usb_desc_endp *endpdesc;
+      endpdesc = grub_usb_get_endpdescriptor (dev, endpoint);
+
+      if (endpdesc)
+       max = endpdesc->maxpacket;
+    }
+
+  return max;
+}
+
+
 static grub_usb_err_t
 grub_usb_execute_and_wait_transfer (grub_usb_device_t dev, 
                                    grub_usb_transfer_t transfer,
@@ -224,20 +244,6 @@ grub_usb_bulk_setup_readwrite (grub_usb_device_t dev,
   if (type == GRUB_USB_TRANSFER_TYPE_OUT)
     grub_memcpy ((char *) data, data_in, size);
 
-  /* Use the maximum packet size given in the endpoint descriptor.  */
-  if (dev->initialized)
-    {
-      struct grub_usb_desc_endp *endpdesc;
-      endpdesc = grub_usb_get_endpdescriptor (dev, endpoint);
-
-      if (endpdesc)
-       max = endpdesc->maxpacket;
-      else
-       max = 64;
-    }
-  else
-    max = 64;
-
   /* Create a transfer.  */
   transfer = grub_malloc (sizeof (struct grub_usb_transfer));
   if (! transfer)
@@ -246,6 +252,8 @@ grub_usb_bulk_setup_readwrite (grub_usb_device_t dev,
       return NULL;
     }
 
+  max = grub_usb_bulk_maxpacket (dev, endpoint);
+
   datablocks = ((size + max - 1) / max);
   transfer->transcnt = datablocks;
   transfer->size = size - 1;
@@ -333,38 +341,36 @@ grub_usb_bulk_readwrite (grub_usb_device_t dev,
   return err;
 }
 
-grub_usb_err_t
-grub_usb_bulk_write (grub_usb_device_t dev,
-                    int endpoint, grub_size_t size, char *data)
-{
-  grub_size_t actual;
-  grub_usb_err_t err;
-
-  err = grub_usb_bulk_readwrite (dev, endpoint, size, data,
-                                GRUB_USB_TRANSFER_TYPE_OUT, 1000, &actual);
-  if (!err && actual != size)
-    err = GRUB_USB_ERR_DATA;
-  return err;
-}
-
-grub_usb_err_t
-grub_usb_bulk_read (grub_usb_device_t dev,
-                   int endpoint, grub_size_t size, char *data)
+static grub_usb_err_t
+grub_usb_bulk_readwrite_packetize (grub_usb_device_t dev,
+                                  int endpoint,
+                                  grub_transfer_type_t type,
+                                  grub_size_t size, char *data)
 {
   grub_size_t actual, transferred;
   grub_usb_err_t err;
   grub_size_t current_size, position;
+  grub_size_t max_bulk_transfer_len = MAX_USB_TRANSFER_LEN;
+  grub_size_t max;
+
+  if (dev->controller.dev->max_bulk_tds)
+    {
+      max = grub_usb_bulk_maxpacket (dev, endpoint);
+
+      /* Calculate max. possible length of bulk transfer */
+      max_bulk_transfer_len = dev->controller.dev->max_bulk_tds * max;
+    }
 
   for (position = 0, transferred = 0;
-       position < size; position += MAX_USB_TRANSFER_LEN)
+       position < size; position += max_bulk_transfer_len)
     {
       current_size = size - position;
-      if (current_size >= MAX_USB_TRANSFER_LEN)
-       current_size = MAX_USB_TRANSFER_LEN;
+      if (current_size >= max_bulk_transfer_len)
+       current_size = max_bulk_transfer_len;
       err = grub_usb_bulk_readwrite (dev, endpoint, current_size,
-              &data[position], GRUB_USB_TRANSFER_TYPE_IN, 1000, &actual);
+              &data[position], type, 1000, &actual);
       transferred += actual;
-      if (err || (current_size != actual) ) break;
+      if (err || (current_size != actual)) break;
     }
 
   if (!err && transferred != size)
@@ -372,6 +378,24 @@ grub_usb_bulk_read (grub_usb_device_t dev,
   return err;
 }
 
+grub_usb_err_t
+grub_usb_bulk_write (grub_usb_device_t dev,
+                    int endpoint, grub_size_t size, char *data)
+{
+  return grub_usb_bulk_readwrite_packetize (dev, endpoint,
+                                           GRUB_USB_TRANSFER_TYPE_OUT,
+                                           size, data);
+}
+
+grub_usb_err_t
+grub_usb_bulk_read (grub_usb_device_t dev,
+                   int endpoint, grub_size_t size, char *data)
+{
+  return grub_usb_bulk_readwrite_packetize (dev, endpoint,
+                                           GRUB_USB_TRANSFER_TYPE_IN,
+                                           size, data);
+}
+
 grub_usb_err_t
 grub_usb_check_transfer (grub_usb_transfer_t transfer, grub_size_t *actual)
 {
index cefa8b6ff0886e9cb2faeff75a6654e7cf351dbe..55f65f77ed17fa09d8616cce405c18de0eff7ecf 100644 (file)
@@ -124,6 +124,13 @@ struct grub_usb_controller_dev
 
   /* Per controller flag - port reset pending, don't do another reset */
   grub_uint64_t pending_reset;
+
+  /* Max. number of transfer descriptors used per one bulk transfer */
+  /* The reason is to prevent "exhausting" of TD by large bulk */
+  /* transfer - number of TD is limited in USB host driver */
+  /* Value is calculated/estimated in driver - some TDs should be */
+  /* reserved for posible concurrent control or "interrupt" transfers */
+  grub_size_t max_bulk_tds;
   
   /* The next host controller.  */
   struct grub_usb_controller_dev *next;