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