px.c revision 7656:2621e50fdf4a
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 2008 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26/*
27 * PCI Express nexus driver interface
28 */
29
30#include <sys/types.h>
31#include <sys/conf.h>		/* nulldev */
32#include <sys/stat.h>		/* devctl */
33#include <sys/kmem.h>
34#include <sys/sunddi.h>
35#include <sys/sunndi.h>
36#include <sys/ddi_impldefs.h>
37#include <sys/ddi_subrdefs.h>
38#include <sys/spl.h>
39#include <sys/epm.h>
40#include <sys/iommutsb.h>
41#include <sys/hotplug/pci/pcihp.h>
42#include <sys/hotplug/pci/pciehpc.h>
43#include "px_obj.h"
44#include <sys/pci_tools.h>
45#include "px_tools_ext.h"
46#include "pcie_pwr.h"
47
48/*LINTLIBRARY*/
49
50/*
51 * function prototypes for dev ops routines:
52 */
53static int px_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
54static int px_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
55static int px_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
56	void *arg, void **result);
57static int px_cb_attach(px_t *);
58static void px_cb_detach(px_t *);
59static int px_pwr_setup(dev_info_t *dip);
60static void px_pwr_teardown(dev_info_t *dip);
61
62static void px_set_mps(px_t *px_p);
63
64extern int pcie_max_mps;
65
66extern errorq_t *pci_target_queue;
67
68/*
69 * function prototypes for hotplug routines:
70 */
71static int px_init_hotplug(px_t *px_p);
72static int px_uninit_hotplug(dev_info_t *dip);
73
74/*
75 * bus ops and dev ops structures:
76 */
77static struct bus_ops px_bus_ops = {
78	BUSO_REV,
79	px_map,
80	0,
81	0,
82	0,
83	i_ddi_map_fault,
84	px_dma_setup,
85	px_dma_allochdl,
86	px_dma_freehdl,
87	px_dma_bindhdl,
88	px_dma_unbindhdl,
89	px_lib_dma_sync,
90	px_dma_win,
91	px_dma_ctlops,
92	px_ctlops,
93	ddi_bus_prop_op,
94	ndi_busop_get_eventcookie,
95	ndi_busop_add_eventcall,
96	ndi_busop_remove_eventcall,
97	ndi_post_event,
98	NULL,
99	NULL,			/* (*bus_config)(); */
100	NULL,			/* (*bus_unconfig)(); */
101	px_fm_init_child,	/* (*bus_fm_init)(); */
102	NULL,			/* (*bus_fm_fini)(); */
103	px_bus_enter,		/* (*bus_fm_access_enter)(); */
104	px_bus_exit,		/* (*bus_fm_access_fini)(); */
105	pcie_bus_power,		/* (*bus_power)(); */
106	px_intr_ops		/* (*bus_intr_op)(); */
107};
108
109extern struct cb_ops px_cb_ops;
110
111static struct dev_ops px_ops = {
112	DEVO_REV,
113	0,
114	px_info,
115	nulldev,
116	0,
117	px_attach,
118	px_detach,
119	nodev,
120	&px_cb_ops,
121	&px_bus_ops,
122	nulldev,
123	ddi_quiesce_not_needed,		/* quiesce */
124};
125
126/*
127 * module definitions:
128 */
129#include <sys/modctl.h>
130extern struct mod_ops mod_driverops;
131
132static struct modldrv modldrv = {
133	&mod_driverops, 		/* Type of module - driver */
134	"PCI Express nexus driver",	/* Name of module. */
135	&px_ops,			/* driver ops */
136};
137
138static struct modlinkage modlinkage = {
139	MODREV_1, (void *)&modldrv, NULL
140};
141
142/* driver soft state */
143void *px_state_p;
144
145int
146_init(void)
147{
148	int e;
149
150	/*
151	 * Initialize per-px bus soft state pointer.
152	 */
153	e = ddi_soft_state_init(&px_state_p, sizeof (px_t), 1);
154	if (e != DDI_SUCCESS)
155		return (e);
156
157	/*
158	 * Install the module.
159	 */
160	e = mod_install(&modlinkage);
161	if (e != DDI_SUCCESS)
162		ddi_soft_state_fini(&px_state_p);
163	return (e);
164}
165
166int
167_fini(void)
168{
169	int e;
170
171	/*
172	 * Remove the module.
173	 */
174	e = mod_remove(&modlinkage);
175	if (e != DDI_SUCCESS)
176		return (e);
177	/*
178	 * Destroy pci_target_queue, and set it to NULL.
179	 */
180	if (pci_target_queue)
181		errorq_destroy(pci_target_queue);
182
183	pci_target_queue = NULL;
184
185	/* Free px soft state */
186	ddi_soft_state_fini(&px_state_p);
187
188	return (e);
189}
190
191int
192_info(struct modinfo *modinfop)
193{
194	return (mod_info(&modlinkage, modinfop));
195}
196
197/* ARGSUSED */
198static int
199px_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
200{
201	int	instance = getminor((dev_t)arg);
202	px_t	*px_p = INST_TO_STATE(instance);
203
204	/*
205	 * Allow hotplug to deal with ones it manages
206	 * Hot Plug will be done later.
207	 */
208	if (px_p && (px_p->px_dev_caps & PX_HOTPLUG_CAPABLE))
209		return (pcihp_info(dip, infocmd, arg, result));
210
211	/* non-hotplug or not attached */
212	switch (infocmd) {
213	case DDI_INFO_DEVT2INSTANCE:
214		*result = (void *)(intptr_t)instance;
215		return (DDI_SUCCESS);
216
217	case DDI_INFO_DEVT2DEVINFO:
218		if (px_p == NULL)
219			return (DDI_FAILURE);
220		*result = (void *)px_p->px_dip;
221		return (DDI_SUCCESS);
222
223	default:
224		return (DDI_FAILURE);
225	}
226}
227
228/* device driver entry points */
229/*
230 * attach entry point:
231 */
232/*ARGSUSED*/
233static int
234px_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
235{
236	px_t		*px_p;	/* per bus state pointer */
237	int		instance = DIP_TO_INST(dip);
238	int		ret = DDI_SUCCESS;
239	devhandle_t	dev_hdl = NULL;
240
241	switch (cmd) {
242	case DDI_ATTACH:
243		DBG(DBG_ATTACH, dip, "DDI_ATTACH\n");
244
245		/*
246		 * Allocate and get the per-px soft state structure.
247		 */
248		if (ddi_soft_state_zalloc(px_state_p, instance)
249		    != DDI_SUCCESS) {
250			cmn_err(CE_WARN, "%s%d: can't allocate px state",
251			    ddi_driver_name(dip), instance);
252			goto err_bad_px_softstate;
253		}
254		px_p = INST_TO_STATE(instance);
255		px_p->px_dip = dip;
256		mutex_init(&px_p->px_mutex, NULL, MUTEX_DRIVER, NULL);
257		px_p->px_soft_state = PX_SOFT_STATE_CLOSED;
258		px_p->px_open_count = 0;
259
260		(void) ddi_prop_update_string(DDI_DEV_T_NONE, dip,
261		    "device_type", "pciex");
262
263		/* Initialize px_dbg for high pil printing */
264		px_dbg_attach(dip, &px_p->px_dbg_hdl);
265
266		/*
267		 * Get key properties of the pci bridge node and
268		 * determine it's type (psycho, schizo, etc ...).
269		 */
270		if (px_get_props(px_p, dip) == DDI_FAILURE)
271			goto err_bad_px_prop;
272
273		if (px_lib_dev_init(dip, &dev_hdl) != DDI_SUCCESS)
274			goto err_bad_dev_init;
275
276		/* Initialize device handle */
277		px_p->px_dev_hdl = dev_hdl;
278
279		/* Cache the BDF of the root port nexus */
280		px_p->px_bdf = px_lib_get_bdf(px_p);
281
282		/*
283		 * Initialize interrupt block.  Note that this
284		 * initialize error handling for the PEC as well.
285		 */
286		if ((ret = px_ib_attach(px_p)) != DDI_SUCCESS)
287			goto err_bad_ib;
288
289		if (px_cb_attach(px_p) != DDI_SUCCESS)
290			goto err_bad_cb;
291
292		/*
293		 * Start creating the modules.
294		 * Note that attach() routines should
295		 * register and enable their own interrupts.
296		 */
297
298		if ((px_mmu_attach(px_p)) != DDI_SUCCESS)
299			goto err_bad_mmu;
300
301		if ((px_msiq_attach(px_p)) != DDI_SUCCESS)
302			goto err_bad_msiq;
303
304		if ((px_msi_attach(px_p)) != DDI_SUCCESS)
305			goto err_bad_msi;
306
307		if ((px_pec_attach(px_p)) != DDI_SUCCESS)
308			goto err_bad_pec;
309
310		if ((px_dma_attach(px_p)) != DDI_SUCCESS)
311			goto err_bad_dma; /* nothing to uninitialize on DMA */
312
313		if ((px_fm_attach(px_p)) != DDI_SUCCESS)
314			goto err_bad_dma;
315
316		/*
317		 * All of the error handlers have been registered
318		 * by now so it's time to activate the interrupt.
319		 */
320		if ((ret = px_err_add_intr(&px_p->px_fault)) != DDI_SUCCESS)
321			goto err_bad_intr;
322
323		(void) px_init_hotplug(px_p);
324
325		(void) px_set_mps(px_p);
326
327		/*
328		 * Create the "devctl" node for hotplug and pcitool support.
329		 * For non-hotplug bus, we still need ":devctl" to
330		 * support DEVCTL_DEVICE_* and DEVCTL_BUS_* ioctls.
331		 */
332		if (ddi_create_minor_node(dip, "devctl", S_IFCHR,
333		    PCIHP_AP_MINOR_NUM(instance, PCIHP_DEVCTL_MINOR),
334		    DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
335			goto err_bad_devctl_node;
336		}
337
338		if (pxtool_init(dip) != DDI_SUCCESS)
339			goto err_bad_pcitool_node;
340
341		/*
342		 * power management setup. Even if it fails, attach will
343		 * succeed as this is a optional feature. Since we are
344		 * always at full power, this is not critical.
345		 */
346		if (pwr_common_setup(dip) != DDI_SUCCESS) {
347			DBG(DBG_PWR, dip, "pwr_common_setup failed\n");
348		} else if (px_pwr_setup(dip) != DDI_SUCCESS) {
349			DBG(DBG_PWR, dip, "px_pwr_setup failed \n");
350			pwr_common_teardown(dip);
351		}
352
353		/*
354		 * add cpr callback
355		 */
356		px_cpr_add_callb(px_p);
357
358		ddi_report_dev(dip);
359
360		px_p->px_state = PX_ATTACHED;
361		DBG(DBG_ATTACH, dip, "attach success\n");
362		break;
363
364err_bad_pcitool_node:
365		ddi_remove_minor_node(dip, "devctl");
366err_bad_devctl_node:
367		px_err_rem_intr(&px_p->px_fault);
368err_bad_intr:
369		px_fm_detach(px_p);
370err_bad_dma:
371		px_pec_detach(px_p);
372err_bad_pec:
373		px_msi_detach(px_p);
374err_bad_msi:
375		px_msiq_detach(px_p);
376err_bad_msiq:
377		px_mmu_detach(px_p);
378err_bad_mmu:
379		px_cb_detach(px_p);
380err_bad_cb:
381		px_ib_detach(px_p);
382err_bad_ib:
383		if (px_lib_dev_fini(dip) != DDI_SUCCESS) {
384			DBG(DBG_ATTACH, dip, "px_lib_dev_fini failed\n");
385		}
386err_bad_dev_init:
387		px_free_props(px_p);
388err_bad_px_prop:
389		px_dbg_detach(dip, &px_p->px_dbg_hdl);
390		mutex_destroy(&px_p->px_mutex);
391		ddi_soft_state_free(px_state_p, instance);
392err_bad_px_softstate:
393		ret = DDI_FAILURE;
394		break;
395
396	case DDI_RESUME:
397		DBG(DBG_ATTACH, dip, "DDI_RESUME\n");
398
399		px_p = INST_TO_STATE(instance);
400
401		mutex_enter(&px_p->px_mutex);
402
403		/* suspend might have not succeeded */
404		if (px_p->px_state != PX_SUSPENDED) {
405			DBG(DBG_ATTACH, px_p->px_dip,
406			    "instance NOT suspended\n");
407			ret = DDI_FAILURE;
408			break;
409		}
410
411		px_msiq_resume(px_p);
412		px_lib_resume(dip);
413		(void) pcie_pwr_resume(dip);
414		px_p->px_state = PX_ATTACHED;
415
416		mutex_exit(&px_p->px_mutex);
417
418		break;
419	default:
420		DBG(DBG_ATTACH, dip, "unsupported attach op\n");
421		ret = DDI_FAILURE;
422		break;
423	}
424
425	return (ret);
426}
427
428/*
429 * detach entry point:
430 */
431/*ARGSUSED*/
432static int
433px_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
434{
435	int instance = ddi_get_instance(dip);
436	px_t *px_p = INST_TO_STATE(instance);
437	int ret;
438
439	/*
440	 * Make sure we are currently attached
441	 */
442	if (px_p->px_state != PX_ATTACHED) {
443		DBG(DBG_DETACH, dip, "Instance not attached\n");
444		return (DDI_FAILURE);
445	}
446
447	mutex_enter(&px_p->px_mutex);
448
449	switch (cmd) {
450	case DDI_DETACH:
451		DBG(DBG_DETACH, dip, "DDI_DETACH\n");
452
453		/*
454		 * remove cpr callback
455		 */
456		px_cpr_rem_callb(px_p);
457
458		if (px_p->px_dev_caps & PX_HOTPLUG_CAPABLE)
459			if (px_uninit_hotplug(dip) != DDI_SUCCESS) {
460				mutex_exit(&px_p->px_mutex);
461				return (DDI_FAILURE);
462			}
463
464		/*
465		 * things which used to be done in obj_destroy
466		 * are now in-lined here.
467		 */
468
469		px_p->px_state = PX_DETACHED;
470
471		pxtool_uninit(dip);
472
473		ddi_remove_minor_node(dip, "devctl");
474		px_err_rem_intr(&px_p->px_fault);
475		px_fm_detach(px_p);
476		px_pec_detach(px_p);
477		px_pwr_teardown(dip);
478		pwr_common_teardown(dip);
479		px_msi_detach(px_p);
480		px_msiq_detach(px_p);
481		px_mmu_detach(px_p);
482		px_cb_detach(px_p);
483		px_ib_detach(px_p);
484		if (px_lib_dev_fini(dip) != DDI_SUCCESS) {
485			DBG(DBG_DETACH, dip, "px_lib_dev_fini failed\n");
486		}
487
488		/*
489		 * Free the px soft state structure and the rest of the
490		 * resources it's using.
491		 */
492		px_free_props(px_p);
493		px_dbg_detach(dip, &px_p->px_dbg_hdl);
494		mutex_exit(&px_p->px_mutex);
495		mutex_destroy(&px_p->px_mutex);
496
497		/* Free the interrupt-priorities prop if we created it. */
498		{
499			int len;
500
501			if (ddi_getproplen(DDI_DEV_T_ANY, dip,
502			    DDI_PROP_NOTPROM | DDI_PROP_DONTPASS,
503			    "interrupt-priorities", &len) == DDI_PROP_SUCCESS)
504				(void) ddi_prop_remove(DDI_DEV_T_NONE, dip,
505				    "interrupt-priorities");
506		}
507
508		px_p->px_dev_hdl = NULL;
509		ddi_soft_state_free(px_state_p, instance);
510
511		return (DDI_SUCCESS);
512
513	case DDI_SUSPEND:
514		if (pcie_pwr_suspend(dip) != DDI_SUCCESS) {
515			mutex_exit(&px_p->px_mutex);
516			return (DDI_FAILURE);
517		}
518		if ((ret = px_lib_suspend(dip)) == DDI_SUCCESS)
519			px_p->px_state = PX_SUSPENDED;
520		mutex_exit(&px_p->px_mutex);
521
522		return (ret);
523
524	default:
525		DBG(DBG_DETACH, dip, "unsupported detach op\n");
526		mutex_exit(&px_p->px_mutex);
527		return (DDI_FAILURE);
528	}
529}
530
531int
532px_cb_attach(px_t *px_p)
533{
534	px_fault_t	*fault_p = &px_p->px_cb_fault;
535	dev_info_t	*dip = px_p->px_dip;
536	sysino_t	sysino;
537
538	if (px_lib_intr_devino_to_sysino(dip,
539	    px_p->px_inos[PX_INTR_XBC], &sysino) != DDI_SUCCESS)
540		return (DDI_FAILURE);
541
542	fault_p->px_fh_dip = dip;
543	fault_p->px_fh_sysino = sysino;
544	fault_p->px_err_func = px_err_cb_intr;
545	fault_p->px_intr_ino = px_p->px_inos[PX_INTR_XBC];
546
547	return (px_cb_add_intr(fault_p));
548}
549
550void
551px_cb_detach(px_t *px_p)
552{
553	px_cb_rem_intr(&px_p->px_cb_fault);
554}
555
556/*
557 * power management related initialization specific to px
558 * called by px_attach()
559 */
560static int
561px_pwr_setup(dev_info_t *dip)
562{
563	pcie_pwr_t *pwr_p;
564	int instance = ddi_get_instance(dip);
565	px_t *px_p = INST_TO_STATE(instance);
566	ddi_intr_handle_impl_t hdl;
567
568	ASSERT(PCIE_PMINFO(dip));
569	pwr_p = PCIE_NEXUS_PMINFO(dip);
570	ASSERT(pwr_p);
571
572	/*
573	 * indicate support LDI (Layered Driver Interface)
574	 * Create the property, if it is not already there
575	 */
576	if (!ddi_prop_exists(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
577	    DDI_KERNEL_IOCTL)) {
578		if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
579		    DDI_KERNEL_IOCTL, NULL, 0) != DDI_PROP_SUCCESS) {
580			DBG(DBG_PWR, dip, "can't create kernel ioctl prop\n");
581			return (DDI_FAILURE);
582		}
583	}
584	/* No support for device PM. We are always at full power */
585	pwr_p->pwr_func_lvl = PM_LEVEL_D0;
586
587	mutex_init(&px_p->px_l23ready_lock, NULL, MUTEX_DRIVER,
588	    DDI_INTR_PRI(px_pwr_pil));
589	cv_init(&px_p->px_l23ready_cv, NULL, CV_DRIVER, NULL);
590
591	/* Initialize handle */
592	bzero(&hdl, sizeof (ddi_intr_handle_impl_t));
593	hdl.ih_cb_arg1 = px_p;
594	hdl.ih_ver = DDI_INTR_VERSION;
595	hdl.ih_state = DDI_IHDL_STATE_ALLOC;
596	hdl.ih_dip = dip;
597	hdl.ih_pri = px_pwr_pil;
598
599	/* Add PME_TO_ACK message handler */
600	hdl.ih_cb_func = (ddi_intr_handler_t *)px_pmeq_intr;
601	if (px_add_msiq_intr(dip, dip, &hdl, MSG_REC,
602	    (msgcode_t)PCIE_PME_ACK_MSG, &px_p->px_pm_msiq_id) != DDI_SUCCESS) {
603		DBG(DBG_PWR, dip, "px_pwr_setup: couldn't add "
604		    " PME_TO_ACK intr\n");
605		goto pwr_setup_err1;
606	}
607	px_lib_msg_setmsiq(dip, PCIE_PME_ACK_MSG, px_p->px_pm_msiq_id);
608	px_lib_msg_setvalid(dip, PCIE_PME_ACK_MSG, PCIE_MSG_VALID);
609
610	if (px_ib_update_intr_state(px_p, px_p->px_dip, hdl.ih_inum,
611	    px_msiqid_to_devino(px_p, px_p->px_pm_msiq_id), px_pwr_pil,
612	    PX_INTR_STATE_ENABLE, MSG_REC, PCIE_PME_ACK_MSG) != DDI_SUCCESS) {
613		DBG(DBG_PWR, dip, "px_pwr_setup: PME_TO_ACK update interrupt"
614		    " state failed\n");
615		goto px_pwrsetup_err_state;
616	}
617
618	return (DDI_SUCCESS);
619
620px_pwrsetup_err_state:
621	px_lib_msg_setvalid(dip, PCIE_PME_ACK_MSG, PCIE_MSG_INVALID);
622	(void) px_rem_msiq_intr(dip, dip, &hdl, MSG_REC, PCIE_PME_ACK_MSG,
623	    px_p->px_pm_msiq_id);
624pwr_setup_err1:
625	mutex_destroy(&px_p->px_l23ready_lock);
626	cv_destroy(&px_p->px_l23ready_cv);
627
628	return (DDI_FAILURE);
629}
630
631/*
632 * undo whatever is done in px_pwr_setup. called by px_detach()
633 */
634static void
635px_pwr_teardown(dev_info_t *dip)
636{
637	int instance = ddi_get_instance(dip);
638	px_t *px_p = INST_TO_STATE(instance);
639	ddi_intr_handle_impl_t	hdl;
640
641	if (!PCIE_PMINFO(dip) || !PCIE_NEXUS_PMINFO(dip))
642		return;
643
644	/* Initialize handle */
645	bzero(&hdl, sizeof (ddi_intr_handle_impl_t));
646	hdl.ih_ver = DDI_INTR_VERSION;
647	hdl.ih_state = DDI_IHDL_STATE_ALLOC;
648	hdl.ih_dip = dip;
649	hdl.ih_pri = px_pwr_pil;
650
651	px_lib_msg_setvalid(dip, PCIE_PME_ACK_MSG, PCIE_MSG_INVALID);
652	(void) px_rem_msiq_intr(dip, dip, &hdl, MSG_REC, PCIE_PME_ACK_MSG,
653	    px_p->px_pm_msiq_id);
654
655	(void) px_ib_update_intr_state(px_p, px_p->px_dip, hdl.ih_inum,
656	    px_msiqid_to_devino(px_p, px_p->px_pm_msiq_id), px_pwr_pil,
657	    PX_INTR_STATE_DISABLE, MSG_REC, PCIE_PME_ACK_MSG);
658
659	px_p->px_pm_msiq_id = (msiqid_t)-1;
660
661	cv_destroy(&px_p->px_l23ready_cv);
662	mutex_destroy(&px_p->px_l23ready_lock);
663}
664
665/* bus driver entry points */
666
667/*
668 * bus map entry point:
669 *
670 * 	if map request is for an rnumber
671 *		get the corresponding regspec from device node
672 * 	build a new regspec in our parent's format
673 *	build a new map_req with the new regspec
674 *	call up the tree to complete the mapping
675 */
676int
677px_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
678	off_t off, off_t len, caddr_t *addrp)
679{
680	px_t *px_p = DIP_TO_STATE(dip);
681	struct regspec p_regspec;
682	ddi_map_req_t p_mapreq;
683	int reglen, rval, r_no;
684	pci_regspec_t reloc_reg, *rp = &reloc_reg;
685
686	DBG(DBG_MAP, dip, "rdip=%s%d:",
687	    ddi_driver_name(rdip), ddi_get_instance(rdip));
688
689	if (mp->map_flags & DDI_MF_USER_MAPPING)
690		return (DDI_ME_UNIMPLEMENTED);
691
692	switch (mp->map_type) {
693	case DDI_MT_REGSPEC:
694		reloc_reg = *(pci_regspec_t *)mp->map_obj.rp;	/* dup whole */
695		break;
696
697	case DDI_MT_RNUMBER:
698		r_no = mp->map_obj.rnumber;
699		DBG(DBG_MAP | DBG_CONT, dip, " r#=%x", r_no);
700
701		if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
702		    "reg", (caddr_t)&rp, &reglen) != DDI_SUCCESS)
703			return (DDI_ME_RNUMBER_RANGE);
704
705		if (r_no < 0 || r_no >= reglen / sizeof (pci_regspec_t)) {
706			kmem_free(rp, reglen);
707			return (DDI_ME_RNUMBER_RANGE);
708		}
709		rp += r_no;
710		break;
711
712	default:
713		return (DDI_ME_INVAL);
714	}
715	DBG(DBG_MAP | DBG_CONT, dip, "\n");
716
717	if ((rp->pci_phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) {
718		/*
719		 * There may be a need to differentiate between PCI
720		 * and PCI-Ex devices so the following range check is
721		 * done correctly, depending on the implementation of
722		 * px_pci bridge nexus driver.
723		 */
724		if ((off >= PCIE_CONF_HDR_SIZE) ||
725		    (len > PCIE_CONF_HDR_SIZE) ||
726		    (off + len > PCIE_CONF_HDR_SIZE))
727			return (DDI_ME_INVAL);
728		/*
729		 * the following function returning a DDI_FAILURE assumes
730		 * that there are no virtual config space access services
731		 * defined in this layer. Otherwise it is availed right
732		 * here and we return.
733		 */
734		rval = px_lib_map_vconfig(dip, mp, off, rp, addrp);
735		if (rval == DDI_SUCCESS)
736			goto done;
737	}
738
739	/*
740	 * No virtual config space services or we are mapping
741	 * a region of memory mapped config/IO/memory space, so proceed
742	 * to the parent.
743	 */
744
745	/* relocate within 64-bit pci space through "assigned-addresses" */
746	if (rval = px_reloc_reg(dip, rdip, px_p, rp))
747		goto done;
748
749	if (len)	/* adjust regspec according to mapping request */
750		rp->pci_size_low = len;	/* MIN ? */
751	rp->pci_phys_low += off;
752
753	/* translate relocated pci regspec into parent space through "ranges" */
754	if (rval = px_xlate_reg(px_p, rp, &p_regspec))
755		goto done;
756
757	p_mapreq = *mp;		/* dup the whole structure */
758	p_mapreq.map_type = DDI_MT_REGSPEC;
759	p_mapreq.map_obj.rp = &p_regspec;
760	px_lib_map_attr_check(&p_mapreq);
761	rval = ddi_map(dip, &p_mapreq, 0, 0, addrp);
762
763	if (rval == DDI_SUCCESS) {
764		/*
765		 * Set-up access functions for FM access error capable drivers.
766		 */
767		if (DDI_FM_ACC_ERR_CAP(ddi_fm_capable(rdip)))
768			px_fm_acc_setup(mp, rdip, rp);
769	}
770
771done:
772	if (mp->map_type == DDI_MT_RNUMBER)
773		kmem_free(rp - r_no, reglen);
774
775	return (rval);
776}
777
778/*
779 * bus dma map entry point
780 * return value:
781 *	DDI_DMA_PARTIAL_MAP	 1
782 *	DDI_DMA_MAPOK		 0
783 *	DDI_DMA_MAPPED		 0
784 *	DDI_DMA_NORESOURCES	-1
785 *	DDI_DMA_NOMAPPING	-2
786 *	DDI_DMA_TOOBIG		-3
787 */
788int
789px_dma_setup(dev_info_t *dip, dev_info_t *rdip, ddi_dma_req_t *dmareq,
790	ddi_dma_handle_t *handlep)
791{
792	px_t *px_p = DIP_TO_STATE(dip);
793	px_mmu_t *mmu_p = px_p->px_mmu_p;
794	ddi_dma_impl_t *mp;
795	int ret;
796
797	DBG(DBG_DMA_MAP, dip, "mapping - rdip=%s%d type=%s\n",
798	    ddi_driver_name(rdip), ddi_get_instance(rdip),
799	    handlep ? "alloc" : "advisory");
800
801	if (!(mp = px_dma_lmts2hdl(dip, rdip, mmu_p, dmareq)))
802		return (DDI_DMA_NORESOURCES);
803	if (mp == (ddi_dma_impl_t *)DDI_DMA_NOMAPPING)
804		return (DDI_DMA_NOMAPPING);
805	if (ret = px_dma_type(px_p, dmareq, mp))
806		goto freehandle;
807	if (ret = px_dma_pfn(px_p, dmareq, mp))
808		goto freehandle;
809
810	switch (PX_DMA_TYPE(mp)) {
811	case PX_DMAI_FLAGS_DVMA:	/* LINTED E_EQUALITY_NOT_ASSIGNMENT */
812		if ((ret = px_dvma_win(px_p, dmareq, mp)) || !handlep)
813			goto freehandle;
814		if (!PX_DMA_CANCACHE(mp)) {	/* try fast track */
815			if (PX_DMA_CANFAST(mp)) {
816				if (!px_dvma_map_fast(mmu_p, mp))
817					break;
818			/* LINTED E_NOP_ELSE_STMT */
819			} else {
820				PX_DVMA_FASTTRAK_PROF(mp);
821			}
822		}
823		if (ret = px_dvma_map(mp, dmareq, mmu_p))
824			goto freehandle;
825		break;
826	case PX_DMAI_FLAGS_PTP:	/* LINTED E_EQUALITY_NOT_ASSIGNMENT */
827		if ((ret = px_dma_physwin(px_p, dmareq, mp)) || !handlep)
828			goto freehandle;
829		break;
830	case PX_DMAI_FLAGS_BYPASS:
831	default:
832		cmn_err(CE_PANIC, "%s%d: px_dma_setup: bad dma type 0x%x",
833		    ddi_driver_name(rdip), ddi_get_instance(rdip),
834		    PX_DMA_TYPE(mp));
835		/*NOTREACHED*/
836	}
837	*handlep = (ddi_dma_handle_t)mp;
838	mp->dmai_flags |= PX_DMAI_FLAGS_INUSE;
839	px_dump_dma_handle(DBG_DMA_MAP, dip, mp);
840
841	return ((mp->dmai_nwin == 1) ? DDI_DMA_MAPPED : DDI_DMA_PARTIAL_MAP);
842freehandle:
843	if (ret == DDI_DMA_NORESOURCES)
844		px_dma_freemp(mp); /* don't run_callback() */
845	else
846		(void) px_dma_freehdl(dip, rdip, (ddi_dma_handle_t)mp);
847	return (ret);
848}
849
850
851/*
852 * bus dma alloc handle entry point:
853 */
854int
855px_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attrp,
856	int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
857{
858	px_t *px_p = DIP_TO_STATE(dip);
859	ddi_dma_impl_t *mp;
860	int rval;
861
862	DBG(DBG_DMA_ALLOCH, dip, "rdip=%s%d\n",
863	    ddi_driver_name(rdip), ddi_get_instance(rdip));
864
865	if (attrp->dma_attr_version != DMA_ATTR_V0)
866		return (DDI_DMA_BADATTR);
867
868	if (!(mp = px_dma_allocmp(dip, rdip, waitfp, arg)))
869		return (DDI_DMA_NORESOURCES);
870
871	/*
872	 * Save requestor's information
873	 */
874	mp->dmai_attr	= *attrp; /* whole object - augmented later  */
875	*PX_DEV_ATTR(mp)	= *attrp; /* whole object - device orig attr */
876	DBG(DBG_DMA_ALLOCH, dip, "mp=%p\n", mp);
877
878	/* check and convert dma attributes to handle parameters */
879	if (rval = px_dma_attr2hdl(px_p, mp)) {
880		px_dma_freehdl(dip, rdip, (ddi_dma_handle_t)mp);
881		*handlep = NULL;
882		return (rval);
883	}
884	*handlep = (ddi_dma_handle_t)mp;
885	return (DDI_SUCCESS);
886}
887
888
889/*
890 * bus dma free handle entry point:
891 */
892/*ARGSUSED*/
893int
894px_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle)
895{
896	DBG(DBG_DMA_FREEH, dip, "rdip=%s%d mp=%p\n",
897	    ddi_driver_name(rdip), ddi_get_instance(rdip), handle);
898	px_dma_freemp((ddi_dma_impl_t *)handle);
899
900	if (px_kmem_clid) {
901		DBG(DBG_DMA_FREEH, dip, "run handle callback\n");
902		ddi_run_callback(&px_kmem_clid);
903	}
904	return (DDI_SUCCESS);
905}
906
907
908/*
909 * bus dma bind handle entry point:
910 */
911int
912px_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
913	ddi_dma_handle_t handle, ddi_dma_req_t *dmareq,
914	ddi_dma_cookie_t *cookiep, uint_t *ccountp)
915{
916	px_t *px_p = DIP_TO_STATE(dip);
917	px_mmu_t *mmu_p = px_p->px_mmu_p;
918	ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle;
919	int ret;
920
921	DBG(DBG_DMA_BINDH, dip, "rdip=%s%d mp=%p dmareq=%p\n",
922	    ddi_driver_name(rdip), ddi_get_instance(rdip), mp, dmareq);
923
924	if (mp->dmai_flags & PX_DMAI_FLAGS_INUSE)
925		return (DDI_DMA_INUSE);
926
927	ASSERT((mp->dmai_flags & ~PX_DMAI_FLAGS_PRESERVE) == 0);
928	mp->dmai_flags |= PX_DMAI_FLAGS_INUSE;
929
930	if (ret = px_dma_type(px_p, dmareq, mp))
931		goto err;
932	if (ret = px_dma_pfn(px_p, dmareq, mp))
933		goto err;
934
935	switch (PX_DMA_TYPE(mp)) {
936	case PX_DMAI_FLAGS_DVMA:
937		if (ret = px_dvma_win(px_p, dmareq, mp))
938			goto map_err;
939		if (!PX_DMA_CANCACHE(mp)) {	/* try fast track */
940			if (PX_DMA_CANFAST(mp)) {
941				if (!px_dvma_map_fast(mmu_p, mp))
942					goto mapped; /*LINTED E_NOP_ELSE_STMT*/
943			} else {
944				PX_DVMA_FASTTRAK_PROF(mp);
945			}
946		}
947		if (ret = px_dvma_map(mp, dmareq, mmu_p))
948			goto map_err;
949mapped:
950		*ccountp = 1;
951		MAKE_DMA_COOKIE(cookiep, mp->dmai_mapping, mp->dmai_size);
952		break;
953	case PX_DMAI_FLAGS_BYPASS:
954	case PX_DMAI_FLAGS_PTP:
955		if (ret = px_dma_physwin(px_p, dmareq, mp))
956			goto map_err;
957		*ccountp = PX_WINLST(mp)->win_ncookies;
958		*cookiep =
959		    *(ddi_dma_cookie_t *)(PX_WINLST(mp) + 1); /* wholeobj */
960		break;
961	default:
962		cmn_err(CE_PANIC, "%s%d: px_dma_bindhdl(%p): bad dma type",
963		    ddi_driver_name(rdip), ddi_get_instance(rdip), mp);
964		/*NOTREACHED*/
965	}
966	DBG(DBG_DMA_BINDH, dip, "cookie %" PRIx64 "+%x\n",
967	    cookiep->dmac_address, cookiep->dmac_size);
968	px_dump_dma_handle(DBG_DMA_MAP, dip, mp);
969
970	/* insert dma handle into FMA cache */
971	if (mp->dmai_attr.dma_attr_flags & DDI_DMA_FLAGERR) {
972		(void) ndi_fmc_insert(rdip, DMA_HANDLE, mp, NULL);
973		mp->dmai_error.err_cf = px_err_dma_hdl_check;
974	}
975
976	return (mp->dmai_nwin == 1 ? DDI_DMA_MAPPED : DDI_DMA_PARTIAL_MAP);
977map_err:
978	px_dma_freepfn(mp);
979err:
980	mp->dmai_flags &= PX_DMAI_FLAGS_PRESERVE;
981	return (ret);
982}
983
984
985/*
986 * bus dma unbind handle entry point:
987 */
988/*ARGSUSED*/
989int
990px_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle)
991{
992	ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle;
993	px_t *px_p = DIP_TO_STATE(dip);
994	px_mmu_t *mmu_p = px_p->px_mmu_p;
995
996	DBG(DBG_DMA_UNBINDH, dip, "rdip=%s%d, mp=%p\n",
997	    ddi_driver_name(rdip), ddi_get_instance(rdip), handle);
998	if ((mp->dmai_flags & PX_DMAI_FLAGS_INUSE) == 0) {
999		DBG(DBG_DMA_UNBINDH, dip, "handle not inuse\n");
1000		return (DDI_FAILURE);
1001	}
1002
1003	/* remove dma handle from FMA cache */
1004	if (mp->dmai_attr.dma_attr_flags & DDI_DMA_FLAGERR) {
1005		if (DEVI(rdip)->devi_fmhdl != NULL &&
1006		    DDI_FM_DMA_ERR_CAP(DEVI(rdip)->devi_fmhdl->fh_cap)) {
1007			(void) ndi_fmc_remove(rdip, DMA_HANDLE, mp);
1008		}
1009	}
1010
1011	/*
1012	 * Here if the handle is using the iommu.  Unload all the iommu
1013	 * translations.
1014	 */
1015	switch (PX_DMA_TYPE(mp)) {
1016	case PX_DMAI_FLAGS_DVMA:
1017		px_mmu_unmap_window(mmu_p, mp);
1018		px_dvma_unmap(mmu_p, mp);
1019		px_dma_freepfn(mp);
1020		break;
1021	case PX_DMAI_FLAGS_BYPASS:
1022	case PX_DMAI_FLAGS_PTP:
1023		px_dma_freewin(mp);
1024		break;
1025	default:
1026		cmn_err(CE_PANIC, "%s%d: px_dma_unbindhdl:bad dma type %p",
1027		    ddi_driver_name(rdip), ddi_get_instance(rdip), mp);
1028		/*NOTREACHED*/
1029	}
1030	if (mmu_p->mmu_dvma_clid != 0) {
1031		DBG(DBG_DMA_UNBINDH, dip, "run dvma callback\n");
1032		ddi_run_callback(&mmu_p->mmu_dvma_clid);
1033	}
1034	if (px_kmem_clid) {
1035		DBG(DBG_DMA_UNBINDH, dip, "run handle callback\n");
1036		ddi_run_callback(&px_kmem_clid);
1037	}
1038	mp->dmai_flags &= PX_DMAI_FLAGS_PRESERVE;
1039
1040	return (DDI_SUCCESS);
1041}
1042
1043/*
1044 * bus dma win entry point:
1045 */
1046int
1047px_dma_win(dev_info_t *dip, dev_info_t *rdip,
1048	ddi_dma_handle_t handle, uint_t win, off_t *offp,
1049	size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp)
1050{
1051	ddi_dma_impl_t	*mp = (ddi_dma_impl_t *)handle;
1052	int		ret;
1053
1054	DBG(DBG_DMA_WIN, dip, "rdip=%s%d\n",
1055	    ddi_driver_name(rdip), ddi_get_instance(rdip));
1056
1057	px_dump_dma_handle(DBG_DMA_WIN, dip, mp);
1058	if (win >= mp->dmai_nwin) {
1059		DBG(DBG_DMA_WIN, dip, "%x out of range\n", win);
1060		return (DDI_FAILURE);
1061	}
1062
1063	switch (PX_DMA_TYPE(mp)) {
1064	case PX_DMAI_FLAGS_DVMA:
1065		if (win != PX_DMA_CURWIN(mp)) {
1066			px_t *px_p = DIP_TO_STATE(dip);
1067			px_mmu_t *mmu_p = px_p->px_mmu_p;
1068			px_mmu_unmap_window(mmu_p, mp);
1069
1070			/* map_window sets dmai_mapping/size/offset */
1071			px_mmu_map_window(mmu_p, mp, win);
1072			if ((ret = px_mmu_map_window(mmu_p,
1073			    mp, win)) != DDI_SUCCESS)
1074				return (ret);
1075		}
1076		if (cookiep)
1077			MAKE_DMA_COOKIE(cookiep, mp->dmai_mapping,
1078			    mp->dmai_size);
1079		if (ccountp)
1080			*ccountp = 1;
1081		break;
1082	case PX_DMAI_FLAGS_PTP:
1083	case PX_DMAI_FLAGS_BYPASS: {
1084		int i;
1085		ddi_dma_cookie_t *ck_p;
1086		px_dma_win_t *win_p = mp->dmai_winlst;
1087
1088		for (i = 0; i < win; win_p = win_p->win_next, i++) {};
1089		ck_p = (ddi_dma_cookie_t *)(win_p + 1);
1090		*cookiep = *ck_p;
1091		mp->dmai_offset = win_p->win_offset;
1092		mp->dmai_size   = win_p->win_size;
1093		mp->dmai_mapping = ck_p->dmac_laddress;
1094		mp->dmai_cookie = ck_p + 1;
1095		win_p->win_curseg = 0;
1096		if (ccountp)
1097			*ccountp = win_p->win_ncookies;
1098		}
1099		break;
1100	default:
1101		cmn_err(CE_WARN, "%s%d: px_dma_win:bad dma type 0x%x",
1102		    ddi_driver_name(rdip), ddi_get_instance(rdip),
1103		    PX_DMA_TYPE(mp));
1104		return (DDI_FAILURE);
1105	}
1106	if (cookiep)
1107		DBG(DBG_DMA_WIN, dip,
1108		    "cookie - dmac_address=%x dmac_size=%x\n",
1109		    cookiep->dmac_address, cookiep->dmac_size);
1110	if (offp)
1111		*offp = (off_t)mp->dmai_offset;
1112	if (lenp)
1113		*lenp = mp->dmai_size;
1114	return (DDI_SUCCESS);
1115}
1116
1117#ifdef	DEBUG
1118static char *px_dmactl_str[] = {
1119	"DDI_DMA_FREE",
1120	"DDI_DMA_SYNC",
1121	"DDI_DMA_HTOC",
1122	"DDI_DMA_KVADDR",
1123	"DDI_DMA_MOVWIN",
1124	"DDI_DMA_REPWIN",
1125	"DDI_DMA_GETERR",
1126	"DDI_DMA_COFF",
1127	"DDI_DMA_NEXTWIN",
1128	"DDI_DMA_NEXTSEG",
1129	"DDI_DMA_SEGTOC",
1130	"DDI_DMA_RESERVE",
1131	"DDI_DMA_RELEASE",
1132	"DDI_DMA_RESETH",
1133	"DDI_DMA_CKSYNC",
1134	"DDI_DMA_IOPB_ALLOC",
1135	"DDI_DMA_IOPB_FREE",
1136	"DDI_DMA_SMEM_ALLOC",
1137	"DDI_DMA_SMEM_FREE",
1138	"DDI_DMA_SET_SBUS64"
1139};
1140#endif	/* DEBUG */
1141
1142/*
1143 * bus dma control entry point:
1144 */
1145/*ARGSUSED*/
1146int
1147px_dma_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle,
1148	enum ddi_dma_ctlops cmd, off_t *offp, size_t *lenp, caddr_t *objp,
1149	uint_t cache_flags)
1150{
1151	ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle;
1152
1153#ifdef	DEBUG
1154	DBG(DBG_DMA_CTL, dip, "%s: rdip=%s%d\n", px_dmactl_str[cmd],
1155	    ddi_driver_name(rdip), ddi_get_instance(rdip));
1156#endif	/* DEBUG */
1157
1158	switch (cmd) {
1159	case DDI_DMA_FREE:
1160		(void) px_dma_unbindhdl(dip, rdip, handle);
1161		(void) px_dma_freehdl(dip, rdip, handle);
1162		return (DDI_SUCCESS);
1163	case DDI_DMA_RESERVE: {
1164		px_t *px_p = DIP_TO_STATE(dip);
1165		return (px_fdvma_reserve(dip, rdip, px_p,
1166		    (ddi_dma_req_t *)offp, (ddi_dma_handle_t *)objp));
1167		}
1168	case DDI_DMA_RELEASE: {
1169		px_t *px_p = DIP_TO_STATE(dip);
1170		return (px_fdvma_release(dip, px_p, mp));
1171		}
1172	default:
1173		break;
1174	}
1175
1176	switch (PX_DMA_TYPE(mp)) {
1177	case PX_DMAI_FLAGS_DVMA:
1178		return (px_dvma_ctl(dip, rdip, mp, cmd, offp, lenp, objp,
1179		    cache_flags));
1180	case PX_DMAI_FLAGS_PTP:
1181	case PX_DMAI_FLAGS_BYPASS:
1182		return (px_dma_ctl(dip, rdip, mp, cmd, offp, lenp, objp,
1183		    cache_flags));
1184	default:
1185		cmn_err(CE_PANIC, "%s%d: px_dma_ctlops(%x):bad dma type %x",
1186		    ddi_driver_name(rdip), ddi_get_instance(rdip), cmd,
1187		    mp->dmai_flags);
1188		/*NOTREACHED*/
1189	}
1190	return (0);
1191}
1192
1193/*
1194 * control ops entry point:
1195 *
1196 * Requests handled completely:
1197 *	DDI_CTLOPS_INITCHILD	see init_child() for details
1198 *	DDI_CTLOPS_UNINITCHILD
1199 *	DDI_CTLOPS_REPORTDEV	see report_dev() for details
1200 *	DDI_CTLOPS_IOMIN	cache line size if streaming otherwise 1
1201 *	DDI_CTLOPS_REGSIZE
1202 *	DDI_CTLOPS_NREGS
1203 *	DDI_CTLOPS_DVMAPAGESIZE
1204 *	DDI_CTLOPS_POKE
1205 *	DDI_CTLOPS_PEEK
1206 *
1207 * All others passed to parent.
1208 */
1209int
1210px_ctlops(dev_info_t *dip, dev_info_t *rdip,
1211	ddi_ctl_enum_t op, void *arg, void *result)
1212{
1213	px_t *px_p = DIP_TO_STATE(dip);
1214	struct detachspec *ds;
1215	struct attachspec *as;
1216
1217	switch (op) {
1218	case DDI_CTLOPS_INITCHILD:
1219		return (px_init_child(px_p, (dev_info_t *)arg));
1220
1221	case DDI_CTLOPS_UNINITCHILD:
1222		return (px_uninit_child(px_p, (dev_info_t *)arg));
1223
1224	case DDI_CTLOPS_ATTACH:
1225		if (!pcie_is_child(dip, rdip))
1226			return (DDI_SUCCESS);
1227
1228		as = (struct attachspec *)arg;
1229		switch (as->when) {
1230		case DDI_PRE:
1231			if (as->cmd == DDI_ATTACH) {
1232				DBG(DBG_PWR, dip, "PRE_ATTACH for %s@%d\n",
1233				    ddi_driver_name(rdip),
1234				    ddi_get_instance(rdip));
1235				return (pcie_pm_hold(dip));
1236			}
1237			if (as->cmd == DDI_RESUME) {
1238				DBG(DBG_PWR, dip, "PRE_RESUME for %s@%d\n",
1239				    ddi_driver_name(rdip),
1240				    ddi_get_instance(rdip));
1241
1242				pcie_clear_errors(rdip);
1243			}
1244			return (DDI_SUCCESS);
1245
1246		case DDI_POST:
1247			DBG(DBG_PWR, dip, "POST_ATTACH for %s@%d\n",
1248			    ddi_driver_name(rdip), ddi_get_instance(rdip));
1249			if (as->cmd == DDI_ATTACH && as->result != DDI_SUCCESS)
1250				pcie_pm_release(dip);
1251
1252			if (as->result == DDI_SUCCESS)
1253				pf_init(rdip, (void *)px_p->px_fm_ibc, as->cmd);
1254
1255			(void) pcie_postattach_child(rdip);
1256
1257			return (DDI_SUCCESS);
1258		default:
1259			break;
1260		}
1261		break;
1262
1263	case DDI_CTLOPS_DETACH:
1264		if (!pcie_is_child(dip, rdip))
1265			return (DDI_SUCCESS);
1266
1267		ds = (struct detachspec *)arg;
1268		switch (ds->when) {
1269		case DDI_POST:
1270			if (ds->cmd == DDI_DETACH &&
1271			    ds->result == DDI_SUCCESS) {
1272				DBG(DBG_PWR, dip, "POST_DETACH for %s@%d\n",
1273				    ddi_driver_name(rdip),
1274				    ddi_get_instance(rdip));
1275				return (pcie_pm_remove_child(dip, rdip));
1276			}
1277			return (DDI_SUCCESS);
1278		case DDI_PRE:
1279			pf_fini(rdip, ds->cmd);
1280			return (DDI_SUCCESS);
1281		default:
1282			break;
1283		}
1284		break;
1285
1286	case DDI_CTLOPS_REPORTDEV:
1287		return (px_report_dev(rdip));
1288
1289	case DDI_CTLOPS_IOMIN:
1290		return (DDI_SUCCESS);
1291
1292	case DDI_CTLOPS_REGSIZE:
1293		*((off_t *)result) = px_get_reg_set_size(rdip, *((int *)arg));
1294		return (*((off_t *)result) == 0 ? DDI_FAILURE : DDI_SUCCESS);
1295
1296	case DDI_CTLOPS_NREGS:
1297		*((uint_t *)result) = px_get_nreg_set(rdip);
1298		return (DDI_SUCCESS);
1299
1300	case DDI_CTLOPS_DVMAPAGESIZE:
1301		*((ulong_t *)result) = MMU_PAGE_SIZE;
1302		return (DDI_SUCCESS);
1303
1304	case DDI_CTLOPS_POKE:	/* platform dependent implementation. */
1305		return (px_lib_ctlops_poke(dip, rdip,
1306		    (peekpoke_ctlops_t *)arg));
1307
1308	case DDI_CTLOPS_PEEK:	/* platform dependent implementation. */
1309		return (px_lib_ctlops_peek(dip, rdip,
1310		    (peekpoke_ctlops_t *)arg, result));
1311
1312	case DDI_CTLOPS_POWER:
1313	default:
1314		break;
1315	}
1316
1317	/*
1318	 * Now pass the request up to our parent.
1319	 */
1320	DBG(DBG_CTLOPS, dip, "passing request to parent: rdip=%s%d\n",
1321	    ddi_driver_name(rdip), ddi_get_instance(rdip));
1322	return (ddi_ctlops(dip, rdip, op, arg, result));
1323}
1324
1325/* ARGSUSED */
1326int
1327px_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
1328    ddi_intr_handle_impl_t *hdlp, void *result)
1329{
1330	int	intr_types, ret = DDI_SUCCESS;
1331
1332	DBG(DBG_INTROPS, dip, "px_intr_ops: rdip=%s%d\n",
1333	    ddi_driver_name(rdip), ddi_get_instance(rdip));
1334
1335	/* Process DDI_INTROP_SUPPORTED_TYPES request here */
1336	if (intr_op == DDI_INTROP_SUPPORTED_TYPES) {
1337		*(int *)result = i_ddi_get_intx_nintrs(rdip) ?
1338		    DDI_INTR_TYPE_FIXED : 0;
1339
1340		if ((pci_msi_get_supported_type(rdip,
1341		    &intr_types)) == DDI_SUCCESS) {
1342			/*
1343			 * Double check supported interrupt types vs.
1344			 * what the host bridge supports.
1345			 */
1346			*(int *)result |= intr_types;
1347		}
1348
1349		return (ret);
1350	}
1351
1352	/*
1353	 * PCI-E nexus driver supports fixed, MSI and MSI-X interrupts.
1354	 * Return failure if interrupt type is not supported.
1355	 */
1356	switch (hdlp->ih_type) {
1357	case DDI_INTR_TYPE_FIXED:
1358		ret = px_intx_ops(dip, rdip, intr_op, hdlp, result);
1359		break;
1360	case DDI_INTR_TYPE_MSI:
1361	case DDI_INTR_TYPE_MSIX:
1362		ret = px_msix_ops(dip, rdip, intr_op, hdlp, result);
1363		break;
1364	default:
1365		ret = DDI_ENOTSUP;
1366		break;
1367	}
1368
1369	return (ret);
1370}
1371
1372static int
1373px_init_hotplug(px_t *px_p)
1374{
1375	px_bus_range_t bus_range;
1376	dev_info_t *dip;
1377	pciehpc_regops_t regops;
1378
1379	dip = px_p->px_dip;
1380
1381	if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1382	    "hotplug-capable") == 0)
1383		return (DDI_FAILURE);
1384
1385	/*
1386	 * Before initializing hotplug - open up bus range.  The busra
1387	 * module will initialize its pool of bus numbers from this.
1388	 * "busra" will be the agent that keeps track of them during
1389	 * hotplug.  Also, note, that busra will remove any bus numbers
1390	 * already in use from boot time.
1391	 */
1392	if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1393	    "bus-range") == 0) {
1394		cmn_err(CE_WARN, "%s%d: bus-range not found\n",
1395		    ddi_driver_name(dip), ddi_get_instance(dip));
1396#ifdef	DEBUG
1397		bus_range.lo = 0x0;
1398		bus_range.hi = 0xff;
1399
1400		if (ndi_prop_update_int_array(DDI_DEV_T_NONE,
1401		    dip, "bus-range", (int *)&bus_range, 2)
1402		    != DDI_PROP_SUCCESS) {
1403			return (DDI_FAILURE);
1404		}
1405#else
1406		return (DDI_FAILURE);
1407#endif
1408	}
1409
1410	if (px_lib_hotplug_init(dip, (void *)&regops) != DDI_SUCCESS)
1411		return (DDI_FAILURE);
1412
1413	if (pciehpc_init(dip, &regops) != DDI_SUCCESS) {
1414		px_lib_hotplug_uninit(dip);
1415		return (DDI_FAILURE);
1416	}
1417
1418	if (pcihp_init(dip) != DDI_SUCCESS) {
1419		(void) pciehpc_uninit(dip);
1420		px_lib_hotplug_uninit(dip);
1421		return (DDI_FAILURE);
1422	}
1423
1424	if (pcihp_get_cb_ops() != NULL) {
1425		DBG(DBG_ATTACH, dip, "%s%d hotplug enabled",
1426		    ddi_driver_name(dip), ddi_get_instance(dip));
1427		px_p->px_dev_caps |= PX_HOTPLUG_CAPABLE;
1428	}
1429
1430	return (DDI_SUCCESS);
1431}
1432
1433static int
1434px_uninit_hotplug(dev_info_t *dip)
1435{
1436	if (pcihp_uninit(dip) != DDI_SUCCESS)
1437		return (DDI_FAILURE);
1438
1439	if (pciehpc_uninit(dip) != DDI_SUCCESS)
1440		return (DDI_FAILURE);
1441
1442	px_lib_hotplug_uninit(dip);
1443
1444	return (DDI_SUCCESS);
1445}
1446
1447static void
1448px_set_mps(px_t *px_p)
1449{
1450	dev_info_t	*dip;
1451	pcie_bus_t	*bus_p;
1452	int		max_supported;
1453
1454	dip = px_p->px_dip;
1455	bus_p = PCIE_DIP2BUS(dip);
1456
1457	bus_p->bus_mps = -1;
1458
1459	if (pcie_root_port(dip) == DDI_FAILURE) {
1460		if (px_lib_get_root_complex_mps(px_p, dip,
1461		    &max_supported) < 0) {
1462
1463			DBG(DBG_MPS, dip, "MPS:  Can not get RC MPS\n");
1464			return;
1465		}
1466
1467		DBG(DBG_MPS, dip, "MPS: Root Complex MPS Cap of = %x\n",
1468		    max_supported);
1469
1470		if (pcie_max_mps < max_supported)
1471			max_supported = pcie_max_mps;
1472
1473		(void) pcie_get_fabric_mps(dip, ddi_get_child(dip),
1474		    &max_supported);
1475
1476		bus_p->bus_mps = max_supported;
1477
1478		(void) px_lib_set_root_complex_mps(px_p, dip, bus_p->bus_mps);
1479
1480		DBG(DBG_MPS, dip, "MPS: Root Complex MPS Set to = %x\n",
1481		    bus_p->bus_mps);
1482	}
1483}
1484