mirror of https://gitee.com/openkylin/linux.git
IB/ipath: Fix check for no interrupts to reliably fallback to INTx
Newer HCAs support MSI interrupts and also INTx interrupts. Fix the code so that INTx can be reliably enabled if MSI interrupts are not working. Signed-off-by: Dave Olson <dave.olson@qlogic.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
This commit is contained in:
parent
1d7c2e529f
commit
9b436eb4f8
|
@ -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,
|
static inline void read_bars(struct ipath_devdata *dd, struct pci_dev *dev,
|
||||||
u32 *bar0, u32 *bar1)
|
u32 *bar0, u32 *bar1)
|
||||||
{
|
{
|
||||||
|
@ -218,8 +205,6 @@ static struct ipath_devdata *ipath_alloc_devdata(struct pci_dev *pdev)
|
||||||
dd->pcidev = pdev;
|
dd->pcidev = pdev;
|
||||||
pci_set_drvdata(pdev, dd);
|
pci_set_drvdata(pdev, dd);
|
||||||
|
|
||||||
INIT_DELAYED_WORK(&dd->status_work, ipath_check_status);
|
|
||||||
|
|
||||||
list_add(&dd->ipath_list, &ipath_dev_list);
|
list_add(&dd->ipath_list, &ipath_dev_list);
|
||||||
|
|
||||||
bail_unlock:
|
bail_unlock:
|
||||||
|
@ -620,9 +605,6 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
|
||||||
ipath_diag_add(dd);
|
ipath_diag_add(dd);
|
||||||
ipath_register_ib_device(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;
|
goto bail;
|
||||||
|
|
||||||
bail_irqsetup:
|
bail_irqsetup:
|
||||||
|
@ -753,7 +735,6 @@ static void __devexit ipath_remove_one(struct pci_dev *pdev)
|
||||||
*/
|
*/
|
||||||
ipath_shutdown_device(dd);
|
ipath_shutdown_device(dd);
|
||||||
|
|
||||||
cancel_delayed_work(&dd->status_work);
|
|
||||||
flush_scheduled_work();
|
flush_scheduled_work();
|
||||||
|
|
||||||
if (dd->verbs_dev)
|
if (dd->verbs_dev)
|
||||||
|
@ -2195,6 +2176,10 @@ void ipath_shutdown_device(struct ipath_devdata *dd)
|
||||||
del_timer_sync(&dd->ipath_stats_timer);
|
del_timer_sync(&dd->ipath_stats_timer);
|
||||||
dd->ipath_stats_timer_active = 0;
|
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
|
* clear all interrupts and errors, so that the next time the driver
|
||||||
|
|
|
@ -665,6 +665,28 @@ static int init_housekeeping(struct ipath_devdata *dd, int reinit)
|
||||||
return ret;
|
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
|
* ipath_init_chip - do the actual initialization sequence on the chip
|
||||||
* @dd: the infinipath device
|
* @dd: the infinipath device
|
||||||
|
@ -968,6 +990,20 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
|
||||||
0ULL);
|
0ULL);
|
||||||
/* chip is usable; mark it as initialized */
|
/* chip is usable; mark it as initialized */
|
||||||
*dd->ipath_statusp |= IPATH_STATUS_INITTED;
|
*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
|
} else
|
||||||
ipath_dev_err(dd, "No interrupts enabled, couldn't "
|
ipath_dev_err(dd, "No interrupts enabled, couldn't "
|
||||||
"setup interrupt address\n");
|
"setup interrupt address\n");
|
||||||
|
|
|
@ -426,6 +426,8 @@ struct ipath_devdata {
|
||||||
struct class_device *diag_class_dev;
|
struct class_device *diag_class_dev;
|
||||||
/* timer used to prevent stats overflow, error throttling, etc. */
|
/* timer used to prevent stats overflow, error throttling, etc. */
|
||||||
struct timer_list ipath_stats_timer;
|
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 */
|
void *ipath_dummy_hdrq; /* used after port close */
|
||||||
dma_addr_t ipath_dummy_hdrq_phys;
|
dma_addr_t ipath_dummy_hdrq_phys;
|
||||||
|
|
||||||
|
@ -629,9 +631,6 @@ struct ipath_devdata {
|
||||||
u32 ipath_overrun_thresh_errs;
|
u32 ipath_overrun_thresh_errs;
|
||||||
u32 ipath_lli_errs;
|
u32 ipath_lli_errs;
|
||||||
|
|
||||||
/* status check work */
|
|
||||||
struct delayed_work status_work;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Not all devices managed by a driver instance are the same
|
* Not all devices managed by a driver instance are the same
|
||||||
* type, so these fields must be per-device.
|
* type, so these fields must be per-device.
|
||||||
|
|
Loading…
Reference in New Issue