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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * hot-plug services module
30 #include <sys/modctl.h>
32 #include <sys/sunddi.h>
33 #include <sys/sunndi.h>
36 #include <sys/hotplug/hpcsvc.h>
37 #include <sys/callb.h>
46 static void debug(char *, uintptr_t, uintptr_t, uintptr_t,
47 uintptr_t, uintptr_t);
50 debug(fmt, 0, 0, 0, 0, 0);
51 #define DEBUG1(fmt, a1) \
52 debug(fmt, (uintptr_t)(a1), 0, 0, 0, 0);
53 #define DEBUG2(fmt, a1, a2) \
54 debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), 0, 0, 0);
55 #define DEBUG3(fmt, a1, a2, a3) \
56 debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), (uintptr_t)(a3), 0, 0);
59 #define DEBUG1(fmt, a1)
60 #define DEBUG2(fmt, a1, a2)
61 #define DEBUG3(fmt, a1, a2, a3)
65 * Definitions for the bus node registration list:
67 * The hot-plug service module maintains a linked list of items
68 * representing the device bus nodes that have been registered via
69 * hpc_nexus_register, or identified as candidates for registration
70 * by the bus argument to hpc_slot_register.
72 * The head of the linked listed is stored in hpc_bus_list_head. Insertions
73 * and removals from the list should be locked with mutex hpc_bus_mutex.
75 * Items in the list are allocated/freed with the macros hpc_alloc_bus_entry()
76 * and hpc_free_bus_entry().
78 * Each item in the list contains the following fields:
80 * bus_dip - pointer to devinfo node of the registering bus
82 * bus_name - device path name of the bus (ie /pci@1f,4000)
84 * bus_callback - bus nexus driver callback function registered
87 * bus_registered - a boolean value which is true if the bus has
88 * been registered with hpc_nexus_register, false otherwise
90 * bus_mutex - mutex lock to be held while updating this list entry
92 * bus_slot_list - linked list of the slots registered for this
93 * bus node (see slot list details below)
95 * bus_thread - kernel thread for running slot event handlers for
96 * slots associated with this bus
98 * bus_thread_cv - condition variable for synchronization between
99 * the service routines and the thread for running slot
102 * bus_thread_exit - a boolean value used to instruct the thread
103 * for invoking the slot event handlers to exit
105 * bus_slot_event_list_head - the head of the linked list of instances
106 * of slot event handlers to be run
107 * handlers to be invoked
109 * bus_next - pointer to next list entry
112 typedef struct hpc_bus_entry hpc_bus_entry_t
;
113 typedef struct hpc_slot_entry hpc_slot_entry_t
;
114 typedef struct hpc_event_entry hpc_event_entry_t
;
116 struct hpc_event_entry
{
117 hpc_slot_entry_t
*slotp
;
119 hpc_event_entry_t
*next
;
122 #define hpc_alloc_event_entry() \
123 (hpc_event_entry_t *)kmem_zalloc(sizeof (hpc_event_entry_t), KM_SLEEP)
125 #define hpc_free_event_entry(a) \
126 kmem_free((a), sizeof (hpc_event_entry_t))
128 struct hpc_bus_entry
{
130 char bus_name
[MAXPATHLEN
+ 1];
131 boolean_t bus_registered
;
133 int (* bus_callback
)(dev_info_t
*dip
, hpc_slot_t hdl
,
134 hpc_slot_info_t
*slot_info
, int slot_state
);
135 hpc_slot_entry_t
*bus_slot_list
;
136 kthread_t
*bus_thread
;
137 kcondvar_t bus_thread_cv
;
138 boolean_t bus_thread_exit
;
139 hpc_event_entry_t
*bus_slot_event_list_head
;
140 hpc_bus_entry_t
*bus_next
;
143 #define hpc_alloc_bus_entry() \
144 (hpc_bus_entry_t *)kmem_zalloc(sizeof (hpc_bus_entry_t), KM_SLEEP)
146 #define hpc_free_bus_entry(a) \
147 kmem_free((a), sizeof (hpc_bus_entry_t))
151 * Definitions for the per-bus node slot registration list:
153 * For each bus node in the bus list, the hot-plug service module maintains
154 * a doubly linked link list of items representing the slots that have been
155 * registered (by hot-plug controllers) for that bus.
157 * The head of the linked listed is stored in bus_slot_list field of the bus
158 * node. Insertions and removals from this list should locked with the mutex
159 * in the bus_mutex field of the bus node.
161 * Items in the list are allocated/freed with the macros hpc_alloc_slot_entry()
162 * and hpc_free_slot_entry().
164 * Each item in the list contains the following fields:
166 * slot_handle - handle for slot (hpc_slot_t)
168 * slot_info - information registered with the slot (hpc_slot_info_t)
170 * slot_ops - ops vector registered with the slot (hpc_slot_ops_t)
172 * slot_ops_arg - argument to be passed to ops routines (caddr_t)
174 * slot_event_handler - handler registered for slot events
176 * slot_event_handler_arg - argument to be passed to event handler
178 * slot_event_mask - the set of events for which the event handler
181 * slot_bus - pointer to bus node for the slot
183 * slot_hpc_dip - devinfo node pointer to the HPC driver instance
184 * that controls this slot
186 * slot_{prev,next} - point to {previous,next} node in the list
189 struct hpc_slot_entry
{
190 hpc_slot_t slot_handle
;
191 hpc_slot_info_t slot_info
; /* should be static & copied */
192 hpc_slot_ops_t slot_ops
;
193 caddr_t slot_ops_arg
;
194 int (* slot_event_handler
)(caddr_t
, uint_t
);
195 caddr_t slot_event_handler_arg
;
196 uint_t slot_event_mask
;
197 hpc_bus_entry_t
*slot_bus
;
198 dev_info_t
*slot_hpc_dip
;
199 hpc_slot_entry_t
*slot_next
, *slot_prev
;
202 #define hpc_alloc_slot_entry() \
203 (hpc_slot_entry_t *)kmem_zalloc(sizeof (hpc_slot_entry_t), KM_SLEEP)
205 #define hpc_free_slot_entry(a) \
206 kmem_free((a), sizeof (hpc_slot_entry_t))
210 * Definitions for slot registration callback table.
213 typedef struct hpc_callback_entry hpc_callback_entry_t
;
215 struct hpc_callback_entry
{
216 int (* callback
)(dev_info_t
*dip
, hpc_slot_t hdl
,
217 hpc_slot_info_t
*slot_info
, int slot_state
);
220 hpc_slot_info_t
*slot_info
;
222 hpc_callback_entry_t
*next
;
225 #define hpc_alloc_callback_entry() \
226 (hpc_callback_entry_t *) \
227 kmem_zalloc(sizeof (hpc_callback_entry_t), KM_SLEEP)
229 #define hpc_free_callback_entry(a) \
230 kmem_free((a), sizeof (hpc_callback_entry_t))
235 * Mutex lock for bus registration table and table head.
237 static kmutex_t hpc_bus_mutex
;
238 static hpc_bus_entry_t
*hpc_bus_list_head
;
242 * Forward function declarations.
244 static hpc_bus_entry_t
*hpc_find_bus_by_name(char *name
);
245 static void hpc_slot_event_dispatcher(hpc_bus_entry_t
*busp
);
249 * loadable module definitions:
251 extern struct mod_ops mod_miscops
;
253 static struct modlmisc modlmisc
= {
254 &mod_miscops
, /* Type of module */
255 "hot-plug controller services"
258 static struct modlinkage modlinkage
= {
259 MODREV_1
, (void *)&modlmisc
, NULL
267 mutex_init(&hpc_bus_mutex
, NULL
, MUTEX_DRIVER
, NULL
);
270 * Install the module.
272 e
= mod_install(&modlinkage
);
274 mutex_destroy(&hpc_bus_mutex
);
284 e
= mod_remove(&modlinkage
);
286 mutex_destroy(&hpc_bus_mutex
);
292 _info(struct modinfo
*modinfop
)
294 return (mod_info(&modlinkage
, modinfop
));
300 hpc_alloc_slot_ops(int flag
)
304 ops
= (hpc_slot_ops_t
*)kmem_zalloc(sizeof (hpc_slot_ops_t
), flag
);
310 hpc_free_slot_ops(hpc_slot_ops_t
*ops
)
312 kmem_free((void *)ops
, sizeof (hpc_slot_ops_t
));
318 hpc_nexus_register_bus(dev_info_t
*dip
,
319 int (* callback
)(dev_info_t
*dip
, hpc_slot_t hdl
,
320 hpc_slot_info_t
*slot_info
, int slot_state
), uint_t flags
)
322 hpc_bus_entry_t
*busp
;
323 hpc_slot_entry_t
*slotp
;
324 char bus_path
[MAXPATHLEN
+ 1];
326 DEBUG2("hpc_nexus_register_bus: %s%d",
327 ddi_node_name(dip
), ddi_get_instance(dip
));
328 mutex_enter(&hpc_bus_mutex
);
329 (void) ddi_pathname(dip
, bus_path
);
330 busp
= hpc_find_bus_by_name(bus_path
);
334 * Initialize the new bus node and link it at the head
337 DEBUG0("hpc_nexus_register_bus: not in bus list");
338 busp
= hpc_alloc_bus_entry();
340 busp
->bus_registered
= B_TRUE
;
341 (void) strcpy(busp
->bus_name
, bus_path
);
342 mutex_init(&busp
->bus_mutex
, NULL
, MUTEX_DRIVER
, NULL
);
343 busp
->bus_callback
= callback
;
344 busp
->bus_slot_list
= NULL
;
345 busp
->bus_next
= hpc_bus_list_head
;
346 hpc_bus_list_head
= busp
;
351 * The bus is in the bus list but isn't registered yet.
352 * Mark it as registered, and run the registration callbacks
355 DEBUG0("hpc_nexus_register_bus: in list, but not registered");
356 mutex_enter(&busp
->bus_mutex
);
357 if (busp
->bus_registered
== B_TRUE
) {
358 mutex_exit(&busp
->bus_mutex
);
359 mutex_exit(&hpc_bus_mutex
);
360 return (HPC_ERR_BUS_DUPLICATE
);
363 busp
->bus_callback
= callback
;
364 busp
->bus_registered
= B_TRUE
;
366 mutex_exit(&busp
->bus_mutex
);
367 mutex_exit(&hpc_bus_mutex
);
369 DEBUG0("hpc_nexus_register_bus: running callbacks");
370 for (slotp
= busp
->bus_slot_list
; slotp
;
371 slotp
= slotp
->slot_next
) {
372 (void) callback(dip
, slotp
, &slotp
->slot_info
,
376 return (HPC_SUCCESS
);
378 mutex_exit(&hpc_bus_mutex
);
379 return (HPC_SUCCESS
);
384 hpc_nexus_unregister_bus(dev_info_t
*dip
)
386 hpc_bus_entry_t
*busp
, *busp_prev
;
387 hpc_slot_entry_t
*slotp
;
390 * Search the list for the bus node and remove it.
392 DEBUG2("hpc_nexus_unregister_bus: %s%d",
393 ddi_node_name(dip
), ddi_get_instance(dip
));
394 mutex_enter(&hpc_bus_mutex
);
395 for (busp
= hpc_bus_list_head
; busp
!= NULL
; busp_prev
= busp
,
396 busp
= busp
->bus_next
) {
397 if (busp
->bus_dip
== dip
)
401 mutex_exit(&hpc_bus_mutex
);
402 return (HPC_ERR_BUS_NOTREGISTERED
);
406 * If the bus has slots, mark the bus as unregistered, otherwise
407 * remove the bus entry from the list.
409 mutex_enter(&busp
->bus_mutex
);
410 if (busp
->bus_slot_list
== NULL
) {
411 if (busp
== hpc_bus_list_head
)
412 hpc_bus_list_head
= busp
->bus_next
;
414 busp_prev
->bus_next
= busp
->bus_next
;
415 mutex_exit(&busp
->bus_mutex
);
416 mutex_destroy(&busp
->bus_mutex
);
417 hpc_free_bus_entry(busp
);
418 mutex_exit(&hpc_bus_mutex
);
419 return (HPC_SUCCESS
);
423 * unregister event handlers for all the slots on this bus.
425 for (slotp
= busp
->bus_slot_list
; slotp
!= NULL
;
426 slotp
= slotp
->slot_next
) {
427 slotp
->slot_event_handler
= NULL
;
428 slotp
->slot_event_handler_arg
= NULL
;
430 busp
->bus_registered
= B_FALSE
;
431 mutex_exit(&busp
->bus_mutex
);
432 mutex_exit(&hpc_bus_mutex
);
433 return (HPC_SUCCESS
);
439 hpc_slot_register(dev_info_t
*hpc_dip
, char *bus
, hpc_slot_info_t
*infop
,
440 hpc_slot_t
*handlep
, hpc_slot_ops_t
*opsp
,
441 caddr_t ops_arg
, uint_t flags
)
443 hpc_bus_entry_t
*busp
;
444 hpc_slot_entry_t
*slotp
, *slot_list_head
;
445 boolean_t run_callback
= B_FALSE
;
446 int (* callback
)(dev_info_t
*dip
, hpc_slot_t hdl
,
447 hpc_slot_info_t
*slot_info
, int slot_state
);
452 * Validate the arguments.
454 DEBUG1("hpc_slot_register: %s", bus
);
455 if (handlep
== NULL
|| infop
== NULL
|| opsp
== NULL
|| hpc_dip
== NULL
)
456 return (HPC_ERR_INVALID
);
459 * The bus for the slot may or may not be in the bus list. If it's
460 * not, we create a node for the bus in the bus list and mark it as
463 mutex_enter(&hpc_bus_mutex
);
464 busp
= hpc_find_bus_by_name(bus
);
468 * Initialize the new bus node and link it at the
469 * head of the bus list.
471 DEBUG1("hpc_slot_register: %s not in bus list", bus
);
472 busp
= hpc_alloc_bus_entry();
473 busp
->bus_registered
= B_FALSE
;
474 (void) strcpy(busp
->bus_name
, bus
);
475 mutex_init(&busp
->bus_mutex
, NULL
, MUTEX_DRIVER
, NULL
);
476 busp
->bus_slot_list
= NULL
;
477 busp
->bus_next
= hpc_bus_list_head
;
478 hpc_bus_list_head
= busp
;
481 if (busp
->bus_registered
== B_TRUE
) {
482 run_callback
= B_TRUE
;
483 callback
= busp
->bus_callback
;
488 mutex_enter(&busp
->bus_mutex
);
489 slot_list_head
= busp
->bus_slot_list
;
490 if (slot_list_head
== NULL
) {
493 * The slot list was empty, so this is the first slot
494 * registered for the bus. Create a per-bus thread
495 * for running the slot event handlers.
497 DEBUG0("hpc_slot_register: creating event callback thread");
498 cv_init(&busp
->bus_thread_cv
, NULL
, CV_DRIVER
, NULL
);
499 busp
->bus_thread_exit
= B_FALSE
;
500 t
= thread_create(NULL
, 0, hpc_slot_event_dispatcher
,
501 (caddr_t
)busp
, 0, &p0
, TS_RUN
, minclsyspri
);
502 busp
->bus_thread
= t
;
506 * Create and initialize a new entry in the slot list for the bus.
508 slotp
= hpc_alloc_slot_entry();
509 slotp
->slot_handle
= (hpc_slot_t
)slotp
;
510 slotp
->slot_info
= *infop
;
511 slotp
->slot_ops
= *opsp
;
512 slotp
->slot_ops_arg
= ops_arg
;
513 slotp
->slot_bus
= busp
;
514 slotp
->slot_hpc_dip
= hpc_dip
;
515 slotp
->slot_prev
= NULL
;
516 busp
->bus_slot_list
= slotp
;
517 slotp
->slot_next
= slot_list_head
;
518 if (slot_list_head
!= NULL
)
519 slot_list_head
->slot_prev
= slotp
;
520 mutex_exit(&busp
->bus_mutex
);
521 mutex_exit(&hpc_bus_mutex
);
524 * Return the handle to the caller prior to return to avoid recursion.
526 *handlep
= (hpc_slot_t
)slotp
;
529 * If the bus was registered, we run the callback registered by
533 DEBUG0("hpc_slot_register: running callback");
535 (void) callback(dip
, slotp
, infop
, HPC_SLOT_ONLINE
);
539 * Keep hpc driver in memory
541 (void) ndi_hold_driver(hpc_dip
);
543 return (HPC_SUCCESS
);
548 hpc_slot_unregister(hpc_slot_t
*handlep
)
550 hpc_slot_entry_t
*slotp
;
551 hpc_bus_entry_t
*busp
, *busp_prev
;
552 boolean_t run_callback
;
553 int (* callback
)(dev_info_t
*dip
, hpc_slot_t hdl
,
554 hpc_slot_info_t
*slot_info
, int slot_state
);
559 DEBUG0("hpc_slot_unregister:");
561 ASSERT(handlep
!= NULL
);
563 /* validate the handle */
564 slotp
= (hpc_slot_entry_t
*)*handlep
;
565 if ((slotp
== NULL
) || slotp
->slot_handle
!= *handlep
)
566 return (HPC_ERR_INVALID
);
569 * Get the bus list entry from the slot to grap the mutex for
570 * the slot list of the bus.
572 mutex_enter(&hpc_bus_mutex
);
573 busp
= slotp
->slot_bus
;
574 DEBUG2("hpc_slot_unregister: handlep=%x, slotp=%x", handlep
, slotp
);
576 mutex_exit(&hpc_bus_mutex
);
577 return (HPC_ERR_SLOT_NOTREGISTERED
);
581 * Determine if we need to run the slot offline callback and
582 * save the data necessary to do so.
584 callback
= busp
->bus_callback
;
585 run_callback
= (busp
->bus_registered
== B_TRUE
) && (callback
!= NULL
);
587 bus_name
= busp
->bus_name
;
590 * Run the slot offline callback if necessary.
593 mutex_exit(&hpc_bus_mutex
);
594 DEBUG0("hpc_slot_unregister: running callback");
595 r
= callback(dip
, (hpc_slot_t
)slotp
, &slotp
->slot_info
,
597 DEBUG1("hpc_slot_unregister: callback returned %x", r
);
598 if (r
!= HPC_SUCCESS
)
599 return (HPC_ERR_FAILED
);
600 mutex_enter(&hpc_bus_mutex
);
604 * Remove the slot from list and free the memory associated with it.
606 mutex_enter(&busp
->bus_mutex
);
607 DEBUG1("hpc_slot_unregister: freeing slot, bus_slot_list=%x",
608 busp
->bus_slot_list
);
609 if (slotp
->slot_prev
!= NULL
)
610 slotp
->slot_prev
->slot_next
= slotp
->slot_next
;
611 if (slotp
->slot_next
!= NULL
)
612 slotp
->slot_next
->slot_prev
= slotp
->slot_prev
;
613 if (slotp
== busp
->bus_slot_list
)
614 busp
->bus_slot_list
= slotp
->slot_next
;
617 * Release hold from slot registration
619 ndi_rele_driver(slotp
->slot_hpc_dip
);
621 /* Free the memory associated with the slot entry structure */
622 hpc_free_slot_entry(slotp
);
625 * If the slot list is empty then stop the event handler thread.
627 if (busp
->bus_slot_list
== NULL
) {
628 DEBUG0("hpc_slot_unregister: stopping thread");
629 busp
->bus_thread_exit
= B_TRUE
;
630 cv_signal(&busp
->bus_thread_cv
);
631 DEBUG0("hpc_slot_unregister: waiting for thread to exit");
632 cv_wait(&busp
->bus_thread_cv
, &busp
->bus_mutex
);
633 DEBUG0("hpc_slot_unregister: thread exit");
634 cv_destroy(&busp
->bus_thread_cv
);
638 * If the bus is unregistered and this is the last slot for this bus
639 * then remove the entry from the bus list.
641 if (busp
->bus_registered
== B_FALSE
&& busp
->bus_slot_list
== NULL
) {
642 /* locate the previous entry in the bus list */
643 for (busp
= hpc_bus_list_head
; busp
!= NULL
; busp_prev
= busp
,
644 busp
= busp
->bus_next
)
645 if (strcmp(bus_name
, busp
->bus_name
) == 0)
648 if (busp
== hpc_bus_list_head
)
649 hpc_bus_list_head
= busp
->bus_next
;
651 busp_prev
->bus_next
= busp
->bus_next
;
653 mutex_exit(&busp
->bus_mutex
);
654 mutex_destroy(&busp
->bus_mutex
);
655 hpc_free_bus_entry(busp
);
657 mutex_exit(&busp
->bus_mutex
);
658 mutex_exit(&hpc_bus_mutex
);
661 * reset the slot handle.
664 return (HPC_SUCCESS
);
669 hpc_install_event_handler(hpc_slot_t handle
, uint_t event_mask
,
670 int (*event_handler
)(caddr_t
, uint_t
), caddr_t arg
)
672 hpc_slot_entry_t
*slotp
;
673 hpc_bus_entry_t
*busp
;
675 DEBUG3("hpc_install_event_handler: handle=%x, mask=%x, arg=%x",
676 handle
, event_mask
, arg
);
677 ASSERT((handle
!= NULL
) && (event_handler
!= NULL
));
678 slotp
= (hpc_slot_entry_t
*)handle
;
679 busp
= slotp
->slot_bus
;
680 ASSERT(slotp
== slotp
->slot_handle
);
681 mutex_enter(&busp
->bus_mutex
);
682 slotp
->slot_event_mask
= event_mask
;
683 slotp
->slot_event_handler
= event_handler
;
684 slotp
->slot_event_handler_arg
= arg
;
685 mutex_exit(&busp
->bus_mutex
);
686 return (HPC_SUCCESS
);
691 hpc_remove_event_handler(hpc_slot_t handle
)
693 hpc_slot_entry_t
*slotp
;
694 hpc_bus_entry_t
*busp
;
696 DEBUG1("hpc_remove_event_handler: handle=%x", handle
);
697 ASSERT(handle
!= NULL
);
698 slotp
= (hpc_slot_entry_t
*)handle
;
699 ASSERT(slotp
== slotp
->slot_handle
);
700 busp
= slotp
->slot_bus
;
701 mutex_enter(&busp
->bus_mutex
);
702 slotp
->slot_event_mask
= 0;
703 slotp
->slot_event_handler
= NULL
;
704 slotp
->slot_event_handler_arg
= NULL
;
705 mutex_exit(&busp
->bus_mutex
);
706 return (HPC_SUCCESS
);
712 hpc_slot_event_notify(hpc_slot_t handle
, uint_t event
, uint_t flags
)
714 hpc_slot_entry_t
*slotp
;
715 hpc_bus_entry_t
*busp
;
716 hpc_event_entry_t
*eventp
;
718 DEBUG2("hpc_slot_event_notify: handle=%x event=%x", handle
, event
);
719 ASSERT(handle
!= NULL
);
720 slotp
= (hpc_slot_entry_t
*)handle
;
721 ASSERT(slotp
== slotp
->slot_handle
);
723 if (slotp
->slot_event_handler
== NULL
)
724 return (HPC_EVENT_UNCLAIMED
);
727 * If the request is to handle the event synchronously, then call
728 * the event handler without queuing the event.
730 if (flags
== HPC_EVENT_SYNCHRONOUS
) {
732 int (* func
)(caddr_t
, uint_t
);
734 func
= slotp
->slot_event_handler
;
735 arg
= slotp
->slot_event_handler_arg
;
736 return (func(arg
, event
));
739 * Insert the event into the bus slot event handler list and
740 * signal the bus slot event handler dispatch thread.
742 busp
= slotp
->slot_bus
;
743 mutex_enter(&busp
->bus_mutex
);
745 if (busp
->bus_slot_event_list_head
== NULL
) {
746 eventp
= busp
->bus_slot_event_list_head
=
747 hpc_alloc_event_entry();
749 for (eventp
= busp
->bus_slot_event_list_head
;
750 eventp
->next
!= NULL
; eventp
= eventp
->next
)
752 eventp
->next
= hpc_alloc_event_entry();
753 eventp
= eventp
->next
;
755 eventp
->slotp
= slotp
;
756 eventp
->event
= event
;
758 DEBUG2("hpc_slot_event_notify: busp=%x event=%x", busp
, event
);
759 cv_signal(&busp
->bus_thread_cv
);
760 mutex_exit(&busp
->bus_mutex
);
761 return (HPC_EVENT_CLAIMED
);
766 hpc_nexus_connect(hpc_slot_t handle
, void *data
, uint_t flags
)
768 hpc_slot_entry_t
*slotp
;
770 ASSERT(handle
!= NULL
);
771 slotp
= (hpc_slot_entry_t
*)handle
;
772 if (slotp
->slot_ops
.hpc_op_connect
)
773 return (slotp
->slot_ops
.hpc_op_connect(slotp
->slot_ops_arg
,
774 handle
, data
, flags
));
775 return (HPC_ERR_FAILED
);
780 hpc_nexus_disconnect(hpc_slot_t handle
, void *data
, uint_t flags
)
782 hpc_slot_entry_t
*slotp
;
784 ASSERT(handle
!= NULL
);
785 slotp
= (hpc_slot_entry_t
*)handle
;
786 if (slotp
->slot_ops
.hpc_op_disconnect
)
787 return (slotp
->slot_ops
.hpc_op_disconnect(slotp
->slot_ops_arg
,
788 handle
, data
, flags
));
789 return (HPC_ERR_FAILED
);
794 hpc_nexus_insert(hpc_slot_t handle
, void *data
, uint_t flags
)
796 hpc_slot_entry_t
*slotp
;
798 ASSERT(handle
!= NULL
);
799 slotp
= (hpc_slot_entry_t
*)handle
;
800 if (slotp
->slot_ops
.hpc_op_insert
)
801 return (slotp
->slot_ops
.hpc_op_insert(slotp
->slot_ops_arg
,
802 handle
, data
, flags
));
803 return (HPC_ERR_FAILED
);
808 hpc_nexus_remove(hpc_slot_t handle
, void *data
, uint_t flags
)
810 hpc_slot_entry_t
*slotp
;
812 ASSERT(handle
!= NULL
);
813 slotp
= (hpc_slot_entry_t
*)handle
;
814 if (slotp
->slot_ops
.hpc_op_remove
)
815 return (slotp
->slot_ops
.hpc_op_remove(slotp
->slot_ops_arg
,
816 handle
, data
, flags
));
817 return (HPC_ERR_FAILED
);
822 hpc_nexus_control(hpc_slot_t handle
, int request
, caddr_t arg
)
824 hpc_slot_entry_t
*slotp
;
826 ASSERT(handle
!= NULL
);
827 slotp
= (hpc_slot_entry_t
*)handle
;
828 if (slotp
->slot_ops
.hpc_op_control
)
829 return (slotp
->slot_ops
.hpc_op_control(slotp
->slot_ops_arg
,
830 handle
, request
, arg
));
831 return (HPC_ERR_FAILED
);
835 * The following function is run from the bus entries slot event handling
839 hpc_slot_event_dispatcher(hpc_bus_entry_t
*busp
)
841 hpc_event_entry_t
*eventp
;
842 hpc_slot_entry_t
*slotp
;
845 int (* func
)(caddr_t
, uint_t
);
849 * The creator of this thread is waiting to be signaled that
850 * the thread has been started.
852 DEBUG1("hpc_slot_event_dispatcher: busp=%x", busp
);
854 CALLB_CPR_INIT(&cprinfo
, &busp
->bus_mutex
, callb_generic_cpr
,
855 "hpc_slot_event_dispatcher");
857 mutex_enter(&busp
->bus_mutex
);
859 * Wait for events to queue and then process them.
864 * Note we only hold the mutex while determining
865 * the number of entries that have been added to
866 * the event list, while updating the event list
867 * after processing the event list entries.
869 if (busp
->bus_slot_event_list_head
== NULL
) {
870 CALLB_CPR_SAFE_BEGIN(&cprinfo
);
871 cv_wait(&busp
->bus_thread_cv
, &busp
->bus_mutex
);
872 CALLB_CPR_SAFE_END(&cprinfo
, &busp
->bus_mutex
);
873 if (busp
->bus_thread_exit
)
879 * We have an event handler instance in the list to
880 * process. Remove the head of the list, saving the
881 * information required to run the event handler.
882 * Then run the event handler while the bus mutex
885 eventp
= busp
->bus_slot_event_list_head
;
886 slotp
= eventp
->slotp
;
887 event
= eventp
->event
;
888 func
= slotp
->slot_event_handler
;
889 arg
= slotp
->slot_event_handler_arg
;
890 busp
->bus_slot_event_list_head
= eventp
->next
;
891 hpc_free_event_entry(eventp
);
892 mutex_exit(&busp
->bus_mutex
);
894 mutex_enter(&busp
->bus_mutex
);
896 if (busp
->bus_thread_exit
)
900 DEBUG0("hpc_slot_event_dispatcher: thread_exit");
901 cv_signal(&busp
->bus_thread_cv
);
902 CALLB_CPR_EXIT(&cprinfo
);
907 static hpc_bus_entry_t
*
908 hpc_find_bus_by_name(char *path
)
910 hpc_bus_entry_t
*busp
;
912 for (busp
= hpc_bus_list_head
; busp
!= NULL
; busp
= busp
->bus_next
) {
913 if (strcmp(path
, busp
->bus_name
) == 0)
920 hpc_bus_registered(hpc_slot_t slot_hdl
)
922 hpc_slot_entry_t
*slotp
;
923 hpc_bus_entry_t
*busp
;
925 slotp
= (hpc_slot_entry_t
*)slot_hdl
;
926 busp
= slotp
->slot_bus
;
927 return (busp
->bus_registered
);
933 extern void prom_printf(const char *, ...);
936 debug(char *fmt
, uintptr_t a1
, uintptr_t a2
, uintptr_t a3
,
937 uintptr_t a4
, uintptr_t a5
)
939 if (hpcsvc_debug
!= 0) {
940 cmn_err(CE_CONT
, "hpcsvc: ");
941 cmn_err(CE_CONT
, fmt
, a1
, a2
, a3
, a4
, a5
);
942 cmn_err(CE_CONT
, "\n");