From 45b13f9d1572538ea6dc89017767abb9676e9426 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Tue, 19 Mar 2013 08:17:51 +0100 Subject: [PATCH 211/471] Better estimate the maximum USB transfer size. --- ChangeLog | 4 ++ grub-core/bus/usb/ehci.c | 4 +- grub-core/bus/usb/ohci.c | 4 +- grub-core/bus/usb/uhci.c | 4 +- grub-core/bus/usb/usbtrans.c | 96 +++++++++++++++++++++++++++----------------- include/grub/usb.h | 7 ++++ 6 files changed, 80 insertions(+), 39 deletions(-) diff --git a/ChangeLog b/ChangeLog index ad84d27..d331cb4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2013-03-19 Aleš Nesrsta + + Better estimate the maximum USB transfer size. + 2013-03-17 Vladimir Serbinenko Resend a packet if we got the wrong buffer in status. diff --git a/grub-core/bus/usb/ehci.c b/grub-core/bus/usb/ehci.c index 9215866..c60873d 100644 --- a/grub-core/bus/usb/ehci.c +++ b/grub-core/bus/usb/ehci.c @@ -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) diff --git a/grub-core/bus/usb/ohci.c b/grub-core/bus/usb/ohci.c index 835bb15..2f3fd91 100644 --- a/grub-core/bus/usb/ohci.c +++ b/grub-core/bus/usb/ohci.c @@ -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; diff --git a/grub-core/bus/usb/uhci.c b/grub-core/bus/usb/uhci.c index 74de392..3639c42 100644 --- a/grub-core/bus/usb/uhci.c +++ b/grub-core/bus/usb/uhci.c @@ -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) diff --git a/grub-core/bus/usb/usbtrans.c b/grub-core/bus/usb/usbtrans.c index 154c72d..4c4d8b4 100644 --- a/grub-core/bus/usb/usbtrans.c +++ b/grub-core/bus/usb/usbtrans.c @@ -25,6 +25,26 @@ #include #include + +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) @@ -373,6 +379,24 @@ grub_usb_bulk_read (grub_usb_device_t dev, } 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) { grub_usb_err_t err; diff --git a/include/grub/usb.h b/include/grub/usb.h index cefa8b6..55f65f7 100644 --- a/include/grub/usb.h +++ b/include/grub/usb.h @@ -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; -- 1.8.2.1