⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bcmcore_irq.c

📁 一个很好的嵌入式linux平台下的bootloader
💻 C
字号:
/*  *********************************************************************    *  Broadcom Common Firmware Environment (CFE)    *      *  Polled interrupt dispatch routines	File: bcmcore_irq.c    *      *********************************************************************      *    *  Copyright 2000,2001,2002,2003    *  Broadcom Corporation. All rights reserved.    *      *  This software is furnished under license and may be used and     *  copied only in accordance with the following terms and     *  conditions.  Subject to these conditions, you may download,     *  copy, install, use, modify and distribute modified or unmodified     *  copies of this software in source and/or binary form.  No title     *  or ownership is transferred hereby.    *      *  1) Any source code used, modified or distributed must reproduce     *     and retain this copyright notice and list of conditions     *     as they appear in the source file.    *      *  2) No right is granted to use any trade name, trademark, or     *     logo of Broadcom Corporation.  The "Broadcom Corporation"     *     name may not be used to endorse or promote products derived     *     from this software without the prior written permission of     *     Broadcom Corporation.    *      *  3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR    *     IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED    *     WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR     *     PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT     *     SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN     *     PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,    *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES     *     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE    *     GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR    *     BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY     *     OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR     *     TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF     *     THE POSSIBILITY OF SUCH DAMAGE.    ********************************************************************* *//*  *********************************************************************    *  This module provides an interface for associating service    *  routines with BCM47xx system interrupt sources.  The CPU Cause    *  register is periodically polled and the requested service    *  routine is invoked when a corresponding interrupt request is    *  active and enabled.    *    *  This is not a full-fledged interrupt handler.    *    *  If CFG_INTERRUPTS == 0, it operates synchronously with the    *  main polling loop and is never invoked directly by the    *  hardware exception handler.  If CFG_INTERRUPTS == 1, certain    *  interrupt sources can be handled asynchronously as exceptions.    *    ********************************************************************* */#include "cpu_config.h"#include "lib_types.h"#include "lib_printf.h"#include "lib_malloc.h"#include "sbmips32.h"extern void bcmcore_update_sr(uint32_t clear, uint32_t set);extern void bcmcore_irq_install(void);extern void bcmcore_irq_arm(void);#if !defined(_BCM96345_) && !defined(_BCM9635x_) /* XXX ISB, not SB */#include "sb_utils.h"#endif#include "exception.h"#include "cfe_irq.h"extern void cfe_ledstr(const char *);   /* debugging *//* First level dispatching (MIPS IP level). *//* * The BCMCORE provides only a single level of dispatch.  To preserve * compatibility with existing clients (XXX temporary?), we accept * handlers of type ip_handler_t, which have exclusive ownership of * interrupts at the given level, or of type void (*)(void *), which * are potentially sharable. */#define IP_LEVELS 8typedef struct irq_action_s irq_action_t;struct irq_action_s {    void (*handler)(void *arg);    void *arg;    unsigned long flags;    int device;              /* to distinguish actions for shared interrupts */    irq_action_t *next;};typedef struct irq_desc_s {    irq_action_t *actions;    int depth;    int status;} irq_desc_t;/* status flags */#define IRQ_DISABLED  0x0001/* Shared variables that must be protected in non-interrupt code. */static irq_desc_t irq_desc[IP_LEVELS];static ip_handler_t ip_handler[IP_LEVELS] = {NULL};voidcfe_irq_setvector(int index, ip_handler_t handler){    if (index >= 0 && index < IP_LEVELS) {	uint32_t sr;	sr = cfe_irq_disable();	ip_handler[index] = NULL;   /* disable: see demux */	if (handler == NULL)	    sr &= ~_MM_MAKEMASK1(S_SR_IMMASK + index);	else	    sr |=  _MM_MAKEMASK1(S_SR_IMMASK + index);	ip_handler[index] = handler;	cfe_irq_enable(sr);    }}static voidbcmcore_dispatch_irqs(irq_desc_t *desc){    irq_action_t *action;    for (action = desc->actions; action != NULL; action = action->next) {	if (action->handler != NULL) {	    (*action->handler)(action->arg);	    }	}}/* * Dispatch functions called from the exception handler for * asynchronous (non-polled) interrupts. * info is a pointer to the saved register block. * * At entry, interrupts will be masked. *//* Called from the exception handler */static voidbcmcore_irq_demux(int code, mips_reg_t *info){    mips_reg_t pending;    mips_reg_t mask_ip;    int i;    irq_desc_t *desc;    pending = info[XCP0_CAUSE] & info[XCP0_SR];    mask_ip = _MM_MAKEMASK1(S_CAUSE_IPMASK + (IP_LEVELS-1));    desc = &irq_desc[IP_LEVELS-1];    for (i = IP_LEVELS-1; i >= 0; i--) {	if (pending & mask_ip) {	    if (ip_handler[i] != NULL)		(*(ip_handler[i]))(i);	    else if (desc->actions != NULL)		bcmcore_dispatch_irqs(desc);	    else {		/* mask off the interrupt or we're caught here forever */		bcmcore_update_sr(mask_ip, 0);		}	    }	mask_ip >>= 1;	desc--;	}}/* * Dispatch functions called for explicit polling (synchronous * interrupts).  The argument pending is a bit mask of pending enabled * interrupts with the bits positioned as in C0_CAUSE. */void bcmcore_dispatch_pending(uint32_t pending);voidbcmcore_dispatch_pending(uint32_t pending){    uint32_t mask_ip;    int i;    irq_desc_t *desc;    mask_ip = _MM_MAKEMASK1(S_CAUSE_IPMASK + (IP_LEVELS-1));    desc = &irq_desc[IP_LEVELS-1];    for (i = IP_LEVELS-1; i >= 0; i--) {	if (pending & mask_ip) {	    if (ip_handler[i] != NULL)		(*(ip_handler[i]))(i);	    else if (desc->actions != NULL)		bcmcore_dispatch_irqs(desc);	    else {		/* mask off the interrupt or we're caught here forever */		bcmcore_update_sr(mask_ip, 0);		}	    }	mask_ip >>= 1;	desc--;	}}/* * Initialize the MIPS level dispatch vector. * This function should be called with interrupts disabled. */static voidbcmcore_irq_vectorinit(void){    int  i;    for (i = 0; i < IP_LEVELS; i++) {	ip_handler[i] = NULL;	}#if CFG_INTERRUPTS    _exc_setvector(XTYPE_INTERRUPT, (void *) bcmcore_irq_demux);    bcmcore_irq_arm();#else    (void) bcmcore_irq_demux;#endif}/* *  cfe_irq_init is called early in the boot sequence.  It is *  responsible for setting up the interrupt mapper and initializing *  the handler table that will be used for dispatching pending *  interrupts.  If hard interrupts are used, it then enables hardware *  interrupts (initially all masked). * *  This function should be called before interrupts are enabled. */voidcfe_irq_init(void){    int i;    irq_desc_t *p;    for (i = 0, p = irq_desc; i < IP_LEVELS; i++, p++) {        p->actions = NULL;	p->depth = 0;	p->status = IRQ_DISABLED;	}    bcmcore_irq_install();    bcmcore_irq_vectorinit();}#if 0  /* needed? *//* cfe_mask_irq() is called to mask an interrupt at the hw level */voidcfe_mask_irq(int cpu, unsigned int irq){    if (irq < IP_LEVELS) {	uint32_t sr;	sr = cfe_irq_disable();	sr &= ~_MM_MAKEMASK1(S_SR_IMMASK + irq);	cfe_irq_enable(sr);	}}/* cfe_unmask_irq() is called to unmask an interrupt at the hw level */voidcfe_unmask_irq(int cpu, unsigned int irq){    if (irq < IP_LEVELS) {	uint32_t sr;	sr = cfe_irq_disable();	sr |= _MM_MAKEMASK1(S_SR_IMMASK + irq);	cfe_irq_enable(sr);	}}#endif /* 0 *//* * The mapping of backplane interrupts to MIPS interrupts is * controlled by the CPU core's SBIPSFLAG and SBINTVEC registers.  The * following function further adjusts from MIPS interrupt priority * (IPn) to the index in the Status/Cause bit masks. */static inline unsigned intbcmcore_map_irq(unsigned int irq){#if !defined(_BCM96345_) && !defined(_BCM9635x_) /* XXX cleanup */    return sb_map_irq(irq) + 2;#else    return (irq % 4) + 3;    /* XXX Works for external interrupts only? */#endif}/* If depth is 0, unmask the interrupt. Increment depth. */voidcfe_enable_irq(unsigned int irq){    unsigned int level = bcmcore_map_irq(irq);    if (level < IP_LEVELS) {	uint32_t sr;	irq_desc_t *desc;	desc = &irq_desc[level];	/* The following code must be atomic */	sr = cfe_irq_disable();	if (desc->depth == 0) {	    sr |= _MM_MAKEMASK1(S_SR_IMMASK + level);	    desc->status &=~ IRQ_DISABLED;	    }	desc->depth++;	cfe_irq_enable(sr);	}}/* Decrement depth. If depth is 0, mask the interrupt. */voidcfe_disable_irq(unsigned int irq){    unsigned int level = bcmcore_map_irq(irq);    if (level < IP_LEVELS) {	uint32_t sr;	irq_desc_t *desc;	desc = &irq_desc[level];	/* The following code must be atomic */	sr = cfe_irq_disable();	desc->depth--;	if (desc->depth == 0) {	    sr &= ~_MM_MAKEMASK1(S_SR_IMMASK + level);	    desc->status |= IRQ_DISABLED;	    }	cfe_irq_enable(sr);	}}/* *  cfe_request_irq() is called by drivers to request addition to the *  chain of handlers called for a given interrupt.   */intcfe_request_irq(unsigned int irq, 		void (*handler)(void *), void *arg,		unsigned long irqflags, int device){    int sr;    unsigned int level;    irq_action_t *action;    irq_desc_t *desc;    irq_action_t *p;    if (handler == NULL) {        return -1;	}    level = bcmcore_map_irq(irq);    action = (irq_action_t *) KMALLOC(sizeof(irq_action_t), 0);    if (action == NULL) {        return -1;	}    action->handler = handler;    action->arg = arg;    action->flags = irqflags;    action->device = device;    action->next = NULL;    desc = &irq_desc[level];    /* The following block of code has to be executed atomically */    sr = cfe_irq_disable();    p = desc->actions;    if (p == NULL) {        desc->actions = action;        desc->depth = 0;        desc->status |= IRQ_DISABLED;	sr &= ~_MM_MAKEMASK1(S_SR_IMMASK + level);	}    else {        /* Can't share interrupts unless both agree to */        if ((p->flags & action->flags & CFE_IRQ_FLAGS_SHARED) == 0) {	    cfe_enable_irq(irq);	    KFREE(action);	    xprintf("cfe_request_irq: conflicting unsharable interrupts.\n");            return -1;	    }	while (p->next != NULL) {	    p = p->next;	    }	p->next = action;	}    cfe_irq_enable(sr);    cfe_enable_irq(irq);    return 0;}/* *  free_irq() releases a handler set up by request_irq() */voidcfe_free_irq(unsigned int irq, int device){    int sr;    unsigned int level;    irq_desc_t *desc;    irq_action_t *p, *q;    level = bcmcore_map_irq(irq);    desc = &irq_desc[level];    /* The following block of code has to be executed atomically */    sr = cfe_irq_disable();    p = desc->actions;    q = NULL;    while (p != NULL) {	if (p->device == device) {	    if (q == NULL) {		desc->actions = p->next;		if (desc->actions == NULL) {		    desc->status |= IRQ_DISABLED;		    sr &= ~_MM_MAKEMASK1(S_SR_IMMASK + level);		    }		}	    else		q->next = p->next;	    break;	    }	else {	    q = p;	    p = p->next;	    }	}    cfe_irq_enable(sr);    if (p != NULL)	KFREE(p);}

⌨️ 快捷键说明

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