1487 lines
37 KiB
C
1487 lines
37 KiB
C
/*++
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
mp_nic.c
|
|
|
|
Abstract:
|
|
This module contains miniport send/receive routines
|
|
|
|
Revision History:
|
|
Who When What
|
|
-------- -------- ----------------------------------------------
|
|
DChen 11-01-99 created
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
|
|
#if DBG
|
|
#define _FILENUMBER 'CINM'
|
|
#endif
|
|
|
|
__inline VOID MP_FREE_SEND_PACKET(
|
|
IN PMP_ADAPTER Adapter,
|
|
IN PMP_TCB pMpTcb
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Recycle a MP_TCB and complete the packet if necessary
|
|
Assumption: Send spinlock has been acquired
|
|
|
|
Arguments:
|
|
|
|
Adapter Pointer to our adapter
|
|
pMpTcb Pointer to MP_TCB
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
|
|
PNDIS_PACKET Packet;
|
|
PNDIS_BUFFER CurrBuffer;
|
|
|
|
ASSERT(MP_TEST_FLAG(pMpTcb, fMP_TCB_IN_USE));
|
|
|
|
Packet = pMpTcb->Packet;
|
|
pMpTcb->Packet = NULL;
|
|
pMpTcb->Count = 0;
|
|
|
|
if (pMpTcb->MpTxBuf)
|
|
{
|
|
ASSERT(MP_TEST_FLAG(pMpTcb, fMP_TCB_USE_LOCAL_BUF));
|
|
|
|
PushEntryList(&Adapter->SendBufList, &pMpTcb->MpTxBuf->SList);
|
|
pMpTcb->MpTxBuf = NULL;
|
|
}
|
|
else if (MP_TEST_FLAG(Adapter, fMP_ADAPTER_MAP_REGISTER))
|
|
{
|
|
//
|
|
// Complete physical mapping for each buffer in this packet
|
|
//
|
|
ASSERT(Packet);
|
|
|
|
CurrBuffer = pMpTcb->FirstBuffer;
|
|
while (CurrBuffer)
|
|
{
|
|
NdisMCompleteBufferPhysicalMapping(
|
|
Adapter->AdapterHandle,
|
|
CurrBuffer,
|
|
Adapter->CurrMapRegHead);
|
|
|
|
Adapter->CurrMapRegHead++;
|
|
if (Adapter->CurrMapRegHead == (ULONG)Adapter->NumTbd)
|
|
Adapter->CurrMapRegHead = 0;
|
|
|
|
//
|
|
// Get the next buffer
|
|
//
|
|
NdisGetNextBuffer(CurrBuffer, &CurrBuffer);
|
|
}
|
|
}
|
|
|
|
MP_CLEAR_FLAGS(pMpTcb);
|
|
|
|
Adapter->CurrSendHead = Adapter->CurrSendHead->Next;
|
|
Adapter->nBusySend--;
|
|
ASSERT(Adapter->nBusySend >= 0);
|
|
|
|
if (Packet)
|
|
{
|
|
NdisReleaseSpinLock(&Adapter->SendLock);
|
|
DBGPRINT(MP_TRACE, ("Calling NdisMSendComplete, Pkt= "PTR_FORMAT"\n", Packet));
|
|
NdisMSendComplete(
|
|
MP_GET_ADAPTER_HANDLE(Adapter),
|
|
Packet,
|
|
NDIS_STATUS_SUCCESS);
|
|
|
|
NdisAcquireSpinLock(&Adapter->SendLock);
|
|
}
|
|
}
|
|
|
|
NDIS_STATUS MpSendPacket(
|
|
IN PMP_ADAPTER Adapter,
|
|
IN PNDIS_PACKET Packet,
|
|
IN BOOLEAN bFromQueue
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Do the work to send a packet
|
|
Assumption: Send spinlock has been acquired
|
|
|
|
Arguments:
|
|
|
|
Adapter Pointer to our adapter
|
|
Packet The packet
|
|
bFromQueue TRUE if it's taken from the send wait queue
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS
|
|
NDIS_STATUS_PENDING Put into the send wait queue
|
|
NDIS_STATUS_HARD_ERRORS
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_PENDING;
|
|
NDIS_STATUS SendStatus;
|
|
PMP_TCB pMpTcb = NULL;
|
|
PMP_TXBUF pMpTxBuf = NULL;
|
|
ULONG BytesCopied;
|
|
BOOLEAN bCompletePacket = FALSE;
|
|
|
|
// Mimiced frag list if map registers are used, on the local stack as it's not so big
|
|
MP_FRAG_LIST FragList;
|
|
|
|
// Pointer to either the scatter gather or the local mimiced frag list
|
|
PMP_FRAG_LIST pFragList;
|
|
|
|
DBGPRINT(MP_TRACE, ("--> MpSendPacket, Pkt= "PTR_FORMAT"\n", Packet));
|
|
|
|
pMpTcb = Adapter->CurrSendTail;
|
|
ASSERT(!MP_TEST_FLAG(pMpTcb, fMP_TCB_IN_USE));
|
|
|
|
NdisQueryPacket(
|
|
Packet,
|
|
&pMpTcb->PhysBufCount,
|
|
&pMpTcb->BufferCount,
|
|
&pMpTcb->FirstBuffer,
|
|
&pMpTcb->PacketLength);
|
|
|
|
ASSERT(pMpTcb->PhysBufCount);
|
|
ASSERT(pMpTcb->FirstBuffer);
|
|
ASSERT(pMpTcb->PacketLength);
|
|
|
|
//
|
|
// Check to see if we need to coalesce
|
|
//
|
|
if (pMpTcb->PacketLength < NIC_MIN_PACKET_SIZE ||
|
|
pMpTcb->PhysBufCount > NIC_MAX_PHYS_BUF_COUNT)
|
|
{
|
|
//
|
|
// A local MP_TXBUF available (for local data copying)?
|
|
//
|
|
if (IsSListEmpty(&Adapter->SendBufList))
|
|
{
|
|
Adapter->nWaitSend++;
|
|
if (bFromQueue)
|
|
{
|
|
InsertHeadQueue(&Adapter->SendWaitQueue, MP_GET_PACKET_MR(Packet));
|
|
}
|
|
else
|
|
{
|
|
InsertTailQueue(&Adapter->SendWaitQueue, MP_GET_PACKET_MR(Packet));
|
|
}
|
|
|
|
DBGPRINT(MP_TRACE, ("<-- MpSendPacket - queued, no buf\n"));
|
|
return Status;
|
|
}
|
|
|
|
pMpTxBuf = (PMP_TXBUF) PopEntryList(&Adapter->SendBufList);
|
|
ASSERT(pMpTxBuf);
|
|
|
|
//
|
|
// Copy the buffers in this packet, enough to give the first buffer as they are linked
|
|
//
|
|
BytesCopied = MpCopyPacket(pMpTcb->FirstBuffer, pMpTxBuf);
|
|
|
|
#ifdef NDIS51_MINIPORT
|
|
//
|
|
// MpCopyPacket may return 0 if system resources are low or exhausted
|
|
//
|
|
if (BytesCopied == 0)
|
|
{
|
|
PushEntryList(&Adapter->SendBufList, &pMpTxBuf->SList);
|
|
|
|
DBGPRINT(MP_ERROR, ("Calling NdisMSendComplete with NDIS_STATUS_RESOURCES, Pkt= "PTR_FORMAT"\n", Packet));
|
|
|
|
NdisReleaseSpinLock(&Adapter->SendLock);
|
|
NdisMSendComplete(
|
|
MP_GET_ADAPTER_HANDLE(Adapter),
|
|
Packet,
|
|
NDIS_STATUS_RESOURCES);
|
|
|
|
NdisAcquireSpinLock(&Adapter->SendLock);
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
#endif
|
|
|
|
pMpTcb->MpTxBuf = pMpTxBuf;
|
|
|
|
//
|
|
// Set up the frag list, only one fragment after it's coalesced
|
|
//
|
|
pFragList = &FragList;
|
|
pFragList->NumberOfElements = 1;
|
|
pFragList->Elements[0].Address = pMpTxBuf->BufferPa;
|
|
pFragList->Elements[0].Length = (BytesCopied >= NIC_MIN_PACKET_SIZE) ?
|
|
BytesCopied : NIC_MIN_PACKET_SIZE;
|
|
//
|
|
// we can complete it from this routine because it's copied
|
|
//
|
|
bCompletePacket = TRUE;
|
|
pMpTcb->Packet = NULL;
|
|
MP_SET_FLAG(pMpTcb, fMP_TCB_USE_LOCAL_BUF);
|
|
}
|
|
else
|
|
{
|
|
if (MP_TEST_FLAG(Adapter, fMP_ADAPTER_SCATTER_GATHER))
|
|
{
|
|
//
|
|
// In scatter/gather case, use the frag list pointer saved
|
|
// in the packet info field
|
|
//
|
|
pFragList = (PMP_FRAG_LIST) NDIS_PER_PACKET_INFO_FROM_PACKET(Packet,
|
|
ScatterGatherListPacketInfo);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// In the map register case, use the local frag list structure
|
|
//
|
|
pFragList = &FragList;
|
|
|
|
//
|
|
// Do the physical mapping to get all the fragment physical addresses
|
|
//
|
|
MpStartPacketPhysicalMapping(
|
|
Adapter,
|
|
pMpTcb->FirstBuffer,
|
|
pFragList);
|
|
}
|
|
|
|
pMpTcb->Packet = Packet;
|
|
}
|
|
|
|
MP_SET_FLAG(pMpTcb, fMP_TCB_IN_USE);
|
|
|
|
//
|
|
// Call the NIC specific send handler, it only needs to deal with the frag list
|
|
//
|
|
Status = NICSendPacket(Adapter, pMpTcb, pFragList);
|
|
|
|
Adapter->nBusySend++;
|
|
ASSERT(Adapter->nBusySend <= Adapter->NumTcb);
|
|
Adapter->CurrSendTail = Adapter->CurrSendTail->Next;
|
|
|
|
if (bCompletePacket)
|
|
{
|
|
DBGPRINT(MP_TRACE, ("Calling NdisMSendComplete, Pkt= "PTR_FORMAT"\n", Packet));
|
|
|
|
NdisReleaseSpinLock(&Adapter->SendLock);
|
|
|
|
NdisMSendComplete( MP_GET_ADAPTER_HANDLE(Adapter), Packet, Status);
|
|
|
|
NdisAcquireSpinLock(&Adapter->SendLock);
|
|
}
|
|
|
|
DBGPRINT(MP_TRACE, ("<-- MpSendPacket\n"));
|
|
return Status;
|
|
|
|
}
|
|
|
|
ULONG MpCopyPacket(
|
|
IN PNDIS_BUFFER CurrBuffer,
|
|
IN PMP_TXBUF pMpTxBuf
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Copy the packet data to a local buffer
|
|
Either the packet is too small or it has too many fragments
|
|
Assumption: Send spinlock has been acquired
|
|
|
|
Arguments:
|
|
|
|
CurrBuffer Pointer to the first NDIS_BUFFER
|
|
pMpTxBuf Pointer to the local buffer (MP_TXBUF)
|
|
|
|
Return Value:
|
|
|
|
Bytes copied
|
|
|
|
--*/
|
|
{
|
|
UINT CurrLength;
|
|
PUCHAR pSrc;
|
|
PUCHAR pDest;
|
|
UINT BytesCopied = 0;
|
|
|
|
DBGPRINT(MP_TRACE, ("--> MpCopyPacket\n"));
|
|
|
|
pDest = pMpTxBuf->pBuffer;
|
|
|
|
while (CurrBuffer)
|
|
{
|
|
|
|
#ifdef NDIS51_MINIPORT
|
|
NdisQueryBufferSafe( CurrBuffer, &pSrc, &CurrLength, NormalPagePriority );
|
|
if (pSrc == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
#else
|
|
NdisQueryBuffer( CurrBuffer, &pSrc, &CurrLength );
|
|
#endif
|
|
|
|
if (CurrLength)
|
|
{
|
|
//
|
|
// Copy the data.
|
|
//
|
|
NdisMoveMemory(pDest, pSrc, CurrLength);
|
|
BytesCopied += CurrLength;
|
|
pDest += CurrLength;
|
|
}
|
|
|
|
NdisGetNextBuffer( CurrBuffer, &CurrBuffer);
|
|
}
|
|
|
|
//
|
|
// Zero out the padding bytes
|
|
//
|
|
if (BytesCopied < NIC_MIN_PACKET_SIZE)
|
|
{
|
|
NdisZeroMemory(pDest, NIC_MIN_PACKET_SIZE - BytesCopied);
|
|
}
|
|
|
|
|
|
NdisAdjustBufferLength(pMpTxBuf->NdisBuffer, BytesCopied);
|
|
|
|
NdisFlushBuffer(pMpTxBuf->NdisBuffer, TRUE);
|
|
|
|
ASSERT(BytesCopied <= pMpTxBuf->BufferSize);
|
|
|
|
DBGPRINT(MP_TRACE, ("<-- MpCopyPacket\n"));
|
|
|
|
return BytesCopied;
|
|
}
|
|
|
|
VOID MpStartPacketPhysicalMapping(
|
|
IN PMP_ADAPTER Adapter,
|
|
IN PNDIS_BUFFER CurrBuffer,
|
|
OUT PMP_FRAG_LIST pFragList
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Call NdisMStartBufferPhysicalMapping on each NDIS buffer
|
|
Get the physical address for each fragment and save them in the fragment list
|
|
We use the same fragment list as the scatter gather so the driver writers only need
|
|
to deal one type.
|
|
Assumption: spinlock has been acquired
|
|
|
|
Arguments:
|
|
|
|
Adapter Pointer to our adapter
|
|
CurrBuffer Pointer to the first NDIS_BUFFER
|
|
pFragList The pointer to the frag list to be filled
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
NDIS_PHYSICAL_ADDRESS_UNIT PhysAddrUnits[NIC_MAX_PHYS_BUF_COUNT];
|
|
UINT ArraySize, i;
|
|
ULONG ElementIndex = 0;
|
|
|
|
DBGPRINT(MP_TRACE, ("--> MpStartPacketPhysicalMapping\n"));
|
|
|
|
while (CurrBuffer)
|
|
{
|
|
NdisMStartBufferPhysicalMapping(
|
|
Adapter->AdapterHandle,
|
|
CurrBuffer,
|
|
Adapter->CurrMapRegTail,
|
|
TRUE,
|
|
PhysAddrUnits,
|
|
&ArraySize);
|
|
|
|
Adapter->CurrMapRegTail++;
|
|
if (Adapter->CurrMapRegTail == (ULONG)Adapter->NumTbd)
|
|
{
|
|
Adapter->CurrMapRegTail = 0;
|
|
}
|
|
|
|
for (i = 0; i < ArraySize; i++)
|
|
{
|
|
pFragList->Elements[ElementIndex].Address = PhysAddrUnits[i].PhysicalAddress;
|
|
pFragList->Elements[ElementIndex].Length = PhysAddrUnits[i].Length;
|
|
ElementIndex++;
|
|
}
|
|
|
|
//
|
|
// Flush the current buffer because it could be cached
|
|
//
|
|
NdisFlushBuffer(CurrBuffer, TRUE);
|
|
|
|
//
|
|
// point to the next buffer
|
|
//
|
|
NdisGetNextBuffer(CurrBuffer, &CurrBuffer);
|
|
}
|
|
|
|
pFragList->NumberOfElements = ElementIndex;
|
|
ASSERT(pFragList->NumberOfElements);
|
|
|
|
DBGPRINT(MP_TRACE, ("<-- MpStartPacketPhysicalMapping\n"));
|
|
|
|
}
|
|
|
|
NDIS_STATUS NICSendPacket(
|
|
IN PMP_ADAPTER Adapter,
|
|
IN PMP_TCB pMpTcb,
|
|
IN PMP_FRAG_LIST pFragList
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
NIC specific send handler
|
|
Assumption: Send spinlock has been acquired
|
|
|
|
Arguments:
|
|
|
|
Adapter Pointer to our adapter
|
|
pMpTcb Pointer to MP_TCB
|
|
pFragList The pointer to the frag list to be filled
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS
|
|
NDIS_STATUS_HARD_ERRORS
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status;
|
|
ULONG index;
|
|
UCHAR TbdCount = 0;
|
|
|
|
PHW_TCB pHwTcb = pMpTcb->HwTcb;
|
|
PTBD_STRUC pHwTbd = pMpTcb->HwTbd;
|
|
|
|
DBGPRINT(MP_TRACE, ("--> NICSendPacket\n"));
|
|
|
|
for (index = 0; index < pFragList->NumberOfElements; index++)
|
|
{
|
|
if (pFragList->Elements[index].Length)
|
|
{
|
|
pHwTbd->TbdBufferAddress = NdisGetPhysicalAddressLow(pFragList->Elements[index].Address);
|
|
pHwTbd->TbdCount = pFragList->Elements[index].Length;
|
|
|
|
pHwTbd++;
|
|
TbdCount++;
|
|
}
|
|
}
|
|
|
|
pHwTcb->TxCbHeader.CbStatus = 0;
|
|
pHwTcb->TxCbHeader.CbCommand = CB_S_BIT | CB_TRANSMIT | CB_TX_SF_BIT;
|
|
|
|
pHwTcb->TxCbTbdPointer = pMpTcb->HwTbdPhys;
|
|
pHwTcb->TxCbTbdNumber = TbdCount;
|
|
pHwTcb->TxCbCount = 0;
|
|
pHwTcb->TxCbThreshold = (UCHAR) Adapter->AiThreshold;
|
|
|
|
Status = NICStartSend(Adapter, pMpTcb);
|
|
|
|
DBGPRINT(MP_TRACE, ("<-- NICSendPacket\n"));
|
|
|
|
return Status;
|
|
}
|
|
|
|
NDIS_STATUS NICStartSend(
|
|
IN PMP_ADAPTER Adapter,
|
|
IN PMP_TCB pMpTcb
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Issue a send command to the NIC
|
|
Assumption: Send spinlock has been acquired
|
|
|
|
Arguments:
|
|
|
|
Adapter Pointer to our adapter
|
|
pMpTcb Pointer to MP_TCB
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS
|
|
NDIS_STATUS_HARD_ERRORS
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status;
|
|
|
|
DBGPRINT(MP_TRACE, ("--> NICStartSend\n"));
|
|
|
|
//
|
|
// If the transmit unit is idle (very first transmit) then we must
|
|
// setup the general pointer and issue a full CU-start
|
|
//
|
|
if (Adapter->TransmitIdle)
|
|
{
|
|
|
|
DBGPRINT(MP_INFO, ("CU is idle -- First TCB added to Active List\n"));
|
|
|
|
//
|
|
// Wait for the SCB to clear before we set the general pointer
|
|
//
|
|
if (!WaitScb(Adapter))
|
|
{
|
|
Status = NDIS_STATUS_HARD_ERRORS;
|
|
MP_EXIT;
|
|
}
|
|
|
|
//
|
|
// Don't try to start the transmitter if the command unit is not
|
|
// idle ((not idle) == (Cu-Suspended or Cu-Active)).
|
|
//
|
|
if ((Adapter->CSRAddress->ScbStatus & SCB_CUS_MASK) != SCB_CUS_IDLE)
|
|
{
|
|
DBGPRINT(MP_ERROR, ("Adapter = "PTR_FORMAT", CU Not IDLE\n", Adapter));
|
|
MP_SET_HARDWARE_ERROR(Adapter);
|
|
NdisStallExecution(25);
|
|
}
|
|
|
|
Adapter->CSRAddress->ScbGeneralPointer = pMpTcb->HwTcbPhys;
|
|
|
|
Status = D100IssueScbCommand(Adapter, SCB_CUC_START, FALSE);
|
|
|
|
Adapter->TransmitIdle = FALSE;
|
|
Adapter->ResumeWait = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If the command unit has already been started, then append this
|
|
// TCB onto the end of the transmit chain, and issue a CU-Resume.
|
|
//
|
|
DBGPRINT(MP_LOUD, ("adding TCB to Active chain\n"));
|
|
|
|
//
|
|
// Clear the suspend bit on the previous packet.
|
|
//
|
|
pMpTcb->PrevHwTcb->TxCbHeader.CbCommand &= ~CB_S_BIT;
|
|
|
|
//
|
|
// Issue a CU-Resume command to the device. We only need to do a
|
|
// WaitScb if the last command was NOT a RESUME.
|
|
//
|
|
Status = D100IssueScbCommand(Adapter, SCB_CUC_RESUME, Adapter->ResumeWait);
|
|
}
|
|
|
|
exit:
|
|
|
|
DBGPRINT(MP_TRACE, ("<-- NICStartSend\n"));
|
|
|
|
return Status;
|
|
}
|
|
|
|
NDIS_STATUS MpHandleSendInterrupt(
|
|
IN PMP_ADAPTER Adapter
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Interrupt handler for sending processing
|
|
Re-claim the send resources, complete sends and get more to send from the send wait queue
|
|
Assumption: Send spinlock has been acquired
|
|
|
|
Arguments:
|
|
|
|
Adapter Pointer to our adapter
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS
|
|
NDIS_STATUS_HARD_ERRORS
|
|
NDIS_STATUS_PENDING
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
PMP_TCB pMpTcb;
|
|
|
|
#if DBG
|
|
LONG i;
|
|
#endif
|
|
|
|
DBGPRINT(MP_TRACE, ("---> MpHandleSendInterrupt\n"));
|
|
|
|
//
|
|
// Any packets being sent? Any packet waiting in the send queue?
|
|
//
|
|
if (Adapter->nBusySend == 0 &&
|
|
IsQueueEmpty(&Adapter->SendWaitQueue))
|
|
{
|
|
ASSERT(Adapter->CurrSendHead == Adapter->CurrSendTail);
|
|
DBGPRINT(MP_TRACE, ("<--- MpHandleSendInterrupt\n"));
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Check the first TCB on the send list
|
|
//
|
|
while (Adapter->nBusySend > 0)
|
|
{
|
|
|
|
#if DBG
|
|
pMpTcb = Adapter->CurrSendHead;
|
|
for (i = 0; i < Adapter->nBusySend; i++)
|
|
{
|
|
pMpTcb = pMpTcb->Next;
|
|
}
|
|
|
|
if (pMpTcb != Adapter->CurrSendTail)
|
|
{
|
|
DBGPRINT(MP_ERROR, ("nBusySend= %d\n", Adapter->nBusySend));
|
|
DBGPRINT(MP_ERROR, ("CurrSendhead= "PTR_FORMAT"\n", Adapter->CurrSendHead));
|
|
DBGPRINT(MP_ERROR, ("CurrSendTail= "PTR_FORMAT"\n", Adapter->CurrSendTail));
|
|
ASSERT(FALSE);
|
|
}
|
|
#endif
|
|
|
|
pMpTcb = Adapter->CurrSendHead;
|
|
|
|
//
|
|
// Is this TCB completed?
|
|
//
|
|
if (pMpTcb->HwTcb->TxCbHeader.CbStatus & CB_STATUS_COMPLETE)
|
|
{
|
|
//
|
|
// Check if this is a multicast hw workaround packet
|
|
//
|
|
if ((pMpTcb->HwTcb->TxCbHeader.CbCommand & CB_CMD_MASK) != CB_MULTICAST)
|
|
{
|
|
MP_FREE_SEND_PACKET_FUN(Adapter, pMpTcb);
|
|
|
|
}
|
|
else
|
|
{
|
|
MP_CLEAR_FLAGS(pMpTcb);
|
|
pMpTcb->Count = 0;
|
|
Adapter->CurrSendHead = Adapter->CurrSendHead->Next;
|
|
|
|
Adapter->nBusySend--;
|
|
|
|
#if OFFLOAD
|
|
NdisInterlockedDecrement(&Adapter->SharedMemRefCount);
|
|
if (Adapter->SharedMemRefCount == 0)
|
|
{
|
|
// DbgPrint("Clear the flag\n");
|
|
MP_CLEAR_FLAG(Adapter, fMP_SHARED_MEM_IN_USE);
|
|
}
|
|
#endif
|
|
ASSERT(Adapter->nBusySend >= 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we queued any transmits because we didn't have any TCBs earlier,
|
|
// dequeue and send those packets now, as long as we have free TCBs.
|
|
//
|
|
if (MP_IS_READY(Adapter))
|
|
{
|
|
while (!IsQueueEmpty(&Adapter->SendWaitQueue) &&
|
|
MP_TCB_RESOURCES_AVAIABLE(Adapter))
|
|
{
|
|
PNDIS_PACKET Packet;
|
|
PQUEUE_ENTRY pEntry;
|
|
|
|
#if OFFLOAD
|
|
if (MP_TEST_FLAG(Adapter, fMP_SHARED_MEM_IN_USE))
|
|
{
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
pEntry = RemoveHeadQueue(&Adapter->SendWaitQueue);
|
|
|
|
ASSERT(pEntry);
|
|
|
|
Adapter->nWaitSend--;
|
|
|
|
Packet = CONTAINING_RECORD(pEntry, NDIS_PACKET, MiniportReserved);
|
|
|
|
DBGPRINT(MP_INFO, ("MpHandleSendInterrupt - send a queued packet\n"));
|
|
|
|
Status = MpSendPacketFun(Adapter, Packet, TRUE);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
DBGPRINT(MP_TRACE, ("<--- MpHandleSendInterrupt\n"));
|
|
return Status;
|
|
}
|
|
|
|
VOID MpHandleRecvInterrupt(
|
|
IN PMP_ADAPTER Adapter
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Interrupt handler for receive processing
|
|
Put the received packets into an array and call NdisMIndicateReceivePacket
|
|
If we run low on RFDs, allocate another one
|
|
Assumption: Rcv spinlock has been acquired
|
|
|
|
Arguments:
|
|
|
|
Adapter Pointer to our adapter
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PMP_RFD pMpRfd;
|
|
PHW_RFD pHwRfd;
|
|
|
|
PNDIS_PACKET PacketArray[NIC_DEF_RFDS];
|
|
PNDIS_PACKET PacketFreeArray[NIC_DEF_RFDS];
|
|
UINT PacketArrayCount;
|
|
UINT PacketFreeCount;
|
|
UINT Index;
|
|
UINT LoopIndex = 0;
|
|
UINT LoopCount = NIC_MAX_RFDS / NIC_DEF_RFDS + 1; // avoid staying here too long
|
|
|
|
BOOLEAN bContinue = TRUE;
|
|
BOOLEAN bAllocNewRfd = FALSE;
|
|
USHORT PacketStatus;
|
|
#if OFFLOAD
|
|
UINT i;
|
|
|
|
#endif
|
|
|
|
|
|
DBGPRINT(MP_TRACE, ("---> MpHandleRecvInterrupt\n"));
|
|
|
|
ASSERT(Adapter->nReadyRecv >= NIC_MIN_RFDS);
|
|
|
|
while (LoopIndex++ < LoopCount && bContinue)
|
|
{
|
|
PacketArrayCount = 0;
|
|
PacketFreeCount = 0;
|
|
|
|
//
|
|
// Process up to the array size RFD's
|
|
//
|
|
while (PacketArrayCount < NIC_DEF_RFDS)
|
|
{
|
|
if (IsListEmpty(&Adapter->RecvList))
|
|
{
|
|
ASSERT(Adapter->nReadyRecv == 0);
|
|
bContinue = FALSE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Get the next MP_RFD to process
|
|
//
|
|
pMpRfd = (PMP_RFD)GetListHeadEntry(&Adapter->RecvList);
|
|
|
|
//
|
|
// Get the associated HW_RFD
|
|
//
|
|
pHwRfd = pMpRfd->HwRfd;
|
|
|
|
//
|
|
// Is this packet completed?
|
|
//
|
|
PacketStatus = NIC_RFD_GET_STATUS(pHwRfd);
|
|
if (!NIC_RFD_STATUS_COMPLETED(PacketStatus))
|
|
{
|
|
bContinue = FALSE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// HW specific - check if actual count field has been updated
|
|
//
|
|
if (!NIC_RFD_VALID_ACTUALCOUNT(pHwRfd))
|
|
{
|
|
bContinue = FALSE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Remove the RFD from the head of the List
|
|
//
|
|
RemoveEntryList((PLIST_ENTRY)pMpRfd);
|
|
Adapter->nReadyRecv--;
|
|
ASSERT(Adapter->nReadyRecv >= 0);
|
|
|
|
ASSERT(MP_TEST_FLAG(pMpRfd, fMP_RFD_RECV_READY));
|
|
MP_CLEAR_FLAG(pMpRfd, fMP_RFD_RECV_READY);
|
|
|
|
//
|
|
// A good packet? drop it if not.
|
|
//
|
|
if (!NIC_RFD_STATUS_SUCCESS(PacketStatus))
|
|
{
|
|
DBGPRINT(MP_WARN, ("Receive failure = %x\n", PacketStatus));
|
|
NICReturnRFD(Adapter, pMpRfd);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Do not receive any packets until a filter has been set
|
|
//
|
|
if (!Adapter->PacketFilter)
|
|
{
|
|
NICReturnRFD(Adapter, pMpRfd);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Do not receive any packets until we are at D0
|
|
//
|
|
if (Adapter->CurrentPowerState != NdisDeviceStateD0)
|
|
{
|
|
NICReturnRFD(Adapter, pMpRfd);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Get the packet size
|
|
//
|
|
pMpRfd->PacketSize = NIC_RFD_GET_PACKET_SIZE(pHwRfd);
|
|
|
|
NdisAdjustBufferLength(pMpRfd->NdisBuffer, pMpRfd->PacketSize);
|
|
NdisFlushBuffer(pMpRfd->NdisBuffer, FALSE);
|
|
|
|
// we don't mess up the buffer chain, no need to make this call in this case
|
|
// NdisRecalculatePacketCounts(pMpRfd->ReceivePacket);
|
|
|
|
//
|
|
// set the status on the packet, either resources or success
|
|
//
|
|
if (Adapter->nReadyRecv >= MIN_NUM_RFD)
|
|
{
|
|
// NDIS_STATUS_SUCCESS
|
|
NDIS_SET_PACKET_STATUS(pMpRfd->NdisPacket, NDIS_STATUS_SUCCESS);
|
|
MP_SET_FLAG(pMpRfd, fMP_RFD_RECV_PEND);
|
|
|
|
InsertTailList(&Adapter->RecvPendList, (PLIST_ENTRY)pMpRfd);
|
|
MP_INC_RCV_REF(Adapter);
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// NDIS_STATUS_RESOURCES
|
|
//
|
|
NDIS_SET_PACKET_STATUS(pMpRfd->NdisPacket, NDIS_STATUS_RESOURCES);
|
|
MP_SET_FLAG(pMpRfd, fMP_RFD_RESOURCES);
|
|
|
|
PacketFreeArray[PacketFreeCount] = pMpRfd->NdisPacket;
|
|
PacketFreeCount++;
|
|
|
|
//
|
|
// Reset the RFD shrink count - don't attempt to shrink RFD
|
|
//
|
|
Adapter->RfdShrinkCount = 0;
|
|
|
|
//
|
|
// Remember to allocate a new RFD later
|
|
//
|
|
bAllocNewRfd = TRUE;
|
|
}
|
|
|
|
PacketArray[PacketArrayCount] = pMpRfd->NdisPacket;
|
|
PacketArrayCount++;
|
|
}
|
|
|
|
//
|
|
// if we didn't process any receives, just return from here
|
|
//
|
|
if (PacketArrayCount == 0) break;
|
|
|
|
//
|
|
// Update the number of outstanding Recvs
|
|
//
|
|
Adapter->PoMgmt.OutstandingRecv += PacketArrayCount;
|
|
|
|
NdisDprReleaseSpinLock(&Adapter->RcvLock);
|
|
|
|
|
|
NdisMIndicateReceivePacket(
|
|
Adapter->AdapterHandle,
|
|
PacketArray,
|
|
PacketArrayCount);
|
|
|
|
NdisDprAcquireSpinLock(&Adapter->RcvLock);
|
|
|
|
//
|
|
// NDIS won't take ownership for the packets with NDIS_STATUS_RESOURCES.
|
|
// For other packets, NDIS always takes the ownership and gives them back
|
|
// by calling MPReturnPackets
|
|
//
|
|
for (Index = 0; Index < PacketFreeCount; Index++)
|
|
{
|
|
|
|
//
|
|
// Get the MP_RFD saved in this packet, in NICAllocRfd
|
|
//
|
|
pMpRfd = MP_GET_PACKET_RFD(PacketFreeArray[Index]);
|
|
|
|
ASSERT(MP_TEST_FLAG(pMpRfd, fMP_RFD_RESOURCES));
|
|
MP_CLEAR_FLAG(pMpRfd, fMP_RFD_RESOURCES);
|
|
|
|
//
|
|
// Decrement the number of outstanding Recvs
|
|
//
|
|
Adapter->PoMgmt.OutstandingRecv --;
|
|
|
|
NICReturnRFD(Adapter, pMpRfd);
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we ran low on RFD's, we need to allocate a new RFD
|
|
//
|
|
if (bAllocNewRfd)
|
|
{
|
|
//
|
|
// Allocate one more RFD only if no pending new RFD allocation AND
|
|
// it doesn't exceed the max RFD limit
|
|
//
|
|
if (!Adapter->bAllocNewRfd && Adapter->CurrNumRfd < Adapter->MaxNumRfd)
|
|
{
|
|
PMP_RFD TempMpRfd;
|
|
NDIS_STATUS TempStatus;
|
|
|
|
TempMpRfd = NdisAllocateFromNPagedLookasideList(&Adapter->RecvLookaside);
|
|
if (TempMpRfd)
|
|
{
|
|
MP_INC_REF(Adapter);
|
|
Adapter->bAllocNewRfd = TRUE;
|
|
|
|
MP_SET_FLAG(TempMpRfd, fMP_RFD_ALLOC_PEND);
|
|
|
|
//
|
|
// Allocate the shared memory for this RFD.
|
|
//
|
|
TempStatus = NdisMAllocateSharedMemoryAsync(
|
|
Adapter->AdapterHandle,
|
|
Adapter->HwRfdSize,
|
|
FALSE,
|
|
TempMpRfd);
|
|
|
|
//
|
|
// The return value will be either NDIS_STATUS_PENDING or NDIS_STATUS_FAILURE
|
|
//
|
|
if (TempStatus == NDIS_STATUS_FAILURE)
|
|
{
|
|
MP_CLEAR_FLAGS(TempMpRfd);
|
|
NdisFreeToNPagedLookasideList(&Adapter->RecvLookaside, TempMpRfd);
|
|
|
|
Adapter->bAllocNewRfd = FALSE;
|
|
MP_DEC_REF(Adapter);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ASSERT(Adapter->nReadyRecv >= NIC_MIN_RFDS);
|
|
|
|
DBGPRINT(MP_TRACE, ("<--- MpHandleRecvInterrupt\n"));
|
|
}
|
|
|
|
VOID NICReturnRFD(
|
|
IN PMP_ADAPTER Adapter,
|
|
IN PMP_RFD pMpRfd
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Recycle a RFD and put it back onto the receive list
|
|
Assumption: Rcv spinlock has been acquired
|
|
|
|
Arguments:
|
|
|
|
Adapter Pointer to our adapter
|
|
pMpRfd Pointer to the RFD
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PMP_RFD pLastMpRfd;
|
|
PHW_RFD pHwRfd = pMpRfd->HwRfd;
|
|
|
|
ASSERT(pMpRfd->Flags == 0);
|
|
MP_SET_FLAG(pMpRfd, fMP_RFD_RECV_READY);
|
|
|
|
//
|
|
// HW_SPECIFIC_START
|
|
//
|
|
pHwRfd->RfdCbHeader.CbStatus = 0;
|
|
pHwRfd->RfdActualCount = 0;
|
|
pHwRfd->RfdCbHeader.CbCommand = (RFD_EL_BIT);
|
|
pHwRfd->RfdCbHeader.CbLinkPointer = DRIVER_NULL;
|
|
|
|
//
|
|
// We don't use any of the OOB data besides status
|
|
// Otherwise, we need to clean up OOB data
|
|
// NdisZeroMemory(NDIS_OOB_DATA_FROM_PACKET(pMpRfd->NdisPacket),14);
|
|
//
|
|
// Append this RFD to the RFD chain
|
|
if (!IsListEmpty(&Adapter->RecvList))
|
|
{
|
|
pLastMpRfd = (PMP_RFD)GetListTailEntry(&Adapter->RecvList);
|
|
|
|
// Link it onto the end of the chain dynamically
|
|
pHwRfd = pLastMpRfd->HwRfd;
|
|
pHwRfd->RfdCbHeader.CbLinkPointer = pMpRfd->HwRfdPhys;
|
|
pHwRfd->RfdCbHeader.CbCommand = 0;
|
|
}
|
|
|
|
//
|
|
// HW_SPECIFIC_END
|
|
//
|
|
|
|
//
|
|
// The processing on this RFD is done, so put it back on the tail of
|
|
// our list
|
|
//
|
|
InsertTailList(&Adapter->RecvList, (PLIST_ENTRY)pMpRfd);
|
|
Adapter->nReadyRecv++;
|
|
ASSERT(Adapter->nReadyRecv <= Adapter->CurrNumRfd);
|
|
}
|
|
|
|
NDIS_STATUS NICStartRecv(
|
|
IN PMP_ADAPTER Adapter
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Start the receive unit if it's not in a ready state
|
|
Assumption: Rcv spinlock has been acquired
|
|
|
|
Arguments:
|
|
|
|
Adapter Pointer to our adapter
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS
|
|
NDIS_STATUS_HARD_ERRROS
|
|
|
|
--*/
|
|
{
|
|
PMP_RFD pMpRfd;
|
|
NDIS_STATUS Status;
|
|
|
|
DBGPRINT(MP_TRACE, ("---> NICStartRecv\n"));
|
|
|
|
//
|
|
// If the receiver is ready, then don't try to restart.
|
|
//
|
|
if (NIC_IS_RECV_READY(Adapter))
|
|
{
|
|
DBGPRINT(MP_LOUD, ("Receive unit already active\n"));
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
DBGPRINT(MP_LOUD, ("Re-start receive unit...\n"));
|
|
ASSERT(!IsListEmpty(&Adapter->RecvList));
|
|
|
|
//
|
|
// Get the MP_RFD head
|
|
//
|
|
pMpRfd = (PMP_RFD)GetListHeadEntry(&Adapter->RecvList);
|
|
|
|
//
|
|
// If more packets are received, clean up RFD chain again
|
|
//
|
|
if (NIC_RFD_GET_STATUS(pMpRfd->HwRfd))
|
|
{
|
|
MpHandleRecvInterrupt(Adapter);
|
|
ASSERT(!IsListEmpty(&Adapter->RecvList));
|
|
|
|
//
|
|
// Get the new MP_RFD head
|
|
//
|
|
pMpRfd = (PMP_RFD)GetListHeadEntry(&Adapter->RecvList);
|
|
}
|
|
|
|
//
|
|
// Wait for the SCB to clear before we set the general pointer
|
|
//
|
|
if (!WaitScb(Adapter))
|
|
{
|
|
Status = NDIS_STATUS_HARD_ERRORS;
|
|
MP_EXIT;
|
|
}
|
|
|
|
if (Adapter->CurrentPowerState > NdisDeviceStateD0)
|
|
{
|
|
Status = NDIS_STATUS_HARD_ERRORS;
|
|
MP_EXIT;
|
|
}
|
|
//
|
|
// Set the SCB General Pointer to point the current Rfd
|
|
//
|
|
Adapter->CSRAddress->ScbGeneralPointer = pMpRfd->HwRfdPhys;
|
|
|
|
//
|
|
// Issue the SCB RU start command
|
|
//
|
|
Status = D100IssueScbCommand(Adapter, SCB_RUC_START, FALSE);
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
// wait for the command to be accepted
|
|
if (!WaitScb(Adapter))
|
|
{
|
|
Status = NDIS_STATUS_HARD_ERRORS;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
|
|
DBGPRINT_S(Status, ("<--- NICStartRecv, Status=%x\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
VOID MpFreeQueuedSendPackets(
|
|
IN PMP_ADAPTER Adapter
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Free and complete the pended sends on SendWaitQueue
|
|
Assumption: spinlock has been acquired
|
|
|
|
Arguments:
|
|
|
|
Adapter Pointer to our adapter
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PQUEUE_ENTRY pEntry;
|
|
PNDIS_PACKET Packet;
|
|
NDIS_STATUS Status = MP_GET_STATUS_FROM_FLAGS(Adapter);
|
|
|
|
DBGPRINT(MP_TRACE, ("--> MpFreeQueuedSendPackets\n"));
|
|
|
|
while (!IsQueueEmpty(&Adapter->SendWaitQueue))
|
|
{
|
|
pEntry = RemoveHeadQueue(&Adapter->SendWaitQueue);
|
|
Adapter->nWaitSend--;
|
|
NdisReleaseSpinLock(&Adapter->SendLock);
|
|
|
|
ASSERT(pEntry);
|
|
Packet = CONTAINING_RECORD(pEntry, NDIS_PACKET, MiniportReserved);
|
|
|
|
NdisMSendComplete(
|
|
MP_GET_ADAPTER_HANDLE(Adapter),
|
|
Packet,
|
|
Status);
|
|
|
|
NdisAcquireSpinLock(&Adapter->SendLock);
|
|
}
|
|
|
|
DBGPRINT(MP_TRACE, ("<-- MpFreeQueuedSendPackets\n"));
|
|
|
|
}
|
|
|
|
void MpFreeBusySendPackets(
|
|
IN PMP_ADAPTER Adapter
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Free and complete the stopped active sends
|
|
Assumption: Send spinlock has been acquired
|
|
|
|
Arguments:
|
|
|
|
Adapter Pointer to our adapter
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PMP_TCB pMpTcb;
|
|
|
|
DBGPRINT(MP_TRACE, ("--> MpFreeBusySendPackets\n"));
|
|
|
|
//
|
|
// Any packets being sent? Check the first TCB on the send list
|
|
//
|
|
while (Adapter->nBusySend > 0)
|
|
{
|
|
pMpTcb = Adapter->CurrSendHead;
|
|
|
|
//
|
|
// Is this TCB completed?
|
|
//
|
|
if ((pMpTcb->HwTcb->TxCbHeader.CbCommand & CB_CMD_MASK) != CB_MULTICAST)
|
|
{
|
|
MP_FREE_SEND_PACKET_FUN(Adapter, pMpTcb);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
DBGPRINT(MP_TRACE, ("<-- MpFreeBusySendPackets\n"));
|
|
}
|
|
|
|
VOID NICResetRecv(
|
|
IN PMP_ADAPTER Adapter
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Reset the receive list
|
|
Assumption: Rcv spinlock has been acquired
|
|
|
|
Arguments:
|
|
|
|
Adapter Pointer to our adapter
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PMP_RFD pMpRfd;
|
|
PHW_RFD pHwRfd;
|
|
LONG RfdCount;
|
|
|
|
DBGPRINT(MP_TRACE, ("--> NICResetRecv\n"));
|
|
|
|
ASSERT(!IsListEmpty(&Adapter->RecvList));
|
|
|
|
//
|
|
// Get the MP_RFD head
|
|
//
|
|
pMpRfd = (PMP_RFD)GetListHeadEntry(&Adapter->RecvList);
|
|
for (RfdCount = 0; RfdCount < Adapter->nReadyRecv; RfdCount++)
|
|
{
|
|
pHwRfd = pMpRfd->HwRfd;
|
|
pHwRfd->RfdCbHeader.CbStatus = 0;
|
|
|
|
pMpRfd = (PMP_RFD)GetListFLink(&pMpRfd->List);
|
|
}
|
|
|
|
DBGPRINT(MP_TRACE, ("<-- NICResetRecv\n"));
|
|
}
|
|
|
|
VOID MpLinkDetectionDpc(
|
|
IN PVOID SystemSpecific1,
|
|
IN PVOID FunctionContext,
|
|
IN PVOID SystemSpecific2,
|
|
IN PVOID SystemSpecific3
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Timer function for postponed link negotiation
|
|
|
|
Arguments:
|
|
|
|
SystemSpecific1 Not used
|
|
FunctionContext Pointer to our adapter
|
|
SystemSpecific2 Not used
|
|
SystemSpecific3 Not used
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PMP_ADAPTER Adapter = (PMP_ADAPTER)FunctionContext;
|
|
NDIS_STATUS Status;
|
|
|
|
//
|
|
// Handle the link negotiation.
|
|
//
|
|
if (Adapter->bLinkDetectionWait)
|
|
{
|
|
Status = ScanAndSetupPhy(Adapter);
|
|
}
|
|
else
|
|
{
|
|
Status = PhyDetect(Adapter);
|
|
}
|
|
|
|
if (Status == NDIS_STATUS_PENDING)
|
|
{
|
|
// Wait for 100 ms
|
|
Adapter->bLinkDetectionWait = TRUE;
|
|
NdisMSetTimer(&Adapter->LinkDetectionTimer, NIC_LINK_DETECTION_DELAY);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Reset some variables for link detection
|
|
//
|
|
Adapter->bLinkDetectionWait = FALSE;
|
|
|
|
DBGPRINT(MP_WARN, ("MpLinkDetectionDpc - negotiation done\n"));
|
|
|
|
NdisDprAcquireSpinLock(&Adapter->Lock);
|
|
MP_CLEAR_FLAG(Adapter, fMP_ADAPTER_LINK_DETECTION);
|
|
NdisDprReleaseSpinLock(&Adapter->Lock);
|
|
|
|
//
|
|
// Any OID query request?
|
|
//
|
|
if (Adapter->bQueryPending)
|
|
{
|
|
|
|
switch(Adapter->QueryRequest.Oid)
|
|
{
|
|
case OID_GEN_LINK_SPEED:
|
|
*((PULONG) Adapter->QueryRequest.InformationBuffer) = Adapter->usLinkSpeed * 10000;
|
|
*((PULONG) Adapter->QueryRequest.BytesWritten) = sizeof(ULONG);
|
|
|
|
break;
|
|
|
|
case OID_GEN_MEDIA_CONNECT_STATUS:
|
|
default:
|
|
ASSERT(Adapter->QueryRequest.Oid == OID_GEN_MEDIA_CONNECT_STATUS);
|
|
*((PULONG) Adapter->QueryRequest.InformationBuffer) = NICGetMediaState(Adapter);
|
|
*((PULONG) Adapter->QueryRequest.BytesWritten) = sizeof(ULONG);
|
|
}
|
|
|
|
Adapter->bQueryPending = FALSE;
|
|
NdisMQueryInformationComplete(Adapter->AdapterHandle, NDIS_STATUS_SUCCESS);
|
|
}
|
|
|
|
//
|
|
// Any OID set request?
|
|
//
|
|
if (Adapter->bSetPending)
|
|
{
|
|
ULONG PacketFilter;
|
|
|
|
ASSERT(Adapter->SetRequest.Oid == OID_GEN_CURRENT_PACKET_FILTER);
|
|
|
|
PacketFilter = *((PULONG)Adapter->SetRequest.InformationBuffer);
|
|
|
|
NdisDprAcquireSpinLock(&Adapter->Lock);
|
|
|
|
Status = NICSetPacketFilter(
|
|
Adapter,
|
|
PacketFilter);
|
|
|
|
NdisDprReleaseSpinLock(&Adapter->Lock);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
Adapter->PacketFilter = PacketFilter;
|
|
}
|
|
|
|
Adapter->bSetPending = FALSE;
|
|
NdisMSetInformationComplete(Adapter->AdapterHandle, Status);
|
|
}
|
|
|
|
NdisDprAcquireSpinLock(&Adapter->Lock);
|
|
//
|
|
// Any pendingf reset?
|
|
//
|
|
if (Adapter->bResetPending)
|
|
{
|
|
// The link detection may have held some requests and caused reset.
|
|
// Complete the reset with NOT_READY status
|
|
Adapter->bResetPending = FALSE;
|
|
MP_CLEAR_FLAG(Adapter, fMP_ADAPTER_RESET_IN_PROGRESS);
|
|
|
|
NdisDprReleaseSpinLock(&Adapter->Lock);
|
|
|
|
NdisMResetComplete(
|
|
Adapter->AdapterHandle,
|
|
NDIS_STATUS_ADAPTER_NOT_READY,
|
|
FALSE);
|
|
}
|
|
else
|
|
{
|
|
NdisDprReleaseSpinLock(&Adapter->Lock);
|
|
}
|
|
|
|
NdisDprAcquireSpinLock(&Adapter->RcvLock);
|
|
|
|
//
|
|
// Start the NIC receive unit
|
|
//
|
|
Status = NICStartRecv(Adapter);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
MP_SET_HARDWARE_ERROR(Adapter);
|
|
}
|
|
|
|
NdisDprReleaseSpinLock(&Adapter->RcvLock);
|
|
NdisDprAcquireSpinLock(&Adapter->SendLock);
|
|
|
|
//
|
|
// Send packets which have been queued while link detection was going on.
|
|
//
|
|
if (MP_IS_READY(Adapter))
|
|
{
|
|
while (!IsQueueEmpty(&Adapter->SendWaitQueue) &&
|
|
Adapter->nBusySend < Adapter->NumTcb)
|
|
{
|
|
PNDIS_PACKET Packet;
|
|
PQUEUE_ENTRY pEntry = RemoveHeadQueue(&Adapter->SendWaitQueue);
|
|
ASSERT(pEntry);
|
|
|
|
Adapter->nWaitSend--;
|
|
|
|
Packet = CONTAINING_RECORD(pEntry, NDIS_PACKET, MiniportReserved);
|
|
|
|
DBGPRINT(MP_INFO, ("MpLinkDetectionDpc - send a queued packet\n"));
|
|
|
|
Status = MpSendPacket(Adapter, Packet, TRUE);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
MP_DEC_REF(Adapter);
|
|
|
|
if (MP_GET_REF(Adapter) == 0)
|
|
{
|
|
NdisSetEvent(&Adapter->ExitEvent);
|
|
}
|
|
|
|
NdisReleaseSpinLock(&Adapter->SendLock);
|
|
|
|
}
|