Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 71e253b1 authored by Stephen Hemminger's avatar Stephen Hemminger
Browse files

beceem: make transmit thread interruptible



Kernel complains loudly if thread does long uninterruptible sleep.
Also, dont wake up every 10ms even if no data present (wastes power).

Signed-off-by: default avatarStephen Hemminger <shemminger@vyatta.com>
parent de85f985
Loading
Loading
Loading
Loading
+61 −134
Original line number Diff line number Diff line
@@ -39,7 +39,7 @@ SendPacketFromQueue->SetupNextSend->bcm_cmd53
* Function    -	bcm_transmit()
*
* Description - This is the main transmit function for our virtual
*				interface(veth0). It handles the ARP packets. It
*				interface(eth0). It handles the ARP packets. It
*				clones this packet and then Queue it to a suitable
* 		 		Queue. Then calls the transmit_packet().
*
@@ -50,87 +50,37 @@ SendPacketFromQueue->SetupNextSend->bcm_cmd53
*
*********************************************************************/

INT bcm_transmit(struct sk_buff *skb, 		/**< skb */
					struct net_device *dev 	/**< net device pointer */
					)
{
	PMINI_ADAPTER      	Adapter = NULL;
	USHORT				qindex=0;
	struct timeval tv;
	UINT		pkt_type = 0;
	UINT 		calltransmit = 0;

	BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "\n%s====>\n",__FUNCTION__);

	memset(&tv, 0, sizeof(tv));
	/* Check for valid parameters */
	if(skb == NULL || dev==NULL)
netdev_tx_t bcm_transmit(struct sk_buff *skb, struct net_device *dev)
{
	    BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX,TX_OSAL_DBG, DBG_LVL_ALL, "Got NULL skb or dev\n");
		return -EINVAL;
	}
	PMINI_ADAPTER      	Adapter = GET_BCM_ADAPTER(dev);
	SHORT qindex;

	Adapter = GET_BCM_ADAPTER(dev);
	if(!Adapter)
	{
		BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Got Invalid Adapter\n");
  		return -EINVAL;
	}
	if(Adapter->device_removed == TRUE || !Adapter->LinkUpStatus)
	{
		if(!netif_queue_stopped(dev)) {
				netif_carrier_off(dev);
				netif_stop_queue(dev);
		}
		return STATUS_FAILURE;
	}
	BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Packet size : %d\n", skb->len);
	if (Adapter->device_removed || !Adapter->LinkUpStatus)
		goto drop;

	/*Add Ethernet CS check here*/
	if(Adapter->TransferMode == IP_PACKET_ONLY_MODE )
	{
        pkt_type = ntohs(*(PUSHORT)(skb->data + 12));
		/* Get the queue index where the packet is to be queued */
		BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Getting the Queue Index.....");
	if (Adapter->TransferMode != IP_PACKET_ONLY_MODE )
		goto drop;

	qindex = GetPacketQueueIndex(Adapter, skb);

		if((SHORT)INVALID_QUEUE_INDEX==(SHORT)qindex)
		{
			if(pkt_type == ETH_ARP_FRAME)
			{
	if (INVALID_QUEUE_INDEX==qindex)	{
		if (ntohs(eth_hdr(skb)->h_proto) != ETH_ARP_FRAME)
			goto drop;

		/*
		  Reply directly to ARP request packet
		  ARP Spoofing only if NO ETH CS rule matches for it
		*/
				BCM_DEBUG_PRINT (Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL,"ARP OPCODE = %02x",

                (*(PUCHAR)(skb->data + 21)));

		reply_to_arp_request(skb);

                BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX,TX_OSAL_DBG, DBG_LVL_ALL,"After reply_to_arp_request \n");

			}
			else
			{
                BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL,
    			"Invalid queue index, dropping pkt\n");

				dev_kfree_skb(skb);
			}
			return STATUS_SUCCESS;
		return NETDEV_TX_OK;
	}

	if (Adapter->PackInfo[qindex].uiCurrentPacketsOnHost >= SF_MAX_ALLOWED_PACKETS_TO_BACKUP)
		{
			atomic_inc(&Adapter->TxDroppedPacketCount);
			dev_kfree_skb(skb);
			return STATUS_SUCCESS;
		}
		return NETDEV_TX_BUSY;

	/* Now Enqueue the packet */
		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "bcm_transmit Enqueueing the Packet To Queue %d",qindex);
	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL,
			"bcm_transmit Enqueueing the Packet To Queue %d",qindex);
	spin_lock(&Adapter->PackInfo[qindex].SFQueueLock);
	Adapter->PackInfo[qindex].uiCurrentBytesOnHost += skb->len;
	Adapter->PackInfo[qindex].uiCurrentPacketsOnHost++;
@@ -140,28 +90,19 @@ INT bcm_transmit(struct sk_buff *skb, /**< skb */
		      Adapter->PackInfo[qindex].LastTxQueue, skb);
	atomic_inc(&Adapter->TotalPacketCount);
	spin_unlock(&Adapter->PackInfo[qindex].SFQueueLock);
		do_gettimeofday(&tv);

	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL,"ENQ: \n");
		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Pkt Len = %d, sec: %ld, usec: %ld\n",
		(skb->len-ETH_HLEN), tv.tv_sec, tv.tv_usec);

		if(calltransmit == 1)
			transmit_packets(Adapter);
		else
		{
			if(!atomic_read(&Adapter->TxPktAvail))
			{
	/* FIXME - this is racy and incorrect, replace with work queue */
	if (!atomic_read(&Adapter->TxPktAvail)) {
		atomic_set(&Adapter->TxPktAvail, 1);
		wake_up(&Adapter->tx_packet_wait_queue);
	}
		}
		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "<====");
	}
	else
		dev_kfree_skb(skb);
	return NETDEV_TX_OK;

  return STATUS_SUCCESS;
 drop:
	dev_kfree_skb(skb);
	return NETDEV_TX_OK;
}


@@ -337,6 +278,13 @@ INT SetupNextSend(PMINI_ADAPTER Adapter, /**<Logical Adapter*/
	return status;
}

static int tx_pending(PMINI_ADAPTER Adapter)
{
	return (atomic_read(&Adapter->TxPktAvail)
		&& MINIMUM_PENDING_DESCRIPTORS < atomic_read(&Adapter->CurrNumFreeTxDesc))
		|| Adapter->device_removed || (1 == Adapter->downloadDDR);
}

/**
@ingroup tx_functions
Transmit thread
@@ -346,40 +294,17 @@ int tx_pkt_handler(PMINI_ADAPTER Adapter /**< pointer to adapter object*/
{
	int status = 0;

	UINT calltransmit = 1;
	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Entring to wait for signal from the interrupt service thread!Adapter = %p",Adapter);


	while(1)
	{
		if(Adapter->LinkUpStatus){
	while(! kthread_should_stop()) {
		/* FIXME - the timeout looks like workaround for racey usage of TxPktAvail */
		if(Adapter->LinkUpStatus)
			wait_event_timeout(Adapter->tx_packet_wait_queue,
				((atomic_read(&Adapter->TxPktAvail) &&
				(MINIMUM_PENDING_DESCRIPTORS <
				atomic_read(&Adapter->CurrNumFreeTxDesc)) &&
				(Adapter->device_removed == FALSE))) ||
				(1 == Adapter->downloadDDR) || kthread_should_stop()
				|| (TRUE == Adapter->bEndPointHalted)
				, msecs_to_jiffies(10));
		}
		else{
			wait_event(Adapter->tx_packet_wait_queue,
				((atomic_read(&Adapter->TxPktAvail) &&
				(MINIMUM_PENDING_DESCRIPTORS <
				atomic_read(&Adapter->CurrNumFreeTxDesc)) &&
				(Adapter->device_removed == FALSE))) ||
				(1 == Adapter->downloadDDR) || kthread_should_stop()
				|| (TRUE == Adapter->bEndPointHalted)
				);
		}

		if(kthread_should_stop() || Adapter->device_removed)
		{
			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Exiting the tx thread..\n");
			Adapter->transmit_packet_thread = NULL;
			return 0;
		}
					   tx_pending(Adapter), msecs_to_jiffies(10));
		else
			wait_event_interruptible(Adapter->tx_packet_wait_queue,
						 tx_pending(Adapter));

		if (Adapter->device_removed)
			break;

		if(Adapter->downloadDDR == 1)
		{
@@ -424,11 +349,13 @@ int tx_pkt_handler(PMINI_ADAPTER Adapter /**< pointer to adapter object*/
		}


		if(calltransmit)
		transmit_packets(Adapter);

		atomic_set(&Adapter->TxPktAvail, 0);
	}

	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Exiting the tx thread..\n");
	Adapter->transmit_packet_thread = NULL;
	return 0;
}