From cde9070d9970eef1f7ec2360586c802a16230ad8 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Fri, 10 May 2024 07:43:50 +0000 Subject: [PATCH] rtl88x2CE_WiFi_linux driver --- kernel/drivers/irqchip/irq-bcm2836.c | 170 +++++++++++++++++++++++++++++++++++++++++++------------- 1 files changed, 131 insertions(+), 39 deletions(-) diff --git a/kernel/drivers/irqchip/irq-bcm2836.c b/kernel/drivers/irqchip/irq-bcm2836.c index dfe4a46..cbc7c74 100644 --- a/kernel/drivers/irqchip/irq-bcm2836.c +++ b/kernel/drivers/irqchip/irq-bcm2836.c @@ -1,17 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Root interrupt controller for the BCM2836 (Raspberry Pi 2). * * Copyright 2015 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/cpu.h> @@ -19,6 +10,7 @@ #include <linux/of_irq.h> #include <linux/irqchip.h> #include <linux/irqdomain.h> +#include <linux/irqchip/chained_irq.h> #include <linux/irqchip/irq-bcm2836.h> #include <asm/exception.h> @@ -98,12 +90,24 @@ .irq_unmask = bcm2836_arm_irqchip_unmask_gpu_irq, }; +static void bcm2836_arm_irqchip_dummy_op(struct irq_data *d) +{ +} + +static struct irq_chip bcm2836_arm_irqchip_dummy = { + .name = "bcm2836-dummy", + .irq_eoi = bcm2836_arm_irqchip_dummy_op, +}; + static int bcm2836_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) { struct irq_chip *chip; switch (hw) { + case LOCAL_IRQ_MAILBOX0: + chip = &bcm2836_arm_irqchip_dummy; + break; case LOCAL_IRQ_CNTPSIRQ: case LOCAL_IRQ_CNTPNSIRQ: case LOCAL_IRQ_CNTHPIRQ: @@ -136,17 +140,7 @@ u32 stat; stat = readl_relaxed(intc.base + LOCAL_IRQ_PENDING0 + 4 * cpu); - if (stat & BIT(LOCAL_IRQ_MAILBOX0)) { -#ifdef CONFIG_SMP - void __iomem *mailbox0 = (intc.base + - LOCAL_MAILBOX0_CLR0 + 16 * cpu); - u32 mbox_val = readl(mailbox0); - u32 ipi = ffs(mbox_val) - 1; - - writel(1 << ipi, mailbox0); - handle_IPI(ipi, regs); -#endif - } else if (stat) { + if (stat) { u32 hwirq = ffs(stat) - 1; handle_domain_irq(intc.domain, hwirq, regs); @@ -154,8 +148,35 @@ } #ifdef CONFIG_SMP -static void bcm2836_arm_irqchip_send_ipi(const struct cpumask *mask, - unsigned int ipi) +static struct irq_domain *ipi_domain; + +static void bcm2836_arm_irqchip_handle_ipi(struct irq_desc *desc) +{ + struct irq_chip *chip = irq_desc_get_chip(desc); + int cpu = smp_processor_id(); + u32 mbox_val; + + chained_irq_enter(chip, desc); + + mbox_val = readl_relaxed(intc.base + LOCAL_MAILBOX0_CLR0 + 16 * cpu); + if (mbox_val) { + int hwirq = ffs(mbox_val) - 1; + generic_handle_irq(irq_find_mapping(ipi_domain, hwirq)); + } + + chained_irq_exit(chip, desc); +} + +static void bcm2836_arm_irqchip_ipi_eoi(struct irq_data *d) +{ + int cpu = smp_processor_id(); + + writel_relaxed(BIT(d->hwirq), + intc.base + LOCAL_MAILBOX0_CLR0 + 16 * cpu); +} + +static void bcm2836_arm_irqchip_ipi_send_mask(struct irq_data *d, + const struct cpumask *mask) { int cpu; void __iomem *mailbox0_base = intc.base + LOCAL_MAILBOX0_SET0; @@ -166,10 +187,46 @@ */ smp_wmb(); - for_each_cpu(cpu, mask) { - writel(1 << ipi, mailbox0_base + 16 * cpu); - } + for_each_cpu(cpu, mask) + writel_relaxed(BIT(d->hwirq), mailbox0_base + 16 * cpu); } + +static struct irq_chip bcm2836_arm_irqchip_ipi = { + .name = "IPI", + .irq_mask = bcm2836_arm_irqchip_dummy_op, + .irq_unmask = bcm2836_arm_irqchip_dummy_op, + .irq_eoi = bcm2836_arm_irqchip_ipi_eoi, + .ipi_send_mask = bcm2836_arm_irqchip_ipi_send_mask, +}; + +static int bcm2836_arm_irqchip_ipi_alloc(struct irq_domain *d, + unsigned int virq, + unsigned int nr_irqs, void *args) +{ + int i; + + for (i = 0; i < nr_irqs; i++) { + irq_set_percpu_devid(virq + i); + irq_domain_set_info(d, virq + i, i, &bcm2836_arm_irqchip_ipi, + d->host_data, + handle_percpu_devid_fasteoi_ipi, + NULL, NULL); + } + + return 0; +} + +static void bcm2836_arm_irqchip_ipi_free(struct irq_domain *d, + unsigned int virq, + unsigned int nr_irqs) +{ + /* Not freeing IPIs */ +} + +static const struct irq_domain_ops ipi_domain_ops = { + .alloc = bcm2836_arm_irqchip_ipi_alloc, + .free = bcm2836_arm_irqchip_ipi_free, +}; static int bcm2836_cpu_starting(unsigned int cpu) { @@ -184,25 +241,58 @@ cpu); return 0; } + +#define BITS_PER_MBOX 32 + +static void __init bcm2836_arm_irqchip_smp_init(void) +{ + struct irq_fwspec ipi_fwspec = { + .fwnode = intc.domain->fwnode, + .param_count = 1, + .param = { + [0] = LOCAL_IRQ_MAILBOX0, + }, + }; + int base_ipi, mux_irq; + + mux_irq = irq_create_fwspec_mapping(&ipi_fwspec); + if (WARN_ON(mux_irq <= 0)) + return; + + ipi_domain = irq_domain_create_linear(intc.domain->fwnode, + BITS_PER_MBOX, &ipi_domain_ops, + NULL); + if (WARN_ON(!ipi_domain)) + return; + + ipi_domain->flags |= IRQ_DOMAIN_FLAG_IPI_SINGLE; + irq_domain_update_bus_token(ipi_domain, DOMAIN_BUS_IPI); + + base_ipi = __irq_domain_alloc_irqs(ipi_domain, -1, BITS_PER_MBOX, + NUMA_NO_NODE, NULL, + false, NULL); + + if (WARN_ON(!base_ipi)) + return; + + set_smp_ipi_range(base_ipi, BITS_PER_MBOX); + + irq_set_chained_handler_and_data(mux_irq, + bcm2836_arm_irqchip_handle_ipi, NULL); + + /* Unmask IPIs to the boot CPU. */ + cpuhp_setup_state(CPUHP_AP_IRQ_BCM2836_STARTING, + "irqchip/bcm2836:starting", bcm2836_cpu_starting, + bcm2836_cpu_dying); +} +#else +#define bcm2836_arm_irqchip_smp_init() do { } while(0) #endif static const struct irq_domain_ops bcm2836_arm_irqchip_intc_ops = { .xlate = irq_domain_xlate_onetwocell, .map = bcm2836_map, }; - -static void -bcm2836_arm_irqchip_smp_init(void) -{ -#ifdef CONFIG_SMP - /* Unmask IPIs to the boot CPU. */ - cpuhp_setup_state(CPUHP_AP_IRQ_BCM2836_STARTING, - "irqchip/bcm2836:starting", bcm2836_cpu_starting, - bcm2836_cpu_dying); - - set_smp_cross_call(bcm2836_arm_irqchip_send_ipi); -#endif -} /* * The LOCAL_IRQ_CNT* timer firings are based off of the external @@ -241,6 +331,8 @@ if (!intc.domain) panic("%pOF: unable to create IRQ domain\n", node); + irq_domain_update_bus_token(intc.domain, DOMAIN_BUS_WIRED); + bcm2836_arm_irqchip_smp_init(); set_handle_irq(bcm2836_arm_irqchip_handle_irq); -- Gitblit v1.6.2