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
pci_common_name_child(dev_info_t * child,char * name,int namelen)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
pci_common_set_parent_private_data(dev_info_t * dip)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
pci_get_priority(dev_info_t * dip,ddi_intr_handle_impl_t * hdlp,int * pri)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
pci_common_intr_ops(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_op_t intr_op,ddi_intr_handle_impl_t * hdlp,void * result)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 if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
537 pci_rval = pci_msi_get_cap(rdip, hdlp->ih_type,
538 &pci_status);
539 else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
540 pci_rval = pci_intx_get_cap(rdip, &pci_status);
541
542 /* next check with PSM module */
543 if (psm_intr_ops != NULL)
544 psm_rval = (*psm_intr_ops)(rdip, hdlp,
545 PSM_INTR_OP_GET_CAP, &psm_status);
546
547 DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned psm_rval = %x, "
548 "psm_status = %x, pci_rval = %x, pci_status = %x\n",
549 psm_rval, psm_status, pci_rval, pci_status));
550
551 if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) {
552 *(int *)result = 0;
553 return (DDI_FAILURE);
554 }
555
556 if (psm_rval == PSM_SUCCESS)
557 *(int *)result = psm_status;
558
559 if (pci_rval == DDI_SUCCESS)
560 *(int *)result |= pci_status;
561
562 DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned = %x\n",
563 *(int *)result));
564 break;
565 case DDI_INTROP_SETCAP:
566 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
567 "SETCAP cap=0x%x\n", *(int *)result));
568 if (psm_intr_ops == NULL)
569 return (DDI_FAILURE);
570
571 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result)) {
572 DDI_INTR_NEXDBG((CE_CONT, "GETCAP: psm_intr_ops"
573 " returned failure\n"));
574 return (DDI_FAILURE);
575 }
576 break;
577 case DDI_INTROP_ENABLE:
578 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE\n"));
579 if (psm_intr_ops == NULL)
580 return (DDI_FAILURE);
581
582 if (pci_enable_intr(pdip, rdip, hdlp, hdlp->ih_inum) !=
583 DDI_SUCCESS)
584 return (DDI_FAILURE);
585
586 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE "
587 "vector=0x%x\n", hdlp->ih_vector));
588 break;
589 case DDI_INTROP_DISABLE:
590 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE\n"));
591 if (psm_intr_ops == NULL)
592 return (DDI_FAILURE);
593
594 pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum);
595 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE "
596 "vector = %x\n", hdlp->ih_vector));
597 break;
598 case DDI_INTROP_BLOCKENABLE:
599 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
600 "BLOCKENABLE\n"));
601 if (hdlp->ih_type != DDI_INTR_TYPE_MSI) {
602 DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: not MSI\n"));
603 return (DDI_FAILURE);
604 }
605
606 /* Check if psm_intr_ops is NULL? */
607 if (psm_intr_ops == NULL)
608 return (DDI_FAILURE);
609
610 count = hdlp->ih_scratch1;
611 h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2;
612 for (i = 0; i < count; i++) {
613 hdlp = (ddi_intr_handle_impl_t *)h_array[i];
614 if (pci_enable_intr(pdip, rdip, hdlp,
615 hdlp->ih_inum) != DDI_SUCCESS) {
616 DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: "
617 "pci_enable_intr failed for %d\n", i));
618 for (j = 0; j < i; j++) {
619 hdlp = (ddi_intr_handle_impl_t *)
620 h_array[j];
621 pci_disable_intr(pdip, rdip, hdlp,
622 hdlp->ih_inum);
623 }
624 return (DDI_FAILURE);
625 }
626 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
627 "BLOCKENABLE inum %x done\n", hdlp->ih_inum));
628 }
629 break;
630 case DDI_INTROP_BLOCKDISABLE:
631 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
632 "BLOCKDISABLE\n"));
633 if (hdlp->ih_type != DDI_INTR_TYPE_MSI) {
634 DDI_INTR_NEXDBG((CE_CONT, "BLOCKDISABLE: not MSI\n"));
635 return (DDI_FAILURE);
636 }
637
638 /* Check if psm_intr_ops is present */
639 if (psm_intr_ops == NULL)
640 return (DDI_FAILURE);
641
642 count = hdlp->ih_scratch1;
643 h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2;
644 for (i = 0; i < count; i++) {
645 hdlp = (ddi_intr_handle_impl_t *)h_array[i];
646 pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum);
647 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
648 "BLOCKDISABLE inum %x done\n", hdlp->ih_inum));
649 }
650 break;
651 case DDI_INTROP_SETMASK:
652 case DDI_INTROP_CLRMASK:
653 /*
654 * First handle in the config space
655 */
656 if (intr_op == DDI_INTROP_SETMASK) {
657 if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
658 pci_status = pci_msi_set_mask(rdip,
659 hdlp->ih_type, hdlp->ih_inum);
660 else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
661 pci_status = pci_intx_set_mask(rdip);
662 } else {
663 if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
664 pci_status = pci_msi_clr_mask(rdip,
665 hdlp->ih_type, hdlp->ih_inum);
666 else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
667 pci_status = pci_intx_clr_mask(rdip);
668 }
669
670 /* For MSI/X; no need to check with PSM module */
671 if (hdlp->ih_type != DDI_INTR_TYPE_FIXED)
672 return (pci_status);
673
674 /* For fixed interrupts only: handle config space first */
675 if (hdlp->ih_type == DDI_INTR_TYPE_FIXED &&
676 pci_status == DDI_SUCCESS)
677 break;
678
679 /* For fixed interrupts only: confer with PSM module next */
680 if (psm_intr_ops != NULL) {
681 /* If interrupt is shared; do nothing */
682 psm_rval = (*psm_intr_ops)(rdip, hdlp,
683 PSM_INTR_OP_GET_SHARED, &psm_status);
684
685 if (psm_rval == PSM_FAILURE || psm_status == 1)
686 return (pci_status);
687
688 /* Now, PSM module should try to set/clear the mask */
689 if (intr_op == DDI_INTROP_SETMASK)
690 psm_rval = (*psm_intr_ops)(rdip, hdlp,
691 PSM_INTR_OP_SET_MASK, NULL);
692 else
693 psm_rval = (*psm_intr_ops)(rdip, hdlp,
694 PSM_INTR_OP_CLEAR_MASK, NULL);
695 }
696 return ((psm_rval == PSM_FAILURE) ? DDI_FAILURE : DDI_SUCCESS);
697 case DDI_INTROP_GETPENDING:
698 /*
699 * First check the config space and/or
700 * MSI capability register(s)
701 */
702 if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
703 pci_rval = pci_msi_get_pending(rdip, hdlp->ih_type,
704 hdlp->ih_inum, &pci_status);
705 else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
706 pci_rval = pci_intx_get_pending(rdip, &pci_status);
707
708 /* On failure; next try with PSM module */
709 if (pci_rval != DDI_SUCCESS && psm_intr_ops != NULL)
710 psm_rval = (*psm_intr_ops)(rdip, hdlp,
711 PSM_INTR_OP_GET_PENDING, &psm_status);
712
713 DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned "
714 "psm_rval = %x, psm_status = %x, pci_rval = %x, "
715 "pci_status = %x\n", psm_rval, psm_status, pci_rval,
716 pci_status));
717 if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) {
718 *(int *)result = 0;
719 return (DDI_FAILURE);
720 }
721
722 if (psm_rval != PSM_FAILURE)
723 *(int *)result = psm_status;
724 else if (pci_rval != DDI_FAILURE)
725 *(int *)result = pci_status;
726 DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned = %x\n",
727 *(int *)result));
728 break;
729 case DDI_INTROP_GETTARGET:
730 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: GETTARGET\n"));
731
732 bcopy(hdlp, &tmp_hdl, sizeof (ddi_intr_handle_impl_t));
733 tmp_hdl.ih_private = (void *)&intrinfo;
734 intrinfo.avgi_req_flags = PSMGI_INTRBY_DEFAULT;
735 intrinfo.avgi_req_flags |= PSMGI_REQ_CPUID;
736
737 if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_GET_INTR,
738 NULL) == PSM_FAILURE)
739 return (DDI_FAILURE);
740
741 *(int *)result = intrinfo.avgi_cpu_id;
742 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: GETTARGET "
743 "vector = 0x%x, cpu = 0x%x\n", hdlp->ih_vector,
744 *(int *)result));
745 break;
746 case DDI_INTROP_SETTARGET:
747 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: SETTARGET\n"));
748
749 bcopy(hdlp, &tmp_hdl, sizeof (ddi_intr_handle_impl_t));
750 tmp_hdl.ih_private = (void *)(uintptr_t)*(int *)result;
751 tmp_hdl.ih_flags = PSMGI_INTRBY_DEFAULT;
752
753 if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_SET_CPU,
754 &psm_status) == PSM_FAILURE)
755 return (DDI_FAILURE);
756
757 hdlp->ih_vector = tmp_hdl.ih_vector;
758 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: SETTARGET "
759 "vector = 0x%x\n", hdlp->ih_vector));
760 break;
761 case DDI_INTROP_GETPOOL:
762 /*
763 * For MSI/X interrupts use global IRM pool if available.
764 */
765 if (apix_irm_pool_p && DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
766 *(ddi_irm_pool_t **)result = apix_irm_pool_p;
767 return (DDI_SUCCESS);
768 }
769 return (DDI_ENOTSUP);
770 default:
771 return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result));
772 }
773
774 return (DDI_SUCCESS);
775 }
776
777 /*
778 * Allocate a vector for FIXED type interrupt.
779 */
780 int
pci_alloc_intr_fixed(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp,void * result)781 pci_alloc_intr_fixed(dev_info_t *pdip, dev_info_t *rdip,
782 ddi_intr_handle_impl_t *hdlp, void *result)
783 {
784 struct intrspec *ispec;
785 ddi_intr_handle_impl_t info_hdl;
786 int ret;
787 int free_phdl = 0;
788 int pci_rval;
789 int pci_status = 0;
790 apic_get_type_t type_info;
791
792 if (psm_intr_ops == NULL)
793 return (DDI_FAILURE);
794
795 /* Figure out if this device supports MASKING */
796 pci_rval = pci_intx_get_cap(rdip, &pci_status);
797 if (pci_rval == DDI_SUCCESS && pci_status)
798 hdlp->ih_cap |= pci_status;
799
800 /*
801 * If the PSM module is "APIX" then pass the request for
802 * allocating the vector now.
803 */
804 bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t));
805 info_hdl.ih_private = &type_info;
806 if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) ==
807 PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) {
808 ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip,
809 (int)hdlp->ih_inum);
810 if (ispec == NULL)
811 return (DDI_FAILURE);
812 if (hdlp->ih_private == NULL) { /* allocate phdl structure */
813 free_phdl = 1;
814 i_ddi_alloc_intr_phdl(hdlp);
815 }
816 ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
817 ret = (*psm_intr_ops)(rdip, hdlp,
818 PSM_INTR_OP_ALLOC_VECTORS, result);
819 if (free_phdl) { /* free up the phdl structure */
820 free_phdl = 0;
821 i_ddi_free_intr_phdl(hdlp);
822 hdlp->ih_private = NULL;
823 }
824 } else {
825 /*
826 * No APIX module; fall back to the old scheme where the
827 * interrupt vector is allocated during ddi_enable_intr() call.
828 */
829 *(int *)result = 1;
830 ret = DDI_SUCCESS;
831 }
832
833 return (ret);
834 }
835
836 /*
837 * Free up the vector for FIXED (legacy) type interrupt.
838 */
839 static int
pci_free_intr_fixed(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)840 pci_free_intr_fixed(dev_info_t *pdip, dev_info_t *rdip,
841 ddi_intr_handle_impl_t *hdlp)
842 {
843 struct intrspec *ispec;
844 ddi_intr_handle_impl_t info_hdl;
845 int ret;
846 apic_get_type_t type_info;
847
848 if (psm_intr_ops == NULL)
849 return (DDI_FAILURE);
850
851 /*
852 * If the PSM module is "APIX" then pass the request to it
853 * to free up the vector now.
854 */
855 bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t));
856 info_hdl.ih_private = &type_info;
857 if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) ==
858 PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) {
859 ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip,
860 (int)hdlp->ih_inum);
861 if (ispec == NULL)
862 return (DDI_FAILURE);
863 ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
864 ret = (*psm_intr_ops)(rdip, hdlp,
865 PSM_INTR_OP_FREE_VECTORS, NULL);
866 } else {
867 /*
868 * No APIX module; fall back to the old scheme where
869 * the interrupt vector was already freed during
870 * ddi_disable_intr() call.
871 */
872 ret = DDI_SUCCESS;
873 }
874
875 return (ret);
876 }
877
878 int
pci_get_intr_from_vecirq(apic_get_intr_t * intrinfo_p,int vecirq,boolean_t is_irq)879 pci_get_intr_from_vecirq(apic_get_intr_t *intrinfo_p,
880 int vecirq, boolean_t is_irq)
881 {
882 ddi_intr_handle_impl_t get_info_ii_hdl;
883
884 if (is_irq)
885 intrinfo_p->avgi_req_flags |= PSMGI_INTRBY_IRQ;
886
887 /*
888 * For this locally-declared and used handle, ih_private will contain a
889 * pointer to apic_get_intr_t, not an ihdl_plat_t as used for
890 * global interrupt handling.
891 */
892 get_info_ii_hdl.ih_private = intrinfo_p;
893 get_info_ii_hdl.ih_vector = vecirq;
894
895 if ((*psm_intr_ops)(NULL, &get_info_ii_hdl,
896 PSM_INTR_OP_GET_INTR, NULL) == PSM_FAILURE)
897 return (DDI_FAILURE);
898
899 return (DDI_SUCCESS);
900 }
901
902
903 int
pci_get_cpu_from_vecirq(int vecirq,boolean_t is_irq)904 pci_get_cpu_from_vecirq(int vecirq, boolean_t is_irq)
905 {
906 int rval;
907 apic_get_intr_t intrinfo;
908
909 intrinfo.avgi_req_flags = PSMGI_REQ_CPUID;
910 rval = pci_get_intr_from_vecirq(&intrinfo, vecirq, is_irq);
911
912 if (rval == DDI_SUCCESS)
913 return (intrinfo.avgi_cpu_id);
914 else
915 return (-1);
916 }
917
918
919 static int
pci_enable_intr(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp,uint32_t inum)920 pci_enable_intr(dev_info_t *pdip, dev_info_t *rdip,
921 ddi_intr_handle_impl_t *hdlp, uint32_t inum)
922 {
923 struct intrspec *ispec;
924 int irq;
925 ihdl_plat_t *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
926
927 DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: hdlp %p inum %x\n",
928 (void *)hdlp, inum));
929
930 /* Translate the interrupt if needed */
931 ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
932 if (ispec == NULL)
933 return (DDI_FAILURE);
934 if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
935 ispec->intrspec_vec = inum;
936 ispec->intrspec_pri = hdlp->ih_pri;
937 }
938 ihdl_plat_datap->ip_ispecp = ispec;
939
940 /* translate the interrupt if needed */
941 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq) ==
942 PSM_FAILURE)
943 return (DDI_FAILURE);
944 DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: priority=%x irq=%x\n",
945 hdlp->ih_pri, irq));
946
947 /* Add the interrupt handler */
948 if (!add_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func,
949 DEVI(rdip)->devi_name, irq, hdlp->ih_cb_arg1,
950 hdlp->ih_cb_arg2, &ihdl_plat_datap->ip_ticks, rdip))
951 return (DDI_FAILURE);
952
953 hdlp->ih_vector = irq;
954
955 return (DDI_SUCCESS);
956 }
957
958
959 static void
pci_disable_intr(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp,uint32_t inum)960 pci_disable_intr(dev_info_t *pdip, dev_info_t *rdip,
961 ddi_intr_handle_impl_t *hdlp, uint32_t inum)
962 {
963 int irq;
964 struct intrspec *ispec;
965 ihdl_plat_t *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
966
967 DDI_INTR_NEXDBG((CE_CONT, "pci_disable_intr: \n"));
968 ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
969 if (ispec == NULL)
970 return;
971 if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
972 ispec->intrspec_vec = inum;
973 ispec->intrspec_pri = hdlp->ih_pri;
974 }
975 ihdl_plat_datap->ip_ispecp = ispec;
976
977 /* translate the interrupt if needed */
978 (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq);
979
980 /* Disable the interrupt handler */
981 rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, irq);
982 ihdl_plat_datap->ip_ispecp = NULL;
983 }
984
985 /*
986 * Miscellaneous library function
987 */
988 int
pci_common_get_reg_prop(dev_info_t * dip,pci_regspec_t * pci_rp)989 pci_common_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp)
990 {
991 int i;
992 int number;
993 int assigned_addr_len;
994 uint_t phys_hi = pci_rp->pci_phys_hi;
995 pci_regspec_t *assigned_addr;
996
997 if (((phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) ||
998 (phys_hi & PCI_RELOCAT_B))
999 return (DDI_SUCCESS);
1000
1001 /*
1002 * the "reg" property specifies relocatable, get and interpret the
1003 * "assigned-addresses" property.
1004 */
1005 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1006 "assigned-addresses", (int **)&assigned_addr,
1007 (uint_t *)&assigned_addr_len) != DDI_PROP_SUCCESS)
1008 return (DDI_FAILURE);
1009
1010 /*
1011 * Scan the "assigned-addresses" for one that matches the specified
1012 * "reg" property entry.
1013 */
1014 phys_hi &= PCI_CONF_ADDR_MASK;
1015 number = assigned_addr_len / (sizeof (pci_regspec_t) / sizeof (int));
1016 for (i = 0; i < number; i++) {
1017 if ((assigned_addr[i].pci_phys_hi & PCI_CONF_ADDR_MASK) ==
1018 phys_hi) {
1019 pci_rp->pci_phys_mid = assigned_addr[i].pci_phys_mid;
1020 pci_rp->pci_phys_low = assigned_addr[i].pci_phys_low;
1021 ddi_prop_free(assigned_addr);
1022 return (DDI_SUCCESS);
1023 }
1024 }
1025
1026 ddi_prop_free(assigned_addr);
1027 return (DDI_FAILURE);
1028 }
1029
1030
1031 /*
1032 * To handle PCI tool ioctls
1033 */
1034
1035 /*ARGSUSED*/
1036 int
pci_common_ioctl(dev_info_t * dip,dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)1037 pci_common_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg,
1038 int mode, cred_t *credp, int *rvalp)
1039 {
1040 minor_t minor = getminor(dev);
1041 int rv = ENOTTY;
1042
1043 switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
1044 case PCI_TOOL_REG_MINOR_NUM:
1045
1046 switch (cmd) {
1047 case PCITOOL_DEVICE_SET_REG:
1048 case PCITOOL_DEVICE_GET_REG:
1049
1050 /* Require full privileges. */
1051 if (secpolicy_kmdb(credp))
1052 rv = EPERM;
1053 else
1054 rv = pcitool_dev_reg_ops(dip, (void *)arg,
1055 cmd, mode);
1056 break;
1057
1058 case PCITOOL_NEXUS_SET_REG:
1059 case PCITOOL_NEXUS_GET_REG:
1060
1061 /* Require full privileges. */
1062 if (secpolicy_kmdb(credp))
1063 rv = EPERM;
1064 else
1065 rv = pcitool_bus_reg_ops(dip, (void *)arg,
1066 cmd, mode);
1067 break;
1068 }
1069 break;
1070
1071 case PCI_TOOL_INTR_MINOR_NUM:
1072
1073 switch (cmd) {
1074 case PCITOOL_DEVICE_SET_INTR:
1075
1076 /* Require PRIV_SYS_RES_CONFIG, same as psradm */
1077 if (secpolicy_ponline(credp)) {
1078 rv = EPERM;
1079 break;
1080 }
1081
1082 /*FALLTHRU*/
1083 /* These require no special privileges. */
1084 case PCITOOL_DEVICE_GET_INTR:
1085 case PCITOOL_SYSTEM_INTR_INFO:
1086 rv = pcitool_intr_admn(dip, (void *)arg, cmd, mode);
1087 break;
1088 }
1089 break;
1090
1091 default:
1092 break;
1093 }
1094
1095 return (rv);
1096 }
1097
1098
1099 int
pci_common_ctlops_poke(peekpoke_ctlops_t * in_args)1100 pci_common_ctlops_poke(peekpoke_ctlops_t *in_args)
1101 {
1102 size_t size = in_args->size;
1103 uintptr_t dev_addr = in_args->dev_addr;
1104 uintptr_t host_addr = in_args->host_addr;
1105 ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
1106 ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
1107 size_t repcount = in_args->repcount;
1108 uint_t flags = in_args->flags;
1109 int err = DDI_SUCCESS;
1110
1111 /*
1112 * if no handle then this is a poke. We have to return failure here
1113 * as we have no way of knowing whether this is a MEM or IO space access
1114 */
1115 if (in_args->handle == NULL)
1116 return (DDI_FAILURE);
1117
1118 /*
1119 * rest of this function is actually for cautious puts
1120 */
1121 for (; repcount; repcount--) {
1122 if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
1123 switch (size) {
1124 case sizeof (uint8_t):
1125 pci_config_wr8(hp, (uint8_t *)dev_addr,
1126 *(uint8_t *)host_addr);
1127 break;
1128 case sizeof (uint16_t):
1129 pci_config_wr16(hp, (uint16_t *)dev_addr,
1130 *(uint16_t *)host_addr);
1131 break;
1132 case sizeof (uint32_t):
1133 pci_config_wr32(hp, (uint32_t *)dev_addr,
1134 *(uint32_t *)host_addr);
1135 break;
1136 case sizeof (uint64_t):
1137 pci_config_wr64(hp, (uint64_t *)dev_addr,
1138 *(uint64_t *)host_addr);
1139 break;
1140 default:
1141 err = DDI_FAILURE;
1142 break;
1143 }
1144 } else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
1145 if (hdlp->ah_acc.devacc_attr_endian_flags ==
1146 DDI_STRUCTURE_BE_ACC) {
1147 switch (size) {
1148 case sizeof (uint8_t):
1149 i_ddi_io_put8(hp,
1150 (uint8_t *)dev_addr,
1151 *(uint8_t *)host_addr);
1152 break;
1153 case sizeof (uint16_t):
1154 i_ddi_io_swap_put16(hp,
1155 (uint16_t *)dev_addr,
1156 *(uint16_t *)host_addr);
1157 break;
1158 case sizeof (uint32_t):
1159 i_ddi_io_swap_put32(hp,
1160 (uint32_t *)dev_addr,
1161 *(uint32_t *)host_addr);
1162 break;
1163 /*
1164 * note the 64-bit case is a dummy
1165 * function - so no need to swap
1166 */
1167 case sizeof (uint64_t):
1168 i_ddi_io_put64(hp,
1169 (uint64_t *)dev_addr,
1170 *(uint64_t *)host_addr);
1171 break;
1172 default:
1173 err = DDI_FAILURE;
1174 break;
1175 }
1176 } else {
1177 switch (size) {
1178 case sizeof (uint8_t):
1179 i_ddi_io_put8(hp,
1180 (uint8_t *)dev_addr,
1181 *(uint8_t *)host_addr);
1182 break;
1183 case sizeof (uint16_t):
1184 i_ddi_io_put16(hp,
1185 (uint16_t *)dev_addr,
1186 *(uint16_t *)host_addr);
1187 break;
1188 case sizeof (uint32_t):
1189 i_ddi_io_put32(hp,
1190 (uint32_t *)dev_addr,
1191 *(uint32_t *)host_addr);
1192 break;
1193 case sizeof (uint64_t):
1194 i_ddi_io_put64(hp,
1195 (uint64_t *)dev_addr,
1196 *(uint64_t *)host_addr);
1197 break;
1198 default:
1199 err = DDI_FAILURE;
1200 break;
1201 }
1202 }
1203 } else {
1204 if (hdlp->ah_acc.devacc_attr_endian_flags ==
1205 DDI_STRUCTURE_BE_ACC) {
1206 switch (size) {
1207 case sizeof (uint8_t):
1208 *(uint8_t *)dev_addr =
1209 *(uint8_t *)host_addr;
1210 break;
1211 case sizeof (uint16_t):
1212 *(uint16_t *)dev_addr =
1213 ddi_swap16(*(uint16_t *)host_addr);
1214 break;
1215 case sizeof (uint32_t):
1216 *(uint32_t *)dev_addr =
1217 ddi_swap32(*(uint32_t *)host_addr);
1218 break;
1219 case sizeof (uint64_t):
1220 *(uint64_t *)dev_addr =
1221 ddi_swap64(*(uint64_t *)host_addr);
1222 break;
1223 default:
1224 err = DDI_FAILURE;
1225 break;
1226 }
1227 } else {
1228 switch (size) {
1229 case sizeof (uint8_t):
1230 *(uint8_t *)dev_addr =
1231 *(uint8_t *)host_addr;
1232 break;
1233 case sizeof (uint16_t):
1234 *(uint16_t *)dev_addr =
1235 *(uint16_t *)host_addr;
1236 break;
1237 case sizeof (uint32_t):
1238 *(uint32_t *)dev_addr =
1239 *(uint32_t *)host_addr;
1240 break;
1241 case sizeof (uint64_t):
1242 *(uint64_t *)dev_addr =
1243 *(uint64_t *)host_addr;
1244 break;
1245 default:
1246 err = DDI_FAILURE;
1247 break;
1248 }
1249 }
1250 }
1251 host_addr += size;
1252 if (flags == DDI_DEV_AUTOINCR)
1253 dev_addr += size;
1254 }
1255 return (err);
1256 }
1257
1258
1259 int
pci_fm_acc_setup(ddi_acc_hdl_t * hp,off_t offset,off_t len)1260 pci_fm_acc_setup(ddi_acc_hdl_t *hp, off_t offset, off_t len)
1261 {
1262 ddi_acc_impl_t *ap = (ddi_acc_impl_t *)hp->ah_platform_private;
1263
1264 /* endian-ness check */
1265 if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC)
1266 return (DDI_FAILURE);
1267
1268 /*
1269 * range check
1270 */
1271 if ((offset >= PCI_CONF_HDR_SIZE) ||
1272 (len > PCI_CONF_HDR_SIZE) ||
1273 (offset + len > PCI_CONF_HDR_SIZE))
1274 return (DDI_FAILURE);
1275
1276 ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE;
1277 /*
1278 * always use cautious mechanism for config space gets
1279 */
1280 ap->ahi_get8 = i_ddi_caut_get8;
1281 ap->ahi_get16 = i_ddi_caut_get16;
1282 ap->ahi_get32 = i_ddi_caut_get32;
1283 ap->ahi_get64 = i_ddi_caut_get64;
1284 ap->ahi_rep_get8 = i_ddi_caut_rep_get8;
1285 ap->ahi_rep_get16 = i_ddi_caut_rep_get16;
1286 ap->ahi_rep_get32 = i_ddi_caut_rep_get32;
1287 ap->ahi_rep_get64 = i_ddi_caut_rep_get64;
1288 if (hp->ah_acc.devacc_attr_access == DDI_CAUTIOUS_ACC) {
1289 ap->ahi_put8 = i_ddi_caut_put8;
1290 ap->ahi_put16 = i_ddi_caut_put16;
1291 ap->ahi_put32 = i_ddi_caut_put32;
1292 ap->ahi_put64 = i_ddi_caut_put64;
1293 ap->ahi_rep_put8 = i_ddi_caut_rep_put8;
1294 ap->ahi_rep_put16 = i_ddi_caut_rep_put16;
1295 ap->ahi_rep_put32 = i_ddi_caut_rep_put32;
1296 ap->ahi_rep_put64 = i_ddi_caut_rep_put64;
1297 } else {
1298 ap->ahi_put8 = pci_config_wr8;
1299 ap->ahi_put16 = pci_config_wr16;
1300 ap->ahi_put32 = pci_config_wr32;
1301 ap->ahi_put64 = pci_config_wr64;
1302 ap->ahi_rep_put8 = pci_config_rep_wr8;
1303 ap->ahi_rep_put16 = pci_config_rep_wr16;
1304 ap->ahi_rep_put32 = pci_config_rep_wr32;
1305 ap->ahi_rep_put64 = pci_config_rep_wr64;
1306 }
1307
1308 /* Initialize to default check/notify functions */
1309 ap->ahi_fault_check = i_ddi_acc_fault_check;
1310 ap->ahi_fault_notify = i_ddi_acc_fault_notify;
1311 ap->ahi_fault = 0;
1312 impl_acc_err_init(hp);
1313 return (DDI_SUCCESS);
1314 }
1315
1316
1317 int
pci_common_ctlops_peek(peekpoke_ctlops_t * in_args)1318 pci_common_ctlops_peek(peekpoke_ctlops_t *in_args)
1319 {
1320 size_t size = in_args->size;
1321 uintptr_t dev_addr = in_args->dev_addr;
1322 uintptr_t host_addr = in_args->host_addr;
1323 ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
1324 ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
1325 size_t repcount = in_args->repcount;
1326 uint_t flags = in_args->flags;
1327 int err = DDI_SUCCESS;
1328
1329 /*
1330 * if no handle then this is a peek. We have to return failure here
1331 * as we have no way of knowing whether this is a MEM or IO space access
1332 */
1333 if (in_args->handle == NULL)
1334 return (DDI_FAILURE);
1335
1336 for (; repcount; repcount--) {
1337 if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
1338 switch (size) {
1339 case sizeof (uint8_t):
1340 *(uint8_t *)host_addr = pci_config_rd8(hp,
1341 (uint8_t *)dev_addr);
1342 break;
1343 case sizeof (uint16_t):
1344 *(uint16_t *)host_addr = pci_config_rd16(hp,
1345 (uint16_t *)dev_addr);
1346 break;
1347 case sizeof (uint32_t):
1348 *(uint32_t *)host_addr = pci_config_rd32(hp,
1349 (uint32_t *)dev_addr);
1350 break;
1351 case sizeof (uint64_t):
1352 *(uint64_t *)host_addr = pci_config_rd64(hp,
1353 (uint64_t *)dev_addr);
1354 break;
1355 default:
1356 err = DDI_FAILURE;
1357 break;
1358 }
1359 } else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
1360 if (hdlp->ah_acc.devacc_attr_endian_flags ==
1361 DDI_STRUCTURE_BE_ACC) {
1362 switch (size) {
1363 case sizeof (uint8_t):
1364 *(uint8_t *)host_addr =
1365 i_ddi_io_get8(hp,
1366 (uint8_t *)dev_addr);
1367 break;
1368 case sizeof (uint16_t):
1369 *(uint16_t *)host_addr =
1370 i_ddi_io_swap_get16(hp,
1371 (uint16_t *)dev_addr);
1372 break;
1373 case sizeof (uint32_t):
1374 *(uint32_t *)host_addr =
1375 i_ddi_io_swap_get32(hp,
1376 (uint32_t *)dev_addr);
1377 break;
1378 /*
1379 * note the 64-bit case is a dummy
1380 * function - so no need to swap
1381 */
1382 case sizeof (uint64_t):
1383 *(uint64_t *)host_addr =
1384 i_ddi_io_get64(hp,
1385 (uint64_t *)dev_addr);
1386 break;
1387 default:
1388 err = DDI_FAILURE;
1389 break;
1390 }
1391 } else {
1392 switch (size) {
1393 case sizeof (uint8_t):
1394 *(uint8_t *)host_addr =
1395 i_ddi_io_get8(hp,
1396 (uint8_t *)dev_addr);
1397 break;
1398 case sizeof (uint16_t):
1399 *(uint16_t *)host_addr =
1400 i_ddi_io_get16(hp,
1401 (uint16_t *)dev_addr);
1402 break;
1403 case sizeof (uint32_t):
1404 *(uint32_t *)host_addr =
1405 i_ddi_io_get32(hp,
1406 (uint32_t *)dev_addr);
1407 break;
1408 case sizeof (uint64_t):
1409 *(uint64_t *)host_addr =
1410 i_ddi_io_get64(hp,
1411 (uint64_t *)dev_addr);
1412 break;
1413 default:
1414 err = DDI_FAILURE;
1415 break;
1416 }
1417 }
1418 } else {
1419 if (hdlp->ah_acc.devacc_attr_endian_flags ==
1420 DDI_STRUCTURE_BE_ACC) {
1421 switch (in_args->size) {
1422 case sizeof (uint8_t):
1423 *(uint8_t *)host_addr =
1424 *(uint8_t *)dev_addr;
1425 break;
1426 case sizeof (uint16_t):
1427 *(uint16_t *)host_addr =
1428 ddi_swap16(*(uint16_t *)dev_addr);
1429 break;
1430 case sizeof (uint32_t):
1431 *(uint32_t *)host_addr =
1432 ddi_swap32(*(uint32_t *)dev_addr);
1433 break;
1434 case sizeof (uint64_t):
1435 *(uint64_t *)host_addr =
1436 ddi_swap64(*(uint64_t *)dev_addr);
1437 break;
1438 default:
1439 err = DDI_FAILURE;
1440 break;
1441 }
1442 } else {
1443 switch (in_args->size) {
1444 case sizeof (uint8_t):
1445 *(uint8_t *)host_addr =
1446 *(uint8_t *)dev_addr;
1447 break;
1448 case sizeof (uint16_t):
1449 *(uint16_t *)host_addr =
1450 *(uint16_t *)dev_addr;
1451 break;
1452 case sizeof (uint32_t):
1453 *(uint32_t *)host_addr =
1454 *(uint32_t *)dev_addr;
1455 break;
1456 case sizeof (uint64_t):
1457 *(uint64_t *)host_addr =
1458 *(uint64_t *)dev_addr;
1459 break;
1460 default:
1461 err = DDI_FAILURE;
1462 break;
1463 }
1464 }
1465 }
1466 host_addr += size;
1467 if (flags == DDI_DEV_AUTOINCR)
1468 dev_addr += size;
1469 }
1470 return (err);
1471 }
1472
1473 /*ARGSUSED*/
1474 int
pci_common_peekpoke(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t ctlop,void * arg,void * result)1475 pci_common_peekpoke(dev_info_t *dip, dev_info_t *rdip,
1476 ddi_ctl_enum_t ctlop, void *arg, void *result)
1477 {
1478 if (ctlop == DDI_CTLOPS_PEEK)
1479 return (pci_common_ctlops_peek((peekpoke_ctlops_t *)arg));
1480 else
1481 return (pci_common_ctlops_poke((peekpoke_ctlops_t *)arg));
1482 }
1483
1484 /*
1485 * These are the get and put functions to be shared with drivers. The
1486 * mutex locking is done inside the functions referenced, rather than
1487 * here, and is thus shared across PCI child drivers and any other
1488 * consumers of PCI config space (such as the ACPI subsystem).
1489 *
1490 * The configuration space addresses come in as pointers. This is fine on
1491 * a 32-bit system, where the VM space and configuration space are the same
1492 * size. It's not such a good idea on a 64-bit system, where memory
1493 * addresses are twice as large as configuration space addresses. At some
1494 * point in the call tree we need to take a stand and say "you are 32-bit
1495 * from this time forth", and this seems like a nice self-contained place.
1496 */
1497
1498 uint8_t
pci_config_rd8(ddi_acc_impl_t * hdlp,uint8_t * addr)1499 pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr)
1500 {
1501 pci_acc_cfblk_t *cfp;
1502 uint8_t rval;
1503 int reg;
1504
1505 ASSERT64(((uintptr_t)addr >> 32) == 0);
1506
1507 reg = (int)(uintptr_t)addr;
1508
1509 cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1510
1511 rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
1512 reg);
1513
1514 return (rval);
1515 }
1516
1517 void
pci_config_rep_rd8(ddi_acc_impl_t * hdlp,uint8_t * host_addr,uint8_t * dev_addr,size_t repcount,uint_t flags)1518 pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
1519 uint8_t *dev_addr, size_t repcount, uint_t flags)
1520 {
1521 uint8_t *h, *d;
1522
1523 h = host_addr;
1524 d = dev_addr;
1525
1526 if (flags == DDI_DEV_AUTOINCR)
1527 for (; repcount; repcount--)
1528 *h++ = pci_config_rd8(hdlp, d++);
1529 else
1530 for (; repcount; repcount--)
1531 *h++ = pci_config_rd8(hdlp, d);
1532 }
1533
1534 uint16_t
pci_config_rd16(ddi_acc_impl_t * hdlp,uint16_t * addr)1535 pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr)
1536 {
1537 pci_acc_cfblk_t *cfp;
1538 uint16_t rval;
1539 int reg;
1540
1541 ASSERT64(((uintptr_t)addr >> 32) == 0);
1542
1543 reg = (int)(uintptr_t)addr;
1544
1545 cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1546
1547 rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
1548 reg);
1549
1550 return (rval);
1551 }
1552
1553 void
pci_config_rep_rd16(ddi_acc_impl_t * hdlp,uint16_t * host_addr,uint16_t * dev_addr,size_t repcount,uint_t flags)1554 pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
1555 uint16_t *dev_addr, size_t repcount, uint_t flags)
1556 {
1557 uint16_t *h, *d;
1558
1559 h = host_addr;
1560 d = dev_addr;
1561
1562 if (flags == DDI_DEV_AUTOINCR)
1563 for (; repcount; repcount--)
1564 *h++ = pci_config_rd16(hdlp, d++);
1565 else
1566 for (; repcount; repcount--)
1567 *h++ = pci_config_rd16(hdlp, d);
1568 }
1569
1570 uint32_t
pci_config_rd32(ddi_acc_impl_t * hdlp,uint32_t * addr)1571 pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr)
1572 {
1573 pci_acc_cfblk_t *cfp;
1574 uint32_t rval;
1575 int reg;
1576
1577 ASSERT64(((uintptr_t)addr >> 32) == 0);
1578
1579 reg = (int)(uintptr_t)addr;
1580
1581 cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1582
1583 rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum,
1584 cfp->c_funcnum, reg);
1585
1586 return (rval);
1587 }
1588
1589 void
pci_config_rep_rd32(ddi_acc_impl_t * hdlp,uint32_t * host_addr,uint32_t * dev_addr,size_t repcount,uint_t flags)1590 pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
1591 uint32_t *dev_addr, size_t repcount, uint_t flags)
1592 {
1593 uint32_t *h, *d;
1594
1595 h = host_addr;
1596 d = dev_addr;
1597
1598 if (flags == DDI_DEV_AUTOINCR)
1599 for (; repcount; repcount--)
1600 *h++ = pci_config_rd32(hdlp, d++);
1601 else
1602 for (; repcount; repcount--)
1603 *h++ = pci_config_rd32(hdlp, d);
1604 }
1605
1606
1607 void
pci_config_wr8(ddi_acc_impl_t * hdlp,uint8_t * addr,uint8_t value)1608 pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value)
1609 {
1610 pci_acc_cfblk_t *cfp;
1611 int reg;
1612
1613 ASSERT64(((uintptr_t)addr >> 32) == 0);
1614
1615 reg = (int)(uintptr_t)addr;
1616
1617 cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1618
1619 (*pci_putb_func)(cfp->c_busnum, cfp->c_devnum,
1620 cfp->c_funcnum, reg, value);
1621 }
1622
1623 void
pci_config_rep_wr8(ddi_acc_impl_t * hdlp,uint8_t * host_addr,uint8_t * dev_addr,size_t repcount,uint_t flags)1624 pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
1625 uint8_t *dev_addr, size_t repcount, uint_t flags)
1626 {
1627 uint8_t *h, *d;
1628
1629 h = host_addr;
1630 d = dev_addr;
1631
1632 if (flags == DDI_DEV_AUTOINCR)
1633 for (; repcount; repcount--)
1634 pci_config_wr8(hdlp, d++, *h++);
1635 else
1636 for (; repcount; repcount--)
1637 pci_config_wr8(hdlp, d, *h++);
1638 }
1639
1640 void
pci_config_wr16(ddi_acc_impl_t * hdlp,uint16_t * addr,uint16_t value)1641 pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value)
1642 {
1643 pci_acc_cfblk_t *cfp;
1644 int reg;
1645
1646 ASSERT64(((uintptr_t)addr >> 32) == 0);
1647
1648 reg = (int)(uintptr_t)addr;
1649
1650 cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1651
1652 (*pci_putw_func)(cfp->c_busnum, cfp->c_devnum,
1653 cfp->c_funcnum, reg, value);
1654 }
1655
1656 void
pci_config_rep_wr16(ddi_acc_impl_t * hdlp,uint16_t * host_addr,uint16_t * dev_addr,size_t repcount,uint_t flags)1657 pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
1658 uint16_t *dev_addr, size_t repcount, uint_t flags)
1659 {
1660 uint16_t *h, *d;
1661
1662 h = host_addr;
1663 d = dev_addr;
1664
1665 if (flags == DDI_DEV_AUTOINCR)
1666 for (; repcount; repcount--)
1667 pci_config_wr16(hdlp, d++, *h++);
1668 else
1669 for (; repcount; repcount--)
1670 pci_config_wr16(hdlp, d, *h++);
1671 }
1672
1673 void
pci_config_wr32(ddi_acc_impl_t * hdlp,uint32_t * addr,uint32_t value)1674 pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value)
1675 {
1676 pci_acc_cfblk_t *cfp;
1677 int reg;
1678
1679 ASSERT64(((uintptr_t)addr >> 32) == 0);
1680
1681 reg = (int)(uintptr_t)addr;
1682
1683 cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1684
1685 (*pci_putl_func)(cfp->c_busnum, cfp->c_devnum,
1686 cfp->c_funcnum, reg, value);
1687 }
1688
1689 void
pci_config_rep_wr32(ddi_acc_impl_t * hdlp,uint32_t * host_addr,uint32_t * dev_addr,size_t repcount,uint_t flags)1690 pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
1691 uint32_t *dev_addr, size_t repcount, uint_t flags)
1692 {
1693 uint32_t *h, *d;
1694
1695 h = host_addr;
1696 d = dev_addr;
1697
1698 if (flags == DDI_DEV_AUTOINCR)
1699 for (; repcount; repcount--)
1700 pci_config_wr32(hdlp, d++, *h++);
1701 else
1702 for (; repcount; repcount--)
1703 pci_config_wr32(hdlp, d, *h++);
1704 }
1705
1706 uint64_t
pci_config_rd64(ddi_acc_impl_t * hdlp,uint64_t * addr)1707 pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr)
1708 {
1709 uint32_t lw_val;
1710 uint32_t hi_val;
1711 uint32_t *dp;
1712 uint64_t val;
1713
1714 dp = (uint32_t *)addr;
1715 lw_val = pci_config_rd32(hdlp, dp);
1716 dp++;
1717 hi_val = pci_config_rd32(hdlp, dp);
1718 val = ((uint64_t)hi_val << 32) | lw_val;
1719 return (val);
1720 }
1721
1722 void
pci_config_wr64(ddi_acc_impl_t * hdlp,uint64_t * addr,uint64_t value)1723 pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value)
1724 {
1725 uint32_t lw_val;
1726 uint32_t hi_val;
1727 uint32_t *dp;
1728
1729 dp = (uint32_t *)addr;
1730 lw_val = (uint32_t)(value & 0xffffffff);
1731 hi_val = (uint32_t)(value >> 32);
1732 pci_config_wr32(hdlp, dp, lw_val);
1733 dp++;
1734 pci_config_wr32(hdlp, dp, hi_val);
1735 }
1736
1737 void
pci_config_rep_rd64(ddi_acc_impl_t * hdlp,uint64_t * host_addr,uint64_t * dev_addr,size_t repcount,uint_t flags)1738 pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
1739 uint64_t *dev_addr, size_t repcount, uint_t flags)
1740 {
1741 if (flags == DDI_DEV_AUTOINCR) {
1742 for (; repcount; repcount--)
1743 *host_addr++ = pci_config_rd64(hdlp, dev_addr++);
1744 } else {
1745 for (; repcount; repcount--)
1746 *host_addr++ = pci_config_rd64(hdlp, dev_addr);
1747 }
1748 }
1749
1750 void
pci_config_rep_wr64(ddi_acc_impl_t * hdlp,uint64_t * host_addr,uint64_t * dev_addr,size_t repcount,uint_t flags)1751 pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
1752 uint64_t *dev_addr, size_t repcount, uint_t flags)
1753 {
1754 if (flags == DDI_DEV_AUTOINCR) {
1755 for (; repcount; repcount--)
1756 pci_config_wr64(hdlp, host_addr++, *dev_addr++);
1757 } else {
1758 for (; repcount; repcount--)
1759 pci_config_wr64(hdlp, host_addr++, *dev_addr);
1760 }
1761 }
1762