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