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