2010-09-08 21:46:36 +00:00
|
|
|
#include "headers.h"
|
2010-11-01 17:34:35 +00:00
|
|
|
|
2014-06-30 08:10:02 +00:00
|
|
|
static void handle_control_packet(struct bcm_interface_adapter *interface,
|
|
|
|
struct bcm_mini_adapter *ad,
|
|
|
|
struct bcm_leader *leader,
|
|
|
|
struct sk_buff *skb,
|
|
|
|
struct urb *urb)
|
|
|
|
{
|
|
|
|
BCM_DEBUG_PRINT(interface->psAdapter, DBG_TYPE_RX, RX_CTRL, DBG_LVL_ALL,
|
|
|
|
"Received control pkt...");
|
|
|
|
*(PUSHORT)skb->data = leader->Status;
|
|
|
|
memcpy(skb->data+sizeof(USHORT), urb->transfer_buffer +
|
|
|
|
(sizeof(struct bcm_leader)), leader->PLength);
|
|
|
|
skb->len = leader->PLength + sizeof(USHORT);
|
|
|
|
|
|
|
|
spin_lock(&ad->control_queue_lock);
|
|
|
|
ENQUEUEPACKET(ad->RxControlHead, ad->RxControlTail, skb);
|
|
|
|
spin_unlock(&ad->control_queue_lock);
|
|
|
|
|
|
|
|
atomic_inc(&ad->cntrlpktCnt);
|
|
|
|
wake_up(&ad->process_rx_cntrlpkt);
|
|
|
|
}
|
|
|
|
|
2014-06-30 08:10:03 +00:00
|
|
|
static void format_eth_hdr_to_stack(struct bcm_interface_adapter *interface,
|
|
|
|
struct bcm_mini_adapter *ad,
|
|
|
|
struct bcm_leader *p_leader,
|
|
|
|
struct sk_buff *skb,
|
|
|
|
struct urb *urb,
|
|
|
|
UINT ui_index,
|
|
|
|
int queue_index,
|
2014-06-30 08:10:04 +00:00
|
|
|
bool b_header_supression_endabled)
|
2014-06-30 08:10:03 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Data Packet, Format a proper Ethernet Header
|
|
|
|
* and give it to the stack
|
|
|
|
*/
|
|
|
|
BCM_DEBUG_PRINT(interface->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), p_leader->PLength);
|
|
|
|
skb->dev = ad->dev;
|
|
|
|
|
|
|
|
/* currently skb->len has extra ETH_HLEN bytes in the beginning */
|
|
|
|
skb_put(skb, p_leader->PLength + ETH_HLEN);
|
|
|
|
ad->PackInfo[queue_index].uiTotalRxBytes += p_leader->PLength;
|
|
|
|
ad->PackInfo[queue_index].uiThisPeriodRxBytes += p_leader->PLength;
|
|
|
|
BCM_DEBUG_PRINT(interface->psAdapter, DBG_TYPE_RX, RX_DATA,
|
|
|
|
DBG_LVL_ALL, "Received Data pkt of len :0x%X",
|
|
|
|
p_leader->PLength);
|
|
|
|
|
|
|
|
if (netif_running(ad->dev)) {
|
|
|
|
/* Moving ahead by ETH_HLEN to the data ptr as received from FW */
|
|
|
|
skb_pull(skb, ETH_HLEN);
|
|
|
|
PHSReceive(ad, p_leader->Vcid, skb, &skb->len,
|
|
|
|
NULL, b_header_supression_endabled);
|
|
|
|
|
|
|
|
if (!ad->PackInfo[queue_index].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;
|
|
|
|
p_leader->PLength += ETH_HLEN;
|
|
|
|
}
|
|
|
|
|
|
|
|
skb->protocol = eth_type_trans(skb, ad->dev);
|
2014-06-30 08:10:04 +00:00
|
|
|
netif_rx(skb);
|
2014-06-30 08:10:03 +00:00
|
|
|
} else {
|
|
|
|
BCM_DEBUG_PRINT(interface->psAdapter, DBG_TYPE_RX,
|
|
|
|
RX_DATA, DBG_LVL_ALL,
|
|
|
|
"i/f not up hance freeing SKB...");
|
|
|
|
dev_kfree_skb(skb);
|
|
|
|
}
|
|
|
|
|
|
|
|
++ad->dev->stats.rx_packets;
|
|
|
|
ad->dev->stats.rx_bytes += p_leader->PLength;
|
|
|
|
|
|
|
|
for (ui_index = 0; ui_index < MIBS_MAX_HIST_ENTRIES; ui_index++) {
|
|
|
|
if ((p_leader->PLength <=
|
|
|
|
MIBS_PKTSIZEHIST_RANGE*(ui_index+1)) &&
|
|
|
|
(p_leader->PLength > MIBS_PKTSIZEHIST_RANGE*(ui_index)))
|
|
|
|
|
|
|
|
ad->aRxPktSizeHist[ui_index]++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-08 22:15:06 +00:00
|
|
|
static int SearchVcid(struct bcm_mini_adapter *Adapter, unsigned short usVcid)
|
2010-11-01 17:34:35 +00:00
|
|
|
{
|
2014-01-08 22:15:05 +00:00
|
|
|
int iIndex = 0;
|
2010-11-01 17:34:35 +00:00
|
|
|
|
2014-01-08 22:15:08 +00:00
|
|
|
for (iIndex = (NO_OF_QUEUES-1); iIndex >= 0; iIndex--)
|
|
|
|
if (Adapter->PackInfo[iIndex].usVCID_Value == usVcid)
|
2010-11-01 17:34:35 +00:00
|
|
|
return iIndex;
|
|
|
|
return NO_OF_QUEUES+1;
|
|
|
|
|
|
|
|
}
|
2010-09-08 21:46:36 +00:00
|
|
|
|
|
|
|
|
2012-11-02 03:42:22 +00:00
|
|
|
static struct bcm_usb_rcb *
|
2012-11-02 03:42:21 +00:00
|
|
|
GetBulkInRcb(struct bcm_interface_adapter *psIntfAdapter)
|
2010-09-08 21:46:36 +00:00
|
|
|
{
|
2012-11-02 03:42:22 +00:00
|
|
|
struct bcm_usb_rcb *pRcb = NULL;
|
2010-09-08 21:46:36 +00:00
|
|
|
UINT index = 0;
|
|
|
|
|
2014-01-08 22:15:08 +00:00
|
|
|
if ((atomic_read(&psIntfAdapter->uNumRcbUsed) < MAXIMUM_USB_RCB) &&
|
2014-01-08 22:15:09 +00:00
|
|
|
(psIntfAdapter->psAdapter->StopAllXaction == false)) {
|
2010-09-08 21:46:36 +00:00
|
|
|
index = atomic_read(&psIntfAdapter->uCurrRcb);
|
|
|
|
pRcb = &psIntfAdapter->asUsbRcb[index];
|
|
|
|
pRcb->bUsed = TRUE;
|
2014-01-08 22:15:05 +00:00
|
|
|
pRcb->psIntfAdapter = psIntfAdapter;
|
2014-06-30 08:10:01 +00:00
|
|
|
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_RX, RX_DPC,
|
|
|
|
DBG_LVL_ALL, "Got Rx desc %d used %d", index,
|
|
|
|
atomic_read(&psIntfAdapter->uNumRcbUsed));
|
2010-09-08 21:46:36 +00:00
|
|
|
index = (index + 1) % MAXIMUM_USB_RCB;
|
|
|
|
atomic_set(&psIntfAdapter->uCurrRcb, index);
|
|
|
|
atomic_inc(&psIntfAdapter->uNumRcbUsed);
|
|
|
|
}
|
|
|
|
return pRcb;
|
|
|
|
}
|
|
|
|
|
2011-03-31 01:57:33 +00:00
|
|
|
/*this is receive call back - when pkt available for receive (BULK IN- end point)*/
|
2010-09-08 21:46:36 +00:00
|
|
|
static void read_bulk_callback(struct urb *urb)
|
|
|
|
{
|
|
|
|
struct sk_buff *skb = NULL;
|
2013-10-28 08:36:19 +00:00
|
|
|
bool bHeaderSupressionEnabled = false;
|
2010-09-08 21:46:36 +00:00
|
|
|
int QueueIndex = NO_OF_QUEUES + 1;
|
2014-01-08 22:15:05 +00:00
|
|
|
UINT uiIndex = 0;
|
2012-11-02 03:42:22 +00:00
|
|
|
struct bcm_usb_rcb *pRcb = (struct bcm_usb_rcb *)urb->context;
|
2012-11-02 03:42:21 +00:00
|
|
|
struct bcm_interface_adapter *psIntfAdapter = pRcb->psIntfAdapter;
|
2012-05-26 16:05:12 +00:00
|
|
|
struct bcm_mini_adapter *Adapter = psIntfAdapter->psAdapter;
|
2012-05-26 16:05:11 +00:00
|
|
|
struct bcm_leader *pLeader = urb->transfer_buffer;
|
2010-09-08 21:46:36 +00:00
|
|
|
|
2010-11-01 16:18:36 +00:00
|
|
|
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);
|
2010-09-08 21:46:36 +00:00
|
|
|
|
2014-01-08 22:15:08 +00:00
|
|
|
if ((Adapter->device_removed == TRUE) ||
|
|
|
|
(TRUE == Adapter->bEndPointHalted) ||
|
2014-01-08 22:15:09 +00:00
|
|
|
(0 == urb->actual_length)) {
|
2014-01-08 22:15:07 +00:00
|
|
|
pRcb->bUsed = false;
|
|
|
|
atomic_dec(&psIntfAdapter->uNumRcbUsed);
|
2010-09-08 21:46:36 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-01-08 22:15:09 +00:00
|
|
|
if (urb->status != STATUS_SUCCESS) {
|
|
|
|
if (urb->status == -EPIPE) {
|
2014-01-08 22:15:05 +00:00
|
|
|
Adapter->bEndPointHalted = TRUE;
|
2010-09-08 21:46:36 +00:00
|
|
|
wake_up(&Adapter->tx_packet_wait_queue);
|
2014-01-08 22:15:09 +00:00
|
|
|
} else {
|
2014-06-30 08:10:01 +00:00
|
|
|
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC,
|
|
|
|
DBG_LVL_ALL,
|
|
|
|
"Rx URB has got cancelled. status :%d",
|
|
|
|
urb->status);
|
2010-09-08 21:46:36 +00:00
|
|
|
}
|
2013-10-28 08:36:19 +00:00
|
|
|
pRcb->bUsed = false;
|
2014-01-08 22:15:07 +00:00
|
|
|
atomic_dec(&psIntfAdapter->uNumRcbUsed);
|
2014-01-08 22:15:05 +00:00
|
|
|
urb->status = STATUS_SUCCESS;
|
|
|
|
return;
|
2010-09-08 21:46:36 +00:00
|
|
|
}
|
|
|
|
|
2014-01-08 22:15:09 +00:00
|
|
|
if (Adapter->bDoSuspend && (Adapter->bPreparingForLowPowerMode)) {
|
2014-06-30 08:10:01 +00:00
|
|
|
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");
|
2014-01-08 22:15:05 +00:00
|
|
|
return;
|
2010-09-08 21:46:36 +00:00
|
|
|
}
|
|
|
|
|
2014-06-30 08:10:01 +00:00
|
|
|
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL,
|
|
|
|
"Read back done len %d\n", pLeader->PLength);
|
2014-01-08 22:15:09 +00:00
|
|
|
if (!pLeader->PLength) {
|
2014-06-30 08:10:01 +00:00
|
|
|
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL,
|
|
|
|
"Leader Length 0");
|
2010-09-08 21:46:36 +00:00
|
|
|
atomic_dec(&psIntfAdapter->uNumRcbUsed);
|
|
|
|
return;
|
|
|
|
}
|
2014-06-30 08:10:01 +00:00
|
|
|
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);
|
2014-01-08 22:15:09 +00:00
|
|
|
if (MAX_CNTL_PKT_SIZE < pLeader->PLength) {
|
2010-11-01 16:18:36 +00:00
|
|
|
if (netif_msg_rx_err(Adapter))
|
|
|
|
pr_info(PFX "%s: corrupted leader length...%d\n",
|
|
|
|
Adapter->dev->name, pLeader->PLength);
|
2010-11-01 17:34:35 +00:00
|
|
|
++Adapter->dev->stats.rx_dropped;
|
2010-09-08 21:46:36 +00:00
|
|
|
atomic_dec(&psIntfAdapter->uNumRcbUsed);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-01-08 22:15:08 +00:00
|
|
|
QueueIndex = SearchVcid(Adapter, pLeader->Vcid);
|
2014-01-08 22:15:09 +00:00
|
|
|
if (QueueIndex < NO_OF_QUEUES) {
|
2010-09-08 21:46:36 +00:00
|
|
|
bHeaderSupressionEnabled =
|
|
|
|
Adapter->PackInfo[QueueIndex].bHeaderSuppressionEnabled;
|
|
|
|
bHeaderSupressionEnabled =
|
|
|
|
bHeaderSupressionEnabled & Adapter->bPHSEnabled;
|
|
|
|
}
|
|
|
|
|
2014-06-30 08:10:01 +00:00
|
|
|
skb = dev_alloc_skb(pLeader->PLength + SKB_RESERVE_PHS_BYTES +
|
|
|
|
SKB_RESERVE_ETHERNET_HEADER);
|
2014-01-08 22:15:09 +00:00
|
|
|
if (!skb) {
|
2014-06-30 08:10:01 +00:00
|
|
|
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
|
|
|
"NO SKBUFF!!! Dropping the Packet");
|
2010-09-08 21:46:36 +00:00
|
|
|
atomic_dec(&psIntfAdapter->uNumRcbUsed);
|
|
|
|
return;
|
|
|
|
}
|
2014-01-08 22:15:07 +00:00
|
|
|
/* If it is a control Packet, then call handle_bcm_packet ()*/
|
2014-01-08 22:15:08 +00:00
|
|
|
if ((ntohs(pLeader->Vcid) == VCID_CONTROL_PACKET) ||
|
2014-01-08 22:15:09 +00:00
|
|
|
(!(pLeader->Status >= 0x20 && pLeader->Status <= 0x3F))) {
|
2014-06-30 08:10:02 +00:00
|
|
|
handle_control_packet(psIntfAdapter, Adapter, pLeader, skb,
|
|
|
|
urb);
|
2014-01-08 22:15:09 +00:00
|
|
|
} else {
|
2014-06-30 08:10:03 +00:00
|
|
|
format_eth_hdr_to_stack(psIntfAdapter, Adapter, pLeader, skb,
|
|
|
|
urb, uiIndex, QueueIndex,
|
2014-06-30 08:10:04 +00:00
|
|
|
bHeaderSupressionEnabled);
|
2010-09-08 21:46:36 +00:00
|
|
|
}
|
2014-01-08 22:15:07 +00:00
|
|
|
Adapter->PrevNumRecvDescs++;
|
2013-10-28 08:36:19 +00:00
|
|
|
pRcb->bUsed = false;
|
2010-09-08 21:46:36 +00:00
|
|
|
atomic_dec(&psIntfAdapter->uNumRcbUsed);
|
|
|
|
}
|
|
|
|
|
2014-06-30 08:10:01 +00:00
|
|
|
static int ReceiveRcb(struct bcm_interface_adapter *psIntfAdapter,
|
|
|
|
struct bcm_usb_rcb *pRcb)
|
2010-09-08 21:46:36 +00:00
|
|
|
{
|
|
|
|
struct urb *urb = pRcb->urb;
|
|
|
|
int retval = 0;
|
|
|
|
|
2014-06-30 08:10:01 +00:00
|
|
|
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);
|
|
|
|
|
2014-01-08 22:15:08 +00:00
|
|
|
if (false == psIntfAdapter->psAdapter->device_removed &&
|
|
|
|
false == psIntfAdapter->psAdapter->bEndPointHalted &&
|
|
|
|
false == psIntfAdapter->bSuspended &&
|
2014-01-08 22:15:09 +00:00
|
|
|
false == psIntfAdapter->bPreparingForBusSuspend) {
|
2010-09-08 21:46:36 +00:00
|
|
|
retval = usb_submit_urb(urb, GFP_ATOMIC);
|
2014-01-08 22:15:09 +00:00
|
|
|
if (retval) {
|
2014-06-30 08:10:01 +00:00
|
|
|
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_RX,
|
|
|
|
RX_DPC, DBG_LVL_ALL,
|
|
|
|
"failed submitting read urb, error %d",
|
|
|
|
retval);
|
2014-01-08 22:15:10 +00:00
|
|
|
/* if this return value is because of pipe halt. need to clear this. */
|
2014-01-08 22:15:09 +00:00
|
|
|
if (retval == -EPIPE) {
|
2014-01-08 22:15:05 +00:00
|
|
|
psIntfAdapter->psAdapter->bEndPointHalted = TRUE;
|
2010-09-08 21:46:36 +00:00
|
|
|
wake_up(&psIntfAdapter->psAdapter->tx_packet_wait_queue);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Function: InterfaceRx
|
|
|
|
|
2011-06-23 18:40:18 +00:00
|
|
|
Description: This is the hardware specific Function for Receiving
|
2010-09-08 21:46:36 +00:00
|
|
|
data packet/control packets from the device.
|
|
|
|
|
2012-05-26 16:05:12 +00:00
|
|
|
Input parameters: IN struct bcm_mini_adapter *Adapter - Miniport Adapter Context
|
2010-09-08 21:46:36 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Return: TRUE - If Rx was successful.
|
2011-03-31 01:57:33 +00:00
|
|
|
Other - If an error occurred.
|
2010-09-08 21:46:36 +00:00
|
|
|
*/
|
|
|
|
|
2014-01-08 22:15:08 +00:00
|
|
|
bool InterfaceRx(struct bcm_interface_adapter *psIntfAdapter)
|
2010-09-08 21:46:36 +00:00
|
|
|
{
|
2014-06-30 08:10:01 +00:00
|
|
|
USHORT RxDescCount = NUM_RX_DESC -
|
|
|
|
atomic_read(&psIntfAdapter->uNumRcbUsed);
|
|
|
|
|
2012-11-02 03:42:22 +00:00
|
|
|
struct bcm_usb_rcb *pRcb = NULL;
|
2010-09-08 21:46:36 +00:00
|
|
|
|
2014-01-08 22:15:09 +00:00
|
|
|
while (RxDescCount) {
|
2010-09-08 21:46:36 +00:00
|
|
|
pRcb = GetBulkInRcb(psIntfAdapter);
|
2014-01-08 22:15:09 +00:00
|
|
|
if (pRcb == NULL) {
|
2014-06-30 08:10:01 +00:00
|
|
|
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
|
|
|
|
DBG_TYPE_PRINTK, 0, 0,
|
|
|
|
"Unable to get Rcb pointer");
|
2013-10-28 08:36:19 +00:00
|
|
|
return false;
|
2010-09-08 21:46:36 +00:00
|
|
|
}
|
|
|
|
ReceiveRcb(psIntfAdapter, pRcb);
|
|
|
|
RxDescCount--;
|
2014-01-08 22:15:07 +00:00
|
|
|
}
|
2010-09-08 21:46:36 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|