Print this page
4782 usba shouldn't abuse ddi_get_time(9f)
Reviewed by: Robert Mustacchi <rm@joyent.com>


   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2012 Garrett D'Amore <garrett@damore.org>.  All rights reserved.

  24  */
  25 
  26 /*
  27  * USBA: Solaris USB Architecture support for the hub
  28  * including root hub
  29  * Most of the code for hubd resides in this file and
  30  * is shared between the HCD root hub support and hubd
  31  */
  32 #define USBA_FRAMEWORK
  33 #include <sys/usb/usba.h>
  34 #include <sys/usb/usba/usba_devdb.h>
  35 #include <sys/sunndi.h>
  36 #include <sys/usb/usba/usba_impl.h>
  37 #include <sys/usb/usba/usba_types.h>
  38 #include <sys/usb/usba/hubdi.h>
  39 #include <sys/usb/usba/hcdi_impl.h>
  40 #include <sys/usb/hubd/hub.h>
  41 #include <sys/usb/hubd/hubdvar.h>
  42 #include <sys/usb/hubd/hubd_impl.h>
  43 #include <sys/kobj.h>


 732  * NOTE: suspend here means going to lower power, not CPR suspend.
 733  */
 734 static int
 735 hubd_can_suspend(hubd_t *hubd)
 736 {
 737         hub_power_t     *hubpm;
 738         int             total_power = 0;
 739         usb_port_t      port;
 740 
 741         hubpm = hubd->h_hubpm;
 742 
 743         if (DEVI_IS_DETACHING(hubd->h_dip)) {
 744 
 745                 return (USB_SUCCESS);
 746         }
 747 
 748         /*
 749          * Don't go to lower power if haven't been at full power for enough
 750          * time to let hotplug thread kickoff.
 751          */
 752         if (ddi_get_time() < (hubpm->hubp_time_at_full_power +
 753             hubpm->hubp_min_pm_threshold)) {
 754 
 755                 return (USB_FAILURE);
 756         }
 757 
 758         for (port = 1; (total_power == 0) &&
 759             (port <= hubd->h_hub_descr.bNbrPorts); port++) {
 760                 total_power += hubpm->hubp_child_pwrstate[port];
 761         }
 762 
 763         USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
 764             "hubd_can_suspend: %d", total_power);
 765 
 766         return (total_power ? USB_FAILURE : USB_SUCCESS);
 767 }
 768 
 769 
 770 /*
 771  * resume port depending on current device state
 772  */


1703         hub_power_t     *hubpm;
1704         int             rval;
1705 
1706         USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, "hubd_pwrlvl3");
1707 
1708         hubpm = hubd->h_hubpm;
1709         switch (hubd->h_dev_state) {
1710         case USB_DEV_PWRED_DOWN:
1711                 ASSERT(hubpm->hubp_current_power == USB_DEV_OS_PWR_OFF);
1712                 if (usba_is_root_hub(hubd->h_dip)) {
1713                         /* implement global resume here */
1714                         USB_DPRINTF_L2(DPRINT_MASK_PM,
1715                             hubd->h_log_handle,
1716                             "Global Resume: Not Yet Implemented");
1717                 }
1718                 /* Issue USB D0 command to the device here */
1719                 rval = usb_set_device_pwrlvl0(hubd->h_dip);
1720                 ASSERT(rval == USB_SUCCESS);
1721                 hubd->h_dev_state = USB_DEV_ONLINE;
1722                 hubpm->hubp_current_power = USB_DEV_OS_FULL_PWR;
1723                 hubpm->hubp_time_at_full_power = ddi_get_time();
1724                 hubd_start_polling(hubd, 0);
1725 
1726                 /* FALLTHRU */
1727         case USB_DEV_ONLINE:
1728                 /* we are already in full power */
1729 
1730                 /* FALLTHRU */
1731         case USB_DEV_DISCONNECTED:
1732         case USB_DEV_SUSPENDED:
1733                 /*
1734                  * PM framework tries to put you in full power
1735                  * during system shutdown. If we are disconnected
1736                  * return success. Also, we should not change state
1737                  * when we are disconnected or suspended or about to
1738                  * transition to that state
1739                  */
1740 
1741                 return (USB_SUCCESS);
1742         default:
1743                 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle,


3695 
3696                 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
3697                     "hubd_hotplug_thread: "
3698                     "bus_power in progress/hotplugging undesirable - quit");
3699 
3700                 return;
3701         }
3702         mutex_exit(HUBD_MUTEX(hubd));
3703 
3704         ndi_hold_devi(hdip); /* so we don't race with detach */
3705 
3706         mutex_enter(HUBD_MUTEX(hubd));
3707 
3708         /* is this the root hub? */
3709         if (hdip == rh_dip) {
3710                 if (hubd->h_dev_state == USB_DEV_PWRED_DOWN) {
3711                         hubpm = hubd->h_hubpm;
3712 
3713                         /* mark the root hub as full power */
3714                         hubpm->hubp_current_power = USB_DEV_OS_FULL_PWR;
3715                         hubpm->hubp_time_at_full_power = ddi_get_time();
3716                         mutex_exit(HUBD_MUTEX(hubd));
3717 
3718                         USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
3719                             "hubd_hotplug_thread: call pm_power_has_changed");
3720 
3721                         (void) pm_power_has_changed(hdip, 0,
3722                             USB_DEV_OS_FULL_PWR);
3723 
3724                         mutex_enter(HUBD_MUTEX(hubd));
3725                         hubd->h_dev_state = USB_DEV_ONLINE;
3726                 }
3727 
3728         } else {
3729                 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
3730                     "hubd_hotplug_thread: not root hub");
3731         }
3732 
3733         mutex_exit(HUBD_MUTEX(hubd));
3734 
3735         /*


7256 /*
7257  * Power management
7258  *
7259  * create the pm components required for power management
7260  */
7261 static void
7262 hubd_create_pm_components(dev_info_t *dip, hubd_t *hubd)
7263 {
7264         hub_power_t     *hubpm;
7265 
7266         USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
7267             "hubd_create_pm_components: Begin");
7268 
7269         /* Allocate the state structure */
7270         hubpm = kmem_zalloc(sizeof (hub_power_t), KM_SLEEP);
7271 
7272         hubd->h_hubpm = hubpm;
7273         hubpm->hubp_hubd = hubd;
7274         hubpm->hubp_pm_capabilities = 0;
7275         hubpm->hubp_current_power = USB_DEV_OS_FULL_PWR;
7276         hubpm->hubp_time_at_full_power = ddi_get_time();
7277         hubpm->hubp_min_pm_threshold = hubdi_min_pm_threshold;
7278 
7279         /* alloc memory to save power states of children */
7280         hubpm->hubp_child_pwrstate = (uint8_t *)
7281             kmem_zalloc(MAX_PORTS + 1, KM_SLEEP);
7282 
7283         /*
7284          * if the enable remote wakeup fails
7285          * we still want to enable
7286          * parent notification so we can PM the children
7287          */
7288         usb_enable_parent_notification(dip);
7289 
7290         if (usb_handle_remote_wakeup(dip,
7291             USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) {
7292                 uint_t          pwr_states;
7293 
7294                 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle,
7295                     "hubd_create_pm_components: "
7296                     "Remote Wakeup Enabled");
7297 


8692 
8693         if (hubd_wait_for_hotplug_exit(hubd) == USB_FAILURE) {
8694                 /* we got woken up because of a timeout */
8695                 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG,
8696                     hubd->h_log_handle, "Time out when resetting the device"
8697                     " %s%d. Please disconnect and reconnect this device.",
8698                     devname, devinst);
8699 
8700                 goto Fail;
8701         }
8702 
8703         hubd->h_hotplug_thread++;
8704 
8705         /* is this the root hub? */
8706         if ((hdip == rh_dip) &&
8707             (hubd->h_dev_state == USB_DEV_PWRED_DOWN)) {
8708                 hubpm = hubd->h_hubpm;
8709 
8710                 /* mark the root hub as full power */
8711                 hubpm->hubp_current_power = USB_DEV_OS_FULL_PWR;
8712                 hubpm->hubp_time_at_full_power = ddi_get_time();
8713                 mutex_exit(HUBD_MUTEX(hubd));
8714 
8715                 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
8716                     "hubd_reset_thread: call pm_power_has_changed");
8717 
8718                 (void) pm_power_has_changed(hdip, 0,
8719                     USB_DEV_OS_FULL_PWR);
8720 
8721                 mutex_enter(HUBD_MUTEX(hubd));
8722                 hubd->h_dev_state = USB_DEV_ONLINE;
8723         }
8724 
8725         mutex_exit(HUBD_MUTEX(hubd));
8726 
8727         /*
8728          * this ensures one reset activity per system at a time.
8729          * we enter the parent PCI node to have this serialization.
8730          * this also excludes ioctls and deathrow thread
8731          */
8732         ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ);




   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2012 Garrett D'Amore <garrett@damore.org>.  All rights reserved.
  24  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
  25  */
  26 
  27 /*
  28  * USBA: Solaris USB Architecture support for the hub
  29  * including root hub
  30  * Most of the code for hubd resides in this file and
  31  * is shared between the HCD root hub support and hubd
  32  */
  33 #define USBA_FRAMEWORK
  34 #include <sys/usb/usba.h>
  35 #include <sys/usb/usba/usba_devdb.h>
  36 #include <sys/sunndi.h>
  37 #include <sys/usb/usba/usba_impl.h>
  38 #include <sys/usb/usba/usba_types.h>
  39 #include <sys/usb/usba/hubdi.h>
  40 #include <sys/usb/usba/hcdi_impl.h>
  41 #include <sys/usb/hubd/hub.h>
  42 #include <sys/usb/hubd/hubdvar.h>
  43 #include <sys/usb/hubd/hubd_impl.h>
  44 #include <sys/kobj.h>


 733  * NOTE: suspend here means going to lower power, not CPR suspend.
 734  */
 735 static int
 736 hubd_can_suspend(hubd_t *hubd)
 737 {
 738         hub_power_t     *hubpm;
 739         int             total_power = 0;
 740         usb_port_t      port;
 741 
 742         hubpm = hubd->h_hubpm;
 743 
 744         if (DEVI_IS_DETACHING(hubd->h_dip)) {
 745 
 746                 return (USB_SUCCESS);
 747         }
 748 
 749         /*
 750          * Don't go to lower power if haven't been at full power for enough
 751          * time to let hotplug thread kickoff.
 752          */
 753         if (gethrtime() < (hubpm->hubp_time_at_full_power +
 754             hubpm->hubp_min_pm_threshold)) {
 755 
 756                 return (USB_FAILURE);
 757         }
 758 
 759         for (port = 1; (total_power == 0) &&
 760             (port <= hubd->h_hub_descr.bNbrPorts); port++) {
 761                 total_power += hubpm->hubp_child_pwrstate[port];
 762         }
 763 
 764         USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
 765             "hubd_can_suspend: %d", total_power);
 766 
 767         return (total_power ? USB_FAILURE : USB_SUCCESS);
 768 }
 769 
 770 
 771 /*
 772  * resume port depending on current device state
 773  */


1704         hub_power_t     *hubpm;
1705         int             rval;
1706 
1707         USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, "hubd_pwrlvl3");
1708 
1709         hubpm = hubd->h_hubpm;
1710         switch (hubd->h_dev_state) {
1711         case USB_DEV_PWRED_DOWN:
1712                 ASSERT(hubpm->hubp_current_power == USB_DEV_OS_PWR_OFF);
1713                 if (usba_is_root_hub(hubd->h_dip)) {
1714                         /* implement global resume here */
1715                         USB_DPRINTF_L2(DPRINT_MASK_PM,
1716                             hubd->h_log_handle,
1717                             "Global Resume: Not Yet Implemented");
1718                 }
1719                 /* Issue USB D0 command to the device here */
1720                 rval = usb_set_device_pwrlvl0(hubd->h_dip);
1721                 ASSERT(rval == USB_SUCCESS);
1722                 hubd->h_dev_state = USB_DEV_ONLINE;
1723                 hubpm->hubp_current_power = USB_DEV_OS_FULL_PWR;
1724                 hubpm->hubp_time_at_full_power = gethrtime();
1725                 hubd_start_polling(hubd, 0);
1726 
1727                 /* FALLTHRU */
1728         case USB_DEV_ONLINE:
1729                 /* we are already in full power */
1730 
1731                 /* FALLTHRU */
1732         case USB_DEV_DISCONNECTED:
1733         case USB_DEV_SUSPENDED:
1734                 /*
1735                  * PM framework tries to put you in full power
1736                  * during system shutdown. If we are disconnected
1737                  * return success. Also, we should not change state
1738                  * when we are disconnected or suspended or about to
1739                  * transition to that state
1740                  */
1741 
1742                 return (USB_SUCCESS);
1743         default:
1744                 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle,


3696 
3697                 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
3698                     "hubd_hotplug_thread: "
3699                     "bus_power in progress/hotplugging undesirable - quit");
3700 
3701                 return;
3702         }
3703         mutex_exit(HUBD_MUTEX(hubd));
3704 
3705         ndi_hold_devi(hdip); /* so we don't race with detach */
3706 
3707         mutex_enter(HUBD_MUTEX(hubd));
3708 
3709         /* is this the root hub? */
3710         if (hdip == rh_dip) {
3711                 if (hubd->h_dev_state == USB_DEV_PWRED_DOWN) {
3712                         hubpm = hubd->h_hubpm;
3713 
3714                         /* mark the root hub as full power */
3715                         hubpm->hubp_current_power = USB_DEV_OS_FULL_PWR;
3716                         hubpm->hubp_time_at_full_power = gethrtime();
3717                         mutex_exit(HUBD_MUTEX(hubd));
3718 
3719                         USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
3720                             "hubd_hotplug_thread: call pm_power_has_changed");
3721 
3722                         (void) pm_power_has_changed(hdip, 0,
3723                             USB_DEV_OS_FULL_PWR);
3724 
3725                         mutex_enter(HUBD_MUTEX(hubd));
3726                         hubd->h_dev_state = USB_DEV_ONLINE;
3727                 }
3728 
3729         } else {
3730                 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
3731                     "hubd_hotplug_thread: not root hub");
3732         }
3733 
3734         mutex_exit(HUBD_MUTEX(hubd));
3735 
3736         /*


7257 /*
7258  * Power management
7259  *
7260  * create the pm components required for power management
7261  */
7262 static void
7263 hubd_create_pm_components(dev_info_t *dip, hubd_t *hubd)
7264 {
7265         hub_power_t     *hubpm;
7266 
7267         USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
7268             "hubd_create_pm_components: Begin");
7269 
7270         /* Allocate the state structure */
7271         hubpm = kmem_zalloc(sizeof (hub_power_t), KM_SLEEP);
7272 
7273         hubd->h_hubpm = hubpm;
7274         hubpm->hubp_hubd = hubd;
7275         hubpm->hubp_pm_capabilities = 0;
7276         hubpm->hubp_current_power = USB_DEV_OS_FULL_PWR;
7277         hubpm->hubp_time_at_full_power = gethrtime();
7278         hubpm->hubp_min_pm_threshold = hubdi_min_pm_threshold * NANOSEC;
7279 
7280         /* alloc memory to save power states of children */
7281         hubpm->hubp_child_pwrstate = (uint8_t *)
7282             kmem_zalloc(MAX_PORTS + 1, KM_SLEEP);
7283 
7284         /*
7285          * if the enable remote wakeup fails
7286          * we still want to enable
7287          * parent notification so we can PM the children
7288          */
7289         usb_enable_parent_notification(dip);
7290 
7291         if (usb_handle_remote_wakeup(dip,
7292             USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) {
7293                 uint_t          pwr_states;
7294 
7295                 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle,
7296                     "hubd_create_pm_components: "
7297                     "Remote Wakeup Enabled");
7298 


8693 
8694         if (hubd_wait_for_hotplug_exit(hubd) == USB_FAILURE) {
8695                 /* we got woken up because of a timeout */
8696                 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG,
8697                     hubd->h_log_handle, "Time out when resetting the device"
8698                     " %s%d. Please disconnect and reconnect this device.",
8699                     devname, devinst);
8700 
8701                 goto Fail;
8702         }
8703 
8704         hubd->h_hotplug_thread++;
8705 
8706         /* is this the root hub? */
8707         if ((hdip == rh_dip) &&
8708             (hubd->h_dev_state == USB_DEV_PWRED_DOWN)) {
8709                 hubpm = hubd->h_hubpm;
8710 
8711                 /* mark the root hub as full power */
8712                 hubpm->hubp_current_power = USB_DEV_OS_FULL_PWR;
8713                 hubpm->hubp_time_at_full_power = gethrtime();
8714                 mutex_exit(HUBD_MUTEX(hubd));
8715 
8716                 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
8717                     "hubd_reset_thread: call pm_power_has_changed");
8718 
8719                 (void) pm_power_has_changed(hdip, 0,
8720                     USB_DEV_OS_FULL_PWR);
8721 
8722                 mutex_enter(HUBD_MUTEX(hubd));
8723                 hubd->h_dev_state = USB_DEV_ONLINE;
8724         }
8725 
8726         mutex_exit(HUBD_MUTEX(hubd));
8727 
8728         /*
8729          * this ensures one reset activity per system at a time.
8730          * we enter the parent PCI node to have this serialization.
8731          * this also excludes ioctls and deathrow thread
8732          */
8733         ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ);