xref: /illumos-gate/usr/src/uts/i86pc/io/pciex/npe.c (revision 8a8d276f8934b606981d1c46b57c2eda30c67610)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  *	Host to PCI-Express local bus driver
31  */
32 
33 #include <sys/conf.h>
34 #include <sys/modctl.h>
35 #include <sys/pcie.h>
36 #include <sys/pci_impl.h>
37 #include <sys/sysmacros.h>
38 #include <sys/ddi_intr.h>
39 #include <sys/sunndi.h>
40 #include <sys/sunddi.h>
41 #include <sys/ddifm.h>
42 #include <sys/ndifm.h>
43 #include <sys/fm/util.h>
44 #include <sys/hotplug/pci/pcihp.h>
45 #include <io/pci/pci_common.h>
46 #include <io/pci/pci_tools_ext.h>
47 #include <io/pciex/pcie_error.h>
48 
49 /*
50  * Bus Operation functions
51  */
52 static int	npe_bus_map(dev_info_t *, dev_info_t *, ddi_map_req_t *,
53 		    off_t, off_t, caddr_t *);
54 static int	npe_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t,
55 		    void *, void *);
56 static int	npe_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t,
57 		    ddi_intr_handle_impl_t *, void *);
58 static int	npe_fm_init(dev_info_t *, dev_info_t *, int,
59 		    ddi_iblock_cookie_t *);
60 
61 static int	npe_fm_callback(dev_info_t *, ddi_fm_error_t *, const void *);
62 
63 struct bus_ops npe_bus_ops = {
64 	BUSO_REV,
65 	npe_bus_map,
66 	NULL,
67 	NULL,
68 	NULL,
69 	i_ddi_map_fault,
70 	ddi_dma_map,
71 	ddi_dma_allochdl,
72 	ddi_dma_freehdl,
73 	ddi_dma_bindhdl,
74 	ddi_dma_unbindhdl,
75 	ddi_dma_flush,
76 	ddi_dma_win,
77 	ddi_dma_mctl,
78 	npe_ctlops,
79 	ddi_bus_prop_op,
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 	npe_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 	npe_intr_ops	/* (*bus_intr_op)(); */
93 };
94 
95 /*
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 using the PCI devctl node.
100  */
101 static int	npe_open(dev_t *, int, int, cred_t *);
102 static int	npe_close(dev_t, int, int, cred_t *);
103 static int	npe_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
104 static int	npe_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *,
105 		    caddr_t, int *);
106 static int	npe_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
107 
108 struct cb_ops npe_cb_ops = {
109 	npe_open,			/* open */
110 	npe_close,			/* close */
111 	nodev,				/* strategy */
112 	nodev,				/* print */
113 	nodev,				/* dump */
114 	nodev,				/* read */
115 	nodev,				/* write */
116 	npe_ioctl,			/* ioctl */
117 	nodev,				/* devmap */
118 	nodev,				/* mmap */
119 	nodev,				/* segmap */
120 	nochpoll,			/* poll */
121 	npe_prop_op,			/* cb_prop_op */
122 	NULL,				/* streamtab */
123 	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
124 	CB_REV,				/* rev */
125 	nodev,				/* int (*cb_aread)() */
126 	nodev				/* int (*cb_awrite)() */
127 };
128 
129 
130 /*
131  * Device Node Operation functions
132  */
133 static int	npe_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
134 static int	npe_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
135 
136 struct dev_ops npe_ops = {
137 	DEVO_REV,		/* devo_rev */
138 	0,			/* refcnt  */
139 	npe_info,		/* info */
140 	nulldev,		/* identify */
141 	nulldev,		/* probe */
142 	npe_attach,		/* attach */
143 	npe_detach,		/* detach */
144 	nulldev,		/* reset */
145 	&npe_cb_ops,		/* driver operations */
146 	&npe_bus_ops		/* bus operations */
147 };
148 
149 /*
150  * Internal routines in support of particular npe_ctlops.
151  */
152 static int npe_removechild(dev_info_t *child);
153 static int npe_initchild(dev_info_t *child);
154 
155 /*
156  * External support routine
157  */
158 extern void	npe_query_acpi_mcfg(dev_info_t *dip);
159 extern void	npe_ck804_fix_aer_ptr(ddi_acc_handle_t cfg_hdl);
160 extern int	npe_disable_empty_bridges_workaround(dev_info_t *child);
161 
162 /*
163  * Module linkage information for the kernel.
164  */
165 static struct modldrv modldrv = {
166 	&mod_driverops, /* Type of module */
167 	"Host to PCIe nexus driver %I%",
168 	&npe_ops,	/* driver ops */
169 };
170 
171 static struct modlinkage modlinkage = {
172 	MODREV_1,
173 	(void *)&modldrv,
174 	NULL
175 };
176 
177 /* Save minimal state. */
178 void *npe_statep;
179 
180 
181 int
182 _init(void)
183 {
184 	int e;
185 
186 	/*
187 	 * Initialize per-pci bus soft state pointer.
188 	 */
189 	e = ddi_soft_state_init(&npe_statep, sizeof (pci_state_t), 1);
190 	if (e != 0)
191 		return (e);
192 
193 	if ((e = mod_install(&modlinkage)) != 0)
194 		ddi_soft_state_fini(&npe_statep);
195 
196 	return (e);
197 }
198 
199 
200 int
201 _fini(void)
202 {
203 	int rc;
204 
205 	rc = mod_remove(&modlinkage);
206 	if (rc != 0)
207 		return (rc);
208 
209 	ddi_soft_state_fini(&npe_statep);
210 	return (rc);
211 }
212 
213 
214 int
215 _info(struct modinfo *modinfop)
216 {
217 	return (mod_info(&modlinkage, modinfop));
218 }
219 
220 /*ARGSUSED*/
221 static int
222 npe_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
223 {
224 	/*
225 	 * Use the minor number as constructed by pcihp, as the index value to
226 	 * ddi_soft_state_zalloc.
227 	 */
228 	int instance = ddi_get_instance(devi);
229 	pci_state_t *pcip = NULL;
230 
231 	if (ddi_prop_update_string(DDI_DEV_T_NONE, devi, "device_type",
232 	    "pciex") != DDI_PROP_SUCCESS) {
233 		cmn_err(CE_WARN, "npe:  'device_type' prop create failed");
234 	}
235 
236 	if (ddi_soft_state_zalloc(npe_statep, instance) == DDI_SUCCESS)
237 		pcip = ddi_get_soft_state(npe_statep, instance);
238 
239 	if (pcip == NULL)
240 		return (DDI_FAILURE);
241 
242 	pcip->pci_dip = devi;
243 
244 	/*
245 	 * Initialize hotplug support on this bus. At minimum
246 	 * (for non hotplug bus) this would create ":devctl" minor
247 	 * node to support DEVCTL_DEVICE_* and DEVCTL_BUS_* ioctls
248 	 * to this bus.
249 	 */
250 	if (pcihp_init(devi) != DDI_SUCCESS) {
251 		cmn_err(CE_WARN, "npe: Failed to setup hotplug framework");
252 		ddi_soft_state_free(npe_statep, instance);
253 		return (DDI_FAILURE);
254 	}
255 
256 	/* Second arg: initialize for pci_express root nexus */
257 	if (pcitool_init(devi, B_TRUE) != DDI_SUCCESS) {
258 		(void) pcihp_uninit(devi);
259 		ddi_soft_state_free(npe_statep, instance);
260 		return (DDI_FAILURE);
261 	}
262 	pcip->pci_fmcap = DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE |
263 	    DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE;
264 	ddi_fm_init(devi, &pcip->pci_fmcap, &pcip->pci_fm_ibc);
265 
266 	if (pcip->pci_fmcap & DDI_FM_ERRCB_CAPABLE)
267 		ddi_fm_handler_register(devi, npe_fm_callback, NULL);
268 
269 	npe_query_acpi_mcfg(devi);
270 	ddi_report_dev(devi);
271 	return (DDI_SUCCESS);
272 
273 }
274 
275 
276 /*ARGSUSED*/
277 static int
278 npe_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
279 {
280 	int instance = ddi_get_instance(devi);
281 	pci_state_t *pcip;
282 
283 	pcip = ddi_get_soft_state(npe_statep, ddi_get_instance(devi));
284 
285 	/* Uninitialize pcitool support. */
286 	pcitool_uninit(devi);
287 
288 	/*
289 	 * Uninitialize hotplug support on this bus.
290 	 */
291 	(void) pcihp_uninit(devi);
292 
293 	if (pcip->pci_fmcap & DDI_FM_ERRCB_CAPABLE)
294 		ddi_fm_handler_unregister(devi);
295 
296 	ddi_fm_fini(devi);
297 	ddi_soft_state_free(npe_statep, instance);
298 	return (DDI_SUCCESS);
299 }
300 
301 
302 static int
303 npe_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
304     off_t offset, off_t len, caddr_t *vaddrp)
305 {
306 	int 		rnumber;
307 	int		length;
308 	int		space;
309 	ddi_acc_impl_t	*ap;
310 	ddi_acc_hdl_t	*hp;
311 	ddi_map_req_t	mr;
312 	pci_regspec_t	pci_reg;
313 	pci_regspec_t	*pci_rp;
314 	struct regspec	reg;
315 	pci_acc_cfblk_t	*cfp;
316 	int		retval;
317 
318 	mr = *mp; /* Get private copy of request */
319 	mp = &mr;
320 
321 	/*
322 	 * check for register number
323 	 */
324 	switch (mp->map_type) {
325 	case DDI_MT_REGSPEC:
326 		pci_reg = *(pci_regspec_t *)(mp->map_obj.rp);
327 		pci_rp = &pci_reg;
328 		if (pci_common_get_reg_prop(rdip, pci_rp) != DDI_SUCCESS)
329 			return (DDI_FAILURE);
330 		break;
331 	case DDI_MT_RNUMBER:
332 		rnumber = mp->map_obj.rnumber;
333 		/*
334 		 * get ALL "reg" properties for dip, select the one of
335 		 * of interest. In x86, "assigned-addresses" property
336 		 * is identical to the "reg" property, so there is no
337 		 * need to cross check the two to determine the physical
338 		 * address of the registers.
339 		 * This routine still performs some validity checks to
340 		 * make sure that everything is okay.
341 		 */
342 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip,
343 		    DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
344 		    (uint_t *)&length) != DDI_PROP_SUCCESS)
345 			return (DDI_FAILURE);
346 
347 		/*
348 		 * validate the register number.
349 		 */
350 		length /= (sizeof (pci_regspec_t) / sizeof (int));
351 		if (rnumber >= length) {
352 			ddi_prop_free(pci_rp);
353 			return (DDI_FAILURE);
354 		}
355 
356 		/*
357 		 * copy the required entry.
358 		 */
359 		pci_reg = pci_rp[rnumber];
360 
361 		/*
362 		 * free the memory allocated by ddi_prop_lookup_int_array
363 		 */
364 		ddi_prop_free(pci_rp);
365 
366 		pci_rp = &pci_reg;
367 		if (pci_common_get_reg_prop(rdip, pci_rp) != DDI_SUCCESS)
368 			return (DDI_FAILURE);
369 		mp->map_type = DDI_MT_REGSPEC;
370 		break;
371 	default:
372 		return (DDI_ME_INVAL);
373 	}
374 
375 	space = pci_rp->pci_phys_hi & PCI_REG_ADDR_M;
376 
377 	/*
378 	 * check for unmap and unlock of address space
379 	 */
380 	if ((mp->map_op == DDI_MO_UNMAP) || (mp->map_op == DDI_MO_UNLOCK)) {
381 		switch (space) {
382 		case PCI_ADDR_IO:
383 			reg.regspec_bustype = 1;
384 			break;
385 
386 		case PCI_ADDR_CONFIG:
387 			/*
388 			 * Check for AMD's northbridges
389 			 *	AND
390 			 * for any PCI device.
391 			 *
392 			 * This is a workaround fix for
393 			 * AMD-8132's inability to handle MMCFG
394 			 * accesses on Galaxy's PE servers
395 			 *	AND
396 			 * to disable MMCFG for any PCI device.
397 			 *
398 			 * If a device is *not* found to have PCIe
399 			 * capability, then assume it is a PCI device.
400 			 */
401 
402 			if (is_amd_northbridge(rdip) == 0 ||
403 			    (ddi_prop_get_int(DDI_DEV_T_ANY, rdip,
404 			    DDI_PROP_DONTPASS, "pcie-capid-pointer",
405 			    PCI_CAP_NEXT_PTR_NULL) == PCI_CAP_NEXT_PTR_NULL)) {
406 				if (DDI_FM_ACC_ERR_CAP(ddi_fm_capable(rdip)) &&
407 				    mp->map_handlep->ah_acc.devacc_attr_access
408 				    != DDI_DEFAULT_ACC) {
409 					ndi_fmc_remove(rdip, ACC_HANDLE,
410 					    (void *)mp->map_handlep);
411 				}
412 				return (DDI_SUCCESS);
413 			}
414 
415 
416 			/* FALLTHROUGH */
417 		case PCI_ADDR_MEM64:
418 			/*
419 			 * MEM64 requires special treatment on map, to check
420 			 * that the device is below 4G.  On unmap, however,
421 			 * we can assume that everything is OK... the map
422 			 * must have succeeded.
423 			 */
424 			/* FALLTHROUGH */
425 		case PCI_ADDR_MEM32:
426 			reg.regspec_bustype = 0;
427 			break;
428 
429 		default:
430 			return (DDI_FAILURE);
431 		}
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 		reg.regspec_addr = pci_rp->pci_phys_low;
442 		reg.regspec_size = pci_rp->pci_size_low;
443 
444 		mp->map_obj.rp = &reg;
445 		retval = ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp);
446 		if (DDI_FM_ACC_ERR_CAP(ddi_fm_capable(rdip)) &&
447 		    mp->map_handlep->ah_acc.devacc_attr_access !=
448 		    DDI_DEFAULT_ACC) {
449 			ndi_fmc_remove(rdip, ACC_HANDLE,
450 			    (void *)mp->map_handlep);
451 		}
452 		return (retval);
453 
454 	}
455 
456 	/* check for user mapping request - not legal for Config */
457 	if (mp->map_op == DDI_MO_MAP_HANDLE && space == PCI_ADDR_CONFIG) {
458 		cmn_err(CE_NOTE, "npe: Config mapping request from user\n");
459 		return (DDI_FAILURE);
460 	}
461 
462 
463 	/*
464 	 * Note that pci_fm_acc_setup() is called to serve two purposes
465 	 * i) enable legacy PCI I/O style config space access
466 	 * ii) register with FMA
467 	 */
468 	if (space == PCI_ADDR_CONFIG) {
469 		/* Can't map config space without a handle */
470 		hp = (ddi_acc_hdl_t *)mp->map_handlep;
471 		if (hp == NULL)
472 			return (DDI_FAILURE);
473 
474 		/* record the device address for future reference */
475 		cfp = (pci_acc_cfblk_t *)&hp->ah_bus_private;
476 		cfp->c_busnum = PCI_REG_BUS_G(pci_rp->pci_phys_hi);
477 		cfp->c_devnum = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
478 		cfp->c_funcnum = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
479 
480 		*vaddrp = (caddr_t)offset;
481 
482 		/*
483 		 * Check for AMD's northbridges, pci devices and
484 		 * devices underneath a pci bridge.  This is to setup
485 		 * I/O based config space access.
486 		 */
487 		if (is_amd_northbridge(rdip) == 0 ||
488 		    (ddi_prop_get_int(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
489 		    "pcie-capid-pointer", PCI_CAP_NEXT_PTR_NULL) ==
490 		    PCI_CAP_NEXT_PTR_NULL)) {
491 			int ret;
492 
493 			if ((ret = pci_fm_acc_setup(hp, offset, len)) ==
494 			    DDI_SUCCESS) {
495 				if (DDI_FM_ACC_ERR_CAP(ddi_fm_capable(rdip)) &&
496 				    mp->map_handlep->ah_acc.devacc_attr_access
497 				    != DDI_DEFAULT_ACC) {
498 					ndi_fmc_insert(rdip, ACC_HANDLE,
499 					    (void *)mp->map_handlep, NULL);
500 				}
501 			}
502 			return (ret);
503 		}
504 
505 		pci_rp->pci_phys_low = ddi_prop_get_int64(DDI_DEV_T_ANY,
506 		    rdip, 0, "ecfga-base-address", 0);
507 
508 		pci_rp->pci_phys_low += ((cfp->c_busnum << 20) |
509 		    (cfp->c_devnum) << 15 | (cfp->c_funcnum << 12));
510 
511 		pci_rp->pci_size_low = PCIE_CONF_HDR_SIZE;
512 	}
513 
514 	length = pci_rp->pci_size_low;
515 
516 	/*
517 	 * range check
518 	 */
519 	if ((offset >= length) || (len > length) || (offset + len > length))
520 		return (DDI_FAILURE);
521 
522 	/*
523 	 * Adjust offset and length
524 	 * A non-zero length means override the one in the regspec.
525 	 */
526 	pci_rp->pci_phys_low += (uint_t)offset;
527 	if (len != 0)
528 		pci_rp->pci_size_low = len;
529 
530 	/*
531 	 * convert the pci regsec into the generic regspec used by the
532 	 * parent root nexus driver.
533 	 */
534 	switch (space) {
535 	case PCI_ADDR_IO:
536 		reg.regspec_bustype = 1;
537 		break;
538 	case PCI_ADDR_CONFIG:
539 	case PCI_ADDR_MEM64:
540 		/*
541 		 * We can't handle 64-bit devices that are mapped above
542 		 * 4G or that are larger than 4G.
543 		 */
544 		if (pci_rp->pci_phys_mid != 0 || pci_rp->pci_size_hi != 0)
545 			return (DDI_FAILURE);
546 		/*
547 		 * Other than that, we can treat them as 32-bit mappings
548 		 */
549 		/* FALLTHROUGH */
550 	case PCI_ADDR_MEM32:
551 		reg.regspec_bustype = 0;
552 		break;
553 	default:
554 		return (DDI_FAILURE);
555 	}
556 
557 	reg.regspec_addr = pci_rp->pci_phys_low;
558 	reg.regspec_size = pci_rp->pci_size_low;
559 
560 	mp->map_obj.rp = &reg;
561 	retval = ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp);
562 	if (retval == DDI_SUCCESS) {
563 		/*
564 		 * For config space gets force use of cautious access routines.
565 		 * These will handle default and protected mode accesses too.
566 		 */
567 		if (space == PCI_ADDR_CONFIG) {
568 			ap = (ddi_acc_impl_t *)mp->map_handlep;
569 			ap->ahi_acc_attr &= ~DDI_ACCATTR_DIRECT;
570 			ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE;
571 			ap->ahi_get8 = i_ddi_caut_get8;
572 			ap->ahi_get16 = i_ddi_caut_get16;
573 			ap->ahi_get32 = i_ddi_caut_get32;
574 			ap->ahi_get64 = i_ddi_caut_get64;
575 			ap->ahi_rep_get8 = i_ddi_caut_rep_get8;
576 			ap->ahi_rep_get16 = i_ddi_caut_rep_get16;
577 			ap->ahi_rep_get32 = i_ddi_caut_rep_get32;
578 			ap->ahi_rep_get64 = i_ddi_caut_rep_get64;
579 		}
580 		if (DDI_FM_ACC_ERR_CAP(ddi_fm_capable(rdip)) &&
581 		    mp->map_handlep->ah_acc.devacc_attr_access !=
582 		    DDI_DEFAULT_ACC) {
583 			ndi_fmc_insert(rdip, ACC_HANDLE,
584 			    (void *)mp->map_handlep, NULL);
585 		}
586 	}
587 	return (retval);
588 }
589 
590 
591 
592 /*ARGSUSED*/
593 static int
594 npe_ctlops(dev_info_t *dip, dev_info_t *rdip,
595 	ddi_ctl_enum_t ctlop, void *arg, void *result)
596 {
597 	int		rn;
598 	int		totreg;
599 	uint_t		reglen;
600 	pci_regspec_t	*drv_regp;
601 
602 	switch (ctlop) {
603 	case DDI_CTLOPS_REPORTDEV:
604 		if (rdip == (dev_info_t *)0)
605 			return (DDI_FAILURE);
606 		cmn_err(CE_CONT, "?PCI Express-device: %s@%s, %s%d\n",
607 		    ddi_node_name(rdip), ddi_get_name_addr(rdip),
608 		    ddi_driver_name(rdip), ddi_get_instance(rdip));
609 		return (DDI_SUCCESS);
610 
611 	case DDI_CTLOPS_INITCHILD:
612 		return (npe_initchild((dev_info_t *)arg));
613 
614 	case DDI_CTLOPS_UNINITCHILD:
615 		return (npe_removechild((dev_info_t *)arg));
616 
617 	case DDI_CTLOPS_SIDDEV:
618 		return (DDI_SUCCESS);
619 
620 	case DDI_CTLOPS_REGSIZE:
621 	case DDI_CTLOPS_NREGS:
622 		if (rdip == (dev_info_t *)0)
623 			return (DDI_FAILURE);
624 
625 		*(int *)result = 0;
626 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip,
627 		    DDI_PROP_DONTPASS, "reg", (int **)&drv_regp,
628 		    &reglen) != DDI_PROP_SUCCESS) {
629 			return (DDI_FAILURE);
630 		}
631 
632 		totreg = (reglen * sizeof (int)) / sizeof (pci_regspec_t);
633 		if (ctlop == DDI_CTLOPS_NREGS)
634 			*(int *)result = totreg;
635 		else if (ctlop == DDI_CTLOPS_REGSIZE) {
636 			rn = *(int *)arg;
637 			if (rn >= totreg) {
638 				ddi_prop_free(drv_regp);
639 				return (DDI_FAILURE);
640 			}
641 			*(off_t *)result = drv_regp[rn].pci_size_low;
642 		}
643 		ddi_prop_free(drv_regp);
644 
645 		return (DDI_SUCCESS);
646 
647 	case DDI_CTLOPS_POWER:
648 	{
649 		power_req_t	*reqp = (power_req_t *)arg;
650 		/*
651 		 * We currently understand reporting of PCI_PM_IDLESPEED
652 		 * capability. Everything else is passed up.
653 		 */
654 		if ((reqp->request_type == PMR_REPORT_PMCAP) &&
655 		    (reqp->req.report_pmcap_req.cap ==  PCI_PM_IDLESPEED))
656 			return (DDI_SUCCESS);
657 
658 		break;
659 	}
660 
661 	case DDI_CTLOPS_PEEK:
662 	case DDI_CTLOPS_POKE:
663 		return (pci_common_peekpoke(dip, rdip, ctlop, arg, result));
664 
665 	default:
666 		break;
667 	}
668 
669 	return (ddi_ctlops(dip, rdip, ctlop, arg, result));
670 
671 }
672 
673 
674 /*
675  * npe_intr_ops
676  */
677 static int
678 npe_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
679     ddi_intr_handle_impl_t *hdlp, void *result)
680 {
681 	return (pci_common_intr_ops(pdip, rdip, intr_op, hdlp, result));
682 }
683 
684 
685 static int
686 npe_initchild(dev_info_t *child)
687 {
688 	char			name[80];
689 	ddi_acc_handle_t	cfg_hdl;
690 
691 	/*
692 	 * Do not bind drivers to empty bridges.
693 	 * Fail above, if the bridge is found to be hotplug capable
694 	 */
695 	if (npe_disable_empty_bridges_workaround(child) == 1)
696 		return (DDI_FAILURE);
697 
698 	if (pci_common_name_child(child, name, 80) != DDI_SUCCESS)
699 		return (DDI_FAILURE);
700 
701 	ddi_set_name_addr(child, name);
702 
703 	/*
704 	 * Pseudo nodes indicate a prototype node with per-instance
705 	 * properties to be merged into the real h/w device node.
706 	 * The interpretation of the unit-address is DD[,F]
707 	 * where DD is the device id and F is the function.
708 	 */
709 	if (ndi_dev_is_persistent_node(child) == 0) {
710 		extern int pci_allow_pseudo_children;
711 
712 		ddi_set_parent_data(child, NULL);
713 
714 		/*
715 		 * Try to merge the properties from this prototype
716 		 * node into real h/w nodes.
717 		 */
718 		if (ndi_merge_node(child, pci_common_name_child) ==
719 		    DDI_SUCCESS) {
720 			/*
721 			 * Merged ok - return failure to remove the node.
722 			 */
723 			ddi_set_name_addr(child, NULL);
724 			return (DDI_FAILURE);
725 		}
726 
727 		/* workaround for DDIVS to run under PCI Express */
728 		if (pci_allow_pseudo_children) {
729 			/*
730 			 * If the "interrupts" property doesn't exist,
731 			 * this must be the ddivs no-intr case, and it returns
732 			 * DDI_SUCCESS instead of DDI_FAILURE.
733 			 */
734 			if (ddi_prop_get_int(DDI_DEV_T_ANY, child,
735 			    DDI_PROP_DONTPASS, "interrupts", -1) == -1)
736 				return (DDI_SUCCESS);
737 			/*
738 			 * Create the ddi_parent_private_data for a pseudo
739 			 * child.
740 			 */
741 			pci_common_set_parent_private_data(child);
742 			return (DDI_SUCCESS);
743 		}
744 
745 		/*
746 		 * The child was not merged into a h/w node,
747 		 * but there's not much we can do with it other
748 		 * than return failure to cause the node to be removed.
749 		 */
750 		cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged",
751 		    ddi_get_name(child), ddi_get_name_addr(child),
752 		    ddi_get_name(child));
753 		ddi_set_name_addr(child, NULL);
754 		return (DDI_NOT_WELL_FORMED);
755 	}
756 
757 	if (ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
758 	    "interrupts", -1) != -1)
759 		pci_common_set_parent_private_data(child);
760 	else
761 		ddi_set_parent_data(child, NULL);
762 
763 	/*
764 	 * Enable AER next pointer being displayed and PCIe Error initilization
765 	 */
766 	if (pci_config_setup(child, &cfg_hdl) == DDI_SUCCESS) {
767 		npe_ck804_fix_aer_ptr(cfg_hdl);
768 		(void) pcie_error_enable(child, cfg_hdl);
769 		pci_config_teardown(&cfg_hdl);
770 	}
771 
772 	return (DDI_SUCCESS);
773 }
774 
775 
776 static int
777 npe_removechild(dev_info_t *dip)
778 {
779 	ddi_acc_handle_t		cfg_hdl;
780 	struct ddi_parent_private_data	*pdptr;
781 
782 	/*
783 	 * Do it way early.
784 	 * Otherwise ddi_map() call form pcie_error_fini crashes
785 	 */
786 	if (pci_config_setup(dip, &cfg_hdl) == DDI_SUCCESS) {
787 		pcie_error_disable(dip, cfg_hdl);
788 		pci_config_teardown(&cfg_hdl);
789 	}
790 
791 	if ((pdptr = ddi_get_parent_data(dip)) != NULL) {
792 		kmem_free(pdptr, (sizeof (*pdptr) + sizeof (struct intrspec)));
793 		ddi_set_parent_data(dip, NULL);
794 	}
795 	ddi_set_name_addr(dip, NULL);
796 
797 	/*
798 	 * Strip the node to properly convert it back to prototype form
799 	 */
800 	ddi_remove_minor_node(dip, NULL);
801 
802 	ddi_prop_remove_all(dip);
803 
804 	return (DDI_SUCCESS);
805 }
806 
807 
808 /*
809  * When retrofitting this module for pci_tools, functions such as open, close,
810  * and ioctl are now pulled into this module.  Before this, the functions in
811  * the pcihp module were referenced directly.  Now they are called or
812  * referenced through the pcihp cb_ops structure from functions in this module.
813  */
814 static int
815 npe_open(dev_t *devp, int flags, int otyp, cred_t *credp)
816 {
817 	return ((pcihp_get_cb_ops())->cb_open(devp, flags, otyp, credp));
818 }
819 
820 static int
821 npe_close(dev_t dev, int flags, int otyp, cred_t *credp)
822 {
823 	return ((pcihp_get_cb_ops())->cb_close(dev, flags, otyp, credp));
824 }
825 
826 static int
827 npe_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
828 {
829 	minor_t		minor = getminor(dev);
830 	int		instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
831 	pci_state_t	*pci_p = ddi_get_soft_state(npe_statep, instance);
832 	dev_info_t	*dip;
833 
834 	if (pci_p == NULL)
835 		return (ENXIO);
836 
837 	dip = pci_p->pci_dip;
838 	return (pci_common_ioctl(dip, dev, cmd, arg, mode, credp, rvalp));
839 }
840 
841 static int
842 npe_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
843 	int flags, char *name, caddr_t valuep, int *lengthp)
844 {
845 	return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip, prop_op, flags,
846 	    name, valuep, lengthp));
847 }
848 
849 static int
850 npe_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
851 {
852 	return (pcihp_info(dip, cmd, arg, result));
853 }
854 
855 /*ARGSUSED*/
856 static int
857 npe_fm_init(dev_info_t *dip, dev_info_t *tdip, int cap,
858     ddi_iblock_cookie_t *ibc)
859 {
860 	pci_state_t  *pcip = ddi_get_soft_state(npe_statep,
861 	    ddi_get_instance(dip));
862 
863 	ASSERT(ibc != NULL);
864 	*ibc = pcip->pci_fm_ibc;
865 
866 	return (pcip->pci_fmcap);
867 }
868 
869 /*ARGSUSED*/
870 static int
871 npe_fm_callback(dev_info_t *dip, ddi_fm_error_t *derr, const void *no_used)
872 {
873 	return (ndi_fm_handler_dispatch(dip, NULL, derr));
874 }
875