PCI: mvebu: Set PCI_BRIDGE_EMUL_NO_IO_FORWARD when IO is unsupported
authorPali Rohár <pali@kernel.org>
Tue, 4 Jan 2022 15:35:25 +0000 (16:35 +0100)
committerLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Thu, 3 Feb 2022 10:54:06 +0000 (10:54 +0000)
This will make PCI bridge to return zeros when accessing IO base and limit
registers, as required by PCIe base specification.

This allows to remove adhoc checks around mvebu_pcie_handle_iobase_change()
function for unsupported IO ranges. PCI_BRIDGE_EMUL_NO_IO_FORWARD ensures
that there will be no non-zeros write to IO registers when IO is not
supported.

Link: https://lore.kernel.org/r/20220104153529.31647-8-pali@kernel.org
Signed-off-by: Pali Rohár <pali@kernel.org>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: Rob Herring <robh@kernel.org>
drivers/pci/controller/pci-mvebu.c

index a7eaa58..806cfcd 100644 (file)
@@ -438,12 +438,6 @@ static int mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
                return mvebu_pcie_set_window(port, port->io_target, port->io_attr,
                                             &desired, &port->iowin);
 
-       if (!mvebu_has_ioport(port)) {
-               dev_WARN(&port->pcie->pdev->dev,
-                        "Attempt to set IO when IO is disabled\n");
-               return -EOPNOTSUPP;
-       }
-
        /*
         * We read the PCI-to-PCI bridge emulated registers, and
         * calculate the base address and size of the address decoding
@@ -599,24 +593,18 @@ mvebu_pci_bridge_emul_base_conf_write(struct pci_bridge_emul *bridge,
 
        switch (reg) {
        case PCI_COMMAND:
-               if (!mvebu_has_ioport(port)) {
-                       conf->command = cpu_to_le16(
-                               le16_to_cpu(conf->command) & ~PCI_COMMAND_IO);
-                       new &= ~PCI_COMMAND_IO;
-               }
-
                mvebu_writel(port, new, PCIE_CMD_OFF);
                break;
 
        case PCI_IO_BASE:
-               if ((mask & 0xffff) && mvebu_pcie_handle_iobase_change(port)) {
+               if ((mask & 0xffff) && mvebu_has_ioport(port) &&
+                   mvebu_pcie_handle_iobase_change(port)) {
                        /* On error disable IO range */
                        conf->iobase &= ~0xf0;
                        conf->iolimit &= ~0xf0;
+                       conf->iobase |= 0xf0;
                        conf->iobaseupper = cpu_to_le16(0x0000);
                        conf->iolimitupper = cpu_to_le16(0x0000);
-                       if (mvebu_has_ioport(port))
-                               conf->iobase |= 0xf0;
                }
                break;
 
@@ -630,14 +618,14 @@ mvebu_pci_bridge_emul_base_conf_write(struct pci_bridge_emul *bridge,
                break;
 
        case PCI_IO_BASE_UPPER16:
-               if (mvebu_pcie_handle_iobase_change(port)) {
+               if (mvebu_has_ioport(port) &&
+                   mvebu_pcie_handle_iobase_change(port)) {
                        /* On error disable IO range */
                        conf->iobase &= ~0xf0;
                        conf->iolimit &= ~0xf0;
+                       conf->iobase |= 0xf0;
                        conf->iobaseupper = cpu_to_le16(0x0000);
                        conf->iolimitupper = cpu_to_le16(0x0000);
-                       if (mvebu_has_ioport(port))
-                               conf->iobase |= 0xf0;
                }
                break;
 
@@ -722,6 +710,7 @@ static const struct pci_bridge_emul_ops mvebu_pci_bridge_emul_ops = {
  */
 static int mvebu_pci_bridge_emul_init(struct mvebu_pcie_port *port)
 {
+       unsigned int bridge_flags = PCI_BRIDGE_EMUL_NO_PREFMEM_FORWARD;
        struct pci_bridge_emul *bridge = &port->bridge;
        u32 pcie_cap = mvebu_readl(port, PCIE_CAP_PCIEXP);
        u8 pcie_cap_ver = ((pcie_cap >> 16) & PCI_EXP_FLAGS_VERS);
@@ -735,6 +724,8 @@ static int mvebu_pci_bridge_emul_init(struct mvebu_pcie_port *port)
                /* We support 32 bits I/O addressing */
                bridge->conf.iobase = PCI_IO_RANGE_TYPE_32;
                bridge->conf.iolimit = PCI_IO_RANGE_TYPE_32;
+       } else {
+               bridge_flags |= PCI_BRIDGE_EMUL_NO_IO_FORWARD;
        }
 
        /*
@@ -747,7 +738,7 @@ static int mvebu_pci_bridge_emul_init(struct mvebu_pcie_port *port)
        bridge->data = port;
        bridge->ops = &mvebu_pci_bridge_emul_ops;
 
-       return pci_bridge_emul_init(bridge, PCI_BRIDGE_EMUL_NO_PREFMEM_FORWARD);
+       return pci_bridge_emul_init(bridge, bridge_flags);
 }
 
 static inline struct mvebu_pcie *sys_to_pcie(struct pci_sys_data *sys)