summaryrefslogtreecommitdiffstats
path: root/drivers/xen/xen-pciback
diff options
context:
space:
mode:
authorKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2014-12-03 16:40:32 -0500
committerDavid Vrabel <david.vrabel@citrix.com>2014-12-04 07:42:02 -0500
commitb1df4a56bf4a61113e8928f932d346bed6eef553 (patch)
tree5cf357104c15548775dec5b67c7540ca0976881b /drivers/xen/xen-pciback
parent98d9b271250bd83337e3ed66d63e7deefcda8712 (diff)
xen/pciback: Restore configuration space when detaching from a guest.
The commit "xen/pciback: Don't deadlock when unbinding." was using the version of pci_reset_function which would lock the device lock. That is no good as we can dead-lock. As such we swapped to using the lock-less version and requiring that the callers of 'pcistub_put_pci_dev' take the device lock. And as such this bug got exposed. Using the lock-less version is OK, except that we tried to use 'pci_restore_state' after the lock-less version of __pci_reset_function_locked - which won't work as 'state_saved' is set to false. Said 'state_saved' is a toggle boolean that is to be used by the sequence of a) pci_save_state/pci_restore_state or b) pci_load_and_free_saved_state/pci_restore_state. We don't want to use a) as the guest might have messed up the PCI configuration space and we want it to revert to the state when the PCI device was binded to us. Therefore we pick b) to restore the configuration space. We restore from our 'golden' version of PCI configuration space, when an: - Device is unbinded from pciback - Device is detached from a guest. Reported-by: Sander Eikelenboom <linux@eikelenboom.it> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Signed-off-by: David Vrabel <david.vrabel@citrix.com>
Diffstat (limited to 'drivers/xen/xen-pciback')
-rw-r--r--drivers/xen/xen-pciback/pci_stub.c16
1 files changed, 14 insertions, 2 deletions
diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c
index 843a2baffc2b..8580e53355ec 100644
--- a/drivers/xen/xen-pciback/pci_stub.c
+++ b/drivers/xen/xen-pciback/pci_stub.c
@@ -105,7 +105,7 @@ static void pcistub_device_release(struct kref *kref)
105 */ 105 */
106 __pci_reset_function_locked(dev); 106 __pci_reset_function_locked(dev);
107 if (pci_load_and_free_saved_state(dev, &dev_data->pci_saved_state)) 107 if (pci_load_and_free_saved_state(dev, &dev_data->pci_saved_state))
108 dev_dbg(&dev->dev, "Could not reload PCI state\n"); 108 dev_info(&dev->dev, "Could not reload PCI state\n");
109 else 109 else
110 pci_restore_state(dev); 110 pci_restore_state(dev);
111 111
@@ -257,6 +257,8 @@ void pcistub_put_pci_dev(struct pci_dev *dev)
257{ 257{
258 struct pcistub_device *psdev, *found_psdev = NULL; 258 struct pcistub_device *psdev, *found_psdev = NULL;
259 unsigned long flags; 259 unsigned long flags;
260 struct xen_pcibk_dev_data *dev_data;
261 int ret;
260 262
261 spin_lock_irqsave(&pcistub_devices_lock, flags); 263 spin_lock_irqsave(&pcistub_devices_lock, flags);
262 264
@@ -280,8 +282,18 @@ void pcistub_put_pci_dev(struct pci_dev *dev)
280 */ 282 */
281 device_lock_assert(&dev->dev); 283 device_lock_assert(&dev->dev);
282 __pci_reset_function_locked(dev); 284 __pci_reset_function_locked(dev);
283 pci_restore_state(dev);
284 285
286 dev_data = pci_get_drvdata(dev);
287 ret = pci_load_saved_state(dev, dev_data->pci_saved_state);
288 if (!ret) {
289 /*
290 * The usual sequence is pci_save_state & pci_restore_state
291 * but the guest might have messed the configuration space up.
292 * Use the initial version (when device was bound to us).
293 */
294 pci_restore_state(dev);
295 } else
296 dev_info(&dev->dev, "Could not reload PCI state\n");
285 /* This disables the device. */ 297 /* This disables the device. */
286 xen_pcibk_reset_device(dev); 298 xen_pcibk_reset_device(dev);
287 299