xref: /illumos-gate/usr/src/uts/i86pc/io/pci/pci_common.c (revision fe54a78e1aacf39261ad56e9903bce02e3fb6d21)
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 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  *	File that has code which is common between pci(7d) and npe(7d)
29  *	It shares the following:
30  *	- interrupt code
31  *	- pci_tools ioctl code
32  *	- name_child code
33  *	- set_parent_private_data code
34  */
35 
36 #include <sys/conf.h>
37 #include <sys/pci.h>
38 #include <sys/sunndi.h>
39 #include <sys/mach_intr.h>
40 #include <sys/hotplug/pci/pcihp.h>
41 #include <sys/pci_intr_lib.h>
42 #include <sys/psm.h>
43 #include <sys/policy.h>
44 #include <sys/sysmacros.h>
45 #include <sys/clock.h>
46 #include <sys/apic.h>
47 #include <sys/pci_tools.h>
48 #include <io/pci/pci_var.h>
49 #include <io/pci/pci_tools_ext.h>
50 #include <io/pci/pci_common.h>
51 #include <sys/pci_cfgspace.h>
52 #include <sys/pci_impl.h>
53 #include <sys/pci_cap.h>
54 
55 /*
56  * Function prototypes
57  */
58 static int	pci_get_priority(dev_info_t *, ddi_intr_handle_impl_t *, int *);
59 static int	pci_enable_intr(dev_info_t *, dev_info_t *,
60 		    ddi_intr_handle_impl_t *, uint32_t);
61 static void	pci_disable_intr(dev_info_t *, dev_info_t *,
62 		    ddi_intr_handle_impl_t *, uint32_t);
63 
64 /* Extern decalration for pcplusmp module */
65 extern int	(*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *,
66 		    psm_intr_op_t, int *);
67 
68 /*
69  * pci_name_child:
70  *
71  *	Assign the address portion of the node name
72  */
73 int
74 pci_common_name_child(dev_info_t *child, char *name, int namelen)
75 {
76 	int		dev, func, length;
77 	char		**unit_addr;
78 	uint_t		n;
79 	pci_regspec_t	*pci_rp;
80 
81 	if (ndi_dev_is_persistent_node(child) == 0) {
82 		/*
83 		 * For .conf node, use "unit-address" property
84 		 */
85 		if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
86 		    DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) !=
87 		    DDI_PROP_SUCCESS) {
88 			cmn_err(CE_WARN, "cannot find unit-address in %s.conf",
89 			    ddi_get_name(child));
90 			return (DDI_FAILURE);
91 		}
92 		if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
93 			cmn_err(CE_WARN, "unit-address property in %s.conf"
94 			    " not well-formed", ddi_get_name(child));
95 			ddi_prop_free(unit_addr);
96 			return (DDI_FAILURE);
97 		}
98 		(void) snprintf(name, namelen, "%s", *unit_addr);
99 		ddi_prop_free(unit_addr);
100 		return (DDI_SUCCESS);
101 	}
102 
103 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
104 	    "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
105 		cmn_err(CE_WARN, "cannot find reg property in %s",
106 		    ddi_get_name(child));
107 		return (DDI_FAILURE);
108 	}
109 
110 	/* copy the device identifications */
111 	dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
112 	func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
113 
114 	/*
115 	 * free the memory allocated by ddi_prop_lookup_int_array
116 	 */
117 	ddi_prop_free(pci_rp);
118 
119 	if (func != 0) {
120 		(void) snprintf(name, namelen, "%x,%x", dev, func);
121 	} else {
122 		(void) snprintf(name, namelen, "%x", dev);
123 	}
124 
125 	return (DDI_SUCCESS);
126 }
127 
128 /*
129  * Interrupt related code:
130  *
131  * The following busop is common to npe and pci drivers
132  *	bus_introp
133  */
134 
135 /*
136  * Create the ddi_parent_private_data for a pseudo child.
137  */
138 void
139 pci_common_set_parent_private_data(dev_info_t *dip)
140 {
141 	struct ddi_parent_private_data *pdptr;
142 
143 	pdptr = (struct ddi_parent_private_data *)kmem_zalloc(
144 	    (sizeof (struct ddi_parent_private_data) +
145 	    sizeof (struct intrspec)), KM_SLEEP);
146 	pdptr->par_intr = (struct intrspec *)(pdptr + 1);
147 	pdptr->par_nintr = 1;
148 	ddi_set_parent_data(dip, pdptr);
149 }
150 
151 /*
152  * pci_get_priority:
153  *	Figure out the priority of the device
154  */
155 static int
156 pci_get_priority(dev_info_t *dip, ddi_intr_handle_impl_t *hdlp, int *pri)
157 {
158 	struct intrspec *ispec;
159 
160 	DDI_INTR_NEXDBG((CE_CONT, "pci_get_priority: dip = 0x%p, hdlp = %p\n",
161 	    (void *)dip, (void *)hdlp));
162 
163 	if ((ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip,
164 	    hdlp->ih_inum)) == NULL) {
165 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
166 			int class = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
167 			    DDI_PROP_DONTPASS, "class-code", -1);
168 
169 			*pri = (class == -1) ? 1 : pci_devclass_to_ipl(class);
170 			pci_common_set_parent_private_data(hdlp->ih_dip);
171 			ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip,
172 			    hdlp->ih_inum);
173 			return (DDI_SUCCESS);
174 		}
175 		return (DDI_FAILURE);
176 	}
177 
178 	*pri = ispec->intrspec_pri;
179 	return (DDI_SUCCESS);
180 }
181 
182 
183 
184 static int pcie_pci_intr_pri_counter = 0;
185 
186 /*
187  * pci_common_intr_ops: bus_intr_op() function for interrupt support
188  */
189 int
190 pci_common_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
191     ddi_intr_handle_impl_t *hdlp, void *result)
192 {
193 	int			priority = 0;
194 	int			psm_status = 0;
195 	int			pci_status = 0;
196 	int			pci_rval, psm_rval = PSM_FAILURE;
197 	int			types = 0;
198 	int			pciepci = 0;
199 	int			i, j, count;
200 	int			rv;
201 	int			behavior;
202 	int			cap_ptr;
203 	uint16_t		msi_cap_base, msix_cap_base, cap_ctrl;
204 	char			*prop;
205 	ddi_intrspec_t		isp;
206 	struct intrspec		*ispec;
207 	ddi_intr_handle_impl_t	tmp_hdl;
208 	ddi_intr_msix_t		*msix_p;
209 	ihdl_plat_t		*ihdl_plat_datap;
210 	ddi_intr_handle_t	*h_array;
211 	ddi_acc_handle_t	handle;
212 
213 	DDI_INTR_NEXDBG((CE_CONT,
214 	    "pci_common_intr_ops: pdip 0x%p, rdip 0x%p, op %x handle 0x%p\n",
215 	    (void *)pdip, (void *)rdip, intr_op, (void *)hdlp));
216 
217 	/* Process the request */
218 	switch (intr_op) {
219 	case DDI_INTROP_SUPPORTED_TYPES:
220 		/*
221 		 * First we determine the interrupt types supported by the
222 		 * device itself, then we filter them through what the OS
223 		 * and system supports.  We determine system-level
224 		 * interrupt type support for anything other than fixed intrs
225 		 * through the psm_intr_ops vector
226 		 */
227 		rv = DDI_FAILURE;
228 
229 		/* Fixed supported by default */
230 		types = DDI_INTR_TYPE_FIXED;
231 
232 		if (psm_intr_ops == NULL) {
233 			*(int *)result = types;
234 			return (DDI_SUCCESS);
235 		}
236 		if (pci_config_setup(rdip, &handle) != DDI_SUCCESS)
237 			return (DDI_FAILURE);
238 
239 		/* Sanity test cap control values if found */
240 
241 		if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI, &msi_cap_base) ==
242 		    DDI_SUCCESS) {
243 			cap_ctrl = PCI_CAP_GET16(handle, 0, msi_cap_base,
244 			    PCI_MSI_CTRL);
245 			if (cap_ctrl == PCI_CAP_EINVAL16)
246 				goto SUPPORTED_TYPES_OUT;
247 
248 			types |= DDI_INTR_TYPE_MSI;
249 		}
250 
251 		if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI_X, &msix_cap_base) ==
252 		    DDI_SUCCESS) {
253 			cap_ctrl = PCI_CAP_GET16(handle, 0, msix_cap_base,
254 			    PCI_MSIX_CTRL);
255 			if (cap_ctrl == PCI_CAP_EINVAL16)
256 				goto SUPPORTED_TYPES_OUT;
257 
258 			types |= DDI_INTR_TYPE_MSIX;
259 		}
260 
261 		/*
262 		 * Filter device-level types through system-level support
263 		 */
264 		tmp_hdl.ih_type = types;
265 		if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_CHECK_MSI,
266 		    &types) != PSM_SUCCESS)
267 			goto SUPPORTED_TYPES_OUT;
268 
269 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
270 		    "rdip: 0x%p supported types: 0x%x\n", (void *)rdip,
271 		    *(int *)result));
272 
273 		/*
274 		 * Export any MSI/MSI-X cap locations via properties
275 		 */
276 		if (types & DDI_INTR_TYPE_MSI) {
277 			if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip,
278 			    "pci-msi-capid-pointer", (int)msi_cap_base) !=
279 			    DDI_PROP_SUCCESS)
280 				goto SUPPORTED_TYPES_OUT;
281 		}
282 		if (types & DDI_INTR_TYPE_MSIX) {
283 			if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip,
284 			    "pci-msix-capid-pointer", (int)msix_cap_base) !=
285 			    DDI_PROP_SUCCESS)
286 				goto SUPPORTED_TYPES_OUT;
287 		}
288 
289 		rv = DDI_SUCCESS;
290 
291 SUPPORTED_TYPES_OUT:
292 		*(int *)result = types;
293 		pci_config_teardown(&handle);
294 		return (rv);
295 
296 	case DDI_INTROP_NAVAIL:
297 	case DDI_INTROP_NINTRS:
298 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
299 			if (pci_msi_get_nintrs(hdlp->ih_dip, hdlp->ih_type,
300 			    result) != DDI_SUCCESS)
301 				return (DDI_FAILURE);
302 		} else {
303 			*(int *)result = i_ddi_get_intx_nintrs(hdlp->ih_dip);
304 			if (*(int *)result == 0)
305 				return (DDI_FAILURE);
306 		}
307 		break;
308 	case DDI_INTROP_ALLOC:
309 		/*
310 		 * MSI or MSIX (figure out number of vectors available)
311 		 * FIXED interrupts: just return available interrupts
312 		 */
313 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) &&
314 		    (psm_intr_ops != NULL) &&
315 		    (pci_get_priority(rdip, hdlp, &priority) == DDI_SUCCESS)) {
316 			/*
317 			 * Following check is a special case for 'pcie_pci'.
318 			 * This makes sure vectors with the right priority
319 			 * are allocated for pcie_pci during ALLOC time.
320 			 */
321 			if (strcmp(ddi_driver_name(rdip), "pcie_pci") == 0) {
322 				hdlp->ih_pri =
323 				    (pcie_pci_intr_pri_counter % 2) ? 4 : 7;
324 				pciepci = 1;
325 			} else
326 				hdlp->ih_pri = priority;
327 			behavior = (int)(uintptr_t)hdlp->ih_scratch2;
328 
329 			/*
330 			 * Cache in the config handle and cap_ptr
331 			 */
332 			if (i_ddi_get_pci_config_handle(rdip) == NULL) {
333 				if (pci_config_setup(rdip, &handle) !=
334 				    DDI_SUCCESS)
335 					return (DDI_FAILURE);
336 				i_ddi_set_pci_config_handle(rdip, handle);
337 			}
338 
339 			prop = NULL;
340 			cap_ptr = 0;
341 			if (hdlp->ih_type == DDI_INTR_TYPE_MSI)
342 				prop = "pci-msi-capid-pointer";
343 			else if (hdlp->ih_type == DDI_INTR_TYPE_MSIX)
344 				prop = "pci-msix-capid-pointer";
345 
346 			/*
347 			 * Enforce the calling of DDI_INTROP_SUPPORTED_TYPES
348 			 * for MSI(X) before allocation
349 			 */
350 			if (prop != NULL) {
351 				cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, rdip,
352 				    DDI_PROP_DONTPASS, prop, 0);
353 				if (cap_ptr == 0) {
354 					DDI_INTR_NEXDBG((CE_CONT,
355 					    "pci_common_intr_ops: rdip: 0x%p "
356 					    "attempted MSI(X) alloc without "
357 					    "cap property\n", (void *)rdip));
358 					return (DDI_FAILURE);
359 				}
360 			}
361 			i_ddi_set_msi_msix_cap_ptr(rdip, cap_ptr);
362 
363 			/*
364 			 * Allocate interrupt vectors
365 			 */
366 			(void) (*psm_intr_ops)(rdip, hdlp,
367 			    PSM_INTR_OP_ALLOC_VECTORS, result);
368 
369 			if (*(int *)result == 0)
370 				return (DDI_INTR_NOTFOUND);
371 
372 			/* verify behavior flag and take appropriate action */
373 			if ((behavior == DDI_INTR_ALLOC_STRICT) &&
374 			    (*(int *)result < hdlp->ih_scratch1)) {
375 				DDI_INTR_NEXDBG((CE_CONT,
376 				    "pci_common_intr_ops: behavior %x, "
377 				    "couldn't get enough intrs\n", behavior));
378 				hdlp->ih_scratch1 = *(int *)result;
379 				(void) (*psm_intr_ops)(rdip, hdlp,
380 				    PSM_INTR_OP_FREE_VECTORS, NULL);
381 				return (DDI_EAGAIN);
382 			}
383 
384 			if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) {
385 				if (!(msix_p = i_ddi_get_msix(hdlp->ih_dip))) {
386 					msix_p = pci_msix_init(hdlp->ih_dip);
387 					if (msix_p)
388 						i_ddi_set_msix(hdlp->ih_dip,
389 						    msix_p);
390 				}
391 			}
392 
393 			if (pciepci) {
394 				/* update priority in ispec */
395 				isp = pci_intx_get_ispec(pdip, rdip,
396 				    (int)hdlp->ih_inum);
397 				ispec = (struct intrspec *)isp;
398 				if (ispec)
399 					ispec->intrspec_pri = hdlp->ih_pri;
400 				++pcie_pci_intr_pri_counter;
401 			}
402 
403 		} else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) {
404 			/* Figure out if this device supports MASKING */
405 			pci_rval = pci_intx_get_cap(rdip, &pci_status);
406 			if (pci_rval == DDI_SUCCESS && pci_status)
407 				hdlp->ih_cap |= pci_status;
408 			*(int *)result = 1;	/* DDI_INTR_TYPE_FIXED */
409 		} else
410 			return (DDI_FAILURE);
411 		break;
412 	case DDI_INTROP_FREE:
413 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) &&
414 		    (psm_intr_ops != NULL)) {
415 			if (i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1 ==
416 			    0) {
417 				if (handle = i_ddi_get_pci_config_handle(
418 				    rdip)) {
419 					(void) pci_config_teardown(&handle);
420 					i_ddi_set_pci_config_handle(rdip, NULL);
421 				}
422 				if (cap_ptr = i_ddi_get_msi_msix_cap_ptr(rdip))
423 					i_ddi_set_msi_msix_cap_ptr(rdip, 0);
424 			}
425 
426 			(void) (*psm_intr_ops)(rdip, hdlp,
427 			    PSM_INTR_OP_FREE_VECTORS, NULL);
428 
429 			if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) {
430 				msix_p = i_ddi_get_msix(hdlp->ih_dip);
431 				if (msix_p &&
432 				    (i_ddi_intr_get_current_nintrs(
433 				    hdlp->ih_dip) - 1) == 0) {
434 					pci_msix_fini(msix_p);
435 					i_ddi_set_msix(hdlp->ih_dip, NULL);
436 				}
437 			}
438 		}
439 		break;
440 	case DDI_INTROP_GETPRI:
441 		/* Get the priority */
442 		if (pci_get_priority(rdip, hdlp, &priority) != DDI_SUCCESS)
443 			return (DDI_FAILURE);
444 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
445 		    "priority = 0x%x\n", priority));
446 		*(int *)result = priority;
447 		break;
448 	case DDI_INTROP_SETPRI:
449 		/* Validate the interrupt priority passed */
450 		if (*(int *)result > LOCK_LEVEL)
451 			return (DDI_FAILURE);
452 
453 		/* Ensure that PSM is all initialized */
454 		if (psm_intr_ops == NULL)
455 			return (DDI_FAILURE);
456 
457 		/* Change the priority */
458 		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_PRI, result) ==
459 		    PSM_FAILURE)
460 			return (DDI_FAILURE);
461 
462 		/* update ispec */
463 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
464 		ispec = (struct intrspec *)isp;
465 		if (ispec)
466 			ispec->intrspec_pri = *(int *)result;
467 		break;
468 	case DDI_INTROP_ADDISR:
469 		/* update ispec */
470 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
471 		ispec = (struct intrspec *)isp;
472 		if (ispec) {
473 			ispec->intrspec_func = hdlp->ih_cb_func;
474 			ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
475 			pci_kstat_create(&ihdl_plat_datap->ip_ksp, pdip, hdlp);
476 		}
477 		break;
478 	case DDI_INTROP_REMISR:
479 		/* Get the interrupt structure pointer */
480 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
481 		ispec = (struct intrspec *)isp;
482 		if (ispec) {
483 			ispec->intrspec_func = (uint_t (*)()) 0;
484 			ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
485 			if (ihdl_plat_datap->ip_ksp != NULL)
486 				pci_kstat_delete(ihdl_plat_datap->ip_ksp);
487 		}
488 		break;
489 	case DDI_INTROP_GETCAP:
490 		/*
491 		 * First check the config space and/or
492 		 * MSI capability register(s)
493 		 */
494 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
495 			pci_rval = pci_msi_get_cap(rdip, hdlp->ih_type,
496 			    &pci_status);
497 		else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
498 			pci_rval = pci_intx_get_cap(rdip, &pci_status);
499 
500 		/* next check with pcplusmp */
501 		if (psm_intr_ops != NULL)
502 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
503 			    PSM_INTR_OP_GET_CAP, &psm_status);
504 
505 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned psm_rval = %x, "
506 		    "psm_status = %x, pci_rval = %x, pci_status = %x\n",
507 		    psm_rval, psm_status, pci_rval, pci_status));
508 
509 		if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) {
510 			*(int *)result = 0;
511 			return (DDI_FAILURE);
512 		}
513 
514 		if (psm_rval == PSM_SUCCESS)
515 			*(int *)result = psm_status;
516 
517 		if (pci_rval == DDI_SUCCESS)
518 			*(int *)result |= pci_status;
519 
520 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned = %x\n",
521 		    *(int *)result));
522 		break;
523 	case DDI_INTROP_SETCAP:
524 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
525 		    "SETCAP cap=0x%x\n", *(int *)result));
526 		if (psm_intr_ops == NULL)
527 			return (DDI_FAILURE);
528 
529 		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result)) {
530 			DDI_INTR_NEXDBG((CE_CONT, "GETCAP: psm_intr_ops"
531 			    " returned failure\n"));
532 			return (DDI_FAILURE);
533 		}
534 		break;
535 	case DDI_INTROP_ENABLE:
536 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE\n"));
537 		if (psm_intr_ops == NULL)
538 			return (DDI_FAILURE);
539 
540 		if (pci_enable_intr(pdip, rdip, hdlp, hdlp->ih_inum) !=
541 		    DDI_SUCCESS)
542 			return (DDI_FAILURE);
543 
544 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE "
545 		    "vector=0x%x\n", hdlp->ih_vector));
546 		break;
547 	case DDI_INTROP_DISABLE:
548 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE\n"));
549 		if (psm_intr_ops == NULL)
550 			return (DDI_FAILURE);
551 
552 		pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum);
553 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE "
554 		    "vector = %x\n", hdlp->ih_vector));
555 		break;
556 	case DDI_INTROP_BLOCKENABLE:
557 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
558 		    "BLOCKENABLE\n"));
559 		if (hdlp->ih_type != DDI_INTR_TYPE_MSI) {
560 			DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: not MSI\n"));
561 			return (DDI_FAILURE);
562 		}
563 
564 		/* Check if psm_intr_ops is NULL? */
565 		if (psm_intr_ops == NULL)
566 			return (DDI_FAILURE);
567 
568 		count = hdlp->ih_scratch1;
569 		h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2;
570 		for (i = 0; i < count; i++) {
571 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
572 			if (pci_enable_intr(pdip, rdip, hdlp,
573 			    hdlp->ih_inum) != DDI_SUCCESS) {
574 				DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: "
575 				    "pci_enable_intr failed for %d\n", i));
576 				for (j = 0; j < i; j++) {
577 					hdlp = (ddi_intr_handle_impl_t *)
578 					    h_array[j];
579 					pci_disable_intr(pdip, rdip, hdlp,
580 					    hdlp->ih_inum);
581 				}
582 				return (DDI_FAILURE);
583 			}
584 			DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
585 			    "BLOCKENABLE inum %x done\n", hdlp->ih_inum));
586 		}
587 		break;
588 	case DDI_INTROP_BLOCKDISABLE:
589 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
590 		    "BLOCKDISABLE\n"));
591 		if (hdlp->ih_type != DDI_INTR_TYPE_MSI) {
592 			DDI_INTR_NEXDBG((CE_CONT, "BLOCKDISABLE: not MSI\n"));
593 			return (DDI_FAILURE);
594 		}
595 
596 		/* Check if psm_intr_ops is present */
597 		if (psm_intr_ops == NULL)
598 			return (DDI_FAILURE);
599 
600 		count = hdlp->ih_scratch1;
601 		h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2;
602 		for (i = 0; i < count; i++) {
603 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
604 			pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum);
605 			DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
606 			    "BLOCKDISABLE inum %x done\n", hdlp->ih_inum));
607 		}
608 		break;
609 	case DDI_INTROP_SETMASK:
610 	case DDI_INTROP_CLRMASK:
611 		/*
612 		 * First handle in the config space
613 		 */
614 		if (intr_op == DDI_INTROP_SETMASK) {
615 			if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
616 				pci_status = pci_msi_set_mask(rdip,
617 				    hdlp->ih_type, hdlp->ih_inum);
618 			else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
619 				pci_status = pci_intx_set_mask(rdip);
620 		} else {
621 			if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
622 				pci_status = pci_msi_clr_mask(rdip,
623 				    hdlp->ih_type, hdlp->ih_inum);
624 			else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
625 				pci_status = pci_intx_clr_mask(rdip);
626 		}
627 
628 		/* For MSI/X; no need to check with pcplusmp */
629 		if (hdlp->ih_type != DDI_INTR_TYPE_FIXED)
630 			return (pci_status);
631 
632 		/* For fixed interrupts only: handle config space first */
633 		if (hdlp->ih_type == DDI_INTR_TYPE_FIXED &&
634 		    pci_status == DDI_SUCCESS)
635 			break;
636 
637 		/* For fixed interrupts only: confer with pcplusmp next */
638 		if (psm_intr_ops != NULL) {
639 			/* If interrupt is shared; do nothing */
640 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
641 			    PSM_INTR_OP_GET_SHARED, &psm_status);
642 
643 			if (psm_rval == PSM_FAILURE || psm_status == 1)
644 				return (pci_status);
645 
646 			/* Now, pcplusmp should try to set/clear the mask */
647 			if (intr_op == DDI_INTROP_SETMASK)
648 				psm_rval = (*psm_intr_ops)(rdip, hdlp,
649 				    PSM_INTR_OP_SET_MASK, NULL);
650 			else
651 				psm_rval = (*psm_intr_ops)(rdip, hdlp,
652 				    PSM_INTR_OP_CLEAR_MASK, NULL);
653 		}
654 		return ((psm_rval == PSM_FAILURE) ? DDI_FAILURE : DDI_SUCCESS);
655 	case DDI_INTROP_GETPENDING:
656 		/*
657 		 * First check the config space and/or
658 		 * MSI capability register(s)
659 		 */
660 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
661 			pci_rval = pci_msi_get_pending(rdip, hdlp->ih_type,
662 			    hdlp->ih_inum, &pci_status);
663 		else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
664 			pci_rval = pci_intx_get_pending(rdip, &pci_status);
665 
666 		/* On failure; next try with pcplusmp */
667 		if (pci_rval != DDI_SUCCESS && psm_intr_ops != NULL)
668 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
669 			    PSM_INTR_OP_GET_PENDING, &psm_status);
670 
671 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned "
672 		    "psm_rval = %x, psm_status = %x, pci_rval = %x, "
673 		    "pci_status = %x\n", psm_rval, psm_status, pci_rval,
674 		    pci_status));
675 		if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) {
676 			*(int *)result = 0;
677 			return (DDI_FAILURE);
678 		}
679 
680 		if (psm_rval != PSM_FAILURE)
681 			*(int *)result = psm_status;
682 		else if (pci_rval != DDI_FAILURE)
683 			*(int *)result = pci_status;
684 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned = %x\n",
685 		    *(int *)result));
686 		break;
687 	default:
688 		return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result));
689 	}
690 
691 	return (DDI_SUCCESS);
692 }
693 
694 int
695 pci_get_intr_from_vecirq(apic_get_intr_t *intrinfo_p,
696     int vecirq, boolean_t is_irq)
697 {
698 	ddi_intr_handle_impl_t	get_info_ii_hdl;
699 
700 	if (is_irq)
701 		intrinfo_p->avgi_req_flags |= PSMGI_INTRBY_IRQ;
702 
703 	/*
704 	 * For this locally-declared and used handle, ih_private will contain a
705 	 * pointer to apic_get_intr_t, not an ihdl_plat_t as used for
706 	 * global interrupt handling.
707 	 */
708 	get_info_ii_hdl.ih_private = intrinfo_p;
709 	get_info_ii_hdl.ih_vector = (ushort_t)vecirq;
710 
711 	if ((*psm_intr_ops)(NULL, &get_info_ii_hdl,
712 	    PSM_INTR_OP_GET_INTR, NULL) == PSM_FAILURE)
713 		return (DDI_FAILURE);
714 
715 	return (DDI_SUCCESS);
716 }
717 
718 
719 int
720 pci_get_cpu_from_vecirq(int vecirq, boolean_t is_irq)
721 {
722 	int rval;
723 
724 	apic_get_intr_t	intrinfo;
725 	intrinfo.avgi_req_flags = PSMGI_REQ_CPUID;
726 	rval = pci_get_intr_from_vecirq(&intrinfo, vecirq, is_irq);
727 
728 	if (rval == DDI_SUCCESS)
729 		return (intrinfo.avgi_cpu_id);
730 	else
731 		return (-1);
732 }
733 
734 
735 static int
736 pci_enable_intr(dev_info_t *pdip, dev_info_t *rdip,
737     ddi_intr_handle_impl_t *hdlp, uint32_t inum)
738 {
739 	struct intrspec	*ispec;
740 	int		irq;
741 	ihdl_plat_t	*ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
742 
743 	DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: hdlp %p inum %x\n",
744 	    (void *)hdlp, inum));
745 
746 	/* Translate the interrupt if needed */
747 	ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
748 	if (ispec == NULL)
749 		return (DDI_FAILURE);
750 	if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
751 		ispec->intrspec_vec = inum;
752 	ihdl_plat_datap->ip_ispecp = ispec;
753 
754 	/* translate the interrupt if needed */
755 	(void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq);
756 	DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: priority=%x irq=%x\n",
757 	    hdlp->ih_pri, irq));
758 
759 	/* Add the interrupt handler */
760 	if (!add_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func,
761 	    DEVI(rdip)->devi_name, irq, hdlp->ih_cb_arg1,
762 	    hdlp->ih_cb_arg2, &ihdl_plat_datap->ip_ticks, rdip))
763 		return (DDI_FAILURE);
764 
765 	/* Note this really is an irq. */
766 	hdlp->ih_vector = (ushort_t)irq;
767 
768 	return (DDI_SUCCESS);
769 }
770 
771 
772 static void
773 pci_disable_intr(dev_info_t *pdip, dev_info_t *rdip,
774     ddi_intr_handle_impl_t *hdlp, uint32_t inum)
775 {
776 	int		irq;
777 	struct intrspec	*ispec;
778 	ihdl_plat_t	*ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
779 
780 	DDI_INTR_NEXDBG((CE_CONT, "pci_disable_intr: \n"));
781 	ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
782 	if (ispec == NULL)
783 		return;
784 	if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
785 		ispec->intrspec_vec = inum;
786 	ihdl_plat_datap->ip_ispecp = ispec;
787 
788 	/* translate the interrupt if needed */
789 	(void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq);
790 
791 	/* Disable the interrupt handler */
792 	rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, irq);
793 	ihdl_plat_datap->ip_ispecp = NULL;
794 }
795 
796 /*
797  * Miscellaneous library function
798  */
799 int
800 pci_common_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp)
801 {
802 	int		i;
803 	int 		number;
804 	int		assigned_addr_len;
805 	uint_t		phys_hi = pci_rp->pci_phys_hi;
806 	pci_regspec_t	*assigned_addr;
807 
808 	if (((phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) ||
809 	    (phys_hi & PCI_RELOCAT_B))
810 		return (DDI_SUCCESS);
811 
812 	/*
813 	 * the "reg" property specifies relocatable, get and interpret the
814 	 * "assigned-addresses" property.
815 	 */
816 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
817 	    "assigned-addresses", (int **)&assigned_addr,
818 	    (uint_t *)&assigned_addr_len) != DDI_PROP_SUCCESS)
819 		return (DDI_FAILURE);
820 
821 	/*
822 	 * Scan the "assigned-addresses" for one that matches the specified
823 	 * "reg" property entry.
824 	 */
825 	phys_hi &= PCI_CONF_ADDR_MASK;
826 	number = assigned_addr_len / (sizeof (pci_regspec_t) / sizeof (int));
827 	for (i = 0; i < number; i++) {
828 		if ((assigned_addr[i].pci_phys_hi & PCI_CONF_ADDR_MASK) ==
829 		    phys_hi) {
830 			pci_rp->pci_phys_mid = assigned_addr[i].pci_phys_mid;
831 			pci_rp->pci_phys_low = assigned_addr[i].pci_phys_low;
832 			ddi_prop_free(assigned_addr);
833 			return (DDI_SUCCESS);
834 		}
835 	}
836 
837 	ddi_prop_free(assigned_addr);
838 	return (DDI_FAILURE);
839 }
840 
841 
842 /*
843  * For pci_tools
844  */
845 
846 int
847 pci_common_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg,
848     int mode, cred_t *credp, int *rvalp)
849 {
850 	int rv = ENOTTY;
851 
852 	minor_t minor = getminor(dev);
853 
854 	switch (PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
855 	case PCI_TOOL_REG_MINOR_NUM:
856 
857 		switch (cmd) {
858 		case PCITOOL_DEVICE_SET_REG:
859 		case PCITOOL_DEVICE_GET_REG:
860 
861 			/* Require full privileges. */
862 			if (secpolicy_kmdb(credp))
863 				rv = EPERM;
864 			else
865 				rv = pcitool_dev_reg_ops(dip, (void *)arg,
866 				    cmd, mode);
867 			break;
868 
869 		case PCITOOL_NEXUS_SET_REG:
870 		case PCITOOL_NEXUS_GET_REG:
871 
872 			/* Require full privileges. */
873 			if (secpolicy_kmdb(credp))
874 				rv = EPERM;
875 			else
876 				rv = pcitool_bus_reg_ops(dip, (void *)arg,
877 				    cmd, mode);
878 			break;
879 		}
880 		break;
881 
882 	case PCI_TOOL_INTR_MINOR_NUM:
883 
884 		switch (cmd) {
885 		case PCITOOL_DEVICE_SET_INTR:
886 
887 			/* Require PRIV_SYS_RES_CONFIG, same as psradm */
888 			if (secpolicy_ponline(credp)) {
889 				rv = EPERM;
890 				break;
891 			}
892 
893 		/*FALLTHRU*/
894 		/* These require no special privileges. */
895 		case PCITOOL_DEVICE_GET_INTR:
896 		case PCITOOL_SYSTEM_INTR_INFO:
897 			rv = pcitool_intr_admn(dip, (void *)arg, cmd, mode);
898 			break;
899 		}
900 		break;
901 
902 	/*
903 	 * All non-PCItool ioctls go through here, including:
904 	 *   devctl ioctls with minor number PCIHP_DEVCTL_MINOR and
905 	 *   those for attachment points with where minor number is the
906 	 *   device number.
907 	 */
908 	default:
909 		rv = (pcihp_get_cb_ops())->cb_ioctl(dev, cmd, arg, mode,
910 		    credp, rvalp);
911 		break;
912 	}
913 
914 	return (rv);
915 }
916 
917 
918 int
919 pci_common_ctlops_poke(peekpoke_ctlops_t *in_args)
920 {
921 	size_t size = in_args->size;
922 	uintptr_t dev_addr = in_args->dev_addr;
923 	uintptr_t host_addr = in_args->host_addr;
924 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
925 	ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
926 	size_t repcount = in_args->repcount;
927 	uint_t flags = in_args->flags;
928 	int err = DDI_SUCCESS;
929 
930 	/*
931 	 * if no handle then this is a poke. We have to return failure here
932 	 * as we have no way of knowing whether this is a MEM or IO space access
933 	 */
934 	if (in_args->handle == NULL)
935 		return (DDI_FAILURE);
936 
937 	/*
938 	 * rest of this function is actually for cautious puts
939 	 */
940 	for (; repcount; repcount--) {
941 		if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
942 			switch (size) {
943 			case sizeof (uint8_t):
944 				pci_config_wr8(hp, (uint8_t *)dev_addr,
945 				    *(uint8_t *)host_addr);
946 				break;
947 			case sizeof (uint16_t):
948 				pci_config_wr16(hp, (uint16_t *)dev_addr,
949 				    *(uint16_t *)host_addr);
950 				break;
951 			case sizeof (uint32_t):
952 				pci_config_wr32(hp, (uint32_t *)dev_addr,
953 				    *(uint32_t *)host_addr);
954 				break;
955 			case sizeof (uint64_t):
956 				pci_config_wr64(hp, (uint64_t *)dev_addr,
957 				    *(uint64_t *)host_addr);
958 				break;
959 			default:
960 				err = DDI_FAILURE;
961 				break;
962 			}
963 		} else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
964 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
965 			    DDI_STRUCTURE_BE_ACC) {
966 				switch (size) {
967 				case sizeof (uint8_t):
968 					i_ddi_io_put8(hp,
969 					    (uint8_t *)dev_addr,
970 					    *(uint8_t *)host_addr);
971 					break;
972 				case sizeof (uint16_t):
973 					i_ddi_io_swap_put16(hp,
974 					    (uint16_t *)dev_addr,
975 					    *(uint16_t *)host_addr);
976 					break;
977 				case sizeof (uint32_t):
978 					i_ddi_io_swap_put32(hp,
979 					    (uint32_t *)dev_addr,
980 					    *(uint32_t *)host_addr);
981 					break;
982 				/*
983 				 * note the 64-bit case is a dummy
984 				 * function - so no need to swap
985 				 */
986 				case sizeof (uint64_t):
987 					i_ddi_io_put64(hp,
988 					    (uint64_t *)dev_addr,
989 					    *(uint64_t *)host_addr);
990 					break;
991 				default:
992 					err = DDI_FAILURE;
993 					break;
994 				}
995 			} else {
996 				switch (size) {
997 				case sizeof (uint8_t):
998 					i_ddi_io_put8(hp,
999 					    (uint8_t *)dev_addr,
1000 					    *(uint8_t *)host_addr);
1001 					break;
1002 				case sizeof (uint16_t):
1003 					i_ddi_io_put16(hp,
1004 					    (uint16_t *)dev_addr,
1005 					    *(uint16_t *)host_addr);
1006 					break;
1007 				case sizeof (uint32_t):
1008 					i_ddi_io_put32(hp,
1009 					    (uint32_t *)dev_addr,
1010 					    *(uint32_t *)host_addr);
1011 					break;
1012 				case sizeof (uint64_t):
1013 					i_ddi_io_put64(hp,
1014 					    (uint64_t *)dev_addr,
1015 					    *(uint64_t *)host_addr);
1016 					break;
1017 				default:
1018 					err = DDI_FAILURE;
1019 					break;
1020 				}
1021 			}
1022 		} else {
1023 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
1024 			    DDI_STRUCTURE_BE_ACC) {
1025 				switch (size) {
1026 				case sizeof (uint8_t):
1027 					*(uint8_t *)dev_addr =
1028 					    *(uint8_t *)host_addr;
1029 					break;
1030 				case sizeof (uint16_t):
1031 					*(uint16_t *)dev_addr =
1032 					    ddi_swap16(*(uint16_t *)host_addr);
1033 					break;
1034 				case sizeof (uint32_t):
1035 					*(uint32_t *)dev_addr =
1036 					    ddi_swap32(*(uint32_t *)host_addr);
1037 					break;
1038 				case sizeof (uint64_t):
1039 					*(uint64_t *)dev_addr =
1040 					    ddi_swap64(*(uint64_t *)host_addr);
1041 					break;
1042 				default:
1043 					err = DDI_FAILURE;
1044 					break;
1045 				}
1046 			} else {
1047 				switch (size) {
1048 				case sizeof (uint8_t):
1049 					*(uint8_t *)dev_addr =
1050 					    *(uint8_t *)host_addr;
1051 					break;
1052 				case sizeof (uint16_t):
1053 					*(uint16_t *)dev_addr =
1054 					    *(uint16_t *)host_addr;
1055 					break;
1056 				case sizeof (uint32_t):
1057 					*(uint32_t *)dev_addr =
1058 					    *(uint32_t *)host_addr;
1059 					break;
1060 				case sizeof (uint64_t):
1061 					*(uint64_t *)dev_addr =
1062 					    *(uint64_t *)host_addr;
1063 					break;
1064 				default:
1065 					err = DDI_FAILURE;
1066 					break;
1067 				}
1068 			}
1069 		}
1070 		host_addr += size;
1071 		if (flags == DDI_DEV_AUTOINCR)
1072 			dev_addr += size;
1073 	}
1074 	return (err);
1075 }
1076 
1077 
1078 int
1079 pci_fm_acc_setup(ddi_acc_hdl_t *hp, off_t offset, off_t len)
1080 {
1081 	ddi_acc_impl_t	*ap = (ddi_acc_impl_t *)hp->ah_platform_private;
1082 
1083 	/* endian-ness check */
1084 	if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC)
1085 		return (DDI_FAILURE);
1086 
1087 	/*
1088 	 * range check
1089 	 */
1090 	if ((offset >= PCI_CONF_HDR_SIZE) ||
1091 	    (len > PCI_CONF_HDR_SIZE) ||
1092 	    (offset + len > PCI_CONF_HDR_SIZE))
1093 		return (DDI_FAILURE);
1094 
1095 	ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE;
1096 	/*
1097 	 * always use cautious mechanism for config space gets
1098 	 */
1099 	ap->ahi_get8 = i_ddi_caut_get8;
1100 	ap->ahi_get16 = i_ddi_caut_get16;
1101 	ap->ahi_get32 = i_ddi_caut_get32;
1102 	ap->ahi_get64 = i_ddi_caut_get64;
1103 	ap->ahi_rep_get8 = i_ddi_caut_rep_get8;
1104 	ap->ahi_rep_get16 = i_ddi_caut_rep_get16;
1105 	ap->ahi_rep_get32 = i_ddi_caut_rep_get32;
1106 	ap->ahi_rep_get64 = i_ddi_caut_rep_get64;
1107 	if (hp->ah_acc.devacc_attr_access == DDI_CAUTIOUS_ACC) {
1108 		ap->ahi_put8 = i_ddi_caut_put8;
1109 		ap->ahi_put16 = i_ddi_caut_put16;
1110 		ap->ahi_put32 = i_ddi_caut_put32;
1111 		ap->ahi_put64 = i_ddi_caut_put64;
1112 		ap->ahi_rep_put8 = i_ddi_caut_rep_put8;
1113 		ap->ahi_rep_put16 = i_ddi_caut_rep_put16;
1114 		ap->ahi_rep_put32 = i_ddi_caut_rep_put32;
1115 		ap->ahi_rep_put64 = i_ddi_caut_rep_put64;
1116 	} else {
1117 		ap->ahi_put8 = pci_config_wr8;
1118 		ap->ahi_put16 = pci_config_wr16;
1119 		ap->ahi_put32 = pci_config_wr32;
1120 		ap->ahi_put64 = pci_config_wr64;
1121 		ap->ahi_rep_put8 = pci_config_rep_wr8;
1122 		ap->ahi_rep_put16 = pci_config_rep_wr16;
1123 		ap->ahi_rep_put32 = pci_config_rep_wr32;
1124 		ap->ahi_rep_put64 = pci_config_rep_wr64;
1125 	}
1126 
1127 	/* Initialize to default check/notify functions */
1128 	ap->ahi_fault_check = i_ddi_acc_fault_check;
1129 	ap->ahi_fault_notify = i_ddi_acc_fault_notify;
1130 	ap->ahi_fault = 0;
1131 	impl_acc_err_init(hp);
1132 	return (DDI_SUCCESS);
1133 }
1134 
1135 
1136 int
1137 pci_common_ctlops_peek(peekpoke_ctlops_t *in_args)
1138 {
1139 	size_t size = in_args->size;
1140 	uintptr_t dev_addr = in_args->dev_addr;
1141 	uintptr_t host_addr = in_args->host_addr;
1142 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
1143 	ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
1144 	size_t repcount = in_args->repcount;
1145 	uint_t flags = in_args->flags;
1146 	int err = DDI_SUCCESS;
1147 
1148 	/*
1149 	 * if no handle then this is a peek. We have to return failure here
1150 	 * as we have no way of knowing whether this is a MEM or IO space access
1151 	 */
1152 	if (in_args->handle == NULL)
1153 		return (DDI_FAILURE);
1154 
1155 	for (; repcount; repcount--) {
1156 		if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
1157 			switch (size) {
1158 			case sizeof (uint8_t):
1159 				*(uint8_t *)host_addr = pci_config_rd8(hp,
1160 				    (uint8_t *)dev_addr);
1161 				break;
1162 			case sizeof (uint16_t):
1163 				*(uint16_t *)host_addr = pci_config_rd16(hp,
1164 				    (uint16_t *)dev_addr);
1165 				break;
1166 			case sizeof (uint32_t):
1167 				*(uint32_t *)host_addr = pci_config_rd32(hp,
1168 				    (uint32_t *)dev_addr);
1169 				break;
1170 			case sizeof (uint64_t):
1171 				*(uint64_t *)host_addr = pci_config_rd64(hp,
1172 				    (uint64_t *)dev_addr);
1173 				break;
1174 			default:
1175 				err = DDI_FAILURE;
1176 				break;
1177 			}
1178 		} else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
1179 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
1180 			    DDI_STRUCTURE_BE_ACC) {
1181 				switch (size) {
1182 				case sizeof (uint8_t):
1183 					*(uint8_t *)host_addr =
1184 					    i_ddi_io_get8(hp,
1185 					    (uint8_t *)dev_addr);
1186 					break;
1187 				case sizeof (uint16_t):
1188 					*(uint16_t *)host_addr =
1189 					    i_ddi_io_swap_get16(hp,
1190 					    (uint16_t *)dev_addr);
1191 					break;
1192 				case sizeof (uint32_t):
1193 					*(uint32_t *)host_addr =
1194 					    i_ddi_io_swap_get32(hp,
1195 					    (uint32_t *)dev_addr);
1196 					break;
1197 				/*
1198 				 * note the 64-bit case is a dummy
1199 				 * function - so no need to swap
1200 				 */
1201 				case sizeof (uint64_t):
1202 					*(uint64_t *)host_addr =
1203 					    i_ddi_io_get64(hp,
1204 					    (uint64_t *)dev_addr);
1205 					break;
1206 				default:
1207 					err = DDI_FAILURE;
1208 					break;
1209 				}
1210 			} else {
1211 				switch (size) {
1212 				case sizeof (uint8_t):
1213 					*(uint8_t *)host_addr =
1214 					    i_ddi_io_get8(hp,
1215 					    (uint8_t *)dev_addr);
1216 					break;
1217 				case sizeof (uint16_t):
1218 					*(uint16_t *)host_addr =
1219 					    i_ddi_io_get16(hp,
1220 					    (uint16_t *)dev_addr);
1221 					break;
1222 				case sizeof (uint32_t):
1223 					*(uint32_t *)host_addr =
1224 					    i_ddi_io_get32(hp,
1225 					    (uint32_t *)dev_addr);
1226 					break;
1227 				case sizeof (uint64_t):
1228 					*(uint64_t *)host_addr =
1229 					    i_ddi_io_get64(hp,
1230 					    (uint64_t *)dev_addr);
1231 					break;
1232 				default:
1233 					err = DDI_FAILURE;
1234 					break;
1235 				}
1236 			}
1237 		} else {
1238 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
1239 			    DDI_STRUCTURE_BE_ACC) {
1240 				switch (in_args->size) {
1241 				case sizeof (uint8_t):
1242 					*(uint8_t *)host_addr =
1243 					    *(uint8_t *)dev_addr;
1244 					break;
1245 				case sizeof (uint16_t):
1246 					*(uint16_t *)host_addr =
1247 					    ddi_swap16(*(uint16_t *)dev_addr);
1248 					break;
1249 				case sizeof (uint32_t):
1250 					*(uint32_t *)host_addr =
1251 					    ddi_swap32(*(uint32_t *)dev_addr);
1252 					break;
1253 				case sizeof (uint64_t):
1254 					*(uint64_t *)host_addr =
1255 					    ddi_swap64(*(uint64_t *)dev_addr);
1256 					break;
1257 				default:
1258 					err = DDI_FAILURE;
1259 					break;
1260 				}
1261 			} else {
1262 				switch (in_args->size) {
1263 				case sizeof (uint8_t):
1264 					*(uint8_t *)host_addr =
1265 					    *(uint8_t *)dev_addr;
1266 					break;
1267 				case sizeof (uint16_t):
1268 					*(uint16_t *)host_addr =
1269 					    *(uint16_t *)dev_addr;
1270 					break;
1271 				case sizeof (uint32_t):
1272 					*(uint32_t *)host_addr =
1273 					    *(uint32_t *)dev_addr;
1274 					break;
1275 				case sizeof (uint64_t):
1276 					*(uint64_t *)host_addr =
1277 					    *(uint64_t *)dev_addr;
1278 					break;
1279 				default:
1280 					err = DDI_FAILURE;
1281 					break;
1282 				}
1283 			}
1284 		}
1285 		host_addr += size;
1286 		if (flags == DDI_DEV_AUTOINCR)
1287 			dev_addr += size;
1288 	}
1289 	return (err);
1290 }
1291 
1292 /*ARGSUSED*/
1293 int
1294 pci_common_peekpoke(dev_info_t *dip, dev_info_t *rdip,
1295 	ddi_ctl_enum_t ctlop, void *arg, void *result)
1296 {
1297 	if (ctlop == DDI_CTLOPS_PEEK)
1298 		return (pci_common_ctlops_peek((peekpoke_ctlops_t *)arg));
1299 	else
1300 		return (pci_common_ctlops_poke((peekpoke_ctlops_t *)arg));
1301 }
1302 
1303 /*
1304  * These are the get and put functions to be shared with drivers. The
1305  * mutex locking is done inside the functions referenced, rather than
1306  * here, and is thus shared across PCI child drivers and any other
1307  * consumers of PCI config space (such as the ACPI subsystem).
1308  *
1309  * The configuration space addresses come in as pointers.  This is fine on
1310  * a 32-bit system, where the VM space and configuration space are the same
1311  * size.  It's not such a good idea on a 64-bit system, where memory
1312  * addresses are twice as large as configuration space addresses.  At some
1313  * point in the call tree we need to take a stand and say "you are 32-bit
1314  * from this time forth", and this seems like a nice self-contained place.
1315  */
1316 
1317 uint8_t
1318 pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr)
1319 {
1320 	pci_acc_cfblk_t *cfp;
1321 	uint8_t	rval;
1322 	int reg;
1323 
1324 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1325 
1326 	reg = (int)(uintptr_t)addr;
1327 
1328 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1329 
1330 	rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
1331 	    reg);
1332 
1333 	return (rval);
1334 }
1335 
1336 void
1337 pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
1338 	uint8_t *dev_addr, size_t repcount, uint_t flags)
1339 {
1340 	uint8_t *h, *d;
1341 
1342 	h = host_addr;
1343 	d = dev_addr;
1344 
1345 	if (flags == DDI_DEV_AUTOINCR)
1346 		for (; repcount; repcount--)
1347 			*h++ = pci_config_rd8(hdlp, d++);
1348 	else
1349 		for (; repcount; repcount--)
1350 			*h++ = pci_config_rd8(hdlp, d);
1351 }
1352 
1353 uint16_t
1354 pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr)
1355 {
1356 	pci_acc_cfblk_t *cfp;
1357 	uint16_t rval;
1358 	int reg;
1359 
1360 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1361 
1362 	reg = (int)(uintptr_t)addr;
1363 
1364 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1365 
1366 	rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
1367 	    reg);
1368 
1369 	return (rval);
1370 }
1371 
1372 void
1373 pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
1374 	uint16_t *dev_addr, size_t repcount, uint_t flags)
1375 {
1376 	uint16_t *h, *d;
1377 
1378 	h = host_addr;
1379 	d = dev_addr;
1380 
1381 	if (flags == DDI_DEV_AUTOINCR)
1382 		for (; repcount; repcount--)
1383 			*h++ = pci_config_rd16(hdlp, d++);
1384 	else
1385 		for (; repcount; repcount--)
1386 			*h++ = pci_config_rd16(hdlp, d);
1387 }
1388 
1389 uint32_t
1390 pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr)
1391 {
1392 	pci_acc_cfblk_t *cfp;
1393 	uint32_t rval;
1394 	int reg;
1395 
1396 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1397 
1398 	reg = (int)(uintptr_t)addr;
1399 
1400 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1401 
1402 	rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum,
1403 	    cfp->c_funcnum, reg);
1404 
1405 	return (rval);
1406 }
1407 
1408 void
1409 pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
1410 	uint32_t *dev_addr, size_t repcount, uint_t flags)
1411 {
1412 	uint32_t *h, *d;
1413 
1414 	h = host_addr;
1415 	d = dev_addr;
1416 
1417 	if (flags == DDI_DEV_AUTOINCR)
1418 		for (; repcount; repcount--)
1419 			*h++ = pci_config_rd32(hdlp, d++);
1420 	else
1421 		for (; repcount; repcount--)
1422 			*h++ = pci_config_rd32(hdlp, d);
1423 }
1424 
1425 
1426 void
1427 pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value)
1428 {
1429 	pci_acc_cfblk_t *cfp;
1430 	int reg;
1431 
1432 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1433 
1434 	reg = (int)(uintptr_t)addr;
1435 
1436 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1437 
1438 	(*pci_putb_func)(cfp->c_busnum, cfp->c_devnum,
1439 	    cfp->c_funcnum, reg, value);
1440 }
1441 
1442 void
1443 pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
1444 	uint8_t *dev_addr, size_t repcount, uint_t flags)
1445 {
1446 	uint8_t *h, *d;
1447 
1448 	h = host_addr;
1449 	d = dev_addr;
1450 
1451 	if (flags == DDI_DEV_AUTOINCR)
1452 		for (; repcount; repcount--)
1453 			pci_config_wr8(hdlp, d++, *h++);
1454 	else
1455 		for (; repcount; repcount--)
1456 			pci_config_wr8(hdlp, d, *h++);
1457 }
1458 
1459 void
1460 pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value)
1461 {
1462 	pci_acc_cfblk_t *cfp;
1463 	int reg;
1464 
1465 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1466 
1467 	reg = (int)(uintptr_t)addr;
1468 
1469 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1470 
1471 	(*pci_putw_func)(cfp->c_busnum, cfp->c_devnum,
1472 	    cfp->c_funcnum, reg, value);
1473 }
1474 
1475 void
1476 pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
1477 	uint16_t *dev_addr, size_t repcount, uint_t flags)
1478 {
1479 	uint16_t *h, *d;
1480 
1481 	h = host_addr;
1482 	d = dev_addr;
1483 
1484 	if (flags == DDI_DEV_AUTOINCR)
1485 		for (; repcount; repcount--)
1486 			pci_config_wr16(hdlp, d++, *h++);
1487 	else
1488 		for (; repcount; repcount--)
1489 			pci_config_wr16(hdlp, d, *h++);
1490 }
1491 
1492 void
1493 pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value)
1494 {
1495 	pci_acc_cfblk_t *cfp;
1496 	int reg;
1497 
1498 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1499 
1500 	reg = (int)(uintptr_t)addr;
1501 
1502 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1503 
1504 	(*pci_putl_func)(cfp->c_busnum, cfp->c_devnum,
1505 	    cfp->c_funcnum, reg, value);
1506 }
1507 
1508 void
1509 pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
1510 	uint32_t *dev_addr, size_t repcount, uint_t flags)
1511 {
1512 	uint32_t *h, *d;
1513 
1514 	h = host_addr;
1515 	d = dev_addr;
1516 
1517 	if (flags == DDI_DEV_AUTOINCR)
1518 		for (; repcount; repcount--)
1519 			pci_config_wr32(hdlp, d++, *h++);
1520 	else
1521 		for (; repcount; repcount--)
1522 			pci_config_wr32(hdlp, d, *h++);
1523 }
1524 
1525 uint64_t
1526 pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr)
1527 {
1528 	uint32_t lw_val;
1529 	uint32_t hi_val;
1530 	uint32_t *dp;
1531 	uint64_t val;
1532 
1533 	dp = (uint32_t *)addr;
1534 	lw_val = pci_config_rd32(hdlp, dp);
1535 	dp++;
1536 	hi_val = pci_config_rd32(hdlp, dp);
1537 	val = ((uint64_t)hi_val << 32) | lw_val;
1538 	return (val);
1539 }
1540 
1541 void
1542 pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value)
1543 {
1544 	uint32_t lw_val;
1545 	uint32_t hi_val;
1546 	uint32_t *dp;
1547 
1548 	dp = (uint32_t *)addr;
1549 	lw_val = (uint32_t)(value & 0xffffffff);
1550 	hi_val = (uint32_t)(value >> 32);
1551 	pci_config_wr32(hdlp, dp, lw_val);
1552 	dp++;
1553 	pci_config_wr32(hdlp, dp, hi_val);
1554 }
1555 
1556 void
1557 pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
1558 	uint64_t *dev_addr, size_t repcount, uint_t flags)
1559 {
1560 	if (flags == DDI_DEV_AUTOINCR) {
1561 		for (; repcount; repcount--)
1562 			*host_addr++ = pci_config_rd64(hdlp, dev_addr++);
1563 	} else {
1564 		for (; repcount; repcount--)
1565 			*host_addr++ = pci_config_rd64(hdlp, dev_addr);
1566 	}
1567 }
1568 
1569 void
1570 pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
1571 	uint64_t *dev_addr, size_t repcount, uint_t flags)
1572 {
1573 	if (flags == DDI_DEV_AUTOINCR) {
1574 		for (; repcount; repcount--)
1575 			pci_config_wr64(hdlp, host_addr++, *dev_addr++);
1576 	} else {
1577 		for (; repcount; repcount--)
1578 			pci_config_wr64(hdlp, host_addr++, *dev_addr);
1579 	}
1580 }
1581