blob: 4b94d822578cedd469897dbb75eae07dd327cc5d [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]
Stephen Hemminger74416982010-11-01 09:53:58 -04009
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070010bcm_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
Stephen Hemminger74416982010-11-01 09:53:58 -040066 if (INVALID_QUEUE_INDEX==qindex)
67 goto drop;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070068
Stephen Hemminger71e253b2010-11-01 09:49:30 -040069 if (Adapter->PackInfo[qindex].uiCurrentPacketsOnHost >= SF_MAX_ALLOWED_PACKETS_TO_BACKUP)
70 return NETDEV_TX_BUSY;
71
72 /* Now Enqueue the packet */
73 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL,
74 "bcm_transmit Enqueueing the Packet To Queue %d",qindex);
75 spin_lock(&Adapter->PackInfo[qindex].SFQueueLock);
76 Adapter->PackInfo[qindex].uiCurrentBytesOnHost += skb->len;
77 Adapter->PackInfo[qindex].uiCurrentPacketsOnHost++;
78
79 *((B_UINT32 *)skb->cb + SKB_CB_LATENCY_OFFSET ) = jiffies;
80 ENQUEUEPACKET(Adapter->PackInfo[qindex].FirstTxQueue,
81 Adapter->PackInfo[qindex].LastTxQueue, skb);
82 atomic_inc(&Adapter->TotalPacketCount);
83 spin_unlock(&Adapter->PackInfo[qindex].SFQueueLock);
84
85 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL,"ENQ: \n");
86
87 /* FIXME - this is racy and incorrect, replace with work queue */
88 if (!atomic_read(&Adapter->TxPktAvail)) {
89 atomic_set(&Adapter->TxPktAvail, 1);
90 wake_up(&Adapter->tx_packet_wait_queue);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070091 }
Stephen Hemminger71e253b2010-11-01 09:49:30 -040092 return NETDEV_TX_OK;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070093
Stephen Hemminger71e253b2010-11-01 09:49:30 -040094 drop:
95 dev_kfree_skb(skb);
96 return NETDEV_TX_OK;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070097}
98
99
100/**
101@ingroup ctrl_pkt_functions
102This function dispatches control packet to the h/w interface
103@return zero(success) or -ve value(failure)
104*/
105INT SendControlPacket(PMINI_ADAPTER Adapter, /**<Logical Adapter*/
106 char *pControlPacket/**<Control Packet*/
107 )
108{
109 PLEADER PLeader = NULL;
110 struct timeval tv;
111 memset(&tv, 0, sizeof(tv));
112
113
114
115 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "========>");
116
117 PLeader=(PLEADER)pControlPacket;
118 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Tx");
119 if(!pControlPacket || !Adapter)
120 {
121 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Got NULL Control Packet or Adapter");
122 return STATUS_FAILURE;
123 }
124 if((atomic_read( &Adapter->CurrNumFreeTxDesc ) <
125 ((PLeader->PLength-1)/MAX_DEVICE_DESC_SIZE)+1))
126 {
127 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "NO FREE DESCRIPTORS TO SEND CONTROL PACKET");
128 if(Adapter->bcm_jiffies == 0)
129 {
130 Adapter->bcm_jiffies = jiffies;
131 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "UPDATED TIME(hex): %lu",
132 Adapter->bcm_jiffies);
133 }
134 return STATUS_FAILURE;
135 }
136
137 /* Update the netdevice statistics */
138 /* Dump Packet */
139 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader Status: %x", PLeader->Status);
140 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader VCID: %x",PLeader->Vcid);
141 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader Length: %x",PLeader->PLength);
142 if(Adapter->device_removed)
143 return 0;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700144 Adapter->interface_transmit(Adapter->pvInterfaceAdapter,
145 pControlPacket, (PLeader->PLength + LEADER_SIZE));
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700146
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700147 atomic_dec(&Adapter->CurrNumFreeTxDesc);
148 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "<=========");
149 return STATUS_SUCCESS;
150}
151static LEADER Leader={0};
152/**
153@ingroup tx_functions
154This function despatches the IP packets with the given vcid
155to the target via the host h/w interface.
156@return zero(success) or -ve value(failure)
157*/
158INT SetupNextSend(PMINI_ADAPTER Adapter, /**<Logical Adapter*/
159 struct sk_buff *Packet, /**<data buffer*/
160 USHORT Vcid) /**<VCID for this packet*/
161{
162 int status=0;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700163 BOOLEAN bHeaderSupressionEnabled = FALSE;
164 B_UINT16 uiClassifierRuleID;
165 int QueueIndex = NO_OF_QUEUES + 1;
166
167 if(!Adapter || !Packet)
168 {
169 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Got NULL Adapter or Packet");
170 return -EINVAL;
171 }
172 if(Packet->len > MAX_DEVICE_DESC_SIZE)
173 {
174 status = STATUS_FAILURE;
175 goto errExit;
176 }
177
178 /* Get the Classifier Rule ID */
179 uiClassifierRuleID = *((UINT32*) (Packet->cb)+SKB_CB_CLASSIFICATION_OFFSET);
180 QueueIndex = SearchVcid( Adapter,Vcid);
181 if(QueueIndex < NO_OF_QUEUES)
182 {
183 bHeaderSupressionEnabled =
184 Adapter->PackInfo[QueueIndex].bHeaderSuppressionEnabled;
185 bHeaderSupressionEnabled =
186 bHeaderSupressionEnabled & Adapter->bPHSEnabled;
187 }
188 if(Adapter->device_removed)
189 {
190 status = STATUS_FAILURE;
191 goto errExit;
192 }
193
194 status = PHSTransmit(Adapter, &Packet, Vcid, uiClassifierRuleID, bHeaderSupressionEnabled,
195 (UINT *)&Packet->len, Adapter->PackInfo[QueueIndex].bEthCSSupport);
196
197 if(status != STATUS_SUCCESS)
198 {
199 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "PHS Transmit failed..\n");
200 goto errExit;
201 }
202
203 Leader.Vcid = Vcid;
204
205 if(TCP_ACK == *((UINT32*) (Packet->cb) + SKB_CB_TCPACK_OFFSET ))
206 {
207 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Sending TCP ACK\n");
208 Leader.Status = LEADER_STATUS_TCP_ACK;
209 }
210 else
211 {
212 Leader.Status = LEADER_STATUS;
213 }
214
215 if(Adapter->PackInfo[QueueIndex].bEthCSSupport)
216 {
217 Leader.PLength = Packet->len;
218 if(skb_headroom(Packet) < LEADER_SIZE)
219 {
220 if((status = skb_cow(Packet,LEADER_SIZE)))
221 {
222 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL,"bcm_transmit : Failed To Increase headRoom\n");
223 goto errExit;
224 }
225 }
226 skb_push(Packet, LEADER_SIZE);
227 memcpy(Packet->data, &Leader, LEADER_SIZE);
228 }
229
230 else
231 {
232 Leader.PLength = Packet->len - ETH_HLEN;
233 memcpy((LEADER*)skb_pull(Packet, (ETH_HLEN - LEADER_SIZE)), &Leader, LEADER_SIZE);
234 }
235
236 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Packet->len = %d", Packet->len);
237 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Vcid = %d", Vcid);
238
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700239 status = Adapter->interface_transmit(Adapter->pvInterfaceAdapter,
240 Packet->data, (Leader.PLength + LEADER_SIZE));
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700241 if(status)
242 {
243 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Tx Failed..\n");
244 }
245 else
246 {
247 Adapter->PackInfo[QueueIndex].uiTotalTxBytes += Leader.PLength;
248 atomic_add(Leader.PLength, &Adapter->GoodTxByteCount);
249 atomic_inc(&Adapter->TxTotalPacketCount);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700250 }
251
252 atomic_dec(&Adapter->CurrNumFreeTxDesc);
253
254errExit:
255
256 if(STATUS_SUCCESS == status)
257 {
258 Adapter->PackInfo[QueueIndex].uiCurrentTokenCount -= Leader.PLength << 3;
259 Adapter->PackInfo[QueueIndex].uiSentBytes += (Packet->len);
260 Adapter->PackInfo[QueueIndex].uiSentPackets++;
261 Adapter->PackInfo[QueueIndex].NumOfPacketsSent++;
262
263 atomic_dec(&Adapter->PackInfo[QueueIndex].uiPerSFTxResourceCount);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700264 Adapter->PackInfo[QueueIndex].uiThisPeriodSentBytes += Leader.PLength;
265 }
266
267
Stephen Hemminger082e8892010-11-01 09:35:21 -0400268 dev_kfree_skb(Packet);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700269 return status;
270}
271
Stephen Hemminger71e253b2010-11-01 09:49:30 -0400272static int tx_pending(PMINI_ADAPTER Adapter)
273{
274 return (atomic_read(&Adapter->TxPktAvail)
275 && MINIMUM_PENDING_DESCRIPTORS < atomic_read(&Adapter->CurrNumFreeTxDesc))
276 || Adapter->device_removed || (1 == Adapter->downloadDDR);
277}
278
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700279/**
280@ingroup tx_functions
281Transmit thread
282*/
283int tx_pkt_handler(PMINI_ADAPTER Adapter /**< pointer to adapter object*/
284 )
285{
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700286 int status = 0;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700287
Stephen Hemminger71e253b2010-11-01 09:49:30 -0400288 while(! kthread_should_stop()) {
289 /* FIXME - the timeout looks like workaround for racey usage of TxPktAvail */
290 if(Adapter->LinkUpStatus)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700291 wait_event_timeout(Adapter->tx_packet_wait_queue,
Stephen Hemminger71e253b2010-11-01 09:49:30 -0400292 tx_pending(Adapter), msecs_to_jiffies(10));
293 else
294 wait_event_interruptible(Adapter->tx_packet_wait_queue,
295 tx_pending(Adapter));
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700296
Stephen Hemminger71e253b2010-11-01 09:49:30 -0400297 if (Adapter->device_removed)
298 break;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700299
300 if(Adapter->downloadDDR == 1)
301 {
302 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Downloading DDR Settings\n");
303 Adapter->downloadDDR +=1;
304 status = download_ddr_settings(Adapter);
305 if(status)
306 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "DDR DOWNLOAD FAILED!\n");
307 continue;
308 }
309
310 //Check end point for halt/stall.
311 if(Adapter->bEndPointHalted == TRUE)
312 {
313 Bcm_clear_halt_of_endpoints(Adapter);
314 Adapter->bEndPointHalted = FALSE;
315 StartInterruptUrb((PS_INTERFACE_ADAPTER)(Adapter->pvInterfaceAdapter));
316 }
317
318 if(Adapter->LinkUpStatus && !Adapter->IdleMode)
319 {
320 if(atomic_read(&Adapter->TotalPacketCount))
321 {
322 update_per_sf_desc_cnts(Adapter);
323 }
324 }
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700325
326 if( atomic_read(&Adapter->CurrNumFreeTxDesc) &&
327 Adapter->LinkStatus == SYNC_UP_REQUEST &&
328 !Adapter->bSyncUpRequestSent)
329 {
330 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Calling LinkMessage");
331 LinkMessage(Adapter);
332 }
333
334 if((Adapter->IdleMode || Adapter->bShutStatus) && atomic_read(&Adapter->TotalPacketCount))
335 {
336 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Device in Low Power mode...waking up");
337 Adapter->usIdleModePattern = ABORT_IDLE_MODE;
338 Adapter->bWakeUpDevice = TRUE;
339 wake_up(&Adapter->process_rx_cntrlpkt);
340 }
341
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700342
Stephen Hemminger71e253b2010-11-01 09:49:30 -0400343 transmit_packets(Adapter);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700344
345 atomic_set(&Adapter->TxPktAvail, 0);
346 }
Stephen Hemminger71e253b2010-11-01 09:49:30 -0400347
348 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Exiting the tx thread..\n");
349 Adapter->transmit_packet_thread = NULL;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700350 return 0;
351}
352
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700353
354