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