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;

}
Esempio n. 2
0
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;
}