⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 send.c

📁 e100bex网卡驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
//              routine returns, this packet will be ready to send through the
//              adapter, and onto the medium.
//
// Arguments:
//      Adapter - ptr to Adapter object instance
//      Packet - A pointer to a descriptor for the packet that is to be
//               transmitted.
//      SwTcb - Pointer to a software structure that represents a hardware TCB.
//
// Returns:
//      TRUE If we were able to acquire the necessary TBD's or Coalesce buffer
//           for the packet in we are attempting to prepare for transmission.
//      FALSE If we needed a coalesce buffer, and we didn't have any available.
//-----------------------------------------------------------------------------

BOOLEAN
PrepareForTransmit(PD100_ADAPTER Adapter,
                   PNDIS_PACKET Packet,
                   PD100SwTcb SwTcb)

{
    PNDIS_BUFFER                CurrBuff;
    UINT                        i;
    UINT                        BytesCopied;
    PCOALESCE                   Coalesce;
    PTBD_STRUC                  LastTbd = (PTBD_STRUC) 0;
    PNDIS_PHYSICAL_ADDRESS_UNIT p;
    UINT                        ArrayIndex = 0;

    // Debug Code
    DEBUGFUNC("PrepareForTransmit");
    TRACE2(Adapter, ("\n"));

    TRACE3(Adapter, ("Preparing to transmit SwTcb %08x Packet %08x\n", SwTcb, Packet));

    ASSERT(SwTcb);

    //    DEBUGCHAR(Adapter,'U');
    // Assign the packet
    SwTcb->Packet = Packet;

    // Init some variables in the SwTcb
    SwTcb->MapsUsed = 0;
    SwTcb->NumPhysDesc = 0;
    SwTcb->TbdsUsed = 0;
    SwTcb->Coalesce = (PCOALESCE) 0;
    SwTcb->CoalesceBufferLen = 0;

    // Get a virtual buffer count and packet length.
    NdisQueryPacket(SwTcb->Packet,
        &SwTcb->NumPhysDesc,
        &SwTcb->BufferCount,
        &SwTcb->FirstBuffer,
        &SwTcb->PacketLength);

    ASSERT(SwTcb->FirstBuffer);
    ASSERT(SwTcb->BufferCount);
    ASSERT(SwTcb->NumPhysDesc);
    ASSERT(SwTcb->PacketLength);
    ASSERT(SwTcb->PacketLength <= 1514);
    ASSERT(SwTcb->BufferCount <= 512);
    ASSERT(SwTcb->NumPhysDesc <= 512);

    // if the packet is not a valid length, then error out
    if ((!SwTcb->PacketLength) || (SwTcb->PacketLength > MAXIMUM_ETHERNET_PACKET_SIZE))
        return FALSE;

    // start with the first buffer
    CurrBuff = SwTcb->FirstBuffer;


#if DBG
    SwTcb->BufferCountCheck = 0;
    SwTcb->NumPhysDescCheck = SwTcb->NumPhysDesc;
#endif

    // If the packet is less than minimum size, then we'll just copy the packet
    // into the data portion of the TCB.  This means that we won't be acquiring
    // any TBD's.  We also won't need to get a coalesce buffer.
    if (SwTcb->PacketLength <= MINIMUM_ETHERNET_PACKET_SIZE)
    {
        TRACE2(Adapter, ("short packet\n"));
        CurrBuff = 0;
    }

    // If there are too many physical mappings, try to get a coalesce buffer.
    // We do this because its actually faster for us to copy many fragments
    // into a big buffer and give that big buffer to the adapter, than to have
    // the hardware fetch numerous small fragments (this often leads to
    // underruns). The NDIS tester often asks us to send packets that
    // have more than 30 physical components. This method also saves TBD resources.

    else if (SwTcb->NumPhysDesc > Adapter->NumTbdPerTcb)
    {
        // Debug Code
        ASSERT(!SwTcb->Coalesce);
        TRACE2(Adapter,
            ("Failed-> Physical descriptors %d > num Tbd per Tcb %d\n",
            SwTcb->NumPhysDesc, Adapter->NumTbdPerTcb));

        // Try to get the coalesce buffer
        if (!AcquireCoalesceBuffer(Adapter, SwTcb))
            return (FALSE);
        CurrBuff = 0;
    }

    //  Clear NumPhysDesc.
    SwTcb->NumPhysDesc = 0;



    // If we are not coalescing, and the frame is not short, then for each
    // virtual buffer, get the physical components.  We'll need these physical
    // attributes so that we can instruct the adapter to copy the fragments
    // across the bus and into the adapter's internal FIFO.
    for (i = 0; CurrBuff; i++)
    {
        UINT    ArraySize = 0;

        // If the mapping is successful, and there are not too many, then this
        // is where they go.
        PNDIS_PHYSICAL_ADDRESS_UNIT pUnit = &SwTcb->PhysDesc[SwTcb->NumPhysDesc];

        // Decompose the virtual buffer into one or more physical buffers.
        NdisMStartBufferPhysicalMapping(Adapter->D100AdapterHandle,
            CurrBuff,
            Adapter->NextFreeMapReg,
            TRUE,
            Adapter->pUnits,
            &ArraySize);

#if DBG
        if (ArraySize == 0)
        {
            //            TRACESTR(Adapter, ("ZERO Array size -- Buffer %d ArraySize %d\n", i, ArraySize));
            ASSERT(CurrBuff);
        }
#endif

        // Adjust free map register variables.  Since map registers are such
        // a precious system resource we dynamically use them when necessary,
        // rather than allocate so many map registers per TCB.
        Adapter->NextFreeMapReg++;

        // check for wrap condition
        if (Adapter->NextFreeMapReg == Adapter->NumMapRegisters)
            Adapter->NextFreeMapReg = 0;

        // Debug code
        TRACE3(Adapter, ("Buffer %d ArraySize %d\n", i, ArraySize));

        // Mark the number of valid buffer mappings and copy
        // the new mappings into the transmit descriptor.
        SwTcb->MapsUsed++;
        NdisMoveMemory((PVOID) pUnit,
            (PVOID) Adapter->pUnits,
            ArraySize * sizeof(NDIS_PHYSICAL_ADDRESS_UNIT));

        SwTcb->NumPhysDesc += ArraySize;

        // Flush the current buffer because it could be cached
        NdisFlushBuffer(CurrBuff, TRUE);

        // point to the next buffer
        NdisGetNextBuffer(CurrBuff, &CurrBuff);

#if DBG
        SwTcb->BufferCountCheck++;
        ASSERT(SwTcb->BufferCountCheck <= SwTcb->BufferCount);
#endif


    }

    // ------------------------------- NOTE: ----------------------------------
    // At this point, we should have either locked down each physical fragment
    // through the use of map registers, or we should have a coalesce buffer,
    // or we should have a short packet that we'll copy into the TCB data area.


#if DBG
    // Check to make sure that our buffer count was valid
    if (SwTcb->MapsUsed)
    {
        ASSERT(SwTcb->BufferCountCheck == SwTcb->BufferCount);
    }
#endif

    // Check for coalesce buffer
    if (SwTcb->Coalesce)
    {
        ASSERT(SwTcb->CoalesceBufferLen);
        ASSERT(!SwTcb->NumPhysDesc);
        ASSERT(!SwTcb->MapsUsed);

        Coalesce = SwTcb->Coalesce;
        ASSERT(Coalesce->OwningTcb == (PVOID) SwTcb);

        // Copy the packet into the coalesce buffer
        ASSERT(SwTcb->PacketLength <= MAXIMUM_ETHERNET_PACKET_SIZE);

        // Copy all of the packet data to our coalesce buffer
        D100CopyFromPacketToBuffer(Adapter,
            SwTcb->Packet,
            SwTcb->PacketLength,
            (PCHAR) Coalesce->CoalesceBufferPtr,
            SwTcb->FirstBuffer,
            &BytesCopied);


        ASSERT(BytesCopied == SwTcb->PacketLength);

        SwTcb->TbdsUsed = 1;


    }

    // Check if we a doing a fragmented send with TBDs
    else if (SwTcb->NumPhysDesc)
    {
        SwTcb->TbdsUsed = SwTcb->NumPhysDesc;
        ASSERT(!SwTcb->CoalesceBufferLen);
        ASSERT(SwTcb->MapsUsed);
    }

    // check if we are using the TCB's data area with no TBDs.  This should
    // only happen on frames that are <= the minimum ethernet length
    else if ((!SwTcb->NumPhysDesc) && (!SwTcb->Coalesce))
    {
        ASSERT(!SwTcb->CoalesceBufferLen);
        ASSERT(!SwTcb->NumPhysDesc);
        ASSERT(!SwTcb->MapsUsed);

        ASSERT(SwTcb->PacketLength <= MINIMUM_ETHERNET_PACKET_SIZE);

        // Copy the packet into the immediate data portion of the TCB.
        D100CopyFromPacketToBuffer(Adapter,
            SwTcb->Packet,
            SwTcb->PacketLength,
            (PCHAR) &SwTcb->Tcb->TxCbData,
            SwTcb->FirstBuffer,
            &BytesCopied);


        ASSERT(BytesCopied == SwTcb->PacketLength);

        //        // Check for below minimum length packets.
        //        if (SwTcb->PacketLength < MINIMUM_ETHERNET_PACKET_SIZE)
        //        {
        //            NdisZeroMemory(
        //                    ((PCHAR) &SwTcb->Tcb->TxCbData) + SwTcb->PacketLength,
        //                    MINIMUM_ETHERNET_PACKET_SIZE - (SwTcb->PacketLength));
        //        }

    }


    // ------------------------------- NOTE: ----------------------------------
    // At this point, any copying of of data into a coalesce buffer or into the
    // the TCB itself should be complete.  Now the last thing left to do in
    // this routine is to setup the TBD array if TBDs are being used for this
    // particular transmit frame.

    for (i = 0; i < SwTcb->TbdsUsed; i++)
    {
        PTBD_STRUC  Tbd;
        ULONG       OriginalBufferAddress, OriginalBufferCount;

        // Setup pointer to the particular TBD
        Tbd = SwTcb->FirstTbd + i;
        TRACE3(Adapter, ("Setting TBD num %d at virtual addr %x\n", i, Tbd));

        // Assign the physical address of the transmit buffer, and the
        // TBD count to the TCB.
        if (SwTcb->Coalesce)
        {
            Tbd->TbdBufferAddress = Coalesce->CoalesceBufferPhys;
            Tbd->TbdCount = (ULONG) SwTcb->CoalesceBufferLen;
        }
        else
        {
            p = &SwTcb->PhysDesc[ArrayIndex];
            Tbd->TbdBufferAddress = NdisGetPhysicalAddressLow(p->PhysicalAddress);
            Tbd->TbdCount = (ULONG) p->Length;

            ASSERT(p->Length <= 0x00003fff);
            TRACE3(Adapter, ("Buff %d len %d phys %08x\n", ArrayIndex, p->Length, Tbd->TbdBufferAddress));

        }
        ArrayIndex++;

    }

    //    DEBUGCHAR(Adapter,'u');

    return (TRUE);
}

//-----------------------------------------------------------------------------
// Procedure:   AcquireCoalesceBuffer
//
// Description: This routine will attempt to acquire a coalesce buffer, if
//              there were too many physical vectors for a single packet.
//              The coalesce buffer will allow us to double buffer using a
//              only a single destination buffer.
//
// Arguments:
//      Adapter - ptr to Adapter object instance
//      SwTcb - Pointer to a software structure that represents a hardware TCB.
//
// Returns:
//      TRUE If we were able to acquire the necessary Coalesce buffer.
//      FALSE If we were not able to get a coalesce buffer.
//-----------------------------------------------------------------------------

BOOLEAN
AcquireCoalesceBuffer(PD100_ADAPTER Adapter,
                      PD100SwTcb SwTcb
                      )
{
    DEBUGFUNC("AcquireCoalesceBuffer");
    TRACE2(Adapter, ("\n"));

    // Debug code.
    ASSERT(SwTcb);
    ASSERT(!SwTcb->Coalesce);
    ASSERT(!SwTcb->CoalesceBufferLen);
    //    ASSERT(!SwTcb->MapsUsed);

    // Check preconditions for use. Return FALSE if there are none
    // available.
    if (QueueEmpty(&Adapter->CoalesceBufferList))
    {
        TRACE2(Adapter, ("No free coalesce buffers!!!\n"));
        return (FALSE);
    }

    // Allocate the coalesce buffer from the list. The SwTcb will now
    // own it until it's returned to the list.

    SwTcb->Coalesce = (PCOALESCE) QueuePopHead(&Adapter->CoalesceBufferList);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -