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

Commit 2462bacd authored by Grant Likely's avatar Grant Likely
Browse files

irq_domain/microblaze: Convert microblaze to use irq_domains



This patch converts Microblaze to use the irq_domain remapper and get
away from hard coding the offset between hwirq number and the linux irq
number space.  This also paves the way for multiple interrupt controllers.

v2: Don't enable SPARSE_IRQ and keep NR_IRQS set to 33

Signed-off-by: default avatarGrant Likely <grant.likely@secretlab.ca>
Signed-off-by: default avatarMichal Simek <monstr@monstr.eu>
Cc: Rob Herring <rob.herring@calxeda.com>
Cc: John Williams <john.williams@petalogix.com>
Cc: John Linn <john.linn@xilinx.com>
parent ff8c3ab8
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@ config MICROBLAZE
	select TRACING_SUPPORT
	select OF
	select OF_EARLY_FLATTREE
	select IRQ_DOMAIN
	select HAVE_GENERIC_HARDIRQS
	select GENERIC_IRQ_PROBE
	select GENERIC_IRQ_SHOW
+0 −16
Original line number Diff line number Diff line
/*
 * Copyright (C) 2006 Atmark Techno, Inc.
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License. See the file "COPYING" in the main directory of this archive
 * for more details.
 */

#ifndef _ASM_MICROBLAZE_HARDIRQ_H
#define _ASM_MICROBLAZE_HARDIRQ_H

/* should be defined in each interrupt controller driver */
extern unsigned int get_irq(struct pt_regs *regs);

#include <asm-generic/hardirq.h>

#endif /* _ASM_MICROBLAZE_HARDIRQ_H */
+3 −39
Original line number Diff line number Diff line
@@ -9,49 +9,13 @@
#ifndef _ASM_MICROBLAZE_IRQ_H
#define _ASM_MICROBLAZE_IRQ_H


/*
 * Linux IRQ# is currently offset by one to map to the hardware
 * irq number. So hardware IRQ0 maps to Linux irq 1.
 */
#define NO_IRQ_OFFSET	1
#define IRQ_OFFSET	NO_IRQ_OFFSET
#define NR_IRQS		(32 + IRQ_OFFSET)
#define NR_IRQS		(32 + 1)
#include <asm-generic/irq.h>

/* This type is the placeholder for a hardware interrupt number. It has to
 * be big enough to enclose whatever representation is used by a given
 * platform.
 */
typedef unsigned long irq_hw_number_t;

extern unsigned int nr_irq;

struct pt_regs;
extern void do_IRQ(struct pt_regs *regs);

/** FIXME - not implement
 * irq_dispose_mapping - Unmap an interrupt
 * @virq: linux virq number of the interrupt to unmap
 */
static inline void irq_dispose_mapping(unsigned int virq)
{
	return;
}

struct irq_domain;

/**
 * irq_create_mapping - Map a hardware interrupt into linux virq space
 * @host: host owning this hardware interrupt or NULL for default host
 * @hwirq: hardware irq number in that host space
 *
 * Only one mapping per hardware interrupt is permitted. Returns a linux
 * virq number.
 * If the sense/trigger is to be specified, set_irq_type() should be called
 * on the number returned from that call.
 */
extern unsigned int irq_create_mapping(struct irq_domain *host,
					irq_hw_number_t hwirq);
/* should be defined in each interrupt controller driver */
extern unsigned int get_irq(void);

#endif /* _ASM_MICROBLAZE_IRQ_H */
+37 −24
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
 */

#include <linux/init.h>
#include <linux/irqdomain.h>
#include <linux/irq.h>
#include <asm/page.h>
#include <linux/io.h>
@@ -25,8 +26,6 @@ static unsigned int intc_baseaddr;
#define INTC_BASE	intc_baseaddr
#endif

unsigned int nr_irq;

/* No one else should require these constants, so define them locally here. */
#define ISR 0x00			/* Interrupt Status Register */
#define IPR 0x04			/* Interrupt Pending Register */
@@ -84,24 +83,45 @@ static struct irq_chip intc_dev = {
	.irq_mask_ack = intc_mask_ack,
};

unsigned int get_irq(struct pt_regs *regs)
static struct irq_domain *root_domain;

unsigned int get_irq(void)
{
	int irq;
	unsigned int hwirq, irq = -1;

	/*
	 * NOTE: This function is the one that needs to be improved in
	 * order to handle multiple interrupt controllers. It currently
	 * is hardcoded to check for interrupts only on the first INTC.
	 */
	irq = in_be32(INTC_BASE + IVR) + NO_IRQ_OFFSET;
	pr_debug("get_irq: %d\n", irq);
	hwirq = in_be32(INTC_BASE + IVR);
	if (hwirq != -1U)
		irq = irq_find_mapping(root_domain, hwirq);

	pr_debug("get_irq: hwirq=%d, irq=%d\n", hwirq, irq);

	return irq;
}

int xintc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
{
	u32 intr_mask = (u32)d->host_data;

	if (intr_mask & (1 << hw)) {
		irq_set_chip_and_handler_name(irq, &intc_dev,
						handle_edge_irq, "edge");
		irq_clear_status_flags(irq, IRQ_LEVEL);
	} else {
		irq_set_chip_and_handler_name(irq, &intc_dev,
						handle_level_irq, "level");
		irq_set_status_flags(irq, IRQ_LEVEL);
	}
	return 0;
}

static const struct irq_domain_ops xintc_irq_domain_ops = {
	.xlate = irq_domain_xlate_onetwocell,
	.map = xintc_map,
};

void __init init_IRQ(void)
{
	u32 i, intr_mask;
	u32 nr_irq, intr_mask;
	struct device_node *intc = NULL;
#ifdef CONFIG_SELFMOD_INTC
	unsigned int intc_baseaddr = 0;
@@ -146,16 +166,9 @@ void __init init_IRQ(void)
	/* Turn on the Master Enable. */
	out_be32(intc_baseaddr + MER, MER_HIE | MER_ME);

	for (i = IRQ_OFFSET; i < (nr_irq + IRQ_OFFSET); ++i) {
		if (intr_mask & (0x00000001 << (i - IRQ_OFFSET))) {
			irq_set_chip_and_handler_name(i, &intc_dev,
				handle_edge_irq, "edge");
			irq_clear_status_flags(i, IRQ_LEVEL);
		} else {
			irq_set_chip_and_handler_name(i, &intc_dev,
				handle_level_irq, "level");
			irq_set_status_flags(i, IRQ_LEVEL);
		}
		irq_get_irq_data(i)->hwirq = i - IRQ_OFFSET;
	}
	/* Yeah, okay, casting the intr_mask to a void* is butt-ugly, but I'm
	 * lazy and Michal can clean it up to something nicer when he tests
	 * and commits this patch.  ~~gcl */
	root_domain = irq_domain_add_linear(intc, nr_irq, &xintc_irq_domain_ops,
							(void *)intr_mask);
}
+4 −20
Original line number Diff line number Diff line
@@ -31,14 +31,13 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
	trace_hardirqs_off();

	irq_enter();
	irq = get_irq(regs);
	irq = get_irq();
next_irq:
	BUG_ON(!irq);
	/* Substract 1 because of get_irq */
	generic_handle_irq(irq + IRQ_OFFSET - NO_IRQ_OFFSET);
	generic_handle_irq(irq);

	irq = get_irq(regs);
	if (irq) {
	irq = get_irq();
	if (irq != -1U) {
		pr_debug("next irq: %d\n", irq);
		++concurrent_irq;
		goto next_irq;
@@ -48,18 +47,3 @@ next_irq:
	set_irq_regs(old_regs);
	trace_hardirqs_on();
}

/* MS: There is no any advance mapping mechanism. We are using simple 32bit
  intc without any cascades or any connection that's why mapping is 1:1 */
unsigned int irq_create_mapping(struct irq_domain *host, irq_hw_number_t hwirq)
{
	return hwirq + IRQ_OFFSET;
}
EXPORT_SYMBOL_GPL(irq_create_mapping);

unsigned int irq_create_of_mapping(struct device_node *controller,
				   const u32 *intspec, unsigned int intsize)
{
	return intspec[0] + IRQ_OFFSET;
}
EXPORT_SYMBOL_GPL(irq_create_of_mapping);