1
0
Files
kernel-49/arch/mips/rt2880/irq.c
Andrey Zolotarev 1f35525b83 MIPS: Ralink: register panic_notifier_list
For handle calls from new watchdog and kernel panic
2021-03-14 01:18:36 +07:00

237 lines
6.1 KiB
C

/**************************************************************************
*
* BRIEF MODULE DESCRIPTION
* Interrupt routines for Ralink RT2880 solution
*
* Copyright 2007 Ralink Inc. (bruce_chang@ralinktech.com.tw)
*
* 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*
*
**************************************************************************
* May 2007 Bruce Chang
* Initial Release
*
* May 2009 Bruce Chang
* support RT3883 PCIe
*
**************************************************************************
*/
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <asm/setup.h>
#include <asm/irq_cpu.h>
#include <asm/rt2880/rt_mmap.h>
static unsigned int fiq_mask;
unsigned int get_c0_compare_int(void)
{
return SURFBOARDINT_MIPS_TIMER;
}
#if IS_ENABLED(CONFIG_HW_PERF_EVENTS) || IS_ENABLED(CONFIG_OPROFILE)
int get_c0_perfcount_int(void)
{
return SURFBOARDINT_PCTRL;
}
EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
#endif
static void mask_ralink_irq(struct irq_data *id)
{
unsigned int irq_mask = BIT(id->hwirq);
if (irq_mask & fiq_mask)
*(volatile u32 *)(RALINK_FIQDIS) = irq_mask;
else
*(volatile u32 *)(RALINK_INTDIS) = irq_mask;
}
static void unmask_ralink_irq(struct irq_data *id)
{
unsigned int irq_mask = BIT(id->hwirq);
if (irq_mask & fiq_mask)
*(volatile u32 *)(RALINK_FIQENA) = irq_mask;
else
*(volatile u32 *)(RALINK_INTENA) = irq_mask;
}
static struct irq_chip ralink_irq_chip = {
.name = "INTC",
.irq_mask = mask_ralink_irq,
.irq_mask_ack = mask_ralink_irq,
.irq_unmask = unmask_ralink_irq,
.irq_disable = mask_ralink_irq,
.irq_enable = unmask_ralink_irq,
};
static int ralink_intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
{
irq_set_chip_and_handler(irq, &ralink_irq_chip, handle_level_irq);
return 0;
}
static const struct irq_domain_ops ralink_intc_domain_ops = {
.xlate = irq_domain_xlate_onecell,
.map = ralink_intc_map,
};
static void ralink_intc_irq_handler(struct irq_desc *desc)
{
struct irq_domain *domain = irq_desc_get_handler_data(desc);
u32 pending;
if (irq_desc_get_irq(desc) == MIPS_INTC_CHAIN_HW1)
pending = *(volatile u32 *)(RALINK_IRQ1STAT);
else
pending = *(volatile u32 *)(RALINK_IRQ0STAT);
if (unlikely(!pending)) {
spurious_interrupt();
return;
}
generic_handle_irq(irq_find_mapping(domain, __ffs(pending)));
}
static void dispatch_mips_line_timer(void)
{
do_IRQ(SURFBOARDINT_MIPS_TIMER);
}
static void dispatch_mips_line_wlan(void)
{
do_IRQ(SURFBOARDINT_WLAN);
}
static void dispatch_mips_line_fe(void)
{
do_IRQ(SURFBOARDINT_FE);
}
static void dispatch_mips_line_pci(void)
{
do_IRQ(SURFBOARDINT_PCIE0);
}
static void dispatch_mips_chain_hw1(void)
{
do_IRQ(MIPS_INTC_CHAIN_HW1);
}
static void dispatch_mips_chain_hw0(void)
{
do_IRQ(MIPS_INTC_CHAIN_HW0);
}
void mtk_disable_irq_all(void)
{
unsigned long flags;
local_irq_save(flags);
*(volatile u32 *)(RALINK_FIQDIS) = ~0u;
*(volatile u32 *)(RALINK_INTDIS) = ~0u;
local_irq_restore(flags);
}
void __init arch_init_irq(void)
{
struct irq_domain *domain;
unsigned int int_type = 0;
mips_cpu_irq_init();
/* disable all interrupts */
*(volatile u32 *)(RALINK_FIQDIS) = ~0u;
*(volatile u32 *)(RALINK_INTDIS) = ~0u;
/* route some INTC interrupts to MIPS HW1 interrupt (high priority) */
#ifdef RALINK_INTCTL_UHST
int_type |= RALINK_INTCTL_UHST;
#endif
#ifdef RALINK_INTCTL_SDXC
int_type |= RALINK_INTCTL_SDXC;
#endif
#ifdef RALINK_INTCTL_CRYPTO
int_type |= RALINK_INTCTL_CRYPTO;
#endif
int_type |= RALINK_INTCTL_DMA;
*(volatile u32 *)(RALINK_INTTYPE) = int_type;
if (cpu_has_vint) {
pr_info("Setting up vectored interrupts\n");
set_vi_handler(SURFBOARDINT_MIPS_TIMER, dispatch_mips_line_timer);
set_vi_handler(SURFBOARDINT_WLAN, dispatch_mips_line_wlan);
set_vi_handler(SURFBOARDINT_FE, dispatch_mips_line_fe);
set_vi_handler(SURFBOARDINT_PCIE0, dispatch_mips_line_pci);
set_vi_handler(MIPS_INTC_CHAIN_HW1, dispatch_mips_chain_hw1);
set_vi_handler(MIPS_INTC_CHAIN_HW0, dispatch_mips_chain_hw0);
}
domain = irq_domain_add_legacy(NULL, INTC_NUM_INTRS, MIPS_INTC_IRQ_BASE, 0, &ralink_intc_domain_ops, NULL);
if (!domain)
panic("Failed to add irqdomain");
irq_set_chained_handler_and_data(MIPS_INTC_CHAIN_HW0, ralink_intc_irq_handler, domain);
irq_set_chained_handler_and_data(MIPS_INTC_CHAIN_HW1, ralink_intc_irq_handler, domain);
/* enable global interrupt bit */
fiq_mask = int_type;
*(volatile u32 *)(RALINK_FIQENA) = BIT(31);
*(volatile u32 *)(RALINK_INTENA) = BIT(31);
}
asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending;
pending = read_c0_status() & read_c0_cause() & ST0_IM;
if (unlikely(!pending)) {
spurious_interrupt();
return;
}
if (pending & CAUSEF_IP7)
do_IRQ(SURFBOARDINT_MIPS_TIMER);
if (pending & CAUSEF_IP5)
do_IRQ(SURFBOARDINT_FE);
if (pending & CAUSEF_IP6)
do_IRQ(SURFBOARDINT_WLAN);
if (pending & CAUSEF_IP4)
do_IRQ(SURFBOARDINT_PCIE0);
if (pending & CAUSEF_IP3)
do_IRQ(MIPS_INTC_CHAIN_HW1);
if (pending & CAUSEF_IP2)
do_IRQ(MIPS_INTC_CHAIN_HW0);
}