MIPS/resources/soft/perf_func/lib/irq.c
Paul Pan 7b33e4213a a big update
1. add test soft
2. modify verilator (TODO: crossbar need to replace)
3. fix CP0: now CU0 is always 1
4. Controller: cacheop
5. Controller: fix TEN
6. mycpu_top fix CP0_i
7. fix AXI.sv
8. fix AXIReader.sv
9. fix AXIWriter.sv: getting the correct data and length
10. MU: fix cache writeback, fix mem data mux, fix writer address, fix read request
2022-07-29 18:25:58 +08:00

415 lines
9.3 KiB
C

#include <asm/mipsregs.h>
#include <errno.h>
#include <irq.h>
#include <stdlib.h>
static int no_action(int cpl, void *dev_id)
{
return 0;
}
static struct irqaction cascade_irqaction = {
.handler = no_action,
.name = "cascade",
};
unsigned int ack_sb2f_board_irq(unsigned int irq_nr)
{
//printf("ack_sb2f_board_irq %d\n",irq_nr);
(sb2f_board_hw0_icregs+(irq_nr>>5))->int_clr |= (1 << (irq_nr & 0x1f));
}
unsigned int disable_sb2f_board_irq(unsigned int irq_nr)
{
//printf("disable_sb2f_board_irq %d\n",irq_nr);
(sb2f_board_hw0_icregs+(irq_nr>>5))->int_en &= ~(1 << (irq_nr & 0x1f));
}
unsigned int enable_sb2f_board_irq(unsigned int irq_nr)
{
//printf("enable_sb2f_board_irq %d\n",irq_nr);
(sb2f_board_hw0_icregs+(irq_nr>>5))->int_en |= (1 << (irq_nr & 0x1f));
}
int sb2f_board_irq_set_type(unsigned int irq,unsigned int flow_type)
{
unsigned int irq_nr = irq;
int mode;
}
struct irq_chip sb2f_board_irq_chip = {
.name = "SB2F BOARD",
.ack = ack_sb2f_board_irq,
.mask = disable_sb2f_board_irq,
.unmask = enable_sb2f_board_irq,
.eoi = enable_sb2f_board_irq,
.set_type = sb2f_board_irq_set_type
};
struct irq_desc irq_desc[256];
int handle_IRQ_event(unsigned int irq,struct irqaction *action)
{
// printf("I am in handle_IRQ_EVENT\n");
#ifdef MYOPROFILE
local_irq_enable();
#endif
do {
action->handler(action->dev_id);
action = action->next;
}while (action);
#ifdef MYOPROFILE
local_irq_disable();
#endif
// printf("I am out handle_IRQ_EVENT\n");
}
void handle_level_irq(unsigned int irq,struct irq_desc *desc)
{
// printf("i am in handle_level_irq\n");
struct irqaction *action;
desc->chip->mask(irq);/*可以清楚原因寄存器*/
desc->chip->ack(irq);/*可以清除中断状态寄存器*/
action = desc->action;
handle_IRQ_event(irq,action);
desc->chip->unmask(irq);
// printf("i am out handle_level_irq\n");
}
void generic_handle_irq(unsigned int irq)
{
// printf("i am in generic_handler_irq\n");
// CP0_Cause();
struct irq_desc *desc = irq_desc + irq;
desc->handle_irq(irq,desc);
// printf("i am out generic_handler_irq\n");
}
#define do_IRQ(irq) do{ generic_handle_irq(irq);}while(0)
void ls1gp_board_dma_irqdispatch();
void ls1b_board_hw_irqdispatch(int n)
{
int irq;
int intstatus;
intstatus = (sb2f_board_hw0_icregs + n)->int_isr;
irq = ffs(intstatus);
if(!irq)
{
printf("Unknow interrpt intstatus %x\n",intstatus);
}
else if(n == 1 && irq == 11)
{
ls1gp_board_dma_irqdispatch();
}
else do_IRQ(n*32+irq-1);
}
void __set_irq_handler(unsigned int irq, irq_flow_handler_t handler, int is_chained, const char *name)
{
struct irq_desc *desc;
desc = irq_desc + irq;
desc->handle_irq = handler;
}
void default_enable(unsigned int irq)
{
struct irq_desc *desc = irq_desc + irq;
desc->chip->unmask(irq);
}
void default_disable(unsigned int irq)
{
}
unsigned int default_startup(unsigned int irq)
{
irq_desc[irq].chip->enable(irq);
return 0;
}
void irq_chip_set_defaults(struct irq_chip *chip)
{
if(!chip->enable)
chip->enable = default_enable;
if(!chip->disable)
chip->disable = default_disable;
if(!chip->startup)
chip->startup = default_startup;
if(!chip->shutdown)
chip->shutdown = chip->disable;
}
int set_irq_chip(unsigned int irq,struct irq_chip *chip)
{
struct irq_desc *desc;
desc = irq_desc + irq;
irq_chip_set_defaults(chip);
desc->chip = chip;
return 0;
}
void set_irq_chip_and_handler(unsigned int irq,struct irq_chip *chip,irq_flow_handler_t handle)
{
set_irq_chip(irq,chip);
__set_irq_handler(irq, handle, 0, NULL);
}
/*setup dma irq */
struct ls1gp_cop_global_regs
{
volatile unsigned int control;
volatile unsigned int rd_inten;
volatile unsigned int wr_inten;
volatile unsigned int rd_intisr; /* offset 0x10*/
volatile unsigned int wr_intisr;
unsigned int unused[11];
} ;
#define LS1GP_BOARD_DMA_IRQ_BASE 168
#define LS1GP_BOARD_DMA_IRQ_COUNT 16
static struct ls1gp_cop_global_regs *ls1gp_cop_global_regs = (void *)0xbc000000;
void ls1gp_board_dma_irqdispatch()
{
int intstatus;
int irq;
intstatus = (ls1gp_cop_global_regs->wr_intisr & 0xff) << 8 | (ls1gp_cop_global_regs->rd_intisr & 0xff);
irq=ffs(intstatus);
if(!irq){
printf("Unknow dma interrupt status %x \n" , intstatus);
return;
}
else do_IRQ(LS1GP_BOARD_DMA_IRQ_BASE + irq - 1);
}
void disable_ls1gp_dma_irq(unsigned int irq)
{
int irq_nr;
if(irq < LS1GP_BOARD_DMA_IRQ_BASE + 8)
{
irq_nr =irq - LS1GP_BOARD_DMA_IRQ_BASE;
ls1gp_cop_global_regs->rd_inten &= ~(1<<irq_nr);
}
else
{
irq_nr =irq - LS1GP_BOARD_DMA_IRQ_BASE - 8;
ls1gp_cop_global_regs->wr_inten &= ~(1<<irq_nr);
}
}
void enable_ls1gp_dma_irq(unsigned int irq)
{
int irq_nr;
if(irq < LS1GP_BOARD_DMA_IRQ_BASE + 8)
{
irq_nr =irq - LS1GP_BOARD_DMA_IRQ_BASE;
printf("rd irq_nr %d\n",irq_nr);
ls1gp_cop_global_regs->rd_inten |= (1<<irq_nr);
}
else
{
irq_nr =irq - LS1GP_BOARD_DMA_IRQ_BASE - 8;
ls1gp_cop_global_regs->wr_inten |= (1<<irq_nr);
}
}
static void ack_ls1gp_dma_irq(unsigned int irq)
{
int irq_nr;
if(irq < LS1GP_BOARD_DMA_IRQ_BASE + 8)
{
irq_nr =irq - LS1GP_BOARD_DMA_IRQ_BASE;
ls1gp_cop_global_regs->rd_intisr = (1<<irq_nr);
}
else
{
irq_nr =irq - LS1GP_BOARD_DMA_IRQ_BASE - 8;
ls1gp_cop_global_regs->wr_intisr = (1<<irq_nr);
}
}
static void end_ls1gp_dma_irq(unsigned int irq)
{
enable_ls1gp_dma_irq(irq);
}
static struct irq_chip ls1gp_dma_irq_chip = {
.name = "LS1GP BOARD",
.ack = ack_ls1gp_dma_irq,
.mask = disable_ls1gp_dma_irq,
.unmask = enable_ls1gp_dma_irq,
.eoi = enable_ls1gp_dma_irq,
.end = end_ls1gp_dma_irq,
};
void ls1gp_dma_irq_init()
{
int irq;
for (irq = LS1GP_BOARD_DMA_IRQ_BASE; irq < LS1GP_BOARD_DMA_IRQ_BASE + LS1GP_BOARD_DMA_IRQ_COUNT; irq++) {
set_irq_chip_and_handler(irq, &ls1gp_dma_irq_chip, handle_level_irq);
}
}
void sb2f_board_irq_init()
{
int i;
for(i = 0;i <= 159;i++)
{
set_irq_chip_and_handler(i,&sb2f_board_irq_chip,handle_level_irq);
}
}
int setup_irq(unsigned int irq, struct irqaction *newaction)
{
struct irq_desc *desc = irq_desc + irq;
struct irqaction *old, **p;
int shared = 0;
p = &desc->action;
old = *p;
if(old)
{
do
{
p = &old->next;
old= *p;
}while(old);
shared = 1;
}
*p = newaction;
if(!shared)
{
irq_chip_set_defaults(desc->chip);
if(newaction->flags & IRQF_TRIGGER_MASK)
if(desc->chip && desc->chip->set_type)
desc->chip->set_type(irq,newaction->flags & IRQF_TRIGGER_MASK);
if(desc->chip->startup)
desc->chip->startup(irq);
else
desc->chip->enable(irq);
}
return 0;
}
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags,const char *devname, void *dev_id)
{
struct irqaction *action;
int retval;
if(!handler)
return -EINVAL;
action = malloc(sizeof(struct irqaction));
if(!action)
return -ENOMEM;
action->handler = handler;
action->flags = irqflags;
action->next = NULL;
action->name = devname;
action->dev_id = dev_id;
action->irq = irq;
setup_irq(irq,action);
}
///////interrupt
#define INT_PCI_INTA (1<<6)
#define INT_PCI_INTB (1<<7)
#define INT_PCI_INTC (1<<8)
#define INT_PCI_INTD (1<<9)
#define ST0_IM 0x0000ff00
#define CAUSEF_IP7 ( 1 << 15)
#define CAUSEF_IP6 ( 1 << 14)
#define CAUSEF_IP5 ( 1 << 13)
#define CAUSEF_IP4 ( 1 << 12)
#define CAUSEF_IP3 ( 1 << 11)
#define CAUSEF_IP2 ( 1 << 10)
extern struct sb2f_board_intc_regs volatile *sb2f_board_hw0_icregs;
void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned int cause = read_c0_cause() & ST0_IM;
unsigned int status = read_c0_status() & ST0_IM;
unsigned int pending = cause & status;
if(pending & CAUSEF_IP7)
{
#ifdef MYOPROFILE
unsigned long epc;
extern char _ftext[];
extern int irqdepth;
/*only sample in irq*/
#if 1
if(irqdepth>1)
#endif
{
epc = read_c0_epc();
if(epc>=0x80000000) (*(unsigned int *)(epc-(unsigned long)_ftext+0x84000000))++;
}
write_c0_compare(read_c0_count()+MYOPROFILE_TICK);
#else
static int cnt=0;
printf("cnt %d\n",cnt++);
write_c0_compare(read_c0_count()+100000000/100);
#endif
}
else if(pending & CAUSEF_IP2)
{
ls1b_board_hw_irqdispatch(0);
}
else if(pending & CAUSEF_IP3)
{
ls1b_board_hw_irqdispatch(1);
}
else if(pending & CAUSEF_IP4)
{
ls1b_board_hw_irqdispatch(2);
}
else if(pending & CAUSEF_IP5)
{
ls1b_board_hw_irqdispatch(3);
}
else if(pending & CAUSEF_IP6)
{
ls1b_board_hw_irqdispatch(4);
}
else
{
printf("spurious interrupt\n");
}
}
void init_IRQ()
{
int i;
#ifdef MYOPROFILE
memset((void *)0x84000000, 0, 0x200000);
#endif
for(i = 0;i < 5;i++)
{
/* active level setting */
/* uart, keyboard, and mouse are active high */
(sb2f_board_hw0_icregs+i)->int_pol = -1; /*active high*/
/* make all interrupts level triggered */
(sb2f_board_hw0_icregs+i)->int_edge = 0x00000000;
/* mask all interrupts */
(sb2f_board_hw0_icregs+i)->int_clr = 0xffffffff;
}
sb2f_board_irq_init();
ls1gp_dma_irq_init();
setup_irq(32+10, &cascade_irqaction);
clear_c0_status(ST0_IM);
#ifdef MYOPROFILE
write_c0_compare(MYOPROFILE_TICK);
write_c0_count(0);
set_c0_status(0xff01);
#else
set_c0_status(0x7f01);
#endif
}