xref: /illumos-gate/usr/src/uts/common/io/usb/usba/hubdi.c (revision d96925c4)
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 (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  * Copyright 2019, Joyent, Inc.
26  */
27 
28 /*
29  * USBA: Solaris USB Architecture support for the hub
30  * including root hub
31  * Most of the code for hubd resides in this file and
32  * is shared between the HCD root hub support and hubd
33  */
34 #define	USBA_FRAMEWORK
35 #include <sys/usb/usba.h>
36 #include <sys/usb/usba/usba_devdb.h>
37 #include <sys/sunndi.h>
38 #include <sys/usb/usba/usba_impl.h>
39 #include <sys/usb/usba/usba_types.h>
40 #include <sys/usb/usba/hubdi.h>
41 #include <sys/usb/usba/hcdi_impl.h>
42 #include <sys/usb/hubd/hub.h>
43 #include <sys/usb/hubd/hubdvar.h>
44 #include <sys/usb/hubd/hubd_impl.h>
45 #include <sys/kobj.h>
46 #include <sys/kobj_lex.h>
47 #include <sys/fs/dv_node.h>
48 #include <sys/strsun.h>
49 
50 /*
51  * External functions
52  */
53 extern boolean_t consconfig_console_is_ready(void);
54 
55 /*
56  * Prototypes for static functions
57  */
58 static	int	usba_hubdi_bus_ctl(dev_info_t *dip,
59     dev_info_t *rdip,
60     ddi_ctl_enum_t op,
61     void *arg,
62     void *result);
63 
64 static int	usba_hubdi_map_fault(dev_info_t *dip,
65     dev_info_t *rdip,
66     struct hat *hat,
67     struct seg *seg,
68     caddr_t addr,
69     struct devpage *dp,
70     pfn_t pfn,
71     uint_t prot,
72     uint_t lock);
73 
74 static int hubd_busop_get_eventcookie(dev_info_t *dip,
75     dev_info_t *rdip,
76     char *eventname,
77     ddi_eventcookie_t *cookie);
78 static int hubd_busop_add_eventcall(dev_info_t *dip,
79     dev_info_t *rdip,
80     ddi_eventcookie_t cookie,
81     void (*callback)(dev_info_t *dip, ddi_eventcookie_t cookie, void *arg,
82 	void *bus_impldata),
83     void *arg, ddi_callback_id_t *cb_id);
84 static int hubd_busop_remove_eventcall(dev_info_t *dip,
85     ddi_callback_id_t cb_id);
86 static int hubd_bus_config(dev_info_t *dip,
87     uint_t flag,
88     ddi_bus_config_op_t op,
89     void *arg,
90     dev_info_t **child);
91 static int hubd_bus_unconfig(dev_info_t *dip,
92     uint_t flag,
93     ddi_bus_config_op_t op,
94     void *arg);
95 static int hubd_bus_power(dev_info_t *dip, void *impl_arg,
96     pm_bus_power_op_t op, void *arg, void *result);
97 
98 static usb_port_t  hubd_get_port_num(hubd_t *, struct devctl_iocdata *);
99 static dev_info_t *hubd_get_child_dip(hubd_t *, usb_port_t);
100 static uint_t hubd_cfgadm_state(hubd_t *, usb_port_t);
101 static int hubd_toggle_port(hubd_t *, usb_port_t);
102 static void hubd_register_cpr_callback(hubd_t *);
103 static void hubd_unregister_cpr_callback(hubd_t *);
104 
105 /*
106  * Busops vector for USB HUB's
107  */
108 struct bus_ops usba_hubdi_busops =	{
109 	BUSO_REV,
110 	nullbusmap,			/* bus_map */
111 	NULL,				/* bus_get_intrspec */
112 	NULL,				/* bus_add_intrspec */
113 	NULL,				/* bus_remove_intrspec */
114 	usba_hubdi_map_fault,		/* bus_map_fault */
115 	NULL,				/* bus_dma_map */
116 	ddi_dma_allochdl,
117 	ddi_dma_freehdl,
118 	ddi_dma_bindhdl,
119 	ddi_dma_unbindhdl,
120 	ddi_dma_flush,
121 	ddi_dma_win,
122 	ddi_dma_mctl,			/* bus_dma_ctl */
123 	usba_hubdi_bus_ctl,		/* bus_ctl */
124 	ddi_bus_prop_op,		/* bus_prop_op */
125 	hubd_busop_get_eventcookie,
126 	hubd_busop_add_eventcall,
127 	hubd_busop_remove_eventcall,
128 	NULL,				/* bus_post_event */
129 	NULL,				/* bus_intr_ctl */
130 	hubd_bus_config,		/* bus_config */
131 	hubd_bus_unconfig,		/* bus_unconfig */
132 	NULL,				/* bus_fm_init */
133 	NULL,				/* bus_fm_fini */
134 	NULL,				/* bus_fm_access_enter */
135 	NULL,				/* bus_fm_access_exit */
136 	hubd_bus_power			/* bus_power */
137 };
138 
139 #define	USB_HUB_INTEL_VID	0x8087
140 #define	USB_HUB_INTEL_PID	0x0020
141 
142 /*
143  * local variables
144  */
145 static kmutex_t	usba_hubdi_mutex;	/* protects USBA HUB data structures */
146 
147 static usba_list_entry_t	usba_hubdi_list;
148 
149 usb_log_handle_t	hubdi_log_handle;
150 uint_t			hubdi_errlevel = USB_LOG_L4;
151 uint_t			hubdi_errmask = (uint_t)-1;
152 uint8_t			hubdi_min_pm_threshold = 5; /* seconds */
153 uint8_t			hubdi_reset_delay = 20; /* seconds */
154 extern int modrootloaded;
155 
156 /*
157  * initialize private data
158  */
159 void
usba_hubdi_initialization()160 usba_hubdi_initialization()
161 {
162 	hubdi_log_handle = usb_alloc_log_hdl(NULL, "hubdi", &hubdi_errlevel,
163 	    &hubdi_errmask, NULL, 0);
164 
165 	USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubdi_log_handle,
166 	    "usba_hubdi_initialization");
167 
168 	mutex_init(&usba_hubdi_mutex, NULL, MUTEX_DRIVER, NULL);
169 
170 	usba_init_list(&usba_hubdi_list, NULL, NULL);
171 }
172 
173 
174 void
usba_hubdi_destroy()175 usba_hubdi_destroy()
176 {
177 	USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubdi_log_handle,
178 	    "usba_hubdi_destroy");
179 
180 	mutex_destroy(&usba_hubdi_mutex);
181 	usba_destroy_list(&usba_hubdi_list);
182 
183 	usb_free_log_hdl(hubdi_log_handle);
184 }
185 
186 
187 /*
188  * Called by an	HUB to attach an instance of the driver
189  *	make this instance known to USBA
190  *	the HUB	should initialize usba_hubdi structure prior
191  *	to calling this	interface
192  */
193 int
usba_hubdi_register(dev_info_t * dip,uint_t flags)194 usba_hubdi_register(dev_info_t	*dip, uint_t flags)
195 {
196 	usba_hubdi_t *hubdi = kmem_zalloc(sizeof (usba_hubdi_t), KM_SLEEP);
197 	usba_device_t *usba_device = usba_get_usba_device(dip);
198 
199 	USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubdi_log_handle,
200 	    "usba_hubdi_register: %s", ddi_node_name(dip));
201 
202 	hubdi->hubdi_dip = dip;
203 	hubdi->hubdi_flags = flags;
204 
205 	usba_device->usb_hubdi = hubdi;
206 
207 	/*
208 	 * add this hubdi instance to the list of known hubdi's
209 	 */
210 	usba_init_list(&hubdi->hubdi_list, (usb_opaque_t)hubdi,
211 	    usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip)->
212 	    hcdi_iblock_cookie);
213 	mutex_enter(&usba_hubdi_mutex);
214 	usba_add_to_list(&usba_hubdi_list, &hubdi->hubdi_list);
215 	mutex_exit(&usba_hubdi_mutex);
216 
217 	return (DDI_SUCCESS);
218 }
219 
220 
221 /*
222  * Called by an	HUB to detach an instance of the driver
223  */
224 int
usba_hubdi_unregister(dev_info_t * dip)225 usba_hubdi_unregister(dev_info_t *dip)
226 {
227 	usba_device_t *usba_device = usba_get_usba_device(dip);
228 	usba_hubdi_t *hubdi = usba_device->usb_hubdi;
229 
230 	USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubdi_log_handle,
231 	    "usba_hubdi_unregister: %s", ddi_node_name(dip));
232 
233 	mutex_enter(&usba_hubdi_mutex);
234 	(void) usba_rm_from_list(&usba_hubdi_list, &hubdi->hubdi_list);
235 	mutex_exit(&usba_hubdi_mutex);
236 
237 	usba_destroy_list(&hubdi->hubdi_list);
238 
239 	kmem_free(hubdi, sizeof (usba_hubdi_t));
240 
241 	return (DDI_SUCCESS);
242 }
243 
244 
245 /*
246  * misc bus routines currently not used
247  */
248 /*ARGSUSED*/
249 static int
usba_hubdi_map_fault(dev_info_t * dip,dev_info_t * rdip,struct hat * hat,struct seg * seg,caddr_t addr,struct devpage * dp,pfn_t pfn,uint_t prot,uint_t lock)250 usba_hubdi_map_fault(dev_info_t *dip,
251     dev_info_t	*rdip,
252     struct hat	*hat,
253     struct seg	*seg,
254     caddr_t	addr,
255     struct devpage	*dp,
256     pfn_t		pfn,
257     uint_t		prot,
258     uint_t		lock)
259 {
260 	return (DDI_FAILURE);
261 }
262 
263 
264 /*
265  * root hub support. the root hub uses the same devi as the HCD
266  */
267 int
usba_hubdi_bind_root_hub(dev_info_t * dip,uchar_t * root_hub_config_descriptor,size_t config_length,usb_dev_descr_t * root_hub_device_descriptor)268 usba_hubdi_bind_root_hub(dev_info_t *dip,
269     uchar_t	*root_hub_config_descriptor,
270     size_t config_length,
271     usb_dev_descr_t *root_hub_device_descriptor)
272 {
273 	usba_device_t *usba_device;
274 	usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(dip);
275 	hubd_t	*root_hubd;
276 	usb_pipe_handle_t ph = NULL;
277 	dev_info_t *child = ddi_get_child(dip);
278 
279 	if (ndi_prop_create_boolean(DDI_DEV_T_NONE, dip,
280 	    "root-hub") != NDI_SUCCESS) {
281 
282 		return (USB_FAILURE);
283 	}
284 
285 	usba_add_root_hub(dip);
286 
287 	root_hubd = kmem_zalloc(sizeof (hubd_t), KM_SLEEP);
288 
289 	/*
290 	 * create and initialize a usba_device structure
291 	 */
292 	usba_device = usba_alloc_usba_device(dip);
293 
294 	mutex_enter(&usba_device->usb_mutex);
295 	usba_device->usb_hcdi_ops = hcdi->hcdi_ops;
296 	usba_device->usb_cfg = root_hub_config_descriptor;
297 	usba_device->usb_cfg_length = config_length;
298 	usba_device->usb_dev_descr = root_hub_device_descriptor;
299 	usba_device->usb_port = 1;
300 	usba_device->usb_addr = ROOT_HUB_ADDR;
301 	usba_device->usb_root_hubd = root_hubd;
302 	usba_device->usb_cfg_array = kmem_zalloc(sizeof (uchar_t *),
303 	    KM_SLEEP);
304 	usba_device->usb_cfg_array_length = sizeof (uchar_t *);
305 
306 	usba_device->usb_cfg_array_len = kmem_zalloc(sizeof (uint16_t),
307 	    KM_SLEEP);
308 	usba_device->usb_cfg_array_len_length = sizeof (uint16_t);
309 
310 	usba_device->usb_cfg_array[0] = root_hub_config_descriptor;
311 	usba_device->usb_cfg_array_len[0] =
312 	    sizeof (root_hub_config_descriptor);
313 
314 	usba_device->usb_cfg_str_descr = kmem_zalloc(sizeof (uchar_t *),
315 	    KM_SLEEP);
316 	usba_device->usb_n_cfgs = 1;
317 	usba_device->usb_n_ifs = 1;
318 	usba_device->usb_dip = dip;
319 
320 	usba_device->usb_client_flags = kmem_zalloc(
321 	    usba_device->usb_n_ifs * USBA_CLIENT_FLAG_SIZE, KM_SLEEP);
322 
323 	usba_device->usb_client_attach_list = kmem_zalloc(
324 	    usba_device->usb_n_ifs *
325 	    sizeof (*usba_device->usb_client_attach_list), KM_SLEEP);
326 
327 	usba_device->usb_client_ev_cb_list = kmem_zalloc(
328 	    usba_device->usb_n_ifs *
329 	    sizeof (*usba_device->usb_client_ev_cb_list), KM_SLEEP);
330 
331 	/*
332 	 * The bDeviceProtocol field of root hub device specifies,
333 	 * whether root hub is a Super, High, or Full speed usb device.
334 	 */
335 	if (root_hub_device_descriptor->bDeviceProtocol >= 0x3) {
336 		usba_device->usb_port_status = USBA_SUPER_SPEED_DEV;
337 	} else if (root_hub_device_descriptor->bDeviceProtocol > 0) {
338 		usba_device->usb_port_status = USBA_HIGH_SPEED_DEV;
339 	} else {
340 		usba_device->usb_port_status = USBA_FULL_SPEED_DEV;
341 	}
342 
343 	mutex_exit(&usba_device->usb_mutex);
344 
345 	usba_set_usba_device(dip, usba_device);
346 
347 	/*
348 	 * For the root hub the default pipe is not yet open
349 	 */
350 	if (usb_pipe_open(dip, NULL, NULL,
351 	    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph) != USB_SUCCESS) {
352 		goto fail;
353 	}
354 
355 	/*
356 	 * kill off all OBP children, they may not be fully
357 	 * enumerated
358 	 */
359 	while (child) {
360 		dev_info_t *next = ddi_get_next_sibling(child);
361 		(void) ddi_remove_child(child, 0);
362 		child = next;
363 	}
364 
365 	/*
366 	 * "attach" the root hub driver
367 	 */
368 	if (usba_hubdi_attach(dip, DDI_ATTACH) != DDI_SUCCESS) {
369 		goto fail;
370 	}
371 
372 	return (USB_SUCCESS);
373 
374 fail:
375 	if (ph) {
376 		usb_pipe_close(dip, ph,
377 		    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL);
378 	}
379 
380 	kmem_free(usba_device->usb_cfg_array,
381 	    usba_device->usb_cfg_array_length);
382 	kmem_free(usba_device->usb_cfg_array_len,
383 	    usba_device->usb_cfg_array_len_length);
384 
385 	kmem_free(usba_device->usb_cfg_str_descr, sizeof (uchar_t *));
386 
387 	usba_free_usba_device(usba_device);
388 
389 	usba_set_usba_device(dip, NULL);
390 
391 	if (root_hubd) {
392 		kmem_free(root_hubd, sizeof (hubd_t));
393 	}
394 
395 	(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "root-hub");
396 
397 	usba_rem_root_hub(dip);
398 
399 	return (USB_FAILURE);
400 }
401 
402 
403 int
usba_hubdi_unbind_root_hub(dev_info_t * dip)404 usba_hubdi_unbind_root_hub(dev_info_t *dip)
405 {
406 	usba_device_t *usba_device;
407 
408 	/* was root hub attached? */
409 	if (!(usba_is_root_hub(dip))) {
410 
411 		/* return success anyway */
412 		return (USB_SUCCESS);
413 	}
414 
415 	/*
416 	 * usba_hubdi_detach also closes the default pipe
417 	 * and removes properties so there is no need to
418 	 * do it here
419 	 */
420 	if (usba_hubdi_detach(dip, DDI_DETACH) != DDI_SUCCESS) {
421 
422 		if (DEVI_IS_ATTACHING(dip)) {
423 			USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle,
424 			    "failure to unbind root hub after attach failure");
425 		}
426 
427 		return (USB_FAILURE);
428 	}
429 
430 	usba_device = usba_get_usba_device(dip);
431 
432 	kmem_free(usba_device->usb_root_hubd, sizeof (hubd_t));
433 
434 	kmem_free(usba_device->usb_cfg_array,
435 	    usba_device->usb_cfg_array_length);
436 	kmem_free(usba_device->usb_cfg_array_len,
437 	    usba_device->usb_cfg_array_len_length);
438 
439 	kmem_free(usba_device->usb_cfg_str_descr, sizeof (uchar_t *));
440 
441 	usba_free_usba_device(usba_device);
442 
443 	usba_rem_root_hub(dip);
444 
445 	(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "root-hub");
446 
447 	return (USB_SUCCESS);
448 }
449 
450 
451 /*
452  * Actual Hub Driver support code:
453  *	shared by root hub and non-root hubs
454  */
455 #include <sys/usb/usba/usbai_version.h>
456 
457 /* Debugging support */
458 uint_t hubd_errlevel	= USB_LOG_L4;
459 uint_t hubd_errmask	= (uint_t)DPRINT_MASK_ALL;
460 uint_t hubd_instance_debug = (uint_t)-1;
461 static uint_t hubdi_bus_config_debug = 0;
462 
463 _NOTE(DATA_READABLE_WITHOUT_LOCK(hubd_errlevel))
464 _NOTE(DATA_READABLE_WITHOUT_LOCK(hubd_errmask))
465 _NOTE(DATA_READABLE_WITHOUT_LOCK(hubd_instance_debug))
466 
467 _NOTE(SCHEME_PROTECTS_DATA("unique", msgb))
468 _NOTE(SCHEME_PROTECTS_DATA("unique", dev_info))
469 
470 
471 /*
472  * local variables:
473  *
474  * Amount of time to wait between resetting the port and accessing
475  * the device.	The value is in microseconds.
476  */
477 static uint_t hubd_device_delay = 1000000;
478 
479 /*
480  * enumeration retry
481  */
482 #define	HUBD_PORT_RETRY 5
483 static uint_t hubd_retry_enumerate = HUBD_PORT_RETRY;
484 
485 /*
486  * Stale hotremoved device cleanup delay
487  */
488 #define	HUBD_STALE_DIP_CLEANUP_DELAY	5000000
489 static uint_t hubd_dip_cleanup_delay = HUBD_STALE_DIP_CLEANUP_DELAY;
490 
491 /*
492  * retries for USB suspend and resume
493  */
494 #define	HUBD_SUS_RES_RETRY	2
495 
496 void	*hubd_statep;
497 
498 /*
499  * prototypes
500  */
501 static int hubd_cleanup(dev_info_t *dip, hubd_t  *hubd);
502 static int hubd_check_ports(hubd_t  *hubd);
503 
504 static int  hubd_open_intr_pipe(hubd_t *hubd);
505 static void hubd_start_polling(hubd_t *hubd, int always);
506 static void hubd_stop_polling(hubd_t *hubd);
507 static void hubd_close_intr_pipe(hubd_t *hubd);
508 
509 static void hubd_read_cb(usb_pipe_handle_t pipe, usb_intr_req_t *req);
510 static void hubd_exception_cb(usb_pipe_handle_t pipe,
511 						usb_intr_req_t *req);
512 static void hubd_hotplug_thread(void *arg);
513 static void hubd_reset_thread(void *arg);
514 static int hubd_create_child(dev_info_t *dip,
515 		hubd_t		*hubd,
516 		usba_device_t	*usba_device,
517 		usb_port_status_t port_status,
518 		usb_port_t	port,
519 		int		iteration);
520 
521 static int hubd_delete_child(hubd_t *hubd, usb_port_t port, uint_t flag,
522 	boolean_t retry);
523 
524 static int hubd_get_hub_descriptor(hubd_t *hubd);
525 
526 static int hubd_set_hub_depth(hubd_t *hubd);
527 
528 static int hubd_get_hub_status_words(hubd_t *hubd, uint16_t *status);
529 
530 static int hubd_reset_port(hubd_t *hubd, usb_port_t port);
531 
532 static int hubd_get_hub_status(hubd_t *hubd);
533 
534 static int hubd_handle_port_connect(hubd_t *hubd, usb_port_t port);
535 
536 static int hubd_disable_port(hubd_t *hubd, usb_port_t port);
537 
538 static int hubd_enable_port(hubd_t *hubd, usb_port_t port);
539 static int hubd_recover_disabled_port(hubd_t *hubd, usb_port_t port);
540 
541 static int hubd_determine_port_status(hubd_t *hubd, usb_port_t port,
542 	uint16_t *status, uint16_t *change, usb_port_status_t *speed,
543 	uint_t ack_flag);
544 
545 static int hubd_enable_all_port_power(hubd_t *hubd);
546 static int hubd_disable_all_port_power(hubd_t *hubd);
547 static int hubd_disable_port_power(hubd_t *hubd, usb_port_t port);
548 static int hubd_enable_port_power(hubd_t *hubd, usb_port_t port);
549 
550 static void hubd_free_usba_device(hubd_t *hubd, usba_device_t *usba_device);
551 
552 static int hubd_can_suspend(hubd_t *hubd);
553 static void hubd_restore_device_state(dev_info_t *dip, hubd_t *hubd);
554 static int hubd_setdevaddr(hubd_t *hubd, usb_port_t port);
555 static void hubd_setdevconfig(hubd_t *hubd, usb_port_t port);
556 
557 static int hubd_register_events(hubd_t *hubd);
558 static void hubd_do_callback(hubd_t *hubd, dev_info_t *dip,
559 	ddi_eventcookie_t cookie);
560 static void hubd_run_callbacks(hubd_t *hubd, usba_event_t type);
561 static void hubd_post_event(hubd_t *hubd, usb_port_t port, usba_event_t type);
562 static void hubd_create_pm_components(dev_info_t *dip, hubd_t *hubd);
563 
564 static int hubd_disconnect_event_cb(dev_info_t *dip);
565 static int hubd_reconnect_event_cb(dev_info_t *dip);
566 static int hubd_pre_suspend_event_cb(dev_info_t *dip);
567 static int hubd_post_resume_event_cb(dev_info_t *dip);
568 static int hubd_cpr_suspend(hubd_t *hubd);
569 static void hubd_cpr_resume(dev_info_t *dip);
570 static int hubd_restore_state_cb(dev_info_t *dip);
571 static int hubd_check_same_device(hubd_t *hubd, usb_port_t port);
572 
573 static int hubd_init_power_budget(hubd_t *hubd);
574 
575 static ndi_event_definition_t hubd_ndi_event_defs[] = {
576 	{USBA_EVENT_TAG_HOT_REMOVAL, DDI_DEVI_REMOVE_EVENT, EPL_KERNEL,
577 						NDI_EVENT_POST_TO_ALL},
578 	{USBA_EVENT_TAG_HOT_INSERTION, DDI_DEVI_INSERT_EVENT, EPL_KERNEL,
579 						NDI_EVENT_POST_TO_ALL},
580 	{USBA_EVENT_TAG_POST_RESUME, USBA_POST_RESUME_EVENT, EPL_KERNEL,
581 						NDI_EVENT_POST_TO_ALL},
582 	{USBA_EVENT_TAG_PRE_SUSPEND, USBA_PRE_SUSPEND_EVENT, EPL_KERNEL,
583 						NDI_EVENT_POST_TO_ALL}
584 };
585 
586 #define	HUBD_N_NDI_EVENTS \
587 	(sizeof (hubd_ndi_event_defs) / sizeof (ndi_event_definition_t))
588 
589 static ndi_event_set_t hubd_ndi_events = {
590 	NDI_EVENTS_REV1, HUBD_N_NDI_EVENTS, hubd_ndi_event_defs};
591 
592 /* events received from parent */
593 static usb_event_t hubd_events = {
594 	hubd_disconnect_event_cb,
595 	hubd_reconnect_event_cb,
596 	hubd_pre_suspend_event_cb,
597 	hubd_post_resume_event_cb
598 };
599 
600 
601 /*
602  * hubd_get_soft_state() returns the hubd soft state
603  */
604 hubd_t *
hubd_get_soft_state(dev_info_t * dip)605 hubd_get_soft_state(dev_info_t *dip)
606 {
607 	if (dip == NULL) {
608 		return (NULL);
609 	}
610 
611 	if (usba_is_root_hub(dip)) {
612 		usba_device_t *usba_device = usba_get_usba_device(dip);
613 
614 		return (usba_device->usb_root_hubd);
615 	} else {
616 		int instance = ddi_get_instance(dip);
617 
618 		return (ddi_get_soft_state(hubd_statep, instance));
619 	}
620 }
621 
622 
623 /*
624  * PM support functions:
625  */
626 /*ARGSUSED*/
627 static void
hubd_pm_busy_component(hubd_t * hubd,dev_info_t * dip,int component)628 hubd_pm_busy_component(hubd_t *hubd, dev_info_t *dip, int component)
629 {
630 	if (hubd->h_hubpm != NULL) {
631 		hubd->h_hubpm->hubp_busy_pm++;
632 		mutex_exit(HUBD_MUTEX(hubd));
633 		if (pm_busy_component(dip, 0) != DDI_SUCCESS) {
634 			mutex_enter(HUBD_MUTEX(hubd));
635 			hubd->h_hubpm->hubp_busy_pm--;
636 			mutex_exit(HUBD_MUTEX(hubd));
637 		}
638 		mutex_enter(HUBD_MUTEX(hubd));
639 		USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
640 		    "hubd_pm_busy_component: %d", hubd->h_hubpm->hubp_busy_pm);
641 	}
642 }
643 
644 
645 /*ARGSUSED*/
646 static void
hubd_pm_idle_component(hubd_t * hubd,dev_info_t * dip,int component)647 hubd_pm_idle_component(hubd_t *hubd, dev_info_t *dip, int component)
648 {
649 	if (hubd->h_hubpm != NULL) {
650 		mutex_exit(HUBD_MUTEX(hubd));
651 		if (pm_idle_component(dip, 0) == DDI_SUCCESS) {
652 			mutex_enter(HUBD_MUTEX(hubd));
653 			ASSERT(hubd->h_hubpm->hubp_busy_pm > 0);
654 			hubd->h_hubpm->hubp_busy_pm--;
655 			mutex_exit(HUBD_MUTEX(hubd));
656 		}
657 		mutex_enter(HUBD_MUTEX(hubd));
658 		USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
659 		    "hubd_pm_idle_component: %d", hubd->h_hubpm->hubp_busy_pm);
660 	}
661 }
662 
663 
664 /*
665  * track power level changes for children of this instance
666  */
667 static void
hubd_set_child_pwrlvl(hubd_t * hubd,usb_port_t port,uint8_t power)668 hubd_set_child_pwrlvl(hubd_t *hubd, usb_port_t port, uint8_t power)
669 {
670 	int	old_power, new_power, pwr;
671 	usb_port_t	portno;
672 	hub_power_t	*hubpm;
673 
674 	USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
675 	    "hubd_set_child_pwrlvl: port=%d power=%d",
676 	    port, power);
677 
678 	mutex_enter(HUBD_MUTEX(hubd));
679 	hubpm = hubd->h_hubpm;
680 
681 	old_power = 0;
682 	for (portno = 1; portno <= hubd->h_nports; portno++) {
683 		old_power += hubpm->hubp_child_pwrstate[portno];
684 	}
685 
686 	/* assign the port power */
687 	pwr = hubd->h_hubpm->hubp_child_pwrstate[port];
688 	hubd->h_hubpm->hubp_child_pwrstate[port] = power;
689 	new_power = old_power - pwr + power;
690 
691 	USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
692 	    "hubd_set_child_pwrlvl: new_power=%d old_power=%d",
693 	    new_power, old_power);
694 
695 	if ((new_power > 0) && (old_power == 0)) {
696 		/* we have the first child coming out of low power */
697 		(void) hubd_pm_busy_component(hubd, hubd->h_dip, 0);
698 	} else if ((new_power == 0) && (old_power > 0)) {
699 		/* we have the last child going to low power */
700 		(void) hubd_pm_idle_component(hubd, hubd->h_dip, 0);
701 	}
702 	mutex_exit(HUBD_MUTEX(hubd));
703 }
704 
705 
706 /*
707  * given a child dip, locate its port number
708  */
709 static usb_port_t
hubd_child_dip2port(hubd_t * hubd,dev_info_t * dip)710 hubd_child_dip2port(hubd_t *hubd, dev_info_t *dip)
711 {
712 	usb_port_t	port;
713 
714 	mutex_enter(HUBD_MUTEX(hubd));
715 	for (port = 1; port <= hubd->h_nports; port++) {
716 		if (hubd->h_children_dips[port] == dip) {
717 
718 			break;
719 		}
720 	}
721 	ASSERT(port <= hubd->h_nports);
722 	mutex_exit(HUBD_MUTEX(hubd));
723 
724 	return (port);
725 }
726 
727 
728 /*
729  * if the hub can be put into low power mode, return success
730  * NOTE: suspend here means going to lower power, not CPR suspend.
731  */
732 static int
hubd_can_suspend(hubd_t * hubd)733 hubd_can_suspend(hubd_t *hubd)
734 {
735 	hub_power_t	*hubpm;
736 	int		total_power = 0;
737 	usb_port_t	port;
738 
739 	hubpm = hubd->h_hubpm;
740 
741 	if (DEVI_IS_DETACHING(hubd->h_dip)) {
742 
743 		return (USB_SUCCESS);
744 	}
745 
746 	/*
747 	 * Don't go to lower power if haven't been at full power for enough
748 	 * time to let hotplug thread kickoff.
749 	 */
750 	if (gethrtime() < (hubpm->hubp_time_at_full_power +
751 	    hubpm->hubp_min_pm_threshold)) {
752 
753 		return (USB_FAILURE);
754 	}
755 
756 	for (port = 1; (total_power == 0) &&
757 	    (port <= hubd->h_nports); port++) {
758 		total_power += hubpm->hubp_child_pwrstate[port];
759 	}
760 
761 	USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
762 	    "hubd_can_suspend: %d", total_power);
763 
764 	return (total_power ? USB_FAILURE : USB_SUCCESS);
765 }
766 
767 
768 /*
769  * resume port depending on current device state
770  */
771 static int
hubd_resume_port(hubd_t * hubd,usb_port_t port)772 hubd_resume_port(hubd_t *hubd, usb_port_t port)
773 {
774 	int		rval, retry;
775 	usb_cr_t	completion_reason;
776 	usb_cb_flags_t	cb_flags;
777 	uint16_t	status;
778 	uint16_t	change;
779 	int		retval = USB_FAILURE;
780 
781 	mutex_enter(HUBD_MUTEX(hubd));
782 
783 	USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
784 	    "hubd_resume_port: port=%d state=0x%x (%s)", port,
785 	    hubd->h_dev_state, usb_str_dev_state(hubd->h_dev_state));
786 
787 	switch (hubd->h_dev_state) {
788 	case USB_DEV_HUB_CHILD_PWRLVL:
789 		/*
790 		 * This could be a bus ctl for a port other than the one
791 		 * that has a remote wakeup condition. So check.
792 		 */
793 		if ((hubd->h_port_state[port] & PORT_STATUS_PSS) == 0) {
794 			/* the port isn't suspended, so don't resume */
795 			retval = USB_SUCCESS;
796 
797 			USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle,
798 			    "hubd_resume_port: port=%d not suspended", port);
799 
800 			break;
801 		}
802 		/*
803 		 * Device has initiated a wakeup.
804 		 * Issue a ClearFeature(PortSuspend)
805 		 */
806 		mutex_exit(HUBD_MUTEX(hubd));
807 		if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
808 		    hubd->h_default_pipe,
809 		    HUB_HANDLE_PORT_FEATURE_TYPE,
810 		    USB_REQ_CLEAR_FEATURE,
811 		    CFS_PORT_SUSPEND,
812 		    port,
813 		    0, NULL, 0,
814 		    &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
815 			USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle,
816 			    "ClearFeature(PortSuspend) fails "
817 			    "rval=%d cr=%d cb=0x%x", rval,
818 			    completion_reason, cb_flags);
819 		}
820 		mutex_enter(HUBD_MUTEX(hubd));
821 
822 		/* either way ack changes on the port */
823 		(void) hubd_determine_port_status(hubd, port,
824 		    &status, &change, NULL, PORT_CHANGE_PSSC);
825 		retval = USB_SUCCESS;
826 
827 		break;
828 	case USB_DEV_HUB_STATE_RECOVER:
829 		/*
830 		 * When hubd's connect event callback posts a connect
831 		 * event to its child, it results in this busctl call
832 		 * which is valid
833 		 */
834 		/* FALLTHRU */
835 	case USB_DEV_ONLINE:
836 		if (((hubd->h_port_state[port] & PORT_STATUS_CCS) == 0) ||
837 		    ((hubd->h_port_state[port] & PORT_STATUS_PSS) == 0)) {
838 			/*
839 			 * the port isn't suspended, or connected
840 			 * so don't resume
841 			 */
842 			retval = USB_SUCCESS;
843 
844 			USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle,
845 			    "hubd_resume_port: port=%d not suspended", port);
846 
847 			break;
848 		}
849 		/*
850 		 * prevent kicking off the hotplug thread
851 		 */
852 		hubd->h_hotplug_thread++;
853 		hubd_stop_polling(hubd);
854 
855 		/* Now ClearFeature(PortSuspend) */
856 		for (retry = 0; retry < HUBD_SUS_RES_RETRY; retry++) {
857 			mutex_exit(HUBD_MUTEX(hubd));
858 			rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
859 			    hubd->h_default_pipe,
860 			    HUB_HANDLE_PORT_FEATURE_TYPE,
861 			    USB_REQ_CLEAR_FEATURE,
862 			    CFS_PORT_SUSPEND,
863 			    port,
864 			    0, NULL, 0,
865 			    &completion_reason, &cb_flags, 0);
866 			mutex_enter(HUBD_MUTEX(hubd));
867 			if (rval != USB_SUCCESS) {
868 				USB_DPRINTF_L2(DPRINT_MASK_PM,
869 				    hubd->h_log_handle,
870 				    "ClearFeature(PortSuspend) fails"
871 				    "rval=%d cr=%d cb=0x%x", rval,
872 				    completion_reason, cb_flags);
873 			} else {
874 				/*
875 				 * As per spec section 11.9 and 7.1.7.7
876 				 * hub need to provide at least 20ms of
877 				 * resume signalling, and s/w provide 10ms of
878 				 * recovery time before accessing the port.
879 				 */
880 				mutex_exit(HUBD_MUTEX(hubd));
881 				delay(drv_usectohz(40000));
882 				mutex_enter(HUBD_MUTEX(hubd));
883 				(void) hubd_determine_port_status(hubd, port,
884 				    &status, &change, NULL, PORT_CHANGE_PSSC);
885 
886 				if ((status & PORT_STATUS_PSS) == 0) {
887 					/* the port did finally resume */
888 					retval = USB_SUCCESS;
889 
890 					break;
891 				}
892 			}
893 		}
894 
895 		/* allow hotplug thread again */
896 		hubd->h_hotplug_thread--;
897 		hubd_start_polling(hubd, 0);
898 
899 		break;
900 	case USB_DEV_DISCONNECTED:
901 		/* Ignore - NO Operation */
902 		retval = USB_SUCCESS;
903 
904 		break;
905 	case USB_DEV_SUSPENDED:
906 	case USB_DEV_PWRED_DOWN:
907 	default:
908 		USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle,
909 		    "Improper state for port Resume");
910 
911 		break;
912 	}
913 	mutex_exit(HUBD_MUTEX(hubd));
914 
915 	return (retval);
916 }
917 
918 
919 /*
920  * suspend port depending on device state
921  */
922 static int
hubd_suspend_port(hubd_t * hubd,usb_port_t port)923 hubd_suspend_port(hubd_t *hubd, usb_port_t port)
924 {
925 	int		rval, retry;
926 	int		retval = USB_FAILURE;
927 	usb_cr_t	completion_reason;
928 	usb_cb_flags_t	cb_flags;
929 	uint16_t	status;
930 	uint16_t	change;
931 
932 	USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
933 	    "hubd_suspend_port: port=%d", port);
934 
935 	mutex_enter(HUBD_MUTEX(hubd));
936 
937 	switch (hubd->h_dev_state) {
938 	case USB_DEV_HUB_STATE_RECOVER:
939 		/*
940 		 * When hubd's connect event callback posts a connect
941 		 * event to its child, it results in this busctl call
942 		 * which is valid
943 		 */
944 		/* FALLTHRU */
945 	case USB_DEV_HUB_CHILD_PWRLVL:
946 		/*
947 		 * When one child is resuming, the other could timeout
948 		 * and go to low power mode, which is valid
949 		 */
950 		/* FALLTHRU */
951 	case USB_DEV_ONLINE:
952 		hubd->h_hotplug_thread++;
953 		hubd_stop_polling(hubd);
954 
955 		/*
956 		 * Some devices start an unprovoked resume.  According to spec,
957 		 * normal resume time for port is 10ms.  Wait for double that
958 		 * time, then check to be sure port is really suspended.
959 		 */
960 		for (retry = 0; retry < HUBD_SUS_RES_RETRY; retry++) {
961 			/* Now SetFeature(PortSuspend) */
962 			mutex_exit(HUBD_MUTEX(hubd));
963 			if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
964 			    hubd->h_default_pipe,
965 			    HUB_HANDLE_PORT_FEATURE_TYPE,
966 			    USB_REQ_SET_FEATURE,
967 			    CFS_PORT_SUSPEND,
968 			    port,
969 			    0, NULL, 0,
970 			    &completion_reason, &cb_flags, 0)) !=
971 			    USB_SUCCESS) {
972 				USB_DPRINTF_L2(DPRINT_MASK_PM,
973 				    hubd->h_log_handle,
974 				    "SetFeature(PortSuspend) fails"
975 				    "rval=%d cr=%d cb=0x%x",
976 				    rval, completion_reason, cb_flags);
977 			}
978 
979 			/*
980 			 * some devices start an unprovoked resume
981 			 * wait and check port status after some time
982 			 */
983 			delay(drv_usectohz(20000));
984 
985 			/* either ways ack changes on the port */
986 			mutex_enter(HUBD_MUTEX(hubd));
987 			(void) hubd_determine_port_status(hubd, port,
988 			    &status, &change, NULL, PORT_CHANGE_PSSC);
989 			if (status & PORT_STATUS_PSS) {
990 				/* the port is indeed suspended */
991 				retval = USB_SUCCESS;
992 
993 				break;
994 			} else {
995 				USB_DPRINTF_L0(DPRINT_MASK_PM,
996 				    hubd->h_log_handle,
997 				    "hubdi: port%d failed to be suspended!",
998 				    port);
999 			}
1000 		}
1001 
1002 		hubd->h_hotplug_thread--;
1003 		hubd_start_polling(hubd, 0);
1004 
1005 		break;
1006 
1007 	case USB_DEV_DISCONNECTED:
1008 		/* Ignore - No Operation */
1009 		retval = USB_SUCCESS;
1010 
1011 		break;
1012 
1013 	case USB_DEV_SUSPENDED:
1014 	case USB_DEV_PWRED_DOWN:
1015 	default:
1016 		USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle,
1017 		    "Improper state for port Suspend");
1018 
1019 		break;
1020 	}
1021 	mutex_exit(HUBD_MUTEX(hubd));
1022 
1023 	return (retval);
1024 }
1025 
1026 
1027 /*
1028  * child post attach/detach notifications
1029  */
1030 static void
hubd_post_attach(hubd_t * hubd,usb_port_t port,struct attachspec * as)1031 hubd_post_attach(hubd_t *hubd, usb_port_t port, struct attachspec *as)
1032 {
1033 	dev_info_t	*dip;
1034 
1035 	USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
1036 	    "hubd_post_attach: port=%d result=%d",
1037 	    port, as->result);
1038 
1039 	if (as->result == DDI_SUCCESS) {
1040 		/*
1041 		 * Check if the child created wants to be power managed.
1042 		 * If yes, the childs power level gets automatically tracked
1043 		 * by DDI_CTLOPS_POWER busctl.
1044 		 * If no, we set power of the new child by default
1045 		 * to USB_DEV_OS_FULL_PWR. Because we should never suspend.
1046 		 */
1047 		mutex_enter(HUBD_MUTEX(hubd));
1048 		dip = hubd->h_children_dips[port];
1049 		mutex_exit(HUBD_MUTEX(hubd));
1050 		if (DEVI(dip)->devi_pm_info == NULL) {
1051 			hubd_set_child_pwrlvl(hubd, port, USB_DEV_OS_FULL_PWR);
1052 		}
1053 	}
1054 }
1055 
1056 
1057 static void
hubd_post_detach(hubd_t * hubd,usb_port_t port,struct detachspec * ds)1058 hubd_post_detach(hubd_t *hubd, usb_port_t port, struct detachspec *ds)
1059 {
1060 	USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
1061 	    "hubd_post_detach: port=%d result=%d", port, ds->result);
1062 
1063 	/*
1064 	 * if the device is successfully detached and is the
1065 	 * last device to detach, mark component as idle
1066 	 */
1067 	mutex_enter(HUBD_MUTEX(hubd));
1068 	if (ds->result == DDI_SUCCESS) {
1069 		usba_device_t	*usba_device = hubd->h_usba_devices[port];
1070 		dev_info_t	*pdip = hubd->h_dip;
1071 		mutex_exit(HUBD_MUTEX(hubd));
1072 
1073 		usba_hubdi_incr_power_budget(pdip, usba_device);
1074 
1075 		/*
1076 		 * We set power of the detached child
1077 		 * to 0, so that we can suspend if all
1078 		 * our children are gone
1079 		 */
1080 		hubd_set_child_pwrlvl(hubd, port, USB_DEV_OS_PWR_OFF);
1081 
1082 		/* check for leaks on detaching */
1083 		if ((usba_device) && (ds->cmd == DDI_DETACH)) {
1084 			usba_check_for_leaks(usba_device);
1085 		}
1086 	} else {
1087 		mutex_exit(HUBD_MUTEX(hubd));
1088 	}
1089 }
1090 
1091 
1092 /*
1093  * hubd_post_power
1094  *	After the child's power entry point has been called
1095  *	we record its power level in our local struct.
1096  *	If the device has powered off, we suspend port
1097  */
1098 static int
hubd_post_power(hubd_t * hubd,usb_port_t port,pm_bp_child_pwrchg_t * bpc,int result)1099 hubd_post_power(hubd_t *hubd, usb_port_t port, pm_bp_child_pwrchg_t *bpc,
1100     int result)
1101 {
1102 	int	retval = USB_SUCCESS;
1103 
1104 	USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
1105 	    "hubd_post_power: port=%d", port);
1106 
1107 	if (result == DDI_SUCCESS) {
1108 
1109 		/* record this power in our local struct */
1110 		hubd_set_child_pwrlvl(hubd, port, bpc->bpc_nlevel);
1111 
1112 		if (bpc->bpc_nlevel == USB_DEV_OS_PWR_OFF) {
1113 
1114 			/* now suspend the port */
1115 			retval = hubd_suspend_port(hubd, port);
1116 		} else if (bpc->bpc_nlevel == USB_DEV_OS_FULL_PWR) {
1117 
1118 			/* make sure the port is resumed */
1119 			retval = hubd_resume_port(hubd, port);
1120 		}
1121 	} else {
1122 
1123 		/* record old power in our local struct */
1124 		hubd_set_child_pwrlvl(hubd, port, bpc->bpc_olevel);
1125 
1126 		if (bpc->bpc_olevel == USB_DEV_OS_PWR_OFF) {
1127 
1128 			/*
1129 			 * As this device failed to transition from
1130 			 * power off state, suspend the port again
1131 			 */
1132 			retval = hubd_suspend_port(hubd, port);
1133 		}
1134 	}
1135 
1136 	return (retval);
1137 }
1138 
1139 
1140 /*
1141  * bus ctl notifications are handled here, the rest goes up to root hub/hcd
1142  */
1143 static int
usba_hubdi_bus_ctl(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t op,void * arg,void * result)1144 usba_hubdi_bus_ctl(dev_info_t *dip,
1145     dev_info_t	*rdip,
1146     ddi_ctl_enum_t	op,
1147     void		*arg,
1148     void		*result)
1149 {
1150 	usba_device_t *hub_usba_device = usba_get_usba_device(rdip);
1151 	dev_info_t *root_hub_dip = hub_usba_device->usb_root_hub_dip;
1152 	struct attachspec *as;
1153 	struct detachspec *ds;
1154 	hubd_t		*hubd;
1155 	usb_port_t	port;
1156 	int		circ, rval;
1157 	int		retval = DDI_FAILURE;
1158 
1159 	hubd = hubd_get_soft_state(dip);
1160 
1161 	mutex_enter(HUBD_MUTEX(hubd));
1162 
1163 	/* flag that we are currently running bus_ctl */
1164 	hubd->h_bus_ctls++;
1165 	mutex_exit(HUBD_MUTEX(hubd));
1166 
1167 	USB_DPRINTF_L3(DPRINT_MASK_HUBDI, hubd->h_log_handle,
1168 	    "usba_hubdi_bus_ctl:\n\t"
1169 	    "dip=0x%p, rdip=0x%p, op=0x%x, arg=0x%p",
1170 	    (void *)dip, (void *)rdip, op, arg);
1171 
1172 	switch (op) {
1173 	case DDI_CTLOPS_ATTACH:
1174 		as = (struct attachspec *)arg;
1175 		port = hubd_child_dip2port(hubd, rdip);
1176 
1177 		/* there is nothing to do at resume time */
1178 		if (as->cmd == DDI_RESUME) {
1179 			break;
1180 		}
1181 
1182 		/* serialize access */
1183 		ndi_devi_enter(hubd->h_dip, &circ);
1184 
1185 		switch (as->when) {
1186 		case DDI_PRE:
1187 			USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
1188 			    "DDI_PRE DDI_CTLOPS_ATTACH: dip=%p, port=%d",
1189 			    (void *)rdip, port);
1190 
1191 			mutex_enter(HUBD_MUTEX(hubd));
1192 			hubd->h_port_state[port] |= HUBD_CHILD_ATTACHING;
1193 
1194 			/* Go busy here.  Matching idle is DDI_POST case. */
1195 			(void) hubd_pm_busy_component(hubd, dip, 0);
1196 			mutex_exit(HUBD_MUTEX(hubd));
1197 
1198 			/*
1199 			 * if we suspended the port previously
1200 			 * because child went to low power state, and
1201 			 * someone unloaded the driver, the port would
1202 			 * still be suspended and needs to be resumed
1203 			 */
1204 			rval = hubd_resume_port(hubd, port);
1205 			if (rval == USB_SUCCESS) {
1206 				retval = DDI_SUCCESS;
1207 			}
1208 
1209 			break;
1210 		case DDI_POST:
1211 			USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
1212 			    "DDI_POST DDI_CTLOPS_ATTACH: dip=%p, port=%d",
1213 			    (void *)rdip, port);
1214 
1215 			mutex_enter(HUBD_MUTEX(hubd));
1216 			hubd->h_port_state[port] &= ~HUBD_CHILD_ATTACHING;
1217 			mutex_exit(HUBD_MUTEX(hubd));
1218 
1219 			hubd_post_attach(hubd, port, (struct attachspec *)arg);
1220 			retval = DDI_SUCCESS;
1221 			mutex_enter(HUBD_MUTEX(hubd));
1222 
1223 			/* Matching idle call for DDI_PRE busy call. */
1224 			(void) hubd_pm_idle_component(hubd, dip, 0);
1225 			mutex_exit(HUBD_MUTEX(hubd));
1226 		}
1227 		ndi_devi_exit(hubd->h_dip, circ);
1228 
1229 		break;
1230 	case DDI_CTLOPS_DETACH:
1231 		ds = (struct detachspec *)arg;
1232 		port = hubd_child_dip2port(hubd, rdip);
1233 
1234 		/* there is nothing to do at suspend time */
1235 		if (ds->cmd == DDI_SUSPEND) {
1236 			break;
1237 		}
1238 
1239 		/* serialize access */
1240 		ndi_devi_enter(hubd->h_dip, &circ);
1241 
1242 		switch (ds->when) {
1243 		case DDI_PRE:
1244 			USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
1245 			    "DDI_PRE DDI_CTLOPS_DETACH: dip=%p port=%d",
1246 			    (void *)rdip, port);
1247 
1248 			mutex_enter(HUBD_MUTEX(hubd));
1249 			hubd->h_port_state[port] |= HUBD_CHILD_DETACHING;
1250 
1251 			/* Go busy here.  Matching idle is DDI_POST case. */
1252 			(void) hubd_pm_busy_component(hubd, dip, 0);
1253 
1254 			mutex_exit(HUBD_MUTEX(hubd));
1255 			retval = DDI_SUCCESS;
1256 
1257 			break;
1258 		case DDI_POST:
1259 			USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
1260 			    "DDI_POST DDI_CTLOPS_DETACH: dip=%p port=%d",
1261 			    (void *)rdip, port);
1262 
1263 			mutex_enter(HUBD_MUTEX(hubd));
1264 			hubd->h_port_state[port] &= ~HUBD_CHILD_DETACHING;
1265 			mutex_exit(HUBD_MUTEX(hubd));
1266 
1267 			/* Matching idle call for DDI_PRE busy call. */
1268 			hubd_post_detach(hubd, port, (struct detachspec *)arg);
1269 			retval = DDI_SUCCESS;
1270 			mutex_enter(HUBD_MUTEX(hubd));
1271 			(void) hubd_pm_idle_component(hubd, dip, 0);
1272 			mutex_exit(HUBD_MUTEX(hubd));
1273 
1274 			break;
1275 		}
1276 		ndi_devi_exit(hubd->h_dip, circ);
1277 
1278 		break;
1279 	default:
1280 		retval = usba_bus_ctl(root_hub_dip, rdip, op, arg, result);
1281 	}
1282 
1283 	/* decrement bus_ctls count */
1284 	mutex_enter(HUBD_MUTEX(hubd));
1285 	hubd->h_bus_ctls--;
1286 	ASSERT(hubd->h_bus_ctls >= 0);
1287 	mutex_exit(HUBD_MUTEX(hubd));
1288 
1289 	return (retval);
1290 }
1291 
1292 /*
1293  * hubd_config_one:
1294  *	enumerate one child according to 'port'
1295  */
1296 
1297 static boolean_t
hubd_config_one(hubd_t * hubd,int port)1298 hubd_config_one(hubd_t *hubd, int port)
1299 {
1300 	dev_info_t	*hdip = hubd->h_dip;
1301 	dev_info_t	*rh_dip = hubd->h_usba_device->usb_root_hub_dip;
1302 	boolean_t	online_child = B_FALSE, found = B_FALSE;
1303 	int		prh_circ, rh_circ, circ;
1304 
1305 	USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
1306 	    "hubd_config_one:  started, hubd_reset_port = 0x%x", port);
1307 
1308 	ndi_hold_devi(hdip); /* so we don't race with detach */
1309 
1310 	/*
1311 	 * this ensures one config activity per system at a time.
1312 	 * we enter the parent PCI node to have this serialization.
1313 	 * this also excludes ioctls and deathrow thread
1314 	 */
1315 	ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ);
1316 	ndi_devi_enter(rh_dip, &rh_circ);
1317 
1318 	/* exclude other threads */
1319 	ndi_devi_enter(hdip, &circ);
1320 	mutex_enter(HUBD_MUTEX(hubd));
1321 
1322 	hubd_pm_busy_component(hubd, hubd->h_dip, 0);
1323 
1324 	if (!hubd->h_children_dips[port]) {
1325 		uint16_t	status, change;
1326 
1327 		(void) hubd_determine_port_status(hubd, port,
1328 		    &status, &change, NULL, HUBD_ACK_ALL_CHANGES);
1329 
1330 		if (status & PORT_STATUS_CCS) {
1331 			online_child |=	(hubd_handle_port_connect(hubd,
1332 			    port) == USB_SUCCESS);
1333 			found = online_child;
1334 		}
1335 	} else {
1336 		found = B_TRUE;
1337 	}
1338 
1339 	mutex_exit(HUBD_MUTEX(hubd));
1340 
1341 	ndi_devi_exit(hdip, circ);
1342 	ndi_devi_exit(rh_dip, rh_circ);
1343 	ndi_devi_exit(ddi_get_parent(rh_dip), prh_circ);
1344 
1345 	if (online_child) {
1346 		USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
1347 		    "hubd_config_one: onlining child");
1348 
1349 		(void) ndi_devi_online(hubd->h_dip, 0);
1350 	}
1351 
1352 	mutex_enter(HUBD_MUTEX(hubd));
1353 
1354 	(void) hubd_pm_idle_component(hubd, hubd->h_dip, 0);
1355 
1356 	USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
1357 	    "hubd_config_one: exit");
1358 
1359 	mutex_exit(HUBD_MUTEX(hubd));
1360 
1361 	ndi_rele_devi(hdip);
1362 
1363 	return (found);
1364 }
1365 
1366 /*
1367  * bus enumeration entry points
1368  */
1369 static int
hubd_bus_config(dev_info_t * dip,uint_t flag,ddi_bus_config_op_t op,void * arg,dev_info_t ** child)1370 hubd_bus_config(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
1371     void *arg, dev_info_t **child)
1372 {
1373 	hubd_t	*hubd = hubd_get_soft_state(dip);
1374 	int	rval, circ;
1375 	long port;
1376 
1377 	USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
1378 	    "hubd_bus_config: op=%d", op);
1379 
1380 	if (hubdi_bus_config_debug) {
1381 		flag |= NDI_DEVI_DEBUG;
1382 	}
1383 
1384 	if (op == BUS_CONFIG_ONE) {
1385 		boolean_t found;
1386 		char cname[80];
1387 		char *name, *addr;
1388 
1389 		USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle,
1390 		    "hubd_bus_config: op=%d (BUS_CONFIG_ONE)", op);
1391 
1392 		(void) snprintf(cname, 80, "%s", (char *)arg);
1393 		/* split name into "name@addr" parts */
1394 		i_ddi_parse_name(cname, &name, &addr, NULL);
1395 		if (addr && *addr) {
1396 			(void) ddi_strtol(addr, NULL, 16, &port);
1397 		} else {
1398 			return (NDI_FAILURE);
1399 		}
1400 
1401 		found = hubd_config_one(hubd, port);
1402 
1403 		if (found == 0) {
1404 			return (NDI_FAILURE);
1405 		}
1406 
1407 	}
1408 	ndi_devi_enter(hubd->h_dip, &circ);
1409 	rval = ndi_busop_bus_config(dip, flag, op, arg, child, 0);
1410 	ndi_devi_exit(hubd->h_dip, circ);
1411 
1412 	return (rval);
1413 }
1414 
1415 
1416 static int
hubd_bus_unconfig(dev_info_t * dip,uint_t flag,ddi_bus_config_op_t op,void * arg)1417 hubd_bus_unconfig(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
1418     void *arg)
1419 {
1420 	hubd_t		*hubd = hubd_get_soft_state(dip);
1421 	dev_info_t	*cdip;
1422 	usb_port_t	port;
1423 	int		circ;
1424 	int		rval;
1425 
1426 	USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
1427 	    "hubd_bus_unconfig: op=%d", op);
1428 
1429 	if (hubdi_bus_config_debug) {
1430 		flag |= NDI_DEVI_DEBUG;
1431 	}
1432 
1433 	if ((op == BUS_UNCONFIG_ALL) && (flag & NDI_AUTODETACH) == 0) {
1434 		flag |= NDI_DEVI_REMOVE;
1435 	}
1436 
1437 	/* serialize access */
1438 	ndi_devi_enter(dip, &circ);
1439 
1440 	rval = ndi_busop_bus_unconfig(dip, flag, op, arg);
1441 
1442 	/* logically zap children's list */
1443 	mutex_enter(HUBD_MUTEX(hubd));
1444 	for (port = 1; port <= hubd->h_nports; port++) {
1445 		hubd->h_port_state[port] |= HUBD_CHILD_ZAP;
1446 	}
1447 	mutex_exit(HUBD_MUTEX(hubd));
1448 
1449 	/* fill in what's left */
1450 	for (cdip = ddi_get_child(dip); cdip;
1451 	    cdip = ddi_get_next_sibling(cdip)) {
1452 		usba_device_t *usba_device = usba_get_usba_device(cdip);
1453 
1454 		if (usba_device == NULL) {
1455 
1456 			continue;
1457 		}
1458 		mutex_enter(HUBD_MUTEX(hubd));
1459 		port = usba_device->usb_port;
1460 		hubd->h_children_dips[port] = cdip;
1461 		hubd->h_port_state[port] &= ~HUBD_CHILD_ZAP;
1462 		mutex_exit(HUBD_MUTEX(hubd));
1463 	}
1464 
1465 	/* physically zap the children we didn't find */
1466 	mutex_enter(HUBD_MUTEX(hubd));
1467 	for (port = 1; port <= hubd->h_nports; port++) {
1468 		if (hubd->h_port_state[port] &	HUBD_CHILD_ZAP) {
1469 			/* zap the dip and usba_device structure as well */
1470 			hubd_free_usba_device(hubd, hubd->h_usba_devices[port]);
1471 			hubd->h_children_dips[port] = NULL;
1472 			hubd->h_port_state[port] &= ~HUBD_CHILD_ZAP;
1473 		}
1474 	}
1475 	mutex_exit(HUBD_MUTEX(hubd));
1476 
1477 	ndi_devi_exit(dip, circ);
1478 
1479 	USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
1480 	    "hubd_bus_unconfig: rval=%d", rval);
1481 
1482 	return (rval);
1483 }
1484 
1485 
1486 /* bus_power entry point */
1487 static int
hubd_bus_power(dev_info_t * dip,void * impl_arg,pm_bus_power_op_t op,void * arg,void * result)1488 hubd_bus_power(dev_info_t *dip, void *impl_arg, pm_bus_power_op_t op,
1489     void *arg, void *result)
1490 {
1491 	hubd_t		*hubd;
1492 	int		rval, pwrup_res;
1493 	usb_port_t	port;
1494 	int		retval = DDI_FAILURE;
1495 	pm_bp_child_pwrchg_t	*bpc;
1496 	pm_bp_nexus_pwrup_t	bpn;
1497 
1498 	hubd = hubd_get_soft_state(dip);
1499 
1500 	USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubd->h_log_handle,
1501 	    "hubd_bus_power: dip=%p, impl_arg=%p, power_op=%d, arg=%p, "
1502 	    "result=%d\n", (void *)dip, impl_arg, op, arg, *(int *)result);
1503 
1504 	bpc = (pm_bp_child_pwrchg_t *)arg;
1505 
1506 	mutex_enter(HUBD_MUTEX(hubd));
1507 	hubd->h_bus_pwr++;
1508 	mutex_exit(HUBD_MUTEX(hubd));
1509 
1510 	switch (op) {
1511 	case BUS_POWER_PRE_NOTIFICATION:
1512 		port = hubd_child_dip2port(hubd, bpc->bpc_dip);
1513 		USB_DPRINTF_L3(DPRINT_MASK_HUBDI, hubd->h_log_handle,
1514 		    "hubd_bus_power: BUS_POWER_PRE_NOTIFICATION, port=%d",
1515 		    port);
1516 
1517 		/* go to full power if we are powered down */
1518 		mutex_enter(HUBD_MUTEX(hubd));
1519 
1520 		/*
1521 		 * If this case completes normally, idle will be in
1522 		 * hubd_bus_power / BUS_POWER_POST_NOTIFICATION
1523 		 */
1524 		hubd_pm_busy_component(hubd, dip, 0);
1525 
1526 		/*
1527 		 * raise power only if we have created the components
1528 		 * and are currently in low power
1529 		 */
1530 		if ((hubd->h_dev_state == USB_DEV_PWRED_DOWN) &&
1531 		    hubd->h_hubpm->hubp_wakeup_enabled) {
1532 			mutex_exit(HUBD_MUTEX(hubd));
1533 
1534 			bpn.bpn_comp = 0;
1535 			bpn.bpn_dip = dip;
1536 			bpn.bpn_level = USB_DEV_OS_FULL_PWR;
1537 			bpn.bpn_private = bpc->bpc_private;
1538 
1539 			rval = pm_busop_bus_power(dip, impl_arg,
1540 			    BUS_POWER_NEXUS_PWRUP, (void *)&bpn,
1541 			    (void *)&pwrup_res);
1542 
1543 			if (rval != DDI_SUCCESS || pwrup_res != DDI_SUCCESS) {
1544 				mutex_enter(HUBD_MUTEX(hubd));
1545 				hubd_pm_idle_component(hubd, dip, 0);
1546 				mutex_exit(HUBD_MUTEX(hubd));
1547 
1548 				break;
1549 			}
1550 			mutex_enter(HUBD_MUTEX(hubd));
1551 		}
1552 
1553 		/* indicate that child is changing power level */
1554 		hubd->h_port_state[port] |= HUBD_CHILD_PWRLVL_CHNG;
1555 		mutex_exit(HUBD_MUTEX(hubd));
1556 
1557 		if ((bpc->bpc_olevel == 0) &&
1558 		    (bpc->bpc_nlevel > bpc->bpc_olevel)) {
1559 			/*
1560 			 * this child is transitioning from power off
1561 			 * to power on state - resume port
1562 			 */
1563 			rval = hubd_resume_port(hubd, port);
1564 			if (rval == USB_SUCCESS) {
1565 				retval = DDI_SUCCESS;
1566 			} else {
1567 				/* reset this flag on failure */
1568 				mutex_enter(HUBD_MUTEX(hubd));
1569 				hubd->h_port_state[port] &=
1570 				    ~HUBD_CHILD_PWRLVL_CHNG;
1571 				hubd_pm_idle_component(hubd, dip, 0);
1572 				mutex_exit(HUBD_MUTEX(hubd));
1573 			}
1574 		} else {
1575 			retval = DDI_SUCCESS;
1576 		}
1577 
1578 		break;
1579 	case BUS_POWER_POST_NOTIFICATION:
1580 		port = hubd_child_dip2port(hubd, bpc->bpc_dip);
1581 		USB_DPRINTF_L3(DPRINT_MASK_HUBDI, hubd->h_log_handle,
1582 		    "hubd_bus_power: BUS_POWER_POST_NOTIFICATION, port=%d",
1583 		    port);
1584 
1585 		mutex_enter(HUBD_MUTEX(hubd));
1586 		hubd->h_port_state[port] &= ~HUBD_CHILD_PWRLVL_CHNG;
1587 		mutex_exit(HUBD_MUTEX(hubd));
1588 
1589 		/* record child's pwr and suspend port if required */
1590 		rval = hubd_post_power(hubd, port, bpc, *(int *)result);
1591 		if (rval == USB_SUCCESS) {
1592 
1593 			retval = DDI_SUCCESS;
1594 		}
1595 
1596 		mutex_enter(HUBD_MUTEX(hubd));
1597 
1598 		/*
1599 		 * Matching idle for the busy in
1600 		 * hubd_bus_power / BUS_POWER_PRE_NOTIFICATION
1601 		 */
1602 		hubd_pm_idle_component(hubd, dip, 0);
1603 
1604 		mutex_exit(HUBD_MUTEX(hubd));
1605 
1606 		break;
1607 	default:
1608 		retval = pm_busop_bus_power(dip, impl_arg, op, arg, result);
1609 
1610 		break;
1611 	}
1612 
1613 	mutex_enter(HUBD_MUTEX(hubd));
1614 	hubd->h_bus_pwr--;
1615 	mutex_exit(HUBD_MUTEX(hubd));
1616 
1617 	return (retval);
1618 }
1619 
1620 
1621 /*
1622  * functions to handle power transition for OS levels 0 -> 3
1623  */
1624 static int
hubd_pwrlvl0(hubd_t * hubd)1625 hubd_pwrlvl0(hubd_t *hubd)
1626 {
1627 	hub_power_t	*hubpm;
1628 
1629 	/* We can't power down if hotplug thread is running */
1630 	if (hubd->h_hotplug_thread || hubd->h_hubpm->hubp_busy_pm ||
1631 	    (hubd_can_suspend(hubd) == USB_FAILURE)) {
1632 
1633 		return (USB_FAILURE);
1634 	}
1635 
1636 	switch (hubd->h_dev_state) {
1637 	case USB_DEV_ONLINE:
1638 		hubpm = hubd->h_hubpm;
1639 
1640 		/*
1641 		 * To avoid race with bus_power pre_notify on check over
1642 		 * dev_state, we need to correctly set the dev state
1643 		 * before the mutex is dropped in stop polling.
1644 		 */
1645 		hubd->h_dev_state = USB_DEV_PWRED_DOWN;
1646 		hubpm->hubp_current_power = USB_DEV_OS_PWR_OFF;
1647 
1648 		/*
1649 		 * if we are the root hub, do not stop polling
1650 		 * otherwise, we will never see a resume
1651 		 */
1652 		if (usba_is_root_hub(hubd->h_dip)) {
1653 			/* place holder to implement Global Suspend */
1654 			USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle,
1655 			    "Global Suspend: Not Yet Implemented");
1656 		} else {
1657 			hubd_stop_polling(hubd);
1658 		}
1659 
1660 		/* Issue USB D3 command to the device here */
1661 		(void) usb_set_device_pwrlvl3(hubd->h_dip);
1662 
1663 		break;
1664 	case USB_DEV_DISCONNECTED:
1665 	case USB_DEV_SUSPENDED:
1666 	case USB_DEV_PWRED_DOWN:
1667 	default:
1668 
1669 		break;
1670 	}
1671 
1672 	return (USB_SUCCESS);
1673 }
1674 
1675 
1676 /* ARGSUSED */
1677 static int
hubd_pwrlvl1(hubd_t * hubd)1678 hubd_pwrlvl1(hubd_t *hubd)
1679 {
1680 	/* Issue USB D2 command to the device here */
1681 	(void) usb_set_device_pwrlvl2(hubd->h_dip);
1682 
1683 	return (USB_FAILURE);
1684 }
1685 
1686 
1687 /* ARGSUSED */
1688 static int
hubd_pwrlvl2(hubd_t * hubd)1689 hubd_pwrlvl2(hubd_t *hubd)
1690 {
1691 	/* Issue USB D1 command to the device here */
1692 	(void) usb_set_device_pwrlvl1(hubd->h_dip);
1693 
1694 	return (USB_FAILURE);
1695 }
1696 
1697 
1698 static int
hubd_pwrlvl3(hubd_t * hubd)1699 hubd_pwrlvl3(hubd_t *hubd)
1700 {
1701 	hub_power_t	*hubpm;
1702 	int		rval;
1703 
1704 	USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, "hubd_pwrlvl3");
1705 
1706 	hubpm = hubd->h_hubpm;
1707 	switch (hubd->h_dev_state) {
1708 	case USB_DEV_PWRED_DOWN:
1709 		ASSERT(hubpm->hubp_current_power == USB_DEV_OS_PWR_OFF);
1710 		if (usba_is_root_hub(hubd->h_dip)) {
1711 			/* implement global resume here */
1712 			USB_DPRINTF_L2(DPRINT_MASK_PM,
1713 			    hubd->h_log_handle,
1714 			    "Global Resume: Not Yet Implemented");
1715 		}
1716 		/* Issue USB D0 command to the device here */
1717 		rval = usb_set_device_pwrlvl0(hubd->h_dip);
1718 		ASSERT(rval == USB_SUCCESS);
1719 		hubd->h_dev_state = USB_DEV_ONLINE;
1720 		hubpm->hubp_current_power = USB_DEV_OS_FULL_PWR;
1721 		hubpm->hubp_time_at_full_power = gethrtime();
1722 		hubd_start_polling(hubd, 0);
1723 
1724 		/* FALLTHRU */
1725 	case USB_DEV_ONLINE:
1726 		/* we are already in full power */
1727 
1728 		/* FALLTHRU */
1729 	case USB_DEV_DISCONNECTED:
1730 	case USB_DEV_SUSPENDED:
1731 		/*
1732 		 * PM framework tries to put you in full power
1733 		 * during system shutdown. If we are disconnected
1734 		 * return success. Also, we should not change state
1735 		 * when we are disconnected or suspended or about to
1736 		 * transition to that state
1737 		 */
1738 
1739 		return (USB_SUCCESS);
1740 	default:
1741 		USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle,
1742 		    "hubd_pwrlvl3: Illegal dev_state=%d", hubd->h_dev_state);
1743 
1744 		return (USB_FAILURE);
1745 	}
1746 }
1747 
1748 
1749 /* power entry point */
1750 /* ARGSUSED */
1751 int
usba_hubdi_power(dev_info_t * dip,int comp,int level)1752 usba_hubdi_power(dev_info_t *dip, int comp, int level)
1753 {
1754 	hubd_t		*hubd;
1755 	hub_power_t	*hubpm;
1756 	int		retval;
1757 	int		circ;
1758 
1759 	hubd = hubd_get_soft_state(dip);
1760 	USB_DPRINTF_L3(DPRINT_MASK_HUBDI, hubd->h_log_handle,
1761 	    "usba_hubdi_power: level=%d", level);
1762 
1763 	ndi_devi_enter(dip, &circ);
1764 
1765 	mutex_enter(HUBD_MUTEX(hubd));
1766 	hubpm = hubd->h_hubpm;
1767 
1768 	/* check if we are transitioning to a legal power level */
1769 	if (USB_DEV_PWRSTATE_OK(hubpm->hubp_pwr_states, level)) {
1770 		USB_DPRINTF_L2(DPRINT_MASK_HUBDI, hubd->h_log_handle,
1771 		    "usba_hubdi_power: illegal power level=%d "
1772 		    "hubp_pwr_states=0x%x", level, hubpm->hubp_pwr_states);
1773 		mutex_exit(HUBD_MUTEX(hubd));
1774 
1775 		ndi_devi_exit(dip, circ);
1776 
1777 		return (DDI_FAILURE);
1778 	}
1779 
1780 	switch (level) {
1781 	case USB_DEV_OS_PWR_OFF:
1782 		retval = hubd_pwrlvl0(hubd);
1783 
1784 		break;
1785 	case USB_DEV_OS_PWR_1:
1786 		retval = hubd_pwrlvl1(hubd);
1787 
1788 		break;
1789 	case USB_DEV_OS_PWR_2:
1790 		retval = hubd_pwrlvl2(hubd);
1791 
1792 		break;
1793 	case USB_DEV_OS_FULL_PWR:
1794 		retval = hubd_pwrlvl3(hubd);
1795 
1796 		break;
1797 	default:
1798 		retval = USB_FAILURE;
1799 
1800 		break;
1801 	}
1802 	mutex_exit(HUBD_MUTEX(hubd));
1803 
1804 	ndi_devi_exit(dip, circ);
1805 
1806 	return ((retval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
1807 }
1808 
1809 
1810 /* power entry point for the root hub */
1811 int
usba_hubdi_root_hub_power(dev_info_t * dip,int comp,int level)1812 usba_hubdi_root_hub_power(dev_info_t *dip, int comp, int level)
1813 {
1814 	return (usba_hubdi_power(dip, comp, level));
1815 }
1816 
1817 
1818 /*
1819  * standard driver entry points support code
1820  */
1821 int
usba_hubdi_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)1822 usba_hubdi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1823 {
1824 	int			instance = ddi_get_instance(dip);
1825 	hubd_t			*hubd = NULL;
1826 	int			i, rval;
1827 	int			minor;
1828 	uint8_t			ports_count;
1829 	char			*log_name = NULL;
1830 	const char		*root_hub_drvname;
1831 	usb_ep_data_t		*ep_data;
1832 	usba_device_t		*child_ud = NULL;
1833 	usb_dev_descr_t		*usb_dev_descr;
1834 	usb_port_status_t	parent_port_status, child_port_status;
1835 
1836 	USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubdi_log_handle,
1837 	    "hubd_attach instance %d, cmd=0x%x", instance, cmd);
1838 
1839 	switch (cmd) {
1840 	case DDI_ATTACH:
1841 
1842 		break;
1843 	case DDI_RESUME:
1844 		hubd_cpr_resume(dip);
1845 
1846 		return (DDI_SUCCESS);
1847 	default:
1848 		return (DDI_FAILURE);
1849 	}
1850 
1851 	/*
1852 	 * Allocate softc information.
1853 	 */
1854 	if (usba_is_root_hub(dip)) {
1855 		/* soft state has already been allocated */
1856 		hubd = hubd_get_soft_state(dip);
1857 		minor = HUBD_IS_ROOT_HUB;
1858 
1859 		/* generate readable labels for different root hubs */
1860 		root_hub_drvname = ddi_driver_name(dip);
1861 		if (strcmp(root_hub_drvname, "xhci") == 0) {
1862 			log_name = "xusb";
1863 		} else if (strcmp(root_hub_drvname, "ehci") == 0) {
1864 			log_name = "eusb";
1865 		} else if (strcmp(root_hub_drvname, "uhci") == 0) {
1866 			log_name = "uusb";
1867 		} else {
1868 			/* std. for ohci */
1869 			log_name = "usb";
1870 		}
1871 	} else {
1872 		rval = ddi_soft_state_zalloc(hubd_statep, instance);
1873 		minor = 0;
1874 
1875 		if (rval != DDI_SUCCESS) {
1876 			USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle,
1877 			    "cannot allocate soft state (%d)", instance);
1878 			goto fail;
1879 		}
1880 
1881 		hubd = hubd_get_soft_state(dip);
1882 		if (hubd == NULL) {
1883 			goto fail;
1884 		}
1885 	}
1886 
1887 	hubd->h_log_handle = usb_alloc_log_hdl(dip, log_name, &hubd_errlevel,
1888 	    &hubd_errmask, &hubd_instance_debug, 0);
1889 
1890 	hubd->h_usba_device	= child_ud = usba_get_usba_device(dip);
1891 	hubd->h_dip		= dip;
1892 	hubd->h_instance	= instance;
1893 
1894 	mutex_enter(&child_ud->usb_mutex);
1895 	child_port_status = child_ud->usb_port_status;
1896 	usb_dev_descr = child_ud->usb_dev_descr;
1897 	parent_port_status = (child_ud->usb_hs_hub_usba_dev) ?
1898 	    child_ud->usb_hs_hub_usba_dev->usb_port_status : 0;
1899 	mutex_exit(&child_ud->usb_mutex);
1900 
1901 	if ((child_port_status == USBA_FULL_SPEED_DEV) &&
1902 	    (parent_port_status >= USBA_HIGH_SPEED_DEV) &&
1903 	    (usb_dev_descr->bcdUSB == 0x100)) {
1904 		USB_DPRINTF_L0(DPRINT_MASK_ATTA, hubd->h_log_handle,
1905 		    "Use of a USB1.0 hub behind a higher speed port may "
1906 		    "cause unexpected failures");
1907 	}
1908 
1909 	hubd->h_pipe_policy.pp_max_async_reqs = 1;
1910 
1911 	/* register with USBA as client driver */
1912 	if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
1913 		USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
1914 		    "client attach failed");
1915 
1916 		goto fail;
1917 	}
1918 
1919 	if (usb_get_dev_data(dip, &hubd->h_dev_data,
1920 	    USB_PARSE_LVL_IF, 0) != USB_SUCCESS) {
1921 		USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
1922 		    "cannot get dev_data");
1923 
1924 		goto fail;
1925 	}
1926 
1927 	if ((ep_data = usb_lookup_ep_data(dip, hubd->h_dev_data,
1928 	    hubd->h_dev_data->dev_curr_if, 0, 0,
1929 	    (uint_t)USB_EP_ATTR_INTR, (uint_t)USB_EP_DIR_IN)) == NULL) {
1930 		USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
1931 		    "no interrupt IN endpoint found");
1932 
1933 		goto fail;
1934 	}
1935 
1936 	if (usb_ep_xdescr_fill(USB_EP_XDESCR_CURRENT_VERSION, dip, ep_data,
1937 	    &hubd->h_ep1_xdescr) != USB_SUCCESS) {
1938 		goto fail;
1939 	}
1940 
1941 	hubd->h_default_pipe = hubd->h_dev_data->dev_default_ph;
1942 
1943 	mutex_init(HUBD_MUTEX(hubd), NULL, MUTEX_DRIVER,
1944 	    hubd->h_dev_data->dev_iblock_cookie);
1945 	cv_init(&hubd->h_cv_reset_port, NULL, CV_DRIVER, NULL);
1946 	cv_init(&hubd->h_cv_hotplug_dev, NULL, CV_DRIVER, NULL);
1947 
1948 	hubd->h_init_state |= HUBD_LOCKS_DONE;
1949 
1950 	usb_free_descr_tree(dip, hubd->h_dev_data);
1951 
1952 	/*
1953 	 * register this hub instance with usba
1954 	 */
1955 	rval = usba_hubdi_register(dip, 0);
1956 	if (rval != USB_SUCCESS) {
1957 		USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
1958 		    "usba_hubdi_register failed");
1959 		goto fail;
1960 	}
1961 
1962 	mutex_enter(HUBD_MUTEX(hubd));
1963 	hubd->h_init_state |= HUBD_HUBDI_REGISTERED;
1964 	hubd->h_dev_state = USB_DEV_ONLINE;
1965 	mutex_exit(HUBD_MUTEX(hubd));
1966 
1967 	/* now create components to power manage this device */
1968 	hubd_create_pm_components(dip, hubd);
1969 
1970 	/*
1971 	 * Event handling: definition and registration
1972 	 *
1973 	 * first the  definition:
1974 	 * get event handle
1975 	 */
1976 	(void) ndi_event_alloc_hdl(dip, 0, &hubd->h_ndi_event_hdl, NDI_SLEEP);
1977 
1978 	/* bind event set to the handle */
1979 	if (ndi_event_bind_set(hubd->h_ndi_event_hdl, &hubd_ndi_events,
1980 	    NDI_SLEEP)) {
1981 		USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle,
1982 		    "binding event set failed");
1983 
1984 		goto fail;
1985 	}
1986 
1987 	/* event registration */
1988 	if (hubd_register_events(hubd) != USB_SUCCESS) {
1989 		USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
1990 		    "hubd_register_events failed");
1991 
1992 		goto fail;
1993 	}
1994 
1995 	mutex_enter(HUBD_MUTEX(hubd));
1996 	hubd->h_init_state |= HUBD_EVENTS_REGISTERED;
1997 
1998 	if (hubd_get_hub_descriptor(hubd) != USB_SUCCESS) {
1999 		mutex_exit(HUBD_MUTEX(hubd));
2000 
2001 		goto fail;
2002 	}
2003 
2004 	/*
2005 	 * Now that we have our descriptors, we need to give the host controller
2006 	 * a chance to properly configure the device if needed (this is required
2007 	 * for xHCI).
2008 	 *
2009 	 * Note, if anyone ever adds support for using the Multi TT mode for USB
2010 	 * 2 High speed Hubs, the xhci driver will need to be updated and that
2011 	 * will need to be done before this is called.
2012 	 */
2013 	if (hubd->h_usba_device->usb_hcdi_ops->usba_hcdi_hub_update != NULL &&
2014 	    !usba_is_root_hub(dip)) {
2015 		int ret;
2016 		uint8_t chars;
2017 		usba_device_t *ud = hubd->h_usba_device;
2018 
2019 		chars = (hubd->h_hub_chars & HUB_CHARS_TT_THINK_TIME) >>
2020 		    HUB_CHARS_TT_SHIFT;
2021 		ret = ud->usb_hcdi_ops->usba_hcdi_hub_update(ud,
2022 		    hubd->h_nports, chars);
2023 		if (ret != USB_SUCCESS) {
2024 			mutex_exit(HUBD_MUTEX(hubd));
2025 			goto fail;
2026 		}
2027 	}
2028 
2029 	if (hubd_set_hub_depth(hubd) != USB_SUCCESS) {
2030 
2031 		goto fail;
2032 	}
2033 
2034 	if (ddi_prop_exists(DDI_DEV_T_ANY, dip,
2035 	    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
2036 	    "hub-ignore-power-budget") == 1) {
2037 		hubd->h_ignore_pwr_budget = B_TRUE;
2038 	} else {
2039 		hubd->h_ignore_pwr_budget = B_FALSE;
2040 
2041 		/* initialize hub power budget variables */
2042 		if (hubd_init_power_budget(hubd) != USB_SUCCESS) {
2043 			USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2044 			    "hubd_init_power_budget failed");
2045 			mutex_exit(HUBD_MUTEX(hubd));
2046 
2047 			goto fail;
2048 		}
2049 	}
2050 
2051 	/* initialize and create children */
2052 	if (hubd_check_ports(hubd) != USB_SUCCESS) {
2053 		USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2054 		    "hubd_check_ports failed");
2055 		mutex_exit(HUBD_MUTEX(hubd));
2056 
2057 		goto fail;
2058 	}
2059 
2060 	/*
2061 	 * create cfgadm nodes
2062 	 */
2063 	hubd->h_ancestry_str = (char *)kmem_zalloc(HUBD_APID_NAMELEN, KM_SLEEP);
2064 	hubd_get_ancestry_str(hubd);
2065 
2066 	USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
2067 	    "#ports=0x%x", hubd->h_nports);
2068 
2069 	for (i = 1; i <= hubd->h_nports; i++) {
2070 		char ap_name[HUBD_APID_NAMELEN];
2071 
2072 		(void) snprintf(ap_name, HUBD_APID_NAMELEN, "%s%d",
2073 		    hubd->h_ancestry_str, i);
2074 		USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
2075 		    "ap_name=%s", ap_name);
2076 
2077 		if (ddi_create_minor_node(dip, ap_name, S_IFCHR, instance,
2078 		    DDI_NT_USB_ATTACHMENT_POINT, 0) != DDI_SUCCESS) {
2079 			USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2080 			    "cannot create attachment point node (%d)",
2081 			    instance);
2082 			mutex_exit(HUBD_MUTEX(hubd));
2083 
2084 			goto fail;
2085 		}
2086 	}
2087 
2088 	ports_count = hubd->h_nports;
2089 	mutex_exit(HUBD_MUTEX(hubd));
2090 
2091 	/* create minor nodes */
2092 	if (ddi_create_minor_node(dip, "hubd", S_IFCHR,
2093 	    instance | minor, DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
2094 
2095 		USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2096 		    "cannot create devctl minor node (%d)", instance);
2097 
2098 		goto fail;
2099 	}
2100 
2101 	mutex_enter(HUBD_MUTEX(hubd));
2102 	hubd->h_init_state |= HUBD_MINOR_NODE_CREATED;
2103 	mutex_exit(HUBD_MUTEX(hubd));
2104 
2105 	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
2106 	    "usb-port-count", ports_count) != DDI_PROP_SUCCESS) {
2107 		USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2108 		    "usb-port-count update failed");
2109 	}
2110 
2111 	/*
2112 	 * host controller driver has already reported this dev
2113 	 * if we are the root hub
2114 	 */
2115 	if (!usba_is_root_hub(dip)) {
2116 		ddi_report_dev(dip);
2117 	}
2118 
2119 	/* enable deathrow thread */
2120 	hubd->h_cleanup_enabled = B_TRUE;
2121 	mutex_enter(HUBD_MUTEX(hubd));
2122 	hubd_pm_idle_component(hubd, dip, 0);
2123 	mutex_exit(HUBD_MUTEX(hubd));
2124 
2125 	return (DDI_SUCCESS);
2126 
2127 fail:
2128 	{
2129 		char *pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
2130 
2131 		USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle,
2132 		    "cannot attach %s", ddi_pathname(dip, pathname));
2133 
2134 		kmem_free(pathname, MAXPATHLEN);
2135 	}
2136 
2137 	if (hubd != NULL) {
2138 		mutex_enter(HUBD_MUTEX(hubd));
2139 		hubd_pm_idle_component(hubd, dip, 0);
2140 		mutex_exit(HUBD_MUTEX(hubd));
2141 
2142 		rval = hubd_cleanup(dip, hubd);
2143 		if (rval != USB_SUCCESS) {
2144 			USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle,
2145 			    "failure to complete cleanup after attach failure");
2146 		}
2147 	}
2148 
2149 	return (DDI_FAILURE);
2150 }
2151 
2152 
2153 int
usba_hubdi_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)2154 usba_hubdi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2155 {
2156 	hubd_t	*hubd = hubd_get_soft_state(dip);
2157 	int	rval;
2158 
2159 	USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
2160 	    "hubd_detach: cmd=0x%x", cmd);
2161 
2162 	switch (cmd) {
2163 	case DDI_DETACH:
2164 		rval = hubd_cleanup(dip, hubd);
2165 
2166 		return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
2167 	case DDI_SUSPEND:
2168 		rval = hubd_cpr_suspend(hubd);
2169 
2170 		return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
2171 	default:
2172 		return (DDI_FAILURE);
2173 	}
2174 }
2175 
2176 
2177 /*
2178  * hubd_setdevaddr
2179  *	set the device addrs on this port
2180  */
2181 static int
hubd_setdevaddr(hubd_t * hubd,usb_port_t port)2182 hubd_setdevaddr(hubd_t *hubd, usb_port_t port)
2183 {
2184 	int		rval = USB_FAILURE;
2185 	usb_cr_t	completion_reason;
2186 	usb_cb_flags_t	cb_flags;
2187 	usb_pipe_handle_t ph;
2188 	dev_info_t	*child_dip = NULL;
2189 	uchar_t		address = 0;
2190 	usba_device_t	*usba_device;
2191 	int		retry = 0;
2192 	long		time_delay;
2193 
2194 	USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
2195 	    "hubd_setdevaddr: port=%d", port);
2196 
2197 	ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
2198 
2199 	child_dip = hubd->h_children_dips[port];
2200 	address = hubd->h_usba_devices[port]->usb_addr;
2201 	usba_device = hubd->h_usba_devices[port];
2202 
2203 	/* close the default pipe with addr x */
2204 	mutex_exit(HUBD_MUTEX(hubd));
2205 	ph = usba_get_dflt_pipe_handle(child_dip);
2206 	usb_pipe_close(child_dip, ph,
2207 	    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL);
2208 	mutex_enter(HUBD_MUTEX(hubd));
2209 
2210 	/*
2211 	 * If the host controller is in charge of addressing, have it do that
2212 	 * now and skip everything else.
2213 	 */
2214 	if (usba_device->usb_hcdi_ops->usba_hcdi_device_address != NULL) {
2215 		mutex_exit(HUBD_MUTEX(hubd));
2216 		rval = usba_device->usb_hcdi_ops->usba_hcdi_device_address(
2217 		    usba_device);
2218 		mutex_enter(HUBD_MUTEX(hubd));
2219 
2220 		usba_clear_data_toggle(usba_device);
2221 		return (rval);
2222 	}
2223 
2224 	/*
2225 	 * As this device has been reset, temporarily
2226 	 * assign the default address
2227 	 */
2228 	mutex_enter(&usba_device->usb_mutex);
2229 	address = usba_device->usb_addr;
2230 	usba_device->usb_addr = USBA_DEFAULT_ADDR;
2231 	mutex_exit(&usba_device->usb_mutex);
2232 
2233 	mutex_exit(HUBD_MUTEX(hubd));
2234 
2235 	time_delay = drv_usectohz(hubd_device_delay / 20);
2236 	for (retry = 0; retry < hubd_retry_enumerate; retry++) {
2237 
2238 		/* open child's default pipe with USBA_DEFAULT_ADDR */
2239 		if ((rval = usb_pipe_open(child_dip, NULL, NULL,
2240 		    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph)) !=
2241 		    USB_SUCCESS) {
2242 			USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2243 			    "hubd_setdevaddr: Unable to open default pipe");
2244 
2245 			break;
2246 		}
2247 
2248 		/* Set the address of the device */
2249 		if ((rval = usb_pipe_sync_ctrl_xfer(child_dip, ph,
2250 		    USB_DEV_REQ_HOST_TO_DEV,
2251 		    USB_REQ_SET_ADDRESS,	/* bRequest */
2252 		    address,			/* wValue */
2253 		    0,				/* wIndex */
2254 		    0,				/* wLength */
2255 		    NULL, 0,
2256 		    &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
2257 			USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2258 			    "hubd_setdevaddr(%d): rval=%d cr=%d cb_fl=0x%x",
2259 			    retry, rval, completion_reason, cb_flags);
2260 		}
2261 
2262 		usb_pipe_close(child_dip, ph,
2263 		    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL);
2264 
2265 		if (rval == USB_SUCCESS) {
2266 
2267 			break;
2268 		}
2269 
2270 		delay(time_delay);
2271 	}
2272 
2273 	/* Reset to the old address */
2274 	mutex_enter(&usba_device->usb_mutex);
2275 	usba_device->usb_addr = address;
2276 	mutex_exit(&usba_device->usb_mutex);
2277 	mutex_enter(HUBD_MUTEX(hubd));
2278 
2279 	usba_clear_data_toggle(usba_device);
2280 
2281 	return (rval);
2282 }
2283 
2284 
2285 /*
2286  * hubd_setdevconfig
2287  *	set the device addrs on this port
2288  */
2289 static void
hubd_setdevconfig(hubd_t * hubd,usb_port_t port)2290 hubd_setdevconfig(hubd_t *hubd, usb_port_t port)
2291 {
2292 	int			rval;
2293 	usb_cr_t		completion_reason;
2294 	usb_cb_flags_t		cb_flags;
2295 	usb_pipe_handle_t	ph;
2296 	dev_info_t		*child_dip = NULL;
2297 	usba_device_t		*usba_device = NULL;
2298 	uint16_t		config_value;
2299 
2300 	USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
2301 	    "hubd_setdevconfig: port=%d", port);
2302 
2303 	ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
2304 
2305 	child_dip = hubd->h_children_dips[port];
2306 	usba_device = hubd->h_usba_devices[port];
2307 	config_value = hubd->h_usba_devices[port]->usb_cfg_value;
2308 	mutex_exit(HUBD_MUTEX(hubd));
2309 
2310 	/* open the default control pipe */
2311 	if ((rval = usb_pipe_open(child_dip, NULL, NULL,
2312 	    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph)) ==
2313 	    USB_SUCCESS) {
2314 
2315 		/* Set the default configuration of the device */
2316 		if ((rval = usb_pipe_sync_ctrl_xfer(child_dip, ph,
2317 		    USB_DEV_REQ_HOST_TO_DEV,
2318 		    USB_REQ_SET_CFG,		/* bRequest */
2319 		    config_value,		/* wValue */
2320 		    0,				/* wIndex */
2321 		    0,				/* wLength */
2322 		    NULL, 0,
2323 		    &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
2324 			USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2325 			    "hubd_setdevconfig: set device config failed: "
2326 			    "cr=%d cb_fl=0x%x rval=%d",
2327 			    completion_reason, cb_flags, rval);
2328 		}
2329 		/*
2330 		 * After setting the configuration, we make this default
2331 		 * control pipe persistent, so that it gets re-opened
2332 		 * on posting a connect event
2333 		 */
2334 		usba_persistent_pipe_close(usba_device);
2335 	} else {
2336 		USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2337 		    "pipe open fails: rval=%d", rval);
2338 	}
2339 	mutex_enter(HUBD_MUTEX(hubd));
2340 }
2341 
2342 
2343 /*ARGSUSED*/
2344 static int
hubd_check_disconnected_ports(dev_info_t * dip,void * arg)2345 hubd_check_disconnected_ports(dev_info_t *dip, void *arg)
2346 {
2347 	int circ;
2348 	usb_port_t port;
2349 	hubd_t *hubd;
2350 	major_t hub_major = ddi_name_to_major("hubd");
2351 	major_t hwahc_major = ddi_name_to_major("hwahc");
2352 	major_t usbmid_major = ddi_name_to_major("usb_mid");
2353 
2354 	/*
2355 	 * make sure dip is a usb hub, major of root hub is HCD
2356 	 * major
2357 	 */
2358 	if (!usba_is_root_hub(dip)) {
2359 		if (ddi_driver_major(dip) == usbmid_major) {
2360 			/*
2361 			 * need to walk the children since it might be a
2362 			 * HWA device
2363 			 */
2364 
2365 			return (DDI_WALK_CONTINUE);
2366 		}
2367 
2368 		/* TODO: DWA device may also need special handling */
2369 
2370 		if (((ddi_driver_major(dip) != hub_major) &&
2371 		    (ddi_driver_major(dip) != hwahc_major)) ||
2372 		    !i_ddi_devi_attached(dip)) {
2373 
2374 			return (DDI_WALK_PRUNECHILD);
2375 		}
2376 	}
2377 
2378 	hubd = hubd_get_soft_state(dip);
2379 	if (hubd == NULL) {
2380 
2381 		return (DDI_WALK_PRUNECHILD);
2382 	}
2383 
2384 	/* walk child list and remove nodes with flag DEVI_DEVICE_REMOVED */
2385 	ndi_devi_enter(dip, &circ);
2386 
2387 	if (ddi_driver_major(dip) != hwahc_major) {
2388 		/* for normal usb hub or root hub */
2389 		mutex_enter(HUBD_MUTEX(hubd));
2390 		for (port = 1; port <= hubd->h_nports; port++) {
2391 			dev_info_t *cdip = hubd->h_children_dips[port];
2392 
2393 			if (cdip == NULL || DEVI_IS_DEVICE_REMOVED(cdip) == 0) {
2394 
2395 				continue;
2396 			}
2397 
2398 			(void) hubd_delete_child(hubd, port, NDI_DEVI_REMOVE,
2399 			    B_TRUE);
2400 		}
2401 		mutex_exit(HUBD_MUTEX(hubd));
2402 	} else {
2403 		/* for HWA */
2404 		if (hubd->h_cleanup_child != NULL) {
2405 			if (hubd->h_cleanup_child(dip) != USB_SUCCESS) {
2406 				ndi_devi_exit(dip, circ);
2407 
2408 				return (DDI_WALK_PRUNECHILD);
2409 			}
2410 		} else {
2411 			ndi_devi_exit(dip, circ);
2412 
2413 			return (DDI_WALK_PRUNECHILD);
2414 		}
2415 	}
2416 
2417 	ndi_devi_exit(dip, circ);
2418 
2419 	/* skip siblings of root hub */
2420 	if (usba_is_root_hub(dip)) {
2421 
2422 		return (DDI_WALK_PRUNESIB);
2423 	}
2424 
2425 	return (DDI_WALK_CONTINUE);
2426 }
2427 
2428 
2429 /*
2430  * this thread will walk all children under the root hub for this
2431  * USB bus instance and attempt to remove them
2432  */
2433 static void
hubd_root_hub_cleanup_thread(void * arg)2434 hubd_root_hub_cleanup_thread(void *arg)
2435 {
2436 	int circ;
2437 	hubd_t *root_hubd = (hubd_t *)arg;
2438 	dev_info_t *rh_dip = root_hubd->h_dip;
2439 #ifndef __lock_lint
2440 	callb_cpr_t cprinfo;
2441 
2442 	CALLB_CPR_INIT(&cprinfo, HUBD_MUTEX(root_hubd), callb_generic_cpr,
2443 	    "USB root hub");
2444 #endif
2445 
2446 	for (;;) {
2447 		/* don't race with detach */
2448 		ndi_hold_devi(rh_dip);
2449 
2450 		mutex_enter(HUBD_MUTEX(root_hubd));
2451 		root_hubd->h_cleanup_needed = 0;
2452 		mutex_exit(HUBD_MUTEX(root_hubd));
2453 
2454 		(void) devfs_clean(rh_dip, NULL, 0);
2455 
2456 		ndi_devi_enter(ddi_get_parent(rh_dip), &circ);
2457 		ddi_walk_devs(rh_dip, hubd_check_disconnected_ports,
2458 		    NULL);
2459 #ifdef __lock_lint
2460 		(void) hubd_check_disconnected_ports(rh_dip, NULL);
2461 #endif
2462 		ndi_devi_exit(ddi_get_parent(rh_dip), circ);
2463 
2464 		/* quit if we are not enabled anymore */
2465 		mutex_enter(HUBD_MUTEX(root_hubd));
2466 		if ((root_hubd->h_cleanup_enabled == B_FALSE) ||
2467 		    (root_hubd->h_cleanup_needed == B_FALSE)) {
2468 			root_hubd->h_cleanup_active = B_FALSE;
2469 			mutex_exit(HUBD_MUTEX(root_hubd));
2470 			ndi_rele_devi(rh_dip);
2471 
2472 			break;
2473 		}
2474 		mutex_exit(HUBD_MUTEX(root_hubd));
2475 		ndi_rele_devi(rh_dip);
2476 
2477 #ifndef __lock_lint
2478 		mutex_enter(HUBD_MUTEX(root_hubd));
2479 		CALLB_CPR_SAFE_BEGIN(&cprinfo);
2480 		mutex_exit(HUBD_MUTEX(root_hubd));
2481 
2482 		delay(drv_usectohz(hubd_dip_cleanup_delay));
2483 
2484 		mutex_enter(HUBD_MUTEX(root_hubd));
2485 		CALLB_CPR_SAFE_END(&cprinfo, HUBD_MUTEX(root_hubd));
2486 		mutex_exit(HUBD_MUTEX(root_hubd));
2487 #endif
2488 	}
2489 
2490 #ifndef __lock_lint
2491 	mutex_enter(HUBD_MUTEX(root_hubd));
2492 	CALLB_CPR_EXIT(&cprinfo);
2493 #endif
2494 }
2495 
2496 
2497 void
hubd_schedule_cleanup(dev_info_t * rh_dip)2498 hubd_schedule_cleanup(dev_info_t *rh_dip)
2499 {
2500 	hubd_t	*root_hubd;
2501 
2502 	/*
2503 	 * The usb_root_hub_dip pointer for the child hub of the WUSB
2504 	 * wire adapter class device points to the wire adapter, not
2505 	 * the root hub. Need to find the real root hub dip so that
2506 	 * the cleanup thread only starts from the root hub.
2507 	 */
2508 	while (!usba_is_root_hub(rh_dip)) {
2509 		root_hubd = hubd_get_soft_state(rh_dip);
2510 		if (root_hubd != NULL) {
2511 			rh_dip = root_hubd->h_usba_device->usb_root_hub_dip;
2512 			if (rh_dip == NULL) {
2513 				USB_DPRINTF_L2(DPRINT_MASK_ATTA,
2514 				    root_hubd->h_log_handle,
2515 				    "hubd_schedule_cleanup: null rh dip");
2516 
2517 				return;
2518 			}
2519 		} else {
2520 			USB_DPRINTF_L2(DPRINT_MASK_ATTA,
2521 			    root_hubd->h_log_handle,
2522 			    "hubd_schedule_cleanup: cannot find root hub");
2523 
2524 			return;
2525 		}
2526 	}
2527 	root_hubd = hubd_get_soft_state(rh_dip);
2528 
2529 	mutex_enter(HUBD_MUTEX(root_hubd));
2530 	root_hubd->h_cleanup_needed = B_TRUE;
2531 	if (root_hubd->h_cleanup_enabled && !(root_hubd->h_cleanup_active)) {
2532 		root_hubd->h_cleanup_active = B_TRUE;
2533 		mutex_exit(HUBD_MUTEX(root_hubd));
2534 		(void) thread_create(NULL, 0,
2535 		    hubd_root_hub_cleanup_thread,
2536 		    (void *)root_hubd, 0, &p0, TS_RUN,
2537 		    minclsyspri);
2538 	} else {
2539 		mutex_exit(HUBD_MUTEX(root_hubd));
2540 	}
2541 }
2542 
2543 
2544 /*
2545  * hubd_restore_device_state:
2546  *	- set config for the hub
2547  *	- power cycle all the ports
2548  *	- for each port that was connected
2549  *		- reset port
2550  *		- assign addrs to the device on this port
2551  *	- restart polling
2552  *	- reset suspend flag
2553  */
2554 static void
hubd_restore_device_state(dev_info_t * dip,hubd_t * hubd)2555 hubd_restore_device_state(dev_info_t *dip, hubd_t *hubd)
2556 {
2557 	int		rval;
2558 	int		retry;
2559 	uint_t		hub_prev_state;
2560 	usb_port_t	port;
2561 	uint16_t	status;
2562 	uint16_t	change;
2563 	dev_info_t	*ch_dip;
2564 	boolean_t	ehci_root_hub;
2565 
2566 	USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
2567 	    "hubd_restore_device_state:");
2568 
2569 	mutex_enter(HUBD_MUTEX(hubd));
2570 	hub_prev_state = hubd->h_dev_state;
2571 	ASSERT(hub_prev_state != USB_DEV_PWRED_DOWN);
2572 
2573 	/* First bring the device to full power */
2574 	(void) hubd_pm_busy_component(hubd, dip, 0);
2575 	mutex_exit(HUBD_MUTEX(hubd));
2576 
2577 	(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
2578 
2579 	if (!usba_is_root_hub(dip) &&
2580 	    (usb_check_same_device(dip, hubd->h_log_handle, USB_LOG_L0,
2581 	    DPRINT_MASK_HOTPLUG,
2582 	    USB_CHK_BASIC|USB_CHK_CFG, NULL) != USB_SUCCESS)) {
2583 
2584 		/* change the device state to disconnected */
2585 		mutex_enter(HUBD_MUTEX(hubd));
2586 		hubd->h_dev_state = USB_DEV_DISCONNECTED;
2587 		(void) hubd_pm_idle_component(hubd, dip, 0);
2588 		mutex_exit(HUBD_MUTEX(hubd));
2589 
2590 		return;
2591 	}
2592 
2593 	ehci_root_hub = (strcmp(ddi_driver_name(dip), "ehci") == 0);
2594 
2595 	mutex_enter(HUBD_MUTEX(hubd));
2596 	/* First turn off all port power */
2597 	rval = hubd_disable_all_port_power(hubd);
2598 	if (rval != USB_SUCCESS) {
2599 		USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle,
2600 		    "hubd_restore_device_state:"
2601 		    "turning off port power failed");
2602 	}
2603 
2604 	/* Settling time before turning on again */
2605 	mutex_exit(HUBD_MUTEX(hubd));
2606 	delay(drv_usectohz(hubd_device_delay / 100));
2607 	mutex_enter(HUBD_MUTEX(hubd));
2608 
2609 	/* enable power on all ports so we can see connects */
2610 	if (hubd_enable_all_port_power(hubd) != USB_SUCCESS) {
2611 		USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2612 		    "hubd_restore_device_state: turn on port power failed");
2613 
2614 		/* disable whatever was enabled */
2615 		(void) hubd_disable_all_port_power(hubd);
2616 
2617 		(void) hubd_pm_idle_component(hubd, dip, 0);
2618 		mutex_exit(HUBD_MUTEX(hubd));
2619 
2620 		return;
2621 	}
2622 
2623 	/*
2624 	 * wait at least 3 frames before accessing devices
2625 	 * (note that delay's minimal time is one clock tick).
2626 	 */
2627 	mutex_exit(HUBD_MUTEX(hubd));
2628 	delay(drv_usectohz(10000));
2629 	mutex_enter(HUBD_MUTEX(hubd));
2630 
2631 	hubd->h_dev_state = USB_DEV_HUB_STATE_RECOVER;
2632 
2633 	for (port = 1; port <= hubd->h_nports; port++) {
2634 		USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle,
2635 		    "hubd_restore_device_state: port=%d", port);
2636 
2637 		/*
2638 		 * the childen_dips list may have dips that have been
2639 		 * already deallocated. we only get a post_detach notification
2640 		 * but not a destroy notification
2641 		 */
2642 		ch_dip = hubd->h_children_dips[port];
2643 		if (ch_dip) {
2644 			/* get port status */
2645 			(void) hubd_determine_port_status(hubd, port,
2646 			    &status, &change, NULL, PORT_CHANGE_CSC);
2647 
2648 			/* check if it is truly connected */
2649 			if (status & PORT_STATUS_CCS) {
2650 				/*
2651 				 * Now reset port and assign the device
2652 				 * its original address
2653 				 */
2654 				retry = 0;
2655 				do {
2656 					(void) hubd_reset_port(hubd, port);
2657 
2658 					/* required for ppx */
2659 					(void) hubd_enable_port(hubd, port);
2660 
2661 					if (retry) {
2662 						mutex_exit(HUBD_MUTEX(hubd));
2663 						delay(drv_usectohz(
2664 						    hubd_device_delay/2));
2665 						mutex_enter(HUBD_MUTEX(hubd));
2666 					}
2667 
2668 					rval = hubd_setdevaddr(hubd, port);
2669 					retry++;
2670 				} while ((rval != USB_SUCCESS) &&
2671 				    (retry < hubd_retry_enumerate));
2672 
2673 				hubd_setdevconfig(hubd, port);
2674 
2675 				if (hub_prev_state == USB_DEV_DISCONNECTED) {
2676 					/* post a connect event */
2677 					mutex_exit(HUBD_MUTEX(hubd));
2678 					hubd_post_event(hubd, port,
2679 					    USBA_EVENT_TAG_HOT_INSERTION);
2680 					mutex_enter(HUBD_MUTEX(hubd));
2681 				} else {
2682 					/*
2683 					 * Since we have this device connected
2684 					 * mark it reinserted to prevent
2685 					 * cleanup thread from stepping in.
2686 					 */
2687 					mutex_exit(HUBD_MUTEX(hubd));
2688 					mutex_enter(&(DEVI(ch_dip)->devi_lock));
2689 					DEVI_SET_DEVICE_REINSERTED(ch_dip);
2690 					mutex_exit(&(DEVI(ch_dip)->devi_lock));
2691 
2692 					/*
2693 					 * reopen pipes for children for
2694 					 * their DDI_RESUME
2695 					 */
2696 					rval = usba_persistent_pipe_open(
2697 					    usba_get_usba_device(ch_dip));
2698 					mutex_enter(HUBD_MUTEX(hubd));
2699 					ASSERT(rval == USB_SUCCESS);
2700 				}
2701 			} else {
2702 				/*
2703 				 * Mark this dip for deletion as the device
2704 				 * is not physically present, and schedule
2705 				 * cleanup thread upon post resume
2706 				 */
2707 				mutex_exit(HUBD_MUTEX(hubd));
2708 
2709 				USB_DPRINTF_L2(DPRINT_MASK_ATTA,
2710 				    hubd->h_log_handle,
2711 				    "hubd_restore_device_state: "
2712 				    "dip=%p on port=%d marked for cleanup",
2713 				    (void *)ch_dip, port);
2714 				mutex_enter(&(DEVI(ch_dip)->devi_lock));
2715 				DEVI_SET_DEVICE_REMOVED(ch_dip);
2716 				mutex_exit(&(DEVI(ch_dip)->devi_lock));
2717 
2718 				mutex_enter(HUBD_MUTEX(hubd));
2719 			}
2720 		} else if (ehci_root_hub) {
2721 			/* get port status */
2722 			(void) hubd_determine_port_status(hubd, port,
2723 			    &status, &change, NULL, PORT_CHANGE_CSC);
2724 
2725 			/* check if it is truly connected */
2726 			if (status & PORT_STATUS_CCS) {
2727 				/*
2728 				 * reset the port to find out if we have
2729 				 * 2.0 device connected or 1.X. A 2.0
2730 				 * device will still be seen as connected,
2731 				 * while a 1.X device will switch over to
2732 				 * the companion controller.
2733 				 */
2734 				(void) hubd_reset_port(hubd, port);
2735 
2736 				(void) hubd_determine_port_status(hubd, port,
2737 				    &status, &change, NULL, PORT_CHANGE_CSC);
2738 
2739 				if (status &
2740 				    (PORT_STATUS_CCS | PORT_STATUS_HSDA)) {
2741 					/*
2742 					 * We have a USB 2.0 device
2743 					 * connected. Power cycle this port
2744 					 * so that hotplug thread can
2745 					 * enumerate this device.
2746 					 */
2747 					(void) hubd_toggle_port(hubd, port);
2748 				} else {
2749 					USB_DPRINTF_L2(DPRINT_MASK_ATTA,
2750 					    hubd->h_log_handle,
2751 					    "hubd_restore_device_state: "
2752 					    "device on port %d switched over",
2753 					    port);
2754 				}
2755 			}
2756 
2757 		}
2758 	}
2759 
2760 
2761 	/* if the device had remote wakeup earlier, enable it again */
2762 	if (hubd->h_hubpm->hubp_wakeup_enabled) {
2763 		mutex_exit(HUBD_MUTEX(hubd));
2764 		(void) usb_handle_remote_wakeup(hubd->h_dip,
2765 		    USB_REMOTE_WAKEUP_ENABLE);
2766 		mutex_enter(HUBD_MUTEX(hubd));
2767 	}
2768 
2769 	hubd->h_dev_state = USB_DEV_ONLINE;
2770 	hubd_start_polling(hubd, 0);
2771 	(void) hubd_pm_idle_component(hubd, dip, 0);
2772 	mutex_exit(HUBD_MUTEX(hubd));
2773 }
2774 
2775 
2776 /*
2777  * hubd_cleanup:
2778  *	cleanup hubd and deallocate. this function is called for
2779  *	handling attach failures and detaching including dynamic
2780  *	reconfiguration. If called from attaching, it must clean
2781  *	up the whole thing and return success.
2782  */
2783 /*ARGSUSED*/
2784 static int
hubd_cleanup(dev_info_t * dip,hubd_t * hubd)2785 hubd_cleanup(dev_info_t *dip, hubd_t *hubd)
2786 {
2787 	int		circ, rval, old_dev_state;
2788 	hub_power_t	*hubpm;
2789 #ifdef DEBUG
2790 	usb_port_t	port;
2791 #endif
2792 
2793 	USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
2794 	    "hubd_cleanup:");
2795 
2796 	if ((hubd->h_init_state & HUBD_LOCKS_DONE) == 0) {
2797 		goto done;
2798 	}
2799 
2800 	/* ensure we are the only one active */
2801 	ndi_devi_enter(dip, &circ);
2802 
2803 	mutex_enter(HUBD_MUTEX(hubd));
2804 
2805 	/* Cleanup failure is only allowed if called from detach */
2806 	if (DEVI_IS_DETACHING(dip)) {
2807 		dev_info_t *rh_dip = hubd->h_usba_device->usb_root_hub_dip;
2808 
2809 		/*
2810 		 * We are being called from detach.
2811 		 * Fail immediately if the hotplug thread is running
2812 		 * else set the dev_state to disconnected so that
2813 		 * hotplug thread just exits without doing anything.
2814 		 */
2815 		if (hubd->h_bus_ctls || hubd->h_bus_pwr ||
2816 		    hubd->h_hotplug_thread) {
2817 			mutex_exit(HUBD_MUTEX(hubd));
2818 			ndi_devi_exit(dip, circ);
2819 
2820 			USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2821 			    "hubd_cleanup: hotplug thread/bus ctl active "
2822 			    "- failing detach");
2823 
2824 			return (USB_FAILURE);
2825 		}
2826 
2827 		/*
2828 		 * if the deathrow thread is still active or about
2829 		 * to become active, fail detach
2830 		 * the roothup can only be detached if nexus drivers
2831 		 * are unloaded or explicitly offlined
2832 		 */
2833 		if (rh_dip == dip) {
2834 			if (hubd->h_cleanup_needed ||
2835 			    hubd->h_cleanup_active) {
2836 				mutex_exit(HUBD_MUTEX(hubd));
2837 				ndi_devi_exit(dip, circ);
2838 
2839 				USB_DPRINTF_L2(DPRINT_MASK_ATTA,
2840 				    hubd->h_log_handle,
2841 				    "hubd_cleanup: deathrow still active?"
2842 				    "- failing detach");
2843 
2844 				return (USB_FAILURE);
2845 			}
2846 		}
2847 	}
2848 
2849 	old_dev_state = hubd->h_dev_state;
2850 	hubd->h_dev_state = USB_DEV_DISCONNECTED;
2851 
2852 	USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
2853 	    "hubd_cleanup: stop polling");
2854 	hubd_close_intr_pipe(hubd);
2855 
2856 	ASSERT((hubd->h_bus_ctls || hubd->h_bus_pwr ||
2857 	    hubd->h_hotplug_thread) == 0);
2858 	mutex_exit(HUBD_MUTEX(hubd));
2859 
2860 	/*
2861 	 * deallocate events, if events are still registered
2862 	 * (ie. children still attached) then we have to fail the detach
2863 	 */
2864 	if (hubd->h_ndi_event_hdl) {
2865 
2866 		rval = ndi_event_free_hdl(hubd->h_ndi_event_hdl);
2867 		if (DEVI_IS_ATTACHING(dip)) {
2868 
2869 			/* It must return success if attaching. */
2870 			ASSERT(rval == NDI_SUCCESS);
2871 
2872 		} else if (rval != NDI_SUCCESS) {
2873 
2874 			USB_DPRINTF_L2(DPRINT_MASK_ALL, hubd->h_log_handle,
2875 			    "hubd_cleanup: ndi_event_free_hdl failed");
2876 			ndi_devi_exit(dip, circ);
2877 
2878 			return (USB_FAILURE);
2879 
2880 		}
2881 	}
2882 
2883 	mutex_enter(HUBD_MUTEX(hubd));
2884 
2885 	if (hubd->h_init_state & HUBD_CHILDREN_CREATED) {
2886 #ifdef DEBUG
2887 		for (port = 1; port <= hubd->h_nports; port++) {
2888 			ASSERT(hubd->h_usba_devices[port] == NULL);
2889 			ASSERT(hubd->h_children_dips[port] == NULL);
2890 		}
2891 #endif
2892 		kmem_free(hubd->h_children_dips, hubd->h_cd_list_length);
2893 		kmem_free(hubd->h_usba_devices, hubd->h_cd_list_length);
2894 	}
2895 
2896 	/*
2897 	 * Disable the event callbacks first, after this point, event
2898 	 * callbacks will never get called. Note we shouldn't hold
2899 	 * mutex while unregistering events because there may be a
2900 	 * competing event callback thread. Event callbacks are done
2901 	 * with ndi mutex held and this can cause a potential deadlock.
2902 	 * Note that cleanup can't fail after deregistration of events.
2903 	 */
2904 	if (hubd->h_init_state &  HUBD_EVENTS_REGISTERED) {
2905 		mutex_exit(HUBD_MUTEX(hubd));
2906 		usb_unregister_event_cbs(dip, &hubd_events);
2907 		hubd_unregister_cpr_callback(hubd);
2908 		mutex_enter(HUBD_MUTEX(hubd));
2909 	}
2910 
2911 	/* restore the old dev state so that device can be put into low power */
2912 	hubd->h_dev_state = old_dev_state;
2913 	hubpm = hubd->h_hubpm;
2914 
2915 	if ((hubpm) && (hubd->h_dev_state != USB_DEV_DISCONNECTED)) {
2916 		(void) hubd_pm_busy_component(hubd, dip, 0);
2917 		mutex_exit(HUBD_MUTEX(hubd));
2918 		if (hubd->h_hubpm->hubp_wakeup_enabled) {
2919 			/*
2920 			 * Bring the hub to full power before
2921 			 * issuing the disable remote wakeup command
2922 			 */
2923 			(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
2924 
2925 			if ((rval = usb_handle_remote_wakeup(hubd->h_dip,
2926 			    USB_REMOTE_WAKEUP_DISABLE)) != USB_SUCCESS) {
2927 				USB_DPRINTF_L2(DPRINT_MASK_PM,
2928 				    hubd->h_log_handle,
2929 				    "hubd_cleanup: disable remote wakeup "
2930 				    "fails=%d", rval);
2931 			}
2932 		}
2933 
2934 		(void) pm_lower_power(hubd->h_dip, 0, USB_DEV_OS_PWR_OFF);
2935 
2936 		mutex_enter(HUBD_MUTEX(hubd));
2937 		(void) hubd_pm_idle_component(hubd, dip, 0);
2938 	}
2939 
2940 	if (hubpm) {
2941 		if (hubpm->hubp_child_pwrstate) {
2942 			kmem_free(hubpm->hubp_child_pwrstate,
2943 			    MAX_PORTS + 1);
2944 		}
2945 		kmem_free(hubpm, sizeof (hub_power_t));
2946 	}
2947 	mutex_exit(HUBD_MUTEX(hubd));
2948 
2949 	USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
2950 	    "hubd_cleanup: freeing space");
2951 
2952 	if (hubd->h_init_state & HUBD_HUBDI_REGISTERED) {
2953 		rval = usba_hubdi_unregister(dip);
2954 		ASSERT(rval == USB_SUCCESS);
2955 	}
2956 
2957 	if (hubd->h_init_state & HUBD_LOCKS_DONE) {
2958 		mutex_destroy(HUBD_MUTEX(hubd));
2959 		cv_destroy(&hubd->h_cv_reset_port);
2960 		cv_destroy(&hubd->h_cv_hotplug_dev);
2961 	}
2962 
2963 	ndi_devi_exit(dip, circ);
2964 
2965 	if (hubd->h_init_state & HUBD_MINOR_NODE_CREATED) {
2966 		ddi_remove_minor_node(dip, NULL);
2967 	}
2968 
2969 	if (usba_is_root_hub(dip)) {
2970 		usb_pipe_close(dip, hubd->h_default_pipe,
2971 		    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL);
2972 	}
2973 
2974 done:
2975 	if (hubd->h_ancestry_str) {
2976 		kmem_free(hubd->h_ancestry_str, HUBD_APID_NAMELEN);
2977 	}
2978 
2979 	usb_client_detach(dip, hubd->h_dev_data);
2980 
2981 	usb_free_log_hdl(hubd->h_log_handle);
2982 
2983 	if (!usba_is_root_hub(dip)) {
2984 		ddi_soft_state_free(hubd_statep, ddi_get_instance(dip));
2985 	}
2986 
2987 	ddi_prop_remove_all(dip);
2988 
2989 	return (USB_SUCCESS);
2990 }
2991 
2992 
2993 /*
2994  * hubd_determine_port_connection:
2995  *	Determine which port is in connect status but does not
2996  *	have connect status change bit set, and mark port change
2997  *	bit accordingly.
2998  *	This function is applied during hub attach time.
2999  */
3000 static usb_port_mask_t
hubd_determine_port_connection(hubd_t * hubd)3001 hubd_determine_port_connection(hubd_t	*hubd)
3002 {
3003 	usb_port_t	port;
3004 	uint16_t	status;
3005 	uint16_t	change;
3006 	usb_port_mask_t	port_change = 0;
3007 
3008 	ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
3009 
3010 	for (port = 1; port <= hubd->h_nports; port++) {
3011 
3012 		(void) hubd_determine_port_status(hubd, port, &status,
3013 		    &change, NULL, 0);
3014 
3015 		/* Check if port is in connect status */
3016 		if (!(status & PORT_STATUS_CCS)) {
3017 
3018 			continue;
3019 		}
3020 
3021 		/*
3022 		 * Check if port Connect Status Change bit has been set.
3023 		 * If already set, the connection will be handled by
3024 		 * intr polling callback, not during attach.
3025 		 */
3026 		if (change & PORT_CHANGE_CSC) {
3027 
3028 			continue;
3029 		}
3030 
3031 		port_change |= 1 << port;
3032 	}
3033 
3034 	return (port_change);
3035 }
3036 
3037 
3038 /*
3039  * hubd_check_ports:
3040  *	- get hub descriptor
3041  *	- check initial port status
3042  *	- enable power on all ports
3043  *	- enable polling on ep1
3044  */
3045 static int
hubd_check_ports(hubd_t * hubd)3046 hubd_check_ports(hubd_t  *hubd)
3047 {
3048 	int			rval;
3049 	usb_port_mask_t		port_change = 0;
3050 	hubd_hotplug_arg_t	*arg;
3051 
3052 	ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
3053 
3054 	USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle,
3055 	    "hubd_check_ports: addr=0x%x", usb_get_addr(hubd->h_dip));
3056 
3057 	/*
3058 	 * First turn off all port power
3059 	 */
3060 	if ((rval = hubd_disable_all_port_power(hubd)) != USB_SUCCESS) {
3061 
3062 		/* disable whatever was enabled */
3063 		(void) hubd_disable_all_port_power(hubd);
3064 
3065 		return (rval);
3066 	}
3067 
3068 	/*
3069 	 * do not switch on immediately (instantly on root hub)
3070 	 * and allow time to settle
3071 	 */
3072 	mutex_exit(HUBD_MUTEX(hubd));
3073 	delay(drv_usectohz(10000));
3074 	mutex_enter(HUBD_MUTEX(hubd));
3075 
3076 	/*
3077 	 * enable power on all ports so we can see connects
3078 	 */
3079 	if ((rval = hubd_enable_all_port_power(hubd)) != USB_SUCCESS) {
3080 		/* disable whatever was enabled */
3081 		(void) hubd_disable_all_port_power(hubd);
3082 
3083 		return (rval);
3084 	}
3085 
3086 	/* wait at least 3 frames before accessing devices */
3087 	mutex_exit(HUBD_MUTEX(hubd));
3088 	delay(drv_usectohz(10000));
3089 	mutex_enter(HUBD_MUTEX(hubd));
3090 
3091 	/*
3092 	 * allocate arrays for saving the dips of each child per port
3093 	 *
3094 	 * ports go from 1 - n, allocate 1 more entry
3095 	 */
3096 	hubd->h_cd_list_length =
3097 	    (sizeof (dev_info_t **)) * (hubd->h_nports + 1);
3098 
3099 	hubd->h_children_dips = (dev_info_t **)kmem_zalloc(
3100 	    hubd->h_cd_list_length, KM_SLEEP);
3101 	hubd->h_usba_devices = (usba_device_t **)kmem_zalloc(
3102 	    hubd->h_cd_list_length, KM_SLEEP);
3103 
3104 	hubd->h_init_state |= HUBD_CHILDREN_CREATED;
3105 
3106 	mutex_exit(HUBD_MUTEX(hubd));
3107 	arg = (hubd_hotplug_arg_t *)kmem_zalloc(
3108 	    sizeof (hubd_hotplug_arg_t), KM_SLEEP);
3109 	mutex_enter(HUBD_MUTEX(hubd));
3110 
3111 	if ((rval = hubd_open_intr_pipe(hubd)) != USB_SUCCESS) {
3112 		kmem_free(arg, sizeof (hubd_hotplug_arg_t));
3113 
3114 		return (rval);
3115 	}
3116 
3117 	hubd_start_polling(hubd, 0);
3118 
3119 	/*
3120 	 * Some hub devices, like the embedded hub in the CKS ErgoMagic
3121 	 * keyboard, may only have connection status bit set, but not
3122 	 * have connect status change bit set when a device has been
3123 	 * connected to its downstream port before the hub is enumerated.
3124 	 * Then when the hub is in enumeration, the devices connected to
3125 	 * it cannot be detected by the intr pipe and won't be enumerated.
3126 	 * We need to check such situation here and enumerate the downstream
3127 	 * devices for such hubs.
3128 	 */
3129 	port_change = hubd_determine_port_connection(hubd);
3130 
3131 	if (port_change != 0 || hubd->h_port_change != 0) {
3132 		hubd_pm_busy_component(hubd, hubd->h_dip, 0);
3133 
3134 		arg->hubd = hubd;
3135 		arg->hotplug_during_attach = B_TRUE;
3136 		hubd->h_port_change |= port_change;
3137 
3138 		USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
3139 		    "hubd_check_ports: port change=0x%x, need to connect",
3140 		    hubd->h_port_change);
3141 
3142 		if (usb_async_req(hubd->h_dip, hubd_hotplug_thread,
3143 		    (void *)arg, 0) == USB_SUCCESS) {
3144 			hubd->h_hotplug_thread++;
3145 		} else {
3146 			/* mark this device as idle */
3147 			hubd_pm_idle_component(hubd, hubd->h_dip, 0);
3148 			kmem_free(arg, sizeof (hubd_hotplug_arg_t));
3149 		}
3150 	} else {
3151 		kmem_free(arg, sizeof (hubd_hotplug_arg_t));
3152 	}
3153 
3154 	USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
3155 	    "hubd_check_ports done");
3156 
3157 	return (USB_SUCCESS);
3158 }
3159 
3160 
3161 /*
3162  * hubd_get_hub_descriptor:
3163  */
3164 static int
hubd_get_hub_descriptor(hubd_t * hubd)3165 hubd_get_hub_descriptor(hubd_t *hubd)
3166 {
3167 	mblk_t		*data = NULL;
3168 	usb_cr_t	completion_reason;
3169 	usb_cb_flags_t	cb_flags;
3170 	uint16_t	length, wValue;
3171 	int		rval;
3172 	usb_req_attrs_t attr = 0;
3173 
3174 	USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle,
3175 	    "hubd_get_hub_descriptor:");
3176 
3177 	if ((hubd->h_dev_data->dev_descr->idVendor == USB_HUB_INTEL_VID) &&
3178 	    (hubd->h_dev_data->dev_descr->idProduct == USB_HUB_INTEL_PID)) {
3179 		attr = USB_ATTRS_SHORT_XFER_OK;
3180 	}
3181 
3182 	ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
3183 	ASSERT(hubd->h_default_pipe != 0);
3184 
3185 	mutex_exit(HUBD_MUTEX(hubd));
3186 
3187 	/*
3188 	 * The contents of wValue change depending on whether this is a USB 2 or
3189 	 * USB 3 device. SuperSpeed Hubs have different descriptors and you
3190 	 * cannot ask them for the traditional USB 2 descriptor.
3191 	 */
3192 	if (hubd->h_usba_device->usb_port_status >= USBA_SUPER_SPEED_DEV) {
3193 		wValue = USB_DESCR_TYPE_SS_HUB << 8 | HUBD_DEFAULT_DESC_INDEX;
3194 	} else {
3195 		wValue = USB_DESCR_TYPE_HUB << 8 | HUBD_DEFAULT_DESC_INDEX;
3196 	}
3197 
3198 	/*
3199 	 * The hub descriptor length varies in various versions of USB. For
3200 	 * example, in USB 2 it's at least 9 bytes long. To start with, we
3201 	 * always get the first 8 bytes so we can figure out how long it
3202 	 * actually is.
3203 	 */
3204 	if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
3205 	    hubd->h_default_pipe,
3206 	    HUB_CLASS_REQ_TYPE,
3207 	    USB_REQ_GET_DESCR,		/* bRequest */
3208 	    wValue,			/* wValue */
3209 	    0,				/* wIndex */
3210 	    8,				/* wLength */
3211 	    &data, 0,
3212 	    &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
3213 		USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
3214 		    "get hub descriptor failed: cr=%d cb_fl=0x%x rval=%d",
3215 		    completion_reason, cb_flags, rval);
3216 		freemsg(data);
3217 		mutex_enter(HUBD_MUTEX(hubd));
3218 
3219 		return (rval);
3220 	}
3221 
3222 	length = *(data->b_rptr);
3223 
3224 	if (length > 8) {
3225 		freemsg(data);
3226 		data = NULL;
3227 
3228 		/* get complete hub descriptor */
3229 		rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
3230 		    hubd->h_default_pipe,
3231 		    HUB_CLASS_REQ_TYPE,
3232 		    USB_REQ_GET_DESCR,		/* bRequest */
3233 		    wValue,			/* wValue */
3234 		    0,				/* wIndex */
3235 		    length,			/* wLength */
3236 		    &data, attr,
3237 		    &completion_reason, &cb_flags, 0);
3238 
3239 		/*
3240 		 * Hub descriptor data less than 9 bytes is not valid and
3241 		 * may cause trouble if we use it. See USB2.0 Tab11-13.
3242 		 */
3243 		if ((rval != USB_SUCCESS) || (MBLKL(data) <= 8)) {
3244 			USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
3245 			    "get hub descriptor failed: "
3246 			    "cr=%d cb_fl=0x%x rval=%d, len=%ld",
3247 			    completion_reason, cb_flags, rval,
3248 			    (data)?MBLKL(data):0);
3249 			freemsg(data);
3250 			mutex_enter(HUBD_MUTEX(hubd));
3251 
3252 			return (rval);
3253 		}
3254 	}
3255 
3256 	mutex_enter(HUBD_MUTEX(hubd));
3257 
3258 	/*
3259 	 * Parse the hub descriptor. Note that the format of the descriptor
3260 	 * itself depends on the USB version. We handle the different ones and
3261 	 * transform it into a single uniform view.
3262 	 */
3263 
3264 	ASSERT(*(data->b_rptr + 2) <= (MAX_PORTS + 1));
3265 	if (hubd->h_usba_device->usb_port_status >= USBA_SUPER_SPEED_DEV) {
3266 		usb_ss_hub_descr_t hub_descr;
3267 		char *desc = "cccscccs";
3268 		ASSERT(*(data->b_rptr + 1) == ROOT_HUB_SS_DESCRIPTOR_TYPE);
3269 
3270 		/*
3271 		 * Note many hubs may support less than the 255 devices that the
3272 		 * USB specification allows for. In those cases, we'll simply
3273 		 * read less and it should be okay.
3274 		 */
3275 		if (usb_parse_CV_descr(desc, data->b_rptr, MBLKL(data),
3276 		    (void *)&hub_descr, sizeof (hub_descr)) == 0) {
3277 			USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
3278 			    "parsing hub descriptor failed");
3279 			freemsg(data);
3280 			return (USB_FAILURE);
3281 		}
3282 
3283 		hubd->h_nports = hub_descr.bNbrPorts;
3284 		hubd->h_hub_chars = hub_descr.wHubCharacteristics;
3285 		hubd->h_power_good = hub_descr.bPwrOn2PwrGood;
3286 		hubd->h_current = hub_descr.bHubContrCurrent;
3287 	} else {
3288 		usb_hub_descr_t hub_descr;
3289 		if (usb_parse_CV_descr("cccscccccc",
3290 		    data->b_rptr, MBLKL(data),
3291 		    (void *)&hub_descr, sizeof (usb_hub_descr_t)) == 0) {
3292 			USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
3293 			    "parsing hub descriptor failed");
3294 			freemsg(data);
3295 			return (USB_FAILURE);
3296 		}
3297 
3298 		hubd->h_nports = hub_descr.bNbrPorts;
3299 		hubd->h_hub_chars = hub_descr.wHubCharacteristics;
3300 		hubd->h_power_good = hub_descr.bPwrOn2PwrGood;
3301 		hubd->h_current = hub_descr.bHubContrCurrent;
3302 	}
3303 
3304 	freemsg(data);
3305 
3306 	USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
3307 	    "rval=0x%x bNbrPorts=0x%x wHubChars=0x%x "
3308 	    "PwrOn2PwrGood=0x%x HubContrCurrent=%dmA", rval,
3309 	    hubd->h_nports, hubd->h_hub_chars,
3310 	    hubd->h_power_good, hubd->h_current);
3311 
3312 	if (hubd->h_nports > MAX_PORTS) {
3313 		USB_DPRINTF_L0(DPRINT_MASK_ATTA, hubd->h_log_handle,
3314 		    "Hub driver supports max of %d ports on hub. "
3315 		    "Hence using the first %d port of %d ports available",
3316 		    MAX_PORTS, MAX_PORTS, hubd->h_nports);
3317 
3318 		hubd->h_nports = MAX_PORTS;
3319 	}
3320 
3321 	return (USB_SUCCESS);
3322 }
3323 
3324 static int
hubd_set_hub_depth(hubd_t * hubd)3325 hubd_set_hub_depth(hubd_t *hubd)
3326 {
3327 	int rval;
3328 	usb_cr_t	completion_reason;
3329 	usb_cb_flags_t	cb_flags;
3330 	usba_device_t	*ud;
3331 	uint16_t	depth;
3332 
3333 	/*
3334 	 * We only need to set the hub depth devices for hubs that are at least
3335 	 * SuperSpeed devices. This didn't exist for USB 2.0 and older hubs.
3336 	 * There's also no need to call this on the root hub.
3337 	 */
3338 	if (hubd->h_usba_device->usb_port_status < USBA_SUPER_SPEED_DEV ||
3339 	    usba_is_root_hub(hubd->h_dip))
3340 		return (USB_SUCCESS);
3341 
3342 	depth = 0;
3343 	ud = hubd->h_usba_device;
3344 	while (ud->usb_parent_hub != NULL) {
3345 		depth++;
3346 		ud = ud->usb_parent_hub;
3347 	}
3348 	ASSERT(depth > 0);
3349 
3350 	if (depth > HUBD_SS_MAX_DEPTH) {
3351 		const char *mfg, *prod;
3352 
3353 		ud = hubd->h_usba_device;
3354 		prod = ud->usb_product_str;
3355 		if (prod == NULL)
3356 			prod = "Unknown Device";
3357 		mfg = ud->usb_mfg_str;
3358 		if (mfg == NULL)
3359 			mfg = "Unknown Manufacturer";
3360 		cmn_err(CE_WARN, "Unable to attach USB 3.x hub %s %s. A "
3361 		    "maximum of %d hubs may be cascaded", mfg, prod,
3362 		    HUBD_SS_MAX_DEPTH);
3363 		return (USB_FAILURE);
3364 	}
3365 
3366 	/*
3367 	 * When making the HUB_REQ_SET_HUB_DEPTH request, a hub connected to a
3368 	 * root port is considered to have a hub depth of zero whereas we
3369 	 * consider having a hub depth of one above.
3370 	 */
3371 	depth--;
3372 
3373 	if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
3374 	    hubd->h_default_pipe,
3375 	    HUB_SET_HUB_DEPTH_TYPE,
3376 	    HUB_REQ_SET_HUB_DEPTH,	/* bRequest */
3377 	    depth,			/* wValue */
3378 	    0,				/* wIndex */
3379 	    0,				/* wLength */
3380 	    NULL, 0,
3381 	    &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
3382 		USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle,
3383 		    "get set hub depth failed: cr=%d cb=0x%x",
3384 		    completion_reason, cb_flags);
3385 	}
3386 
3387 	return (rval);
3388 }
3389 
3390 /*
3391  * hubd_get_hub_status_words:
3392  */
3393 static int
hubd_get_hub_status_words(hubd_t * hubd,uint16_t * status)3394 hubd_get_hub_status_words(hubd_t *hubd, uint16_t *status)
3395 {
3396 	usb_cr_t	completion_reason;
3397 	usb_cb_flags_t	cb_flags;
3398 	mblk_t		*data = NULL;
3399 
3400 	ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
3401 
3402 	mutex_exit(HUBD_MUTEX(hubd));
3403 
3404 	if (usb_pipe_sync_ctrl_xfer(hubd->h_dip, hubd->h_default_pipe,
3405 	    HUB_CLASS_REQ_TYPE,
3406 	    USB_REQ_GET_STATUS,
3407 	    0,
3408 	    0,
3409 	    GET_STATUS_LENGTH,
3410 	    &data, 0,
3411 	    &completion_reason, &cb_flags, 0) != USB_SUCCESS) {
3412 		USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle,
3413 		    "get hub status failed: cr=%d cb=0x%x",
3414 		    completion_reason, cb_flags);
3415 
3416 		if (data) {
3417 			freemsg(data);
3418 		}
3419 
3420 		mutex_enter(HUBD_MUTEX(hubd));
3421 
3422 		return (USB_FAILURE);
3423 	}
3424 
3425 	mutex_enter(HUBD_MUTEX(hubd));
3426 
3427 	status[0] = (*(data->b_rptr + 1) << 8) | *(data->b_rptr);
3428 	status[1] = (*(data->b_rptr + 3) << 8) | *(data->b_rptr + 2);
3429 
3430 	USB_DPRINTF_L3(DPRINT_MASK_HUB, hubd->h_log_handle,
3431 	    "hub status=0x%x change=0x%x", status[0], status[1]);
3432 
3433 	freemsg(data);
3434 
3435 	return (USB_SUCCESS);
3436 }
3437 
3438 
3439 /*
3440  * hubd_open_intr_pipe:
3441  *	we read all descriptors first for curiosity and then simply
3442  *	open the pipe
3443  */
3444 static int
hubd_open_intr_pipe(hubd_t * hubd)3445 hubd_open_intr_pipe(hubd_t	*hubd)
3446 {
3447 	int			rval;
3448 
3449 	USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle,
3450 	    "hubd_open_intr_pipe:");
3451 
3452 	ASSERT(hubd->h_intr_pipe_state == HUBD_INTR_PIPE_IDLE);
3453 
3454 	hubd->h_intr_pipe_state = HUBD_INTR_PIPE_OPENING;
3455 	mutex_exit(HUBD_MUTEX(hubd));
3456 
3457 	if ((rval = usb_pipe_xopen(hubd->h_dip,
3458 	    &hubd->h_ep1_xdescr, &hubd->h_pipe_policy,
3459 	    0, &hubd->h_ep1_ph)) != USB_SUCCESS) {
3460 		USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle,
3461 		    "open intr pipe failed (%d)", rval);
3462 
3463 		mutex_enter(HUBD_MUTEX(hubd));
3464 		hubd->h_intr_pipe_state = HUBD_INTR_PIPE_IDLE;
3465 
3466 		return (rval);
3467 	}
3468 
3469 	mutex_enter(HUBD_MUTEX(hubd));
3470 	hubd->h_intr_pipe_state = HUBD_INTR_PIPE_ACTIVE;
3471 
3472 	USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle,
3473 	    "open intr pipe succeeded, ph=0x%p", (void *)hubd->h_ep1_ph);
3474 
3475 	return (USB_SUCCESS);
3476 }
3477 
3478 
3479 /*
3480  * hubd_start_polling:
3481  *	start or restart the polling
3482  */
3483 static void
hubd_start_polling(hubd_t * hubd,int always)3484 hubd_start_polling(hubd_t *hubd, int always)
3485 {
3486 	usb_intr_req_t	*reqp;
3487 	int			rval;
3488 	usb_pipe_state_t	pipe_state;
3489 
3490 	USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle,
3491 	    "start polling: always=%d dev_state=%d pipe_state=%d\n\t"
3492 	    "thread=%d ep1_ph=0x%p",
3493 	    always, hubd->h_dev_state, hubd->h_intr_pipe_state,
3494 	    hubd->h_hotplug_thread, (void *)hubd->h_ep1_ph);
3495 
3496 	/*
3497 	 * start or restart polling on the intr pipe
3498 	 * only if hotplug thread is not running
3499 	 */
3500 	if ((always == HUBD_ALWAYS_START_POLLING) ||
3501 	    ((hubd->h_dev_state == USB_DEV_ONLINE) &&
3502 	    (hubd->h_intr_pipe_state == HUBD_INTR_PIPE_ACTIVE) &&
3503 	    (hubd->h_hotplug_thread == 0) && hubd->h_ep1_ph)) {
3504 		USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle,
3505 		    "start polling requested");
3506 
3507 		reqp = usb_alloc_intr_req(hubd->h_dip, 0, USB_FLAGS_SLEEP);
3508 
3509 		reqp->intr_client_private = (usb_opaque_t)hubd;