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 */
43int 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 */
92int 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
187errExit:
188	dev_kfree_skb(Packet);
189	return status;
190}
191
192static 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 */
204int 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}
272