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