From: OGAWA Hirofumi <hirof...@mail.parknet.co.jp>

This is preparation to fix abort operation race (See "xhci: Fix race
related to abort operation"). To make timeout sleepable, use
delayed_work instead of timer.

[change a newly added pending timer fix to pending work -Mathias]
Signed-off-by: OGAWA Hirofumi <hirof...@mail.parknet.co.jp>
Signed-off-by: Mathias Nyman <mathias.ny...@linux.intel.com>
---
 drivers/usb/host/xhci-mem.c  |  7 +++----
 drivers/usb/host/xhci-ring.c | 26 ++++++++++++++++----------
 drivers/usb/host/xhci.h      |  4 ++--
 3 files changed, 21 insertions(+), 16 deletions(-)

diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 1dfd1c2..57c038c 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1829,7 +1829,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
        int size;
        int i, j, num_ports;
 
-       del_timer_sync(&xhci->cmd_timer);
+       cancel_delayed_work_sync(&xhci->cmd_timer);
 
        /* Free the Event Ring Segment Table and the actual Event Ring */
        size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries);
@@ -2376,9 +2376,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
 
        INIT_LIST_HEAD(&xhci->cmd_list);
 
-       /* init command timeout timer */
-       setup_timer(&xhci->cmd_timer, xhci_handle_command_timeout,
-                   (unsigned long)xhci);
+       /* init command timeout work */
+       INIT_DELAYED_WORK(&xhci->cmd_timer, xhci_handle_command_timeout);
 
        page_size = readl(&xhci->op_regs->page_size);
        xhci_dbg_trace(xhci, trace_xhci_dbg_init,
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 2f453e4..fdff6a4 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -279,6 +279,11 @@ void xhci_ring_cmd_db(struct xhci_hcd *xhci)
        readl(&xhci->dba->doorbell[0]);
 }
 
+static bool xhci_mod_cmd_timer(struct xhci_hcd *xhci, unsigned long delay)
+{
+       return mod_delayed_work(system_wq, &xhci->cmd_timer, delay);
+}
+
 static int xhci_abort_cmd_ring(struct xhci_hcd *xhci)
 {
        u64 temp_64;
@@ -295,7 +300,7 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci)
         * but the completion event in never sent. Use the cmd timeout timer to
         * handle those cases. Use twice the time to cover the bit polling retry
         */
-       mod_timer(&xhci->cmd_timer, jiffies + (2 * XHCI_CMD_DEFAULT_TIMEOUT));
+       xhci_mod_cmd_timer(xhci, 2 * XHCI_CMD_DEFAULT_TIMEOUT);
        xhci_write_64(xhci, temp_64 | CMD_RING_ABORT,
                        &xhci->op_regs->cmd_ring);
 
@@ -320,7 +325,7 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci)
 
                xhci_err(xhci, "Stopped the command ring failed, "
                                "maybe the host is dead\n");
-               del_timer(&xhci->cmd_timer);
+               cancel_delayed_work(&xhci->cmd_timer);
                xhci->xhc_state |= XHCI_STATE_DYING;
                xhci_halt(xhci);
                return -ESHUTDOWN;
@@ -1251,21 +1256,22 @@ static void xhci_handle_stopped_cmd_ring(struct 
xhci_hcd *xhci,
        if ((xhci->cmd_ring->dequeue != xhci->cmd_ring->enqueue) &&
            !(xhci->xhc_state & XHCI_STATE_DYING)) {
                xhci->current_cmd = cur_cmd;
-               mod_timer(&xhci->cmd_timer, jiffies + XHCI_CMD_DEFAULT_TIMEOUT);
+               xhci_mod_cmd_timer(xhci, XHCI_CMD_DEFAULT_TIMEOUT);
                xhci_ring_cmd_db(xhci);
        }
        return;
 }
 
 
-void xhci_handle_command_timeout(unsigned long data)
+void xhci_handle_command_timeout(struct work_struct *work)
 {
        struct xhci_hcd *xhci;
        int ret;
        unsigned long flags;
        u64 hw_ring_state;
        bool second_timeout = false;
-       xhci = (struct xhci_hcd *) data;
+
+       xhci = container_of(to_delayed_work(work), struct xhci_hcd, cmd_timer);
 
        spin_lock_irqsave(&xhci->lock, flags);
 
@@ -1273,7 +1279,7 @@ void xhci_handle_command_timeout(unsigned long data)
         * If timeout work is pending, or current_cmd is NULL, it means we
         * raced with command completion. Command is handled so just return.
         */
-       if (!xhci->current_cmd || timer_pending(&xhci->cmd_timer)) {
+       if (!xhci->current_cmd || delayed_work_pending(&xhci->cmd_timer)) {
                spin_unlock_irqrestore(&xhci->lock, flags);
                return;
        }
@@ -1346,7 +1352,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
 
        cmd = list_entry(xhci->cmd_list.next, struct xhci_command, cmd_list);
 
-       del_timer(&xhci->cmd_timer);
+       cancel_delayed_work(&xhci->cmd_timer);
 
        trace_xhci_cmd_completion(cmd_trb, (struct xhci_generic_trb *) event);
 
@@ -1437,7 +1443,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
        if (cmd->cmd_list.next != &xhci->cmd_list) {
                xhci->current_cmd = list_entry(cmd->cmd_list.next,
                                               struct xhci_command, cmd_list);
-               mod_timer(&xhci->cmd_timer, jiffies + XHCI_CMD_DEFAULT_TIMEOUT);
+               xhci_mod_cmd_timer(xhci, XHCI_CMD_DEFAULT_TIMEOUT);
        } else if (xhci->current_cmd == cmd) {
                xhci->current_cmd = NULL;
        }
@@ -3808,9 +3814,9 @@ static int queue_command(struct xhci_hcd *xhci, struct 
xhci_command *cmd,
 
        /* if there are no other commands queued we start the timeout timer */
        if (xhci->cmd_list.next == &cmd->cmd_list &&
-           !timer_pending(&xhci->cmd_timer)) {
+           !delayed_work_pending(&xhci->cmd_timer)) {
                xhci->current_cmd = cmd;
-               mod_timer(&xhci->cmd_timer, jiffies + XHCI_CMD_DEFAULT_TIMEOUT);
+               xhci_mod_cmd_timer(xhci, XHCI_CMD_DEFAULT_TIMEOUT);
        }
 
        queue_trb(xhci, xhci->cmd_ring, false, field1, field2, field3,
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 8ccc11a..b54c486 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1568,7 +1568,7 @@ struct xhci_hcd {
 #define CMD_RING_STATE_STOPPED         (1 << 2)
        struct list_head        cmd_list;
        unsigned int            cmd_ring_reserved_trbs;
-       struct timer_list       cmd_timer;
+       struct delayed_work     cmd_timer;
        struct xhci_command     *current_cmd;
        struct xhci_ring        *event_ring;
        struct xhci_erst        erst;
@@ -1934,7 +1934,7 @@ void xhci_queue_config_ep_quirk(struct xhci_hcd *xhci,
                unsigned int slot_id, unsigned int ep_index,
                struct xhci_dequeue_state *deq_state);
 void xhci_stop_endpoint_command_watchdog(unsigned long arg);
-void xhci_handle_command_timeout(unsigned long data);
+void xhci_handle_command_timeout(struct work_struct *work);
 
 void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id,
                unsigned int ep_index, unsigned int stream_id);
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to