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