aboutsummaryrefslogtreecommitdiff
path: root/drivers/pci/probe.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/probe.c')
-rw-r--r--drivers/pci/probe.c32
1 files changed, 32 insertions, 0 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 073396c5f888..f64d5756142c 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -178,6 +178,9 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
struct pci_bus_region region, inverted_region;
bool bar_too_big = false, bar_too_high = false, bar_invalid = false;
+ if (dev->non_compliant_bars)
+ return 0;
+
mask = type ? PCI_ROM_ADDRESS_MASK : ~0;
/* No printks while decoding is disabled! */
@@ -1016,6 +1019,8 @@ void set_pcie_port_type(struct pci_dev *pdev)
{
int pos;
u16 reg16;
+ int type;
+ struct pci_dev *parent;
pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
if (!pos)
@@ -1025,6 +1030,22 @@ void set_pcie_port_type(struct pci_dev *pdev)
pdev->pcie_flags_reg = reg16;
pci_read_config_word(pdev, pos + PCI_EXP_DEVCAP, &reg16);
pdev->pcie_mpss = reg16 & PCI_EXP_DEVCAP_PAYLOAD;
+
+ /*
+ * A Root Port is always the upstream end of a Link. No PCIe
+ * component has two Links. Two Links are connected by a Switch
+ * that has a Port on each Link and internal logic to connect the
+ * two Ports.
+ */
+ type = pci_pcie_type(pdev);
+ if (type == PCI_EXP_TYPE_ROOT_PORT)
+ pdev->has_secondary_link = 1;
+ else if (type == PCI_EXP_TYPE_UPSTREAM ||
+ type == PCI_EXP_TYPE_DOWNSTREAM) {
+ parent = pci_upstream_bridge(pdev);
+ if (!parent->has_secondary_link)
+ pdev->has_secondary_link = 1;
+ }
}
void set_pcie_hotplug_bridge(struct pci_dev *pdev)
@@ -1157,6 +1178,7 @@ static void pci_msi_setup_pci_dev(struct pci_dev *dev)
int pci_setup_device(struct pci_dev *dev)
{
u32 class;
+ u16 cmd;
u8 hdr_type;
struct pci_slot *slot;
int pos = 0;
@@ -1206,6 +1228,16 @@ int pci_setup_device(struct pci_dev *dev)
/* device class may be changed after fixup */
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 */
case PCI_HEADER_TYPE_NORMAL: /* standard header */
if (class == PCI_CLASS_BRIDGE_PCI)