blob: 1f69625f241e270eae4bfdebcf93d51bf2a53a14 [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
Stephen Hemminger71e253b2010-11-01 09:49:30 -040042* interface(eth0). It handles the ARP packets. It
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070043* 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
Stephen Hemminger71e253b2010-11-01 09:49:30 -040053netdev_tx_t bcm_transmit(struct sk_buff *skb, struct net_device *dev)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070054{
Stephen Hemminger71e253b2010-11-01 09:49:30 -040055 PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev);
56 SHORT qindex;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070057
Stephen Hemminger71e253b2010-11-01 09:49:30 -040058 if (Adapter->device_removed || !Adapter->LinkUpStatus)
59 goto drop;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070060
Stephen Hemminger71e253b2010-11-01 09:49:30 -040061 if (Adapter->TransferMode != IP_PACKET_ONLY_MODE )
62 goto drop;
63
64 qindex = GetPacketQueueIndex(Adapter, skb);
65
66 if (INVALID_QUEUE_INDEX==qindex) {
67 if (ntohs(eth_hdr(skb)->h_proto) != ETH_ARP_FRAME)
68 goto drop;
69
70 /*
71 Reply directly to ARP request packet
72 ARP Spoofing only if NO ETH CS rule matches for it
73 */
74 reply_to_arp_request(skb);
75 return NETDEV_TX_OK;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070076 }
77
Stephen Hemminger71e253b2010-11-01 09:49:30 -040078 if (Adapter->PackInfo[qindex].uiCurrentPacketsOnHost >= SF_MAX_ALLOWED_PACKETS_TO_BACKUP)
79 return NETDEV_TX_BUSY;
80
81 /* Now Enqueue the packet */
82 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL,
83 "bcm_transmit Enqueueing the Packet To Queue %d",qindex);
84 spin_lock(&Adapter->PackInfo[qindex].SFQueueLock);
85 Adapter->PackInfo[qindex].uiCurrentBytesOnHost += skb->len;
86 Adapter->PackInfo[qindex].uiCurrentPacketsOnHost++;
87
88 *((B_UINT32 *)skb->cb + SKB_CB_LATENCY_OFFSET ) = jiffies;
89 ENQUEUEPACKET(Adapter->PackInfo[qindex].FirstTxQueue,
90 Adapter->PackInfo[qindex].LastTxQueue, skb);
91 atomic_inc(&Adapter->TotalPacketCount);
92 spin_unlock(&Adapter->PackInfo[qindex].SFQueueLock);
93
94 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL,"ENQ: \n");
95
96 /* FIXME - this is racy and incorrect, replace with work queue */
97 if (!atomic_read(&Adapter->TxPktAvail)) {
98 atomic_set(&Adapter->TxPktAvail, 1);
99 wake_up(&Adapter->tx_packet_wait_queue);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700100 }
Stephen Hemminger71e253b2010-11-01 09:49:30 -0400101 return NETDEV_TX_OK;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700102
Stephen Hemminger71e253b2010-11-01 09:49:30 -0400103 drop:
104 dev_kfree_skb(skb);
105 return NETDEV_TX_OK;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700106}
107
108
109/**
110@ingroup ctrl_pkt_functions
111This function dispatches control packet to the h/w interface
112@return zero(success) or -ve value(failure)
113*/
114INT SendControlPacket(PMINI_ADAPTER Adapter, /**<Logical Adapter*/
115 char *pControlPacket/**<Control Packet*/
116 )
117{
118 PLEADER PLeader = NULL;
119 struct timeval tv;
120 memset(&tv, 0, sizeof(tv));
121
122
123
124 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "========>");
125
126 PLeader=(PLEADER)pControlPacket;
127 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Tx");
128 if(!pControlPacket || !Adapter)
129 {
130 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Got NULL Control Packet or Adapter");
131 return STATUS_FAILURE;
132 }
133 if((atomic_read( &Adapter->CurrNumFreeTxDesc ) <
134 ((PLeader->PLength-1)/MAX_DEVICE_DESC_SIZE)+1))
135 {
136 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "NO FREE DESCRIPTORS TO SEND CONTROL PACKET");
137 if(Adapter->bcm_jiffies == 0)
138 {
139 Adapter->bcm_jiffies = jiffies;
140 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "UPDATED TIME(hex): %lu",
141 Adapter->bcm_jiffies);
142 }
143 return STATUS_FAILURE;
144 }
145
146 /* Update the netdevice statistics */
147 /* Dump Packet */
148 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader Status: %x", PLeader->Status);
149 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader VCID: %x",PLeader->Vcid);
150 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader Length: %x",PLeader->PLength);
151 if(Adapter->device_removed)
152 return 0;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700153 Adapter->interface_transmit(Adapter->pvInterfaceAdapter,
154 pControlPacket, (PLeader->PLength + LEADER_SIZE));
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700155
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700156 atomic_dec(&Adapter->CurrNumFreeTxDesc);
157 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "<=========");
158 return STATUS_SUCCESS;
159}
160static LEADER Leader={0};
161/**
162@ingroup tx_functions
163This function despatches the IP packets with the given vcid
164to the target via the host h/w interface.
165@return zero(success) or -ve value(failure)
166*/
167INT SetupNextSend(PMINI_ADAPTER Adapter, /**<Logical Adapter*/
168 struct sk_buff *Packet, /**<data buffer*/
169 USHORT Vcid) /**<VCID for this packet*/
170{
171 int status=0;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700172 BOOLEAN bHeaderSupressionEnabled = FALSE;
173 B_UINT16 uiClassifierRuleID;
174 int QueueIndex = NO_OF_QUEUES + 1;
175
176 if(!Adapter || !Packet)
177 {
178 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Got NULL Adapter or Packet");
179 return -EINVAL;
180 }
181 if(Packet->len > MAX_DEVICE_DESC_SIZE)
182 {
183 status = STATUS_FAILURE;
184 goto errExit;
185 }
186
187 /* Get the Classifier Rule ID */
188 uiClassifierRuleID = *((UINT32*) (Packet->cb)+SKB_CB_CLASSIFICATION_OFFSET);
189 QueueIndex = SearchVcid( Adapter,Vcid);
190 if(QueueIndex < NO_OF_QUEUES)
191 {
192 bHeaderSupressionEnabled =
193 Adapter->PackInfo[QueueIndex].bHeaderSuppressionEnabled;
194 bHeaderSupressionEnabled =
195 bHeaderSupressionEnabled & Adapter->bPHSEnabled;
196 }
197 if(Adapter->device_removed)
198 {
199 status = STATUS_FAILURE;
200 goto errExit;
201 }
202
203 status = PHSTransmit(Adapter, &Packet, Vcid, uiClassifierRuleID, bHeaderSupressionEnabled,
204 (UINT *)&Packet->len, Adapter->PackInfo[QueueIndex].bEthCSSupport);
205
206 if(status != STATUS_SUCCESS)
207 {
208 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "PHS Transmit failed..\n");
209 goto errExit;
210 }
211
212 Leader.Vcid = Vcid;
213
214 if(TCP_ACK == *((UINT32*) (Packet->cb) + SKB_CB_TCPACK_OFFSET ))
215 {
216 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Sending TCP ACK\n");
217 Leader.Status = LEADER_STATUS_TCP_ACK;
218 }
219 else
220 {
221 Leader.Status = LEADER_STATUS;
222 }
223
224 if(Adapter->PackInfo[QueueIndex].bEthCSSupport)
225 {
226 Leader.PLength = Packet->len;
227 if(skb_headroom(Packet) < LEADER_SIZE)
228 {
229 if((status = skb_cow(Packet,LEADER_SIZE)))
230 {
231 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL,"bcm_transmit : Failed To Increase headRoom\n");
232 goto errExit;
233 }
234 }
235 skb_push(Packet, LEADER_SIZE);
236 memcpy(Packet->data, &Leader, LEADER_SIZE);
237 }
238
239 else
240 {
241 Leader.PLength = Packet->len - ETH_HLEN;
242 memcpy((LEADER*)skb_pull(Packet, (ETH_HLEN - LEADER_SIZE)), &Leader, LEADER_SIZE);
243 }
244
245 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Packet->len = %d", Packet->len);
246 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Vcid = %d", Vcid);
247
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700248 status = Adapter->interface_transmit(Adapter->pvInterfaceAdapter,
249 Packet->data, (Leader.PLength + LEADER_SIZE));
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700250 if(status)
251 {
252 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Tx Failed..\n");
253 }
254 else
255 {
256 Adapter->PackInfo[QueueIndex].uiTotalTxBytes += Leader.PLength;
257 atomic_add(Leader.PLength, &Adapter->GoodTxByteCount);
258 atomic_inc(&Adapter->TxTotalPacketCount);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700259 }
260
261 atomic_dec(&Adapter->CurrNumFreeTxDesc);
262
263errExit:
264
265 if(STATUS_SUCCESS == status)
266 {
267 Adapter->PackInfo[QueueIndex].uiCurrentTokenCount -= Leader.PLength << 3;
268 Adapter->PackInfo[QueueIndex].uiSentBytes += (Packet->len);
269 Adapter->PackInfo[QueueIndex].uiSentPackets++;
270 Adapter->PackInfo[QueueIndex].NumOfPacketsSent++;
271
272 atomic_dec(&Adapter->PackInfo[QueueIndex].uiPerSFTxResourceCount);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700273 Adapter->PackInfo[QueueIndex].uiThisPeriodSentBytes += Leader.PLength;
274 }
275
276
Stephen Hemminger082e8892010-11-01 09:35:21 -0400277 dev_kfree_skb(Packet);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700278 return status;
279}
280
Stephen Hemminger71e253b2010-11-01 09:49:30 -0400281static int tx_pending(PMINI_ADAPTER Adapter)
282{
283 return (atomic_read(&Adapter->TxPktAvail)
284 && MINIMUM_PENDING_DESCRIPTORS < atomic_read(&Adapter->CurrNumFreeTxDesc))
285 || Adapter->device_removed || (1 == Adapter->downloadDDR);
286}
287
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700288/**
289@ingroup tx_functions
290Transmit thread
291*/
292int tx_pkt_handler(PMINI_ADAPTER Adapter /**< pointer to adapter object*/
293 )
294{
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700295 int status = 0;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700296
Stephen Hemminger71e253b2010-11-01 09:49:30 -0400297 while(! kthread_should_stop()) {
298 /* FIXME - the timeout looks like workaround for racey usage of TxPktAvail */
299 if(Adapter->LinkUpStatus)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700300 wait_event_timeout(Adapter->tx_packet_wait_queue,
Stephen Hemminger71e253b2010-11-01 09:49:30 -0400301 tx_pending(Adapter), msecs_to_jiffies(10));
302 else
303 wait_event_interruptible(Adapter->tx_packet_wait_queue,
304 tx_pending(Adapter));
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700305
Stephen Hemminger71e253b2010-11-01 09:49:30 -0400306 if (Adapter->device_removed)
307 break;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700308
309 if(Adapter->downloadDDR == 1)
310 {
311 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Downloading DDR Settings\n");
312 Adapter->downloadDDR +=1;
313 status = download_ddr_settings(Adapter);
314 if(status)
315 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "DDR DOWNLOAD FAILED!\n");
316 continue;
317 }
318
319 //Check end point for halt/stall.
320 if(Adapter->bEndPointHalted == TRUE)
321 {
322 Bcm_clear_halt_of_endpoints(Adapter);
323 Adapter->bEndPointHalted = FALSE;
324 StartInterruptUrb((PS_INTERFACE_ADAPTER)(Adapter->pvInterfaceAdapter));
325 }
326
327 if(Adapter->LinkUpStatus && !Adapter->IdleMode)
328 {
329 if(atomic_read(&Adapter->TotalPacketCount))
330 {
331 update_per_sf_desc_cnts(Adapter);
332 }
333 }
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700334
335 if( atomic_read(&Adapter->CurrNumFreeTxDesc) &&
336 Adapter->LinkStatus == SYNC_UP_REQUEST &&
337 !Adapter->bSyncUpRequestSent)
338 {
339 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Calling LinkMessage");
340 LinkMessage(Adapter);
341 }
342
343 if((Adapter->IdleMode || Adapter->bShutStatus) && atomic_read(&Adapter->TotalPacketCount))
344 {
345 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Device in Low Power mode...waking up");
346 Adapter->usIdleModePattern = ABORT_IDLE_MODE;
347 Adapter->bWakeUpDevice = TRUE;
348 wake_up(&Adapter->process_rx_cntrlpkt);
349 }
350
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700351
Stephen Hemminger71e253b2010-11-01 09:49:30 -0400352 transmit_packets(Adapter);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700353
354 atomic_set(&Adapter->TxPktAvail, 0);
355 }
Stephen Hemminger71e253b2010-11-01 09:49:30 -0400356
357 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Exiting the tx thread..\n");
358 Adapter->transmit_packet_thread = NULL;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700359 return 0;
360}
361
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700362
363