Skip to content

Commit 88801d0

Browse files
Jiqian Chenjgross1
authored andcommitted
xen/pci: Add a function to reset device for xen
When device on dom0 side has been reset, the vpci on Xen side won't get notification, so that the cached state in vpci is all out of date with the real device state. To solve that problem, add a new function to clear all vpci device state when device is reset on dom0 side. And call that function in pcistub_init_device. Because when using "pci-assignable-add" to assign a passthrough device in Xen, it will reset passthrough device and the vpci state will out of date, and then device will fail to restore bar state. Signed-off-by: Jiqian Chen <[email protected]> Signed-off-by: Huang Rui <[email protected]> Signed-off-by: Jiqian Chen <[email protected]> Reviewed-by: Stefano Stabellini <[email protected]> Message-ID: <[email protected]> Signed-off-by: Juergen Gross <[email protected]>
1 parent c3dea3d commit 88801d0

File tree

4 files changed

+51
-3
lines changed

4 files changed

+51
-3
lines changed

drivers/xen/pci.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,19 @@ static int xen_remove_device(struct device *dev)
173173
return r;
174174
}
175175

176+
int xen_reset_device(const struct pci_dev *dev)
177+
{
178+
struct pci_device_reset device = {
179+
.dev.seg = pci_domain_nr(dev->bus),
180+
.dev.bus = dev->bus->number,
181+
.dev.devfn = dev->devfn,
182+
.flags = PCI_DEVICE_RESET_FLR,
183+
};
184+
185+
return HYPERVISOR_physdev_op(PHYSDEVOP_pci_device_reset, &device);
186+
}
187+
EXPORT_SYMBOL_GPL(xen_reset_device);
188+
176189
static int xen_pci_notifier(struct notifier_block *nb,
177190
unsigned long action, void *data)
178191
{

drivers/xen/xen-pciback/pci_stub.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,16 @@ static struct pcistub_device *pcistub_device_alloc(struct pci_dev *dev)
8989
return psdev;
9090
}
9191

92+
static int pcistub_reset_device_state(struct pci_dev *dev)
93+
{
94+
__pci_reset_function_locked(dev);
95+
96+
if (!xen_pv_domain())
97+
return xen_reset_device(dev);
98+
else
99+
return 0;
100+
}
101+
92102
/* Don't call this directly as it's called by pcistub_device_put */
93103
static void pcistub_device_release(struct kref *kref)
94104
{
@@ -107,7 +117,7 @@ static void pcistub_device_release(struct kref *kref)
107117
/* Call the reset function which does not take lock as this
108118
* is called from "unbind" which takes a device_lock mutex.
109119
*/
110-
__pci_reset_function_locked(dev);
120+
pcistub_reset_device_state(dev);
111121
if (dev_data &&
112122
pci_load_and_free_saved_state(dev, &dev_data->pci_saved_state))
113123
dev_info(&dev->dev, "Could not reload PCI state\n");
@@ -284,7 +294,7 @@ void pcistub_put_pci_dev(struct pci_dev *dev)
284294
* (so it's ready for the next domain)
285295
*/
286296
device_lock_assert(&dev->dev);
287-
__pci_reset_function_locked(dev);
297+
pcistub_reset_device_state(dev);
288298

289299
dev_data = pci_get_drvdata(dev);
290300
ret = pci_load_saved_state(dev, dev_data->pci_saved_state);
@@ -420,7 +430,9 @@ static int pcistub_init_device(struct pci_dev *dev)
420430
dev_err(&dev->dev, "Could not store PCI conf saved state!\n");
421431
else {
422432
dev_dbg(&dev->dev, "resetting (FLR, D3, etc) the device\n");
423-
__pci_reset_function_locked(dev);
433+
err = pcistub_reset_device_state(dev);
434+
if (err)
435+
goto config_release;
424436
pci_restore_state(dev);
425437
}
426438
/* Now disable the device (this also ensures some private device

include/xen/interface/physdev.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,13 +256,30 @@ struct physdev_pci_device_add {
256256
*/
257257
#define PHYSDEVOP_prepare_msix 30
258258
#define PHYSDEVOP_release_msix 31
259+
/*
260+
* Notify the hypervisor that a PCI device has been reset, so that any
261+
* internally cached state is regenerated. Should be called after any
262+
* device reset performed by the hardware domain.
263+
*/
264+
#define PHYSDEVOP_pci_device_reset 32
265+
259266
struct physdev_pci_device {
260267
/* IN */
261268
uint16_t seg;
262269
uint8_t bus;
263270
uint8_t devfn;
264271
};
265272

273+
struct pci_device_reset {
274+
struct physdev_pci_device dev;
275+
#define PCI_DEVICE_RESET_COLD 0x0
276+
#define PCI_DEVICE_RESET_WARM 0x1
277+
#define PCI_DEVICE_RESET_HOT 0x2
278+
#define PCI_DEVICE_RESET_FLR 0x3
279+
#define PCI_DEVICE_RESET_MASK 0x3
280+
uint32_t flags;
281+
};
282+
266283
#define PHYSDEVOP_DBGP_RESET_PREPARE 1
267284
#define PHYSDEVOP_DBGP_RESET_DONE 2
268285

include/xen/pci.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,16 @@
44
#define __XEN_PCI_H__
55

66
#if defined(CONFIG_XEN_DOM0)
7+
int xen_reset_device(const struct pci_dev *dev);
78
int xen_find_device_domain_owner(struct pci_dev *dev);
89
int xen_register_device_domain_owner(struct pci_dev *dev, uint16_t domain);
910
int xen_unregister_device_domain_owner(struct pci_dev *dev);
1011
#else
12+
static inline int xen_reset_device(const struct pci_dev *dev)
13+
{
14+
return -1;
15+
}
16+
1117
static inline int xen_find_device_domain_owner(struct pci_dev *dev)
1218
{
1319
return -1;

0 commit comments

Comments
 (0)