Skip to content

Commit f4cbe79

Browse files
paulusmackgregkh
authored andcommitted
powerpc/MSI: Fix race condition in tearing down MSI interrupts
commit e297c93 upstream. This fixes a race which can result in the same virtual IRQ number being assigned to two different MSI interrupts. The most visible consequence of that is usually a warning and stack trace from the sysfs code about an attempt to create a duplicate entry in sysfs. The race happens when one CPU (say CPU 0) is disposing of an MSI while another CPU (say CPU 1) is setting up an MSI. CPU 0 calls (for example) pnv_teardown_msi_irqs(), which calls msi_bitmap_free_hwirqs() to indicate that the MSI (i.e. its hardware IRQ number) is no longer in use. Then, before CPU 0 gets to calling irq_dispose_mapping() to free up the virtal IRQ number, CPU 1 comes in and calls msi_bitmap_alloc_hwirqs() to allocate an MSI, and gets the same hardware IRQ number that CPU 0 just freed. CPU 1 then calls irq_create_mapping() to get a virtual IRQ number, which sees that there is currently a mapping for that hardware IRQ number and returns the corresponding virtual IRQ number (which is the same virtual IRQ number that CPU 0 was using). CPU 0 then calls irq_dispose_mapping() and frees that virtual IRQ number. Now, if another CPU comes along and calls irq_create_mapping(), it is likely to get the virtual IRQ number that was just freed, resulting in the same virtual IRQ number apparently being used for two different hardware interrupts. To fix this race, we just move the call to msi_bitmap_free_hwirqs() to after the call to irq_dispose_mapping(). Since virq_to_hw() doesn't work for the virtual IRQ number after irq_dispose_mapping() has been called, we need to call it before irq_dispose_mapping() and remember the result for the msi_bitmap_free_hwirqs() call. The pattern of calling msi_bitmap_free_hwirqs() before irq_dispose_mapping() appears in 5 places under arch/powerpc, and appears to have originated in commit 05af7bd ("[POWERPC] MPIC U3/U4 MSI backend") from 2007. Fixes: 05af7bd ("[POWERPC] MPIC U3/U4 MSI backend") Reported-by: Alexey Kardashevskiy <[email protected]> Signed-off-by: Paul Mackerras <[email protected]> Signed-off-by: Michael Ellerman <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 607877b commit f4cbe79

File tree

5 files changed

+15
-10
lines changed

5 files changed

+15
-10
lines changed

arch/powerpc/platforms/pasemi/msi.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,17 +63,18 @@ static struct irq_chip mpic_pasemi_msi_chip = {
6363
static void pasemi_msi_teardown_msi_irqs(struct pci_dev *pdev)
6464
{
6565
struct msi_desc *entry;
66+
irq_hw_number_t hwirq;
6667

6768
pr_debug("pasemi_msi_teardown_msi_irqs, pdev %p\n", pdev);
6869

6970
list_for_each_entry(entry, &pdev->msi_list, list) {
7071
if (entry->irq == NO_IRQ)
7172
continue;
7273

74+
hwirq = virq_to_hw(entry->irq);
7375
irq_set_msi_desc(entry->irq, NULL);
74-
msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap,
75-
virq_to_hw(entry->irq), ALLOC_CHUNK);
7676
irq_dispose_mapping(entry->irq);
77+
msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, hwirq, ALLOC_CHUNK);
7778
}
7879

7980
return;

arch/powerpc/platforms/powernv/pci.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,17 +99,18 @@ void pnv_teardown_msi_irqs(struct pci_dev *pdev)
9999
struct pci_controller *hose = pci_bus_to_host(pdev->bus);
100100
struct pnv_phb *phb = hose->private_data;
101101
struct msi_desc *entry;
102+
irq_hw_number_t hwirq;
102103

103104
if (WARN_ON(!phb))
104105
return;
105106

106107
list_for_each_entry(entry, &pdev->msi_list, list) {
107108
if (entry->irq == NO_IRQ)
108109
continue;
110+
hwirq = virq_to_hw(entry->irq);
109111
irq_set_msi_desc(entry->irq, NULL);
110-
msi_bitmap_free_hwirqs(&phb->msi_bmp,
111-
virq_to_hw(entry->irq) - phb->msi_base, 1);
112112
irq_dispose_mapping(entry->irq);
113+
msi_bitmap_free_hwirqs(&phb->msi_bmp, hwirq - phb->msi_base, 1);
113114
}
114115
}
115116
#endif /* CONFIG_PCI_MSI */

arch/powerpc/sysdev/fsl_msi.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,15 +128,16 @@ static void fsl_teardown_msi_irqs(struct pci_dev *pdev)
128128
{
129129
struct msi_desc *entry;
130130
struct fsl_msi *msi_data;
131+
irq_hw_number_t hwirq;
131132

132133
list_for_each_entry(entry, &pdev->msi_list, list) {
133134
if (entry->irq == NO_IRQ)
134135
continue;
136+
hwirq = virq_to_hw(entry->irq);
135137
msi_data = irq_get_chip_data(entry->irq);
136138
irq_set_msi_desc(entry->irq, NULL);
137-
msi_bitmap_free_hwirqs(&msi_data->bitmap,
138-
virq_to_hw(entry->irq), 1);
139139
irq_dispose_mapping(entry->irq);
140+
msi_bitmap_free_hwirqs(&msi_data->bitmap, hwirq, 1);
140141
}
141142

142143
return;

arch/powerpc/sysdev/mpic_u3msi.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,15 +107,16 @@ static u64 find_u4_magic_addr(struct pci_dev *pdev, unsigned int hwirq)
107107
static void u3msi_teardown_msi_irqs(struct pci_dev *pdev)
108108
{
109109
struct msi_desc *entry;
110+
irq_hw_number_t hwirq;
110111

111112
list_for_each_entry(entry, &pdev->msi_list, list) {
112113
if (entry->irq == NO_IRQ)
113114
continue;
114115

116+
hwirq = virq_to_hw(entry->irq);
115117
irq_set_msi_desc(entry->irq, NULL);
116-
msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap,
117-
virq_to_hw(entry->irq), 1);
118118
irq_dispose_mapping(entry->irq);
119+
msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, hwirq, 1);
119120
}
120121

121122
return;

arch/powerpc/sysdev/ppc4xx_msi.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,16 +124,17 @@ void ppc4xx_teardown_msi_irqs(struct pci_dev *dev)
124124
{
125125
struct msi_desc *entry;
126126
struct ppc4xx_msi *msi_data = &ppc4xx_msi;
127+
irq_hw_number_t hwirq;
127128

128129
dev_dbg(&dev->dev, "PCIE-MSI: tearing down msi irqs\n");
129130

130131
list_for_each_entry(entry, &dev->msi_list, list) {
131132
if (entry->irq == NO_IRQ)
132133
continue;
134+
hwirq = virq_to_hw(entry->irq);
133135
irq_set_msi_desc(entry->irq, NULL);
134-
msi_bitmap_free_hwirqs(&msi_data->bitmap,
135-
virq_to_hw(entry->irq), 1);
136136
irq_dispose_mapping(entry->irq);
137+
msi_bitmap_free_hwirqs(&msi_data->bitmap, hwirq, 1);
137138
}
138139
}
139140

0 commit comments

Comments
 (0)