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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright 2013 Pluribus Networks, Inc.
28 * Support for MSI, MSIX and INTx
32 #include <sys/debug.h>
34 #include <sys/pci_cap.h>
35 #include <sys/pci_intr_lib.h>
36 #include <sys/sunddi.h>
37 #include <sys/bitmap.h>
40 * MSI-X BIR Index Table:
42 * BAR indicator register (BIR) to Base Address register.
44 static uchar_t pci_msix_bir_index
[8] = {0x10, 0x14, 0x18, 0x1c,
45 0x20, 0x24, 0xff, 0xff};
47 /* default class to pil value mapping */
48 pci_class_val_t pci_default_pil
[] = {
49 {0x000000, 0xff0000, 0x1}, /* Class code for pre-2.0 devices */
50 {0x010000, 0xff0000, 0x5}, /* Mass Storage Controller */
51 {0x020000, 0xff0000, 0x6}, /* Network Controller */
52 {0x030000, 0xff0000, 0x9}, /* Display Controller */
53 {0x040000, 0xff0000, 0x8}, /* Multimedia Controller */
54 {0x050000, 0xff0000, 0x9}, /* Memory Controller */
55 {0x060000, 0xff0000, 0x9}, /* Bridge Controller */
56 {0x0c0000, 0xffff00, 0x9}, /* Serial Bus, FireWire (IEEE 1394) */
57 {0x0c0100, 0xffff00, 0x4}, /* Serial Bus, ACCESS.bus */
58 {0x0c0200, 0xffff00, 0x4}, /* Serial Bus, SSA */
59 {0x0c0300, 0xffff00, 0x9}, /* Serial Bus Universal Serial Bus */
61 * XXX - This is a temporary workaround and it will be removed
62 * after x86 interrupt scalability support.
64 #if defined(__i386) || defined(__amd64)
65 {0x0c0400, 0xffff00, 0x5}, /* Serial Bus, Fibre Channel */
67 {0x0c0400, 0xffff00, 0x6}, /* Serial Bus, Fibre Channel */
69 {0x0c0600, 0xffff00, 0x6} /* Serial Bus, Infiniband */
73 * Default class to intr_weight value mapping (% of CPU). A driver.conf
74 * entry on or above the pci node like
76 * pci-class-intr-weights= 0x020000, 0xff0000, 30;
78 * can be used to augment or override entries in the default table below.
80 * NB: The values below give NICs preference on redistribution, and provide
81 * NICs some isolation from other interrupt sources. We need better interfaces
82 * that allow the NIC driver to identify a specific NIC instance as high
83 * bandwidth, and thus deserving of separation from other low bandwidth
84 * NICs additional isolation from other interrupt sources.
86 * NB: We treat Infiniband like a NIC.
88 pci_class_val_t pci_default_intr_weight
[] = {
89 {0x020000, 0xff0000, 35}, /* Network Controller */
90 {0x010000, 0xff0000, 10}, /* Mass Storage Controller */
91 {0x0c0400, 0xffff00, 10}, /* Serial Bus, Fibre Channel */
92 {0x0c0600, 0xffff00, 50} /* Serial Bus, Infiniband */
96 * Library utility functions
102 * Helper function that returns with 'cfg_hdl', MSI/X ctrl pointer,
103 * and caps_ptr for MSI/X if these are found.
106 pci_get_msi_ctrl(dev_info_t
*dip
, int type
, ushort_t
*msi_ctrl
,
107 ushort_t
*caps_ptr
, ddi_acc_handle_t
*h
)
109 *msi_ctrl
= *caps_ptr
= 0;
111 if (pci_config_setup(dip
, h
) != DDI_SUCCESS
) {
112 DDI_INTR_NEXDBG((CE_CONT
, "pci_get_msi_ctrl: "
113 "%s%d can't get config handle",
114 ddi_driver_name(dip
), ddi_get_instance(dip
)));
116 return (DDI_FAILURE
);
119 if ((PCI_CAP_LOCATE(*h
, PCI_CAP_ID_MSI
, caps_ptr
) == DDI_SUCCESS
) &&
120 (type
== DDI_INTR_TYPE_MSI
)) {
121 if ((*msi_ctrl
= PCI_CAP_GET16(*h
, NULL
, *caps_ptr
,
122 PCI_MSI_CTRL
)) == PCI_CAP_EINVAL16
)
125 DDI_INTR_NEXDBG((CE_CONT
, "pci_get_msi_ctrl: MSI "
126 "caps_ptr=%x msi_ctrl=%x\n", *caps_ptr
, *msi_ctrl
));
128 return (DDI_SUCCESS
);
131 if ((PCI_CAP_LOCATE(*h
, PCI_CAP_ID_MSI_X
, caps_ptr
) == DDI_SUCCESS
) &&
132 (type
== DDI_INTR_TYPE_MSIX
)) {
133 if ((*msi_ctrl
= PCI_CAP_GET16(*h
, NULL
, *caps_ptr
,
134 PCI_MSIX_CTRL
)) == PCI_CAP_EINVAL16
)
137 DDI_INTR_NEXDBG((CE_CONT
, "pci_get_msi_ctrl: MSI-X "
138 "caps_ptr=%x msi_ctrl=%x\n", *caps_ptr
, *msi_ctrl
));
140 return (DDI_SUCCESS
);
144 pci_config_teardown(h
);
145 return (DDI_FAILURE
);
152 * Get the capabilities of the MSI/X interrupt
155 pci_msi_get_cap(dev_info_t
*rdip
, int type
, int *flagsp
)
157 ushort_t caps_ptr
, msi_ctrl
;
158 ddi_acc_handle_t cfg_hdle
;
160 DDI_INTR_NEXDBG((CE_CONT
, "pci_msi_get_cap: rdip = 0x%p\n",
165 if (pci_get_msi_ctrl(rdip
, type
, &msi_ctrl
,
166 &caps_ptr
, &cfg_hdle
) != DDI_SUCCESS
)
167 return (DDI_FAILURE
);
169 if (type
== DDI_INTR_TYPE_MSI
) {
170 if (msi_ctrl
& PCI_MSI_64BIT_MASK
)
171 *flagsp
|= DDI_INTR_FLAG_MSI64
;
172 if (msi_ctrl
& PCI_MSI_PVM_MASK
)
173 *flagsp
|= (DDI_INTR_FLAG_MASKABLE
|
174 DDI_INTR_FLAG_PENDING
);
176 *flagsp
|= DDI_INTR_FLAG_BLOCK
;
177 } else if (type
== DDI_INTR_TYPE_MSIX
) {
178 /* MSI-X supports PVM, 64bit by default */
179 *flagsp
|= (DDI_INTR_FLAG_MASKABLE
| DDI_INTR_FLAG_MSI64
|
180 DDI_INTR_FLAG_PENDING
);
183 *flagsp
|= DDI_INTR_FLAG_EDGE
;
185 DDI_INTR_NEXDBG((CE_CONT
, "pci_msi_get_cap: flags = 0x%x\n", *flagsp
));
187 pci_config_teardown(&cfg_hdle
);
188 return (DDI_SUCCESS
);
195 * Configure address/data and number MSI/Xs fields in the MSI/X
196 * capability structure.
200 pci_msi_configure(dev_info_t
*rdip
, int type
, int count
, int inum
,
201 uint64_t addr
, uint64_t data
)
203 ushort_t caps_ptr
, msi_ctrl
;
206 DDI_INTR_NEXDBG((CE_CONT
, "pci_msi_configure: rdip = 0x%p type 0x%x "
207 "count 0x%x inum 0x%x addr 0x%" PRIx64
" data 0x%" PRIx64
"\n",
208 (void *)rdip
, type
, count
, inum
, addr
, data
));
210 if (pci_get_msi_ctrl(rdip
, type
, &msi_ctrl
,
211 &caps_ptr
, &h
) != DDI_SUCCESS
)
212 return (DDI_FAILURE
);
214 if (type
== DDI_INTR_TYPE_MSI
) {
215 /* Set the bits to inform how many MSIs are enabled */
216 msi_ctrl
|= ((highbit(count
) -1) << PCI_MSI_MME_SHIFT
);
217 PCI_CAP_PUT16(h
, NULL
, caps_ptr
, PCI_MSI_CTRL
, msi_ctrl
);
219 DDI_INTR_NEXDBG((CE_CONT
, "pci_msi_configure: msi_ctrl = %x\n",
220 PCI_CAP_GET16(h
, NULL
, caps_ptr
, PCI_MSI_CTRL
)));
222 /* Set the "data" and "addr" bits */
223 PCI_CAP_PUT32(h
, NULL
, caps_ptr
, PCI_MSI_ADDR_OFFSET
, addr
);
225 DDI_INTR_NEXDBG((CE_CONT
, "pci_msi_configure: msi_addr = %x\n",
226 PCI_CAP_GET32(h
, NULL
, caps_ptr
, PCI_MSI_ADDR_OFFSET
)));
228 if (msi_ctrl
& PCI_MSI_64BIT_MASK
) {
229 PCI_CAP_PUT32(h
, NULL
, caps_ptr
, PCI_MSI_ADDR_OFFSET
232 DDI_INTR_NEXDBG((CE_CONT
, "pci_msi_configure: upper "
233 "32bit msi_addr = %x\n", PCI_CAP_GET32(h
, NULL
,
234 caps_ptr
, PCI_MSI_ADDR_OFFSET
+ 4)));
236 PCI_CAP_PUT16(h
, NULL
, caps_ptr
, PCI_MSI_64BIT_DATA
,
239 DDI_INTR_NEXDBG((CE_CONT
, "pci_msi_configure: msi_data "
240 "= %x\n", PCI_CAP_GET16(h
, NULL
, caps_ptr
,
241 PCI_MSI_64BIT_DATA
)));
243 PCI_CAP_PUT16(h
, NULL
, caps_ptr
, PCI_MSI_32BIT_DATA
,
246 DDI_INTR_NEXDBG((CE_CONT
, "pci_msi_configure: msi_data "
247 "= %x\n", PCI_CAP_GET16(h
, NULL
, caps_ptr
,
248 PCI_MSI_32BIT_DATA
)));
250 } else if (type
== DDI_INTR_TYPE_MSIX
) {
252 ddi_intr_msix_t
*msix_p
= i_ddi_get_msix(rdip
);
254 /* Offset into the "inum"th entry in the MSI-X table */
255 off
= (uintptr_t)msix_p
->msix_tbl_addr
+
256 (inum
* PCI_MSIX_VECTOR_SIZE
);
258 /* Set the "data" and "addr" bits */
259 ddi_put32(msix_p
->msix_tbl_hdl
,
260 (uint32_t *)(off
+ PCI_MSIX_DATA_OFFSET
), data
);
263 * Note that the spec only requires 32-bit accesses
264 * to be supported. Apparently some chipsets don't
265 * support 64-bit accesses.
267 ddi_put32(msix_p
->msix_tbl_hdl
,
268 (uint32_t *)(off
+ PCI_MSIX_LOWER_ADDR_OFFSET
), addr
);
269 ddi_put32(msix_p
->msix_tbl_hdl
,
270 (uint32_t *)(off
+ PCI_MSIX_UPPER_ADDR_OFFSET
),
273 DDI_INTR_NEXDBG((CE_CONT
, "pci_msi_configure: "
274 "msix_addr 0x%x.%x msix_data 0x%x\n",
275 ddi_get32(msix_p
->msix_tbl_hdl
,
276 (uint32_t *)(off
+ PCI_MSIX_UPPER_ADDR_OFFSET
)),
277 ddi_get32(msix_p
->msix_tbl_hdl
,
278 (uint32_t *)(off
+ PCI_MSIX_LOWER_ADDR_OFFSET
)),
279 ddi_get32(msix_p
->msix_tbl_hdl
,
280 (uint32_t *)(off
+ PCI_MSIX_DATA_OFFSET
))));
283 pci_config_teardown(&h
);
284 return (DDI_SUCCESS
);
289 * pci_msi_unconfigure:
291 * Unconfigure address/data and number MSI/Xs fields in the MSI/X
292 * capability structure.
296 pci_msi_unconfigure(dev_info_t
*rdip
, int type
, int inum
)
298 ushort_t msi_ctrl
, caps_ptr
;
301 DDI_INTR_NEXDBG((CE_CONT
, "pci_msi_unconfigure: rdip = 0x%p type 0x%x "
302 "inum 0x%x\n", (void *)rdip
, type
, inum
));
304 if (pci_get_msi_ctrl(rdip
, type
, &msi_ctrl
, &caps_ptr
, &h
) !=
306 return (DDI_FAILURE
);
308 if (type
== DDI_INTR_TYPE_MSI
) {
309 msi_ctrl
&= (~PCI_MSI_MME_MASK
);
310 PCI_CAP_PUT16(h
, NULL
, caps_ptr
, PCI_MSI_CTRL
, msi_ctrl
);
312 PCI_CAP_PUT32(h
, NULL
, caps_ptr
, PCI_MSI_ADDR_OFFSET
, 0);
314 if (msi_ctrl
& PCI_MSI_64BIT_MASK
) {
315 PCI_CAP_PUT16(h
, NULL
, caps_ptr
, PCI_MSI_64BIT_DATA
,
317 PCI_CAP_PUT32(h
, NULL
, caps_ptr
, PCI_MSI_ADDR_OFFSET
320 PCI_CAP_PUT16(h
, NULL
, caps_ptr
, PCI_MSI_32BIT_DATA
,
324 DDI_INTR_NEXDBG((CE_CONT
, "pci_msi_unconfigure: msi_ctrl "
325 "= %x\n", PCI_CAP_GET16(h
, NULL
, caps_ptr
, PCI_MSI_CTRL
)));
327 } else if (type
== DDI_INTR_TYPE_MSIX
) {
329 ddi_intr_msix_t
*msix_p
= i_ddi_get_msix(rdip
);
331 /* Offset into the "inum"th entry in the MSI-X table */
332 off
= (uintptr_t)msix_p
->msix_tbl_addr
+
333 (inum
* PCI_MSIX_VECTOR_SIZE
);
335 /* Reset the "data" and "addr" bits */
336 ddi_put32(msix_p
->msix_tbl_hdl
,
337 (uint32_t *)(off
+ PCI_MSIX_DATA_OFFSET
), 0);
340 * Note that the spec only requires 32-bit accesses
341 * to be supported. Apparently some chipsets don't
342 * support 64-bit accesses.
344 ddi_put32(msix_p
->msix_tbl_hdl
,
345 (uint32_t *)(off
+ PCI_MSIX_LOWER_ADDR_OFFSET
), 0);
346 ddi_put32(msix_p
->msix_tbl_hdl
,
347 (uint32_t *)(off
+ PCI_MSIX_UPPER_ADDR_OFFSET
), 0);
350 pci_config_teardown(&h
);
351 return (DDI_SUCCESS
);
356 * pci_is_msi_enabled:
358 * This function returns DDI_SUCCESS if MSI/X is already enabled, otherwise
359 * it returns DDI_FAILURE.
362 pci_is_msi_enabled(dev_info_t
*rdip
, int type
)
364 ushort_t caps_ptr
, msi_ctrl
;
365 ddi_acc_handle_t cfg_hdle
;
366 int ret
= DDI_FAILURE
;
368 DDI_INTR_NEXDBG((CE_CONT
, "pci_is_msi_enabled: rdip = 0x%p, "
369 "type = 0x%x\n", (void *)rdip
, type
));
371 if (pci_get_msi_ctrl(rdip
, type
, &msi_ctrl
,
372 &caps_ptr
, &cfg_hdle
) != DDI_SUCCESS
)
373 return (DDI_FAILURE
);
375 if ((type
== DDI_INTR_TYPE_MSI
) && (msi_ctrl
& PCI_MSI_ENABLE_BIT
))
378 if ((type
== DDI_INTR_TYPE_MSIX
) && (msi_ctrl
& PCI_MSIX_ENABLE_BIT
))
381 pci_config_teardown(&cfg_hdle
);
387 * pci_msi_enable_mode:
389 * This function sets the MSI_ENABLE bit in the capability structure
390 * (for MSI) and MSIX_ENABLE bit in the MSI-X capability structure.
392 * NOTE: It is the nexus driver's responsibility to clear the MSI/X
393 * interrupt's mask bit in the MSI/X capability structure before the
394 * interrupt can be used.
397 pci_msi_enable_mode(dev_info_t
*rdip
, int type
)
399 ushort_t caps_ptr
, msi_ctrl
;
400 ddi_acc_handle_t cfg_hdle
;
402 DDI_INTR_NEXDBG((CE_CONT
, "pci_msi_enable_mode: rdip = 0x%p\n",
405 if (pci_get_msi_ctrl(rdip
, type
, &msi_ctrl
,
406 &caps_ptr
, &cfg_hdle
) != DDI_SUCCESS
)
407 return (DDI_FAILURE
);
409 if (type
== DDI_INTR_TYPE_MSI
) {
410 if (msi_ctrl
& PCI_MSI_ENABLE_BIT
)
413 msi_ctrl
|= PCI_MSI_ENABLE_BIT
;
414 PCI_CAP_PUT16(cfg_hdle
, NULL
, caps_ptr
, PCI_MSI_CTRL
, msi_ctrl
);
416 } else if (type
== DDI_INTR_TYPE_MSIX
) {
417 if (msi_ctrl
& PCI_MSIX_ENABLE_BIT
)
420 msi_ctrl
|= PCI_MSIX_ENABLE_BIT
;
421 PCI_CAP_PUT16(cfg_hdle
, NULL
, caps_ptr
, PCI_MSIX_CTRL
,
426 DDI_INTR_NEXDBG((CE_CONT
, "pci_msi_enable_mode: msi_ctrl = %x\n",
429 pci_config_teardown(&cfg_hdle
);
430 return (DDI_SUCCESS
);
435 * pci_msi_disable_mode:
437 * This function resets the MSI_ENABLE bit in the capability structure
438 * (for MSI) and MSIX_ENABLE bit in the MSI-X capability structure.
440 * NOTE: It is the nexus driver's responsibility to set the MSI/X
441 * interrupt's mask bit in the MSI/X capability structure before the
442 * interrupt can be disabled.
445 pci_msi_disable_mode(dev_info_t
*rdip
, int type
)
447 ushort_t caps_ptr
, msi_ctrl
;
448 ddi_acc_handle_t cfg_hdle
;
450 DDI_INTR_NEXDBG((CE_CONT
, "pci_msi_disable_mode: rdip = 0x%p\n",
453 if (pci_get_msi_ctrl(rdip
, type
, &msi_ctrl
,
454 &caps_ptr
, &cfg_hdle
) != DDI_SUCCESS
)
455 return (DDI_FAILURE
);
457 /* Reset the "enable" bit */
458 if (type
== DDI_INTR_TYPE_MSI
) {
459 if (!(msi_ctrl
& PCI_MSI_ENABLE_BIT
))
461 msi_ctrl
&= ~PCI_MSI_ENABLE_BIT
;
462 PCI_CAP_PUT16(cfg_hdle
, NULL
, caps_ptr
, PCI_MSI_CTRL
, msi_ctrl
);
463 } else if (type
== DDI_INTR_TYPE_MSIX
) {
464 if (!(msi_ctrl
& PCI_MSIX_ENABLE_BIT
))
467 msi_ctrl
&= ~PCI_MSIX_ENABLE_BIT
;
468 PCI_CAP_PUT16(cfg_hdle
, NULL
, caps_ptr
, PCI_MSIX_CTRL
,
473 DDI_INTR_NEXDBG((CE_CONT
, "pci_msi_disable_mode: msi_ctrl = %x\n",
476 pci_config_teardown(&cfg_hdle
);
477 return (DDI_SUCCESS
);
484 * Set the mask bit in the MSI/X capability structure
488 pci_msi_set_mask(dev_info_t
*rdip
, int type
, int inum
)
491 int ret
= DDI_FAILURE
;
492 ushort_t caps_ptr
, msi_ctrl
;
493 ddi_acc_handle_t cfg_hdle
;
496 DDI_INTR_NEXDBG((CE_CONT
, "pci_msi_set_mask: rdip = 0x%p, "
497 "type = 0x%x\n", (void *)rdip
, type
));
499 if (pci_get_msi_ctrl(rdip
, type
, &msi_ctrl
,
500 &caps_ptr
, &cfg_hdle
) != DDI_SUCCESS
)
501 return (DDI_FAILURE
);
503 if (type
== DDI_INTR_TYPE_MSI
) {
504 if (!(msi_ctrl
& PCI_MSI_PVM_MASK
))
507 offset
= (msi_ctrl
& PCI_MSI_64BIT_MASK
) ?
508 PCI_MSI_64BIT_MASKBITS
: PCI_MSI_32BIT_MASK
;
510 if ((mask_bits
= PCI_CAP_GET32(cfg_hdle
, NULL
, caps_ptr
,
511 offset
)) == PCI_CAP_EINVAL32
)
514 mask_bits
|= (1 << inum
);
516 PCI_CAP_PUT32(cfg_hdle
, NULL
, caps_ptr
, offset
, mask_bits
);
518 } else if (type
== DDI_INTR_TYPE_MSIX
) {
520 ddi_intr_msix_t
*msix_p
;
522 /* Set function mask */
523 if (msi_ctrl
& PCI_MSIX_FUNCTION_MASK
) {
528 msix_p
= i_ddi_get_msix(rdip
);
530 /* Offset into the "inum"th entry in the MSI-X table */
531 off
= (uintptr_t)msix_p
->msix_tbl_addr
+ (inum
*
532 PCI_MSIX_VECTOR_SIZE
) + PCI_MSIX_VECTOR_CTRL_OFFSET
;
534 /* Set the Mask bit */
535 ddi_put32(msix_p
->msix_tbl_hdl
, (uint32_t *)off
, 0x1);
540 pci_config_teardown(&cfg_hdle
);
548 * Clear the mask bit in the MSI/X capability structure
552 pci_msi_clr_mask(dev_info_t
*rdip
, int type
, int inum
)
554 ushort_t caps_ptr
, msi_ctrl
;
555 ddi_acc_handle_t cfg_hdle
;
557 int ret
= DDI_FAILURE
;
560 DDI_INTR_NEXDBG((CE_CONT
, "pci_msi_clr_mask: rdip = 0x%p, "
561 "type = 0x%x\n", (void *)rdip
, type
));
563 if (pci_get_msi_ctrl(rdip
, type
, &msi_ctrl
,
564 &caps_ptr
, &cfg_hdle
) != DDI_SUCCESS
)
565 return (DDI_FAILURE
);
567 if (type
== DDI_INTR_TYPE_MSI
) {
568 if (!(msi_ctrl
& PCI_MSI_PVM_MASK
))
571 offset
= (msi_ctrl
& PCI_MSI_64BIT_MASK
) ?
572 PCI_MSI_64BIT_MASKBITS
: PCI_MSI_32BIT_MASK
;
573 if ((mask_bits
= PCI_CAP_GET32(cfg_hdle
, NULL
, caps_ptr
,
574 offset
)) == PCI_CAP_EINVAL32
)
577 mask_bits
&= ~(1 << inum
);
579 PCI_CAP_PUT32(cfg_hdle
, NULL
, caps_ptr
, offset
, mask_bits
);
581 } else if (type
== DDI_INTR_TYPE_MSIX
) {
583 ddi_intr_msix_t
*msix_p
;
585 if (msi_ctrl
& PCI_MSIX_FUNCTION_MASK
) {
590 msix_p
= i_ddi_get_msix(rdip
);
592 /* Offset into the "inum"th entry in the MSI-X table */
593 off
= (uintptr_t)msix_p
->msix_tbl_addr
+ (inum
*
594 PCI_MSIX_VECTOR_SIZE
) + PCI_MSIX_VECTOR_CTRL_OFFSET
;
596 /* Clear the Mask bit */
597 ddi_put32(msix_p
->msix_tbl_hdl
, (uint32_t *)off
, 0x0);
602 pci_config_teardown(&cfg_hdle
);
608 * pci_msi_get_pending:
610 * Get the pending bit from the MSI/X capability structure
614 pci_msi_get_pending(dev_info_t
*rdip
, int type
, int inum
, int *pendingp
)
616 ushort_t caps_ptr
, msi_ctrl
;
617 ddi_acc_handle_t cfg_hdle
;
619 int ret
= DDI_FAILURE
;
621 DDI_INTR_NEXDBG((CE_CONT
, "pci_msi_get_pending: rdip = 0x%p\n",
624 if (pci_get_msi_ctrl(rdip
, type
, &msi_ctrl
,
625 &caps_ptr
, &cfg_hdle
) != DDI_SUCCESS
)
626 return (DDI_FAILURE
);
628 if (type
== DDI_INTR_TYPE_MSI
) {
629 uint32_t pending_bits
;
631 if (!(msi_ctrl
& PCI_MSI_PVM_MASK
)) {
632 DDI_INTR_NEXDBG((CE_CONT
, "pci_msi_get_pending: "
633 "PVM is not supported\n"));
637 offset
= (msi_ctrl
& PCI_MSI_64BIT_MASK
) ?
638 PCI_MSI_64BIT_PENDING
: PCI_MSI_32BIT_PENDING
;
640 if ((pending_bits
= PCI_CAP_GET32(cfg_hdle
, NULL
, caps_ptr
,
641 offset
)) == PCI_CAP_EINVAL32
)
644 *pendingp
= pending_bits
& ~(1 >> inum
);
646 } else if (type
== DDI_INTR_TYPE_MSIX
) {
648 uint64_t pending_bits
;
649 ddi_intr_msix_t
*msix_p
= i_ddi_get_msix(rdip
);
651 /* Offset into the PBA array which has entry for "inum" */
652 off
= (uintptr_t)msix_p
->msix_pba_addr
+ (inum
/ 64);
654 /* Read the PBA array */
655 pending_bits
= ddi_get64(msix_p
->msix_pba_hdl
, (uint64_t *)off
);
657 *pendingp
= pending_bits
& ~(1 >> inum
);
662 pci_config_teardown(&cfg_hdle
);
668 * pci_msi_get_nintrs:
670 * For a given type (MSI/X) returns the number of interrupts supported
673 pci_msi_get_nintrs(dev_info_t
*rdip
, int type
, int *nintrs
)
675 ushort_t caps_ptr
, msi_ctrl
;
676 ddi_acc_handle_t cfg_hdle
;
678 DDI_INTR_NEXDBG((CE_CONT
, "pci_msi_get_nintrs: rdip = 0x%p\n",
681 if (pci_get_msi_ctrl(rdip
, type
, &msi_ctrl
,
682 &caps_ptr
, &cfg_hdle
) != DDI_SUCCESS
)
683 return (DDI_FAILURE
);
685 if (type
== DDI_INTR_TYPE_MSI
) {
686 *nintrs
= 1 << ((msi_ctrl
& PCI_MSI_MMC_MASK
) >>
688 } else if (type
== DDI_INTR_TYPE_MSIX
) {
689 if (msi_ctrl
& PCI_MSIX_TBL_SIZE_MASK
)
690 *nintrs
= (msi_ctrl
& PCI_MSIX_TBL_SIZE_MASK
) + 1;
693 DDI_INTR_NEXDBG((CE_CONT
, "pci_msi_get_nintrs: "
694 "nintr = 0x%x\n", *nintrs
));
696 pci_config_teardown(&cfg_hdle
);
697 return (DDI_SUCCESS
);
702 * pci_msi_set_nintrs:
704 * For a given type (MSI/X) sets the number of interrupts supported
706 * For MSI: Return an error if this func is called for navail > 32
707 * For MSI-X: Return an error if this func is called for navail > 2048
710 pci_msi_set_nintrs(dev_info_t
*rdip
, int type
, int navail
)
712 ushort_t caps_ptr
, msi_ctrl
;
713 ddi_acc_handle_t cfg_hdle
;
715 DDI_INTR_NEXDBG((CE_CONT
, "pci_msi_set_nintrs: rdip = 0x%p, "
716 "navail = 0x%x\n", (void *)rdip
, navail
));
718 /* Check for valid input argument */
719 if (((type
== DDI_INTR_TYPE_MSI
) && (navail
> PCI_MSI_MAX_INTRS
)) ||
720 ((type
== DDI_INTR_TYPE_MSIX
) && (navail
> PCI_MSIX_MAX_INTRS
)))
723 if (pci_get_msi_ctrl(rdip
, type
, &msi_ctrl
,
724 &caps_ptr
, &cfg_hdle
) != DDI_SUCCESS
)
725 return (DDI_FAILURE
);
727 if (type
== DDI_INTR_TYPE_MSI
) {
728 msi_ctrl
|= ((highbit(navail
) -1) << PCI_MSI_MME_SHIFT
);
730 PCI_CAP_PUT16(cfg_hdle
, NULL
, caps_ptr
, PCI_MSI_CTRL
, msi_ctrl
);
731 } else if (type
== DDI_INTR_TYPE_MSIX
) {
732 DDI_INTR_NEXDBG((CE_CONT
, "pci_msi_set_nintrs: unsupported\n"));
735 pci_config_teardown(&cfg_hdle
);
736 return (DDI_SUCCESS
);
741 * pci_msi_get_supported_type:
743 * Returns DDI_INTR_TYPE_MSI and/or DDI_INTR_TYPE_MSIX as supported
744 * types if device supports them. A DDI_FAILURE is returned otherwise.
747 pci_msi_get_supported_type(dev_info_t
*rdip
, int *typesp
)
749 ushort_t caps_ptr
, msi_ctrl
;
750 ddi_acc_handle_t cfg_hdle
;
752 DDI_INTR_NEXDBG((CE_CONT
, "pci_msi_get_supported_type: "
753 "rdip = 0x%p\n", (void *)rdip
));
757 if (pci_get_msi_ctrl(rdip
, DDI_INTR_TYPE_MSI
, &msi_ctrl
,
758 &caps_ptr
, &cfg_hdle
) == DDI_SUCCESS
) {
759 *typesp
|= DDI_INTR_TYPE_MSI
;
760 pci_config_teardown(&cfg_hdle
);
763 if (pci_get_msi_ctrl(rdip
, DDI_INTR_TYPE_MSIX
, &msi_ctrl
,
764 &caps_ptr
, &cfg_hdle
) == DDI_SUCCESS
) {
765 *typesp
|= DDI_INTR_TYPE_MSIX
;
766 pci_config_teardown(&cfg_hdle
);
769 DDI_INTR_NEXDBG((CE_CONT
, "pci_msi_get_supported_type: "
770 "rdip = 0x%p types 0x%x\n", (void *)rdip
, *typesp
));
772 return (*typesp
== 0 ? DDI_FAILURE
: DDI_SUCCESS
);
778 * This function initializes the various handles/addrs etc.
779 * needed for MSI-X support. It also allocates a private
780 * structure to keep track of these.
783 pci_msix_init(dev_info_t
*rdip
)
785 uint_t rnumber
, breg
, nregs
;
786 size_t msix_tbl_size
;
788 ushort_t caps_ptr
, msix_ctrl
;
789 ddi_intr_msix_t
*msix_p
;
790 ddi_acc_handle_t cfg_hdle
;
792 int reg_size
, addr_space
, offset
, *regs_list
;
795 DDI_INTR_NEXDBG((CE_CONT
, "pci_msix_init: rdip = %p\n", (void *)rdip
));
797 if (pci_get_msi_ctrl(rdip
, DDI_INTR_TYPE_MSIX
, &msix_ctrl
,
798 &caps_ptr
, &cfg_hdle
) != DDI_SUCCESS
)
801 msix_p
= kmem_zalloc(sizeof (ddi_intr_msix_t
), KM_SLEEP
);
804 * Initialize the devacc structure
806 msix_p
->msix_dev_attr
.devacc_attr_version
= DDI_DEVICE_ATTR_V0
;
807 msix_p
->msix_dev_attr
.devacc_attr_endian_flags
=
808 DDI_STRUCTURE_LE_ACC
;
809 msix_p
->msix_dev_attr
.devacc_attr_dataorder
= DDI_STRICTORDER_ACC
;
811 /* Map the entire MSI-X vector table */
812 msix_p
->msix_tbl_offset
= PCI_CAP_GET32(cfg_hdle
, NULL
, caps_ptr
,
813 PCI_MSIX_TBL_OFFSET
);
815 if ((breg
= pci_msix_bir_index
[msix_p
->msix_tbl_offset
&
816 PCI_MSIX_TBL_BIR_MASK
]) == 0xff)
819 msix_p
->msix_tbl_offset
= msix_p
->msix_tbl_offset
&
820 ~PCI_MSIX_TBL_BIR_MASK
;
821 msix_tbl_size
= ((msix_ctrl
& PCI_MSIX_TBL_SIZE_MASK
) + 1) *
822 PCI_MSIX_VECTOR_SIZE
;
824 DDI_INTR_NEXDBG((CE_CONT
, "pci_msix_init: MSI-X table offset 0x%x "
825 "breg 0x%x size 0x%lx\n", msix_p
->msix_tbl_offset
, breg
,
828 if ((ret
= ddi_prop_lookup_int_array(DDI_DEV_T_ANY
, rdip
,
829 DDI_PROP_DONTPASS
, "reg", (int **)®s_list
, &nregs
))
830 != DDI_PROP_SUCCESS
) {
831 DDI_INTR_NEXDBG((CE_CONT
, "pci_msix_init: "
832 "ddi_prop_lookup_int_array failed %d\n", ret
));
837 reg_size
= sizeof (pci_regspec_t
) / sizeof (int);
839 for (i
= 1, rnumber
= 0; i
< nregs
/reg_size
; i
++) {
840 rp
= (pci_regspec_t
*)®s_list
[i
* reg_size
];
841 addr_space
= rp
->pci_phys_hi
& PCI_ADDR_MASK
;
842 offset
= PCI_REG_REG_G(rp
->pci_phys_hi
);
844 if ((offset
== breg
) && ((addr_space
== PCI_ADDR_MEM32
) ||
845 (addr_space
== PCI_ADDR_MEM64
))) {
851 DDI_INTR_NEXDBG((CE_CONT
, "pci_msix_init: MSI-X rnum = %d\n", rnumber
));
854 DDI_INTR_NEXDBG((CE_CONT
, "pci_msix_init: "
855 "no mtaching reg number for offset 0x%x\n", breg
));
860 if ((ret
= ddi_regs_map_setup(rdip
, rnumber
,
861 (caddr_t
*)&msix_p
->msix_tbl_addr
, msix_p
->msix_tbl_offset
,
862 msix_tbl_size
, &msix_p
->msix_dev_attr
,
863 &msix_p
->msix_tbl_hdl
)) != DDI_SUCCESS
) {
864 DDI_INTR_NEXDBG((CE_CONT
, "pci_msix_init: MSI-X Table "
865 "ddi_regs_map_setup failed %d\n", ret
));
871 * Map in the MSI-X Pending Bit Array
873 msix_p
->msix_pba_offset
= PCI_CAP_GET32(cfg_hdle
, NULL
, caps_ptr
,
874 PCI_MSIX_PBA_OFFSET
);
876 if ((breg
= pci_msix_bir_index
[msix_p
->msix_pba_offset
&
877 PCI_MSIX_PBA_BIR_MASK
]) == 0xff)
880 msix_p
->msix_pba_offset
= msix_p
->msix_pba_offset
&
881 ~PCI_MSIX_PBA_BIR_MASK
;
882 pba_tbl_size
= ((msix_ctrl
& PCI_MSIX_TBL_SIZE_MASK
) + 1)/8;
884 DDI_INTR_NEXDBG((CE_CONT
, "pci_msix_init: PBA table offset 0x%x "
885 "breg 0x%x size 0x%lx\n", msix_p
->msix_pba_offset
, breg
,
888 for (i
= 1, rnumber
= 0; i
< nregs
/reg_size
; i
++) {
889 rp
= (pci_regspec_t
*)®s_list
[i
* reg_size
];
890 addr_space
= rp
->pci_phys_hi
& PCI_ADDR_MASK
;
891 offset
= PCI_REG_REG_G(rp
->pci_phys_hi
);
893 if ((offset
== breg
) && ((addr_space
== PCI_ADDR_MEM32
) ||
894 (addr_space
== PCI_ADDR_MEM64
))) {
900 DDI_INTR_NEXDBG((CE_CONT
, "pci_msix_init: PBA rnum = %d\n", rnumber
));
903 DDI_INTR_NEXDBG((CE_CONT
, "pci_msix_init: "
904 "no matching reg number for offset 0x%x\n", breg
));
909 if ((ret
= ddi_regs_map_setup(rdip
, rnumber
,
910 (caddr_t
*)&msix_p
->msix_pba_addr
, msix_p
->msix_pba_offset
,
911 pba_tbl_size
, &msix_p
->msix_dev_attr
,
912 &msix_p
->msix_pba_hdl
)) != DDI_SUCCESS
) {
913 DDI_INTR_NEXDBG((CE_CONT
, "pci_msix_init: PBA "
914 "ddi_regs_map_setup failed %d\n", ret
));
919 DDI_INTR_NEXDBG((CE_CONT
, "pci_msix_init: msix_p = 0x%p DONE!!\n",
922 ddi_prop_free(regs_list
);
926 ddi_regs_map_free(&msix_p
->msix_tbl_hdl
);
928 ddi_prop_free(regs_list
);
930 kmem_free(msix_p
, sizeof (ddi_intr_msix_t
));
933 pci_config_teardown(&cfg_hdle
);
940 * This function cleans up previously allocated handles/addrs etc.
941 * It is only called if no more MSI-X interrupts are being used.
944 pci_msix_fini(ddi_intr_msix_t
*msix_p
)
946 DDI_INTR_NEXDBG((CE_CONT
, "pci_msix_fini: msix_p = 0x%p\n",
949 ddi_regs_map_free(&msix_p
->msix_pba_hdl
);
950 ddi_regs_map_free(&msix_p
->msix_tbl_hdl
);
951 kmem_free(msix_p
, sizeof (ddi_intr_msix_t
));
957 * This function duplicates the address and data pair of one msi-x
958 * vector to another msi-x vector.
961 pci_msix_dup(dev_info_t
*rdip
, int org_inum
, int dup_inum
)
963 ddi_intr_msix_t
*msix_p
= i_ddi_get_msix(rdip
);
968 DDI_INTR_NEXDBG((CE_CONT
, "pci_msix_dup: dip = %p, inum = 0x%x, "
969 "to_vector = 0x%x\n", (void *)rdip
, org_inum
, dup_inum
));
971 /* Offset into the original inum's entry in the MSI-X table */
972 off
= (uintptr_t)msix_p
->msix_tbl_addr
+
973 (org_inum
* PCI_MSIX_VECTOR_SIZE
);
976 * For the MSI-X number passed in, get the "data" and "addr" fields.
978 * Note that the spec only requires 32-bit accesses to be supported.
979 * Apparently some chipsets don't support 64-bit accesses.
981 addr
= ddi_get32(msix_p
->msix_tbl_hdl
,
982 (uint32_t *)(off
+ PCI_MSIX_UPPER_ADDR_OFFSET
));
983 addr
= (addr
<< 32) | ddi_get32(msix_p
->msix_tbl_hdl
,
984 (uint32_t *)(off
+ PCI_MSIX_LOWER_ADDR_OFFSET
));
986 data
= ddi_get32(msix_p
->msix_tbl_hdl
,
987 (uint32_t *)(off
+ PCI_MSIX_DATA_OFFSET
));
989 /* Program new vector with these existing values */
990 return (pci_msi_configure(rdip
, DDI_INTR_TYPE_MSIX
, 1, dup_inum
, addr
,
996 * Next set of routines are for INTx (legacy) PCI interrupt
1002 * For non-MSI devices that comply to PCI v2.3 or greater;
1003 * read the command register. Bit 10 implies interrupt disable.
1004 * Set this bit and then read the status register bit 3.
1005 * Bit 3 of status register is Interrupt state.
1006 * If it is set; then the device supports 'Masking'
1008 * Reset the device back to the original state.
1011 pci_intx_get_cap(dev_info_t
*dip
, int *flagsp
)
1013 uint16_t cmdreg
, savereg
;
1014 ddi_acc_handle_t cfg_hdl
;
1020 DDI_INTR_NEXDBG((CE_CONT
, "pci_intx_get_cap: %s%d: called\n",
1021 ddi_driver_name(dip
), ddi_get_instance(dip
)));
1023 if (pci_config_setup(dip
, &cfg_hdl
) != DDI_SUCCESS
) {
1024 DDI_INTR_NEXDBG((CE_CONT
, "pci_intx_get_cap: can't get "
1025 "config handle\n"));
1026 return (DDI_FAILURE
);
1029 savereg
= pci_config_get16(cfg_hdl
, PCI_CONF_COMM
);
1030 DDI_INTR_NEXDBG((CE_CONT
, "pci_intx_get_cap: "
1031 "command register was 0x%x\n", savereg
));
1033 /* Disable the interrupts */
1034 cmdreg
= savereg
| PCI_COMM_INTX_DISABLE
;
1035 pci_config_put16(cfg_hdl
, PCI_CONF_COMM
, cmdreg
);
1038 statreg
= pci_config_get16(cfg_hdl
, PCI_CONF_STAT
);
1039 DDI_INTR_NEXDBG((CE_CONT
, "pci_intx_get_cap: "
1040 "status register is 0x%x\n", statreg
));
1043 /* Read the bit back */
1044 cmdreg
= pci_config_get16(cfg_hdl
, PCI_CONF_COMM
);
1045 DDI_INTR_NEXDBG((CE_CONT
, "pci_intx_get_cap: "
1046 "command register is now 0x%x\n", cmdreg
));
1048 *flagsp
= DDI_INTR_FLAG_LEVEL
;
1050 if (cmdreg
& PCI_COMM_INTX_DISABLE
) {
1051 DDI_INTR_NEXDBG((CE_CONT
, "pci_intx_get_cap: "
1052 "masking supported\n"));
1053 *flagsp
|= (DDI_INTR_FLAG_MASKABLE
|
1054 DDI_INTR_FLAG_PENDING
);
1057 /* Restore the device back to the original state and return */
1058 pci_config_put16(cfg_hdl
, PCI_CONF_COMM
, savereg
);
1060 pci_config_teardown(&cfg_hdl
);
1061 return (DDI_SUCCESS
);
1066 * pci_intx_clr_mask:
1067 * For non-MSI devices that comply to PCI v2.3 or greater;
1068 * clear the bit10 in the command register.
1071 pci_intx_clr_mask(dev_info_t
*dip
)
1074 ddi_acc_handle_t cfg_hdl
;
1076 DDI_INTR_NEXDBG((CE_CONT
, "pci_intx_clr_mask: %s%d: called\n",
1077 ddi_driver_name(dip
), ddi_get_instance(dip
)));
1079 if (pci_config_setup(dip
, &cfg_hdl
) != DDI_SUCCESS
) {
1080 DDI_INTR_NEXDBG((CE_CONT
, "pci_intx_clr_mask: can't get "
1081 "config handle\n"));
1082 return (DDI_FAILURE
);
1085 cmdreg
= pci_config_get16(cfg_hdl
, PCI_CONF_COMM
);
1086 DDI_INTR_NEXDBG((CE_CONT
, "pci_intx_clr_mask: "
1087 "command register was 0x%x\n", cmdreg
));
1089 /* Enable the interrupts */
1090 cmdreg
&= ~PCI_COMM_INTX_DISABLE
;
1091 pci_config_put16(cfg_hdl
, PCI_CONF_COMM
, cmdreg
);
1092 pci_config_teardown(&cfg_hdl
);
1093 return (DDI_SUCCESS
);
1098 * pci_intx_set_mask:
1099 * For non-MSI devices that comply to PCI v2.3 or greater;
1100 * set the bit10 in the command register.
1103 pci_intx_set_mask(dev_info_t
*dip
)
1106 ddi_acc_handle_t cfg_hdl
;
1108 DDI_INTR_NEXDBG((CE_CONT
, "pci_intx_set_mask: %s%d: called\n",
1109 ddi_driver_name(dip
), ddi_get_instance(dip
)));
1111 if (pci_config_setup(dip
, &cfg_hdl
) != DDI_SUCCESS
) {
1112 DDI_INTR_NEXDBG((CE_CONT
, "pci_intx_set_mask: can't get "
1113 "config handle\n"));
1114 return (DDI_FAILURE
);
1117 cmdreg
= pci_config_get16(cfg_hdl
, PCI_CONF_COMM
);
1118 DDI_INTR_NEXDBG((CE_CONT
, "pci_intx_set_mask: "
1119 "command register was 0x%x\n", cmdreg
));
1121 /* Disable the interrupts */
1122 cmdreg
|= PCI_COMM_INTX_DISABLE
;
1123 pci_config_put16(cfg_hdl
, PCI_CONF_COMM
, cmdreg
);
1124 pci_config_teardown(&cfg_hdl
);
1125 return (DDI_SUCCESS
);
1129 * pci_intx_get_pending:
1130 * For non-MSI devices that comply to PCI v2.3 or greater;
1131 * read the status register. Bit 3 of status register is
1132 * Interrupt state. If it is set; then the interrupt is
1136 pci_intx_get_pending(dev_info_t
*dip
, int *pendingp
)
1139 ddi_acc_handle_t cfg_hdl
;
1142 DDI_INTR_NEXDBG((CE_CONT
, "pci_intx_get_pending: %s%d: called\n",
1143 ddi_driver_name(dip
), ddi_get_instance(dip
)));
1145 if (pci_config_setup(dip
, &cfg_hdl
) != DDI_SUCCESS
) {
1146 DDI_INTR_NEXDBG((CE_CONT
, "pci_intx_get_pending: can't get "
1147 "config handle\n"));
1148 return (DDI_FAILURE
);
1151 statreg
= pci_config_get16(cfg_hdl
, PCI_CONF_STAT
);
1153 if (statreg
& PCI_STAT_INTR
) {
1154 DDI_INTR_NEXDBG((CE_CONT
, "pci_intx_get_pending: "
1155 "interrupt is pending\n"));
1159 pci_config_teardown(&cfg_hdl
);
1160 return (DDI_SUCCESS
);
1165 * pci_intx_get_ispec:
1166 * Get intrspec for PCI devices (legacy support)
1167 * NOTE: This is moved here from x86 pci.c and is
1168 * needed here as pci-ide.c uses it as well
1172 pci_intx_get_ispec(dev_info_t
*dip
, dev_info_t
*rdip
, int inum
)
1175 uint_t num_intpriorities
;
1176 struct intrspec
*ispec
;
1177 ddi_acc_handle_t cfg_hdl
;
1178 struct ddi_parent_private_data
*pdptr
;
1180 if ((pdptr
= ddi_get_parent_data(rdip
)) == NULL
)
1183 ispec
= pdptr
->par_intr
;
1186 /* check if the intrspec_pri has been initialized */
1187 if (!ispec
->intrspec_pri
) {
1188 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY
, rdip
,
1189 DDI_PROP_DONTPASS
, "interrupt-priorities",
1190 &intpriorities
, &num_intpriorities
) == DDI_PROP_SUCCESS
) {
1191 if (inum
< num_intpriorities
)
1192 ispec
->intrspec_pri
= intpriorities
[inum
];
1193 ddi_prop_free(intpriorities
);
1196 /* If still no priority, guess based on the class code */
1197 if (ispec
->intrspec_pri
== 0)
1198 ispec
->intrspec_pri
= pci_class_to_pil(rdip
);
1201 /* Get interrupt line value */
1202 if (!ispec
->intrspec_vec
) {
1203 if (pci_config_setup(rdip
, &cfg_hdl
) != DDI_SUCCESS
) {
1204 DDI_INTR_NEXDBG((CE_CONT
, "pci_intx_get_iline: "
1205 "can't get config handle\n"));
1206 return ((ddi_intrspec_t
)ispec
);
1209 ispec
->intrspec_vec
= pci_config_get8(cfg_hdl
, PCI_CONF_ILINE
);
1210 pci_config_teardown(&cfg_hdl
);
1213 return ((ddi_intrspec_t
)ispec
);
1217 pci_match_class_val(uint32_t key
, pci_class_val_t
*rec_p
, int nrec
,
1218 uint32_t default_val
)
1222 for (i
= 0; i
< nrec
; rec_p
++, i
++) {
1223 if ((rec_p
->class_code
& rec_p
->class_mask
) ==
1224 (key
& rec_p
->class_mask
))
1225 return (rec_p
->class_val
);
1228 return (default_val
);
1232 * Return the configuration value, based on class code and sub class code,
1233 * from the specified property based or default pci_class_val_t table.
1236 pci_class_to_val(dev_info_t
*rdip
, char *property_name
, pci_class_val_t
*rec_p
,
1237 int nrec
, uint32_t default_val
)
1240 uint32_t class_code
;
1241 pci_class_val_t
*conf
;
1242 uint32_t val
= default_val
;
1245 * Use the "class-code" property to get the base and sub class
1246 * codes for the requesting device.
1248 class_code
= (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY
, rdip
,
1249 DDI_PROP_DONTPASS
, "class-code", -1);
1251 if (class_code
== -1)
1254 /* look up the val from the default table */
1255 val
= pci_match_class_val(class_code
, rec_p
, nrec
, val
);
1258 /* see if there is a more specific property specified value */
1259 if (ddi_getlongprop(DDI_DEV_T_ANY
, rdip
, DDI_PROP_NOTPROM
,
1260 property_name
, (caddr_t
)&conf
, &property_len
))
1263 if ((property_len
% sizeof (pci_class_val_t
)) == 0)
1264 val
= pci_match_class_val(class_code
, conf
,
1265 property_len
/ sizeof (pci_class_val_t
), val
);
1266 kmem_free(conf
, property_len
);
1273 * Return the pil for a given PCI device.
1276 pci_class_to_pil(dev_info_t
*rdip
)
1280 /* Default pil is 1 */
1281 pil
= pci_class_to_val(rdip
,
1282 "pci-class-priorities", pci_default_pil
,
1283 sizeof (pci_default_pil
) / sizeof (pci_class_val_t
), 1);
1285 /* Range check the result */
1293 * pci_class_to_intr_weight:
1295 * Return the intr_weight for a given PCI device.
1298 pci_class_to_intr_weight(dev_info_t
*rdip
)
1300 int32_t intr_weight
;
1302 /* default weight is 0% */
1303 intr_weight
= pci_class_to_val(rdip
,
1304 "pci-class-intr-weights", pci_default_intr_weight
,
1305 sizeof (pci_default_intr_weight
) / sizeof (pci_class_val_t
), 0);
1307 /* range check the result */
1308 if (intr_weight
< 0)
1310 if (intr_weight
> 1000)
1313 return (intr_weight
);