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