|
@@ -282,7 +282,7 @@ static irqreturn_t pvrdma_intr0_handler(int irq, void *dev_id)
|
|
|
|
|
|
dev_dbg(&dev->pdev->dev, "interrupt 0 (response) handler\n");
|
|
dev_dbg(&dev->pdev->dev, "interrupt 0 (response) handler\n");
|
|
|
|
|
|
- if (dev->intr.type != PVRDMA_INTR_TYPE_MSIX) {
|
|
|
|
|
|
+ if (!dev->pdev->msix_enabled) {
|
|
/* Legacy intr */
|
|
/* Legacy intr */
|
|
icr = pvrdma_read_reg(dev, PVRDMA_REG_ICR);
|
|
icr = pvrdma_read_reg(dev, PVRDMA_REG_ICR);
|
|
if (icr == 0)
|
|
if (icr == 0)
|
|
@@ -489,31 +489,13 @@ static irqreturn_t pvrdma_intrx_handler(int irq, void *dev_id)
|
|
return IRQ_HANDLED;
|
|
return IRQ_HANDLED;
|
|
}
|
|
}
|
|
|
|
|
|
-static void pvrdma_disable_msi_all(struct pvrdma_dev *dev)
|
|
|
|
-{
|
|
|
|
- if (dev->intr.type == PVRDMA_INTR_TYPE_MSIX)
|
|
|
|
- pci_disable_msix(dev->pdev);
|
|
|
|
- else if (dev->intr.type == PVRDMA_INTR_TYPE_MSI)
|
|
|
|
- pci_disable_msi(dev->pdev);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static void pvrdma_free_irq(struct pvrdma_dev *dev)
|
|
static void pvrdma_free_irq(struct pvrdma_dev *dev)
|
|
{
|
|
{
|
|
int i;
|
|
int i;
|
|
|
|
|
|
dev_dbg(&dev->pdev->dev, "freeing interrupts\n");
|
|
dev_dbg(&dev->pdev->dev, "freeing interrupts\n");
|
|
-
|
|
|
|
- if (dev->intr.type == PVRDMA_INTR_TYPE_MSIX) {
|
|
|
|
- for (i = 0; i < dev->intr.size; i++) {
|
|
|
|
- if (dev->intr.enabled[i]) {
|
|
|
|
- free_irq(dev->intr.msix_entry[i].vector, dev);
|
|
|
|
- dev->intr.enabled[i] = 0;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- } else if (dev->intr.type == PVRDMA_INTR_TYPE_INTX ||
|
|
|
|
- dev->intr.type == PVRDMA_INTR_TYPE_MSI) {
|
|
|
|
- free_irq(dev->pdev->irq, dev);
|
|
|
|
- }
|
|
|
|
|
|
+ for (i = 0; i < dev->nr_vectors; i++)
|
|
|
|
+ free_irq(pci_irq_vector(dev->pdev, i), dev);
|
|
}
|
|
}
|
|
|
|
|
|
static void pvrdma_enable_intrs(struct pvrdma_dev *dev)
|
|
static void pvrdma_enable_intrs(struct pvrdma_dev *dev)
|
|
@@ -528,126 +510,48 @@ static void pvrdma_disable_intrs(struct pvrdma_dev *dev)
|
|
pvrdma_write_reg(dev, PVRDMA_REG_IMR, ~0);
|
|
pvrdma_write_reg(dev, PVRDMA_REG_IMR, ~0);
|
|
}
|
|
}
|
|
|
|
|
|
-static int pvrdma_enable_msix(struct pci_dev *pdev, struct pvrdma_dev *dev)
|
|
|
|
-{
|
|
|
|
- int i;
|
|
|
|
- int ret;
|
|
|
|
-
|
|
|
|
- for (i = 0; i < PVRDMA_MAX_INTERRUPTS; i++) {
|
|
|
|
- dev->intr.msix_entry[i].entry = i;
|
|
|
|
- dev->intr.msix_entry[i].vector = i;
|
|
|
|
-
|
|
|
|
- switch (i) {
|
|
|
|
- case 0:
|
|
|
|
- /* CMD ring handler */
|
|
|
|
- dev->intr.handler[i] = pvrdma_intr0_handler;
|
|
|
|
- break;
|
|
|
|
- case 1:
|
|
|
|
- /* Async event ring handler */
|
|
|
|
- dev->intr.handler[i] = pvrdma_intr1_handler;
|
|
|
|
- break;
|
|
|
|
- default:
|
|
|
|
- /* Completion queue handler */
|
|
|
|
- dev->intr.handler[i] = pvrdma_intrx_handler;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- ret = pci_enable_msix(pdev, dev->intr.msix_entry,
|
|
|
|
- PVRDMA_MAX_INTERRUPTS);
|
|
|
|
- if (!ret) {
|
|
|
|
- dev->intr.type = PVRDMA_INTR_TYPE_MSIX;
|
|
|
|
- dev->intr.size = PVRDMA_MAX_INTERRUPTS;
|
|
|
|
- } else if (ret > 0) {
|
|
|
|
- ret = pci_enable_msix(pdev, dev->intr.msix_entry, ret);
|
|
|
|
- if (!ret) {
|
|
|
|
- dev->intr.type = PVRDMA_INTR_TYPE_MSIX;
|
|
|
|
- dev->intr.size = ret;
|
|
|
|
- } else {
|
|
|
|
- dev->intr.size = 0;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- dev_dbg(&pdev->dev, "using interrupt type %d, size %d\n",
|
|
|
|
- dev->intr.type, dev->intr.size);
|
|
|
|
-
|
|
|
|
- return ret;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static int pvrdma_alloc_intrs(struct pvrdma_dev *dev)
|
|
static int pvrdma_alloc_intrs(struct pvrdma_dev *dev)
|
|
{
|
|
{
|
|
- int ret = 0;
|
|
|
|
- int i;
|
|
|
|
|
|
+ struct pci_dev *pdev = dev->pdev;
|
|
|
|
+ int ret = 0, i;
|
|
|
|
|
|
- if (pci_find_capability(dev->pdev, PCI_CAP_ID_MSIX) &&
|
|
|
|
- pvrdma_enable_msix(dev->pdev, dev)) {
|
|
|
|
- /* Try MSI */
|
|
|
|
- ret = pci_enable_msi(dev->pdev);
|
|
|
|
- if (!ret) {
|
|
|
|
- dev->intr.type = PVRDMA_INTR_TYPE_MSI;
|
|
|
|
- } else {
|
|
|
|
- /* Legacy INTR */
|
|
|
|
- dev->intr.type = PVRDMA_INTR_TYPE_INTX;
|
|
|
|
- }
|
|
|
|
|
|
+ ret = pci_alloc_irq_vectors(pdev, 1, PVRDMA_MAX_INTERRUPTS,
|
|
|
|
+ PCI_IRQ_MSIX);
|
|
|
|
+ if (ret < 0) {
|
|
|
|
+ ret = pci_alloc_irq_vectors(pdev, 1, 1,
|
|
|
|
+ PCI_IRQ_MSI | PCI_IRQ_LEGACY);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ return ret;
|
|
}
|
|
}
|
|
|
|
+ dev->nr_vectors = ret;
|
|
|
|
|
|
- /* Request First IRQ */
|
|
|
|
- switch (dev->intr.type) {
|
|
|
|
- case PVRDMA_INTR_TYPE_INTX:
|
|
|
|
- case PVRDMA_INTR_TYPE_MSI:
|
|
|
|
- ret = request_irq(dev->pdev->irq, pvrdma_intr0_handler,
|
|
|
|
- IRQF_SHARED, DRV_NAME, dev);
|
|
|
|
- if (ret) {
|
|
|
|
- dev_err(&dev->pdev->dev,
|
|
|
|
- "failed to request interrupt\n");
|
|
|
|
- goto disable_msi;
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
- case PVRDMA_INTR_TYPE_MSIX:
|
|
|
|
- ret = request_irq(dev->intr.msix_entry[0].vector,
|
|
|
|
- pvrdma_intr0_handler, 0, DRV_NAME, dev);
|
|
|
|
- if (ret) {
|
|
|
|
- dev_err(&dev->pdev->dev,
|
|
|
|
- "failed to request interrupt 0\n");
|
|
|
|
- goto disable_msi;
|
|
|
|
- }
|
|
|
|
- dev->intr.enabled[0] = 1;
|
|
|
|
- break;
|
|
|
|
- default:
|
|
|
|
- /* Not reached */
|
|
|
|
- break;
|
|
|
|
|
|
+ ret = request_irq(pci_irq_vector(dev->pdev, 0), pvrdma_intr0_handler,
|
|
|
|
+ pdev->msix_enabled ? 0 : IRQF_SHARED, DRV_NAME, dev);
|
|
|
|
+ if (ret) {
|
|
|
|
+ dev_err(&dev->pdev->dev,
|
|
|
|
+ "failed to request interrupt 0\n");
|
|
|
|
+ goto out_free_vectors;
|
|
}
|
|
}
|
|
|
|
|
|
- /* For MSIX: request intr for each vector */
|
|
|
|
- if (dev->intr.size > 1) {
|
|
|
|
- ret = request_irq(dev->intr.msix_entry[1].vector,
|
|
|
|
- pvrdma_intr1_handler, 0, DRV_NAME, dev);
|
|
|
|
|
|
+ for (i = 1; i < dev->nr_vectors; i++) {
|
|
|
|
+ ret = request_irq(pci_irq_vector(dev->pdev, i),
|
|
|
|
+ i == 1 ? pvrdma_intr1_handler :
|
|
|
|
+ pvrdma_intrx_handler,
|
|
|
|
+ 0, DRV_NAME, dev);
|
|
if (ret) {
|
|
if (ret) {
|
|
dev_err(&dev->pdev->dev,
|
|
dev_err(&dev->pdev->dev,
|
|
- "failed to request interrupt 1\n");
|
|
|
|
- goto free_irq;
|
|
|
|
- }
|
|
|
|
- dev->intr.enabled[1] = 1;
|
|
|
|
-
|
|
|
|
- for (i = 2; i < dev->intr.size; i++) {
|
|
|
|
- ret = request_irq(dev->intr.msix_entry[i].vector,
|
|
|
|
- pvrdma_intrx_handler, 0,
|
|
|
|
- DRV_NAME, dev);
|
|
|
|
- if (ret) {
|
|
|
|
- dev_err(&dev->pdev->dev,
|
|
|
|
- "failed to request interrupt %d\n", i);
|
|
|
|
- goto free_irq;
|
|
|
|
- }
|
|
|
|
- dev->intr.enabled[i] = 1;
|
|
|
|
|
|
+ "failed to request interrupt %d\n", i);
|
|
|
|
+ goto free_irqs;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
-free_irq:
|
|
|
|
- pvrdma_free_irq(dev);
|
|
|
|
-disable_msi:
|
|
|
|
- pvrdma_disable_msi_all(dev);
|
|
|
|
|
|
+free_irqs:
|
|
|
|
+ while (--i >= 0)
|
|
|
|
+ free_irq(pci_irq_vector(dev->pdev, i), dev);
|
|
|
|
+out_free_vectors:
|
|
|
|
+ pci_free_irq_vectors(pdev);
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1091,7 +995,7 @@ err_free_uar_table:
|
|
pvrdma_uar_table_cleanup(dev);
|
|
pvrdma_uar_table_cleanup(dev);
|
|
err_free_intrs:
|
|
err_free_intrs:
|
|
pvrdma_free_irq(dev);
|
|
pvrdma_free_irq(dev);
|
|
- pvrdma_disable_msi_all(dev);
|
|
|
|
|
|
+ pci_free_irq_vectors(pdev);
|
|
err_free_cq_ring:
|
|
err_free_cq_ring:
|
|
pvrdma_page_dir_cleanup(dev, &dev->cq_pdir);
|
|
pvrdma_page_dir_cleanup(dev, &dev->cq_pdir);
|
|
err_free_async_ring:
|
|
err_free_async_ring:
|
|
@@ -1141,7 +1045,7 @@ static void pvrdma_pci_remove(struct pci_dev *pdev)
|
|
|
|
|
|
pvrdma_disable_intrs(dev);
|
|
pvrdma_disable_intrs(dev);
|
|
pvrdma_free_irq(dev);
|
|
pvrdma_free_irq(dev);
|
|
- pvrdma_disable_msi_all(dev);
|
|
|
|
|
|
+ pci_free_irq_vectors(pdev);
|
|
|
|
|
|
/* Deactivate pvrdma device */
|
|
/* Deactivate pvrdma device */
|
|
pvrdma_write_reg(dev, PVRDMA_REG_CTL, PVRDMA_DEVICE_CTL_RESET);
|
|
pvrdma_write_reg(dev, PVRDMA_REG_CTL, PVRDMA_DEVICE_CTL_RESET);
|