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, 50 "Got NULL Control Packet or Adapter"); 51 return STATUS_FAILURE; 52 } 53 if ((atomic_read(&Adapter->CurrNumFreeTxDesc) < 54 ((PLeader->PLength-1)/MAX_DEVICE_DESC_SIZE)+1)) { 55 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, 56 "NO FREE DESCRIPTORS TO SEND CONTROL PACKET"); 57 return STATUS_FAILURE; 58 } 59 60 /* Update the netdevice statistics */ 61 /* Dump Packet */ 62 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, 63 "Leader Status: %x", PLeader->Status); 64 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, 65 "Leader VCID: %x", PLeader->Vcid); 66 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, 67 "Leader Length: %x", PLeader->PLength); 68 if (Adapter->device_removed) 69 return 0; 70 71 if (netif_msg_pktdata(Adapter)) 72 print_hex_dump(KERN_DEBUG, PFX "tx control: ", DUMP_PREFIX_NONE, 73 16, 1, pControlPacket, 74 PLeader->PLength + LEADER_SIZE, 0); 75 76 Adapter->interface_transmit(Adapter->pvInterfaceAdapter, 77 pControlPacket, 78 (PLeader->PLength + LEADER_SIZE)); 79 80 atomic_dec(&Adapter->CurrNumFreeTxDesc); 81 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, 82 "<========="); 83 return STATUS_SUCCESS; 84} 85 86/** 87 * @ingroup tx_functions 88 * This function despatches the IP packets with the given vcid 89 * to the target via the host h/w interface. 90 * @return zero(success) or -ve value(failure) 91 */ 92int SetupNextSend(struct bcm_mini_adapter *Adapter, 93 struct sk_buff *Packet, USHORT Vcid) 94{ 95 int status = 0; 96 bool bHeaderSupressionEnabled = false; 97 B_UINT16 uiClassifierRuleID; 98 u16 QueueIndex = skb_get_queue_mapping(Packet); 99 struct bcm_packet_info *curr_packet_info = 100 &Adapter->PackInfo[QueueIndex]; 101 struct bcm_leader Leader = {0}; 102 103 if (Packet->len > MAX_DEVICE_DESC_SIZE) { 104 status = STATUS_FAILURE; 105 goto errExit; 106 } 107 108 /* Get the Classifier Rule ID */ 109 uiClassifierRuleID = *((UINT32 *) (Packet->cb) + 110 SKB_CB_CLASSIFICATION_OFFSET); 111 112 bHeaderSupressionEnabled = curr_packet_info->bHeaderSuppressionEnabled & 113 Adapter->bPHSEnabled; 114 115 if (Adapter->device_removed) { 116 status = STATUS_FAILURE; 117 goto errExit; 118 } 119 120 status = PHSTransmit(Adapter, &Packet, Vcid, uiClassifierRuleID, 121 bHeaderSupressionEnabled, 122 (UINT *)&Packet->len, 123 curr_packet_info->bEthCSSupport); 124 125 if (status != STATUS_SUCCESS) { 126 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, 127 "PHS Transmit failed..\n"); 128 goto errExit; 129 } 130 131 Leader.Vcid = Vcid; 132 133 if (TCP_ACK == *((UINT32 *) (Packet->cb) + SKB_CB_TCPACK_OFFSET)) 134 Leader.Status = LEADER_STATUS_TCP_ACK; 135 else 136 Leader.Status = LEADER_STATUS; 137 138 if (curr_packet_info->bEthCSSupport) { 139 Leader.PLength = Packet->len; 140 if (skb_headroom(Packet) < LEADER_SIZE) { 141 status = skb_cow(Packet, LEADER_SIZE); 142 if (status) { 143 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, NEXT_SEND, 144 DBG_LVL_ALL, 145 "bcm_transmit : Failed To Increase headRoom\n"); 146 goto errExit; 147 } 148 } 149 skb_push(Packet, LEADER_SIZE); 150 memcpy(Packet->data, &Leader, LEADER_SIZE); 151 } else { 152 Leader.PLength = Packet->len - ETH_HLEN; 153 memcpy((struct bcm_leader *)skb_pull(Packet, 154 (ETH_HLEN - LEADER_SIZE)), 155 &Leader, 156 LEADER_SIZE); 157 } 158 159 status = Adapter->interface_transmit(Adapter->pvInterfaceAdapter, 160 Packet->data, 161 (Leader.PLength + LEADER_SIZE)); 162 if (status) { 163 ++Adapter->dev->stats.tx_errors; 164 if (netif_msg_tx_err(Adapter)) 165 pr_info(PFX "%s: transmit error %d\n", 166 Adapter->dev->name, 167 status); 168 } else { 169 struct net_device_stats *netstats = &Adapter->dev->stats; 170 171 curr_packet_info->uiTotalTxBytes += Leader.PLength; 172 173 netstats->tx_bytes += Leader.PLength; 174 ++netstats->tx_packets; 175 176 curr_packet_info->uiCurrentTokenCount -= Leader.PLength << 3; 177 curr_packet_info->uiSentBytes += (Packet->len); 178 curr_packet_info->uiSentPackets++; 179 curr_packet_info->NumOfPacketsSent++; 180 181 atomic_dec(&curr_packet_info->uiPerSFTxResourceCount); 182 curr_packet_info->uiThisPeriodSentBytes += Leader.PLength; 183 } 184 185 atomic_dec(&Adapter->CurrNumFreeTxDesc); 186 187errExit: 188 dev_kfree_skb(Packet); 189 return status; 190} 191 192static int tx_pending(struct bcm_mini_adapter *Adapter) 193{ 194 return (atomic_read(&Adapter->TxPktAvail) 195 && MINIMUM_PENDING_DESCRIPTORS < 196 atomic_read(&Adapter->CurrNumFreeTxDesc)) 197 || Adapter->device_removed || (1 == Adapter->downloadDDR); 198} 199 200/** 201 * @ingroup tx_functions 202 * Transmit thread 203 */ 204int tx_pkt_handler(struct bcm_mini_adapter *Adapter) 205{ 206 int status = 0; 207 208 while (!kthread_should_stop()) { 209 /* FIXME - the timeout looks like workaround 210 * for racey usage of TxPktAvail 211 */ 212 if (Adapter->LinkUpStatus) 213 wait_event_timeout(Adapter->tx_packet_wait_queue, 214 tx_pending(Adapter), 215 msecs_to_jiffies(10)); 216 else 217 wait_event_interruptible(Adapter->tx_packet_wait_queue, 218 tx_pending(Adapter)); 219 220 if (Adapter->device_removed) 221 break; 222 223 if (Adapter->downloadDDR == 1) { 224 Adapter->downloadDDR += 1; 225 status = download_ddr_settings(Adapter); 226 if (status) 227 pr_err(PFX "DDR DOWNLOAD FAILED! %d\n", status); 228 continue; 229 } 230 231 /* Check end point for halt/stall. */ 232 if (Adapter->bEndPointHalted == TRUE) { 233 Bcm_clear_halt_of_endpoints(Adapter); 234 Adapter->bEndPointHalted = false; 235 StartInterruptUrb((struct bcm_interface_adapter *) 236 (Adapter->pvInterfaceAdapter)); 237 } 238 239 if (Adapter->LinkUpStatus && !Adapter->IdleMode) { 240 if (atomic_read(&Adapter->TotalPacketCount)) 241 update_per_sf_desc_cnts(Adapter); 242 } 243 244 if (atomic_read(&Adapter->CurrNumFreeTxDesc) && 245 Adapter->LinkStatus == SYNC_UP_REQUEST && 246 !Adapter->bSyncUpRequestSent) { 247 248 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, 249 DBG_LVL_ALL, "Calling LinkMessage"); 250 LinkMessage(Adapter); 251 } 252 253 if ((Adapter->IdleMode || Adapter->bShutStatus) && 254 atomic_read(&Adapter->TotalPacketCount)) { 255 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, 256 TX_PACKETS, DBG_LVL_ALL, 257 "Device in Low Power mode...waking up"); 258 Adapter->usIdleModePattern = ABORT_IDLE_MODE; 259 Adapter->bWakeUpDevice = TRUE; 260 wake_up(&Adapter->process_rx_cntrlpkt); 261 } 262 263 transmit_packets(Adapter); 264 atomic_set(&Adapter->TxPktAvail, 0); 265 } 266 267 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, 268 "Exiting the tx thread..\n"); 269 Adapter->transmit_packet_thread = NULL; 270 return 0; 271} 272