usb: hub: rename hub_events() to hub_event() and handle only one event there

We would like to convert khubd kthread to a workqueue. As a result hub_events()
will handle only one event per call.

In fact, we could do this already now because there is another cycle in
hub_thread(). It calls hub_events() until hub_event_list is empty.

This patch renames the function to hub_event(), removes the while cycle, and
renames the goto targets from loop* to out*.

When touching the code, it fixes also formatting of dev_err() and dev_dbg()
calls to make checkpatch.pl happy :-)

Signed-off-by: Petr Mladek <pmladek@suse.cz>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Petr Mladek 2014-09-19 17:32:20 +02:00 committed by Greg Kroah-Hartman
parent 5d14f32383
commit eb6e292487

View File

@ -4996,8 +4996,7 @@ static void port_event(struct usb_hub *hub, int port1)
hub_port_connect_change(hub, port1, portstatus, portchange); hub_port_connect_change(hub, port1, portstatus, portchange);
} }
static void hub_event(void)
static void hub_events(void)
{ {
struct list_head *tmp; struct list_head *tmp;
struct usb_device *hdev; struct usb_device *hdev;
@ -5008,144 +5007,131 @@ static void hub_events(void)
u16 hubchange; u16 hubchange;
int i, ret; int i, ret;
/* /* Grab the first entry at the beginning of the list */
* We restart the list every time to avoid a deadlock with spin_lock_irq(&hub_event_lock);
* deleting hubs downstream from this one. This should be if (list_empty(&hub_event_list)) {
* safe since we delete the hub from the event list.
* Not the most efficient, but avoids deadlocks.
*/
while (1) {
/* Grab the first entry at the beginning of the list */
spin_lock_irq(&hub_event_lock);
if (list_empty(&hub_event_list)) {
spin_unlock_irq(&hub_event_lock);
break;
}
tmp = hub_event_list.next;
list_del_init(tmp);
hub = list_entry(tmp, struct usb_hub, event_list);
kref_get(&hub->kref);
spin_unlock_irq(&hub_event_lock); spin_unlock_irq(&hub_event_lock);
return;
}
hdev = hub->hdev; tmp = hub_event_list.next;
hub_dev = hub->intfdev; list_del_init(tmp);
intf = to_usb_interface(hub_dev);
dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n",
hdev->state, hdev->maxchild,
/* NOTE: expects max 15 ports... */
(u16) hub->change_bits[0],
(u16) hub->event_bits[0]);
/* Lock the device, then check to see if we were hub = list_entry(tmp, struct usb_hub, event_list);
* disconnected while waiting for the lock to succeed. */ kref_get(&hub->kref);
usb_lock_device(hdev); spin_unlock_irq(&hub_event_lock);
if (unlikely(hub->disconnected))
goto loop_disconnected;
/* If the hub has died, clean up after it */ hdev = hub->hdev;
if (hdev->state == USB_STATE_NOTATTACHED) { hub_dev = hub->intfdev;
hub->error = -ENODEV; intf = to_usb_interface(hub_dev);
hub_quiesce(hub, HUB_DISCONNECT); dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n",
goto loop; hdev->state, hdev->maxchild,
} /* NOTE: expects max 15 ports... */
(u16) hub->change_bits[0],
(u16) hub->event_bits[0]);
/* Autoresume */ /* Lock the device, then check to see if we were
ret = usb_autopm_get_interface(intf); * disconnected while waiting for the lock to succeed. */
usb_lock_device(hdev);
if (unlikely(hub->disconnected))
goto out_disconnected;
/* If the hub has died, clean up after it */
if (hdev->state == USB_STATE_NOTATTACHED) {
hub->error = -ENODEV;
hub_quiesce(hub, HUB_DISCONNECT);
goto out;
}
/* Autoresume */
ret = usb_autopm_get_interface(intf);
if (ret) {
dev_dbg(hub_dev, "Can't autoresume: %d\n", ret);
goto out;
}
/* If this is an inactive hub, do nothing */
if (hub->quiescing)
goto out_autopm;
if (hub->error) {
dev_dbg(hub_dev, "resetting for error %d\n", hub->error);
ret = usb_reset_device(hdev);
if (ret) { if (ret) {
dev_dbg(hub_dev, "Can't autoresume: %d\n", ret); dev_dbg(hub_dev, "error resetting hub: %d\n", ret);
goto loop; goto out_autopm;
} }
/* If this is an inactive hub, do nothing */ hub->nerrors = 0;
if (hub->quiescing) hub->error = 0;
goto loop_autopm; }
if (hub->error) { /* deal with port status changes */
dev_dbg (hub_dev, "resetting for error %d\n", for (i = 1; i <= hdev->maxchild; i++) {
hub->error); struct usb_port *port_dev = hub->ports[i - 1];
ret = usb_reset_device(hdev); if (test_bit(i, hub->event_bits)
if (ret) { || test_bit(i, hub->change_bits)
dev_dbg (hub_dev, || test_bit(i, hub->wakeup_bits)) {
"error resetting hub: %d\n", ret); /*
goto loop_autopm; * The get_noresume and barrier ensure that if
} * the port was in the process of resuming, we
* flush that work and keep the port active for
hub->nerrors = 0; * the duration of the port_event(). However,
hub->error = 0; * if the port is runtime pm suspended
* (powered-off), we leave it in that state, run
* an abbreviated port_event(), and move on.
*/
pm_runtime_get_noresume(&port_dev->dev);
pm_runtime_barrier(&port_dev->dev);
usb_lock_port(port_dev);
port_event(hub, i);
usb_unlock_port(port_dev);
pm_runtime_put_sync(&port_dev->dev);
} }
}
/* deal with port status changes */ /* deal with hub status changes */
for (i = 1; i <= hdev->maxchild; i++) { if (test_and_clear_bit(0, hub->event_bits) == 0)
struct usb_port *port_dev = hub->ports[i - 1]; ; /* do nothing */
else if (hub_hub_status(hub, &hubstatus, &hubchange) < 0)
if (test_bit(i, hub->event_bits) dev_err(hub_dev, "get_hub_status failed\n");
|| test_bit(i, hub->change_bits) else {
|| test_bit(i, hub->wakeup_bits)) { if (hubchange & HUB_CHANGE_LOCAL_POWER) {
/* dev_dbg(hub_dev, "power change\n");
* The get_noresume and barrier ensure that if clear_hub_feature(hdev, C_HUB_LOCAL_POWER);
* the port was in the process of resuming, we if (hubstatus & HUB_STATUS_LOCAL_POWER)
* flush that work and keep the port active for /* FIXME: Is this always true? */
* the duration of the port_event(). However, hub->limited_power = 1;
* if the port is runtime pm suspended else
* (powered-off), we leave it in that state, run hub->limited_power = 0;
* an abbreviated port_event(), and move on.
*/
pm_runtime_get_noresume(&port_dev->dev);
pm_runtime_barrier(&port_dev->dev);
usb_lock_port(port_dev);
port_event(hub, i);
usb_unlock_port(port_dev);
pm_runtime_put_sync(&port_dev->dev);
}
} }
if (hubchange & HUB_CHANGE_OVERCURRENT) {
u16 status = 0;
u16 unused;
/* deal with hub status changes */ dev_dbg(hub_dev, "over-current change\n");
if (test_and_clear_bit(0, hub->event_bits) == 0) clear_hub_feature(hdev, C_HUB_OVER_CURRENT);
; /* do nothing */ msleep(500); /* Cool down */
else if (hub_hub_status(hub, &hubstatus, &hubchange) < 0) hub_power_on(hub, true);
dev_err (hub_dev, "get_hub_status failed\n"); hub_hub_status(hub, &status, &unused);
else { if (status & HUB_STATUS_OVERCURRENT)
if (hubchange & HUB_CHANGE_LOCAL_POWER) { dev_err(hub_dev, "over-current condition\n");
dev_dbg (hub_dev, "power change\n");
clear_hub_feature(hdev, C_HUB_LOCAL_POWER);
if (hubstatus & HUB_STATUS_LOCAL_POWER)
/* FIXME: Is this always true? */
hub->limited_power = 1;
else
hub->limited_power = 0;
}
if (hubchange & HUB_CHANGE_OVERCURRENT) {
u16 status = 0;
u16 unused;
dev_dbg(hub_dev, "over-current change\n");
clear_hub_feature(hdev, C_HUB_OVER_CURRENT);
msleep(500); /* Cool down */
hub_power_on(hub, true);
hub_hub_status(hub, &status, &unused);
if (status & HUB_STATUS_OVERCURRENT)
dev_err(hub_dev, "over-current "
"condition\n");
}
} }
}
loop_autopm: out_autopm:
/* Balance the usb_autopm_get_interface() above */ /* Balance the usb_autopm_get_interface() above */
usb_autopm_put_interface_no_suspend(intf); usb_autopm_put_interface_no_suspend(intf);
loop: out:
/* Balance the usb_autopm_get_interface_no_resume() in /* Balance the usb_autopm_get_interface_no_resume() in
* kick_khubd() and allow autosuspend. * kick_khubd() and allow autosuspend.
*/ */
usb_autopm_put_interface(intf); usb_autopm_put_interface(intf);
loop_disconnected: out_disconnected:
usb_unlock_device(hdev); usb_unlock_device(hdev);
kref_put(&hub->kref, hub_release); kref_put(&hub->kref, hub_release);
} /* end while (1) */
} }
static int hub_thread(void *__unused) static int hub_thread(void *__unused)
@ -5158,7 +5144,7 @@ static int hub_thread(void *__unused)
set_freezable(); set_freezable();
do { do {
hub_events(); hub_event();
wait_event_freezable(khubd_wait, wait_event_freezable(khubd_wait,
!list_empty(&hub_event_list) || !list_empty(&hub_event_list) ||
kthread_should_stop()); kthread_should_stop());