3557 dumpvp_size is not updated correctly when a dump zvol's size is changed
[unleashed.git] / usr / src / uts / common / io / pci_intr_lib.c
bloba73ef1a08eb21d525459f75cc6e67e8caa693137
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * Support for MSI, MSIX and INTx
30 #include <sys/conf.h>
31 #include <sys/debug.h>
32 #include <sys/pci.h>
33 #include <sys/pci_cap.h>
34 #include <sys/pci_intr_lib.h>
35 #include <sys/sunddi.h>
36 #include <sys/bitmap.h>
39 * MSI-X BIR Index Table:
41 * BAR indicator register (BIR) to Base Address register.
43 static uchar_t pci_msix_bir_index[8] = {0x10, 0x14, 0x18, 0x1c,
44 0x20, 0x24, 0xff, 0xff};
46 /* default class to pil value mapping */
47 pci_class_val_t pci_default_pil [] = {
48 {0x000000, 0xff0000, 0x1}, /* Class code for pre-2.0 devices */
49 {0x010000, 0xff0000, 0x5}, /* Mass Storage Controller */
50 {0x020000, 0xff0000, 0x6}, /* Network Controller */
51 {0x030000, 0xff0000, 0x9}, /* Display Controller */
52 {0x040000, 0xff0000, 0x8}, /* Multimedia Controller */
53 {0x050000, 0xff0000, 0x9}, /* Memory Controller */
54 {0x060000, 0xff0000, 0x9}, /* Bridge Controller */
55 {0x0c0000, 0xffff00, 0x9}, /* Serial Bus, FireWire (IEEE 1394) */
56 {0x0c0100, 0xffff00, 0x4}, /* Serial Bus, ACCESS.bus */
57 {0x0c0200, 0xffff00, 0x4}, /* Serial Bus, SSA */
58 {0x0c0300, 0xffff00, 0x9}, /* Serial Bus Universal Serial Bus */
60 * XXX - This is a temporary workaround and it will be removed
61 * after x86 interrupt scalability support.
63 #if defined(__i386) || defined(__amd64)
64 {0x0c0400, 0xffff00, 0x5}, /* Serial Bus, Fibre Channel */
65 #else
66 {0x0c0400, 0xffff00, 0x6}, /* Serial Bus, Fibre Channel */
67 #endif
68 {0x0c0600, 0xffff00, 0x6} /* Serial Bus, Infiniband */
72 * Default class to intr_weight value mapping (% of CPU). A driver.conf
73 * entry on or above the pci node like
75 * pci-class-intr-weights= 0x020000, 0xff0000, 30;
77 * can be used to augment or override entries in the default table below.
79 * NB: The values below give NICs preference on redistribution, and provide
80 * NICs some isolation from other interrupt sources. We need better interfaces
81 * that allow the NIC driver to identify a specific NIC instance as high
82 * bandwidth, and thus deserving of separation from other low bandwidth
83 * NICs additional isolation from other interrupt sources.
85 * NB: We treat Infiniband like a NIC.
87 pci_class_val_t pci_default_intr_weight [] = {
88 {0x020000, 0xff0000, 35}, /* Network Controller */
89 {0x010000, 0xff0000, 10}, /* Mass Storage Controller */
90 {0x0c0400, 0xffff00, 10}, /* Serial Bus, Fibre Channel */
91 {0x0c0600, 0xffff00, 50} /* Serial Bus, Infiniband */
95 * Library utility functions
99 * pci_get_msi_ctrl:
101 * Helper function that returns with 'cfg_hdl', MSI/X ctrl pointer,
102 * and caps_ptr for MSI/X if these are found.
104 static int
105 pci_get_msi_ctrl(dev_info_t *dip, int type, ushort_t *msi_ctrl,
106 ushort_t *caps_ptr, ddi_acc_handle_t *h)
108 *msi_ctrl = *caps_ptr = 0;
110 if (pci_config_setup(dip, h) != DDI_SUCCESS) {
111 DDI_INTR_NEXDBG((CE_CONT, "pci_get_msi_ctrl: "
112 "%s%d can't get config handle",
113 ddi_driver_name(dip), ddi_get_instance(dip)));
115 return (DDI_FAILURE);
118 if ((PCI_CAP_LOCATE(*h, PCI_CAP_ID_MSI, caps_ptr) == DDI_SUCCESS) &&
119 (type == DDI_INTR_TYPE_MSI)) {
120 if ((*msi_ctrl = PCI_CAP_GET16(*h, NULL, *caps_ptr,
121 PCI_MSI_CTRL)) == PCI_CAP_EINVAL16)
122 goto done;
124 DDI_INTR_NEXDBG((CE_CONT, "pci_get_msi_ctrl: MSI "
125 "caps_ptr=%x msi_ctrl=%x\n", *caps_ptr, *msi_ctrl));
127 return (DDI_SUCCESS);
130 if ((PCI_CAP_LOCATE(*h, PCI_CAP_ID_MSI_X, caps_ptr) == DDI_SUCCESS) &&
131 (type == DDI_INTR_TYPE_MSIX)) {
132 if ((*msi_ctrl = PCI_CAP_GET16(*h, NULL, *caps_ptr,
133 PCI_MSIX_CTRL)) == PCI_CAP_EINVAL16)
134 goto done;
136 DDI_INTR_NEXDBG((CE_CONT, "pci_get_msi_ctrl: MSI-X "
137 "caps_ptr=%x msi_ctrl=%x\n", *caps_ptr, *msi_ctrl));
139 return (DDI_SUCCESS);
142 done:
143 pci_config_teardown(h);
144 return (DDI_FAILURE);
149 * pci_msi_get_cap:
151 * Get the capabilities of the MSI/X interrupt
154 pci_msi_get_cap(dev_info_t *rdip, int type, int *flagsp)
156 ushort_t caps_ptr, msi_ctrl;
157 ddi_acc_handle_t cfg_hdle;
159 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_get_cap: rdip = 0x%p\n",
160 (void *)rdip));
162 *flagsp = 0;
164 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl,
165 &caps_ptr, &cfg_hdle) != DDI_SUCCESS)
166 return (DDI_FAILURE);
168 if (type == DDI_INTR_TYPE_MSI) {
169 if (msi_ctrl & PCI_MSI_64BIT_MASK)
170 *flagsp |= DDI_INTR_FLAG_MSI64;
171 if (msi_ctrl & PCI_MSI_PVM_MASK)
172 *flagsp |= (DDI_INTR_FLAG_MASKABLE |
173 DDI_INTR_FLAG_PENDING);
174 else
175 *flagsp |= DDI_INTR_FLAG_BLOCK;
176 } else if (type == DDI_INTR_TYPE_MSIX) {
177 /* MSI-X supports PVM, 64bit by default */
178 *flagsp |= (DDI_INTR_FLAG_MASKABLE | DDI_INTR_FLAG_MSI64 |
179 DDI_INTR_FLAG_PENDING);
182 *flagsp |= DDI_INTR_FLAG_EDGE;
184 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_get_cap: flags = 0x%x\n", *flagsp));
186 pci_config_teardown(&cfg_hdle);
187 return (DDI_SUCCESS);
192 * pci_msi_configure:
194 * Configure address/data and number MSI/Xs fields in the MSI/X
195 * capability structure.
197 /* ARGSUSED */
199 pci_msi_configure(dev_info_t *rdip, int type, int count, int inum,
200 uint64_t addr, uint64_t data)
202 ushort_t caps_ptr, msi_ctrl;
203 ddi_acc_handle_t h;
205 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_configure: rdip = 0x%p type 0x%x "
206 "count 0x%x inum 0x%x addr 0x%" PRIx64 " data 0x%" PRIx64 "\n",
207 (void *)rdip, type, count, inum, addr, data));
209 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl,
210 &caps_ptr, &h) != DDI_SUCCESS)
211 return (DDI_FAILURE);
213 if (type == DDI_INTR_TYPE_MSI) {
214 /* Set the bits to inform how many MSIs are enabled */
215 msi_ctrl |= ((highbit(count) -1) << PCI_MSI_MME_SHIFT);
216 PCI_CAP_PUT16(h, NULL, caps_ptr, PCI_MSI_CTRL, msi_ctrl);
218 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_configure: msi_ctrl = %x\n",
219 PCI_CAP_GET16(h, NULL, caps_ptr, PCI_MSI_CTRL)));
221 /* Set the "data" and "addr" bits */
222 PCI_CAP_PUT32(h, NULL, caps_ptr, PCI_MSI_ADDR_OFFSET, addr);
224 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_configure: msi_addr = %x\n",
225 PCI_CAP_GET32(h, NULL, caps_ptr, PCI_MSI_ADDR_OFFSET)));
227 if (msi_ctrl & PCI_MSI_64BIT_MASK) {
228 PCI_CAP_PUT32(h, NULL, caps_ptr, PCI_MSI_ADDR_OFFSET
229 + 4, addr >> 32);
231 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_configure: upper "
232 "32bit msi_addr = %x\n", PCI_CAP_GET32(h, NULL,
233 caps_ptr, PCI_MSI_ADDR_OFFSET + 4)));
235 PCI_CAP_PUT16(h, NULL, caps_ptr, PCI_MSI_64BIT_DATA,
236 data);
238 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_configure: msi_data "
239 "= %x\n", PCI_CAP_GET16(h, NULL, caps_ptr,
240 PCI_MSI_64BIT_DATA)));
241 } else {
242 PCI_CAP_PUT16(h, NULL, caps_ptr, PCI_MSI_32BIT_DATA,
243 data);
245 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_configure: msi_data "
246 "= %x\n", PCI_CAP_GET16(h, NULL, caps_ptr,
247 PCI_MSI_32BIT_DATA)));
249 } else if (type == DDI_INTR_TYPE_MSIX) {
250 uintptr_t off;
251 ddi_intr_msix_t *msix_p = i_ddi_get_msix(rdip);
253 /* Offset into the "inum"th entry in the MSI-X table */
254 off = (uintptr_t)msix_p->msix_tbl_addr +
255 (inum * PCI_MSIX_VECTOR_SIZE);
257 /* Set the "data" and "addr" bits */
258 ddi_put32(msix_p->msix_tbl_hdl,
259 (uint32_t *)(off + PCI_MSIX_DATA_OFFSET), data);
261 ddi_put64(msix_p->msix_tbl_hdl,
262 (uint64_t *)(off + PCI_MSIX_LOWER_ADDR_OFFSET), addr);
264 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_configure: "
265 "msix_addr 0x%" PRIx64 " msix_data 0x%x\n",
266 ddi_get64(msix_p->msix_tbl_hdl,
267 (uint64_t *)(off + PCI_MSIX_LOWER_ADDR_OFFSET)),
268 ddi_get32(msix_p->msix_tbl_hdl,
269 (uint32_t *)(off + PCI_MSIX_DATA_OFFSET))));
272 pci_config_teardown(&h);
273 return (DDI_SUCCESS);
278 * pci_msi_unconfigure:
280 * Unconfigure address/data and number MSI/Xs fields in the MSI/X
281 * capability structure.
283 /* ARGSUSED */
285 pci_msi_unconfigure(dev_info_t *rdip, int type, int inum)
287 ushort_t msi_ctrl, caps_ptr;
288 ddi_acc_handle_t h;
290 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_unconfigure: rdip = 0x%p type 0x%x "
291 "inum 0x%x\n", (void *)rdip, type, inum));
293 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl, &caps_ptr, &h) !=
294 DDI_SUCCESS)
295 return (DDI_FAILURE);
297 if (type == DDI_INTR_TYPE_MSI) {
298 msi_ctrl &= (~PCI_MSI_MME_MASK);
299 PCI_CAP_PUT16(h, NULL, caps_ptr, PCI_MSI_CTRL, msi_ctrl);
301 PCI_CAP_PUT32(h, NULL, caps_ptr, PCI_MSI_ADDR_OFFSET, 0);
303 if (msi_ctrl & PCI_MSI_64BIT_MASK) {
304 PCI_CAP_PUT16(h, NULL, caps_ptr, PCI_MSI_64BIT_DATA,
306 PCI_CAP_PUT32(h, NULL, caps_ptr, PCI_MSI_ADDR_OFFSET
307 + 4, 0);
308 } else {
309 PCI_CAP_PUT16(h, NULL, caps_ptr, PCI_MSI_32BIT_DATA,
313 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_unconfigure: msi_ctrl "
314 "= %x\n", PCI_CAP_GET16(h, NULL, caps_ptr, PCI_MSI_CTRL)));
316 } else if (type == DDI_INTR_TYPE_MSIX) {
317 uintptr_t off;
318 ddi_intr_msix_t *msix_p = i_ddi_get_msix(rdip);
320 /* Offset into the "inum"th entry in the MSI-X table */
321 off = (uintptr_t)msix_p->msix_tbl_addr +
322 (inum * PCI_MSIX_VECTOR_SIZE);
324 /* Reset the "data" and "addr" bits */
325 ddi_put32(msix_p->msix_tbl_hdl,
326 (uint32_t *)(off + PCI_MSIX_DATA_OFFSET), 0);
328 ddi_put64(msix_p->msix_tbl_hdl,
329 (uint64_t *)(off + PCI_MSIX_LOWER_ADDR_OFFSET), 0);
332 pci_config_teardown(&h);
333 return (DDI_SUCCESS);
338 * pci_is_msi_enabled:
340 * This function returns DDI_SUCCESS if MSI/X is already enabled, otherwise
341 * it returns DDI_FAILURE.
344 pci_is_msi_enabled(dev_info_t *rdip, int type)
346 ushort_t caps_ptr, msi_ctrl;
347 ddi_acc_handle_t cfg_hdle;
348 int ret = DDI_FAILURE;
350 DDI_INTR_NEXDBG((CE_CONT, "pci_is_msi_enabled: rdip = 0x%p, "
351 "type = 0x%x\n", (void *)rdip, type));
353 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl,
354 &caps_ptr, &cfg_hdle) != DDI_SUCCESS)
355 return (DDI_FAILURE);
357 if ((type == DDI_INTR_TYPE_MSI) && (msi_ctrl & PCI_MSI_ENABLE_BIT))
358 ret = DDI_SUCCESS;
360 if ((type == DDI_INTR_TYPE_MSIX) && (msi_ctrl & PCI_MSIX_ENABLE_BIT))
361 ret = DDI_SUCCESS;
363 pci_config_teardown(&cfg_hdle);
364 return (ret);
369 * pci_msi_enable_mode:
371 * This function sets the MSI_ENABLE bit in the capability structure
372 * (for MSI) and MSIX_ENABLE bit in the MSI-X capability structure.
374 * NOTE: It is the nexus driver's responsibility to clear the MSI/X
375 * interrupt's mask bit in the MSI/X capability structure before the
376 * interrupt can be used.
379 pci_msi_enable_mode(dev_info_t *rdip, int type)
381 ushort_t caps_ptr, msi_ctrl;
382 ddi_acc_handle_t cfg_hdle;
384 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_enable_mode: rdip = 0x%p\n",
385 (void *)rdip));
387 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl,
388 &caps_ptr, &cfg_hdle) != DDI_SUCCESS)
389 return (DDI_FAILURE);
391 if (type == DDI_INTR_TYPE_MSI) {
392 if (msi_ctrl & PCI_MSI_ENABLE_BIT)
393 goto finished;
395 msi_ctrl |= PCI_MSI_ENABLE_BIT;
396 PCI_CAP_PUT16(cfg_hdle, NULL, caps_ptr, PCI_MSI_CTRL, msi_ctrl);
398 } else if (type == DDI_INTR_TYPE_MSIX) {
399 if (msi_ctrl & PCI_MSIX_ENABLE_BIT)
400 goto finished;
402 msi_ctrl |= PCI_MSIX_ENABLE_BIT;
403 PCI_CAP_PUT16(cfg_hdle, NULL, caps_ptr, PCI_MSIX_CTRL,
404 msi_ctrl);
407 finished:
408 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_enable_mode: msi_ctrl = %x\n",
409 msi_ctrl));
411 pci_config_teardown(&cfg_hdle);
412 return (DDI_SUCCESS);
417 * pci_msi_disable_mode:
419 * This function resets the MSI_ENABLE bit in the capability structure
420 * (for MSI) and MSIX_ENABLE bit in the MSI-X capability structure.
422 * NOTE: It is the nexus driver's responsibility to set the MSI/X
423 * interrupt's mask bit in the MSI/X capability structure before the
424 * interrupt can be disabled.
427 pci_msi_disable_mode(dev_info_t *rdip, int type)
429 ushort_t caps_ptr, msi_ctrl;
430 ddi_acc_handle_t cfg_hdle;
432 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_disable_mode: rdip = 0x%p\n",
433 (void *)rdip));
435 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl,
436 &caps_ptr, &cfg_hdle) != DDI_SUCCESS)
437 return (DDI_FAILURE);
439 /* Reset the "enable" bit */
440 if (type == DDI_INTR_TYPE_MSI) {
441 if (!(msi_ctrl & PCI_MSI_ENABLE_BIT))
442 goto finished;
443 msi_ctrl &= ~PCI_MSI_ENABLE_BIT;
444 PCI_CAP_PUT16(cfg_hdle, NULL, caps_ptr, PCI_MSI_CTRL, msi_ctrl);
445 } else if (type == DDI_INTR_TYPE_MSIX) {
446 if (!(msi_ctrl & PCI_MSIX_ENABLE_BIT))
447 goto finished;
449 msi_ctrl &= ~PCI_MSIX_ENABLE_BIT;
450 PCI_CAP_PUT16(cfg_hdle, NULL, caps_ptr, PCI_MSIX_CTRL,
451 msi_ctrl);
454 finished:
455 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_disable_mode: msi_ctrl = %x\n",
456 msi_ctrl));
458 pci_config_teardown(&cfg_hdle);
459 return (DDI_SUCCESS);
464 * pci_msi_set_mask:
466 * Set the mask bit in the MSI/X capability structure
468 /* ARGSUSED */
470 pci_msi_set_mask(dev_info_t *rdip, int type, int inum)
472 int offset;
473 int ret = DDI_FAILURE;
474 ushort_t caps_ptr, msi_ctrl;
475 ddi_acc_handle_t cfg_hdle;
476 uint32_t mask_bits;
478 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_set_mask: rdip = 0x%p, "
479 "type = 0x%x\n", (void *)rdip, type));
481 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl,
482 &caps_ptr, &cfg_hdle) != DDI_SUCCESS)
483 return (DDI_FAILURE);
485 if (type == DDI_INTR_TYPE_MSI) {
486 if (!(msi_ctrl & PCI_MSI_PVM_MASK))
487 goto done;
489 offset = (msi_ctrl & PCI_MSI_64BIT_MASK) ?
490 PCI_MSI_64BIT_MASKBITS : PCI_MSI_32BIT_MASK;
492 if ((mask_bits = PCI_CAP_GET32(cfg_hdle, NULL, caps_ptr,
493 offset)) == PCI_CAP_EINVAL32)
494 goto done;
496 mask_bits |= (1 << inum);
498 PCI_CAP_PUT32(cfg_hdle, NULL, caps_ptr, offset, mask_bits);
500 } else if (type == DDI_INTR_TYPE_MSIX) {
501 uintptr_t off;
502 ddi_intr_msix_t *msix_p;
504 /* Set function mask */
505 if (msi_ctrl & PCI_MSIX_FUNCTION_MASK) {
506 ret = DDI_SUCCESS;
507 goto done;
510 msix_p = i_ddi_get_msix(rdip);
512 /* Offset into the "inum"th entry in the MSI-X table */
513 off = (uintptr_t)msix_p->msix_tbl_addr + (inum *
514 PCI_MSIX_VECTOR_SIZE) + PCI_MSIX_VECTOR_CTRL_OFFSET;
516 /* Set the Mask bit */
517 ddi_put32(msix_p->msix_tbl_hdl, (uint32_t *)off, 0x1);
520 ret = DDI_SUCCESS;
521 done:
522 pci_config_teardown(&cfg_hdle);
523 return (ret);
528 * pci_msi_clr_mask:
530 * Clear the mask bit in the MSI/X capability structure
532 /* ARGSUSED */
534 pci_msi_clr_mask(dev_info_t *rdip, int type, int inum)
536 ushort_t caps_ptr, msi_ctrl;
537 ddi_acc_handle_t cfg_hdle;
538 int offset;
539 int ret = DDI_FAILURE;
540 uint32_t mask_bits;
542 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_clr_mask: rdip = 0x%p, "
543 "type = 0x%x\n", (void *)rdip, type));
545 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl,
546 &caps_ptr, &cfg_hdle) != DDI_SUCCESS)
547 return (DDI_FAILURE);
549 if (type == DDI_INTR_TYPE_MSI) {
550 if (!(msi_ctrl & PCI_MSI_PVM_MASK))
551 goto done;
553 offset = (msi_ctrl & PCI_MSI_64BIT_MASK) ?
554 PCI_MSI_64BIT_MASKBITS : PCI_MSI_32BIT_MASK;
555 if ((mask_bits = PCI_CAP_GET32(cfg_hdle, NULL, caps_ptr,
556 offset)) == PCI_CAP_EINVAL32)
557 goto done;
559 mask_bits &= ~(1 << inum);
561 PCI_CAP_PUT32(cfg_hdle, NULL, caps_ptr, offset, mask_bits);
563 } else if (type == DDI_INTR_TYPE_MSIX) {
564 uintptr_t off;
565 ddi_intr_msix_t *msix_p;
567 if (msi_ctrl & PCI_MSIX_FUNCTION_MASK) {
568 ret = DDI_SUCCESS;
569 goto done;
572 msix_p = i_ddi_get_msix(rdip);
574 /* Offset into the "inum"th entry in the MSI-X table */
575 off = (uintptr_t)msix_p->msix_tbl_addr + (inum *
576 PCI_MSIX_VECTOR_SIZE) + PCI_MSIX_VECTOR_CTRL_OFFSET;
578 /* Clear the Mask bit */
579 ddi_put32(msix_p->msix_tbl_hdl, (uint32_t *)off, 0x0);
582 ret = DDI_SUCCESS;
583 done:
584 pci_config_teardown(&cfg_hdle);
585 return (ret);
590 * pci_msi_get_pending:
592 * Get the pending bit from the MSI/X capability structure
594 /* ARGSUSED */
596 pci_msi_get_pending(dev_info_t *rdip, int type, int inum, int *pendingp)
598 ushort_t caps_ptr, msi_ctrl;
599 ddi_acc_handle_t cfg_hdle;
600 int offset;
601 int ret = DDI_FAILURE;
603 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_get_pending: rdip = 0x%p\n",
604 (void *)rdip));
606 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl,
607 &caps_ptr, &cfg_hdle) != DDI_SUCCESS)
608 return (DDI_FAILURE);
610 if (type == DDI_INTR_TYPE_MSI) {
611 uint32_t pending_bits;
613 if (!(msi_ctrl & PCI_MSI_PVM_MASK)) {
614 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_get_pending: "
615 "PVM is not supported\n"));
616 goto done;
619 offset = (msi_ctrl & PCI_MSI_64BIT_MASK) ?
620 PCI_MSI_64BIT_PENDING : PCI_MSI_32BIT_PENDING;
622 if ((pending_bits = PCI_CAP_GET32(cfg_hdle, NULL, caps_ptr,
623 offset)) == PCI_CAP_EINVAL32)
624 goto done;
626 *pendingp = pending_bits & ~(1 >> inum);
628 } else if (type == DDI_INTR_TYPE_MSIX) {
629 uintptr_t off;
630 uint64_t pending_bits;
631 ddi_intr_msix_t *msix_p = i_ddi_get_msix(rdip);
633 /* Offset into the PBA array which has entry for "inum" */
634 off = (uintptr_t)msix_p->msix_pba_addr + (inum / 64);
636 /* Read the PBA array */
637 pending_bits = ddi_get64(msix_p->msix_pba_hdl, (uint64_t *)off);
639 *pendingp = pending_bits & ~(1 >> inum);
642 ret = DDI_SUCCESS;
643 done:
644 pci_config_teardown(&cfg_hdle);
645 return (ret);
650 * pci_msi_get_nintrs:
652 * For a given type (MSI/X) returns the number of interrupts supported
655 pci_msi_get_nintrs(dev_info_t *rdip, int type, int *nintrs)
657 ushort_t caps_ptr, msi_ctrl;
658 ddi_acc_handle_t cfg_hdle;
660 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_get_nintrs: rdip = 0x%p\n",
661 (void *)rdip));
663 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl,
664 &caps_ptr, &cfg_hdle) != DDI_SUCCESS)
665 return (DDI_FAILURE);
667 if (type == DDI_INTR_TYPE_MSI) {
668 *nintrs = 1 << ((msi_ctrl & PCI_MSI_MMC_MASK) >>
669 PCI_MSI_MMC_SHIFT);
670 } else if (type == DDI_INTR_TYPE_MSIX) {
671 if (msi_ctrl & PCI_MSIX_TBL_SIZE_MASK)
672 *nintrs = (msi_ctrl & PCI_MSIX_TBL_SIZE_MASK) + 1;
675 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_get_nintrs: "
676 "nintr = 0x%x\n", *nintrs));
678 pci_config_teardown(&cfg_hdle);
679 return (DDI_SUCCESS);
684 * pci_msi_set_nintrs:
686 * For a given type (MSI/X) sets the number of interrupts supported
687 * by the system.
688 * For MSI: Return an error if this func is called for navail > 32
689 * For MSI-X: Return an error if this func is called for navail > 2048
692 pci_msi_set_nintrs(dev_info_t *rdip, int type, int navail)
694 ushort_t caps_ptr, msi_ctrl;
695 ddi_acc_handle_t cfg_hdle;
697 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_set_nintrs: rdip = 0x%p, "
698 "navail = 0x%x\n", (void *)rdip, navail));
700 /* Check for valid input argument */
701 if (((type == DDI_INTR_TYPE_MSI) && (navail > PCI_MSI_MAX_INTRS)) ||
702 ((type == DDI_INTR_TYPE_MSIX) && (navail > PCI_MSIX_MAX_INTRS)))
703 return (DDI_EINVAL);
705 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl,
706 &caps_ptr, &cfg_hdle) != DDI_SUCCESS)
707 return (DDI_FAILURE);
709 if (type == DDI_INTR_TYPE_MSI) {
710 msi_ctrl |= ((highbit(navail) -1) << PCI_MSI_MME_SHIFT);
712 PCI_CAP_PUT16(cfg_hdle, NULL, caps_ptr, PCI_MSI_CTRL, msi_ctrl);
713 } else if (type == DDI_INTR_TYPE_MSIX) {
714 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_set_nintrs: unsupported\n"));
717 pci_config_teardown(&cfg_hdle);
718 return (DDI_SUCCESS);
723 * pci_msi_get_supported_type:
725 * Returns DDI_INTR_TYPE_MSI and/or DDI_INTR_TYPE_MSIX as supported
726 * types if device supports them. A DDI_FAILURE is returned otherwise.
729 pci_msi_get_supported_type(dev_info_t *rdip, int *typesp)
731 ushort_t caps_ptr, msi_ctrl;
732 ddi_acc_handle_t cfg_hdle;
734 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_get_supported_type: "
735 "rdip = 0x%p\n", (void *)rdip));
737 *typesp = 0;
739 if (pci_get_msi_ctrl(rdip, DDI_INTR_TYPE_MSI, &msi_ctrl,
740 &caps_ptr, &cfg_hdle) == DDI_SUCCESS) {
741 *typesp |= DDI_INTR_TYPE_MSI;
742 pci_config_teardown(&cfg_hdle);
745 if (pci_get_msi_ctrl(rdip, DDI_INTR_TYPE_MSIX, &msi_ctrl,
746 &caps_ptr, &cfg_hdle) == DDI_SUCCESS) {
747 *typesp |= DDI_INTR_TYPE_MSIX;
748 pci_config_teardown(&cfg_hdle);
751 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_get_supported_type: "
752 "rdip = 0x%p types 0x%x\n", (void *)rdip, *typesp));
754 return (*typesp == 0 ? DDI_FAILURE : DDI_SUCCESS);
759 * pci_msix_init:
760 * This function initializes the various handles/addrs etc.
761 * needed for MSI-X support. It also allocates a private
762 * structure to keep track of these.
764 ddi_intr_msix_t *
765 pci_msix_init(dev_info_t *rdip)
767 uint_t rnumber, breg, nregs;
768 size_t msix_tbl_size;
769 size_t pba_tbl_size;
770 ushort_t caps_ptr, msix_ctrl;
771 ddi_intr_msix_t *msix_p;
772 ddi_acc_handle_t cfg_hdle;
773 pci_regspec_t *rp;
774 int reg_size, addr_space, offset, *regs_list;
775 int i, ret;
777 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: rdip = %p\n", (void *)rdip));
779 if (pci_get_msi_ctrl(rdip, DDI_INTR_TYPE_MSIX, &msix_ctrl,
780 &caps_ptr, &cfg_hdle) != DDI_SUCCESS)
781 return (NULL);
783 msix_p = kmem_zalloc(sizeof (ddi_intr_msix_t), KM_SLEEP);
786 * Initialize the devacc structure
788 msix_p->msix_dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
789 msix_p->msix_dev_attr.devacc_attr_endian_flags =
790 DDI_STRUCTURE_LE_ACC;
791 msix_p->msix_dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
793 /* Map the entire MSI-X vector table */
794 msix_p->msix_tbl_offset = PCI_CAP_GET32(cfg_hdle, NULL, caps_ptr,
795 PCI_MSIX_TBL_OFFSET);
797 if ((breg = pci_msix_bir_index[msix_p->msix_tbl_offset &
798 PCI_MSIX_TBL_BIR_MASK]) == 0xff)
799 goto fail1;
801 msix_p->msix_tbl_offset = msix_p->msix_tbl_offset &
802 ~PCI_MSIX_TBL_BIR_MASK;
803 msix_tbl_size = ((msix_ctrl & PCI_MSIX_TBL_SIZE_MASK) + 1) *
804 PCI_MSIX_VECTOR_SIZE;
806 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: MSI-X table offset 0x%x "
807 "breg 0x%x size 0x%lx\n", msix_p->msix_tbl_offset, breg,
808 msix_tbl_size));
810 if ((ret = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip,
811 DDI_PROP_DONTPASS, "reg", (int **)&regs_list, &nregs))
812 != DDI_PROP_SUCCESS) {
813 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: "
814 "ddi_prop_lookup_int_array failed %d\n", ret));
816 goto fail1;
819 reg_size = sizeof (pci_regspec_t) / sizeof (int);
821 for (i = 1, rnumber = 0; i < nregs/reg_size; i++) {
822 rp = (pci_regspec_t *)&regs_list[i * reg_size];
823 addr_space = rp->pci_phys_hi & PCI_ADDR_MASK;
824 offset = PCI_REG_REG_G(rp->pci_phys_hi);
826 if ((offset == breg) && ((addr_space == PCI_ADDR_MEM32) ||
827 (addr_space == PCI_ADDR_MEM64))) {
828 rnumber = i;
829 break;
833 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: MSI-X rnum = %d\n", rnumber));
835 if (rnumber == 0) {
836 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: "
837 "no mtaching reg number for offset 0x%x\n", breg));
839 goto fail2;
842 if ((ret = ddi_regs_map_setup(rdip, rnumber,
843 (caddr_t *)&msix_p->msix_tbl_addr, msix_p->msix_tbl_offset,
844 msix_tbl_size, &msix_p->msix_dev_attr,
845 &msix_p->msix_tbl_hdl)) != DDI_SUCCESS) {
846 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: MSI-X Table "
847 "ddi_regs_map_setup failed %d\n", ret));
849 goto fail2;
853 * Map in the MSI-X Pending Bit Array
855 msix_p->msix_pba_offset = PCI_CAP_GET32(cfg_hdle, NULL, caps_ptr,
856 PCI_MSIX_PBA_OFFSET);
858 if ((breg = pci_msix_bir_index[msix_p->msix_pba_offset &
859 PCI_MSIX_PBA_BIR_MASK]) == 0xff)
860 goto fail3;
862 msix_p->msix_pba_offset = msix_p->msix_pba_offset &
863 ~PCI_MSIX_PBA_BIR_MASK;
864 pba_tbl_size = ((msix_ctrl & PCI_MSIX_TBL_SIZE_MASK) + 1)/8;
866 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: PBA table offset 0x%x "
867 "breg 0x%x size 0x%lx\n", msix_p->msix_pba_offset, breg,
868 pba_tbl_size));
870 for (i = 1, rnumber = 0; i < nregs/reg_size; i++) {
871 rp = (pci_regspec_t *)&regs_list[i * reg_size];
872 addr_space = rp->pci_phys_hi & PCI_ADDR_MASK;
873 offset = PCI_REG_REG_G(rp->pci_phys_hi);
875 if ((offset == breg) && ((addr_space == PCI_ADDR_MEM32) ||
876 (addr_space == PCI_ADDR_MEM64))) {
877 rnumber = i;
878 break;
882 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: PBA rnum = %d\n", rnumber));
884 if (rnumber == 0) {
885 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: "
886 "no matching reg number for offset 0x%x\n", breg));
888 goto fail3;
891 if ((ret = ddi_regs_map_setup(rdip, rnumber,
892 (caddr_t *)&msix_p->msix_pba_addr, msix_p->msix_pba_offset,
893 pba_tbl_size, &msix_p->msix_dev_attr,
894 &msix_p->msix_pba_hdl)) != DDI_SUCCESS) {
895 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: PBA "
896 "ddi_regs_map_setup failed %d\n", ret));
898 goto fail3;
901 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: msix_p = 0x%p DONE!!\n",
902 (void *)msix_p));
904 ddi_prop_free(regs_list);
905 goto done;
907 fail3:
908 ddi_regs_map_free(&msix_p->msix_tbl_hdl);
909 fail2:
910 ddi_prop_free(regs_list);
911 fail1:
912 kmem_free(msix_p, sizeof (ddi_intr_msix_t));
913 msix_p = NULL;
914 done:
915 pci_config_teardown(&cfg_hdle);
916 return (msix_p);
921 * pci_msix_fini:
922 * This function cleans up previously allocated handles/addrs etc.
923 * It is only called if no more MSI-X interrupts are being used.
925 void
926 pci_msix_fini(ddi_intr_msix_t *msix_p)
928 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_fini: msix_p = 0x%p\n",
929 (void *)msix_p));
931 ddi_regs_map_free(&msix_p->msix_pba_hdl);
932 ddi_regs_map_free(&msix_p->msix_tbl_hdl);
933 kmem_free(msix_p, sizeof (ddi_intr_msix_t));
938 * pci_msix_dup:
939 * This function duplicates the address and data pair of one msi-x
940 * vector to another msi-x vector.
943 pci_msix_dup(dev_info_t *rdip, int org_inum, int dup_inum)
945 ddi_intr_msix_t *msix_p = i_ddi_get_msix(rdip);
946 uint64_t addr;
947 uint64_t data;
948 uintptr_t off;
950 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_dup: dip = %p, inum = 0x%x, "
951 "to_vector = 0x%x\n", (void *)rdip, org_inum, dup_inum));
953 /* Offset into the original inum's entry in the MSI-X table */
954 off = (uintptr_t)msix_p->msix_tbl_addr +
955 (org_inum * PCI_MSIX_VECTOR_SIZE);
957 /* For the MSI-X number passed in, get the "data" and "addr" fields */
958 addr = ddi_get64(msix_p->msix_tbl_hdl,
959 (uint64_t *)(off + PCI_MSIX_LOWER_ADDR_OFFSET));
961 data = ddi_get32(msix_p->msix_tbl_hdl,
962 (uint32_t *)(off + PCI_MSIX_DATA_OFFSET));
964 /* Program new vector with these existing values */
965 return (pci_msi_configure(rdip, DDI_INTR_TYPE_MSIX, 1, dup_inum, addr,
966 data));
971 * Next set of routines are for INTx (legacy) PCI interrupt
972 * support only.
976 * pci_intx_get_cap:
977 * For non-MSI devices that comply to PCI v2.3 or greater;
978 * read the command register. Bit 10 implies interrupt disable.
979 * Set this bit and then read the status register bit 3.
980 * Bit 3 of status register is Interrupt state.
981 * If it is set; then the device supports 'Masking'
983 * Reset the device back to the original state.
986 pci_intx_get_cap(dev_info_t *dip, int *flagsp)
988 uint16_t cmdreg, savereg;
989 ddi_acc_handle_t cfg_hdl;
990 #ifdef DEBUG
991 uint16_t statreg;
992 #endif /* DEBUG */
994 *flagsp = 0;
995 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_get_cap: %s%d: called\n",
996 ddi_driver_name(dip), ddi_get_instance(dip)));
998 if (pci_config_setup(dip, &cfg_hdl) != DDI_SUCCESS) {
999 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_get_cap: can't get "
1000 "config handle\n"));
1001 return (DDI_FAILURE);
1004 savereg = pci_config_get16(cfg_hdl, PCI_CONF_COMM);
1005 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_get_cap: "
1006 "command register was 0x%x\n", savereg));
1008 /* Disable the interrupts */
1009 cmdreg = savereg | PCI_COMM_INTX_DISABLE;
1010 pci_config_put16(cfg_hdl, PCI_CONF_COMM, cmdreg);
1012 #ifdef DEBUG
1013 statreg = pci_config_get16(cfg_hdl, PCI_CONF_STAT);
1014 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_get_cap: "
1015 "status register is 0x%x\n", statreg));
1016 #endif /* DEBUG */
1018 /* Read the bit back */
1019 cmdreg = pci_config_get16(cfg_hdl, PCI_CONF_COMM);
1020 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_get_cap: "
1021 "command register is now 0x%x\n", cmdreg));
1023 *flagsp = DDI_INTR_FLAG_LEVEL;
1025 if (cmdreg & PCI_COMM_INTX_DISABLE) {
1026 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_get_cap: "
1027 "masking supported\n"));
1028 *flagsp |= (DDI_INTR_FLAG_MASKABLE |
1029 DDI_INTR_FLAG_PENDING);
1032 /* Restore the device back to the original state and return */
1033 pci_config_put16(cfg_hdl, PCI_CONF_COMM, savereg);
1035 pci_config_teardown(&cfg_hdl);
1036 return (DDI_SUCCESS);
1041 * pci_intx_clr_mask:
1042 * For non-MSI devices that comply to PCI v2.3 or greater;
1043 * clear the bit10 in the command register.
1046 pci_intx_clr_mask(dev_info_t *dip)
1048 uint16_t cmdreg;
1049 ddi_acc_handle_t cfg_hdl;
1051 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_clr_mask: %s%d: called\n",
1052 ddi_driver_name(dip), ddi_get_instance(dip)));
1054 if (pci_config_setup(dip, &cfg_hdl) != DDI_SUCCESS) {
1055 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_clr_mask: can't get "
1056 "config handle\n"));
1057 return (DDI_FAILURE);
1060 cmdreg = pci_config_get16(cfg_hdl, PCI_CONF_COMM);
1061 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_clr_mask: "
1062 "command register was 0x%x\n", cmdreg));
1064 /* Enable the interrupts */
1065 cmdreg &= ~PCI_COMM_INTX_DISABLE;
1066 pci_config_put16(cfg_hdl, PCI_CONF_COMM, cmdreg);
1067 pci_config_teardown(&cfg_hdl);
1068 return (DDI_SUCCESS);
1073 * pci_intx_set_mask:
1074 * For non-MSI devices that comply to PCI v2.3 or greater;
1075 * set the bit10 in the command register.
1078 pci_intx_set_mask(dev_info_t *dip)
1080 uint16_t cmdreg;
1081 ddi_acc_handle_t cfg_hdl;
1083 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_set_mask: %s%d: called\n",
1084 ddi_driver_name(dip), ddi_get_instance(dip)));
1086 if (pci_config_setup(dip, &cfg_hdl) != DDI_SUCCESS) {
1087 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_set_mask: can't get "
1088 "config handle\n"));
1089 return (DDI_FAILURE);
1092 cmdreg = pci_config_get16(cfg_hdl, PCI_CONF_COMM);
1093 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_set_mask: "
1094 "command register was 0x%x\n", cmdreg));
1096 /* Disable the interrupts */
1097 cmdreg |= PCI_COMM_INTX_DISABLE;
1098 pci_config_put16(cfg_hdl, PCI_CONF_COMM, cmdreg);
1099 pci_config_teardown(&cfg_hdl);
1100 return (DDI_SUCCESS);
1104 * pci_intx_get_pending:
1105 * For non-MSI devices that comply to PCI v2.3 or greater;
1106 * read the status register. Bit 3 of status register is
1107 * Interrupt state. If it is set; then the interrupt is
1108 * 'Pending'.
1111 pci_intx_get_pending(dev_info_t *dip, int *pendingp)
1113 uint16_t statreg;
1114 ddi_acc_handle_t cfg_hdl;
1116 *pendingp = 0;
1117 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_get_pending: %s%d: called\n",
1118 ddi_driver_name(dip), ddi_get_instance(dip)));
1120 if (pci_config_setup(dip, &cfg_hdl) != DDI_SUCCESS) {
1121 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_get_pending: can't get "
1122 "config handle\n"));
1123 return (DDI_FAILURE);
1126 statreg = pci_config_get16(cfg_hdl, PCI_CONF_STAT);
1128 if (statreg & PCI_STAT_INTR) {
1129 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_get_pending: "
1130 "interrupt is pending\n"));
1131 *pendingp = 1;
1134 pci_config_teardown(&cfg_hdl);
1135 return (DDI_SUCCESS);
1140 * pci_intx_get_ispec:
1141 * Get intrspec for PCI devices (legacy support)
1142 * NOTE: This is moved here from x86 pci.c and is
1143 * needed here as pci-ide.c uses it as well
1145 /*ARGSUSED*/
1146 ddi_intrspec_t
1147 pci_intx_get_ispec(dev_info_t *dip, dev_info_t *rdip, int inum)
1149 int *intpriorities;
1150 uint_t num_intpriorities;
1151 struct intrspec *ispec;
1152 ddi_acc_handle_t cfg_hdl;
1153 struct ddi_parent_private_data *pdptr;
1155 if ((pdptr = ddi_get_parent_data(rdip)) == NULL)
1156 return (NULL);
1158 ispec = pdptr->par_intr;
1159 ASSERT(ispec);
1161 /* check if the intrspec_pri has been initialized */
1162 if (!ispec->intrspec_pri) {
1163 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip,
1164 DDI_PROP_DONTPASS, "interrupt-priorities",
1165 &intpriorities, &num_intpriorities) == DDI_PROP_SUCCESS) {
1166 if (inum < num_intpriorities)
1167 ispec->intrspec_pri = intpriorities[inum];
1168 ddi_prop_free(intpriorities);
1171 /* If still no priority, guess based on the class code */
1172 if (ispec->intrspec_pri == 0)
1173 ispec->intrspec_pri = pci_class_to_pil(rdip);
1176 /* Get interrupt line value */
1177 if (!ispec->intrspec_vec) {
1178 if (pci_config_setup(rdip, &cfg_hdl) != DDI_SUCCESS) {
1179 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_get_iline: "
1180 "can't get config handle\n"));
1181 return ((ddi_intrspec_t)ispec);
1184 ispec->intrspec_vec = pci_config_get8(cfg_hdl, PCI_CONF_ILINE);
1185 pci_config_teardown(&cfg_hdl);
1188 return ((ddi_intrspec_t)ispec);
1191 static uint32_t
1192 pci_match_class_val(uint32_t key, pci_class_val_t *rec_p, int nrec,
1193 uint32_t default_val)
1195 int i;
1197 for (i = 0; i < nrec; rec_p++, i++) {
1198 if ((rec_p->class_code & rec_p->class_mask) ==
1199 (key & rec_p->class_mask))
1200 return (rec_p->class_val);
1203 return (default_val);
1207 * Return the configuration value, based on class code and sub class code,
1208 * from the specified property based or default pci_class_val_t table.
1210 uint32_t
1211 pci_class_to_val(dev_info_t *rdip, char *property_name, pci_class_val_t *rec_p,
1212 int nrec, uint32_t default_val)
1214 int property_len;
1215 uint32_t class_code;
1216 pci_class_val_t *conf;
1217 uint32_t val = default_val;
1220 * Use the "class-code" property to get the base and sub class
1221 * codes for the requesting device.
1223 class_code = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY, rdip,
1224 DDI_PROP_DONTPASS, "class-code", -1);
1226 if (class_code == -1)
1227 return (val);
1229 /* look up the val from the default table */
1230 val = pci_match_class_val(class_code, rec_p, nrec, val);
1233 /* see if there is a more specific property specified value */
1234 if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_NOTPROM,
1235 property_name, (caddr_t)&conf, &property_len))
1236 return (val);
1238 if ((property_len % sizeof (pci_class_val_t)) == 0)
1239 val = pci_match_class_val(class_code, conf,
1240 property_len / sizeof (pci_class_val_t), val);
1241 kmem_free(conf, property_len);
1242 return (val);
1246 * pci_class_to_pil:
1248 * Return the pil for a given PCI device.
1250 uint32_t
1251 pci_class_to_pil(dev_info_t *rdip)
1253 uint32_t pil;
1255 /* Default pil is 1 */
1256 pil = pci_class_to_val(rdip,
1257 "pci-class-priorities", pci_default_pil,
1258 sizeof (pci_default_pil) / sizeof (pci_class_val_t), 1);
1260 /* Range check the result */
1261 if (pil >= 0xf)
1262 pil = 1;
1264 return (pil);
1268 * pci_class_to_intr_weight:
1270 * Return the intr_weight for a given PCI device.
1272 int32_t
1273 pci_class_to_intr_weight(dev_info_t *rdip)
1275 int32_t intr_weight;
1277 /* default weight is 0% */
1278 intr_weight = pci_class_to_val(rdip,
1279 "pci-class-intr-weights", pci_default_intr_weight,
1280 sizeof (pci_default_intr_weight) / sizeof (pci_class_val_t), 0);
1282 /* range check the result */
1283 if (intr_weight < 0)
1284 intr_weight = 0;
1285 if (intr_weight > 1000)
1286 intr_weight = 1000;
1288 return (intr_weight);