ipic.c

来自「linux 内核源代码」· C语言 代码 · 共 758 行 · 第 1/2 页

C
758
字号
{	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;}static struct irq_chip ipic_irq_chip = {	.typename	= " IPIC  ",	.unmask		= ipic_unmask_irq,	.mask		= ipic_mask_irq,	.mask_ack	= ipic_mask_irq_and_ack,	.ack		= ipic_ack_irq,	.set_type	= ipic_set_irq_type,};static int ipic_host_match(struct irq_host *h, struct device_node *node){	/* Exact match, unless ipic node is NULL */	return h->of_node == NULL || h->of_node == node;}static int ipic_host_map(struct irq_host *h, unsigned int virq,			 irq_hw_number_t hw){	struct ipic *ipic = h->host_data;	struct irq_chip *chip;	/* Default chip */	chip = &ipic->hc_irq;	set_irq_chip_data(virq, ipic);	set_irq_chip_and_handler(virq, chip, handle_level_irq);	/* Set default irq type */	set_irq_type(virq, IRQ_TYPE_NONE);	return 0;}static int ipic_host_xlate(struct irq_host *h, struct device_node *ct,			   u32 *intspec, unsigned int intsize,			   irq_hw_number_t *out_hwirq, unsigned int *out_flags){	/* interrupt sense values coming from the device tree equal either	 * LEVEL_LOW (low assertion) or EDGE_FALLING (high-to-low change)	 */	*out_hwirq = intspec[0];	if (intsize > 1)		*out_flags = intspec[1];	else		*out_flags = IRQ_TYPE_NONE;	return 0;}static struct irq_host_ops ipic_host_ops = {	.match	= ipic_host_match,	.map	= ipic_host_map,	.xlate	= ipic_host_xlate,};struct ipic * __init ipic_init(struct device_node *node, unsigned int flags){	struct ipic	*ipic;	struct resource res;	u32 temp = 0, ret;	ipic = alloc_bootmem(sizeof(struct ipic));	if (ipic == NULL)		return NULL;	memset(ipic, 0, sizeof(struct ipic));	ipic->irqhost = irq_alloc_host(of_node_get(node), IRQ_HOST_MAP_LINEAR,				       NR_IPIC_INTS,				       &ipic_host_ops, 0);	if (ipic->irqhost == NULL) {		of_node_put(node);		return NULL;	}	ret = of_address_to_resource(node, 0, &res);	if (ret) {		of_node_put(node);		return NULL;	}	ipic->regs = ioremap(res.start, res.end - res.start + 1);	ipic->irqhost->host_data = ipic;	ipic->hc_irq = ipic_irq_chip;	/* init hw */	ipic_write(ipic->regs, IPIC_SICNR, 0x0);	/* default priority scheme is grouped. If spread mode is required	 * configure SICFR accordingly */	if (flags & IPIC_SPREADMODE_GRP_A)		temp |= SICFR_IPSA;	if (flags & IPIC_SPREADMODE_GRP_D)		temp |= SICFR_IPSD;	if (flags & IPIC_SPREADMODE_MIX_A)		temp |= SICFR_MPSA;	if (flags & IPIC_SPREADMODE_MIX_B)		temp |= SICFR_MPSB;	ipic_write(ipic->regs, IPIC_SICNR, temp);	/* handle MCP route */	temp = 0;	if (flags & IPIC_DISABLE_MCP_OUT)		temp = SERCR_MCPR;	ipic_write(ipic->regs, IPIC_SERCR, temp);	/* handle routing of IRQ0 to MCP */	temp = ipic_read(ipic->regs, IPIC_SEMSR);	if (flags & IPIC_IRQ0_MCP)		temp |= SEMSR_SIRQ0;	else		temp &= ~SEMSR_SIRQ0;	ipic_write(ipic->regs, IPIC_SEMSR, temp);	primary_ipic = ipic;	irq_set_default_host(primary_ipic->irqhost);	printk ("IPIC (%d IRQ sources) at %p\n", NR_IPIC_INTS,			primary_ipic->regs);	return ipic;}int ipic_set_priority(unsigned int virq, unsigned int priority){	struct ipic *ipic = ipic_from_irq(virq);	unsigned int src = ipic_irq_to_hw(virq);	u32 temp;	if (priority > 7)		return -EINVAL;	if (src > 127)		return -EINVAL;	if (ipic_info[src].prio == 0)		return -EINVAL;	temp = ipic_read(ipic->regs, ipic_info[src].prio);	if (priority < 4) {		temp &= ~(0x7 << (20 + (3 - priority) * 3));		temp |= ipic_info[src].prio_mask << (20 + (3 - priority) * 3);	} else {		temp &= ~(0x7 << (4 + (7 - priority) * 3));		temp |= ipic_info[src].prio_mask << (4 + (7 - priority) * 3);	}	ipic_write(ipic->regs, ipic_info[src].prio, temp);	return 0;}void ipic_set_highest_priority(unsigned int virq){	struct ipic *ipic = ipic_from_irq(virq);	unsigned int src = ipic_irq_to_hw(virq);	u32 temp;	temp = ipic_read(ipic->regs, IPIC_SICFR);	/* clear and set HPI */	temp &= 0x7f000000;	temp |= (src & 0x7f) << 24;	ipic_write(ipic->regs, IPIC_SICFR, temp);}void ipic_set_default_priority(void){	ipic_write(primary_ipic->regs, IPIC_SIPRR_A, IPIC_SIPRR_A_DEFAULT);	ipic_write(primary_ipic->regs, IPIC_SIPRR_D, IPIC_SIPRR_D_DEFAULT);	ipic_write(primary_ipic->regs, IPIC_SMPRR_A, IPIC_SMPRR_A_DEFAULT);	ipic_write(primary_ipic->regs, IPIC_SMPRR_B, IPIC_SMPRR_B_DEFAULT);}void ipic_enable_mcp(enum ipic_mcp_irq mcp_irq){	struct ipic *ipic = primary_ipic;	u32 temp;	temp = ipic_read(ipic->regs, IPIC_SERMR);	temp |= (1 << (31 - mcp_irq));	ipic_write(ipic->regs, IPIC_SERMR, temp);}void ipic_disable_mcp(enum ipic_mcp_irq mcp_irq){	struct ipic *ipic = primary_ipic;	u32 temp;	temp = ipic_read(ipic->regs, IPIC_SERMR);	temp &= (1 << (31 - mcp_irq));	ipic_write(ipic->regs, IPIC_SERMR, temp);}u32 ipic_get_mcp_status(void){	return ipic_read(primary_ipic->regs, IPIC_SERMR);}void ipic_clear_mcp_status(u32 mask){	ipic_write(primary_ipic->regs, IPIC_SERMR, mask);}/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */unsigned int ipic_get_irq(void){	int irq;	BUG_ON(primary_ipic == NULL);#define IPIC_SIVCR_VECTOR_MASK	0x7f	irq = ipic_read(primary_ipic->regs, IPIC_SIVCR) & IPIC_SIVCR_VECTOR_MASK;	if (irq == 0)    /* 0 --> no irq is pending */		return NO_IRQ;	return irq_linear_revmap(primary_ipic->irqhost, irq);}static struct sysdev_class ipic_sysclass = {	set_kset_name("ipic"),};static struct sys_device device_ipic = {	.id		= 0,	.cls		= &ipic_sysclass,};static int __init init_ipic_sysfs(void){	int rc;	if (!primary_ipic->regs)		return -ENODEV;	printk(KERN_DEBUG "Registering ipic with sysfs...\n");	rc = sysdev_class_register(&ipic_sysclass);	if (rc) {		printk(KERN_ERR "Failed registering ipic sys class\n");		return -ENODEV;	}	rc = sysdev_register(&device_ipic);	if (rc) {		printk(KERN_ERR "Failed registering ipic sys device\n");		return -ENODEV;	}	return 0;}subsys_initcall(init_ipic_sysfs);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?