diff options
Diffstat (limited to 'drivers/staging/bcm/InterfaceRx.c')
| -rw-r--r-- | drivers/staging/bcm/InterfaceRx.c | 233 |
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; +} + |
