From 4fb127898e46f0adf9fcca3cfae0987975ef34ec Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Mon, 9 Dec 2013 16:20:13 +0100 Subject: [PATCH 1/7] dfu: Export allocated dfu buffer size The method for exporting size of allocated buffer is provided. It is afterwards used by USB's dfu function code. Signed-off-by: Lukasz Majewski --- drivers/dfu/dfu.c | 5 +++++ include/dfu.h | 1 + 2 files changed, 6 insertions(+) diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c index 1eb92e54176..07011e99a85 100644 --- a/drivers/dfu/dfu.c +++ b/drivers/dfu/dfu.c @@ -74,6 +74,11 @@ unsigned char *dfu_free_buf(void) return dfu_buf; } +unsigned long dfu_get_buf_size(void) +{ + return dfu_buf_size; +} + unsigned char *dfu_get_buf(void) { char *s; diff --git a/include/dfu.h b/include/dfu.h index cc140449271..9a50721104c 100644 --- a/include/dfu.h +++ b/include/dfu.h @@ -131,6 +131,7 @@ bool dfu_reset(void); int dfu_init_env_entities(char *interface, int dev); unsigned char *dfu_get_buf(void); unsigned char *dfu_free_buf(void); +unsigned long dfu_get_buf_size(void); int dfu_read(struct dfu_entity *de, void *buf, int size, int blk_seq_num); int dfu_write(struct dfu_entity *de, void *buf, int size, int blk_seq_num); From 33fac4a6a23b595a2a3cdfa76eddde98d48947b4 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Mon, 9 Dec 2013 16:20:14 +0100 Subject: [PATCH 2/7] usb: dfu: f_dfu: Provide infrastructure to adjust DFU's Poll Timeout value It is necessary to deter the host from sending subsequent DFU_GETSTATUS request in the case of e.g. writing the buffer to medium. Here the timeout is increased when we fill up the whole buffer. This delay allows eMMC memory to perform its internal operations. Otherwise we end up with HOST's error regarding GET_STATUS receive timeout. Signed-off-by: Lukasz Majewski --- drivers/usb/gadget/f_dfu.c | 39 +++++++++++++++++++++++++++++++++++--- drivers/usb/gadget/f_dfu.h | 2 ++ include/dfu.h | 3 +++ 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/f_dfu.c b/drivers/usb/gadget/f_dfu.c index 37d04a19285..b4b4aa4f5b2 100644 --- a/drivers/usb/gadget/f_dfu.c +++ b/drivers/usb/gadget/f_dfu.c @@ -40,6 +40,7 @@ struct f_dfu { /* Send/received block number is handy for data integrity check */ int blk_seq_num; + unsigned int poll_timeout; }; typedef int (*dfu_state_fn) (struct f_dfu *, @@ -128,6 +129,33 @@ static struct usb_gadget_strings *dfu_strings[] = { NULL, }; +static void dfu_set_poll_timeout(struct dfu_status *dstat, unsigned int ms) +{ + /* + * The bwPollTimeout DFU_GETSTATUS request payload provides information + * about minimum time, in milliseconds, that the host should wait before + * sending a subsequent DFU_GETSTATUS request + * + * This permits the device to vary the delay depending on its need to + * erase or program the memory + * + */ + + unsigned char *p = (unsigned char *)&ms; + + if (!ms || (ms & ~DFU_POLL_TIMEOUT_MASK)) { + dstat->bwPollTimeout[0] = 0; + dstat->bwPollTimeout[1] = 0; + dstat->bwPollTimeout[2] = 0; + + return; + } + + dstat->bwPollTimeout[0] = *p++; + dstat->bwPollTimeout[1] = *p++; + dstat->bwPollTimeout[2] = *p; +} + /*-------------------------------------------------------------------------*/ static void dnload_request_complete(struct usb_ep *ep, struct usb_request *req) @@ -157,11 +185,15 @@ static void handle_getstatus(struct usb_request *req) break; } + dfu_set_poll_timeout(dstat, 0); + + if (f_dfu->poll_timeout) + if (!(f_dfu->blk_seq_num % + (dfu_get_buf_size() / DFU_USB_BUFSIZ))) + dfu_set_poll_timeout(dstat, f_dfu->poll_timeout); + /* send status response */ dstat->bStatus = f_dfu->dfu_status; - dstat->bwPollTimeout[0] = 0; - dstat->bwPollTimeout[1] = 0; - dstat->bwPollTimeout[2] = 0; dstat->bState = f_dfu->dfu_state; dstat->iString = 0; } @@ -725,6 +757,7 @@ static int dfu_bind_config(struct usb_configuration *c) f_dfu->usb_function.disable = dfu_disable; f_dfu->usb_function.strings = dfu_generic_strings, f_dfu->usb_function.setup = dfu_handle, + f_dfu->poll_timeout = DFU_DEFAULT_POLL_TIMEOUT; status = usb_add_function(c, &f_dfu->usb_function); if (status) diff --git a/drivers/usb/gadget/f_dfu.h b/drivers/usb/gadget/f_dfu.h index cc2c45567b6..0c29954add7 100644 --- a/drivers/usb/gadget/f_dfu.h +++ b/drivers/usb/gadget/f_dfu.h @@ -82,4 +82,6 @@ struct dfu_function_descriptor { __le16 wTransferSize; __le16 bcdDFUVersion; } __packed; + +#define DFU_POLL_TIMEOUT_MASK (0xFFFFFFUL) #endif /* __F_DFU_H_ */ diff --git a/include/dfu.h b/include/dfu.h index 9a50721104c..f973426aa90 100644 --- a/include/dfu.h +++ b/include/dfu.h @@ -77,6 +77,9 @@ static inline unsigned int get_mmc_blk_size(int dev) #ifndef CONFIG_SYS_DFU_MAX_FILE_SIZE #define CONFIG_SYS_DFU_MAX_FILE_SIZE CONFIG_SYS_DFU_DATA_BUF_SIZE #endif +#ifndef DFU_DEFAULT_POLL_TIMEOUT +#define DFU_DEFAULT_POLL_TIMEOUT 0 +#endif struct dfu_entity { char name[DFU_NAME_SIZE]; From 77b95042889c958c0da5a96a093aeb5a605ea3b4 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Mon, 9 Dec 2013 16:20:15 +0100 Subject: [PATCH 3/7] usb: f_dfu: cosmetic: Code cleanup Code cleanup for dfu_bind_config function Signed-off-by: Lukasz Majewski --- drivers/usb/gadget/f_dfu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/f_dfu.c b/drivers/usb/gadget/f_dfu.c index b4b4aa4f5b2..a045864d730 100644 --- a/drivers/usb/gadget/f_dfu.c +++ b/drivers/usb/gadget/f_dfu.c @@ -755,8 +755,8 @@ static int dfu_bind_config(struct usb_configuration *c) f_dfu->usb_function.unbind = dfu_unbind; f_dfu->usb_function.set_alt = dfu_set_alt; f_dfu->usb_function.disable = dfu_disable; - f_dfu->usb_function.strings = dfu_generic_strings, - f_dfu->usb_function.setup = dfu_handle, + f_dfu->usb_function.strings = dfu_generic_strings; + f_dfu->usb_function.setup = dfu_handle; f_dfu->poll_timeout = DFU_DEFAULT_POLL_TIMEOUT; status = usb_add_function(c, &f_dfu->usb_function); From 3990994c43e3abb05c0127d19ef67d7abde3c1b7 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Mon, 9 Dec 2013 16:20:16 +0100 Subject: [PATCH 4/7] ARM: trats: dfu: Enable default Poll Timeout for Trats board Provide default Poll Timeout value for Trats board. Signed-off-by: Lukasz Majewski --- include/configs/trats.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/configs/trats.h b/include/configs/trats.h index 08771422ec4..6cd15c25bdb 100644 --- a/include/configs/trats.h +++ b/include/configs/trats.h @@ -99,6 +99,7 @@ #define CONFIG_THOR_FUNCTION #define CONFIG_SYS_DFU_DATA_BUF_SIZE SZ_32M +#define DFU_DEFAULT_POLL_TIMEOUT 300 #define CONFIG_DFU_FUNCTION #define CONFIG_DFU_MMC From 8fb83547b93cd30a803eca1fec005b3d2b86a21f Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 13 Dec 2013 23:36:33 +0100 Subject: [PATCH 5/7] usb: ehci-pci: Clarify and cleanup the EHCI controller detection The detection function of the EHCI PCI controller was really cryptic, add a beefy comment and clean the portion of the code up a bit. No change in the logic of the code. Signed-off-by: Marek Vasut Cc: Simon Glass --- drivers/usb/host/ehci-pci.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 7a1ffe5e28b..991b19998b7 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -54,9 +54,31 @@ static pci_dev_t ehci_find_class(int index) bdf += PCI_BDF(0, 0, 1)) { pci_read_config_dword(bdf, PCI_CLASS_REVISION, &class); - if ((class >> 8 == PCI_CLASS_SERIAL_USB_EHCI) - && !index--) - return bdf; + class >>= 8; + /* + * Here be dragons! In case we have multiple + * PCI EHCI controllers, this function will + * be called multiple times as well. This + * function will scan the PCI busses, always + * starting from bus 0, device 0, function 0, + * until it finds an USB controller. The USB + * stack gives us an 'index' of a controller + * that is currently being registered, which + * is a number, starting from 0 and growing + * in ascending order as controllers are added. + * To avoid probing the same controller in tne + * subsequent runs of this function, we will + * skip 'index - 1' detected controllers and + * report the index'th controller. + */ + if (class != PCI_CLASS_SERIAL_USB_EHCI) + continue; + if (index) { + index--; + continue; + } + /* Return index'th controller. */ + return bdf; } } } From 1e1be6d478c7c2cddf97e2623dd5c4c10bc23020 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 14 Dec 2013 02:03:11 +0100 Subject: [PATCH 6/7] usb: ehci: Do not de-init uninited controllers In case the controller is not initialized, we shall not de-initialize it. As the control structure will not be filled, we will produce a null ptr dereference if the controller is not inited. Signed-off-by: Marek Vasut Cc: Simon Glass --- drivers/usb/host/ehci-hcd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 8bd1eb8a998..3ef204d6abc 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -201,6 +201,9 @@ static int ehci_shutdown(struct ehci_ctrl *ctrl) int i, ret = 0; uint32_t cmd, reg; + if (!ctrl || !ctrl->hcor) + return -EINVAL; + cmd = ehci_readl(&ctrl->hcor->or_usbcmd); cmd &= ~(CMD_PSE | CMD_ASE); ehci_writel(&ctrl->hcor->or_usbcmd, cmd); From eb63218b9b95a59baa8b241f3a88e4415dabf833 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 14 Dec 2013 02:04:52 +0100 Subject: [PATCH 7/7] usb: ehci: Fix register access Fix the register access in EHCI HCD. We need to use address of the register as an ehci_writel() argument. Signed-off-by: Marek Vasut Cc: Simon Glass --- drivers/usb/host/ehci-hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 3ef204d6abc..17187caed48 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -948,7 +948,7 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller) #endif /* Set the high address word (aka segment) for 64-bit controller */ if (ehci_readl(&ehcic[index].hccr->cr_hccparams) & 1) - ehci_writel(ehcic[index].hcor->or_ctrldssegment, 0); + ehci_writel(&ehcic[index].hcor->or_ctrldssegment, 0); qh_list = &ehcic[index].qh_list;