]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/bcm/Transmit.c
Revert "net: phy: Set the driver when registering an MDIO bus device"
[karo-tx-linux.git] / drivers / staging / bcm / Transmit.c
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  */
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, "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  */
86 int 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
167 errExit:
168         dev_kfree_skb(Packet);
169         return status;
170 }
171
172 static 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  */
183 int 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 }