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