IPC
IPC(Inter-Processor Communication)是C6678中用于核间交互的一种方式。
每个核可以通过IPC中断来和其他核进行交互,以达到核间同步的目的,也可以用作一个核给另外一个核的定向通知。
Each of the cores can communicate with one another through inter-processor interrupts for core synchronization, allowing for direct notification from one core to another.
IPC寄存器
在C6678(Keystone I)架构中,有IPCGRx和IPCARx两类寄存器,其中x表示为核心号core_num。
IPCGRx
IPCGRx(IPC Generation Register)用于产生一个IPC中断。其寄存器结构如下图所示:
在IPCGRx中,IPCGRx[0](IPCG)为IPC中断使能位,当该位置1,将会给核心core_num = x产生一个IPC中断;IPCGR[31:4](SRCS)是可以用来区分IPC中断的源ID,用户可以自由的将这几位配置成不同含义,用于不同消息类型的IPC通知。
IPCARx
IPCARx(IPC Acknowledgement Register)是用来相应IPC中断的寄存器。其寄存器结构如下图所示:
在IPCAR[31:4](SRCC)中写入1,可清除IPCGR中对应的SRCS位。
IPC中断程序
IPC中断配置
IPC中断作为一个Primary Events,跟其他Primary Events的配置方式也相同。
两个核心都需要使能全局中断和IPC中断。
使能全局中断
CSL_IntcContext context;
CSL_IntcEventHandlerRecord recordTable[CSL_INTC_EVENTID_CNT];
int interrupt_init(void)
{
// the interrupt handler function table
context.eventhandlerRecord = recordTable;
// the num of interrupt, equal the num of the function table
context.numEvtEntries = CSL_INTC_EVENTID_CNT; // 不懂什么意思
// must be called once before using the CSL INTC APIs.
if (CSL_intcInit(&context) != CSL_SOK){
printf("Error: GEM-INTC initialization failed\n");
return -1;
}
// enable the global interrupt and NMI
// must be enabled if want to use INT4-15
if (CSL_intcGlobalEnable(NULL) != CSL_SOK){
printf("Error: GEM-INTC global NMI enable failed\n");
return -1;
}
if (CSL_intcGlobalNmiEnable() != CSL_SOK)
{
printf("Error: GEM-INTC global NMI enable failed\n");
return -1;
}
return 0;
}
使能IPC中断
static ipc_interruptCfg ipc_intInfo[8] =
{
{0, 91, CSL_INTC_VECTID_6, NULL},
{1, 91, CSL_INTC_VECTID_6, &IPC_ISR_core1},
{2, 91, CSL_INTC_VECTID_6, NULL},
{3, 91, CSL_INTC_VECTID_6, NULL},
{4, 91, CSL_INTC_VECTID_6, NULL},
{5, 91, CSL_INTC_VECTID_6, NULL},
{6, 91, CSL_INTC_VECTID_6, NULL},
{7, 91, CSL_INTC_VECTID_6, NULL},
};
static volatile unsigned int IPCGRx_addr[8] =
{
0x02620240, //IPCGR0
0x02620244, //IPCGR1
0x02620248, //IPCGR2
0x0262024c, //IPCGR3
0x02620250, //IPCGR4
0x02620254, //IPCGR5
0x02620258, //IPCGR6
0x0262025c, //IPCGR7
};
static volatile unsigned int IPCGAx_addr[8] =
{
0x02620280, //IPCAR0
0x02620284, //IPCAR1
0x02620288, //IPCAR2
0x0262028c, //IPCAR3
0x02620290, //IPCAR4
0x02620294, //IPCAR5
0x02620298, //IPCAR6
0x0262029c, //IPCAR7
};
void ipc_interrupt_init(void)
{
Uint32 core_id;
CSL_IntcObj ipc_intc_obj;
CSL_IntcHandle ipc_intc_hnd;
CSL_IntcEventHandlerRecord EventRecord;
CSL_IntcEventId event_ID;
CSL_IntcParam vectID;
core_id = CSL_chipReadReg(CSL_CHIP_DNUM);
if( ipc_intInfo[core_id].core == core_id )
{
event_ID = ipc_intInfo[core_id].event_ID;
vectID = ipc_intInfo[core_id].vect;
ipc_intc_hnd = CSL_intcOpen(&ipc_intc_obj, event_ID, &vectID, NULL);
if(ipc_intc_hnd == NULL)
{
printf("Error: GEM-INTC Open failed\n");
return;
}
if (ipc_intInfo[core_id].isr != NULL)
{
EventRecord.handler = ipc_intInfo[core_id].isr;
}
else
{
printf("Please add a ISR function!\n");
return;
}
EventRecord.arg = (void *)event_ID;
if (CSL_intcPlugEventHandler(ipc_intc_hnd, &EventRecord) != CSL_SOK)
{
printf("Error: GEM-INTC Plug event handler failed\n");
return;
}
/* Enabling the events. */
if (CSL_intcHwControl(ipc_intc_hnd, CSL_INTC_CMD_EVTENABLE, NULL) != CSL_SOK)
{
printf("Error: GEM-INTC CSL_INTC_CMD_EVTENABLE command failed\n");
return;
}
}
else
{
printf("IPC: ipc_intInfo.core is in wrong order, ipc init failed !!!\n");
}
}
触发IPC中断
#include <ti/csl/csl_bootcfgAux.h>
void ipc_interrupt_trig(int core_id, Uint32 src)
{
CSL_BootCfgUnlockKicker();
*(volatile unsigned int *)(IPCGRx_addr[core_id]) = src & 0xFFFFFFF8; // send a inter-core interrupt to core[dnum]
*(volatile unsigned int *)(IPCGRx_addr[core_id]) |= 1;
CSL_BootCfgLockKicker();
}
IPC中断服务函数
void IPC_ISR_core1(void *arg)
{
volatile unsigned int read_ipcgr;
Uint32 core_id;
core_id = CSL_chipReadReg(CSL_CHIP_DNUM);
//当前核接收到的信息
read_ipcgr = *(volatile unsigned int *)(IPCGRx_addr[core_id]);
CSL_BootCfgUnlockKicker();
//清除SRCS位
*(volatile unsigned int *) IPCGAx_addr[core_id] = read_ipcgr; //clear the related source info
CSL_BootCfgLockKicker();
//根据read_ipcgr中的源ID添加相应的中断处理
}
IPC中断使能一次,但是IPC_ISR响应两次
在Keystone I关于IPC的手册(2.4节)中说明,
Any master that has access to BOOTCFG space can write to these registers.
向IPCGRx和IPCARx寄存器中写入数据都需要访问BOOTCFG的权限,因此在IPC中断触发和清楚IPC中断标志位的过程中写入寄存器IPCGRx和IPCARx都需要进行KICK0和KICK1的解锁操作,即CSL_BootCfgUnlockKicker();这样才能正确清除IPC中断标志位,否则将触发两次IPC中断,执行两次IPC中断服务函数。