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