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 * Safari Configurator (gptwocfg)
31 #include <sys/types.h>
36 #include <sys/cmn_err.h>
38 #include <sys/sunddi.h>
39 #include <sys/sunndi.h>
40 #include <sys/modctl.h>
42 #include <sys/param.h>
43 #include <sys/autoconf.h>
44 #include <sys/ksynch.h>
45 #include <sys/promif.h>
46 #include <sys/ndi_impldefs.h>
47 #include <sys/ddi_impldefs.h>
48 #include <sys/gp2cfg.h>
49 #include <sys/machsystm.h>
50 #include <sys/platform_module.h>
51 #pragma weak starcat_dr_name
54 int gptwocfg_debug
= 0;
56 static void debug(char *, uintptr_t, uintptr_t,
57 uintptr_t, uintptr_t, uintptr_t);
59 #define GPTWO_DEBUG0(level, flag, s) if (gptwocfg_debug >= level) \
61 #define GPTWO_DEBUG1(level, flag, fmt, a1) if (gptwocfg_debug >= level) \
62 debug(fmt, (uintptr_t)(a1), 0, 0, 0, 0);
63 #define GPTWO_DEBUG2(level, flag, fmt, a1, a2) if (gptwocfg_debug >= level) \
64 debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), 0, 0, 0);
65 #define GPTWO_DEBUG3(level, flag, fmt, a1, a2, a3) \
66 if (gptwocfg_debug >= level) \
67 debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), (uintptr_t)(a3), 0, 0);
69 #define GPTWO_DEBUG0(level, flag, s)
70 #define GPTWO_DEBUG1(level, flag, fmt, a1)
71 #define GPTWO_DEBUG2(level, flag, fmt, a1, a2)
72 #define GPTWO_DEBUG3(level, flag, fmt, a1, a2, a3)
75 kmutex_t gptwo_handle_list_lock
;
76 gptwocfg_handle_list_t
*gptwocfg_handle_list
;
78 static kmutex_t gptwo_config_list_lock
;
79 static gptwocfg_config_t
*gptwo_config_list
;
81 static gptwo_new_nodes_t
*
82 gptwocfg_get_obp_created_nodes(dev_info_t
*, uint_t
);
84 void (*gptwocfg_unclaim_address
)(uint_t
);
86 extern caddr_t efcode_vaddr
;
87 extern int efcode_size
;
89 #define GPTWO_NUMBER_OF_DEVICE_TYPES 6
91 static kmutex_t gptwocfg_ops_table_lock
;
92 gptwocfg_ops_t
*gptwocfg_ops_table
[GPTWO_NUMBER_OF_DEVICE_TYPES
];
95 * Module linkage information for the kernel.
98 extern struct mod_ops mod_miscops
;
100 static struct modlmisc modlmisc
= {
101 &mod_miscops
, /* Type of module */
102 "gptwo configurator",
105 static struct modlinkage modlinkage
= {
106 MODREV_1
, (void *)&modlmisc
, NULL
114 GPTWO_DEBUG0(1, CE_WARN
, "gptwocfg (Safari Configurator) "
115 "has been loaded\n");
117 mutex_init(&gptwo_config_list_lock
, NULL
, MUTEX_DRIVER
, NULL
);
118 mutex_init(&gptwocfg_ops_table_lock
, NULL
, MUTEX_DRIVER
, NULL
);
119 gptwo_config_list
= NULL
;
121 mutex_init(&gptwo_handle_list_lock
, NULL
, MUTEX_DRIVER
, NULL
);
122 gptwocfg_handle_list
= NULL
;
124 for (i
= 0; i
< GPTWO_NUMBER_OF_DEVICE_TYPES
; i
++)
125 gptwocfg_ops_table
[i
] = NULL
;
127 return (mod_install(&modlinkage
));
135 error
= mod_remove(&modlinkage
);
139 mutex_destroy(&gptwo_config_list_lock
);
140 mutex_destroy(&gptwocfg_ops_table_lock
);
141 mutex_destroy(&gptwo_handle_list_lock
);
148 struct modinfo
*modinfop
;
150 return (mod_info(&modlinkage
, modinfop
));
154 gptwocfg_allocate_node_list(int number_of_nodes
)
156 gptwo_new_nodes_t
*gptwo_new_nodes
;
159 GPTWO_DEBUG1(1, CE_CONT
, "gptwocfg_allocate_node_list- %d nodes",
162 size
= sizeof (gptwo_new_nodes_t
) +
163 ((number_of_nodes
-1) * sizeof (dev_info_t
*));
165 gptwo_new_nodes
= kmem_zalloc(size
, KM_SLEEP
);
167 gptwo_new_nodes
->gptwo_number_of_nodes
= number_of_nodes
;
168 gptwo_new_nodes
->gptwo_version
= GP2_VERSION
;
170 GPTWO_DEBUG1(1, CE_CONT
, "gptwocfg_allocate_node_list- returned %p\n",
173 return (gptwo_new_nodes
);
177 gptwocfg_free_node_list(gptwo_new_nodes_t
*gptwo_new_nodes
)
181 GPTWO_DEBUG2(1, CE_CONT
, "gptwocfg_free_node_list- %p %d nodes",
182 gptwo_new_nodes
, gptwo_new_nodes
->gptwo_number_of_nodes
);
184 size
= sizeof (gptwo_new_nodes_t
) +
185 ((gptwo_new_nodes
->gptwo_number_of_nodes
- 1) *
186 sizeof (dev_info_t
*));
188 kmem_free(gptwo_new_nodes
, size
);
192 gptwocfg_register_ops(uint_t type
, gptwo_cfgfunc_t
*cfg_func
,
193 gptwo_uncfgfunc_t
*uncfg_func
)
195 /* KM_SLEEP guarantees success */
196 gptwocfg_ops_t
*ops
= kmem_zalloc(sizeof (gptwocfg_ops_t
), KM_SLEEP
);
198 GPTWO_DEBUG2(1, CE_CONT
, "gptwocfg_register_ops: type=%x ops=%lx\n",
200 ASSERT(type
< GPTWO_NUMBER_OF_DEVICE_TYPES
);
201 ops
->gptwocfg_type
= type
;
202 ops
->gptwocfg_version
= GPTWOCFG_OPS_VERSION
;
203 ops
->gptwocfg_configure
= cfg_func
;
204 ops
->gptwocfg_unconfigure
= uncfg_func
;
206 mutex_enter(&gptwocfg_ops_table_lock
);
207 gptwocfg_ops_table
[type
] = ops
;
208 mutex_exit(&gptwocfg_ops_table_lock
);
214 gptwocfg_unregister_ops(uint_t type
)
216 GPTWO_DEBUG1(1, CE_CONT
, "gptwocfg_unregister_ops: type=%x\n", type
);
218 ASSERT(type
< GPTWO_NUMBER_OF_DEVICE_TYPES
);
220 mutex_enter(&gptwocfg_ops_table_lock
);
221 kmem_free(gptwocfg_ops_table
[type
], sizeof (gptwocfg_ops_t
));
222 gptwocfg_ops_table
[type
] = NULL
;
223 mutex_exit(&gptwocfg_ops_table_lock
);
227 gptwocfg_configure(dev_info_t
*ap
, spcd_t
*pcd
, gptwo_aid_t id
)
229 gptwo_new_nodes_t
*new_nodes
= NULL
;
230 gptwocfg_config_t
*config
;
233 GPTWO_DEBUG3(1, CE_CONT
, "gptwocfg_configure: ap=0x%p pcd=%p id=%x\n",
237 * Look to see if the port is already configured.
239 mutex_enter(&gptwo_config_list_lock
);
240 config
= gptwo_config_list
;
241 while (config
!= NULL
) {
242 if (&starcat_dr_name
) {
243 if (starcat_dr_name(ddi_node_name(ap
)) < 0) {
244 config
= config
->gptwo_next
;
248 if (config
->gptwo_portid
== id
) {
249 cmn_err(CE_WARN
, "gptwocfg: gptwocfg_configure: "
250 "0x%x Port already configured\n", id
);
251 mutex_exit(&gptwo_config_list_lock
);
254 config
= config
->gptwo_next
;
256 mutex_exit(&gptwo_config_list_lock
);
259 GPTWO_DEBUG0(1, CE_CONT
, "gptwocfg_configure: pcd=NULL\n");
263 if ((pcd
->spcd_magic
!= PCD_MAGIC
) ||
264 (pcd
->spcd_version
!= PCD_VERSION
)) {
265 cmn_err(CE_WARN
, "gptwocfg: Invalid Port "
266 "Configuration Descriptor\n");
270 if (pcd
->spcd_ptype
>= GPTWO_NUMBER_OF_DEVICE_TYPES
) {
272 "gptwocfg: Invalid device type %x", pcd
->spcd_ptype
);
276 if (pcd
->spcd_prsv
!= SPCD_RSV_PASS
) {
278 "gptwocfg: Agent at ID %x has not passed test(s)\n", id
);
282 mutex_enter(&gptwocfg_ops_table_lock
);
284 ops
= gptwocfg_ops_table
[pcd
->spcd_ptype
];
287 cmn_err(CE_WARN
, "gptwocfg: Ops for type %x have not been "
288 "registered\n", pcd
->spcd_ptype
);
289 mutex_exit(&gptwocfg_ops_table_lock
);
293 if (ops
->gptwocfg_configure
== NULL
) {
294 cmn_err(CE_WARN
, "gptwocfg: no configure routine registered "
295 "for sfaari type %x\n", pcd
->spcd_ptype
);
296 mutex_exit(&gptwocfg_ops_table_lock
);
300 new_nodes
= ops
->gptwocfg_configure(ap
, pcd
, id
);
302 mutex_exit(&gptwocfg_ops_table_lock
);
304 if (new_nodes
!= NULL
) {
305 config
= kmem_zalloc(sizeof (gptwocfg_config_t
), KM_SLEEP
);
306 config
->gptwo_version
= GP2_VERSION
;
307 config
->gptwo_ap
= ap
;
308 config
->gptwo_portid
= id
;
309 config
->gptwo_nodes
= new_nodes
;
310 config
->gptwo_ops
= ops
;
313 * put config on config list
315 mutex_enter(&gptwo_config_list_lock
);
316 config
->gptwo_next
= gptwo_config_list
;
317 gptwo_config_list
= config
;
318 mutex_exit(&gptwo_config_list_lock
);
323 return ((gptwocfg_cookie_t
)config
);
327 gptwocfg_unconfigure(dev_info_t
*ap
, gptwo_aid_t id
)
332 gptwocfg_config_t
*config
, *temp
;
333 gptwo_new_nodes_t
*obp_nodes
;
336 GPTWO_DEBUG2(1, CE_CONT
, "gptwocfg_unconfigure: ap=0x%p id=0x%lx\n",
339 mutex_enter(&gptwo_config_list_lock
);
340 config
= gptwo_config_list
;
341 while (config
!= NULL
) {
342 if (config
->gptwo_portid
== id
) {
345 config
= config
->gptwo_next
;
347 mutex_exit(&gptwo_config_list_lock
);
349 if (config
== NULL
) {
351 * There is no config structure associated with this agent id
352 * so it was probably built by firmware at start of day. We
353 * need to create a config structure before we can continue.
355 GPTWO_DEBUG1(1, CE_CONT
, "gptwocfg_unconfigure: id=0x%lx "
356 "No config structure - Need to build one\n", id
);
358 obp_nodes
= gptwocfg_get_obp_created_nodes(ap
, id
);
360 if (obp_nodes
!= NULL
) {
361 config
= kmem_zalloc(sizeof (gptwocfg_config_t
),
363 config
->gptwo_version
= GP2_VERSION
;
364 config
->gptwo_ap
= ap
;
365 config
->gptwo_portid
= id
;
366 config
->gptwo_nodes
= obp_nodes
;
369 * put config on config list
371 mutex_enter(&gptwo_config_list_lock
);
372 config
->gptwo_next
= gptwo_config_list
;
373 gptwo_config_list
= config
;
374 mutex_exit(&gptwo_config_list_lock
);
376 cmn_err(CE_WARN
, "gptwocfg: gptwocfg_unconfigure: "
377 "No OBP created nodes for ap=0x%lx agent id=0x%x",
383 GPTWO_DEBUG1(1, CE_CONT
, "gptwocfg_unconfigure config=0x%lx\n",
386 ops
= config
->gptwo_ops
;
388 GPTWO_DEBUG1(1, CE_CONT
, "gptwocfg_unconfigure: ops=%lx\n", ops
);
390 ndi_devi_enter(ap
, &circ
);
392 for (i
= 0; i
< config
->gptwo_nodes
->gptwo_number_of_nodes
; i
++) {
393 dev_info_t
*fdip
= NULL
;
395 saf_dip
= config
->gptwo_nodes
->gptwo_nodes
[i
];
397 GPTWO_DEBUG1(1, CE_CONT
, "gptwocfg_unconfigure saf_dip=0x%lx\n",
400 if (saf_dip
== NULL
) {
401 GPTWO_DEBUG0(1, CE_CONT
, "gptwocfg_unconfigure: "
402 "skipping NULLL saf device\n");
407 config
->gptwo_nodes
->gptwo_nodes
[i
] = NULL
;
410 GPTWO_DEBUG1(1, CE_CONT
, "gptwocfg_configure "
411 "ops->gptwocfg_configure=%lx\n",
412 ops
->gptwocfg_configure
);
414 GPTWO_DEBUG1(1, CE_CONT
, "gptwocfg_unconfigure "
415 "ops->gptwocfg_unconfigure=%lx\n",
416 ops
->gptwocfg_unconfigure
);
418 if (ops
->gptwocfg_unconfigure
!= NULL
) {
419 config
->gptwo_nodes
->gptwo_nodes
[i
] =
420 ops
->gptwocfg_unconfigure(saf_dip
);
425 GPTWO_DEBUG1(1, CE_CONT
, "e_ddi_branch_destroy <%s>\n",
426 ddi_get_name(saf_dip
));
428 ASSERT(e_ddi_branch_held(saf_dip
));
431 * Don't hold parent busy when calling
432 * e_ddi_branch_unconfigure/destroy/referenced()
434 ndi_devi_exit(ap
, circ
);
435 if (e_ddi_branch_destroy(saf_dip
, &fdip
, 0)) {
436 char *path
= kmem_alloc(MAXPATHLEN
, KM_SLEEP
);
439 * If non-NULL, fdip is held and must be released.
442 (void) ddi_pathname(fdip
, path
);
443 ddi_release_devi(fdip
);
445 (void) ddi_pathname(saf_dip
, path
);
448 cmn_err(CE_WARN
, "saf node removal failed: %s (%p)",
449 path
, fdip
? (void *)fdip
: (void *)saf_dip
);
451 kmem_free(path
, MAXPATHLEN
);
453 config
->gptwo_nodes
->gptwo_nodes
[i
] = saf_dip
;
456 ndi_devi_enter(ap
, &circ
);
459 ndi_devi_exit(ap
, circ
);
462 gptwocfg_free_node_list(config
->gptwo_nodes
);
464 mutex_enter(&gptwo_config_list_lock
);
465 if (gptwo_config_list
== config
) {
466 gptwo_config_list
= config
->gptwo_next
;
468 temp
= gptwo_config_list
;
469 while (temp
->gptwo_next
!= config
) {
470 temp
= temp
->gptwo_next
;
472 temp
->gptwo_next
= config
->gptwo_next
;
474 mutex_exit(&gptwo_config_list_lock
);
476 kmem_free(config
, sizeof (gptwocfg_config_t
));
484 gptwocfg_next_node(gptwocfg_cookie_t c
, dev_info_t
*previous
, dev_info_t
**next
)
486 gptwocfg_config_t
*cookie
;
489 GPTWO_DEBUG3(1, CE_WARN
, "gptwocfg_next_node"
490 "(c=0x%lx, previous=0x%lx, next=0x%lx)\n", c
, previous
, next
);
492 cookie
= (gptwocfg_config_t
*)c
;
494 for (i
= 0; i
< cookie
->gptwo_nodes
->gptwo_number_of_nodes
; i
++) {
495 GPTWO_DEBUG1(1, CE_WARN
, "0x%lx\n",
496 cookie
->gptwo_nodes
->gptwo_nodes
[i
]);
499 if (previous
== NULL
) {
500 for (i
= 0; i
< cookie
->gptwo_nodes
->gptwo_number_of_nodes
;
502 if (cookie
->gptwo_nodes
->gptwo_nodes
[i
]) {
503 *next
= cookie
->gptwo_nodes
->gptwo_nodes
[i
];
504 GPTWO_DEBUG1(1, CE_WARN
, "returned 0x%lx\n",
512 for (i
= 0; i
< cookie
->gptwo_nodes
->gptwo_number_of_nodes
; i
++) {
513 if (cookie
->gptwo_nodes
->gptwo_nodes
[i
] == previous
) {
515 j
< cookie
->gptwo_nodes
->gptwo_number_of_nodes
;
517 if (cookie
->gptwo_nodes
->gptwo_nodes
[j
]) {
519 cookie
->gptwo_nodes
->gptwo_nodes
[j
];
520 GPTWO_DEBUG1(1, CE_WARN
,
521 "returned 0x%lx\n", *next
);
526 GPTWO_DEBUG1(1, CE_WARN
, "returned 0x%lx\n",
533 * previous is probably an invalid dev_info.
538 static gptwo_new_nodes_t
*
539 gptwocfg_get_obp_created_nodes(dev_info_t
*ap
, uint_t id
)
541 gptwo_new_nodes_t
*obp_nodes
;
543 int i
= 0, nodes
= 0;
546 GPTWO_DEBUG2(1, CE_CONT
, "gptwocfg_get_obp_created_nodes - ap=0x%lx "
547 "id=0x%x\n", ap
, id
);
549 ndi_devi_enter(ap
, &circular_count
);
552 * First go through all the children of the attachment point
553 * to count matching safari agent ids
555 saf_dev
= ddi_get_child(ap
);
556 while (saf_dev
!= NULL
) {
557 if (ddi_getprop(DDI_DEV_T_ANY
, saf_dev
, DDI_PROP_DONTPASS
,
558 "portid", -1) == id
) {
559 if (&starcat_dr_name
) {
560 if (starcat_dr_name(ddi_node_name(saf_dev
))
562 saf_dev
= ddi_get_next_sibling(saf_dev
);
568 saf_dev
= ddi_get_next_sibling(saf_dev
);
571 GPTWO_DEBUG1(1, CE_CONT
, "gptwocfg_get_obp_created_nodes - %d nodes "
574 obp_nodes
= gptwocfg_allocate_node_list(nodes
);
577 * Then fill in the nodes structure.
579 saf_dev
= ddi_get_child(ap
);
580 while ((saf_dev
!= NULL
) && (i
< nodes
)) {
581 if (ddi_getprop(DDI_DEV_T_ANY
, saf_dev
, DDI_PROP_DONTPASS
,
582 "portid", -1) == id
) {
583 if (&starcat_dr_name
) {
584 if (starcat_dr_name(ddi_node_name(saf_dev
))
586 saf_dev
= ddi_get_next_sibling(saf_dev
);
591 * Branch rooted at this dip must have been
592 * held by the DR driver.
594 ASSERT(e_ddi_branch_held(saf_dev
));
595 obp_nodes
->gptwo_nodes
[i
++] = saf_dev
;
597 saf_dev
= ddi_get_next_sibling(saf_dev
);
600 ndi_devi_exit(ap
, circular_count
);
602 GPTWO_DEBUG1(1, CE_CONT
, "gptwocfg_get_obp_created_nodes - "
603 "Returning 0x%lx\n", obp_nodes
);
609 gptwocfg_save_handle(dev_info_t
*dip
, fco_handle_t fco_handle
)
611 gptwocfg_handle_list_t
*h
;
613 GPTWO_DEBUG2(1, CE_CONT
, "gptwocfg_save_handle - "
614 "dip=%lx fco_handle=%lx\n", dip
, fco_handle
);
616 h
= kmem_zalloc(sizeof (gptwocfg_handle_list_t
), KM_SLEEP
);
618 mutex_enter(&gptwo_handle_list_lock
);
620 h
->next
= gptwocfg_handle_list
;
622 h
->fco_handle
= fco_handle
;
623 gptwocfg_handle_list
= h
;
625 mutex_exit(&gptwo_handle_list_lock
);
629 gptwocfg_get_handle(dev_info_t
*dip
)
631 gptwocfg_handle_list_t
*h
, *last
;
632 fco_handle_t fco_handle
;
634 mutex_enter(&gptwo_handle_list_lock
);
636 h
= last
= gptwocfg_handle_list
;
640 if (h
== gptwocfg_handle_list
)
641 gptwocfg_handle_list
= h
->next
;
643 last
->next
= h
->next
;
645 mutex_exit(&gptwo_handle_list_lock
);
647 fco_handle
= h
->fco_handle
;
649 kmem_free(h
, sizeof (gptwocfg_handle_list_t
));
651 GPTWO_DEBUG2(1, CE_CONT
, "gptwocfg_get_handle - "
652 "dip=%lx fco_handle=%lx\n", dip
, fco_handle
);
660 mutex_exit(&gptwo_handle_list_lock
);
662 GPTWO_DEBUG1(1, CE_CONT
, "gptwocfg_get_handle - dip=%lx NO HANDLE\n",
669 gptwocfg_devi_attach_to_parent(dev_info_t
*dip
)
671 (void) i_ndi_config_node(dip
, DS_LINKED
, 0);
676 debug(char *fmt
, uintptr_t a1
, uintptr_t a2
, uintptr_t a3
,
677 uintptr_t a4
, uintptr_t a5
)
679 cmn_err(CE_CONT
, fmt
, a1
, a2
, a3
, a4
, a5
);