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