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 2009 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 * Host to hypervisor virtual devices nexus driver
34 * - Add watchpoints on vbd/vif and enumerate/offline on watch callback
36 * - Filter/restrict property lookups into xenstore
41 #include <sys/debug.h>
42 #include <sys/modctl.h>
43 #include <sys/autoconf.h>
44 #include <sys/ddi_impldefs.h>
45 #include <sys/ddi_subrdefs.h>
47 #include <sys/sunddi.h>
48 #include <sys/sunndi.h>
49 #include <sys/avintr.h>
52 #include <sys/promif.h>
54 #include <sys/bootconf.h>
55 #include <sys/bootsvcs.h>
56 #include <util/sscanf.h>
57 #include <sys/mach_intr.h>
58 #include <sys/bootinfo.h>
60 #include <sys/xpv_support.h>
61 #include <sys/hypervisor.h>
62 #include <sys/archsystm.h>
64 #include <public/xen.h>
65 #include <public/event_channel.h>
66 #include <public/io/xenbus.h>
68 #include <sys/hypervisor.h>
69 #include <sys/evtchn_impl.h>
70 #include <sys/xen_mmu.h>
72 #include <xen/sys/xenbus_impl.h>
73 #include <xen/sys/xendev.h>
76 * DDI dev_ops entrypoints
78 static int xpvd_info(dev_info_t
*, ddi_info_cmd_t
, void *, void **);
79 static int xpvd_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
);
80 static int xpvd_detach(dev_info_t
*devi
, ddi_detach_cmd_t cmd
);
84 * NDI bus_ops entrypoints
86 static int xpvd_ctlops(dev_info_t
*, dev_info_t
*, ddi_ctl_enum_t
, void *,
88 static int xpvd_intr_ops(dev_info_t
*, dev_info_t
*, ddi_intr_op_t
,
89 ddi_intr_handle_impl_t
*, void *);
90 static int xpvd_prop_op(dev_t
, dev_info_t
*, dev_info_t
*, ddi_prop_op_t
,
91 int, char *, caddr_t
, int *);
92 static int xpvd_bus_config(dev_info_t
*, uint_t
, ddi_bus_config_op_t
,
93 void *, dev_info_t
**);
94 static int xpvd_bus_unconfig(dev_info_t
*, uint_t
, ddi_bus_config_op_t
,
96 static int xpvd_get_eventcookie(dev_info_t
*, dev_info_t
*,
97 char *, ddi_eventcookie_t
*);
98 static int xpvd_add_eventcall(dev_info_t
*, dev_info_t
*,
99 ddi_eventcookie_t
, void (*)(dev_info_t
*,
100 ddi_eventcookie_t
, void *, void *),
101 void *, ddi_callback_id_t
*);
102 static int xpvd_remove_eventcall(dev_info_t
*, ddi_callback_id_t
);
103 static int xpvd_post_event(dev_info_t
*, dev_info_t
*,
104 ddi_eventcookie_t
, void *);
109 static int xpvd_enable_intr(dev_info_t
*, ddi_intr_handle_impl_t
*, int);
110 static void xpvd_disable_intr(dev_info_t
*, ddi_intr_handle_impl_t
*, int);
111 static int xpvd_removechild(dev_info_t
*);
112 static int xpvd_initchild(dev_info_t
*);
113 static int xpvd_name_child(dev_info_t
*, char *, int);
114 static boolean_t
i_xpvd_parse_devname(char *, xendev_devclass_t
*,
118 /* Extern declarations */
119 extern int (*psm_intr_ops
)(dev_info_t
*, ddi_intr_handle_impl_t
*,
120 psm_intr_op_t
, int *);
122 struct bus_ops xpvd_bus_ops
= {
139 xpvd_get_eventcookie
,
141 xpvd_remove_eventcall
,
143 0, /* (*bus_intr_ctl)(); */
146 NULL
, /* (*bus_fm_init)(); */
147 NULL
, /* (*bus_fm_fini)(); */
148 NULL
, /* (*bus_fm_access_enter)(); */
149 NULL
, /* (*bus_fm_access_exit)(); */
150 NULL
, /* (*bus_power)(); */
151 xpvd_intr_ops
/* (*bus_intr_op)(); */
154 struct dev_ops xpvd_ops
= {
155 DEVO_REV
, /* devo_rev */
157 xpvd_info
, /* info */
158 nulldev
, /* identify */
160 xpvd_attach
, /* attach */
161 xpvd_detach
, /* detach */
163 (struct cb_ops
*)0, /* driver operations */
164 &xpvd_bus_ops
, /* bus operations */
166 ddi_quiesce_not_needed
, /* quiesce */
170 dev_info_t
*xpvd_dip
;
175 static ndi_event_definition_t xpvd_ndi_event_defs
[] = {
176 { 0, XS_OE_STATE
, EPL_KERNEL
, NDI_EVENT_POST_TO_TGT
},
177 { 1, XS_HP_STATE
, EPL_KERNEL
, NDI_EVENT_POST_TO_TGT
},
180 #define XENDEV_N_NDI_EVENTS \
181 (sizeof (xpvd_ndi_event_defs) / sizeof (xpvd_ndi_event_defs[0]))
183 static ndi_event_set_t xpvd_ndi_events
= {
184 NDI_EVENTS_REV1
, XENDEV_N_NDI_EVENTS
, xpvd_ndi_event_defs
187 static ndi_event_hdl_t xpvd_ndi_event_handle
;
190 * Hypervisor interrupt capabilities
192 #define XENDEV_INTR_CAPABILITIES \
193 (DDI_INTR_FLAG_EDGE | DDI_INTR_FLAG_MASKABLE | DDI_INTR_FLAG_PENDING)
196 * Module linkage information for the kernel.
199 static struct modldrv modldrv
= {
200 &mod_driverops
, /* Type of module */
201 "virtual device nexus driver",
202 &xpvd_ops
, /* driver ops */
205 static struct modlinkage modlinkage
= {
214 return (mod_install(&modlinkage
));
220 return (mod_remove(&modlinkage
));
224 _info(struct modinfo
*modinfop
)
226 return (mod_info(&modlinkage
, modinfop
));
231 xpvd_info(dev_info_t
*dip
, ddi_info_cmd_t cmd
, void *arg
, void **result
)
235 return (DDI_FAILURE
);
237 case DDI_INFO_DEVT2INSTANCE
:
239 return (DDI_SUCCESS
);
241 case DDI_INFO_DEVT2DEVINFO
:
242 *result
= (void *)xpvd_dip
;
243 return (DDI_SUCCESS
);
249 xpvd_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
)
251 extern void xvdi_watch_devices(int);
252 #ifdef XPV_HVM_DRIVER
253 extern dev_info_t
*xpv_dip
;
255 if (xpv_dip
== NULL
) {
256 if (ddi_hold_installed_driver(ddi_name_to_major("xpv")) ==
258 cmn_err(CE_WARN
, "Couldn't initialize xpv framework");
259 return (DDI_FAILURE
);
262 #endif /* XPV_HVM_DRIVER */
264 if (ndi_event_alloc_hdl(devi
, 0, &xpvd_ndi_event_handle
,
265 NDI_SLEEP
) != NDI_SUCCESS
) {
267 return (DDI_FAILURE
);
269 if (ndi_event_bind_set(xpvd_ndi_event_handle
, &xpvd_ndi_events
,
270 NDI_SLEEP
) != NDI_SUCCESS
) {
271 (void) ndi_event_free_hdl(xpvd_ndi_event_handle
);
273 return (DDI_FAILURE
);
276 #ifdef XPV_HVM_DRIVER
277 (void) ddi_prop_update_int(DDI_DEV_T_NONE
, devi
, DDI_NO_AUTODETACH
, 1);
280 * Report our version to dom0.
282 if (xenbus_printf(XBT_NULL
, "guest/xpvd", "version", "%d",
284 cmn_err(CE_WARN
, "xpvd: couldn't write version\n");
285 #endif /* XPV_HVM_DRIVER */
287 /* watch both frontend and backend for new devices */
288 if (DOMAIN_IS_INITDOMAIN(xen_info
))
289 (void) xs_register_xenbus_callback(xvdi_watch_devices
);
291 xvdi_watch_devices(XENSTORE_UP
);
294 ddi_report_dev(devi
);
296 return (DDI_SUCCESS
);
301 xpvd_detach(dev_info_t
*devi
, ddi_detach_cmd_t cmd
)
303 return (DDI_FAILURE
);
309 * Query xenstore for the value of properties if DDI_PROP_NOTPROM
310 * is not set. Xenstore property values are represented as ascii strings.
313 xpvd_prop_op(dev_t dev
, dev_info_t
*dip
, dev_info_t
*ch_dip
,
314 ddi_prop_op_t prop_op
, int mod_flags
, char *name
, caddr_t valuep
,
318 struct xendev_ppd
*pdp
;
324 pdp
= (struct xendev_ppd
*)ddi_get_parent_data(ch_dip
);
326 if ((pdp
== NULL
) || !(mod_flags
& (DDI_PROP_CANSLEEP
)) ||
327 (mod_flags
& DDI_PROP_NOTPROM
) || (pdp
->xd_xsdev
.nodename
== NULL
))
330 * First try reading the property off the the frontend. if that
331 * fails, try and read it from the backend node. If that
332 * also fails, pass the request on the DDI framework
335 if ((xenbus_read(XBT_NULL
, pdp
->xd_xsdev
.nodename
, name
, &prop_str
,
336 &len
) == 0) && (prop_str
!= NULL
) && (strlen(prop_str
) != 0))
340 if ((pdp
->xd_xsdev
.otherend
!= NULL
) &&
341 (xenbus_read(XBT_NULL
, pdp
->xd_xsdev
.otherend
, name
, &prop_str
,
342 &len
) == 0) && (prop_str
!= NULL
) && (strlen(prop_str
) != 0))
346 return (ddi_bus_prop_op(dev
, dip
, ch_dip
, prop_op
,
347 mod_flags
| DDI_PROP_NOTPROM
, name
, valuep
, lengthp
));
350 prop_len
= strlen(prop_str
) + 1;
351 rv
= DDI_PROP_SUCCESS
;
358 case PROP_LEN_AND_VAL_ALLOC
:
359 buff
= kmem_alloc((size_t)prop_len
, KM_SLEEP
);
360 *(caddr_t
*)valuep
= (caddr_t
)buff
;
362 case PROP_LEN_AND_VAL_BUF
:
363 buff
= (caddr_t
)valuep
;
364 if (*lengthp
< prop_len
)
365 rv
= DDI_PROP_BUF_TOO_SMALL
;
368 rv
= DDI_PROP_INVAL_ARG
;
372 if ((rv
== DDI_PROP_SUCCESS
) && (prop_len
> 0)) {
373 bcopy(prop_str
, buff
, prop_len
);
376 kmem_free(prop_str
, len
);
382 * return address of the device's interrupt spec structure.
386 xpvd_get_ispec(dev_info_t
*rdip
, uint_t inumber
)
388 struct xendev_ppd
*pdp
;
390 ASSERT(inumber
== 0);
392 if ((pdp
= ddi_get_parent_data(rdip
)) == NULL
)
395 return (&pdp
->xd_ispec
);
399 * return (and determine) the interrupt priority of the device.
403 xpvd_get_priority(dev_info_t
*dip
, int inum
, int *pri
)
405 struct xendev_ppd
*pdp
;
406 struct intrspec
*ispec
;
408 uint_t num_intpriorities
;
410 DDI_INTR_NEXDBG((CE_CONT
, "xpvd_get_priority: dip = 0x%p\n",
415 if ((pdp
= ddi_get_parent_data(dip
)) == NULL
)
416 return (DDI_FAILURE
);
418 ispec
= &pdp
->xd_ispec
;
421 * Set the default priority based on the device class. The
422 * "interrupt-priorities" property can be used to override
425 if (ispec
->intrspec_pri
== 0) {
426 ispec
->intrspec_pri
= xendev_devclass_ipl(pdp
->xd_devclass
);
427 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY
, dip
,
428 DDI_PROP_NOTPROM
| DDI_PROP_DONTPASS
,
429 "interrupt-priorities", &intpriorities
,
430 &num_intpriorities
) == DDI_PROP_SUCCESS
) {
431 ispec
->intrspec_pri
= intpriorities
[0];
432 ddi_prop_free(intpriorities
);
435 *pri
= ispec
->intrspec_pri
;
436 return (DDI_SUCCESS
);
441 * xpvd_intr_ops: bus_intr_op() function for interrupt support
445 xpvd_intr_ops(dev_info_t
*pdip
, dev_info_t
*rdip
, ddi_intr_op_t intr_op
,
446 ddi_intr_handle_impl_t
*hdlp
, void *result
)
449 struct intrspec
*ispec
;
450 struct xendev_ppd
*pdp
;
452 DDI_INTR_NEXDBG((CE_CONT
,
453 "xpvd_intr_ops: pdip 0x%p, rdip 0x%p, op %x handle 0x%p\n",
454 (void *)pdip
, (void *)rdip
, intr_op
, (void *)hdlp
));
456 /* Process the request */
458 case DDI_INTROP_SUPPORTED_TYPES
:
459 /* Fixed supported by default */
460 *(int *)result
= DDI_INTR_TYPE_FIXED
;
463 case DDI_INTROP_NINTRS
:
467 case DDI_INTROP_ALLOC
:
469 * FIXED interrupts: just return available interrupts
471 if (hdlp
->ih_type
== DDI_INTR_TYPE_FIXED
) {
473 * event channels are edge-triggered, maskable,
474 * and support int pending.
476 hdlp
->ih_cap
|= XENDEV_INTR_CAPABILITIES
;
477 *(int *)result
= 1; /* DDI_INTR_TYPE_FIXED */
479 return (DDI_FAILURE
);
483 case DDI_INTROP_FREE
:
484 ispec
= xpvd_get_ispec(rdip
, (int)hdlp
->ih_inum
);
486 return (DDI_FAILURE
);
487 ispec
->intrspec_pri
= 0; /* mark as un-initialized */
490 case DDI_INTROP_GETPRI
:
491 if (xpvd_get_priority(rdip
, hdlp
->ih_inum
, &priority
) !=
493 return (DDI_FAILURE
);
494 DDI_INTR_NEXDBG((CE_CONT
, "xpvd_intr_ops: priority = 0x%x\n",
496 *(int *)result
= priority
;
499 case DDI_INTROP_SETPRI
:
500 /* Validate the interrupt priority passed */
501 if (*(int *)result
> LOCK_LEVEL
)
502 return (DDI_FAILURE
);
504 /* Ensure that PSM is all initialized */
505 if (psm_intr_ops
== NULL
)
506 return (DDI_FAILURE
);
508 /* Change the priority */
509 if ((*psm_intr_ops
)(rdip
, hdlp
, PSM_INTR_OP_SET_PRI
, result
) ==
511 return (DDI_FAILURE
);
513 ispec
= xpvd_get_ispec(rdip
, (int)hdlp
->ih_inum
);
515 return (DDI_FAILURE
);
516 ispec
->intrspec_pri
= *(int *)result
;
519 case DDI_INTROP_ADDISR
:
521 ispec
= xpvd_get_ispec(rdip
, (int)hdlp
->ih_inum
);
523 return (DDI_FAILURE
);
524 ispec
->intrspec_func
= hdlp
->ih_cb_func
;
528 case DDI_INTROP_REMISR
:
529 ispec
= xpvd_get_ispec(rdip
, (int)hdlp
->ih_inum
);
530 pdp
= (struct xendev_ppd
*)ddi_get_parent_data(rdip
);
533 ASSERT(pdp
->xd_evtchn
!= INVALID_EVTCHN
);
536 ispec
->intrspec_vec
= 0;
537 ispec
->intrspec_func
= (uint_t (*)()) 0;
539 pdp
->xd_evtchn
= INVALID_EVTCHN
;
542 case DDI_INTROP_GETCAP
:
543 if (hdlp
->ih_type
== DDI_INTR_TYPE_FIXED
) {
545 * event channels are edge-triggered, maskable,
546 * and support int pending.
548 *(int *)result
= XENDEV_INTR_CAPABILITIES
;
551 return (DDI_FAILURE
);
553 DDI_INTR_NEXDBG((CE_CONT
, "xpvd: GETCAP returned = %x\n",
556 case DDI_INTROP_SETCAP
:
557 DDI_INTR_NEXDBG((CE_CONT
, "xpvd_intr_ops: SETCAP cap=0x%x\n",
559 if (psm_intr_ops
== NULL
)
560 return (DDI_FAILURE
);
562 if ((*psm_intr_ops
)(rdip
, hdlp
, PSM_INTR_OP_SET_CAP
, result
)) {
563 DDI_INTR_NEXDBG((CE_CONT
, "GETCAP: psm_intr_ops"
564 " returned failure\n"));
565 return (DDI_FAILURE
);
569 case DDI_INTROP_ENABLE
:
570 if (psm_intr_ops
== NULL
)
571 return (DDI_FAILURE
);
573 if (xpvd_enable_intr(rdip
, hdlp
, (int)hdlp
->ih_inum
) !=
575 return (DDI_FAILURE
);
577 DDI_INTR_NEXDBG((CE_CONT
, "xpvd_intr_ops: ENABLE vec=0x%x\n",
581 case DDI_INTROP_DISABLE
:
582 if (psm_intr_ops
== NULL
)
583 return (DDI_FAILURE
);
584 xpvd_disable_intr(rdip
, hdlp
, hdlp
->ih_inum
);
585 DDI_INTR_NEXDBG((CE_CONT
, "xpvd_intr_ops: DISABLE vec = %x\n",
589 case DDI_INTROP_BLOCKENABLE
:
590 case DDI_INTROP_BLOCKDISABLE
:
591 return (DDI_FAILURE
);
593 case DDI_INTROP_SETMASK
:
594 case DDI_INTROP_CLRMASK
:
595 #ifdef XPV_HVM_DRIVER
596 return (DDI_ENOTSUP
);
601 if (hdlp
->ih_type
!= DDI_INTR_TYPE_FIXED
)
602 return (DDI_FAILURE
);
603 if (intr_op
== DDI_INTROP_SETMASK
) {
604 ec_disable_irq(hdlp
->ih_vector
);
606 ec_enable_irq(hdlp
->ih_vector
);
610 case DDI_INTROP_GETPENDING
:
611 #ifdef XPV_HVM_DRIVER
612 return (DDI_ENOTSUP
);
614 if (hdlp
->ih_type
!= DDI_INTR_TYPE_FIXED
)
615 return (DDI_FAILURE
);
616 *(int *)result
= ec_pending_irq(hdlp
->ih_vector
);
617 DDI_INTR_NEXDBG((CE_CONT
, "xpvd: GETPENDING returned = %x\n",
622 case DDI_INTROP_NAVAIL
:
624 DDI_INTR_NEXDBG((CE_CONT
, "xpvd: NAVAIL returned = %x\n",
629 return (i_ddi_intr_ops(pdip
, rdip
, intr_op
, hdlp
, result
));
632 return (DDI_SUCCESS
);
637 xpvd_enable_intr(dev_info_t
*rdip
, ddi_intr_handle_impl_t
*hdlp
, int inum
)
640 ihdl_plat_t
*ihdl_plat_datap
= (ihdl_plat_t
*)hdlp
->ih_private
;
642 DDI_INTR_NEXDBG((CE_CONT
, "xpvd_enable_intr: hdlp %p inum %x\n",
643 (void *)hdlp
, inum
));
645 ihdl_plat_datap
->ip_ispecp
= xpvd_get_ispec(rdip
, inum
);
646 if (ihdl_plat_datap
->ip_ispecp
== NULL
)
647 return (DDI_FAILURE
);
649 /* translate the interrupt if needed */
650 (void) (*psm_intr_ops
)(rdip
, hdlp
, PSM_INTR_OP_XLATE_VECTOR
, &vector
);
651 DDI_INTR_NEXDBG((CE_CONT
, "xpvd_enable_intr: priority=%x vector=%x\n",
652 hdlp
->ih_pri
, vector
));
654 /* Add the interrupt handler */
655 if (!add_avintr((void *)hdlp
, hdlp
->ih_pri
, hdlp
->ih_cb_func
,
656 DEVI(rdip
)->devi_name
, vector
, hdlp
->ih_cb_arg1
,
657 hdlp
->ih_cb_arg2
, NULL
, rdip
))
658 return (DDI_FAILURE
);
660 /* Note this really is an irq. */
661 hdlp
->ih_vector
= (ushort_t
)vector
;
663 return (DDI_SUCCESS
);
668 xpvd_disable_intr(dev_info_t
*rdip
, ddi_intr_handle_impl_t
*hdlp
, int inum
)
671 ihdl_plat_t
*ihdl_plat_datap
= (ihdl_plat_t
*)hdlp
->ih_private
;
673 DDI_INTR_NEXDBG((CE_CONT
, "xpvd_disable_intr: \n"));
674 ihdl_plat_datap
->ip_ispecp
= xpvd_get_ispec(rdip
, inum
);
675 if (ihdl_plat_datap
->ip_ispecp
== NULL
)
678 /* translate the interrupt if needed */
679 (void) (*psm_intr_ops
)(rdip
, hdlp
, PSM_INTR_OP_XLATE_VECTOR
, &vector
);
681 /* Disable the interrupt handler */
682 rem_avintr((void *)hdlp
, hdlp
->ih_pri
, hdlp
->ih_cb_func
, vector
);
683 ihdl_plat_datap
->ip_ispecp
= NULL
;
688 xpvd_ctlops(dev_info_t
*dip
, dev_info_t
*rdip
,
689 ddi_ctl_enum_t ctlop
, void *arg
, void *result
)
692 case DDI_CTLOPS_REPORTDEV
:
693 if (rdip
== (dev_info_t
*)0)
694 return (DDI_FAILURE
);
695 cmn_err(CE_CONT
, "?%s@%s, %s%d\n", ddi_node_name(rdip
),
696 ddi_get_name_addr(rdip
), ddi_driver_name(rdip
),
697 ddi_get_instance(rdip
));
698 return (DDI_SUCCESS
);
700 case DDI_CTLOPS_INITCHILD
:
701 return (xpvd_initchild((dev_info_t
*)arg
));
703 case DDI_CTLOPS_UNINITCHILD
:
704 return (xpvd_removechild((dev_info_t
*)arg
));
706 case DDI_CTLOPS_SIDDEV
:
707 return (DDI_SUCCESS
);
709 case DDI_CTLOPS_REGSIZE
:
710 case DDI_CTLOPS_NREGS
:
711 return (DDI_FAILURE
);
713 case DDI_CTLOPS_POWER
: {
714 return (ddi_ctlops(dip
, rdip
, ctlop
, arg
, result
));
718 return (ddi_ctlops(dip
, rdip
, ctlop
, arg
, result
));
726 * Assign the address portion of the node name
729 xpvd_name_child(dev_info_t
*child
, char *addr
, int addrlen
)
732 uint_t ndomain
, nvdev
;
736 * i_xpvd_parse_devname() knows the formats used by this
737 * routine. If this code changes, so must that.
740 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY
, child
, DDI_PROP_DONTPASS
,
741 "domain", &domain
, &ndomain
) != DDI_PROP_SUCCESS
)
742 return (DDI_FAILURE
);
743 ASSERT(ndomain
== 1);
746 * Use "domain" and "vdev" properties (backend drivers).
748 if (*domain
!= DOMID_SELF
) {
749 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY
, child
,
750 DDI_PROP_DONTPASS
, "vdev", &vdev
, &nvdev
)
751 != DDI_PROP_SUCCESS
) {
752 ddi_prop_free(domain
);
753 return (DDI_FAILURE
);
757 (void) snprintf(addr
, addrlen
, "%d,%d", domain
[0], vdev
[0]);
759 ddi_prop_free(domain
);
760 return (DDI_SUCCESS
);
762 ddi_prop_free(domain
);
765 * Use "unit-address" property (frontend/softdev drivers).
767 if (ddi_prop_lookup_string(DDI_DEV_T_ANY
, child
, DDI_PROP_DONTPASS
,
768 "unit-address", &prop_str
) != DDI_PROP_SUCCESS
)
769 return (DDI_FAILURE
);
770 (void) strlcpy(addr
, prop_str
, addrlen
);
771 ddi_prop_free(prop_str
);
772 return (DDI_SUCCESS
);
776 xpvd_initchild(dev_info_t
*child
)
781 * Pseudo nodes indicate a prototype node with per-instance
782 * properties to be merged into the real h/w device node.
784 if (ndi_dev_is_persistent_node(child
) == 0) {
785 ddi_set_parent_data(child
, NULL
);
788 * Try to merge the properties from this prototype
789 * node into real h/w nodes.
791 if (ndi_merge_node(child
, xpvd_name_child
) == DDI_SUCCESS
) {
793 * Merged ok - return failure to remove the node.
795 ddi_set_name_addr(child
, NULL
);
796 return (DDI_FAILURE
);
800 * The child was not merged into a h/w node,
801 * but there's not much we can do with it other
802 * than return failure to cause the node to be removed.
804 cmn_err(CE_WARN
, "!%s@%s: %s.conf properties not merged",
805 ddi_get_name(child
), ddi_get_name_addr(child
),
806 ddi_get_name(child
));
807 ddi_set_name_addr(child
, NULL
);
808 return (DDI_NOT_WELL_FORMED
);
811 if (xvdi_init_dev(child
) != DDI_SUCCESS
)
812 return (DDI_FAILURE
);
814 if (xpvd_name_child(child
, addr
, sizeof (addr
)) != DDI_SUCCESS
) {
815 xvdi_uninit_dev(child
);
816 return (DDI_FAILURE
);
818 ddi_set_name_addr(child
, addr
);
820 return (DDI_SUCCESS
);
824 xpvd_removechild(dev_info_t
*dip
)
826 xvdi_uninit_dev(dip
);
828 ddi_set_name_addr(dip
, NULL
);
831 * Strip the node to properly convert it back to prototype
834 ddi_remove_minor_node(dip
, NULL
);
836 return (DDI_SUCCESS
);
840 xpvd_bus_unconfig(dev_info_t
*parent
, uint_t flag
, ddi_bus_config_op_t op
,
843 return (ndi_busop_bus_unconfig(parent
, flag
, op
, device_name
));
847 * Given the name of a child of xpvd, determine the device class,
848 * domain and vdevnum to which it refers.
851 i_xpvd_parse_devname(char *name
, xendev_devclass_t
*devclassp
,
852 domid_t
*domp
, int *vdevp
)
854 int len
= strlen(name
) + 1;
855 char *device_name
= i_ddi_strdup(name
, KM_SLEEP
);
856 char *cname
= NULL
, *caddr
= NULL
;
859 i_ddi_parse_name(device_name
, &cname
, &caddr
, NULL
);
861 if ((cname
== NULL
) || (strlen(cname
) == 0) ||
862 (caddr
== NULL
) || (strlen(caddr
) == 0)) {
867 *devclassp
= xendev_nodename_to_devclass(cname
);
868 if (*devclassp
< 0) {
874 * Parsing the address component requires knowledge of how
875 * xpvd_name_child() works. If that code changes, so must
879 /* Backend format is "<domain>,<vdev>". */
880 if (sscanf(caddr
, "%hu,%d", domp
, vdevp
) == 2) {
885 /* Frontend format is "<vdev>". */
887 if (sscanf(caddr
, "%d", vdevp
) == 1)
890 kmem_free(device_name
, len
);
898 * Enumerate the exact instance of a driver.
901 * Enumerate all the instances of all the possible children (seen before
902 * and never seen before).
905 * Enumerate all the instances of a particular driver.
908 xpvd_bus_config(dev_info_t
*parent
, uint_t flag
, ddi_bus_config_op_t op
,
909 void *arg
, dev_info_t
**childp
)
914 ndi_devi_enter(parent
, &circ
);
917 case BUS_CONFIG_ONE
: {
918 xendev_devclass_t devclass
;
922 if (!i_xpvd_parse_devname(arg
, &devclass
, &dom
, &vdev
)) {
923 ndi_devi_exit(parent
, circ
);
924 return (NDI_FAILURE
);
927 *childp
= xvdi_find_dev(parent
, devclass
, dom
, vdev
);
929 *childp
= xvdi_create_dev(parent
, devclass
, dom
, vdev
);
931 ndi_devi_exit(parent
, circ
);
934 return (NDI_FAILURE
);
936 return (ndi_busop_bus_config(parent
, flag
,
937 op
, arg
, childp
, 0));
940 case BUS_CONFIG_DRIVER
: {
941 xendev_devclass_t devclass
= XEN_INVAL
;
943 cname
= ddi_major_to_name((major_t
)(uintptr_t)arg
);
945 devclass
= xendev_nodename_to_devclass(cname
);
947 if (devclass
== XEN_INVAL
) {
948 ndi_devi_exit(parent
, circ
);
949 return (NDI_FAILURE
);
951 xendev_enum_class(parent
, devclass
);
952 ndi_devi_exit(parent
, circ
);
953 return (ndi_busop_bus_config(parent
, flag
, op
,
960 xendev_enum_all(parent
, B_FALSE
);
961 ndi_devi_exit(parent
, circ
);
963 return (ndi_busop_bus_config(parent
, flag
, op
,
967 ndi_devi_exit(parent
, circ
);
968 return (NDI_FAILURE
);
974 xpvd_get_eventcookie(dev_info_t
*dip
, dev_info_t
*rdip
,
975 char *eventname
, ddi_eventcookie_t
*cookie
)
977 return (ndi_event_retrieve_cookie(xpvd_ndi_event_handle
,
978 rdip
, eventname
, cookie
, NDI_EVENT_NOPASS
));
983 xpvd_add_eventcall(dev_info_t
*dip
, dev_info_t
*rdip
,
984 ddi_eventcookie_t cookie
, void (*callback
)(dev_info_t
*dip
,
985 ddi_eventcookie_t cookie
, void *arg
, void *bus_impldata
),
986 void *arg
, ddi_callback_id_t
*cb_id
)
988 return (ndi_event_add_callback(xpvd_ndi_event_handle
,
989 rdip
, cookie
, callback
, arg
, NDI_SLEEP
, cb_id
));
994 xpvd_remove_eventcall(dev_info_t
*dip
, ddi_callback_id_t cb_id
)
996 return (ndi_event_remove_callback(xpvd_ndi_event_handle
,
1002 xpvd_post_event(dev_info_t
*dip
, dev_info_t
*rdip
,
1003 ddi_eventcookie_t cookie
, void *bus_impldata
)
1005 return (ndi_event_run_callbacks(xpvd_ndi_event_handle
, rdip
,
1006 cookie
, bus_impldata
));