1 /*
   2  * CDDL HEADER START
   3  *
   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 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 /*
  26  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
  27  */
  28 
  29 #ifndef _SYS_USB_HUBDVAR_H
  30 #define _SYS_USB_HUBDVAR_H
  31 
  32 
  33 #ifdef  __cplusplus
  34 extern "C" {
  35 #endif
  36 
  37 #include <sys/sunndi.h>
  38 #include <sys/ndi_impldefs.h>
  39 #include <sys/usb/usba/usba_types.h>
  40 #include <sys/callb.h>
  41 
  42 /*
  43  * HUB USB device state management :
  44  *
  45  *                          CHILD PWRLVL---1>--------+
  46  *                               ^                   |
  47  *                               8                   |
  48  *                               |                   |
  49  *                               9                   |
  50  *                               v                   |
  51  *      PWRED_DWN---<3----4>--ONLINE---<2-----1>-DISCONNECTED
  52  *          |                  |  ^                |  |
  53  *          |                  |  10               |  |
  54  *          |                  |  |                |  |
  55  *          |                  |  RECOVER-<2-------+  |
  56  *          |                  |  ^                   |
  57  *          |                  5  6                   |
  58  *          |                  |  |                   |
  59  *          |                  v  |                   |
  60  *          +----5>----------SUSPENDED----<5----7>----+
  61  *
  62  *      1 = Device Unplug
  63  *      2 = Original Device reconnected and after hub driver restores its own
  64  *          device state.
  65  *      3 = Device idles for time T & transitions to low power state
  66  *      4 = Remote wakeup by device OR Application kicking off IO to device
  67  *      5 = Notification to save state prior to DDI_SUSPEND
  68  *      6 = Notification to restore state after DDI_RESUME with correct device
  69  *          and after hub driver restores its own device state.
  70  *      7 = Notification to restore state after DDI_RESUME with device
  71  *          disconnected or a wrong device
  72  *      8 = Hub detect child doing remote wakeup and request the PM
  73  *          framework to bring it to full power
  74  *      9 = PM framework has compeleted call power entry point of the child
  75  *          and bus ctls of hub
  76  *     10 = Restoring states of its children i.e. set addrs & config.
  77  *
  78  */
  79 
  80 #define HUBD_INITIAL_SOFT_SPACE 4
  81 
  82 typedef struct hub_power_struct {
  83         void            *hubp_hubd;     /* points back to hubd_t */
  84 
  85         uint8_t         hubp_wakeup_enabled;    /* remote wakeup enabled? */
  86 
  87         /* this is the bit mask of the power states that device has */
  88         uint8_t         hubp_pwr_states;
  89 
  90         int             hubp_busy_pm;   /* device busy accounting */
  91 
  92         /* wakeup and power transition capabilities of an interface */
  93         uint8_t         hubp_pm_capabilities;
  94 
  95         uint8_t         hubp_current_power;     /* current power level */
  96 
  97         hrtime_t        hubp_time_at_full_power;        /* timestamp 0->3 */
  98 
  99         hrtime_t        hubp_min_pm_threshold;          /* in nanoseconds */
 100 
 101         /* power state of all children are tracked here */
 102         uint8_t         *hubp_child_pwrstate;
 103 
 104         /* pm-components properties are stored here */
 105         char            *hubp_pmcomp[5];
 106 
 107         usba_cfg_pwr_descr_t    hubp_confpwr_descr; /* config pwr descr */
 108 } hub_power_t;
 109 
 110 /* warlock directives, stable data */
 111 _NOTE(DATA_READABLE_WITHOUT_LOCK(hub_power_t::hubp_hubd))
 112 _NOTE(DATA_READABLE_WITHOUT_LOCK(hub_power_t::hubp_wakeup_enabled))
 113 _NOTE(DATA_READABLE_WITHOUT_LOCK(hub_power_t::hubp_pwr_states))
 114 _NOTE(DATA_READABLE_WITHOUT_LOCK(hub_power_t::hubp_time_at_full_power))
 115 _NOTE(DATA_READABLE_WITHOUT_LOCK(hub_power_t::hubp_min_pm_threshold))
 116 _NOTE(DATA_READABLE_WITHOUT_LOCK(hub_power_t::hubp_pm_capabilities))
 117 _NOTE(DATA_READABLE_WITHOUT_LOCK(hub_power_t::hubp_pmcomp))
 118 _NOTE(DATA_READABLE_WITHOUT_LOCK(hub_power_t::hubp_confpwr_descr))
 119 
 120 
 121 #define HUBD_APID_NAMELEN       32              /* max len in cfgadm display */
 122 
 123 /*
 124  * hubd cpr data structure used for callback before kernel threads are
 125  * suspended
 126  */
 127 typedef struct hubd_cpr {
 128         callb_cpr_t             cpr;            /* for cpr related info */
 129         struct hubd             *statep;        /* ohci soft state struct */
 130         kmutex_t                lockp;
 131 } hubd_cpr_t;
 132 
 133 _NOTE(DATA_READABLE_WITHOUT_LOCK(hubd_cpr_t::cpr))
 134 _NOTE(DATA_READABLE_WITHOUT_LOCK(hubd_cpr_t::statep))
 135 
 136 
 137 /*
 138  * soft state information for this hubd
 139  */
 140 typedef struct hubd {
 141         int                     h_instance;
 142         uint_t                  h_init_state;
 143         uint_t                  h_dev_state;
 144         int8_t                  h_bus_ctls;
 145         int8_t                  h_bus_pwr;
 146         hub_power_t             *h_hubpm; /* pointer to power struct */
 147         dev_info_t              *h_dip;
 148 
 149         /*
 150          * mutex to protect softstate and hw regs
 151          */
 152         kmutex_t                h_mutex;
 153 
 154         /*
 155          * save the usba_device pointer
 156          */
 157         usba_device_t           *h_usba_device;
 158 
 159         int                     h_softstate;
 160 
 161         /*
 162          * default pipe handle
 163          */
 164         usb_pipe_handle_t       h_default_pipe;
 165 
 166         /*
 167          * pipe handle for ep1
 168          */
 169         usb_pipe_handle_t       h_ep1_ph;
 170         usb_ep_descr_t          h_ep1_descr;
 171         usb_pipe_policy_t       h_pipe_policy;
 172         uint_t                  h_intr_pipe_state;
 173 
 174         /*
 175          * root hub descriptor
 176          */
 177         struct usb_hub_descr    h_hub_descr;
 178 
 179         /*
 180          * hotplug handling
 181          */
 182         uint_t                  h_hotplug_thread;
 183 
 184         /*
 185          * h_children_dips is a  array for holding
 186          * each child dip indexed by port
 187          * h_usba_devices is the corresponding usba_device
 188          */
 189         dev_info_t              **h_children_dips;
 190         size_t                  h_cd_list_length;
 191         usba_device_t           **h_usba_devices;
 192 
 193         /* change reported by hub, limited to 31 ports */
 194         usb_port_mask_t         h_port_change;
 195 
 196         /* waiting for reset completion callback */
 197         usb_port_mask_t         h_port_reset_wait;
 198 
 199         /* track transitions of child on each port */
 200         uint16_t                h_port_state[MAX_PORTS + 1];
 201 
 202         /* track reset state of each port */
 203         boolean_t               h_reset_port[MAX_PORTS + 1];
 204 
 205         /* track event registration of children */
 206         uint8_t                 h_child_events[MAX_PORTS + 1];
 207 
 208         kcondvar_t              h_cv_reset_port;
 209         kcondvar_t              h_cv_hotplug_dev;
 210         uint_t                  h_intr_completion_reason;
 211         usb_log_handle_t        h_log_handle;   /* for logging msgs */
 212 
 213         ndi_event_hdl_t         h_ndi_event_hdl;
 214         hubd_cpr_t              *h_cpr_cb;
 215 
 216         /*
 217          * Hotplug event statistics since hub was attached
 218          */
 219         ulong_t                 h_total_hotplug_success;
 220         ulong_t                 h_total_hotplug_failure;
 221 
 222         /* for minor node */
 223         char                    *h_ancestry_str;
 224 
 225         /* registration data */
 226         usb_client_dev_data_t   *h_dev_data;
 227 
 228         /* for deathrow implementation */
 229         boolean_t               h_cleanup_enabled;
 230         boolean_t               h_cleanup_needed;
 231         boolean_t               h_cleanup_active;
 232 
 233         /*
 234          * for power budget support
 235          * h_pwr_limit and h_pwr_left are expressed
 236          * in 2mA units
 237          */
 238         boolean_t               h_local_pwr_capable;
 239         boolean_t               h_local_pwr_on;
 240         uint16_t                h_pwr_limit; /* per port pwr limit */
 241         int16_t                 h_pwr_left; /* limit on the whole hub */
 242 
 243         /*
 244          * conf file override to power budget property
 245          * if 1, power budget is disabled
 246          */
 247         boolean_t               h_ignore_pwr_budget;
 248 
 249         /* for HWA to cleanup child, NULL for normal hubs */
 250         int                     (*h_cleanup_child)(dev_info_t *);
 251 } hubd_t;
 252 
 253 _NOTE(MUTEX_PROTECTS_DATA(hubd::h_mutex, hubd))
 254 _NOTE(MUTEX_PROTECTS_DATA(hubd::h_mutex, hub_power_t))
 255 _NOTE(DATA_READABLE_WITHOUT_LOCK(hubd::h_default_pipe
 256                 hubd::h_usba_device
 257                 hubd::h_dev_data
 258                 hubd::h_ndi_event_hdl
 259                 hubd::h_cpr_cb
 260                 hubd::h_log_handle
 261                 hubd::h_ep1_ph
 262                 hubd::h_instance
 263                 hubd::h_hubpm
 264                 hubd::h_dip
 265                 hubd::h_ignore_pwr_budget
 266                 hubd::h_hub_descr
 267                 hubd::h_cleanup_child
 268 ))
 269 
 270 _NOTE(SCHEME_PROTECTS_DATA("stable data", usb_ep_descr))
 271 
 272 /*
 273  * hubd hotplug thread argument data structure
 274  */
 275 typedef struct hubd_hotplug_arg {
 276         hubd_t          *hubd;
 277 
 278         /*
 279          * flag to indicate if a hotplug thread is started
 280          * during hubd attach time, if true, it means the
 281          * connected devices need to be enumerated regardless
 282          * of the connect status change bit
 283          */
 284         boolean_t       hotplug_during_attach;
 285 } hubd_hotplug_arg_t;
 286 
 287 /*
 288  * hubd reset thread argument data structure
 289  */
 290 typedef struct hubd_reset_arg {
 291         hubd_t          *hubd;
 292         /* The port needs to be reset */
 293         uint16_t        reset_port;
 294 } hubd_reset_arg_t;
 295 
 296 _NOTE(SCHEME_PROTECTS_DATA("unshared", hubd_hotplug_arg))
 297 _NOTE(SCHEME_PROTECTS_DATA("unshared", hubd_reset_arg))
 298 
 299 #define HUBD_UNIT(dev)          (getminor((dev)))
 300 #define HUBD_MUTEX(hubd)        (&((hubd)->h_mutex))
 301 #define HUBD_SS_ISOPEN          0x0001
 302 #define HUBD_ACK_ALL_CHANGES    PORT_CHANGE_MASK
 303 
 304 /* init state */
 305 #define HUBD_LOCKS_DONE         0x0001
 306 #define HUBD_HUBDI_REGISTERED   0x0002
 307 #define HUBD_MINOR_NODE_CREATED 0x0004
 308 #define HUBD_CHILDREN_CREATED   0x0008
 309 #define HUBD_EVENTS_REGISTERED  0x0020
 310 
 311 /*
 312  * port flags : These are essentially extensions of  Port Status Field Bits
 313  * as in USB 2.0 spec Table 11-21 and #defined in hubd.h file. We make use
 314  * of the unused bits (5-7,13-15) here to track states of the hub's child.
 315  */
 316 #define HUBD_CHILD_ATTACHING            0x0020
 317 #define HUBD_CHILD_DETACHING            0x0040
 318 #define HUBD_CHILD_PWRLVL_CHNG          0x0080
 319 #define HUBD_CHILD_RAISE_POWER          0x2000
 320 #define HUBD_CHILD_ZAP                  0x4000
 321 
 322 /* Tracking events registered by children */
 323 #define HUBD_CHILD_EVENT_DISCONNECT     0x01
 324 #define HUBD_CHILD_EVENT_PRESUSPEND     0x02
 325 
 326 /* This dev state is used exclusively by hub to change port suspend/resume */
 327 #define USB_DEV_HUB_CHILD_PWRLVL        0x80
 328 #define USB_DEV_HUB_STATE_RECOVER       0x81
 329 
 330 /*
 331  * hubd interrupt pipe management :
 332  *
 333  * Following are the states of the interrupt pipe
 334  *
 335  * IDLE:
 336  *      initial state and after closing of the interrupt pipe
 337  *
 338  * OPENING:
 339  *      Set when the pipe is being opened
 340  *
 341  * ACTIVE:
 342  *      Set when the pipe has been opened in hubd_open_intr_pipe. This is
 343  *      typically after a hub has got enumerated and initialized.
 344  *
 345  * CLOSING :
 346  *      Set when the pipe is closed by calling hubd_close_intr_pipe(). This is
 347  *      typically called on hub disconnect via hubd_cleanup.
 348  */
 349 #define HUBD_INTR_PIPE_IDLE             0
 350 #define HUBD_INTR_PIPE_OPENING          1
 351 #define HUBD_INTR_PIPE_ACTIVE           2
 352 #define HUBD_INTR_PIPE_STOPPED          3
 353 #define HUBD_INTR_PIPE_CLOSING          4
 354 
 355 
 356 /* request structure for putting dips on deathrow list */
 357 typedef struct hubd_offline_req {
 358         usba_list_entry_t       or_queue; /* DO NOT MOVE! */
 359         hubd_t                  *or_hubd;
 360         usb_port_t              or_port;
 361         dev_info_t              *or_dip;
 362         uint_t                  or_flag;
 363 } hubd_offline_req_t;
 364 
 365 _NOTE(SCHEME_PROTECTS_DATA("unshared", hubd_offline_req))
 366 
 367 
 368 /*
 369  * cfgadm state values
 370  */
 371 #define HUBD_CFGADM_NORMAL              0       /* normal state */
 372 #define HUBD_CFGADM_DISCONNECTED        1       /* logically disconnected */
 373 #define HUBD_CFGADM_UNCONFIGURED        2       /* port is unconfigured */
 374 #define HUBD_CFGADM_EMPTY               3       /* port is empty */
 375 #define HUBD_CFGADM_STILL_REFERENCED    4       /* ndi_devi_offline failed */
 376 #define HUBD_CFGADM_CONFIGURED          5       /* port is configured */
 377 
 378 /*
 379  * Debug printing
 380  * Masks
 381  */
 382 #define DPRINT_MASK_ATTA        0x00000001
 383 #define DPRINT_MASK_CBOPS       0x00000002
 384 #define DPRINT_MASK_CALLBACK    0x00000004
 385 #define DPRINT_MASK_PORT        0x00000008
 386 #define DPRINT_MASK_HUB         0x00000010
 387 #define DPRINT_MASK_HOTPLUG     0x00000020
 388 #define DPRINT_MASK_EVENTS      0x00000040
 389 #define DPRINT_MASK_PM          0x00000080
 390 #define DPRINT_MASK_ALL         0xFFFFFFFF
 391 
 392 
 393 /* status length used in getting hub status */
 394 #define GET_STATUS_LENGTH       0x04            /* length of get status req */
 395 
 396 /* flag for hubd_start_polling */
 397 #define HUBD_ALWAYS_START_POLLING       1
 398 
 399 /* enumeration timeout */
 400 #define HUBDI_ENUM_TIMEOUT      1       /* 1 second */
 401 
 402 /* power budget unit in mA */
 403 #define USB_PWR_UNIT_LOAD       100
 404 
 405 /* power values in 100mA units */
 406 #define USB_HIGH_PWR_VALUE      5
 407 #define USB_LOW_PWR_VALUE       1
 408 
 409 /*
 410  * According to section 9.6.3 of USB 2.0 spec,
 411  * bMaxPower in the device configuration descriptor
 412  * is expressed in 2mA units
 413  */
 414 #define USB_CFG_DESCR_PWR_UNIT  2
 415 
 416 /* variables shared with wire adapter class drivers */
 417 extern uint_t hubd_errlevel;
 418 extern uint_t hubd_errmask;
 419 extern uint_t hubd_instance_debug;
 420 
 421 /* common interfaces for hub and wire adapter class devices */
 422 hubd_t  *hubd_get_soft_state(dev_info_t *);
 423 void    hubd_get_ancestry_str(hubd_t *);
 424 int     hubd_get_all_device_config_cloud(hubd_t *, dev_info_t *,
 425         usba_device_t *);
 426 int     hubd_select_device_configuration(hubd_t *, usb_port_t,
 427         dev_info_t *, usba_device_t *);
 428 dev_info_t *hubd_ready_device(hubd_t *, dev_info_t *, usba_device_t *,
 429         uint_t);
 430 void    hubd_schedule_cleanup(dev_info_t *);
 431 
 432 #ifdef  __cplusplus
 433 }
 434 #endif
 435 
 436 #endif  /* _SYS_USB_HUBDVAR_H */