NDIS_STATUS NICInitializeAdapter( IN PMP_ADAPTER Adapter, IN NDIS_HANDLE WrapperConfigurationContext ) /*++ Routine Description: Query assigned resources and initialize the adapter. Arguments: Adapter Pointer to our adapter Return Value: NDIS_STATUS_SUCCESS NDIS_STATUS_ADAPTER_NOT_FOUND --*/ { NDIS_STATUS Status = NDIS_STATUS_ADAPTER_NOT_FOUND; typedef __declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) NicResourceCharBuf; NicResourceCharBuf resBuf[NIC_RESOURCE_BUF_SIZE]; PNDIS_RESOURCE_LIST resList = (PNDIS_RESOURCE_LIST)resBuf; UINT bufSize = NIC_RESOURCE_BUF_SIZE; PCM_PARTIAL_RESOURCE_DESCRIPTOR pResDesc; ULONG index; DEBUGP(MP_TRACE, ("---> InitializeAdapter\n")); PAGED_CODE(); do { // // Get the resources assigned by the PNP manager. NDIS gets // these resources in IRP_MN_START_DEVICE request. // NdisMQueryAdapterResources( &Status, WrapperConfigurationContext, resList, &bufSize); if (Status == NDIS_STATUS_SUCCESS) { #pragma prefast(suppress: 8199, "resList is initialized by NdisMQueryAdapterResources") for (index=0; index < resList->Count; index++) { pResDesc = &resList->PartialDescriptors[index]; switch(pResDesc->Type) { case CmResourceTypePort: DEBUGP(MP_INFO, ("IoBaseAddress = 0x%x\n", NdisGetPhysicalAddressLow(pResDesc->u.Port.Start))); DEBUGP(MP_INFO, ("IoRange = x%x\n", pResDesc->u.Port.Length)); break; case CmResourceTypeInterrupt: DEBUGP(MP_INFO, ("InterruptLevel = x%x\n", pResDesc->u.Interrupt.Level)); break; case CmResourceTypeMemory: DEBUGP(MP_INFO, ("MemPhysAddress(Low) = 0x%0x\n", NdisGetPhysicalAddressLow(pResDesc->u.Memory.Start))); DEBUGP(MP_INFO, ("MemPhysAddress(High) = 0x%0x\n", NdisGetPhysicalAddressHigh(pResDesc->u.Memory.Start))); break; } } } Status = NDIS_STATUS_SUCCESS; // // Map bus-relative IO range to system IO space using // NdisMRegisterIoPortRange // // // Map bus-relative registers to virtual system-space // using NdisMMapIoSpace // // // Disable interrupts here as soon as possible // // // Register the interrupt using NdisMRegisterInterrupt // // // Initialize the hardware with mapped resources // #ifdef NDIS50_MINIPORT // // Register a shutdown handler for NDIS50 or earlier miniports // For NDIS51 miniports, set AdapterShutdownHandler. // NdisMRegisterAdapterShutdownHandler( Adapter->AdapterHandle, (PVOID) Adapter, (ADAPTER_SHUTDOWN_HANDLER) MPShutdown); #endif // // Enable the interrupt // } while (FALSE); DEBUGP(MP_TRACE, ("<--- InitializeAdapter, Status=%x\n", Status)); return Status; }
/*+ * * AllocateAdapterMemory * * Routine Description: * * This routine allocates memory for: * * - Transmit descriptor ring * - Receive descriptor ring * - Receive buffers * - Transmit buffer * - Setup buffer * * Arguments: * * Adapter - The adapter to allocate memory for. * * Functional description * * For each allocated zone, we maintain a set of pointers: * - virtual & physical addresses of the allocated block * - virtual & physical addresses of the aligned structure (descriptor ring, buffer,...) * whithin the block * * Return Value: * * Returns FALSE if an allocation fails. * -*/ extern BOOLEAN AllocateAdapterMemory( IN PDC21X4_ADAPTER Adapter ) { PDC21X4_TRANSMIT_DESCRIPTOR TransmitDescriptor; PDC21X4_RECEIVE_DESCRIPTOR ReceiveDescriptor; NDIS_STATUS Status; PRCV_HEADER RcvHeader; PNDIS_PACKET Packet; ULONG AllocSize; PULONG AllocVa; NDIS_PHYSICAL_ADDRESS AllocPa; ULONG Va; ULONG Pa; UINT i; ULONG Offset; INT TransmitDescriptorRingSize; INT ReceiveDescriptorRingSize; Adapter->RcvHeaderSize = ((RCV_HEADER_SIZE + Adapter->CacheLineSize - 1) / Adapter->CacheLineSize) * Adapter->CacheLineSize; #if _DBG DbgPrint("Alloc Rcv_ring[%d desc.], Txm_ring[%d desc.], setup_buf[%d]...\n", Adapter->ReceiveRingSize, TRANSMIT_RING_SIZE, DC21X4_SETUP_BUFFER_SIZE ); #endif // Allocate space for transmit descriptor ring, // the receive descriptor ring and the setup buffer TransmitDescriptorRingSize = Adapter->DescriptorSize * TRANSMIT_RING_SIZE; ReceiveDescriptorRingSize = Adapter->DescriptorSize * Adapter->ReceiveRingSize; Adapter->DescriptorRing.AllocSize = TransmitDescriptorRingSize + ReceiveDescriptorRingSize + DC21X4_SETUP_BUFFER_SIZE + Adapter->CacheLineSize; NdisMAllocateSharedMemory( Adapter->MiniportAdapterHandle, Adapter->DescriptorRing.AllocSize, FALSE, // NON-CACHED (PVOID *)&Adapter->DescriptorRing.AllocVa, // virtual ... &Adapter->DescriptorRing.AllocPa // and physical address of the allocation ); // Check the allocation success if ((PVOID)Adapter->DescriptorRing.AllocVa == (PVOID)NULL) { return FALSE; } if (NdisGetPhysicalAddressHigh(Adapter->DescriptorRing.AllocPa) != 0) { return FALSE; } NdisZeroMemory ( (PVOID)(Adapter->DescriptorRing.AllocVa), (ULONG)(Adapter->DescriptorRing.AllocSize) ); // Align to the next cache line boundary AlignStructure ( &Adapter->DescriptorRing, Adapter->CacheLineSize ); Adapter->TransmitDescriptorRingVa = Adapter->DescriptorRing.Va; Adapter->TransmitDescriptorRingPa = Adapter->DescriptorRing.Pa; Offset = TransmitDescriptorRingSize; Adapter->ReceiveDescriptorRingVa = Adapter->DescriptorRing.Va + Offset; Adapter->ReceiveDescriptorRingPa = Adapter->DescriptorRing.Pa + Offset; Offset += ReceiveDescriptorRingSize; Adapter->SetupBufferVa = Adapter->DescriptorRing.Va + Offset; Adapter->SetupBufferPa = Adapter->DescriptorRing.Pa + Offset; //Initialize the setup buffer NdisZeroMemory ( (PVOID)(Adapter->SetupBufferVa), DC21X4_SETUP_BUFFER_SIZE ); // Allocate a pool of NDIS buffers NdisAllocateBufferPool( &Status, &Adapter->FlushBufferPoolHandle, ( Adapter->ReceiveRingSize + Adapter->ExtraReceiveBuffers + DC21X4_NUMBER_OF_MAX_TRANSMIT_BUFFERS + DC21X4_NUMBER_OF_MIN_TRANSMIT_BUFFERS ) ); if (Status != NDIS_STATUS_SUCCESS) { return FALSE; } // Allocate a pool of packets. #if _DBG DbgPrint("Allocate PacketPool [%d packets]\n", Adapter->ExtraReceivePackets); #endif NdisAllocatePacketPool( &Status, &Adapter->ReceivePacketPool, Adapter->ExtraReceivePackets, 0 ); if (Status != NDIS_STATUS_SUCCESS) { return FALSE; } // Allocate all of the packets out of the packet pool // and place them on a queue. for (i = 0; i < Adapter->ExtraReceivePackets; i++) { // Allocate a packet from the pool. NdisAllocatePacket( &Status, &Packet, Adapter->ReceivePacketPool ); if (Status != NDIS_STATUS_SUCCESS) { return(FALSE); } // Set the header size in the packet's Out-Of-Band information. // All other fields in the Out-Of-Band information have been // initialized to 0 by NdisAllocatePacket(). NDIS_SET_PACKET_HEADER_SIZE(Packet, ETH_HEADER_SIZE); // Place it on the receive packet free list. RCV_RESERVED(Packet)->Next = Adapter->FreePacketList; Adapter->FreePacketList = Packet; } // Clear out the free receive list of buffers. Adapter->FreeRcvList = NULL; // We allocate the receive buffers. We allocate both // the buffers for the descriptor ring and the extra // buffers and place them all on the free queue. #if _DBG DbgPrint("Allocate Receive Buffers [%d]\n", Adapter->ExtraReceiveBuffers+Adapter->ReceiveRingSize); #endif // Attempt to allocate all the receive buffer space // in one block // If it fails,allocate each buffer individually // Allocation size Adapter->RcvBufferSpace.AllocSize = ((Adapter->ExtraReceiveBuffers + Adapter->ReceiveRingSize) * (DC21X4_RECEIVE_BUFFER_SIZE + Adapter->RcvHeaderSize)) + Adapter->CacheLineSize; NdisMAllocateSharedMemory( Adapter->MiniportAdapterHandle, Adapter->RcvBufferSpace.AllocSize, TRUE, (PVOID *)&Adapter->RcvBufferSpace.AllocVa, &Adapter->RcvBufferSpace.AllocPa ); // Check the allocation success if (((PVOID)Adapter->RcvBufferSpace.AllocVa != (PVOID)NULL) && (NdisGetPhysicalAddressHigh(Adapter->RcvBufferSpace.AllocPa) == 0)) { NdisZeroMemory ( (PVOID)(Adapter->RcvBufferSpace.AllocVa), (ULONG)(Adapter->RcvBufferSpace.AllocSize) ); // Align to the next cache line boundary AlignStructure ( &Adapter->RcvBufferSpace, Adapter->CacheLineSize ); // Allocation size needed for the receive buffer AllocSize = DC21X4_RECEIVE_BUFFER_SIZE + Adapter->RcvHeaderSize; Offset=0; } else { // Allocation size needed for the receive buffer AllocSize = DC21X4_RECEIVE_BUFFER_SIZE + Adapter->RcvHeaderSize + Adapter->CacheLineSize; Adapter->RcvBufferSpace.Va=0; } for (i = 0; i < (Adapter->ExtraReceiveBuffers + Adapter->ReceiveRingSize); i++ ) { if (Adapter->RcvBufferSpace.Va != 0) { Va = Adapter->RcvBufferSpace.Va + Offset; Pa = Adapter->RcvBufferSpace.Pa + Offset; Offset += AllocSize; } else { // Allocate a receive buffer. NdisMAllocateSharedMemory( Adapter->MiniportAdapterHandle, AllocSize, TRUE, (PVOID *)&AllocVa, &AllocPa ); if (((PVOID)AllocVa == (PVOID)NULL) || (NdisGetPhysicalAddressHigh(AllocPa) != 0)) { return FALSE; } NdisZeroMemory(AllocVa, AllocSize); // Align on the cache line boundary Offset = Adapter->CacheLineSize - ((ULONG)AllocVa % Adapter->CacheLineSize); Va = (ULONG)(AllocVa) + Offset; Pa = NdisGetPhysicalAddressLow(AllocPa) + Offset; } //The receive header points to the aligned va. RcvHeader = (PRCV_HEADER)Va; RcvHeader->AllocVa = (ULONG)AllocVa; RcvHeader->AllocPa = AllocPa; RcvHeader->AllocSize = (USHORT)AllocSize; // These addresses point to the data buffer RcvHeader->Va = (ULONG)(Va + Adapter->RcvHeaderSize); RcvHeader->Pa = Pa + Adapter->RcvHeaderSize; RcvHeader->Size = DC21X4_RECEIVE_BUFFER_SIZE; #if DBG RcvHeader->Signature = 'dHxR'; #if _DBG DbgPrint( "%-3d RcvHeader: %lx, RcvBuffer: %lx/%lx, HeaderSize: %lx\n", i,RcvHeader, RcvHeader->Va, RcvHeader->Pa, Adapter->RcvHeaderSize ); #endif #endif // Allocate an NDIS flush buffer for each receive buffer. NdisAllocateBuffer( &Status, &RcvHeader->FlushBuffer, Adapter->FlushBufferPoolHandle, (PVOID)RcvHeader->Va, DC21X4_RECEIVE_BUFFER_SIZE ); if (Status != NDIS_STATUS_SUCCESS) { return FALSE; } // Grab a packet off of the free packet list and // associate it with the buffer. Packet = Adapter->FreePacketList; Adapter->FreePacketList = RCV_RESERVED(Packet)->Next; // Chain the buffer on the packet. NdisChainBufferAtFront(Packet, RcvHeader->FlushBuffer); // Save a pointer to the receive header with the packet. RCV_RESERVED(Packet)->RcvHeader = RcvHeader; // Save the packet with the receive header. RcvHeader->Packet = Packet; // Place the descriptor on the free queue. RcvHeader->Next = Adapter->FreeRcvList; Adapter->FreeRcvList = RcvHeader; Adapter->CurrentReceiveBufferCount++; } #if _DBG DbgPrint("Init Rcv ring..\n"); #endif // Assign the receive buffers to the descriptors. for (i = 0, ReceiveDescriptor = (PDC21X4_RECEIVE_DESCRIPTOR)Adapter->ReceiveDescriptorRingVa, Pa = Adapter->ReceiveDescriptorRingPa; i < Adapter->ReceiveRingSize; i++, (PCHAR)ReceiveDescriptor += Adapter->DescriptorSize, Pa += Adapter->DescriptorSize ) { // Grab a receive buffer from the free list. ASSERT(Adapter->FreeRcvList != NULL); RcvHeader = Adapter->FreeRcvList; Adapter->FreeRcvList = RcvHeader->Next; Adapter->CurrentReceiveBufferCount--; // Associate the buffer with the descriptor. ReceiveDescriptor->RcvHeader = RcvHeader; ReceiveDescriptor->FirstBufferAddress = RcvHeader->Pa; ReceiveDescriptor->Status = DESC_OWNED_BY_DC21X4; ReceiveDescriptor->Control = DC21X4_RECEIVE_BUFFER_SIZE; ReceiveDescriptor->Next = (PDC21X4_RECEIVE_DESCRIPTOR)((PCHAR)ReceiveDescriptor + Adapter->DescriptorSize); } //last descriptor of the ring (PCHAR)ReceiveDescriptor -= Adapter->DescriptorSize; ReceiveDescriptor->Control |= DC21X4_RDES_SECOND_ADDR_CHAINED; ReceiveDescriptor->SecondBufferAddress = Adapter->ReceiveDescriptorRingPa; ReceiveDescriptor->Next = (PDC21X4_RECEIVE_DESCRIPTOR)Adapter->ReceiveDescriptorRingVa; #if _DBG DbgPrint("Init Txm ring..\n"); #endif // Initialize the Transmit Descriptor ring for (i=0, TransmitDescriptor = (PDC21X4_TRANSMIT_DESCRIPTOR)Adapter->TransmitDescriptorRingVa, Pa = Adapter->TransmitDescriptorRingPa; i < TRANSMIT_RING_SIZE; i++, (PCHAR)TransmitDescriptor += Adapter->DescriptorSize, Pa += Adapter->DescriptorSize ) { TransmitDescriptor->MapTableIndex = i * NUMBER_OF_SEGMENT_PER_DESC; TransmitDescriptor->DescriptorPa = Pa; TransmitDescriptor->Next = (PDC21X4_TRANSMIT_DESCRIPTOR)((PCHAR)TransmitDescriptor + Adapter->DescriptorSize); } //last descriptor of the ring (PCHAR)TransmitDescriptor -= Adapter->DescriptorSize; TransmitDescriptor->Control = DC21X4_TDES_SECOND_ADDR_CHAINED; TransmitDescriptor->SecondBufferAddress = Adapter->TransmitDescriptorRingPa; TransmitDescriptor->Next = (PDC21X4_TRANSMIT_DESCRIPTOR)Adapter->TransmitDescriptorRingVa; // Txm buffers for (i = 0;i < DC21X4_NUMBER_OF_MAX_TRANSMIT_BUFFERS;i ++) { Adapter->MaxTransmitBuffer[i].AllocSize = DC21X4_MAX_TRANSMIT_BUFFER_SIZE + Adapter->CacheLineSize; NdisMAllocateSharedMemory( Adapter->MiniportAdapterHandle, Adapter->MaxTransmitBuffer[i].AllocSize, TRUE, // CACHED (PVOID *)&Adapter->MaxTransmitBuffer[i].AllocVa, // virtual ... &Adapter->MaxTransmitBuffer[i].AllocPa // and physical address of the buffer allocation ); // Check the allocation success if (((PVOID)Adapter->MaxTransmitBuffer[i].AllocVa == (PVOID)NULL) || (NdisGetPhysicalAddressHigh(Adapter->MaxTransmitBuffer[i].AllocPa) != 0)) { return FALSE; } // Align the buffer on the cache line boundary AlignStructure ( &Adapter->MaxTransmitBuffer[i], Adapter->CacheLineSize ); // Allocate an NDIS flush buffer for each transmit buffer NdisAllocateBuffer( &Status, &Adapter->MaxTransmitBuffer[i].FlushBuffer, Adapter->FlushBufferPoolHandle, (PVOID)Adapter->MaxTransmitBuffer[i].Va, DC21X4_MAX_TRANSMIT_BUFFER_SIZE ); if (Status != NDIS_STATUS_SUCCESS) { return FALSE; } } // Allocate the minimal packet buffers Adapter->MinTransmitBuffer[0].AllocSize = (DC21X4_NUMBER_OF_MIN_TRANSMIT_BUFFERS * DC21X4_MIN_TRANSMIT_BUFFER_SIZE) + Adapter->CacheLineSize; NdisMAllocateSharedMemory( Adapter->MiniportAdapterHandle, Adapter->MinTransmitBuffer[0].AllocSize, TRUE, // CACHED (PVOID *)&Adapter->MinTransmitBuffer[0].AllocVa, // virtual ... &Adapter->MinTransmitBuffer[0].AllocPa // and physical address of the buffer allocation ); // Check the allocation success if (((PVOID)Adapter->MinTransmitBuffer[0].AllocVa == (PVOID)NULL) || (NdisGetPhysicalAddressHigh(Adapter->MinTransmitBuffer[0].AllocPa) != 0)) { Adapter->DontUseMinTransmitBuffer = TRUE; return TRUE; } // Align the buffer on the cache line boundary AlignStructure ( &Adapter->MinTransmitBuffer[0], Adapter->CacheLineSize ); for (i = 0;i < DC21X4_NUMBER_OF_MIN_TRANSMIT_BUFFERS;i ++) { Offset = i * DC21X4_MIN_TRANSMIT_BUFFER_SIZE; Adapter->MinTransmitBuffer[i].Va = Adapter->MinTransmitBuffer[0].Va + Offset; Adapter->MinTransmitBuffer[i].Pa = Adapter->MinTransmitBuffer[0].Pa + Offset; // Allocate an NDIS flush buffer for each transmit buffer NdisAllocateBuffer( &Status, &Adapter->MinTransmitBuffer[i].FlushBuffer, Adapter->FlushBufferPoolHandle, (PVOID)Adapter->MinTransmitBuffer[i].Va, DC21X4_MIN_TRANSMIT_BUFFER_SIZE ); if (Status != NDIS_STATUS_SUCCESS) { return FALSE; } } // Allocation has completed successfully return TRUE; }