PCI: disable mmio during bar sizing
authorJacob Pan <jacob.jun.pan@linux.intel.com>
Fri, 16 Jul 2010 17:19:22 +0000 (10:19 -0700)
committerJesse Barnes <jbarnes@virtuousgeek.org>
Fri, 30 Jul 2010 16:29:35 +0000 (09:29 -0700)
It is a known issue that mmio decoding shall be disabled while doing PCI
bar sizing. Host bridge and other devices (PCI PIC) shall be excluded for
certain platforms. This patch mainly comes from Mathew Willcox's
patch in http://kerneltrap.org/mailarchive/linux-kernel/2007/9/13/258969.

A new flag bit "mmio_alway_on" is added to pci_dev with the intention that
devices with their mmio decoding cannot be disabled during BAR sizing shall
have this bit set, preferrablly in their quirks.

Without this patch, Intel Moorestown platform graphics unit will be
corrupted during bar sizing activities.

Signed-off-by: Jacob Pan <jacob.jun.pan@linux.intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
drivers/pci/probe.c
drivers/pci/quirks.c
include/linux/pci.h

index f4adba2d1dd3e6671b08c3a3ccb156a841829dfa..12625d90f8b573785f1a05a0a719fad46aa3155f 100644 (file)
@@ -163,9 +163,16 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
                        struct resource *res, unsigned int pos)
 {
        u32 l, sz, mask;
+       u16 orig_cmd;
 
        mask = type ? PCI_ROM_ADDRESS_MASK : ~0;
 
+       if (!dev->mmio_always_on) {
+               pci_read_config_word(dev, PCI_COMMAND, &orig_cmd);
+               pci_write_config_word(dev, PCI_COMMAND,
+                       orig_cmd & ~(PCI_COMMAND_MEMORY | PCI_COMMAND_IO));
+       }
+
        res->name = pci_name(dev);
 
        pci_read_config_dword(dev, pos, &l);
@@ -173,6 +180,9 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
        pci_read_config_dword(dev, pos, &sz);
        pci_write_config_dword(dev, pos, l);
 
+       if (!dev->mmio_always_on)
+               pci_write_config_word(dev, PCI_COMMAND, orig_cmd);
+
        /*
         * All bits set in sz means the device isn't working properly.
         * If the BAR isn't implemented, all bits must be 0.  If it's a
index 3a81d9d44019ef77b5509a2f5d79b5078272693d..202efa6f57c4bff21649d257f2a482ea4b47f24d 100644 (file)
@@ -91,6 +91,19 @@ static void __devinit quirk_resource_alignment(struct pci_dev *dev)
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_resource_alignment);
 
+/*
+ * Decoding should be disabled for a PCI device during BAR sizing to avoid
+ * conflict. But doing so may cause problems on host bridge and perhaps other
+ * key system devices. For devices that need to have mmio decoding always-on,
+ * we need to set the dev->mmio_always_on bit.
+ */
+static void __devinit quirk_mmio_always_on(struct pci_dev *dev)
+{
+       if ((dev->class >> 8) == PCI_CLASS_BRIDGE_HOST)
+               dev->mmio_always_on = 1;
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, quirk_mmio_always_on);
+
 /* The Mellanox Tavor device gives false positive parity errors
  * Mark this device with a broken_parity_status, to allow
  * PCI scanning code to "skip" this now blacklisted device.
index f26fda76b87fc66816f2fa286e97d760c545f165..b1d17956a1536ff9f1e913cc6f33410f2e54cfa8 100644 (file)
@@ -270,6 +270,8 @@ struct pci_dev {
        unsigned int    d1_support:1;   /* Low power state D1 is supported */
        unsigned int    d2_support:1;   /* Low power state D2 is supported */
        unsigned int    no_d1d2:1;      /* Only allow D0 and D3 */
+       unsigned int    mmio_always_on:1;       /* disallow turning off io/mem
+                                                  decoding during bar sizing */
        unsigned int    wakeup_prepared:1;
        unsigned int    d3_delay;       /* D3->D0 transition time in ms */