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