xref: /titanic_50/usr/src/uts/i86pc/io/pci/pci_common.c (revision 2449e17f82f6097fd2c665b64723e31ceecbeca6)
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 *)
585 					    h_array[j];
586 					pci_disable_intr(pdip, rdip, hdlp,
587 					    hdlp->ih_inum);
588 				}
589 				return (DDI_FAILURE);
590 			}
591 			DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
592 			    "BLOCKENABLE inum %x done\n", hdlp->ih_inum));
593 		}
594 		break;
595 	case DDI_INTROP_BLOCKDISABLE:
596 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
597 		    "BLOCKDISABLE\n"));
598 		if (hdlp->ih_type != DDI_INTR_TYPE_MSI) {
599 			DDI_INTR_NEXDBG((CE_CONT, "BLOCKDISABLE: not MSI\n"));
600 			return (DDI_FAILURE);
601 		}
602 
603 		/* Check if psm_intr_ops is present */
604 		if (psm_intr_ops == NULL)
605 			return (DDI_FAILURE);
606 
607 		count = hdlp->ih_scratch1;
608 		h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2;
609 		for (i = 0; i < count; i++) {
610 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
611 			pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum);
612 			DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
613 			    "BLOCKDISABLE inum %x done\n", hdlp->ih_inum));
614 		}
615 		break;
616 	case DDI_INTROP_SETMASK:
617 	case DDI_INTROP_CLRMASK:
618 		/*
619 		 * First handle in the config space
620 		 */
621 		if (intr_op == DDI_INTROP_SETMASK) {
622 			if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
623 				pci_status = pci_msi_set_mask(rdip,
624 				    hdlp->ih_type, hdlp->ih_inum);
625 			else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
626 				pci_status = pci_intx_set_mask(rdip);
627 		} else {
628 			if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
629 				pci_status = pci_msi_clr_mask(rdip,
630 				    hdlp->ih_type, hdlp->ih_inum);
631 			else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
632 				pci_status = pci_intx_clr_mask(rdip);
633 		}
634 
635 		/* For MSI/X; no need to check with pcplusmp */
636 		if (hdlp->ih_type != DDI_INTR_TYPE_FIXED)
637 			return (pci_status);
638 
639 		/* For fixed interrupts only: handle config space first */
640 		if (hdlp->ih_type == DDI_INTR_TYPE_FIXED &&
641 		    pci_status == DDI_SUCCESS)
642 			break;
643 
644 		/* For fixed interrupts only: confer with pcplusmp next */
645 		if (psm_intr_ops != NULL) {
646 			/* If interrupt is shared; do nothing */
647 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
648 			    PSM_INTR_OP_GET_SHARED, &psm_status);
649 
650 			if (psm_rval == PSM_FAILURE || psm_status == 1)
651 				return (pci_status);
652 
653 			/* Now, pcplusmp should try to set/clear the mask */
654 			if (intr_op == DDI_INTROP_SETMASK)
655 				psm_rval = (*psm_intr_ops)(rdip, hdlp,
656 				    PSM_INTR_OP_SET_MASK, NULL);
657 			else
658 				psm_rval = (*psm_intr_ops)(rdip, hdlp,
659 				    PSM_INTR_OP_CLEAR_MASK, NULL);
660 		}
661 		return ((psm_rval == PSM_FAILURE) ? DDI_FAILURE : DDI_SUCCESS);
662 	case DDI_INTROP_GETPENDING:
663 		/*
664 		 * First check the config space and/or
665 		 * MSI capability register(s)
666 		 */
667 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
668 			pci_rval = pci_msi_get_pending(rdip, hdlp->ih_type,
669 			    hdlp->ih_inum, &pci_status);
670 		else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
671 			pci_rval = pci_intx_get_pending(rdip, &pci_status);
672 
673 		/* On failure; next try with pcplusmp */
674 		if (pci_rval != DDI_SUCCESS && psm_intr_ops != NULL)
675 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
676 			    PSM_INTR_OP_GET_PENDING, &psm_status);
677 
678 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned "
679 		    "psm_rval = %x, psm_status = %x, pci_rval = %x, "
680 		    "pci_status = %x\n", psm_rval, psm_status, pci_rval,
681 		    pci_status));
682 		if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) {
683 			*(int *)result = 0;
684 			return (DDI_FAILURE);
685 		}
686 
687 		if (psm_rval != PSM_FAILURE)
688 			*(int *)result = psm_status;
689 		else if (pci_rval != DDI_FAILURE)
690 			*(int *)result = pci_status;
691 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned = %x\n",
692 		    *(int *)result));
693 		break;
694 	default:
695 		return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result));
696 	}
697 
698 	return (DDI_SUCCESS);
699 }
700 
701 int
702 pci_get_intr_from_vecirq(apic_get_intr_t *intrinfo_p,
703     int vecirq, boolean_t is_irq)
704 {
705 	ddi_intr_handle_impl_t	get_info_ii_hdl;
706 
707 	if (is_irq)
708 		intrinfo_p->avgi_req_flags |= PSMGI_INTRBY_IRQ;
709 
710 	/*
711 	 * For this locally-declared and used handle, ih_private will contain a
712 	 * pointer to apic_get_intr_t, not an ihdl_plat_t as used for
713 	 * global interrupt handling.
714 	 */
715 	get_info_ii_hdl.ih_private = intrinfo_p;
716 	get_info_ii_hdl.ih_vector = (ushort_t)vecirq;
717 
718 	if ((*psm_intr_ops)(NULL, &get_info_ii_hdl,
719 	    PSM_INTR_OP_GET_INTR, NULL) == PSM_FAILURE)
720 		return (DDI_FAILURE);
721 
722 	return (DDI_SUCCESS);
723 }
724 
725 
726 int
727 pci_get_cpu_from_vecirq(int vecirq, boolean_t is_irq)
728 {
729 	int rval;
730 
731 	apic_get_intr_t	intrinfo;
732 	intrinfo.avgi_req_flags = PSMGI_REQ_CPUID;
733 	rval = pci_get_intr_from_vecirq(&intrinfo, vecirq, is_irq);
734 
735 	if (rval == DDI_SUCCESS)
736 		return (intrinfo.avgi_cpu_id);
737 	else
738 		return (-1);
739 }
740 
741 
742 static int
743 pci_enable_intr(dev_info_t *pdip, dev_info_t *rdip,
744     ddi_intr_handle_impl_t *hdlp, uint32_t inum)
745 {
746 	struct intrspec	*ispec;
747 	int		irq;
748 	ihdl_plat_t	*ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
749 
750 	DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: hdlp %p inum %x\n",
751 	    (void *)hdlp, inum));
752 
753 	/* Translate the interrupt if needed */
754 	ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
755 	if (ispec == NULL)
756 		return (DDI_FAILURE);
757 	if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
758 		ispec->intrspec_vec = inum;
759 	ihdl_plat_datap->ip_ispecp = ispec;
760 
761 	/* translate the interrupt if needed */
762 	(void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq);
763 	DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: priority=%x irq=%x\n",
764 	    hdlp->ih_pri, irq));
765 
766 	/* Add the interrupt handler */
767 	if (!add_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func,
768 	    DEVI(rdip)->devi_name, irq, hdlp->ih_cb_arg1,
769 	    hdlp->ih_cb_arg2, &ihdl_plat_datap->ip_ticks, rdip))
770 		return (DDI_FAILURE);
771 
772 	/* Note this really is an irq. */
773 	hdlp->ih_vector = (ushort_t)irq;
774 
775 	return (DDI_SUCCESS);
776 }
777 
778 
779 static void
780 pci_disable_intr(dev_info_t *pdip, dev_info_t *rdip,
781     ddi_intr_handle_impl_t *hdlp, uint32_t inum)
782 {
783 	int		irq;
784 	struct intrspec	*ispec;
785 	ihdl_plat_t	*ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
786 
787 	DDI_INTR_NEXDBG((CE_CONT, "pci_disable_intr: \n"));
788 	ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
789 	if (ispec == NULL)
790 		return;
791 	if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
792 		ispec->intrspec_vec = inum;
793 	ihdl_plat_datap->ip_ispecp = ispec;
794 
795 	/* translate the interrupt if needed */
796 	(void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq);
797 
798 	/* Disable the interrupt handler */
799 	rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, irq);
800 	ihdl_plat_datap->ip_ispecp = NULL;
801 }
802 
803 /*
804  * Miscellaneous library function
805  */
806 int
807 pci_common_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp)
808 {
809 	int		i;
810 	int 		number;
811 	int		assigned_addr_len;
812 	uint_t		phys_hi = pci_rp->pci_phys_hi;
813 	pci_regspec_t	*assigned_addr;
814 
815 	if (((phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) ||
816 	    (phys_hi & PCI_RELOCAT_B))
817 		return (DDI_SUCCESS);
818 
819 	/*
820 	 * the "reg" property specifies relocatable, get and interpret the
821 	 * "assigned-addresses" property.
822 	 */
823 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
824 	    "assigned-addresses", (int **)&assigned_addr,
825 	    (uint_t *)&assigned_addr_len) != DDI_PROP_SUCCESS)
826 		return (DDI_FAILURE);
827 
828 	/*
829 	 * Scan the "assigned-addresses" for one that matches the specified
830 	 * "reg" property entry.
831 	 */
832 	phys_hi &= PCI_CONF_ADDR_MASK;
833 	number = assigned_addr_len / (sizeof (pci_regspec_t) / sizeof (int));
834 	for (i = 0; i < number; i++) {
835 		if ((assigned_addr[i].pci_phys_hi & PCI_CONF_ADDR_MASK) ==
836 		    phys_hi) {
837 			pci_rp->pci_phys_mid = assigned_addr[i].pci_phys_mid;
838 			pci_rp->pci_phys_low = assigned_addr[i].pci_phys_low;
839 			ddi_prop_free(assigned_addr);
840 			return (DDI_SUCCESS);
841 		}
842 	}
843 
844 	ddi_prop_free(assigned_addr);
845 	return (DDI_FAILURE);
846 }
847 
848 
849 /*
850  * For pci_tools
851  */
852 
853 int
854 pci_common_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg,
855     int mode, cred_t *credp, int *rvalp)
856 {
857 	int rv = ENOTTY;
858 
859 	minor_t minor = getminor(dev);
860 
861 	switch (PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
862 	case PCI_TOOL_REG_MINOR_NUM:
863 
864 		switch (cmd) {
865 		case PCITOOL_DEVICE_SET_REG:
866 		case PCITOOL_DEVICE_GET_REG:
867 
868 			/* Require full privileges. */
869 			if (secpolicy_kmdb(credp))
870 				rv = EPERM;
871 			else
872 				rv = pcitool_dev_reg_ops(dip, (void *)arg,
873 				    cmd, mode);
874 			break;
875 
876 		case PCITOOL_NEXUS_SET_REG:
877 		case PCITOOL_NEXUS_GET_REG:
878 
879 			/* Require full privileges. */
880 			if (secpolicy_kmdb(credp))
881 				rv = EPERM;
882 			else
883 				rv = pcitool_bus_reg_ops(dip, (void *)arg,
884 				    cmd, mode);
885 			break;
886 		}
887 		break;
888 
889 	case PCI_TOOL_INTR_MINOR_NUM:
890 
891 		switch (cmd) {
892 		case PCITOOL_DEVICE_SET_INTR:
893 
894 			/* Require PRIV_SYS_RES_CONFIG, same as psradm */
895 			if (secpolicy_ponline(credp)) {
896 				rv = EPERM;
897 				break;
898 			}
899 
900 		/*FALLTHRU*/
901 		/* These require no special privileges. */
902 		case PCITOOL_DEVICE_GET_INTR:
903 		case PCITOOL_SYSTEM_INTR_INFO:
904 			rv = pcitool_intr_admn(dip, (void *)arg, cmd, mode);
905 			break;
906 		}
907 		break;
908 
909 	/*
910 	 * All non-PCItool ioctls go through here, including:
911 	 *   devctl ioctls with minor number PCIHP_DEVCTL_MINOR and
912 	 *   those for attachment points with where minor number is the
913 	 *   device number.
914 	 */
915 	default:
916 		rv = (pcihp_get_cb_ops())->cb_ioctl(dev, cmd, arg, mode,
917 		    credp, rvalp);
918 		break;
919 	}
920 
921 	return (rv);
922 }
923 
924 
925 int
926 pci_common_ctlops_poke(peekpoke_ctlops_t *in_args)
927 {
928 	size_t size = in_args->size;
929 	uintptr_t dev_addr = in_args->dev_addr;
930 	uintptr_t host_addr = in_args->host_addr;
931 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
932 	ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
933 	size_t repcount = in_args->repcount;
934 	uint_t flags = in_args->flags;
935 	int err = DDI_SUCCESS;
936 
937 	/*
938 	 * if no handle then this is a poke. We have to return failure here
939 	 * as we have no way of knowing whether this is a MEM or IO space access
940 	 */
941 	if (in_args->handle == NULL)
942 		return (DDI_FAILURE);
943 
944 	/*
945 	 * rest of this function is actually for cautious puts
946 	 */
947 	for (; repcount; repcount--) {
948 		if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
949 			switch (size) {
950 			case sizeof (uint8_t):
951 				pci_config_wr8(hp, (uint8_t *)dev_addr,
952 				    *(uint8_t *)host_addr);
953 				break;
954 			case sizeof (uint16_t):
955 				pci_config_wr16(hp, (uint16_t *)dev_addr,
956 				    *(uint16_t *)host_addr);
957 				break;
958 			case sizeof (uint32_t):
959 				pci_config_wr32(hp, (uint32_t *)dev_addr,
960 				    *(uint32_t *)host_addr);
961 				break;
962 			case sizeof (uint64_t):
963 				pci_config_wr64(hp, (uint64_t *)dev_addr,
964 				    *(uint64_t *)host_addr);
965 				break;
966 			default:
967 				err = DDI_FAILURE;
968 				break;
969 			}
970 		} else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
971 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
972 			    DDI_STRUCTURE_BE_ACC) {
973 				switch (size) {
974 				case sizeof (uint8_t):
975 					i_ddi_io_put8(hp,
976 					    (uint8_t *)dev_addr,
977 					    *(uint8_t *)host_addr);
978 					break;
979 				case sizeof (uint16_t):
980 					i_ddi_io_swap_put16(hp,
981 					    (uint16_t *)dev_addr,
982 					    *(uint16_t *)host_addr);
983 					break;
984 				case sizeof (uint32_t):
985 					i_ddi_io_swap_put32(hp,
986 					    (uint32_t *)dev_addr,
987 					    *(uint32_t *)host_addr);
988 					break;
989 				/*
990 				 * note the 64-bit case is a dummy
991 				 * function - so no need to swap
992 				 */
993 				case sizeof (uint64_t):
994 					i_ddi_io_put64(hp,
995 					    (uint64_t *)dev_addr,
996 					    *(uint64_t *)host_addr);
997 					break;
998 				default:
999 					err = DDI_FAILURE;
1000 					break;
1001 				}
1002 			} else {
1003 				switch (size) {
1004 				case sizeof (uint8_t):
1005 					i_ddi_io_put8(hp,
1006 					    (uint8_t *)dev_addr,
1007 					    *(uint8_t *)host_addr);
1008 					break;
1009 				case sizeof (uint16_t):
1010 					i_ddi_io_put16(hp,
1011 					    (uint16_t *)dev_addr,
1012 					    *(uint16_t *)host_addr);
1013 					break;
1014 				case sizeof (uint32_t):
1015 					i_ddi_io_put32(hp,
1016 					    (uint32_t *)dev_addr,
1017 					    *(uint32_t *)host_addr);
1018 					break;
1019 				case sizeof (uint64_t):
1020 					i_ddi_io_put64(hp,
1021 					    (uint64_t *)dev_addr,
1022 					    *(uint64_t *)host_addr);
1023 					break;
1024 				default:
1025 					err = DDI_FAILURE;
1026 					break;
1027 				}
1028 			}
1029 		} else {
1030 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
1031 			    DDI_STRUCTURE_BE_ACC) {
1032 				switch (size) {
1033 				case sizeof (uint8_t):
1034 					*(uint8_t *)dev_addr =
1035 					    *(uint8_t *)host_addr;
1036 					break;
1037 				case sizeof (uint16_t):
1038 					*(uint16_t *)dev_addr =
1039 					    ddi_swap16(*(uint16_t *)host_addr);
1040 					break;
1041 				case sizeof (uint32_t):
1042 					*(uint32_t *)dev_addr =
1043 					    ddi_swap32(*(uint32_t *)host_addr);
1044 					break;
1045 				case sizeof (uint64_t):
1046 					*(uint64_t *)dev_addr =
1047 					    ddi_swap64(*(uint64_t *)host_addr);
1048 					break;
1049 				default:
1050 					err = DDI_FAILURE;
1051 					break;
1052 				}
1053 			} else {
1054 				switch (size) {
1055 				case sizeof (uint8_t):
1056 					*(uint8_t *)dev_addr =
1057 					    *(uint8_t *)host_addr;
1058 					break;
1059 				case sizeof (uint16_t):
1060 					*(uint16_t *)dev_addr =
1061 					    *(uint16_t *)host_addr;
1062 					break;
1063 				case sizeof (uint32_t):
1064 					*(uint32_t *)dev_addr =
1065 					    *(uint32_t *)host_addr;
1066 					break;
1067 				case sizeof (uint64_t):
1068 					*(uint64_t *)dev_addr =
1069 					    *(uint64_t *)host_addr;
1070 					break;
1071 				default:
1072 					err = DDI_FAILURE;
1073 					break;
1074 				}
1075 			}
1076 		}
1077 		host_addr += size;
1078 		if (flags == DDI_DEV_AUTOINCR)
1079 			dev_addr += size;
1080 	}
1081 	return (err);
1082 }
1083 
1084 
1085 int
1086 pci_fm_acc_setup(ddi_acc_hdl_t *hp, off_t offset, off_t len)
1087 {
1088 	ddi_acc_impl_t	*ap = (ddi_acc_impl_t *)hp->ah_platform_private;
1089 
1090 	/* endian-ness check */
1091 	if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC)
1092 		return (DDI_FAILURE);
1093 
1094 	/*
1095 	 * range check
1096 	 */
1097 	if ((offset >= PCI_CONF_HDR_SIZE) ||
1098 	    (len > PCI_CONF_HDR_SIZE) ||
1099 	    (offset + len > PCI_CONF_HDR_SIZE))
1100 		return (DDI_FAILURE);
1101 
1102 	ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE;
1103 	/*
1104 	 * always use cautious mechanism for config space gets
1105 	 */
1106 	ap->ahi_get8 = i_ddi_caut_get8;
1107 	ap->ahi_get16 = i_ddi_caut_get16;
1108 	ap->ahi_get32 = i_ddi_caut_get32;
1109 	ap->ahi_get64 = i_ddi_caut_get64;
1110 	ap->ahi_rep_get8 = i_ddi_caut_rep_get8;
1111 	ap->ahi_rep_get16 = i_ddi_caut_rep_get16;
1112 	ap->ahi_rep_get32 = i_ddi_caut_rep_get32;
1113 	ap->ahi_rep_get64 = i_ddi_caut_rep_get64;
1114 	if (hp->ah_acc.devacc_attr_access == DDI_CAUTIOUS_ACC) {
1115 		ap->ahi_put8 = i_ddi_caut_put8;
1116 		ap->ahi_put16 = i_ddi_caut_put16;
1117 		ap->ahi_put32 = i_ddi_caut_put32;
1118 		ap->ahi_put64 = i_ddi_caut_put64;
1119 		ap->ahi_rep_put8 = i_ddi_caut_rep_put8;
1120 		ap->ahi_rep_put16 = i_ddi_caut_rep_put16;
1121 		ap->ahi_rep_put32 = i_ddi_caut_rep_put32;
1122 		ap->ahi_rep_put64 = i_ddi_caut_rep_put64;
1123 	} else {
1124 		ap->ahi_put8 = pci_config_wr8;
1125 		ap->ahi_put16 = pci_config_wr16;
1126 		ap->ahi_put32 = pci_config_wr32;
1127 		ap->ahi_put64 = pci_config_wr64;
1128 		ap->ahi_rep_put8 = pci_config_rep_wr8;
1129 		ap->ahi_rep_put16 = pci_config_rep_wr16;
1130 		ap->ahi_rep_put32 = pci_config_rep_wr32;
1131 		ap->ahi_rep_put64 = pci_config_rep_wr64;
1132 	}
1133 
1134 	/* Initialize to default check/notify functions */
1135 	ap->ahi_fault_check = i_ddi_acc_fault_check;
1136 	ap->ahi_fault_notify = i_ddi_acc_fault_notify;
1137 	ap->ahi_fault = 0;
1138 	impl_acc_err_init(hp);
1139 	return (DDI_SUCCESS);
1140 }
1141 
1142 
1143 int
1144 pci_common_ctlops_peek(peekpoke_ctlops_t *in_args)
1145 {
1146 	size_t size = in_args->size;
1147 	uintptr_t dev_addr = in_args->dev_addr;
1148 	uintptr_t host_addr = in_args->host_addr;
1149 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
1150 	ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
1151 	size_t repcount = in_args->repcount;
1152 	uint_t flags = in_args->flags;
1153 	int err = DDI_SUCCESS;
1154 
1155 	/*
1156 	 * if no handle then this is a peek. We have to return failure here
1157 	 * as we have no way of knowing whether this is a MEM or IO space access
1158 	 */
1159 	if (in_args->handle == NULL)
1160 		return (DDI_FAILURE);
1161 
1162 	for (; repcount; repcount--) {
1163 		if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
1164 			switch (size) {
1165 			case sizeof (uint8_t):
1166 				*(uint8_t *)host_addr = pci_config_rd8(hp,
1167 				    (uint8_t *)dev_addr);
1168 				break;
1169 			case sizeof (uint16_t):
1170 				*(uint16_t *)host_addr = pci_config_rd16(hp,
1171 				    (uint16_t *)dev_addr);
1172 				break;
1173 			case sizeof (uint32_t):
1174 				*(uint32_t *)host_addr = pci_config_rd32(hp,
1175 				    (uint32_t *)dev_addr);
1176 				break;
1177 			case sizeof (uint64_t):
1178 				*(uint64_t *)host_addr = pci_config_rd64(hp,
1179 				    (uint64_t *)dev_addr);
1180 				break;
1181 			default:
1182 				err = DDI_FAILURE;
1183 				break;
1184 			}
1185 		} else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
1186 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
1187 			    DDI_STRUCTURE_BE_ACC) {
1188 				switch (size) {
1189 				case sizeof (uint8_t):
1190 					*(uint8_t *)host_addr =
1191 					    i_ddi_io_get8(hp,
1192 					    (uint8_t *)dev_addr);
1193 					break;
1194 				case sizeof (uint16_t):
1195 					*(uint16_t *)host_addr =
1196 					    i_ddi_io_swap_get16(hp,
1197 					    (uint16_t *)dev_addr);
1198 					break;
1199 				case sizeof (uint32_t):
1200 					*(uint32_t *)host_addr =
1201 					    i_ddi_io_swap_get32(hp,
1202 					    (uint32_t *)dev_addr);
1203 					break;
1204 				/*
1205 				 * note the 64-bit case is a dummy
1206 				 * function - so no need to swap
1207 				 */
1208 				case sizeof (uint64_t):
1209 					*(uint64_t *)host_addr =
1210 					    i_ddi_io_get64(hp,
1211 					    (uint64_t *)dev_addr);
1212 					break;
1213 				default:
1214 					err = DDI_FAILURE;
1215 					break;
1216 				}
1217 			} else {
1218 				switch (size) {
1219 				case sizeof (uint8_t):
1220 					*(uint8_t *)host_addr =
1221 					    i_ddi_io_get8(hp,
1222 					    (uint8_t *)dev_addr);
1223 					break;
1224 				case sizeof (uint16_t):
1225 					*(uint16_t *)host_addr =
1226 					    i_ddi_io_get16(hp,
1227 					    (uint16_t *)dev_addr);
1228 					break;
1229 				case sizeof (uint32_t):
1230 					*(uint32_t *)host_addr =
1231 					    i_ddi_io_get32(hp,
1232 					    (uint32_t *)dev_addr);
1233 					break;
1234 				case sizeof (uint64_t):
1235 					*(uint64_t *)host_addr =
1236 					    i_ddi_io_get64(hp,
1237 					    (uint64_t *)dev_addr);
1238 					break;
1239 				default:
1240 					err = DDI_FAILURE;
1241 					break;
1242 				}
1243 			}
1244 		} else {
1245 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
1246 			    DDI_STRUCTURE_BE_ACC) {
1247 				switch (in_args->size) {
1248 				case sizeof (uint8_t):
1249 					*(uint8_t *)host_addr =
1250 					    *(uint8_t *)dev_addr;
1251 					break;
1252 				case sizeof (uint16_t):
1253 					*(uint16_t *)host_addr =
1254 					    ddi_swap16(*(uint16_t *)dev_addr);
1255 					break;
1256 				case sizeof (uint32_t):
1257 					*(uint32_t *)host_addr =
1258 					    ddi_swap32(*(uint32_t *)dev_addr);
1259 					break;
1260 				case sizeof (uint64_t):
1261 					*(uint64_t *)host_addr =
1262 					    ddi_swap64(*(uint64_t *)dev_addr);
1263 					break;
1264 				default:
1265 					err = DDI_FAILURE;
1266 					break;
1267 				}
1268 			} else {
1269 				switch (in_args->size) {
1270 				case sizeof (uint8_t):
1271 					*(uint8_t *)host_addr =
1272 					    *(uint8_t *)dev_addr;
1273 					break;
1274 				case sizeof (uint16_t):
1275 					*(uint16_t *)host_addr =
1276 					    *(uint16_t *)dev_addr;
1277 					break;
1278 				case sizeof (uint32_t):
1279 					*(uint32_t *)host_addr =
1280 					    *(uint32_t *)dev_addr;
1281 					break;
1282 				case sizeof (uint64_t):
1283 					*(uint64_t *)host_addr =
1284 					    *(uint64_t *)dev_addr;
1285 					break;
1286 				default:
1287 					err = DDI_FAILURE;
1288 					break;
1289 				}
1290 			}
1291 		}
1292 		host_addr += size;
1293 		if (flags == DDI_DEV_AUTOINCR)
1294 			dev_addr += size;
1295 	}
1296 	return (err);
1297 }
1298 
1299 /*ARGSUSED*/
1300 int
1301 pci_common_peekpoke(dev_info_t *dip, dev_info_t *rdip,
1302 	ddi_ctl_enum_t ctlop, void *arg, void *result)
1303 {
1304 	if (ctlop == DDI_CTLOPS_PEEK)
1305 		return (pci_common_ctlops_peek((peekpoke_ctlops_t *)arg));
1306 	else
1307 		return (pci_common_ctlops_poke((peekpoke_ctlops_t *)arg));
1308 }
1309 
1310 /*
1311  * These are the get and put functions to be shared with drivers. The
1312  * mutex locking is done inside the functions referenced, rather than
1313  * here, and is thus shared across PCI child drivers and any other
1314  * consumers of PCI config space (such as the ACPI subsystem).
1315  *
1316  * The configuration space addresses come in as pointers.  This is fine on
1317  * a 32-bit system, where the VM space and configuration space are the same
1318  * size.  It's not such a good idea on a 64-bit system, where memory
1319  * addresses are twice as large as configuration space addresses.  At some
1320  * point in the call tree we need to take a stand and say "you are 32-bit
1321  * from this time forth", and this seems like a nice self-contained place.
1322  */
1323 
1324 uint8_t
1325 pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr)
1326 {
1327 	pci_acc_cfblk_t *cfp;
1328 	uint8_t	rval;
1329 	int reg;
1330 
1331 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1332 
1333 	reg = (int)(uintptr_t)addr;
1334 
1335 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1336 
1337 	rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
1338 	    reg);
1339 
1340 	return (rval);
1341 }
1342 
1343 void
1344 pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
1345 	uint8_t *dev_addr, size_t repcount, uint_t flags)
1346 {
1347 	uint8_t *h, *d;
1348 
1349 	h = host_addr;
1350 	d = dev_addr;
1351 
1352 	if (flags == DDI_DEV_AUTOINCR)
1353 		for (; repcount; repcount--)
1354 			*h++ = pci_config_rd8(hdlp, d++);
1355 	else
1356 		for (; repcount; repcount--)
1357 			*h++ = pci_config_rd8(hdlp, d);
1358 }
1359 
1360 uint16_t
1361 pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr)
1362 {
1363 	pci_acc_cfblk_t *cfp;
1364 	uint16_t rval;
1365 	int reg;
1366 
1367 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1368 
1369 	reg = (int)(uintptr_t)addr;
1370 
1371 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1372 
1373 	rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
1374 	    reg);
1375 
1376 	return (rval);
1377 }
1378 
1379 void
1380 pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
1381 	uint16_t *dev_addr, size_t repcount, uint_t flags)
1382 {
1383 	uint16_t *h, *d;
1384 
1385 	h = host_addr;
1386 	d = dev_addr;
1387 
1388 	if (flags == DDI_DEV_AUTOINCR)
1389 		for (; repcount; repcount--)
1390 			*h++ = pci_config_rd16(hdlp, d++);
1391 	else
1392 		for (; repcount; repcount--)
1393 			*h++ = pci_config_rd16(hdlp, d);
1394 }
1395 
1396 uint32_t
1397 pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr)
1398 {
1399 	pci_acc_cfblk_t *cfp;
1400 	uint32_t rval;
1401 	int reg;
1402 
1403 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1404 
1405 	reg = (int)(uintptr_t)addr;
1406 
1407 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1408 
1409 	rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum,
1410 	    cfp->c_funcnum, reg);
1411 
1412 	return (rval);
1413 }
1414 
1415 void
1416 pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
1417 	uint32_t *dev_addr, size_t repcount, uint_t flags)
1418 {
1419 	uint32_t *h, *d;
1420 
1421 	h = host_addr;
1422 	d = dev_addr;
1423 
1424 	if (flags == DDI_DEV_AUTOINCR)
1425 		for (; repcount; repcount--)
1426 			*h++ = pci_config_rd32(hdlp, d++);
1427 	else
1428 		for (; repcount; repcount--)
1429 			*h++ = pci_config_rd32(hdlp, d);
1430 }
1431 
1432 
1433 void
1434 pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value)
1435 {
1436 	pci_acc_cfblk_t *cfp;
1437 	int reg;
1438 
1439 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1440 
1441 	reg = (int)(uintptr_t)addr;
1442 
1443 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1444 
1445 	(*pci_putb_func)(cfp->c_busnum, cfp->c_devnum,
1446 	    cfp->c_funcnum, reg, value);
1447 }
1448 
1449 void
1450 pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
1451 	uint8_t *dev_addr, size_t repcount, uint_t flags)
1452 {
1453 	uint8_t *h, *d;
1454 
1455 	h = host_addr;
1456 	d = dev_addr;
1457 
1458 	if (flags == DDI_DEV_AUTOINCR)
1459 		for (; repcount; repcount--)
1460 			pci_config_wr8(hdlp, d++, *h++);
1461 	else
1462 		for (; repcount; repcount--)
1463 			pci_config_wr8(hdlp, d, *h++);
1464 }
1465 
1466 void
1467 pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value)
1468 {
1469 	pci_acc_cfblk_t *cfp;
1470 	int reg;
1471 
1472 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1473 
1474 	reg = (int)(uintptr_t)addr;
1475 
1476 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1477 
1478 	(*pci_putw_func)(cfp->c_busnum, cfp->c_devnum,
1479 	    cfp->c_funcnum, reg, value);
1480 }
1481 
1482 void
1483 pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
1484 	uint16_t *dev_addr, size_t repcount, uint_t flags)
1485 {
1486 	uint16_t *h, *d;
1487 
1488 	h = host_addr;
1489 	d = dev_addr;
1490 
1491 	if (flags == DDI_DEV_AUTOINCR)
1492 		for (; repcount; repcount--)
1493 			pci_config_wr16(hdlp, d++, *h++);
1494 	else
1495 		for (; repcount; repcount--)
1496 			pci_config_wr16(hdlp, d, *h++);
1497 }
1498 
1499 void
1500 pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value)
1501 {
1502 	pci_acc_cfblk_t *cfp;
1503 	int reg;
1504 
1505 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1506 
1507 	reg = (int)(uintptr_t)addr;
1508 
1509 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1510 
1511 	(*pci_putl_func)(cfp->c_busnum, cfp->c_devnum,
1512 	    cfp->c_funcnum, reg, value);
1513 }
1514 
1515 void
1516 pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
1517 	uint32_t *dev_addr, size_t repcount, uint_t flags)
1518 {
1519 	uint32_t *h, *d;
1520 
1521 	h = host_addr;
1522 	d = dev_addr;
1523 
1524 	if (flags == DDI_DEV_AUTOINCR)
1525 		for (; repcount; repcount--)
1526 			pci_config_wr32(hdlp, d++, *h++);
1527 	else
1528 		for (; repcount; repcount--)
1529 			pci_config_wr32(hdlp, d, *h++);
1530 }
1531 
1532 uint64_t
1533 pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr)
1534 {
1535 	uint32_t lw_val;
1536 	uint32_t hi_val;
1537 	uint32_t *dp;
1538 	uint64_t val;
1539 
1540 	dp = (uint32_t *)addr;
1541 	lw_val = pci_config_rd32(hdlp, dp);
1542 	dp++;
1543 	hi_val = pci_config_rd32(hdlp, dp);
1544 	val = ((uint64_t)hi_val << 32) | lw_val;
1545 	return (val);
1546 }
1547 
1548 void
1549 pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value)
1550 {
1551 	uint32_t lw_val;
1552 	uint32_t hi_val;
1553 	uint32_t *dp;
1554 
1555 	dp = (uint32_t *)addr;
1556 	lw_val = (uint32_t)(value & 0xffffffff);
1557 	hi_val = (uint32_t)(value >> 32);
1558 	pci_config_wr32(hdlp, dp, lw_val);
1559 	dp++;
1560 	pci_config_wr32(hdlp, dp, hi_val);
1561 }
1562 
1563 void
1564 pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
1565 	uint64_t *dev_addr, size_t repcount, uint_t flags)
1566 {
1567 	if (flags == DDI_DEV_AUTOINCR) {
1568 		for (; repcount; repcount--)
1569 			*host_addr++ = pci_config_rd64(hdlp, dev_addr++);
1570 	} else {
1571 		for (; repcount; repcount--)
1572 			*host_addr++ = pci_config_rd64(hdlp, dev_addr);
1573 	}
1574 }
1575 
1576 void
1577 pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
1578 	uint64_t *dev_addr, size_t repcount, uint_t flags)
1579 {
1580 	if (flags == DDI_DEV_AUTOINCR) {
1581 		for (; repcount; repcount--)
1582 			pci_config_wr64(hdlp, host_addr++, *dev_addr++);
1583 	} else {
1584 		for (; repcount; repcount--)
1585 			pci_config_wr64(hdlp, host_addr++, *dev_addr);
1586 	}
1587 }
1588 
1589 
1590 /*
1591  * Enable Legacy PCI config space access for the following four north bridges
1592  *	Host bridge: AMD HyperTransport Technology Configuration
1593  *	Host bridge: AMD Address Map
1594  *	Host bridge: AMD DRAM Controller
1595  *	Host bridge: AMD Miscellaneous Control
1596  */
1597 int
1598 is_amd_northbridge(dev_info_t *dip)
1599 {
1600 	int vendor_id, device_id;
1601 
1602 	vendor_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1603 	    "vendor-id", -1);
1604 	device_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1605 	    "device-id", -1);
1606 
1607 	if (IS_AMD_NTBRIDGE(vendor_id, device_id))
1608 		return (0);
1609 
1610 	return (1);
1611 }
1612