PCI: pci-bridge-emul: Properly mark reserved PCIe bits in PCI config space
authorPali Rohár <pali@kernel.org>
Wed, 24 Nov 2021 15:59:40 +0000 (16:59 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 27 Jan 2022 10:05:13 +0000 (11:05 +0100)
commit 7b067ac63a5730d2fae18399fed7e45f23d36912 upstream.

Some bits in PCI config space are reserved when device is PCIe. Properly
define behavior of PCI registers for PCIe emulated bridge and ensure that
it would not be possible change these reserved bits.

Link: https://lore.kernel.org/r/20211124155944.1290-3-pali@kernel.org
Fixes: 23a5fba4d941 ("PCI: Introduce PCI bridge emulated config space common logic")
Signed-off-by: Pali Rohár <pali@kernel.org>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: stable@vger.kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/pci/pci-bridge-emul.c

index 5de8b8dde2093c35bfe035fade6b230b51bd981e..0cbb4e3ca827c1ae934f3b71fa439f5d6b69677f 100644 (file)
@@ -295,6 +295,27 @@ int pci_bridge_emul_init(struct pci_bridge_emul *bridge,
                        kfree(bridge->pci_regs_behavior);
                        return -ENOMEM;
                }
+               /* These bits are applicable only for PCI and reserved on PCIe */
+               bridge->pci_regs_behavior[PCI_CACHE_LINE_SIZE / 4].ro &=
+                       ~GENMASK(15, 8);
+               bridge->pci_regs_behavior[PCI_COMMAND / 4].ro &=
+                       ~((PCI_COMMAND_SPECIAL | PCI_COMMAND_INVALIDATE |
+                          PCI_COMMAND_VGA_PALETTE | PCI_COMMAND_WAIT |
+                          PCI_COMMAND_FAST_BACK) |
+                         (PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK |
+                          PCI_STATUS_DEVSEL_MASK) << 16);
+               bridge->pci_regs_behavior[PCI_PRIMARY_BUS / 4].ro &=
+                       ~GENMASK(31, 24);
+               bridge->pci_regs_behavior[PCI_IO_BASE / 4].ro &=
+                       ~((PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK |
+                          PCI_STATUS_DEVSEL_MASK) << 16);
+               bridge->pci_regs_behavior[PCI_INTERRUPT_LINE / 4].rw &=
+                       ~((PCI_BRIDGE_CTL_MASTER_ABORT |
+                          BIT(8) | BIT(9) | BIT(11)) << 16);
+               bridge->pci_regs_behavior[PCI_INTERRUPT_LINE / 4].ro &=
+                       ~((PCI_BRIDGE_CTL_FAST_BACK) << 16);
+               bridge->pci_regs_behavior[PCI_INTERRUPT_LINE / 4].w1c &=
+                       ~(BIT(10) << 16);
        }
 
        if (flags & PCI_BRIDGE_EMUL_NO_PREFETCHABLE_BAR) {