xref: /titanic_51/usr/src/uts/i86pc/io/pci/pci_common.c (revision dbed73cbda2229fd1aa6dc5743993cae7f0a7ee9)
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 2009 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 	(void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq);
817 	DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: priority=%x irq=%x\n",
818 	    hdlp->ih_pri, irq));
819 
820 	/* Add the interrupt handler */
821 	if (!add_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func,
822 	    DEVI(rdip)->devi_name, irq, hdlp->ih_cb_arg1,
823 	    hdlp->ih_cb_arg2, &ihdl_plat_datap->ip_ticks, rdip))
824 		return (DDI_FAILURE);
825 
826 	/* Note this really is an irq. */
827 	hdlp->ih_vector = (ushort_t)irq;
828 
829 	return (DDI_SUCCESS);
830 }
831 
832 
833 static void
834 pci_disable_intr(dev_info_t *pdip, dev_info_t *rdip,
835     ddi_intr_handle_impl_t *hdlp, uint32_t inum)
836 {
837 	int		irq;
838 	struct intrspec	*ispec;
839 	ihdl_plat_t	*ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
840 
841 	DDI_INTR_NEXDBG((CE_CONT, "pci_disable_intr: \n"));
842 	ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
843 	if (ispec == NULL)
844 		return;
845 	if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
846 		ispec->intrspec_vec = inum;
847 		ispec->intrspec_pri = hdlp->ih_pri;
848 	}
849 	ihdl_plat_datap->ip_ispecp = ispec;
850 
851 	/* translate the interrupt if needed */
852 	(void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq);
853 
854 	/* Disable the interrupt handler */
855 	rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, irq);
856 	ihdl_plat_datap->ip_ispecp = NULL;
857 }
858 
859 /*
860  * Miscellaneous library function
861  */
862 int
863 pci_common_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp)
864 {
865 	int		i;
866 	int 		number;
867 	int		assigned_addr_len;
868 	uint_t		phys_hi = pci_rp->pci_phys_hi;
869 	pci_regspec_t	*assigned_addr;
870 
871 	if (((phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) ||
872 	    (phys_hi & PCI_RELOCAT_B))
873 		return (DDI_SUCCESS);
874 
875 	/*
876 	 * the "reg" property specifies relocatable, get and interpret the
877 	 * "assigned-addresses" property.
878 	 */
879 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
880 	    "assigned-addresses", (int **)&assigned_addr,
881 	    (uint_t *)&assigned_addr_len) != DDI_PROP_SUCCESS)
882 		return (DDI_FAILURE);
883 
884 	/*
885 	 * Scan the "assigned-addresses" for one that matches the specified
886 	 * "reg" property entry.
887 	 */
888 	phys_hi &= PCI_CONF_ADDR_MASK;
889 	number = assigned_addr_len / (sizeof (pci_regspec_t) / sizeof (int));
890 	for (i = 0; i < number; i++) {
891 		if ((assigned_addr[i].pci_phys_hi & PCI_CONF_ADDR_MASK) ==
892 		    phys_hi) {
893 			pci_rp->pci_phys_mid = assigned_addr[i].pci_phys_mid;
894 			pci_rp->pci_phys_low = assigned_addr[i].pci_phys_low;
895 			ddi_prop_free(assigned_addr);
896 			return (DDI_SUCCESS);
897 		}
898 	}
899 
900 	ddi_prop_free(assigned_addr);
901 	return (DDI_FAILURE);
902 }
903 
904 
905 /*
906  * To handle PCI tool ioctls
907  */
908 
909 /*ARGSUSED*/
910 int
911 pci_common_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg,
912     int mode, cred_t *credp, int *rvalp)
913 {
914 	minor_t	minor = getminor(dev);
915 	int	rv = ENOTTY;
916 
917 	switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
918 	case PCI_TOOL_REG_MINOR_NUM:
919 
920 		switch (cmd) {
921 		case PCITOOL_DEVICE_SET_REG:
922 		case PCITOOL_DEVICE_GET_REG:
923 
924 			/* Require full privileges. */
925 			if (secpolicy_kmdb(credp))
926 				rv = EPERM;
927 			else
928 				rv = pcitool_dev_reg_ops(dip, (void *)arg,
929 				    cmd, mode);
930 			break;
931 
932 		case PCITOOL_NEXUS_SET_REG:
933 		case PCITOOL_NEXUS_GET_REG:
934 
935 			/* Require full privileges. */
936 			if (secpolicy_kmdb(credp))
937 				rv = EPERM;
938 			else
939 				rv = pcitool_bus_reg_ops(dip, (void *)arg,
940 				    cmd, mode);
941 			break;
942 		}
943 		break;
944 
945 	case PCI_TOOL_INTR_MINOR_NUM:
946 
947 		switch (cmd) {
948 		case PCITOOL_DEVICE_SET_INTR:
949 
950 			/* Require PRIV_SYS_RES_CONFIG, same as psradm */
951 			if (secpolicy_ponline(credp)) {
952 				rv = EPERM;
953 				break;
954 			}
955 
956 		/*FALLTHRU*/
957 		/* These require no special privileges. */
958 		case PCITOOL_DEVICE_GET_INTR:
959 		case PCITOOL_SYSTEM_INTR_INFO:
960 			rv = pcitool_intr_admn(dip, (void *)arg, cmd, mode);
961 			break;
962 		}
963 		break;
964 
965 	default:
966 		break;
967 	}
968 
969 	return (rv);
970 }
971 
972 
973 int
974 pci_common_ctlops_poke(peekpoke_ctlops_t *in_args)
975 {
976 	size_t size = in_args->size;
977 	uintptr_t dev_addr = in_args->dev_addr;
978 	uintptr_t host_addr = in_args->host_addr;
979 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
980 	ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
981 	size_t repcount = in_args->repcount;
982 	uint_t flags = in_args->flags;
983 	int err = DDI_SUCCESS;
984 
985 	/*
986 	 * if no handle then this is a poke. We have to return failure here
987 	 * as we have no way of knowing whether this is a MEM or IO space access
988 	 */
989 	if (in_args->handle == NULL)
990 		return (DDI_FAILURE);
991 
992 	/*
993 	 * rest of this function is actually for cautious puts
994 	 */
995 	for (; repcount; repcount--) {
996 		if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
997 			switch (size) {
998 			case sizeof (uint8_t):
999 				pci_config_wr8(hp, (uint8_t *)dev_addr,
1000 				    *(uint8_t *)host_addr);
1001 				break;
1002 			case sizeof (uint16_t):
1003 				pci_config_wr16(hp, (uint16_t *)dev_addr,
1004 				    *(uint16_t *)host_addr);
1005 				break;
1006 			case sizeof (uint32_t):
1007 				pci_config_wr32(hp, (uint32_t *)dev_addr,
1008 				    *(uint32_t *)host_addr);
1009 				break;
1010 			case sizeof (uint64_t):
1011 				pci_config_wr64(hp, (uint64_t *)dev_addr,
1012 				    *(uint64_t *)host_addr);
1013 				break;
1014 			default:
1015 				err = DDI_FAILURE;
1016 				break;
1017 			}
1018 		} else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
1019 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
1020 			    DDI_STRUCTURE_BE_ACC) {
1021 				switch (size) {
1022 				case sizeof (uint8_t):
1023 					i_ddi_io_put8(hp,
1024 					    (uint8_t *)dev_addr,
1025 					    *(uint8_t *)host_addr);
1026 					break;
1027 				case sizeof (uint16_t):
1028 					i_ddi_io_swap_put16(hp,
1029 					    (uint16_t *)dev_addr,
1030 					    *(uint16_t *)host_addr);
1031 					break;
1032 				case sizeof (uint32_t):
1033 					i_ddi_io_swap_put32(hp,
1034 					    (uint32_t *)dev_addr,
1035 					    *(uint32_t *)host_addr);
1036 					break;
1037 				/*
1038 				 * note the 64-bit case is a dummy
1039 				 * function - so no need to swap
1040 				 */
1041 				case sizeof (uint64_t):
1042 					i_ddi_io_put64(hp,
1043 					    (uint64_t *)dev_addr,
1044 					    *(uint64_t *)host_addr);
1045 					break;
1046 				default:
1047 					err = DDI_FAILURE;
1048 					break;
1049 				}
1050 			} else {
1051 				switch (size) {
1052 				case sizeof (uint8_t):
1053 					i_ddi_io_put8(hp,
1054 					    (uint8_t *)dev_addr,
1055 					    *(uint8_t *)host_addr);
1056 					break;
1057 				case sizeof (uint16_t):
1058 					i_ddi_io_put16(hp,
1059 					    (uint16_t *)dev_addr,
1060 					    *(uint16_t *)host_addr);
1061 					break;
1062 				case sizeof (uint32_t):
1063 					i_ddi_io_put32(hp,
1064 					    (uint32_t *)dev_addr,
1065 					    *(uint32_t *)host_addr);
1066 					break;
1067 				case sizeof (uint64_t):
1068 					i_ddi_io_put64(hp,
1069 					    (uint64_t *)dev_addr,
1070 					    *(uint64_t *)host_addr);
1071 					break;
1072 				default:
1073 					err = DDI_FAILURE;
1074 					break;
1075 				}
1076 			}
1077 		} else {
1078 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
1079 			    DDI_STRUCTURE_BE_ACC) {
1080 				switch (size) {
1081 				case sizeof (uint8_t):
1082 					*(uint8_t *)dev_addr =
1083 					    *(uint8_t *)host_addr;
1084 					break;
1085 				case sizeof (uint16_t):
1086 					*(uint16_t *)dev_addr =
1087 					    ddi_swap16(*(uint16_t *)host_addr);
1088 					break;
1089 				case sizeof (uint32_t):
1090 					*(uint32_t *)dev_addr =
1091 					    ddi_swap32(*(uint32_t *)host_addr);
1092 					break;
1093 				case sizeof (uint64_t):
1094 					*(uint64_t *)dev_addr =
1095 					    ddi_swap64(*(uint64_t *)host_addr);
1096 					break;
1097 				default:
1098 					err = DDI_FAILURE;
1099 					break;
1100 				}
1101 			} else {
1102 				switch (size) {
1103 				case sizeof (uint8_t):
1104 					*(uint8_t *)dev_addr =
1105 					    *(uint8_t *)host_addr;
1106 					break;
1107 				case sizeof (uint16_t):
1108 					*(uint16_t *)dev_addr =
1109 					    *(uint16_t *)host_addr;
1110 					break;
1111 				case sizeof (uint32_t):
1112 					*(uint32_t *)dev_addr =
1113 					    *(uint32_t *)host_addr;
1114 					break;
1115 				case sizeof (uint64_t):
1116 					*(uint64_t *)dev_addr =
1117 					    *(uint64_t *)host_addr;
1118 					break;
1119 				default:
1120 					err = DDI_FAILURE;
1121 					break;
1122 				}
1123 			}
1124 		}
1125 		host_addr += size;
1126 		if (flags == DDI_DEV_AUTOINCR)
1127 			dev_addr += size;
1128 	}
1129 	return (err);
1130 }
1131 
1132 
1133 int
1134 pci_fm_acc_setup(ddi_acc_hdl_t *hp, off_t offset, off_t len)
1135 {
1136 	ddi_acc_impl_t	*ap = (ddi_acc_impl_t *)hp->ah_platform_private;
1137 
1138 	/* endian-ness check */
1139 	if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC)
1140 		return (DDI_FAILURE);
1141 
1142 	/*
1143 	 * range check
1144 	 */
1145 	if ((offset >= PCI_CONF_HDR_SIZE) ||
1146 	    (len > PCI_CONF_HDR_SIZE) ||
1147 	    (offset + len > PCI_CONF_HDR_SIZE))
1148 		return (DDI_FAILURE);
1149 
1150 	ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE;
1151 	/*
1152 	 * always use cautious mechanism for config space gets
1153 	 */
1154 	ap->ahi_get8 = i_ddi_caut_get8;
1155 	ap->ahi_get16 = i_ddi_caut_get16;
1156 	ap->ahi_get32 = i_ddi_caut_get32;
1157 	ap->ahi_get64 = i_ddi_caut_get64;
1158 	ap->ahi_rep_get8 = i_ddi_caut_rep_get8;
1159 	ap->ahi_rep_get16 = i_ddi_caut_rep_get16;
1160 	ap->ahi_rep_get32 = i_ddi_caut_rep_get32;
1161 	ap->ahi_rep_get64 = i_ddi_caut_rep_get64;
1162 	if (hp->ah_acc.devacc_attr_access == DDI_CAUTIOUS_ACC) {
1163 		ap->ahi_put8 = i_ddi_caut_put8;
1164 		ap->ahi_put16 = i_ddi_caut_put16;
1165 		ap->ahi_put32 = i_ddi_caut_put32;
1166 		ap->ahi_put64 = i_ddi_caut_put64;
1167 		ap->ahi_rep_put8 = i_ddi_caut_rep_put8;
1168 		ap->ahi_rep_put16 = i_ddi_caut_rep_put16;
1169 		ap->ahi_rep_put32 = i_ddi_caut_rep_put32;
1170 		ap->ahi_rep_put64 = i_ddi_caut_rep_put64;
1171 	} else {
1172 		ap->ahi_put8 = pci_config_wr8;
1173 		ap->ahi_put16 = pci_config_wr16;
1174 		ap->ahi_put32 = pci_config_wr32;
1175 		ap->ahi_put64 = pci_config_wr64;
1176 		ap->ahi_rep_put8 = pci_config_rep_wr8;
1177 		ap->ahi_rep_put16 = pci_config_rep_wr16;
1178 		ap->ahi_rep_put32 = pci_config_rep_wr32;
1179 		ap->ahi_rep_put64 = pci_config_rep_wr64;
1180 	}
1181 
1182 	/* Initialize to default check/notify functions */
1183 	ap->ahi_fault_check = i_ddi_acc_fault_check;
1184 	ap->ahi_fault_notify = i_ddi_acc_fault_notify;
1185 	ap->ahi_fault = 0;
1186 	impl_acc_err_init(hp);
1187 	return (DDI_SUCCESS);
1188 }
1189 
1190 
1191 int
1192 pci_common_ctlops_peek(peekpoke_ctlops_t *in_args)
1193 {
1194 	size_t size = in_args->size;
1195 	uintptr_t dev_addr = in_args->dev_addr;
1196 	uintptr_t host_addr = in_args->host_addr;
1197 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
1198 	ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
1199 	size_t repcount = in_args->repcount;
1200 	uint_t flags = in_args->flags;
1201 	int err = DDI_SUCCESS;
1202 
1203 	/*
1204 	 * if no handle then this is a peek. We have to return failure here
1205 	 * as we have no way of knowing whether this is a MEM or IO space access
1206 	 */
1207 	if (in_args->handle == NULL)
1208 		return (DDI_FAILURE);
1209 
1210 	for (; repcount; repcount--) {
1211 		if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
1212 			switch (size) {
1213 			case sizeof (uint8_t):
1214 				*(uint8_t *)host_addr = pci_config_rd8(hp,
1215 				    (uint8_t *)dev_addr);
1216 				break;
1217 			case sizeof (uint16_t):
1218 				*(uint16_t *)host_addr = pci_config_rd16(hp,
1219 				    (uint16_t *)dev_addr);
1220 				break;
1221 			case sizeof (uint32_t):
1222 				*(uint32_t *)host_addr = pci_config_rd32(hp,
1223 				    (uint32_t *)dev_addr);
1224 				break;
1225 			case sizeof (uint64_t):
1226 				*(uint64_t *)host_addr = pci_config_rd64(hp,
1227 				    (uint64_t *)dev_addr);
1228 				break;
1229 			default:
1230 				err = DDI_FAILURE;
1231 				break;
1232 			}
1233 		} else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
1234 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
1235 			    DDI_STRUCTURE_BE_ACC) {
1236 				switch (size) {
1237 				case sizeof (uint8_t):
1238 					*(uint8_t *)host_addr =
1239 					    i_ddi_io_get8(hp,
1240 					    (uint8_t *)dev_addr);
1241 					break;
1242 				case sizeof (uint16_t):
1243 					*(uint16_t *)host_addr =
1244 					    i_ddi_io_swap_get16(hp,
1245 					    (uint16_t *)dev_addr);
1246 					break;
1247 				case sizeof (uint32_t):
1248 					*(uint32_t *)host_addr =
1249 					    i_ddi_io_swap_get32(hp,
1250 					    (uint32_t *)dev_addr);
1251 					break;
1252 				/*
1253 				 * note the 64-bit case is a dummy
1254 				 * function - so no need to swap
1255 				 */
1256 				case sizeof (uint64_t):
1257 					*(uint64_t *)host_addr =
1258 					    i_ddi_io_get64(hp,
1259 					    (uint64_t *)dev_addr);
1260 					break;
1261 				default:
1262 					err = DDI_FAILURE;
1263 					break;
1264 				}
1265 			} else {
1266 				switch (size) {
1267 				case sizeof (uint8_t):
1268 					*(uint8_t *)host_addr =
1269 					    i_ddi_io_get8(hp,
1270 					    (uint8_t *)dev_addr);
1271 					break;
1272 				case sizeof (uint16_t):
1273 					*(uint16_t *)host_addr =
1274 					    i_ddi_io_get16(hp,
1275 					    (uint16_t *)dev_addr);
1276 					break;
1277 				case sizeof (uint32_t):
1278 					*(uint32_t *)host_addr =
1279 					    i_ddi_io_get32(hp,
1280 					    (uint32_t *)dev_addr);
1281 					break;
1282 				case sizeof (uint64_t):
1283 					*(uint64_t *)host_addr =
1284 					    i_ddi_io_get64(hp,
1285 					    (uint64_t *)dev_addr);
1286 					break;
1287 				default:
1288 					err = DDI_FAILURE;
1289 					break;
1290 				}
1291 			}
1292 		} else {
1293 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
1294 			    DDI_STRUCTURE_BE_ACC) {
1295 				switch (in_args->size) {
1296 				case sizeof (uint8_t):
1297 					*(uint8_t *)host_addr =
1298 					    *(uint8_t *)dev_addr;
1299 					break;
1300 				case sizeof (uint16_t):
1301 					*(uint16_t *)host_addr =
1302 					    ddi_swap16(*(uint16_t *)dev_addr);
1303 					break;
1304 				case sizeof (uint32_t):
1305 					*(uint32_t *)host_addr =
1306 					    ddi_swap32(*(uint32_t *)dev_addr);
1307 					break;
1308 				case sizeof (uint64_t):
1309 					*(uint64_t *)host_addr =
1310 					    ddi_swap64(*(uint64_t *)dev_addr);
1311 					break;
1312 				default:
1313 					err = DDI_FAILURE;
1314 					break;
1315 				}
1316 			} else {
1317 				switch (in_args->size) {
1318 				case sizeof (uint8_t):
1319 					*(uint8_t *)host_addr =
1320 					    *(uint8_t *)dev_addr;
1321 					break;
1322 				case sizeof (uint16_t):
1323 					*(uint16_t *)host_addr =
1324 					    *(uint16_t *)dev_addr;
1325 					break;
1326 				case sizeof (uint32_t):
1327 					*(uint32_t *)host_addr =
1328 					    *(uint32_t *)dev_addr;
1329 					break;
1330 				case sizeof (uint64_t):
1331 					*(uint64_t *)host_addr =
1332 					    *(uint64_t *)dev_addr;
1333 					break;
1334 				default:
1335 					err = DDI_FAILURE;
1336 					break;
1337 				}
1338 			}
1339 		}
1340 		host_addr += size;
1341 		if (flags == DDI_DEV_AUTOINCR)
1342 			dev_addr += size;
1343 	}
1344 	return (err);
1345 }
1346 
1347 /*ARGSUSED*/
1348 int
1349 pci_common_peekpoke(dev_info_t *dip, dev_info_t *rdip,
1350 	ddi_ctl_enum_t ctlop, void *arg, void *result)
1351 {
1352 	if (ctlop == DDI_CTLOPS_PEEK)
1353 		return (pci_common_ctlops_peek((peekpoke_ctlops_t *)arg));
1354 	else
1355 		return (pci_common_ctlops_poke((peekpoke_ctlops_t *)arg));
1356 }
1357 
1358 /*
1359  * These are the get and put functions to be shared with drivers. The
1360  * mutex locking is done inside the functions referenced, rather than
1361  * here, and is thus shared across PCI child drivers and any other
1362  * consumers of PCI config space (such as the ACPI subsystem).
1363  *
1364  * The configuration space addresses come in as pointers.  This is fine on
1365  * a 32-bit system, where the VM space and configuration space are the same
1366  * size.  It's not such a good idea on a 64-bit system, where memory
1367  * addresses are twice as large as configuration space addresses.  At some
1368  * point in the call tree we need to take a stand and say "you are 32-bit
1369  * from this time forth", and this seems like a nice self-contained place.
1370  */
1371 
1372 uint8_t
1373 pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr)
1374 {
1375 	pci_acc_cfblk_t *cfp;
1376 	uint8_t	rval;
1377 	int reg;
1378 
1379 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1380 
1381 	reg = (int)(uintptr_t)addr;
1382 
1383 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1384 
1385 	rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
1386 	    reg);
1387 
1388 	return (rval);
1389 }
1390 
1391 void
1392 pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
1393 	uint8_t *dev_addr, size_t repcount, uint_t flags)
1394 {
1395 	uint8_t *h, *d;
1396 
1397 	h = host_addr;
1398 	d = dev_addr;
1399 
1400 	if (flags == DDI_DEV_AUTOINCR)
1401 		for (; repcount; repcount--)
1402 			*h++ = pci_config_rd8(hdlp, d++);
1403 	else
1404 		for (; repcount; repcount--)
1405 			*h++ = pci_config_rd8(hdlp, d);
1406 }
1407 
1408 uint16_t
1409 pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr)
1410 {
1411 	pci_acc_cfblk_t *cfp;
1412 	uint16_t rval;
1413 	int reg;
1414 
1415 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1416 
1417 	reg = (int)(uintptr_t)addr;
1418 
1419 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1420 
1421 	rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
1422 	    reg);
1423 
1424 	return (rval);
1425 }
1426 
1427 void
1428 pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
1429 	uint16_t *dev_addr, size_t repcount, uint_t flags)
1430 {
1431 	uint16_t *h, *d;
1432 
1433 	h = host_addr;
1434 	d = dev_addr;
1435 
1436 	if (flags == DDI_DEV_AUTOINCR)
1437 		for (; repcount; repcount--)
1438 			*h++ = pci_config_rd16(hdlp, d++);
1439 	else
1440 		for (; repcount; repcount--)
1441 			*h++ = pci_config_rd16(hdlp, d);
1442 }
1443 
1444 uint32_t
1445 pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr)
1446 {
1447 	pci_acc_cfblk_t *cfp;
1448 	uint32_t rval;
1449 	int reg;
1450 
1451 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1452 
1453 	reg = (int)(uintptr_t)addr;
1454 
1455 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1456 
1457 	rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum,
1458 	    cfp->c_funcnum, reg);
1459 
1460 	return (rval);
1461 }
1462 
1463 void
1464 pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
1465 	uint32_t *dev_addr, size_t repcount, uint_t flags)
1466 {
1467 	uint32_t *h, *d;
1468 
1469 	h = host_addr;
1470 	d = dev_addr;
1471 
1472 	if (flags == DDI_DEV_AUTOINCR)
1473 		for (; repcount; repcount--)
1474 			*h++ = pci_config_rd32(hdlp, d++);
1475 	else
1476 		for (; repcount; repcount--)
1477 			*h++ = pci_config_rd32(hdlp, d);
1478 }
1479 
1480 
1481 void
1482 pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value)
1483 {
1484 	pci_acc_cfblk_t *cfp;
1485 	int reg;
1486 
1487 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1488 
1489 	reg = (int)(uintptr_t)addr;
1490 
1491 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1492 
1493 	(*pci_putb_func)(cfp->c_busnum, cfp->c_devnum,
1494 	    cfp->c_funcnum, reg, value);
1495 }
1496 
1497 void
1498 pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
1499 	uint8_t *dev_addr, size_t repcount, uint_t flags)
1500 {
1501 	uint8_t *h, *d;
1502 
1503 	h = host_addr;
1504 	d = dev_addr;
1505 
1506 	if (flags == DDI_DEV_AUTOINCR)
1507 		for (; repcount; repcount--)
1508 			pci_config_wr8(hdlp, d++, *h++);
1509 	else
1510 		for (; repcount; repcount--)
1511 			pci_config_wr8(hdlp, d, *h++);
1512 }
1513 
1514 void
1515 pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value)
1516 {
1517 	pci_acc_cfblk_t *cfp;
1518 	int reg;
1519 
1520 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1521 
1522 	reg = (int)(uintptr_t)addr;
1523 
1524 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1525 
1526 	(*pci_putw_func)(cfp->c_busnum, cfp->c_devnum,
1527 	    cfp->c_funcnum, reg, value);
1528 }
1529 
1530 void
1531 pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
1532 	uint16_t *dev_addr, size_t repcount, uint_t flags)
1533 {
1534 	uint16_t *h, *d;
1535 
1536 	h = host_addr;
1537 	d = dev_addr;
1538 
1539 	if (flags == DDI_DEV_AUTOINCR)
1540 		for (; repcount; repcount--)
1541 			pci_config_wr16(hdlp, d++, *h++);
1542 	else
1543 		for (; repcount; repcount--)
1544 			pci_config_wr16(hdlp, d, *h++);
1545 }
1546 
1547 void
1548 pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value)
1549 {
1550 	pci_acc_cfblk_t *cfp;
1551 	int reg;
1552 
1553 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1554 
1555 	reg = (int)(uintptr_t)addr;
1556 
1557 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1558 
1559 	(*pci_putl_func)(cfp->c_busnum, cfp->c_devnum,
1560 	    cfp->c_funcnum, reg, value);
1561 }
1562 
1563 void
1564 pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
1565 	uint32_t *dev_addr, size_t repcount, uint_t flags)
1566 {
1567 	uint32_t *h, *d;
1568 
1569 	h = host_addr;
1570 	d = dev_addr;
1571 
1572 	if (flags == DDI_DEV_AUTOINCR)
1573 		for (; repcount; repcount--)
1574 			pci_config_wr32(hdlp, d++, *h++);
1575 	else
1576 		for (; repcount; repcount--)
1577 			pci_config_wr32(hdlp, d, *h++);
1578 }
1579 
1580 uint64_t
1581 pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr)
1582 {
1583 	uint32_t lw_val;
1584 	uint32_t hi_val;
1585 	uint32_t *dp;
1586 	uint64_t val;
1587 
1588 	dp = (uint32_t *)addr;
1589 	lw_val = pci_config_rd32(hdlp, dp);
1590 	dp++;
1591 	hi_val = pci_config_rd32(hdlp, dp);
1592 	val = ((uint64_t)hi_val << 32) | lw_val;
1593 	return (val);
1594 }
1595 
1596 void
1597 pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value)
1598 {
1599 	uint32_t lw_val;
1600 	uint32_t hi_val;
1601 	uint32_t *dp;
1602 
1603 	dp = (uint32_t *)addr;
1604 	lw_val = (uint32_t)(value & 0xffffffff);
1605 	hi_val = (uint32_t)(value >> 32);
1606 	pci_config_wr32(hdlp, dp, lw_val);
1607 	dp++;
1608 	pci_config_wr32(hdlp, dp, hi_val);
1609 }
1610 
1611 void
1612 pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
1613 	uint64_t *dev_addr, size_t repcount, uint_t flags)
1614 {
1615 	if (flags == DDI_DEV_AUTOINCR) {
1616 		for (; repcount; repcount--)
1617 			*host_addr++ = pci_config_rd64(hdlp, dev_addr++);
1618 	} else {
1619 		for (; repcount; repcount--)
1620 			*host_addr++ = pci_config_rd64(hdlp, dev_addr);
1621 	}
1622 }
1623 
1624 void
1625 pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
1626 	uint64_t *dev_addr, size_t repcount, uint_t flags)
1627 {
1628 	if (flags == DDI_DEV_AUTOINCR) {
1629 		for (; repcount; repcount--)
1630 			pci_config_wr64(hdlp, host_addr++, *dev_addr++);
1631 	} else {
1632 		for (; repcount; repcount--)
1633 			pci_config_wr64(hdlp, host_addr++, *dev_addr);
1634 	}
1635 }
1636