• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
SendControlPacket(struct bcm_mini_adapter * Adapter,char * pControlPacket)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  */
SetupNextSend(struct bcm_mini_adapter * Adapter,struct sk_buff * Packet,USHORT Vcid)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 
tx_pending(struct bcm_mini_adapter * Adapter)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  */
tx_pkt_handler(struct bcm_mini_adapter * Adapter)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 }
272