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