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