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