/***************************************************************************** * * Filename: * --------- * ccci_ipc.c * * * Author: * ------- * ****************************************************************************/ #include #include #include #include #include #define local_AP_id_2_unify_id(id) local_xx_id_2_unify_id(id,1) #define local_MD_id_2_unify_id(id) local_xx_id_2_unify_id(id,0) #define unify_AP_id_2_local_id(id) unify_xx_id_2_local_id(id,1) #define unify_MD_id_2_local_id(id) unify_xx_id_2_local_id(id,0) typedef struct _ipc_ctl_block { int m_md_id; spinlock_t ccci_ipc_wr_lock; spinlock_t ccci_ipc_rd_lock; CCCI_IPC_MEM *ipc_mem; unsigned int ccci_ipc_smem_base_phy; int ccci_ipc_smem_size; unsigned int ccci_ipc_wr_buffer_phy; unsigned int ccci_ipc_rd_buffer_phy; struct cdev ccci_ipc_cdev; wait_queue_head_t poll_md_queue_head; int md_is_ready; IPC_TASK ipc_task[MAX_NUM_IPC_TASKS] ; MD_CALL_BACK_QUEUE md_status_update_call_back; int major; int start_minor; }ipc_ctl_block_t; static ipc_ctl_block_t *ipc_ctl_block[MAX_MD_NUM]; static void release_recv_item(CCCI_RECV_ITEM *item); static void ipc_call_back_func(MD_CALL_BACK_QUEUE*,unsigned long); static void ipc_smem_init(CCCI_IPC_MEM *ipc_mem) { int i; ipc_mem->buffer.buff_wr.size=CCCI_IPC_BUFFER_SIZE; ipc_mem->buffer.buff_wr.rx_offset=0; ipc_mem->buffer.buff_wr.tx_offset=0; ipc_mem->buffer.buff_rd.size=CCCI_IPC_BUFFER_SIZE; ipc_mem->buffer.buff_rd.rx_offset=0; ipc_mem->buffer.buff_rd.tx_offset=0; for (i=0;iilm+i)->src_mod_id = -1UL; (ipc_mem->ilm+i)->dest_mod_id = -1UL; (ipc_mem->ilm+i)->sap_id = -1UL; (ipc_mem->ilm+i)->msg_id = -1UL; (ipc_mem->ilm+i)->local_para_ptr = NULL; (ipc_mem->ilm+i)->local_para_ptr = NULL; } } int ccci_ipc_ipo_h_restore(int md_id) { ipc_ctl_block_t *ctl_b; ctl_b = ipc_ctl_block[md_id]; ipc_smem_init(ctl_b->ipc_mem); return 0; } static void ipc_call_back_func(MD_CALL_BACK_QUEUE *queue,unsigned long data) { IPC_TASK *tsk; int i; CCCI_RECV_ITEM *item,*n; ipc_ctl_block_t *ctl_b = container_of(queue, ipc_ctl_block_t, md_status_update_call_back); unsigned long flags; switch (data) { case CCCI_MD_EXCEPTION: ctl_b->md_is_ready=0; CCCI_DBG_MSG(ctl_b->m_md_id, "ipc", "MD exception call chain !\n"); break; case CCCI_MD_RESET: //if (ctl_b->md_is_ready) { ctl_b->md_is_ready=0; CCCI_DBG_MSG(ctl_b->m_md_id, "ipc", "MD reset call chain !\n"); for (i=0;iipc_task+i; spin_lock_irqsave(&tsk->lock, flags); list_for_each_entry_safe(item,n,&tsk->recv_list,list) { release_recv_item(item); } spin_unlock_irqrestore(&tsk->lock, flags); //__wake_up(&tsk->write_wait_queue, TASK_NORMAL, 0, (void*)POLLERR); //__wake_up(&tsk->read_wait_queue, TASK_NORMAL, 0, (void*)POLLERR); } spin_lock_irqsave(&ctl_b->ccci_ipc_wr_lock, flags); ctl_b->ipc_mem->buffer.buff_wr.tx_offset=0; ctl_b->ipc_mem->buffer.buff_wr.rx_offset=0; spin_unlock_irqrestore(&ctl_b->ccci_ipc_wr_lock, flags); spin_lock_irqsave(&ctl_b->ccci_ipc_rd_lock, flags); ctl_b->ipc_mem->buffer.buff_rd.tx_offset=0; ctl_b->ipc_mem->buffer.buff_rd.rx_offset=0; spin_unlock_irqrestore(&ctl_b->ccci_ipc_rd_lock, flags); } break; case CCCI_MD_BOOTUP: ctl_b->md_is_ready=1; wake_up_all(&ctl_b->poll_md_queue_head); CCCI_IPC_MSG(ctl_b->m_md_id, "MD boot up successfully.\n"); break; } } static IPC_MSGSVC_TASKMAP_T ipc_msgsvc_maptbl[] = { // X_IPC_MODULE_CONF(1,M_SSDBG1,0,1) //TASK_ID_1 // X_IPC_MODULE_CONF(1,AP_SSDBG2,1,1) //TASK_ID_2 #define __IPC_ID_TABLE #include "ccci_ipc_task_ID.h" #undef __IPC_ID_TABLE }; void find_task_to_clear(IPC_TASK task_table[], unsigned int to_id) { IPC_TASK *task=NULL; int i, tmp; ipc_ctl_block_t *ctl_b = (ipc_ctl_block_t*)(container_of(task_table, ipc_ctl_block_t, ipc_task[0])); for (i=0;im_md_id, "ipc", "%s: task->to_id(%d:%d)\n", __func__, i, task_table[i].to_id); if (task==NULL) { task=ctl_b->ipc_task+i; tmp=i; continue; } if (time_after(task->jiffies,task_table[i].jiffies)) { task=task_table+i; CCCI_DBG_MSG(ctl_b->m_md_id, "ipc", "%s: select task->to_id(%d:%d)\n", __func__, i, task_table[i].to_id); } else if (task->jiffies==task_table[i].jiffies) { CCCI_DBG_MSG(ctl_b->m_md_id, "ipc", "[Error]Wrong time stamp(%ld, %ld), select task->to_id(%d:%d)\n", task->jiffies, task_table[i].jiffies, tmp, task->to_id); } } } if (task==NULL) { CCCI_MSG_INF(ctl_b->m_md_id, "ipc", "Wrong MD ID(%d) to clear for next recv.\n",to_id); return; } CCCI_IPC_MSG(ctl_b->m_md_id, "wake up task:%d \n", task-ctl_b->ipc_task); clear_bit(CCCI_TASK_PENDING,&task->flag); wake_up_poll(&task->write_wait_queue, POLLOUT); } static IPC_MSGSVC_TASKMAP_T *local_xx_id_2_unify_id(uint32 local_id,int AP) { int i; for (i=0;ilist)) list_del_init(&item->list); if (item->data) kfree(item->data); kfree(item); } } void *read_from_ring_buffer(int md_id, ipc_ilm_t *ilm, BUFF *buff_rd, int *len) { int size; int write; int read; int data_size; uint8 *data; void *ret=NULL; int over=0; int copy=0; int real_size=0; unsigned long flag; ipc_ctl_block_t *ctl_b = ipc_ctl_block[md_id]; spin_lock_irqsave(&ctl_b->ccci_ipc_rd_lock, flag); size=buff_rd->size; write=buff_rd->tx_offset; read=buff_rd->rx_offset; data_size=(write-read)>=0?(write-read):(size-(read-write)); if(data_size == 0) CCCI_IPC_MSG(md_id, "data_size=0, read(%d)", read); else if (data_size < 0) { CCCI_MSG_INF(md_id, "ipc", "[Error]wrong data_size: %d", data_size); return NULL; } CCCI_IPC_MSG(md_id, "tx_offset=%d, rx_offset=%d\n", write, read); data=(uint8 *)kmalloc(data_size+sizeof(ipc_ilm_t), GFP_ATOMIC); if (data==NULL) { CCCI_MSG_INF(md_id, "ipc", "kmalloc for read ilm fail!\n"); ret=NULL; goto out; } *((ipc_ilm_t *)data)=*ilm; ilm=(ipc_ilm_t *)data; data +=sizeof(ipc_ilm_t) ; if (writebuffer+read,over); copy+=over; read=(read+over)&(size-1); } if (copybuffer+read,data_size-copy); } real_size +=(ilm->local_para_ptr)?((local_para_struct *)data)->msg_len:0; data +=real_size; real_size +=(ilm->peer_buff_ptr)?((peer_buff_struct *)data)->pdu_len:0; buff_rd->rx_offset += real_size; buff_rd->rx_offset &= size-1; ret=ilm; *len=real_size+sizeof(ipc_ilm_t); if(real_size>data_size) CCCI_MSG_INF(md_id, "ipc", "[Error]wrong real_size(%d)>data_size(%d)", real_size, data_size); out: spin_unlock_irqrestore(&ctl_b->ccci_ipc_rd_lock, flag); CCCI_IPC_MSG(md_id, "recv real_size=%08x data_size=%08x\n", real_size, data_size); return ret; } static void recv_item(int md_id, unsigned int addr, unsigned int len, IPC_TASK *task, BUFF *buff_rd) { ipc_ctl_block_t *ctl_b = ipc_ctl_block[md_id]; ipc_ilm_t *ilm=(ipc_ilm_t *)((uint32)ctl_b->ipc_mem+(addr - ctl_b->ccci_ipc_smem_base_phy + get_md2_ap_phy_addr_fixed())); CCCI_RECV_ITEM *item ; unsigned long flags; if(len!=sizeof(ipc_ilm_t)) CCCI_MSG_INF(md_id, "ipc", "[Error]Wrong msg len: sizeof(ipc_ilm_t)=%d,len=%d\n", sizeof(ipc_ilm_t), len); CCCI_IPC_MSG(md_id, "Recv item Physical_Addr:%x Virtual_Addr:%p Len:%d.\n", addr, ilm, len); if (addr > ctl_b->ccci_ipc_smem_base_phy - get_md2_ap_phy_addr_fixed() + offset_of(CCCI_IPC_MEM, ilm_md) + sizeof(ipc_ilm_t)*MAX_NUM_IPC_TASKS_MD) { CCCI_MSG_INF(md_id, "ipc", "[Error]Wrong physical address(%x)\n", addr); return ; } item=kmalloc(sizeof(CCCI_RECV_ITEM),GFP_ATOMIC); if (item==NULL) { CCCI_MSG_INF(md_id, "ipc", "kmalloc for recv_item fail!\n"); goto out; } if (ilm->local_para_ptr){ if((uint32)ilm->local_para_ptr<(uint32)ctl_b->ccci_ipc_rd_buffer_phy || (uint32)ilm->local_para_ptr>=(uint32)ctl_b->ccci_ipc_rd_buffer_phy+CCCI_IPC_BUFFER_SIZE) CCCI_MSG_INF(md_id, "ipc", "[Error]wrong ilm->local_para_ptr address(%p)", ilm->local_para_ptr); } if (ilm->peer_buff_ptr){ if((uint32)ilm->peer_buff_ptr<(uint32)ctl_b->ccci_ipc_rd_buffer_phy || (uint32)ilm->peer_buff_ptr>=(uint32)ctl_b->ccci_ipc_rd_buffer_phy+CCCI_IPC_BUFFER_SIZE) CCCI_MSG_INF(md_id, "ipc", "[Error]wrong ilm->peer_buff_ptr address(%p)", ilm->peer_buff_ptr); } CCCI_IPC_MSG(md_id, "recv ilm->local_para_ptr(%p), ilm->peer_buff_ptr(%p)\n", ilm->local_para_ptr, ilm->peer_buff_ptr); INIT_LIST_HEAD(&item->list); item->data=(uint8 *)read_from_ring_buffer(md_id, ilm, buff_rd, &item->len); if (item->data==NULL) { CCCI_MSG_INF(md_id, "ipc", "read ipc rx data fail\n"); goto out1; } spin_lock_irqsave(&task->lock,flags); list_add_tail(&item->list,&task->recv_list); spin_unlock_irqrestore(&task->lock,flags); kill_fasync(&task->fasync, SIGIO, POLL_IN); wake_up_poll(&task->read_wait_queue,POLLIN); goto out; out1: kfree(item); out: return; } static int write_to_ring_buffer(int md_id, uint8 *data, int count, IPC_TASK *task, BUFF *ipc_buffer) { int ret=0; int free; int write,read,over,copy; int size; int write_begin; unsigned long flags; ipc_ilm_t *ilm=task->ilm_p; local_para_struct *local_para = ilm->local_para_ptr?(local_para_struct*)data:NULL; peer_buff_struct *peer_buff=ilm->peer_buff_ptr? (peer_buff_struct*)((uint32)data+(local_para?local_para->msg_len:0)):NULL; ipc_ctl_block_t *ctl_b = ipc_ctl_block[md_id]; CCCI_IPC_MSG(md_id, "local_para_struct addr=%p peer_buff_struct addr=%p\n",local_para,peer_buff); if ((local_para?local_para->msg_len:0)+(peer_buff?peer_buff->pdu_len:0)!=count) { CCCI_MSG_INF(md_id, "ipc", "[Error]Count is not equal(%x != %x ) !\n", (local_para?local_para->msg_len:0)+(peer_buff?peer_buff->pdu_len:0),count); return -EINVAL; } if ((local_para?local_para->ref_count!=1:0)||(peer_buff?peer_buff->ref_count!=1:0)) { CCCI_MSG_INF(md_id, "ipc", "[Error]ref count !=1 .\n"); return -EINVAL; } spin_lock_irqsave(&ctl_b->ccci_ipc_wr_lock, flags); write_begin=write=ipc_buffer->tx_offset; read=ipc_buffer->rx_offset; size=ipc_buffer->size; copy=0; if (read < write) { free=size-(write-read); over=size-write; } else if (read == write) { free = size - 1; over = size - write; } else { free = read - write -1; over=0; } if (count>free) { CCCI_MSG_INF(md_id, "ipc", "[Error]memory isn't enough, data_len(%d)>free_len(%d, %d, %d)\n", count, free, write, read); ret=-E2BIG; goto out; } if (over) { if (countbuffer+write,data,over); copy+=over; write=(write+over)&(size-1); data+=copy; } if (copybuffer+write, data, count-copy); } mb(); ipc_buffer->tx_offset += count; ipc_buffer->tx_offset &= size-1; ret=count; ilm->local_para_ptr=local_para?(local_para_struct *)(ctl_b->ccci_ipc_wr_buffer_phy+write_begin):NULL; ilm->peer_buff_ptr=peer_buff? (peer_buff_struct *)(ctl_b->ccci_ipc_wr_buffer_phy+((write_begin+(local_para?local_para->msg_len:0))&(size-1))):NULL; out: spin_unlock_irqrestore(&ctl_b->ccci_ipc_wr_lock, flags); return ret; } static void ccci_ipc_callback(void *private) { IPC_TASK *task; IPC_MSGSVC_TASKMAP_T *id_map; logic_channel_info_t *ch_info = (logic_channel_info_t*)private; ccci_msg_t msg; ipc_ctl_block_t *ctl_b = (ipc_ctl_block_t *)ch_info->m_owner; int md_id = ctl_b->m_md_id; while(get_logic_ch_data(ch_info, &msg)) { if (msg.channel==CCCI_IPC_RX_ACK||msg.channel==CCCI_IPC_TX) { CCCI_MSG_INF(md_id, "ipc", "[Error]invalid ipc rx channel(%d)!\n", msg.channel); } if (msg.channel==CCCI_IPC_RX) { CCCI_IPC_MSG(md_id, "CCCI_IPC_RX:Unify AP id(%x) \n", msg.reserved); if ((id_map=unify_AP_id_2_local_id(msg.reserved))==NULL) { CCCI_MSG_INF(md_id, "ipc", "[Error]Wrong Unify AP id(%x)@RX\n", msg.reserved); return; } task=((ipc_ctl_block_t *)(ch_info->m_owner))->ipc_task+id_map->task_id; recv_item(md_id, msg.addr, msg.len, task, &ctl_b->ipc_mem->buffer.buff_rd); ccci_ipc_ack(md_id, CCCI_IPC_RX_ACK, IPC_MSGSVC_RVC_DONE, msg.reserved); } if (msg.channel==CCCI_IPC_TX_ACK) { CCCI_IPC_MSG(md_id, "CCCI_IPC_TX_ACK: Unify MD ID(%x)\n", msg.reserved); if ((id_map=unify_MD_id_2_local_id(msg.reserved))==NULL) { CCCI_MSG_INF(md_id, "ipc", "[Error]Wrong AP Unify id (%d)@Tx ack.\n",msg.reserved); return; } find_task_to_clear(ctl_b->ipc_task, id_map->task_id); if(msg.id!=IPC_MSGSVC_RVC_DONE) CCCI_MSG_INF(md_id, "ipc", "[Error]Not write mailbox id: %d\n", msg.id); } } } static void ipc_task_init(int md_id, IPC_TASK *task,ipc_ilm_t *ilm) { ipc_ctl_block_t *ctl_b = ipc_ctl_block[md_id]; spin_lock_init(&task->lock); task->flag = 0; task->user = (atomic_t)ATOMIC_INIT(0); task->jiffies = -1UL; task->fasync = NULL; task->ilm_p = ilm; task->time_out = -1; task->ilm_phy_addr = ctl_b->ccci_ipc_smem_base_phy - get_md2_ap_phy_addr_fixed() + offset_of(CCCI_IPC_MEM, ilm) +(uint32)ilm-(uint32)(ctl_b->ipc_mem->ilm); task->to_id = -1; init_waitqueue_head(&task->read_wait_queue); init_waitqueue_head(&task->write_wait_queue); INIT_LIST_HEAD(&task->recv_list); task->owner = ipc_ctl_block[md_id]; } static int ccci_ipc_open(struct inode *inode, struct file *file) { int md_id; int major; int index; ipc_ctl_block_t *ctl_b; major = imajor(inode); md_id = get_md_id_by_dev_major(major); if(md_id < 0) { CCCI_MSG("IPC open fail: invalid major id:%d\n", major); return -1; } ctl_b = ipc_ctl_block[md_id]; index = iminor(inode) - ctl_b->start_minor; if (index >= MAX_NUM_IPC_TASKS) { CCCI_MSG_INF(md_id, "ipc", "[Error]Wrong minor num %d.\n",index); return -EINVAL; } CCCI_DBG_MSG(md_id, "ipc", "%s: register task%d\n", __func__, index); nonseekable_open(inode,file); file->private_data = ctl_b->ipc_task+index; atomic_inc(&((ctl_b->ipc_task+index)->user)); return 0; } static ssize_t ccci_ipc_read(struct file *file, char *buf, size_t count, loff_t *ppos) { int ret = 0; IPC_TASK *task = file->private_data; CCCI_RECV_ITEM *recv_data; ipc_ctl_block_t *ctl_b; unsigned long flags; ctl_b = (ipc_ctl_block_t *)task->owner; retry: spin_lock_irqsave(&task->lock, flags); if (ctl_b->md_is_ready == 0) { ret=-EIO; goto out_unlock; } if (list_empty(&task->recv_list)) { if (file->f_flags & O_NONBLOCK) { ret = -EAGAIN; goto out_unlock; } spin_unlock_irqrestore(&task->lock, flags); interruptible_sleep_on(&task->read_wait_queue); if (signal_pending(current)) { CCCI_IPC_MSG(ctl_b->m_md_id, "Interrupt read sys_call : task:%s pid:%d tgid:%d SIGPEND:%#llx. GROUP_SIGPEND:%#llx .\n", current->comm,current->pid,current->tgid, *(unsigned long long *)current->pending.signal.sig, *(unsigned long long *)current->signal->shared_pending.signal.sig); ret = -EINTR; goto out; } goto retry; } recv_data=container_of(task->recv_list.next,CCCI_RECV_ITEM,list); if (recv_data->len > count) { CCCI_MSG_INF(ctl_b->m_md_id, "ipc", "[Error]Recv buff is too small(count=%d data_len=%d)!\n", \ count,recv_data->len); ret = -E2BIG; goto out_unlock; } list_del_init(&recv_data->list); spin_unlock_irqrestore(&task->lock, flags); if (copy_to_user(buf, recv_data->data, recv_data->len)) { ret = -EFAULT; release_recv_item(recv_data); goto out; } ret = recv_data->len; release_recv_item(recv_data); goto out; out_unlock: spin_unlock_irqrestore(&task->lock, flags); out: return ret; } static ssize_t ccci_ipc_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { int ret = 0; IPC_TASK *task = file->private_data; ipc_ctl_block_t *ctl_b; IPC_MSGSVC_TASKMAP_T *id_map; ipc_ilm_t *ilm = NULL; int md_id; ctl_b = (ipc_ctl_block_t *)task->owner; md_id = ctl_b->m_md_id; if (count < sizeof(ipc_ilm_t)) { CCCI_MSG_INF(md_id, "ipc", "%s: [Error]Write len(%d) < ipc_ilm_t\n", __func__, count); ret = -EINVAL; goto out; } ilm = kmalloc(count, GFP_KERNEL); if (ilm == NULL) { CCCI_MSG_INF(md_id, "ipc", "%s: kmalloc fail!\n", __func__); ret = -ENOMEM; goto out; } if (copy_from_user(ilm, buf, count)) { CCCI_MSG_INF(md_id, "ipc", "%s: copy_from_user fail!\n", __func__); ret = -EFAULT; goto out_free; } if ((id_map = local_MD_id_2_unify_id(ilm->dest_mod_id)) == NULL) { CCCI_MSG_INF(md_id, "ipc", "%s: [Error]Invalid Dest MD id (%d)\n", __func__, ilm->dest_mod_id); ret = -EINVAL; goto out_free; } if (test_and_set_bit(CCCI_TASK_PENDING, &task->flag)) { CCCI_IPC_MSG(md_id, "write is busy. Task ID=%d.\n", task-ctl_b->ipc_task); if (file->f_flags & O_NONBLOCK) { ret = -EBUSY; goto out_free; } else if (wait_event_interruptible_exclusive(task->write_wait_queue, !test_and_set_bit(CCCI_TASK_PENDING,&task->flag)||ctl_b->md_is_ready==0) == -ERESTARTSYS) { ret = -EINTR; goto out_free; } } spin_lock_irq(&task->lock); if (ctl_b->md_is_ready == 0) { ret = -EIO; spin_unlock_irq(&task->lock); goto out_free; } spin_unlock_irq(&task->lock); task->jiffies = jiffies; *task->ilm_p = *ilm; task->to_id = ilm->dest_mod_id; task->ilm_p->src_mod_id = task - ctl_b->ipc_task; CCCI_DBG_MSG(md_id, "ipc", "%s: src=%d, dst=%d, data_len=%d\n", __func__, task->ilm_p->src_mod_id, task->to_id, count); if (count > sizeof(ipc_ilm_t)) { if (write_to_ring_buffer(md_id, (uint8*)(ilm+1), count-sizeof(ipc_ilm_t), task, &ctl_b->ipc_mem->buffer.buff_wr) != count-sizeof(ipc_ilm_t)) { CCCI_MSG_INF(md_id, "ipc", "[Error]write_to_ring_buffer fail!\n"); clear_bit(CCCI_TASK_PENDING, &task->flag); ret = -EAGAIN; goto out_free; } } ret = ccci_ipc_write_stream(md_id, CCCI_IPC_TX, task->ilm_phy_addr, sizeof(ipc_ilm_t), id_map->extq_id); if (ret != sizeof(ccci_msg_t)) { CCCI_MSG_INF(md_id, "ipc", "%s: ccci_ipc_write_stream fail: %d\n", __func__, ret); clear_bit(CCCI_TASK_PENDING, &task->flag); ret = -EAGAIN; goto out_free; } out_free: kfree(ilm); out: return ret==sizeof(ccci_msg_t)?count:ret; } static long ccci_ipc_ioctl( struct file *file, unsigned int cmd, unsigned long arg) { IPC_TASK *task = file->private_data; CCCI_RECV_ITEM *item, *n; unsigned long flags; long ret = 0; ipc_ctl_block_t *ctl_b; ctl_b = (ipc_ctl_block_t *)task->owner; switch(cmd) { case CCCI_IPC_RESET_RECV: spin_lock_irqsave(&task->lock, flags); list_for_each_entry_safe(item,n,&task->recv_list,list) { release_recv_item(item); } spin_unlock_irqrestore(&task->lock, flags); ret=0; break; case CCCI_IPC_RESET_SEND: clear_bit(CCCI_TASK_PENDING,&task->flag); wake_up(&task->write_wait_queue); break; case CCCI_IPC_WAIT_MD_READY: if (ctl_b->md_is_ready == 0) { interruptible_sleep_on(&ctl_b->poll_md_queue_head); if (signal_pending(current)) { CCCI_MSG_INF(ctl_b->m_md_id, "ipc", "Got signal @ WAIT_MD_READY\n"); ret = -EINTR; } } break; default: ret = -EINVAL; break; } return ret; } static int ccci_ipc_release(struct inode *inode, struct file *file) { CCCI_RECV_ITEM *item,*n; IPC_TASK *task = file->private_data; unsigned long flags; if (atomic_dec_and_test(&task->user)) { spin_lock_irqsave(&task->lock, flags); list_for_each_entry_safe(item, n, &task->recv_list, list) { release_recv_item(item); } spin_unlock_irqrestore(&task->lock, flags); } clear_bit(CCCI_TASK_PENDING, &task->flag); CCCI_DBG_MSG(0, "ipc", "%s\n", __func__); return 0; } static int ccci_ipc_fasync(int fd, struct file *file, int on) { IPC_TASK *task = file->private_data; return fasync_helper(fd, file, on, &task->fasync); } static uint32 ccci_ipc_poll(struct file *file, poll_table *wait) { IPC_TASK *task = file->private_data; int ret = 0; ipc_ctl_block_t *ctl_b; ctl_b = (ipc_ctl_block_t *)task->owner; poll_wait(file,&task->read_wait_queue, wait); poll_wait(file,&task->write_wait_queue, wait); spin_lock_irq(&task->lock); if (ctl_b->md_is_ready==0) { //ret |= POLLERR; goto out; } if (!list_empty(&task->recv_list)) ret |= POLLIN|POLLRDNORM; if (!test_bit(CCCI_TASK_PENDING,&task->flag)) ret |= POLLOUT|POLLWRNORM; out: spin_unlock_irq(&task->lock); return ret; } static struct file_operations ccci_ipc_fops= { .owner = THIS_MODULE, .open = ccci_ipc_open, .read = ccci_ipc_read, .write = ccci_ipc_write, .release = ccci_ipc_release, .unlocked_ioctl = ccci_ipc_ioctl, .fasync = ccci_ipc_fasync, .poll = ccci_ipc_poll, }; int __init ccci_ipc_init(int md_id) { int ret = 0; int i = 0; int major, minor; char buf[16]; ipc_ctl_block_t *ctl_b; ret = get_dev_id_by_md_id(md_id, "ipc", &major, &minor); if(ret < 0) { CCCI_MSG("ccci_ipc_init: get md device number failed(%d)\n", ret); return ret; } // Allocate ipc ctrl struct memory ctl_b = (ipc_ctl_block_t *)kmalloc(sizeof(ipc_ctl_block_t), GFP_KERNEL); if(ctl_b == NULL) return -CCCI_ERR_GET_MEM_FAIL; memset(ctl_b, 0, sizeof(ipc_ctl_block_t)); ipc_ctl_block[md_id] = ctl_b; spin_lock_init(&ctl_b->ccci_ipc_wr_lock); spin_lock_init(&ctl_b->ccci_ipc_rd_lock); init_waitqueue_head(&ctl_b->poll_md_queue_head); ctl_b->md_status_update_call_back.call = ipc_call_back_func; ctl_b->md_status_update_call_back.next = NULL, ctl_b->m_md_id = md_id; ctl_b->major = major; ctl_b->start_minor = minor; ccci_ipc_base_req(md_id, (int*)(&ctl_b->ipc_mem),&ctl_b->ccci_ipc_smem_base_phy,&ctl_b->ccci_ipc_smem_size); ctl_b->ccci_ipc_wr_buffer_phy = ctl_b->ccci_ipc_smem_base_phy - get_md2_ap_phy_addr_fixed() \ +offset_of(CCCI_IPC_MEM,buffer.buff_wr.buffer); ctl_b->ccci_ipc_rd_buffer_phy = ctl_b->ccci_ipc_smem_base_phy - get_md2_ap_phy_addr_fixed() \ +offset_of(CCCI_IPC_MEM,buffer.buff_rd.buffer); //CCCI_MSG_INF(md_id, "ipc", "ccci_ipc_wr_buffer_phy: %#x, ccci_ipc_buffer_phy_rd: %#x.\n", // ctl_b->ccci_ipc_wr_buffer_phy, ctl_b->ccci_ipc_rd_buffer_phy); ipc_smem_init(ctl_b->ipc_mem); for (i=0;iipc_task+i,ctl_b->ipc_mem->ilm+i); } snprintf(buf, 16, "CCCI_IPC_DEV%d", md_id); if (register_chrdev_region(MKDEV(major,minor),MAX_NUM_IPC_TASKS,buf) != 0) { CCCI_MSG_INF(md_id, "ipc", "Regsiter CCCI_IPC_DEV failed!\n"); ret = -1; goto _IPC_MAPPING_FAIL; } cdev_init(&ctl_b->ccci_ipc_cdev,&ccci_ipc_fops); ctl_b->ccci_ipc_cdev.owner = THIS_MODULE; if ((ret = cdev_add(&ctl_b->ccci_ipc_cdev, MKDEV(major, minor), MAX_NUM_IPC_TASKS))< 0) { CCCI_MSG_INF(md_id, "ipc", "cdev_add failed!\n"); goto _CHR_DEV_ADD_FAIL; } if (register_to_logic_ch(md_id, CCCI_IPC_RX, ccci_ipc_callback, ctl_b)|| register_to_logic_ch(md_id, CCCI_IPC_TX_ACK, ccci_ipc_callback, ctl_b)) { CCCI_MSG_INF(md_id, "ipc", "ccci_ipc_register failed!\n"); ret = -1; goto _REG_LOGIC_CH_FAIL; } md_register_call_chain(md_id, &ctl_b->md_status_update_call_back); goto out; _REG_LOGIC_CH_FAIL: un_register_to_logic_ch(md_id, CCCI_IPC_RX); un_register_to_logic_ch(md_id, CCCI_IPC_TX_ACK); _CHR_DEV_ADD_FAIL: cdev_del(&ctl_b->ccci_ipc_cdev); _IPC_MAPPING_FAIL: kfree(ctl_b); ipc_ctl_block[md_id] = NULL; out: return ret; } void __exit ccci_ipc_exit(int md_id) { int i; ipc_ctl_block_t *ctl_b = ipc_ctl_block[md_id]; if(ctl_b == NULL) return; for (i = 0;i < MAX_NUM_IPC_TASKS; i++) { if (atomic_read(&ctl_b->ipc_task[i].user)) { CCCI_MSG_INF(md_id, "ipc", "BUG for taskID %d module exit count.\n",i); } } cdev_del(&ctl_b->ccci_ipc_cdev); unregister_chrdev_region(MKDEV(ctl_b->major,ctl_b->start_minor),MAX_NUM_IPC_TASKS); md_unregister_call_chain(md_id, &ctl_b->md_status_update_call_back); un_register_to_logic_ch(md_id, CCCI_IPC_RX); un_register_to_logic_ch(md_id, CCCI_IPC_TX_ACK); kfree(ctl_b); ipc_ctl_block[md_id] = NULL; }