[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20210506153153.30454-36-pali@kernel.org>
Date: Thu, 6 May 2021 17:31:46 +0200
From: Pali Rohár <pali@...nel.org>
To: Lorenzo Pieralisi <lorenzo.pieralisi@....com>,
Thomas Petazzoni <thomas.petazzoni@...tlin.com>,
Rob Herring <robh@...nel.org>,
Bjorn Helgaas <bhelgaas@...gle.com>
Cc: Russell King <rmk+kernel@...linux.org.uk>,
Marek Behún <kabel@...nel.org>,
Remi Pommarel <repk@...plefau.lt>, Xogium <contact@...ium.me>,
Tomasz Maciej Nowak <tmn505@...il.com>,
Marc Zyngier <maz@...nel.org>, linux-pci@...r.kernel.org,
linux-arm-kernel@...ts.infradead.org, linux-kernel@...r.kernel.org
Subject: [PATCH 35/42] PCI: aardvark: Add support for PCI_BRIDGE_CTL_BUS_RESET on emulated bridge
PCI aardvark hardware supports PCIe Hot Reset via PCIE_CORE_CTRL1_REG
register. Use it for implementing PCI_BRIDGE_CTL_BUS_RESET bit of
PCI_BRIDGE_CONTROL register on emulated bridge.
With this change the function pci_reset_secondary_bus() starts working and
can reset connected PCIe card. Also custom userspace script [1] which uses
setpci can trigger PCIe Hot Reset and reset the card manually.
[1] - https://alexforencich.com/wiki/en/pcie/hot-reset-linux
Signed-off-by: Pali Rohár <pali@...nel.org>
Reviewed-by: Marek Behún <kabel@...nel.org>
Fixes: 8a3ebd8de328 ("PCI: aardvark: Implement emulated root PCI bridge config space")
---
drivers/pci/controller/pci-aardvark.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c
index 13bbc0b5134d..d8fb43604154 100644
--- a/drivers/pci/controller/pci-aardvark.c
+++ b/drivers/pci/controller/pci-aardvark.c
@@ -558,6 +558,22 @@ advk_pci_bridge_emul_base_conf_read(struct pci_bridge_emul *bridge,
*value = advk_readl(pcie, PCIE_CORE_CMD_STATUS_REG);
return PCI_BRIDGE_EMUL_HANDLED;
+ case PCI_INTERRUPT_LINE: {
+ /*
+ * From the whole 32bit register we support propagating to HW
+ * only one bit: PCI_BRIDGE_CTL_BUS_RESET. Other bits are
+ * retrieved only from emulated config space buffer.
+ */
+ __le32 *cfgspace = (__le32 *)&bridge->conf;
+ u32 val = le32_to_cpu(cfgspace[PCI_INTERRUPT_LINE / 4]);
+ if (advk_readl(pcie, PCIE_CORE_CTRL1_REG) & HOT_RESET_GEN)
+ val |= PCI_BRIDGE_CTL_BUS_RESET << 16;
+ else
+ val &= ~(PCI_BRIDGE_CTL_BUS_RESET << 16);
+ *value = val;
+ return PCI_BRIDGE_EMUL_HANDLED;
+ }
+
default:
return PCI_BRIDGE_EMUL_NOT_HANDLED;
}
@@ -574,6 +590,17 @@ advk_pci_bridge_emul_base_conf_write(struct pci_bridge_emul *bridge,
advk_writel(pcie, new, PCIE_CORE_CMD_STATUS_REG);
break;
+ case PCI_INTERRUPT_LINE:
+ if (mask & (PCI_BRIDGE_CTL_BUS_RESET << 16)) {
+ u32 val = advk_readl(pcie, PCIE_CORE_CTRL1_REG);
+ if (new & (PCI_BRIDGE_CTL_BUS_RESET << 16))
+ val |= HOT_RESET_GEN;
+ else
+ val &= ~HOT_RESET_GEN;
+ advk_writel(pcie, val, PCIE_CORE_CTRL1_REG);
+ }
+ break;
+
default:
break;
}
--
2.20.1
Powered by blists - more mailing lists