NTSTATUS NICStartSend( __in PFDO_DATA FdoData, __in PMP_TCB pMpTcb ) /*++ Routine Description: Issue a send command to the NIC Assumption: Send spinlock has been acquired Arguments: FdoData Pointer to our FdoData pMpTcb Pointer to MP_TCB Return Value: NTSTATUS code --*/ { NTSTATUS status; DebugPrint(TRACE, DBG_WRITE, "--> 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 (FdoData->TransmitIdle) { DebugPrint(TRACE, DBG_WRITE, "CU is idle -- First TCB added to Active List\n"); // // Wait for the SCB to clear before we set the general pointer // if (!WaitScb(FdoData)) { DebugPrint(ERROR, DBG_WRITE, "NICStartSend -- WaitScb returned error\n"); status = STATUS_DEVICE_DATA_ERROR; goto exit; } // // Don't try to start the transmitter if the command unit is not // idle ((not idle) == (Cu-Suspended or Cu-Active)). // if ((FdoData->CSRAddress->ScbStatus & SCB_CUS_MASK) != SCB_CUS_IDLE) { DebugPrint(ERROR, DBG_WRITE, "FdoData = %p, CU Not IDLE\n", FdoData); MP_SET_HARDWARE_ERROR(FdoData); KeStallExecutionProcessor(25); } FdoData->CSRAddress->ScbGeneralPointer = pMpTcb->HwTcbPhys; status = D100IssueScbCommand(FdoData, SCB_CUC_START, FALSE); FdoData->TransmitIdle = FALSE; FdoData->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. // DebugPrint(LOUD, DBG_WRITE, "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(FdoData, SCB_CUC_RESUME, FdoData->ResumeWait); } exit: DebugPrint(TRACE, DBG_WRITE, "<-- NICStartSend\n"); return status; }
NTSTATUS MPSetUpFilterCB( __in PFDO_DATA FdoData ) { NTSTATUS status = STATUS_SUCCESS; PCB_HEADER_STRUC NonTxCmdBlockHdr = (PCB_HEADER_STRUC)FdoData->NonTxCmdBlock; PFILTER_CB_STRUC pFilterCb = (PFILTER_CB_STRUC)NonTxCmdBlockHdr; ULONG Curr = 0; ULONG Next = 0; PLIST_ENTRY pPatternEntry = ListNext(&FdoData->PoMgmt.PatternList) ; DebugPrint(TRACE, DBG_POWER, "--> MPSetUpFilterCB\n"); RtlZeroMemory (pFilterCb, sizeof(*pFilterCb)); // Individual Address Setup NonTxCmdBlockHdr->CbStatus = 0; NonTxCmdBlockHdr->CbCommand = CB_EL_BIT | CB_LOAD_PROG_FILTER; NonTxCmdBlockHdr->CbLinkPointer = DRIVER_NULL; // go through each filter in the list. while (pPatternEntry != (&FdoData->PoMgmt.PatternList)) { PMP_WAKE_PATTERN pWakeUpPattern = NULL; // initialize local variables pWakeUpPattern = CONTAINING_RECORD(pPatternEntry, MP_WAKE_PATTERN, linkListEntry); // increment the iterator pPatternEntry = ListNext (pPatternEntry); // Update the Curr Array Pointer Curr = Next; // Create the Programmable filter for this device. MPCreateProgrammableFilter (pWakeUpPattern , &pFilterCb->Pattern[Curr], &Next); if (Next >=16) { break; } } { // Set the EL bit on the last pattern PUCHAR pLastPattern = (PUCHAR) &pFilterCb->Pattern[Curr]; // Get to bit 31 pLastPattern[3] |= CB_FILTER_EL ; } ASSERT(FdoData->CSRAddress->ScbCommandLow == 0); // Wait for the CU to Idle before giving it this command if(!WaitScb(FdoData)) { status = STATUS_DEVICE_DATA_ERROR; } DebugPrint(TRACE, DBG_POWER, "<-- MPSetUpFilterCB\n"); return status; }
NTSTATUS NICSetMulticastList( PFDO_DATA FdoData ) /*++ Routine Description: This routine will set up the FdoData for a specified multicast address list Arguments: FdoData Pointer to our FdoData Return Value: --*/ { NTSTATUS status; PUCHAR McAddress; UINT i, j; BOOLEAN bResult; DebugPrint(TRACE, DBG_IOCTLS, "--> NICSetMulticastList\n"); // // Setup the command block for the multicast command. // for (i = 0; i < FdoData->MCAddressCount; i++) { DebugPrint(TRACE, DBG_IOCTLS, "MC(%d) = %02x-%02x-%02x-%02x-%02x-%02x\n", i, FdoData->MCList[i][0], FdoData->MCList[i][1], FdoData->MCList[i][2], FdoData->MCList[i][3], FdoData->MCList[i][4], FdoData->MCList[i][5]); McAddress = &FdoData->NonTxCmdBlock->NonTxCb.Multicast.McAddress[i*ETHERNET_ADDRESS_LENGTH]; for (j = 0; j < ETH_LENGTH_OF_ADDRESS; j++) *(McAddress++) = FdoData->MCList[i][j]; } FdoData->NonTxCmdBlock->NonTxCb.Multicast.McCount = (USHORT)(FdoData->MCAddressCount * ETH_LENGTH_OF_ADDRESS); ((PCB_HEADER_STRUC)FdoData->NonTxCmdBlock)->CbStatus = 0; ((PCB_HEADER_STRUC)FdoData->NonTxCmdBlock)->CbCommand = CB_MULTICAST; // // Wait for the SCB to clear before we check the CU status. // if (!WaitScb(FdoData)) { status = STATUS_DEVICE_DATA_ERROR; MP_EXIT; } // // If we have issued any transmits, then the CU will either be active, or // in the suspended state. If the CU is active, then we wait for it to be // suspended. // if (FdoData->TransmitIdle == FALSE) { // // Wait for suspended state // MP_STALL_AND_WAIT((FdoData->CSRAddress->ScbStatus & SCB_CUS_MASK) != SCB_CUS_ACTIVE, 5000, bResult); if (!bResult) { MP_SET_HARDWARE_ERROR(FdoData); status = STATUS_DEVICE_DATA_ERROR; } // // Restore the transmit software flags. After the multicast command is // issued, the command unit will be idle, because the EL bit will be // set in the multicast commmand block. // FdoData->TransmitIdle = TRUE; FdoData->ResumeWait = TRUE; } // // Update the command list pointer. // FdoData->CSRAddress->ScbGeneralPointer = FdoData->NonTxCmdBlockPhys; // // Submit the multicast command to the FdoData and wait for it to complete. // status = D100SubmitCommandBlockAndWait(FdoData); if (status != STATUS_SUCCESS) { status = STATUS_DEVICE_NOT_READY; } exit: DebugPrint(TRACE, DBG_IOCTLS, "<-- NICSetMulticastList, status=%x\n", status); return(status); }
NTSTATUS NICSetPacketFilter( __in PFDO_DATA FdoData, __in ULONG PacketFilter ) /*++ Routine Description: This routine will set up the FdoData so that it accepts packets that match the specified packet filter. The only filter bits that can truly be toggled are for broadcast and promiscuous Arguments: FdoData Pointer to our FdoData PacketFilter The new packet filter Return Value: --*/ { NTSTATUS status = STATUS_SUCCESS; UCHAR NewParameterField; UINT i; BOOLEAN bResult; DebugPrint(TRACE, DBG_IOCTLS, "--> NICSetPacketFilter, PacketFilter=%08x\n", PacketFilter); // // Need to enable or disable broadcast and promiscuous support depending // on the new filter // NewParameterField = CB_557_CFIG_DEFAULT_PARM15; if (PacketFilter & NDIS_PACKET_TYPE_BROADCAST) { NewParameterField &= ~CB_CFIG_BROADCAST_DIS; } else { NewParameterField |= CB_CFIG_BROADCAST_DIS; } if (PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS) { NewParameterField |= CB_CFIG_PROMISCUOUS; } else { NewParameterField &= ~CB_CFIG_PROMISCUOUS; } do { if ((FdoData->OldParameterField == NewParameterField ) && !(PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST)) { break; } // // Only need to do something to the HW if the filter bits have changed. // FdoData->OldParameterField = NewParameterField; ((PCB_HEADER_STRUC)FdoData->NonTxCmdBlock)->CbCommand = CB_CONFIGURE; ((PCB_HEADER_STRUC)FdoData->NonTxCmdBlock)->CbStatus = 0; ((PCB_HEADER_STRUC)FdoData->NonTxCmdBlock)->CbLinkPointer = DRIVER_NULL; // // First fill in the static (end user can't change) config bytes // FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[0] = CB_557_CFIG_DEFAULT_PARM0; FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[2] = CB_557_CFIG_DEFAULT_PARM2; FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[3] = CB_557_CFIG_DEFAULT_PARM3; FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[6] = CB_557_CFIG_DEFAULT_PARM6; FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[9] = CB_557_CFIG_DEFAULT_PARM9; FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[10] = CB_557_CFIG_DEFAULT_PARM10; FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[11] = CB_557_CFIG_DEFAULT_PARM11; FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[12] = CB_557_CFIG_DEFAULT_PARM12; FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[13] = CB_557_CFIG_DEFAULT_PARM13; FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[14] = CB_557_CFIG_DEFAULT_PARM14; FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[16] = CB_557_CFIG_DEFAULT_PARM16; FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[17] = CB_557_CFIG_DEFAULT_PARM17; FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[18] = CB_557_CFIG_DEFAULT_PARM18; FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[20] = CB_557_CFIG_DEFAULT_PARM20; // // Set the Tx underrun retries // FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[7] = (UCHAR) (CB_557_CFIG_DEFAULT_PARM7 | (FdoData->AiUnderrunRetry << 1)); // // Set the Tx and Rx Fifo limits // FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[1] = (UCHAR) ((FdoData->AiTxFifo << 4) | FdoData->AiRxFifo); // // set the MWI enable bit if needed // if (FdoData->MWIEnable) FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[3] |= CB_CFIG_B3_MWI_ENABLE; // // Set the Tx and Rx DMA maximum byte count fields. // if ((FdoData->AiRxDmaCount) || (FdoData->AiTxDmaCount)) { FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[4] = FdoData->AiRxDmaCount; FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[5] = (UCHAR) (FdoData->AiTxDmaCount | CB_CFIG_DMBC_EN); } else { FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[4] = CB_557_CFIG_DEFAULT_PARM4; FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[5] = CB_557_CFIG_DEFAULT_PARM5; } // // Setup for MII or 503 operation. The CRS+CDT bit should only be // set when operating in 503 mode. // if (FdoData->PhyAddress == 32) { FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[8] = (CB_557_CFIG_DEFAULT_PARM8 & (~CB_CFIG_503_MII)); FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[15] = (UCHAR) (NewParameterField | CB_CFIG_CRS_OR_CDT); } else { FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[8] = (CB_557_CFIG_DEFAULT_PARM8 | CB_CFIG_503_MII); FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[15] = (UCHAR) (NewParameterField & (~CB_CFIG_CRS_OR_CDT)); } // // Setup Full duplex stuff // // // If forced to half duplex // if (FdoData->AiForceDpx == 1) { FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[19] = (CB_557_CFIG_DEFAULT_PARM19 & (~(CB_CFIG_FORCE_FDX| CB_CFIG_FDX_ENABLE))); } // // If forced to full duplex // else if (FdoData->AiForceDpx == 2) { FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[19] = (CB_557_CFIG_DEFAULT_PARM19 | CB_CFIG_FORCE_FDX); } // // If auto-duplex // else { FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[19] = CB_557_CFIG_DEFAULT_PARM19; } // // if multicast all is being turned on, set the bit // if (PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST) { FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[21] = (CB_557_CFIG_DEFAULT_PARM21 | CB_CFIG_MULTICAST_ALL); } else { FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[21] = CB_557_CFIG_DEFAULT_PARM21; } // // Wait for the SCB to clear before we check the CU status. // if (!WaitScb(FdoData)) { status = STATUS_DEVICE_DATA_ERROR; break; } // // If we have issued any transmits, then the CU will either be active, // or in the suspended state. If the CU is active, then we wait for // it to be suspended. // if (FdoData->TransmitIdle == FALSE) { // // Wait for suspended state // MP_STALL_AND_WAIT((FdoData->CSRAddress->ScbStatus & SCB_CUS_MASK) != SCB_CUS_ACTIVE, 5000, bResult); if (!bResult) { MP_SET_HARDWARE_ERROR(FdoData); status = STATUS_DEVICE_DATA_ERROR; break; } // // Check the current status of the receive unit // if ((FdoData->CSRAddress->ScbStatus & SCB_RUS_MASK) != SCB_RUS_IDLE) { // Issue an RU abort. Since an interrupt will be issued, the // RU will be started by the DPC. status = D100IssueScbCommand(FdoData, SCB_RUC_ABORT, TRUE); if (status != STATUS_SUCCESS) { break; } } if (!WaitScb(FdoData)) { status = STATUS_DEVICE_DATA_ERROR; break; } // // Restore the transmit software flags. After the multicast // command is issued, the command unit will be idle, because the // EL bit will be set in the multicast commmand block. // FdoData->TransmitIdle = TRUE; FdoData->ResumeWait = TRUE; } // // Display config info // DebugPrint(TRACE, DBG_IOCTLS, "Re-Issuing Configure command for filter change\n"); DebugPrint(TRACE, DBG_IOCTLS, "Config Block at virt addr %p, phys address %x\n", &((PCB_HEADER_STRUC)FdoData->NonTxCmdBlock)->CbStatus, FdoData->NonTxCmdBlockPhys); for (i = 0; i < CB_CFIG_BYTE_COUNT; i++) DebugPrint(LOUD, DBG_IOCTLS, " Config byte %x = %.2x\n", i, FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[i]); // // Submit the configure command to the chip, and wait for it to complete. // FdoData->CSRAddress->ScbGeneralPointer = FdoData->NonTxCmdBlockPhys; status = D100SubmitCommandBlockAndWait(FdoData); if (status != STATUS_SUCCESS) { status = STATUS_DEVICE_NOT_READY; } } while (FALSE); DebugPrint(TRACE, DBG_IOCTLS, "<-- NICSetPacketFilter, Status=%x\n", status); return(status); }
NTSTATUS NICStartRecv( IN PFDO_DATA FdoData ) /*++ Routine Description: Start the receive unit if it's not in a ready state Assumption: This function is called with the Rcv SPINLOCK held. Arguments: FdoData Pointer to our FdoData Return Value: NT Status code --*/ { PMP_RFD pMpRfd; NTSTATUS status; TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "---> NICStartRecv\n"); // // If the receiver is ready, then don't try to restart. // if (NIC_IS_RECV_READY(FdoData)) { TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "Receive unit already active\n"); return STATUS_SUCCESS; } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "Re-start receive unit...\n"); ASSERT(!IsListEmpty(&FdoData->RecvList)); // // Get the MP_RFD head // pMpRfd = (PMP_RFD)GetListHeadEntry(&FdoData->RecvList); // // If more packets are received, clean up RFD chain again // if (NIC_RFD_GET_STATUS(pMpRfd->HwRfd)) { NICHandleRecvInterrupt(FdoData); ASSERT(!IsListEmpty(&FdoData->RecvList)); // // Get the new MP_RFD head // pMpRfd = (PMP_RFD)GetListHeadEntry(&FdoData->RecvList); } // // Wait for the SCB to clear before we set the general pointer // if (!WaitScb(FdoData)) { status = STATUS_DEVICE_DATA_ERROR; goto exit; } if (FdoData->DevicePowerState > PowerDeviceD0) { status = STATUS_DEVICE_DATA_ERROR; goto exit; } // // Set the SCB General Pointer to point the current Rfd // FdoData->CSRAddress->ScbGeneralPointer = pMpRfd->HwRfdPhys; // // Issue the SCB RU start command // status = D100IssueScbCommand(FdoData, SCB_RUC_START, FALSE); if (status == STATUS_SUCCESS) { // wait for the command to be accepted if (!WaitScb(FdoData)) { status = STATUS_DEVICE_DATA_ERROR; } } exit: TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "<--- NICStartRecv, Status=%x\n", status); return status; }