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