aboutsummaryrefslogtreecommitdiff
path: root/drivers/staging/bcm/InterfaceRx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/bcm/InterfaceRx.c')
-rw-r--r--drivers/staging/bcm/InterfaceRx.c233
1 files changed, 233 insertions, 0 deletions
diff --git a/drivers/staging/bcm/InterfaceRx.c b/drivers/staging/bcm/InterfaceRx.c
new file mode 100644
index 00000000000..11008173f91
--- /dev/null
+++ b/drivers/staging/bcm/InterfaceRx.c
@@ -0,0 +1,233 @@
+#include "headers.h"
+
+static int SearchVcid(struct bcm_mini_adapter *Adapter, unsigned short usVcid)
+{
+ int iIndex = 0;
+
+ for (iIndex = (NO_OF_QUEUES-1); iIndex >= 0; iIndex--)
+ if (Adapter->PackInfo[iIndex].usVCID_Value == usVcid)
+ return iIndex;
+ return NO_OF_QUEUES+1;
+
+}
+
+
+static struct bcm_usb_rcb *
+GetBulkInRcb(struct bcm_interface_adapter *psIntfAdapter)
+{
+ struct bcm_usb_rcb *pRcb = NULL;
+ UINT index = 0;
+
+ if ((atomic_read(&psIntfAdapter->uNumRcbUsed) < MAXIMUM_USB_RCB) &&
+ (psIntfAdapter->psAdapter->StopAllXaction == false)) {
+ index = atomic_read(&psIntfAdapter->uCurrRcb);
+ pRcb = &psIntfAdapter->asUsbRcb[index];
+ pRcb->bUsed = TRUE;
+ pRcb->psIntfAdapter = psIntfAdapter;
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "Got Rx desc %d used %d",
+ index, atomic_read(&psIntfAdapter->uNumRcbUsed));
+ index = (index + 1) % MAXIMUM_USB_RCB;
+ atomic_set(&psIntfAdapter->uCurrRcb, index);
+ atomic_inc(&psIntfAdapter->uNumRcbUsed);
+ }
+ return pRcb;
+}
+
+/*this is receive call back - when pkt available for receive (BULK IN- end point)*/
+static void read_bulk_callback(struct urb *urb)
+{
+ struct sk_buff *skb = NULL;
+ bool bHeaderSupressionEnabled = false;
+ int QueueIndex = NO_OF_QUEUES + 1;
+ UINT uiIndex = 0;
+ int process_done = 1;
+ struct bcm_usb_rcb *pRcb = (struct bcm_usb_rcb *)urb->context;
+ struct bcm_interface_adapter *psIntfAdapter = pRcb->psIntfAdapter;
+ struct bcm_mini_adapter *Adapter = psIntfAdapter->psAdapter;
+ struct bcm_leader *pLeader = urb->transfer_buffer;
+
+ if (unlikely(netif_msg_rx_status(Adapter)))
+ pr_info(PFX "%s: rx urb status %d length %d\n",
+ Adapter->dev->name, urb->status, urb->actual_length);
+
+ if ((Adapter->device_removed == TRUE) ||
+ (TRUE == Adapter->bEndPointHalted) ||
+ (0 == urb->actual_length)) {
+ pRcb->bUsed = false;
+ atomic_dec(&psIntfAdapter->uNumRcbUsed);
+ return;
+ }
+
+ if (urb->status != STATUS_SUCCESS) {
+ if (urb->status == -EPIPE) {
+ Adapter->bEndPointHalted = TRUE;
+ wake_up(&Adapter->tx_packet_wait_queue);
+ } else {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "Rx URB has got cancelled. status :%d", urb->status);
+ }
+ pRcb->bUsed = false;
+ atomic_dec(&psIntfAdapter->uNumRcbUsed);
+ urb->status = STATUS_SUCCESS;
+ return;
+ }
+
+ if (Adapter->bDoSuspend && (Adapter->bPreparingForLowPowerMode)) {
+ 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");
+ return;
+ }
+
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "Read back done len %d\n", pLeader->PLength);
+ if (!pLeader->PLength) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "Leader Length 0");
+ atomic_dec(&psIntfAdapter->uNumRcbUsed);
+ return;
+ }
+ 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);
+ if (MAX_CNTL_PKT_SIZE < pLeader->PLength) {
+ if (netif_msg_rx_err(Adapter))
+ pr_info(PFX "%s: corrupted leader length...%d\n",
+ Adapter->dev->name, pLeader->PLength);
+ ++Adapter->dev->stats.rx_dropped;
+ atomic_dec(&psIntfAdapter->uNumRcbUsed);
+ return;
+ }
+
+ QueueIndex = SearchVcid(Adapter, pLeader->Vcid);
+ if (QueueIndex < NO_OF_QUEUES) {
+ bHeaderSupressionEnabled =
+ Adapter->PackInfo[QueueIndex].bHeaderSuppressionEnabled;
+ bHeaderSupressionEnabled =
+ bHeaderSupressionEnabled & Adapter->bPHSEnabled;
+ }
+
+ skb = dev_alloc_skb(pLeader->PLength + SKB_RESERVE_PHS_BYTES + SKB_RESERVE_ETHERNET_HEADER);
+ if (!skb) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "NO SKBUFF!!! Dropping the Packet");
+ atomic_dec(&psIntfAdapter->uNumRcbUsed);
+ return;
+ }
+ /* If it is a control Packet, then call handle_bcm_packet ()*/
+ if ((ntohs(pLeader->Vcid) == VCID_CONTROL_PACKET) ||
+ (!(pLeader->Status >= 0x20 && pLeader->Status <= 0x3F))) {
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_RX, RX_CTRL, DBG_LVL_ALL, "Received control pkt...");
+ *(PUSHORT)skb->data = pLeader->Status;
+ memcpy(skb->data+sizeof(USHORT), urb->transfer_buffer +
+ (sizeof(struct bcm_leader)), pLeader->PLength);
+ skb->len = pLeader->PLength + sizeof(USHORT);
+
+ spin_lock(&Adapter->control_queue_lock);
+ ENQUEUEPACKET(Adapter->RxControlHead, Adapter->RxControlTail, skb);
+ spin_unlock(&Adapter->control_queue_lock);
+
+ atomic_inc(&Adapter->cntrlpktCnt);
+ wake_up(&Adapter->process_rx_cntrlpkt);
+ } else {
+ /*
+ * Data Packet, Format a proper Ethernet Header
+ * and give it to the stack
+ */
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_RX, RX_DATA, DBG_LVL_ALL, "Received Data pkt...");
+ skb_reserve(skb, 2 + SKB_RESERVE_PHS_BYTES);
+ memcpy(skb->data+ETH_HLEN, (PUCHAR)urb->transfer_buffer + sizeof(struct bcm_leader), pLeader->PLength);
+ skb->dev = Adapter->dev;
+
+ /* currently skb->len has extra ETH_HLEN bytes in the beginning */
+ skb_put(skb, pLeader->PLength + ETH_HLEN);
+ Adapter->PackInfo[QueueIndex].uiTotalRxBytes += pLeader->PLength;
+ Adapter->PackInfo[QueueIndex].uiThisPeriodRxBytes += pLeader->PLength;
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_RX, RX_DATA, DBG_LVL_ALL, "Received Data pkt of len :0x%X", pLeader->PLength);
+
+ if (netif_running(Adapter->dev)) {
+ /* Moving ahead by ETH_HLEN to the data ptr as received from FW */
+ skb_pull(skb, ETH_HLEN);
+ PHSReceive(Adapter, pLeader->Vcid, skb, &skb->len,
+ NULL, bHeaderSupressionEnabled);
+
+ if (!Adapter->PackInfo[QueueIndex].bEthCSSupport) {
+ skb_push(skb, ETH_HLEN);
+
+ memcpy(skb->data, skb->dev->dev_addr, 6);
+ memcpy(skb->data+6, skb->dev->dev_addr, 6);
+ (*(skb->data+11))++;
+ *(skb->data+12) = 0x08;
+ *(skb->data+13) = 0x00;
+ pLeader->PLength += ETH_HLEN;
+ }
+
+ skb->protocol = eth_type_trans(skb, Adapter->dev);
+ process_done = netif_rx(skb);
+ } else {
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_RX, RX_DATA, DBG_LVL_ALL, "i/f not up hance freeing SKB...");
+ dev_kfree_skb(skb);
+ }
+
+ ++Adapter->dev->stats.rx_packets;
+ Adapter->dev->stats.rx_bytes += pLeader->PLength;
+
+ for (uiIndex = 0; uiIndex < MIBS_MAX_HIST_ENTRIES; uiIndex++) {
+ if ((pLeader->PLength <= MIBS_PKTSIZEHIST_RANGE*(uiIndex+1)) &&
+ (pLeader->PLength > MIBS_PKTSIZEHIST_RANGE*(uiIndex)))
+ Adapter->aRxPktSizeHist[uiIndex]++;
+ }
+ }
+ Adapter->PrevNumRecvDescs++;
+ pRcb->bUsed = false;
+ atomic_dec(&psIntfAdapter->uNumRcbUsed);
+}
+
+static int ReceiveRcb(struct bcm_interface_adapter *psIntfAdapter, struct bcm_usb_rcb *pRcb)
+{
+ struct urb *urb = pRcb->urb;
+ int retval = 0;
+
+ usb_fill_bulk_urb(urb, psIntfAdapter->udev, usb_rcvbulkpipe(psIntfAdapter->udev, psIntfAdapter->sBulkIn.bulk_in_endpointAddr),
+ urb->transfer_buffer, BCM_USB_MAX_READ_LENGTH, read_bulk_callback, pRcb);
+ if (false == psIntfAdapter->psAdapter->device_removed &&
+ false == psIntfAdapter->psAdapter->bEndPointHalted &&
+ false == psIntfAdapter->bSuspended &&
+ false == psIntfAdapter->bPreparingForBusSuspend) {
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+ if (retval) {
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "failed submitting read urb, error %d", retval);
+ /* if this return value is because of pipe halt. need to clear this. */
+ if (retval == -EPIPE) {
+ psIntfAdapter->psAdapter->bEndPointHalted = TRUE;
+ wake_up(&psIntfAdapter->psAdapter->tx_packet_wait_queue);
+ }
+
+ }
+ }
+ return retval;
+}
+
+/*
+Function: InterfaceRx
+
+Description: This is the hardware specific Function for Receiving
+ data packet/control packets from the device.
+
+Input parameters: IN struct bcm_mini_adapter *Adapter - Miniport Adapter Context
+
+
+
+Return: TRUE - If Rx was successful.
+ Other - If an error occurred.
+*/
+
+bool InterfaceRx(struct bcm_interface_adapter *psIntfAdapter)
+{
+ USHORT RxDescCount = NUM_RX_DESC - atomic_read(&psIntfAdapter->uNumRcbUsed);
+ struct bcm_usb_rcb *pRcb = NULL;
+
+ while (RxDescCount) {
+ pRcb = GetBulkInRcb(psIntfAdapter);
+ if (pRcb == NULL) {
+ BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "Unable to get Rcb pointer");
+ return false;
+ }
+ ReceiveRcb(psIntfAdapter, pRcb);
+ RxDescCount--;
+ }
+ return TRUE;
+}
+