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 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
27 * Copyright 2016 Joyent, Inc.
31 * Host to PCI local bus driver
35 #include <sys/modctl.h>
37 #include <sys/pci_impl.h>
38 #include <sys/sysmacros.h>
39 #include <sys/sunndi.h>
40 #include <sys/ddifm.h>
41 #include <sys/ndifm.h>
42 #include <sys/fm/protocol.h>
43 #include <sys/hotplug/pci/pcihp.h>
44 #include <io/pci/pci_common.h>
45 #include <io/pci/pci_tools_ext.h>
47 /* Save minimal state. */
51 * Bus Operation functions
53 static int pci_bus_map(dev_info_t
*, dev_info_t
*, ddi_map_req_t
*,
54 off_t
, off_t
, caddr_t
*);
55 static int pci_ctlops(dev_info_t
*, dev_info_t
*, ddi_ctl_enum_t
,
57 static int pci_intr_ops(dev_info_t
*, dev_info_t
*, ddi_intr_op_t
,
58 ddi_intr_handle_impl_t
*, void *);
59 static int pci_fm_init(dev_info_t
*, dev_info_t
*, int,
60 ddi_iblock_cookie_t
*);
61 static int pci_fm_callback(dev_info_t
*, ddi_fm_error_t
*, const void *);
63 struct bus_ops pci_bus_ops
= {
80 0, /* (*bus_get_eventcookie)(); */
81 0, /* (*bus_add_eventcall)(); */
82 0, /* (*bus_remove_eventcall)(); */
83 0, /* (*bus_post_event)(); */
84 0, /* (*bus_intr_ctl)(); */
85 0, /* (*bus_config)(); */
86 0, /* (*bus_unconfig)(); */
87 pci_fm_init
, /* (*bus_fm_init)(); */
88 NULL
, /* (*bus_fm_fini)(); */
89 NULL
, /* (*bus_fm_access_enter)(); */
90 NULL
, /* (*bus_fm_access_exit)(); */
91 NULL
, /* (*bus_power)(); */
92 pci_intr_ops
/* (*bus_intr_op)(); */
96 * One goal here is to leverage off of the pcihp.c source without making
97 * changes to it. Call into it's cb_ops directly if needed, piggybacking
98 * anything else needed by the pci_tools.c module. Only pci_tools and pcihp
99 * will be opening PCI nexus driver file descriptors.
101 static int pci_open(dev_t
*, int, int, cred_t
*);
102 static int pci_close(dev_t
, int, int, cred_t
*);
103 static int pci_ioctl(dev_t
, int, intptr_t, int, cred_t
*, int *);
104 static int pci_prop_op(dev_t
, dev_info_t
*, ddi_prop_op_t
, int, char *,
106 static int pci_info(dev_info_t
*, ddi_info_cmd_t
, void *, void **);
107 static void pci_peekpoke_cb(dev_info_t
*, ddi_fm_error_t
*);
109 struct cb_ops pci_cb_ops
= {
111 pci_close
, /* close */
112 nodev
, /* strategy */
117 pci_ioctl
, /* ioctl */
122 pci_prop_op
, /* cb_prop_op */
123 NULL
, /* streamtab */
124 D_NEW
| D_MP
| D_HOTPLUG
, /* Driver compatibility flag */
126 nodev
, /* int (*cb_aread)() */
127 nodev
/* int (*cb_awrite)() */
131 * Device Node Operation functions
133 static int pci_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
);
134 static int pci_detach(dev_info_t
*devi
, ddi_detach_cmd_t cmd
);
136 struct dev_ops pci_ops
= {
137 DEVO_REV
, /* devo_rev */
140 nulldev
, /* identify */
142 pci_attach
, /* attach */
143 pci_detach
, /* detach */
145 &pci_cb_ops
, /* driver operations */
146 &pci_bus_ops
, /* bus operations */
148 ddi_quiesce_not_needed
/* quiesce */
152 * This variable controls the default setting of the command register
153 * for pci devices. See pci_initchild() for details.
155 static ushort_t pci_command_default
= PCI_COMM_ME
|
160 * Internal routines in support of particular pci_ctlops.
162 static int pci_removechild(dev_info_t
*child
);
163 static int pci_initchild(dev_info_t
*child
);
166 * Module linkage information for the kernel.
169 static struct modldrv modldrv
= {
170 &mod_driverops
, /* Type of module */
171 "x86 Host to PCI nexus driver", /* Name of module */
172 &pci_ops
, /* driver ops */
175 static struct modlinkage modlinkage
= {
187 * Initialize per-pci bus soft state pointer.
189 e
= ddi_soft_state_init(&pci_statep
, sizeof (pci_state_t
), 1);
193 if ((e
= mod_install(&modlinkage
)) != 0)
194 ddi_soft_state_fini(&pci_statep
);
204 rc
= mod_remove(&modlinkage
);
208 ddi_soft_state_fini(&pci_statep
);
214 _info(struct modinfo
*modinfop
)
216 return (mod_info(&modlinkage
, modinfop
));
221 pci_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
)
224 * Use the minor number as constructed by pcihp, as the index value to
225 * ddi_soft_state_zalloc.
227 int instance
= ddi_get_instance(devi
);
228 pci_state_t
*pcip
= NULL
;
234 return (DDI_SUCCESS
);
237 return (DDI_FAILURE
);
240 if (ddi_prop_update_string(DDI_DEV_T_NONE
, devi
, "device_type", "pci")
241 != DDI_PROP_SUCCESS
) {
242 cmn_err(CE_WARN
, "pci: 'device_type' prop create failed");
245 if (ddi_soft_state_zalloc(pci_statep
, instance
) == DDI_SUCCESS
) {
246 pcip
= ddi_get_soft_state(pci_statep
, instance
);
253 pcip
->pci_dip
= devi
;
254 pcip
->pci_soft_state
= PCI_SOFT_STATE_CLOSED
;
257 * Initialize hotplug support on this bus. At minimum
258 * (for non hotplug bus) this would create ":devctl" minor
259 * node to support DEVCTL_DEVICE_* and DEVCTL_BUS_* ioctls
262 if (pcihp_init(devi
) != DDI_SUCCESS
) {
263 cmn_err(CE_WARN
, "pci: Failed to setup hotplug framework");
267 /* Second arg: initialize for pci, not pci_express */
268 if (pcitool_init(devi
, B_FALSE
) != DDI_SUCCESS
) {
269 goto bad_pcitool_init
;
272 pcip
->pci_fmcap
= DDI_FM_ERRCB_CAPABLE
|
273 DDI_FM_ACCCHK_CAPABLE
| DDI_FM_DMACHK_CAPABLE
;
274 ddi_fm_init(devi
, &pcip
->pci_fmcap
, &pcip
->pci_fm_ibc
);
275 mutex_init(&pcip
->pci_mutex
, NULL
, MUTEX_DRIVER
, NULL
);
276 mutex_init(&pcip
->pci_err_mutex
, NULL
, MUTEX_DRIVER
,
277 (void *)pcip
->pci_fm_ibc
);
278 mutex_init(&pcip
->pci_peek_poke_mutex
, NULL
, MUTEX_DRIVER
,
279 (void *)pcip
->pci_fm_ibc
);
280 if (pcip
->pci_fmcap
& DDI_FM_ERRCB_CAPABLE
) {
281 pci_ereport_setup(devi
);
282 ddi_fm_handler_register(devi
, pci_fm_callback
, NULL
);
285 ddi_report_dev(devi
);
287 return (DDI_SUCCESS
);
290 (void) pcihp_uninit(devi
);
292 ddi_soft_state_free(pci_statep
, instance
);
294 return (DDI_FAILURE
);
299 pci_detach(dev_info_t
*devi
, ddi_detach_cmd_t cmd
)
301 int instance
= ddi_get_instance(devi
);
304 pcip
= ddi_get_soft_state(pci_statep
, ddi_get_instance(devi
));
309 if (pcip
->pci_fmcap
& DDI_FM_ERRCB_CAPABLE
) {
310 ddi_fm_handler_unregister(devi
);
311 pci_ereport_teardown(devi
);
313 mutex_destroy(&pcip
->pci_peek_poke_mutex
);
314 mutex_destroy(&pcip
->pci_err_mutex
);
315 mutex_destroy(&pcip
->pci_mutex
);
316 ddi_fm_fini(devi
); /* Uninitialize pcitool support. */
317 pcitool_uninit(devi
);
319 /* Uninitialize hotplug support on this bus. */
320 (void) pcihp_uninit(devi
);
322 ddi_soft_state_free(pci_statep
, instance
);
324 return (DDI_SUCCESS
);
326 return (DDI_SUCCESS
);
328 return (DDI_FAILURE
);
333 pci_bus_map(dev_info_t
*dip
, dev_info_t
*rdip
, ddi_map_req_t
*mp
,
334 off_t offset
, off_t len
, caddr_t
*vaddrp
)
336 struct regspec64 reg
;
339 ddi_acc_impl_t
*hdlp
;
340 pci_regspec_t pci_reg
;
341 pci_regspec_t
*pci_rp
;
343 uint64_t pci_rlength
;
345 pci_acc_cfblk_t
*cfp
;
349 mr
= *mp
; /* Get private copy of request */
352 if (mp
->map_handlep
!= NULL
) {
353 pcip
= ddi_get_soft_state(pci_statep
, ddi_get_instance(dip
));
354 hdlp
= (ddi_acc_impl_t
*)(mp
->map_handlep
)->ah_platform_private
;
355 hdlp
->ahi_err_mutexp
= &pcip
->pci_err_mutex
;
356 hdlp
->ahi_peekpoke_mutexp
= &pcip
->pci_peek_poke_mutex
;
357 hdlp
->ahi_scan_dip
= dip
;
358 hdlp
->ahi_scan
= pci_peekpoke_cb
;
362 * check for register number
364 switch (mp
->map_type
) {
366 pci_reg
= *(pci_regspec_t
*)(mp
->map_obj
.rp
);
368 if (pci_common_get_reg_prop(rdip
, pci_rp
) != DDI_SUCCESS
)
369 return (DDI_FAILURE
);
372 rnumber
= mp
->map_obj
.rnumber
;
374 * get ALL "reg" properties for dip, select the one of
375 * of interest. In x86, "assigned-addresses" property
376 * is identical to the "reg" property, so there is no
377 * need to cross check the two to determine the physical
378 * address of the registers.
379 * This routine still performs some validity checks to
380 * make sure that everything is okay.
382 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY
, rdip
,
383 DDI_PROP_DONTPASS
, "reg", (int **)&pci_rp
, &nelems
) !=
385 return (DDI_FAILURE
);
388 * validate the register number.
390 nelems
/= (sizeof (pci_regspec_t
) / sizeof (int));
391 if (rnumber
>= nelems
) {
392 ddi_prop_free(pci_rp
);
393 return (DDI_FAILURE
);
397 * copy the required entry.
399 pci_reg
= pci_rp
[rnumber
];
402 * free the memory allocated by ddi_prop_lookup_int_array
404 ddi_prop_free(pci_rp
);
407 if (pci_common_get_reg_prop(rdip
, pci_rp
) != DDI_SUCCESS
)
408 return (DDI_FAILURE
);
409 mp
->map_type
= DDI_MT_REGSPEC
;
412 return (DDI_ME_INVAL
);
415 space
= pci_rp
->pci_phys_hi
& PCI_REG_ADDR_M
;
418 * check for unmap and unlock of address space
420 if ((mp
->map_op
== DDI_MO_UNMAP
) || (mp
->map_op
== DDI_MO_UNLOCK
)) {
422 case PCI_ADDR_CONFIG
:
423 /* No work required on unmap of Config space */
424 return (DDI_SUCCESS
);
427 reg
.regspec_bustype
= 1;
432 reg
.regspec_bustype
= 0;
436 return (DDI_FAILURE
);
439 reg
.regspec_addr
= (uint64_t)pci_rp
->pci_phys_mid
<< 32 |
440 (uint64_t)pci_rp
->pci_phys_low
;
441 reg
.regspec_size
= (uint64_t)pci_rp
->pci_size_hi
<< 32 |
442 (uint64_t)pci_rp
->pci_size_low
;
445 * Adjust offset and length
446 * A non-zero length means override the one in the regspec.
448 if (reg
.regspec_addr
+ offset
< MAX(reg
.regspec_addr
, offset
))
449 return (DDI_FAILURE
);
450 reg
.regspec_addr
+= offset
;
452 reg
.regspec_size
= len
;
454 mp
->map_obj
.rp
= (struct regspec
*)®
;
455 mp
->map_flags
|= DDI_MF_EXT_REGSPEC
;
456 return (ddi_map(dip
, mp
, (off_t
)0, (off_t
)0, vaddrp
));
460 /* check for user mapping request - not legal for Config */
461 if (mp
->map_op
== DDI_MO_MAP_HANDLE
&& space
== PCI_ADDR_CONFIG
) {
462 return (DDI_FAILURE
);
466 * check for config space
467 * On x86, CONFIG is not mapped via MMU and there is
468 * no endian-ness issues. Set the attr field in the handle to
469 * indicate that the common routines to call the nexus driver.
471 if (space
== PCI_ADDR_CONFIG
) {
472 /* Can't map config space without a handle */
473 hp
= (ddi_acc_hdl_t
*)mp
->map_handlep
;
475 return (DDI_FAILURE
);
477 /* record the device address for future reference */
478 cfp
= (pci_acc_cfblk_t
*)&hp
->ah_bus_private
;
479 cfp
->c_busnum
= PCI_REG_BUS_G(pci_rp
->pci_phys_hi
);
480 cfp
->c_devnum
= PCI_REG_DEV_G(pci_rp
->pci_phys_hi
);
481 cfp
->c_funcnum
= PCI_REG_FUNC_G(pci_rp
->pci_phys_hi
);
483 *vaddrp
= (caddr_t
)offset
;
484 return (pci_fm_acc_setup(hp
, offset
, len
));
490 pci_rlength
= (uint64_t)pci_rp
->pci_size_low
|
491 (uint64_t)pci_rp
->pci_size_hi
<< 32;
492 if ((offset
>= pci_rlength
) || (len
> pci_rlength
) ||
493 (offset
+ len
> pci_rlength
) || (offset
+ len
< MAX(offset
, len
))) {
494 return (DDI_FAILURE
);
498 * convert the pci regsec into the generic regspec used by the
499 * parent root nexus driver.
503 reg
.regspec_bustype
= 1;
507 reg
.regspec_bustype
= 0;
510 return (DDI_FAILURE
);
513 reg
.regspec_addr
= (uint64_t)pci_rp
->pci_phys_mid
<< 32 |
514 (uint64_t)pci_rp
->pci_phys_low
;
515 reg
.regspec_size
= pci_rlength
;
518 * Adjust offset and length
519 * A non-zero length means override the one in the regspec.
521 if (reg
.regspec_addr
+ offset
< MAX(reg
.regspec_addr
, offset
))
522 return (DDI_FAILURE
);
523 reg
.regspec_addr
+= offset
;
525 reg
.regspec_size
= len
;
527 mp
->map_obj
.rp
= (struct regspec
*)®
;
528 mp
->map_flags
|= DDI_MF_EXT_REGSPEC
;
529 return (ddi_map(dip
, mp
, (off_t
)0, (off_t
)0, vaddrp
));
535 pci_ctlops(dev_info_t
*dip
, dev_info_t
*rdip
,
536 ddi_ctl_enum_t ctlop
, void *arg
, void *result
)
538 pci_regspec_t
*drv_regp
;
542 struct attachspec
*asp
;
543 struct detachspec
*dsp
;
546 case DDI_CTLOPS_REPORTDEV
:
547 if (rdip
== (dev_info_t
*)0)
548 return (DDI_FAILURE
);
549 cmn_err(CE_CONT
, "?PCI-device: %s@%s, %s%d\n",
550 ddi_node_name(rdip
), ddi_get_name_addr(rdip
),
551 ddi_driver_name(rdip
),
552 ddi_get_instance(rdip
));
553 return (DDI_SUCCESS
);
555 case DDI_CTLOPS_INITCHILD
:
556 return (pci_initchild((dev_info_t
*)arg
));
558 case DDI_CTLOPS_UNINITCHILD
:
559 return (pci_removechild((dev_info_t
*)arg
));
561 case DDI_CTLOPS_SIDDEV
:
562 return (DDI_SUCCESS
);
564 case DDI_CTLOPS_REGSIZE
:
565 case DDI_CTLOPS_NREGS
:
566 if (rdip
== (dev_info_t
*)0)
567 return (DDI_FAILURE
);
570 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY
, rdip
,
571 DDI_PROP_DONTPASS
, "reg", (int **)&drv_regp
,
572 ®len
) != DDI_PROP_SUCCESS
) {
573 return (DDI_FAILURE
);
576 totreg
= (reglen
* sizeof (int)) / sizeof (pci_regspec_t
);
577 if (ctlop
== DDI_CTLOPS_NREGS
)
578 *(int *)result
= totreg
;
579 else if (ctlop
== DDI_CTLOPS_REGSIZE
) {
585 ddi_prop_free(drv_regp
);
586 return (DDI_FAILURE
);
588 val
= drv_regp
[rn
].pci_size_low
|
589 (uint64_t)drv_regp
[rn
].pci_size_hi
<< 32;
595 dev_err(rdip
, ce
, "failed to get register "
596 "size, value larger than OFF_MAX: 0x%"
598 return (DDI_FAILURE
);
600 *(off_t
*)result
= (off_t
)val
;
602 ddi_prop_free(drv_regp
);
604 return (DDI_SUCCESS
);
606 case DDI_CTLOPS_POWER
: {
607 power_req_t
*reqp
= (power_req_t
*)arg
;
609 * We currently understand reporting of PCI_PM_IDLESPEED
610 * capability. Everything else is passed up.
612 if ((reqp
->request_type
== PMR_REPORT_PMCAP
) &&
613 (reqp
->req
.report_pmcap_req
.cap
== PCI_PM_IDLESPEED
)) {
615 return (DDI_SUCCESS
);
617 return (ddi_ctlops(dip
, rdip
, ctlop
, arg
, result
));
620 case DDI_CTLOPS_PEEK
:
621 case DDI_CTLOPS_POKE
:
622 pcip
= ddi_get_soft_state(pci_statep
, ddi_get_instance(dip
));
623 return (pci_peekpoke_check(dip
, rdip
, ctlop
, arg
, result
,
624 pci_common_peekpoke
, &pcip
->pci_err_mutex
,
625 &pcip
->pci_peek_poke_mutex
, pci_peekpoke_cb
));
627 /* for now only X86 systems support PME wakeup from suspended state */
628 case DDI_CTLOPS_ATTACH
:
629 asp
= (struct attachspec
*)arg
;
630 if (asp
->cmd
== DDI_RESUME
&& asp
->when
== DDI_PRE
)
631 if (pci_pre_resume(rdip
) != DDI_SUCCESS
)
632 return (DDI_FAILURE
);
633 return (ddi_ctlops(dip
, rdip
, ctlop
, arg
, result
));
635 case DDI_CTLOPS_DETACH
:
636 dsp
= (struct detachspec
*)arg
;
637 if (dsp
->cmd
== DDI_SUSPEND
&& dsp
->when
== DDI_POST
)
638 if (pci_post_suspend(rdip
) != DDI_SUCCESS
)
639 return (DDI_FAILURE
);
640 return (ddi_ctlops(dip
, rdip
, ctlop
, arg
, result
));
643 return (ddi_ctlops(dip
, rdip
, ctlop
, arg
, result
));
654 pci_intr_ops(dev_info_t
*pdip
, dev_info_t
*rdip
, ddi_intr_op_t intr_op
,
655 ddi_intr_handle_impl_t
*hdlp
, void *result
)
657 return (pci_common_intr_ops(pdip
, rdip
, intr_op
, hdlp
, result
));
662 pci_initchild(dev_info_t
*child
)
665 ddi_acc_handle_t config_handle
;
666 ushort_t command_preserve
, command
;
668 if (pci_common_name_child(child
, name
, 80) != DDI_SUCCESS
) {
669 return (DDI_FAILURE
);
671 ddi_set_name_addr(child
, name
);
674 * Pseudo nodes indicate a prototype node with per-instance
675 * properties to be merged into the real h/w device node.
676 * The interpretation of the unit-address is DD[,F]
677 * where DD is the device id and F is the function.
679 if (ndi_dev_is_persistent_node(child
) == 0) {
680 extern int pci_allow_pseudo_children
;
682 ddi_set_parent_data(child
, NULL
);
685 * Try to merge the properties from this prototype
686 * node into real h/w nodes.
688 if (ndi_merge_node(child
, pci_common_name_child
) ==
691 * Merged ok - return failure to remove the node.
693 ddi_set_name_addr(child
, NULL
);
694 return (DDI_FAILURE
);
697 /* workaround for ddivs to run under PCI */
698 if (pci_allow_pseudo_children
) {
700 * If the "interrupts" property doesn't exist,
701 * this must be the ddivs no-intr case, and it returns
702 * DDI_SUCCESS instead of DDI_FAILURE.
704 if (ddi_prop_get_int(DDI_DEV_T_ANY
, child
,
705 DDI_PROP_DONTPASS
, "interrupts", -1) == -1)
706 return (DDI_SUCCESS
);
708 * Create the ddi_parent_private_data for a pseudo
711 pci_common_set_parent_private_data(child
);
712 return (DDI_SUCCESS
);
716 * The child was not merged into a h/w node,
717 * but there's not much we can do with it other
718 * than return failure to cause the node to be removed.
720 cmn_err(CE_WARN
, "!%s@%s: %s.conf properties not merged",
721 ddi_get_name(child
), ddi_get_name_addr(child
),
722 ddi_get_name(child
));
723 ddi_set_name_addr(child
, NULL
);
724 return (DDI_NOT_WELL_FORMED
);
727 if (ddi_prop_get_int(DDI_DEV_T_ANY
, child
, DDI_PROP_DONTPASS
,
728 "interrupts", -1) != -1)
729 pci_common_set_parent_private_data(child
);
731 ddi_set_parent_data(child
, NULL
);
734 * initialize command register
736 if (pci_config_setup(child
, &config_handle
) != DDI_SUCCESS
)
737 return (DDI_FAILURE
);
740 * Support for the "command-preserve" property.
742 command_preserve
= ddi_prop_get_int(DDI_DEV_T_ANY
, child
,
743 DDI_PROP_DONTPASS
, "command-preserve", 0);
744 command
= pci_config_get16(config_handle
, PCI_CONF_COMM
);
745 command
&= (command_preserve
| PCI_COMM_BACK2BACK_ENAB
);
746 command
|= (pci_command_default
& ~command_preserve
);
747 pci_config_put16(config_handle
, PCI_CONF_COMM
, command
);
749 pci_config_teardown(&config_handle
);
750 return (DDI_SUCCESS
);
754 pci_removechild(dev_info_t
*dip
)
756 struct ddi_parent_private_data
*pdptr
;
758 if ((pdptr
= ddi_get_parent_data(dip
)) != NULL
) {
759 kmem_free(pdptr
, (sizeof (*pdptr
) + sizeof (struct intrspec
)));
760 ddi_set_parent_data(dip
, NULL
);
762 ddi_set_name_addr(dip
, NULL
);
765 * Strip the node to properly convert it back to prototype form
767 ddi_remove_minor_node(dip
, NULL
);
769 impl_rem_dev_props(dip
);
771 return (DDI_SUCCESS
);
776 * When retrofitting this module for pci_tools, functions such as open, close,
777 * and ioctl are now pulled into this module. Before this, the functions in
778 * the pcihp module were referenced directly. Now they are called or
779 * referenced through the pcihp cb_ops structure from functions in this module.
783 pci_open(dev_t
*devp
, int flags
, int otyp
, cred_t
*credp
)
785 return ((pcihp_get_cb_ops())->cb_open(devp
, flags
, otyp
, credp
));
789 pci_close(dev_t dev
, int flags
, int otyp
, cred_t
*credp
)
791 return ((pcihp_get_cb_ops())->cb_close(dev
, flags
, otyp
, credp
));
795 pci_ioctl(dev_t dev
, int cmd
, intptr_t arg
, int mode
, cred_t
*credp
, int *rvalp
)
797 minor_t minor
= getminor(dev
);
798 int instance
= PCI_MINOR_NUM_TO_INSTANCE(minor
);
799 pci_state_t
*pci_p
= ddi_get_soft_state(pci_statep
, instance
);
805 switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor
)) {
806 case PCI_TOOL_REG_MINOR_NUM
:
807 case PCI_TOOL_INTR_MINOR_NUM
:
808 /* To handle pcitool related ioctls */
809 ret
= pci_common_ioctl(pci_p
->pci_dip
, dev
, cmd
, arg
, mode
,
813 /* To handle devctl and hotplug related ioctls */
814 ret
= (pcihp_get_cb_ops())->cb_ioctl(dev
, cmd
, arg
, mode
,
824 pci_prop_op(dev_t dev
, dev_info_t
*dip
, ddi_prop_op_t prop_op
,
825 int flags
, char *name
, caddr_t valuep
, int *lengthp
)
827 return ((pcihp_get_cb_ops())->cb_prop_op(dev
, dip
, prop_op
, flags
,
828 name
, valuep
, lengthp
));
832 pci_info(dev_info_t
*dip
, ddi_info_cmd_t cmd
, void *arg
, void **result
)
834 return (pcihp_info(dip
, cmd
, arg
, result
));
837 void pci_peekpoke_cb(dev_info_t
*dip
, ddi_fm_error_t
*derr
) {
838 (void) pci_ereport_post(dip
, derr
, NULL
);
843 pci_fm_init(dev_info_t
*dip
, dev_info_t
*tdip
, int cap
,
844 ddi_iblock_cookie_t
*ibc
)
846 pci_state_t
*pcip
= ddi_get_soft_state(pci_statep
,
847 ddi_get_instance(dip
));
850 *ibc
= pcip
->pci_fm_ibc
;
852 return (pcip
->pci_fmcap
);
857 pci_fm_callback(dev_info_t
*dip
, ddi_fm_error_t
*derr
, const void *no_used
)
859 pci_state_t
*pcip
= ddi_get_soft_state(pci_statep
,
860 ddi_get_instance(dip
));
862 mutex_enter(&pcip
->pci_err_mutex
);
863 pci_ereport_post(dip
, derr
, NULL
);
864 mutex_exit(&pcip
->pci_err_mutex
);
865 return (derr
->fme_status
);