static void timer_func(unsigned long data) { ccmni_v2_instance_t *ccmni=(ccmni_v2_instance_t *)data; int contin=0; int ret=0; ccci_msg_t msg; ccmni_v2_ctl_block_t *ctl_b = (ccmni_v2_ctl_block_t*)ccmni->owner; int md_id = ctl_b->m_md_id; spin_lock_bh(&ccmni->spinlock); if (ctl_b == 0) goto out; if (test_bit(CCMNI_RECV_ACK_PENDING,&ccmni->flags)) { msg.magic = 0; msg.id = CCMNI_CHANNEL_OFFSET + ccmni->channel; msg.channel = ccmni->uart_rx_ack; msg.reserved = 0; ret = ccci_message_send(md_id, &msg, 1); if (ret==-CCCI_ERR_CCIF_NO_PHYSICAL_CHANNEL) contin=1; else clear_bit(CCMNI_RECV_ACK_PENDING, &ccmni->flags); } if (test_bit(CCMNI_SEND_PENDING,&ccmni->flags)) { msg.magic = 0; msg.id = ccmni->send_len; msg.channel = ccmni->uart_tx; msg.reserved = 0; ret = ccci_message_send(md_id, &msg, 1); if (ret==-CCCI_ERR_CCIF_NO_PHYSICAL_CHANNEL) contin=1; else { clear_bit(CCMNI_SEND_PENDING,&ccmni->flags); ccmni->send_len=0; } } if (test_bit(CCMNI_RECV_PENDING,&ccmni->flags)) { tasklet_schedule(&ccmni->tasklet); } out: spin_unlock_bh(&ccmni->spinlock); if (contin) mod_timer(&ccmni->timer,jiffies+2); return; }
static void ccmni_read(unsigned long arg) { int part, size; int ret; int read, write, consumed; unsigned char *string; struct ccmni_instance_t *ccmni = (struct ccmni_instance_t *) arg; struct ccci_msg_t msg; struct ccmni_v1_ctl_block_t *ctl_b = (struct ccmni_v1_ctl_block_t *) ccmni->owner; int md_id = ctl_b->m_md_id; char *rx_buffer; spin_lock_bh(&ccmni->spinlock); if (ctl_b->ccci_is_ready == 0) { CCCI_DBG_MSG(md_id, "net", "CCMNI%d_read fail when modem not ready\n", ccmni->channel); goto out; } string = ccmni->read_buffer; read = ccmni->shared_mem->rx_control.read; write = ccmni->shared_mem->rx_control.write; size = write - read; part = 0; rx_buffer = ccmni->shared_mem->buffer; if (size < 0) size += ccmni->shared_mem->rx_control.length; if (read > write) { part = ccmni->shared_mem->rx_control.length - read; memcpy(string, &rx_buffer[read], part); size -= part; string += part; read = 0; } memcpy(string, &rx_buffer[read], size); CCCI_CCMNI_MSG(md_id, "CCMNI%d_receive[Before]: size=%d, read=%d\n", ccmni->channel, (size + part), read); consumed = ccmni_receive(ccmni, size + part); CCCI_CCMNI_MSG(md_id, "CCMNI%d_receive[After]: consume=%d\n", ccmni->channel, consumed); /* Calculate the new position of the read pointer. */ /* Take into consideration the number of bytes actually consumed; */ /* i.e. number of bytes taken up by complete IP packets. */ read += size; if (read >= ccmni->shared_mem->rx_control.length) read -= ccmni->shared_mem->rx_control.length; if (consumed < (size + part)) { read -= ((size + part) - consumed); if (read < 0) read += ccmni->shared_mem->rx_control.length; } ccmni->shared_mem->rx_control.read = read; /* Send an acknowledgement back to modem side. */ CCCI_CCMNI_MSG(md_id, "CCMNI%d_read to write mailbox(ch%d, tty%d)\n", ccmni->channel, ccmni->uart_rx_ack, CCMNI_CHANNEL_OFFSET + ccmni->channel); /* ret = ccci_write_mailbox(ccmni->uart_rx_ack, CCMNI_CHANNEL_OFFSET + ccmni->channel); */ msg.magic = 0xFFFFFFFF; msg.id = CCMNI_CHANNEL_OFFSET + ccmni->channel; msg.channel = ccmni->uart_rx_ack; msg.reserved = 0; ret = ccci_message_send(md_id, &msg, 1); if (ret == -CCCI_ERR_CCIF_NO_PHYSICAL_CHANNEL) { set_bit(CCMNI_RECV_ACK_PENDING, &ccmni->flags); mod_timer(&ccmni->timer, jiffies); } else if (ret == sizeof(struct ccci_msg_t)) clear_bit(CCMNI_RECV_ACK_PENDING, &ccmni->flags); out: spin_unlock_bh(&ccmni->spinlock); CCCI_CCMNI_MSG(md_id, "CCMNI%d_read invoke wake_lock_timeout(1s)\n", ccmni->channel); wake_lock_timeout(&ctl_b->ccmni_wake_lock, HZ); return; }
// The function start_xmit is called when there is one packet to transmit. static int ccmni_v2_start_xmit(struct sk_buff *skb, struct net_device *dev) { int ret = NETDEV_TX_OK; int result = 0; int read_out, avai_in, avai_out, q_length, q_idx; #if CCMNI_DBG_INFO dbg_info_ccmni_t *dbg_info; #endif unsigned char *ccmni_ptr; ccmni_v2_instance_t *ccmni = netdev_priv(dev); ccmni_v2_ctl_block_t *ctl_b = (ccmni_v2_ctl_block_t *)(ccmni->owner); int md_id = ctl_b->m_md_id; ccci_msg_t msg; spin_lock_bh(&ccmni->spinlock); if (ctl_b->ccci_is_ready==0) { CCCI_DBG_MSG(md_id, "net", "CCMNI%d transfer data fail when modem not ready \n", ccmni->channel); ret = NETDEV_TX_BUSY; goto _ccmni_start_xmit_busy; } read_out = ccmni->shared_mem->tx_control.read_out; avai_in = ccmni->shared_mem->tx_control.avai_in; avai_out = ccmni->shared_mem->tx_control.avai_out; q_length = ccmni->shared_mem->tx_control.q_length; if ((read_out < 0) || (avai_out < 0) || (avai_in < 0) || (q_length < 0)) { CCCI_DBG_MSG(md_id, "net", "CCMNI%d_read fail: avai_out=%d, read_out=%d, avai_in=%d, q_length=%d\n", \ ccmni->channel, avai_out, read_out, avai_in, q_length); goto _ccmni_start_xmit_busy; } if ((read_out >= q_length) || (avai_out >= q_length) || (avai_in >= q_length)) { CCCI_DBG_MSG(md_id, "net", "CCMNI%d_read fail: avai_out=%d, read_out=%d, avai_in=%d, q_length=%d\n", \ ccmni->channel, avai_out, read_out, avai_in, q_length); goto _ccmni_start_xmit_busy; } //Choose Q index q_idx = avai_out; ccmni_ptr = ccmni->shared_mem->q_tx_ringbuff[q_idx].ptr; //check if too many data waiting to be read out or Q not initialized yet //ccmni_ptr=NULL when not initialized???? haow.wang if ((q_idx == avai_in) || (ccmni_ptr == NULL) ) { CCCI_DBG_MSG(md_id, "net", "CCMNI%d TX busy and stop queue: q_idx=%d, skb->len=%d \n", \ ccmni->channel, q_idx, skb->len); CCCI_DBG_MSG(md_id, "net", " TX read_out = %d avai_out = %d avai_in = %d\n", \ ccmni->shared_mem->tx_control.read_out, ccmni->shared_mem->tx_control.avai_out, ccmni->shared_mem->tx_control.avai_in); CCCI_DBG_MSG(md_id, "net", " RX read_out = %d avai_out = %d avai_in = %d\n", \ ccmni->shared_mem->rx_control.read_out, ccmni->shared_mem->rx_control.avai_out, ccmni->shared_mem->rx_control.avai_in); netif_stop_queue(ccmni->dev); //Set CCMNI ready to ZERO, and wait for the ACK from modem side. ccmni->ready = 0; ret = NETDEV_TX_BUSY; goto _ccmni_start_xmit_busy; } ccmni_ptr = ccmni_v2_phys_to_virt(md_id, (unsigned char *)(ccmni->shared_mem->q_tx_ringbuff[q_idx].ptr)); CCCI_CCMNI_MSG(md_id, "CCMNI%d_start_xmit: skb_len=%d, ccmni_ready=%d \n", \ ccmni->channel, skb->len, ccmni->ready); if (skb->len > CCMNI_MTU) { //Sanity check; this should not happen! //Digest and return OK. CCCI_DBG_MSG(md_id, "net", "CCMNI%d packet size exceed 1500 bytes: size=%d \n", \ ccmni->channel, skb->len); dev->stats.tx_dropped++; goto _ccmni_start_xmit_exit; } #if CCMNI_DBG_INFO //DBG info dbg_info = (dbg_info_ccmni_t *)(ccmni_ptr - CCMNI_BUFF_HEADER_SIZE - CCMNI_BUFF_DBG_INFO_SIZE); dbg_info->avai_out_no = q_idx; #endif memcpy(ccmni_ptr, skb->data, skb->len); ccmni->shared_mem->q_tx_ringbuff[q_idx].len = skb->len; //End byte *(unsigned char*)(ccmni_ptr + skb->len) = CCMNI_DATA_END; mb(); //Update avail_out after data buffer filled q_idx++; ccmni->shared_mem->tx_control.avai_out = (q_idx & (q_length - 1)); mb(); msg.addr = 0; msg.len = skb->len; msg.channel = ccmni->uart_tx; msg.reserved = 0; result = ccci_message_send(md_id, &msg, 1); if (result==-CCCI_ERR_CCIF_NO_PHYSICAL_CHANNEL) { set_bit(CCMNI_SEND_PENDING,&ccmni->flags); ccmni->send_len +=skb->len; mod_timer(&ccmni->timer,jiffies); } else if (result==sizeof(ccci_msg_t)) clear_bit(CCMNI_SEND_PENDING,&ccmni->flags); dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; _ccmni_start_xmit_exit: dev_kfree_skb(skb); _ccmni_start_xmit_busy: spin_unlock_bh(&ccmni->spinlock); return ret; }
static void ccmni_v2_read(unsigned long arg) { int ret; int read_out, avai_out, avai_in, q_length; int packet_cnt, packet_cnt_save, consumed; int rx_buf_res_left_cnt; #if CCMNI_DBG_INFO dbg_info_ccmni_t *dbg_info; #endif ccmni_v2_instance_t *ccmni = (ccmni_v2_instance_t *) arg; unsigned char *ccmni_ptr; unsigned int ccmni_len, q_idx; ccmni_v2_ctl_block_t *ctl_b = (ccmni_v2_ctl_block_t*)ccmni->owner; int md_id = ctl_b->m_md_id; ccci_msg_t msg; if (ccmni == NULL) { CCCI_DBG_MSG(md_id, "net", "[Error]CCMNI%d_read: invalid private data\n", ccmni->channel); return; } spin_lock_bh(&ccmni->spinlock); if (ctl_b->ccci_is_ready==0) { CCCI_DBG_MSG(md_id, "net", "CCMNI%d_read fail when modem not ready\n", ccmni->channel); goto out; } read_out = ccmni->shared_mem->rx_control.read_out; avai_out = ccmni->shared_mem->rx_control.avai_out; avai_in = ccmni->shared_mem->rx_control.avai_in; q_length = ccmni->shared_mem->rx_control.q_length; if ((read_out < 0) || (avai_out < 0) || (avai_in < 0) || (q_length < 0)) { CCCI_DBG_MSG(md_id, "net", "CCMNI%d_read fail: avai_out=%d, read_out=%d, avai_in=%d, q_length=%d\n", \ ccmni->channel, avai_out, read_out, avai_in, q_length); goto out; } if ((read_out >= q_length) || (avai_out >= q_length) || (avai_in >= q_length)) { CCCI_DBG_MSG(md_id, "net", "CCMNI%d_read fail: avai_out=%d, read_out=%d, avai_in=%d, q_length=%d\n", \ ccmni->channel, avai_out, read_out, avai_in, q_length); goto out; } //Number of packets waiting to be processed packet_cnt = avai_out >= read_out ? (avai_out - read_out) : (avai_out - read_out + q_length); packet_cnt_save = packet_cnt; rx_buf_res_left_cnt = avai_in >= avai_out ? (avai_in - avai_out) : (avai_in - avai_out + q_length); if (packet_cnt <= 0) { CCCI_DBG_MSG(md_id, "net", "CCMNI%d_read fail: nothing to read, avai_out=%d, read_out=%d, q_length=%d\n", \ ccmni->channel, avai_out, read_out, q_length); goto out; } q_idx = read_out; CCCI_CCMNI_MSG(md_id, "CCMNI%d_receive[Before]: avai_out=%d, read_out=%d, avai_in=%d, packet_cnt=%d\n", \ ccmni->channel, avai_out, read_out, avai_in, packet_cnt); consumed = 0; for (; packet_cnt > 0; packet_cnt--) { q_idx &= q_length - 1; ccmni_ptr = ccmni_v2_phys_to_virt(md_id, (unsigned char *)(ccmni->shared_mem->q_rx_ringbuff[q_idx].ptr)); ccmni_len = ccmni->shared_mem->q_rx_ringbuff[q_idx].len; #if CCMNI_DBG_INFO //DBG info dbg_info = (dbg_info_ccmni_t *)(ccmni_ptr - CCMNI_BUFF_HEADER_SIZE - CCMNI_BUFF_DBG_INFO_SIZE); #endif if (-CCCI_ERR_MEM_CHECK_FAIL == ccmni_v2_check_info(md_id, ccmni->channel, ccmni_ptr, ccmni_len)) { CCCI_DBG_MSG(md_id, "net", "CCMNI%d_read: check info error, read_out=%d\n", ccmni->channel, read_out); #if CCMNI_DBG_INFO //dbg_info->port = ccmni->channel; dbg_info->avai_in_no = q_idx; //dbg_info->avai_out_no = q_idx; dbg_info->read_out_no = q_idx; #endif avai_in++; avai_in &= q_length - 1; ccmni->shared_mem->q_rx_ringbuff[avai_in].ptr = ccmni->shared_mem->q_rx_ringbuff[q_idx].ptr; ccmni_ptr = ccmni_v2_phys_to_virt(md_id, (unsigned char *)(ccmni->shared_mem->q_rx_ringbuff[avai_in].ptr)); #if CCMNI_DBG_INFO dbg_info = (dbg_info_ccmni_t *)(ccmni_ptr - CCMNI_BUFF_HEADER_SIZE - CCMNI_BUFF_DBG_INFO_SIZE); dbg_info->avai_in_no = avai_in; #endif q_idx++; consumed++; continue; } ret = ccmni_v2_receive(ccmni, ccmni_ptr, ccmni_len); if(0 == ret) { #if CCMNI_DBG_INFO //dbg_info->port = ccmni->channel; dbg_info->avai_in_no = q_idx; //dbg_info->avai_out_no = q_idx; dbg_info->read_out_no = q_idx; #endif avai_in++; avai_in &= q_length - 1; ccmni->shared_mem->q_rx_ringbuff[avai_in].ptr = ccmni->shared_mem->q_rx_ringbuff[q_idx].ptr; ccmni_ptr = ccmni_v2_phys_to_virt(md_id, (unsigned char *)(ccmni->shared_mem->q_rx_ringbuff[avai_in].ptr)); #if CCMNI_DBG_INFO dbg_info = (dbg_info_ccmni_t *)(ccmni_ptr - CCMNI_BUFF_HEADER_SIZE - CCMNI_BUFF_DBG_INFO_SIZE); dbg_info->avai_in_no = avai_in; #endif q_idx++; consumed++; } else if (-CCCI_ERR_MEM_CHECK_FAIL == ret) { //If dev_alloc_skb() failed, retry right now may still fail. So setup timer, and retry later. set_bit(CCMNI_RECV_PENDING,&ccmni->flags); //avai_in++; //avai_in &= q_length - 1; //ccmni->shared_mem->q_rx_ringbuff[avai_in].ptr = ccmni->shared_mem->q_rx_ringbuff[q_idx].ptr; //ccmni->dev->stats.rx_dropped++; CCCI_DBG_MSG(md_id, "net", "CCMNI%d_read: no sk_buff, retrying, read_out=%d, avai_out=%d\n", \ ccmni->channel, q_idx, avai_out); mod_timer(&ccmni->timer,jiffies + msecs_to_jiffies(10)); //10 ms??? break; //q_idx++; //consumed++; } } read_out = (q_idx & (q_length - 1)); CCCI_CCMNI_MSG(md_id, "CCMNI%d_receive[After]: consumed=%d\n", ccmni->channel, consumed); if (consumed > packet_cnt_save) { //Sanity check. This should not happen! CCCI_DBG_MSG(md_id, "net", "CCMNI%d_read fail: consumed more than packet_cnt, consumed = %d, packet_cnt = %d\n", \ ccmni->channel, consumed, packet_cnt_save); //Should ignore all data in buffer??? haow.wang ccmni->shared_mem->rx_control.read_out = avai_out; ccmni->shared_mem->rx_control.avai_in = avai_in; goto out; } ccmni->shared_mem->rx_control.read_out = read_out; ccmni->shared_mem->rx_control.avai_in = avai_in; CCCI_CCMNI_MSG(md_id, "CCMNI%d_read to write mailbox(ch%d, tty%d)\n", ccmni->channel, ccmni->uart_rx_ack, CCMNI_CHANNEL_OFFSET + ccmni->channel); msg.magic = 0xFFFFFFFF; msg.id = CCMNI_CHANNEL_OFFSET + ccmni->channel; msg.channel = ccmni->uart_rx_ack; msg.reserved = 0; ret = ccci_message_send(md_id, &msg, 1); if (ret==-CCCI_ERR_CCIF_NO_PHYSICAL_CHANNEL) { set_bit(CCMNI_RECV_ACK_PENDING,&ccmni->flags); mod_timer(&ccmni->timer,jiffies); } else if (ret==sizeof(ccci_msg_t)) clear_bit(CCMNI_RECV_ACK_PENDING,&ccmni->flags); out: spin_unlock_bh(&ccmni->spinlock); CCCI_CCMNI_MSG(md_id, "CCMNI%d_read invoke wake_lock_timeout(1s)\n", ccmni->channel); wake_lock_timeout(&ctl_b->ccmni_wake_lock, HZ); return; }