]> Pileus Git - ~andy/linux/blob - drivers/staging/bcm/InterfaceRx.c
Merge tag 'for-v3.14-fixes' of git://git.infradead.org/battery-2.6
[~andy/linux] / drivers / staging / bcm / InterfaceRx.c
1 #include "headers.h"
2
3 static int SearchVcid(struct bcm_mini_adapter *Adapter, unsigned short usVcid)
4 {
5         int iIndex = 0;
6
7         for (iIndex = (NO_OF_QUEUES-1); iIndex >= 0; iIndex--)
8                 if (Adapter->PackInfo[iIndex].usVCID_Value == usVcid)
9                         return iIndex;
10         return NO_OF_QUEUES+1;
11
12 }
13
14
15 static struct bcm_usb_rcb *
16 GetBulkInRcb(struct bcm_interface_adapter *psIntfAdapter)
17 {
18         struct bcm_usb_rcb *pRcb = NULL;
19         UINT index = 0;
20
21         if ((atomic_read(&psIntfAdapter->uNumRcbUsed) < MAXIMUM_USB_RCB) &&
22             (psIntfAdapter->psAdapter->StopAllXaction == false)) {
23                 index = atomic_read(&psIntfAdapter->uCurrRcb);
24                 pRcb = &psIntfAdapter->asUsbRcb[index];
25                 pRcb->bUsed = TRUE;
26                 pRcb->psIntfAdapter = psIntfAdapter;
27                 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "Got Rx desc %d used %d",
28                                 index, atomic_read(&psIntfAdapter->uNumRcbUsed));
29                 index = (index + 1) % MAXIMUM_USB_RCB;
30                 atomic_set(&psIntfAdapter->uCurrRcb, index);
31                 atomic_inc(&psIntfAdapter->uNumRcbUsed);
32         }
33         return pRcb;
34 }
35
36 /*this is receive call back - when pkt available for receive (BULK IN- end point)*/
37 static void read_bulk_callback(struct urb *urb)
38 {
39         struct sk_buff *skb = NULL;
40         bool bHeaderSupressionEnabled = false;
41         int QueueIndex = NO_OF_QUEUES + 1;
42         UINT uiIndex = 0;
43         int process_done = 1;
44         struct bcm_usb_rcb *pRcb = (struct bcm_usb_rcb *)urb->context;
45         struct bcm_interface_adapter *psIntfAdapter = pRcb->psIntfAdapter;
46         struct bcm_mini_adapter *Adapter = psIntfAdapter->psAdapter;
47         struct bcm_leader *pLeader = urb->transfer_buffer;
48
49         if (unlikely(netif_msg_rx_status(Adapter)))
50                 pr_info(PFX "%s: rx urb status %d length %d\n",
51                         Adapter->dev->name, urb->status, urb->actual_length);
52
53         if ((Adapter->device_removed == TRUE) ||
54             (TRUE == Adapter->bEndPointHalted) ||
55             (0 == urb->actual_length)) {
56                 pRcb->bUsed = false;
57                 atomic_dec(&psIntfAdapter->uNumRcbUsed);
58                 return;
59         }
60
61         if (urb->status != STATUS_SUCCESS) {
62                 if (urb->status == -EPIPE) {
63                         Adapter->bEndPointHalted = TRUE;
64                         wake_up(&Adapter->tx_packet_wait_queue);
65                 } else {
66                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "Rx URB has got cancelled. status :%d", urb->status);
67                 }
68                 pRcb->bUsed = false;
69                 atomic_dec(&psIntfAdapter->uNumRcbUsed);
70                 urb->status = STATUS_SUCCESS;
71                 return;
72         }
73
74         if (Adapter->bDoSuspend && (Adapter->bPreparingForLowPowerMode)) {
75                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "device is going in low power mode while PMU option selected..hence rx packet should not be process");
76                 return;
77         }
78
79         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "Read back done len %d\n", pLeader->PLength);
80         if (!pLeader->PLength) {
81                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "Leader Length 0");
82                 atomic_dec(&psIntfAdapter->uNumRcbUsed);
83                 return;
84         }
85         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "Leader Status:0x%hX, Length:0x%hX, VCID:0x%hX", pLeader->Status, pLeader->PLength, pLeader->Vcid);
86         if (MAX_CNTL_PKT_SIZE < pLeader->PLength) {
87                 if (netif_msg_rx_err(Adapter))
88                         pr_info(PFX "%s: corrupted leader length...%d\n",
89                                 Adapter->dev->name, pLeader->PLength);
90                 ++Adapter->dev->stats.rx_dropped;
91                 atomic_dec(&psIntfAdapter->uNumRcbUsed);
92                 return;
93         }
94
95         QueueIndex = SearchVcid(Adapter, pLeader->Vcid);
96         if (QueueIndex < NO_OF_QUEUES) {
97                 bHeaderSupressionEnabled =
98                         Adapter->PackInfo[QueueIndex].bHeaderSuppressionEnabled;
99                 bHeaderSupressionEnabled =
100                         bHeaderSupressionEnabled & Adapter->bPHSEnabled;
101         }
102
103         skb = dev_alloc_skb(pLeader->PLength + SKB_RESERVE_PHS_BYTES + SKB_RESERVE_ETHERNET_HEADER);
104         if (!skb) {
105                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "NO SKBUFF!!! Dropping the Packet");
106                 atomic_dec(&psIntfAdapter->uNumRcbUsed);
107                 return;
108         }
109         /* If it is a control Packet, then call handle_bcm_packet ()*/
110         if ((ntohs(pLeader->Vcid) == VCID_CONTROL_PACKET) ||
111             (!(pLeader->Status >= 0x20  &&  pLeader->Status <= 0x3F))) {
112                 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_RX, RX_CTRL, DBG_LVL_ALL, "Received control pkt...");
113                 *(PUSHORT)skb->data = pLeader->Status;
114                 memcpy(skb->data+sizeof(USHORT), urb->transfer_buffer +
115                        (sizeof(struct bcm_leader)), pLeader->PLength);
116                 skb->len = pLeader->PLength + sizeof(USHORT);
117
118                 spin_lock(&Adapter->control_queue_lock);
119                 ENQUEUEPACKET(Adapter->RxControlHead, Adapter->RxControlTail, skb);
120                 spin_unlock(&Adapter->control_queue_lock);
121
122                 atomic_inc(&Adapter->cntrlpktCnt);
123                 wake_up(&Adapter->process_rx_cntrlpkt);
124         } else {
125                 /*
126                  * Data Packet, Format a proper Ethernet Header
127                  * and give it to the stack
128                  */
129                 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_RX, RX_DATA, DBG_LVL_ALL, "Received Data pkt...");
130                 skb_reserve(skb, 2 + SKB_RESERVE_PHS_BYTES);
131                 memcpy(skb->data+ETH_HLEN, (PUCHAR)urb->transfer_buffer + sizeof(struct bcm_leader), pLeader->PLength);
132                 skb->dev = Adapter->dev;
133
134                 /* currently skb->len has extra ETH_HLEN bytes in the beginning */
135                 skb_put(skb, pLeader->PLength + ETH_HLEN);
136                 Adapter->PackInfo[QueueIndex].uiTotalRxBytes += pLeader->PLength;
137                 Adapter->PackInfo[QueueIndex].uiThisPeriodRxBytes += pLeader->PLength;
138                 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_RX, RX_DATA, DBG_LVL_ALL, "Received Data pkt of len :0x%X", pLeader->PLength);
139
140                 if (netif_running(Adapter->dev)) {
141                         /* Moving ahead by ETH_HLEN to the data ptr as received from FW */
142                         skb_pull(skb, ETH_HLEN);
143                         PHSReceive(Adapter, pLeader->Vcid, skb, &skb->len,
144                                    NULL, bHeaderSupressionEnabled);
145
146                         if (!Adapter->PackInfo[QueueIndex].bEthCSSupport) {
147                                 skb_push(skb, ETH_HLEN);
148
149                                 memcpy(skb->data, skb->dev->dev_addr, 6);
150                                 memcpy(skb->data+6, skb->dev->dev_addr, 6);
151                                 (*(skb->data+11))++;
152                                 *(skb->data+12) = 0x08;
153                                 *(skb->data+13) = 0x00;
154                                 pLeader->PLength += ETH_HLEN;
155                         }
156
157                         skb->protocol = eth_type_trans(skb, Adapter->dev);
158                         process_done = netif_rx(skb);
159                 } else {
160                         BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_RX, RX_DATA, DBG_LVL_ALL, "i/f not up hance freeing SKB...");
161                         dev_kfree_skb(skb);
162                 }
163
164                 ++Adapter->dev->stats.rx_packets;
165                 Adapter->dev->stats.rx_bytes += pLeader->PLength;
166
167                 for (uiIndex = 0; uiIndex < MIBS_MAX_HIST_ENTRIES; uiIndex++) {
168                         if ((pLeader->PLength <= MIBS_PKTSIZEHIST_RANGE*(uiIndex+1)) &&
169                             (pLeader->PLength > MIBS_PKTSIZEHIST_RANGE*(uiIndex)))
170                                 Adapter->aRxPktSizeHist[uiIndex]++;
171                 }
172         }
173         Adapter->PrevNumRecvDescs++;
174         pRcb->bUsed = false;
175         atomic_dec(&psIntfAdapter->uNumRcbUsed);
176 }
177
178 static int ReceiveRcb(struct bcm_interface_adapter *psIntfAdapter, struct bcm_usb_rcb *pRcb)
179 {
180         struct urb *urb = pRcb->urb;
181         int retval = 0;
182
183         usb_fill_bulk_urb(urb, psIntfAdapter->udev, usb_rcvbulkpipe(psIntfAdapter->udev, psIntfAdapter->sBulkIn.bulk_in_endpointAddr),
184                           urb->transfer_buffer, BCM_USB_MAX_READ_LENGTH, read_bulk_callback, pRcb);
185         if (false == psIntfAdapter->psAdapter->device_removed &&
186             false == psIntfAdapter->psAdapter->bEndPointHalted &&
187             false == psIntfAdapter->bSuspended &&
188             false == psIntfAdapter->bPreparingForBusSuspend) {
189                 retval = usb_submit_urb(urb, GFP_ATOMIC);
190                 if (retval) {
191                         BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "failed submitting read urb, error %d", retval);
192                         /* if this return value is because of pipe halt. need to clear this. */
193                         if (retval == -EPIPE) {
194                                 psIntfAdapter->psAdapter->bEndPointHalted = TRUE;
195                                 wake_up(&psIntfAdapter->psAdapter->tx_packet_wait_queue);
196                         }
197
198                 }
199         }
200         return retval;
201 }
202
203 /*
204 Function:                               InterfaceRx
205
206 Description:                    This is the hardware specific Function for Receiving
207                                                 data packet/control packets from the device.
208
209 Input parameters:               IN struct bcm_mini_adapter *Adapter   - Miniport Adapter Context
210
211
212
213 Return:                         TRUE  - If Rx was successful.
214                                         Other - If an error occurred.
215 */
216
217 bool InterfaceRx(struct bcm_interface_adapter *psIntfAdapter)
218 {
219         USHORT RxDescCount = NUM_RX_DESC - atomic_read(&psIntfAdapter->uNumRcbUsed);
220         struct bcm_usb_rcb *pRcb = NULL;
221
222         while (RxDescCount) {
223                 pRcb = GetBulkInRcb(psIntfAdapter);
224                 if (pRcb == NULL) {
225                         BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "Unable to get Rcb pointer");
226                         return false;
227                 }
228                 ReceiveRcb(psIntfAdapter, pRcb);
229                 RxDescCount--;
230         }
231         return TRUE;
232 }
233