linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: linux-kernel@vger.kernel.org, stable@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	alan@lxorguk.ukuu.org.uk, Elric Fu <elricfu1@gmail.com>,
	Sarah Sharp <sarah.a.sharp@linux.intel.com>,
	Miroslav Sabljic <miroslav.sabljic@avl.com>
Subject: [ 29/52] xHCI: add aborting command ring function
Date: Thu,  4 Oct 2012 14:21:20 -0700	[thread overview]
Message-ID: <20121004210638.997023603@linuxfoundation.org> (raw)
In-Reply-To: <20121004210635.372689554@linuxfoundation.org>

3.4-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Elric Fu <elricfu1@gmail.com>

commit b92cc66c047ff7cf587b318fe377061a353c120f upstream.

Software have to abort command ring and cancel command
when a command is failed or hang. Otherwise, the command
ring will hang up and can't handle the others. An example
of a command that may hang is the Address Device Command,
because waiting for a SET_ADDRESS request to be acknowledged
by a USB device is outside of the xHC's ability to control.

To cancel a command, software will initialize a command
descriptor for the cancel command, and add it into a
cancel_cmd_list of xhci.

Sarah: Fixed missing newline on "Have the command ring been stopped?"
debugging statement.

This patch should be backported to kernels as old as 3.0, that contain
the commit 7ed603ecf8b68ab81f4c83097d3063d43ec73bb8 "xhci: Add an
assertion to check for virt_dev=0 bug." That commit papers over a NULL
pointer dereference, and this patch fixes the underlying issue that
caused the NULL pointer dereference.

Signed-off-by: Elric Fu <elricfu1@gmail.com>
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Tested-by: Miroslav Sabljic <miroslav.sabljic@avl.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

---
 drivers/usb/host/xhci-mem.c  |    7 ++
 drivers/usb/host/xhci-ring.c |  108 +++++++++++++++++++++++++++++++++++++++++++
 drivers/usb/host/xhci.c      |    2 
 drivers/usb/host/xhci.h      |   12 ++++
 4 files changed, 128 insertions(+), 1 deletion(-)

--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1772,6 +1772,7 @@ void xhci_mem_cleanup(struct xhci_hcd *x
 {
 	struct pci_dev	*pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
 	struct dev_info	*dev_info, *next;
+	struct xhci_cd  *cur_cd, *next_cd;
 	unsigned long	flags;
 	int size;
 	int i, j, num_ports;
@@ -1793,6 +1794,11 @@ void xhci_mem_cleanup(struct xhci_hcd *x
 		xhci_ring_free(xhci, xhci->cmd_ring);
 	xhci->cmd_ring = NULL;
 	xhci_dbg(xhci, "Freed command ring\n");
+	list_for_each_entry_safe(cur_cd, next_cd,
+			&xhci->cancel_cmd_list, cancel_cmd_list) {
+		list_del(&cur_cd->cancel_cmd_list);
+		kfree(cur_cd);
+	}
 
 	for (i = 1; i < MAX_HC_SLOTS; ++i)
 		xhci_free_virt_device(xhci, i);
@@ -2338,6 +2344,7 @@ int xhci_mem_init(struct xhci_hcd *xhci,
 	xhci->cmd_ring = xhci_ring_alloc(xhci, 1, 1, TYPE_COMMAND, flags);
 	if (!xhci->cmd_ring)
 		goto fail;
+	INIT_LIST_HEAD(&xhci->cancel_cmd_list);
 	xhci_dbg(xhci, "Allocated command ring at %p\n", xhci->cmd_ring);
 	xhci_dbg(xhci, "First segment DMA is 0x%llx\n",
 			(unsigned long long)xhci->cmd_ring->first_seg->dma);
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -289,6 +289,114 @@ void xhci_ring_cmd_db(struct xhci_hcd *x
 	xhci_readl(xhci, &xhci->dba->doorbell[0]);
 }
 
+static int xhci_abort_cmd_ring(struct xhci_hcd *xhci)
+{
+	u64 temp_64;
+	int ret;
+
+	xhci_dbg(xhci, "Abort command ring\n");
+
+	if (!(xhci->cmd_ring_state & CMD_RING_STATE_RUNNING)) {
+		xhci_dbg(xhci, "The command ring isn't running, "
+				"Have the command ring been stopped?\n");
+		return 0;
+	}
+
+	temp_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
+	if (!(temp_64 & CMD_RING_RUNNING)) {
+		xhci_dbg(xhci, "Command ring had been stopped\n");
+		return 0;
+	}
+	xhci->cmd_ring_state = CMD_RING_STATE_ABORTED;
+	xhci_write_64(xhci, temp_64 | CMD_RING_ABORT,
+			&xhci->op_regs->cmd_ring);
+
+	/* Section 4.6.1.2 of xHCI 1.0 spec says software should
+	 * time the completion od all xHCI commands, including
+	 * the Command Abort operation. If software doesn't see
+	 * CRR negated in a timely manner (e.g. longer than 5
+	 * seconds), then it should assume that the there are
+	 * larger problems with the xHC and assert HCRST.
+	 */
+	ret = handshake(xhci, &xhci->op_regs->cmd_ring,
+			CMD_RING_RUNNING, 0, 5 * 1000 * 1000);
+	if (ret < 0) {
+		xhci_err(xhci, "Stopped the command ring failed, "
+				"maybe the host is dead\n");
+		xhci->xhc_state |= XHCI_STATE_DYING;
+		xhci_quiesce(xhci);
+		xhci_halt(xhci);
+		return -ESHUTDOWN;
+	}
+
+	return 0;
+}
+
+static int xhci_queue_cd(struct xhci_hcd *xhci,
+		struct xhci_command *command,
+		union xhci_trb *cmd_trb)
+{
+	struct xhci_cd *cd;
+	cd = kzalloc(sizeof(struct xhci_cd), GFP_ATOMIC);
+	if (!cd)
+		return -ENOMEM;
+	INIT_LIST_HEAD(&cd->cancel_cmd_list);
+
+	cd->command = command;
+	cd->cmd_trb = cmd_trb;
+	list_add_tail(&cd->cancel_cmd_list, &xhci->cancel_cmd_list);
+
+	return 0;
+}
+
+/*
+ * Cancel the command which has issue.
+ *
+ * Some commands may hang due to waiting for acknowledgement from
+ * usb device. It is outside of the xHC's ability to control and
+ * will cause the command ring is blocked. When it occurs software
+ * should intervene to recover the command ring.
+ * See Section 4.6.1.1 and 4.6.1.2
+ */
+int xhci_cancel_cmd(struct xhci_hcd *xhci, struct xhci_command *command,
+		union xhci_trb *cmd_trb)
+{
+	int retval = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&xhci->lock, flags);
+
+	if (xhci->xhc_state & XHCI_STATE_DYING) {
+		xhci_warn(xhci, "Abort the command ring,"
+				" but the xHCI is dead.\n");
+		retval = -ESHUTDOWN;
+		goto fail;
+	}
+
+	/* queue the cmd desriptor to cancel_cmd_list */
+	retval = xhci_queue_cd(xhci, command, cmd_trb);
+	if (retval) {
+		xhci_warn(xhci, "Queuing command descriptor failed.\n");
+		goto fail;
+	}
+
+	/* abort command ring */
+	retval = xhci_abort_cmd_ring(xhci);
+	if (retval) {
+		xhci_err(xhci, "Abort command ring failed\n");
+		if (unlikely(retval == -ESHUTDOWN)) {
+			spin_unlock_irqrestore(&xhci->lock, flags);
+			usb_hc_died(xhci_to_hcd(xhci)->primary_hcd);
+			xhci_dbg(xhci, "xHCI host controller is dead.\n");
+			return retval;
+		}
+	}
+
+fail:
+	spin_unlock_irqrestore(&xhci->lock, flags);
+	return retval;
+}
+
 void xhci_ring_ep_doorbell(struct xhci_hcd *xhci,
 		unsigned int slot_id,
 		unsigned int ep_index,
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -52,7 +52,7 @@ MODULE_PARM_DESC(link_quirk, "Don't clea
  * handshake done).  There are two failure modes:  "usec" have passed (major
  * hardware flakeout), or the register reads as all-ones (hardware removed).
  */
-static int handshake(struct xhci_hcd *xhci, void __iomem *ptr,
+int handshake(struct xhci_hcd *xhci, void __iomem *ptr,
 		      u32 mask, u32 done, int usec)
 {
 	u32	result;
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1252,6 +1252,13 @@ struct xhci_td {
 	union xhci_trb		*last_trb;
 };
 
+/* command descriptor */
+struct xhci_cd {
+	struct list_head	cancel_cmd_list;
+	struct xhci_command	*command;
+	union xhci_trb		*cmd_trb;
+};
+
 struct xhci_dequeue_state {
 	struct xhci_segment *new_deq_seg;
 	union xhci_trb *new_deq_ptr;
@@ -1421,6 +1428,7 @@ struct xhci_hcd {
 #define CMD_RING_STATE_RUNNING         (1 << 0)
 #define CMD_RING_STATE_ABORTED         (1 << 1)
 #define CMD_RING_STATE_STOPPED         (1 << 2)
+	struct list_head        cancel_cmd_list;
 	unsigned int		cmd_ring_reserved_trbs;
 	struct xhci_ring	*event_ring;
 	struct xhci_erst	erst;
@@ -1699,6 +1707,8 @@ static inline void xhci_unregister_plat(
 
 /* xHCI host controller glue */
 typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *);
+int handshake(struct xhci_hcd *xhci, void __iomem *ptr,
+		u32 mask, u32 done, int usec);
 void xhci_quiesce(struct xhci_hcd *xhci);
 int xhci_halt(struct xhci_hcd *xhci);
 int xhci_reset(struct xhci_hcd *xhci);
@@ -1789,6 +1799,8 @@ void xhci_queue_config_ep_quirk(struct x
 		unsigned int slot_id, unsigned int ep_index,
 		struct xhci_dequeue_state *deq_state);
 void xhci_stop_endpoint_command_watchdog(unsigned long arg);
+int xhci_cancel_cmd(struct xhci_hcd *xhci, struct xhci_command *command,
+		union xhci_trb *cmd_trb);
 void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id,
 		unsigned int ep_index, unsigned int stream_id);
 



  parent reply	other threads:[~2012-10-04 21:44 UTC|newest]

Thread overview: 57+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-10-04 21:20 [ 00/52] 3.4.13-stable review Greg Kroah-Hartman
2012-10-04 21:20 ` [ 01/52] vfs: dcache: fix deadlock in tree traversal Greg Kroah-Hartman
2012-10-04 21:20 ` [ 02/52] dm: handle requests beyond end of device instead of using BUG_ON Greg Kroah-Hartman
2012-10-04 21:20 ` [ 03/52] dm table: clear add_random unless all devices have it set Greg Kroah-Hartman
2012-10-04 21:20 ` [ 04/52] dm verity: fix overflow check Greg Kroah-Hartman
2012-10-04 21:20 ` [ 05/52] usb: gadget: dummy_hcd: fixup error probe path Greg Kroah-Hartman
2012-10-04 21:20 ` [ 06/52] USB: option: blacklist QMI interface on ZTE MF683 Greg Kroah-Hartman
2012-10-04 21:20 ` [ 07/52] USB: ftdi_sio: add TIAO USB Multi-Protocol Adapter (TUMPA) support Greg Kroah-Hartman
2012-10-04 21:20 ` [ 08/52] USB: qcaux: add Pantech vendor class match Greg Kroah-Hartman
2012-10-04 21:21 ` [ 09/52] usb: host: xhci: Fix Null pointer dereferencing with 71c731a for non-x86 systems Greg Kroah-Hartman
2012-10-04 21:21 ` [ 10/52] staging: speakup_soft: Fix reading of init string Greg Kroah-Hartman
2012-10-04 21:21 ` [ 11/52] tty: keyboard.c: Remove locking from vt_get_leds Greg Kroah-Hartman
2012-10-04 21:21 ` [ 12/52] staging: r8712u: Do not queue cloned skb Greg Kroah-Hartman
2012-10-04 21:21 ` [ 13/52] staging: comedi: s626: dont dereference insn->data Greg Kroah-Hartman
2012-10-04 21:21 ` [ 14/52] staging: comedi: jr3_pci: fix iomem dereference Greg Kroah-Hartman
2012-10-04 21:21 ` [ 15/52] staging: comedi: dont dereference user memory for INSN_INTTRIG Greg Kroah-Hartman
2012-10-04 21:21 ` [ 16/52] staging: comedi: fix memory leak for saved channel list Greg Kroah-Hartman
2012-10-04 21:21 ` [ 17/52] Remove BUG_ON from n_tty_read() Greg Kroah-Hartman
2012-10-04 21:21 ` [ 18/52] TTY: ttyprintk, dont touch behind tty->write_buf Greg Kroah-Hartman
2012-10-04 21:21 ` [ 19/52] serial: omap: fix software flow control Greg Kroah-Hartman
2012-10-04 21:21 ` [ 20/52] serial: pl011: handle corruption at high clock speeds Greg Kroah-Hartman
2012-10-04 21:21 ` [ 21/52] serial: set correct baud_base for EXSYS EX-41092 Dual 16950 Greg Kroah-Hartman
2012-10-04 21:21 ` [ 22/52] tools/hv: Fix file handle leak Greg Kroah-Hartman
2012-10-04 21:21 ` [ 23/52] tools/hv: Fix exit() error code Greg Kroah-Hartman
2012-10-04 21:21 ` [ 24/52] tools/hv: Check for read/write errors Greg Kroah-Hartman
2012-10-04 21:21 ` [ 25/52] b43legacy: Fix crash on unload when firmware not available Greg Kroah-Hartman
2012-10-04 21:21 ` [ 26/52] firmware: Add missing attributes to EFI variable attribute print out from sysfs Greg Kroah-Hartman
2012-10-04 21:21 ` [ 27/52] xhci: Intel Panther Point BEI quirk Greg Kroah-Hartman
2012-10-04 21:21 ` [ 28/52] xHCI: add cmd_ring_state Greg Kroah-Hartman
2012-10-07  0:54   ` Ben Hutchings
2012-10-07 14:39     ` Greg Kroah-Hartman
2012-10-04 21:21 ` Greg Kroah-Hartman [this message]
2012-10-07  1:02   ` [ 29/52] xHCI: add aborting command ring function Ben Hutchings
2012-10-08 20:48     ` Sarah Sharp
2012-10-04 21:21 ` [ 30/52] xHCI: cancel command after command timeout Greg Kroah-Hartman
2012-10-04 21:21 ` [ 31/52] xHCI: handle command after aborting the command ring Greg Kroah-Hartman
2012-10-04 21:21 ` [ 32/52] Increase XHCI suspend timeout to 16ms Greg Kroah-Hartman
2012-10-04 21:21 ` [ 33/52] ath9k: Disable ASPM only for AR9285 Greg Kroah-Hartman
2012-10-04 21:21 ` [ 34/52] coredump: prevent double-free on an error path in core dumper Greg Kroah-Hartman
2012-10-04 21:21 ` [ 35/52] n_gsm.c: Implement 3GPP27.010 DLC start-up procedure in MUX Greg Kroah-Hartman
2012-10-04 21:21 ` [ 36/52] n_gsm: uplink SKBs accumulate on list Greg Kroah-Hartman
2012-10-04 21:21 ` [ 37/52] n_gsm: added interlocking for gsm_data_lock for certain code paths Greg Kroah-Hartman
2012-10-04 21:21 ` [ 38/52] n_gsm: memory leak in uplink error path Greg Kroah-Hartman
2012-10-04 21:21 ` [ 39/52] UBI: fix autoresize handling in R/O mode Greg Kroah-Hartman
2012-10-04 21:21 ` [ 40/52] Yama: handle 32-bit userspace prctl Greg Kroah-Hartman
2012-10-04 21:21 ` [ 41/52] SCSI: ibmvscsi: Fix host config length field overflow Greg Kroah-Hartman
2012-10-04 21:21 ` [ 42/52] SCSI: hpsa: Use LUN reset instead of target reset Greg Kroah-Hartman
2012-10-04 21:21 ` [ 43/52] can: mscan-mpc5xxx: fix return value check in mpc512x_can_get_clock() Greg Kroah-Hartman
2012-10-04 21:21 ` [ 44/52] remoteproc: select VIRTIO to avoid build breakage Greg Kroah-Hartman
2012-10-04 21:21 ` [ 45/52] remoteproc: fix a potential NULL-dereference on cleanup Greg Kroah-Hartman
2012-10-04 21:21 ` [ 46/52] IPoIB: Fix use-after-free of multicast object Greg Kroah-Hartman
2012-10-04 21:21 ` [ 47/52] IB/srp: Fix use-after-free in srp_reset_req() Greg Kroah-Hartman
2012-10-04 21:21 ` [ 48/52] IB/srp: Avoid having aborted requests hang Greg Kroah-Hartman
2012-10-04 21:21 ` [ 49/52] isci: fix isci_pci_probe() generates warning on efi failure path Greg Kroah-Hartman
2012-10-04 21:21 ` [ 50/52] x86/alternatives: Fix p6 nops on non-modular kernels Greg Kroah-Hartman
2012-10-04 21:21 ` [ 51/52] SCSI: scsi_remove_target: fix softlockup regression on hot remove Greg Kroah-Hartman
2012-10-04 21:21 ` [ 52/52] SCSI: scsi_dh_alua: Enable STPG for unavailable ports Greg Kroah-Hartman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20121004210638.997023603@linuxfoundation.org \
    --to=gregkh@linuxfoundation.org \
    --cc=alan@lxorguk.ukuu.org.uk \
    --cc=elricfu1@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=miroslav.sabljic@avl.com \
    --cc=sarah.a.sharp@linux.intel.com \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).