xref: /titanic_50/usr/src/uts/i86pc/io/pciex/npe.c (revision 04580fdfa39e6e9d80ef4c60bfcf6e8461687692)
1 /*
2  * CDDL HEADER START
3  *
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.
8  *
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.
13  *
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]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 #pragma ident	"%Z%%M%	%I%	%E% SMI"
29 
30 /*
31  *	Host to PCI-Express local bus driver
32  */
33 
34 #include <sys/conf.h>
35 #include <sys/modctl.h>
36 #include <sys/pcie.h>
37 #include <sys/pci_impl.h>
38 #include <sys/sysmacros.h>
39 #include <sys/ddi_intr.h>
40 #include <sys/sunndi.h>
41 #include <sys/hotplug/pci/pcihp.h>
42 #include <io/pci/pci_common.h>
43 #include <io/pci/pci_tools_ext.h>
44 #include <io/pciex/pcie_error.h>
45 
46 /*
47  * Bus Operation functions
48  */
49 static int	npe_bus_map(dev_info_t *, dev_info_t *, ddi_map_req_t *,
50 		    off_t, off_t, caddr_t *);
51 static int	npe_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t,
52 		    void *, void *);
53 static int	npe_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t,
54 		    ddi_intr_handle_impl_t *, void *);
55 
56 struct bus_ops npe_bus_ops = {
57 	BUSO_REV,
58 	npe_bus_map,
59 	NULL,
60 	NULL,
61 	NULL,
62 	i_ddi_map_fault,
63 	ddi_dma_map,
64 	ddi_dma_allochdl,
65 	ddi_dma_freehdl,
66 	ddi_dma_bindhdl,
67 	ddi_dma_unbindhdl,
68 	ddi_dma_flush,
69 	ddi_dma_win,
70 	ddi_dma_mctl,
71 	npe_ctlops,
72 	ddi_bus_prop_op,
73 	0,		/* (*bus_get_eventcookie)();	*/
74 	0,		/* (*bus_add_eventcall)();	*/
75 	0,		/* (*bus_remove_eventcall)();	*/
76 	0,		/* (*bus_post_event)();		*/
77 	0,		/* (*bus_intr_ctl)(); */
78 	0,		/* (*bus_config)(); */
79 	0,		/* (*bus_unconfig)(); */
80 	NULL,		/* (*bus_fm_init)(); */
81 	NULL,		/* (*bus_fm_fini)(); */
82 	NULL,		/* (*bus_fm_access_enter)(); */
83 	NULL,		/* (*bus_fm_access_exit)(); */
84 	NULL,		/* (*bus_power)(); */
85 	npe_intr_ops	/* (*bus_intr_op)(); */
86 };
87 
88 /*
89  * One goal here is to leverage off of the pcihp.c source without making
90  * changes to it.  Call into it's cb_ops directly if needed, piggybacking
91  * anything else needed by the pci_tools.c module.  Only pci_tools and pcihp
92  * will be using the PCI devctl node.
93  */
94 static int	npe_open(dev_t *, int, int, cred_t *);
95 static int	npe_close(dev_t, int, int, cred_t *);
96 static int	npe_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
97 static int	npe_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *,
98 		    caddr_t, int *);
99 static int	npe_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
100 
101 struct cb_ops npe_cb_ops = {
102 	npe_open,			/* open */
103 	npe_close,			/* close */
104 	nodev,				/* strategy */
105 	nodev,				/* print */
106 	nodev,				/* dump */
107 	nodev,				/* read */
108 	nodev,				/* write */
109 	npe_ioctl,			/* ioctl */
110 	nodev,				/* devmap */
111 	nodev,				/* mmap */
112 	nodev,				/* segmap */
113 	nochpoll,			/* poll */
114 	npe_prop_op,			/* cb_prop_op */
115 	NULL,				/* streamtab */
116 	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
117 	CB_REV,				/* rev */
118 	nodev,				/* int (*cb_aread)() */
119 	nodev				/* int (*cb_awrite)() */
120 };
121 
122 
123 /*
124  * Device Node Operation functions
125  */
126 static int	npe_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
127 static int	npe_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
128 
129 struct dev_ops npe_ops = {
130 	DEVO_REV,		/* devo_rev */
131 	0,			/* refcnt  */
132 	pcihp_info,		/* info */
133 	nulldev,		/* identify */
134 	nulldev,		/* probe */
135 	npe_attach,		/* attach */
136 	npe_detach,		/* detach */
137 	nulldev,		/* reset */
138 	&npe_cb_ops,		/* driver operations */
139 	&npe_bus_ops		/* bus operations */
140 };
141 
142 /*
143  * Internal routines in support of particular npe_ctlops.
144  */
145 static int npe_removechild(dev_info_t *child);
146 static int npe_initchild(dev_info_t *child);
147 
148 /*
149  * External support routine
150  */
151 extern void	npe_query_acpi_mcfg(dev_info_t *dip);
152 extern void	npe_ck804_fix_aer_ptr(dev_info_t *child);
153 
154 /*
155  * Module linkage information for the kernel.
156  */
157 static struct modldrv modldrv = {
158 	&mod_driverops, /* Type of module */
159 	"Host to PCIe nexus driver %I%",
160 	&npe_ops,	/* driver ops */
161 };
162 
163 static struct modlinkage modlinkage = {
164 	MODREV_1,
165 	(void *)&modldrv,
166 	NULL
167 };
168 
169 /* Save minimal state. */
170 void *npe_statep;
171 
172 
173 int
174 _init(void)
175 {
176 	int e;
177 
178 	/*
179 	 * Initialize per-pci bus soft state pointer.
180 	 */
181 	e = ddi_soft_state_init(&npe_statep, sizeof (pci_state_t), 1);
182 	if (e != 0)
183 		return (e);
184 
185 	if ((e = mod_install(&modlinkage)) != 0)
186 		ddi_soft_state_fini(&npe_statep);
187 
188 	return (e);
189 }
190 
191 
192 int
193 _fini(void)
194 {
195 	int rc;
196 
197 	rc = mod_remove(&modlinkage);
198 	if (rc != 0)
199 		return (rc);
200 
201 	ddi_soft_state_fini(&npe_statep);
202 	return (rc);
203 }
204 
205 
206 int
207 _info(struct modinfo *modinfop)
208 {
209 	return (mod_info(&modlinkage, modinfop));
210 }
211 
212 
213 /*ARGSUSED*/
214 static int
215 npe_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
216 {
217 	/*
218 	 * Use the minor number as constructed by pcihp, as the index value to
219 	 * ddi_soft_state_zalloc.
220 	 */
221 	int instance = ddi_get_instance(devi);
222 	pci_state_t *pcip = NULL;
223 
224 	if (ddi_prop_update_string(DDI_DEV_T_NONE, devi, "device_type",
225 	    "pciex") != DDI_PROP_SUCCESS) {
226 		cmn_err(CE_WARN, "npe:  'device_type' prop create failed");
227 	}
228 
229 	if (ddi_soft_state_zalloc(npe_statep, instance) == DDI_SUCCESS)
230 		pcip = ddi_get_soft_state(npe_statep, instance);
231 
232 	if (pcip == NULL)
233 		return (DDI_FAILURE);
234 
235 	pcip->pci_dip = devi;
236 
237 	/*
238 	 * Initialize hotplug support on this bus. At minimum
239 	 * (for non hotplug bus) this would create ":devctl" minor
240 	 * node to support DEVCTL_DEVICE_* and DEVCTL_BUS_* ioctls
241 	 * to this bus.
242 	 */
243 	if (pcihp_init(devi) != DDI_SUCCESS) {
244 		cmn_err(CE_WARN, "npe: Failed to setup hotplug framework");
245 		ddi_soft_state_free(npe_statep, instance);
246 		return (DDI_FAILURE);
247 	}
248 
249 	/* Second arg: initialize for pci_express root nexus */
250 	if (pcitool_init(devi, B_TRUE) != DDI_SUCCESS) {
251 		(void) pcihp_uninit(devi);
252 		ddi_soft_state_free(npe_statep, instance);
253 		return (DDI_FAILURE);
254 	}
255 
256 	npe_query_acpi_mcfg(devi);
257 	ddi_report_dev(devi);
258 	return (DDI_SUCCESS);
259 
260 }
261 
262 
263 /*ARGSUSED*/
264 static int
265 npe_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
266 {
267 	int instance = ddi_get_instance(devi);
268 
269 	/* Uninitialize pcitool support. */
270 	pcitool_uninit(devi);
271 
272 	/*
273 	 * Uninitialize hotplug support on this bus.
274 	 */
275 	(void) pcihp_uninit(devi);
276 	ddi_soft_state_free(npe_statep, instance);
277 	return (DDI_SUCCESS);
278 }
279 
280 
281 static int
282 npe_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
283     off_t offset, off_t len, caddr_t *vaddrp)
284 {
285 	int 		rnumber;
286 	int		length;
287 	int		space;
288 	ddi_acc_hdl_t	*hp;
289 	ddi_map_req_t	mr;
290 	pci_regspec_t	pci_reg;
291 	pci_regspec_t	*pci_rp;
292 	struct regspec	reg;
293 	pci_acc_cfblk_t	*cfp;
294 
295 
296 	mr = *mp; /* Get private copy of request */
297 	mp = &mr;
298 
299 	/*
300 	 * check for register number
301 	 */
302 	switch (mp->map_type) {
303 	case DDI_MT_REGSPEC:
304 		pci_reg = *(pci_regspec_t *)(mp->map_obj.rp);
305 		pci_rp = &pci_reg;
306 		if (pci_common_get_reg_prop(rdip, pci_rp) != DDI_SUCCESS)
307 			return (DDI_FAILURE);
308 		break;
309 	case DDI_MT_RNUMBER:
310 		rnumber = mp->map_obj.rnumber;
311 		/*
312 		 * get ALL "reg" properties for dip, select the one of
313 		 * of interest. In x86, "assigned-addresses" property
314 		 * is identical to the "reg" property, so there is no
315 		 * need to cross check the two to determine the physical
316 		 * address of the registers.
317 		 * This routine still performs some validity checks to
318 		 * make sure that everything is okay.
319 		 */
320 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip,
321 		    DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
322 		    (uint_t *)&length) != DDI_PROP_SUCCESS)
323 			return (DDI_FAILURE);
324 
325 		/*
326 		 * validate the register number.
327 		 */
328 		length /= (sizeof (pci_regspec_t) / sizeof (int));
329 		if (rnumber >= length) {
330 			ddi_prop_free(pci_rp);
331 			return (DDI_FAILURE);
332 		}
333 
334 		/*
335 		 * copy the required entry.
336 		 */
337 		pci_reg = pci_rp[rnumber];
338 
339 		/*
340 		 * free the memory allocated by ddi_prop_lookup_int_array
341 		 */
342 		ddi_prop_free(pci_rp);
343 
344 		pci_rp = &pci_reg;
345 		if (pci_common_get_reg_prop(rdip, pci_rp) != DDI_SUCCESS)
346 			return (DDI_FAILURE);
347 		mp->map_type = DDI_MT_REGSPEC;
348 		break;
349 	default:
350 		return (DDI_ME_INVAL);
351 	}
352 
353 	space = pci_rp->pci_phys_hi & PCI_REG_ADDR_M;
354 
355 	/*
356 	 * check for unmap and unlock of address space
357 	 */
358 	if ((mp->map_op == DDI_MO_UNMAP) || (mp->map_op == DDI_MO_UNLOCK)) {
359 		/*
360 		 * Adjust offset and length
361 		 * A non-zero length means override the one in the regspec.
362 		 */
363 		pci_rp->pci_phys_low += (uint_t)offset;
364 		if (len != 0)
365 			pci_rp->pci_size_low = len;
366 
367 		switch (space) {
368 		case PCI_ADDR_IO:
369 			reg.regspec_bustype = 1;
370 			break;
371 
372 		case PCI_ADDR_CONFIG:
373 			/* Just fall through */
374 		case PCI_ADDR_MEM64:
375 			/*
376 			 * MEM64 requires special treatment on map, to check
377 			 * that the device is below 4G.  On unmap, however,
378 			 * we can assume that everything is OK... the map
379 			 * must have succeeded.
380 			 */
381 			/* FALLTHROUGH */
382 		case PCI_ADDR_MEM32:
383 			reg.regspec_bustype = 0;
384 			break;
385 
386 		default:
387 			return (DDI_FAILURE);
388 		}
389 		reg.regspec_addr = pci_rp->pci_phys_low;
390 		reg.regspec_size = pci_rp->pci_size_low;
391 
392 		mp->map_obj.rp = &reg;
393 		return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp));
394 
395 	}
396 
397 	/* check for user mapping request - not legal for Config */
398 	if (mp->map_op == DDI_MO_MAP_HANDLE && space == PCI_ADDR_CONFIG) {
399 		cmn_err(CE_NOTE, "npe: Config mapping request from user\n");
400 		return (DDI_FAILURE);
401 	}
402 
403 
404 	if (space == PCI_ADDR_CONFIG) {
405 		/* Can't map config space without a handle */
406 		hp = (ddi_acc_hdl_t *)mp->map_handlep;
407 		if (hp == NULL)
408 			return (DDI_FAILURE);
409 
410 		pci_rp->pci_phys_low = ddi_prop_get_int64(DDI_DEV_T_ANY,
411 		    rdip, 0, "ecfga-base-address", 0);
412 
413 		/* record the device address for future reference */
414 		cfp = (pci_acc_cfblk_t *)&hp->ah_bus_private;
415 		cfp->c_busnum = PCI_REG_BUS_G(pci_rp->pci_phys_hi);
416 		cfp->c_devnum = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
417 		cfp->c_funcnum = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
418 
419 		pci_rp->pci_phys_low += ((cfp->c_busnum << 20) |
420 		    (cfp->c_devnum) << 15 | (cfp->c_funcnum << 12));
421 
422 		pci_rp->pci_size_low = PCIE_CONF_HDR_SIZE;
423 	}
424 
425 	length = pci_rp->pci_size_low;
426 
427 	/*
428 	 * range check
429 	 */
430 	if ((offset >= length) || (len > length) || (offset + len > length))
431 		return (DDI_FAILURE);
432 
433 	/*
434 	 * Adjust offset and length
435 	 * A non-zero length means override the one in the regspec.
436 	 */
437 	pci_rp->pci_phys_low += (uint_t)offset;
438 	if (len != 0)
439 		pci_rp->pci_size_low = len;
440 
441 	/*
442 	 * convert the pci regsec into the generic regspec used by the
443 	 * parent root nexus driver.
444 	 */
445 	switch (space) {
446 	case PCI_ADDR_IO:
447 		reg.regspec_bustype = 1;
448 		break;
449 	case PCI_ADDR_CONFIG:
450 	case PCI_ADDR_MEM64:
451 		/*
452 		 * We can't handle 64-bit devices that are mapped above
453 		 * 4G or that are larger than 4G.
454 		 */
455 		if (pci_rp->pci_phys_mid != 0 || pci_rp->pci_size_hi != 0)
456 			return (DDI_FAILURE);
457 		/*
458 		 * Other than that, we can treat them as 32-bit mappings
459 		 */
460 		/* FALLTHROUGH */
461 	case PCI_ADDR_MEM32:
462 		reg.regspec_bustype = 0;
463 		break;
464 	default:
465 		return (DDI_FAILURE);
466 	}
467 
468 	reg.regspec_addr = pci_rp->pci_phys_low;
469 	reg.regspec_size = pci_rp->pci_size_low;
470 
471 	mp->map_obj.rp = &reg;
472 	return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp));
473 }
474 
475 
476 /*ARGSUSED*/
477 static int
478 npe_ctlops(dev_info_t *dip, dev_info_t *rdip,
479 	ddi_ctl_enum_t ctlop, void *arg, void *result)
480 {
481 	int		rn;
482 	int		totreg;
483 	uint_t		reglen;
484 	pci_regspec_t	*drv_regp;
485 
486 	switch (ctlop) {
487 	case DDI_CTLOPS_REPORTDEV:
488 		if (rdip == (dev_info_t *)0)
489 			return (DDI_FAILURE);
490 		cmn_err(CE_CONT, "?PCI Express-device: %s@%s, %s%d\n",
491 		    ddi_node_name(rdip), ddi_get_name_addr(rdip),
492 		    ddi_driver_name(rdip), ddi_get_instance(rdip));
493 		return (DDI_SUCCESS);
494 
495 	case DDI_CTLOPS_INITCHILD:
496 		return (npe_initchild((dev_info_t *)arg));
497 
498 	case DDI_CTLOPS_UNINITCHILD:
499 		return (npe_removechild((dev_info_t *)arg));
500 
501 	case DDI_CTLOPS_SIDDEV:
502 		return (DDI_SUCCESS);
503 
504 	case DDI_CTLOPS_REGSIZE:
505 	case DDI_CTLOPS_NREGS:
506 		if (rdip == (dev_info_t *)0)
507 			return (DDI_FAILURE);
508 
509 		*(int *)result = 0;
510 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip,
511 		    DDI_PROP_DONTPASS, "reg", (int **)&drv_regp,
512 		    &reglen) != DDI_PROP_SUCCESS) {
513 			return (DDI_FAILURE);
514 		}
515 
516 		totreg = (reglen * sizeof (int)) / sizeof (pci_regspec_t);
517 		if (ctlop == DDI_CTLOPS_NREGS)
518 			*(int *)result = totreg;
519 		else if (ctlop == DDI_CTLOPS_REGSIZE) {
520 			rn = *(int *)arg;
521 			if (rn >= totreg) {
522 				ddi_prop_free(drv_regp);
523 				return (DDI_FAILURE);
524 			}
525 			*(off_t *)result = drv_regp[rn].pci_size_low;
526 		}
527 		ddi_prop_free(drv_regp);
528 
529 		return (DDI_SUCCESS);
530 
531 	case DDI_CTLOPS_POWER:
532 	{
533 		power_req_t	*reqp = (power_req_t *)arg;
534 		/*
535 		 * We currently understand reporting of PCI_PM_IDLESPEED
536 		 * capability. Everything else is passed up.
537 		 */
538 		if ((reqp->request_type == PMR_REPORT_PMCAP) &&
539 		    (reqp->req.report_pmcap_req.cap ==  PCI_PM_IDLESPEED))
540 			return (DDI_SUCCESS);
541 
542 		break;
543 	}
544 
545 	default:
546 		break;
547 	}
548 
549 	return (ddi_ctlops(dip, rdip, ctlop, arg, result));
550 
551 }
552 
553 
554 /*
555  * npe_intr_ops
556  */
557 static int
558 npe_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
559     ddi_intr_handle_impl_t *hdlp, void *result)
560 {
561 	return (pci_common_intr_ops(pdip, rdip, intr_op, hdlp, result));
562 }
563 
564 
565 static int
566 npe_initchild(dev_info_t *child)
567 {
568 	char	name[80];
569 
570 	if (pci_common_name_child(child, name, 80) != DDI_SUCCESS)
571 		return (DDI_FAILURE);
572 
573 	ddi_set_name_addr(child, name);
574 
575 	/*
576 	 * Pseudo nodes indicate a prototype node with per-instance
577 	 * properties to be merged into the real h/w device node.
578 	 * The interpretation of the unit-address is DD[,F]
579 	 * where DD is the device id and F is the function.
580 	 */
581 	if (ndi_dev_is_persistent_node(child) == 0) {
582 		extern int pci_allow_pseudo_children;
583 
584 		ddi_set_parent_data(child, NULL);
585 
586 		/*
587 		 * Try to merge the properties from this prototype
588 		 * node into real h/w nodes.
589 		 */
590 		if (ndi_merge_node(child, pci_common_name_child) ==
591 		    DDI_SUCCESS) {
592 			/*
593 			 * Merged ok - return failure to remove the node.
594 			 */
595 			ddi_set_name_addr(child, NULL);
596 			return (DDI_FAILURE);
597 		}
598 
599 		/* workaround for DDIVS to run under PCI Express */
600 		if (pci_allow_pseudo_children) {
601 			/*
602 			 * If the "interrupts" property doesn't exist,
603 			 * this must be the ddivs no-intr case, and it returns
604 			 * DDI_SUCCESS instead of DDI_FAILURE.
605 			 */
606 			if (ddi_prop_get_int(DDI_DEV_T_ANY, child,
607 			    DDI_PROP_DONTPASS, "interrupts", -1) == -1)
608 				return (DDI_SUCCESS);
609 			/*
610 			 * Create the ddi_parent_private_data for a pseudo
611 			 * child.
612 			 */
613 			pci_common_set_parent_private_data(child);
614 			return (DDI_SUCCESS);
615 		}
616 
617 		/*
618 		 * The child was not merged into a h/w node,
619 		 * but there's not much we can do with it other
620 		 * than return failure to cause the node to be removed.
621 		 */
622 		cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged",
623 		    ddi_get_name(child), ddi_get_name_addr(child),
624 		    ddi_get_name(child));
625 		ddi_set_name_addr(child, NULL);
626 		return (DDI_NOT_WELL_FORMED);
627 	}
628 
629 	if (ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
630 	    "interrupts", -1) != -1)
631 		pci_common_set_parent_private_data(child);
632 	else
633 		ddi_set_parent_data(child, NULL);
634 
635 	/*
636 	 * Enable AER next pointer being displayed
637 	 */
638 	npe_ck804_fix_aer_ptr(child);
639 
640 	(void) pcie_error_init(child);
641 
642 	return (DDI_SUCCESS);
643 }
644 
645 
646 static int
647 npe_removechild(dev_info_t *dip)
648 {
649 	struct ddi_parent_private_data *pdptr;
650 
651 	/*
652 	 * Do it way early.
653 	 * Otherwise ddi_map() call form pcie_error_fini crashes
654 	 */
655 	pcie_error_fini(dip);
656 
657 	if ((pdptr = ddi_get_parent_data(dip)) != NULL) {
658 		kmem_free(pdptr, (sizeof (*pdptr) + sizeof (struct intrspec)));
659 		ddi_set_parent_data(dip, NULL);
660 	}
661 	ddi_set_name_addr(dip, NULL);
662 
663 	/*
664 	 * Strip the node to properly convert it back to prototype form
665 	 */
666 	ddi_remove_minor_node(dip, NULL);
667 
668 	ddi_prop_remove_all(dip);
669 
670 	return (DDI_SUCCESS);
671 }
672 
673 
674 /*
675  * When retrofitting this module for pci_tools, functions such as open, close,
676  * and ioctl are now pulled into this module.  Before this, the functions in
677  * the pcihp module were referenced directly.  Now they are called or
678  * referenced through the pcihp cb_ops structure from functions in this module.
679  */
680 static int
681 npe_open(dev_t *devp, int flags, int otyp, cred_t *credp)
682 {
683 	return ((pcihp_get_cb_ops())->cb_open(devp, flags, otyp, credp));
684 }
685 
686 static int
687 npe_close(dev_t dev, int flags, int otyp, cred_t *credp)
688 {
689 	return ((pcihp_get_cb_ops())->cb_close(dev, flags, otyp, credp));
690 }
691 
692 static int
693 npe_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
694 {
695 	minor_t		minor = getminor(dev);
696 	int		instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
697 	pci_state_t	*pci_p = ddi_get_soft_state(npe_statep, instance);
698 	dev_info_t	*dip;
699 
700 	if (pci_p == NULL)
701 		return (ENXIO);
702 
703 	dip = pci_p->pci_dip;
704 	return (pci_common_ioctl(dip, dev, cmd, arg, mode, credp, rvalp));
705 }
706 
707 static int
708 npe_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
709 	int flags, char *name, caddr_t valuep, int *lengthp)
710 {
711 	return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip, prop_op, flags,
712 	    name, valuep, lengthp));
713 }
714 
715 static int
716 npe_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
717 {
718 	return (pcihp_info(dip, cmd, arg, result));
719 }
720