beceem: make transmit thread interruptible
authorStephen Hemminger <stephen.hemminger@vyatta.com>
Mon, 1 Nov 2010 13:49:30 +0000 (09:49 -0400)
committerStephen Hemminger <stephen.hemminger@vyatta.com>
Mon, 1 Nov 2010 13:49:30 +0000 (09:49 -0400)
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>
drivers/staging/bcm/Transmit.c

index 9932d71..1f69625 100644 (file)
@@ -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,118 +50,59 @@ SendPacketFromQueue->SetupNextSend->bcm_cmd53
 *
 *********************************************************************/
 
-INT bcm_transmit(struct sk_buff *skb,          /**< skb */
-                                       struct net_device *dev  /**< net device pointer */
-                                       )
+netdev_tx_t bcm_transmit(struct sk_buff *skb, struct net_device *dev)
 {
-       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__);
+       PMINI_ADAPTER           Adapter = GET_BCM_ADAPTER(dev);
+       SHORT qindex;
 
-       memset(&tv, 0, sizeof(tv));
-       /* Check for valid parameters */
-       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);
-       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);
+       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",
+       if (INVALID_QUEUE_INDEX==qindex)        {
+               if (ntohs(eth_hdr(skb)->h_proto) != ETH_ARP_FRAME)
+                       goto drop;
 
-                (*(PUCHAR)(skb->data + 21)));
+               /*
+                 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;
+       }
 
-                reply_to_arp_request(skb);
+       if (Adapter->PackInfo[qindex].uiCurrentPacketsOnHost >= SF_MAX_ALLOWED_PACKETS_TO_BACKUP)
+               return NETDEV_TX_BUSY;
 
-                BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX,TX_OSAL_DBG, DBG_LVL_ALL,"After reply_to_arp_request \n");
+       /* 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++;
 
-                       }
-                       else
-                       {
-                BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL,
-                       "Invalid queue index, dropping pkt\n");
+       *((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);
 
-                               dev_kfree_skb(skb);
-                       }
-                       return STATUS_SUCCESS;
-        }
+       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL,"ENQ: \n");
 
-               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, "<====");
+       /* 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);
        }
-       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 @@ errExit:
        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);
+               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;
 }