blob: 9932d71a6fe00cc352d87c5aadaaf1e7ee87e387 [file] [log] [blame]
Stephen Hemmingerf8942e02010-09-08 14:46:36 -07001/**
2@file Transmit.c
3@defgroup tx_functions Transmission
4@section Queueing
5@dot
6digraph transmit1 {
7node[shape=box]
8edge[weight=5;color=red]
9bcm_transmit->reply_to_arp_request[label="ARP"]
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* Function - bcm_transmit()
40*
41* Description - This is the main transmit function for our virtual
42* interface(veth0). It handles the ARP packets. It
43* clones this packet and then Queue it to a suitable
44* Queue. Then calls the transmit_packet().
45*
46* Parameter - skb - Pointer to the socket buffer structure
47* dev - Pointer to the virtual net device structure
48*
49* Returns - zero (success) or -ve value (failure)
50*
51*********************************************************************/
52
53INT bcm_transmit(struct sk_buff *skb, /**< skb */
54 struct net_device *dev /**< net device pointer */
55 )
56{
57 PMINI_ADAPTER Adapter = NULL;
58 USHORT qindex=0;
59 struct timeval tv;
60 UINT pkt_type = 0;
61 UINT calltransmit = 0;
62
63 BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "\n%s====>\n",__FUNCTION__);
64
65 memset(&tv, 0, sizeof(tv));
66 /* Check for valid parameters */
67 if(skb == NULL || dev==NULL)
68 {
69 BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX,TX_OSAL_DBG, DBG_LVL_ALL, "Got NULL skb or dev\n");
70 return -EINVAL;
71 }
72
73 Adapter = GET_BCM_ADAPTER(dev);
74 if(!Adapter)
75 {
76 BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Got Invalid Adapter\n");
77 return -EINVAL;
78 }
79 if(Adapter->device_removed == TRUE || !Adapter->LinkUpStatus)
80 {
81 if(!netif_queue_stopped(dev)) {
82 netif_carrier_off(dev);
83 netif_stop_queue(dev);
84 }
85 return STATUS_FAILURE;
86 }
87 BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Packet size : %d\n", skb->len);
88
89 /*Add Ethernet CS check here*/
90 if(Adapter->TransferMode == IP_PACKET_ONLY_MODE )
91 {
92 pkt_type = ntohs(*(PUSHORT)(skb->data + 12));
93 /* Get the queue index where the packet is to be queued */
94 BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Getting the Queue Index.....");
95
96 qindex = GetPacketQueueIndex(Adapter,skb);
97
98 if((SHORT)INVALID_QUEUE_INDEX==(SHORT)qindex)
99 {
100 if(pkt_type == ETH_ARP_FRAME)
101 {
102 /*
103 Reply directly to ARP request packet
104 ARP Spoofing only if NO ETH CS rule matches for it
105 */
106 BCM_DEBUG_PRINT (Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL,"ARP OPCODE = %02x",
107
108 (*(PUCHAR)(skb->data + 21)));
109
110 reply_to_arp_request(skb);
111
112 BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX,TX_OSAL_DBG, DBG_LVL_ALL,"After reply_to_arp_request \n");
113
114 }
115 else
116 {
117 BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL,
118 "Invalid queue index, dropping pkt\n");
119
Stephen Hemminger082e8892010-11-01 09:35:21 -0400120 dev_kfree_skb(skb);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700121 }
122 return STATUS_SUCCESS;
123 }
124
125 if(Adapter->PackInfo[qindex].uiCurrentPacketsOnHost >= SF_MAX_ALLOWED_PACKETS_TO_BACKUP)
126 {
127 atomic_inc(&Adapter->TxDroppedPacketCount);
Stephen Hemminger082e8892010-11-01 09:35:21 -0400128 dev_kfree_skb(skb);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700129 return STATUS_SUCCESS;
130 }
131
132 /* Now Enqueue the packet */
133 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "bcm_transmit Enqueueing the Packet To Queue %d",qindex);
134 spin_lock(&Adapter->PackInfo[qindex].SFQueueLock);
135 Adapter->PackInfo[qindex].uiCurrentBytesOnHost += skb->len;
136 Adapter->PackInfo[qindex].uiCurrentPacketsOnHost++;
137
138 *((B_UINT32 *)skb->cb + SKB_CB_LATENCY_OFFSET ) = jiffies;
139 ENQUEUEPACKET(Adapter->PackInfo[qindex].FirstTxQueue,
140 Adapter->PackInfo[qindex].LastTxQueue, skb);
141 atomic_inc(&Adapter->TotalPacketCount);
142 spin_unlock(&Adapter->PackInfo[qindex].SFQueueLock);
143 do_gettimeofday(&tv);
144
145 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL,"ENQ: \n");
146 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Pkt Len = %d, sec: %ld, usec: %ld\n",
147 (skb->len-ETH_HLEN), tv.tv_sec, tv.tv_usec);
148
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700149 if(calltransmit == 1)
150 transmit_packets(Adapter);
151 else
152 {
153 if(!atomic_read(&Adapter->TxPktAvail))
154 {
155 atomic_set(&Adapter->TxPktAvail, 1);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700156 wake_up(&Adapter->tx_packet_wait_queue);
157 }
158 }
159 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "<====");
160 }
161 else
Stephen Hemminger082e8892010-11-01 09:35:21 -0400162 dev_kfree_skb(skb);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700163
164 return STATUS_SUCCESS;
165}
166
167
168/**
169@ingroup ctrl_pkt_functions
170This function dispatches control packet to the h/w interface
171@return zero(success) or -ve value(failure)
172*/
173INT SendControlPacket(PMINI_ADAPTER Adapter, /**<Logical Adapter*/
174 char *pControlPacket/**<Control Packet*/
175 )
176{
177 PLEADER PLeader = NULL;
178 struct timeval tv;
179 memset(&tv, 0, sizeof(tv));
180
181
182
183 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "========>");
184
185 PLeader=(PLEADER)pControlPacket;
186 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Tx");
187 if(!pControlPacket || !Adapter)
188 {
189 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Got NULL Control Packet or Adapter");
190 return STATUS_FAILURE;
191 }
192 if((atomic_read( &Adapter->CurrNumFreeTxDesc ) <
193 ((PLeader->PLength-1)/MAX_DEVICE_DESC_SIZE)+1))
194 {
195 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "NO FREE DESCRIPTORS TO SEND CONTROL PACKET");
196 if(Adapter->bcm_jiffies == 0)
197 {
198 Adapter->bcm_jiffies = jiffies;
199 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "UPDATED TIME(hex): %lu",
200 Adapter->bcm_jiffies);
201 }
202 return STATUS_FAILURE;
203 }
204
205 /* Update the netdevice statistics */
206 /* Dump Packet */
207 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader Status: %x", PLeader->Status);
208 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader VCID: %x",PLeader->Vcid);
209 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader Length: %x",PLeader->PLength);
210 if(Adapter->device_removed)
211 return 0;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700212 Adapter->interface_transmit(Adapter->pvInterfaceAdapter,
213 pControlPacket, (PLeader->PLength + LEADER_SIZE));
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700214
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700215 atomic_dec(&Adapter->CurrNumFreeTxDesc);
216 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "<=========");
217 return STATUS_SUCCESS;
218}
219static LEADER Leader={0};
220/**
221@ingroup tx_functions
222This function despatches the IP packets with the given vcid
223to the target via the host h/w interface.
224@return zero(success) or -ve value(failure)
225*/
226INT SetupNextSend(PMINI_ADAPTER Adapter, /**<Logical Adapter*/
227 struct sk_buff *Packet, /**<data buffer*/
228 USHORT Vcid) /**<VCID for this packet*/
229{
230 int status=0;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700231 BOOLEAN bHeaderSupressionEnabled = FALSE;
232 B_UINT16 uiClassifierRuleID;
233 int QueueIndex = NO_OF_QUEUES + 1;
234
235 if(!Adapter || !Packet)
236 {
237 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Got NULL Adapter or Packet");
238 return -EINVAL;
239 }
240 if(Packet->len > MAX_DEVICE_DESC_SIZE)
241 {
242 status = STATUS_FAILURE;
243 goto errExit;
244 }
245
246 /* Get the Classifier Rule ID */
247 uiClassifierRuleID = *((UINT32*) (Packet->cb)+SKB_CB_CLASSIFICATION_OFFSET);
248 QueueIndex = SearchVcid( Adapter,Vcid);
249 if(QueueIndex < NO_OF_QUEUES)
250 {
251 bHeaderSupressionEnabled =
252 Adapter->PackInfo[QueueIndex].bHeaderSuppressionEnabled;
253 bHeaderSupressionEnabled =
254 bHeaderSupressionEnabled & Adapter->bPHSEnabled;
255 }
256 if(Adapter->device_removed)
257 {
258 status = STATUS_FAILURE;
259 goto errExit;
260 }
261
262 status = PHSTransmit(Adapter, &Packet, Vcid, uiClassifierRuleID, bHeaderSupressionEnabled,
263 (UINT *)&Packet->len, Adapter->PackInfo[QueueIndex].bEthCSSupport);
264
265 if(status != STATUS_SUCCESS)
266 {
267 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "PHS Transmit failed..\n");
268 goto errExit;
269 }
270
271 Leader.Vcid = Vcid;
272
273 if(TCP_ACK == *((UINT32*) (Packet->cb) + SKB_CB_TCPACK_OFFSET ))
274 {
275 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Sending TCP ACK\n");
276 Leader.Status = LEADER_STATUS_TCP_ACK;
277 }
278 else
279 {
280 Leader.Status = LEADER_STATUS;
281 }
282
283 if(Adapter->PackInfo[QueueIndex].bEthCSSupport)
284 {
285 Leader.PLength = Packet->len;
286 if(skb_headroom(Packet) < LEADER_SIZE)
287 {
288 if((status = skb_cow(Packet,LEADER_SIZE)))
289 {
290 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL,"bcm_transmit : Failed To Increase headRoom\n");
291 goto errExit;
292 }
293 }
294 skb_push(Packet, LEADER_SIZE);
295 memcpy(Packet->data, &Leader, LEADER_SIZE);
296 }
297
298 else
299 {
300 Leader.PLength = Packet->len - ETH_HLEN;
301 memcpy((LEADER*)skb_pull(Packet, (ETH_HLEN - LEADER_SIZE)), &Leader, LEADER_SIZE);
302 }
303
304 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Packet->len = %d", Packet->len);
305 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Vcid = %d", Vcid);
306
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700307 status = Adapter->interface_transmit(Adapter->pvInterfaceAdapter,
308 Packet->data, (Leader.PLength + LEADER_SIZE));
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700309 if(status)
310 {
311 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Tx Failed..\n");
312 }
313 else
314 {
315 Adapter->PackInfo[QueueIndex].uiTotalTxBytes += Leader.PLength;
316 atomic_add(Leader.PLength, &Adapter->GoodTxByteCount);
317 atomic_inc(&Adapter->TxTotalPacketCount);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700318 }
319
320 atomic_dec(&Adapter->CurrNumFreeTxDesc);
321
322errExit:
323
324 if(STATUS_SUCCESS == status)
325 {
326 Adapter->PackInfo[QueueIndex].uiCurrentTokenCount -= Leader.PLength << 3;
327 Adapter->PackInfo[QueueIndex].uiSentBytes += (Packet->len);
328 Adapter->PackInfo[QueueIndex].uiSentPackets++;
329 Adapter->PackInfo[QueueIndex].NumOfPacketsSent++;
330
331 atomic_dec(&Adapter->PackInfo[QueueIndex].uiPerSFTxResourceCount);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700332 Adapter->PackInfo[QueueIndex].uiThisPeriodSentBytes += Leader.PLength;
333 }
334
335
Stephen Hemminger082e8892010-11-01 09:35:21 -0400336 dev_kfree_skb(Packet);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700337 return status;
338}
339
340/**
341@ingroup tx_functions
342Transmit thread
343*/
344int tx_pkt_handler(PMINI_ADAPTER Adapter /**< pointer to adapter object*/
345 )
346{
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700347 int status = 0;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700348
349 UINT calltransmit = 1;
Arnd Bergmann9f1c75a2010-09-30 10:24:11 +0200350 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);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700351
352
353 while(1)
354 {
355 if(Adapter->LinkUpStatus){
356 wait_event_timeout(Adapter->tx_packet_wait_queue,
357 ((atomic_read(&Adapter->TxPktAvail) &&
358 (MINIMUM_PENDING_DESCRIPTORS <
359 atomic_read(&Adapter->CurrNumFreeTxDesc)) &&
360 (Adapter->device_removed == FALSE))) ||
361 (1 == Adapter->downloadDDR) || kthread_should_stop()
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700362 || (TRUE == Adapter->bEndPointHalted)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700363 , msecs_to_jiffies(10));
364 }
365 else{
366 wait_event(Adapter->tx_packet_wait_queue,
367 ((atomic_read(&Adapter->TxPktAvail) &&
368 (MINIMUM_PENDING_DESCRIPTORS <
369 atomic_read(&Adapter->CurrNumFreeTxDesc)) &&
370 (Adapter->device_removed == FALSE))) ||
371 (1 == Adapter->downloadDDR) || kthread_should_stop()
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700372 || (TRUE == Adapter->bEndPointHalted)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700373 );
374 }
375
376 if(kthread_should_stop() || Adapter->device_removed)
377 {
378 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Exiting the tx thread..\n");
379 Adapter->transmit_packet_thread = NULL;
380 return 0;
381 }
382
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700383
384 if(Adapter->downloadDDR == 1)
385 {
386 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Downloading DDR Settings\n");
387 Adapter->downloadDDR +=1;
388 status = download_ddr_settings(Adapter);
389 if(status)
390 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "DDR DOWNLOAD FAILED!\n");
391 continue;
392 }
393
394 //Check end point for halt/stall.
395 if(Adapter->bEndPointHalted == TRUE)
396 {
397 Bcm_clear_halt_of_endpoints(Adapter);
398 Adapter->bEndPointHalted = FALSE;
399 StartInterruptUrb((PS_INTERFACE_ADAPTER)(Adapter->pvInterfaceAdapter));
400 }
401
402 if(Adapter->LinkUpStatus && !Adapter->IdleMode)
403 {
404 if(atomic_read(&Adapter->TotalPacketCount))
405 {
406 update_per_sf_desc_cnts(Adapter);
407 }
408 }
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700409
410 if( atomic_read(&Adapter->CurrNumFreeTxDesc) &&
411 Adapter->LinkStatus == SYNC_UP_REQUEST &&
412 !Adapter->bSyncUpRequestSent)
413 {
414 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Calling LinkMessage");
415 LinkMessage(Adapter);
416 }
417
418 if((Adapter->IdleMode || Adapter->bShutStatus) && atomic_read(&Adapter->TotalPacketCount))
419 {
420 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Device in Low Power mode...waking up");
421 Adapter->usIdleModePattern = ABORT_IDLE_MODE;
422 Adapter->bWakeUpDevice = TRUE;
423 wake_up(&Adapter->process_rx_cntrlpkt);
424 }
425
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700426
427 if(calltransmit)
428 transmit_packets(Adapter);
429
430 atomic_set(&Adapter->TxPktAvail, 0);
431 }
432 return 0;
433}
434
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700435
436