/***************************************************************************** 函 数 名 : mailbox_init_all_handle 接口类型 : 对内接口 功能描述 : 初始化邮箱的所有通道句柄 输入参数 : struct mb *mb -- 邮箱总句柄 struct mb_cfg *config -- 邮箱通道的全局配置表。 unsigned long cpu_id -- 注册此通道的CPU号。 输出参数 : 无 返 回 值 : 邮箱操作句柄 调用函数 : 被调函数 : 修改历史 : 1.日 期 : 2012年9月7日 作 者 : 莫南 00176101 修改内容 : 新生成函数 *****************************************************************************/ MAILBOX_LOCAL long mailbox_init_all_handle( struct mb *mb, struct mb_cfg *config, unsigned long cpu_id) { struct mb_queue *queue = MAILBOX_NULL; unsigned long direct= MIALBOX_DIRECTION_INVALID; /*标记当前邮箱通道 是不是本核相关的有效通道*/ unsigned long ret_val = MAILBOX_OK; struct mb_link *send_link = MAILBOX_NULL;/*指向主结构体的发送通道 数组基地址*/ struct mb_link *recv_link = MAILBOX_NULL; /*指向主结构体的接收通道 数组基地址*/ struct mb_buff *mbuf_prob = &g_mailbox_channel_handle_pool[0]; struct mb_cb *cb_prob = &g_mailbox_user_cb_pool[0]; struct mb_buff *mbuf_cur = MAILBOX_NULL; /*指向正在处理的邮箱通道*/ unsigned long channel_sum = 0; unsigned long use_sum = 0; unsigned long src_id = 0; unsigned long dst_id = 0; unsigned long carrier_id = 0; unsigned long use_max = 0; send_link = mb->send_tbl; recv_link = mb->recv_tbl; /*第二次循环对每个通道句柄分配空间,并赋值。(这段代码变量太多,不方便拆开另建函数)*/ /*初始化每个邮箱的控制句柄*/ while (MAILBOX_MAILCODE_INVALID != config->butt_id) { direct = MIALBOX_DIRECTION_INVALID; src_id = mailbox_get_src_id(config->butt_id); dst_id = mailbox_get_dst_id(config->butt_id); carrier_id = mailbox_get_carrier_id(config->butt_id); use_max = mailbox_get_use_id(config->butt_id); /*检查是不是本CPU发送通道*/ if (cpu_id == src_id) { direct = MIALBOX_DIRECTION_SEND; /*没有分配空间则分配空间*/ if (MAILBOX_NULL == send_link[dst_id].channel_buff) { send_link[dst_id].channel_buff = mbuf_prob; mbuf_prob += (send_link[dst_id].carrier_butt); channel_sum += (send_link[dst_id].carrier_butt); if (channel_sum > MAILBOX_CHANNEL_NUM) { return mailbox_logerro_p1(MAILBOX_CRIT_GUT_INIT_CHANNEL_POOL_TOO_SMALL, channel_sum); } } mbuf_cur = &send_link[dst_id].channel_buff[carrier_id]; } /*检查是不是本CPU接收通道*/ if (cpu_id == dst_id) { direct = MIALBOX_DIRECTION_RECEIVE; /*没有分配空间则分配空间*/ if (MAILBOX_NULL == recv_link[src_id].channel_buff) { recv_link[src_id].channel_buff = mbuf_prob; mbuf_prob += (recv_link[src_id].carrier_butt); channel_sum += (recv_link[src_id].carrier_butt); if (channel_sum > MAILBOX_CHANNEL_NUM) { return mailbox_logerro_p1(MAILBOX_CRIT_GUT_INIT_CHANNEL_POOL_TOO_SMALL, channel_sum); } } mbuf_cur = &recv_link[src_id].channel_buff[carrier_id]; /*1。为邮件注册回调函数申请空间*/ mbuf_cur->read_cb = cb_prob; cb_prob += use_max; use_sum += use_max; if (use_sum > MAILBOX_USER_NUM) { return mailbox_logerro_p1(MAILBOX_CRIT_GUT_INIT_USER_POOL_TOO_SMALL, use_sum); } /*3.注册邮箱线程回调接口,用于获取共享内存邮箱数据的处理*/ ret_val = mailbox_process_register(mailbox_get_channel_id(config->butt_id), mailbox_read_channel, mbuf_cur); /*4.初始化邮箱共享内存,设置标志位。*/ ret_val |= mailbox_init_mem(config); } if ((MIALBOX_DIRECTION_INVALID != direct ) && (MAILBOX_NULL != mbuf_cur)) { /*给控制句柄赋予邮箱ID号*/ mbuf_cur->channel_id = mailbox_get_channel_id(config->butt_id); mbuf_cur->seq_num = MAILBOX_SEQNUM_START; #ifdef MAILBOX_OPEN_MNTN mbuf_cur->mntn.peak_traffic_left = MAILBOX_QUEUE_LEFT_INVALID; mbuf_cur->mntn.mbuff = mbuf_cur; #endif /*给邮箱配置物理资源*/ mbuf_cur->config = config; /*初始化通道资源*/ queue = &(mbuf_cur->mail_queue); /*初始化邮箱通道的环形队列控制符,以下两项是初始化以后不会再变化的。*/ queue->length = mbuf_cur->config->data_size - (MAILBOX_DATA_LEN_PROTECT_NUM * MAILBOX_PROTECT_LEN); queue->base = mbuf_cur->config->data_addr + (MAILBOX_DATA_BASE_PROTECT_NUM * MAILBOX_PROTECT_LEN); /*把此通道注册到具体平台*/ ret_val = mailbox_channel_register(mailbox_get_channel_id(config->butt_id), /*lint !e539*/ config->int_src, mailbox_get_dst_id(config->butt_id), direct, &mbuf_cur->mutex); } config++; } /*检查内存池大小是否刚好,如果报错,请检查宏设置是否匹配: 这里检查下面三个数组的空间是否适配。 g_mailbox_global_cfg_tbl[]; g_mailbox_channel_handle_pool[MAILBOX_CHANNEL_NUM]; g_mailbox_user_cb_pool[MAILBOX_USER_NUM]; */ if((unsigned long)MAILBOX_CHANNEL_NUM != channel_sum ) { ret_val = mailbox_logerro_p1(MAILBOX_ERR_GUT_INIT_CHANNEL_POOL_TOO_LARGE, (MAILBOX_CHANNEL_NUM<<16) | channel_sum); } if(MAILBOX_USER_NUM != use_sum) { ret_val = mailbox_logerro_p1(MAILBOX_ERR_GUT_INIT_USER_POOL_TOO_LARGE, use_sum); } return ret_val; }
/***************************************************************************** 函 数 名 : mailbox_read_mail 接口类型 : 对内接口 功能描述 : 读取并处理一封邮箱的正文数据内容,接受邮箱数据的数据层入口, 并且调用上层注册的邮件数据处理回调函数 输入参数 : mb_buff* mbuff - 邮箱通道操作符 输出参数 : 无 返 回 值 : 读取的邮件数据长度,包括邮件头,返回0表示失败。 调用函数 : 被调函数 : 修改历史 : 1.日 期 : 2012年9月24日 作 者 : 莫南 00176101 修改内容 : 新生成函数 *****************************************************************************/ MAILBOX_LOCAL long mailbox_read_mail(struct mb_buff *mbuff) { struct mb_mail mail; struct mb_cb *read_cb = MAILBOX_NULL;/*此邮箱通道的功能回调函数队列*/ struct mb_queue tmp_queue; struct mb_queue *usr_queue = MAILBOX_NULL; struct mb_queue *m_queue = MAILBOX_NULL; unsigned long use_id; unsigned long slice_start; unsigned long to_bottom; void *usr_handle; void *usr_data; void (*usr_func)(void *mbuf, void *handle, void *data); m_queue = &(mbuff->mail_queue); usr_queue = &(mbuff->usr_queue); mailbox_memcpy((void *) usr_queue, (const void *) m_queue, sizeof(struct mb_queue)); /*保存临时队列状态,交换读写指针。*/ tmp_queue.base = usr_queue->base; tmp_queue.length = usr_queue->length; tmp_queue.front = usr_queue->rear; tmp_queue.rear = usr_queue->front; /*读取邮件的头信息*/ mailbox_queue_read(usr_queue, (char*)&mail, sizeof(struct mb_mail)); /*1.检查邮件头,判断读到的消息是否存在异常,包括SN号是否连续、消息滞留时间是否过长。 2.填充信息读取时间*/ mailbox_check_mail(mbuff, &mail, m_queue->rear); /*把读取时间写回邮箱队列*/ mailbox_queue_write(&tmp_queue, (char*)&mail, sizeof(struct mb_mail)); use_id = mailbox_get_use_id(mail.ulMailCode); /*检查Use ID的有效性*/ if (use_id >= mailbox_get_use_id(mbuff->config->butt_id)) { mailbox_logerro_p1(MAILBOX_ERR_GUT_INVALID_USER_ID, mail.ulMailCode); goto EXIT; } read_cb = &mbuff->read_cb[use_id]; mailbox_mutex_lock(&mbuff->mutex); usr_handle = read_cb->handle; usr_data = read_cb->data; usr_func = read_cb->func; mailbox_mutex_unlock(&mbuff->mutex); if (MAILBOX_NULL != usr_func) { usr_queue->size = mail.ulMsgLength; slice_start = mailbox_get_timestamp(); usr_func(mbuff, usr_handle , usr_data); /*记录可维可测信息*/ #ifdef MAILBOX_OPEN_MNTN mailbox_record_receive(&mbuff->mntn, mbuff->channel_id, slice_start); #endif } else { mailbox_logerro_p1(MAILBOX_ERR_GUT_READ_CALLBACK_NOT_FIND, mail.ulMailCode); } EXIT: /*不管用户有没有用回调读数据,读了多少数据,邮箱队列的读指针都需要按实际 大小偏移,以保证后面邮件读取的正确性。*/ to_bottom = (m_queue->base + m_queue->length) - m_queue->rear; if (to_bottom > (mail.ulMsgLength + sizeof(struct mb_mail))) { m_queue->rear += (mail.ulMsgLength + sizeof(struct mb_mail)); } else { m_queue->rear = m_queue->base + ((mail.ulMsgLength + sizeof(struct mb_mail)) - to_bottom); } /*读保证指针4字节对齐*/ m_queue->rear = mailbox_align_size(m_queue->rear, MAILBOX_ALIGN); return (mailbox_align_size(mail.ulMsgLength, MAILBOX_ALIGN) + sizeof(struct mb_mail)); }
MAILBOX_GLOBAL long mailbox_init(void) { unsigned long offset = 0; int i = 0; struct mb_head *head = NULL; if (MAILBOX_INIT_MAGIC == g_mailbox_handle.init_flag) { /*考虑到单核下电重启,静态数据不会丢失,这里只打印告警, 返回错误的话,后面的平台初始化将调不到,IPC中断无法注册*/ return mailbox_logerro_p1(MAILBOX_ERR_GUT_ALREADY_INIT, g_mailbox_handle.init_flag); } printk("func = %s, line = %d baseaddr = 0x%x\n", __func__, __LINE__, MAILBOX_MEM_BASEADDR); g_shareMemBase = ioremap(MAILBOX_MEM_BASEADDR, MAILBOX_MEM_LENGTH); /*初始化邮箱中的数据*/ //memset(g_shareMemBase,0x0,MAILBOX_MEM_LENGTH); if(NULL == g_shareMemBase) { printk("func = %s, mmap mailbox mem error!!\n", __func__); return mailbox_logerro_p0(MAILBOX_CRIT_GUT_MEMORY_CONFIG); } offset = (unsigned long)g_shareMemBase - MAILBOX_MEM_BASEADDR; for(i = 0; i < MAILBOX_GLOBAL_CHANNEL_NUM; i++) { g_mailbox_global_cfg_tbl[i].head_addr = g_mailbox_global_cfg_tbl[i].head_addr + offset; g_mailbox_global_cfg_tbl[i].data_addr = g_mailbox_global_cfg_tbl[i].data_addr + offset; printk("i = %d, head_addr = 0x%lx, data_addr = 0x%lx\n", i, g_mailbox_global_cfg_tbl[i].head_addr, g_mailbox_global_cfg_tbl[i].data_addr); /*初始化邮箱头*/ head = (struct mb_head *)g_mailbox_global_cfg_tbl[i].head_addr; head->ulFront = 0x0; head->ulRear = 0x0; head->ulFrontslice = 0x0; head->ulRearslice = 0x0; } /*TODO:进行单核下电重启特性开发时,这行需要删除*/ mailbox_memset(&g_mailbox_handle, 0x00, sizeof(struct mb)); #ifdef MAILBOX_OPEN_MNTN if ((MAILBOX_HEAD_BOTTOM_ADDR > (MAILBOX_MEM_BASEADDR + MAILBOX_MEM_HEAD_LEN)) || (MAILBOX_MEMORY_BOTTOM_ADDR > (MAILBOX_MEM_BASEADDR + MAILBOX_MEM_LENGTH))) { mailbox_out(("mailbox address overflow: headbuttom valid(0x%x), config(0x%x)!\n\\r databuttom valid(0x%x), config(0x%x)!\n", (MAILBOX_MEM_BASEADDR + MAILBOX_MEM_HEAD_LEN), MAILBOX_HEAD_BOTTOM_ADDR, (MAILBOX_MEM_BASEADDR + MAILBOX_MEM_LENGTH), MAILBOX_MEMORY_BOTTOM_ADDR)); return mailbox_logerro_p0(MAILBOX_CRIT_GUT_MEMORY_CONFIG); } #endif /*初始化邮箱主体部分,创建邮箱总句柄。*/ if (MAILBOX_OK != mailbox_create_box(&g_mailbox_handle, &g_mailbox_global_cfg_tbl[0], MAILBOX_LOCAL_CPUID)) { return mailbox_logerro_p0(MAILBOX_ERR_GUT_CREATE_BOX); } /*初始化平台差异部分*/ if (MAILBOX_OK != mailbox_init_platform()) { return mailbox_logerro_p0(MAILBOX_ERR_GUT_INIT_PLATFORM); } g_mailbox_handle.init_flag = MAILBOX_INIT_MAGIC; #ifndef _DRV_LLT_ //mailbox_ifc_test_init(); #endif //fixme: there isn't go to unremap g_slice_reg = (void*)ioremap(SLICE_REG, 0x4); if (NULL == g_slice_reg) { printk("ioremap of slice reg fail.\n"); } mailbox_out(("mb init OK!\n")); return MAILBOX_OK; }
MAILBOX_EXTERN long mailbox_process_register( unsigned long channel_id, long (*cb)(unsigned long channel_id), void *priv) { struct mb_local_work *local_work = MAILBOX_NULL; struct mb_local_cfg *local_cfg = &g_mb_local_cfg_tbl[0]; struct mb_local_proc *local_proc = &g_mailbox_local_proc_tbl[0]; struct mb_local_cfg* find_cfg = MAILBOX_NULL; unsigned long count = sizeof(g_mailbox_local_proc_tbl)/sizeof(struct mb_local_proc); while (MAILBOX_MAILCODE_INVALID != local_cfg->channel_id) { /*找到与传入邮箱ID最适配的系统邮箱配置*/ if (local_cfg->channel_id == channel_id) { find_cfg = local_cfg; break; } local_cfg++; } if (find_cfg) { /*加入邮箱任务对应的邮箱工作队列*/ while (count) { if (find_cfg->property == local_proc->proc_id) { if (local_proc->work_list) { local_work = local_proc->work_list; while (MAILBOX_NULL != local_work->next) { local_work = local_work->next; } local_work->next = (struct mb_local_work *)kcalloc( sizeof(struct mb_local_work), 1, GFP_KERNEL); if (NULL == local_work->next) { (void)printk(KERN_ERR "%s: memory alloc error!\n",__func__); return MAILBOX_ERR_LINUX_ALLOC_MEMORY; } local_work->next->channel_id = find_cfg->channel_id; local_work->next->cb = cb; local_work->next->next = MAILBOX_NULL; local_work->next->mb_priv = priv; } else { local_proc->work_list = (struct mb_local_work *)kcalloc( sizeof(struct mb_local_work), 1, GFP_KERNEL); if (NULL == local_proc->work_list) { (void)printk(KERN_ERR "%s: memory alloc error!\n",__func__); return MAILBOX_ERR_LINUX_ALLOC_MEMORY; } local_proc->work_list->channel_id = find_cfg->channel_id; local_proc->work_list->cb = cb; local_proc->work_list->next = MAILBOX_NULL; local_proc->work_list->mb_priv = priv; } } count--; local_proc++; } return MAILBOX_OK; } return mailbox_logerro_p1(MAILBOX_ERR_LINUX_CHANNEL_NOT_FIND, channel_id); }
MAILBOX_LOCAL long mailbox_request_channel( struct mb *mb, struct mb_buff ** mb_buf, unsigned long mailcode) { struct mb_head *head = MAILBOX_NULL; struct mb_queue *queue = MAILBOX_NULL; struct mb_buff *mbuff = MAILBOX_NULL; long ret_val = MAILBOX_OK; mailbox_dpm_device_get(); *mb_buf = MAILBOX_NULL; mbuff = mailbox_get_channel_handle(mb, mailcode); if (MAILBOX_NULL == mbuff) { ret_val = MAILBOX_ERRO; goto request_erro; } /*通过判断通道保护字,检查通道有没有初始化*/ head = (struct mb_head*)mbuff->config->head_addr; if (( (MAILBOX_PROTECT1 != head->ulProtectWord1) ) || (MAILBOX_PROTECT2 != head->ulProtectWord2) ||(MAILBOX_PROTECT1 != head->ulProtectWord3) || (MAILBOX_PROTECT2 != head->ulProtectWord4)) { #if 1/*k3 modify 保护字不正确重新初始化一下邮箱头,不要return影响通信流程,后续再找根因*/ /*保护字不正确,说明邮箱未初始化,或者内存被踩,报错。*/ /* do not check cause hifi maybe not pwr on when the first ipc message send */ mailbox_init_mem(mbuff->config); mailbox_logerro_p1(MAILBOX_NOT_READY, mailcode); #endif } if(mailbox_get_src_id(mailcode) == mb->local_id) { /* 不允许在中断中发邮件*/ if (MAILBOX_TRUE == mailbox_int_context()) { //TODO:接下来的开发(IFC for 低功耗)可能需要支持在中断中发送邮件,这里就需要锁中断。 ret_val = mailbox_logerro_p1(MAILBOX_ERR_GUT_SEND_MAIL_IN_INT_CONTEXT, mailcode); goto request_erro; } else { if (MAILBOX_OK != mailbox_mutex_lock(&mbuff->mutex)) { /*非中断发送,需要资源保护,获取当前通道资源。*/ ret_val = mailbox_logerro_p1(MAILBOX_CRIT_GUT_MUTEX_LOCK_FAILED, mailcode); goto request_erro; } } } mbuff->mailcode = mailcode; /*共享内存队列,需要依据邮箱头信息对队列操作符进行填充*/ queue = &mbuff->mail_queue; queue->front = queue->base + head->ulFront * sizeof(unsigned long); queue->rear = queue->base + head->ulRear * sizeof(unsigned long); mbuff->mb = mb; *mb_buf = mbuff; return MAILBOX_OK; request_erro: mailbox_out(("###mailbox_request_channel ERR! \n")); mailbox_dpm_device_put(); return ret_val; }