]>
Commit | Line | Data |
---|---|---|
f8942e07 | 1 | /** |
b9e25f81 KM |
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 | */ | |
f8942e07 SH |
35 | |
36 | #include "headers.h" | |
37 | ||
f8942e07 | 38 | /** |
b9e25f81 KM |
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 | */ | |
ae1cbea5 | 43 | int SendControlPacket(struct bcm_mini_adapter *Adapter, char *pControlPacket) |
f8942e07 | 44 | { |
ff352042 | 45 | struct bcm_leader *PLeader = (struct bcm_leader *)pControlPacket; |
f8942e07 | 46 | |
22976bc3 | 47 | BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Tx"); |
97e0a509 | 48 | if (!pControlPacket || !Adapter) { |
22976bc3 KM |
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) < | |
97e0a509 | 53 | ((PLeader->PLength-1)/MAX_DEVICE_DESC_SIZE)+1)) { |
22976bc3 | 54 | BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "NO FREE DESCRIPTORS TO SEND CONTROL PACKET"); |
f8942e07 SH |
55 | return STATUS_FAILURE; |
56 | } | |
f8942e07 SH |
57 | |
58 | /* Update the netdevice statistics */ | |
59 | /* Dump Packet */ | |
22976bc3 KM |
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) | |
f8942e07 | 64 | return 0; |
349fa794 SH |
65 | |
66 | if (netif_msg_pktdata(Adapter)) | |
67 | print_hex_dump(KERN_DEBUG, PFX "tx control: ", DUMP_PREFIX_NONE, | |
22976bc3 | 68 | 16, 1, pControlPacket, PLeader->PLength + LEADER_SIZE, 0); |
349fa794 | 69 | |
f8942e07 | 70 | Adapter->interface_transmit(Adapter->pvInterfaceAdapter, |
22976bc3 | 71 | pControlPacket, (PLeader->PLength + LEADER_SIZE)); |
f8942e07 | 72 | |
f8942e07 | 73 | atomic_dec(&Adapter->CurrNumFreeTxDesc); |
22976bc3 | 74 | BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "<========="); |
f8942e07 SH |
75 | return STATUS_SUCCESS; |
76 | } | |
ac1b1ae7 | 77 | |
f8942e07 | 78 | /** |
b9e25f81 KM |
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 | */ | |
ae1cbea5 | 84 | int SetupNextSend(struct bcm_mini_adapter *Adapter, struct sk_buff *Packet, USHORT Vcid) |
f8942e07 | 85 | { |
22976bc3 | 86 | int status = 0; |
f70c8a91 | 87 | bool bHeaderSupressionEnabled = false; |
22976bc3 | 88 | B_UINT16 uiClassifierRuleID; |
cacd9222 | 89 | u16 QueueIndex = skb_get_queue_mapping(Packet); |
22976bc3 | 90 | struct bcm_leader Leader = {0}; |
f8942e07 | 91 | |
97e0a509 | 92 | if (Packet->len > MAX_DEVICE_DESC_SIZE) { |
f8942e07 SH |
93 | status = STATUS_FAILURE; |
94 | goto errExit; | |
95 | } | |
96 | ||
97 | /* Get the Classifier Rule ID */ | |
22976bc3 | 98 | uiClassifierRuleID = *((UINT32 *) (Packet->cb) + SKB_CB_CLASSIFICATION_OFFSET); |
cacd9222 SH |
99 | |
100 | bHeaderSupressionEnabled = Adapter->PackInfo[QueueIndex].bHeaderSuppressionEnabled | |
101 | & Adapter->bPHSEnabled; | |
102 | ||
97e0a509 | 103 | if (Adapter->device_removed) { |
f8942e07 SH |
104 | status = STATUS_FAILURE; |
105 | goto errExit; | |
22976bc3 | 106 | } |
f8942e07 SH |
107 | |
108 | status = PHSTransmit(Adapter, &Packet, Vcid, uiClassifierRuleID, bHeaderSupressionEnabled, | |
22976bc3 | 109 | (UINT *)&Packet->len, Adapter->PackInfo[QueueIndex].bEthCSSupport); |
f8942e07 | 110 | |
97e0a509 | 111 | if (status != STATUS_SUCCESS) { |
22976bc3 | 112 | BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "PHS Transmit failed..\n"); |
f8942e07 SH |
113 | goto errExit; |
114 | } | |
115 | ||
22976bc3 | 116 | Leader.Vcid = Vcid; |
f8942e07 | 117 | |
22976bc3 | 118 | if (TCP_ACK == *((UINT32 *) (Packet->cb) + SKB_CB_TCPACK_OFFSET)) |
f8942e07 | 119 | Leader.Status = LEADER_STATUS_TCP_ACK; |
f8942e07 | 120 | else |
f8942e07 | 121 | Leader.Status = LEADER_STATUS; |
f8942e07 | 122 | |
97e0a509 | 123 | if (Adapter->PackInfo[QueueIndex].bEthCSSupport) { |
f8942e07 | 124 | Leader.PLength = Packet->len; |
97e0a509 | 125 | if (skb_headroom(Packet) < LEADER_SIZE) { |
d5873d38 KM |
126 | status = skb_cow(Packet, LEADER_SIZE); |
127 | if (status) { | |
22976bc3 | 128 | BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "bcm_transmit : Failed To Increase headRoom\n"); |
f8942e07 SH |
129 | goto errExit; |
130 | } | |
131 | } | |
132 | skb_push(Packet, LEADER_SIZE); | |
133 | memcpy(Packet->data, &Leader, LEADER_SIZE); | |
97e0a509 | 134 | } else { |
f8942e07 | 135 | Leader.PLength = Packet->len - ETH_HLEN; |
ff352042 | 136 | memcpy((struct bcm_leader *)skb_pull(Packet, (ETH_HLEN - LEADER_SIZE)), &Leader, LEADER_SIZE); |
f8942e07 SH |
137 | } |
138 | ||
f8942e07 | 139 | status = Adapter->interface_transmit(Adapter->pvInterfaceAdapter, |
22976bc3 | 140 | Packet->data, (Leader.PLength + LEADER_SIZE)); |
97e0a509 | 141 | if (status) { |
ac1b1ae7 SH |
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); | |
97e0a509 | 146 | } else { |
e6f597a1 | 147 | struct net_device_stats *netstats = &Adapter->dev->stats; |
f8942e07 | 148 | Adapter->PackInfo[QueueIndex].uiTotalTxBytes += Leader.PLength; |
cacd9222 | 149 | |
e6f597a1 AS |
150 | netstats->tx_bytes += Leader.PLength; |
151 | ++netstats->tx_packets; | |
cacd9222 | 152 | |
f8942e07 SH |
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); | |
f8942e07 SH |
159 | Adapter->PackInfo[QueueIndex].uiThisPeriodSentBytes += Leader.PLength; |
160 | } | |
161 | ||
ac1b1ae7 SH |
162 | atomic_dec(&Adapter->CurrNumFreeTxDesc); |
163 | ||
164 | errExit: | |
082e889b | 165 | dev_kfree_skb(Packet); |
f8942e07 SH |
166 | return status; |
167 | } | |
168 | ||
2979460d | 169 | static int tx_pending(struct bcm_mini_adapter *Adapter) |
71e253b1 SH |
170 | { |
171 | return (atomic_read(&Adapter->TxPktAvail) | |
172 | && MINIMUM_PENDING_DESCRIPTORS < atomic_read(&Adapter->CurrNumFreeTxDesc)) | |
173 | || Adapter->device_removed || (1 == Adapter->downloadDDR); | |
174 | } | |
175 | ||
f8942e07 | 176 | /** |
b9e25f81 KM |
177 | * @ingroup tx_functions |
178 | * Transmit thread | |
179 | */ | |
22976bc3 | 180 | int tx_pkt_handler(struct bcm_mini_adapter *Adapter /**< pointer to adapter object*/) |
f8942e07 | 181 | { |
f8942e07 | 182 | int status = 0; |
f8942e07 | 183 | |
22976bc3 | 184 | while (!kthread_should_stop()) { |
71e253b1 | 185 | /* FIXME - the timeout looks like workaround for racey usage of TxPktAvail */ |
22976bc3 | 186 | if (Adapter->LinkUpStatus) |
f8942e07 | 187 | wait_event_timeout(Adapter->tx_packet_wait_queue, |
22976bc3 | 188 | tx_pending(Adapter), msecs_to_jiffies(10)); |
71e253b1 SH |
189 | else |
190 | wait_event_interruptible(Adapter->tx_packet_wait_queue, | |
22976bc3 | 191 | tx_pending(Adapter)); |
f8942e07 | 192 | |
71e253b1 SH |
193 | if (Adapter->device_removed) |
194 | break; | |
f8942e07 | 195 | |
97e0a509 | 196 | if (Adapter->downloadDDR == 1) { |
22976bc3 | 197 | Adapter->downloadDDR += 1; |
f8942e07 | 198 | status = download_ddr_settings(Adapter); |
22976bc3 | 199 | if (status) |
ac1b1ae7 | 200 | pr_err(PFX "DDR DOWNLOAD FAILED! %d\n", status); |
f8942e07 SH |
201 | continue; |
202 | } | |
203 | ||
b9e25f81 | 204 | /* Check end point for halt/stall. */ |
97e0a509 | 205 | if (Adapter->bEndPointHalted == TRUE) { |
f8942e07 | 206 | Bcm_clear_halt_of_endpoints(Adapter); |
f70c8a91 | 207 | Adapter->bEndPointHalted = false; |
d6861cfe | 208 | StartInterruptUrb((struct bcm_interface_adapter *)(Adapter->pvInterfaceAdapter)); |
f8942e07 SH |
209 | } |
210 | ||
97e0a509 | 211 | if (Adapter->LinkUpStatus && !Adapter->IdleMode) { |
22976bc3 | 212 | if (atomic_read(&Adapter->TotalPacketCount)) |
f8942e07 | 213 | update_per_sf_desc_cnts(Adapter); |
f8942e07 | 214 | } |
f8942e07 | 215 | |
22976bc3 | 216 | if (atomic_read(&Adapter->CurrNumFreeTxDesc) && |
f8942e07 | 217 | Adapter->LinkStatus == SYNC_UP_REQUEST && |
97e0a509 KM |
218 | !Adapter->bSyncUpRequestSent) { |
219 | ||
22976bc3 | 220 | BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Calling LinkMessage"); |
f8942e07 SH |
221 | LinkMessage(Adapter); |
222 | } | |
223 | ||
97e0a509 | 224 | if ((Adapter->IdleMode || Adapter->bShutStatus) && atomic_read(&Adapter->TotalPacketCount)) { |
22976bc3 KM |
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); | |
f8942e07 SH |
229 | } |
230 | ||
71e253b1 | 231 | transmit_packets(Adapter); |
f8942e07 SH |
232 | atomic_set(&Adapter->TxPktAvail, 0); |
233 | } | |
71e253b1 | 234 | |
22976bc3 | 235 | BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Exiting the tx thread..\n"); |
71e253b1 | 236 | Adapter->transmit_packet_thread = NULL; |
f8942e07 SH |
237 | return 0; |
238 | } |