Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 38541742 authored by Jayachandran C's avatar Jayachandran C Committed by John Crispin
Browse files

MIPS: Netlogic: PIC IRQ handling update for multi-chip



Create struct nlm_pic_irq for interrupts handled by the PIC.
This simplifies IRQ handling for multi-SoC as well as
the single SoC cases. Also split the setup of percpu and PIC
interrupts so that we can configure the PIC interrupts for
every node.

Signed-off-by: default avatarJayachandran C <jchandra@broadcom.com>
Patchwork: http://patchwork.linux-mips.org/patch/4467


Signed-off-by: default avatarJohn Crispin <blogic@openwrt.org>
parent bb1e4bc5
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -53,7 +53,7 @@
struct irq_desc;
struct irq_desc;
void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc);
void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc);
void nlm_smp_resched_ipi_handler(unsigned int irq, struct irq_desc *desc);
void nlm_smp_resched_ipi_handler(unsigned int irq, struct irq_desc *desc);
void nlm_smp_irq_init(void);
void nlm_smp_irq_init(int hwcpuid);
void nlm_boot_secondary_cpus(void);
void nlm_boot_secondary_cpus(void);
int nlm_wakeup_secondary_cpus(void);
int nlm_wakeup_secondary_cpus(void);
void nlm_rmiboot_preboot(void);
void nlm_rmiboot_preboot(void);
+0 −1
Original line number Original line Diff line number Diff line
@@ -382,7 +382,6 @@ nlm_pic_init_irt(uint64_t base, int irt, int irq, int hwt)
}
}


int nlm_irq_to_irt(int irq);
int nlm_irq_to_irt(int irq);
int nlm_irt_to_irq(int irt);


#endif /* __ASSEMBLY__ */
#endif /* __ASSEMBLY__ */
#endif /* _NLM_HAL_PIC_H */
#endif /* _NLM_HAL_PIC_H */
+97 −73
Original line number Original line Diff line number Diff line
@@ -36,7 +36,6 @@
#include <linux/init.h>
#include <linux/init.h>
#include <linux/linkage.h>
#include <linux/linkage.h>
#include <linux/interrupt.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/irq.h>
#include <linux/irq.h>
@@ -62,68 +61,66 @@
#else
#else
#error "Unknown CPU"
#error "Unknown CPU"
#endif
#endif
/*
 * These are the routines that handle all the low level interrupt stuff.
 * Actions handled here are: initialization of the interrupt map, requesting of
 * interrupt lines by handlers, dispatching if interrupts to handlers, probing
 * for interrupt lines
 */


/* Globals */
#ifdef CONFIG_SMP
#define SMP_IRQ_MASK	((1ULL << IRQ_IPI_SMP_FUNCTION) | \
				 (1ULL << IRQ_IPI_SMP_RESCHEDULE))
#else
#define SMP_IRQ_MASK	0
#endif
#define PERCPU_IRQ_MASK	(SMP_IRQ_MASK | (1ull << IRQ_TIMER))


struct nlm_pic_irq {
	void	(*extra_ack)(struct irq_data *);
	struct	nlm_soc_info *node;
	int	picirq;
	int	irt;
	int	flags;
};

static void xlp_pic_enable(struct irq_data *d)
static void xlp_pic_enable(struct irq_data *d)
{
{
	unsigned long flags;
	unsigned long flags;
	struct nlm_soc_info *nodep;
	struct nlm_pic_irq *pd = irq_data_get_irq_handler_data(d);
	int irt;


	nodep = nlm_current_node();
	BUG_ON(!pd);
	irt = nlm_irq_to_irt(d->irq);
	spin_lock_irqsave(&pd->node->piclock, flags);
	if (irt == -1)
	nlm_pic_enable_irt(pd->node->picbase, pd->irt);
		return;
	spin_unlock_irqrestore(&pd->node->piclock, flags);
	spin_lock_irqsave(&nodep->piclock, flags);
	nlm_pic_enable_irt(nodep->picbase, irt);
	spin_unlock_irqrestore(&nodep->piclock, flags);
}
}


static void xlp_pic_disable(struct irq_data *d)
static void xlp_pic_disable(struct irq_data *d)
{
{
	struct nlm_soc_info *nodep;
	struct nlm_pic_irq *pd = irq_data_get_irq_handler_data(d);
	unsigned long flags;
	unsigned long flags;
	int irt;


	nodep = nlm_current_node();
	BUG_ON(!pd);
	irt = nlm_irq_to_irt(d->irq);
	spin_lock_irqsave(&pd->node->piclock, flags);
	if (irt == -1)
	nlm_pic_disable_irt(pd->node->picbase, pd->irt);
		return;
	spin_unlock_irqrestore(&pd->node->piclock, flags);
	spin_lock_irqsave(&nodep->piclock, flags);
	nlm_pic_disable_irt(nodep->picbase, irt);
	spin_unlock_irqrestore(&nodep->piclock, flags);
}
}


static void xlp_pic_mask_ack(struct irq_data *d)
static void xlp_pic_mask_ack(struct irq_data *d)
{
{
	uint64_t mask = 1ull << d->irq;
	struct nlm_pic_irq *pd = irq_data_get_irq_handler_data(d);
	uint64_t mask = 1ull << pd->picirq;


	write_c0_eirr(mask);            /* ack by writing EIRR */
	write_c0_eirr(mask);            /* ack by writing EIRR */
}
}


static void xlp_pic_unmask(struct irq_data *d)
static void xlp_pic_unmask(struct irq_data *d)
{
{
	void *hd = irq_data_get_irq_handler_data(d);
	struct nlm_pic_irq *pd = irq_data_get_irq_handler_data(d);
	struct nlm_soc_info *nodep;
	int irt;


	nodep = nlm_current_node();
	if (!pd)
	irt = nlm_irq_to_irt(d->irq);
	if (irt == -1)
		return;
		return;


	if (hd) {
	if (pd->extra_ack)
		void (*extra_ack)(void *) = hd;
		pd->extra_ack(d);
		extra_ack(d);

	}
	/* Ack is a single write, no need to lock */
	/* Ack is a single write, no need to lock */
	nlm_pic_ack(nodep->picbase, irt);
	nlm_pic_ack(pd->node->picbase, pd->irt);
}
}


static struct irq_chip xlp_pic = {
static struct irq_chip xlp_pic = {
@@ -177,51 +174,84 @@ struct irq_chip nlm_cpu_intr = {
	.irq_eoi	= cpuintr_ack,
	.irq_eoi	= cpuintr_ack,
};
};


void __init init_nlm_common_irqs(void)
static void __init nlm_init_percpu_irqs(void)
{
{
	int i, irq, irt;
	int i;
	uint64_t irqmask;
	struct nlm_soc_info *nodep;


	nodep = nlm_current_node();
	irqmask = (1ULL << IRQ_TIMER);
	for (i = 0; i < PIC_IRT_FIRST_IRQ; i++)
	for (i = 0; i < PIC_IRT_FIRST_IRQ; i++)
		irq_set_chip_and_handler(i, &nlm_cpu_intr, handle_percpu_irq);
		irq_set_chip_and_handler(i, &nlm_cpu_intr, handle_percpu_irq);

	for (i = PIC_IRT_FIRST_IRQ; i <= PIC_IRT_LAST_IRQ ; i++)
		irq_set_chip_and_handler(i, &xlp_pic, handle_level_irq);

#ifdef CONFIG_SMP
#ifdef CONFIG_SMP
	irq_set_chip_and_handler(IRQ_IPI_SMP_FUNCTION, &nlm_cpu_intr,
	irq_set_chip_and_handler(IRQ_IPI_SMP_FUNCTION, &nlm_cpu_intr,
			 nlm_smp_function_ipi_handler);
			 nlm_smp_function_ipi_handler);
	irq_set_chip_and_handler(IRQ_IPI_SMP_RESCHEDULE, &nlm_cpu_intr,
	irq_set_chip_and_handler(IRQ_IPI_SMP_RESCHEDULE, &nlm_cpu_intr,
			 nlm_smp_resched_ipi_handler);
			 nlm_smp_resched_ipi_handler);
	irqmask |=
	    ((1ULL << IRQ_IPI_SMP_FUNCTION) | (1ULL << IRQ_IPI_SMP_RESCHEDULE));
#endif
#endif
}

void nlm_setup_pic_irq(int node, int picirq, int irq, int irt)
{
	struct nlm_pic_irq *pic_data;
	int xirq;

	xirq = nlm_irq_to_xirq(node, irq);
	pic_data = kzalloc(sizeof(*pic_data), GFP_KERNEL);
	BUG_ON(pic_data == NULL);
	pic_data->irt = irt;
	pic_data->picirq = picirq;
	pic_data->node = nlm_get_node(node);
	irq_set_chip_and_handler(xirq, &xlp_pic, handle_level_irq);
	irq_set_handler_data(xirq, pic_data);
}

void nlm_set_pic_extra_ack(int node, int irq, void (*xack)(struct irq_data *))
{
	struct nlm_pic_irq *pic_data;
	int xirq;

	xirq = nlm_irq_to_xirq(node, irq);
	pic_data = irq_get_handler_data(xirq);
	pic_data->extra_ack = xack;
}


	for (irq = PIC_IRT_FIRST_IRQ; irq <= PIC_IRT_LAST_IRQ; irq++) {
static void nlm_init_node_irqs(int node)
		irt = nlm_irq_to_irt(irq);
{
	int i, irt;
	uint64_t irqmask;
	struct nlm_soc_info *nodep;

	pr_info("Init IRQ for node %d\n", node);
	nodep = nlm_get_node(node);
	irqmask = PERCPU_IRQ_MASK;
	for (i = PIC_IRT_FIRST_IRQ; i <= PIC_IRT_LAST_IRQ; i++) {
		irt = nlm_irq_to_irt(i);
		if (irt == -1)
		if (irt == -1)
			continue;
			continue;
		irqmask |= (1ULL << irq);
		nlm_setup_pic_irq(node, i, i, irt);
		nlm_pic_init_irt(nodep->picbase, irt, irq, 0);
		/* set interrupts to first cpu in node */
		nlm_pic_init_irt(nodep->picbase, irt, i,
					node * NLM_CPUS_PER_NODE);
		irqmask |= (1ull << i);
	}
	}

	nodep->irqmask = irqmask;
	nodep->irqmask = irqmask;
}
}


void __init arch_init_irq(void)
void __init arch_init_irq(void)
{
{
	/* Initialize the irq descriptors */
	/* Initialize the irq descriptors */
	init_nlm_common_irqs();
	nlm_init_percpu_irqs();

	nlm_init_node_irqs(0);
	write_c0_eimr(nlm_current_node()->irqmask);
	write_c0_eimr(nlm_current_node()->irqmask);
}
}


void __cpuinit nlm_smp_irq_init(void)
void nlm_smp_irq_init(int hwcpuid)
{
{
	/* set interrupt mask for non-zero cpus */
	int node, cpu;

	node = hwcpuid / NLM_CPUS_PER_NODE;
	cpu  = hwcpuid % NLM_CPUS_PER_NODE;

	if (cpu == 0 && node != 0)
		nlm_init_node_irqs(node);
	write_c0_eimr(nlm_current_node()->irqmask);
	write_c0_eimr(nlm_current_node()->irqmask);
}
}


@@ -232,23 +262,17 @@ asmlinkage void plat_irq_dispatch(void)


	node = nlm_nodeid();
	node = nlm_nodeid();
	eirr = read_c0_eirr() & read_c0_eimr();
	eirr = read_c0_eirr() & read_c0_eimr();
	if (eirr & (1 << IRQ_TIMER)) {

		do_IRQ(IRQ_TIMER);
		return;
	}
#ifdef CONFIG_SMP
	if (eirr & IRQ_IPI_SMP_FUNCTION) {
		do_IRQ(IRQ_IPI_SMP_FUNCTION);
		return;
	}
	if (eirr & IRQ_IPI_SMP_RESCHEDULE) {
		do_IRQ(IRQ_IPI_SMP_RESCHEDULE);
		return;
	}
#endif
	i = __ilog2_u64(eirr);
	i = __ilog2_u64(eirr);
	if (i == -1)
	if (i == -1)
		return;
		return;


	/* per-CPU IRQs don't need translation */
	if (eirr & PERCPU_IRQ_MASK) {
		do_IRQ(i);
		return;
	}

	/* top level irq handling */
	do_IRQ(nlm_irq_to_xirq(node, i));
	do_IRQ(nlm_irq_to_xirq(node, i));
}
}
+5 −2
Original line number Original line Diff line number Diff line
@@ -114,8 +114,11 @@ void nlm_early_init_secondary(int cpu)
 */
 */
static void __cpuinit nlm_init_secondary(void)
static void __cpuinit nlm_init_secondary(void)
{
{
	current_cpu_data.core = hard_smp_processor_id() / NLM_THREADS_PER_CORE;
	int hwtid;
	nlm_smp_irq_init();

	hwtid = hard_smp_processor_id();
	current_cpu_data.core = hwtid / NLM_THREADS_PER_CORE;
	nlm_smp_irq_init(hwtid);
}
}


void nlm_prepare_cpus(unsigned int max_cpus)
void nlm_prepare_cpus(unsigned int max_cpus)
+0 −38
Original line number Original line Diff line number Diff line
@@ -100,44 +100,6 @@ int nlm_irq_to_irt(int irq)
	}
	}
}
}


int nlm_irt_to_irq(int irt)
{
	switch (irt) {
	case PIC_IRT_UART_0_INDEX:
		return PIC_UART_0_IRQ;
	case PIC_IRT_UART_1_INDEX:
		return PIC_UART_1_IRQ;
	case PIC_IRT_PCIE_LINK_0_INDEX:
	       return PIC_PCIE_LINK_0_IRQ;
	case PIC_IRT_PCIE_LINK_1_INDEX:
	       return PIC_PCIE_LINK_1_IRQ;
	case PIC_IRT_PCIE_LINK_2_INDEX:
	       return PIC_PCIE_LINK_2_IRQ;
	case PIC_IRT_PCIE_LINK_3_INDEX:
	       return PIC_PCIE_LINK_3_IRQ;
	case PIC_IRT_EHCI_0_INDEX:
		return PIC_EHCI_0_IRQ;
	case PIC_IRT_EHCI_1_INDEX:
		return PIC_EHCI_1_IRQ;
	case PIC_IRT_OHCI_0_INDEX:
		return PIC_OHCI_0_IRQ;
	case PIC_IRT_OHCI_1_INDEX:
		return PIC_OHCI_1_IRQ;
	case PIC_IRT_OHCI_2_INDEX:
		return PIC_OHCI_2_IRQ;
	case PIC_IRT_OHCI_3_INDEX:
		return PIC_OHCI_3_IRQ;
	case PIC_IRT_MMC_INDEX:
	       return PIC_MMC_IRQ;
	case PIC_IRT_I2C_0_INDEX:
		return PIC_I2C_0_IRQ;
	case PIC_IRT_I2C_1_INDEX:
		return PIC_I2C_1_IRQ;
	default:
		return -1;
	}
}

unsigned int nlm_get_core_frequency(int node, int core)
unsigned int nlm_get_core_frequency(int node, int core)
{
{
	unsigned int pll_divf, pll_divr, dfs_div, ext_div;
	unsigned int pll_divf, pll_divr, dfs_div, ext_div;