summaryrefslogtreecommitdiff
path: root/drivers/pci/controller/pci-mvebu.c
diff options
context:
space:
mode:
authorPali Rohár <pali@kernel.org>2021-11-25 13:45:56 +0100
committerLorenzo Pieralisi <lorenzo.pieralisi@arm.com>2022-01-04 14:58:43 +0000
commite42b85583719adb87ab88dc7bcd41b38011f7d11 (patch)
treeea4fa8ca12294177ba9221785bee835186ddba02 /drivers/pci/controller/pci-mvebu.c
parent319e6046bd5a59e09c1a08fd6f6929df4ae9a1dc (diff)
PCI: mvebu: Fix support for bus mastering and PCI_COMMAND on emulated bridge
According to PCI specifications bits [0:2] of Command Register, this should be by default disabled on reset. So explicitly disable these bits at early beginning of driver initialization. Also remove code which unconditionally enables all 3 bits and let kernel code (via pci_set_master() function) to handle bus mastering of PCI Bridge via emulated PCI_COMMAND on emulated bridge. Adjust existing functions mvebu_pcie_handle_iobase_change() and mvebu_pcie_handle_membase_change() to handle PCI_IO_BASE and PCI_MEM_BASE registers correctly even when bus mastering on emulated bridge is disabled. Link: https://lore.kernel.org/r/20211125124605.25915-7-pali@kernel.org Signed-off-by: Pali Rohár <pali@kernel.org> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Diffstat (limited to 'drivers/pci/controller/pci-mvebu.c')
-rw-r--r--drivers/pci/controller/pci-mvebu.c52
1 files changed, 32 insertions, 20 deletions
diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c
index d9c76780d7cf..c4497bb759dd 100644
--- a/drivers/pci/controller/pci-mvebu.c
+++ b/drivers/pci/controller/pci-mvebu.c
@@ -215,16 +215,14 @@ static void mvebu_pcie_setup_hw(struct mvebu_pcie_port *port)
{
u32 cmd, mask;
- /* Point PCIe unit MBUS decode windows to DRAM space. */
- mvebu_pcie_setup_wins(port);
-
- /* Master + slave enable. */
+ /* Disable Root Bridge I/O space, memory space and bus mastering. */
cmd = mvebu_readl(port, PCIE_CMD_OFF);
- cmd |= PCI_COMMAND_IO;
- cmd |= PCI_COMMAND_MEMORY;
- cmd |= PCI_COMMAND_MASTER;
+ cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
mvebu_writel(port, cmd, PCIE_CMD_OFF);
+ /* Point PCIe unit MBUS decode windows to DRAM space. */
+ mvebu_pcie_setup_wins(port);
+
/* Enable interrupt lines A-D. */
mask = mvebu_readl(port, PCIE_MASK_OFF);
mask |= PCIE_MASK_ENABLE_INTS;
@@ -374,8 +372,7 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
/* Are the new iobase/iolimit values invalid? */
if (conf->iolimit < conf->iobase ||
- conf->iolimitupper < conf->iobaseupper ||
- !(conf->command & PCI_COMMAND_IO)) {
+ conf->iolimitupper < conf->iobaseupper) {
mvebu_pcie_set_window(port, port->io_target, port->io_attr,
&desired, &port->iowin);
return;
@@ -412,8 +409,7 @@ static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port)
struct pci_bridge_emul_conf *conf = &port->bridge.conf;
/* Are the new membase/memlimit values invalid? */
- if (conf->memlimit < conf->membase ||
- !(conf->command & PCI_COMMAND_MEMORY)) {
+ if (conf->memlimit < conf->membase) {
mvebu_pcie_set_window(port, port->mem_target, port->mem_attr,
&desired, &port->memwin);
return;
@@ -434,6 +430,24 @@ static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port)
}
static pci_bridge_emul_read_status_t
+mvebu_pci_bridge_emul_base_conf_read(struct pci_bridge_emul *bridge,
+ int reg, u32 *value)
+{
+ struct mvebu_pcie_port *port = bridge->data;
+
+ switch (reg) {
+ case PCI_COMMAND:
+ *value = mvebu_readl(port, PCIE_CMD_OFF);
+ break;
+
+ default:
+ return PCI_BRIDGE_EMUL_NOT_HANDLED;
+ }
+
+ return PCI_BRIDGE_EMUL_HANDLED;
+}
+
+static pci_bridge_emul_read_status_t
mvebu_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge,
int reg, u32 *value)
{
@@ -487,17 +501,14 @@ mvebu_pci_bridge_emul_base_conf_write(struct pci_bridge_emul *bridge,
switch (reg) {
case PCI_COMMAND:
- {
- if (!mvebu_has_ioport(port))
- conf->command &= ~PCI_COMMAND_IO;
-
- if ((old ^ new) & PCI_COMMAND_IO)
- mvebu_pcie_handle_iobase_change(port);
- if ((old ^ new) & PCI_COMMAND_MEMORY)
- mvebu_pcie_handle_membase_change(port);
+ 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:
/*
@@ -564,6 +575,7 @@ mvebu_pci_bridge_emul_pcie_conf_write(struct pci_bridge_emul *bridge,
}
static struct pci_bridge_emul_ops mvebu_pci_bridge_emul_ops = {
+ .read_base = mvebu_pci_bridge_emul_base_conf_read,
.write_base = mvebu_pci_bridge_emul_base_conf_write,
.read_pcie = mvebu_pci_bridge_emul_pcie_conf_read,
.write_pcie = mvebu_pci_bridge_emul_pcie_conf_write,