mirror of
https://github.com/coolsnowwolf/lede.git
synced 2025-07-05 22:07:06 +08:00

These patches were generated from: https://github.com/raspberrypi/linux/commits/rpi-6.12.y With the following command: git format-patch -N v6.12.27..HEAD (HEAD -> 8d3206ee456a5ecdf9ddbfd8e5e231e4f0cd716e) Exceptions: - (def)configs patches - github workflows patches - applied & reverted patches - readme patches - wireless patches Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
563 lines
16 KiB
Diff
563 lines
16 KiB
Diff
From 59fda55d75884efea5fc33f6bde55cbc62ab7471 Mon Sep 17 00:00:00 2001
|
|
From: Stanimir Varbanov <svarbanov@suse.de>
|
|
Date: Mon, 20 Jan 2025 15:01:11 +0200
|
|
Subject: [PATCH] irqchip: Add Broadcom bcm2712 MSI-X interrupt controller
|
|
|
|
Add an interrupt controller driver for MSI-X Interrupt Peripheral (MIP)
|
|
hardware block found in bcm2712. The interrupt controller is used to
|
|
handle MSI-X interrupts from peripherials behind PCIe endpoints like
|
|
RP1 south bridge found in RPi5.
|
|
|
|
There are two MIPs on bcm2712, the first has 64 consecutive SPIs
|
|
assigned to 64 output vectors, and the second has 17 SPIs, but only
|
|
8 of them are consecutive starting at the 8th output vector.
|
|
|
|
Signed-off-by: Stanimir Varbanov <svarbanov@suse.de>
|
|
---
|
|
drivers/irqchip/Kconfig | 14 +-
|
|
drivers/irqchip/Makefile | 2 +-
|
|
drivers/irqchip/irq-bcm2712-mip.c | 399 ++++++++++++++----------------
|
|
3 files changed, 196 insertions(+), 219 deletions(-)
|
|
|
|
--- a/drivers/irqchip/Kconfig
|
|
+++ b/drivers/irqchip/Kconfig
|
|
@@ -110,12 +110,20 @@ config I8259
|
|
select IRQ_DOMAIN
|
|
|
|
config BCM2712_MIP
|
|
- bool "Broadcom 2712 MSI-X Interrupt Peripheral support"
|
|
+ tristate "Broadcom BCM2712 MSI-X Interrupt Peripheral support"
|
|
+ depends on ARCH_BRCMSTB || COMPILE_TEST
|
|
+ default m if ARCH_BRCMSTB
|
|
depends on ARM_GIC
|
|
select GENERIC_IRQ_CHIP
|
|
- select IRQ_DOMAIN
|
|
+ select IRQ_DOMAIN_HIERARCHY
|
|
+ select GENERIC_MSI_IRQ
|
|
+ select IRQ_MSI_LIB
|
|
help
|
|
- Enable support for the Broadcom BCM2712 MSI-X target peripheral.
|
|
+ Enable support for the Broadcom BCM2712 MSI-X target peripheral
|
|
+ (MIP) needed by brcmstb PCIe to handle MSI-X interrupts on
|
|
+ Raspberry Pi 5.
|
|
+
|
|
+ If unsure say n.
|
|
|
|
config BCM6345_L1_IRQ
|
|
bool
|
|
--- a/drivers/irqchip/Makefile
|
|
+++ b/drivers/irqchip/Makefile
|
|
@@ -62,7 +62,7 @@ obj-$(CONFIG_XTENSA_MX) += irq-xtensa-
|
|
obj-$(CONFIG_XILINX_INTC) += irq-xilinx-intc.o
|
|
obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o
|
|
obj-$(CONFIG_SOC_VF610) += irq-vf610-mscm-ir.o
|
|
-obj-$(CONFIG_BCM2712_MIP) += irq-bcm2712-mip.o
|
|
+obj-$(CONFIG_BCM2712_MIP) += irq-bcm2712-mip.o
|
|
obj-$(CONFIG_BCM6345_L1_IRQ) += irq-bcm6345-l1.o
|
|
obj-$(CONFIG_BCM7038_L1_IRQ) += irq-bcm7038-l1.o
|
|
obj-$(CONFIG_BCM7120_L2_IRQ) += irq-bcm7120-l2.o
|
|
--- a/drivers/irqchip/irq-bcm2712-mip.c
|
|
+++ b/drivers/irqchip/irq-bcm2712-mip.c
|
|
@@ -1,19 +1,20 @@
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
- * Copyright (C) 2021 Raspberry Pi Ltd., All Rights Reserved.
|
|
+ * Copyright (C) 2024 Raspberry Pi Ltd., All Rights Reserved.
|
|
+ * Copyright (c) 2024 SUSE
|
|
*/
|
|
|
|
-#include <linux/pci.h>
|
|
+#include <linux/bitmap.h>
|
|
+#include <linux/irqchip.h>
|
|
+#include <linux/irqdomain.h>
|
|
#include <linux/msi.h>
|
|
-#include <linux/of.h>
|
|
#include <linux/of_address.h>
|
|
-#include <linux/of_irq.h>
|
|
-#include <linux/of_pci.h>
|
|
+#include <linux/of_platform.h>
|
|
|
|
-#include <linux/irqchip.h>
|
|
+#include "irq-msi-lib.h"
|
|
|
|
-#define MIP_INT_RAISED 0x00
|
|
-#define MIP_INT_CLEARED 0x10
|
|
+#define MIP_INT_RAISE 0x00
|
|
+#define MIP_INT_CLEAR 0x10
|
|
#define MIP_INT_CFGL_HOST 0x20
|
|
#define MIP_INT_CFGH_HOST 0x30
|
|
#define MIP_INT_MASKL_HOST 0x40
|
|
@@ -25,57 +26,40 @@
|
|
#define MIP_INT_STATUSL_VPU 0xa0
|
|
#define MIP_INT_STATUSH_VPU 0xb0
|
|
|
|
+/**
|
|
+ * struct mip_priv - MSI-X interrupt controller data
|
|
+ * @lock: Used to protect bitmap alloc/free
|
|
+ * @base: Base address of MMIO area
|
|
+ * @msg_addr: PCIe MSI-X address
|
|
+ * @msi_base: MSI base
|
|
+ * @num_msis: Count of MSIs
|
|
+ * @msi_offset: MSI offset
|
|
+ * @bitmap: A bitmap for hwirqs
|
|
+ * @parent: Parent domain (GIC)
|
|
+ * @dev: A device pointer
|
|
+ */
|
|
struct mip_priv {
|
|
- spinlock_t msi_map_lock;
|
|
- spinlock_t hw_lock;
|
|
- void * __iomem base;
|
|
- phys_addr_t msg_addr;
|
|
- u32 msi_base; /* The SGI number that MSIs start */
|
|
- u32 num_msis; /* The number of SGIs for MSIs */
|
|
- u32 msi_offset; /* Shift the allocated msi up by N */
|
|
- unsigned long *msi_map;
|
|
+ spinlock_t lock;
|
|
+ void __iomem *base;
|
|
+ u64 msg_addr;
|
|
+ u32 msi_base;
|
|
+ u32 num_msis;
|
|
+ u32 msi_offset;
|
|
+ unsigned long *bitmap;
|
|
+ struct irq_domain *parent;
|
|
+ struct device *dev;
|
|
};
|
|
|
|
-static void mip_mask_msi_irq(struct irq_data *d)
|
|
-{
|
|
- pci_msi_mask_irq(d);
|
|
- irq_chip_mask_parent(d);
|
|
-}
|
|
-
|
|
-static void mip_unmask_msi_irq(struct irq_data *d)
|
|
-{
|
|
- pci_msi_unmask_irq(d);
|
|
- irq_chip_unmask_parent(d);
|
|
-}
|
|
-
|
|
static void mip_compose_msi_msg(struct irq_data *d, struct msi_msg *msg)
|
|
{
|
|
- struct mip_priv *priv = irq_data_get_irq_chip_data(d);
|
|
+ struct mip_priv *mip = irq_data_get_irq_chip_data(d);
|
|
|
|
- msg->address_hi = upper_32_bits(priv->msg_addr);
|
|
- msg->address_lo = lower_32_bits(priv->msg_addr);
|
|
+ msg->address_hi = upper_32_bits(mip->msg_addr);
|
|
+ msg->address_lo = lower_32_bits(mip->msg_addr);
|
|
msg->data = d->hwirq;
|
|
}
|
|
|
|
-// The "bus-specific" irq_chip (the MIP doesn't _have_ to be used with PCIe)
|
|
-
|
|
-static struct irq_chip mip_msi_irq_chip = {
|
|
- .name = "MIP-MSI",
|
|
- .irq_unmask = mip_unmask_msi_irq,
|
|
- .irq_mask = mip_mask_msi_irq,
|
|
- .irq_eoi = irq_chip_eoi_parent,
|
|
- .irq_set_affinity = irq_chip_set_affinity_parent,
|
|
-};
|
|
-
|
|
-static struct msi_domain_info mip_msi_domain_info = {
|
|
- .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
|
|
- MSI_FLAG_PCI_MSIX),
|
|
- .chip = &mip_msi_irq_chip,
|
|
-};
|
|
-
|
|
-// The "middle" irq_chip (the hardware control part)
|
|
-
|
|
-static struct irq_chip mip_irq_chip = {
|
|
+static struct irq_chip mip_middle_irq_chip = {
|
|
.name = "MIP",
|
|
.irq_mask = irq_chip_mask_parent,
|
|
.irq_unmask = irq_chip_unmask_parent,
|
|
@@ -85,239 +69,224 @@ static struct irq_chip mip_irq_chip = {
|
|
.irq_compose_msi_msg = mip_compose_msi_msg,
|
|
};
|
|
|
|
+static int mip_alloc_hwirq(struct mip_priv *mip, unsigned int nr_irqs)
|
|
+{
|
|
+ guard(spinlock)(&mip->lock);
|
|
+ return bitmap_find_free_region(mip->bitmap, mip->num_msis, ilog2(nr_irqs));
|
|
+}
|
|
|
|
-// And a domain to connect it to its parent (the GIC)
|
|
+static void mip_free_hwirq(struct mip_priv *mip, unsigned int hwirq,
|
|
+ unsigned int nr_irqs)
|
|
+{
|
|
+ guard(spinlock)(&mip->lock);
|
|
+ bitmap_release_region(mip->bitmap, hwirq, ilog2(nr_irqs));
|
|
+}
|
|
|
|
-static int mip_irq_domain_alloc(struct irq_domain *domain,
|
|
- unsigned int virq, unsigned int nr_irqs,
|
|
- void *args)
|
|
+static int mip_middle_domain_alloc(struct irq_domain *domain, unsigned int virq,
|
|
+ unsigned int nr_irqs, void *arg)
|
|
{
|
|
- struct mip_priv *priv = domain->host_data;
|
|
- struct irq_fwspec fwspec;
|
|
+ struct mip_priv *mip = domain->host_data;
|
|
+ struct irq_fwspec fwspec = {0};
|
|
+ unsigned int hwirq, i;
|
|
struct irq_data *irqd;
|
|
- int hwirq, ret, i;
|
|
-
|
|
- spin_lock(&priv->msi_map_lock);
|
|
+ int irq, ret;
|
|
|
|
- hwirq = bitmap_find_free_region(priv->msi_map, priv->num_msis, ilog2(nr_irqs));
|
|
+ irq = mip_alloc_hwirq(mip, nr_irqs);
|
|
+ if (irq < 0)
|
|
+ return irq;
|
|
|
|
- spin_unlock(&priv->msi_map_lock);
|
|
+ hwirq = irq + mip->msi_offset;
|
|
|
|
- if (hwirq < 0)
|
|
- return -ENOSPC;
|
|
-
|
|
- hwirq += priv->msi_offset;
|
|
fwspec.fwnode = domain->parent->fwnode;
|
|
fwspec.param_count = 3;
|
|
fwspec.param[0] = 0;
|
|
- fwspec.param[1] = hwirq + priv->msi_base;
|
|
+ fwspec.param[1] = hwirq + mip->msi_base;
|
|
fwspec.param[2] = IRQ_TYPE_EDGE_RISING;
|
|
|
|
ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &fwspec);
|
|
if (ret)
|
|
- return ret;
|
|
+ goto err_free_hwirq;
|
|
|
|
for (i = 0; i < nr_irqs; i++) {
|
|
irqd = irq_domain_get_irq_data(domain->parent, virq + i);
|
|
irqd->chip->irq_set_type(irqd, IRQ_TYPE_EDGE_RISING);
|
|
|
|
- irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
|
|
- &mip_irq_chip, priv);
|
|
+ ret = irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
|
|
+ &mip_middle_irq_chip, mip);
|
|
+ if (ret)
|
|
+ goto err_free;
|
|
+
|
|
irqd = irq_get_irq_data(virq + i);
|
|
irqd_set_single_target(irqd);
|
|
irqd_set_affinity_on_activate(irqd);
|
|
}
|
|
|
|
return 0;
|
|
-}
|
|
-
|
|
-static void mip_irq_domain_free(struct irq_domain *domain,
|
|
- unsigned int virq, unsigned int nr_irqs)
|
|
-{
|
|
- struct irq_data *d = irq_domain_get_irq_data(domain, virq);
|
|
- struct mip_priv *priv = irq_data_get_irq_chip_data(d);
|
|
|
|
+err_free:
|
|
irq_domain_free_irqs_parent(domain, virq, nr_irqs);
|
|
- d->hwirq -= priv->msi_offset;
|
|
-
|
|
- spin_lock(&priv->msi_map_lock);
|
|
-
|
|
- bitmap_release_region(priv->msi_map, d->hwirq, ilog2(nr_irqs));
|
|
-
|
|
- spin_unlock(&priv->msi_map_lock);
|
|
+err_free_hwirq:
|
|
+ mip_free_hwirq(mip, irq, nr_irqs);
|
|
+ return ret;
|
|
}
|
|
|
|
-#if 0
|
|
-static int mip_irq_domain_activate(struct irq_domain *domain,
|
|
- struct irq_data *d, bool reserve)
|
|
+static void mip_middle_domain_free(struct irq_domain *domain, unsigned int virq,
|
|
+ unsigned int nr_irqs)
|
|
{
|
|
- struct mip_priv *priv = irq_data_get_irq_chip_data(d);
|
|
- unsigned long flags;
|
|
- unsigned int irq = d->hwirq;
|
|
- void *__iomem reg = priv->base +
|
|
- ((irq < 32) ? MIP_INT_MASKL_HOST : MIP_INT_MASKH_HOST);
|
|
- u32 val;
|
|
-
|
|
- spin_lock_irqsave(&priv->hw_lock, flags);
|
|
- val = readl(reg);
|
|
- val &= ~(1 << (irq % 32)); // Clear the mask
|
|
- writel(val, reg);
|
|
- spin_unlock_irqrestore(&priv->hw_lock, flags);
|
|
- return 0;
|
|
-}
|
|
+ struct irq_data *irqd = irq_domain_get_irq_data(domain, virq);
|
|
+ struct mip_priv *mip;
|
|
+ unsigned int hwirq;
|
|
|
|
-static void mip_irq_domain_deactivate(struct irq_domain *domain,
|
|
- struct irq_data *d)
|
|
-{
|
|
- struct mip_priv *priv = irq_data_get_irq_chip_data(d);
|
|
- unsigned long flags;
|
|
- unsigned int irq = d->hwirq - priv->msi_base;
|
|
- void *__iomem reg = priv->base +
|
|
- ((irq < 32) ? MIP_INT_MASKL_HOST : MIP_INT_MASKH_HOST);
|
|
- u32 val;
|
|
-
|
|
- spin_lock_irqsave(&priv->hw_lock, flags);
|
|
- val = readl(reg);
|
|
- val |= (1 << (irq % 32)); // Mask it out
|
|
- writel(val, reg);
|
|
- spin_unlock_irqrestore(&priv->hw_lock, flags);
|
|
+ if (!irqd)
|
|
+ return;
|
|
+
|
|
+ mip = irq_data_get_irq_chip_data(irqd);
|
|
+ hwirq = irqd_to_hwirq(irqd);
|
|
+ irq_domain_free_irqs_parent(domain, virq, nr_irqs);
|
|
+ mip_free_hwirq(mip, hwirq - mip->msi_offset, nr_irqs);
|
|
}
|
|
-#endif
|
|
|
|
-static const struct irq_domain_ops mip_irq_domain_ops = {
|
|
- .alloc = mip_irq_domain_alloc,
|
|
- .free = mip_irq_domain_free,
|
|
- //.activate = mip_irq_domain_activate,
|
|
- //.deactivate = mip_irq_domain_deactivate,
|
|
+static const struct irq_domain_ops mip_middle_domain_ops = {
|
|
+ .select = msi_lib_irq_domain_select,
|
|
+ .alloc = mip_middle_domain_alloc,
|
|
+ .free = mip_middle_domain_free,
|
|
};
|
|
|
|
-static int mip_init_domains(struct mip_priv *priv,
|
|
- struct device_node *node)
|
|
-{
|
|
- struct irq_domain *middle_domain, *msi_domain, *gic_domain;
|
|
- struct device_node *gic_node;
|
|
-
|
|
- gic_node = of_irq_find_parent(node);
|
|
- if (!gic_node) {
|
|
- pr_err("Failed to find the GIC node\n");
|
|
- return -ENODEV;
|
|
- }
|
|
+#define MIP_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \
|
|
+ MSI_FLAG_USE_DEF_CHIP_OPS | \
|
|
+ MSI_FLAG_PCI_MSI_MASK_PARENT)
|
|
+
|
|
+#define MIP_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \
|
|
+ MSI_FLAG_MULTI_PCI_MSI | \
|
|
+ MSI_FLAG_PCI_MSIX)
|
|
+
|
|
+static const struct msi_parent_ops mip_msi_parent_ops = {
|
|
+ .supported_flags = MIP_MSI_FLAGS_SUPPORTED,
|
|
+ .required_flags = MIP_MSI_FLAGS_REQUIRED,
|
|
+ .bus_select_token = DOMAIN_BUS_GENERIC_MSI,
|
|
+ .bus_select_mask = MATCH_PCI_MSI,
|
|
+ .prefix = "MIP-MSI-",
|
|
+ .init_dev_msi_info = msi_lib_init_dev_msi_info,
|
|
+};
|
|
|
|
- gic_domain = irq_find_host(gic_node);
|
|
- if (!gic_domain) {
|
|
- pr_err("Failed to find the GIC domain\n");
|
|
- return -ENXIO;
|
|
- }
|
|
+static int mip_init_domains(struct mip_priv *mip, struct device_node *np)
|
|
+{
|
|
+ struct irq_domain *middle;
|
|
|
|
- middle_domain = irq_domain_add_hierarchy(gic_domain, 0, 0, NULL,
|
|
- &mip_irq_domain_ops,
|
|
- priv);
|
|
- if (!middle_domain) {
|
|
- pr_err("Failed to create the MIP middle domain\n");
|
|
+ middle = irq_domain_add_hierarchy(mip->parent, 0, mip->num_msis, np,
|
|
+ &mip_middle_domain_ops, mip);
|
|
+ if (!middle)
|
|
return -ENOMEM;
|
|
- }
|
|
|
|
- msi_domain = pci_msi_create_irq_domain(of_node_to_fwnode(node),
|
|
- &mip_msi_domain_info,
|
|
- middle_domain);
|
|
- if (!msi_domain) {
|
|
- pr_err("Failed to create MSI domain\n");
|
|
- irq_domain_remove(middle_domain);
|
|
- return -ENOMEM;
|
|
- }
|
|
+ irq_domain_update_bus_token(middle, DOMAIN_BUS_GENERIC_MSI);
|
|
+ middle->dev = mip->dev;
|
|
+ middle->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT;
|
|
+ middle->msi_parent_ops = &mip_msi_parent_ops;
|
|
+
|
|
+ /*
|
|
+ * All MSI-X unmasked for the host, masked for the VPU, and edge-triggered.
|
|
+ */
|
|
+ writel(0, mip->base + MIP_INT_MASKL_HOST);
|
|
+ writel(0, mip->base + MIP_INT_MASKH_HOST);
|
|
+ writel(~0, mip->base + MIP_INT_MASKL_VPU);
|
|
+ writel(~0, mip->base + MIP_INT_MASKH_VPU);
|
|
+ writel(~0, mip->base + MIP_INT_CFGL_HOST);
|
|
+ writel(~0, mip->base + MIP_INT_CFGH_HOST);
|
|
|
|
return 0;
|
|
}
|
|
|
|
-static int __init mip_of_msi_init(struct device_node *node,
|
|
- struct device_node *parent)
|
|
+static int mip_parse_dt(struct mip_priv *mip, struct device_node *np)
|
|
{
|
|
- struct mip_priv *priv;
|
|
- struct resource res;
|
|
+ struct of_phandle_args args;
|
|
+ u64 size;
|
|
int ret;
|
|
|
|
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
|
- if (!priv)
|
|
- return -ENOMEM;
|
|
+ ret = of_property_read_u32(np, "brcm,msi-offset", &mip->msi_offset);
|
|
+ if (ret)
|
|
+ mip->msi_offset = 0;
|
|
|
|
- spin_lock_init(&priv->msi_map_lock);
|
|
- spin_lock_init(&priv->hw_lock);
|
|
+ ret = of_parse_phandle_with_args(np, "msi-ranges", "#interrupt-cells",
|
|
+ 0, &args);
|
|
+ if (ret)
|
|
+ return ret;
|
|
|
|
- ret = of_address_to_resource(node, 0, &res);
|
|
- if (ret) {
|
|
- pr_err("Failed to allocate resource\n");
|
|
- goto err_priv;
|
|
- }
|
|
+ ret = of_property_read_u32_index(np, "msi-ranges", args.args_count + 1,
|
|
+ &mip->num_msis);
|
|
+ if (ret)
|
|
+ goto err_put;
|
|
|
|
- if (of_property_read_u32(node, "brcm,msi-base-spi", &priv->msi_base)) {
|
|
- pr_err("Unable to parse MSI base\n");
|
|
- ret = -EINVAL;
|
|
- goto err_priv;
|
|
- }
|
|
+ ret = of_property_read_reg(np, 1, &mip->msg_addr, &size);
|
|
+ if (ret)
|
|
+ goto err_put;
|
|
+
|
|
+ mip->msi_base = args.args[1];
|
|
|
|
- if (of_property_read_u32(node, "brcm,msi-num-spis", &priv->num_msis)) {
|
|
- pr_err("Unable to parse MSI numbers\n");
|
|
+ mip->parent = irq_find_host(args.np);
|
|
+ if (!mip->parent)
|
|
ret = -EINVAL;
|
|
- goto err_priv;
|
|
- }
|
|
|
|
- if (of_property_read_u32(node, "brcm,msi-offset", &priv->msi_offset))
|
|
- priv->msi_offset = 0;
|
|
+err_put:
|
|
+ of_node_put(args.np);
|
|
+ return ret;
|
|
+}
|
|
|
|
- if (of_property_read_u64(node, "brcm,msi-pci-addr", &priv->msg_addr)) {
|
|
- pr_err("Unable to parse MSI address\n");
|
|
- ret = -EINVAL;
|
|
+static int __init mip_of_msi_init(struct device_node *node, struct device_node *parent)
|
|
+{
|
|
+ struct platform_device *pdev;
|
|
+ struct mip_priv *mip;
|
|
+ int ret;
|
|
+
|
|
+ pdev = of_find_device_by_node(node);
|
|
+ of_node_put(node);
|
|
+ if (!pdev)
|
|
+ return -EPROBE_DEFER;
|
|
+
|
|
+ mip = kzalloc(sizeof(*mip), GFP_KERNEL);
|
|
+ if (!mip)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ spin_lock_init(&mip->lock);
|
|
+ mip->dev = &pdev->dev;
|
|
+
|
|
+ ret = mip_parse_dt(mip, node);
|
|
+ if (ret)
|
|
goto err_priv;
|
|
- }
|
|
|
|
- priv->base = ioremap(res.start, resource_size(&res));
|
|
- if (!priv->base) {
|
|
- pr_err("Failed to ioremap regs\n");
|
|
- ret = -ENOMEM;
|
|
+ mip->base = of_iomap(node, 0);
|
|
+ if (!mip->base) {
|
|
+ ret = -ENXIO;
|
|
goto err_priv;
|
|
}
|
|
|
|
- priv->msi_map = kcalloc(BITS_TO_LONGS(priv->num_msis),
|
|
- sizeof(*priv->msi_map),
|
|
- GFP_KERNEL);
|
|
- if (!priv->msi_map) {
|
|
+ mip->bitmap = bitmap_zalloc(mip->num_msis, GFP_KERNEL);
|
|
+ if (!mip->bitmap) {
|
|
ret = -ENOMEM;
|
|
goto err_base;
|
|
}
|
|
|
|
- pr_debug("Registering %d msixs, starting at %d\n",
|
|
- priv->num_msis, priv->msi_base);
|
|
-
|
|
- /*
|
|
- * Begin with all MSI-Xs masked in for the host, masked out for the
|
|
- * VPU, and edge-triggered.
|
|
- */
|
|
- writel(0, priv->base + MIP_INT_MASKL_HOST);
|
|
- writel(0, priv->base + MIP_INT_MASKH_HOST);
|
|
- writel(~0, priv->base + MIP_INT_MASKL_VPU);
|
|
- writel(~0, priv->base + MIP_INT_MASKH_VPU);
|
|
- writel(~0, priv->base + MIP_INT_CFGL_HOST);
|
|
- writel(~0, priv->base + MIP_INT_CFGH_HOST);
|
|
-
|
|
- ret = mip_init_domains(priv, node);
|
|
- if (ret) {
|
|
- pr_err("Failed to allocate msi_map\n");
|
|
+ ret = mip_init_domains(mip, node);
|
|
+ if (ret)
|
|
goto err_map;
|
|
- }
|
|
+
|
|
+ dev_dbg(&pdev->dev, "MIP: MSI-X count: %u, base: %u, offset: %u, msg_addr: %llx\n",
|
|
+ mip->num_msis, mip->msi_base, mip->msi_offset, mip->msg_addr);
|
|
|
|
return 0;
|
|
|
|
err_map:
|
|
- kfree(priv->msi_map);
|
|
-
|
|
+ bitmap_free(mip->bitmap);
|
|
err_base:
|
|
- iounmap(priv->base);
|
|
-
|
|
+ iounmap(mip->base);
|
|
err_priv:
|
|
- kfree(priv);
|
|
-
|
|
- pr_err("%s: failed - err %d\n", __func__, ret);
|
|
-
|
|
+ kfree(mip);
|
|
return ret;
|
|
}
|
|
-IRQCHIP_DECLARE(bcm_mip, "brcm,bcm2712-mip-intc", mip_of_msi_init);
|
|
+
|
|
+IRQCHIP_PLATFORM_DRIVER_BEGIN(mip_msi)
|
|
+IRQCHIP_MATCH("brcm,bcm2712-mip", mip_of_msi_init)
|
|
+IRQCHIP_PLATFORM_DRIVER_END(mip_msi)
|
|
+MODULE_DESCRIPTION("Broadcom BCM2712 MSI-X interrupt controller");
|
|
+MODULE_AUTHOR("Phil Elwell <phil@raspberrypi.com>");
|
|
+MODULE_AUTHOR("Stanimir Varbanov <svarbanov@suse.de>");
|
|
+MODULE_LICENSE("GPL");
|