5255 uts shouldn't open-code ISP2
[illumos-gate.git] / usr / src / uts / common / io / 1394 / nx1394.c
blob216b70a319e507b74502537df4e060c01f7b41dc
1 /*
2 * CDDL HEADER START
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
7 * with the License.
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]
20 * CDDL HEADER END
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.
31 * nx1394.c
32 * 1394 Services Layer Nexus Support Routines
33 * Routines in this file implement nexus bus_ops.
36 #include <sys/conf.h>
37 #include <sys/ddi.h>
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 = {
70 BUSO_REV,
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 */
77 nx1394_dma_allochdl,
78 ddi_dma_freehdl,
79 ddi_dma_bindhdl,
80 ddi_dma_unbindhdl,
81 ddi_dma_flush,
82 ddi_dma_win,
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
125 * nx1394_bus_ctl()
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
132 * address).
134 static int
135 nx1394_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op, void *arg,
136 void *result)
138 int status;
140 TNF_PROBE_0_DEBUG(nx1394_bus_ctl_enter, S1394_TNF_SL_NEXUS_STACK, "");
142 switch (op) {
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,
149 "");
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);
156 int reglen, i;
157 uint32_t *regptr;
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 **)&regptr,
165 (uint_t *)&reglen);
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,
175 "initchild");
176 return (DDI_NOT_WELL_FORMED);
179 ASSERT(reglen != 0);
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]);
187 } else {
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) {
199 cmn_err(CE_NOTE,
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,
205 "Duplicate nodes");
206 TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit,
207 S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op,
208 "initchild");
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",
225 ddi_node_name(cdip),
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\" "
230 "property");
231 TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit,
232 S1394_TNF_SL_NEXUS_STACK, "", tnf_string,
233 op, "initchild");
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");
256 return (status);
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,
282 "");
283 return (DDI_FAILURE);
287 * Everything else (e.g. PTOB/BTOP/BTOPR requests) we pass up
289 default: {
290 status = ddi_ctlops(dip, rdip, op, arg, result);
291 TNF_PROBE_0_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK,
292 "");
293 return (status);
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().
304 static int
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)
308 s1394_hal_t *hal;
309 ddi_dma_attr_t *hal_attr;
310 int status;
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,
315 "");
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.
322 if (dip != rdip) {
323 hal = s1394_dip_to_hal(ddi_get_parent(rdip));
324 ASSERT(hal);
325 hal_attr = &hal->halinfo.dma_attr;
326 ASSERT(hal_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);
332 return (status);
336 * nx1394_get_event_cookie()
337 * Called when a child node calls ddi_get_eventcookie().
338 * Returns event cookie corresponding to event "name".
340 static int
341 nx1394_get_event_cookie(dev_info_t *dip, dev_info_t *rdip, char *name,
342 ddi_eventcookie_t *event_cookiep)
344 int ret;
345 s1394_hal_t *hal;
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);
351 ASSERT(hal);
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);
361 return (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
369 * event framework.
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.
373 static int
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)
378 int ret;
379 s1394_hal_t *hal;
380 #if defined(DEBUG)
381 char *event_name = NULL;
382 #endif
384 hal = s1394_dip_to_hal(dip);
385 ASSERT(hal);
387 TNF_PROBE_0_DEBUG(nx1394_add_eventcall_enter, S1394_TNF_SL_NEXUS_STACK,
388 "");
390 ret = ndi_event_add_callback(hal->hal_ndi_event_hdl, rdip, cookie,
391 callback, arg, NDI_NOSLEEP, cb_id);
392 #if defined(DEBUG)
393 event_name = ndi_event_cookie_to_name(hal->hal_ndi_event_hdl, cookie);
394 if (event_name == NULL)
395 event_name = "";
396 #endif
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);
402 return (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.
410 static int
411 nx1394_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id)
413 int ret;
414 s1394_hal_t *hal;
415 ddi_eventcookie_t cookie;
416 #if defined(DEBUG)
417 char *event_name = NULL;
418 #endif
420 ASSERT(cb_id);
421 cookie = ((ndi_event_callbacks_t *)cb_id)->ndi_evtcb_cookie;
423 hal = s1394_dip_to_hal(dip);
424 ASSERT(hal);
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);
431 #if defined(DEBUG)
432 event_name = ndi_event_cookie_to_name(hal->hal_ndi_event_hdl, cookie);
433 if (event_name == NULL)
434 event_name = "";
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);
440 #endif
442 return (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().
455 static int
456 nx1394_post_event(dev_info_t *dip, dev_info_t *rdip, ddi_eventcookie_t cookie,
457 void *impl_data)
459 int ret;
460 char *name;
461 s1394_hal_t *hal;
462 t1394_localinfo_t localinfo;
464 hal = s1394_dip_to_hal(dip);
465 ASSERT(hal);
467 TNF_PROBE_0_DEBUG(nx1394_post_event_enter, S1394_TNF_SL_NEXUS_STACK,
468 "");
470 name = ndi_event_cookie_to_name(hal->hal_ndi_event_hdl, cookie);
471 /* name is NULL if we don't generate the event */
472 if (name != NULL) {
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);
487 return (ret);
489 } else {
490 ret = ndi_post_event(ddi_get_parent(dip), rdip, cookie,
491 impl_data);
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);
495 return (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)
506 int ret;
508 TNF_PROBE_0_DEBUG(nx1394_define_events_enter, S1394_TNF_SL_NEXUS_STACK,
509 "");
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);
517 } else {
518 /* and bind to it */
519 ret = ndi_event_bind_set(hal->hal_ndi_event_hdl, &nx1394_events,
520 NDI_SLEEP);
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,
532 "");
534 return (DDI_SUCCESS);
538 * nx1394_undefine_events()
539 * Unbinds event set bound to the hal and frees the event handle.
541 void
542 nx1394_undefine_events(s1394_hal_t *hal)
544 int ret;
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,
550 NDI_SLEEP);
551 if (ret != NDI_SUCCESS) {
552 TNF_PROBE_1(nx1394_undefine_events_unbind_fail,
553 S1394_TNF_SL_NEXUS_ERROR, "", tnf_int, ret, ret);
554 } else {
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, "");