Unregister gasket IRQs on suspend

- Use the existing gasket_interrupt_msix_cleanup at suspend time to
remove our IRQs from the system. Without doing this, we leave 13 IRQs
per device registered, which can cause issues during suspend if many
devices are loaded in the system.
- Restore them at resume time, using the gasket_interrupt_reinit
functionality.
- This allows successful suspend without any errors taking the CPUs
down, and passing the multi-tpu stress test after resume.

Change-Id: Ied1aca8605c0cb3b64ba591d05312d10cf45343f
diff --git a/drivers/staging/gasket/apex_driver.c b/drivers/staging/gasket/apex_driver.c
index 1d7b7ce..f4cf518 100644
--- a/drivers/staging/gasket/apex_driver.c
+++ b/drivers/staging/gasket/apex_driver.c
@@ -1125,6 +1125,21 @@
 	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 @@
 	}
 	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 @@
 	.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/drivers/staging/gasket/gasket_interrupt.c b/drivers/staging/gasket/gasket_interrupt.c
index 1e8b960..dee62e0 100644
--- a/drivers/staging/gasket/gasket_interrupt.c
+++ b/drivers/staging/gasket/gasket_interrupt.c
@@ -395,9 +395,9 @@
 
 	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 @@
 		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 @@
 
 	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/drivers/staging/gasket/gasket_interrupt.h b/drivers/staging/gasket/gasket_interrupt.h
index b17b723..048564a7 100644
--- a/drivers/staging/gasket/gasket_interrupt.h
+++ b/drivers/staging/gasket/gasket_interrupt.h
@@ -45,6 +45,14 @@
  */
 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,