diff --git a/apex_driver.c b/apex_driver.c index 1d7b7ce..f4cf518 100644 --- a/apex_driver.c +++ b/apex_driver.c @@ -1125,6 +1125,21 @@ remove_device: pci_disable_device(pci_dev); } +static int apex_pci_suspend(struct pci_dev *pci_dev, pm_message_t state) { + struct apex_dev *apex_dev = pci_get_drvdata(pci_dev); + struct gasket_dev *gasket_dev; + + if (!apex_dev) { + dev_err_once(&pci_dev->dev, "NULL apex_dev\n"); + return -ENODEV; + } + + // Tear down MSI-x interrupts before suspending. + gasket_dev = apex_dev->gasket_dev_ptr; + gasket_interrupt_msix_cleanup(gasket_dev->interrupt_data); + return 0; +} + static int apex_pci_resume(struct pci_dev *pci_dev) { struct apex_dev *apex_dev = pci_get_drvdata(pci_dev); @@ -1136,6 +1151,7 @@ static int apex_pci_resume(struct pci_dev *pci_dev) } gasket_dev = apex_dev->gasket_dev_ptr; + gasket_interrupt_reinit(gasket_dev); apex_reset(gasket_dev); program_hw_temp_warnings(apex_dev); enable_thermal_sensing(gasket_dev); @@ -1194,6 +1210,7 @@ static struct pci_driver apex_pci_driver = { .probe = apex_pci_probe, .remove = apex_pci_remove, #ifdef CONFIG_PM_SLEEP + .suspend = apex_pci_suspend, .resume = apex_pci_resume, #endif .id_table = apex_pci_ids, diff --git a/gasket_interrupt.c b/gasket_interrupt.c index 1e8b960..dee62e0 100644 --- a/gasket_interrupt.c +++ b/gasket_interrupt.c @@ -395,9 +395,9 @@ int gasket_interrupt_init(struct gasket_dev *gasket_dev) return 0; } +EXPORT_SYMBOL(gasket_interrupt_init); -static void -gasket_interrupt_msix_cleanup(struct gasket_interrupt_data *interrupt_data) +void gasket_interrupt_msix_cleanup(struct gasket_interrupt_data *interrupt_data) { int i; @@ -412,7 +412,9 @@ gasket_interrupt_msix_cleanup(struct gasket_interrupt_data *interrupt_data) pci_disable_msix(interrupt_data->pci_dev); interrupt_data->msix_configured = 0; kfree(interrupt_data->msix_entries); + interrupt_data->msix_entries = NULL; } +EXPORT_SYMBOL(gasket_interrupt_msix_cleanup); int gasket_interrupt_reinit(struct gasket_dev *gasket_dev) { @@ -454,6 +456,7 @@ int gasket_interrupt_reinit(struct gasket_dev *gasket_dev) return 0; } +EXPORT_SYMBOL(gasket_interrupt_reinit); /* See gasket_interrupt.h for description. */ int gasket_interrupt_reset_counts(struct gasket_dev *gasket_dev) diff --git a/gasket_interrupt.h b/gasket_interrupt.h index b17b723..048564a 100644 --- a/gasket_interrupt.h +++ b/gasket_interrupt.h @@ -45,6 +45,14 @@ void gasket_interrupt_cleanup(struct gasket_dev *gasket_dev); */ int gasket_interrupt_reinit(struct gasket_dev *gasket_dev); +/* + * Clean up the MSI-x subsystem. + * @interrupt_data: The interrupt data structure for this device. + * + * Performs a teardown of the MSI-x subsystem. Does not free the underlying data structures. + */ +void gasket_interrupt_msix_cleanup(struct gasket_interrupt_data *interrupt_data); + /* Handle gasket interrupt processing, called from an external handler. */ void gasket_handle_interrupt(struct gasket_interrupt_data *interrupt_data,