aboutsummaryrefslogtreecommitdiff
path: root/pkgs/patches-linux-5.15/0011-PCI-mvebu-Propagate-errors-when-updating-PCI_IO_BASE.patch
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/patches-linux-5.15/0011-PCI-mvebu-Propagate-errors-when-updating-PCI_IO_BASE.patch')
-rw-r--r--pkgs/patches-linux-5.15/0011-PCI-mvebu-Propagate-errors-when-updating-PCI_IO_BASE.patch195
1 files changed, 195 insertions, 0 deletions
diff --git a/pkgs/patches-linux-5.15/0011-PCI-mvebu-Propagate-errors-when-updating-PCI_IO_BASE.patch b/pkgs/patches-linux-5.15/0011-PCI-mvebu-Propagate-errors-when-updating-PCI_IO_BASE.patch
new file mode 100644
index 0000000..225965c
--- /dev/null
+++ b/pkgs/patches-linux-5.15/0011-PCI-mvebu-Propagate-errors-when-updating-PCI_IO_BASE.patch
@@ -0,0 +1,195 @@
+From 14d8c749e493bd09b00e5766ba96631794e1a109 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
+Date: Fri, 17 Sep 2021 11:34:50 +0200
+Subject: [PATCH 11/90] PCI: mvebu: Propagate errors when updating PCI_IO_BASE
+ and PCI_MEM_BASE registers
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Properly propagate failure from mvebu_pcie_add_windows() function back to
+the caller mvebu_pci_bridge_emul_base_conf_write() and correctly updates
+PCI_IO_BASE, PCI_MEM_BASE and PCI_IO_BASE_UPPER16 registers on error.
+On error set base value higher than limit value which indicates that
+address range is disabled. When IO is unsupported then let IO registers
+zeroed as required by PCIe base specification.
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Cc: stable@vger.kernel.org
+---
+ drivers/pci/controller/pci-mvebu.c | 82 ++++++++++++++++++++----------
+ 1 file changed, 55 insertions(+), 27 deletions(-)
+
+diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c
+index 0a8b552364aa..32aa78059e96 100644
+--- a/drivers/pci/controller/pci-mvebu.c
++++ b/drivers/pci/controller/pci-mvebu.c
+@@ -329,7 +329,7 @@ static void mvebu_pcie_del_windows(struct mvebu_pcie_port *port,
+ * areas each having a power of two size. We start from the largest
+ * one (i.e highest order bit set in the size).
+ */
+-static void mvebu_pcie_add_windows(struct mvebu_pcie_port *port,
++static int mvebu_pcie_add_windows(struct mvebu_pcie_port *port,
+ unsigned int target, unsigned int attribute,
+ phys_addr_t base, size_t size,
+ phys_addr_t remap)
+@@ -350,7 +350,7 @@ static void mvebu_pcie_add_windows(struct mvebu_pcie_port *port,
+ &base, &end, ret);
+ mvebu_pcie_del_windows(port, base - size_mapped,
+ size_mapped);
+- return;
++ return ret;
+ }
+
+ size -= sz;
+@@ -359,16 +359,20 @@ static void mvebu_pcie_add_windows(struct mvebu_pcie_port *port,
+ if (remap != MVEBU_MBUS_NO_REMAP)
+ remap += sz;
+ }
++
++ return 0;
+ }
+
+-static void mvebu_pcie_set_window(struct mvebu_pcie_port *port,
++static int mvebu_pcie_set_window(struct mvebu_pcie_port *port,
+ unsigned int target, unsigned int attribute,
+ const struct mvebu_pcie_window *desired,
+ struct mvebu_pcie_window *cur)
+ {
++ int ret;
++
+ if (desired->base == cur->base && desired->remap == cur->remap &&
+ desired->size == cur->size)
+- return;
++ return 0;
+
+ if (cur->size != 0) {
+ mvebu_pcie_del_windows(port, cur->base, cur->size);
+@@ -383,30 +387,35 @@ static void mvebu_pcie_set_window(struct mvebu_pcie_port *port,
+ }
+
+ if (desired->size == 0)
+- return;
++ return 0;
++
++ ret = mvebu_pcie_add_windows(port, target, attribute, desired->base,
++ desired->size, desired->remap);
++ if (ret) {
++ cur->size = 0;
++ cur->base = 0;
++ return ret;
++ }
+
+- mvebu_pcie_add_windows(port, target, attribute, desired->base,
+- desired->size, desired->remap);
+ *cur = *desired;
++ return 0;
+ }
+
+-static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
++static int mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
+ {
+ struct mvebu_pcie_window desired = {};
+ struct pci_bridge_emul_conf *conf = &port->bridge.conf;
+
+ /* Are the new iobase/iolimit values invalid? */
+ if (conf->iolimit < conf->iobase ||
+- conf->iolimitupper < conf->iobaseupper) {
+- mvebu_pcie_set_window(port, port->io_target, port->io_attr,
+- &desired, &port->iowin);
+- return;
+- }
++ conf->iolimitupper < conf->iobaseupper)
++ 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;
++ return -EOPNOTSUPP;
+ }
+
+ /*
+@@ -424,21 +433,19 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
+ desired.remap) +
+ 1;
+
+- mvebu_pcie_set_window(port, port->io_target, port->io_attr, &desired,
+- &port->iowin);
++ return mvebu_pcie_set_window(port, port->io_target, port->io_attr, &desired,
++ &port->iowin);
+ }
+
+-static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port)
++static int mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port)
+ {
+ struct mvebu_pcie_window desired = {.remap = MVEBU_MBUS_NO_REMAP};
+ struct pci_bridge_emul_conf *conf = &port->bridge.conf;
+
+ /* Are the new membase/memlimit values invalid? */
+- if (conf->memlimit < conf->membase) {
+- mvebu_pcie_set_window(port, port->mem_target, port->mem_attr,
+- &desired, &port->memwin);
+- return;
+- }
++ if (conf->memlimit < conf->membase)
++ return mvebu_pcie_set_window(port, port->mem_target, port->mem_attr,
++ &desired, &port->memwin);
+
+ /*
+ * We read the PCI-to-PCI bridge emulated registers, and
+@@ -450,8 +457,8 @@ static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port)
+ desired.size = (((conf->memlimit & 0xFFF0) << 16) | 0xFFFFF) -
+ desired.base + 1;
+
+- mvebu_pcie_set_window(port, port->mem_target, port->mem_attr, &desired,
+- &port->memwin);
++ return mvebu_pcie_set_window(port, port->mem_target, port->mem_attr, &desired,
++ &port->memwin);
+ }
+
+ static pci_bridge_emul_read_status_t
+@@ -576,15 +583,36 @@ mvebu_pci_bridge_emul_base_conf_write(struct pci_bridge_emul *bridge,
+ break;
+
+ case PCI_IO_BASE:
+- mvebu_pcie_handle_iobase_change(port);
++ if ((mask & 0xffff) && mvebu_pcie_handle_iobase_change(port)) {
++ /* On error disable IO range */
++ conf->iobase &= ~0xf0;
++ conf->iolimit &= ~0xf0;
++ conf->iobaseupper = cpu_to_le16(0x0000);
++ conf->iolimitupper = cpu_to_le16(0x0000);
++ if (mvebu_has_ioport(port))
++ conf->iobase |= 0xf0;
++ }
+ break;
+
+ case PCI_MEMORY_BASE:
+- mvebu_pcie_handle_membase_change(port);
++ if (mvebu_pcie_handle_membase_change(port)) {
++ /* On error disable mem range */
++ conf->membase = cpu_to_le16(le16_to_cpu(conf->membase) & ~0xfff0);
++ conf->memlimit = cpu_to_le16(le16_to_cpu(conf->memlimit) & ~0xfff0);
++ conf->membase = cpu_to_le16(le16_to_cpu(conf->membase) | 0xfff0);
++ }
+ break;
+
+ case PCI_IO_BASE_UPPER16:
+- mvebu_pcie_handle_iobase_change(port);
++ if (mvebu_pcie_handle_iobase_change(port)) {
++ /* On error disable IO range */
++ conf->iobase &= ~0xf0;
++ conf->iolimit &= ~0xf0;
++ conf->iobaseupper = cpu_to_le16(0x0000);
++ conf->iolimitupper = cpu_to_le16(0x0000);
++ if (mvebu_has_ioport(port))
++ conf->iobase |= 0xf0;
++ }
+ break;
+
+ case PCI_PRIMARY_BUS:
+--
+2.34.1
+