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