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]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
29 * sun4 root nexus driver
33 #include <sys/modctl.h>
34 #include <sys/ddi_subrdefs.h>
35 #include <sys/sunndi.h>
36 #include <sys/vmsystm.h>
37 #include <sys/async.h>
39 #include <sys/ndifm.h>
40 #include <vm/seg_dev.h>
41 #include <vm/seg_kmem.h>
42 #include <sys/ontrap.h>
44 /* Useful debugging Stuff */
45 #include <sys/nexusdebug.h>
46 #define ROOTNEX_MAP_DEBUG 0x1
47 #define ROOTNEX_INTR_DEBUG 0x2
54 rootnex_map(dev_info_t
*dip
, dev_info_t
*rdip
, ddi_map_req_t
*mp
,
55 off_t offset
, off_t len
, caddr_t
*vaddrp
);
58 rootnex_intr_ops(dev_info_t
*, dev_info_t
*, ddi_intr_op_t
,
59 ddi_intr_handle_impl_t
*, void *);
62 rootnex_map_fault(dev_info_t
*dip
, dev_info_t
*rdip
,
63 struct hat
*hat
, struct seg
*seg
, caddr_t addr
,
64 struct devpage
*dp
, pfn_t pfn
, uint_t prot
, uint_t lock
);
67 rootnex_ctlops(dev_info_t
*, dev_info_t
*, ddi_ctl_enum_t
, void *, void *);
70 rootnex_busop_fminit(dev_info_t
*dip
, dev_info_t
*tdip
, int tcap
,
71 ddi_iblock_cookie_t
*ibc
);
74 rootnex_fm_init(dev_info_t
*);
77 rootnex_ctlops_peekpoke(ddi_ctl_enum_t
, peekpoke_ctlops_t
*, void *result
);
80 * Defined in $KARCH/io/mach_rootnex.c
82 int rootnex_add_intr_impl(dev_info_t
*dip
, dev_info_t
*rdip
,
83 ddi_intr_handle_impl_t
*hdlp
);
84 #pragma weak rootnex_add_intr_impl
86 int rootnex_remove_intr_impl(dev_info_t
*dip
, dev_info_t
*rdip
,
87 ddi_intr_handle_impl_t
*hdlp
);
88 #pragma weak rootnex_remove_intr_impl
90 int rootnex_get_intr_pri(dev_info_t
*dip
, dev_info_t
*rdip
,
91 ddi_intr_handle_impl_t
*hdlp
);
92 #pragma weak rootnex_get_intr_pri
94 int rootnex_name_child_impl(dev_info_t
*child
, char *name
, int namelen
);
95 #pragma weak rootnex_name_child_impl
97 int rootnex_ctl_initchild_impl(dev_info_t
*dip
);
98 #pragma weak rootnex_initchild_impl
100 void rootnex_ctl_uninitchild_impl(dev_info_t
*dip
);
101 #pragma weak rootnex_uninitchild_impl
103 int rootnex_ctl_reportdev_impl(dev_info_t
*dev
);
104 #pragma weak rootnex_reportdev_impl
106 static struct cb_ops rootnex_cb_ops
= {
109 nodev
, /* strategy */
118 nochpoll
, /* chpoll */
119 ddi_prop_op
, /* cb_prop_op */
120 NULL
, /* struct streamtab */
121 D_NEW
| D_MP
| D_HOTPLUG
, /* compatibility flags */
123 nodev
, /* cb_aread */
124 nodev
/* cb_awrite */
127 static struct bus_ops rootnex_bus_ops
= {
134 ddi_no_dma_map
, /* no rootnex_dma_map- now in sysio nexus */
138 ddi_no_dma_unbindhdl
,
141 ddi_no_dma_mctl
, /* no rootnex_dma_mctl- now in sysio nexus */
144 i_ddi_rootnex_get_eventcookie
,
145 i_ddi_rootnex_add_eventcall
,
146 i_ddi_rootnex_remove_eventcall
,
147 i_ddi_rootnex_post_event
,
148 NULL
, /* bus_intr_ctl */
149 NULL
, /* bus_config */
150 NULL
, /* bus_unconfig */
151 rootnex_busop_fminit
, /* bus_fm_init */
152 NULL
, /* bus_fm_fini */
153 NULL
, /* bus_fm_access_enter */
154 NULL
, /* bus_fm_access_fini */
155 NULL
, /* bus_power */
156 rootnex_intr_ops
/* bus_intr_op */
159 static int rootnex_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
);
160 static int rootnex_detach(dev_info_t
*devi
, ddi_detach_cmd_t cmd
);
162 static struct dev_ops rootnex_ops
= {
165 ddi_no_info
, /* info */
174 ddi_quiesce_not_needed
, /* quiesce */
178 extern uint_t root_phys_addr_lo_mask
;
179 extern uint_t root_phys_addr_hi_mask
;
180 extern struct mod_ops mod_driverops
;
181 extern struct dev_ops rootnex_ops
;
182 extern struct cpu cpu0
;
183 extern ddi_iblock_cookie_t rootnex_err_ibc
;
187 * Add statically defined root properties to this list...
189 static const int pagesize
= PAGESIZE
;
190 static const int mmu_pagesize
= MMU_PAGESIZE
;
191 static const int mmu_pageoffset
= MMU_PAGEOFFSET
;
198 static struct prop_def root_props
[] = {
199 { "PAGESIZE", (caddr_t
)&pagesize
},
200 { "MMU_PAGESIZE", (caddr_t
)&mmu_pagesize
},
201 { "MMU_PAGEOFFSET", (caddr_t
)&mmu_pageoffset
},
204 static vmem_t
*rootnex_regspec_arena
;
206 #define NROOT_PROPS (sizeof (root_props) / sizeof (struct prop_def))
211 * Module linkage information for the kernel.
214 static struct modldrv modldrv
= {
215 &mod_driverops
, /* Type of module. This one is a nexus driver */
217 &rootnex_ops
, /* Driver ops */
220 static struct modlinkage modlinkage
= {
221 MODREV_1
, (void *)&modldrv
, NULL
227 return (mod_install(&modlinkage
));
237 _info(struct modinfo
*modinfop
)
239 return (mod_info(&modlinkage
, modinfop
));
245 * attach the root nexus.
247 static void add_root_props(dev_info_t
*);
251 rootnex_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
)
257 * Only do these functions when the driver is acting as the
258 * root nexus, not when it is driving a memory controller.
260 if (ddi_root_node() == devi
) {
261 rootnex_fm_init(devi
);
262 add_root_props(devi
);
263 i_ddi_rootnex_init_events(devi
);
264 rootnex_regspec_arena
= vmem_create("regspec",
265 (void *)PIOMAPBASE
, PIOMAPSIZE
, MMU_PAGESIZE
, NULL
, NULL
,
269 if (ddi_prop_op(DDI_DEV_T_ANY
, devi
, PROP_LEN_AND_VAL_ALLOC
,
270 DDI_PROP_DONTPASS
, "banner-name", (caddr_t
)&valuep
,
271 &length
) == DDI_PROP_SUCCESS
) {
272 cmn_err(CE_CONT
, "?root nexus = %s\n", valuep
);
273 kmem_free(valuep
, length
);
276 * Add a no-suspend-resume property so that NDI
277 * does not attempt to suspend/resume the rootnex
278 * (or any of its aliases) node.
280 (void) ddi_prop_update_string(DDI_DEV_T_NONE
, devi
,
281 "pm-hardware-state", "no-suspend-resume");
283 return (DDI_SUCCESS
);
288 rootnex_detach(dev_info_t
*devi
, ddi_detach_cmd_t cmd
)
290 return (DDI_SUCCESS
);
294 add_root_props(dev_info_t
*devi
)
297 struct prop_def
*rpp
;
300 * Note that this for loop works because all of the
301 * properties in root_prop are integers
303 for (i
= 0, rpp
= root_props
; i
< NROOT_PROPS
; ++i
, ++rpp
) {
304 (void) e_ddi_prop_update_int(DDI_DEV_T_NONE
, devi
,
305 rpp
->prop_name
, *((int *)rpp
->prop_value
));
309 * Create the root node "boolean" property
310 * corresponding to addressing type supported in the root node:
313 * "relative-addressing" (OBP PROMS)
314 * "generic-addressing" (SunMon -- pseudo OBP/DDI)
317 (void) e_ddi_prop_update_int(DDI_DEV_T_NONE
, devi
,
318 DDI_RELATIVE_ADDRESSING
, 1);
321 * Create fault management capability property
323 (void) e_ddi_prop_update_int(DDI_DEV_T_NONE
, devi
, "fm-capable",
324 ddi_fm_capable(devi
));
328 rootnex_map_regspec(ddi_map_req_t
*mp
, caddr_t
*vaddrp
, uint_t mapping_attr
)
335 struct regspec
*rp
= mp
->map_obj
.rp
;
338 base
= (uint64_t)rp
->regspec_addr
& (~MMU_PAGEOFFSET
); /* base addr */
341 * Take the bustype and addr and convert it to a
344 pfn
= mmu_btop(((uint64_t)(rp
->regspec_bustype
&
345 root_phys_addr_hi_mask
) << 32) | base
);
348 * Do a quick sanity check to make sure we are in I/O space.
350 if (pf_is_memory(pfn
))
351 return (DDI_ME_INVAL
);
353 if (rp
->regspec_size
== 0) {
354 DPRINTF(ROOTNEX_MAP_DEBUG
, ("rootnex_map_regspec: zero "
356 return (DDI_ME_INVAL
);
359 if (mp
->map_flags
& DDI_MF_DEVICE_MAPPING
)
360 *vaddrp
= (caddr_t
)pfn
;
362 pgoffset
= (ulong_t
)rp
->regspec_addr
& MMU_PAGEOFFSET
;
363 npages
= mmu_btopr(rp
->regspec_size
+ pgoffset
);
365 DPRINTF(ROOTNEX_MAP_DEBUG
, ("rootnex_map_regspec: Mapping "
366 "%lu pages physical %x.%lx ", npages
, rp
->regspec_bustype
,
369 if ((kaddr
= vmem_alloc(rootnex_regspec_arena
,
370 ptob(npages
), VM_NOSLEEP
)) == NULL
)
371 return (DDI_ME_NORESOURCES
);
374 * Now map in the pages we've allocated...
376 hat_devload(kas
.a_hat
, kaddr
, ptob(npages
), pfn
,
377 mp
->map_prot
| mapping_attr
, HAT_LOAD_LOCK
);
379 *vaddrp
= kaddr
+ pgoffset
;
381 hp
= mp
->map_handlep
;
384 hp
->ah_pnum
= npages
;
388 DPRINTF(ROOTNEX_MAP_DEBUG
, ("at virtual 0x%p\n", (void *)*vaddrp
));
393 rootnex_unmap_regspec(ddi_map_req_t
*mp
, caddr_t
*vaddrp
)
395 caddr_t addr
= *vaddrp
;
401 if (mp
->map_flags
& DDI_MF_DEVICE_MAPPING
)
405 pgoffset
= (uintptr_t)addr
& MMU_PAGEOFFSET
;
407 if (rp
->regspec_size
== 0) {
408 DPRINTF(ROOTNEX_MAP_DEBUG
, ("rootnex_unmap_regspec: "
409 "zero regspec_size\n"));
410 return (DDI_ME_INVAL
);
413 base
= addr
- pgoffset
;
414 npages
= mmu_btopr(rp
->regspec_size
+ pgoffset
);
415 hat_unload(kas
.a_hat
, base
, ptob(npages
), HAT_UNLOAD_UNLOCK
);
416 vmem_free(rootnex_regspec_arena
, base
, ptob(npages
));
419 * Destroy the pointer - the mapping has logically gone
421 *vaddrp
= (caddr_t
)0;
427 rootnex_map_handle(ddi_map_req_t
*mp
)
431 register struct regspec
*rp
;
434 * Set up the hat_flags for the mapping.
436 hp
= mp
->map_handlep
;
438 switch (hp
->ah_acc
.devacc_attr_endian_flags
) {
439 case DDI_NEVERSWAP_ACC
:
440 hat_flags
= HAT_NEVERSWAP
| HAT_STRICTORDER
;
442 case DDI_STRUCTURE_BE_ACC
:
443 hat_flags
= HAT_STRUCTURE_BE
;
445 case DDI_STRUCTURE_LE_ACC
:
446 hat_flags
= HAT_STRUCTURE_LE
;
449 return (DDI_REGS_ACC_CONFLICT
);
452 switch (hp
->ah_acc
.devacc_attr_dataorder
) {
453 case DDI_STRICTORDER_ACC
:
455 case DDI_UNORDERED_OK_ACC
:
456 hat_flags
|= HAT_UNORDERED_OK
;
458 case DDI_MERGING_OK_ACC
:
459 hat_flags
|= HAT_MERGING_OK
;
461 case DDI_LOADCACHING_OK_ACC
:
462 hat_flags
|= HAT_LOADCACHING_OK
;
464 case DDI_STORECACHING_OK_ACC
:
465 hat_flags
|= HAT_STORECACHING_OK
;
468 return (DDI_FAILURE
);
472 if (rp
->regspec_size
== 0)
473 return (DDI_ME_INVAL
);
475 hp
->ah_hat_flags
= hat_flags
;
476 hp
->ah_pfn
= mmu_btop((ulong_t
)rp
->regspec_addr
& (~MMU_PAGEOFFSET
));
477 hp
->ah_pnum
= mmu_btopr(rp
->regspec_size
+
478 (ulong_t
)rp
->regspec_addr
& MMU_PAGEOFFSET
);
479 return (DDI_SUCCESS
);
483 rootnex_map(dev_info_t
*dip
, dev_info_t
*rdip
, ddi_map_req_t
*mp
,
484 off_t offset
, off_t len
, caddr_t
*vaddrp
)
486 struct regspec
*rp
, tmp_reg
;
487 ddi_map_req_t mr
= *mp
; /* Get private copy of request */
490 ddi_acc_hdl_t
*hp
= NULL
;
494 switch (mp
->map_op
) {
495 case DDI_MO_MAP_LOCKED
:
497 case DDI_MO_MAP_HANDLE
:
500 DPRINTF(ROOTNEX_MAP_DEBUG
, ("rootnex_map: unimplemented map "
501 "op %d.", mp
->map_op
));
502 return (DDI_ME_UNIMPLEMENTED
);
505 if (mp
->map_flags
& DDI_MF_USER_MAPPING
) {
506 DPRINTF(ROOTNEX_MAP_DEBUG
, ("rootnex_map: unimplemented map "
508 return (DDI_ME_UNIMPLEMENTED
);
512 * First, if given an rnumber, convert it to a regspec...
513 * (Presumably, this is on behalf of a child of the root node?)
516 if (mp
->map_type
== DDI_MT_RNUMBER
) {
518 int rnumber
= mp
->map_obj
.rnumber
;
520 rp
= i_ddi_rnumber_to_regspec(rdip
, rnumber
);
521 if (rp
== (struct regspec
*)0) {
522 DPRINTF(ROOTNEX_MAP_DEBUG
, ("rootnex_map: Out of "
523 "range rnumber <%d>, device <%s>", rnumber
,
524 ddi_get_name(rdip
)));
525 return (DDI_ME_RNUMBER_RANGE
);
529 * Convert the given ddi_map_req_t from rnumber to regspec...
532 mp
->map_type
= DDI_MT_REGSPEC
;
537 * Adjust offset and length corresponding to called values...
538 * XXX: A non-zero length means override the one in the regspec
539 * XXX: regardless of what's in the parent's range?.
542 tmp_reg
= *(mp
->map_obj
.rp
); /* Preserve underlying data */
543 rp
= mp
->map_obj
.rp
= &tmp_reg
; /* Use tmp_reg in request */
545 rp
->regspec_addr
+= (uint_t
)offset
;
547 rp
->regspec_size
= (uint_t
)len
;
550 * Apply any parent ranges at this level, if applicable.
551 * (This is where nexus specific regspec translation takes place.
552 * Use of this function is implicit agreement that translation is
553 * provided via ddi_apply_range.)
556 DPRINTF(ROOTNEX_MAP_DEBUG
, ("rootnex_map: applying range of parent "
557 "<%s> to child <%s>...\n", ddi_get_name(dip
), ddi_get_name(rdip
)));
559 if ((error
= i_ddi_apply_range(dip
, rdip
, mp
->map_obj
.rp
)) != 0)
562 switch (mp
->map_op
) {
563 case DDI_MO_MAP_LOCKED
:
566 * Set up the locked down kernel mapping to the regspec...
570 * If we were passed an access handle we need to determine
571 * the "endian-ness" of the mapping and fill in the handle.
573 if (mp
->map_handlep
) {
574 hp
= mp
->map_handlep
;
575 switch (hp
->ah_acc
.devacc_attr_endian_flags
) {
576 case DDI_NEVERSWAP_ACC
:
577 mapping_attr
= HAT_NEVERSWAP
| HAT_STRICTORDER
;
579 case DDI_STRUCTURE_BE_ACC
:
580 mapping_attr
= HAT_STRUCTURE_BE
;
582 case DDI_STRUCTURE_LE_ACC
:
583 mapping_attr
= HAT_STRUCTURE_LE
;
586 return (DDI_REGS_ACC_CONFLICT
);
589 switch (hp
->ah_acc
.devacc_attr_dataorder
) {
590 case DDI_STRICTORDER_ACC
:
592 case DDI_UNORDERED_OK_ACC
:
593 mapping_attr
|= HAT_UNORDERED_OK
;
595 case DDI_MERGING_OK_ACC
:
596 mapping_attr
|= HAT_MERGING_OK
;
598 case DDI_LOADCACHING_OK_ACC
:
599 mapping_attr
|= HAT_LOADCACHING_OK
;
601 case DDI_STORECACHING_OK_ACC
:
602 mapping_attr
|= HAT_STORECACHING_OK
;
605 return (DDI_REGS_ACC_CONFLICT
);
608 mapping_attr
= HAT_NEVERSWAP
| HAT_STRICTORDER
;
612 * Set up the mapping.
614 error
= rootnex_map_regspec(mp
, vaddrp
, mapping_attr
);
617 * Fill in the access handle if needed.
620 hp
->ah_addr
= *vaddrp
;
621 hp
->ah_hat_flags
= mapping_attr
;
623 impl_acc_hdl_init(hp
);
633 return (rootnex_unmap_regspec(mp
, vaddrp
));
635 case DDI_MO_MAP_HANDLE
:
636 return (rootnex_map_handle(mp
));
640 return (DDI_ME_UNIMPLEMENTED
);
644 rootnex_intr_ops(dev_info_t
*dip
, dev_info_t
*rdip
, ddi_intr_op_t intr_op
,
645 ddi_intr_handle_impl_t
*hdlp
, void *result
)
647 int ret
= DDI_SUCCESS
;
649 DPRINTF(ROOTNEX_INTR_DEBUG
, ("rootnex_intr_ops: rdip=%s%d "
650 "intr_op 0x%x hdlp 0x%p\n", ddi_driver_name(rdip
),
651 ddi_get_instance(rdip
), intr_op
, (void *)hdlp
));
654 case DDI_INTROP_GETCAP
:
655 *(int *)result
= DDI_INTR_FLAG_LEVEL
;
657 case DDI_INTROP_SETCAP
:
660 case DDI_INTROP_ALLOC
:
661 *(int *)result
= hdlp
->ih_scratch1
;
663 case DDI_INTROP_FREE
:
665 case DDI_INTROP_GETPRI
:
666 *(int *)result
= rootnex_get_intr_pri(dip
, rdip
, hdlp
);
668 case DDI_INTROP_SETPRI
:
670 case DDI_INTROP_ADDISR
:
671 ret
= rootnex_add_intr_impl(dip
, rdip
, hdlp
);
673 case DDI_INTROP_REMISR
:
674 ret
= rootnex_remove_intr_impl(dip
, rdip
, hdlp
);
676 case DDI_INTROP_ENABLE
:
677 case DDI_INTROP_DISABLE
:
679 case DDI_INTROP_NINTRS
:
680 case DDI_INTROP_NAVAIL
:
681 *(int *)result
= i_ddi_get_intx_nintrs(rdip
);
683 case DDI_INTROP_SUPPORTED_TYPES
:
684 /* Root nexus driver supports only fixed interrupts */
685 *(int *)result
= i_ddi_get_intx_nintrs(rdip
) ?
686 DDI_INTR_TYPE_FIXED
: 0;
701 #define DMAOBJ_PP_PP dmao_obj.pp_obj.pp_pp
702 #define DMAOBJ_PP_OFF dmao_ogj.pp_obj.pp_offset
703 #define ALO dma_lim->dlim_addr_lo
704 #define AHI dma_lim->dlim_addr_hi
705 #define OBJSIZE dmareq->dmar_object.dmao_size
706 #define ORIGVADDR dmareq->dmar_object.dmao_obj.virt_obj.v_addr
707 #define RED ((mp->dmai_rflags & DDI_DMA_REDZONE)? 1 : 0)
708 #define DIRECTION (mp->dmai_rflags & DDI_DMA_RDWR)
713 * fault in mappings for requestors
718 rootnex_map_fault(dev_info_t
*dip
, dev_info_t
*rdip
,
719 struct hat
*hat
, struct seg
*seg
, caddr_t addr
,
720 struct devpage
*dp
, pfn_t pfn
, uint_t prot
, uint_t lock
)
722 extern struct seg_ops segdev_ops
;
724 DPRINTF(ROOTNEX_MAP_DEBUG
, ("rootnex_map_fault: address <%p> "
725 "pfn <%lx>", (void *)addr
, pfn
));
726 DPRINTF(ROOTNEX_MAP_DEBUG
, (" Seg <%s>\n",
727 seg
->s_ops
== &segdev_ops
? "segdev" :
728 seg
== &kvseg
? "segkmem" : "NONE!"));
731 * This is all terribly broken, but it is a start
733 * XXX Note that this test means that segdev_ops
734 * must be exported from seg_dev.c.
735 * XXX What about devices with their own segment drivers?
737 if (seg
->s_ops
== &segdev_ops
) {
738 register struct segdev_data
*sdp
=
739 (struct segdev_data
*)seg
->s_data
;
743 * This is one plausible interpretation of
744 * a null hat i.e. use the first hat on the
745 * address space hat list which by convention is
746 * the hat of the system MMU. At alternative
747 * would be to panic .. this might well be better ..
749 ASSERT(AS_READ_HELD(seg
->s_as
));
750 hat
= seg
->s_as
->a_hat
;
751 cmn_err(CE_NOTE
, "rootnex_map_fault: nil hat");
753 hat_devload(hat
, addr
, MMU_PAGESIZE
, pfn
, prot
| sdp
->hat_attr
,
754 (lock
? HAT_LOAD_LOCK
: HAT_LOAD
));
755 } else if (seg
== &kvseg
&& dp
== (struct devpage
*)0) {
756 hat_devload(kas
.a_hat
, addr
, MMU_PAGESIZE
, pfn
, prot
,
759 return (DDI_FAILURE
);
760 return (DDI_SUCCESS
);
764 * Name a child of rootnex
766 * This may be called multiple times, independent of initchild calls.
769 rootnex_name_child(dev_info_t
*child
, char *name
, int namelen
)
771 return (rootnex_name_child_impl(child
, name
, namelen
));
776 rootnex_ctl_initchild(dev_info_t
*dip
)
778 return (rootnex_ctl_initchild_impl(dip
));
783 rootnex_ctl_uninitchild(dev_info_t
*dip
)
785 extern void impl_free_ddi_ppd(dev_info_t
*);
787 rootnex_ctl_uninitchild_impl(dip
);
790 * strip properties and convert node to prototype form
792 impl_free_ddi_ppd(dip
);
793 ddi_set_name_addr(dip
, NULL
);
794 impl_rem_dev_props(dip
);
795 return (DDI_SUCCESS
);
800 rootnex_ctl_reportdev(dev_info_t
*dev
)
802 return (rootnex_ctl_reportdev_impl(dev
));
807 rootnex_ctlops_peekpoke(ddi_ctl_enum_t cmd
, peekpoke_ctlops_t
*in_args
,
810 int err
= DDI_SUCCESS
;
813 /* No safe access except for peek/poke is supported. */
814 if (in_args
->handle
!= NULL
)
815 return (DDI_FAILURE
);
817 /* Set up protected environment. */
818 if (!on_trap(&otd
, OT_DATA_ACCESS
)) {
819 uintptr_t tramp
= otd
.ot_trampoline
;
821 if (cmd
== DDI_CTLOPS_POKE
) {
822 otd
.ot_trampoline
= (uintptr_t)&poke_fault
;
823 err
= do_poke(in_args
->size
, (void *)in_args
->dev_addr
,
824 (void *)in_args
->host_addr
);
826 otd
.ot_trampoline
= (uintptr_t)&peek_fault
;
827 err
= do_peek(in_args
->size
, (void *)in_args
->dev_addr
,
828 (void *)in_args
->host_addr
);
829 result
= (void *)in_args
->host_addr
;
831 otd
.ot_trampoline
= tramp
;
835 /* Take down protected environment. */
843 rootnex_ctlops(dev_info_t
*dip
, dev_info_t
*rdip
,
844 ddi_ctl_enum_t ctlop
, void *arg
, void *result
)
846 register int n
, *ptr
;
847 register struct ddi_parent_private_data
*pdp
;
849 static boolean_t reserved_msg_printed
= B_FALSE
;
852 case DDI_CTLOPS_DMAPMAPC
:
853 return (DDI_FAILURE
);
855 case DDI_CTLOPS_BTOP
:
857 * Convert byte count input to physical page units.
858 * (byte counts that are not a page-size multiple
861 *(ulong_t
*)result
= btop(*(ulong_t
*)arg
);
862 return (DDI_SUCCESS
);
864 case DDI_CTLOPS_PTOB
:
866 * Convert size in physical pages to bytes
868 *(ulong_t
*)result
= ptob(*(ulong_t
*)arg
);
869 return (DDI_SUCCESS
);
871 case DDI_CTLOPS_BTOPR
:
873 * Convert byte count input to physical page units
874 * (byte counts that are not a page-size multiple
877 *(ulong_t
*)result
= btopr(*(ulong_t
*)arg
);
878 return (DDI_SUCCESS
);
880 case DDI_CTLOPS_INITCHILD
:
881 return (rootnex_ctl_initchild((dev_info_t
*)arg
));
883 case DDI_CTLOPS_UNINITCHILD
:
884 return (rootnex_ctl_uninitchild((dev_info_t
*)arg
));
886 case DDI_CTLOPS_REPORTDEV
:
887 return (rootnex_ctl_reportdev(rdip
));
889 case DDI_CTLOPS_IOMIN
:
891 * Nothing to do here but reflect back..
893 return (DDI_SUCCESS
);
895 case DDI_CTLOPS_REGSIZE
:
896 case DDI_CTLOPS_NREGS
:
899 case DDI_CTLOPS_SIDDEV
:
900 if (ndi_dev_is_prom_node(rdip
))
901 return (DDI_SUCCESS
);
902 if (ndi_dev_is_persistent_node(rdip
))
903 return (DDI_SUCCESS
);
904 return (DDI_FAILURE
);
906 case DDI_CTLOPS_POWER
: {
907 return ((*pm_platform_power
)((power_req_t
*)arg
));
910 case DDI_CTLOPS_RESERVED0
: /* Was DDI_CTLOPS_NINTRS, obsolete */
911 case DDI_CTLOPS_RESERVED1
: /* Was DDI_CTLOPS_POKE_INIT, obsolete */
912 case DDI_CTLOPS_RESERVED2
: /* Was DDI_CTLOPS_POKE_FLUSH, obsolete */
913 case DDI_CTLOPS_RESERVED3
: /* Was DDI_CTLOPS_POKE_FINI, obsolete */
914 case DDI_CTLOPS_RESERVED4
: /* Was DDI_CTLOPS_INTR_HILEVEL, obsolete */
915 case DDI_CTLOPS_RESERVED5
: /* Was DDI_CTLOPS_XLATE_INTRS, obsolete */
916 if (!reserved_msg_printed
) {
917 reserved_msg_printed
= B_TRUE
;
918 cmn_err(CE_WARN
, "Failing ddi_ctlops call(s) for "
919 "1 or more reserved/obsolete operations.");
921 return (DDI_FAILURE
);
923 case DDI_CTLOPS_POKE
:
924 case DDI_CTLOPS_PEEK
:
925 return (rootnex_ctlops_peekpoke(ctlop
, (peekpoke_ctlops_t
*)arg
,
929 return (DDI_FAILURE
);
933 * The rest are for "hardware" properties
935 if ((pdp
= ddi_get_parent_data(rdip
)) == NULL
)
936 return (DDI_FAILURE
);
938 if (ctlop
== DDI_CTLOPS_NREGS
) {
940 *ptr
= pdp
->par_nreg
;
941 } else { /* ctlop == DDI_CTLOPS_REGSIZE */
942 off_t
*size
= (off_t
*)result
;
946 if (n
>= pdp
->par_nreg
) {
947 return (DDI_FAILURE
);
949 *size
= (off_t
)pdp
->par_reg
[n
].regspec_size
;
951 return (DDI_SUCCESS
);
956 rootnex_busop_fminit(dev_info_t
*dip
, dev_info_t
*tdip
, int cap
,
957 ddi_iblock_cookie_t
*ibc
)
959 *ibc
= rootnex_err_ibc
;
960 return (ddi_system_fmcap
| DDI_FM_ACCCHK_CAPABLE
|
961 DDI_FM_DMACHK_CAPABLE
);
965 rootnex_fm_init(dev_info_t
*dip
)
969 /* Minimum fm capability level for sun4u platforms */
970 ddi_system_fmcap
= DDI_FM_EREPORT_CAPABLE
| DDI_FM_ERRCB_CAPABLE
;
972 fmcap
= ddi_system_fmcap
;
975 * Initialize ECC error handling
977 rootnex_err_ibc
= (ddi_iblock_cookie_t
)PIL_15
;
978 ddi_fm_init(dip
, &fmcap
, &rootnex_err_ibc
);