On Wed, Mar 26, 2014 at 12:44 PM, Alan Stern <[email protected]> wrote: > On Wed, 19 Mar 2014, Dan Williams wrote: > >> In preparation for synchronizing port handling with pm_runtime >> transitions refactor port handling into its own subroutine. >> >> We expect that clearing some status flags will be required regardless of >> the port state, so handle those first and group all non-trivial actions >> at the bottom of the routine. >> >> This also splits off the bottom half of hub_port_connect_change() into >> hub_port_reconnect() in prepartion for introducing a port->status_lock. >> hub_port_reconnect() will expect the port lock to not be held while >> hub_port_connect_change() expects to enter with it held. >> >> Other cleanups include: >> 1/ reflowing to 80 columns >> 2/ replacing redundant usages of 'hub->hdev' with 'hdev' >> 3/ consolidate clearing of ->change_bits() in hub_port_connect_change >> >> Signed-off-by: Dan Williams <[email protected]> > > Although this is basically good, I think it might be worthwhile to > separate the various minor cleanups from the code movement and > reflowing. Also, there is one more cleanup we could attempt. > >> @@ -4390,66 +4390,15 @@ hub_power_remaining (struct usb_hub *hub) >> return remaining; >> } >> >> -/* Handle physical or logical connection change events. >> - * This routine is called when: >> - * a port connection-change occurs; >> - * a port enable-change occurs (often caused by EMI); >> - * usb_reset_and_verify_device() encounters changed descriptors (as from >> - * a firmware download) >> - * caller already locked the hub >> - */ >> -static void hub_port_connect_change(struct usb_hub *hub, int port1, >> - u16 portstatus, u16 portchange) >> +static void hub_port_reconnect(struct usb_hub *hub, int port1, u16 >> portstatus, >> + u16 portchange) >> { >> + int status, i; >> + unsigned unit_load; >> struct usb_device *hdev = hub->hdev; >> struct usb_hcd *hcd = bus_to_hcd(hdev->bus); >> struct usb_port *port_dev = hub->ports[port1 - 1]; >> - struct usb_device *udev; >> - int status, i; >> - unsigned unit_load; > > Not that it makes any difference, but why did you move the declarations > of status, i, and unit_load to the top?
Commit 5a0e3ad6af86 "include cleanup: Update gfp.h and slab.h includes
to prepare for breaking implicit slab.h" introduced me to the concept
of "christmas-tree" or "reverse christmas-tree" declaration ordering.
I wasn't even aware there was such a thing previously, but now I can't
un-learn it and my OCD compels me to "christmas tree all the
declarations!".
> Here's a second question. I don't know if there's any definitive
> answer. What do you think of passing values like hdev, hcd, and
> port_dev as arguments, as opposed to re-deriving them from the other
> values?
>
> In theory, it could result in slightly smaller object code,
> particularly in cases (like here) where the whole routine can be
> inlined. Also, it might reduce slightly the chances for copy/pasting
> errors.
>
> This isn't a big deal either way. But people seem to prefer passing
> fewer arguments, and I have often wondered why.
80 columns?
We could do something like:
struct usb_port_context {
struct usb_port port_dev;
struct usb_hub *hub;
struct usb_device *hdev;
int port1;
u16 portstatus, portchange;
}
...and pass that around. But I think that is a cleanup for another
patch series.
>
>> @@ -4682,6 +4690,125 @@ static int hub_handle_remote_wakeup(struct usb_hub
>> *hub, unsigned int port,
>> return connect_change;
>> }
>>
>> +static void port_event(struct usb_hub *hub, int port1)
>> +{
>> + struct usb_port *port_dev = hub->ports[port1 - 1];
>> + struct usb_device *udev = port_dev->child;
>> + struct usb_device *hdev = hub->hdev;
>> + int connect_change, wakeup_change;
>> + u16 portstatus, portchange;
>
> Another example where passing additional arguments could be beneficial.
>
>> +
>> + connect_change = test_bit(port1, hub->change_bits);
>> + wakeup_change = test_and_clear_bit(port1, hub->wakeup_bits);
>> +
>> + if (hub_port_status(hub, port1, &portstatus, &portchange) < 0)
>> + return;
>> +
>> + if (portchange & USB_PORT_STAT_C_CONNECTION) {
>> + usb_clear_port_feature(hdev, port1,
>> USB_PORT_FEAT_C_CONNECTION);
>> + connect_change = 1;
>> + }
>> +
>> + if (portchange & USB_PORT_STAT_C_ENABLE) {
>> + if (!connect_change)
>> + dev_dbg(&port_dev->dev, "enable change, status %08x\n",
>> + portstatus);
>> + usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE);
>> +
>> + /*
>> + * EM interference sometimes causes badly shielded USB devices
>> + * to be shutdown by the hub, this hack enables them again.
>> + * Works at least with mouse driver.
>> + */
>> + if (!(portstatus & USB_PORT_STAT_ENABLE)
>> + && !connect_change && udev) {
>> + dev_err(&port_dev->dev, "disabled by hub (EMI?),
>> re-enabling...\n");
>> + connect_change = 1;
>> + }
>> + }
>> +
>> + if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
>> + u16 status = 0, unused;
>> +
>> + dev_dbg(&port_dev->dev, " over-current change\n");
>
> Extra ' ' at the start of the string.
fixed.
>
>> + usb_clear_port_feature(hdev, port1,
>> + USB_PORT_FEAT_C_OVER_CURRENT);
>> + msleep(100); /* Cool down */
>> + hub_power_on(hub, true);
>> + hub_port_status(hub, port1, &status, &unused);
>> + if (status & USB_PORT_STAT_OVERCURRENT)
>> + dev_err(&port_dev->dev, "over-current condition\n");
>> + }
>> +
>> + if (portchange & USB_PORT_STAT_C_RESET) {
>> + dev_dbg(&port_dev->dev, "reset change\n");
>> + usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_RESET);
>> + }
>> + if ((portchange & USB_PORT_STAT_C_BH_RESET)
>> + && hub_is_superspeed(hdev)) {
>> + dev_dbg(&port_dev->dev, "warm reset change\n");
>> + usb_clear_port_feature(hdev, port1,
>> + USB_PORT_FEAT_C_BH_PORT_RESET);
>> + }
>> + if (portchange & USB_PORT_STAT_C_LINK_STATE) {
>> + dev_dbg(&port_dev->dev, "link state change\n");
>> + usb_clear_port_feature(hdev, port1,
>> + USB_PORT_FEAT_C_PORT_LINK_STATE);
>> + }
>> + if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) {
>> + dev_warn(&port_dev->dev, "config error\n");
>> + usb_clear_port_feature(hdev, port1,
>> + USB_PORT_FEAT_C_PORT_CONFIG_ERROR);
>> + }
>> +
>> + if (hub_handle_remote_wakeup(hub, port1, portstatus, portchange))
>> + connect_change = 1;
>
> Moving this little portion is a candidate for the cleanup patch.
Moving it where? Sorry I've cache flushed the context for this bit.
>
>> +
>> + /*
>> + * Warm reset a USB3 protocol port if it's in
>> + * SS.Inactive state.
>> + */
>> + if (hub_port_warm_reset_required(hub, portstatus)) {
>> + int status;
>> +
>> + dev_dbg(&port_dev->dev, "do warm reset\n");
>> + if (!udev || !(portstatus & USB_PORT_STAT_CONNECTION)
>> + || udev->state == USB_STATE_NOTATTACHED) {
>> + status = hub_port_reset(hub, port1, NULL,
>> + HUB_BH_RESET_TIME, true);
>> + if (status < 0)
>> + hub_port_disable(hub, port1, 1);
>> + } else {
>> + usb_lock_device(udev);
>> + status = usb_reset_device(udev);
>
> Another cleanup candidate: status doesn't get used.
Went ahead and removed it.
>
>> + usb_unlock_device(udev);
>> + connect_change = 0;
>> + }
>> + /*
>> + * On disconnect USB3 protocol ports transit from U0 to
>> + * SS.Inactive to Rx.Detect. If this happens a warm-
>> + * reset is not needed, but a (re)connect may happen
>> + * before khubd runs and sees the disconnect, and the
>> + * device may be an unknown state.
>> + *
>> + * If the port went through SS.Inactive without khubd
>> + * seeing it the C_LINK_STATE change flag will be set,
>> + * and we reset the dev to put it in a known state.
>> + */
>> + } else if (udev && hub_is_superspeed(hub->hdev) &&
>> + (portchange & USB_PORT_STAT_C_LINK_STATE) &&
>> + (portstatus & USB_PORT_STAT_CONNECTION)) {
>> + usb_lock_device(udev);
>> + usb_reset_device(udev);
>> + usb_unlock_device(udev);
>> + connect_change = 0;
>> + }
>
> This is almost identical to the code just above. The big difference
> is in how the USB_OPRT_STAT_C_LINK_STATE bit in portchange is used.
> Can you figure out how to combine these two pieces?
Done.
Attached for review, but will be resubmitted with a refresh the whole patch set
usb-synchronize-port-poweroff
Description: Binary data
