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

Commit b9e5b4e6 authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Paul Mackerras
Browse files

[POWERPC] Use the genirq framework



This adapts the generic powerpc interrupt handling code, and all of
the platforms except for the embedded 6xx machines, to use the new
genirq framework.

Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent 5a43a066
Loading
Loading
Loading
Loading
+12 −18
Original line number Diff line number Diff line
@@ -62,28 +62,27 @@
#endif

int __irq_offset_value;
#ifdef CONFIG_PPC32
EXPORT_SYMBOL(__irq_offset_value);
#endif

static int ppc_spurious_interrupts;

#ifdef CONFIG_PPC32
#define NR_MASK_WORDS	((NR_IRQS + 31) / 32)
EXPORT_SYMBOL(__irq_offset_value);
atomic_t ppc_n_lost_interrupts;

#ifndef CONFIG_PPC_MERGE
#define NR_MASK_WORDS	((NR_IRQS + 31) / 32)
unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
atomic_t ppc_n_lost_interrupts;
#endif

#ifdef CONFIG_TAU_INT
extern int tau_initialized;
extern int tau_interrupts(int);
#endif
#endif /* CONFIG_PPC32 */

#if defined(CONFIG_SMP) && !defined(CONFIG_PPC_MERGE)
extern atomic_t ipi_recv;
extern atomic_t ipi_sent;
#endif
#endif /* CONFIG_PPC32 */

#ifdef CONFIG_PPC64
EXPORT_SYMBOL(irq_desc);
@@ -219,15 +218,19 @@ void do_IRQ(struct pt_regs *regs)
		curtp = current_thread_info();
		irqtp = hardirq_ctx[smp_processor_id()];
		if (curtp != irqtp) {
			struct irq_desc *desc = irq_desc + irq;
			void *handler = desc->handle_irq;
			if (handler == NULL)
				handler = &__do_IRQ;
			irqtp->task = curtp->task;
			irqtp->flags = 0;
			call___do_IRQ(irq, regs, irqtp);
			call_handle_irq(irq, desc, regs, irqtp, handler);
			irqtp->task = NULL;
			if (irqtp->flags)
				set_bits(irqtp->flags, &curtp->flags);
		} else
#endif
			__do_IRQ(irq, regs);
			generic_handle_irq(irq, regs);
	} else if (irq != -2)
		/* That's not SMP safe ... but who cares ? */
		ppc_spurious_interrupts++;
@@ -245,15 +248,6 @@ void do_IRQ(struct pt_regs *regs)

void __init init_IRQ(void)
{
#ifdef CONFIG_PPC64
	static int once = 0;

	if (once)
		return;

	once++;

#endif
	ppc_md.init_IRQ();
#ifdef CONFIG_PPC64
	irq_ctx_init();
+6 −4
Original line number Diff line number Diff line
@@ -51,12 +51,14 @@ _GLOBAL(call_do_softirq)
	mtlr	r0
	blr

_GLOBAL(call___do_IRQ)
_GLOBAL(call_handle_irq)
	ld	r8,0(r7)
	mflr	r0
	std	r0,16(r1)
	stdu	r1,THREAD_SIZE-112(r5)
	mr	r1,r5
	bl	.__do_IRQ
	mtctr	r8
	stdu	r1,THREAD_SIZE-112(r6)
	mr	r1,r6
	bctrl
	ld	r1,0(r1)
	ld	r0,16(r1)
	mtlr	r0
+56 −55
Original line number Diff line number Diff line
@@ -37,64 +37,51 @@
struct iic {
	struct cbe_iic_thread_regs __iomem *regs;
	u8 target_id;
	u8 eoi_stack[16];
	int eoi_ptr;
};

static DEFINE_PER_CPU(struct iic, iic);

void iic_local_enable(void)
static void iic_mask(unsigned int irq)
{
	struct iic *iic = &__get_cpu_var(iic);
	u64 tmp;

	/*
	 * There seems to be a bug that is present in DD2.x CPUs
	 * and still only partially fixed in DD3.1.
	 * This bug causes a value written to the priority register
	 * not to make it there, resulting in a system hang unless we
	 * write it again.
	 * Masking with 0xf0 is done because the Cell BE does not
	 * implement the lower four bits of the interrupt priority,
	 * they always read back as zeroes, although future CPUs
	 * might implement different bits.
	 */
	do {
		out_be64(&iic->regs->prio, 0xff);
		tmp = in_be64(&iic->regs->prio);
	} while ((tmp & 0xf0) != 0xf0);
}

void iic_local_disable(void)
{
	out_be64(&__get_cpu_var(iic).regs->prio, 0x0);
}

static unsigned int iic_startup(unsigned int irq)
{
	return 0;
}

static void iic_enable(unsigned int irq)
{
	iic_local_enable();
}

static void iic_disable(unsigned int irq)
static void iic_unmask(unsigned int irq)
{
}

static void iic_end(unsigned int irq)
static void iic_eoi(unsigned int irq)
{
	iic_local_enable();
	struct iic *iic = &__get_cpu_var(iic);
	out_be64(&iic->regs->prio, iic->eoi_stack[--iic->eoi_ptr]);
	BUG_ON(iic->eoi_ptr < 0);
}

static struct hw_interrupt_type iic_pic = {
static struct irq_chip iic_chip = {
	.typename = " CELL-IIC ",
	.startup = iic_startup,
	.enable = iic_enable,
	.disable = iic_disable,
	.end = iic_end,
	.mask = iic_mask,
	.unmask = iic_unmask,
	.eoi = iic_eoi,
};

/* XXX All of this has to be reworked completely. We need to assign a real
 * interrupt numbers to the external interrupts and remove all the hard coded
 * interrupt maps (rely on the device-tree whenever possible).
 *
 * Basically, my scheme is to define the "pendings" bits to be the HW interrupt
 * number (ignoring the data and flags here). That means we can sort-of split
 * external sources based on priority, and we can use request_irq() on pretty
 * much anything.
 *
 * For spider or axon, they have their own interrupt space. spider will just have
 * local "hardward" interrupts 0...xx * node stride. The node stride is not
 * necessary (separate interrupt chips will have separate HW number space), but
 * will allow to be compatible with existing device-trees.
 *
 * All of thise little world will get a standard remapping scheme to map those HW
 * numbers into the linux flat irq number space.
*/
static int iic_external_get_irq(struct cbe_iic_pending_bits pending)
{
	int irq;
@@ -118,9 +105,10 @@ static int iic_external_get_irq(struct cbe_iic_pending_bits pending)
		 */
		if (pending.class != 2)
			break;
		irq = IIC_EXT_OFFSET
			+ spider_get_irq(node)
			+ node * IIC_NODE_STRIDE;
		/* TODO: We might want to silently ignore cascade interrupts
		 * when no cascade handler exist yet
		 */
		irq = IIC_EXT_CASCADE + node * IIC_NODE_STRIDE;
		break;
	case 0x01 ... 0x04:
	case 0x07 ... 0x0a:
@@ -152,6 +140,8 @@ int iic_get_irq(struct pt_regs *regs)
	iic = &__get_cpu_var(iic);
	*(unsigned long *) &pending = 
		in_be64((unsigned long __iomem *) &iic->regs->pending_destr);
	iic->eoi_stack[++iic->eoi_ptr] = pending.prio;
	BUG_ON(iic->eoi_ptr > 15);

	irq = -1;
	if (pending.flags & CBE_IIC_IRQ_VALID) {
@@ -172,7 +162,7 @@ int iic_get_irq(struct pt_regs *regs)

/* hardcoded part to be compatible with older firmware */

static int setup_iic_hardcoded(void)
static int __init setup_iic_hardcoded(void)
{
	struct device_node *np;
	int nodeid, cpu;
@@ -207,12 +197,13 @@ static int setup_iic_hardcoded(void)
		printk(KERN_INFO "IIC for CPU %d at %lx\n", cpu, regs);
		iic->regs = ioremap(regs, sizeof(struct cbe_iic_thread_regs));
		iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe);
		iic->eoi_stack[0] = 0xff;
	}

	return 0;
}

static int setup_iic(void)
static int __init setup_iic(void)
{
	struct device_node *dn;
	unsigned long *regs;
@@ -248,11 +239,14 @@ static int setup_iic(void)
 		iic = &per_cpu(iic, np[0]);
 		iic->regs = ioremap(regs[0], sizeof(struct cbe_iic_thread_regs));
		iic->target_id = ((np[0] & 2) << 3) + ((np[0] & 1) ? 0xf : 0xe);
		iic->eoi_stack[0] = 0xff;
 		printk("IIC for CPU %d at %lx mapped to %p\n", np[0], regs[0], iic->regs);

 		iic = &per_cpu(iic, np[1]);
 		iic->regs = ioremap(regs[2], sizeof(struct cbe_iic_thread_regs));
		iic->target_id = ((np[1] & 2) << 3) + ((np[1] & 1) ? 0xf : 0xe);
		iic->eoi_stack[0] = 0xff;

 		printk("IIC for CPU %d at %lx mapped to %p\n", np[1], regs[2], iic->regs);

		found++;
@@ -304,10 +298,10 @@ static void iic_request_ipi(int ipi, const char *name)
	int irq;

	irq = iic_ipi_to_irq(ipi);

	/* IPIs are marked IRQF_DISABLED as they must run with irqs
	 * disabled */
	get_irq_desc(irq)->chip = &iic_pic;
	get_irq_desc(irq)->status |= IRQ_PER_CPU;
 	set_irq_chip_and_handler(irq, &iic_chip, handle_percpu_irq);
	request_irq(irq, iic_ipi_action, IRQF_DISABLED, name, NULL);
}

@@ -321,20 +315,26 @@ void iic_request_IPIs(void)
}
#endif /* CONFIG_SMP */

static void iic_setup_spe_handlers(void)
static void __init iic_setup_builtin_handlers(void)
{
	int be, isrc;

	/* Assume two threads per BE are present */
	/* XXX FIXME: Assume two threads per BE are present */
	for (be=0; be < num_present_cpus() / 2; be++) {
		int irq;

		/* setup SPE chip and handlers */
		for (isrc = 0; isrc < IIC_CLASS_STRIDE * 3; isrc++) {
			int irq = IIC_NODE_STRIDE * be + IIC_SPE_OFFSET + isrc;
			get_irq_desc(irq)->chip = &iic_pic;
			irq = IIC_NODE_STRIDE * be + IIC_SPE_OFFSET + isrc;
			set_irq_chip_and_handler(irq, &iic_chip, handle_fasteoi_irq);
		}
		/* setup cascade chip */
		irq = IIC_EXT_CASCADE + be * IIC_NODE_STRIDE;
		set_irq_chip_and_handler(irq, &iic_chip, handle_fasteoi_irq);
	}
}

void iic_init_IRQ(void)
void __init iic_init_IRQ(void)
{
	int cpu, irq_offset;
	struct iic *iic;
@@ -348,5 +348,6 @@ void iic_init_IRQ(void)
		if (iic->regs)
			out_be64(&iic->regs->prio, 0xff);
	}
	iic_setup_spe_handlers();
	iic_setup_builtin_handlers();

}
+1 −3
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@

enum {
	IIC_EXT_OFFSET   = 0x00, /* Start of south bridge IRQs */
	IIC_EXT_CASCADE  = 0x20, /* There is no interrupt 32 on spider */
	IIC_NUM_EXT      = 0x40, /* Number of south bridge IRQs */
	IIC_SPE_OFFSET   = 0x40, /* Start of SPE interrupts */
	IIC_CLASS_STRIDE = 0x10, /* SPE IRQs per class    */
@@ -51,13 +52,10 @@ extern int iic_get_irq(struct pt_regs *regs);
extern void iic_cause_IPI(int cpu, int mesg);
extern void iic_request_IPIs(void);
extern void iic_setup_cpu(void);
extern void iic_local_enable(void);
extern void iic_local_disable(void);

extern u8 iic_get_target_id(int cpu);

extern void spider_init_IRQ(void);
extern int spider_get_irq(int node);

#endif
#endif /* ASM_CELL_PIC_H */
+9 −3
Original line number Diff line number Diff line
@@ -80,10 +80,14 @@ static void cell_progress(char *s, unsigned short hex)
	printk("*** %04x : %s\n", hex, s ? s : "");
}

static void __init cell_init_irq(void)
{
	iic_init_IRQ();
	spider_init_IRQ();
}

static void __init cell_setup_arch(void)
{
	ppc_md.init_IRQ       = iic_init_IRQ;
	ppc_md.get_irq        = iic_get_irq;
#ifdef CONFIG_SPU_BASE
	spu_priv1_ops         = &spu_priv1_mmio_ops;
#endif
@@ -109,7 +113,6 @@ static void __init cell_setup_arch(void)
	/* Find and initialize PCI host bridges */
	init_pci_config_tokens();
	find_and_init_phbs();
	spider_init_IRQ();
	cbe_pervasive_init();
#ifdef CONFIG_DUMMY_CONSOLE
	conswitchp = &dummy_con;
@@ -174,6 +177,9 @@ define_machine(cell) {
	.calibrate_decr		= generic_calibrate_decr,
	.check_legacy_ioport	= cell_check_legacy_ioport,
	.progress		= cell_progress,
	.init_IRQ       	= cell_init_irq,
	.get_irq        	= iic_get_irq,

#ifdef CONFIG_KEXEC
	.machine_kexec		= default_machine_kexec,
	.machine_kexec_prepare	= default_machine_kexec_prepare,
Loading