in drivers/virt/nitro_enclaves/ne_pci_dev.c [295:364]
static int ne_setup_msix(struct pci_dev *pdev)
{
struct ne_pci_dev *ne_pci_dev = pci_get_drvdata(pdev);
int nr_vecs = 0;
int rc = -EINVAL;
nr_vecs = pci_msix_vec_count(pdev);
if (nr_vecs < 0) {
rc = nr_vecs;
dev_err(&pdev->dev, "Error in getting vec count [rc=%d]\n", rc);
return rc;
}
rc = pci_alloc_irq_vectors(pdev, nr_vecs, nr_vecs, PCI_IRQ_MSIX);
if (rc < 0) {
dev_err(&pdev->dev, "Error in alloc MSI-X vecs [rc=%d]\n", rc);
return rc;
}
/*
* This IRQ gets triggered every time the PCI device responds to a
* command request. The reply is then retrieved, reading from the MMIO
* space of the PCI device.
*/
rc = request_irq(pci_irq_vector(pdev, NE_VEC_REPLY), ne_reply_handler,
0, "enclave_cmd", ne_pci_dev);
if (rc < 0) {
dev_err(&pdev->dev, "Error in request irq reply [rc=%d]\n", rc);
goto free_irq_vectors;
}
ne_pci_dev->event_wq = create_singlethread_workqueue("ne_pci_dev_wq");
if (!ne_pci_dev->event_wq) {
rc = -ENOMEM;
dev_err(&pdev->dev, "Cannot get wq for dev events [rc=%d]\n", rc);
goto free_reply_irq_vec;
}
INIT_WORK(&ne_pci_dev->notify_work, ne_event_work_handler);
/*
* This IRQ gets triggered every time any enclave's state changes. Its
* handler then scans for the changes and propagates them to the user
* space.
*/
rc = request_irq(pci_irq_vector(pdev, NE_VEC_EVENT), ne_event_handler,
0, "enclave_evt", ne_pci_dev);
if (rc < 0) {
dev_err(&pdev->dev, "Error in request irq event [rc=%d]\n", rc);
goto destroy_wq;
}
return 0;
destroy_wq:
destroy_workqueue(ne_pci_dev->event_wq);
free_reply_irq_vec:
free_irq(pci_irq_vector(pdev, NE_VEC_REPLY), ne_pci_dev);
free_irq_vectors:
pci_free_irq_vectors(pdev);
return rc;
}