Error recovery for vfio-pci devices on s390x
Subsystems (6)
Farhan Ali
maintainerv7 cover Error recovery for vfio-pci devices on s390x
Hi,
This Linux kernel patch series introduces support for error recovery for passthrough PCI devices on System Z (s390x).
Background
----------
For PCI devices on s390x an operating system receives platform specific error events from firmware rather than through AER.Today for passthrough/userspace devices, we don't attempt any error recovery and ignore any error events for the devices. The passthrough/userspace devices are managed by the vfio-pci driver. The driver does register error handling callbacks (error_detected), and on an error trigger an eventfd to userspace. But we need a mechanism to notify userspace (QEMU/guest/userspace drivers) about the error event.
Proposal
--------
We can expose this error information (currently only the PCI Error Code) via a device feature. Userspace can then obtain the error information via VFIO_DEVICE_FEATURE ioctl and take appropriate actions such as driving a device reset.
This is how a typical flow for passthrough devices to a VM would work:
For passthrough devices to a VM, the driver bound to the device on the host is vfio-pci. vfio-pci driver does support the error_detected() callback (vfio_pci_core_aer_err_detected()), and on an PCI error s390x recovery code on the host will call the vfio-pci error_detected() callback. The vfio-pci error_detected() callback will notify userspace/QEMU via an eventfd, and return PCI_ERS_RESULT_CAN_RECOVER. At this point the s390x error recovery on the host will skip any further action(see patch 6) and let userspace drive the error recovery.
Once userspace/QEMU is notified, it then injects this error into the VM so device drivers in the VM can take recovery actions. For example for a passthrough NVMe device, the VM's OS NVMe driver will access the device. At this point the VM's NVMe driver's error_detected() will drive the recovery by returning PCI_ERS_RESULT_NEED_RESET, and the s390x error recovery in the VM's OS will try to do a reset. Resets are privileged operations and so the VM will need intervention from QEMU to perform the reset. QEMU will invoke the VFIO_DEVICE_RESET ioctl to now notify the host that the VM is requesting a reset of the device. The vfio-pci driver on the host will then perform the reset on the device to recover it.
Thanks
Farhan
ChangeLog
---------
v6 series https://lore.kernel.org/all/[email protected]/
v6 -> v7
- Rebase on 6.19-rc4
- Update commit message based on Niklas's suggestion (patch 3).
v5 series https://lore.kernel.org/all/[email protected]/
v5 -> v6
- Rebase on 6.18 + Lukas's PCI: Universal error recoverability of devices series (https://lore.kernel.org/all/[email protected]/)
- Re-work config space accessibility check to pci_dev_save_and_disable() (patch 3). This avoids saving the config space, in the reset path, if the device's config space is corrupted or inaccessible.
v4 series https://lore.kernel.org/all/[email protected]/
v4 -> v5
- Rebase on 6.18-rc5
- Move bug fixes to the beginning of the series (patch 1 and 2). These patches were posted as a separate fixes series
https://lore.kernel.org/all/[email protected]/
- Add matching pci_put_dev() for pci_get_slot() (patch 6).
v3 series https://lore.kernel.org/all/[email protected]/
v3 -> v4
- Remove warn messages for each PCI capability not restored (patch 1)
- Check PCI_COMMAND and PCI_STATUS register for error value instead of device id (patch 1)
- Fix kernel crash in patch 3
- Added reviewed by tags
- Address comments from Niklas's (patches 4, 5, 7)
- Fix compilation error non s390x system (patch 8)
- Explicitly align struct vfio_device_feature_zpci_err (patch 8)
v2 series https://lore.kernel.org/all/[email protected]/
v2 -> v3
- Patch 1 avoids saving any config space state if the device is in error (suggested by Alex)
- Patch 2 adds additional check only for FLR reset to try other function reset method (suggested by Alex).
- Patch 3 fixes a bug in s390 for resetting PCI devices with multiple functions. Creates a new flag pci_slot to allow per function slot.
- Patch 4 fixes a bug in s390 for resource to bus address translation.
- Rebase on 6.17-rc5
v1 series https://lore.kernel.org/all/[email protected]/
v1 - > v2
- Patches 1 and 2 adds some additional checks for FLR/PM reset to try other function reset method (suggested by Alex).
- Patch 3 fixes a bug in s390 for resetting PCI devices with multiple functions.
- Patch 7 adds a new device feature for zPCI devices for the VFIO_DEVICE_FEATURE ioctl. The ioctl is used by userspace to retriece any PCI error information for the device (suggested by Alex).
- Patch 8 adds a reset_done() callback for the vfio-pci driver, to restore the state of the device after a reset.
- Patch 9 removes the pcie check for triggering VFIO_PCI_ERR_IRQ_INDEX.
Farhan Ali (9):
PCI: Allow per function PCI slots
s390/pci: Add architecture specific resource/bus address translation
PCI: Avoid saving config space state if inaccessible
PCI: Add additional checks for flr reset
s390/pci: Update the logic for detecting passthrough device s390/pci: Store PCI error information for passthrough devices vfio-pci/zdev: Add a device feature for error information
vfio: Add a reset_done callback for vfio-pci driver
vfio: Remove the pcie check for VFIO_PCI_ERR_IRQ_INDEX
arch/s390/include/asm/pci.h | 29 ++++++++ arch/s390/pci/pci.c | 75 +++++++++++++++++++++ arch/s390/pci/pci_event.c | 107 +++++++++++++++++------------- drivers/pci/host-bridge.c | 4 +- drivers/pci/pci.c | 19 +++++- drivers/pci/slot.c | 25 ++++++- drivers/vfio/pci/vfio_pci_core.c | 20 ++++-- drivers/vfio/pci/vfio_pci_intrs.c | 3 +- drivers/vfio/pci/vfio_pci_priv.h | 9 +++ drivers/vfio/pci/vfio_pci_zdev.c | 45 ++++++++++++- include/linux/pci.h | 1 + include/uapi/linux/vfio.h | 16 +++++ 12 files changed, 292 insertions(+), 61 deletions(-)
Signature · 1 line
2.43.0
Farhan Ali
maintainerPATCH v7 1/9 PCI: Allow per function PCI slots
On s390 systems, which use a machine level hypervisor, PCI devices are always accessed through a form of PCI pass-through which fundamentally operates on a per PCI function granularity. This is also reflected in the s390 PCI hotplug driver which creates hotplug slots for individual PCI functions. Its reset_slot() function, which is a wrapper for zpci_hot_reset_device(), thus also resets individual functions.
Currently, the kernel's PCI_SLOT() macro assigns the same pci_slot object to multifunction devices. This approach worked fine on s390 systems that only exposed virtual functions as individual PCI domains to the operating system. Since commit 44510d6fa0c0 ("s390/pci: Handling multifunctions") s390 supports exposing the topology of multifunction PCI devices by grouping them in a shared PCI domain. When attempting to reset a function through the hotplug driver, the shared slot assignment causes the wrong function to be reset instead of the intended one. It also leaks memory as we do create a pci_slot object for the function, but don't correctly free it in pci_slot_release().
Add a flag for struct pci_slot to allow per function PCI slots for functions managed through a hypervisor, which exposes individual PCI functions while retaining the topology.
--- drivers/pci/pci.c | 5 +++-- drivers/pci/slot.c | 25 ++++++++++++++++++++++--- include/linux/pci.h | 1 + 3 files changed, 26 insertions(+), 5 deletions(-)
drivers/pci/pci.c +3 -2
@@ -4832,8 +4832,9 @@ static int pci_reset_hotplug_slot(struct hotplug_slot *hotplug, bool probe)static int pci_dev_reset_slot_function (struct pci_dev *dev,bool probe) { -if (dev->multifunction || dev->subordinate || !dev->slot || - dev->dev_flags &PCI_DEV_FLAGS_NO_BUS_RESET ) +if (dev->subordinate || !dev->slot || + dev->dev_flags &PCI_DEV_FLAGS_NO_BUS_RESET || + (dev->multifunction && !dev->slot->per_func_slot))return -ENOTTY ;return pci_reset_hotplug_slot (dev->slot->hotplug, probe);
drivers/pci/slot.c +22 -3
@@ -63,6 +63,22 @@ static ssize_t cur_speed_read_file(struct pci_slot *slot, char *buf)return bus_speed_read (slot->bus->cur_bus_speed, buf); } +static bool pci_dev_matches_slot (struct pci_dev *dev,struct pci_slot *slot) +{ +if (slot->per_func_slot) +return dev->devfn == slot->number; + +return PCI_SLOT (dev->devfn) == slot->number; +} + +static bool pci_slot_enabled_per_func (void ) +{ +if (IS_ENABLED (CONFIG_S390 )) +return true; + +return false; +} +static void pci_slot_release (struct kobject *kobj) {struct pci_dev *dev;
@@ -73,7 +89,7 @@ static void pci_slot_release(struct kobject *kobj)down_read (&pci_bus_sem);list_for_each_entry (dev, &slot->bus->devices, bus_list) -if (PCI_SLOT (dev->devfn) == slot->number) +if (pci_dev_matches_slot (dev, slot)) dev->slot =NULL ;up_read (&pci_bus_sem);
@@ -166,7 +182,7 @@ void pci_dev_assign_slot(struct pci_dev *dev)mutex_lock (&pci_slot_mutex);list_for_each_entry (slot, &dev->bus->slots, list) -if (PCI_SLOT (dev->devfn) == slot->number) +if (pci_dev_matches_slot (dev, slot)) dev->slot = slot;mutex_unlock (&pci_slot_mutex); }
@@ -265,6 +281,9 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, slot->bus =pci_bus_get (parent); slot->number = slot_nr; +if (pci_slot_enabled_per_func ()) + slot->per_func_slot =1 ; + slot->kobj.kset = pci_slots_kset; slot_name =make_slot_name (name);
@@ -285,7 +304,7 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,down_read (&pci_bus_sem);list_for_each_entry (dev, &parent->devices, bus_list) -if (PCI_SLOT (dev->devfn) == slot_nr) +if (pci_dev_matches_slot (dev, slot)) dev->slot = slot;up_read (&pci_bus_sem);
include/linux/pci.h +1 -0
@@ -78,6 +78,7 @@ struct pci_slot {struct list_head list;/* Node in list of slots */ struct hotplug_slot *hotplug;/* Hotplug info (move here) */ unsigned char number;/* PCI_SLOT(pci_dev->devfn) */ + unsigned int per_func_slot:1; /* Allow per function slot */struct kobject kobj; };
Signature · 1 line
2.43.0
Farhan Ali
maintainerPATCH v7 2/9 s390/pci: Add architecture specific resource/bus address translation
In reply to Farhan AliOn s390 today we overwrite the PCI BAR resource address to either an artificial cookie address or MIO address. However this address is different from the bus address of the BARs programmed by firmware. The artificial cookie address was created to index into an array of function handles (zpci_iomap_start). The MIO (mapped I/O) addresses are provided by firmware but maybe different from the bus addresses. This creates an issue when trying to convert the BAR resource address to bus address using the generic pcibios_resource_to_bus().
Implement an architecture specific pcibios_resource_to_bus() function to correctly translate PCI BAR resource addresses to bus addresses for s390. Similarly add architecture specific pcibios_bus_to_resource function to do the reverse translation.
--- arch/s390/pci/pci.c | 74 +++++++++++++++++++++++++++++++++++++++ drivers/pci/host-bridge.c | 4 +-- 2 files changed, 76 insertions(+), 2 deletions(-)
arch/s390/pci/pci.c +74 -0
@@ -263,6 +263,80 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,return 0 ; } +void pcibios_resource_to_bus (struct pci_bus *bus,struct pci_bus_region *region, +struct resource *res) +{ +struct zpci_bus *zbus = bus->sysdata; +struct zpci_bar_struct *zbar; +struct zpci_dev *zdev; + + region->start = res->start; + region->end = res->end; + +for (int i =0 ; i <ZPCI_FUNCTIONS_PER_BUS ; i++) { +int j =0 ; + + zbar =NULL ; + zdev = zbus->function[i]; +if (!zdev) +continue ; + +for (j =0 ; j <PCI_STD_NUM_BARS ; j++) { +if (zdev->bars[j].res->start == res->start && + zdev->bars[j].res->end == res->end && + res->flags &IORESOURCE_MEM ) { + zbar = &zdev->bars[j]; +break ; + } + } + +if (zbar) { +/* only MMIO is supported */ + region->start = zbar->val &PCI_BASE_ADDRESS_MEM_MASK ; +if (zbar->val &PCI_BASE_ADDRESS_MEM_TYPE_64 ) + region->start |= (u64 )zdev->bars[j +1 ].val <<32 ; + + region->end = region->start + (1UL << zbar->size) -1 ; +return ; + } + } +} + +void pcibios_bus_to_resource (struct pci_bus *bus,struct resource *res, +struct pci_bus_region *region) +{ +struct zpci_bus *zbus = bus->sysdata; +struct zpci_dev *zdev; +resource_size_t start, end; + + res->start = region->start; + res->end = region->end; + +for (int i =0 ; i <ZPCI_FUNCTIONS_PER_BUS ; i++) { + zdev = zbus->function[i]; +if (!zdev || !zdev->has_resources) +continue ; + +for (int j =0 ; j <PCI_STD_NUM_BARS ; j++) { +if (!zdev->bars[j].size) +continue ; + +/* only MMIO is supported */ + start = zdev->bars[j].val &PCI_BASE_ADDRESS_MEM_MASK ; +if (zdev->bars[j].val &PCI_BASE_ADDRESS_MEM_TYPE_64 ) + start |= (u64 )zdev->bars[j +1 ].val <<32 ; + + end = start + (1UL << zdev->bars[j].size) -1 ; + +if (start == region->start && end == region->end) { + res->start = zdev->bars[j].res->start; + res->end = zdev->bars[j].res->end; +return ; + } + } + } +} +void __iomem *ioremap_prot (phys_addr_t phys_addr,size_t size,pgprot_t prot) {
drivers/pci/host-bridge.c +2 -2
@@ -49,7 +49,7 @@ void pci_set_host_bridge_release(struct pci_host_bridge *bridge, }EXPORT_SYMBOL_GPL (pci_set_host_bridge_release); -void pcibios_resource_to_bus (struct pci_bus *bus,struct pci_bus_region *region, +void __weak pcibios_resource_to_bus (struct pci_bus *bus,struct pci_bus_region *region,struct resource *res) {struct pci_host_bridge *bridge =pci_find_host_bridge (bus);
@@ -74,7 +74,7 @@ static bool region_contains(struct pci_bus_region *region1,return region1->start <= region2->start && region1->end >= region2->end; } -void pcibios_bus_to_resource (struct pci_bus *bus,struct resource *res, +void __weak pcibios_bus_to_resource (struct pci_bus *bus,struct resource *res,struct pci_bus_region *region) {struct pci_host_bridge *bridge =pci_find_host_bridge (bus);
Signature · 1 line
2.43.0
Niklas Schnelle
maintainerRe: [PATCH v7 2/9] s390/pci: Add architecture specific resource/bus address translation
Quoted 9 lines · Farhan Ali
On s390 today we overwrite the PCI BAR resource address to either an artificial cookie address or MIO address. However this address is different from the bus address of the BARs programmed by firmware. The artificial cookie address was created to index into an array of function handles (
zpci_iomap_start). The MIO (mapped I/O) addresses are provided by firmware but maybe different from the bus addresses. This creates an issue when trying to convert the BAR resource address to bus address using the genericpcibios_resource_to_bus().
Quoted 8 lines
Implement an architecture specific
pcibios_resource_to_bus()function to correctly translate PCI BAR resource addresses to bus addresses for s390. Similarly add architecture specificpcibios_bus_to_resourcefunction to do the reverse translation.Reviewed-by Niklas Schnelle <[email protected]>Signed-off-by Farhan Ali <[email protected]>---
My R-b stands but I'd like to add that checkpatch.pl with "--strict" notes that your commit description is not properly wrapped at 75 characters. Furthermore it reports the following code alignment issues:
CHECK: Alignment should match open parenthesis
#125: FILE: drivers/pci/host-bridge.c:53:
+void __weak pcibios_resource_to_bus(struct pci_bus *bus, struct pci_bus_region *region,
struct resource *res)
CHECK: Alignment should match open parenthesis
#134: FILE: drivers/pci/host-bridge.c:78:
+void __weak pcibios_bus_to_resource(struct pci_bus *bus, struct resource *res,
struct pci_bus_region *region)
Thanks,
Niklas
Farhan Ali
maintainerPATCH v7 3/9 PCI: Avoid saving config space state if inaccessible
In reply to Farhan AliThe current reset process saves the device's config space state before reset and restores it afterward. However errors may occur unexpectedly and it may then be impossible to save config space because the device may be inaccessible (e.g. DPC) or config space may be corrupted. This results in saving corrupted values that get written back to the device during state restoration.
With a reset we want to recover/restore the device into a functional state. So avoid saving the state of the config space when the device config space is inaccessible.
--- drivers/pci/pci.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/pci/pci.c +7 -0
@@ -4960,6 +4960,7 @@ EXPORT_SYMBOL_GPL(pci_dev_unlock);static void pci_dev_save_and_disable (struct pci_dev *dev) { +u32 val;const struct pci_error_handlers *err_handler = dev->driver ? dev->driver->err_handler :NULL ;
@@ -4980,6 +4981,12 @@ static void pci_dev_save_and_disable(struct pci_dev *dev)*/ pci_set_power_state (dev,PCI_D0 ); +pci_read_config_dword (dev,PCI_COMMAND , &val); +if (PCI_POSSIBLE_ERROR (val)) { +pci_warn (dev,"Device config space inaccessible\n" ); +return ; + } +pci_save_state (dev);/* * Disable the device by clearing the Command register, except for
Signature · 1 line
2.43.0
Niklas Schnelle
maintainerRe: [PATCH v7 3/9] PCI: Avoid saving config space state if inaccessible
Quoted 28 lines · Farhan Ali
The current reset process saves the device's config space state before reset and restores it afterward. However errors may occur unexpectedly and it may then be impossible to save config space because the device may be inaccessible (e.g. DPC) or config space may be corrupted. This results in saving corrupted values that get written back to the device during state restoration.
With a reset we want to recover/restore the device into a functional state. So avoid saving the state of the config space when the device config space is inaccessible.
Signed-off-by Farhan Ali <[email protected]>--- drivers/pci/pci.c | 7 +++++++ 1 file changed, 7 insertions(+)drivers/pci/pci.c +1
-0@@ -4960,6 +4960,7 @@ EXPORT_SYMBOL_GPL(pci_dev_unlock);static void pci_dev_save_and_disable (struct pci_dev *dev) { +u32 val;const struct pci_error_handlers *err_handler = dev->driver ? dev->driver->err_handler :NULL ;
drivers/pci/pci.c static void pci_dev_save_and_disable(struct pci_dev *dev) · line 4984
Quoted 4 lines
drivers/pci/pci.c +1
-0@@ -4980,6 +4981,12 @@ static void pci_dev_save_and_disable(struct pci_dev *dev)*/ pci_set_power_state (dev,PCI_D0 ); +pci_read_config_dword (dev,PCI_COMMAND , &val);
Since the PCI_COMMAND field is only 16 bits I think it warrants a comment that you're reading both PCI_COMMAND and PCI_STATUS and that both together should never be 0xffffffff and why. I think at least PCI_STATUS_PARITY should never be set in a config space we want to restore.
drivers/pci/pci.c static void pci_dev_save_and_disable(struct pci_dev *dev) · line 4992
Quoted 8 lines
drivers/pci/pci.c +5
-0+if (PCI_POSSIBLE_ERROR (val)) { +pci_warn (dev,"Device config space inaccessible\n" ); +return ; + } +pci_save_state (dev);/* * Disable the device by clearing the Command register, except for
Functionally this looks good to me and I agree that with both DPC and s390x PCI error state behavior this makes sense.
Thanks,
Niklas
Farhan Ali
maintainerRe: [PATCH v7 3/9] PCI: Avoid saving config space state if inaccessible
Quoted 32 lines · Niklas Schnelle
Quoted 31 lines · Farhan Ali
The current reset process saves the device's config space state before reset and restores it afterward. However errors may occur unexpectedly and it may then be impossible to save config space because the device may be inaccessible (e.g. DPC) or config space may be corrupted. This results in saving corrupted values that get written back to the device during state restoration.
With a reset we want to recover/restore the device into a functional state. So avoid saving the state of the config space when the device config space is inaccessible.
Signed-off-by Farhan Ali<[email protected]>--- drivers/pci/pci.c | 7 +++++++ 1 file changed, 7 insertions(+)drivers/pci/pci.c +1
-0@@ -4960,6 +4960,7 @@ EXPORT_SYMBOL_GPL(pci_dev_unlock);static void pci_dev_save_and_disable (struct pci_dev *dev) { +u32 val;const struct pci_error_handlers *err_handler = dev->driver ? dev->driver->err_handler :NULL ;@@ -4980,6 +4981,12 @@ static void pci_dev_save_and_disable(struct pci_dev *dev)*/ pci_set_power_state (dev,PCI_D0 );
Quoted 6 lines
drivers/pci/pci.c static void pci_dev_save_and_disable(struct pci_dev *dev) · line 4984
Quoted 1 line
drivers/pci/pci.c +1
-0+pci_read_config_dword (dev,PCI_COMMAND , &val);Since the
PCI_COMMANDfield is only 16 bits I think it warrants a comment that you're reading bothPCI_COMMANDandPCI_STATUSand that both together should never be0xffffffffand why. I think at leastPCI_STATUS_PARITYshould never be set in a config space we want to restore.
Makes sense will add a comment. Note this is the mechanism used to check device config accessibility in pci_dev_wait() (for some context discussed here https://lore.kernel.org/all/[email protected]/).
Thanks
Farhan
Niklas Schnelle
maintainerRe: [PATCH v7 3/9] PCI: Avoid saving config space state if inaccessible
In reply to Farhan AliQuoted 6 lines · Farhan Ali
The current reset process saves the device's config space state before reset and restores it afterward. However errors may occur unexpectedly and it may then be impossible to save config space because the device may be inaccessible (e.g. DPC) or config space may be corrupted. This results in saving corrupted values that get written back to the device during state restoration.
Quoted 6 lines
With a reset we want to recover/restore the device into a functional state. So avoid saving the state of the config space when the device config space is inaccessible.
Signed-off-by Farhan Ali <[email protected]>---
Running checkpatch.pl with "--strict" on the series it pointed out that this commit description has lines over 75 characters.
Thanks,
Niklas
Farhan Ali
maintainerPATCH v7 4/9 PCI: Add additional checks for flr reset
In reply to Farhan AliIf a device is in an error state, then any reads of device registers can return error value. Add addtional checks to validate if a device is in an error state before doing an flr reset.
--- drivers/pci/pci.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/pci/pci.c +7 -0
@@ -4358,12 +4358,19 @@ EXPORT_SYMBOL_GPL(pcie_flr);*/ int pcie_reset_flr (struct pci_dev *dev,bool probe) { +u32 reg; +if (dev->dev_flags &PCI_DEV_FLAGS_NO_FLR_RESET )return -ENOTTY ;if (!(dev->devcap &PCI_EXP_DEVCAP_FLR ))return -ENOTTY ; +if (pcie_capability_read_dword (dev,PCI_EXP_DEVCAP , ®)) { +pci_warn (dev,"Device unable to do an FLR\n" ); +return -ENOTTY ; + } +if (probe)return 0 ;
Signature · 1 line
2.43.0
Re: [PATCH v7 4/9] PCI: Add additional checks for flr reset
Quoted 25 lines · Farhan Ali
If a device is in an error state, then any reads of device registers can return error value. Add addtional checks to validate if a device is in an error state before doing an flr reset.
Reviewed-by Benjamin Block <[email protected]>Signed-off-by Farhan Ali <[email protected]>--- drivers/pci/pci.c | 7 +++++++ 1 file changed, 7 insertions(+)drivers/pci/pci.c +2
-0@@ -4358,12 +4358,19 @@ EXPORT_SYMBOL_GPL(pcie_flr);*/ int pcie_reset_flr (struct pci_dev *dev,bool probe) { +u32 reg; +if (dev->dev_flags &PCI_DEV_FLAGS_NO_FLR_RESET )return -ENOTTY ;if (!(dev->devcap &PCI_EXP_DEVCAP_FLR ))
drivers/pci/pci.c EXPORT_SYMBOL_GPL(pcie_flr); · line 4376
Quoted 10 lines
drivers/pci/pci.c +5
-0return -ENOTTY ; +if (pcie_capability_read_dword (dev,PCI_EXP_DEVCAP , ®)) { +pci_warn (dev,"Device unable to do an FLR\n" ); +return -ENOTTY ; + } +if (probe)return 0 ;
Looks good to me. I'm not 100% convinced the additional pci_warn() is needed since at least aer_root_reset() already prints that the FLR isn't supported but there are other callers which don't and this may help pinpoint the new behavior in case it does affect something unexpectedly. So I think I'd also rather keep it.
Feel free to add my:
Farhan Ali
maintainerPATCH v7 5/9 s390/pci: Update the logic for detecting passthrough device
In reply to Farhan AliWe can now have userspace drivers (vfio-pci based) on s390x. The userspace drivers will not have any KVM fd and so no kzdev associated with them. So we need to update the logic for detecting passthrough devices to not depend on struct kvm_zdev.
--- arch/s390/include/asm/pci.h | 1 + arch/s390/pci/pci_event.c | 14 ++++---------- drivers/vfio/pci/vfio_pci_zdev.c | 9 ++++++++- 3 files changed, 13 insertions(+), 11 deletions(-)
arch/s390/include/asm/pci.h +1 -0
@@ -171,6 +171,7 @@ struct zpci_dev {char res_name[16 ];bool mio_capable; +bool mediated_recovery;struct zpci_bar_struct bars[PCI_STD_NUM_BARS ];u64 start_dma;/* Start of available DMA addresses */
arch/s390/pci/pci_event.c +4 -10
@@ -60,16 +60,10 @@ static inline bool ers_result_indicates_abort(pci_ers_result_t ers_res) } } -static bool is_passed_through (struct pci_dev *pdev) +static bool needs_mediated_recovery (struct pci_dev *pdev) {struct zpci_dev *zdev =to_zpci (pdev); -bool ret; - -mutex_lock (&zdev->kzdev_lock); - ret = !!zdev->kzdev; -mutex_unlock (&zdev->kzdev_lock); - -return ret; +return zdev->mediated_recovery; }static bool is_driver_supported (struct pci_driver *driver)
@@ -194,7 +188,7 @@ static pci_ers_result_t zpci_event_attempt_error_recovery(struct pci_dev *pdev) } pdev->error_state = pci_channel_io_frozen; -if (is_passed_through (pdev)) { +if (needs_mediated_recovery (pdev)) {pr_info ("%s: Cannot be recovered in the host because it is a pass-through device\n" ,pci_name (pdev)); status_str ="failed (pass-through)" ;
@@ -279,7 +273,7 @@ static void zpci_event_io_failure(struct pci_dev *pdev, pci_channel_state_t es)* we will inject the error event and let the guest recover the device * itself. */ -if (is_passed_through (pdev)) +if (needs_mediated_recovery (pdev)) goto out; driver =to_pci_driver (pdev->dev.driver);if (driver && driver->err_handler && driver->err_handler->error_detected)
drivers/vfio/pci/vfio_pci_zdev.c +8 -1
@@ -148,6 +148,8 @@ int vfio_pci_zdev_open_device(struct vfio_pci_core_device *vdev)if (!zdev)return -ENODEV ; + zdev->mediated_recovery = true; +if (!vdev->vdev.kvm)return 0 ;
@@ -161,7 +163,12 @@ void vfio_pci_zdev_close_device(struct vfio_pci_core_device *vdev) {struct zpci_dev *zdev =to_zpci (vdev->pdev); -if (!zdev || !vdev->vdev.kvm) +if (!zdev) +return ; + + zdev->mediated_recovery = false; + +if (!vdev->vdev.kvm)return ;if (zpci_kvm_hook.kvm_unregister)
Signature · 1 line
2.43.0
Farhan Ali
maintainerPATCH v7 6/9 s390/pci: Store PCI error information for passthrough devices
In reply to Farhan AliFor a passthrough device we need co-operation from user space to recover the device. This would require to bubble up any error information to user space. Let's store this error information for passthrough devices, so it can be retrieved later.
--- arch/s390/include/asm/pci.h | 28 ++++++++++ arch/s390/pci/pci.c | 1 + arch/s390/pci/pci_event.c | 95 +++++++++++++++++++------------- drivers/vfio/pci/vfio_pci_zdev.c | 2 + 4 files changed, 88 insertions(+), 38 deletions(-)
arch/s390/include/asm/pci.h +28 -0
@@ -118,6 +118,31 @@ struct zpci_bus {enum pci_bus_speed max_bus_speed; }; +/* Content Code Description for PCI Function Error */ +struct zpci_ccdf_err { +u32 reserved1; +u32 fh;/* function handle */ +u32 fid;/* function id */ +u32 ett :4 ;/* expected table type */ +u32 mvn :12 ;/* MSI vector number */ +u32 dmaas :8 ;/* DMA address space */ +u32 reserved2 :6 ; +u32 q :1 ;/* event qualifier */ +u32 rw :1 ;/* read/write */ +u64 faddr;/* failing address */ +u32 reserved3; +u16 reserved4; +u16 pec;/* PCI event code */ +} __packed; + +#define ZPCI_ERR_PENDING_MAX 4 +struct zpci_ccdf_pending { +u8 count; +u8 head; +u8 tail; +struct zpci_ccdf_err err[ZPCI_ERR_PENDING_MAX ]; +}; +/* Private data per function */ struct zpci_dev {struct zpci_bus *zbus;
@@ -193,6 +218,8 @@ struct zpci_dev {struct iommu_domain *s390_domain;/* attached IOMMU domain */ struct kvm_zdev *kzdev;struct mutex kzdev_lock; +struct zpci_ccdf_pending pending_errs; +struct mutex pending_errs_lock;spinlock_t dom_lock;/* protect s390_domain change */ };
@@ -331,6 +358,7 @@ void zpci_debug_exit_device(struct zpci_dev *);int zpci_report_error (struct pci_dev *,struct zpci_report_error_header *);int zpci_clear_error_state (struct zpci_dev *zdev);int zpci_reset_load_store_blocked (struct zpci_dev *zdev); +void zpci_cleanup_pending_errors (struct zpci_dev *zdev);#ifdef CONFIG_NUMA
arch/s390/pci/pci.c +1 -0
@@ -902,6 +902,7 @@ struct zpci_dev *zpci_create_device(u32 fid, u32 fh, enum zpci_state state)mutex_init (&zdev->state_lock);mutex_init (&zdev->fmb_lock);mutex_init (&zdev->kzdev_lock); +mutex_init (&zdev->pending_errs_lock);return zdev;
arch/s390/pci/pci_event.c +57 -38
155 lines not on this page · raw message
drivers/vfio/pci/vfio_pci_zdev.c +2 -0
@@ -168,6 +168,8 @@ void vfio_pci_zdev_close_device(struct vfio_pci_core_device *vdev) zdev->mediated_recovery = false; +zpci_cleanup_pending_errors (zdev); +if (!vdev->vdev.kvm)return ;
Signature · 1 line
2.43.0
Re: [PATCH v7 6/9] s390/pci: Store PCI error information for passthrough devices
Quoted 5 lines · Farhan Ali
For a passthrough device we need co-operation from user space to recover the device. This would require to bubble up any error information to user space. Let's store this error information for passthrough devices, so it can be retrieved later.
Quoted 9 lines
Signed-off-by Farhan Ali <[email protected]>--- arch/s390/include/asm/pci.h | 28 ++++++++++ arch/s390/pci/pci.c | 1 + arch/s390/pci/pci_event.c | 95 +++++++++++++++++++------------- drivers/vfio/pci/vfio_pci_zdev.c | 2 + 4 files changed, 88 insertions(+), 38 deletions(-)
--- snip ---
arch/s390/pci/pci_event.c static bool is_driver_supported(struct pci_driver *driver) · line 70
Quoted 11 lines
arch/s390/pci/pci_event.c +10
-0+static void zpci_store_pci_error (struct pci_dev *pdev, +struct zpci_ccdf_err *ccdf) +{ +struct zpci_dev *zdev =to_zpci (pdev); +int i; + +mutex_lock (&zdev->pending_errs_lock); +if (zdev->pending_errs.count >=ZPCI_ERR_PENDING_MAX ) { +pr_err ("%s: Maximum number (%d) of pending error events queued" , +pci_name (pdev),ZPCI_ERR_PENDING_MAX );
Nit: Here and in a few other places the alignment doesn't match the open parenthesis. These are caught by checkpatch.pl with "--strict". That also points out a couple of lines over 75 characters in commit messages in this series.
Quoted 10 lines
arch/s390/pci/pci_event.c +10
-0+mutex_unlock (&zdev->pending_errs_lock); +return ; + } + + i = zdev->pending_errs.tail %ZPCI_ERR_PENDING_MAX ; +memcpy (&zdev->pending_errs.err[i], ccdf,sizeof (struct zpci_ccdf_err )); + zdev->pending_errs.tail++; + zdev->pending_errs.count++; +mutex_unlock (&zdev->pending_errs_lock); +}
arch/s390/pci/pci_event.c static bool is_driver_supported(struct pci_driver *driver) · line 90
Quoted 10 lines
arch/s390/pci/pci_event.c +10
-0+ +void zpci_cleanup_pending_errors (struct zpci_dev *zdev) +{ +struct pci_dev *pdev =NULL ; + +mutex_lock (&zdev->pending_errs_lock); + pdev =pci_get_slot (zdev->zbus->bus, zdev->devfn); +if (zdev->pending_errs.count) +pr_info ("%s: Unhandled PCI error events count=%d" , +pci_name (pdev), zdev->pending_errs.count);
Nit: Align with open parenthesis (see above)
arch/s390/pci/pci_event.c static bool is_driver_supported(struct pci_driver *driver) · line 92
Quoted 2 lines
arch/s390/pci/pci_event.c +2
-0+memset (&zdev->pending_errs,0 ,sizeof (struct zpci_ccdf_pending )); +pci_dev_put (pdev);
Yay, the previously missing pci_dev_put()
arch/s390/pci/pci_event.c static bool is_driver_supported(struct pci_driver *driver) · line 96
Quoted 5 lines
arch/s390/pci/pci_event.c +4
-0+mutex_unlock (&zdev->pending_errs_lock); +} +EXPORT_SYMBOL_GPL (zpci_cleanup_pending_errors); +
--- snip ---
Quoted 6 lines
arch/s390/pci/pci_event.c +2
-0@@ -210,12 +223,23 @@ static pci_ers_result_t zpci_event_attempt_error_recovery(struct pci_dev *pdev) goto out_unlock; } +if (needs_mediated_recovery (pdev)) +zpci_store_pci_error (pdev, ccdf);
arch/s390/pci/pci_event.c static pci_ers_result_t zpci_event_attempt_error_recovery(struct pci_dev *pdev) · line 237
Quoted 10 lines
arch/s390/pci/pci_event.c +4
-0+ ers_res =zpci_event_notify_error_detected (pdev, driver);if (ers_result_indicates_abort (ers_res)) { status_str ="failed (abort on detection)" ; goto out_unlock; } +if (needs_mediated_recovery (pdev)) { +pr_info ("%s: Leaving recovery of pass-through device to user-space\n" , +pci_name (pdev));
Nit: Code alignment
arch/s390/pci/pci_event.c static pci_ers_result_t zpci_event_attempt_error_recovery(struct pci_dev *pdev) · line 242
Quoted 5 lines
arch/s390/pci/pci_event.c +5
-0+ ers_res =PCI_ERS_RESULT_RECOVERED ; + status_str ="in progress" ; + goto out_unlock; + } +
With the style issues fixed feel free to add my:
Farhan Ali
maintainerPATCH v7 7/9 vfio-pci/zdev: Add a device feature for error information
In reply to Farhan AliFor zPCI devices, we have platform specific error information. The platform firmware provides this error information to the operating system in an architecture specific mechanism. To enable recovery from userspace for these devices, we want to expose this error information to userspace. Add a new device feature to expose this information.
--- drivers/vfio/pci/vfio_pci_core.c | 2 ++ drivers/vfio/pci/vfio_pci_priv.h | 9 +++++++++ drivers/vfio/pci/vfio_pci_zdev.c | 34 ++++++++++++++++++++++++++++++++ include/uapi/linux/vfio.h | 16 +++++++++++++++ 4 files changed, 61 insertions(+)
drivers/vfio/pci/vfio_pci_core.c +2 -0
@@ -1526,6 +1526,8 @@ int vfio_pci_core_ioctl_feature(struct vfio_device *device, u32 flags,return vfio_pci_core_feature_token (vdev, flags, arg, argsz);case VFIO_DEVICE_FEATURE_DMA_BUF :return vfio_pci_core_feature_dma_buf (vdev, flags, arg, argsz); +case VFIO_DEVICE_FEATURE_ZPCI_ERROR : +return vfio_pci_zdev_feature_err (device, flags, arg, argsz);default :return -ENOTTY ; }
drivers/vfio/pci/vfio_pci_priv.h +9 -0
@@ -89,6 +89,8 @@ int vfio_pci_info_zdev_add_caps(struct vfio_pci_core_device *vdev, struct vfio_info_cap *caps);int vfio_pci_zdev_open_device (struct vfio_pci_core_device *vdev);void vfio_pci_zdev_close_device (struct vfio_pci_core_device *vdev); +int vfio_pci_zdev_feature_err (struct vfio_device *device,u32 flags, +void __user *arg,size_t argsz);#else static inline int vfio_pci_info_zdev_add_caps (struct vfio_pci_core_device *vdev,struct vfio_info_cap *caps)
@@ -103,6 +105,13 @@ static inline int vfio_pci_zdev_open_device(struct vfio_pci_core_device *vdev)static inline void vfio_pci_zdev_close_device (struct vfio_pci_core_device *vdev) {} + +static inline int vfio_pci_zdev_feature_err (struct vfio_device *device, +u32 flags,void __user *arg, +size_t argsz) +{ +return -ENODEV ; +}#endif static inline bool vfio_pci_is_vga (struct pci_dev *pdev)
drivers/vfio/pci/vfio_pci_zdev.c +34 -0
@@ -141,6 +141,40 @@ int vfio_pci_info_zdev_add_caps(struct vfio_pci_core_device *vdev,return ret; } +int vfio_pci_zdev_feature_err (struct vfio_device *device,u32 flags, +void __user *arg,size_t argsz) +{ +struct vfio_device_feature_zpci_err err; +struct vfio_pci_core_device *vdev = + container_of(device, struct vfio_pci_core_device, vdev); +struct zpci_dev *zdev =to_zpci (vdev->pdev); +int ret; +int head =0 ; + +if (!zdev) +return -ENODEV ; + + ret =vfio_check_feature (flags, argsz,VFIO_DEVICE_FEATURE_GET , +sizeof (err)); +if (ret !=1 ) +return ret; + +mutex_lock (&zdev->pending_errs_lock); +if (zdev->pending_errs.count) { + head = zdev->pending_errs.head %ZPCI_ERR_PENDING_MAX ; + err.pec = zdev->pending_errs.err[head].pec; + zdev->pending_errs.head++; + zdev->pending_errs.count--; + err.pending_errors = zdev->pending_errs.count; + } +mutex_unlock (&zdev->pending_errs_lock); + +if (copy_to_user (arg, &err,sizeof (err))) +return -EFAULT ; + +return 0 ; +} +int vfio_pci_zdev_open_device (struct vfio_pci_core_device *vdev) {struct zpci_dev *zdev =to_zpci (vdev->pdev);
include/uapi/linux/vfio.h +16 -0
@@ -1506,6 +1506,22 @@ struct vfio_device_feature_dma_buf { struct vfio_region_dma_range dma_ranges[] __counted_by(nr_ranges); }; +/** +* VFIO_DEVICE_FEATURE_ZPCI_ERROR feature provides PCI error information to +* userspace for vfio-pci devices on s390x. On s390x PCI error recovery involves +* platform firmware and notification to operating system is done by +* architecture specific mechanism. Exposing this information to userspace +* allows userspace to take appropriate actions to handle an error on the +* device. +*/ + +struct vfio_device_feature_zpci_err { +__u16 pec; +__u8 pending_errors; +__u8 pad; +}; +#define VFIO_DEVICE_FEATURE_ZPCI_ERROR 12 +/* -------- API for Type1 VFIO IOMMU -------- */ /**
Signature · 1 line
2.43.0
Re: [PATCH v7 7/9] vfio-pci/zdev: Add a device feature for error information
Quoted 19 lines · Farhan Ali
For zPCI devices, we have platform specific error information. The platform firmware provides this error information to the operating system in an architecture specific mechanism. To enable recovery from userspace for these devices, we want to expose this error information to userspace. Add a new device feature to expose this information.
Signed-off-by Farhan Ali <[email protected]>--- drivers/vfio/pci/vfio_pci_core.c | 2 ++ drivers/vfio/pci/vfio_pci_priv.h | 9 +++++++++ drivers/vfio/pci/vfio_pci_zdev.c | 34 ++++++++++++++++++++++++++++++++ include/uapi/linux/vfio.h | 16 +++++++++++++++ 4 files changed, 61 insertions(+)drivers/vfio/pci/vfio_pci_core.c +0
-0
drivers/vfio/pci/vfio_pci_core.c int vfio_pci_core_ioctl_feature(struct vfio_device *device, u32 flags, · line 1530
Quoted 5 lines
drivers/vfio/pci/vfio_pci_core.c +2
-0@@ -1526,6 +1526,8 @@ int vfio_pci_core_ioctl_feature(struct vfio_device *device, u32 flags,return vfio_pci_core_feature_token (vdev, flags, arg, argsz);case VFIO_DEVICE_FEATURE_DMA_BUF :return vfio_pci_core_feature_dma_buf (vdev, flags, arg, argsz); +case VFIO_DEVICE_FEATURE_ZPCI_ERROR : +return vfio_pci_zdev_feature_err (device, flags, arg, argsz);
Would it make sense to name this more generically, e.g. VFIO_DEVICE_FEATURE_ERROR_RECOVERY, in case other architectures also want to support something like this in the future?
-- snip --
Quoted 9 lines
drivers/vfio/pci/vfio_pci_core.c +0
-0static inline bool vfio_pci_is_vga (struct pci_dev *pdev)drivers/vfio/pci/vfio_pci_zdev.c +0
-0@@ -141,6 +141,40 @@ int vfio_pci_info_zdev_add_caps(struct vfio_pci_core_device *vdev,return ret; }
drivers/vfio/pci/vfio_pci_zdev.c int vfio_pci_info_zdev_add_caps(struct vfio_pci_core_device *vdev, · line 152
Quoted 10 lines
drivers/vfio/pci/vfio_pci_zdev.c +9
-0+int vfio_pci_zdev_feature_err (struct vfio_device *device,u32 flags, +void __user *arg,size_t argsz) +{ +struct vfio_device_feature_zpci_err err; +struct vfio_pci_core_device *vdev = + container_of(device, struct vfio_pci_core_device, vdev); +struct zpci_dev *zdev =to_zpci (vdev->pdev); +int ret; +int head =0 ;
Maybe we should use reverse x-mas notation:
struct vfio_device_feature_zpci_err err; struct vfio_pci_core_device *vdev; struct zpci_dev *zdev; int head = 0; int ret; vdev = container_of(device, struct vfio_pci_core_device, vdev); zdev = to_zpci(vdev->pdev);
-- snip --
Farhan Ali
maintainerRe: [PATCH v7 7/9] vfio-pci/zdev: Add a device feature for error information
Quoted 14 lines · Julian Ruess
Quoted 14 lines
For zPCI devices, we have platform specific error information. The platform firmware provides this error information to the operating system in an architecture specific mechanism. To enable recovery from userspace for these devices, we want to expose this error information to userspace. Add a new device feature to expose this information.
Signed-off-by Farhan Ali<[email protected]>--- drivers/vfio/pci/vfio_pci_core.c | 2 ++ drivers/vfio/pci/vfio_pci_priv.h | 9 +++++++++ drivers/vfio/pci/vfio_pci_zdev.c | 34 ++++++++++++++++++++++++++++++++ include/uapi/linux/vfio.h | 16 +++++++++++++++ 4 files changed, 61 insertions(+)
Quoted 13 lines
drivers/vfio/pci/vfio_pci_core.c int vfio_pci_core_ioctl_feature(struct vfio_device *device, u32 flags, · line 1530
Quoted 10 lines
drivers/vfio/pci/vfio_pci_core.c +2
-0@@ -1526,6 +1526,8 @@ int vfio_pci_core_ioctl_feature(struct vfio_device *device, u32 flags,return vfio_pci_core_feature_token (vdev, flags, arg, argsz);case VFIO_DEVICE_FEATURE_DMA_BUF :return vfio_pci_core_feature_dma_buf (vdev, flags, arg, argsz); +case VFIO_DEVICE_FEATURE_ZPCI_ERROR : +return vfio_pci_zdev_feature_err (device, flags, arg, argsz);Would it make sense to name this more generically, e.g.
VFIO_DEVICE_FEATURE_ERROR_RECOVERY, in case other architectures also want to support something like this in the future?
The error recovery mechanism here and also the uapi structure exposed via this device feature is very specific to zPCI devices. Making this a generic device feature would mean having different uapi structure for zPCI devices vs PCI devices on other architectures. I am not sure that would be desirable and might be cleaner to have separate device feature and separate uapi constructs for zPCI vs other architectures.
Thanks
Farhan
Farhan Ali
maintainerPATCH v7 8/9 vfio: Add a reset_done callback for vfio-pci driver
In reply to Farhan AliOn error recovery for a PCI device bound to vfio-pci driver, we want to recover the state of the device to its last known saved state. The callback restores the state of the device to its initial saved state.
--- drivers/vfio/pci/vfio_pci_core.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
drivers/vfio/pci/vfio_pci_core.c +12 -0
@@ -2249,6 +2249,17 @@ pci_ers_result_t vfio_pci_core_aer_err_detected(struct pci_dev *pdev, }EXPORT_SYMBOL_GPL (vfio_pci_core_aer_err_detected); +static void vfio_pci_core_aer_reset_done (struct pci_dev *pdev) +{ +struct vfio_pci_core_device *vdev =dev_get_drvdata (&pdev->dev); + +if (!vdev->pci_saved_state) +return ; + +pci_load_saved_state (pdev, vdev->pci_saved_state); +pci_restore_state (pdev); +} +int vfio_pci_core_sriov_configure (struct vfio_pci_core_device *vdev,int nr_virtfn) {
@@ -2313,6 +2324,7 @@ EXPORT_SYMBOL_GPL(vfio_pci_core_sriov_configure);const struct pci_error_handlers vfio_pci_core_err_handlers = { .error_detected = vfio_pci_core_aer_err_detected, + .reset_done = vfio_pci_core_aer_reset_done, };EXPORT_SYMBOL_GPL (vfio_pci_core_err_handlers);
Signature · 1 line
2.43.0
Re: [PATCH v7 8/9] vfio: Add a reset_done callback for vfio-pci driver
Quoted 32 lines · Farhan Ali
On error recovery for a PCI device bound to vfio-pci driver, we want to recover the state of the device to its last known saved state. The callback restores the state of the device to its initial saved state.
Signed-off-by Farhan Ali <[email protected]>--- drivers/vfio/pci/vfio_pci_core.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)drivers/vfio/pci/vfio_pci_core.c +11
-0@@ -2249,6 +2249,17 @@ pci_ers_result_t vfio_pci_core_aer_err_detected(struct pci_dev *pdev, }EXPORT_SYMBOL_GPL (vfio_pci_core_aer_err_detected); +static void vfio_pci_core_aer_reset_done (struct pci_dev *pdev) +{ +struct vfio_pci_core_device *vdev =dev_get_drvdata (&pdev->dev); + +if (!vdev->pci_saved_state) +return ; + +pci_load_saved_state (pdev, vdev->pci_saved_state); +pci_restore_state (pdev); +} +int vfio_pci_core_sriov_configure (struct vfio_pci_core_device *vdev,int nr_virtfn) {
drivers/vfio/pci/vfio_pci_core.c EXPORT_SYMBOL_GPL(vfio_pci_core_sriov_configure); · line 2330
Quoted 7 lines
drivers/vfio/pci/vfio_pci_core.c +1
-0@@ -2313,6 +2324,7 @@ EXPORT_SYMBOL_GPL(vfio_pci_core_sriov_configure);const struct pci_error_handlers vfio_pci_core_err_handlers = { .error_detected = vfio_pci_core_aer_err_detected, + .reset_done = vfio_pci_core_aer_reset_done, };EXPORT_SYMBOL_GPL (vfio_pci_core_err_handlers);
Feel free to add my
Thanks,
Julian
Farhan Ali
maintainerPATCH v7 9/9 vfio: Remove the pcie check for VFIO_PCI_ERR_IRQ_INDEX
In reply to Farhan AliWe are configuring the error signaling on the vast majority of devices and it's extremely rare that it fires anyway. This allows userspace to be notified on errors for legacy PCI devices. The Internal Shared Memory (ISM) device on s390x is one such device. For PCI devices on IBM s390x error recovery involves platform firmware and notification to operating system is done by architecture specific way. So the ISM device can still be recovered when notified of an error.
--- drivers/vfio/pci/vfio_pci_core.c | 6 ++---- drivers/vfio/pci/vfio_pci_intrs.c | 3 +-- 2 files changed, 3 insertions(+), 6 deletions(-)
drivers/vfio/pci/vfio_pci_core.c +2 -4
@@ -778,8 +778,7 @@ static int vfio_pci_get_irq_count(struct vfio_pci_core_device *vdev, int irq_typreturn (flags &PCI_MSIX_FLAGS_QSIZE ) +1 ; } }else if (irq_type ==VFIO_PCI_ERR_IRQ_INDEX ) { -if (pci_is_pcie (vdev->pdev)) -return 1 ; +return 1 ; }else if (irq_type ==VFIO_PCI_REQ_IRQ_INDEX ) {return 1 ; }
@@ -1157,8 +1156,7 @@ static int vfio_pci_ioctl_get_irq_info(struct vfio_pci_core_device *vdev,case VFIO_PCI_REQ_IRQ_INDEX :break ;case VFIO_PCI_ERR_IRQ_INDEX : -if (pci_is_pcie (vdev->pdev)) -break ; +break ; fallthrough;default :return -EINVAL ;
drivers/vfio/pci/vfio_pci_intrs.c +1 -2
@@ -859,8 +859,7 @@ int vfio_pci_set_irqs_ioctl(struct vfio_pci_core_device *vdev, uint32_t flags,case VFIO_PCI_ERR_IRQ_INDEX :switch (flags &VFIO_IRQ_SET_ACTION_TYPE_MASK ) {case VFIO_IRQ_SET_ACTION_TRIGGER : -if (pci_is_pcie (vdev->pdev)) - func = vfio_pci_set_err_trigger; + func = vfio_pci_set_err_trigger;break ; }break ;
Signature · 1 line
2.43.0
Re: [PATCH v7 9/9] vfio: Remove the pcie check for VFIO_PCI_ERR_IRQ_INDEX
Quoted 29 lines · Farhan Ali
We are configuring the error signaling on the vast majority of devices and it's extremely rare that it fires anyway. This allows userspace to be notified on errors for legacy PCI devices. The Internal Shared Memory (ISM) device on s390x is one such device. For PCI devices on IBM s390x error recovery involves platform firmware and notification to operating system is done by architecture specific way. So the ISM device can still be recovered when notified of an error.
Signed-off-by Farhan Ali <[email protected]>--- drivers/vfio/pci/vfio_pci_core.c | 6 ++---- drivers/vfio/pci/vfio_pci_intrs.c | 3 +-- 2 files changed, 3 insertions(+), 6 deletions(-)drivers/vfio/pci/vfio_pci_core.c +1
-2@@ -778,8 +778,7 @@ static int vfio_pci_get_irq_count(struct vfio_pci_core_device *vdev, int irq_typreturn (flags &PCI_MSIX_FLAGS_QSIZE ) +1 ; } }else if (irq_type ==VFIO_PCI_ERR_IRQ_INDEX ) { -if (pci_is_pcie (vdev->pdev)) -return 1 ; +return 1 ; }else if (irq_type ==VFIO_PCI_REQ_IRQ_INDEX ) {return 1 ; }
drivers/vfio/pci/vfio_pci_core.c static int vfio_pci_ioctl_get_irq_info(struct vfio_pci_core_device *vdev, · line 1160
Quoted 7 lines
drivers/vfio/pci/vfio_pci_core.c +1
-2@@ -1157,8 +1156,7 @@ static int vfio_pci_ioctl_get_irq_info(struct vfio_pci_core_device *vdev,case VFIO_PCI_REQ_IRQ_INDEX :break ;case VFIO_PCI_ERR_IRQ_INDEX : -if (pci_is_pcie (vdev->pdev)) -break ; +break ; fallthrough;
Isn't the fallthrough unreachable now?
-- snip --
Farhan Ali
maintainerRe: [PATCH v7 9/9] vfio: Remove the pcie check for VFIO_PCI_ERR_IRQ_INDEX
Quoted 39 lines · Julian Ruess
Quoted 29 lines · Farhan Ali
We are configuring the error signaling on the vast majority of devices and it's extremely rare that it fires anyway. This allows userspace to be notified on errors for legacy PCI devices. The Internal Shared Memory (ISM) device on s390x is one such device. For PCI devices on IBM s390x error recovery involves platform firmware and notification to operating system is done by architecture specific way. So the ISM device can still be recovered when notified of an error.
Signed-off-by Farhan Ali <[email protected]>--- drivers/vfio/pci/vfio_pci_core.c | 6 ++---- drivers/vfio/pci/vfio_pci_intrs.c | 3 +-- 2 files changed, 3 insertions(+), 6 deletions(-)drivers/vfio/pci/vfio_pci_core.c +1
-2@@ -778,8 +778,7 @@ static int vfio_pci_get_irq_count(struct vfio_pci_core_device *vdev, int irq_typreturn (flags &PCI_MSIX_FLAGS_QSIZE ) +1 ; } }else if (irq_type ==VFIO_PCI_ERR_IRQ_INDEX ) { -if (pci_is_pcie (vdev->pdev)) -return 1 ; +return 1 ; }else if (irq_type ==VFIO_PCI_REQ_IRQ_INDEX ) {return 1 ; }drivers/vfio/pci/vfio_pci_core.c static int vfio_pci_ioctl_get_irq_info(struct vfio_pci_core_device *vdev, · line 1160
Quoted 7 lines
drivers/vfio/pci/vfio_pci_core.c +1
-2@@ -1157,8 +1156,7 @@ static int vfio_pci_ioctl_get_irq_info(struct vfio_pci_core_device *vdev,case VFIO_PCI_REQ_IRQ_INDEX :break ;case VFIO_PCI_ERR_IRQ_INDEX : -if (pci_is_pcie (vdev->pdev)) -break ; +break ; fallthrough;Isn't the fallthrough unreachable now?
Quoted 1 line
-- snip --
Yes indeed, I forget why I still had the fallthrough statement. But I don't think that's needed anymore, since we will have explicit break statements for all the valid cases.
Thanks
Farhan
Farhan Ali
maintainerPolite ping :)... would appreciate some feedback on this patch series.
Thanks
Farhan
Quoted 152 lines · Farhan Ali
Hi,
This Linux kernel patch series introduces support for error recovery for passthrough PCI devices on System Z (s390x).
Background
----------
For PCI devices on s390x an operating system receives platform specific error events from firmware rather than through AER.Today for passthrough/userspace devices, we don't attempt any error recovery and ignore any error events for the devices. The passthrough/userspace devices are managed by the vfio-pci driver. The driver does register error handling callbacks (error_detected), and on an error trigger an eventfd to userspace. But we need a mechanism to notify userspace (QEMU/guest/userspace drivers) about the error event.Proposal
--------
We can expose this error information (currently only the PCI Error Code) via a device feature. Userspace can then obtain the error information viaVFIO_DEVICE_FEATUREioctl and take appropriate actions such as driving a device reset.This is how a typical flow for passthrough devices to a VM would work:
For passthrough devices to a VM, the driver bound to the device on the host is vfio-pci. vfio-pci driver does support theerror_detected()callback (vfio_pci_core_aer_err_detected()), and on an PCI error s390x recovery code on the host will call the vfio-pcierror_detected()callback. The vfio-pcierror_detected()callback will notify userspace/QEMU via an eventfd, and returnPCI_ERS_RESULT_CAN_RECOVER. At this point the s390x error recovery on the host will skip any further action(see patch 6) and let userspace drive the error recovery.Once userspace/QEMU is notified, it then injects this error into the VM so device drivers in the VM can take recovery actions. For example for a passthrough NVMe device, the VM's OS NVMe driver will access the device. At this point the VM's NVMe driver's
error_detected()will drive the recovery by returningPCI_ERS_RESULT_NEED_RESET, and the s390x error recovery in the VM's OS will try to do a reset. Resets are privileged operations and so the VM will need intervention from QEMU to perform the reset. QEMU will invoke theVFIO_DEVICE_RESETioctl to now notify the host that the VM is requesting a reset of the device. The vfio-pci driver on the host will then perform the reset on the device to recover it.Thanks
FarhanChangeLog
---------
v6 series https://lore.kernel.org/all/[email protected]/
v6 -> v7
- Rebase on 6.19-rc4- Update commit message based on Niklas's suggestion (patch 3).
v5 series https://lore.kernel.org/all/[email protected]/
v5 -> v6
- Rebase on 6.18 + Lukas's PCI: Universal error recoverability of devices series (https://lore.kernel.org/all/[email protected]/)- Re-work config space accessibility check to
pci_dev_save_and_disable()(patch 3). This avoids saving the config space, in the reset path, if the device's config space is corrupted or inaccessible.v4 series https://lore.kernel.org/all/[email protected]/
v4 -> v5
- Rebase on 6.18-rc5- Move bug fixes to the beginning of the series (patch 1 and 2). These patches were posted as a separate fixes series
https://lore.kernel.org/all/[email protected]/- Add matching
pci_put_dev()forpci_get_slot()(patch 6).v3 series https://lore.kernel.org/all/[email protected]/
v3 -> v4
- Remove warn messages for each PCI capability not restored (patch 1)- Check
PCI_COMMANDandPCI_STATUSregister for error value instead of device id (patch 1)- Fix kernel crash in patch 3
- Added reviewed by tags
- Address comments from Niklas's (patches 4, 5, 7)
- Fix compilation error non s390x system (patch 8)
- Explicitly align struct
vfio_device_feature_zpci_err(patch 8)v2 series https://lore.kernel.org/all/[email protected]/
v2 -> v3
- Patch 1 avoids saving any config space state if the device is in error (suggested by Alex)- Patch 2 adds additional check only for FLR reset to try other function reset method (suggested by Alex).
- Patch 3 fixes a bug in s390 for resetting PCI devices with multiple functions. Creates a new flag
pci_slotto allow per function slot.- Patch 4 fixes a bug in s390 for resource to bus address translation.
- Rebase on 6.17-rc5
v1 series https://lore.kernel.org/all/[email protected]/
v1 - > v2
- Patches 1 and 2 adds some additional checks for FLR/PM reset to try other function reset method (suggested by Alex).- Patch 3 fixes a bug in s390 for resetting PCI devices with multiple functions.
- Patch 7 adds a new device feature for zPCI devices for the
VFIO_DEVICE_FEATUREioctl. The ioctl is used by userspace to retriece any PCI error information for the device (suggested by Alex).- Patch 8 adds a
reset_done()callback for the vfio-pci driver, to restore the state of the device after a reset.- Patch 9 removes the pcie check for triggering
VFIO_PCI_ERR_IRQ_INDEX.Farhan Ali (9):
PCI: Allow per function PCI slots
s390/pci: Add architecture specific resource/bus address translation
PCI: Avoid saving config space state if inaccessible
PCI: Add additional checks for flr reset
s390/pci: Update the logic for detecting passthrough device s390/pci: Store PCI error information for passthrough devices vfio-pci/zdev: Add a device feature for error information
vfio: Add areset_donecallback for vfio-pci driver
vfio: Remove the pcie check forVFIO_PCI_ERR_IRQ_INDEXarch/s390/include/asm/pci.h | 29 ++++++++ arch/s390/pci/pci.c | 75 +++++++++++++++++++++ arch/s390/pci/pci_event.c | 107 +++++++++++++++++------------- drivers/pci/host-bridge.c | 4 +- drivers/pci/pci.c | 19 +++++- drivers/pci/slot.c | 25 ++++++- drivers/vfio/pci/vfio_pci_core.c | 20 ++++-- drivers/vfio/pci/vfio_pci_intrs.c | 3 +- drivers/vfio/pci/vfio_pci_priv.h | 9 +++ drivers/vfio/pci/vfio_pci_zdev.c | 45 ++++++++++++- include/linux/pci.h | 1 + include/uapi/linux/vfio.h | 16 +++++ 12 files changed, 292 insertions(+), 61 deletions(-)