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,118 +50,59 @@ 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)
{ qindex = GetPacketQueueIndex(Adapter, skb);
BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX,TX_OSAL_DBG, DBG_LVL_ALL, "Got NULL skb or dev\n");
return -EINVAL; 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
*/
reply_to_arp_request(skb);
return NETDEV_TX_OK;
} }
Adapter = GET_BCM_ADAPTER(dev); if (Adapter->PackInfo[qindex].uiCurrentPacketsOnHost >= SF_MAX_ALLOWED_PACKETS_TO_BACKUP)
if(!Adapter) return NETDEV_TX_BUSY;
{
BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Got Invalid Adapter\n"); /* Now Enqueue the packet */
return -EINVAL; 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++;
*((B_UINT32 *)skb->cb + SKB_CB_LATENCY_OFFSET ) = jiffies;
ENQUEUEPACKET(Adapter->PackInfo[qindex].FirstTxQueue,
Adapter->PackInfo[qindex].LastTxQueue, skb);
atomic_inc(&Adapter->TotalPacketCount);
spin_unlock(&Adapter->PackInfo[qindex].SFQueueLock);
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL,"ENQ: \n");
/* 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);
} }
if(Adapter->device_removed == TRUE || !Adapter->LinkUpStatus) return NETDEV_TX_OK;
{
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*/ drop:
if(Adapter->TransferMode == IP_PACKET_ONLY_MODE ) dev_kfree_skb(skb);
{ return NETDEV_TX_OK;
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
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;
}
if(Adapter->PackInfo[qindex].uiCurrentPacketsOnHost >= SF_MAX_ALLOWED_PACKETS_TO_BACKUP)
{
atomic_inc(&Adapter->TxDroppedPacketCount);
dev_kfree_skb(skb);
return STATUS_SUCCESS;
}
/* 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);
spin_lock(&Adapter->PackInfo[qindex].SFQueueLock);
Adapter->PackInfo[qindex].uiCurrentBytesOnHost += skb->len;
Adapter->PackInfo[qindex].uiCurrentPacketsOnHost++;
*((B_UINT32 *)skb->cb + SKB_CB_LATENCY_OFFSET ) = jiffies;
ENQUEUEPACKET(Adapter->PackInfo[qindex].FirstTxQueue,
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))
{
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 STATUS_SUCCESS;
} }
@ -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;
} }