blob: 5e603ce76fea5a401030315b4310be7cfa3979f7 [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
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070038
39/**
40@ingroup ctrl_pkt_functions
41This function dispatches control packet to the h/w interface
42@return zero(success) or -ve value(failure)
43*/
Kevin McKinney29794602012-05-26 12:05:12 -040044INT SendControlPacket(struct bcm_mini_adapter *Adapter, char *pControlPacket)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070045{
Kevin McKinneyff352042012-05-26 12:05:11 -040046 struct bcm_leader *PLeader = (struct bcm_leader *)pControlPacket;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070047
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070048 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");
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070058 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;
Stephen Hemminger349fa792010-11-01 14:09:05 -040068
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
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070073 Adapter->interface_transmit(Adapter->pvInterfaceAdapter,
74 pControlPacket, (PLeader->PLength + LEADER_SIZE));
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070075
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070076 atomic_dec(&Adapter->CurrNumFreeTxDesc);
77 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "<=========");
78 return STATUS_SUCCESS;
79}
Stephen Hemmingerac1b1ae2010-11-01 12:20:09 -040080
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070081/**
82@ingroup tx_functions
83This function despatches the IP packets with the given vcid
84to the target via the host h/w interface.
85@return zero(success) or -ve value(failure)
86*/
Kevin McKinney29794602012-05-26 12:05:12 -040087INT SetupNextSend(struct bcm_mini_adapter *Adapter, struct sk_buff *Packet, USHORT Vcid)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070088{
89 int status=0;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070090 BOOLEAN bHeaderSupressionEnabled = FALSE;
91 B_UINT16 uiClassifierRuleID;
Stephen Hemmingercacd9222010-11-01 13:34:35 -040092 u16 QueueIndex = skb_get_queue_mapping(Packet);
Kevin McKinneyff352042012-05-26 12:05:11 -040093 struct bcm_leader Leader={0};
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070094
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070095 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);
Stephen Hemmingercacd9222010-11-01 13:34:35 -0400103
104 bHeaderSupressionEnabled = Adapter->PackInfo[QueueIndex].bHeaderSuppressionEnabled
105 & Adapter->bPHSEnabled;
106
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700107 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
Stephen Hemmingerac1b1ae2010-11-01 12:20:09 -0400124 if(TCP_ACK == *((UINT32*) (Packet->cb) + SKB_CB_TCPACK_OFFSET ))
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700125 Leader.Status = LEADER_STATUS_TCP_ACK;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700126 else
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700127 Leader.Status = LEADER_STATUS;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700128
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 }
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700143 else
144 {
145 Leader.PLength = Packet->len - ETH_HLEN;
Kevin McKinneyff352042012-05-26 12:05:11 -0400146 memcpy((struct bcm_leader *)skb_pull(Packet, (ETH_HLEN - LEADER_SIZE)), &Leader, LEADER_SIZE);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700147 }
148
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700149 status = Adapter->interface_transmit(Adapter->pvInterfaceAdapter,
150 Packet->data, (Leader.PLength + LEADER_SIZE));
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700151 if(status)
152 {
Stephen Hemmingerac1b1ae2010-11-01 12:20:09 -0400153 ++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);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700157 }
158 else
159 {
Andres Salomone6f597a2011-01-17 16:11:12 -0800160 struct net_device_stats *netstats = &Adapter->dev->stats;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700161 Adapter->PackInfo[QueueIndex].uiTotalTxBytes += Leader.PLength;
Stephen Hemmingercacd9222010-11-01 13:34:35 -0400162
Andres Salomone6f597a2011-01-17 16:11:12 -0800163 netstats->tx_bytes += Leader.PLength;
164 ++netstats->tx_packets;
Stephen Hemmingercacd9222010-11-01 13:34:35 -0400165
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700166 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);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700172 Adapter->PackInfo[QueueIndex].uiThisPeriodSentBytes += Leader.PLength;
173 }
174
Stephen Hemmingerac1b1ae2010-11-01 12:20:09 -0400175 atomic_dec(&Adapter->CurrNumFreeTxDesc);
176
177errExit:
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700178
Stephen Hemminger082e8892010-11-01 09:35:21 -0400179 dev_kfree_skb(Packet);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700180 return status;
181}
182
Kevin McKinney29794602012-05-26 12:05:12 -0400183static int tx_pending(struct bcm_mini_adapter *Adapter)
Stephen Hemminger71e253b2010-11-01 09:49:30 -0400184{
185 return (atomic_read(&Adapter->TxPktAvail)
186 && MINIMUM_PENDING_DESCRIPTORS < atomic_read(&Adapter->CurrNumFreeTxDesc))
187 || Adapter->device_removed || (1 == Adapter->downloadDDR);
188}
189
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700190/**
191@ingroup tx_functions
192Transmit thread
193*/
Kevin McKinney29794602012-05-26 12:05:12 -0400194int tx_pkt_handler(struct bcm_mini_adapter *Adapter /**< pointer to adapter object*/
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700195 )
196{
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700197 int status = 0;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700198
Stephen Hemminger71e253b2010-11-01 09:49:30 -0400199 while(! kthread_should_stop()) {
200 /* FIXME - the timeout looks like workaround for racey usage of TxPktAvail */
201 if(Adapter->LinkUpStatus)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700202 wait_event_timeout(Adapter->tx_packet_wait_queue,
Stephen Hemminger71e253b2010-11-01 09:49:30 -0400203 tx_pending(Adapter), msecs_to_jiffies(10));
204 else
205 wait_event_interruptible(Adapter->tx_packet_wait_queue,
206 tx_pending(Adapter));
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700207
Stephen Hemminger71e253b2010-11-01 09:49:30 -0400208 if (Adapter->device_removed)
209 break;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700210
211 if(Adapter->downloadDDR == 1)
212 {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700213 Adapter->downloadDDR +=1;
214 status = download_ddr_settings(Adapter);
215 if(status)
Stephen Hemmingerac1b1ae2010-11-01 12:20:09 -0400216 pr_err(PFX "DDR DOWNLOAD FAILED! %d\n", status);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700217 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 }
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700235
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
Stephen Hemminger71e253b2010-11-01 09:49:30 -0400252 transmit_packets(Adapter);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700253
254 atomic_set(&Adapter->TxPktAvail, 0);
255 }
Stephen Hemminger71e253b2010-11-01 09:49:30 -0400256
257 BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Exiting the tx thread..\n");
258 Adapter->transmit_packet_thread = NULL;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700259 return 0;
260}