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 */
SendControlPacket(PMINI_ADAPTER Adapter,char * pControlPacket)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         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;
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 
73 	Adapter->interface_transmit(Adapter->pvInterfaceAdapter,
74 					pControlPacket, (PLeader->PLength + LEADER_SIZE));
75 
76 	atomic_dec(&Adapter->CurrNumFreeTxDesc);
77 	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "<=========");
78 	return STATUS_SUCCESS;
79 }
80 
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 */
SetupNextSend(PMINI_ADAPTER Adapter,struct sk_buff * Packet,USHORT Vcid)87 INT SetupNextSend(PMINI_ADAPTER Adapter,  struct sk_buff *Packet, USHORT Vcid)
88 {
89 	int		status=0;
90 	BOOLEAN bHeaderSupressionEnabled = FALSE;
91 	B_UINT16            uiClassifierRuleID;
92 	u16	QueueIndex = skb_get_queue_mapping(Packet);
93 	LEADER Leader={0};
94 
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);
103 
104 	bHeaderSupressionEnabled = Adapter->PackInfo[QueueIndex].bHeaderSuppressionEnabled
105 		& Adapter->bPHSEnabled;
106 
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 
124 	if(TCP_ACK == *((UINT32*) (Packet->cb) + SKB_CB_TCPACK_OFFSET ))
125 		Leader.Status = LEADER_STATUS_TCP_ACK;
126 	else
127 		Leader.Status = LEADER_STATUS;
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 	}
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 
149 	status = Adapter->interface_transmit(Adapter->pvInterfaceAdapter,
150 			Packet->data, (Leader.PLength + LEADER_SIZE));
151 	if(status)
152 	{
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);
157 	}
158 	else
159 	{
160 		struct net_device_stats *netstats = &Adapter->dev->stats;
161 		Adapter->PackInfo[QueueIndex].uiTotalTxBytes += Leader.PLength;
162 
163 		netstats->tx_bytes += Leader.PLength;
164 		++netstats->tx_packets;
165 
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);
172 		Adapter->PackInfo[QueueIndex].uiThisPeriodSentBytes += Leader.PLength;
173 	}
174 
175 	atomic_dec(&Adapter->CurrNumFreeTxDesc);
176 
177 errExit:
178 
179 	dev_kfree_skb(Packet);
180 	return status;
181 }
182 
tx_pending(PMINI_ADAPTER Adapter)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 
190 /**
191 @ingroup tx_functions
192 Transmit thread
193 */
tx_pkt_handler(PMINI_ADAPTER Adapter)194 int tx_pkt_handler(PMINI_ADAPTER Adapter  /**< pointer to adapter object*/
195 				)
196 {
197 	int status = 0;
198 
199 	while(! kthread_should_stop()) {
200 		/* FIXME - the timeout looks like workaround for racey usage of TxPktAvail */
201 		if(Adapter->LinkUpStatus)
202 			wait_event_timeout(Adapter->tx_packet_wait_queue,
203 					   tx_pending(Adapter), msecs_to_jiffies(10));
204 		else
205 			wait_event_interruptible(Adapter->tx_packet_wait_queue,
206 						 tx_pending(Adapter));
207 
208 		if (Adapter->device_removed)
209 			break;
210 
211 		if(Adapter->downloadDDR == 1)
212 		{
213 			Adapter->downloadDDR +=1;
214 			status = download_ddr_settings(Adapter);
215 			if(status)
216 				pr_err(PFX "DDR DOWNLOAD FAILED! %d\n", status);
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 		}
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 
252 		transmit_packets(Adapter);
253 
254 		atomic_set(&Adapter->TxPktAvail, 0);
255 	}
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;
259 	return 0;
260 }
261