diff options
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_driver.c | 23 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_init_chip.c | 36 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_kernel.h | 5 |
3 files changed, 42 insertions, 22 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index 1245180f210c..a3141bbc177a 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c @@ -138,19 +138,6 @@ static struct pci_driver ipath_driver = { }, }; -static void ipath_check_status(struct work_struct *work) -{ - struct ipath_devdata *dd = container_of(work, struct ipath_devdata, - status_work.work); - - /* - * If we don't have any interrupts, let the user know and - * don't bother checking again. - */ - if (dd->ipath_int_counter == 0) - dev_err(&dd->pcidev->dev, "No interrupts detected.\n"); -} - static inline void read_bars(struct ipath_devdata *dd, struct pci_dev *dev, u32 *bar0, u32 *bar1) { @@ -218,8 +205,6 @@ static struct ipath_devdata *ipath_alloc_devdata(struct pci_dev *pdev) dd->pcidev = pdev; pci_set_drvdata(pdev, dd); - INIT_DELAYED_WORK(&dd->status_work, ipath_check_status); - list_add(&dd->ipath_list, &ipath_dev_list); bail_unlock: @@ -620,9 +605,6 @@ static int __devinit ipath_init_one(struct pci_dev *pdev, ipath_diag_add(dd); ipath_register_ib_device(dd); - /* Check that card status in STATUS_TIMEOUT seconds. */ - schedule_delayed_work(&dd->status_work, HZ * STATUS_TIMEOUT); - goto bail; bail_irqsetup: @@ -753,7 +735,6 @@ static void __devexit ipath_remove_one(struct pci_dev *pdev) */ ipath_shutdown_device(dd); - cancel_delayed_work(&dd->status_work); flush_scheduled_work(); if (dd->verbs_dev) @@ -2195,6 +2176,10 @@ void ipath_shutdown_device(struct ipath_devdata *dd) del_timer_sync(&dd->ipath_stats_timer); dd->ipath_stats_timer_active = 0; } + if (dd->ipath_intrchk_timer.data) { + del_timer_sync(&dd->ipath_intrchk_timer); + dd->ipath_intrchk_timer.data = 0; + } /* * clear all interrupts and errors, so that the next time the driver diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/infiniband/hw/ipath/ipath_init_chip.c index 1adafa97e082..0db19c1b45c3 100644 --- a/drivers/infiniband/hw/ipath/ipath_init_chip.c +++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c @@ -665,6 +665,28 @@ done: return ret; } +static void verify_interrupt(unsigned long opaque) +{ + struct ipath_devdata *dd = (struct ipath_devdata *) opaque; + + if (!dd) + return; /* being torn down */ + + /* + * If we don't have any interrupts, let the user know and + * don't bother checking again. + */ + if (dd->ipath_int_counter == 0) { + if (!dd->ipath_f_intr_fallback(dd)) + dev_err(&dd->pcidev->dev, "No interrupts detected, " + "not usable.\n"); + else /* re-arm the timer to see if fallback works */ + mod_timer(&dd->ipath_intrchk_timer, jiffies + HZ/2); + } else + ipath_cdbg(VERBOSE, "%u interrupts at timer check\n", + dd->ipath_int_counter); +} + /** * ipath_init_chip - do the actual initialization sequence on the chip * @dd: the infinipath device @@ -968,6 +990,20 @@ done: 0ULL); /* chip is usable; mark it as initialized */ *dd->ipath_statusp |= IPATH_STATUS_INITTED; + + /* + * setup to verify we get an interrupt, and fallback + * to an alternate if necessary and possible + */ + if (!reinit) { + init_timer(&dd->ipath_intrchk_timer); + dd->ipath_intrchk_timer.function = + verify_interrupt; + dd->ipath_intrchk_timer.data = + (unsigned long) dd; + } + dd->ipath_intrchk_timer.expires = jiffies + HZ/2; + add_timer(&dd->ipath_intrchk_timer); } else ipath_dev_err(dd, "No interrupts enabled, couldn't " "setup interrupt address\n"); diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h index cef3296efb96..56e51cd7d6b9 100644 --- a/drivers/infiniband/hw/ipath/ipath_kernel.h +++ b/drivers/infiniband/hw/ipath/ipath_kernel.h @@ -426,6 +426,8 @@ struct ipath_devdata { struct class_device *diag_class_dev; /* timer used to prevent stats overflow, error throttling, etc. */ struct timer_list ipath_stats_timer; + /* timer to verify interrupts work, and fallback if possible */ + struct timer_list ipath_intrchk_timer; void *ipath_dummy_hdrq; /* used after port close */ dma_addr_t ipath_dummy_hdrq_phys; @@ -629,9 +631,6 @@ struct ipath_devdata { u32 ipath_overrun_thresh_errs; u32 ipath_lli_errs; - /* status check work */ - struct delayed_work status_work; - /* * Not all devices managed by a driver instance are the same * type, so these fields must be per-device. |