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