Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  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, "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 */
 84int SetupNextSend(struct bcm_mini_adapter *Adapter,  struct sk_buff *Packet, USHORT Vcid)
 85{
 86	int	status = 0;
 87	bool	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
164errExit:
165	dev_kfree_skb(Packet);
166	return status;
167}
168
169static 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 */
180int 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}