From dccce749ac66aa01593273d86cf3c55542ce6fc0 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 5 Aug 2019 14:14:26 -0500 Subject: USB: gadget: udc: s3c2410_udc: Mark expected switch fall-throughs Mark switch cases where we are expecting to fall through. This patch fixes the following warning (Building: tct_hammer_defconfig arm): drivers/usb/gadget/udc/s3c2410_udc.c:314:7: warning: this statement may fall through [-Wimplicit-fallthrough=] drivers/usb/gadget/udc/s3c2410_udc.c:418:7: warning: this statement may fall through [-Wimplicit-fallthrough=] Signed-off-by: Gustavo A. R. Silva Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/s3c2410_udc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc/s3c2410_udc.c b/drivers/usb/gadget/udc/s3c2410_udc.c index af3e63316ace..f82208fbc249 100644 --- a/drivers/usb/gadget/udc/s3c2410_udc.c +++ b/drivers/usb/gadget/udc/s3c2410_udc.c @@ -312,6 +312,7 @@ static int s3c2410_udc_write_fifo(struct s3c2410_ep *ep, switch (idx) { default: idx = 0; + /* fall through */ case 0: fifo_reg = S3C2410_UDC_EP0_FIFO_REG; break; @@ -416,6 +417,7 @@ static int s3c2410_udc_read_fifo(struct s3c2410_ep *ep, switch (idx) { default: idx = 0; + /* fall through */ case 0: fifo_reg = S3C2410_UDC_EP0_FIFO_REG; break; -- cgit v1.2.3-73-gaa49b From 27125cf8b5aee9f62dd108051203ccbd2e426b51 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 5 Aug 2019 13:48:42 -0500 Subject: usb: gadget: atmel_usba_udc: Mark expected switch fall-through Mark switch cases where we are expecting to fall through. This patch fixes the following warning (Building: at91_dt_defconfig arm): drivers/usb/gadget/udc/atmel_usba_udc.c:329:13: warning: this statement may fall through [-Wimplicit-fallthrough=] Signed-off-by: Gustavo A. R. Silva Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/atmel_usba_udc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index 503d275bc4c4..86ffc8307864 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -327,6 +327,7 @@ static int usba_config_fifo_table(struct usba_udc *udc) switch (fifo_mode) { default: fifo_mode = 0; + /* fall through */ case 0: udc->fifo_cfg = NULL; n = 0; -- cgit v1.2.3-73-gaa49b From 8484aa0cb36d8fd751db77e46763719c78a03b22 Mon Sep 17 00:00:00 2001 From: Chuhong Yuan Date: Wed, 24 Jul 2019 21:18:49 +0800 Subject: usb: gadget: pch_udc: Use dev_get_drvdata Instead of using to_pci_dev + pci_get_drvdata, use dev_get_drvdata to make code simpler. Signed-off-by: Chuhong Yuan Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/pch_udc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index cded51f36fc1..265dab2bbfac 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -3046,8 +3046,7 @@ static void pch_udc_remove(struct pci_dev *pdev) #ifdef CONFIG_PM_SLEEP static int pch_udc_suspend(struct device *d) { - struct pci_dev *pdev = to_pci_dev(d); - struct pch_udc_dev *dev = pci_get_drvdata(pdev); + struct pch_udc_dev *dev = dev_get_drvdata(d); pch_udc_disable_interrupts(dev, UDC_DEVINT_MSK); pch_udc_disable_ep_interrupts(dev, UDC_EPINT_MSK_DISABLE_ALL); -- cgit v1.2.3-73-gaa49b From 9fbbeb4eff076859891c022c151ad20eda83d983 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 26 Jul 2019 15:05:30 +1000 Subject: usb: gadget: aspeed: Don't set port enable change bit on reset This bit should be only set when the port enable goes down, for example, on errors. Not when it gets set after a port reset. Some USB stacks seem to be sensitive to this and fails enumeration. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/aspeed-vhub/hub.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc/aspeed-vhub/hub.c b/drivers/usb/gadget/udc/aspeed-vhub/hub.c index 7c040f56100e..0755115fd90d 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/hub.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/hub.c @@ -449,8 +449,15 @@ static void ast_vhub_change_port_stat(struct ast_vhub *vhub, USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET | USB_PORT_STAT_C_L1; - p->change |= chg; + /* + * We only set USB_PORT_STAT_C_ENABLE if we are disabling + * the port as per USB spec, otherwise MacOS gets upset + */ + if (p->status & USB_PORT_STAT_ENABLE) + chg &= ~USB_PORT_STAT_C_ENABLE; + + p->change = chg; ast_vhub_update_hub_ep1(vhub, port); } } -- cgit v1.2.3-73-gaa49b From d042c35eb86a8ef13c4b5180fd6953a51d9e1efc Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 26 Jul 2019 15:05:31 +1000 Subject: usb: gadget: aspeed: Cleanup EP0 state on port reset Otherwise, we can have a stale state after a disconnect and reconnect causing errors on the first SETUP packet to the device. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/aspeed-vhub/dev.c | 3 +++ drivers/usb/gadget/udc/aspeed-vhub/ep0.c | 9 +++++++++ drivers/usb/gadget/udc/aspeed-vhub/vhub.h | 1 + 3 files changed, 13 insertions(+) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc/aspeed-vhub/dev.c b/drivers/usb/gadget/udc/aspeed-vhub/dev.c index 6b1b16b17d7d..678bbdbd0971 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/dev.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/dev.c @@ -55,6 +55,9 @@ static void ast_vhub_dev_enable(struct ast_vhub_dev *d) if (d->enabled) return; + /* Cleanup EP0 state */ + ast_vhub_reset_ep0(d); + /* Enable device and its EP0 interrupts */ reg = VHUB_DEV_EN_ENABLE_PORT | VHUB_DEV_EN_EP0_IN_ACK_IRQEN | diff --git a/drivers/usb/gadget/udc/aspeed-vhub/ep0.c b/drivers/usb/gadget/udc/aspeed-vhub/ep0.c index e2927fb083cf..5e4714d7febb 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/ep0.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/ep0.c @@ -459,6 +459,15 @@ static const struct usb_ep_ops ast_vhub_ep0_ops = { .free_request = ast_vhub_free_request, }; +void ast_vhub_reset_ep0(struct ast_vhub_dev *dev) +{ + struct ast_vhub_ep *ep = &dev->ep0; + + ast_vhub_nuke(ep, -EIO); + ep->ep0.state = ep0_state_token; +} + + void ast_vhub_init_ep0(struct ast_vhub *vhub, struct ast_vhub_ep *ep, struct ast_vhub_dev *dev) { diff --git a/drivers/usb/gadget/udc/aspeed-vhub/vhub.h b/drivers/usb/gadget/udc/aspeed-vhub/vhub.h index 4ed03d33a5a9..2e7ef387f4f0 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/vhub.h +++ b/drivers/usb/gadget/udc/aspeed-vhub/vhub.h @@ -507,6 +507,7 @@ void ast_vhub_init_hw(struct ast_vhub *vhub); /* ep0.c */ void ast_vhub_ep0_handle_ack(struct ast_vhub_ep *ep, bool in_ack); void ast_vhub_ep0_handle_setup(struct ast_vhub_ep *ep); +void ast_vhub_reset_ep0(struct ast_vhub_dev *dev); void ast_vhub_init_ep0(struct ast_vhub *vhub, struct ast_vhub_ep *ep, struct ast_vhub_dev *dev); int ast_vhub_reply(struct ast_vhub_ep *ep, char *ptr, int len); -- cgit v1.2.3-73-gaa49b From 7e420cef9047dc945b019dc235ec91c792c30f2d Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 26 Jul 2019 15:05:32 +1000 Subject: usb: gadget: aspeed: Fix EP0 stall handling When stalling EP0, we need to wait for an ACK interrupt, otherwise we may get out of sync on the next setup packet data phase. Also we need to ignore the direction when processing that interrupt as the HW reports a potential mismatch. Implement this by adding a stall state to EP0. This fixes some reported issues with mass storage and some hosts. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/aspeed-vhub/ep0.c | 48 ++++++++++++++++++++----------- drivers/usb/gadget/udc/aspeed-vhub/vhub.h | 1 + 2 files changed, 33 insertions(+), 16 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc/aspeed-vhub/ep0.c b/drivers/usb/gadget/udc/aspeed-vhub/ep0.c index 5e4714d7febb..b64dca7933b0 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/ep0.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/ep0.c @@ -105,18 +105,20 @@ void ast_vhub_ep0_handle_setup(struct ast_vhub_ep *ep) (crq.bRequestType & USB_DIR_IN) ? "in" : "out", ep->ep0.state); - /* Check our state, cancel pending requests if needed */ - if (ep->ep0.state != ep0_state_token) { + /* + * Check our state, cancel pending requests if needed + * + * Note: Under some circumstances, we can get a new setup + * packet while waiting for the stall ack, just accept it. + * + * In any case, a SETUP packet in wrong state should have + * reset the HW state machine, so let's just log, nuke + * requests, move on. + */ + if (ep->ep0.state != ep0_state_token && + ep->ep0.state != ep0_state_stall) { EPDBG(ep, "wrong state\n"); ast_vhub_nuke(ep, -EIO); - - /* - * Accept the packet regardless, this seems to happen - * when stalling a SETUP packet that has an OUT data - * phase. - */ - ast_vhub_nuke(ep, 0); - goto stall; } /* Calculate next state for EP0 */ @@ -165,7 +167,7 @@ void ast_vhub_ep0_handle_setup(struct ast_vhub_ep *ep) stall: EPDBG(ep, "stalling\n"); writel(VHUB_EP0_CTRL_STALL, ep->ep0.ctlstat); - ep->ep0.state = ep0_state_status; + ep->ep0.state = ep0_state_stall; ep->ep0.dir_in = false; return; @@ -299,8 +301,8 @@ void ast_vhub_ep0_handle_ack(struct ast_vhub_ep *ep, bool in_ack) if ((ep->ep0.dir_in && (stat & VHUB_EP0_TX_BUFF_RDY)) || (!ep->ep0.dir_in && (stat & VHUB_EP0_RX_BUFF_RDY)) || (ep->ep0.dir_in != in_ack)) { + /* In that case, ignore interrupt */ dev_warn(dev, "irq state mismatch"); - stall = true; break; } /* @@ -335,12 +337,22 @@ void ast_vhub_ep0_handle_ack(struct ast_vhub_ep *ep, bool in_ack) dev_warn(dev, "status direction mismatch\n"); stall = true; } + break; + case ep0_state_stall: + /* + * There shouldn't be any request left, but nuke just in case + * otherwise the stale request will block subsequent ones + */ + ast_vhub_nuke(ep, -EIO); + break; } - /* Reset to token state */ - ep->ep0.state = ep0_state_token; - if (stall) + /* Reset to token state or stall */ + if (stall) { writel(VHUB_EP0_CTRL_STALL, ep->ep0.ctlstat); + ep->ep0.state = ep0_state_stall; + } else + ep->ep0.state = ep0_state_token; } static int ast_vhub_ep0_queue(struct usb_ep* u_ep, struct usb_request *u_req, @@ -390,8 +402,12 @@ static int ast_vhub_ep0_queue(struct usb_ep* u_ep, struct usb_request *u_req, spin_lock_irqsave(&vhub->lock, flags); /* EP0 can only support a single request at a time */ - if (!list_empty(&ep->queue) || ep->ep0.state == ep0_state_token) { + if (!list_empty(&ep->queue) || + ep->ep0.state == ep0_state_token || + ep->ep0.state == ep0_state_stall) { dev_warn(dev, "EP0: Request in wrong state\n"); + EPVDBG(ep, "EP0: list_empty=%d state=%d\n", + list_empty(&ep->queue), ep->ep0.state); spin_unlock_irqrestore(&vhub->lock, flags); return -EBUSY; } diff --git a/drivers/usb/gadget/udc/aspeed-vhub/vhub.h b/drivers/usb/gadget/udc/aspeed-vhub/vhub.h index 2e7ef387f4f0..00f922604a1c 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/vhub.h +++ b/drivers/usb/gadget/udc/aspeed-vhub/vhub.h @@ -257,6 +257,7 @@ enum ep0_state { ep0_state_token, ep0_state_data, ep0_state_status, + ep0_state_stall, }; /* -- cgit v1.2.3-73-gaa49b From ef9d34686bae33de38b0198a4c6c1a50daab31d7 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 26 Jul 2019 15:05:33 +1000 Subject: usb: gadget: aspeed: Don't reject requests on suspended devices A disconnect may just suspend the hub in absence of a physical disconnect detection. If we start rejecting requests, the mass storage function gets into a spin trying to requeue the same request for ever and hangs. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/aspeed-vhub/dev.c | 13 +++++++++---- drivers/usb/gadget/udc/aspeed-vhub/ep0.c | 2 +- drivers/usb/gadget/udc/aspeed-vhub/epn.c | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc/aspeed-vhub/dev.c b/drivers/usb/gadget/udc/aspeed-vhub/dev.c index 678bbdbd0971..71e2416858fd 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/dev.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/dev.c @@ -204,14 +204,19 @@ int ast_vhub_std_dev_request(struct ast_vhub_ep *ep, u16 wValue, wIndex; /* No driver, we shouldn't be enabled ... */ - if (!d->driver || !d->enabled || d->suspended) { + if (!d->driver || !d->enabled) { EPDBG(ep, - "Device is wrong state driver=%p enabled=%d" - " suspended=%d\n", - d->driver, d->enabled, d->suspended); + "Device is wrong state driver=%p enabled=%d\n", + d->driver, d->enabled); return std_req_stall; } + /* + * Note: we used to reject/stall requests while suspended, + * we don't do that anymore as we seem to have cases of + * mass storage getting very upset. + */ + /* First packet, grab speed */ if (d->gadget.speed == USB_SPEED_UNKNOWN) { d->gadget.speed = ep->vhub->speed; diff --git a/drivers/usb/gadget/udc/aspeed-vhub/ep0.c b/drivers/usb/gadget/udc/aspeed-vhub/ep0.c index b64dca7933b0..022b777b85f8 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/ep0.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/ep0.c @@ -379,7 +379,7 @@ static int ast_vhub_ep0_queue(struct usb_ep* u_ep, struct usb_request *u_req, return -EINVAL; /* Disabled device */ - if (ep->dev && (!ep->dev->enabled || ep->dev->suspended)) + if (ep->dev && !ep->dev->enabled) return -ESHUTDOWN; /* Data, no buffer and not internal ? */ diff --git a/drivers/usb/gadget/udc/aspeed-vhub/epn.c b/drivers/usb/gadget/udc/aspeed-vhub/epn.c index 35941dc125f9..7475c74aa5c5 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/epn.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/epn.c @@ -352,7 +352,7 @@ static int ast_vhub_epn_queue(struct usb_ep* u_ep, struct usb_request *u_req, /* Endpoint enabled ? */ if (!ep->epn.enabled || !u_ep->desc || !ep->dev || !ep->d_idx || - !ep->dev->enabled || ep->dev->suspended) { + !ep->dev->enabled) { EPDBG(ep, "Enqueuing request on wrong or disabled EP\n"); return -ESHUTDOWN; } -- cgit v1.2.3-73-gaa49b From 155940a16d688b5376f7c955a5f53259c6fe5689 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 26 Jul 2019 15:05:34 +1000 Subject: usb: gadget: aspeed: Check suspend/resume callback existence .. before calling them Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/aspeed-vhub/dev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc/aspeed-vhub/dev.c b/drivers/usb/gadget/udc/aspeed-vhub/dev.c index 71e2416858fd..5f7e3b6de531 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/dev.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/dev.c @@ -458,7 +458,7 @@ static const struct usb_gadget_ops ast_vhub_udc_ops = { void ast_vhub_dev_suspend(struct ast_vhub_dev *d) { d->suspended = true; - if (d->driver) { + if (d->driver && d->driver->suspend) { spin_unlock(&d->vhub->lock); d->driver->suspend(&d->gadget); spin_lock(&d->vhub->lock); @@ -468,7 +468,7 @@ void ast_vhub_dev_suspend(struct ast_vhub_dev *d) void ast_vhub_dev_resume(struct ast_vhub_dev *d) { d->suspended = false; - if (d->driver) { + if (d->driver && d->driver->resume) { spin_unlock(&d->vhub->lock); d->driver->resume(&d->gadget); spin_lock(&d->vhub->lock); -- cgit v1.2.3-73-gaa49b From 5f0625aaba5e4c0db75e942ff3c76516465a77d9 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 26 Jul 2019 15:05:35 +1000 Subject: usb: gadget: aspeed: Rework the reset logic We had some dodgy code using the speed setting to decide whether a port reset would reset the device or just enable it. Instead, if the device is disabled and has a gadget attached, a reset will enable it. If it's already enabled, a reset will reset it. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/aspeed-vhub/dev.c | 58 +++++++++++++++----------------- 1 file changed, 27 insertions(+), 31 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc/aspeed-vhub/dev.c b/drivers/usb/gadget/udc/aspeed-vhub/dev.c index 5f7e3b6de531..79d3cb6bd2e7 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/dev.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/dev.c @@ -50,7 +50,7 @@ void ast_vhub_dev_irq(struct ast_vhub_dev *d) static void ast_vhub_dev_enable(struct ast_vhub_dev *d) { - u32 reg, hmsk; + u32 reg, hmsk, i; if (d->enabled) return; @@ -76,6 +76,20 @@ static void ast_vhub_dev_enable(struct ast_vhub_dev *d) /* Set EP0 DMA buffer address */ writel(d->ep0.buf_dma, d->regs + AST_VHUB_DEV_EP0_DATA); + /* Clear stall on all EPs */ + for (i = 0; i < AST_VHUB_NUM_GEN_EPs; i++) { + struct ast_vhub_ep *ep = d->epns[i]; + + if (ep && (ep->epn.stalled || ep->epn.wedged)) { + ep->epn.stalled = false; + ep->epn.wedged = false; + ast_vhub_update_epn_stall(ep); + } + } + + /* Additional cleanups */ + d->wakeup_en = false; + d->suspended = false; d->enabled = true; } @@ -477,46 +491,28 @@ void ast_vhub_dev_resume(struct ast_vhub_dev *d) void ast_vhub_dev_reset(struct ast_vhub_dev *d) { - /* - * If speed is not set, we enable the port. If it is, - * send reset to the gadget and reset "speed". - * - * Speed is an indication that we have got the first - * setup packet to the device. - */ - if (d->gadget.speed == USB_SPEED_UNKNOWN && !d->enabled) { - DDBG(d, "Reset at unknown speed of disabled device, enabling...\n"); - ast_vhub_dev_enable(d); - d->suspended = false; + /* No driver, just disable the device and return */ + if (!d->driver) { + ast_vhub_dev_disable(d); + return; } - if (d->gadget.speed != USB_SPEED_UNKNOWN && d->driver) { - unsigned int i; - DDBG(d, "Reset at known speed of bound device, resetting...\n"); + /* If the port isn't enabled, just enable it */ + if (!d->enabled) { + DDBG(d, "Reset of disabled device, enabling...\n"); + ast_vhub_dev_enable(d); + } else { + DDBG(d, "Reset of enabled device, resetting...\n"); spin_unlock(&d->vhub->lock); - d->driver->reset(&d->gadget); + usb_gadget_udc_reset(&d->gadget, d->driver); spin_lock(&d->vhub->lock); /* - * Disable/re-enable HW, this will clear the address + * Disable and maybe re-enable HW, this will clear the address * and speed setting. */ ast_vhub_dev_disable(d); ast_vhub_dev_enable(d); - - /* Clear stall on all EPs */ - for (i = 0; i < AST_VHUB_NUM_GEN_EPs; i++) { - struct ast_vhub_ep *ep = d->epns[i]; - - if (ep && ep->epn.stalled) { - ep->epn.stalled = false; - ast_vhub_update_epn_stall(ep); - } - } - - /* Additional cleanups */ - d->wakeup_en = false; - d->suspended = false; } } -- cgit v1.2.3-73-gaa49b From 8016759894089ef79415852d253eb54217b44539 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 26 Jul 2019 15:05:36 +1000 Subject: usb: gadget: aspeed: Remove unused "suspended" flag The state bit in the hub is sufficient Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/aspeed-vhub/dev.c | 4 ---- drivers/usb/gadget/udc/aspeed-vhub/vhub.h | 1 - 2 files changed, 5 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc/aspeed-vhub/dev.c b/drivers/usb/gadget/udc/aspeed-vhub/dev.c index 79d3cb6bd2e7..4008e7a51188 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/dev.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/dev.c @@ -89,7 +89,6 @@ static void ast_vhub_dev_enable(struct ast_vhub_dev *d) /* Additional cleanups */ d->wakeup_en = false; - d->suspended = false; d->enabled = true; } @@ -110,7 +109,6 @@ static void ast_vhub_dev_disable(struct ast_vhub_dev *d) writel(0, d->regs + AST_VHUB_DEV_EN_CTRL); d->gadget.speed = USB_SPEED_UNKNOWN; d->enabled = false; - d->suspended = false; } static int ast_vhub_dev_feature(struct ast_vhub_dev *d, @@ -471,7 +469,6 @@ static const struct usb_gadget_ops ast_vhub_udc_ops = { void ast_vhub_dev_suspend(struct ast_vhub_dev *d) { - d->suspended = true; if (d->driver && d->driver->suspend) { spin_unlock(&d->vhub->lock); d->driver->suspend(&d->gadget); @@ -481,7 +478,6 @@ void ast_vhub_dev_suspend(struct ast_vhub_dev *d) void ast_vhub_dev_resume(struct ast_vhub_dev *d) { - d->suspended = false; if (d->driver && d->driver->resume) { spin_unlock(&d->vhub->lock); d->driver->resume(&d->gadget); diff --git a/drivers/usb/gadget/udc/aspeed-vhub/vhub.h b/drivers/usb/gadget/udc/aspeed-vhub/vhub.h index 00f922604a1c..761919e220d3 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/vhub.h +++ b/drivers/usb/gadget/udc/aspeed-vhub/vhub.h @@ -354,7 +354,6 @@ struct ast_vhub_dev { struct usb_gadget_driver *driver; bool registered : 1; bool wakeup_en : 1; - bool suspended : 1; bool enabled : 1; /* Endpoint structures */ -- cgit v1.2.3-73-gaa49b From cca1754c1d004370b86f41ad346130589fd41152 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 26 Jul 2019 15:05:37 +1000 Subject: usb: gadget: aspeed: Improve debugging when nuking When nuking requests, it's useful to display how many were actually nuked. It has proven handy when debugging issues where EP0 went in a wrong state. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/aspeed-vhub/core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc/aspeed-vhub/core.c b/drivers/usb/gadget/udc/aspeed-vhub/core.c index db3628be38c0..9e698de4b1e8 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/core.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/core.c @@ -65,14 +65,16 @@ void ast_vhub_done(struct ast_vhub_ep *ep, struct ast_vhub_req *req, void ast_vhub_nuke(struct ast_vhub_ep *ep, int status) { struct ast_vhub_req *req; - - EPDBG(ep, "Nuking\n"); + int count = 0; /* Beware, lock will be dropped & req-acquired by done() */ while (!list_empty(&ep->queue)) { req = list_first_entry(&ep->queue, struct ast_vhub_req, queue); ast_vhub_done(ep, req, status); + count++; } + if (count) + EPDBG(ep, "Nuked %d request(s)\n", count); } struct usb_request *ast_vhub_alloc_request(struct usb_ep *u_ep, -- cgit v1.2.3-73-gaa49b From aa31332f67ac5418d0ca448153cf49ad09dba360 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 26 Jul 2019 15:05:39 +1000 Subject: usb: gadget: aspeed: Implement dummy hub TT requests We just accept them instead of stalling and return zeros on GetTTState. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/aspeed-vhub/hub.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc/aspeed-vhub/hub.c b/drivers/usb/gadget/udc/aspeed-vhub/hub.c index 0755115fd90d..19b3517e04c0 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/hub.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/hub.c @@ -730,6 +730,12 @@ enum std_req_rc ast_vhub_class_hub_request(struct ast_vhub_ep *ep, case ClearPortFeature: EPDBG(ep, "ClearPortFeature(%d,%d)\n", wIndex & 0xf, wValue); return ast_vhub_clr_port_feature(ep, wIndex & 0xf, wValue); + case ClearTTBuffer: + case ResetTT: + case StopTT: + return std_req_complete; + case GetTTState: + return ast_vhub_simple_reply(ep, 0, 0, 0, 0); default: EPDBG(ep, "Unknown class request\n"); } -- cgit v1.2.3-73-gaa49b From 163be6ff7739b12ff300d77897d340f661821da2 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Thu, 22 Aug 2019 16:40:28 +0300 Subject: usb: gadget: udc: core: Fix segfault if udc_bind_to_driver() for pending driver fails If a gadget driver is in the pending drivers list, a UDC becomes available and udc_bind_to_driver() fails, then it gets deleted from the pending list. i.e. list_del(&driver->pending) in check_pending_gadget_drivers(). Then if that gadget driver is unregistered, usb_gadget_unregister_driver() does a list_del(&driver->pending) again thus causing a page fault as that list entry has been poisoned by the previous list_del(). Fix this by using list_del_init() instead of list_del() in check_pending_gadget_drivers(). Test case: - Make sure no UDC is available - modprobe g_mass_storage file=wrongfile - Load UDC driver so it becomes available lun0: unable to open backing file: wrongfile - modprobe -r g_mass_storage [ 60.900431] Unable to handle kernel paging request at virtual address dead000000000108 [ 60.908346] Mem abort info: [ 60.911145] ESR = 0x96000044 [ 60.914227] Exception class = DABT (current EL), IL = 32 bits [ 60.920162] SET = 0, FnV = 0 [ 60.923217] EA = 0, S1PTW = 0 [ 60.926354] Data abort info: [ 60.929228] ISV = 0, ISS = 0x00000044 [ 60.933058] CM = 0, WnR = 1 [ 60.936011] [dead000000000108] address between user and kernel address ranges [ 60.943136] Internal error: Oops: 96000044 [#1] PREEMPT SMP [ 60.948691] Modules linked in: g_mass_storage(-) usb_f_mass_storage libcomposite xhci_plat_hcd xhci_hcd usbcore ti_am335x_adc kfifo_buf omap_rng cdns3 rng_core udc_core crc32_ce xfrm_user crct10dif_ce snd_so6 [ 60.993995] Process modprobe (pid: 834, stack limit = 0x00000000c2aebc69) [ 61.000765] CPU: 0 PID: 834 Comm: modprobe Not tainted 4.19.59-01963-g065f42a60499 #92 [ 61.008658] Hardware name: Texas Instruments SoC (DT) [ 61.014472] pstate: 60000005 (nZCv daif -PAN -UAO) [ 61.019253] pc : usb_gadget_unregister_driver+0x7c/0x108 [udc_core] [ 61.025503] lr : usb_gadget_unregister_driver+0x30/0x108 [udc_core] [ 61.031750] sp : ffff00001338fda0 [ 61.035049] x29: ffff00001338fda0 x28: ffff800846d40000 [ 61.040346] x27: 0000000000000000 x26: 0000000000000000 [ 61.045642] x25: 0000000056000000 x24: 0000000000000800 [ 61.050938] x23: ffff000008d7b0d0 x22: ffff0000088b07c8 [ 61.056234] x21: ffff000001100000 x20: ffff000002020260 [ 61.061530] x19: ffff0000010ffd28 x18: 0000000000000000 [ 61.066825] x17: 0000000000000000 x16: 0000000000000000 [ 61.072121] x15: 0000000000000000 x14: 0000000000000000 [ 61.077417] x13: ffff000000000000 x12: ffffffffffffffff [ 61.082712] x11: 0000000000000030 x10: 7f7f7f7f7f7f7f7f [ 61.088008] x9 : fefefefefefefeff x8 : 0000000000000000 [ 61.093304] x7 : ffffffffffffffff x6 : 000000000000ffff [ 61.098599] x5 : 8080000000000000 x4 : 0000000000000000 [ 61.103895] x3 : ffff000001100020 x2 : ffff800846d40000 [ 61.109190] x1 : dead000000000100 x0 : dead000000000200 [ 61.114486] Call trace: [ 61.116922] usb_gadget_unregister_driver+0x7c/0x108 [udc_core] [ 61.122828] usb_composite_unregister+0x10/0x18 [libcomposite] [ 61.128643] msg_cleanup+0x18/0xfce0 [g_mass_storage] [ 61.133682] __arm64_sys_delete_module+0x17c/0x1f0 [ 61.138458] el0_svc_common+0x90/0x158 [ 61.142192] el0_svc_handler+0x2c/0x80 [ 61.145926] el0_svc+0x8/0xc [ 61.148794] Code: eb03003f d10be033 54ffff21 a94d0281 (f9000420) [ 61.154869] ---[ end trace afb22e9b637bd9a7 ]--- Segmentation fault Acked-by: Alan Stern Signed-off-by: Roger Quadros Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index 7cf34beb50df..92af8dc98c3d 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -1143,7 +1143,7 @@ static int check_pending_gadget_drivers(struct usb_udc *udc) dev_name(&udc->dev)) == 0) { ret = udc_bind_to_driver(udc, driver); if (ret != -EPROBE_DEFER) - list_del(&driver->pending); + list_del_init(&driver->pending); break; } -- cgit v1.2.3-73-gaa49b From 566aacaf80b8ae0cb0e6bc3d11d49a36ab7f32ca Mon Sep 17 00:00:00 2001 From: Mao Wenan Date: Thu, 22 Aug 2019 15:05:57 +0800 Subject: usb: udc: lpc32xx: remove set but not used 3 variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes gcc '-Wunused-but-set-variable' warning: drivers/usb/gadget/udc/lpc32xx_udc.c: In function ‘udc_protocol_cmd_r’: drivers/usb/gadget/udc/lpc32xx_udc.c:744:6: warning: variable ‘tmp’ set but not used [-Wunused-but-set-variable] drivers/usb/gadget/udc/lpc32xx_udc.c: In function ‘udc_handle_dma_ep’: drivers/usb/gadget/udc/lpc32xx_udc.c:1994:14: warning: variable ‘epstatus’ set but not used [-Wunused-but-set-variable] drivers/usb/gadget/udc/lpc32xx_udc.c: In function ‘udc_handle_ep0_setup’: drivers/usb/gadget/udc/lpc32xx_udc.c:2200:22: warning: variable ‘wLength’ set but not used [-Wunused-but-set-variable] It is not used since commit 90fccb529d24 ("usb: gadget: Gadget directory cleanup - group UDC drivers") Signed-off-by: Mao Wenan Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/lpc32xx_udc.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c index 5f1b14f3e5a0..2c8084deb671 100644 --- a/drivers/usb/gadget/udc/lpc32xx_udc.c +++ b/drivers/usb/gadget/udc/lpc32xx_udc.c @@ -742,7 +742,6 @@ static inline void udc_protocol_cmd_data_w(struct lpc32xx_udc *udc, u32 cmd, * response data */ static u32 udc_protocol_cmd_r(struct lpc32xx_udc *udc, u32 cmd) { - u32 tmp; int to = 1000; /* Write a command and read data from the protocol engine */ @@ -752,7 +751,6 @@ static u32 udc_protocol_cmd_r(struct lpc32xx_udc *udc, u32 cmd) /* Write command code */ udc_protocol_cmd_w(udc, cmd); - tmp = readl(USBD_DEVINTST(udc->udp_baseaddr)); while ((!(readl(USBD_DEVINTST(udc->udp_baseaddr)) & USBD_CDFULL)) && (to > 0)) to--; @@ -1992,7 +1990,7 @@ void udc_handle_eps(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep) /* DMA end of transfer completion */ static void udc_handle_dma_ep(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep) { - u32 status, epstatus; + u32 status; struct lpc32xx_request *req; struct lpc32xx_usbd_dd_gad *dd; @@ -2086,7 +2084,7 @@ static void udc_handle_dma_ep(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep) if (udc_clearep_getsts(udc, ep->hwep_num) & EP_SEL_F) { udc_clearep_getsts(udc, ep->hwep_num); uda_enable_hwepint(udc, ep->hwep_num); - epstatus = udc_clearep_getsts(udc, ep->hwep_num); + udc_clearep_getsts(udc, ep->hwep_num); /* Let the EP interrupt handle the ZLP */ return; @@ -2198,7 +2196,7 @@ static void udc_handle_ep0_setup(struct lpc32xx_udc *udc) struct lpc32xx_ep *ep, *ep0 = &udc->ep[0]; struct usb_ctrlrequest ctrlpkt; int i, bytes; - u16 wIndex, wValue, wLength, reqtype, req, tmp; + u16 wIndex, wValue, reqtype, req, tmp; /* Nuke previous transfers */ nuke(ep0, -EPROTO); @@ -2214,7 +2212,6 @@ static void udc_handle_ep0_setup(struct lpc32xx_udc *udc) /* Native endianness */ wIndex = le16_to_cpu(ctrlpkt.wIndex); wValue = le16_to_cpu(ctrlpkt.wValue); - wLength = le16_to_cpu(ctrlpkt.wLength); reqtype = le16_to_cpu(ctrlpkt.bRequestType); /* Set direction of EP0 */ -- cgit v1.2.3-73-gaa49b From c33f141615c2850ab512f7dca654f8f0914ab9ab Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 20 Aug 2019 21:16:27 -0500 Subject: usb: udc: lpc32xx: silence fall-through warning Silence the following fall-through warning by adding a break statement: drivers/usb/gadget/udc/lpc32xx_udc.c:2230:3: warning: this statement may fall through [-Wimplicit-fallthrough=] Signed-off-by: Gustavo A. R. Silva Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/lpc32xx_udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c index 2c8084deb671..bb287da20e16 100644 --- a/drivers/usb/gadget/udc/lpc32xx_udc.c +++ b/drivers/usb/gadget/udc/lpc32xx_udc.c @@ -2262,7 +2262,7 @@ static void udc_handle_ep0_setup(struct lpc32xx_udc *udc) default: break; } - + break; case USB_REQ_SET_ADDRESS: if (reqtype == (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) { -- cgit v1.2.3-73-gaa49b From cca3854010c5aebf3a06be0de04f26c4f1ae5810 Mon Sep 17 00:00:00 2001 From: Thinh Nguyen Date: Mon, 19 Aug 2019 18:36:12 -0700 Subject: usb: gadget: composite: Set recommended BESL values Set the recommended BESL deep and baseline values based on the gadget's configuration parameters to the extended BOS descriptor. This feature helps to optimize power savings by maximizing the opportunity for longer L1 residency time. Signed-off-by: Thinh Nguyen Signed-off-by: Felipe Balbi --- drivers/usb/gadget/composite.c | 38 ++++++++++++++++++++++++++------------ include/uapi/linux/usb/ch9.h | 2 ++ 2 files changed, 28 insertions(+), 12 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 9118b42c70b6..7ed009dc0f92 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -612,6 +612,7 @@ static int bos_desc(struct usb_composite_dev *cdev) struct usb_ext_cap_descriptor *usb_ext; struct usb_dcd_config_params dcd_config_params; struct usb_bos_descriptor *bos = cdev->req->buf; + unsigned int besl = 0; bos->bLength = USB_DT_BOS_SIZE; bos->bDescriptorType = USB_DT_BOS; @@ -619,6 +620,29 @@ static int bos_desc(struct usb_composite_dev *cdev) bos->wTotalLength = cpu_to_le16(USB_DT_BOS_SIZE); bos->bNumDeviceCaps = 0; + /* Get Controller configuration */ + if (cdev->gadget->ops->get_config_params) { + cdev->gadget->ops->get_config_params(cdev->gadget, + &dcd_config_params); + } else { + dcd_config_params.besl_baseline = + USB_DEFAULT_BESL_UNSPECIFIED; + dcd_config_params.besl_deep = + USB_DEFAULT_BESL_UNSPECIFIED; + dcd_config_params.bU1devExitLat = + USB_DEFAULT_U1_DEV_EXIT_LAT; + dcd_config_params.bU2DevExitLat = + cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT); + } + + if (dcd_config_params.besl_baseline != USB_DEFAULT_BESL_UNSPECIFIED) + besl = USB_BESL_BASELINE_VALID | + USB_SET_BESL_BASELINE(dcd_config_params.besl_baseline); + + if (dcd_config_params.besl_deep != USB_DEFAULT_BESL_UNSPECIFIED) + besl |= USB_BESL_DEEP_VALID | + USB_SET_BESL_DEEP(dcd_config_params.besl_deep); + /* * A SuperSpeed device shall include the USB2.0 extension descriptor * and shall support LPM when operating in USB2.0 HS mode. @@ -629,7 +653,8 @@ static int bos_desc(struct usb_composite_dev *cdev) usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE; usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY; usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT; - usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT | USB_BESL_SUPPORT); + usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT | + USB_BESL_SUPPORT | besl); /* * The Superspeed USB Capability descriptor shall be implemented by all @@ -650,17 +675,6 @@ static int bos_desc(struct usb_composite_dev *cdev) USB_HIGH_SPEED_OPERATION | USB_5GBPS_OPERATION); ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION; - - /* Get Controller configuration */ - if (cdev->gadget->ops->get_config_params) { - cdev->gadget->ops->get_config_params(cdev->gadget, - &dcd_config_params); - } else { - dcd_config_params.bU1devExitLat = - USB_DEFAULT_U1_DEV_EXIT_LAT; - dcd_config_params.bU2DevExitLat = - cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT); - } ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat; ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat; } diff --git a/include/uapi/linux/usb/ch9.h b/include/uapi/linux/usb/ch9.h index d5a5caec8fbc..2b623f36af6b 100644 --- a/include/uapi/linux/usb/ch9.h +++ b/include/uapi/linux/usb/ch9.h @@ -894,6 +894,8 @@ struct usb_ext_cap_descriptor { /* Link Power Management */ #define USB_BESL_SUPPORT (1 << 2) /* supports BESL */ #define USB_BESL_BASELINE_VALID (1 << 3) /* Baseline BESL valid*/ #define USB_BESL_DEEP_VALID (1 << 4) /* Deep BESL valid */ +#define USB_SET_BESL_BASELINE(p) (((p) & 0xf) << 8) +#define USB_SET_BESL_DEEP(p) (((p) & 0xf) << 12) #define USB_GET_BESL_BASELINE(p) (((p) & (0xf << 8)) >> 8) #define USB_GET_BESL_DEEP(p) (((p) & (0xf << 12)) >> 12) } __attribute__((packed)); -- cgit v1.2.3-73-gaa49b From ec8ca8a3489cc87ca43a865af7e7393690841810 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 30 Aug 2019 13:56:10 +1000 Subject: usb: gadget: net2280: Move all "ll" registers in one structure The split into multiple structures of the "ll" register bank is impractical. It makes it hard to add ll_lfps_timers_2 which is at offset 0x794, which is outside of the existing "lfps" structure and would require us to add yet another one. Instead, move all the "ll" registers into a single usb338x_ll_regs structure, and add ll_lfps_timers_2 while at it. It will be used in a subsequent patch. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/net2280.c | 28 +++++++++++----------------- drivers/usb/gadget/udc/net2280.h | 3 --- include/linux/usb/usb338x.h | 35 +++++++++++++++++++++++++---------- 3 files changed, 36 insertions(+), 30 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index b6bbe2e448ba..e0191146ba22 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c @@ -2244,30 +2244,30 @@ static void usb_reinit_338x(struct net2280 *dev) } /* Hardware Defect and Workaround */ - val = readl(&dev->ll_lfps_regs->ll_lfps_5); + val = readl(&dev->llregs->ll_lfps_5); val &= ~(0xf << TIMER_LFPS_6US); val |= 0x5 << TIMER_LFPS_6US; - writel(val, &dev->ll_lfps_regs->ll_lfps_5); + writel(val, &dev->llregs->ll_lfps_5); - val = readl(&dev->ll_lfps_regs->ll_lfps_6); + val = readl(&dev->llregs->ll_lfps_6); val &= ~(0xffff << TIMER_LFPS_80US); val |= 0x0100 << TIMER_LFPS_80US; - writel(val, &dev->ll_lfps_regs->ll_lfps_6); + writel(val, &dev->llregs->ll_lfps_6); /* * AA_AB Errata. Issue 4. Workaround for SuperSpeed USB * Hot Reset Exit Handshake may Fail in Specific Case using * Default Register Settings. Workaround for Enumeration test. */ - val = readl(&dev->ll_tsn_regs->ll_tsn_counters_2); + val = readl(&dev->llregs->ll_tsn_counters_2); val &= ~(0x1f << HOT_TX_NORESET_TS2); val |= 0x10 << HOT_TX_NORESET_TS2; - writel(val, &dev->ll_tsn_regs->ll_tsn_counters_2); + writel(val, &dev->llregs->ll_tsn_counters_2); - val = readl(&dev->ll_tsn_regs->ll_tsn_counters_3); + val = readl(&dev->llregs->ll_tsn_counters_3); val &= ~(0x1f << HOT_RX_RESET_TS2); val |= 0x3 << HOT_RX_RESET_TS2; - writel(val, &dev->ll_tsn_regs->ll_tsn_counters_3); + writel(val, &dev->llregs->ll_tsn_counters_3); /* * Set Recovery Idle to Recover bit: @@ -2276,10 +2276,10 @@ static void usb_reinit_338x(struct net2280 *dev) * - It is safe to set for all connection speeds; all chip revisions. * - R-M-W to leave other bits undisturbed. * - Reference PLX TT-7372 - */ - val = readl(&dev->ll_chicken_reg->ll_tsn_chicken_bit); + */ + val = readl(&dev->llregs->ll_tsn_chicken_bit); val |= BIT(RECOVERY_IDLE_TO_RECOVER_FMW); - writel(val, &dev->ll_chicken_reg->ll_tsn_chicken_bit); + writel(val, &dev->llregs->ll_tsn_chicken_bit); INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); @@ -3669,12 +3669,6 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id) (base + 0x00b4); dev->llregs = (struct usb338x_ll_regs __iomem *) (base + 0x0700); - dev->ll_lfps_regs = (struct usb338x_ll_lfps_regs __iomem *) - (base + 0x0748); - dev->ll_tsn_regs = (struct usb338x_ll_tsn_regs __iomem *) - (base + 0x077c); - dev->ll_chicken_reg = (struct usb338x_ll_chi_regs __iomem *) - (base + 0x079c); dev->plregs = (struct usb338x_pl_regs __iomem *) (base + 0x0800); usbstat = readl(&dev->usb->usbstat); diff --git a/drivers/usb/gadget/udc/net2280.h b/drivers/usb/gadget/udc/net2280.h index b65a797544d7..85d3ca1698ba 100644 --- a/drivers/usb/gadget/udc/net2280.h +++ b/drivers/usb/gadget/udc/net2280.h @@ -178,9 +178,6 @@ struct net2280 { struct net2280_dep_regs __iomem *dep; struct net2280_ep_regs __iomem *epregs; struct usb338x_ll_regs __iomem *llregs; - struct usb338x_ll_lfps_regs __iomem *ll_lfps_regs; - struct usb338x_ll_tsn_regs __iomem *ll_tsn_regs; - struct usb338x_ll_chi_regs __iomem *ll_chicken_reg; struct usb338x_pl_regs __iomem *plregs; struct dma_pool *requests; diff --git a/include/linux/usb/usb338x.h b/include/linux/usb/usb338x.h index 7189e3387bf9..20020c1336d5 100644 --- a/include/linux/usb/usb338x.h +++ b/include/linux/usb/usb338x.h @@ -113,7 +113,10 @@ struct usb338x_ll_regs { u32 ll_ltssm_ctrl1; u32 ll_ltssm_ctrl2; u32 ll_ltssm_ctrl3; - u32 unused[2]; + u32 unused1; + + /* 0x710 */ + u32 unused2; u32 ll_general_ctrl0; u32 ll_general_ctrl1; #define PM_U3_AUTO_EXIT 29 @@ -136,29 +139,41 @@ struct usb338x_ll_regs { u32 ll_general_ctrl2; #define SELECT_INVERT_LANE_POLARITY 7 #define FORCE_INVERT_LANE_POLARITY 6 + + /* 0x720 */ u32 ll_general_ctrl3; u32 ll_general_ctrl4; u32 ll_error_gen; -} __packed; + u32 unused3; + + /* 0x730 */ + u32 unused4[4]; -struct usb338x_ll_lfps_regs { - /* offset 0x748 */ + /* 0x740 */ + u32 unused5[2]; u32 ll_lfps_5; #define TIMER_LFPS_6US 16 u32 ll_lfps_6; #define TIMER_LFPS_80US 0 -} __packed; -struct usb338x_ll_tsn_regs { - /* offset 0x77C */ + /* 0x750 */ + u32 unused6[8]; + + /* 0x770 */ + u32 unused7[3]; u32 ll_tsn_counters_2; #define HOT_TX_NORESET_TS2 24 + + /* 0x780 */ u32 ll_tsn_counters_3; #define HOT_RX_RESET_TS2 0 -} __packed; + u32 unused8[3]; -struct usb338x_ll_chi_regs { - /* offset 0x79C */ + /* 0x790 */ + u32 unused9; + u32 ll_lfps_timers_2; +#define LFPS_TIMERS_2_WORKAROUND_VALUE 0x084d + u32 unused10; u32 ll_tsn_chicken_bit; #define RECOVERY_IDLE_TO_RECOVER_FMW 3 } __packed; -- cgit v1.2.3-73-gaa49b From 18a93cd38be3e69ac5b067c570a78a369b79e31d Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 30 Aug 2019 13:56:14 +1000 Subject: usb: gadget: net2280: Add workaround for AB chip Errata 11 The errata description is: Workaround for Default Duration of LFPS Handshake Signaling for Device-Initiated U1 Exit is too short. The default duration of the LFPS handshake generated by USB3380 for a device-initiated U1-exit may not be long enough for certain SuperSpeed downstream ports (SuperSpeed hubs/hosts) to recognize. This could lead to USB3380 entering the recovery state pre-maturely and ending up in the SS.Inactive state. I have observed various enumeration failures, seemingly related to lost transactions or SETUP status phases on modern hosts (typically thunderbolt capable systems) without this workaround. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/net2280.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index e0191146ba22..51efee21915f 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c @@ -2269,6 +2269,16 @@ static void usb_reinit_338x(struct net2280 *dev) val |= 0x3 << HOT_RX_RESET_TS2; writel(val, &dev->llregs->ll_tsn_counters_3); + /* + * AB errata. Errata 11. Workaround for Default Duration of LFPS + * Handshake Signaling for Device-Initiated U1 Exit is too short. + * Without this, various enumeration failures observed with + * modern superspeed hosts. + */ + val = readl(&dev->llregs->ll_lfps_timers_2); + writel((val & 0xffff0000) | LFPS_TIMERS_2_WORKAROUND_VALUE, + &dev->llregs->ll_lfps_timers_2); + /* * Set Recovery Idle to Recover bit: * - On SS connections, setting Recovery Idle to Recover Fmw improves -- cgit v1.2.3-73-gaa49b