#include "includes.h" /* 1.共享buf互斥操作,注意P11在等待主系统BUF锁时候需要响应主系统的操作, 防止主系统等待导致死锁,处理来自主系统的M2P中断(通过硬件lock不需要这一点) 2.接口互斥,不能同时操作 P11在等待主系统ack消息时,也要防止死锁(P11和主系统同时发送ACK消息时会死锁), 有以下处理: 主系统 1.主系统不能在关中断/中断中发送ACK类型的消息 2.发送ACK类型的消息需要互斥,即不允许同时发多个ACK类型消息 3.不允许在收到ACK类型消息处理函数中发送ACK类型消息的嵌套,收到ACK类型消息 调用post_ack_flag=0,发送函数判断post_ack_flag=0且当前任务为pmu_task则断言 P11系统: 1.P11系统不能在关中断/中断中发送ACK类型的消息 2.不允许在收到ACK类型消息后,又发送ACK类型消息,由于不会在中断中发送ACK类型消息, 在收到ACK类型的消息后调用post_ack_flag=0,发送函数内部检查post_ack_flag=0则断言 3.不允许重复发送ACK类型的消息,由于一点的保证 4.主系统和P11同时发ACK类型的消息,P11需要响应主系统 */ #define MSG_ENTER_CRITICAL() lp_lock() #define MSG_EXIT_CRITICAL() lp_unlock() #define P11_WKUP_MSYS(msg) P11_SYSTEM->P2M_INT_SET = BIT(P2M_APP_INDEX) #define MSYS_WKUP_P11(msg) //P11_SYSTEM->M2P_INT_SET = BIT(M2P_APP_INDEX) static LP_Q m2p_msg_q; static LP_Q p2m_msg_q; static u8 m2p_pool[MAX_POOL] ALIGNED(4); static u8 p2m_pool[MAX_POOL] ALIGNED(4); static bool post_ack_flag = 1; /* function: 从缓存buf读取指定长度数据 param len: 读取数据长度 */ static int lp_buf_read(LP_Q *q, u8 *buf, u32 len) { if (q->count == 0) { return LP_BUF_READ_NO_DATA; } if (q->count < len) { return LP_BUF_READ_NOT_ENOUGH_DATA; } u32 end = (q->out + len) % q->size; if (end > q->out) { memcpy(buf, (void *)(P11_RAM_BASE + q->start + q->out), len); } else { memcpy(buf, (void *)(P11_RAM_BASE + q->start + q->out), q->size - q->out); memcpy(buf + (q->size - q->out), (void *)(P11_RAM_BASE + q->start), end); } q->out = end; q->count -= len; return LP_BUF_NO_ERR; } static int lp_buf_write_enable(LP_Q *q, u32 len) { if ((q->count + len) > q->size) { return LP_BUF_WRITE_OVER; } else { return LP_BUF_NO_ERR; } } /* function: 从缓存buf写入指定长度数据 return val: 0,写入成功 param len: 写入的数据长度 */ static int lp_buf_write(LP_Q *q, u8 *buf, u32 len) { u32 end = (q->in + len) % q->size; if (end > q->in) { memcpy((void *)(P11_RAM_BASE + q->start + q->in), buf, len); } else { memcpy((void *)(P11_RAM_BASE + q->start + q->in), buf, q->size - q->in); memcpy((void *)(P11_RAM_BASE + q->start), buf + (q->size - q->in), end); } q->in = end; q->count += len; return LP_BUF_NO_ERR; } /* * function:从消息池中获取主系统发送过来的消息 * param head:消息的头部,包含消息类型、长度等信息 * param len:读取消息内存的长度 * param msg:读取到消息 * * return val: MSG_NO_MSG * MSG_NO_ERROR * MSG_BUF_ERROR * MSG_BUF_READ_OVER * */ int m2p_get_msg(struct lp_msg_head *head, u8 *msg, u32 len) { LP_Q *msg_q_p = (LP_Q *)(P11_RAM_BASE + (P2M_CBUF_ADDR0 | P2M_CBUF_ADDR1 << 8 | P2M_CBUF_ADDR2 << 16 | P2M_CBUF_ADDR3 << 24)); //长度至少是头+1byte数据 if (len < sizeof(struct lp_msg_head) + 1) { return MSG_BUF_READ_OVER; } local_irq_disable(); MSG_ENTER_CRITICAL(); //先读取头部数据 int ret = lp_buf_read(msg_q_p, (u8 *)head, sizeof(struct lp_msg_head)); if (ret == LP_BUF_READ_NO_DATA) { //若没有数据则进入低功耗 MSG_EXIT_CRITICAL(); //确保每次事件都能唤醒p11 //get no msg,cpu enter lowpower p11_lowpower_schedule(); local_irq_enable(); return MSG_NO_MSG; } else if (ret == LP_BUF_READ_NOT_ENOUGH_DATA) { MSG_EXIT_CRITICAL(); local_irq_enable(); //读取头部的数据长度不够返回错误 return MSG_BUF_ERROR; } else { //判断长度够不够 if (len < head->len) { MSG_EXIT_CRITICAL(); local_irq_enable(); //读了头,数据读不了返回错误 return MSG_BUF_READ_OVER; } ret = lp_buf_read(msg_q_p, msg, head->len); if (ret != LP_BUF_NO_ERR) { MSG_EXIT_CRITICAL(); local_irq_enable(); //数据长度为控不对返回格式错误 return MSG_BUF_ERROR; } } MSG_EXIT_CRITICAL(); local_irq_enable(); return MSG_NO_ERROR; } /* * function:主系统向P11发送消息,往消息池丢数据,该函数可实现向P11主循环推数据 * * param type: 消息类型,P11收到消息后根据消息类型匹配回调函数 * param ack:该函数不需要ack参数,也即发送的头index为0,预留给该函数使用 * param len:发送消息的长度,单位为一个字节 * param msg:发送的消息 * */ int m2p_post_msg(u32 type, u32 ack, u8 *msg, u32 len) { struct lp_msg_head head; LP_Q *msg_q_p = (LP_Q *)(P11_RAM_BASE + (P2M_CBUF_ADDR0 | P2M_CBUF_ADDR1 << 8 | P2M_CBUF_ADDR2 << 16 | P2M_CBUF_ADDR3 << 24)); MSG_ENTER_CRITICAL(); /*P11的m2p接口不需要ack与index*/ head.type = type; head.ack = 0; head.len = len; head.index = 0; if (lp_buf_write_enable(msg_q_p, len + sizeof(struct lp_msg_head)) == LP_BUF_WRITE_OVER) { MSG_EXIT_CRITICAL(); return MSG_BUF_WRITE_OVER; } //写头 lp_buf_write(msg_q_p, (u8 *)&head, sizeof(struct lp_msg_head)); //写数据 lp_buf_write(msg_q_p, msg, len); MSYS_WKUP_P11(); MSG_EXIT_CRITICAL(); return MSG_NO_ERROR; } /* * 接收到ack消息处理过程中调用 */ void config_post_ack_flag(u32 enable) { local_irq_disable(); if (enable) { post_ack_flag = 1; } else { post_ack_flag = 0; } local_irq_enable(); } static u32 p2m_get_ack_flag(u32 index) { LP_Q *msg_q_p = (LP_Q *)(P11_RAM_BASE + (P2M_CBUF1_ADDR0 | P2M_CBUF1_ADDR1 << 8 | P2M_CBUF1_ADDR2 << 16 | P2M_CBUF1_ADDR3 << 24)); MSG_ENTER_CRITICAL(); u32 ret = msg_q_p->ack_flag & BIT(index); MSG_EXIT_CRITICAL(); return ret ? 0 : 1; } u32 p11_ack_msys(u32 index) { LP_Q *msg_q_p = (LP_Q *)(P11_RAM_BASE + (P2M_CBUF_ADDR0 | P2M_CBUF_ADDR1 << 8 | P2M_CBUF_ADDR2 << 16 | P2M_CBUF_ADDR3 << 24)); MSG_ENTER_CRITICAL(); msg_q_p->ack_flag &= ~BIT(index); MSG_EXIT_CRITICAL(); return 0; } /* * function:P11向主系统发送消息,往消息池丢数据 * * param type: 消息类型,主系统收到消息后根据消息类型匹配回调函数 * param ack:P11收到消息执行完成后是否发送应答消息给主系统,P11死等消息 * 并处理主系统发送过来的所有消息 * param len:发送消息的长度,单位为一个字节 * param msg:发送的消息 * */ int p2m_post_msg(u32 type, u32 ack, u8 *msg, u32 len) { u32 param; struct lp_msg_head head; LP_Q *msg_q_p = (LP_Q *)(P11_RAM_BASE + (P2M_CBUF1_ADDR0 | P2M_CBUF1_ADDR1 << 8 | P2M_CBUF1_ADDR2 << 16 | P2M_CBUF1_ADDR3 << 24)); /*不允许在中断函数/关中断发阻塞操作,因为阻塞的同时要处理 主系统发的消息,不建议在中断函数处理/关闭中断处理*/ if (ack == 1) { ASSERT(!(cpu_in_irq() || cpu_irq_disable()), "p2m_post_msg ack"); } MSG_ENTER_CRITICAL(); u32 index = 0; if (ack) { msg_q_p->ack_flag |= BIT(0); /*收到ACK消息处理函数,不允许发送ACK消息*/ if (post_ack_flag != 1) { ASSERT(0, "post_ack_flag check fail!"); } } head.type = type; head.ack = ack; head.len = len; head.index = index; if (lp_buf_write_enable(msg_q_p, len + sizeof(struct lp_msg_head)) == LP_BUF_WRITE_OVER) { MSG_EXIT_CRITICAL(); return MSG_BUF_WRITE_OVER; } //写头 lp_buf_write(msg_q_p, (u8 *)&head, sizeof(struct lp_msg_head)); //写数据 lp_buf_write(msg_q_p, msg, len); __power_recover(); P11_WKUP_MSYS(); MSG_EXIT_CRITICAL(); if (ack) { while (1) { if (p2m_get_ack_flag(index)) { break; } /*主系统可能在等待P11的消息,处理来自主系统的消息,防止死锁*/ if (m2p_msg_hdl(head.index)) { break; } } } return MSG_NO_ERROR; } void message_init() { MSG_ENTER_CRITICAL(); memset((void *)m2p_pool, 0, MAX_POOL); memset((void *)p2m_pool, 0, MAX_POOL); //初始化m2p消息队列 m2p_msg_q.in = 0; m2p_msg_q.out = 0; m2p_msg_q.start = (u32)m2p_pool; m2p_msg_q.count = 0; m2p_msg_q.size = MAX_POOL; m2p_msg_q.ack_flag = 0; //初始化p2m消息队列 p2m_msg_q.in = 0; p2m_msg_q.out = 0; p2m_msg_q.start = (u32)p2m_pool; p2m_msg_q.count = 0; p2m_msg_q.size = MAX_POOL; p2m_msg_q.ack_flag = 0; //赋值m2p消息队列描述地址 u32 addr = (u32)&m2p_msg_q; P2M_CBUF_ADDR0 = (addr) & 0xff; P2M_CBUF_ADDR1 = (addr >> 8) & 0xff; P2M_CBUF_ADDR2 = (addr >> 16) & 0xff; P2M_CBUF_ADDR3 = (addr >> 24) & 0xff; //赋值p2m消息队列描述地址 addr = (u32)&p2m_msg_q; P2M_CBUF1_ADDR0 = (addr) & 0xff; P2M_CBUF1_ADDR1 = (addr >> 8) & 0xff; P2M_CBUF1_ADDR2 = (addr >> 16) & 0xff; P2M_CBUF1_ADDR3 = (addr >> 24) & 0xff; MSG_EXIT_CRITICAL(); }