760 lines · 15.6 KB · C
RawDownload
/* * arch/powerpc/sysdev/ipic.c * * IPIC routines implementations. * * Copyright 2005 Freescale Semiconductor, Inc. * * 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. */#include <linux/kernel.h>#include <linux/init.h>#include <linux/errno.h>#include <linux/reboot.h>#include <linux/slab.h>#include <linux/stddef.h>#include <linux/sched.h>#include <linux/signal.h>#include <linux/sysdev.h>#include <linux/device.h>#include <linux/bootmem.h>#include <linux/spinlock.h>#include <asm/irq.h>#include <asm/io.h>#include <asm/prom.h>#include <asm/ipic.h> #include "ipic.h" static struct ipic * primary_ipic;static DEFINE_SPINLOCK(ipic_lock); static struct ipic_info ipic_info[] = {	[9] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_H,		.prio	= IPIC_SIPRR_D,		.force	= IPIC_SIFCR_H,		.bit	= 24,		.prio_mask = 0,	},	[10] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_H,		.prio	= IPIC_SIPRR_D,		.force	= IPIC_SIFCR_H,		.bit	= 25,		.prio_mask = 1,	},	[11] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_H,		.prio	= IPIC_SIPRR_D,		.force	= IPIC_SIFCR_H,		.bit	= 26,		.prio_mask = 2,	},	[14] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_H,		.prio	= IPIC_SIPRR_D,		.force	= IPIC_SIFCR_H,		.bit	= 29,		.prio_mask = 5,	},	[15] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_H,		.prio	= IPIC_SIPRR_D,		.force	= IPIC_SIFCR_H,		.bit	= 30,		.prio_mask = 6,	},	[16] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_H,		.prio	= IPIC_SIPRR_D,		.force	= IPIC_SIFCR_H,		.bit	= 31,		.prio_mask = 7,	},	[17] = {		.pend	= IPIC_SEPNR,		.mask	= IPIC_SEMSR,		.prio	= IPIC_SMPRR_A,		.force	= IPIC_SEFCR,		.bit	= 1,		.prio_mask = 5,	},	[18] = {		.pend	= IPIC_SEPNR,		.mask	= IPIC_SEMSR,		.prio	= IPIC_SMPRR_A,		.force	= IPIC_SEFCR,		.bit	= 2,		.prio_mask = 6,	},	[19] = {		.pend	= IPIC_SEPNR,		.mask	= IPIC_SEMSR,		.prio	= IPIC_SMPRR_A,		.force	= IPIC_SEFCR,		.bit	= 3,		.prio_mask = 7,	},	[20] = {		.pend	= IPIC_SEPNR,		.mask	= IPIC_SEMSR,		.prio	= IPIC_SMPRR_B,		.force	= IPIC_SEFCR,		.bit	= 4,		.prio_mask = 4,	},	[21] = {		.pend	= IPIC_SEPNR,		.mask	= IPIC_SEMSR,		.prio	= IPIC_SMPRR_B,		.force	= IPIC_SEFCR,		.bit	= 5,		.prio_mask = 5,	},	[22] = {		.pend	= IPIC_SEPNR,		.mask	= IPIC_SEMSR,		.prio	= IPIC_SMPRR_B,		.force	= IPIC_SEFCR,		.bit	= 6,		.prio_mask = 6,	},	[23] = {		.pend	= IPIC_SEPNR,		.mask	= IPIC_SEMSR,		.prio	= IPIC_SMPRR_B,		.force	= IPIC_SEFCR,		.bit	= 7,		.prio_mask = 7,	},	[32] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_H,		.prio	= IPIC_SIPRR_A,		.force	= IPIC_SIFCR_H,		.bit	= 0,		.prio_mask = 0,	},	[33] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_H,		.prio	= IPIC_SIPRR_A,		.force	= IPIC_SIFCR_H,		.bit	= 1,		.prio_mask = 1,	},	[34] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_H,		.prio	= IPIC_SIPRR_A,		.force	= IPIC_SIFCR_H,		.bit	= 2,		.prio_mask = 2,	},	[35] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_H,		.prio	= IPIC_SIPRR_A,		.force	= IPIC_SIFCR_H,		.bit	= 3,		.prio_mask = 3,	},	[36] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_H,		.prio	= IPIC_SIPRR_A,		.force	= IPIC_SIFCR_H,		.bit	= 4,		.prio_mask = 4,	},	[37] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_H,		.prio	= IPIC_SIPRR_A,		.force	= IPIC_SIFCR_H,		.bit	= 5,		.prio_mask = 5,	},	[38] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_H,		.prio	= IPIC_SIPRR_A,		.force	= IPIC_SIFCR_H,		.bit	= 6,		.prio_mask = 6,	},	[39] = {		.pend	= IPIC_SIPNR_H,		.mask	= IPIC_SIMSR_H,		.prio	= IPIC_SIPRR_A,		.force	= IPIC_SIFCR_H,		.bit	= 7,		.prio_mask = 7,	},	[48] = {		.pend	= IPIC_SEPNR,		.mask	= IPIC_SEMSR,		.prio	= IPIC_SMPRR_A,		.force	= IPIC_SEFCR,		.bit	= 0,		.prio_mask = 4,	},	[64] = {		.pend	= IPIC_SIPNR_L,		.mask	= IPIC_SIMSR_L,		.prio	= IPIC_SMPRR_A,		.force	= IPIC_SIFCR_L,		.bit	= 0,		.prio_mask = 0,	},	[65] = {		.pend	= IPIC_SIPNR_L,		.mask	= IPIC_SIMSR_L,		.prio	= IPIC_SMPRR_A,		.force	= IPIC_SIFCR_L,		.bit	= 1,		.prio_mask = 1,	},	[66] = {		.pend	= IPIC_SIPNR_L,		.mask	= IPIC_SIMSR_L,		.prio	= IPIC_SMPRR_A,		.force	= IPIC_SIFCR_L,		.bit	= 2,		.prio_mask = 2,	},	[67] = {		.pend	= IPIC_SIPNR_L,		.mask	= IPIC_SIMSR_L,		.prio	= IPIC_SMPRR_A,		.force	= IPIC_SIFCR_L,		.bit	= 3,		.prio_mask = 3,	},	[68] = {		.pend	= IPIC_SIPNR_L,		.mask	= IPIC_SIMSR_L,		.prio	= IPIC_SMPRR_B,		.force	= IPIC_SIFCR_L,		.bit	= 4,		.prio_mask = 0,	},	[69] = {		.pend	= IPIC_SIPNR_L,		.mask	= IPIC_SIMSR_L,		.prio	= IPIC_SMPRR_B,		.force	= IPIC_SIFCR_L,		.bit	= 5,		.prio_mask = 1,	},	[70] = {		.pend	= IPIC_SIPNR_L,		.mask	= IPIC_SIMSR_L,		.prio	= IPIC_SMPRR_B,		.force	= IPIC_SIFCR_L,		.bit	= 6,		.prio_mask = 2,	},	[71] = {		.pend	= IPIC_SIPNR_L,		.mask	= IPIC_SIMSR_L,		.prio	= IPIC_SMPRR_B,		.force	= IPIC_SIFCR_L,		.bit	= 7,		.prio_mask = 3,	},	[72] = {		.pend	= IPIC_SIPNR_L,		.mask	= IPIC_SIMSR_L,		.prio	= 0,		.force	= IPIC_SIFCR_L,		.bit	= 8,	},	[73] = {		.pend	= IPIC_SIPNR_L,		.mask	= IPIC_SIMSR_L,		.prio	= 0,		.force	= IPIC_SIFCR_L,		.bit	= 9,	},	[74] = {		.pend	= IPIC_SIPNR_L,		.mask	= IPIC_SIMSR_L,		.prio	= 0,		.force	= IPIC_SIFCR_L,		.bit	= 10,	},	[75] = {		.pend	= IPIC_SIPNR_L,		.mask	= IPIC_SIMSR_L,		.prio	= 0,		.force	= IPIC_SIFCR_L,		.bit	= 11,	},	[76] = {		.pend	= IPIC_SIPNR_L,		.mask	= IPIC_SIMSR_L,		.prio	= 0,		.force	= IPIC_SIFCR_L,		.bit	= 12,	},	[77] = {		.pend	= IPIC_SIPNR_L,		.mask	= IPIC_SIMSR_L,		.prio	= 0,		.force	= IPIC_SIFCR_L,		.bit	= 13,	},	[78] = {		.pend	= IPIC_SIPNR_L,		.mask	= IPIC_SIMSR_L,		.prio	= 0,		.force	= IPIC_SIFCR_L,		.bit	= 14,	},	[79] = {		.pend	= IPIC_SIPNR_L,		.mask	= IPIC_SIMSR_L,		.prio	= 0,		.force	= IPIC_SIFCR_L,		.bit	= 15,	},	[80] = {		.pend	= IPIC_SIPNR_L,		.mask	= IPIC_SIMSR_L,		.prio	= 0,		.force	= IPIC_SIFCR_L,		.bit	= 16,	},	[84] = {		.pend	= IPIC_SIPNR_L,		.mask	= IPIC_SIMSR_L,		.prio	= 0,		.force	= IPIC_SIFCR_L,		.bit	= 20,	},	[85] = {		.pend	= IPIC_SIPNR_L,		.mask	= IPIC_SIMSR_L,		.prio	= 0,		.force	= IPIC_SIFCR_L,		.bit	= 21,	},	[90] = {		.pend	= IPIC_SIPNR_L,		.mask	= IPIC_SIMSR_L,		.prio	= 0,		.force	= IPIC_SIFCR_L,		.bit	= 26,	},	[91] = {		.pend	= IPIC_SIPNR_L,		.mask	= IPIC_SIMSR_L,		.prio	= 0,		.force	= IPIC_SIFCR_L,		.bit	= 27,	},}; static inline u32 ipic_read(volatile u32 __iomem *base, unsigned int reg){	return in_be32(base + (reg >> 2));} static inline void ipic_write(volatile u32 __iomem *base, unsigned int reg, u32 value){	out_be32(base + (reg >> 2), value);} static inline struct ipic * ipic_from_irq(unsigned int virq){	return primary_ipic;} #define ipic_irq_to_hw(virq)	((unsigned int)irq_map[virq].hwirq) static void ipic_unmask_irq(unsigned int virq){	struct ipic *ipic = ipic_from_irq(virq);	unsigned int src = ipic_irq_to_hw(virq);	unsigned long flags;	u32 temp; 	spin_lock_irqsave(&ipic_lock, flags); 	temp = ipic_read(ipic->regs, ipic_info[src].mask);	temp |= (1 << (31 - ipic_info[src].bit));	ipic_write(ipic->regs, ipic_info[src].mask, temp); 	spin_unlock_irqrestore(&ipic_lock, flags);} static void ipic_mask_irq(unsigned int virq){	struct ipic *ipic = ipic_from_irq(virq);	unsigned int src = ipic_irq_to_hw(virq);	unsigned long flags;	u32 temp; 	spin_lock_irqsave(&ipic_lock, flags); 	temp = ipic_read(ipic->regs, ipic_info[src].mask);	temp &= ~(1 << (31 - ipic_info[src].bit));	ipic_write(ipic->regs, ipic_info[src].mask, temp); 	spin_unlock_irqrestore(&ipic_lock, flags);} static void ipic_ack_irq(unsigned int virq){	struct ipic *ipic = ipic_from_irq(virq);	unsigned int src = ipic_irq_to_hw(virq);	unsigned long flags;	u32 temp; 	spin_lock_irqsave(&ipic_lock, flags); 	temp = ipic_read(ipic->regs, ipic_info[src].pend);	temp |= (1 << (31 - ipic_info[src].bit));	ipic_write(ipic->regs, ipic_info[src].pend, temp); 	spin_unlock_irqrestore(&ipic_lock, flags);} static void ipic_mask_irq_and_ack(unsigned int virq){	struct ipic *ipic = ipic_from_irq(virq);	unsigned int src = ipic_irq_to_hw(virq);	unsigned long flags;	u32 temp; 	spin_lock_irqsave(&ipic_lock, flags); 	temp = ipic_read(ipic->regs, ipic_info[src].mask);	temp &= ~(1 << (31 - ipic_info[src].bit));	ipic_write(ipic->regs, ipic_info[src].mask, temp); 	temp = ipic_read(ipic->regs, ipic_info[src].pend);	temp |= (1 << (31 - ipic_info[src].bit));	ipic_write(ipic->regs, ipic_info[src].pend, temp); 	spin_unlock_irqrestore(&ipic_lock, flags);} static int ipic_set_irq_type(unsigned int virq, unsigned int flow_type){	struct ipic *ipic = ipic_from_irq(virq);	unsigned int src = ipic_irq_to_hw(virq);	struct irq_desc *desc = get_irq_desc(virq);	unsigned int vold, vnew, edibit; 	if (flow_type == IRQ_TYPE_NONE)		flow_type = IRQ_TYPE_LEVEL_LOW; 	/* ipic supports only low assertion and high-to-low change senses	 */	if (!(flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING))) {		printk(KERN_ERR "ipic: sense type 0x%x not supported\n",			flow_type);		return -EINVAL;	} 	desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);	desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;	if (flow_type & IRQ_TYPE_LEVEL_LOW)  {		desc->status |= IRQ_LEVEL;		desc->handle_irq = handle_level_irq;	} else {		desc->handle_irq = handle_edge_irq;	} 	/* only EXT IRQ senses are programmable on ipic	 * internal IRQ senses are LEVEL_LOW	 */	if (src == IPIC_IRQ_EXT0)		edibit = 15;	else		if (src >= IPIC_IRQ_EXT1 && src <= IPIC_IRQ_EXT7)			edibit = (14 - (src - IPIC_IRQ_EXT1));		else			return (flow_type & IRQ_TYPE_LEVEL_LOW) ? 0 : -EINVAL; 	vold = ipic_read(ipic->regs, IPIC_SECNR);	if ((flow_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_FALLING) {		vnew = vold | (1 << edibit);	} else {		vnew = vold & ~(1 << edibit);	}	if (vold != vnew)		ipic_write(ipic->regs, IPIC_SECNR, vnew);	return 0;

Lines 1–500 of 760.