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