|
|
@@ -3184,6 +3184,32 @@ vmxnet3_remove_device(struct pci_dev *pdev)
|
|
|
free_netdev(netdev);
|
|
|
}
|
|
|
|
|
|
+static void vmxnet3_shutdown_device(struct pci_dev *pdev)
|
|
|
+{
|
|
|
+ struct net_device *netdev = pci_get_drvdata(pdev);
|
|
|
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ /* Reset_work may be in the middle of resetting the device, wait for its
|
|
|
+ * completion.
|
|
|
+ */
|
|
|
+ while (test_and_set_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state))
|
|
|
+ msleep(1);
|
|
|
+
|
|
|
+ if (test_and_set_bit(VMXNET3_STATE_BIT_QUIESCED,
|
|
|
+ &adapter->state)) {
|
|
|
+ clear_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ spin_lock_irqsave(&adapter->cmd_lock, flags);
|
|
|
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
|
|
|
+ VMXNET3_CMD_QUIESCE_DEV);
|
|
|
+ spin_unlock_irqrestore(&adapter->cmd_lock, flags);
|
|
|
+ vmxnet3_disable_all_intrs(adapter);
|
|
|
+
|
|
|
+ clear_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state);
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
#ifdef CONFIG_PM
|
|
|
|
|
|
@@ -3360,6 +3386,7 @@ static struct pci_driver vmxnet3_driver = {
|
|
|
.id_table = vmxnet3_pciid_table,
|
|
|
.probe = vmxnet3_probe_device,
|
|
|
.remove = vmxnet3_remove_device,
|
|
|
+ .shutdown = vmxnet3_shutdown_device,
|
|
|
#ifdef CONFIG_PM
|
|
|
.driver.pm = &vmxnet3_pm_ops,
|
|
|
#endif
|