4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
32 * 1394 Services Layer Nexus Support Routines
33 * Routines in this file implement nexus bus_ops.
38 #include <sys/modctl.h>
39 #include <sys/sunddi.h>
40 #include <sys/cmn_err.h>
41 #include <sys/types.h>
42 #include <sys/ddi_impldefs.h>
44 #include <sys/tnf_probe.h>
46 #include <sys/1394/t1394.h>
47 #include <sys/1394/s1394.h>
48 #include <sys/1394/h1394.h>
50 static int nx1394_dma_allochdl(dev_info_t
*dip
, dev_info_t
*rdip
,
51 ddi_dma_attr_t
*attr
, int (*waitfnp
)(caddr_t
), caddr_t arg
,
52 ddi_dma_handle_t
*handlep
);
54 static int nx1394_bus_ctl(dev_info_t
*dip
, dev_info_t
*rdip
, ddi_ctl_enum_t op
,
55 void *arg
, void *result
);
57 static int nx1394_get_event_cookie(dev_info_t
*dip
, dev_info_t
*rdip
,
58 char *name
, ddi_eventcookie_t
*event_cookiep
);
60 static int nx1394_add_eventcall(dev_info_t
*dip
, dev_info_t
*rdip
,
61 ddi_eventcookie_t eventhdl
, void (*callback
)(), void *arg
,
62 ddi_callback_id_t
*cb_id
);
64 static int nx1394_remove_eventcall(dev_info_t
*dip
, ddi_callback_id_t cb_id
);
66 static int nx1394_post_event(dev_info_t
*dip
, dev_info_t
*rdip
,
67 ddi_eventcookie_t eventhdl
, void *impl_data
);
69 struct bus_ops nx1394_busops
= {
71 nullbusmap
, /* bus_map */
72 NULL
, /* bus_get_intrspec */
73 NULL
, /* bus_add_intrspec */
74 NULL
, /* bus_remove_intrspec */
75 i_ddi_map_fault
, /* XXXX bus_map_fault */
76 NULL
, /* bus_dma_map */
83 ddi_dma_mctl
, /* bus_dma_ctl */
84 nx1394_bus_ctl
, /* bus_ctl */
85 ddi_bus_prop_op
, /* bus_prop_op */
86 nx1394_get_event_cookie
, /* (*bus_get_eventcookie() */
87 nx1394_add_eventcall
, /* (*bus_add_eventcall)(); */
88 nx1394_remove_eventcall
, /* (*bus_remove_eventcall)(); */
89 nx1394_post_event
, /* (*bus_post_event)(); */
90 0, /* (*interrupt control)(); */
91 0, /* (*bus_config)(); */
92 0, /* (*bus_unconfig)(); */
93 0, /* (*bus_fm_init)(); */
94 0, /* (*bus_fm_fini)(); */
95 0, /* (*bus_fm_access_enter)(); */
96 0, /* (*bus_fm_access_exit)(); */
97 0, /* (*bus_power)(); */
98 i_ddi_intr_ops
/* (*bus_intr_op)(); */
102 * removal/insertion/reset events
104 #define NX1394_EVENT_TAG_HOT_REMOVAL 0
105 #define NX1394_EVENT_TAG_HOT_INSERTION 1
106 #define NX1394_EVENT_TAG_BUS_RESET 2
108 static ndi_event_definition_t nx1394_event_defs
[] = {
109 {NX1394_EVENT_TAG_HOT_REMOVAL
, DDI_DEVI_REMOVE_EVENT
, EPL_KERNEL
,
110 NDI_EVENT_POST_TO_TGT
},
111 {NX1394_EVENT_TAG_HOT_INSERTION
, DDI_DEVI_INSERT_EVENT
, EPL_KERNEL
,
112 NDI_EVENT_POST_TO_TGT
},
113 {NX1394_EVENT_TAG_BUS_RESET
, DDI_DEVI_BUS_RESET_EVENT
, EPL_KERNEL
,
114 NDI_EVENT_POST_TO_ALL
},
117 #define NX1394_N_EVENTS \
118 (sizeof (nx1394_event_defs) / sizeof (ndi_event_definition_t))
120 static ndi_event_set_t nx1394_events
= {
121 NDI_EVENTS_REV1
, NX1394_N_EVENTS
, nx1394_event_defs
126 * This routine implements nexus bus ctl operations. Of importance are
127 * DDI_CTLOPS_REPORTDEV, DDI_CTLOPS_INITCHILD, DDI_CTLOPS_UNINITCHILD
128 * and DDI_CTLOPS_POWER. For DDI_CTLOPS_INITCHILD, it tries to lookup
129 * reg property on the child node and builds and sets the name
130 * (name is of the form GGGGGGGGGGGGGGGG[,AAAAAAAAAAAA], where
131 * GGGGGGGGGGGGGGGG is the GUID and AAAAAAAAAAAA is the optional unit
135 nx1394_bus_ctl(dev_info_t
*dip
, dev_info_t
*rdip
, ddi_ctl_enum_t op
, void *arg
,
140 TNF_PROBE_0_DEBUG(nx1394_bus_ctl_enter
, S1394_TNF_SL_NEXUS_STACK
, "");
143 case DDI_CTLOPS_REPORTDEV
: {
144 dev_info_t
*pdip
= ddi_get_parent(rdip
);
145 cmn_err(CE_CONT
, "?%s%d at %s%d",
146 ddi_node_name(rdip
), ddi_get_instance(rdip
),
147 ddi_node_name(pdip
), ddi_get_instance(pdip
));
148 TNF_PROBE_0_DEBUG(nx1394_bus_ctl_exit
, S1394_TNF_SL_NEXUS_STACK
,
150 return (DDI_SUCCESS
);
153 case DDI_CTLOPS_INITCHILD
: {
154 dev_info_t
*ocdip
, *cdip
= (dev_info_t
*)arg
;
155 dev_info_t
*pdip
= ddi_get_parent(cdip
);
158 char addr
[MAXNAMELEN
];
160 TNF_PROBE_1(nx1394_bus_ctl_init_child
,
161 S1394_TNF_SL_HOTPLUG_STACK
, "", tnf_opaque
, dip
, cdip
);
163 i
= ddi_prop_lookup_int_array(DDI_DEV_T_ANY
, cdip
,
164 DDI_PROP_DONTPASS
, "reg", (int **)®ptr
,
167 if (i
!= DDI_PROP_SUCCESS
) {
168 cmn_err(CE_NOTE
, "!%s(%d): \"reg\" property not found",
169 ddi_node_name(cdip
), ddi_get_instance(cdip
));
170 TNF_PROBE_2(nx1394_bus_ctl
,
171 S1394_TNF_SL_NEXUS_ERROR
, "", tnf_string
, msg
,
172 "Reg property not found", tnf_int
, reason
, i
);
173 TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit
,
174 S1394_TNF_SL_NEXUS_STACK
, "", tnf_string
, op
,
176 return (DDI_NOT_WELL_FORMED
);
182 * addr is of the format GGGGGGGGGGGGGGGG[,AAAAAAAAAAAA]
184 if (regptr
[2] || regptr
[3]) {
185 (void) sprintf(addr
, "%08x%08x,%04x%08x", regptr
[0],
186 regptr
[1], regptr
[2], regptr
[3]);
188 (void) sprintf(addr
, "%08x%08x", regptr
[0], regptr
[1]);
190 ddi_prop_free(regptr
);
191 ddi_set_name_addr(cdip
, addr
);
194 * Check for a node with the same name & addr as the current
195 * node. If such a node exists, return failure.
197 if ((ocdip
= ndi_devi_find(pdip
, ddi_node_name(cdip
), addr
)) !=
198 NULL
&& ocdip
!= cdip
) {
200 "!%s(%d): Duplicate dev_info node found %s@%s",
201 ddi_node_name(cdip
), ddi_get_instance(cdip
),
202 ddi_node_name(ocdip
), addr
);
203 TNF_PROBE_1(nx1394_bus_ctl
,
204 S1394_TNF_SL_NEXUS_ERROR
, "", tnf_string
, msg
,
206 TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit
,
207 S1394_TNF_SL_NEXUS_STACK
, "", tnf_string
, op
,
209 ddi_set_name_addr(cdip
, NULL
);
210 return (DDI_NOT_WELL_FORMED
);
214 * If HAL (parent dip) has "active-dma-flush" property, then
215 * add property to child as well. Workaround for active
216 * context flushing bug in Schizo rev 2.1 and 2.2.
218 if (ddi_prop_exists(DDI_DEV_T_ANY
, pdip
, DDI_PROP_DONTPASS
,
219 "active-dma-flush") != 0) {
220 status
= ndi_prop_update_int(DDI_DEV_T_NONE
, cdip
,
221 "active-dma-flush", 1);
222 if (status
!= NDI_SUCCESS
) {
223 cmn_err(CE_NOTE
, "!%s(%d): Unable to add "
224 "\"active-dma-flush\" property",
226 ddi_get_instance(cdip
));
227 TNF_PROBE_1(nx1394_bus_ctl
,
228 S1394_TNF_SL_NEXUS_ERROR
, "", tnf_string
,
229 msg
, "Unable to add \"active-dma-flush\" "
231 TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit
,
232 S1394_TNF_SL_NEXUS_STACK
, "", tnf_string
,
234 ddi_set_name_addr(cdip
, NULL
);
235 return (DDI_NOT_WELL_FORMED
);
239 TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit
,
240 S1394_TNF_SL_NEXUS_STACK
, "", tnf_string
, op
, "initchild");
241 return (DDI_SUCCESS
);
244 case DDI_CTLOPS_UNINITCHILD
: {
245 ddi_prop_remove_all((dev_info_t
*)arg
);
246 ddi_set_name_addr((dev_info_t
*)arg
, NULL
);
247 TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit
, S1394_TNF_SL_NEXUS_STACK
,
248 "", tnf_string
, op
, "uninitchild");
249 return (DDI_SUCCESS
);
252 case DDI_CTLOPS_IOMIN
: {
253 status
= ddi_ctlops(dip
, rdip
, op
, arg
, result
);
254 TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit
, S1394_TNF_SL_NEXUS_STACK
,
255 "", tnf_string
, op
, "iomin");
259 case DDI_CTLOPS_POWER
: {
260 return (DDI_SUCCESS
);
264 * These ops correspond to functions that "shouldn't" be called
265 * by a 1394 client driver.
267 case DDI_CTLOPS_DMAPMAPC
:
268 case DDI_CTLOPS_REPORTINT
:
269 case DDI_CTLOPS_REGSIZE
:
270 case DDI_CTLOPS_NREGS
:
271 case DDI_CTLOPS_SIDDEV
:
272 case DDI_CTLOPS_SLAVEONLY
:
273 case DDI_CTLOPS_AFFINITY
:
274 case DDI_CTLOPS_POKE
:
275 case DDI_CTLOPS_PEEK
: {
276 cmn_err(CE_CONT
, "!%s(%d): invalid op (%d) from %s(%d)",
277 ddi_node_name(dip
), ddi_get_instance(dip
),
278 op
, ddi_node_name(rdip
), ddi_get_instance(rdip
));
279 TNF_PROBE_2(nx1394_bus_ctl
, S1394_TNF_SL_NEXUS_ERROR
, "",
280 tnf_string
, msg
, "invalid op", tnf_int
, op
, op
);
281 TNF_PROBE_0_DEBUG(nx1394_bus_ctl_exit
, S1394_TNF_SL_NEXUS_STACK
,
283 return (DDI_FAILURE
);
287 * Everything else (e.g. PTOB/BTOP/BTOPR requests) we pass up
290 status
= ddi_ctlops(dip
, rdip
, op
, arg
, result
);
291 TNF_PROBE_0_DEBUG(nx1394_bus_ctl_exit
, S1394_TNF_SL_NEXUS_STACK
,
299 * nx1394_dma_allochdl()
300 * Merges the ddi_dma_attr_t passed in by the target (using
301 * ddi_dma_alloc_handle() call) with that of the hal and passes the alloc
302 * handle request up the device by calling ddi_dma_allochdl().
305 nx1394_dma_allochdl(dev_info_t
*dip
, dev_info_t
*rdip
, ddi_dma_attr_t
*attr
,
306 int (*waitfnp
)(caddr_t
), caddr_t arg
, ddi_dma_handle_t
*handlep
)
309 ddi_dma_attr_t
*hal_attr
;
312 _NOTE(SCHEME_PROTECTS_DATA("unique (per thread)", ddi_dma_attr_t
))
314 TNF_PROBE_0_DEBUG(nx1394_dma_allochdl_enter
, S1394_TNF_SL_NEXUS_STACK
,
318 * If hal calls ddi_dma_alloc_handle, dip == rdip == hal dip.
319 * Unfortunately, we cannot verify this (by way of looking up for hal
320 * dip) here because h1394_attach() may happen much later.
323 hal
= s1394_dip_to_hal(ddi_get_parent(rdip
));
325 hal_attr
= &hal
->halinfo
.dma_attr
;
327 ddi_dma_attr_merge(attr
, hal_attr
);
329 status
= ddi_dma_allochdl(dip
, rdip
, attr
, waitfnp
, arg
, handlep
);
330 TNF_PROBE_1_DEBUG(nx1394_dma_allochdl_exit
, S1394_TNF_SL_NEXUS_STACK
,
331 "", tnf_int
, status
, status
);
336 * nx1394_get_event_cookie()
337 * Called when a child node calls ddi_get_eventcookie().
338 * Returns event cookie corresponding to event "name".
341 nx1394_get_event_cookie(dev_info_t
*dip
, dev_info_t
*rdip
, char *name
,
342 ddi_eventcookie_t
*event_cookiep
)
347 TNF_PROBE_1_DEBUG(nx1394_get_event_cookie_enter
,
348 S1394_TNF_SL_NEXUS_STACK
, "", tnf_string
, name
, name
);
350 hal
= s1394_dip_to_hal(dip
);
353 ret
= ndi_event_retrieve_cookie(hal
->hal_ndi_event_hdl
,
354 rdip
, name
, event_cookiep
, 0);
356 TNF_PROBE_4_DEBUG(nx1394_get_event_cookie_exit
,
357 S1394_TNF_SL_NEXUS_STACK
, "", tnf_opaque
, parent_dip
, (void *)dip
,
358 tnf_opaque
, requestor_dip
, (void *)rdip
, tnf_string
, event_name
,
359 name
, tnf_int
, request_status
, ret
);
366 * nx1394_add_eventcall()
367 * This gets called when a child node calls ddi_add_eventcall(). Registers
368 * the specified callback for the requested event cookie with the ndi
370 * dip is the hal dip. This routine calls ndi_event_add_callback(),
371 * allowing requests for events we don't generate to pass up the tree.
374 nx1394_add_eventcall(dev_info_t
*dip
, dev_info_t
*rdip
,
375 ddi_eventcookie_t cookie
, void (*callback
)(), void *arg
,
376 ddi_callback_id_t
*cb_id
)
381 char *event_name
= NULL
;
384 hal
= s1394_dip_to_hal(dip
);
387 TNF_PROBE_0_DEBUG(nx1394_add_eventcall_enter
, S1394_TNF_SL_NEXUS_STACK
,
390 ret
= ndi_event_add_callback(hal
->hal_ndi_event_hdl
, rdip
, cookie
,
391 callback
, arg
, NDI_NOSLEEP
, cb_id
);
393 event_name
= ndi_event_cookie_to_name(hal
->hal_ndi_event_hdl
, cookie
);
394 if (event_name
== NULL
)
397 TNF_PROBE_4_DEBUG(nx1394_add_eventcall_exit
, S1394_TNF_SL_NEXUS_STACK
,
398 "", tnf_opaque
, parent_dip
, (void *)dip
, tnf_opaque
, requestor_dip
,
399 (void *)rdip
, tnf_string
, event_name
, event_name
, tnf_int
,
400 request_status
, ret
);
406 * nx1394_remove_eventcall()
407 * Called as a result of a child node calling ddi_remove_eventcall().
408 * Unregisters the callback corresponding to the callback id passed in.
411 nx1394_remove_eventcall(dev_info_t
*dip
, ddi_callback_id_t cb_id
)
415 ddi_eventcookie_t cookie
;
417 char *event_name
= NULL
;
421 cookie
= ((ndi_event_callbacks_t
*)cb_id
)->ndi_evtcb_cookie
;
423 hal
= s1394_dip_to_hal(dip
);
426 TNF_PROBE_0_DEBUG(nx1394_remove_eventcall_enter
,
427 S1394_TNF_SL_NEXUS_STACK
, "");
429 ret
= ndi_event_remove_callback(hal
->hal_ndi_event_hdl
, cb_id
);
432 event_name
= ndi_event_cookie_to_name(hal
->hal_ndi_event_hdl
, cookie
);
433 if (event_name
== NULL
)
436 TNF_PROBE_4_DEBUG(nx1394_remove_eventcall_exit
,
437 S1394_TNF_SL_NEXUS_STACK
, "", tnf_opaque
, parent_dip
, (void *)dip
,
438 tnf_opaque
, callback_id
, (void *)cb_id
, tnf_string
, event_name
,
439 event_name
, tnf_int
, request_status
, ret
);
446 * nx1394_post_event()
447 * Called when a child node calls ddi_post_event. If the event is one of
448 * the events supported by us (bus reset/insert/remove, for now), builds
449 * a t1394_localinfo_t structure and calls ndi_event_run_callbacks(). This
450 * will result in all registered callbacks being invoked with
451 * t1394_localinfo_t as the impl_data. (see ddi_add_eventcall for callback
452 * arguments.) If the event is not defined by us, the request is
453 * propagated up the device tree by calling ndi_post_event().
456 nx1394_post_event(dev_info_t
*dip
, dev_info_t
*rdip
, ddi_eventcookie_t cookie
,
462 t1394_localinfo_t localinfo
;
464 hal
= s1394_dip_to_hal(dip
);
467 TNF_PROBE_0_DEBUG(nx1394_post_event_enter
, S1394_TNF_SL_NEXUS_STACK
,
470 name
= ndi_event_cookie_to_name(hal
->hal_ndi_event_hdl
, cookie
);
471 /* name is NULL if we don't generate the event */
474 mutex_enter(&hal
->topology_tree_mutex
);
475 localinfo
.bus_generation
= hal
->generation_count
;
476 localinfo
.local_nodeID
= hal
->node_id
;
477 mutex_exit(&hal
->topology_tree_mutex
);
478 impl_data
= &localinfo
;
480 ret
= ndi_event_run_callbacks(hal
->hal_ndi_event_hdl
,
481 rdip
, cookie
, impl_data
);
483 TNF_PROBE_4_DEBUG(nx1394_post_event_exit
,
484 S1394_TNF_SL_NEXUS_STACK
, "", tnf_opaque
, parent_dip
,
485 (void *)dip
, tnf_opaque
, requestor_dip
, (void *)rdip
,
486 tnf_string
, event_name
, name
, tnf_int
, request_status
, ret
);
490 ret
= ndi_post_event(ddi_get_parent(dip
), rdip
, cookie
,
492 TNF_PROBE_2_DEBUG(nx1394_post_event_exit
,
493 S1394_TNF_SL_NEXUS_STACK
, "", tnf_string
, msg
,
494 "Not our event", tnf_int
, ret
, ret
);
500 * nx1394_define_events()
501 * Allocates event handle for the hal dip and binds event set to it.
504 nx1394_define_events(s1394_hal_t
*hal
)
508 TNF_PROBE_0_DEBUG(nx1394_define_events_enter
, S1394_TNF_SL_NEXUS_STACK
,
511 /* get event handle */
512 ret
= ndi_event_alloc_hdl(hal
->halinfo
.dip
, hal
->halinfo
.hw_interrupt
,
513 &hal
->hal_ndi_event_hdl
, NDI_SLEEP
);
514 if (ret
!= NDI_SUCCESS
) {
515 TNF_PROBE_1(nx1394_define_events_alloc_fail
,
516 S1394_TNF_SL_NEXUS_ERROR
, "", tnf_int
, ret
, ret
);
519 ret
= ndi_event_bind_set(hal
->hal_ndi_event_hdl
, &nx1394_events
,
521 if (ret
!= NDI_SUCCESS
) {
522 TNF_PROBE_1(nx1394_define_events_bind_fail
,
523 S1394_TNF_SL_NEXUS_ERROR
, "", tnf_int
, ret
, ret
);
524 (void) ndi_event_free_hdl(hal
->hal_ndi_event_hdl
);
525 TNF_PROBE_0_DEBUG(nx1394_define_events_exit
,
526 S1394_TNF_SL_NEXUS_STACK
, "");
527 return (DDI_FAILURE
);
531 TNF_PROBE_0_DEBUG(nx1394_define_events_exit
, S1394_TNF_SL_NEXUS_STACK
,
534 return (DDI_SUCCESS
);
538 * nx1394_undefine_events()
539 * Unbinds event set bound to the hal and frees the event handle.
542 nx1394_undefine_events(s1394_hal_t
*hal
)
546 TNF_PROBE_0_DEBUG(nx1394_undefine_events_enter
,
547 S1394_TNF_SL_NEXUS_STACK
, "");
549 ret
= ndi_event_unbind_set(hal
->hal_ndi_event_hdl
, &nx1394_events
,
551 if (ret
!= NDI_SUCCESS
) {
552 TNF_PROBE_1(nx1394_undefine_events_unbind_fail
,
553 S1394_TNF_SL_NEXUS_ERROR
, "", tnf_int
, ret
, ret
);
555 ret
= ndi_event_free_hdl(hal
->hal_ndi_event_hdl
);
556 if (ret
!= NDI_SUCCESS
) {
557 TNF_PROBE_1(nx1394_undefine_events_free_hdl_fail
,
558 S1394_TNF_SL_NEXUS_ERROR
, "", tnf_int
, ret
, ret
);
562 TNF_PROBE_0_DEBUG(nx1394_undefine_events_exit
,
563 S1394_TNF_SL_NEXUS_STACK
, "");