aboutsummaryrefslogtreecommitdiff
path: root/drivers/staging/bcm/Transmit.c
diff options
context:
space:
mode:
authorStephen Hemminger <stephen.hemminger@vyatta.com>2010-09-08 14:46:36 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2010-09-08 21:15:06 -0700
commitf8942e07a3db9d82e8fb11d3d494876b8bae9ff9 (patch)
tree2406636a4f9a4ac6b0bfc90e07aefa8b1b18b8ff /drivers/staging/bcm/Transmit.c
parent2d2f03b022186e6d7520a758abdea9c04a2969fe (diff)
staging: Beeceem USB Wimax driver
The Sprint 4G network uses a Wimax dongle with Beecem chipset. The driver is typical of out of tree drivers, but maybe useful for people, and the hardware is readily available. Here is a staging ready version (i.e warts and all) 0. Started with Rel_5.2.7.3P1_USB from Sprint4GDeveloperPack-1.1 1. Consolidated files in staging 2. Remove Dos cr/lf 3. Remove unnecessary ioctl from usbbcm_fops Applied patches that were in the developer pack, surprising there were ones for 2.6.35 already. This is compile tested only, see TODO for what still needs to be done. Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/bcm/Transmit.c')
-rw-r--r--drivers/staging/bcm/Transmit.c553
1 files changed, 553 insertions, 0 deletions
diff --git a/drivers/staging/bcm/Transmit.c b/drivers/staging/bcm/Transmit.c
new file mode 100644
index 00000000000..9a076b54324
--- /dev/null
+++ b/drivers/staging/bcm/Transmit.c
@@ -0,0 +1,553 @@
+/**
+@file Transmit.c
+@defgroup tx_functions Transmission
+@section Queueing
+@dot
+digraph transmit1 {
+node[shape=box]
+edge[weight=5;color=red]
+bcm_transmit->reply_to_arp_request[label="ARP"]
+bcm_transmit->GetPacketQueueIndex[label="IP Packet"]
+GetPacketQueueIndex->IpVersion4[label="IPV4"]
+GetPacketQueueIndex->IpVersion6[label="IPV6"]
+}
+
+@enddot
+
+@section De-Queueing
+@dot
+digraph transmit2 {
+node[shape=box]
+edge[weight=5;color=red]
+interrupt_service_thread->transmit_packets
+tx_pkt_hdler->transmit_packets
+transmit_packets->CheckAndSendPacketFromIndex
+transmit_packets->UpdateTokenCount
+CheckAndSendPacketFromIndex->PruneQueue
+CheckAndSendPacketFromIndex->IsPacketAllowedForFlow
+CheckAndSendPacketFromIndex->SendControlPacket[label="control pkt"]
+SendControlPacket->bcm_cmd53
+CheckAndSendPacketFromIndex->SendPacketFromQueue[label="data pkt"]
+SendPacketFromQueue->SetupNextSend->bcm_cmd53
+}
+@enddot
+*/
+
+#include "headers.h"
+
+/*******************************************************************
+* Function - bcm_transmit()
+*
+* Description - This is the main transmit function for our virtual
+* interface(veth0). It handles the ARP packets. It
+* clones this packet and then Queue it to a suitable
+* Queue. Then calls the transmit_packet().
+*
+* Parameter - skb - Pointer to the socket buffer structure
+* dev - Pointer to the virtual net device structure
+*
+* Returns - zero (success) or -ve value (failure)
+*
+*********************************************************************/
+
+INT bcm_transmit(struct sk_buff *skb, /**< skb */
+ struct net_device *dev /**< net device pointer */
+ )
+{
+ PMINI_ADAPTER Adapter = NULL;
+ USHORT qindex=0;
+ struct timeval tv;
+ UINT pkt_type = 0;
+ UINT calltransmit = 0;
+
+ BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "\n%s====>\n",__FUNCTION__);
+
+ memset(&tv, 0, sizeof(tv));
+ /* Check for valid parameters */
+ if(skb == NULL || dev==NULL)
+ {
+ BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX,TX_OSAL_DBG, DBG_LVL_ALL, "Got NULL skb or dev\n");
+ return -EINVAL;
+ }
+
+ Adapter = GET_BCM_ADAPTER(dev);
+ if(!Adapter)
+ {
+ BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Got Invalid Adapter\n");
+ return -EINVAL;
+ }
+ if(Adapter->device_removed == TRUE || !Adapter->LinkUpStatus)
+ {
+ if(!netif_queue_stopped(dev)) {
+ netif_carrier_off(dev);
+ netif_stop_queue(dev);
+ }
+ return STATUS_FAILURE;
+ }
+ BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Packet size : %d\n", skb->len);
+
+ /*Add Ethernet CS check here*/
+ if(Adapter->TransferMode == IP_PACKET_ONLY_MODE )
+ {
+ pkt_type = ntohs(*(PUSHORT)(skb->data + 12));
+ /* Get the queue index where the packet is to be queued */
+ BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Getting the Queue Index.....");
+
+ qindex = GetPacketQueueIndex(Adapter,skb);
+
+ if((SHORT)INVALID_QUEUE_INDEX==(SHORT)qindex)
+ {
+ if(pkt_type == ETH_ARP_FRAME)
+ {
+ /*
+ Reply directly to ARP request packet
+ ARP Spoofing only if NO ETH CS rule matches for it
+ */
+ BCM_DEBUG_PRINT (Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL,"ARP OPCODE = %02x",
+
+ (*(PUCHAR)(skb->data + 21)));
+
+ reply_to_arp_request(skb);
+
+ BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX,TX_OSAL_DBG, DBG_LVL_ALL,"After reply_to_arp_request \n");
+
+ }
+ else
+ {
+ BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL,
+ "Invalid queue index, dropping pkt\n");
+
+ bcm_kfree_skb(skb);
+ }
+ return STATUS_SUCCESS;
+ }
+
+ if(Adapter->PackInfo[qindex].uiCurrentPacketsOnHost >= SF_MAX_ALLOWED_PACKETS_TO_BACKUP)
+ {
+ atomic_inc(&Adapter->TxDroppedPacketCount);
+ bcm_kfree_skb(skb);
+ return STATUS_SUCCESS;
+ }
+
+ /* Now Enqueue the packet */
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "bcm_transmit Enqueueing the Packet To Queue %d",qindex);
+ spin_lock(&Adapter->PackInfo[qindex].SFQueueLock);
+ Adapter->PackInfo[qindex].uiCurrentBytesOnHost += skb->len;
+ Adapter->PackInfo[qindex].uiCurrentPacketsOnHost++;
+
+ *((B_UINT32 *)skb->cb + SKB_CB_LATENCY_OFFSET ) = jiffies;
+ ENQUEUEPACKET(Adapter->PackInfo[qindex].FirstTxQueue,
+ Adapter->PackInfo[qindex].LastTxQueue, skb);
+ atomic_inc(&Adapter->TotalPacketCount);
+ spin_unlock(&Adapter->PackInfo[qindex].SFQueueLock);
+ do_gettimeofday(&tv);
+
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL,"ENQ: \n");
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Pkt Len = %d, sec: %ld, usec: %ld\n",
+ (skb->len-ETH_HLEN), tv.tv_sec, tv.tv_usec);
+
+#ifdef BCM_SHM_INTERFACE
+ spin_lock(&Adapter->txtransmitlock);
+ if(Adapter->txtransmit_running == 0)
+ {
+ Adapter->txtransmit_running = 1;
+ calltransmit = 1;
+ }
+ else
+ calltransmit = 0;
+
+ spin_unlock(&Adapter->txtransmitlock);
+#endif
+ if(calltransmit == 1)
+ transmit_packets(Adapter);
+ else
+ {
+ if(!atomic_read(&Adapter->TxPktAvail))
+ {
+ atomic_set(&Adapter->TxPktAvail, 1);
+#ifdef BCM_SHM_INTERFACE
+ virtual_mail_box_interrupt();
+#endif
+ wake_up(&Adapter->tx_packet_wait_queue);
+ }
+ }
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "<====");
+ }
+ else
+ bcm_kfree_skb(skb);
+
+ return STATUS_SUCCESS;
+}
+
+
+/**
+@ingroup ctrl_pkt_functions
+This function dispatches control packet to the h/w interface
+@return zero(success) or -ve value(failure)
+*/
+INT SendControlPacket(PMINI_ADAPTER Adapter, /**<Logical Adapter*/
+ char *pControlPacket/**<Control Packet*/
+ )
+{
+ PLEADER PLeader = NULL;
+ struct timeval tv;
+ memset(&tv, 0, sizeof(tv));
+
+
+
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "========>");
+
+ PLeader=(PLEADER)pControlPacket;
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Tx");
+ if(!pControlPacket || !Adapter)
+ {
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Got NULL Control Packet or Adapter");
+ return STATUS_FAILURE;
+ }
+ if((atomic_read( &Adapter->CurrNumFreeTxDesc ) <
+ ((PLeader->PLength-1)/MAX_DEVICE_DESC_SIZE)+1))
+ {
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "NO FREE DESCRIPTORS TO SEND CONTROL PACKET");
+ if(Adapter->bcm_jiffies == 0)
+ {
+ Adapter->bcm_jiffies = jiffies;
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "UPDATED TIME(hex): %lu",
+ Adapter->bcm_jiffies);
+ }
+ return STATUS_FAILURE;
+ }
+
+ /* Update the netdevice statistics */
+ /* Dump Packet */
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader Status: %x", PLeader->Status);
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader VCID: %x",PLeader->Vcid);
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader Length: %x",PLeader->PLength);
+ if(Adapter->device_removed)
+ return 0;
+#ifndef BCM_SHM_INTERFACE
+ Adapter->interface_transmit(Adapter->pvInterfaceAdapter,
+ pControlPacket, (PLeader->PLength + LEADER_SIZE));
+#else
+ tx_pkts_to_firmware(pControlPacket,(PLeader->PLength + LEADER_SIZE),1);
+
+ if(PLeader->Status==IDLE_MESSAGE)
+ {
+ if(((CONTROL_MESSAGE*)PLeader)->szData[0] == GO_TO_IDLE_MODE_PAYLOAD &&
+ ((CONTROL_MESSAGE*)PLeader)->szData[1] == TARGET_CAN_GO_TO_IDLE_MODE)
+ {
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Idle Mode Ack Sent to the Device\n");
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Host Entering into Idle Mode\n");
+ do_gettimeofday(&tv);
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "IdleMode Msg sent to f/w at time :%ld ms", tv.tv_sec *1000 + tv.tv_usec /1000);
+ if(Adapter->bDoSuspend != TRUE)
+ {
+ Adapter->IdleMode = TRUE;
+ Adapter->bPreparingForLowPowerMode = FALSE ;
+ }
+ }
+ }
+ if((PLeader->Status == LINK_UP_CONTROL_REQ) &&
+ ((PUCHAR)pControlPacket)[sizeof(LEADER)] == LINK_UP_ACK &&
+ ((PUCHAR)pControlPacket)[sizeof(LEADER)+1] ==
+ LINK_SHUTDOWN_REQ_FROM_FIRMWARE &&
+ ((PUCHAR)pControlPacket)[sizeof(LEADER)+2] == SHUTDOWN_ACK_FROM_DRIVER)
+ {
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Shut Down ACK Sent and Host entering Shut State \n");
+ if(Adapter->bDoSuspend != TRUE)
+ {
+ Adapter->bShutStatus = TRUE;
+ Adapter->bPreparingForLowPowerMode = FALSE;
+ Adapter->bTriedToWakeUpFromlowPowerMode = FALSE;
+ }
+
+ }
+#endif
+
+ ((PLINUX_DEP_DATA)Adapter->pvOsDepData)->netstats.tx_packets++;
+ ((PLINUX_DEP_DATA)Adapter->pvOsDepData)->netstats.tx_bytes+=
+ PLeader->PLength;
+ atomic_dec(&Adapter->CurrNumFreeTxDesc);
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "<=========");
+ return STATUS_SUCCESS;
+}
+static LEADER Leader={0};
+/**
+@ingroup tx_functions
+This function despatches the IP packets with the given vcid
+to the target via the host h/w interface.
+@return zero(success) or -ve value(failure)
+*/
+INT SetupNextSend(PMINI_ADAPTER Adapter, /**<Logical Adapter*/
+ struct sk_buff *Packet, /**<data buffer*/
+ USHORT Vcid) /**<VCID for this packet*/
+{
+ int status=0;
+ int dontfree = 0;
+ BOOLEAN bHeaderSupressionEnabled = FALSE;
+ B_UINT16 uiClassifierRuleID;
+ int QueueIndex = NO_OF_QUEUES + 1;
+
+ if(!Adapter || !Packet)
+ {
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Got NULL Adapter or Packet");
+ return -EINVAL;
+ }
+ if(Packet->len > MAX_DEVICE_DESC_SIZE)
+ {
+ status = STATUS_FAILURE;
+ goto errExit;
+ }
+
+ /* Get the Classifier Rule ID */
+ uiClassifierRuleID = *((UINT32*) (Packet->cb)+SKB_CB_CLASSIFICATION_OFFSET);
+ QueueIndex = SearchVcid( Adapter,Vcid);
+ if(QueueIndex < NO_OF_QUEUES)
+ {
+ bHeaderSupressionEnabled =
+ Adapter->PackInfo[QueueIndex].bHeaderSuppressionEnabled;
+ bHeaderSupressionEnabled =
+ bHeaderSupressionEnabled & Adapter->bPHSEnabled;
+ }
+ if(Adapter->device_removed)
+ {
+ status = STATUS_FAILURE;
+ goto errExit;
+ }
+
+ status = PHSTransmit(Adapter, &Packet, Vcid, uiClassifierRuleID, bHeaderSupressionEnabled,
+ (UINT *)&Packet->len, Adapter->PackInfo[QueueIndex].bEthCSSupport);
+
+ if(status != STATUS_SUCCESS)
+ {
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "PHS Transmit failed..\n");
+ goto errExit;
+ }
+
+ Leader.Vcid = Vcid;
+
+ if(TCP_ACK == *((UINT32*) (Packet->cb) + SKB_CB_TCPACK_OFFSET ))
+ {
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Sending TCP ACK\n");
+ Leader.Status = LEADER_STATUS_TCP_ACK;
+ }
+ else
+ {
+ Leader.Status = LEADER_STATUS;
+ }
+
+ if(Adapter->PackInfo[QueueIndex].bEthCSSupport)
+ {
+ Leader.PLength = Packet->len;
+ if(skb_headroom(Packet) < LEADER_SIZE)
+ {
+ if((status = skb_cow(Packet,LEADER_SIZE)))
+ {
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL,"bcm_transmit : Failed To Increase headRoom\n");
+ goto errExit;
+ }
+ }
+ skb_push(Packet, LEADER_SIZE);
+ memcpy(Packet->data, &Leader, LEADER_SIZE);
+ }
+
+ else
+ {
+ Leader.PLength = Packet->len - ETH_HLEN;
+ memcpy((LEADER*)skb_pull(Packet, (ETH_HLEN - LEADER_SIZE)), &Leader, LEADER_SIZE);
+ }
+
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Packet->len = %d", Packet->len);
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Vcid = %d", Vcid);
+
+#ifndef BCM_SHM_INTERFACE
+ status = Adapter->interface_transmit(Adapter->pvInterfaceAdapter,
+ Packet->data, (Leader.PLength + LEADER_SIZE));
+#else
+ status = tx_pkts_to_firmware(Packet,Packet->len,0);
+#endif
+ if(status)
+ {
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Tx Failed..\n");
+ }
+ else
+ {
+ Adapter->PackInfo[QueueIndex].uiTotalTxBytes += Leader.PLength;
+ atomic_add(Leader.PLength, &Adapter->GoodTxByteCount);
+ atomic_inc(&Adapter->TxTotalPacketCount);
+#ifdef GDMA_INTERFACE
+ dontfree = 1;
+#endif
+ }
+
+ atomic_dec(&Adapter->CurrNumFreeTxDesc);
+
+errExit:
+
+ if(STATUS_SUCCESS == status)
+ {
+ Adapter->PackInfo[QueueIndex].uiCurrentTokenCount -= Leader.PLength << 3;
+ Adapter->PackInfo[QueueIndex].uiSentBytes += (Packet->len);
+ Adapter->PackInfo[QueueIndex].uiSentPackets++;
+ Adapter->PackInfo[QueueIndex].NumOfPacketsSent++;
+
+ atomic_dec(&Adapter->PackInfo[QueueIndex].uiPerSFTxResourceCount);
+#ifdef BCM_SHM_INTERFACE
+ if(atomic_read(&Adapter->PackInfo[QueueIndex].uiPerSFTxResourceCount) < 0)
+ {
+ atomic_set(&Adapter->PackInfo[QueueIndex].uiPerSFTxResourceCount, 0);
+ }
+#endif
+ Adapter->PackInfo[QueueIndex].uiThisPeriodSentBytes += Leader.PLength;
+ }
+
+
+#ifdef GDMA_INTERFACE
+ if(!dontfree){
+ bcm_kfree_skb(Packet);
+ }
+#else
+ bcm_kfree_skb(Packet);
+#endif
+ return status;
+}
+
+/**
+@ingroup tx_functions
+Transmit thread
+*/
+int tx_pkt_handler(PMINI_ADAPTER Adapter /**< pointer to adapter object*/
+ )
+{
+#ifndef BCM_SHM_INTERFACE
+ int status = 0;
+#endif
+
+ UINT calltransmit = 1;
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Entring to wait for signal from the interrupt service thread!Adapter = 0x%x",(unsigned int) Adapter);
+
+
+ while(1)
+ {
+ if(Adapter->LinkUpStatus){
+ wait_event_timeout(Adapter->tx_packet_wait_queue,
+ ((atomic_read(&Adapter->TxPktAvail) &&
+ (MINIMUM_PENDING_DESCRIPTORS <
+ atomic_read(&Adapter->CurrNumFreeTxDesc)) &&
+ (Adapter->device_removed == FALSE))) ||
+ (1 == Adapter->downloadDDR) || kthread_should_stop()
+#ifndef BCM_SHM_INTERFACE
+ || (TRUE == Adapter->bEndPointHalted)
+#endif
+ , msecs_to_jiffies(10));
+ }
+ else{
+ wait_event(Adapter->tx_packet_wait_queue,
+ ((atomic_read(&Adapter->TxPktAvail) &&
+ (MINIMUM_PENDING_DESCRIPTORS <
+ atomic_read(&Adapter->CurrNumFreeTxDesc)) &&
+ (Adapter->device_removed == FALSE))) ||
+ (1 == Adapter->downloadDDR) || kthread_should_stop()
+#ifndef BCM_SHM_INTERFACE
+ || (TRUE == Adapter->bEndPointHalted)
+#endif
+ );
+ }
+
+ if(kthread_should_stop() || Adapter->device_removed)
+ {
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Exiting the tx thread..\n");
+ Adapter->transmit_packet_thread = NULL;
+ return 0;
+ }
+
+#ifndef BCM_SHM_INTERFACE
+
+ if(Adapter->downloadDDR == 1)
+ {
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Downloading DDR Settings\n");
+ Adapter->downloadDDR +=1;
+ status = download_ddr_settings(Adapter);
+ if(status)
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "DDR DOWNLOAD FAILED!\n");
+ continue;
+ }
+
+ //Check end point for halt/stall.
+ if(Adapter->bEndPointHalted == TRUE)
+ {
+ Bcm_clear_halt_of_endpoints(Adapter);
+ Adapter->bEndPointHalted = FALSE;
+ StartInterruptUrb((PS_INTERFACE_ADAPTER)(Adapter->pvInterfaceAdapter));
+ }
+
+ if(Adapter->LinkUpStatus && !Adapter->IdleMode)
+ {
+ if(atomic_read(&Adapter->TotalPacketCount))
+ {
+ update_per_sf_desc_cnts(Adapter);
+ }
+ }
+#endif
+
+ if( atomic_read(&Adapter->CurrNumFreeTxDesc) &&
+ Adapter->LinkStatus == SYNC_UP_REQUEST &&
+ !Adapter->bSyncUpRequestSent)
+ {
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Calling LinkMessage");
+ LinkMessage(Adapter);
+ }
+
+ if((Adapter->IdleMode || Adapter->bShutStatus) && atomic_read(&Adapter->TotalPacketCount))
+ {
+ BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Device in Low Power mode...waking up");
+ Adapter->usIdleModePattern = ABORT_IDLE_MODE;
+ Adapter->bWakeUpDevice = TRUE;
+ wake_up(&Adapter->process_rx_cntrlpkt);
+ }
+
+#ifdef BCM_SHM_INTERFACE
+ spin_lock_bh(&Adapter->txtransmitlock);
+ if(Adapter->txtransmit_running == 0)
+ {
+ Adapter->txtransmit_running = 1;
+ calltransmit = 1;
+ }
+ else
+ calltransmit = 0;
+ spin_unlock_bh(&Adapter->txtransmitlock);
+#endif
+
+ if(calltransmit)
+ transmit_packets(Adapter);
+
+ atomic_set(&Adapter->TxPktAvail, 0);
+ }
+ return 0;
+}
+
+#ifdef BCM_SHM_INTERFACE
+extern PMINI_ADAPTER psAdaptertest;
+void virtual_mail_box_interrupt(void)
+{
+
+#ifndef GDMA_INTERFACE
+ PUINT ptr = (PUINT)CPE_VIRTUAL_MAILBOX_REG;
+ UINT intval = (UINT)((*ptr & 0xFF00) >> 8);
+ if (intval != 0)
+ {
+ atomic_set(&psAdaptertest->CurrNumFreeTxDesc, intval);
+ atomic_set (&psAdaptertest->uiMBupdate, TRUE);
+
+ //make it to 0
+ *ptr = *ptr & 0xffff00ff;
+ }
+#endif
+}
+unsigned int total_tx_pkts_pending(void)
+{
+ return atomic_read(&psAdaptertest->TotalPacketCount);
+}
+
+#endif
+
+