| 495 | } |
| 496 | |
| 497 | int |
| 498 | ppt_setup_msi(struct vm *vm, int vcpu, int bus, int slot, int func, |
| 499 | uint64_t addr, uint64_t msg, int numvec) |
| 500 | { |
| 501 | int i, rid, flags; |
| 502 | int msi_count, startrid, error, tmp; |
| 503 | struct pptdev *ppt; |
| 504 | |
| 505 | if (numvec < 0 || numvec > MAX_MSIMSGS) |
| 506 | return (EINVAL); |
| 507 | |
| 508 | error = ppt_find(vm, bus, slot, func, &ppt); |
| 509 | if (error) |
| 510 | return (error); |
| 511 | |
| 512 | /* Reject attempts to enable MSI while MSI-X is active. */ |
| 513 | if (ppt->msix.num_msgs != 0 && numvec != 0) |
| 514 | return (EBUSY); |
| 515 | |
| 516 | /* Free any allocated resources */ |
| 517 | ppt_teardown_msi(ppt); |
| 518 | |
| 519 | if (numvec == 0) /* nothing more to do */ |
| 520 | return (0); |
| 521 | |
| 522 | flags = RF_ACTIVE; |
| 523 | msi_count = pci_msi_count(ppt->dev); |
| 524 | if (msi_count == 0) { |
| 525 | startrid = 0; /* legacy interrupt */ |
| 526 | msi_count = 1; |
| 527 | flags |= RF_SHAREABLE; |
| 528 | } else |
| 529 | startrid = 1; /* MSI */ |
| 530 | |
| 531 | /* |
| 532 | * The device must be capable of supporting the number of vectors |
| 533 | * the guest wants to allocate. |
| 534 | */ |
| 535 | if (numvec > msi_count) |
| 536 | return (EINVAL); |
| 537 | |
| 538 | /* |
| 539 | * Make sure that we can allocate all the MSI vectors that are needed |
| 540 | * by the guest. |
| 541 | */ |
| 542 | if (startrid == 1) { |
| 543 | tmp = numvec; |
| 544 | error = pci_alloc_msi(ppt->dev, &tmp); |
| 545 | if (error) |
| 546 | return (error); |
| 547 | else if (tmp != numvec) { |
| 548 | pci_release_msi(ppt->dev); |
| 549 | return (ENOSPC); |
| 550 | } else { |
| 551 | /* success */ |
| 552 | } |
| 553 | } |
| 554 |
no test coverage detected