pciehp: fix wait command completion
authorKenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Fri, 22 Dec 2006 01:01:10 +0000 (17:01 -0800)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 7 Feb 2007 23:50:05 +0000 (15:50 -0800)
This patch fixes this problem that pciehp driver will sleep
unnecessarily long when waiting for command completion. With this
patch, modprobe pciehp driver becomes very faster as follows for
instance.

  o Without this patch
    # time /sbin/modprobe pciehp

    real    0m4.976s
    user    0m0.000s
    sys     0m0.004s

  o With this patch
    # time /sbin/modprobe pciehp

    real    0m0.640s
    user    0m0.000s
    sys     0m0.004s

Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/pci/hotplug/pciehp.h
drivers/pci/hotplug/pciehp_hpc.c

index 17167d5..927dba9 100644 (file)
@@ -100,6 +100,7 @@ struct controller {
        u16 vendor_id;
        u8 cap_base;
        struct timer_list poll_timer;
+       volatile int cmd_busy;
 };
 
 #define INT_BUTTON_IGNORE              0
index 9fbd9b9..eb1862b 100644 (file)
@@ -251,20 +251,21 @@ static void start_int_poll_timer(struct controller *ctrl, int sec)
 
 static inline int pcie_wait_cmd(struct controller *ctrl)
 {
-       DECLARE_WAITQUEUE(wait, current);
-
-       add_wait_queue(&ctrl->queue, &wait);
-       if (!pciehp_poll_mode)
-               /* Sleep for up to 1 second */
-               msleep_interruptible(1000);
-       else
-               msleep_interruptible(2500);
+       int retval = 0;
+       unsigned int msecs = pciehp_poll_mode ? 2500 : 1000;
+       unsigned long timeout = msecs_to_jiffies(msecs);
+       int rc;
 
-       remove_wait_queue(&ctrl->queue, &wait);
-       if (signal_pending(current))
-               return -EINTR;
+       rc = wait_event_interruptible_timeout(ctrl->queue,
+                                             !ctrl->cmd_busy, timeout);
+       if (!rc)
+               dbg("Command not completed in 1000 msec\n");
+       else if (rc < 0) {
+               retval = -EINTR;
+               info("Command was interrupted by a signal\n");
+       }
 
-       return 0;
+       return retval;
 }
 
 static int pcie_write_cmd(struct slot *slot, u16 cmd)
@@ -291,6 +292,7 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd)
                    __FUNCTION__);
        }
 
+       ctrl->cmd_busy = 1;
        retval = pciehp_writew(ctrl, SLOTCTRL, (cmd | CMD_CMPL_INTR_ENABLE));
        if (retval) {
                err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
@@ -773,6 +775,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
                /* 
                 * Command Complete Interrupt Pending 
                 */
+               ctrl->cmd_busy = 0;
                wake_up_interruptible(&ctrl->queue);
        }