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
,
141 case DDI_CTLOPS_REPORTDEV
: {
142 dev_info_t
*pdip
= ddi_get_parent(rdip
);
143 cmn_err(CE_CONT
, "?%s%d at %s%d",
144 ddi_node_name(rdip
), ddi_get_instance(rdip
),
145 ddi_node_name(pdip
), ddi_get_instance(pdip
));
146 return (DDI_SUCCESS
);
149 case DDI_CTLOPS_INITCHILD
: {
150 dev_info_t
*ocdip
, *cdip
= (dev_info_t
*)arg
;
151 dev_info_t
*pdip
= ddi_get_parent(cdip
);
154 char addr
[MAXNAMELEN
];
156 i
= ddi_prop_lookup_int_array(DDI_DEV_T_ANY
, cdip
,
157 DDI_PROP_DONTPASS
, "reg", (int **)®ptr
,
160 if (i
!= DDI_PROP_SUCCESS
) {
161 cmn_err(CE_NOTE
, "!%s(%d): \"reg\" property not found",
162 ddi_node_name(cdip
), ddi_get_instance(cdip
));
163 return (DDI_NOT_WELL_FORMED
);
169 * addr is of the format GGGGGGGGGGGGGGGG[,AAAAAAAAAAAA]
171 if (regptr
[2] || regptr
[3]) {
172 (void) sprintf(addr
, "%08x%08x,%04x%08x", regptr
[0],
173 regptr
[1], regptr
[2], regptr
[3]);
175 (void) sprintf(addr
, "%08x%08x", regptr
[0], regptr
[1]);
177 ddi_prop_free(regptr
);
178 ddi_set_name_addr(cdip
, addr
);
181 * Check for a node with the same name & addr as the current
182 * node. If such a node exists, return failure.
184 if ((ocdip
= ndi_devi_find(pdip
, ddi_node_name(cdip
), addr
)) !=
185 NULL
&& ocdip
!= cdip
) {
187 "!%s(%d): Duplicate dev_info node found %s@%s",
188 ddi_node_name(cdip
), ddi_get_instance(cdip
),
189 ddi_node_name(ocdip
), addr
);
190 ddi_set_name_addr(cdip
, NULL
);
191 return (DDI_NOT_WELL_FORMED
);
195 * If HAL (parent dip) has "active-dma-flush" property, then
196 * add property to child as well. Workaround for active
197 * context flushing bug in Schizo rev 2.1 and 2.2.
199 if (ddi_prop_exists(DDI_DEV_T_ANY
, pdip
, DDI_PROP_DONTPASS
,
200 "active-dma-flush") != 0) {
201 status
= ndi_prop_update_int(DDI_DEV_T_NONE
, cdip
,
202 "active-dma-flush", 1);
203 if (status
!= NDI_SUCCESS
) {
204 cmn_err(CE_NOTE
, "!%s(%d): Unable to add "
205 "\"active-dma-flush\" property",
207 ddi_get_instance(cdip
));
208 ddi_set_name_addr(cdip
, NULL
);
209 return (DDI_NOT_WELL_FORMED
);
213 return (DDI_SUCCESS
);
216 case DDI_CTLOPS_UNINITCHILD
: {
217 ddi_prop_remove_all((dev_info_t
*)arg
);
218 ddi_set_name_addr((dev_info_t
*)arg
, NULL
);
219 return (DDI_SUCCESS
);
222 case DDI_CTLOPS_IOMIN
: {
223 status
= ddi_ctlops(dip
, rdip
, op
, arg
, result
);
227 case DDI_CTLOPS_POWER
: {
228 return (DDI_SUCCESS
);
232 * These ops correspond to functions that "shouldn't" be called
233 * by a 1394 client driver.
235 case DDI_CTLOPS_DMAPMAPC
:
236 case DDI_CTLOPS_REPORTINT
:
237 case DDI_CTLOPS_REGSIZE
:
238 case DDI_CTLOPS_NREGS
:
239 case DDI_CTLOPS_SIDDEV
:
240 case DDI_CTLOPS_SLAVEONLY
:
241 case DDI_CTLOPS_AFFINITY
:
242 case DDI_CTLOPS_POKE
:
243 case DDI_CTLOPS_PEEK
: {
244 cmn_err(CE_CONT
, "!%s(%d): invalid op (%d) from %s(%d)",
245 ddi_node_name(dip
), ddi_get_instance(dip
),
246 op
, ddi_node_name(rdip
), ddi_get_instance(rdip
));
247 return (DDI_FAILURE
);
251 * Everything else (e.g. PTOB/BTOP/BTOPR requests) we pass up
254 status
= ddi_ctlops(dip
, rdip
, op
, arg
, result
);
261 * nx1394_dma_allochdl()
262 * Merges the ddi_dma_attr_t passed in by the target (using
263 * ddi_dma_alloc_handle() call) with that of the hal and passes the alloc
264 * handle request up the device by calling ddi_dma_allochdl().
267 nx1394_dma_allochdl(dev_info_t
*dip
, dev_info_t
*rdip
, ddi_dma_attr_t
*attr
,
268 int (*waitfnp
)(caddr_t
), caddr_t arg
, ddi_dma_handle_t
*handlep
)
271 ddi_dma_attr_t
*hal_attr
;
274 _NOTE(SCHEME_PROTECTS_DATA("unique (per thread)", ddi_dma_attr_t
))
277 * If hal calls ddi_dma_alloc_handle, dip == rdip == hal dip.
278 * Unfortunately, we cannot verify this (by way of looking up for hal
279 * dip) here because h1394_attach() may happen much later.
282 hal
= s1394_dip_to_hal(ddi_get_parent(rdip
));
284 hal_attr
= &hal
->halinfo
.dma_attr
;
286 ddi_dma_attr_merge(attr
, hal_attr
);
288 status
= ddi_dma_allochdl(dip
, rdip
, attr
, waitfnp
, arg
, handlep
);
293 * nx1394_get_event_cookie()
294 * Called when a child node calls ddi_get_eventcookie().
295 * Returns event cookie corresponding to event "name".
298 nx1394_get_event_cookie(dev_info_t
*dip
, dev_info_t
*rdip
, char *name
,
299 ddi_eventcookie_t
*event_cookiep
)
304 hal
= s1394_dip_to_hal(dip
);
307 ret
= ndi_event_retrieve_cookie(hal
->hal_ndi_event_hdl
,
308 rdip
, name
, event_cookiep
, 0);
315 * nx1394_add_eventcall()
316 * This gets called when a child node calls ddi_add_eventcall(). Registers
317 * the specified callback for the requested event cookie with the ndi
319 * dip is the hal dip. This routine calls ndi_event_add_callback(),
320 * allowing requests for events we don't generate to pass up the tree.
323 nx1394_add_eventcall(dev_info_t
*dip
, dev_info_t
*rdip
,
324 ddi_eventcookie_t cookie
, void (*callback
)(), void *arg
,
325 ddi_callback_id_t
*cb_id
)
330 char *event_name
= NULL
;
333 hal
= s1394_dip_to_hal(dip
);
336 ret
= ndi_event_add_callback(hal
->hal_ndi_event_hdl
, rdip
, cookie
,
337 callback
, arg
, NDI_NOSLEEP
, cb_id
);
339 event_name
= ndi_event_cookie_to_name(hal
->hal_ndi_event_hdl
, cookie
);
340 if (event_name
== NULL
)
348 * nx1394_remove_eventcall()
349 * Called as a result of a child node calling ddi_remove_eventcall().
350 * Unregisters the callback corresponding to the callback id passed in.
353 nx1394_remove_eventcall(dev_info_t
*dip
, ddi_callback_id_t cb_id
)
357 ddi_eventcookie_t cookie
;
359 char *event_name
= NULL
;
363 cookie
= ((ndi_event_callbacks_t
*)cb_id
)->ndi_evtcb_cookie
;
365 hal
= s1394_dip_to_hal(dip
);
368 ret
= ndi_event_remove_callback(hal
->hal_ndi_event_hdl
, cb_id
);
371 event_name
= ndi_event_cookie_to_name(hal
->hal_ndi_event_hdl
, cookie
);
372 if (event_name
== NULL
)
381 * nx1394_post_event()
382 * Called when a child node calls ddi_post_event. If the event is one of
383 * the events supported by us (bus reset/insert/remove, for now), builds
384 * a t1394_localinfo_t structure and calls ndi_event_run_callbacks(). This
385 * will result in all registered callbacks being invoked with
386 * t1394_localinfo_t as the impl_data. (see ddi_add_eventcall for callback
387 * arguments.) If the event is not defined by us, the request is
388 * propagated up the device tree by calling ndi_post_event().
391 nx1394_post_event(dev_info_t
*dip
, dev_info_t
*rdip
, ddi_eventcookie_t cookie
,
397 t1394_localinfo_t localinfo
;
399 hal
= s1394_dip_to_hal(dip
);
402 name
= ndi_event_cookie_to_name(hal
->hal_ndi_event_hdl
, cookie
);
403 /* name is NULL if we don't generate the event */
406 mutex_enter(&hal
->topology_tree_mutex
);
407 localinfo
.bus_generation
= hal
->generation_count
;
408 localinfo
.local_nodeID
= hal
->node_id
;
409 mutex_exit(&hal
->topology_tree_mutex
);
410 impl_data
= &localinfo
;
412 ret
= ndi_event_run_callbacks(hal
->hal_ndi_event_hdl
,
413 rdip
, cookie
, impl_data
);
418 ret
= ndi_post_event(ddi_get_parent(dip
), rdip
, cookie
,
425 * nx1394_define_events()
426 * Allocates event handle for the hal dip and binds event set to it.
429 nx1394_define_events(s1394_hal_t
*hal
)
433 /* get event handle */
434 ret
= ndi_event_alloc_hdl(hal
->halinfo
.dip
, hal
->halinfo
.hw_interrupt
,
435 &hal
->hal_ndi_event_hdl
, NDI_SLEEP
);
436 if (ret
!= NDI_SUCCESS
) {
439 ret
= ndi_event_bind_set(hal
->hal_ndi_event_hdl
, &nx1394_events
,
441 if (ret
!= NDI_SUCCESS
) {
442 (void) ndi_event_free_hdl(hal
->hal_ndi_event_hdl
);
443 return (DDI_FAILURE
);
447 return (DDI_SUCCESS
);
451 * nx1394_undefine_events()
452 * Unbinds event set bound to the hal and frees the event handle.
455 nx1394_undefine_events(s1394_hal_t
*hal
)
459 ret
= ndi_event_unbind_set(hal
->hal_ndi_event_hdl
, &nx1394_events
,
461 if (ret
!= NDI_SUCCESS
) {
463 ret
= ndi_event_free_hdl(hal
->hal_ndi_event_hdl
);
464 if (ret
!= NDI_SUCCESS
) {