2010-09-08 15:46:36 -06:00
|
|
|
/**
|
2012-09-13 19:11:37 -06:00
|
|
|
* @file Transmit.c
|
|
|
|
* @defgroup tx_functions Transmission
|
|
|
|
* @section Queueing
|
|
|
|
* @dot
|
|
|
|
* digraph transmit1 {
|
|
|
|
* node[shape=box]
|
|
|
|
* edge[weight=5;color=red]
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*/
|
2010-09-08 15:46:36 -06:00
|
|
|
|
|
|
|
#include "headers.h"
|
|
|
|
|
|
|
|
/**
|
2012-09-13 19:11:37 -06:00
|
|
|
* @ingroup ctrl_pkt_functions
|
|
|
|
* This function dispatches control packet to the h/w interface
|
|
|
|
* @return zero(success) or -ve value(failure)
|
|
|
|
*/
|
2012-09-13 19:11:38 -06:00
|
|
|
int SendControlPacket(struct bcm_mini_adapter *Adapter, char *pControlPacket)
|
2010-09-08 15:46:36 -06:00
|
|
|
{
|
2012-05-26 10:05:11 -06:00
|
|
|
struct bcm_leader *PLeader = (struct bcm_leader *)pControlPacket;
|
2010-09-08 15:46:36 -06:00
|
|
|
|
2012-09-13 19:11:34 -06:00
|
|
|
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Tx");
|
2012-09-13 19:11:35 -06:00
|
|
|
if (!pControlPacket || !Adapter) {
|
2012-09-13 19:11:34 -06:00
|
|
|
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) <
|
2012-09-13 19:11:35 -06:00
|
|
|
((PLeader->PLength-1)/MAX_DEVICE_DESC_SIZE)+1)) {
|
2012-09-13 19:11:34 -06:00
|
|
|
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "NO FREE DESCRIPTORS TO SEND CONTROL PACKET");
|
2010-09-08 15:46:36 -06:00
|
|
|
return STATUS_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update the netdevice statistics */
|
|
|
|
/* Dump Packet */
|
2012-09-13 19:11:34 -06:00
|
|
|
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)
|
2010-09-08 15:46:36 -06:00
|
|
|
return 0;
|
2010-11-01 12:09:05 -06:00
|
|
|
|
|
|
|
if (netif_msg_pktdata(Adapter))
|
|
|
|
print_hex_dump(KERN_DEBUG, PFX "tx control: ", DUMP_PREFIX_NONE,
|
2012-09-13 19:11:34 -06:00
|
|
|
16, 1, pControlPacket, PLeader->PLength + LEADER_SIZE, 0);
|
2010-11-01 12:09:05 -06:00
|
|
|
|
2010-09-08 15:46:36 -06:00
|
|
|
Adapter->interface_transmit(Adapter->pvInterfaceAdapter,
|
2012-09-13 19:11:34 -06:00
|
|
|
pControlPacket, (PLeader->PLength + LEADER_SIZE));
|
2010-09-08 15:46:36 -06:00
|
|
|
|
|
|
|
atomic_dec(&Adapter->CurrNumFreeTxDesc);
|
2012-09-13 19:11:34 -06:00
|
|
|
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "<=========");
|
2010-09-08 15:46:36 -06:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
2010-11-01 10:20:09 -06:00
|
|
|
|
2010-09-08 15:46:36 -06:00
|
|
|
/**
|
2012-09-13 19:11:37 -06:00
|
|
|
* @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)
|
|
|
|
*/
|
2012-09-13 19:11:38 -06:00
|
|
|
int SetupNextSend(struct bcm_mini_adapter *Adapter, struct sk_buff *Packet, USHORT Vcid)
|
2010-09-08 15:46:36 -06:00
|
|
|
{
|
2012-09-13 19:11:34 -06:00
|
|
|
int status = 0;
|
|
|
|
BOOLEAN bHeaderSupressionEnabled = FALSE;
|
|
|
|
B_UINT16 uiClassifierRuleID;
|
2010-11-01 11:34:35 -06:00
|
|
|
u16 QueueIndex = skb_get_queue_mapping(Packet);
|
2012-09-13 19:11:34 -06:00
|
|
|
struct bcm_leader Leader = {0};
|
2010-09-08 15:46:36 -06:00
|
|
|
|
2012-09-13 19:11:35 -06:00
|
|
|
if (Packet->len > MAX_DEVICE_DESC_SIZE) {
|
2010-09-08 15:46:36 -06:00
|
|
|
status = STATUS_FAILURE;
|
|
|
|
goto errExit;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the Classifier Rule ID */
|
2012-09-13 19:11:34 -06:00
|
|
|
uiClassifierRuleID = *((UINT32 *) (Packet->cb) + SKB_CB_CLASSIFICATION_OFFSET);
|
2010-11-01 11:34:35 -06:00
|
|
|
|
|
|
|
bHeaderSupressionEnabled = Adapter->PackInfo[QueueIndex].bHeaderSuppressionEnabled
|
|
|
|
& Adapter->bPHSEnabled;
|
|
|
|
|
2012-09-13 19:11:35 -06:00
|
|
|
if (Adapter->device_removed) {
|
2010-09-08 15:46:36 -06:00
|
|
|
status = STATUS_FAILURE;
|
|
|
|
goto errExit;
|
2012-09-13 19:11:34 -06:00
|
|
|
}
|
2010-09-08 15:46:36 -06:00
|
|
|
|
|
|
|
status = PHSTransmit(Adapter, &Packet, Vcid, uiClassifierRuleID, bHeaderSupressionEnabled,
|
2012-09-13 19:11:34 -06:00
|
|
|
(UINT *)&Packet->len, Adapter->PackInfo[QueueIndex].bEthCSSupport);
|
2010-09-08 15:46:36 -06:00
|
|
|
|
2012-09-13 19:11:35 -06:00
|
|
|
if (status != STATUS_SUCCESS) {
|
2012-09-13 19:11:34 -06:00
|
|
|
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "PHS Transmit failed..\n");
|
2010-09-08 15:46:36 -06:00
|
|
|
goto errExit;
|
|
|
|
}
|
|
|
|
|
2012-09-13 19:11:34 -06:00
|
|
|
Leader.Vcid = Vcid;
|
2010-09-08 15:46:36 -06:00
|
|
|
|
2012-09-13 19:11:34 -06:00
|
|
|
if (TCP_ACK == *((UINT32 *) (Packet->cb) + SKB_CB_TCPACK_OFFSET))
|
2010-09-08 15:46:36 -06:00
|
|
|
Leader.Status = LEADER_STATUS_TCP_ACK;
|
|
|
|
else
|
|
|
|
Leader.Status = LEADER_STATUS;
|
|
|
|
|
2012-09-13 19:11:35 -06:00
|
|
|
if (Adapter->PackInfo[QueueIndex].bEthCSSupport) {
|
2010-09-08 15:46:36 -06:00
|
|
|
Leader.PLength = Packet->len;
|
2012-09-13 19:11:35 -06:00
|
|
|
if (skb_headroom(Packet) < LEADER_SIZE) {
|
2012-09-13 19:11:36 -06:00
|
|
|
status = skb_cow(Packet, LEADER_SIZE);
|
|
|
|
if (status) {
|
2012-09-13 19:11:34 -06:00
|
|
|
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "bcm_transmit : Failed To Increase headRoom\n");
|
2010-09-08 15:46:36 -06:00
|
|
|
goto errExit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
skb_push(Packet, LEADER_SIZE);
|
|
|
|
memcpy(Packet->data, &Leader, LEADER_SIZE);
|
2012-09-13 19:11:35 -06:00
|
|
|
} else {
|
2010-09-08 15:46:36 -06:00
|
|
|
Leader.PLength = Packet->len - ETH_HLEN;
|
2012-05-26 10:05:11 -06:00
|
|
|
memcpy((struct bcm_leader *)skb_pull(Packet, (ETH_HLEN - LEADER_SIZE)), &Leader, LEADER_SIZE);
|
2010-09-08 15:46:36 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
status = Adapter->interface_transmit(Adapter->pvInterfaceAdapter,
|
2012-09-13 19:11:34 -06:00
|
|
|
Packet->data, (Leader.PLength + LEADER_SIZE));
|
2012-09-13 19:11:35 -06:00
|
|
|
if (status) {
|
2010-11-01 10:20:09 -06:00
|
|
|
++Adapter->dev->stats.tx_errors;
|
|
|
|
if (netif_msg_tx_err(Adapter))
|
|
|
|
pr_info(PFX "%s: transmit error %d\n", Adapter->dev->name,
|
|
|
|
status);
|
2012-09-13 19:11:35 -06:00
|
|
|
} else {
|
2011-01-17 17:11:12 -07:00
|
|
|
struct net_device_stats *netstats = &Adapter->dev->stats;
|
2010-09-08 15:46:36 -06:00
|
|
|
Adapter->PackInfo[QueueIndex].uiTotalTxBytes += Leader.PLength;
|
2010-11-01 11:34:35 -06:00
|
|
|
|
2011-01-17 17:11:12 -07:00
|
|
|
netstats->tx_bytes += Leader.PLength;
|
|
|
|
++netstats->tx_packets;
|
2010-11-01 11:34:35 -06:00
|
|
|
|
2010-09-08 15:46:36 -06:00
|
|
|
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);
|
|
|
|
Adapter->PackInfo[QueueIndex].uiThisPeriodSentBytes += Leader.PLength;
|
|
|
|
}
|
|
|
|
|
2010-11-01 10:20:09 -06:00
|
|
|
atomic_dec(&Adapter->CurrNumFreeTxDesc);
|
|
|
|
|
|
|
|
errExit:
|
2010-11-01 07:35:21 -06:00
|
|
|
dev_kfree_skb(Packet);
|
2010-09-08 15:46:36 -06:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2012-05-26 10:05:12 -06:00
|
|
|
static int tx_pending(struct bcm_mini_adapter *Adapter)
|
2010-11-01 07:49:30 -06:00
|
|
|
{
|
|
|
|
return (atomic_read(&Adapter->TxPktAvail)
|
|
|
|
&& MINIMUM_PENDING_DESCRIPTORS < atomic_read(&Adapter->CurrNumFreeTxDesc))
|
|
|
|
|| Adapter->device_removed || (1 == Adapter->downloadDDR);
|
|
|
|
}
|
|
|
|
|
2010-09-08 15:46:36 -06:00
|
|
|
/**
|
2012-09-13 19:11:37 -06:00
|
|
|
* @ingroup tx_functions
|
|
|
|
* Transmit thread
|
|
|
|
*/
|
2012-09-13 19:11:34 -06:00
|
|
|
int tx_pkt_handler(struct bcm_mini_adapter *Adapter /**< pointer to adapter object*/)
|
2010-09-08 15:46:36 -06:00
|
|
|
{
|
|
|
|
int status = 0;
|
|
|
|
|
2012-09-13 19:11:34 -06:00
|
|
|
while (!kthread_should_stop()) {
|
2010-11-01 07:49:30 -06:00
|
|
|
/* FIXME - the timeout looks like workaround for racey usage of TxPktAvail */
|
2012-09-13 19:11:34 -06:00
|
|
|
if (Adapter->LinkUpStatus)
|
2010-09-08 15:46:36 -06:00
|
|
|
wait_event_timeout(Adapter->tx_packet_wait_queue,
|
2012-09-13 19:11:34 -06:00
|
|
|
tx_pending(Adapter), msecs_to_jiffies(10));
|
2010-11-01 07:49:30 -06:00
|
|
|
else
|
|
|
|
wait_event_interruptible(Adapter->tx_packet_wait_queue,
|
2012-09-13 19:11:34 -06:00
|
|
|
tx_pending(Adapter));
|
2010-09-08 15:46:36 -06:00
|
|
|
|
2010-11-01 07:49:30 -06:00
|
|
|
if (Adapter->device_removed)
|
|
|
|
break;
|
2010-09-08 15:46:36 -06:00
|
|
|
|
2012-09-13 19:11:35 -06:00
|
|
|
if (Adapter->downloadDDR == 1) {
|
2012-09-13 19:11:34 -06:00
|
|
|
Adapter->downloadDDR += 1;
|
2010-09-08 15:46:36 -06:00
|
|
|
status = download_ddr_settings(Adapter);
|
2012-09-13 19:11:34 -06:00
|
|
|
if (status)
|
2010-11-01 10:20:09 -06:00
|
|
|
pr_err(PFX "DDR DOWNLOAD FAILED! %d\n", status);
|
2010-09-08 15:46:36 -06:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2012-09-13 19:11:37 -06:00
|
|
|
/* Check end point for halt/stall. */
|
2012-09-13 19:11:35 -06:00
|
|
|
if (Adapter->bEndPointHalted == TRUE) {
|
2010-09-08 15:46:36 -06:00
|
|
|
Bcm_clear_halt_of_endpoints(Adapter);
|
|
|
|
Adapter->bEndPointHalted = FALSE;
|
|
|
|
StartInterruptUrb((PS_INTERFACE_ADAPTER)(Adapter->pvInterfaceAdapter));
|
|
|
|
}
|
|
|
|
|
2012-09-13 19:11:35 -06:00
|
|
|
if (Adapter->LinkUpStatus && !Adapter->IdleMode) {
|
2012-09-13 19:11:34 -06:00
|
|
|
if (atomic_read(&Adapter->TotalPacketCount))
|
2010-09-08 15:46:36 -06:00
|
|
|
update_per_sf_desc_cnts(Adapter);
|
|
|
|
}
|
|
|
|
|
2012-09-13 19:11:34 -06:00
|
|
|
if (atomic_read(&Adapter->CurrNumFreeTxDesc) &&
|
2010-09-08 15:46:36 -06:00
|
|
|
Adapter->LinkStatus == SYNC_UP_REQUEST &&
|
2012-09-13 19:11:35 -06:00
|
|
|
!Adapter->bSyncUpRequestSent) {
|
|
|
|
|
2012-09-13 19:11:34 -06:00
|
|
|
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Calling LinkMessage");
|
2010-09-08 15:46:36 -06:00
|
|
|
LinkMessage(Adapter);
|
|
|
|
}
|
|
|
|
|
2012-09-13 19:11:35 -06:00
|
|
|
if ((Adapter->IdleMode || Adapter->bShutStatus) && atomic_read(&Adapter->TotalPacketCount)) {
|
2012-09-13 19:11:34 -06:00
|
|
|
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);
|
2010-09-08 15:46:36 -06:00
|
|
|
}
|
|
|
|
|
2010-11-01 07:49:30 -06:00
|
|
|
transmit_packets(Adapter);
|
2010-09-08 15:46:36 -06:00
|
|
|
atomic_set(&Adapter->TxPktAvail, 0);
|
|
|
|
}
|
2010-11-01 07:49:30 -06:00
|
|
|
|
2012-09-13 19:11:34 -06:00
|
|
|
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Exiting the tx thread..\n");
|
2010-11-01 07:49:30 -06:00
|
|
|
Adapter->transmit_packet_thread = NULL;
|
2010-09-08 15:46:36 -06:00
|
|
|
return 0;
|
|
|
|
}
|