Skip to content

Commit c36e33e

Browse files
committed
Merge tag 'irq-urgent-2021-11-14' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull irq fixes from Thomas Gleixner: "A set of fixes for the interrupt subsystem Core code: - A regression fix for the Open Firmware interrupt mapping code where a interrupt controller property in a node caused a map property in the same node to be ignored. Interrupt chip drivers: - Workaround a limitation in SiFive PLIC interrupt chip which silently ignores an EOI when the interrupt line is masked. - Provide the missing mask/unmask implementation for the CSKY MP interrupt controller. PCI/MSI: - Prevent a use after free when PCI/MSI interrupts are released by destroying the sysfs entries before freeing the memory which is accessed in the sysfs show() function. - Implement a mask quirk for the Nvidia ION AHCI chip which does not advertise masking capability despite implementing it. Even worse the chip comes out of reset with all MSI entries masked, which due to the missing masking capability never get unmasked. - Move the check which prevents accessing the MSI[X] masking for XEN back into the low level accessors. The recent consolidation missed that these accessors can be invoked from places which do not have that check which broke XEN. Move them back to he original place instead of sprinkling tons of these checks all over the code" * tag 'irq-urgent-2021-11-14' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: of/irq: Don't ignore interrupt-controller when interrupt-map failed irqchip/sifive-plic: Fixup EOI failed when masked irqchip/csky-mpintc: Fixup mask/unmask implementation PCI/MSI: Destroy sysfs before freeing entries PCI: Add MSI masking quirk for Nvidia ION AHCI PCI/MSI: Deal with devices lying about their MSI mask capability PCI/MSI: Move non-mask check back into low level accessors
2 parents 218cc8b + 979292a commit c36e33e

File tree

8 files changed

+60
-28
lines changed

8 files changed

+60
-28
lines changed

drivers/irqchip/irq-csky-mpintc.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ static void csky_mpintc_handler(struct pt_regs *regs)
7878
readl_relaxed(reg_base + INTCL_RDYIR));
7979
}
8080

81-
static void csky_mpintc_enable(struct irq_data *d)
81+
static void csky_mpintc_unmask(struct irq_data *d)
8282
{
8383
void __iomem *reg_base = this_cpu_read(intcl_reg);
8484

@@ -87,7 +87,7 @@ static void csky_mpintc_enable(struct irq_data *d)
8787
writel_relaxed(d->hwirq, reg_base + INTCL_SENR);
8888
}
8989

90-
static void csky_mpintc_disable(struct irq_data *d)
90+
static void csky_mpintc_mask(struct irq_data *d)
9191
{
9292
void __iomem *reg_base = this_cpu_read(intcl_reg);
9393

@@ -164,8 +164,8 @@ static int csky_irq_set_affinity(struct irq_data *d,
164164
static struct irq_chip csky_irq_chip = {
165165
.name = "C-SKY SMP Intc",
166166
.irq_eoi = csky_mpintc_eoi,
167-
.irq_enable = csky_mpintc_enable,
168-
.irq_disable = csky_mpintc_disable,
167+
.irq_unmask = csky_mpintc_unmask,
168+
.irq_mask = csky_mpintc_mask,
169169
.irq_set_type = csky_mpintc_set_type,
170170
#ifdef CONFIG_SMP
171171
.irq_set_affinity = csky_irq_set_affinity,

drivers/irqchip/irq-sifive-plic.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,13 @@ static void plic_irq_eoi(struct irq_data *d)
163163
{
164164
struct plic_handler *handler = this_cpu_ptr(&plic_handlers);
165165

166-
writel(d->hwirq, handler->hart_base + CONTEXT_CLAIM);
166+
if (irqd_irq_masked(d)) {
167+
plic_irq_unmask(d);
168+
writel(d->hwirq, handler->hart_base + CONTEXT_CLAIM);
169+
plic_irq_mask(d);
170+
} else {
171+
writel(d->hwirq, handler->hart_base + CONTEXT_CLAIM);
172+
}
167173
}
168174

169175
static struct irq_chip plic_chip = {

drivers/of/irq.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,10 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
161161
* if it is then we are done, unless there is an
162162
* interrupt-map which takes precedence.
163163
*/
164+
bool intc = of_property_read_bool(ipar, "interrupt-controller");
165+
164166
imap = of_get_property(ipar, "interrupt-map", &imaplen);
165-
if (imap == NULL &&
166-
of_property_read_bool(ipar, "interrupt-controller")) {
167+
if (imap == NULL && intc) {
167168
pr_debug(" -> got it !\n");
168169
return 0;
169170
}
@@ -244,8 +245,20 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
244245

245246
pr_debug(" -> imaplen=%d\n", imaplen);
246247
}
247-
if (!match)
248+
if (!match) {
249+
if (intc) {
250+
/*
251+
* The PASEMI Nemo is a known offender, so
252+
* let's only warn for anyone else.
253+
*/
254+
WARN(!IS_ENABLED(CONFIG_PPC_PASEMI),
255+
"%pOF interrupt-map failed, using interrupt-controller\n",
256+
ipar);
257+
return 0;
258+
}
259+
248260
goto fail;
261+
}
249262

250263
/*
251264
* Successfully parsed an interrrupt-map translation; copy new

drivers/pci/msi.c

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,9 @@ static noinline void pci_msi_update_mask(struct msi_desc *desc, u32 clear, u32 s
148148
raw_spinlock_t *lock = &desc->dev->msi_lock;
149149
unsigned long flags;
150150

151+
if (!desc->msi_attrib.can_mask)
152+
return;
153+
151154
raw_spin_lock_irqsave(lock, flags);
152155
desc->msi_mask &= ~clear;
153156
desc->msi_mask |= set;
@@ -181,7 +184,8 @@ static void pci_msix_write_vector_ctrl(struct msi_desc *desc, u32 ctrl)
181184
{
182185
void __iomem *desc_addr = pci_msix_desc_addr(desc);
183186

184-
writel(ctrl, desc_addr + PCI_MSIX_ENTRY_VECTOR_CTRL);
187+
if (desc->msi_attrib.can_mask)
188+
writel(ctrl, desc_addr + PCI_MSIX_ENTRY_VECTOR_CTRL);
185189
}
186190

187191
static inline void pci_msix_mask(struct msi_desc *desc)
@@ -200,23 +204,17 @@ static inline void pci_msix_unmask(struct msi_desc *desc)
200204

201205
static void __pci_msi_mask_desc(struct msi_desc *desc, u32 mask)
202206
{
203-
if (pci_msi_ignore_mask || desc->msi_attrib.is_virtual)
204-
return;
205-
206207
if (desc->msi_attrib.is_msix)
207208
pci_msix_mask(desc);
208-
else if (desc->msi_attrib.maskbit)
209+
else
209210
pci_msi_mask(desc, mask);
210211
}
211212

212213
static void __pci_msi_unmask_desc(struct msi_desc *desc, u32 mask)
213214
{
214-
if (pci_msi_ignore_mask || desc->msi_attrib.is_virtual)
215-
return;
216-
217215
if (desc->msi_attrib.is_msix)
218216
pci_msix_unmask(desc);
219-
else if (desc->msi_attrib.maskbit)
217+
else
220218
pci_msi_unmask(desc, mask);
221219
}
222220

@@ -370,6 +368,11 @@ static void free_msi_irqs(struct pci_dev *dev)
370368
for (i = 0; i < entry->nvec_used; i++)
371369
BUG_ON(irq_has_action(entry->irq + i));
372370

371+
if (dev->msi_irq_groups) {
372+
msi_destroy_sysfs(&dev->dev, dev->msi_irq_groups);
373+
dev->msi_irq_groups = NULL;
374+
}
375+
373376
pci_msi_teardown_msi_irqs(dev);
374377

375378
list_for_each_entry_safe(entry, tmp, msi_list, list) {
@@ -381,11 +384,6 @@ static void free_msi_irqs(struct pci_dev *dev)
381384
list_del(&entry->list);
382385
free_msi_entry(entry);
383386
}
384-
385-
if (dev->msi_irq_groups) {
386-
msi_destroy_sysfs(&dev->dev, dev->msi_irq_groups);
387-
dev->msi_irq_groups = NULL;
388-
}
389387
}
390388

391389
static void pci_intx_for_msi(struct pci_dev *dev, int enable)
@@ -479,12 +477,16 @@ msi_setup_entry(struct pci_dev *dev, int nvec, struct irq_affinity *affd)
479477
goto out;
480478

481479
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
480+
/* Lies, damned lies, and MSIs */
481+
if (dev->dev_flags & PCI_DEV_FLAGS_HAS_MSI_MASKING)
482+
control |= PCI_MSI_FLAGS_MASKBIT;
482483

483484
entry->msi_attrib.is_msix = 0;
484485
entry->msi_attrib.is_64 = !!(control & PCI_MSI_FLAGS_64BIT);
485486
entry->msi_attrib.is_virtual = 0;
486487
entry->msi_attrib.entry_nr = 0;
487-
entry->msi_attrib.maskbit = !!(control & PCI_MSI_FLAGS_MASKBIT);
488+
entry->msi_attrib.can_mask = !pci_msi_ignore_mask &&
489+
!!(control & PCI_MSI_FLAGS_MASKBIT);
488490
entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */
489491
entry->msi_attrib.multi_cap = (control & PCI_MSI_FLAGS_QMASK) >> 1;
490492
entry->msi_attrib.multiple = ilog2(__roundup_pow_of_two(nvec));
@@ -495,7 +497,7 @@ msi_setup_entry(struct pci_dev *dev, int nvec, struct irq_affinity *affd)
495497
entry->mask_pos = dev->msi_cap + PCI_MSI_MASK_32;
496498

497499
/* Save the initial mask status */
498-
if (entry->msi_attrib.maskbit)
500+
if (entry->msi_attrib.can_mask)
499501
pci_read_config_dword(dev, entry->mask_pos, &entry->msi_mask);
500502

501503
out:
@@ -639,10 +641,13 @@ static int msix_setup_entries(struct pci_dev *dev, void __iomem *base,
639641
entry->msi_attrib.is_virtual =
640642
entry->msi_attrib.entry_nr >= vec_count;
641643

644+
entry->msi_attrib.can_mask = !pci_msi_ignore_mask &&
645+
!entry->msi_attrib.is_virtual;
646+
642647
entry->msi_attrib.default_irq = dev->irq;
643648
entry->mask_base = base;
644649

645-
if (!entry->msi_attrib.is_virtual) {
650+
if (entry->msi_attrib.can_mask) {
646651
addr = pci_msix_desc_addr(entry);
647652
entry->msix_ctrl = readl(addr + PCI_MSIX_ENTRY_VECTOR_CTRL);
648653
}

drivers/pci/quirks.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5851,3 +5851,9 @@ DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_PERICOM, 0x2303,
58515851
pci_fixup_pericom_acs_store_forward);
58525852
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_PERICOM, 0x2303,
58535853
pci_fixup_pericom_acs_store_forward);
5854+
5855+
static void nvidia_ion_ahci_fixup(struct pci_dev *pdev)
5856+
{
5857+
pdev->dev_flags |= PCI_DEV_FLAGS_HAS_MSI_MASKING;
5858+
}
5859+
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0ab8, nvidia_ion_ahci_fixup);

include/linux/msi.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ struct msi_desc {
148148
u8 is_msix : 1;
149149
u8 multiple : 3;
150150
u8 multi_cap : 3;
151-
u8 maskbit : 1;
151+
u8 can_mask : 1;
152152
u8 is_64 : 1;
153153
u8 is_virtual : 1;
154154
u16 entry_nr;

include/linux/pci.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,8 @@ enum pci_dev_flags {
233233
PCI_DEV_FLAGS_NO_FLR_RESET = (__force pci_dev_flags_t) (1 << 10),
234234
/* Don't use Relaxed Ordering for TLPs directed at this device */
235235
PCI_DEV_FLAGS_NO_RELAXED_ORDERING = (__force pci_dev_flags_t) (1 << 11),
236+
/* Device does honor MSI masking despite saying otherwise */
237+
PCI_DEV_FLAGS_HAS_MSI_MASKING = (__force pci_dev_flags_t) (1 << 12),
236238
};
237239

238240
enum pci_irq_reroute_variant {

kernel/irq/msi.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -529,10 +529,10 @@ static bool msi_check_reservation_mode(struct irq_domain *domain,
529529

530530
/*
531531
* Checking the first MSI descriptor is sufficient. MSIX supports
532-
* masking and MSI does so when the maskbit is set.
532+
* masking and MSI does so when the can_mask attribute is set.
533533
*/
534534
desc = first_msi_entry(dev);
535-
return desc->msi_attrib.is_msix || desc->msi_attrib.maskbit;
535+
return desc->msi_attrib.is_msix || desc->msi_attrib.can_mask;
536536
}
537537

538538
int __msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,

0 commit comments

Comments
 (0)