Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@
$id: http://devicetree.org/schemas/interrupt-controller/apple,pcie-msi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Apple PCIe port MSI controller
title: Apple PCIe root port MSI controller

maintainers:
- Thomas Glanzmann <thomas@glanzmann.de>

description: |
The MSI map of one Apple PCIe root port, for a port that the bootloader
trained and that Linux drives as a generic ECAM host. Endpoint MSI writes
to the doorbell are routed by this map to a contiguous range of AIC
interrupts.
The MSI maps of the Apple PCIe root ports that the bootloader trained
and that Linux drives as a generic ECAM host. Endpoint MSI writes to the
doorbell are routed by each port's map to a contiguous range of AIC
interrupts. The ports of a root complex share that range, so one
controller lists every port of the host.

allOf:
- $ref: /schemas/interrupt-controller/msi-controller.yaml#
Expand All @@ -23,8 +24,9 @@ properties:
const: apple,t8142-pcie-msi

reg:
maxItems: 1
description: The port's MSI map registers.
minItems: 1
maxItems: 3
description: The MSI map registers of each root port.

msi-controller: true

Expand Down
38 changes: 28 additions & 10 deletions drivers/pci/controller/pcie-apple-msi.c
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
// SPDX-License-Identifier: GPL-2.0
/*
* MSI controller for one Apple PCIe port whose link the bootloader trained.
* MSI controller for Apple PCIe ports whose links the bootloader trained.
*
* pcie-apple owns the port when Linux brings the link up itself. On T8142
* (J813) the bootloader trains apcie port 0 and Linux drives the root port as
* a generic ECAM host, which has no MSI support. The port still turns writes
* to the MSI doorbell into AIC interrupts through its MSI map; this driver
* programs that map and provides the parent domain, as pcie-apple does.
*
* The map's entries name AIC interrupts from one range that all ports of the
* root complex share, so the ports of one host use a single controller that
* programs each port's map from one allocator.
*/

#include <linux/bitmap.h>
Expand Down Expand Up @@ -120,7 +124,8 @@ static int apple_msi_probe(struct platform_device *pdev)
.ops = &apple_msi_domain_ops,
};
struct apple_msi *msi;
void __iomem *port;
void __iomem **ports;
unsigned int nports;
int ret;
u32 i;

Expand All @@ -129,9 +134,18 @@ static int apple_msi_probe(struct platform_device *pdev)
return -ENOMEM;
mutex_init(&msi->lock);

port = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(port))
return PTR_ERR(port);
for (nports = 0; platform_get_resource(pdev, IORESOURCE_MEM, nports); nports++)
;
if (!nports)
return -EINVAL;
ports = devm_kcalloc(dev, nports, sizeof(*ports), GFP_KERNEL);
if (!ports)
return -ENOMEM;
for (i = 0; i < nports; i++) {
ports[i] = devm_platform_ioremap_resource(pdev, i);
if (IS_ERR(ports[i]))
return PTR_ERR(ports[i]);
}

ret = of_parse_phandle_with_args(dev->of_node, "msi-ranges",
"#interrupt-cells", 0, &args);
Expand All @@ -157,11 +171,15 @@ static int apple_msi_probe(struct platform_device *pdev)
info.size = msi->nvecs;
info.host_data = msi;

/* MSI data N goes to the Nth interrupt of msi-ranges. */
writel(lower_32_bits(DOORBELL_ADDR), port + PORT_MSIADDR);
for (i = 0; i < msi->nvecs; i++)
writel(PORT_MSIMAP_ENABLE | i, port + PORT_MSIMAP + 4 * i);
writel(readl(port + PORT_MSICFG) | PORT_MSICFG_EN, port + PORT_MSICFG);
/* On every port, MSI data N goes to the Nth interrupt of msi-ranges. */
while (nports--) {
void __iomem *port = ports[nports];

writel(lower_32_bits(DOORBELL_ADDR), port + PORT_MSIADDR);
for (i = 0; i < msi->nvecs; i++)
writel(PORT_MSIMAP_ENABLE | i, port + PORT_MSIMAP + 4 * i);
writel(readl(port + PORT_MSICFG) | PORT_MSICFG_EN, port + PORT_MSICFG);
}

if (!msi_create_parent_irq_domain(&info, &apple_msi_parent_ops))
return -ENOMEM;
Expand Down
Loading