pci: add function reset call that can be used inside of probe
Subsystems (3)
RFC PATCH 1/2 pci: add function reset call that can be used inside of probe
From: Alexander Duyck <[email protected]>
This change makes it so that there are several new calls available.
The first is __pci_reset_dev which works similar to pci_reset_dev, however it does not obtain the device lock. This is important as I found several cases such as __pci_reset_function in which the call was obtaining the device lock even though the lock had yet to be initialized. In addition if one wishes to do such a reset during probe it will hang since the device lock is already being held.
The second change that was added was a function named pci_reset_device_function. This function is similar to pci_reset_function however it does not hold the device lock and so it as well can be called during the driver probe routine.
---
drivers/pci/pci.c | 74 +++++++++++++++++++++++++++++++++++++++++++-------- include/linux/pci.h | 1 + 2 files changed, 64 insertions(+), 11 deletions(-)
drivers/pci/pci.c +63 -11
@@ -2445,17 +2445,14 @@ static int pci_parent_bus_reset(struct pci_dev *dev, int probe)return 0 ; } -static int pci_dev_reset (struct pci_dev *dev,int probe) +static int __pci_dev_reset (struct pci_dev *dev,int probe) {int rc;might_sleep (); -if (!probe) { +if (!probe)pci_block_user_cfg_access (dev); -/* block PM suspend, driver probe, etc. */ -device_lock (&dev->dev); - } rc =pci_dev_specific_reset (dev, probe);if (rc != -ENOTTY )
@@ -2474,11 +2471,26 @@ static int pci_dev_reset(struct pci_dev *dev, int probe) goto done; rc =pci_parent_bus_reset (dev, probe); + done: -if (!probe) { -device_unlock (&dev->dev); +if (!probe)pci_unblock_user_cfg_access (dev); - } + +return rc; +} + +static int pci_dev_reset (struct pci_dev *dev,int probe) +{ +int rc; + +/* block PM suspend, driver probe, etc. */ +if (!probe) +device_lock (&dev->dev); + + rc =__pci_dev_reset (dev, probe); + +if (!probe) +device_unlock (&dev->dev);return rc; }
@@ -2502,7 +2514,7 @@ done:*/ int __pci_reset_function (struct pci_dev *dev) { -return pci_dev_reset (dev,0 ); +return __pci_dev_reset (dev,0 ); }EXPORT_SYMBOL_GPL (__pci_reset_function);
@@ -2519,7 +2531,7 @@ EXPORT_SYMBOL_GPL(__pci_reset_function);*/ int pci_probe_reset_function (struct pci_dev *dev) { -return pci_dev_reset (dev,1 ); +return __pci_dev_reset (dev,1 ); }/**
@@ -2542,7 +2554,7 @@ int pci_reset_function(struct pci_dev *dev) {int rc; - rc =pci_dev_reset (dev,1 ); + rc =__pci_dev_reset (dev,1 );if (rc)return rc;
@@ -2563,6 +2575,46 @@ int pci_reset_function(struct pci_dev *dev)EXPORT_SYMBOL_GPL (pci_reset_function);/** +* pci_reset_device_function - quiesce and reinitialize a PCI device function +* @dev: PCI device to reset +* +* Some devices allow an individual function to be reset without affecting +* other functions in the same device. The PCI device must be responsive +* to PCI config space in order to use this function. +* +* This function is very similar to pci_reset_function, however this function +* does not obtain the device lock during the reset. This is due to the fact +* that the call is meant to be used during probe if the reset_devices +* kernel parameter is set. +* +* Returns 0 if the device function was successfully reset or negative if the +* device doesn't support resetting a single function. +*/ +int pci_reset_device_function (struct pci_dev *dev) +{ +int rc; + + rc =__pci_dev_reset (dev,1 ); +if (rc) +return rc; + +pci_save_state (dev); + +/* +* both INTx and MSI are disabled after the Interrupt Disable bit +* is set and the Bus Master bit is cleared. +*/ +pci_write_config_word (dev,PCI_COMMAND ,PCI_COMMAND_INTX_DISABLE ); + + rc =__pci_dev_reset (dev,0 ); + +pci_restore_state (dev); + +return rc; +} +EXPORT_SYMBOL_GPL (pci_reset_device_function); + +/** * pcix_get_max_mmrbc - get PCI-X maximum designed memory read byte count * @dev: PCI device to query *
include/linux/pci.h +1 -0
@@ -789,6 +789,7 @@ int pcie_get_readrq(struct pci_dev *dev);int pcie_set_readrq (struct pci_dev *dev,int rq);int __pci_reset_function (struct pci_dev *dev);int pci_reset_function (struct pci_dev *dev); +int pci_reset_device_function (struct pci_dev *dev);void pci_update_resource (struct pci_dev *dev,int resno);int __must_check pci_assign_resource (struct pci_dev *dev,int i);int pci_select_bars (struct pci_dev *dev,unsigned long flags);
RFC PATCH 2/2 igb/ixgbe: add code to trigger function reset if reset_devices is set
From: Alexander Duyck <[email protected]>
This change makes it so that both igb and ixgbe can trigger a full pcie function reset if the reset_devices kernel parameter is defined. The main reason for adding this is that kdump can cause serious issues when the kdump kernel resets the IOMMU while DMA transactions are still occurring.
---
drivers/net/igb/igb_main.c | 3 +++ drivers/net/ixgbe/ixgbe_main.c | 3 +++ 2 files changed, 6 insertions(+), 0 deletions(-)
drivers/net/igb/igb_main.c +3 -0
@@ -1731,6 +1731,9 @@ static int __devinit igb_probe(struct pci_dev *pdev,return -EINVAL ; } +if (reset_devices &&pci_reset_device_function (pdev)) +return -ENODEV ; + err =pci_enable_device_mem (pdev);if (err)return err;
drivers/net/ixgbe/ixgbe_main.c +3 -0
@@ -6548,6 +6548,9 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,return -EINVAL ; } +if (reset_devices &&pci_reset_device_function (pdev)) +return -ENODEV ; + err =pci_enable_device_mem (pdev);if (err)return err;
David Miller
maintainerRe: [RFC PATCH 2/2] igb/ixgbe: add code to trigger function reset if reset_devices is set
From: Jeff Kirsher <[email protected]>
Date: Fri, 30 Jul 2010 17:59:12 -0700
Quoted 9 lines
From: Alexander Duyck <[email protected]>
This change makes it so that both igb and ixgbe can trigger a full pcie function reset if the
reset_deviceskernel parameter is defined. The main reason for adding this is that kdump can cause serious issues when the kdump kernel resets the IOMMU while DMA transactions are still occurring.Signed-off-by Alexander Duyck <[email protected]>Signed-off-by Jeff Kirsher <[email protected]>
I tend to disagree with the essence of this change.
Which is that we should add workaround after workaround for things that aren't functioning properly in kdump and kexec.
They should have a pass that shuts devices down properly, so that this kind of stuff doesn't need to happen in the kernel we then boot into.
What happens on non-PCIE systems then? Do they just lose when this happens?
No, you dun goof'd. :-) Find another way to fix this please.
Thanks.
Re: [RFC PATCH 2/2] igb/ixgbe: add code to trigger function reset if reset_devices is set
Quoted 13 lines · David Miller
From: Jeff Kirsher <[email protected]>
Date: Fri, 30 Jul 2010 17:59:12 -0700Quoted 9 lines
From: Alexander Duyck <[email protected]>
This change makes it so that both igb and ixgbe can trigger a full pcie function reset if the
reset_deviceskernel parameter is defined. The main reason for adding this is that kdump can cause serious issues when the kdump kernel resets the IOMMU while DMA transactions are still occurring.Signed-off-by Alexander Duyck <[email protected]>Signed-off-by Jeff Kirsher <[email protected]>
Quoted 7 lines
I tend to disagree with the essence of this change.
Which is that we should add workaround after workaround for things that aren't functioning properly in kdump and kexec.
They should have a pass that shuts devices down properly, so that this kind of stuff doesn't need to happen in the kernel we then boot into.
For a normal kexec, arguably true.
But in the kdump case, the original kernel has *crashed* and we really don't have that option -- we need to jump *straight* to the new kernel and have it reset the hardware.
The device driver really *ought* to be able to reset the hardware from whatever state it's in when the new kernel starts up. Anything less is broken, and reminds me of those crappy drivers that only work after a soft-reboot from Windows.
Most drivers *do* quite happily initialise their device and reliably get it into a known state; it's just that this particular hardware goes into a *particularly* stroppy fit when it gets a DMA master abort (which is what happens when the IOMMU stops it from scribbling into memory after the new kernel has taken over).
Quoted 2 lines
What happens on non-PCIE systems then? Do they just lose when this happens?
If they have a device that's this broken, and the driver can't get it into a working state any other way, then yes -- I don't see any way to *avoid* them losing.
I don't like the reset_devices thing though -- the device driver ought to cope (and reset the device with a full PCIe reset if that's the only way to make it stop sulking) *regardless* of that option, if it's necessary.
Signature · 2 lines
David Woodhouse Open Source Technology Centre [email protected] Intel Corporation
Re: [RFC PATCH 2/2] igb/ixgbe: add code to trigger function reset if reset_devices is set
Quoted 39 lines · David Woodhouse
Quoted 13 lines · David Miller
From: Jeff Kirsher<[email protected]>
Date: Fri, 30 Jul 2010 17:59:12 -0700Quoted 9 lines
From: Alexander Duyck<[email protected]>
This change makes it so that both igb and ixgbe can trigger a full pcie function reset if the
reset_deviceskernel parameter is defined. The main reason for adding this is that kdump can cause serious issues when the kdump kernel resets the IOMMU while DMA transactions are still occurring.Signed-off-by Alexander Duyck<[email protected]>Signed-off-by Jeff Kirsher<[email protected]>Quoted 7 lines
I tend to disagree with the essence of this change.
Which is that we should add workaround after workaround for things that aren't functioning properly in kdump and kexec.
They should have a pass that shuts devices down properly, so that this kind of stuff doesn't need to happen in the kernel we then boot into.
For a normal kexec, arguably true.
But in the kdump case, the original kernel has *crashed* and we really don't have that option -- we need to jump *straight* to the new kernel and have it reset the hardware.
The device driver really *ought* to be able to reset the hardware from whatever state it's in when the new kernel starts up. Anything less is broken, and reminds me of those crappy drivers that only work after a soft-reboot from Windows.
Most drivers *do* quite happily initialise their device and reliably get it into a known state; it's just that this particular hardware goes into a *particularly* stroppy fit when it gets a DMA master abort (which is what happens when the IOMMU stops it from scribbling into memory after the new kernel has taken over).
Quoted 6 lines
Quoted 2 lines
What happens on non-PCIE systems then? Do they just lose when this happens?
If they have a device that's this broken, and the driver can't get it into a working state any other way, then yes -- I don't see any way to *avoid* them losing.
What about asserting secondary RST# on the bridge? It would not work for devices on the root bus though.
Thanks,
Kenji Kaneshige
Quoted 131 lines · Jeff Kirsher
From: Alexander Duyck<[email protected]>
This change makes it so that there are several new calls available.
The first is
__pci_reset_devwhich works similar topci_reset_dev, however it does not obtain the device lock. This is important as I found several cases such as__pci_reset_functionin which the call was obtaining the device lock even though the lock had yet to be initialized. In addition if one wishes to do such a reset during probe it will hang since the device lock is already being held.The second change that was added was a function named
pci_reset_device_function. This function is similar topci_reset_functionhowever it does not hold the device lock and so it as well can be called during the driver probe routine.Signed-off-by Alexander Duyck<[email protected]>Signed-off-by Jeff Kirsher<[email protected]>---
drivers/pci/pci.c | 74 +++++++++++++++++++++++++++++++++++++++++++-------- include/linux/pci.h | 1 + 2 files changed, 64 insertions(+), 11 deletions(-)drivers/pci/pci.c +45
-11@@ -2445,17 +2445,14 @@ static int pci_parent_bus_reset(struct pci_dev *dev, int probe)return 0 ; } -static int pci_dev_reset (struct pci_dev *dev,int probe) +static int __pci_dev_reset (struct pci_dev *dev,int probe) {int rc;might_sleep (); -if (!probe) { +if (!probe)pci_block_user_cfg_access (dev); -/* block PM suspend, driver probe, etc. */ -device_lock (&dev->dev); - } rc =pci_dev_specific_reset (dev, probe);if (rc != -ENOTTY )@@ -2474,11 +2471,26 @@ static int pci_dev_reset(struct pci_dev *dev, int probe) goto done; rc =pci_parent_bus_reset (dev, probe); + done: -if (!probe) { -device_unlock (&dev->dev); +if (!probe)pci_unblock_user_cfg_access (dev); - } + +return rc; +} + +static int pci_dev_reset (struct pci_dev *dev,int probe) +{ +int rc; + +/* block PM suspend, driver probe, etc. */ +if (!probe) +device_lock (&dev->dev); + + rc =__pci_dev_reset (dev, probe); + +if (!probe) +device_unlock (&dev->dev);return rc; }@@ -2502,7 +2514,7 @@ done:*/ int __pci_reset_function (struct pci_dev *dev) { -return pci_dev_reset (dev,0 ); +return __pci_dev_reset (dev,0 ); }EXPORT_SYMBOL_GPL (__pci_reset_function);@@ -2519,7 +2531,7 @@ EXPORT_SYMBOL_GPL(__pci_reset_function);*/ int pci_probe_reset_function (struct pci_dev *dev) { -return pci_dev_reset (dev,1 ); +return __pci_dev_reset (dev,1 ); }/** @@ -2542,7 +2554,7 @@ int pci_reset_function(struct pci_dev *dev) {int rc; - rc =pci_dev_reset (dev,1 ); + rc =__pci_dev_reset (dev,1 );if (rc)return rc;@@ -2563,6 +2575,46 @@ int pci_reset_function(struct pci_dev *dev)EXPORT_SYMBOL_GPL (pci_reset_function);/** +* pci_reset_device_function - quiesce and reinitialize a PCI device function +* @dev: PCI device to reset +* +* Some devices allow an individual function to be reset without affecting +* other functions in the same device. The PCI device must be responsive +* to PCI config space in order to use this function. +* +* This function is very similar to pci_reset_function, however this function +* does not obtain the device lock during the reset. This is due to the fact +* that the call is meant to be used during probe if the reset_devices +* kernel parameter is set. +* +* Returns 0 if the device function was successfully reset or negative if the +* device doesn't support resetting a single function. +*/ +int pci_reset_device_function (struct pci_dev *dev) +{ +int rc; + + rc =__pci_dev_reset (dev,1 ); +if (rc) +return rc;
drivers/pci/pci.c int pci_reset_function(struct pci_dev *dev) · line 2609
Quoted 10 lines
drivers/pci/pci.c +10
-0+ +pci_save_state (dev); + +/* +* both INTx and MSI are disabled after the Interrupt Disable bit +* is set and the Bus Master bit is cleared. +*/ +pci_write_config_word (dev,PCI_COMMAND ,PCI_COMMAND_INTX_DISABLE ); + + rc =__pci_dev_reset (dev,0 );
Could you tell me why you need to program command register before reset?
"MSI enable" and "Bus Master" bits are cleared by the reset. Furthermore, resetting the device clears the "Interrupt Disable bit", even though it was set just before the rest. So I'm a little confused.
Thanks,
Kenji Kaneshige
Quoted 12 lines · Kenji Kaneshige
drivers/pci/pci.c int pci_reset_function(struct pci_dev *dev) · line 2609
Quoted 8 lines · Jeff Kirsher
From: Alexander Duyck<[email protected]>
drivers/pci/pci.c +7
-0+/* +* both INTx and MSI are disabled after the Interrupt Disable bit +* is set and the Bus Master bit is cleared. +*/ +pci_write_config_word (dev,PCI_COMMAND ,PCI_COMMAND_INTX_DISABLE ); + + rc =__pci_dev_reset (dev,0 );Could you tell me why you need to program command register before reset?
Quoted 7 lines
"MSI enable" and "Bus Master" bits are cleared by the reset. Furthermore, resetting the device clears the "Interrupt Disable bit", even though it was set just before the rest. So I'm a little confused.
Thanks,
Kenji Kaneshige
The point is to prevent any pending transactions from being on the bus while we are doing the reset. By writing only the INTX disable bit we are disabling all interrupts from being generated, and also disabling all DMA and MSI interrupts since the bus master enable bit is not set.
Without this change the device might be in the middle of a transaction or sending an interrupt while we are doing the reset which may lead to other issues after the reset.
Thanks,
Alex
Quoted 21 lines · Alexander Duyck
Quoted 10 lines · Kenji Kaneshige
Quoted 8 lines · Jeff Kirsher
From: Alexander Duyck<[email protected]>
+ /*
+ * both INTx and MSI are disabled after the Interrupt Disable bit
+ * is set and the Bus Master bit is cleared.
+ */
+pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE); +
+ rc =__pci_dev_reset(dev, 0);Quoted 9 lines
Could you tell me why you need to program command register before reset?
"MSI enable" and "Bus Master" bits are cleared by the reset. Furthermore, resetting the device clears the "Interrupt Disable bit", even though it was set just before the rest. So I'm a little confused.
Thanks,
Kenji Kaneshige
Quoted 9 lines
The point is to prevent any pending transactions from being on the bus while we are doing the reset. By writing only the INTX disable bit we are disabling all interrupts from being generated, and also disabling all DMA and MSI interrupts since the bus master enable bit is not set.
Without this change the device might be in the middle of a transaction or sending an interrupt while we are doing the reset which may lead to other issues after the reset.
Thank you for clarification. I understood.
Thanks,
Kenji Kaneshige