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