linux/drivers/staging/bcm/Transmit.c
<<
>>
Prefs
   1/**
   2@file Transmit.c
   3@defgroup tx_functions Transmission
   4@section Queueing
   5@dot
   6digraph transmit1 {
   7node[shape=box]
   8edge[weight=5;color=red]
   9
  10bcm_transmit->GetPacketQueueIndex[label="IP Packet"]
  11GetPacketQueueIndex->IpVersion4[label="IPV4"]
  12GetPacketQueueIndex->IpVersion6[label="IPV6"]
  13}
  14
  15@enddot
  16
  17@section De-Queueing
  18@dot
  19digraph transmit2 {
  20node[shape=box]
  21edge[weight=5;color=red]
  22interrupt_service_thread->transmit_packets
  23tx_pkt_hdler->transmit_packets
  24transmit_packets->CheckAndSendPacketFromIndex
  25transmit_packets->UpdateTokenCount
  26CheckAndSendPacketFromIndex->PruneQueue
  27CheckAndSendPacketFromIndex->IsPacketAllowedForFlow
  28CheckAndSendPacketFromIndex->SendControlPacket[label="control pkt"]
  29SendControlPacket->bcm_cmd53
  30CheckAndSendPacketFromIndex->SendPacketFromQueue[label="data pkt"]
  31SendPacketFromQueue->SetupNextSend->bcm_cmd53
  32}
  33@enddot
  34*/
  35
  36#include "headers.h"
  37
  38
  39/**
  40@ingroup ctrl_pkt_functions
  41This function dispatches control packet to the h/w interface
  42@return zero(success) or -ve value(failure)
  43*/
  44INT SendControlPacket(PMINI_ADAPTER Adapter, char *pControlPacket)
  45{
  46        PLEADER PLeader = (PLEADER)pControlPacket;
  47
  48        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Tx");
  49        if(!pControlPacket || !Adapter)
  50        {
  51                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Got NULL Control Packet or Adapter");
  52                return STATUS_FAILURE;
  53        }
  54        if((atomic_read( &Adapter->CurrNumFreeTxDesc ) <
  55                ((PLeader->PLength-1)/MAX_DEVICE_DESC_SIZE)+1))
  56    {
  57        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "NO FREE DESCRIPTORS TO SEND CONTROL PACKET");
  58        return STATUS_FAILURE;
  59    }
  60
  61        /* Update the netdevice statistics */
  62        /* Dump Packet  */
  63        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader Status: %x", PLeader->Status);
  64        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader VCID: %x",PLeader->Vcid);
  65        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader Length: %x",PLeader->PLength);
  66        if(Adapter->device_removed)
  67                return 0;
  68
  69        if (netif_msg_pktdata(Adapter))
  70                print_hex_dump(KERN_DEBUG, PFX "tx control: ", DUMP_PREFIX_NONE,
  71                               16, 1, pControlPacket, PLeader->PLength + LEADER_SIZE, 0);
  72
  73        Adapter->interface_transmit(Adapter->pvInterfaceAdapter,
  74                                        pControlPacket, (PLeader->PLength + LEADER_SIZE));
  75
  76        atomic_dec(&Adapter->CurrNumFreeTxDesc);
  77        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "<=========");
  78        return STATUS_SUCCESS;
  79}
  80
  81/**
  82@ingroup tx_functions
  83This function despatches the IP packets with the given vcid
  84to the target via the host h/w interface.
  85@return  zero(success) or -ve value(failure)
  86*/
  87INT SetupNextSend(PMINI_ADAPTER Adapter,  struct sk_buff *Packet, USHORT Vcid)
  88{
  89        int             status=0;
  90        BOOLEAN bHeaderSupressionEnabled = FALSE;
  91        B_UINT16            uiClassifierRuleID;
  92        u16     QueueIndex = skb_get_queue_mapping(Packet);
  93        LEADER Leader={0};
  94
  95        if(Packet->len > MAX_DEVICE_DESC_SIZE)
  96        {
  97                status = STATUS_FAILURE;
  98                goto errExit;
  99        }
 100
 101        /* Get the Classifier Rule ID */
 102        uiClassifierRuleID = *((UINT32*) (Packet->cb)+SKB_CB_CLASSIFICATION_OFFSET);
 103
 104        bHeaderSupressionEnabled = Adapter->PackInfo[QueueIndex].bHeaderSuppressionEnabled
 105                & Adapter->bPHSEnabled;
 106
 107        if(Adapter->device_removed)
 108                {
 109                status = STATUS_FAILURE;
 110                goto errExit;
 111                }
 112
 113        status = PHSTransmit(Adapter, &Packet, Vcid, uiClassifierRuleID, bHeaderSupressionEnabled,
 114                                                        (UINT *)&Packet->len, Adapter->PackInfo[QueueIndex].bEthCSSupport);
 115
 116        if(status != STATUS_SUCCESS)
 117        {
 118                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "PHS Transmit failed..\n");
 119                goto errExit;
 120        }
 121
 122        Leader.Vcid     = Vcid;
 123
 124        if(TCP_ACK == *((UINT32*) (Packet->cb) + SKB_CB_TCPACK_OFFSET ))
 125                Leader.Status = LEADER_STATUS_TCP_ACK;
 126        else
 127                Leader.Status = LEADER_STATUS;
 128
 129        if(Adapter->PackInfo[QueueIndex].bEthCSSupport)
 130        {
 131                Leader.PLength = Packet->len;
 132                if(skb_headroom(Packet) < LEADER_SIZE)
 133        {
 134                        if((status = skb_cow(Packet,LEADER_SIZE)))
 135                        {
 136                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL,"bcm_transmit : Failed To Increase headRoom\n");
 137                                goto errExit;
 138                        }
 139                }
 140                skb_push(Packet, LEADER_SIZE);
 141                memcpy(Packet->data, &Leader, LEADER_SIZE);
 142        }
 143        else
 144        {
 145                Leader.PLength = Packet->len - ETH_HLEN;
 146                memcpy((LEADER*)skb_pull(Packet, (ETH_HLEN - LEADER_SIZE)), &Leader, LEADER_SIZE);
 147        }
 148
 149        status = Adapter->interface_transmit(Adapter->pvInterfaceAdapter,
 150                        Packet->data, (Leader.PLength + LEADER_SIZE));
 151        if(status)
 152        {
 153                ++Adapter->dev->stats.tx_errors;
 154                if (netif_msg_tx_err(Adapter))
 155                        pr_info(PFX "%s: transmit error %d\n", Adapter->dev->name,
 156                                status);
 157        }
 158        else
 159        {
 160                struct net_device_stats *netstats = &Adapter->dev->stats;
 161                Adapter->PackInfo[QueueIndex].uiTotalTxBytes += Leader.PLength;
 162
 163                netstats->tx_bytes += Leader.PLength;
 164                ++netstats->tx_packets;
 165
 166                Adapter->PackInfo[QueueIndex].uiCurrentTokenCount -= Leader.PLength << 3;
 167                Adapter->PackInfo[QueueIndex].uiSentBytes += (Packet->len);
 168                Adapter->PackInfo[QueueIndex].uiSentPackets++;
 169                Adapter->PackInfo[QueueIndex].NumOfPacketsSent++;
 170
 171                atomic_dec(&Adapter->PackInfo[QueueIndex].uiPerSFTxResourceCount);
 172                Adapter->PackInfo[QueueIndex].uiThisPeriodSentBytes += Leader.PLength;
 173        }
 174
 175        atomic_dec(&Adapter->CurrNumFreeTxDesc);
 176
 177errExit:
 178
 179        dev_kfree_skb(Packet);
 180        return status;
 181}
 182
 183static int tx_pending(PMINI_ADAPTER Adapter)
 184{
 185        return (atomic_read(&Adapter->TxPktAvail)
 186                && MINIMUM_PENDING_DESCRIPTORS < atomic_read(&Adapter->CurrNumFreeTxDesc))
 187                || Adapter->device_removed || (1 == Adapter->downloadDDR);
 188}
 189
 190/**
 191@ingroup tx_functions
 192Transmit thread
 193*/
 194int tx_pkt_handler(PMINI_ADAPTER Adapter  /**< pointer to adapter object*/
 195                                )
 196{
 197        int status = 0;
 198
 199        while(! kthread_should_stop()) {
 200                /* FIXME - the timeout looks like workaround for racey usage of TxPktAvail */
 201                if(Adapter->LinkUpStatus)
 202                        wait_event_timeout(Adapter->tx_packet_wait_queue,
 203                                           tx_pending(Adapter), msecs_to_jiffies(10));
 204                else
 205                        wait_event_interruptible(Adapter->tx_packet_wait_queue,
 206                                                 tx_pending(Adapter));
 207
 208                if (Adapter->device_removed)
 209                        break;
 210
 211                if(Adapter->downloadDDR == 1)
 212                {
 213                        Adapter->downloadDDR +=1;
 214                        status = download_ddr_settings(Adapter);
 215                        if(status)
 216                                pr_err(PFX "DDR DOWNLOAD FAILED! %d\n", status);
 217                        continue;
 218                }
 219
 220                //Check end point for halt/stall.
 221                if(Adapter->bEndPointHalted == TRUE)
 222                {
 223                        Bcm_clear_halt_of_endpoints(Adapter);
 224                        Adapter->bEndPointHalted = FALSE;
 225                        StartInterruptUrb((PS_INTERFACE_ADAPTER)(Adapter->pvInterfaceAdapter));
 226                }
 227
 228                if(Adapter->LinkUpStatus && !Adapter->IdleMode)
 229                {
 230                        if(atomic_read(&Adapter->TotalPacketCount))
 231                        {
 232                                update_per_sf_desc_cnts(Adapter);
 233                        }
 234                }
 235
 236                if( atomic_read(&Adapter->CurrNumFreeTxDesc) &&
 237                        Adapter->LinkStatus == SYNC_UP_REQUEST &&
 238                        !Adapter->bSyncUpRequestSent)
 239                {
 240                        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Calling LinkMessage");
 241                        LinkMessage(Adapter);
 242                }
 243
 244                if((Adapter->IdleMode || Adapter->bShutStatus) && atomic_read(&Adapter->TotalPacketCount))
 245                {
 246                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Device in Low Power mode...waking up");
 247                        Adapter->usIdleModePattern = ABORT_IDLE_MODE;
 248                                Adapter->bWakeUpDevice = TRUE;
 249                                wake_up(&Adapter->process_rx_cntrlpkt);
 250                }
 251
 252                transmit_packets(Adapter);
 253
 254                atomic_set(&Adapter->TxPktAvail, 0);
 255        }
 256
 257        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Exiting the tx thread..\n");
 258        Adapter->transmit_packet_thread = NULL;
 259        return 0;
 260}
 261