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