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