Re: [patch V3 16/22] genirq/msi: Provide new domain id based interfaces for freeing interrupts

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, 2022-11-25 at 00:24 +0100, Thomas Gleixner wrote:
> Provide two sorts of interfaces to handle the different use cases:
> 
>   - msi_domain_free_irqs_range():
> 
>         Handles a caller defined precise range
> 
>   - msi_domain_free_irqs_all():
> 
>         Frees all interrupts associated to a domain
> 
> The latter is useful for device teardown and to handle the legacy MSI support
> which does not have any range information available.
> 
> Signed-off-by: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
> ---

...

> +static void msi_domain_free_locked(struct device *dev, struct msi_ctrl *ctrl)
>  {
> +       struct msi_domain_info *info;
> +       struct msi_domain_ops *ops;
> +       struct irq_domain *domain;
> +
> +       if (!msi_ctrl_valid(dev, ctrl))
> +               return;
> +
> +       domain = msi_get_device_domain(dev, ctrl->domid);
> +       if (!domain)
> +               return;
> +
> +       info = domain->host_data;
> +       ops = info->ops;
> +
> +       if (ops->domain_free_irqs)
> +               ops->domain_free_irqs(domain, dev);

Do you want a call to msi_free_dev_descs(dev) here? In the case where
the core code calls ops->domain_alloc_irqs() it *has* allocated the
descriptors first... but it's expecting the irqdomain to free them?

However, it's not quite as simple as adding msi_free_dev_descs()...

> +       else
> +               __msi_domain_free_irqs(dev, domain, ctrl);
> +

The igb driver seems to set up a single MSI-X in its setup, then tear
that down, then try again with more. Thus exercising the teardown path.

In 6.2-rc3 it fails under Xen (emulation in qemu) thus:

[    1.491207] igb: Intel(R) Gigabit Ethernet Network Driver
[    1.494003] igb: Copyright (c) 2007-2014 Intel Corporation.
[    1.664907] ACPI: \_SB_.LNKA: Enabled at IRQ 10
[    1.670837] ------------[ cut here ]------------
[    1.672644] WARNING: CPU: 1 PID: 1 at drivers/xen/events/events_base.c:793 xen_free_irq+0x156/0x170
[    1.676202] Modules linked in:
[    1.677638] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 6.2.0-rc3+ #1059
[    1.680134] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.1-0-g3208b098f51a-prebuilt.qemu.org 04/01/2014
[    1.684484] RIP: 0010:xen_free_irq+0x156/0x170
[    1.686240] Code: 5c 41 5d 41 5e 41 5f e9 08 03 95 ff e8 a3 5b 95 ff 48 85 c0 74 14 48 8b 58 30 e9 df fe ff ff 31 f6 89 ef e8 6c 59 95 ff eb 94 <0f> 0b 5b 5d 41 5c 41 5d 41 5e 41 5f c3 cc cc cc cc 0f 0b eb 86 0f
[    1.692888] RSP: 0000:ffffc90000013ac8 EFLAGS: 00010246
[    1.694705] RAX: 0000000000000000 RBX: 0000000000000026 RCX: 0000000000000000
[    1.697113] RDX: 0000000000000028 RSI: ffff888001400490 RDI: 0000000000000026
[    1.699498] RBP: 0000000000000026 R08: ffff8880014005e8 R09: ffffffff89c00240
[    1.701917] R10: 0000000000000000 R11: 0000000000000000 R12: 00000000fffffffe
[    1.704520] R13: ffffffff89de6880 R14: 0000000000000000 R15: 0000000000000005
[    1.707202] FS:  0000000000000000(0000) GS:ffff88803ed00000(0000) knlGS:0000000000000000
[    1.709974] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[    1.711867] CR2: 0000000000000000 CR3: 000000003c812001 CR4: 0000000000170ee0
[    1.714260] Call Trace:
[    1.715145]  <TASK>
[    1.715897]  xen_destroy_irq+0x64/0x120
[    1.717181]  ? msi_find_desc+0x41/0xb0
[    1.718552]  xen_teardown_msi_irqs+0x3d/0x70
[    1.720064]  msi_domain_free_locked.part.0+0x58/0x1c0
[    1.721791]  msi_domain_free_irqs_all_locked+0x6a/0x90
[    1.723551]  __pci_enable_msix_range+0x353/0x590
[    1.725159]  igb_set_interrupt_capability+0x90/0x1c0
[    1.726879]  igb_init_interrupt_scheme+0x2d/0x230
[    1.728494]  ? rcu_read_lock_sched_held+0x3f/0x80
[    1.730361]  igb_sw_init+0x1b3/0x260
[    1.731797]  igb_probe+0x3b6/0xf00
[    1.733146]  ? _raw_spin_unlock_irqrestore+0x40/0x60
[    1.734834]  local_pci_probe+0x41/0x80
[    1.736164]  pci_call_probe+0x54/0x160
[    1.737441]  pci_device_probe+0x7c/0x100
[    1.738828]  ? driver_sysfs_add+0x71/0xd0
[    1.740229]  really_probe+0xde/0x380
[    1.741434]  ? pm_runtime_barrier+0x50/0x90
[    1.742873]  __driver_probe_device+0x78/0x170
[    1.744314]  driver_probe_device+0x1f/0x90
[    1.745689]  __driver_attach+0xd2/0x1c0
[    1.747035]  ? __pfx___driver_attach+0x10/0x10
[    1.748518]  bus_for_each_dev+0x79/0xc0
[    1.749859]  bus_add_driver+0x1b1/0x200
[    1.751182]  driver_register+0x89/0xe0
[    1.752472]  ? __pfx_igb_init_module+0x10/0x10
[    1.754054]  do_one_initcall+0x5b/0x320
[    1.755573]  ? rcu_read_lock_sched_held+0x3f/0x80
[    1.757375]  kernel_init_freeable+0x1a6/0x1ec
[    1.759005]  ? __pfx_kernel_init+0x10/0x10
[    1.760375]  kernel_init+0x16/0x130
[    1.761554]  ret_from_fork+0x2c/0x50
[    1.762797]  </TASK>
[    1.763590] irq event stamp: 1798623
[    1.764869] hardirqs last  enabled at (1798633): [<ffffffff8814aa8e>] __up_console_sem+0x5e/0x70
[    1.767762] hardirqs last disabled at (1798642): [<ffffffff8814aa73>] __up_console_sem+0x43/0x70
[    1.770715] softirqs last  enabled at (1798570): [<ffffffff88d91f76>] __do_softirq+0x356/0x4da
[    1.773576] softirqs last disabled at (1798565): [<ffffffff880bb83d>] __irq_exit_rcu+0xdd/0x150
[    1.776492] ---[ end trace 0000000000000000 ]---
[    1.839462] igb 0000:00:04.0: added PHC on eth0
[    1.843531] igb 0000:00:04.0: Intel(R) Gigabit Ethernet Network Connection
[    1.843541] igb 0000:00:04.0: eth0: (PCIe:5.0Gb/s:Width x4) 00:1e:67:cb:7a:93
[    1.843620] igb 0000:00:04.0: eth0: PBA No: 006000-000
[    1.849237] igb 0000:00:04.0: Using legacy interrupts. 1 rx queue(s), 1 tx queue(s)


If I add the missing call to msi_free_msi_descs() then it does work,
but complains differently:

[    1.563055] igb: Intel(R) Gigabit Ethernet Network Driver
[    1.566442] igb: Copyright (c) 2007-2014 Intel Corporation.
[    1.737236] ACPI: \_SB_.LNKA: Enabled at IRQ 10
[    1.742162] ------------[ cut here ]------------
[    1.744393] WARNING: CPU: 0 PID: 1 at kernel/irq/msi.c:196 msi_domain_free_descs+0xe1/0x110
[    1.748248] Modules linked in:
[    1.749289] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 6.2.0-rc3+ #1057
[    1.751466] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.1-0-g3208b098f51a-prebuilt.qemu.org 04/01/2014
[    1.755187] RIP: 0010:msi_domain_free_descs+0xe1/0x110
[    1.756875] Code: 00 48 89 e6 4c 89 e7 e8 ed f4 ba 00 48 89 c3 48 85 c0 0f 84 71 ff ff ff 48 8b 34 24 4c 89 e7 e8 a5 01 bb 00 8b 03 85 c0 74 be <0f> 0b eb cb 48 8b 87 70 03 00 00 be ff ff ff ff 48 8d 78 78 e8 26
[    1.763060] RSP: 0000:ffffc90000013b78 EFLAGS: 00010202
[    1.764804] RAX: 0000000000000026 RBX: ffff888001ac5f00 RCX: 0000000000000000
[    1.767155] RDX: 0000000000000001 RSI: ffffffffa649808a RDI: 00000000ffffffff
[    1.769462] RBP: ffffc90000013ba8 R08: 0000000000000001 R09: 0000000000000000
[    1.771934] R10: 000000006ac46bb1 R11: 00000000aee0433d R12: ffff888001a238c8
[    1.774695] R13: ffffffffa6de6880 R14: ffff888001a51218 R15: ffff888001a50000
[    1.777081] FS:  0000000000000000(0000) GS:ffff88803ec00000(0000) knlGS:0000000000000000
[    1.779754] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[    1.781681] CR2: ffff888010801000 CR3: 000000000e812001 CR4: 0000000000170ef0
[    1.784093] Call Trace:
[    1.784880]  <TASK>
[    1.785640]  msi_domain_free_msi_descs_range+0x34/0x60
[    1.787370]  msi_domain_free_locked.part.0+0x58/0x1c0
[    1.789034]  msi_domain_free_irqs_all_locked+0x6a/0x90
[    1.790815]  pci_free_msi_irqs+0xe/0x30
[    1.792157]  pci_disable_msix+0x48/0x60
[    1.793413]  igb_reset_interrupt_capability+0xa4/0xb0
[    1.795077]  igb_sw_init+0x13f/0x260
[    1.796281]  igb_probe+0x3b6/0xf00
[    1.797421]  ? _raw_spin_unlock_irqrestore+0x40/0x60
[    1.799050]  local_pci_probe+0x41/0x80
[    1.800282]  pci_call_probe+0x54/0x160
[    1.801543]  pci_device_probe+0x7c/0x100
[    1.803393]  ? driver_sysfs_add+0x71/0xd0
[    1.804761]  really_probe+0xde/0x380
[    1.806021]  ? pm_runtime_barrier+0x50/0x90
[    1.807395]  __driver_probe_device+0x78/0x170
[    1.808877]  driver_probe_device+0x1f/0x90
[    1.810257]  __driver_attach+0xd2/0x1c0
[    1.811529]  ? __pfx___driver_attach+0x10/0x10
[    1.813251]  bus_for_each_dev+0x79/0xc0
[    1.814534]  bus_add_driver+0x1b1/0x200
[    1.816058]  driver_register+0x89/0xe0
[    1.817291]  ? __pfx_igb_init_module+0x10/0x10
[    1.818821]  do_one_initcall+0x5b/0x320
[    1.820133]  ? rcu_read_lock_sched_held+0x3f/0x80
[    1.821697]  kernel_init_freeable+0x1a6/0x1ec
[    1.823150]  ? __pfx_kernel_init+0x10/0x10
[    1.824484]  kernel_init+0x16/0x130
[    1.825990]  ret_from_fork+0x2c/0x50
[    1.827757]  </TASK>
[    1.828865] irq event stamp: 1797845
[    1.830573] hardirqs last  enabled at (1797855): [<ffffffffa514aa8e>] __up_console_sem+0x5e/0x70
[    1.834809] hardirqs last disabled at (1797864): [<ffffffffa514aa73>] __up_console_sem+0x43/0x70
[    1.838915] softirqs last  enabled at (1797742): [<ffffffffa5d91f76>] __do_softirq+0x356/0x4da
[    1.842442] softirqs last disabled at (1797737): [<ffffffffa50bb83d>] __irq_exit_rcu+0xdd/0x150
[    1.846094] ---[ end trace 0000000000000000 ]---


If I zero msidesc->irq in the loop in xen_teardown_msi_irqs(), *then*
it both works and stops complaining. But I'm mostly just tampering
empirically now...

I can provide a qemu tree which will let you test this easily with just
`qemu-system-x86_64 -kernel ...` but you have to promise not to look at
the way I've fixed some qemu deadlocks just by commenting out the lock
on MSI delivery/translation :)

You'd also have to provide your own igb device as qemu doesn't emulate
those; I'm testing it in passthrough. Or hack the e1000e driver to do a
setup/teardown/setup... or perhaps just unload and reload its module?

I'll provide a SoB just in case it's actually the right way to fix it…

Signed-off-by: David Woodhouse <dwmw@xxxxxxxxxxxx>

diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
index 790550479831..293e23b7229a 100644
--- a/arch/x86/pci/xen.c
+++ b/arch/x86/pci/xen.c
@@ -390,8 +390,10 @@ static void xen_teardown_msi_irqs(struct pci_dev *dev)
 	int i;
 
 	msi_for_each_desc(msidesc, &dev->dev, MSI_DESC_ASSOCIATED) {
-		for (i = 0; i < msidesc->nvec_used; i++)
+		for (i = 0; i < msidesc->nvec_used; i++) {
 			xen_destroy_irq(msidesc->irq + i);
+			msidesc->irq = 0;
+		}
 	}
 }
 

diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
index 955267bbc2be..812e1ec1a633 100644
--- a/kernel/irq/msi.c
+++ b/kernel/irq/msi.c
@@ -1533,9 +1533,10 @@ static void msi_domain_free_locked(struct device *dev, struct msi_ctrl *ctrl)
 	info = domain->host_data;
 	ops = info->ops;
 
-	if (ops->domain_free_irqs)
+	if (ops->domain_free_irqs) {
 		ops->domain_free_irqs(domain, dev);
-	else
+		msi_free_msi_descs(dev);
+	} else
 		__msi_domain_free_irqs(dev, domain, ctrl);
 
 	if (ops->msi_post_free)


Attachment: smime.p7s
Description: S/MIME cryptographic signature


[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux