Commit 591add21 authored by Bjorn Helgaas's avatar Bjorn Helgaas Committed by Greg Kroah-Hartman

PCI: Disable IO/MEM decoding for devices with non-compliant BARs

commit b84106b4 upstream.

The PCI config header (first 64 bytes of each device's config space) is
defined by the PCI spec so generic software can identify the device and
manage its usage of I/O, memory, and IRQ resources.

Some non-spec-compliant devices put registers other than BARs where the
BARs should be.  When the PCI core sizes these "BARs", the reads and writes
it does may have unwanted side effects, and the "BAR" may appear to
describe non-sensical address space.

Add a flag bit to mark non-compliant devices so we don't touch their BARs.
Turn off IO/MEM decoding to prevent the devices from consuming address
space, since we can't read the BARs to find out what that address space
would be.
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Tested-by: default avatarAndi Kleen <ak@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 319f9d43
...@@ -179,6 +179,9 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, ...@@ -179,6 +179,9 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
u16 orig_cmd; u16 orig_cmd;
struct pci_bus_region region, inverted_region; struct pci_bus_region region, inverted_region;
if (dev->non_compliant_bars)
return 0;
mask = type ? PCI_ROM_ADDRESS_MASK : ~0; mask = type ? PCI_ROM_ADDRESS_MASK : ~0;
/* No printks while decoding is disabled! */ /* No printks while decoding is disabled! */
...@@ -1171,6 +1174,7 @@ static void pci_msi_setup_pci_dev(struct pci_dev *dev) ...@@ -1171,6 +1174,7 @@ static void pci_msi_setup_pci_dev(struct pci_dev *dev)
int pci_setup_device(struct pci_dev *dev) int pci_setup_device(struct pci_dev *dev)
{ {
u32 class; u32 class;
u16 cmd;
u8 hdr_type; u8 hdr_type;
int pos = 0; int pos = 0;
struct pci_bus_region region; struct pci_bus_region region;
...@@ -1214,6 +1218,16 @@ int pci_setup_device(struct pci_dev *dev) ...@@ -1214,6 +1218,16 @@ int pci_setup_device(struct pci_dev *dev)
/* device class may be changed after fixup */ /* device class may be changed after fixup */
class = dev->class >> 8; class = dev->class >> 8;
if (dev->non_compliant_bars) {
pci_read_config_word(dev, PCI_COMMAND, &cmd);
if (cmd & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
dev_info(&dev->dev, "device has non-compliant BARs; disabling IO/MEM decoding\n");
cmd &= ~PCI_COMMAND_IO;
cmd &= ~PCI_COMMAND_MEMORY;
pci_write_config_word(dev, PCI_COMMAND, cmd);
}
}
switch (dev->hdr_type) { /* header type */ switch (dev->hdr_type) { /* header type */
case PCI_HEADER_TYPE_NORMAL: /* standard header */ case PCI_HEADER_TYPE_NORMAL: /* standard header */
if (class == PCI_CLASS_BRIDGE_PCI) if (class == PCI_CLASS_BRIDGE_PCI)
......
...@@ -359,6 +359,7 @@ struct pci_dev { ...@@ -359,6 +359,7 @@ struct pci_dev {
unsigned int io_window_1k:1; /* Intel P2P bridge 1K I/O windows */ unsigned int io_window_1k:1; /* Intel P2P bridge 1K I/O windows */
unsigned int irq_managed:1; unsigned int irq_managed:1;
unsigned int has_secondary_link:1; unsigned int has_secondary_link:1;
unsigned int non_compliant_bars:1; /* broken BARs; ignore them */
pci_dev_flags_t dev_flags; pci_dev_flags_t dev_flags;
atomic_t enable_cnt; /* pci_enable_device has been called */ atomic_t enable_cnt; /* pci_enable_device has been called */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment