PCI: disable MEM decoding while updating 64-bit MEM BARs
[deliverable/linux.git] / drivers / pci / setup-res.c
index eea85dafc7632ce149d432355301ed3157eee195..1a0e60e265ea8bdd12ecbbe3b95153304cb2533c 100644 (file)
@@ -30,6 +30,8 @@
 void pci_update_resource(struct pci_dev *dev, int resno)
 {
        struct pci_bus_region region;
+       bool disable;
+       u16 cmd;
        u32 new, check, mask;
        int reg;
        enum pci_bar_type type;
@@ -67,6 +69,18 @@ void pci_update_resource(struct pci_dev *dev, int resno)
                new |= PCI_ROM_ADDRESS_ENABLE;
        }
 
+       /*
+        * We can't update a 64-bit BAR atomically, so when possible,
+        * disable decoding so that a half-updated BAR won't conflict
+        * with another device.
+        */
+       disable = (res->flags & IORESOURCE_MEM_64) && !dev->mmio_always_on;
+       if (disable) {
+               pci_read_config_word(dev, PCI_COMMAND, &cmd);
+               pci_write_config_word(dev, PCI_COMMAND,
+                                     cmd & ~PCI_COMMAND_MEMORY);
+       }
+
        pci_write_config_dword(dev, reg, new);
        pci_read_config_dword(dev, reg, &check);
 
@@ -84,6 +98,10 @@ void pci_update_resource(struct pci_dev *dev, int resno)
                               "(high %#08x != %#08x)\n", resno, new, check);
                }
        }
+
+       if (disable)
+               pci_write_config_word(dev, PCI_COMMAND, cmd);
+
        res->flags &= ~IORESOURCE_UNSET;
        dev_dbg(&dev->dev, "BAR %d: set to %pR (PCI address [%#llx-%#llx])\n",
                resno, res, (unsigned long long)region.start,
This page took 0.026087 seconds and 5 git commands to generate.