summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0079-usb-gadget-aspeed-backport-aspeed-vhub-bug-fixes.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0079-usb-gadget-aspeed-backport-aspeed-vhub-bug-fixes.patch')
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0079-usb-gadget-aspeed-backport-aspeed-vhub-bug-fixes.patch473
1 files changed, 0 insertions, 473 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0079-usb-gadget-aspeed-backport-aspeed-vhub-bug-fixes.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0079-usb-gadget-aspeed-backport-aspeed-vhub-bug-fixes.patch
deleted file mode 100644
index 17db705d1..000000000
--- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0079-usb-gadget-aspeed-backport-aspeed-vhub-bug-fixes.patch
+++ /dev/null
@@ -1,473 +0,0 @@
-From 0475ac3698cf3d95d78b0230418ec7ef5fdc62c7 Mon Sep 17 00:00:00 2001
-From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
-Date: Tue, 29 Oct 2019 11:42:08 -0700
-Subject: [PATCH] usb: gadget: aspeed: backport aspeed vhub bug fixes
-
-usb: gadget: aspeed: Implement dummy hub TT requests
-
-We just accept them instead of stalling and return
-zeros on GetTTState.
-
-usb: Add definitions for the USB2.0 hub TT requests
-
-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.
-
-usb: gadget: aspeed: Remove unused "suspended" flag
-
-The state bit in the hub is sufficient
-
-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.
-
-usb: gadget: aspeed: Check suspend/resume callback existence
-
-.. before calling them
-
-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.
-
-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.
-
-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.
-
-causing errors on the first SETUP packet to the device.
-
-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 <benh@kernel.crashing.org>
-Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
-Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
----
- drivers/usb/gadget/udc/aspeed-vhub/core.c | 7 +--
- drivers/usb/gadget/udc/aspeed-vhub/dev.c | 80 +++++++++++++++----------------
- drivers/usb/gadget/udc/aspeed-vhub/ep0.c | 59 ++++++++++++++++-------
- drivers/usb/gadget/udc/aspeed-vhub/epn.c | 2 +-
- drivers/usb/gadget/udc/aspeed-vhub/hub.c | 15 +++++-
- drivers/usb/gadget/udc/aspeed-vhub/vhub.h | 3 +-
- include/linux/usb/hcd.h | 4 ++
- 7 files changed, 107 insertions(+), 63 deletions(-)
-
-diff --git a/drivers/usb/gadget/udc/aspeed-vhub/core.c b/drivers/usb/gadget/udc/aspeed-vhub/core.c
-index db3628be38c0..90b134d5dca9 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,
-@@ -348,7 +350,6 @@ static int ast_vhub_probe(struct platform_device *pdev)
- /* Find interrupt and install handler */
- vhub->irq = platform_get_irq(pdev, 0);
- if (vhub->irq < 0) {
-- dev_err(&pdev->dev, "Failed to get interrupt\n");
- rc = vhub->irq;
- goto err;
- }
-diff --git a/drivers/usb/gadget/udc/aspeed-vhub/dev.c b/drivers/usb/gadget/udc/aspeed-vhub/dev.c
-index 6b1b16b17d7d..4008e7a51188 100644
---- a/drivers/usb/gadget/udc/aspeed-vhub/dev.c
-+++ b/drivers/usb/gadget/udc/aspeed-vhub/dev.c
-@@ -50,11 +50,14 @@ 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;
-
-+ /* 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 |
-@@ -73,6 +76,19 @@ 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->enabled = true;
- }
-
-@@ -93,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,
-@@ -201,14 +216,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;
-@@ -449,8 +469,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);
-@@ -459,8 +478,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);
-@@ -469,46 +487,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;
- }
- }
-
-diff --git a/drivers/usb/gadget/udc/aspeed-vhub/ep0.c b/drivers/usb/gadget/udc/aspeed-vhub/ep0.c
-index e2927fb083cf..022b777b85f8 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,
-@@ -367,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 ? */
-@@ -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;
- }
-@@ -459,6 +475,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/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;
- }
-diff --git a/drivers/usb/gadget/udc/aspeed-vhub/hub.c b/drivers/usb/gadget/udc/aspeed-vhub/hub.c
-index 7c040f56100e..19b3517e04c0 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);
- }
- }
-@@ -723,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");
- }
-diff --git a/drivers/usb/gadget/udc/aspeed-vhub/vhub.h b/drivers/usb/gadget/udc/aspeed-vhub/vhub.h
-index 4ed03d33a5a9..761919e220d3 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,
- };
-
- /*
-@@ -353,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 */
-@@ -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);
-diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
-index a20e7815d814..774a03028da2 100644
---- a/include/linux/usb/hcd.h
-+++ b/include/linux/usb/hcd.h
-@@ -594,6 +594,10 @@ extern void usb_ep0_reinit(struct usb_device *);
- #define GetPortStatus HUB_CLASS_REQ(USB_DIR_IN, USB_RT_PORT, USB_REQ_GET_STATUS)
- #define SetHubFeature HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_HUB, USB_REQ_SET_FEATURE)
- #define SetPortFeature HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_PORT, USB_REQ_SET_FEATURE)
-+#define ClearTTBuffer HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_PORT, HUB_CLEAR_TT_BUFFER)
-+#define ResetTT HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_PORT, HUB_RESET_TT)
-+#define GetTTState HUB_CLASS_REQ(USB_DIR_IN, USB_RT_PORT, HUB_GET_TT_STATE)
-+#define StopTT HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_PORT, HUB_STOP_TT)
-
-
- /*-------------------------------------------------------------------------*/
---
-2.7.4
-