Skip to content

Commit f144d14

Browse files
committed
PCI/MSI: Add device flag indicating that 64-bit MSIs don't work
This can be set by quirks/drivers to be used by the architecture code that assigns the MSI addresses. We additionally add verification in the core MSI code that the values assigned by the architecture do satisfy the limitation in order to fail gracefully if they don't (ie. the arch hasn't been updated to deal with that quirk yet). Signed-off-by: Benjamin Herrenschmidt <[email protected]> CC: <[email protected]> Acked-by: Bjorn Helgaas <[email protected]>
1 parent 413cbf4 commit f144d14

File tree

2 files changed

+27
-0
lines changed

2 files changed

+27
-0
lines changed

drivers/pci/msi.c

+26
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,20 @@ static struct msi_desc *msi_setup_entry(struct pci_dev *dev)
590590
return entry;
591591
}
592592

593+
static int msi_verify_entries(struct pci_dev *dev)
594+
{
595+
struct msi_desc *entry;
596+
597+
list_for_each_entry(entry, &dev->msi_list, list) {
598+
if (!dev->no_64bit_msi || !entry->msg.address_hi)
599+
continue;
600+
dev_err(&dev->dev, "Device has broken 64-bit MSI but arch"
601+
" tried to assign one above 4G\n");
602+
return -EIO;
603+
}
604+
return 0;
605+
}
606+
593607
/**
594608
* msi_capability_init - configure device's MSI capability structure
595609
* @dev: pointer to the pci_dev data structure of MSI device function
@@ -627,6 +641,13 @@ static int msi_capability_init(struct pci_dev *dev, int nvec)
627641
return ret;
628642
}
629643

644+
ret = msi_verify_entries(dev);
645+
if (ret) {
646+
msi_mask_irq(entry, mask, ~mask);
647+
free_msi_irqs(dev);
648+
return ret;
649+
}
650+
630651
ret = populate_msi_sysfs(dev);
631652
if (ret) {
632653
msi_mask_irq(entry, mask, ~mask);
@@ -739,6 +760,11 @@ static int msix_capability_init(struct pci_dev *dev,
739760
if (ret)
740761
goto out_avail;
741762

763+
/* Check if all MSI entries honor device restrictions */
764+
ret = msi_verify_entries(dev);
765+
if (ret)
766+
goto out_free;
767+
742768
/*
743769
* Some devices require MSI-X to be enabled before we can touch the
744770
* MSI-X registers. We need to mask all the vectors to prevent

include/linux/pci.h

+1
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@ struct pci_dev {
331331
unsigned int is_added:1;
332332
unsigned int is_busmaster:1; /* device is busmaster */
333333
unsigned int no_msi:1; /* device may not use msi */
334+
unsigned int no_64bit_msi:1; /* device may only use 32-bit MSIs */
334335
unsigned int block_cfg_access:1; /* config space access is blocked */
335336
unsigned int broken_parity_status:1; /* Device generates false positive parity */
336337
unsigned int irq_reroute_variant:2; /* device needs IRQ rerouting variant */

0 commit comments

Comments
 (0)