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