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)
committerLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Mon, 6 Dec 2021 12:18:21 +0000 (12:18 +0000)
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
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) {