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