pci_intx() calls into pcim_intx() in managed mode, i.e., when pcim_enable_device() had been called. This recursive call causes a bug by re-registering the device resource in the release callback. This is the same phenomenon that made it necessary to implement some functionality a second time, see __pcim_request_region(). Implement __pcim_intx() to bypass the hybrid nature of pci_intx() on driver detach. Fixes: https://lore.kernel.org/all/20240708214656.4721-1-Ashish.Kalra@xxxxxxx/ Reported-by: Ashish Kalra <Ashish.Kalra@xxxxxxx> Signed-off-by: Philipp Stanner <pstanner@xxxxxxxxxx> --- Hi Ashish, I hacked down this fix that should be applyable on top. Could you maybe have a first quick look whether this fixes the issue? --- drivers/pci/devres.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/drivers/pci/devres.c b/drivers/pci/devres.c index 2f0379a4e58f..dcef049b72fe 100644 --- a/drivers/pci/devres.c +++ b/drivers/pci/devres.c @@ -408,12 +408,31 @@ static inline bool mask_contains_bar(int mask, int bar) return mask & BIT(bar); } +/* + * This is a copy of pci_intx() used to bypass the problem of occuring + * recursive function calls due to the hybrid nature of pci_intx(). + */ +static void __pcim_intx(struct pci_dev *pdev, int enable) +{ + u16 pci_command, new; + + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); + + if (enable) + new = pci_command & ~PCI_COMMAND_INTX_DISABLE; + else + new = pci_command | PCI_COMMAND_INTX_DISABLE; + + if (new != pci_command) + pci_write_config_word(pdev, PCI_COMMAND, new); +} + static void pcim_intx_restore(struct device *dev, void *data) { struct pci_dev *pdev = to_pci_dev(dev); struct pcim_intx_devres *res = data; - pci_intx(pdev, res->orig_intx); + __pcim_intx(pdev, res->orig_intx); } static struct pcim_intx_devres *get_or_create_intx_devres(struct device *dev) @@ -443,7 +462,6 @@ static struct pcim_intx_devres *get_or_create_intx_devres(struct device *dev) */ int pcim_intx(struct pci_dev *pdev, int enable) { - u16 pci_command, new; struct pcim_intx_devres *res; res = get_or_create_intx_devres(&pdev->dev); @@ -451,16 +469,7 @@ int pcim_intx(struct pci_dev *pdev, int enable) return -ENOMEM; res->orig_intx = !enable; - - pci_read_config_word(pdev, PCI_COMMAND, &pci_command); - - if (enable) - new = pci_command & ~PCI_COMMAND_INTX_DISABLE; - else - new = pci_command | PCI_COMMAND_INTX_DISABLE; - - if (new != pci_command) - pci_write_config_word(pdev, PCI_COMMAND, new); + __pcim_intx(pdev, enable); return 0; } -- 2.45.0