diff options
author | Álvaro Fernández Rojas <noltari@gmail.com> | 2020-03-31 09:26:30 +0200 |
---|---|---|
committer | Álvaro Fernández Rojas <noltari@gmail.com> | 2020-03-31 13:18:08 +0200 |
commit | 49109cedab88d95596e3a3c04ef9e6d30fb4bcb3 (patch) | |
tree | 0aa96a79b6b08c87edc5954bb6b49a2c711f3626 /target/linux/bcm27xx/patches-5.4/950-0460-PCI-brcmstb-Add-MSI-support.patch | |
parent | 84025110cc39191d5525c718aebd1fb4875e95e3 (diff) | |
download | upstream-49109cedab88d95596e3a3c04ef9e6d30fb4bcb3.tar.gz upstream-49109cedab88d95596e3a3c04ef9e6d30fb4bcb3.tar.bz2 upstream-49109cedab88d95596e3a3c04ef9e6d30fb4bcb3.zip |
bcm27xx: update 5.4 patches from RPi foundation
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
Diffstat (limited to 'target/linux/bcm27xx/patches-5.4/950-0460-PCI-brcmstb-Add-MSI-support.patch')
-rw-r--r-- | target/linux/bcm27xx/patches-5.4/950-0460-PCI-brcmstb-Add-MSI-support.patch | 383 |
1 files changed, 0 insertions, 383 deletions
diff --git a/target/linux/bcm27xx/patches-5.4/950-0460-PCI-brcmstb-Add-MSI-support.patch b/target/linux/bcm27xx/patches-5.4/950-0460-PCI-brcmstb-Add-MSI-support.patch deleted file mode 100644 index a27259bd19..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0460-PCI-brcmstb-Add-MSI-support.patch +++ /dev/null @@ -1,383 +0,0 @@ -From 1a90ecdfae1c0cf1b242276f6f0e3d98b5877f14 Mon Sep 17 00:00:00 2001 -From: Jim Quinlan <james.quinlan@broadcom.com> -Date: Mon, 16 Dec 2019 12:01:10 +0100 -Subject: [PATCH] PCI: brcmstb: Add MSI support - -commit 40ca1bf580ef24df30702032ba5e40dfdcaa200b upstream. - -This adds MSI support to the Broadcom STB PCIe host controller. The MSI -controller is physically located within the PCIe block, however, there -is no reason why the MSI controller could not be moved elsewhere in the -future. MSIX is not supported by the HW. - -Since the internal Brcmstb MSI controller is intertwined with the PCIe -controller, it is not its own platform device but rather part of the -PCIe platform device. - -Signed-off-by: Jim Quinlan <james.quinlan@broadcom.com> -Co-developed-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de> -Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de> -Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> -Reviewed-by: Marc Zyngier <maz@kernel.org> -Reviewed-by: Andrew Murray <andrew.murray@arm.com> ---- - drivers/pci/controller/Kconfig | 1 + - drivers/pci/controller/pcie-brcmstb.c | 262 +++++++++++++++++++++++++- - 2 files changed, 262 insertions(+), 1 deletion(-) - ---- a/drivers/pci/controller/Kconfig -+++ b/drivers/pci/controller/Kconfig -@@ -285,6 +285,7 @@ config PCIE_BRCMSTB - tristate "Broadcom Brcmstb PCIe host controller" - depends on ARCH_BCM2835 || COMPILE_TEST - depends on OF -+ depends on PCI_MSI_IRQ_DOMAIN - help - Say Y here to enable PCIe host controller support for - Broadcom STB based SoCs, like the Raspberry Pi 4. ---- a/drivers/pci/controller/pcie-brcmstb.c -+++ b/drivers/pci/controller/pcie-brcmstb.c -@@ -2,6 +2,7 @@ - /* Copyright (C) 2009 - 2019 Broadcom */ - - #include <linux/bitfield.h> -+#include <linux/bitops.h> - #include <linux/clk.h> - #include <linux/compiler.h> - #include <linux/delay.h> -@@ -9,11 +10,13 @@ - #include <linux/interrupt.h> - #include <linux/io.h> - #include <linux/ioport.h> -+#include <linux/irqchip/chained_irq.h> - #include <linux/irqdomain.h> - #include <linux/kernel.h> - #include <linux/list.h> - #include <linux/log2.h> - #include <linux/module.h> -+#include <linux/msi.h> - #include <linux/of_address.h> - #include <linux/of_irq.h> - #include <linux/of_pci.h> -@@ -67,6 +70,12 @@ - #define PCIE_MISC_RC_BAR3_CONFIG_LO 0x403c - #define PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_MASK 0x1f - -+#define PCIE_MISC_MSI_BAR_CONFIG_LO 0x4044 -+#define PCIE_MISC_MSI_BAR_CONFIG_HI 0x4048 -+ -+#define PCIE_MISC_MSI_DATA_CONFIG 0x404c -+#define PCIE_MISC_MSI_DATA_CONFIG_VAL 0xffe06540 -+ - #define PCIE_MISC_PCIE_CTRL 0x4064 - #define PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK 0x1 - -@@ -114,6 +123,11 @@ - - /* PCIe parameters */ - #define BRCM_NUM_PCIE_OUT_WINS 0x4 -+#define BRCM_INT_PCI_MSI_NR 32 -+ -+/* MSI target adresses */ -+#define BRCM_MSI_TARGET_ADDR_LT_4GB 0x0fffffffcULL -+#define BRCM_MSI_TARGET_ADDR_GT_4GB 0xffffffffcULL - - /* MDIO registers */ - #define MDIO_PORT0 0x0 -@@ -135,6 +149,19 @@ - #define SSC_STATUS_SSC_MASK 0x400 - #define SSC_STATUS_PLL_LOCK_MASK 0x800 - -+struct brcm_msi { -+ struct device *dev; -+ void __iomem *base; -+ struct device_node *np; -+ struct irq_domain *msi_domain; -+ struct irq_domain *inner_domain; -+ struct mutex lock; /* guards the alloc/free operations */ -+ u64 target_addr; -+ int irq; -+ /* used indicates which MSI interrupts have been alloc'd */ -+ unsigned long used; -+}; -+ - /* Internal PCIe Host Controller Information.*/ - struct brcm_pcie { - struct device *dev; -@@ -144,6 +171,8 @@ struct brcm_pcie { - struct device_node *np; - bool ssc; - int gen; -+ u64 msi_target_addr; -+ struct brcm_msi *msi; - }; - - /* -@@ -309,6 +338,215 @@ static void brcm_pcie_set_outbound_win(s - writel(tmp, pcie->base + PCIE_MEM_WIN0_LIMIT_HI(win)); - } - -+static struct irq_chip brcm_msi_irq_chip = { -+ .name = "BRCM STB PCIe MSI", -+ .irq_ack = irq_chip_ack_parent, -+ .irq_mask = pci_msi_mask_irq, -+ .irq_unmask = pci_msi_unmask_irq, -+}; -+ -+static struct msi_domain_info brcm_msi_domain_info = { -+ /* Multi MSI is supported by the controller, but not by this driver */ -+ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS), -+ .chip = &brcm_msi_irq_chip, -+}; -+ -+static void brcm_pcie_msi_isr(struct irq_desc *desc) -+{ -+ struct irq_chip *chip = irq_desc_get_chip(desc); -+ unsigned long status, virq; -+ struct brcm_msi *msi; -+ struct device *dev; -+ u32 bit; -+ -+ chained_irq_enter(chip, desc); -+ msi = irq_desc_get_handler_data(desc); -+ dev = msi->dev; -+ -+ status = readl(msi->base + PCIE_MSI_INTR2_STATUS); -+ for_each_set_bit(bit, &status, BRCM_INT_PCI_MSI_NR) { -+ virq = irq_find_mapping(msi->inner_domain, bit); -+ if (virq) -+ generic_handle_irq(virq); -+ else -+ dev_dbg(dev, "unexpected MSI\n"); -+ } -+ -+ chained_irq_exit(chip, desc); -+} -+ -+static void brcm_msi_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) -+{ -+ struct brcm_msi *msi = irq_data_get_irq_chip_data(data); -+ -+ msg->address_lo = lower_32_bits(msi->target_addr); -+ msg->address_hi = upper_32_bits(msi->target_addr); -+ msg->data = (0xffff & PCIE_MISC_MSI_DATA_CONFIG_VAL) | data->hwirq; -+} -+ -+static int brcm_msi_set_affinity(struct irq_data *irq_data, -+ const struct cpumask *mask, bool force) -+{ -+ return -EINVAL; -+} -+ -+static void brcm_msi_ack_irq(struct irq_data *data) -+{ -+ struct brcm_msi *msi = irq_data_get_irq_chip_data(data); -+ -+ writel(1 << data->hwirq, msi->base + PCIE_MSI_INTR2_CLR); -+} -+ -+ -+static struct irq_chip brcm_msi_bottom_irq_chip = { -+ .name = "BRCM STB MSI", -+ .irq_compose_msi_msg = brcm_msi_compose_msi_msg, -+ .irq_set_affinity = brcm_msi_set_affinity, -+ .irq_ack = brcm_msi_ack_irq, -+}; -+ -+static int brcm_msi_alloc(struct brcm_msi *msi) -+{ -+ int hwirq; -+ -+ mutex_lock(&msi->lock); -+ hwirq = bitmap_find_free_region(&msi->used, BRCM_INT_PCI_MSI_NR, 0); -+ mutex_unlock(&msi->lock); -+ -+ return hwirq; -+} -+ -+static void brcm_msi_free(struct brcm_msi *msi, unsigned long hwirq) -+{ -+ mutex_lock(&msi->lock); -+ bitmap_release_region(&msi->used, hwirq, 0); -+ mutex_unlock(&msi->lock); -+} -+ -+static int brcm_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, -+ unsigned int nr_irqs, void *args) -+{ -+ struct brcm_msi *msi = domain->host_data; -+ int hwirq; -+ -+ hwirq = brcm_msi_alloc(msi); -+ -+ if (hwirq < 0) -+ return hwirq; -+ -+ irq_domain_set_info(domain, virq, (irq_hw_number_t)hwirq, -+ &brcm_msi_bottom_irq_chip, domain->host_data, -+ handle_edge_irq, NULL, NULL); -+ return 0; -+} -+ -+static void brcm_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 brcm_msi *msi = irq_data_get_irq_chip_data(d); -+ -+ brcm_msi_free(msi, d->hwirq); -+} -+ -+static const struct irq_domain_ops msi_domain_ops = { -+ .alloc = brcm_irq_domain_alloc, -+ .free = brcm_irq_domain_free, -+}; -+ -+static int brcm_allocate_domains(struct brcm_msi *msi) -+{ -+ struct fwnode_handle *fwnode = of_node_to_fwnode(msi->np); -+ struct device *dev = msi->dev; -+ -+ msi->inner_domain = irq_domain_add_linear(NULL, BRCM_INT_PCI_MSI_NR, -+ &msi_domain_ops, msi); -+ if (!msi->inner_domain) { -+ dev_err(dev, "failed to create IRQ domain\n"); -+ return -ENOMEM; -+ } -+ -+ msi->msi_domain = pci_msi_create_irq_domain(fwnode, -+ &brcm_msi_domain_info, -+ msi->inner_domain); -+ if (!msi->msi_domain) { -+ dev_err(dev, "failed to create MSI domain\n"); -+ irq_domain_remove(msi->inner_domain); -+ return -ENOMEM; -+ } -+ -+ return 0; -+} -+ -+static void brcm_free_domains(struct brcm_msi *msi) -+{ -+ irq_domain_remove(msi->msi_domain); -+ irq_domain_remove(msi->inner_domain); -+} -+ -+static void brcm_msi_remove(struct brcm_pcie *pcie) -+{ -+ struct brcm_msi *msi = pcie->msi; -+ -+ if (!msi) -+ return; -+ irq_set_chained_handler(msi->irq, NULL); -+ irq_set_handler_data(msi->irq, NULL); -+ brcm_free_domains(msi); -+} -+ -+static void brcm_msi_set_regs(struct brcm_msi *msi) -+{ -+ writel(0xffffffff, msi->base + PCIE_MSI_INTR2_MASK_CLR); -+ -+ /* -+ * The 0 bit of PCIE_MISC_MSI_BAR_CONFIG_LO is repurposed to MSI -+ * enable, which we set to 1. -+ */ -+ writel(lower_32_bits(msi->target_addr) | 0x1, -+ msi->base + PCIE_MISC_MSI_BAR_CONFIG_LO); -+ writel(upper_32_bits(msi->target_addr), -+ msi->base + PCIE_MISC_MSI_BAR_CONFIG_HI); -+ -+ writel(PCIE_MISC_MSI_DATA_CONFIG_VAL, -+ msi->base + PCIE_MISC_MSI_DATA_CONFIG); -+} -+ -+static int brcm_pcie_enable_msi(struct brcm_pcie *pcie) -+{ -+ struct brcm_msi *msi; -+ int irq, ret; -+ struct device *dev = pcie->dev; -+ -+ irq = irq_of_parse_and_map(dev->of_node, 1); -+ if (irq <= 0) { -+ dev_err(dev, "cannot map MSI interrupt\n"); -+ return -ENODEV; -+ } -+ -+ msi = devm_kzalloc(dev, sizeof(struct brcm_msi), GFP_KERNEL); -+ if (!msi) -+ return -ENOMEM; -+ -+ mutex_init(&msi->lock); -+ msi->dev = dev; -+ msi->base = pcie->base; -+ msi->np = pcie->np; -+ msi->target_addr = pcie->msi_target_addr; -+ msi->irq = irq; -+ -+ ret = brcm_allocate_domains(msi); -+ if (ret) -+ return ret; -+ -+ irq_set_chained_handler_and_data(msi->irq, brcm_pcie_msi_isr, msi); -+ -+ brcm_msi_set_regs(msi); -+ pcie->msi = msi; -+ -+ return 0; -+} -+ - /* The controller is capable of serving in both RC and EP roles */ - static bool brcm_pcie_rc_mode(struct brcm_pcie *pcie) - { -@@ -497,6 +735,18 @@ static int brcm_pcie_setup(struct brcm_p - PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK); - writel(tmp, base + PCIE_MISC_MISC_CTRL); - -+ /* -+ * We ideally want the MSI target address to be located in the 32bit -+ * addressable memory area. Some devices might depend on it. This is -+ * possible either when the inbound window is located above the lower -+ * 4GB or when the inbound area is smaller than 4GB (taking into -+ * account the rounding-up we're forced to perform). -+ */ -+ if (rc_bar2_offset >= SZ_4G || (rc_bar2_size + rc_bar2_offset) < SZ_4G) -+ pcie->msi_target_addr = BRCM_MSI_TARGET_ADDR_LT_4GB; -+ else -+ pcie->msi_target_addr = BRCM_MSI_TARGET_ADDR_GT_4GB; -+ - /* disable the PCIe->GISB memory window (RC_BAR1) */ - tmp = readl(base + PCIE_MISC_RC_BAR1_CONFIG_LO); - tmp &= ~PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK; -@@ -646,6 +896,7 @@ static void brcm_pcie_turn_off(struct br - - static void __brcm_pcie_remove(struct brcm_pcie *pcie) - { -+ brcm_msi_remove(pcie); - brcm_pcie_turn_off(pcie); - clk_disable_unprepare(pcie->clk); - clk_put(pcie->clk); -@@ -664,7 +915,7 @@ static int brcm_pcie_remove(struct platf - - static int brcm_pcie_probe(struct platform_device *pdev) - { -- struct device_node *np = pdev->dev.of_node; -+ struct device_node *np = pdev->dev.of_node, *msi_np; - struct pci_host_bridge *bridge; - struct brcm_pcie *pcie; - struct pci_bus *child; -@@ -708,6 +959,15 @@ static int brcm_pcie_probe(struct platfo - if (ret) - goto fail; - -+ msi_np = of_parse_phandle(pcie->np, "msi-parent", 0); -+ if (pci_msi_enabled() && msi_np == pcie->np) { -+ ret = brcm_pcie_enable_msi(pcie); -+ if (ret) { -+ dev_err(pcie->dev, "probe of internal MSI failed"); -+ goto fail; -+ } -+ } -+ - bridge->dev.parent = &pdev->dev; - bridge->busnr = 0; - bridge->ops = &brcm_pcie_ops; |