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