xref: /illumos-gate/usr/src/uts/i86pc/io/pciex/npe.c (revision b6c3f786)
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 2007 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 (cmd == DDI_RESUME)
232 		return (DDI_SUCCESS);
233 
234 	if (ddi_prop_update_string(DDI_DEV_T_NONE, devi, "device_type",
235 	    "pciex") != DDI_PROP_SUCCESS) {
236 		cmn_err(CE_WARN, "npe:  'device_type' prop create failed");
237 	}
238 
239 	if (ddi_soft_state_zalloc(npe_statep, instance) == DDI_SUCCESS)
240 		pcip = ddi_get_soft_state(npe_statep, instance);
241 
242 	if (pcip == NULL)
243 		return (DDI_FAILURE);
244 
245 	pcip->pci_dip = devi;
246 
247 	/*
248 	 * Initialize hotplug support on this bus. At minimum
249 	 * (for non hotplug bus) this would create ":devctl" minor
250 	 * node to support DEVCTL_DEVICE_* and DEVCTL_BUS_* ioctls
251 	 * to this bus.
252 	 */
253 	if (pcihp_init(devi) != DDI_SUCCESS) {
254 		cmn_err(CE_WARN, "npe: Failed to setup hotplug framework");
255 		ddi_soft_state_free(npe_statep, instance);
256 		return (DDI_FAILURE);
257 	}
258 
259 	/* Second arg: initialize for pci_express root nexus */
260 	if (pcitool_init(devi, B_TRUE) != DDI_SUCCESS) {
261 		(void) pcihp_uninit(devi);
262 		ddi_soft_state_free(npe_statep, instance);
263 		return (DDI_FAILURE);
264 	}
265 	pcip->pci_fmcap = DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE |
266 	    DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE;
267 	ddi_fm_init(devi, &pcip->pci_fmcap, &pcip->pci_fm_ibc);
268 
269 	if (pcip->pci_fmcap & DDI_FM_ERRCB_CAPABLE)
270 		ddi_fm_handler_register(devi, npe_fm_callback, NULL);
271 
272 	npe_query_acpi_mcfg(devi);
273 	ddi_report_dev(devi);
274 	return (DDI_SUCCESS);
275 
276 }
277 
278 
279 /*ARGSUSED*/
280 static int
281 npe_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
282 {
283 	int instance = ddi_get_instance(devi);
284 	pci_state_t *pcip;
285 
286 	pcip = ddi_get_soft_state(npe_statep, ddi_get_instance(devi));
287 
288 	switch (cmd) {
289 	case DDI_DETACH:
290 
291 		/* Uninitialize pcitool support. */
292 		pcitool_uninit(devi);
293 
294 		/*
295 		 * Uninitialize hotplug support on this bus.
296 		 */
297 		(void) pcihp_uninit(devi);
298 
299 		if (pcip->pci_fmcap & DDI_FM_ERRCB_CAPABLE)
300 			ddi_fm_handler_unregister(devi);
301 
302 		ddi_fm_fini(devi);
303 		ddi_soft_state_free(npe_statep, instance);
304 		return (DDI_SUCCESS);
305 
306 	case DDI_SUSPEND:
307 		return (DDI_SUCCESS);
308 	default:
309 		return (DDI_FAILURE);
310 	}
311 }
312 
313 
314 static int
315 npe_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
316     off_t offset, off_t len, caddr_t *vaddrp)
317 {
318 	int 		rnumber;
319 	int		length;
320 	int		space;
321 	ddi_acc_impl_t	*ap;
322 	ddi_acc_hdl_t	*hp;
323 	ddi_map_req_t	mr;
324 	pci_regspec_t	pci_reg;
325 	pci_regspec_t	*pci_rp;
326 	struct regspec	reg;
327 	pci_acc_cfblk_t	*cfp;
328 	int		retval;
329 
330 	mr = *mp; /* Get private copy of request */
331 	mp = &mr;
332 
333 	/*
334 	 * check for register number
335 	 */
336 	switch (mp->map_type) {
337 	case DDI_MT_REGSPEC:
338 		pci_reg = *(pci_regspec_t *)(mp->map_obj.rp);
339 		pci_rp = &pci_reg;
340 		if (pci_common_get_reg_prop(rdip, pci_rp) != DDI_SUCCESS)
341 			return (DDI_FAILURE);
342 		break;
343 	case DDI_MT_RNUMBER:
344 		rnumber = mp->map_obj.rnumber;
345 		/*
346 		 * get ALL "reg" properties for dip, select the one of
347 		 * of interest. In x86, "assigned-addresses" property
348 		 * is identical to the "reg" property, so there is no
349 		 * need to cross check the two to determine the physical
350 		 * address of the registers.
351 		 * This routine still performs some validity checks to
352 		 * make sure that everything is okay.
353 		 */
354 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip,
355 		    DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
356 		    (uint_t *)&length) != DDI_PROP_SUCCESS)
357 			return (DDI_FAILURE);
358 
359 		/*
360 		 * validate the register number.
361 		 */
362 		length /= (sizeof (pci_regspec_t) / sizeof (int));
363 		if (rnumber >= length) {
364 			ddi_prop_free(pci_rp);
365 			return (DDI_FAILURE);
366 		}
367 
368 		/*
369 		 * copy the required entry.
370 		 */
371 		pci_reg = pci_rp[rnumber];
372 
373 		/*
374 		 * free the memory allocated by ddi_prop_lookup_int_array
375 		 */
376 		ddi_prop_free(pci_rp);
377 
378 		pci_rp = &pci_reg;
379 		if (pci_common_get_reg_prop(rdip, pci_rp) != DDI_SUCCESS)
380 			return (DDI_FAILURE);
381 		mp->map_type = DDI_MT_REGSPEC;
382 		break;
383 	default:
384 		return (DDI_ME_INVAL);
385 	}
386 
387 	space = pci_rp->pci_phys_hi & PCI_REG_ADDR_M;
388 
389 	/*
390 	 * check for unmap and unlock of address space
391 	 */
392 	if ((mp->map_op == DDI_MO_UNMAP) || (mp->map_op == DDI_MO_UNLOCK)) {
393 		switch (space) {
394 		case PCI_ADDR_IO:
395 			reg.regspec_bustype = 1;
396 			break;
397 
398 		case PCI_ADDR_CONFIG:
399 			/*
400 			 * Check for AMD's northbridges
401 			 *	AND
402 			 * for any PCI device.
403 			 *
404 			 * This is a workaround fix for
405 			 * AMD-8132's inability to handle MMCFG
406 			 * accesses on Galaxy's PE servers
407 			 *	AND
408 			 * to disable MMCFG for any PCI device.
409 			 *
410 			 * If a device is *not* found to have PCIe
411 			 * capability, then assume it is a PCI device.
412 			 */
413 
414 			if (is_amd_northbridge(rdip) == 0 ||
415 			    (ddi_prop_get_int(DDI_DEV_T_ANY, rdip,
416 			    DDI_PROP_DONTPASS, "pcie-capid-pointer",
417 			    PCI_CAP_NEXT_PTR_NULL) == PCI_CAP_NEXT_PTR_NULL)) {
418 				if (DDI_FM_ACC_ERR_CAP(ddi_fm_capable(rdip)) &&
419 				    mp->map_handlep->ah_acc.devacc_attr_access
420 				    != DDI_DEFAULT_ACC) {
421 					ndi_fmc_remove(rdip, ACC_HANDLE,
422 					    (void *)mp->map_handlep);
423 				}
424 				return (DDI_SUCCESS);
425 			}
426 
427 
428 			/* FALLTHROUGH */
429 		case PCI_ADDR_MEM64:
430 			/*
431 			 * MEM64 requires special treatment on map, to check
432 			 * that the device is below 4G.  On unmap, however,
433 			 * we can assume that everything is OK... the map
434 			 * must have succeeded.
435 			 */
436 			/* FALLTHROUGH */
437 		case PCI_ADDR_MEM32:
438 			reg.regspec_bustype = 0;
439 			break;
440 
441 		default:
442 			return (DDI_FAILURE);
443 		}
444 
445 		/*
446 		 * Adjust offset and length
447 		 * A non-zero length means override the one in the regspec.
448 		 */
449 		pci_rp->pci_phys_low += (uint_t)offset;
450 		if (len != 0)
451 			pci_rp->pci_size_low = len;
452 
453 		reg.regspec_addr = pci_rp->pci_phys_low;
454 		reg.regspec_size = pci_rp->pci_size_low;
455 
456 		mp->map_obj.rp = &reg;
457 		retval = ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp);
458 		if (DDI_FM_ACC_ERR_CAP(ddi_fm_capable(rdip)) &&
459 		    mp->map_handlep->ah_acc.devacc_attr_access !=
460 		    DDI_DEFAULT_ACC) {
461 			ndi_fmc_remove(rdip, ACC_HANDLE,
462 			    (void *)mp->map_handlep);
463 		}
464 		return (retval);
465 
466 	}
467 
468 	/* check for user mapping request - not legal for Config */
469 	if (mp->map_op == DDI_MO_MAP_HANDLE && space == PCI_ADDR_CONFIG) {
470 		cmn_err(CE_NOTE, "npe: Config mapping request from user\n");
471 		return (DDI_FAILURE);
472 	}
473 
474 
475 	/*
476 	 * Note that pci_fm_acc_setup() is called to serve two purposes
477 	 * i) enable legacy PCI I/O style config space access
478 	 * ii) register with FMA
479 	 */
480 	if (space == PCI_ADDR_CONFIG) {
481 		/* Can't map config space without a handle */
482 		hp = (ddi_acc_hdl_t *)mp->map_handlep;
483 		if (hp == NULL)
484 			return (DDI_FAILURE);
485 
486 		/* record the device address for future reference */
487 		cfp = (pci_acc_cfblk_t *)&hp->ah_bus_private;
488 		cfp->c_busnum = PCI_REG_BUS_G(pci_rp->pci_phys_hi);
489 		cfp->c_devnum = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
490 		cfp->c_funcnum = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
491 
492 		*vaddrp = (caddr_t)offset;
493 
494 		/*
495 		 * Check for AMD's northbridges, pci devices and
496 		 * devices underneath a pci bridge.  This is to setup
497 		 * I/O based config space access.
498 		 */
499 		if (is_amd_northbridge(rdip) == 0 ||
500 		    (ddi_prop_get_int(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
501 		    "pcie-capid-pointer", PCI_CAP_NEXT_PTR_NULL) ==
502 		    PCI_CAP_NEXT_PTR_NULL)) {
503 			int ret;
504 
505 			if ((ret = pci_fm_acc_setup(hp, offset, len)) ==
506 			    DDI_SUCCESS) {
507 				if (DDI_FM_ACC_ERR_CAP(ddi_fm_capable(rdip)) &&
508 				    mp->map_handlep->ah_acc.devacc_attr_access
509 				    != DDI_DEFAULT_ACC) {
510 					ndi_fmc_insert(rdip, ACC_HANDLE,
511 					    (void *)mp->map_handlep, NULL);
512 				}
513 			}
514 			return (ret);
515 		}
516 
517 		pci_rp->pci_phys_low = ddi_prop_get_int64(DDI_DEV_T_ANY,
518 		    rdip, 0, "ecfga-base-address", 0);
519 
520 		pci_rp->pci_phys_low += ((cfp->c_busnum << 20) |
521 		    (cfp->c_devnum) << 15 | (cfp->c_funcnum << 12));
522 
523 		pci_rp->pci_size_low = PCIE_CONF_HDR_SIZE;
524 	}
525 
526 	length = pci_rp->pci_size_low;
527 
528 	/*
529 	 * range check
530 	 */
531 	if ((offset >= length) || (len > length) || (offset + len > length))
532 		return (DDI_FAILURE);
533 
534 	/*
535 	 * Adjust offset and length
536 	 * A non-zero length means override the one in the regspec.
537 	 */
538 	pci_rp->pci_phys_low += (uint_t)offset;
539 	if (len != 0)
540 		pci_rp->pci_size_low = len;
541 
542 	/*
543 	 * convert the pci regsec into the generic regspec used by the
544 	 * parent root nexus driver.
545 	 */
546 	switch (space) {
547 	case PCI_ADDR_IO:
548 		reg.regspec_bustype = 1;
549 		break;
550 	case PCI_ADDR_CONFIG:
551 	case PCI_ADDR_MEM64:
552 		/*
553 		 * We can't handle 64-bit devices that are mapped above
554 		 * 4G or that are larger than 4G.
555 		 */
556 		if (pci_rp->pci_phys_mid != 0 || pci_rp->pci_size_hi != 0)
557 			return (DDI_FAILURE);
558 		/*
559 		 * Other than that, we can treat them as 32-bit mappings
560 		 */
561 		/* FALLTHROUGH */
562 	case PCI_ADDR_MEM32:
563 		reg.regspec_bustype = 0;
564 		break;
565 	default:
566 		return (DDI_FAILURE);
567 	}
568 
569 	reg.regspec_addr = pci_rp->pci_phys_low;
570 	reg.regspec_size = pci_rp->pci_size_low;
571 
572 	mp->map_obj.rp = &reg;
573 	retval = ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp);
574 	if (retval == DDI_SUCCESS) {
575 		/*
576 		 * For config space gets force use of cautious access routines.
577 		 * These will handle default and protected mode accesses too.
578 		 */
579 		if (space == PCI_ADDR_CONFIG) {
580 			ap = (ddi_acc_impl_t *)mp->map_handlep;
581 			ap->ahi_acc_attr &= ~DDI_ACCATTR_DIRECT;
582 			ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE;
583 			ap->ahi_get8 = i_ddi_caut_get8;
584 			ap->ahi_get16 = i_ddi_caut_get16;
585 			ap->ahi_get32 = i_ddi_caut_get32;
586 			ap->ahi_get64 = i_ddi_caut_get64;
587 			ap->ahi_rep_get8 = i_ddi_caut_rep_get8;
588 			ap->ahi_rep_get16 = i_ddi_caut_rep_get16;
589 			ap->ahi_rep_get32 = i_ddi_caut_rep_get32;
590 			ap->ahi_rep_get64 = i_ddi_caut_rep_get64;
591 		}
592 		if (DDI_FM_ACC_ERR_CAP(ddi_fm_capable(rdip)) &&
593 		    mp->map_handlep->ah_acc.devacc_attr_access !=
594 		    DDI_DEFAULT_ACC) {
595 			ndi_fmc_insert(rdip, ACC_HANDLE,
596 			    (void *)mp->map_handlep, NULL);
597 		}
598 	}
599 	return (retval);
600 }
601 
602 
603 
604 /*ARGSUSED*/
605 static int
606 npe_ctlops(dev_info_t *dip, dev_info_t *rdip,
607 	ddi_ctl_enum_t ctlop, void *arg, void *result)
608 {
609 	int		rn;
610 	int		totreg;
611 	uint_t		reglen;
612 	pci_regspec_t	*drv_regp;
613 	struct	attachspec *asp;
614 
615 	switch (ctlop) {
616 	case DDI_CTLOPS_REPORTDEV:
617 		if (rdip == (dev_info_t *)0)
618 			return (DDI_FAILURE);
619 		cmn_err(CE_CONT, "?PCI Express-device: %s@%s, %s%d\n",
620 		    ddi_node_name(rdip), ddi_get_name_addr(rdip),
621 		    ddi_driver_name(rdip), ddi_get_instance(rdip));
622 		return (DDI_SUCCESS);
623 
624 	case DDI_CTLOPS_INITCHILD:
625 		return (npe_initchild((dev_info_t *)arg));
626 
627 	case DDI_CTLOPS_UNINITCHILD:
628 		return (npe_removechild((dev_info_t *)arg));
629 
630 	case DDI_CTLOPS_SIDDEV:
631 		return (DDI_SUCCESS);
632 
633 	case DDI_CTLOPS_REGSIZE:
634 	case DDI_CTLOPS_NREGS:
635 		if (rdip == (dev_info_t *)0)
636 			return (DDI_FAILURE);
637 
638 		*(int *)result = 0;
639 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip,
640 		    DDI_PROP_DONTPASS, "reg", (int **)&drv_regp,
641 		    &reglen) != DDI_PROP_SUCCESS) {
642 			return (DDI_FAILURE);
643 		}
644 
645 		totreg = (reglen * sizeof (int)) / sizeof (pci_regspec_t);
646 		if (ctlop == DDI_CTLOPS_NREGS)
647 			*(int *)result = totreg;
648 		else if (ctlop == DDI_CTLOPS_REGSIZE) {
649 			rn = *(int *)arg;
650 			if (rn >= totreg) {
651 				ddi_prop_free(drv_regp);
652 				return (DDI_FAILURE);
653 			}
654 			*(off_t *)result = drv_regp[rn].pci_size_low;
655 		}
656 		ddi_prop_free(drv_regp);
657 
658 		return (DDI_SUCCESS);
659 
660 	case DDI_CTLOPS_POWER:
661 	{
662 		power_req_t	*reqp = (power_req_t *)arg;
663 		/*
664 		 * We currently understand reporting of PCI_PM_IDLESPEED
665 		 * capability. Everything else is passed up.
666 		 */
667 		if ((reqp->request_type == PMR_REPORT_PMCAP) &&
668 		    (reqp->req.report_pmcap_req.cap ==  PCI_PM_IDLESPEED))
669 			return (DDI_SUCCESS);
670 
671 		break;
672 	}
673 
674 	case DDI_CTLOPS_PEEK:
675 	case DDI_CTLOPS_POKE:
676 		return (pci_common_peekpoke(dip, rdip, ctlop, arg, result));
677 
678 	/* X86 systems support PME wakeup from suspended state */
679 	case DDI_CTLOPS_ATTACH:
680 		asp = (struct attachspec *)arg;
681 		/* only do this for immediate children */
682 		if (asp->cmd == DDI_RESUME && asp->when == DDI_PRE &&
683 		    ddi_get_parent(rdip) == dip)
684 			if (pci_pre_resume(rdip) != DDI_SUCCESS) {
685 				/* Not good, better stop now. */
686 				cmn_err(CE_PANIC,
687 				    "Couldn't pre-resume device %p",
688 				    (void *) dip);
689 				/* NOTREACHED */
690 			}
691 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
692 
693 	case DDI_CTLOPS_DETACH:
694 		asp = (struct attachspec *)arg;
695 		/* only do this for immediate children */
696 		if (asp->cmd == DDI_SUSPEND && asp->when == DDI_POST &&
697 		    ddi_get_parent(rdip) == dip)
698 			if (pci_post_suspend(rdip) != DDI_SUCCESS)
699 				return (DDI_FAILURE);
700 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
701 
702 	default:
703 		break;
704 	}
705 
706 	return (ddi_ctlops(dip, rdip, ctlop, arg, result));
707 
708 }
709 
710 
711 /*
712  * npe_intr_ops
713  */
714 static int
715 npe_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
716     ddi_intr_handle_impl_t *hdlp, void *result)
717 {
718 	return (pci_common_intr_ops(pdip, rdip, intr_op, hdlp, result));
719 }
720 
721 
722 static int
723 npe_initchild(dev_info_t *child)
724 {
725 	char			name[80];
726 	ddi_acc_handle_t	cfg_hdl;
727 
728 	/*
729 	 * Do not bind drivers to empty bridges.
730 	 * Fail above, if the bridge is found to be hotplug capable
731 	 */
732 	if (npe_disable_empty_bridges_workaround(child) == 1)
733 		return (DDI_FAILURE);
734 
735 	if (pci_common_name_child(child, name, 80) != DDI_SUCCESS)
736 		return (DDI_FAILURE);
737 
738 	ddi_set_name_addr(child, name);
739 
740 	/*
741 	 * Pseudo nodes indicate a prototype node with per-instance
742 	 * properties to be merged into the real h/w device node.
743 	 * The interpretation of the unit-address is DD[,F]
744 	 * where DD is the device id and F is the function.
745 	 */
746 	if (ndi_dev_is_persistent_node(child) == 0) {
747 		extern int pci_allow_pseudo_children;
748 
749 		ddi_set_parent_data(child, NULL);
750 
751 		/*
752 		 * Try to merge the properties from this prototype
753 		 * node into real h/w nodes.
754 		 */
755 		if (ndi_merge_node(child, pci_common_name_child) ==
756 		    DDI_SUCCESS) {
757 			/*
758 			 * Merged ok - return failure to remove the node.
759 			 */
760 			ddi_set_name_addr(child, NULL);
761 			return (DDI_FAILURE);
762 		}
763 
764 		/* workaround for DDIVS to run under PCI Express */
765 		if (pci_allow_pseudo_children) {
766 			/*
767 			 * If the "interrupts" property doesn't exist,
768 			 * this must be the ddivs no-intr case, and it returns
769 			 * DDI_SUCCESS instead of DDI_FAILURE.
770 			 */
771 			if (ddi_prop_get_int(DDI_DEV_T_ANY, child,
772 			    DDI_PROP_DONTPASS, "interrupts", -1) == -1)
773 				return (DDI_SUCCESS);
774 			/*
775 			 * Create the ddi_parent_private_data for a pseudo
776 			 * child.
777 			 */
778 			pci_common_set_parent_private_data(child);
779 			return (DDI_SUCCESS);
780 		}
781 
782 		/*
783 		 * The child was not merged into a h/w node,
784 		 * but there's not much we can do with it other
785 		 * than return failure to cause the node to be removed.
786 		 */
787 		cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged",
788 		    ddi_get_name(child), ddi_get_name_addr(child),
789 		    ddi_get_name(child));
790 		ddi_set_name_addr(child, NULL);
791 		return (DDI_NOT_WELL_FORMED);
792 	}
793 
794 	if (ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
795 	    "interrupts", -1) != -1)
796 		pci_common_set_parent_private_data(child);
797 	else
798 		ddi_set_parent_data(child, NULL);
799 
800 	/*
801 	 * Enable AER next pointer being displayed and PCIe Error initilization
802 	 */
803 	if (pci_config_setup(child, &cfg_hdl) == DDI_SUCCESS) {
804 		npe_ck804_fix_aer_ptr(cfg_hdl);
805 		(void) pcie_error_enable(child, cfg_hdl);
806 		pci_config_teardown(&cfg_hdl);
807 	}
808 
809 	return (DDI_SUCCESS);
810 }
811 
812 
813 static int
814 npe_removechild(dev_info_t *dip)
815 {
816 	ddi_acc_handle_t		cfg_hdl;
817 	struct ddi_parent_private_data	*pdptr;
818 
819 	/*
820 	 * Do it way early.
821 	 * Otherwise ddi_map() call form pcie_error_fini crashes
822 	 */
823 	if (pci_config_setup(dip, &cfg_hdl) == DDI_SUCCESS) {
824 		pcie_error_disable(dip, cfg_hdl);
825 		pci_config_teardown(&cfg_hdl);
826 	}
827 
828 	if ((pdptr = ddi_get_parent_data(dip)) != NULL) {
829 		kmem_free(pdptr, (sizeof (*pdptr) + sizeof (struct intrspec)));
830 		ddi_set_parent_data(dip, NULL);
831 	}
832 	ddi_set_name_addr(dip, NULL);
833 
834 	/*
835 	 * Strip the node to properly convert it back to prototype form
836 	 */
837 	ddi_remove_minor_node(dip, NULL);
838 
839 	ddi_prop_remove_all(dip);
840 
841 	return (DDI_SUCCESS);
842 }
843 
844 
845 /*
846  * When retrofitting this module for pci_tools, functions such as open, close,
847  * and ioctl are now pulled into this module.  Before this, the functions in
848  * the pcihp module were referenced directly.  Now they are called or
849  * referenced through the pcihp cb_ops structure from functions in this module.
850  */
851 static int
852 npe_open(dev_t *devp, int flags, int otyp, cred_t *credp)
853 {
854 	return ((pcihp_get_cb_ops())->cb_open(devp, flags, otyp, credp));
855 }
856 
857 static int
858 npe_close(dev_t dev, int flags, int otyp, cred_t *credp)
859 {
860 	return ((pcihp_get_cb_ops())->cb_close(dev, flags, otyp, credp));
861 }
862 
863 static int
864 npe_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
865 {
866 	minor_t		minor = getminor(dev);
867 	int		instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
868 	pci_state_t	*pci_p = ddi_get_soft_state(npe_statep, instance);
869 	dev_info_t	*dip;
870 
871 	if (pci_p == NULL)
872 		return (ENXIO);
873 
874 	dip = pci_p->pci_dip;
875 	return (pci_common_ioctl(dip, dev, cmd, arg, mode, credp, rvalp));
876 }
877 
878 static int
879 npe_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
880 	int flags, char *name, caddr_t valuep, int *lengthp)
881 {
882 	return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip, prop_op, flags,
883 	    name, valuep, lengthp));
884 }
885 
886 static int
887 npe_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
888 {
889 	return (pcihp_info(dip, cmd, arg, result));
890 }
891 
892 /*ARGSUSED*/
893 static int
894 npe_fm_init(dev_info_t *dip, dev_info_t *tdip, int cap,
895     ddi_iblock_cookie_t *ibc)
896 {
897 	pci_state_t  *pcip = ddi_get_soft_state(npe_statep,
898 	    ddi_get_instance(dip));
899 
900 	ASSERT(ibc != NULL);
901 	*ibc = pcip->pci_fm_ibc;
902 
903 	return (pcip->pci_fmcap);
904 }
905 
906 /*ARGSUSED*/
907 static int
908 npe_fm_callback(dev_info_t *dip, ddi_fm_error_t *derr, const void *no_used)
909 {
910 	return (ndi_fm_handler_dispatch(dip, NULL, derr));
911 }
912