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: Stephen Hemminger <shemminger@vyatta.com>
This commit is contained in:
Stephen Hemminger 2010-11-01 09:49:30 -04:00
parent de85f98589
commit 71e253b169

View File

@ -39,7 +39,7 @@ SendPacketFromQueue->SetupNextSend->bcm_cmd53
* Function - bcm_transmit() * Function - bcm_transmit()
* *
* Description - This is the main transmit function for our virtual * 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 * clones this packet and then Queue it to a suitable
* Queue. Then calls the transmit_packet(). * Queue. Then calls the transmit_packet().
* *
@ -50,87 +50,37 @@ SendPacketFromQueue->SetupNextSend->bcm_cmd53
* *
*********************************************************************/ *********************************************************************/
INT bcm_transmit(struct sk_buff *skb, /**< skb */ netdev_tx_t bcm_transmit(struct sk_buff *skb, struct net_device *dev)
struct net_device *dev /**< net device pointer */
)
{ {
PMINI_ADAPTER Adapter = NULL; PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev);
USHORT qindex=0; SHORT qindex;
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__); if (Adapter->device_removed || !Adapter->LinkUpStatus)
goto drop;
memset(&tv, 0, sizeof(tv)); if (Adapter->TransferMode != IP_PACKET_ONLY_MODE )
/* Check for valid parameters */ goto drop;
if(skb == NULL || dev==NULL)
{
BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX,TX_OSAL_DBG, DBG_LVL_ALL, "Got NULL skb or dev\n");
return -EINVAL;
}
Adapter = GET_BCM_ADAPTER(dev); qindex = GetPacketQueueIndex(Adapter, skb);
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);
/*Add Ethernet CS check here*/ if (INVALID_QUEUE_INDEX==qindex) {
if(Adapter->TransferMode == IP_PACKET_ONLY_MODE ) if (ntohs(eth_hdr(skb)->h_proto) != ETH_ARP_FRAME)
{ goto drop;
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.....");
qindex = GetPacketQueueIndex(Adapter,skb);
if((SHORT)INVALID_QUEUE_INDEX==(SHORT)qindex)
{
if(pkt_type == ETH_ARP_FRAME)
{
/* /*
Reply directly to ARP request packet Reply directly to ARP request packet
ARP Spoofing only if NO ETH CS rule matches for it 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); reply_to_arp_request(skb);
return NETDEV_TX_OK;
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;
} }
if(Adapter->PackInfo[qindex].uiCurrentPacketsOnHost >= SF_MAX_ALLOWED_PACKETS_TO_BACKUP) if (Adapter->PackInfo[qindex].uiCurrentPacketsOnHost >= SF_MAX_ALLOWED_PACKETS_TO_BACKUP)
{ return NETDEV_TX_BUSY;
atomic_inc(&Adapter->TxDroppedPacketCount);
dev_kfree_skb(skb);
return STATUS_SUCCESS;
}
/* Now Enqueue the packet */ /* 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); spin_lock(&Adapter->PackInfo[qindex].SFQueueLock);
Adapter->PackInfo[qindex].uiCurrentBytesOnHost += skb->len; Adapter->PackInfo[qindex].uiCurrentBytesOnHost += skb->len;
Adapter->PackInfo[qindex].uiCurrentPacketsOnHost++; Adapter->PackInfo[qindex].uiCurrentPacketsOnHost++;
@ -140,28 +90,19 @@ INT bcm_transmit(struct sk_buff *skb, /**< skb */
Adapter->PackInfo[qindex].LastTxQueue, skb); Adapter->PackInfo[qindex].LastTxQueue, skb);
atomic_inc(&Adapter->TotalPacketCount); atomic_inc(&Adapter->TotalPacketCount);
spin_unlock(&Adapter->PackInfo[qindex].SFQueueLock); 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,"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) /* FIXME - this is racy and incorrect, replace with work queue */
transmit_packets(Adapter); if (!atomic_read(&Adapter->TxPktAvail)) {
else
{
if(!atomic_read(&Adapter->TxPktAvail))
{
atomic_set(&Adapter->TxPktAvail, 1); atomic_set(&Adapter->TxPktAvail, 1);
wake_up(&Adapter->tx_packet_wait_queue); wake_up(&Adapter->tx_packet_wait_queue);
} }
} return NETDEV_TX_OK;
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "<====");
}
else
dev_kfree_skb(skb);
return STATUS_SUCCESS; drop:
dev_kfree_skb(skb);
return NETDEV_TX_OK;
} }
@ -337,6 +278,13 @@ errExit:
return status; 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 @ingroup tx_functions
Transmit thread Transmit thread
@ -346,40 +294,17 @@ int tx_pkt_handler(PMINI_ADAPTER Adapter /**< pointer to adapter object*/
{ {
int status = 0; int status = 0;
UINT calltransmit = 1; while(! kthread_should_stop()) {
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); /* FIXME - the timeout looks like workaround for racey usage of TxPktAvail */
if(Adapter->LinkUpStatus)
while(1)
{
if(Adapter->LinkUpStatus){
wait_event_timeout(Adapter->tx_packet_wait_queue, wait_event_timeout(Adapter->tx_packet_wait_queue,
((atomic_read(&Adapter->TxPktAvail) && tx_pending(Adapter), msecs_to_jiffies(10));
(MINIMUM_PENDING_DESCRIPTORS < else
atomic_read(&Adapter->CurrNumFreeTxDesc)) && wait_event_interruptible(Adapter->tx_packet_wait_queue,
(Adapter->device_removed == FALSE))) || tx_pending(Adapter));
(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;
}
if (Adapter->device_removed)
break;
if(Adapter->downloadDDR == 1) if(Adapter->downloadDDR == 1)
{ {
@ -424,11 +349,13 @@ int tx_pkt_handler(PMINI_ADAPTER Adapter /**< pointer to adapter object*/
} }
if(calltransmit)
transmit_packets(Adapter); transmit_packets(Adapter);
atomic_set(&Adapter->TxPktAvail, 0); 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; return 0;
} }