1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright 2013 Pluribus Networks, Inc.
25 */
26
27 /*
28 * Support for MSI, MSIX and INTx
29 */
30
31 #include <sys/conf.h>
32 #include <sys/debug.h>
33 #include <sys/pci.h>
34 #include <sys/pci_cap.h>
35 #include <sys/pci_intr_lib.h>
36 #include <sys/sunddi.h>
37 #include <sys/bitmap.h>
38
39 /*
40 * MSI-X BIR Index Table:
41 *
42 * BAR indicator register (BIR) to Base Address register.
43 */
44 static uchar_t pci_msix_bir_index[8] = {0x10, 0x14, 0x18, 0x1c,
45 0x20, 0x24, 0xff, 0xff};
46
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 */
60 /*
61 * XXX - This is a temporary workaround and it will be removed
62 * after x86 interrupt scalability support.
63 */
64 #if defined(__i386) || defined(__amd64)
65 {0x0c0400, 0xffff00, 0x5}, /* Serial Bus, Fibre Channel */
66 #else
67 {0x0c0400, 0xffff00, 0x6}, /* Serial Bus, Fibre Channel */
68 #endif
69 {0x0c0600, 0xffff00, 0x6} /* Serial Bus, Infiniband */
70 };
71
72 /*
73 * Default class to intr_weight value mapping (% of CPU). A driver.conf
74 * entry on or above the pci node like
75 *
76 * pci-class-intr-weights= 0x020000, 0xff0000, 30;
77 *
78 * can be used to augment or override entries in the default table below.
79 *
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.
85 *
86 * NB: We treat Infiniband like a NIC.
87 */
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 */
93 };
94
95 /*
96 * Library utility functions
97 */
98
99 /*
100 * pci_get_msi_ctrl:
101 *
102 * Helper function that returns with 'cfg_hdl', MSI/X ctrl pointer,
103 * and caps_ptr for MSI/X if these are found.
104 */
105 static int
pci_get_msi_ctrl(dev_info_t * dip,int type,ushort_t * msi_ctrl,ushort_t * caps_ptr,ddi_acc_handle_t * h)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)
108 {
109 *msi_ctrl = *caps_ptr = 0;
110
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)));
115
116 return (DDI_FAILURE);
117 }
118
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)
123 goto done;
124
125 DDI_INTR_NEXDBG((CE_CONT, "pci_get_msi_ctrl: MSI "
126 "caps_ptr=%x msi_ctrl=%x\n", *caps_ptr, *msi_ctrl));
127
128 return (DDI_SUCCESS);
129 }
130
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)
135 goto done;
136
137 DDI_INTR_NEXDBG((CE_CONT, "pci_get_msi_ctrl: MSI-X "
138 "caps_ptr=%x msi_ctrl=%x\n", *caps_ptr, *msi_ctrl));
139
140 return (DDI_SUCCESS);
141 }
142
143 done:
144 pci_config_teardown(h);
145 return (DDI_FAILURE);
146 }
147
148
149 /*
150 * pci_msi_get_cap:
151 *
152 * Get the capabilities of the MSI/X interrupt
153 */
154 int
pci_msi_get_cap(dev_info_t * rdip,int type,int * flagsp)155 pci_msi_get_cap(dev_info_t *rdip, int type, int *flagsp)
156 {
157 ushort_t caps_ptr, msi_ctrl;
158 ddi_acc_handle_t cfg_hdle;
159
160 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_get_cap: rdip = 0x%p\n",
161 (void *)rdip));
162
163 *flagsp = 0;
164
165 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl,
166 &caps_ptr, &cfg_hdle) != DDI_SUCCESS)
167 return (DDI_FAILURE);
168
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);
175 else
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);
181 }
182
183 *flagsp |= DDI_INTR_FLAG_EDGE;
184
185 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_get_cap: flags = 0x%x\n", *flagsp));
186
187 pci_config_teardown(&cfg_hdle);
188 return (DDI_SUCCESS);
189 }
190
191
192 /*
193 * pci_msi_configure:
194 *
195 * Configure address/data and number MSI/Xs fields in the MSI/X
196 * capability structure.
197 */
198 /* ARGSUSED */
199 int
pci_msi_configure(dev_info_t * rdip,int type,int count,int inum,uint64_t addr,uint64_t data)200 pci_msi_configure(dev_info_t *rdip, int type, int count, int inum,
201 uint64_t addr, uint64_t data)
202 {
203 ushort_t caps_ptr, msi_ctrl;
204 ddi_acc_handle_t h;
205
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));
209
210 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl,
211 &caps_ptr, &h) != DDI_SUCCESS)
212 return (DDI_FAILURE);
213
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);
218
219 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_configure: msi_ctrl = %x\n",
220 PCI_CAP_GET16(h, NULL, caps_ptr, PCI_MSI_CTRL)));
221
222 /* Set the "data" and "addr" bits */
223 PCI_CAP_PUT32(h, NULL, caps_ptr, PCI_MSI_ADDR_OFFSET, addr);
224
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)));
227
228 if (msi_ctrl & PCI_MSI_64BIT_MASK) {
229 PCI_CAP_PUT32(h, NULL, caps_ptr, PCI_MSI_ADDR_OFFSET
230 + 4, addr >> 32);
231
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)));
235
236 PCI_CAP_PUT16(h, NULL, caps_ptr, PCI_MSI_64BIT_DATA,
237 data);
238
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)));
242 } else {
243 PCI_CAP_PUT16(h, NULL, caps_ptr, PCI_MSI_32BIT_DATA,
244 data);
245
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)));
249 }
250 } else if (type == DDI_INTR_TYPE_MSIX) {
251 uintptr_t off;
252 ddi_intr_msix_t *msix_p = i_ddi_get_msix(rdip);
253
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);
257
258 /* Set the "data" and "addr" bits */
259 ddi_put32(msix_p->msix_tbl_hdl,
260 (uint32_t *)(off + PCI_MSIX_DATA_OFFSET), data);
261
262 /*
263 * Note that the spec only requires 32-bit accesses
264 * to be supported. Apparently some chipsets don't
265 * support 64-bit accesses.
266 */
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),
271 addr >> 32);
272
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))));
281 }
282
283 pci_config_teardown(&h);
284 return (DDI_SUCCESS);
285 }
286
287
288 /*
289 * pci_msi_unconfigure:
290 *
291 * Unconfigure address/data and number MSI/Xs fields in the MSI/X
292 * capability structure.
293 */
294 /* ARGSUSED */
295 int
pci_msi_unconfigure(dev_info_t * rdip,int type,int inum)296 pci_msi_unconfigure(dev_info_t *rdip, int type, int inum)
297 {
298 ushort_t msi_ctrl, caps_ptr;
299 ddi_acc_handle_t h;
300
301 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_unconfigure: rdip = 0x%p type 0x%x "
302 "inum 0x%x\n", (void *)rdip, type, inum));
303
304 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl, &caps_ptr, &h) !=
305 DDI_SUCCESS)
306 return (DDI_FAILURE);
307
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);
311
312 PCI_CAP_PUT32(h, NULL, caps_ptr, PCI_MSI_ADDR_OFFSET, 0);
313
314 if (msi_ctrl & PCI_MSI_64BIT_MASK) {
315 PCI_CAP_PUT16(h, NULL, caps_ptr, PCI_MSI_64BIT_DATA,
316 0);
317 PCI_CAP_PUT32(h, NULL, caps_ptr, PCI_MSI_ADDR_OFFSET
318 + 4, 0);
319 } else {
320 PCI_CAP_PUT16(h, NULL, caps_ptr, PCI_MSI_32BIT_DATA,
321 0);
322 }
323
324 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_unconfigure: msi_ctrl "
325 "= %x\n", PCI_CAP_GET16(h, NULL, caps_ptr, PCI_MSI_CTRL)));
326
327 } else if (type == DDI_INTR_TYPE_MSIX) {
328 uintptr_t off;
329 ddi_intr_msix_t *msix_p = i_ddi_get_msix(rdip);
330
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);
334
335 /* Reset the "data" and "addr" bits */
336 ddi_put32(msix_p->msix_tbl_hdl,
337 (uint32_t *)(off + PCI_MSIX_DATA_OFFSET), 0);
338
339 /*
340 * Note that the spec only requires 32-bit accesses
341 * to be supported. Apparently some chipsets don't
342 * support 64-bit accesses.
343 */
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);
348 }
349
350 pci_config_teardown(&h);
351 return (DDI_SUCCESS);
352 }
353
354
355 /*
356 * pci_is_msi_enabled:
357 *
358 * This function returns DDI_SUCCESS if MSI/X is already enabled, otherwise
359 * it returns DDI_FAILURE.
360 */
361 int
pci_is_msi_enabled(dev_info_t * rdip,int type)362 pci_is_msi_enabled(dev_info_t *rdip, int type)
363 {
364 ushort_t caps_ptr, msi_ctrl;
365 ddi_acc_handle_t cfg_hdle;
366 int ret = DDI_FAILURE;
367
368 DDI_INTR_NEXDBG((CE_CONT, "pci_is_msi_enabled: rdip = 0x%p, "
369 "type = 0x%x\n", (void *)rdip, type));
370
371 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl,
372 &caps_ptr, &cfg_hdle) != DDI_SUCCESS)
373 return (DDI_FAILURE);
374
375 if ((type == DDI_INTR_TYPE_MSI) && (msi_ctrl & PCI_MSI_ENABLE_BIT))
376 ret = DDI_SUCCESS;
377
378 if ((type == DDI_INTR_TYPE_MSIX) && (msi_ctrl & PCI_MSIX_ENABLE_BIT))
379 ret = DDI_SUCCESS;
380
381 pci_config_teardown(&cfg_hdle);
382 return (ret);
383 }
384
385
386 /*
387 * pci_msi_enable_mode:
388 *
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.
391 *
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.
395 */
396 int
pci_msi_enable_mode(dev_info_t * rdip,int type)397 pci_msi_enable_mode(dev_info_t *rdip, int type)
398 {
399 ushort_t caps_ptr, msi_ctrl;
400 ddi_acc_handle_t cfg_hdle;
401
402 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_enable_mode: rdip = 0x%p\n",
403 (void *)rdip));
404
405 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl,
406 &caps_ptr, &cfg_hdle) != DDI_SUCCESS)
407 return (DDI_FAILURE);
408
409 if (type == DDI_INTR_TYPE_MSI) {
410 if (msi_ctrl & PCI_MSI_ENABLE_BIT)
411 goto finished;
412
413 msi_ctrl |= PCI_MSI_ENABLE_BIT;
414 PCI_CAP_PUT16(cfg_hdle, NULL, caps_ptr, PCI_MSI_CTRL, msi_ctrl);
415
416 } else if (type == DDI_INTR_TYPE_MSIX) {
417 if (msi_ctrl & PCI_MSIX_ENABLE_BIT)
418 goto finished;
419
420 msi_ctrl |= PCI_MSIX_ENABLE_BIT;
421 PCI_CAP_PUT16(cfg_hdle, NULL, caps_ptr, PCI_MSIX_CTRL,
422 msi_ctrl);
423 }
424
425 finished:
426 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_enable_mode: msi_ctrl = %x\n",
427 msi_ctrl));
428
429 pci_config_teardown(&cfg_hdle);
430 return (DDI_SUCCESS);
431 }
432
433
434 /*
435 * pci_msi_disable_mode:
436 *
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.
439 *
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.
443 */
444 int
pci_msi_disable_mode(dev_info_t * rdip,int type)445 pci_msi_disable_mode(dev_info_t *rdip, int type)
446 {
447 ushort_t caps_ptr, msi_ctrl;
448 ddi_acc_handle_t cfg_hdle;
449
450 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_disable_mode: rdip = 0x%p\n",
451 (void *)rdip));
452
453 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl,
454 &caps_ptr, &cfg_hdle) != DDI_SUCCESS)
455 return (DDI_FAILURE);
456
457 /* Reset the "enable" bit */
458 if (type == DDI_INTR_TYPE_MSI) {
459 if (!(msi_ctrl & PCI_MSI_ENABLE_BIT))
460 goto finished;
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))
465 goto finished;
466
467 msi_ctrl &= ~PCI_MSIX_ENABLE_BIT;
468 PCI_CAP_PUT16(cfg_hdle, NULL, caps_ptr, PCI_MSIX_CTRL,
469 msi_ctrl);
470 }
471
472 finished:
473 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_disable_mode: msi_ctrl = %x\n",
474 msi_ctrl));
475
476 pci_config_teardown(&cfg_hdle);
477 return (DDI_SUCCESS);
478 }
479
480
481 /*
482 * pci_msi_set_mask:
483 *
484 * Set the mask bit in the MSI/X capability structure
485 */
486 /* ARGSUSED */
487 int
pci_msi_set_mask(dev_info_t * rdip,int type,int inum)488 pci_msi_set_mask(dev_info_t *rdip, int type, int inum)
489 {
490 int offset;
491 int ret = DDI_FAILURE;
492 ushort_t caps_ptr, msi_ctrl;
493 ddi_acc_handle_t cfg_hdle;
494 uint32_t mask_bits;
495
496 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_set_mask: rdip = 0x%p, "
497 "type = 0x%x\n", (void *)rdip, type));
498
499 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl,
500 &caps_ptr, &cfg_hdle) != DDI_SUCCESS)
501 return (DDI_FAILURE);
502
503 if (type == DDI_INTR_TYPE_MSI) {
504 if (!(msi_ctrl & PCI_MSI_PVM_MASK))
505 goto done;
506
507 offset = (msi_ctrl & PCI_MSI_64BIT_MASK) ?
508 PCI_MSI_64BIT_MASKBITS : PCI_MSI_32BIT_MASK;
509
510 if ((mask_bits = PCI_CAP_GET32(cfg_hdle, NULL, caps_ptr,
511 offset)) == PCI_CAP_EINVAL32)
512 goto done;
513
514 mask_bits |= (1 << inum);
515
516 PCI_CAP_PUT32(cfg_hdle, NULL, caps_ptr, offset, mask_bits);
517
518 } else if (type == DDI_INTR_TYPE_MSIX) {
519 uintptr_t off;
520 ddi_intr_msix_t *msix_p;
521
522 /* Set function mask */
523 if (msi_ctrl & PCI_MSIX_FUNCTION_MASK) {
524 ret = DDI_SUCCESS;
525 goto done;
526 }
527
528 msix_p = i_ddi_get_msix(rdip);
529
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;
533
534 /* Set the Mask bit */
535 ddi_put32(msix_p->msix_tbl_hdl, (uint32_t *)off, 0x1);
536 }
537
538 ret = DDI_SUCCESS;
539 done:
540 pci_config_teardown(&cfg_hdle);
541 return (ret);
542 }
543
544
545 /*
546 * pci_msi_clr_mask:
547 *
548 * Clear the mask bit in the MSI/X capability structure
549 */
550 /* ARGSUSED */
551 int
pci_msi_clr_mask(dev_info_t * rdip,int type,int inum)552 pci_msi_clr_mask(dev_info_t *rdip, int type, int inum)
553 {
554 ushort_t caps_ptr, msi_ctrl;
555 ddi_acc_handle_t cfg_hdle;
556 int offset;
557 int ret = DDI_FAILURE;
558 uint32_t mask_bits;
559
560 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_clr_mask: rdip = 0x%p, "
561 "type = 0x%x\n", (void *)rdip, type));
562
563 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl,
564 &caps_ptr, &cfg_hdle) != DDI_SUCCESS)
565 return (DDI_FAILURE);
566
567 if (type == DDI_INTR_TYPE_MSI) {
568 if (!(msi_ctrl & PCI_MSI_PVM_MASK))
569 goto done;
570
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)
575 goto done;
576
577 mask_bits &= ~(1 << inum);
578
579 PCI_CAP_PUT32(cfg_hdle, NULL, caps_ptr, offset, mask_bits);
580
581 } else if (type == DDI_INTR_TYPE_MSIX) {
582 uintptr_t off;
583 ddi_intr_msix_t *msix_p;
584
585 if (msi_ctrl & PCI_MSIX_FUNCTION_MASK) {
586 ret = DDI_SUCCESS;
587 goto done;
588 }
589
590 msix_p = i_ddi_get_msix(rdip);
591
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;
595
596 /* Clear the Mask bit */
597 ddi_put32(msix_p->msix_tbl_hdl, (uint32_t *)off, 0x0);
598 }
599
600 ret = DDI_SUCCESS;
601 done:
602 pci_config_teardown(&cfg_hdle);
603 return (ret);
604 }
605
606
607 /*
608 * pci_msi_get_pending:
609 *
610 * Get the pending bit from the MSI/X capability structure
611 */
612 /* ARGSUSED */
613 int
pci_msi_get_pending(dev_info_t * rdip,int type,int inum,int * pendingp)614 pci_msi_get_pending(dev_info_t *rdip, int type, int inum, int *pendingp)
615 {
616 ushort_t caps_ptr, msi_ctrl;
617 ddi_acc_handle_t cfg_hdle;
618 int offset;
619 int ret = DDI_FAILURE;
620
621 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_get_pending: rdip = 0x%p\n",
622 (void *)rdip));
623
624 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl,
625 &caps_ptr, &cfg_hdle) != DDI_SUCCESS)
626 return (DDI_FAILURE);
627
628 if (type == DDI_INTR_TYPE_MSI) {
629 uint32_t pending_bits;
630
631 if (!(msi_ctrl & PCI_MSI_PVM_MASK)) {
632 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_get_pending: "
633 "PVM is not supported\n"));
634 goto done;
635 }
636
637 offset = (msi_ctrl & PCI_MSI_64BIT_MASK) ?
638 PCI_MSI_64BIT_PENDING : PCI_MSI_32BIT_PENDING;
639
640 if ((pending_bits = PCI_CAP_GET32(cfg_hdle, NULL, caps_ptr,
641 offset)) == PCI_CAP_EINVAL32)
642 goto done;
643
644 *pendingp = pending_bits & ~(1 >> inum);
645
646 } else if (type == DDI_INTR_TYPE_MSIX) {
647 uintptr_t off;
648 uint64_t pending_bits;
649 ddi_intr_msix_t *msix_p = i_ddi_get_msix(rdip);
650
651 /* Offset into the PBA array which has entry for "inum" */
652 off = (uintptr_t)msix_p->msix_pba_addr + (inum / 64);
653
654 /* Read the PBA array */
655 pending_bits = ddi_get64(msix_p->msix_pba_hdl, (uint64_t *)off);
656
657 *pendingp = pending_bits & ~(1 >> inum);
658 }
659
660 ret = DDI_SUCCESS;
661 done:
662 pci_config_teardown(&cfg_hdle);
663 return (ret);
664 }
665
666
667 /*
668 * pci_msi_get_nintrs:
669 *
670 * For a given type (MSI/X) returns the number of interrupts supported
671 */
672 int
pci_msi_get_nintrs(dev_info_t * rdip,int type,int * nintrs)673 pci_msi_get_nintrs(dev_info_t *rdip, int type, int *nintrs)
674 {
675 ushort_t caps_ptr, msi_ctrl;
676 ddi_acc_handle_t cfg_hdle;
677
678 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_get_nintrs: rdip = 0x%p\n",
679 (void *)rdip));
680
681 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl,
682 &caps_ptr, &cfg_hdle) != DDI_SUCCESS)
683 return (DDI_FAILURE);
684
685 if (type == DDI_INTR_TYPE_MSI) {
686 *nintrs = 1 << ((msi_ctrl & PCI_MSI_MMC_MASK) >>
687 PCI_MSI_MMC_SHIFT);
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;
691 }
692
693 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_get_nintrs: "
694 "nintr = 0x%x\n", *nintrs));
695
696 pci_config_teardown(&cfg_hdle);
697 return (DDI_SUCCESS);
698 }
699
700
701 /*
702 * pci_msi_set_nintrs:
703 *
704 * For a given type (MSI/X) sets the number of interrupts supported
705 * by the system.
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
708 */
709 int
pci_msi_set_nintrs(dev_info_t * rdip,int type,int navail)710 pci_msi_set_nintrs(dev_info_t *rdip, int type, int navail)
711 {
712 ushort_t caps_ptr, msi_ctrl;
713 ddi_acc_handle_t cfg_hdle;
714
715 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_set_nintrs: rdip = 0x%p, "
716 "navail = 0x%x\n", (void *)rdip, navail));
717
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)))
721 return (DDI_EINVAL);
722
723 if (pci_get_msi_ctrl(rdip, type, &msi_ctrl,
724 &caps_ptr, &cfg_hdle) != DDI_SUCCESS)
725 return (DDI_FAILURE);
726
727 if (type == DDI_INTR_TYPE_MSI) {
728 msi_ctrl |= ((highbit(navail) -1) << PCI_MSI_MME_SHIFT);
729
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"));
733 }
734
735 pci_config_teardown(&cfg_hdle);
736 return (DDI_SUCCESS);
737 }
738
739
740 /*
741 * pci_msi_get_supported_type:
742 *
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.
745 */
746 int
pci_msi_get_supported_type(dev_info_t * rdip,int * typesp)747 pci_msi_get_supported_type(dev_info_t *rdip, int *typesp)
748 {
749 ushort_t caps_ptr, msi_ctrl;
750 ddi_acc_handle_t cfg_hdle;
751
752 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_get_supported_type: "
753 "rdip = 0x%p\n", (void *)rdip));
754
755 *typesp = 0;
756
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);
761 }
762
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);
767 }
768
769 DDI_INTR_NEXDBG((CE_CONT, "pci_msi_get_supported_type: "
770 "rdip = 0x%p types 0x%x\n", (void *)rdip, *typesp));
771
772 return (*typesp == 0 ? DDI_FAILURE : DDI_SUCCESS);
773 }
774
775
776 /*
777 * pci_msix_init:
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.
781 */
782 ddi_intr_msix_t *
pci_msix_init(dev_info_t * rdip)783 pci_msix_init(dev_info_t *rdip)
784 {
785 uint_t rnumber, breg, nregs;
786 size_t msix_tbl_size;
787 size_t pba_tbl_size;
788 ushort_t caps_ptr, msix_ctrl;
789 ddi_intr_msix_t *msix_p;
790 ddi_acc_handle_t cfg_hdle;
791 pci_regspec_t *rp;
792 int reg_size, addr_space, offset, *regs_list;
793 int i, ret;
794
795 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: rdip = %p\n", (void *)rdip));
796
797 if (pci_get_msi_ctrl(rdip, DDI_INTR_TYPE_MSIX, &msix_ctrl,
798 &caps_ptr, &cfg_hdle) != DDI_SUCCESS)
799 return (NULL);
800
801 msix_p = kmem_zalloc(sizeof (ddi_intr_msix_t), KM_SLEEP);
802
803 /*
804 * Initialize the devacc structure
805 */
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;
810
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);
814
815 if ((breg = pci_msix_bir_index[msix_p->msix_tbl_offset &
816 PCI_MSIX_TBL_BIR_MASK]) == 0xff)
817 goto fail1;
818
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;
823
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,
826 msix_tbl_size));
827
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));
833
834 goto fail1;
835 }
836
837 reg_size = sizeof (pci_regspec_t) / sizeof (int);
838
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);
843
844 if ((offset == breg) && ((addr_space == PCI_ADDR_MEM32) ||
845 (addr_space == PCI_ADDR_MEM64))) {
846 rnumber = i;
847 break;
848 }
849 }
850
851 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: MSI-X rnum = %d\n", rnumber));
852
853 if (rnumber == 0) {
854 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: "
855 "no mtaching reg number for offset 0x%x\n", breg));
856
857 goto fail2;
858 }
859
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));
866
867 goto fail2;
868 }
869
870 /*
871 * Map in the MSI-X Pending Bit Array
872 */
873 msix_p->msix_pba_offset = PCI_CAP_GET32(cfg_hdle, NULL, caps_ptr,
874 PCI_MSIX_PBA_OFFSET);
875
876 if ((breg = pci_msix_bir_index[msix_p->msix_pba_offset &
877 PCI_MSIX_PBA_BIR_MASK]) == 0xff)
878 goto fail3;
879
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;
883
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,
886 pba_tbl_size));
887
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);
892
893 if ((offset == breg) && ((addr_space == PCI_ADDR_MEM32) ||
894 (addr_space == PCI_ADDR_MEM64))) {
895 rnumber = i;
896 break;
897 }
898 }
899
900 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: PBA rnum = %d\n", rnumber));
901
902 if (rnumber == 0) {
903 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: "
904 "no matching reg number for offset 0x%x\n", breg));
905
906 goto fail3;
907 }
908
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));
915
916 goto fail3;
917 }
918
919 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_init: msix_p = 0x%p DONE!!\n",
920 (void *)msix_p));
921
922 ddi_prop_free(regs_list);
923 goto done;
924
925 fail3:
926 ddi_regs_map_free(&msix_p->msix_tbl_hdl);
927 fail2:
928 ddi_prop_free(regs_list);
929 fail1:
930 kmem_free(msix_p, sizeof (ddi_intr_msix_t));
931 msix_p = NULL;
932 done:
933 pci_config_teardown(&cfg_hdle);
934 return (msix_p);
935 }
936
937
938 /*
939 * pci_msix_fini:
940 * This function cleans up previously allocated handles/addrs etc.
941 * It is only called if no more MSI-X interrupts are being used.
942 */
943 void
pci_msix_fini(ddi_intr_msix_t * msix_p)944 pci_msix_fini(ddi_intr_msix_t *msix_p)
945 {
946 DDI_INTR_NEXDBG((CE_CONT, "pci_msix_fini: msix_p = 0x%p\n",
947 (void *)msix_p));
948
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));
952 }
953
954
955 /*
956 * pci_msix_dup:
957 * This function duplicates the address and data pair of one msi-x
958 * vector to another msi-x vector.
959 */
960 int
pci_msix_dup(dev_info_t * rdip,int org_inum,int dup_inum)961 pci_msix_dup(dev_info_t *rdip, int org_inum, int dup_inum)
962 {
963 ddi_intr_msix_t *msix_p = i_ddi_get_msix(rdip);
964 uint64_t addr;
965 uint64_t data;
966 uintptr_t off;
967
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));
970
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);
974
975 /*
976 * For the MSI-X number passed in, get the "data" and "addr" fields.
977 *
978 * Note that the spec only requires 32-bit accesses to be supported.
979 * Apparently some chipsets don't support 64-bit accesses.
980 */
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));
985
986 data = ddi_get32(msix_p->msix_tbl_hdl,
987 (uint32_t *)(off + PCI_MSIX_DATA_OFFSET));
988
989 /* Program new vector with these existing values */
990 return (pci_msi_configure(rdip, DDI_INTR_TYPE_MSIX, 1, dup_inum, addr,
991 data));
992 }
993
994
995 /*
996 * Next set of routines are for INTx (legacy) PCI interrupt
997 * support only.
998 */
999
1000 /*
1001 * pci_intx_get_cap:
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'
1007 *
1008 * Reset the device back to the original state.
1009 */
1010 int
pci_intx_get_cap(dev_info_t * dip,int * flagsp)1011 pci_intx_get_cap(dev_info_t *dip, int *flagsp)
1012 {
1013 uint16_t cmdreg, savereg;
1014 ddi_acc_handle_t cfg_hdl;
1015 #ifdef DEBUG
1016 uint16_t statreg;
1017 #endif /* DEBUG */
1018
1019 *flagsp = 0;
1020 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_get_cap: %s%d: called\n",
1021 ddi_driver_name(dip), ddi_get_instance(dip)));
1022
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);
1027 }
1028
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));
1032
1033 /* Disable the interrupts */
1034 cmdreg = savereg | PCI_COMM_INTX_DISABLE;
1035 pci_config_put16(cfg_hdl, PCI_CONF_COMM, cmdreg);
1036
1037 #ifdef DEBUG
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));
1041 #endif /* DEBUG */
1042
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));
1047
1048 *flagsp = DDI_INTR_FLAG_LEVEL;
1049
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);
1055 }
1056
1057 /* Restore the device back to the original state and return */
1058 pci_config_put16(cfg_hdl, PCI_CONF_COMM, savereg);
1059
1060 pci_config_teardown(&cfg_hdl);
1061 return (DDI_SUCCESS);
1062 }
1063
1064
1065 /*
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.
1069 */
1070 int
pci_intx_clr_mask(dev_info_t * dip)1071 pci_intx_clr_mask(dev_info_t *dip)
1072 {
1073 uint16_t cmdreg;
1074 ddi_acc_handle_t cfg_hdl;
1075
1076 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_clr_mask: %s%d: called\n",
1077 ddi_driver_name(dip), ddi_get_instance(dip)));
1078
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);
1083 }
1084
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));
1088
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);
1094 }
1095
1096
1097 /*
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.
1101 */
1102 int
pci_intx_set_mask(dev_info_t * dip)1103 pci_intx_set_mask(dev_info_t *dip)
1104 {
1105 uint16_t cmdreg;
1106 ddi_acc_handle_t cfg_hdl;
1107
1108 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_set_mask: %s%d: called\n",
1109 ddi_driver_name(dip), ddi_get_instance(dip)));
1110
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);
1115 }
1116
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));
1120
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);
1126 }
1127
1128 /*
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
1133 * 'Pending'.
1134 */
1135 int
pci_intx_get_pending(dev_info_t * dip,int * pendingp)1136 pci_intx_get_pending(dev_info_t *dip, int *pendingp)
1137 {
1138 uint16_t statreg;
1139 ddi_acc_handle_t cfg_hdl;
1140
1141 *pendingp = 0;
1142 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_get_pending: %s%d: called\n",
1143 ddi_driver_name(dip), ddi_get_instance(dip)));
1144
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);
1149 }
1150
1151 statreg = pci_config_get16(cfg_hdl, PCI_CONF_STAT);
1152
1153 if (statreg & PCI_STAT_INTR) {
1154 DDI_INTR_NEXDBG((CE_CONT, "pci_intx_get_pending: "
1155 "interrupt is pending\n"));
1156 *pendingp = 1;
1157 }
1158
1159 pci_config_teardown(&cfg_hdl);
1160 return (DDI_SUCCESS);
1161 }
1162
1163
1164 /*
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
1169 */
1170 /*ARGSUSED*/
1171 ddi_intrspec_t
pci_intx_get_ispec(dev_info_t * dip,dev_info_t * rdip,int inum)1172 pci_intx_get_ispec(dev_info_t *dip, dev_info_t *rdip, int inum)
1173 {
1174 int *intpriorities;
1175 uint_t num_intpriorities;
1176 struct intrspec *ispec;
1177 ddi_acc_handle_t cfg_hdl;
1178 struct ddi_parent_private_data *pdptr;
1179
1180 if ((pdptr = ddi_get_parent_data(rdip)) == NULL)
1181 return (NULL);
1182
1183 ispec = pdptr->par_intr;
1184 ASSERT(ispec);
1185
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);
1194 }
1195
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);
1199 }
1200
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);
1207 }
1208
1209 ispec->intrspec_vec = pci_config_get8(cfg_hdl, PCI_CONF_ILINE);
1210 pci_config_teardown(&cfg_hdl);
1211 }
1212
1213 return ((ddi_intrspec_t)ispec);
1214 }
1215
1216 static uint32_t
pci_match_class_val(uint32_t key,pci_class_val_t * rec_p,int nrec,uint32_t default_val)1217 pci_match_class_val(uint32_t key, pci_class_val_t *rec_p, int nrec,
1218 uint32_t default_val)
1219 {
1220 int i;
1221
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);
1226 }
1227
1228 return (default_val);
1229 }
1230
1231 /*
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.
1234 */
1235 uint32_t
pci_class_to_val(dev_info_t * rdip,char * property_name,pci_class_val_t * rec_p,int nrec,uint32_t default_val)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)
1238 {
1239 int property_len;
1240 uint32_t class_code;
1241 pci_class_val_t *conf;
1242 uint32_t val = default_val;
1243
1244 /*
1245 * Use the "class-code" property to get the base and sub class
1246 * codes for the requesting device.
1247 */
1248 class_code = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY, rdip,
1249 DDI_PROP_DONTPASS, "class-code", -1);
1250
1251 if (class_code == -1)
1252 return (val);
1253
1254 /* look up the val from the default table */
1255 val = pci_match_class_val(class_code, rec_p, nrec, val);
1256
1257
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))
1261 return (val);
1262
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);
1267 return (val);
1268 }
1269
1270 /*
1271 * pci_class_to_pil:
1272 *
1273 * Return the pil for a given PCI device.
1274 */
1275 uint32_t
pci_class_to_pil(dev_info_t * rdip)1276 pci_class_to_pil(dev_info_t *rdip)
1277 {
1278 uint32_t pil;
1279
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);
1284
1285 /* Range check the result */
1286 if (pil >= 0xf)
1287 pil = 1;
1288
1289 return (pil);
1290 }
1291
1292 /*
1293 * pci_class_to_intr_weight:
1294 *
1295 * Return the intr_weight for a given PCI device.
1296 */
1297 int32_t
pci_class_to_intr_weight(dev_info_t * rdip)1298 pci_class_to_intr_weight(dev_info_t *rdip)
1299 {
1300 int32_t intr_weight;
1301
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);
1306
1307 /* range check the result */
1308 if (intr_weight < 0)
1309 intr_weight = 0;
1310 if (intr_weight > 1000)
1311 intr_weight = 1000;
1312
1313 return (intr_weight);
1314 }
1315