// First disable interrupts and then deregister interrupts VOID Hw11Stop( __in PHW Hw, __in NDIS_HALT_ACTION HaltAction ) { UNREFERENCED_PARAMETER(HaltAction); HW_ACQUIRE_HARDWARE_LOCK(Hw, FALSE); HW_SET_ADAPTER_STATUS(Hw, HW_ADAPTER_HALTING); HW_RELEASE_HARDWARE_LOCK(Hw, FALSE); // // Deregister interrupts. We must disable them before deregistering interrupts // // MpTrace(COMP_TESTING, DBG_SERIOUS, ("Hw11Stop \n")); HwDisableInterrupt(Hw, HW_ISR_TRACKING_HWSTOP); HwDeregisterInterrupt(Hw); // There must be no pending operations at this time MPASSERT(Hw->AsyncFuncRef == 0); // // Ensure that we have stop beaconing // Hw->MacState.BeaconEnabled = FALSE; Hw->MacState.BSSStarted = FALSE; // // Flush all the MSDU in the reassembly line // HwFlushMSDUReassemblyLine(Hw); // Stop everything in the H/W (We may restart things for context switches, etc) HalStop(Hw->Hal); }
NDIS_STATUS Hw11Pause( __in PHW Hw ) { // // Set the in progress flag. This would stop any new receives // from getting processed. // HW_ACQUIRE_HARDWARE_LOCK(Hw, FALSE); HW_SET_ADAPTER_STATUS(Hw, HW_ADAPTER_PAUSING); HW_RELEASE_HARDWARE_LOCK(Hw, FALSE); // // Wait for any current send/receive interrupt handlers to finish. New ones // may increment the counter but would abort once they find the above flag // set // HW_WAIT_FOR_ACTIVE_OPERATIONS_TO_FINISH(Hw); // Wait for active sends to be finish HW_WAIT_FOR_ACTIVE_SENDS_TO_FINISH(Hw); // For performance reason we also disable the interrupt // MpTrace(COMP_TESTING, DBG_SERIOUS, ("Hw11Pause \n")); HwDisableInterrupt(Hw, HW_ISR_TRACKING_PAUSE); HW_SET_ADAPTER_STATUS(Hw, HW_ADAPTER_PAUSED); HW_CLEAR_ADAPTER_STATUS(Hw, HW_ADAPTER_PAUSING); return NDIS_STATUS_SUCCESS; }
NDIS_STATUS Hw11CtxSStart( __in PHW Hw ) { // // Set the in progress flag. This would stop any new receives // from getting processed. // HW_ACQUIRE_HARDWARE_LOCK(Hw, FALSE); HW_SET_ADAPTER_STATUS(Hw, HW_ADAPTER_IN_CONTEXT_SWITCH); HW_RELEASE_HARDWARE_LOCK(Hw, FALSE); MpTrace(COMP_MISC, DBG_SERIOUS, ("H/W context switch started")); // // Wait for any current send/receive interrupt handlers to finish. New ones // may increment the counter but would abort once they find the above flag // set // HW_WAIT_FOR_ACTIVE_OPERATIONS_TO_FINISH(Hw); HW_WAIT_FOR_ACTIVE_SENDS_TO_FINISH(Hw); return NDIS_STATUS_SUCCESS; }
// // Reset Step 1 - Cleanup any "pending" operations // VOID Hw11NdisResetStep1( __in PHW Hw ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; // if we are being reset because our sends are hung, we do not want to assert. however // if sends are not the cause, we do want to assert. if (!Hw11ArePktsPending(Hw)) { MPASSERT(FALSE); } // // Set state as in reset // HW_ACQUIRE_HARDWARE_LOCK(Hw, FALSE); HW_SET_ADAPTER_STATUS(Hw, HW_ADAPTER_IN_RESET); HW_RELEASE_HARDWARE_LOCK(Hw, FALSE); // // Now cleanup everything // // Cancel scan (if it is running) HwCancelScan(Hw); // Wait for pending operations in the hardware to finish HW_WAIT_FOR_ACTIVE_OPERATIONS_TO_FINISH(Hw); // Wait for active sends to be finish HW_WAIT_FOR_ACTIVE_SENDS_TO_FINISH(Hw); // Disable interrupts HwDisableInterrupt(Hw, HW_ISR_TRACKING_NDIS_RESET); ndisStatus = HalResetStart(Hw->Hal); MPASSERT(ndisStatus == NDIS_STATUS_SUCCESS); HalStop(Hw->Hal); HwFlushSendEngine(Hw, FALSE); // Dont wait for pending receives here. They may be stuck in protocols on // sends & the sends may be queued in the ports. That would cause a deadlock }
NDIS_STATUS HwSetChannel( _In_ PHW Hw, _In_ ULONG PhyId, _In_ UCHAR Channel ) { // Must only be called for the active phy MPASSERT(PhyId == Hw->PhyState.OperatingPhyId); // When setting the channel, we dont check if we are not already on that // channel. This is because this may be called after setting a PhyID and // that does not necessarily set the channel HW_ACQUIRE_HARDWARE_LOCK(Hw, FALSE); HW_SET_ADAPTER_STATUS(Hw, HW_ADAPTER_IN_CHANNEL_SWITCH); HW_RELEASE_HARDWARE_LOCK(Hw, FALSE); // Wait for active send threads to finish. We dont wait // for anything else on an HAL reset since some of those // operations themselves may be causing the reset (Eg. channel // switch of a scan) HW_WAIT_FOR_ACTIVE_SENDS_TO_FINISH(Hw); // MpTrace(COMP_TESTING, DBG_SERIOUS, ("HwSetChannel \n")); HwDisableInterrupt(Hw, HW_ISR_TRACKING_CHANNEL); // Flush the sends HwFlushSendEngine(Hw, FALSE); HalSwitchChannel(Hw->Hal, PhyId, Channel, FALSE ); HwResetSendEngine(Hw, FALSE); HwResetReceiveEngine(Hw, FALSE); HalStartReceive(Hw->Hal); // MpTrace(COMP_TESTING, DBG_SERIOUS, ("HwSetChannel \n")); HwEnableInterrupt(Hw, HW_ISR_TRACKING_CHANNEL); HW_CLEAR_ADAPTER_STATUS(Hw, HW_ADAPTER_IN_CHANNEL_SWITCH); return NDIS_STATUS_SUCCESS; }
VOID Hw11DevicePnPEvent( __in PHW Hw, __in PNET_DEVICE_PNP_EVENT NetDevicePnPEvent ) { if (NetDevicePnPEvent->DevicePnPEvent == NdisDevicePnPEventSurpriseRemoved) { // // If hardware has been surprise removed,remember that. // We have to make sure we do not try to do any I/O on ports // if device has been surprise removed. // HW_ACQUIRE_HARDWARE_LOCK(Hw, FALSE); HW_SET_ADAPTER_STATUS(Hw, HW_ADAPTER_SURPRISE_REMOVED); HW_RELEASE_HARDWARE_LOCK(Hw, FALSE); // Wait for interrupt, etc functions to finish HW_WAIT_FOR_ACTIVE_OPERATIONS_TO_FINISH(Hw); // Wait for active sends to be finish HW_WAIT_FOR_ACTIVE_SENDS_TO_FINISH(Hw); // // We must stop advertising sending beacons and probes. // as the hardware is no longer present // Hw->MacState.BeaconEnabled = FALSE; Hw->MacState.BSSStarted = FALSE; // // Clear the send queue. Since the hardware is gone, we would not get // any more send completes // HwResetSendEngine(Hw, FALSE); // // Any place where we are reading registers and making major // decisions we should consider protecting against FFFF for surprise // removal case // // TODO: Notify the HAL about surprise remove } }
NDIS_STATUS HwSetNicPowerState( _In_ PHW Hw, _In_ ULONG PhyId, _In_ BOOLEAN PowerOn ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; HW_HAL_RESET_PARAMETERS resetParams; // // Our RF cannot be selectively turned on/off. We turn on or turn off all the phys // anytime this OID is set // UNREFERENCED_PARAMETER(PhyId); // // Check if we are already in the specified state. // if (Hw->PhyState.SoftwareRadioOff == !PowerOn) { // No need to take status indications if we are // already in the correct state return NDIS_STATUS_SUCCESS; } if (!PowerOn) { // // Going to power save. Get everything into a stable state // // // If a scan is in progress, cancel scan // if (Hw->ScanContext.ScanInProgress) { HwCancelScan(Hw); } // // Before we turn off the radio, we reset the h/w. // This is to ensure that there isnt any pending operation sitting // on the hardware // NdisZeroMemory(&resetParams, sizeof(HW_HAL_RESET_PARAMETERS)); HwResetHAL(Hw, &resetParams, FALSE); // // Disable the interrupt // HwDisableInterruptWithSync(Hw, HW_ISR_TRACKING_RADIO_STATE); HW_ACQUIRE_HARDWARE_LOCK(Hw, FALSE); HW_SET_ADAPTER_STATUS(Hw, HW_ADAPTER_RADIO_OFF); HW_RELEASE_HARDWARE_LOCK(Hw, FALSE); } // // Update Radio state // // Set flag so other threads (power save, scan timer, etc) wont change // state behind us Hw->PhyState.RadioStateChangeInProgress = TRUE; // We wait for ever for other threads to not reach this state while (Hw->PhyState.RadioAccessRef != 0); // // Set the Radio state // if (PowerOn) { Hw->PhyState.Debug_SoftwareRadioOff = FALSE; HalSetRFPowerState(Hw->Hal, RF_ON); Hw->PhyState.SoftwareRadioOff = FALSE; } else { Hw->PhyState.SoftwareRadioOff = TRUE; HalSetRFPowerState(Hw->Hal, RF_SHUT_DOWN); Hw->PhyState.Debug_SoftwareRadioOff = TRUE; } Hw->PhyState.RadioStateChangeInProgress = FALSE; if (PowerOn) { // Clear the radio off bit HW_ACQUIRE_HARDWARE_LOCK(Hw, FALSE); HW_CLEAR_ADAPTER_STATUS(Hw, HW_ADAPTER_RADIO_OFF); HW_RELEASE_HARDWARE_LOCK(Hw, FALSE); // Re-reset the H/W to get it into a good state NdisZeroMemory(&resetParams, sizeof(HW_HAL_RESET_PARAMETERS)); resetParams.FullReset = TRUE; HwResetHAL(Hw, &resetParams, FALSE); // // Reenable the interrupt // HwEnableInterruptWithSync(Hw, HW_ISR_TRACKING_RADIO_STATE); } // // Save the new radio state in the registry // ndisStatus = HwPersistRadioPowerState(Hw, Hw->PhyState.SoftwareRadioOff); if (ndisStatus != NDIS_STATUS_SUCCESS) { MpTrace(COMP_OID, DBG_SERIOUS, ("Unable to persist new radio state in the registry\n")); return ndisStatus; } // // Report the new power state to the OS // HwIndicatePhyPowerState( Hw, DOT11_PHY_ID_ANY ); return ndisStatus; }
NDIS_STATUS HwResetHAL( __in PHW Hw, __in PHW_HAL_RESET_PARAMETERS ResetParams, __in BOOLEAN DispatchLevel ) { UNREFERENCED_PARAMETER(ResetParams); UNREFERENCED_PARAMETER(DispatchLevel); MPASSERT(!DispatchLevel); // Since we wait, we cannot be called at dispatch HW_ACQUIRE_HARDWARE_LOCK(Hw, FALSE); HW_SET_ADAPTER_STATUS(Hw, HW_ADAPTER_HAL_IN_RESET); HW_RELEASE_HARDWARE_LOCK(Hw, FALSE); // Wait for active send threads to finish. We dont wait // for anything else on an HAL reset since some of those // operations themselves may be causing the reset (Eg. channel // switch of a scan) HW_WAIT_FOR_ACTIVE_SENDS_TO_FINISH(Hw); HwDisableInterrupt(Hw, HW_ISR_TRACKING_HAL_RESET); if (ResetParams->FullReset) { // Perform a full reset of the HW HalResetStart(Hw->Hal); HalStop(Hw->Hal); // Reset the send and receive engine HwWaitForPendingReceives(Hw, NULL); HwResetSendEngine(Hw, FALSE); HwResetReceiveEngine(Hw, FALSE); // Remove old keys, etc HwClearNicState(Hw); // Reset our MAC & PHY state HwResetSoftwareMacState(Hw); HwResetSoftwarePhyState(Hw); HalStart(Hw->Hal, TRUE); // Push the new state on the hardware HwSetNicState(Hw); HalResetEnd(Hw->Hal); } else { // TODO: Currently we are overloading the HalSwitchChannel API for doing a HalReset HalSwitchChannel(Hw->Hal, Hw->PhyState.OperatingPhyId, HalGetPhyMIB(Hw->Hal, Hw->PhyState.OperatingPhyId)->Channel, FALSE ); HwResetReceiveEngine(Hw, FALSE); HwResetSendEngine(Hw, FALSE); HalStartReceive(Hw->Hal); } HwEnableInterrupt(Hw, HW_ISR_TRACKING_HAL_RESET); HW_CLEAR_ADAPTER_STATUS(Hw, HW_ADAPTER_HAL_IN_RESET); return NDIS_STATUS_SUCCESS; }
USHORT HwSelectTXDataRate( __in PHW_MAC_CONTEXT HwMac, __in PDOT11_RATE_SET RemoteRateSet, __in ULONG LinkQuality ) { PDOT11_RATE_SET operationalRateSet; PDOT11_RATE_SET activeRateSet; ULONG indexLocalRates; ULONG indexRemoteRates; USHORT maximumRate; OP_RATE_CHANGE_NOTIFICATION rateNotification; // The active rate set structure needs to be protected HW_ACQUIRE_HARDWARE_LOCK(HwMac->Hw, FALSE); // // Select the best rate supported by both AP and us. // operationalRateSet = &(HwMac->PhyContext[HwMac->OperatingPhyId].OperationalRateSet); activeRateSet = &(HwMac->PhyContext[HwMac->OperatingPhyId].ActiveRateSet); activeRateSet->uRateSetLength = 0; // // We merge the rates from the AP and the client to create the // currently active data rates table // for (indexLocalRates = 0; indexLocalRates < operationalRateSet->uRateSetLength; indexLocalRates++) { for (indexRemoteRates = 0; indexRemoteRates < RemoteRateSet->uRateSetLength; indexRemoteRates++) { if (operationalRateSet->ucRateSet[indexLocalRates] == (RemoteRateSet->ucRateSet[indexRemoteRates] & 0x7f)) { activeRateSet->ucRateSet[activeRateSet->uRateSetLength] = operationalRateSet->ucRateSet[indexLocalRates]; activeRateSet->uRateSetLength++; break; } } } // // If we dont find any rates, we will stick with our management packet rate // if (activeRateSet->uRateSetLength == 0) { activeRateSet->ucRateSet[0] = (UCHAR)HalGetBeaconRate(HwMac->Hw->Hal, HwMac->OperatingPhyId); activeRateSet->uRateSetLength = 1; } else if (activeRateSet->uRateSetLength > 1) { // bubble sort data rates in ascending order INT i, j; UCHAR temp; for (i = activeRateSet->uRateSetLength - 1; i >= 0; i--) { for (j = 1; j <= i; j++) { if (activeRateSet->ucRateSet[j - 1] > activeRateSet->ucRateSet[j]) { temp = activeRateSet->ucRateSet[j - 1]; activeRateSet->ucRateSet[j - 1] = activeRateSet->ucRateSet[j]; activeRateSet->ucRateSet[j] = temp; } } } } // // Now that the active rate set is populated and updated, select // the best rate // // // Determine what the maximum TX rate should be // maximumRate = HW11_MAX_DATA_RATE; // Start with max supported by HW if (LinkQuality < HW_LOW_RATE_LINK_QUALITY_THRESHOLD) { // // The link quality is low, we will go for the lower start rate instead of // the max supported. The hardware does rate fallback, so we pick // something that would cause the least number of retrys // maximumRate = HW_LOW_RATE_MAX_DATA_RATE; } // // Check if this is greater than max permitted value read from the registry // if (maximumRate > HwMac->Hw->RegInfo.MaximumTxRate) { maximumRate = (USHORT)HwMac->Hw->RegInfo.MaximumTxRate; } // // Now find the best matching rate between us and the AP // for (indexLocalRates = activeRateSet->uRateSetLength - 1; indexLocalRates > 0; indexLocalRates--) { // // Check for a rate supported by both us and the AP that is below the max we prefer to use // if (activeRateSet->ucRateSet[indexLocalRates] <= maximumRate) { // // Found the rate we want to use // break; } } HwMac->DefaultTXDataRate = activeRateSet->ucRateSet[indexLocalRates]; // Update our rate info table. In our current implementation this is not-per peer HwMac->RateInfo.CurrentTXDataRate = HwMac->DefaultTXDataRate; MpTrace(COMP_ASSOC, DBG_LOUD, ("TX Data rate: %d\n", HwMac->DefaultTXDataRate)); HW_RELEASE_HARDWARE_LOCK(HwMac->Hw, FALSE); // // Indicate NDIS_STATUS_LINK_STATE to inform the OS about the new // link speed // HwIndicateLinkSpeed(HwMac, HwMac->DefaultTXDataRate); // Indicate change of link speed to the port so that it // can take any necessary action rateNotification.Header.Type = NotificationOpRateChange; rateNotification.Header.Size = sizeof(OP_RATE_CHANGE_NOTIFICATION); rateNotification.Header.pSourceVNic = NULL; rateNotification.NewRate = HwMac->DefaultTXDataRate; rateNotification.OldRate = 0; rateNotification.LowestRate = FALSE; VNic11Notify(HwMac->VNic, &rateNotification); return (UCHAR)HwMac->DefaultTXDataRate; }
/* Tx rate adaptation algorithm: Preconditions to update tx data rate: 1) device is in connect state; 2)device has sent at least 100 data packets retransmitPercentage = (toal retry) / (total packets sent) if retransmit percentage <= threshold for rate increase which default to 35% if not sending at the highest rate if previously came down from higher rate and wait count < wait required increase wait count and exit else if not previously came down from higher rate reset wait required else leave wait required unchanged increase current tx rate to next higher rate, reset all other counters and exit if retransmit percentage >= threshold for roam which default to 350% if already send at the lowest rate try to roam to a better AP, reset all counters and exit else if there are at least fallback skip (which default to 3) lower data rates available reduce current tx rate to third lower data rate, reset all counters and exit else if current sending at second lowest rate set current tx rate to the lowest value, reset all counters and exit else fall through to following rate fallback handler if retransmit percentage >= threshold for rate fallback which default to 125% and not sending at the lowest rate if previously came up from lower rate double current wait required else reset wait required reduce current tx rate to next lower value, reset all other counters and exit */ VOID HwUpdateTxDataRate( __in PHW_MAC_CONTEXT MacContext ) { PDOT11_RATE_SET activeRateSet; PHW_RATE_INFO rateInfo = &MacContext->RateInfo; // We are not doing per peer rate adaptation ULONG rateIndex = 0; USHORT prevTxRate = 0; ULONG totalRetry = rateInfo->TotalRetryCount; ULONG totalSend = rateInfo->PacketsSentForTxRateCheck; ULONG retransmitPercentage = 0; OP_RATE_CHANGE_NOTIFICATION rateNotification; if (HW_TEST_MAC_CONTEXT_STATUS(MacContext, HW_MAC_CONTEXT_CANNOT_SEND_FLAGS) || !HW_TEST_MAC_CONTEXT_STATUS(MacContext, HW_MAC_CONTEXT_LINK_UP)) { // MAC context wont be sending to a peer. There isnt anything for us to do return; } // Check the send threshold if (totalSend < MacContext->Hw->RegInfo.MinPacketsSentForTxRateUpdate) { return; } // reset counters InterlockedExchange(&rateInfo->TotalRetryCount, 0); InterlockedExchange((LONG*)&rateInfo->PacketsSentForTxRateCheck, 0); // The active rate set structure needs to be protected HW_ACQUIRE_HARDWARE_LOCK(MacContext->Hw, FALSE); do { activeRateSet = &(MacContext->PhyContext[MacContext->OperatingPhyId].ActiveRateSet); for (rateIndex = 0; rateIndex < activeRateSet->uRateSetLength; rateIndex++) { if (rateInfo->CurrentTXDataRate == activeRateSet->ucRateSet[rateIndex]) { prevTxRate = rateInfo->CurrentTXDataRate; break; } } // prevTxRate equals 0 means rateInfo->CurrentTXDataRate // is not in activeRateSet->ucRateSet list if (prevTxRate == 0) { MpTrace(COMP_MISC, DBG_LOUD, ("Current TX data rate is not in active rate set\n")); break; } retransmitPercentage = totalRetry * 100 / totalSend; MpTrace(COMP_TESTING, DBG_TRACE, ("%s: retransmitPercentage=%d(%d/%d), waitCount=%d, " "waitRequired=%d, prevRate=%d\n", __FUNCTION__, retransmitPercentage, totalRetry, totalSend, rateInfo->TxRateIncreaseWaitCount, rateInfo->TxRateIncreaseWaitRequired, rateInfo->PrevTxDataRate)); if (retransmitPercentage <= MacContext->Hw->RegInfo.TxFailureThresholdForRateIncrease) { // Consider going up if (rateIndex < activeRateSet->uRateSetLength - 1) { if ((rateInfo->PrevTxDataRate == activeRateSet->ucRateSet[rateIndex + 1]) && (rateInfo->TxRateIncreaseWaitCount + 1 < rateInfo->TxRateIncreaseWaitRequired)) { // I just came down from the rate above me, i dont want to go up yet due to WaitRequired rateInfo->TxRateIncreaseWaitCount++; MpTrace(COMP_TESTING, DBG_TRACE, ("%s: WAIT before increasing Tx rate. retransmitPercentage=%d(%d/%d), " "waitCount=%d, waitRequired=%d, prevRate=%d\n", __FUNCTION__, retransmitPercentage, totalRetry, totalSend, rateInfo->TxRateIncreaseWaitCount, rateInfo->TxRateIncreaseWaitRequired, rateInfo->PrevTxDataRate)); } else { // 1. I came down rate above me and WaitCount >= WaitRequired // 2. I came up from rate below me, no need to wait for additional time if (rateInfo->PrevTxDataRate != activeRateSet->ucRateSet[rateIndex + 1]) { // Case 2 above rateInfo->TxRateIncreaseWaitRequired = 1; } else { // Case 1 above /** don't reset TxRateIncreaseWaitRequired as we need to double */ /** the value if fallback to the current rate again */ } rateInfo->PrevTxDataRate = rateInfo->CurrentTXDataRate; rateInfo->TxRateIncreaseWaitCount = 0; MpTrace(COMP_TESTING, DBG_TRACE, ("%s: increasing Tx data rate from %d to %d. " "retransmitPercentage = %d(%d/%d), waitCount=%d, waitRequired=%d, prevRate=%d\n", __FUNCTION__, rateInfo->CurrentTXDataRate, activeRateSet->ucRateSet[rateIndex + 1], retransmitPercentage, totalRetry, totalSend, rateInfo->TxRateIncreaseWaitCount, rateInfo->TxRateIncreaseWaitRequired, rateInfo->PrevTxDataRate)); rateInfo->CurrentTXDataRate = activeRateSet->ucRateSet[rateIndex + 1]; } } break; } if (retransmitPercentage >= MacContext->Hw->RegInfo.TxFailureThresholdForRoam) { ULONG rateSkipLevel = MacContext->Hw->RegInfo.TxDataRateFallbackSkipLevel; // Really large retry count, consider roaming if (rateIndex == 0) { // I am sending at the lowest rate. Either roam or disconnect. MpTrace(COMP_TESTING, DBG_TRACE, ("%s: too many retransmit happened while " "transmitting at the lowest data rate. Attempting to roam. " "retransmitPercentage=%d(%d/%d), waitCount=%d, waitRequired=%d, prevRate=%d", __FUNCTION__, retransmitPercentage, totalRetry, totalSend, rateInfo->TxRateIncreaseWaitCount, rateInfo->TxRateIncreaseWaitRequired, rateInfo->PrevTxDataRate)); // Our packets arent going through, jump up to using best data rate & // hopefully our packets will go through rateInfo->CurrentTXDataRate = activeRateSet->ucRateSet[activeRateSet->uRateSetLength - 1]; // reset counters rateInfo->PrevTxDataRate = 0; rateInfo->TxRateIncreaseWaitRequired = 1; rateInfo->TxRateIncreaseWaitCount = 0; break; } else if (rateIndex >= rateSkipLevel) { // try to go down three rates MpTrace(COMP_TESTING, DBG_TRACE, ("%s: too many retransmit happened. Reducing Tx rate from %d to %d.\n", __FUNCTION__, rateInfo->CurrentTXDataRate, activeRateSet->ucRateSet[rateIndex - rateSkipLevel])); rateInfo->CurrentTXDataRate = activeRateSet->ucRateSet[rateIndex - rateSkipLevel]; rateInfo->PrevTxDataRate = 0; rateInfo->TxRateIncreaseWaitRequired = 1; rateInfo->TxRateIncreaseWaitCount = 0; break; } else if (rateIndex != 1) { // set tx rate to the lowest rate MpTrace(COMP_TESTING, DBG_TRACE, ("%s: too many retransmit happened. Reducing Tx rate from " "%d to lowest %d.\n", __FUNCTION__, rateInfo->CurrentTXDataRate, activeRateSet->ucRateSet[0])); rateInfo->CurrentTXDataRate = activeRateSet->ucRateSet[0]; rateInfo->PrevTxDataRate = 0; rateInfo->TxRateIncreaseWaitRequired = 1; rateInfo->TxRateIncreaseWaitCount = 0; break; } else { // rateIndex equals to 1. this is the same as lowering tx rate by 1 level // which is what rate fallback handler does. fall through. } } if ((retransmitPercentage >= MacContext->Hw->RegInfo.TxFailureThresholdForRateFallback) && (rateIndex > 0)) { // consider going down. no need to wait for additional time if (rateInfo->PrevTxDataRate == activeRateSet->ucRateSet[rateIndex - 1]) { rateInfo->TxRateIncreaseWaitRequired *= 2; } else { rateInfo->TxRateIncreaseWaitRequired = 1; } rateInfo->PrevTxDataRate = rateInfo->CurrentTXDataRate; rateInfo->TxRateIncreaseWaitCount = 0; MpTrace(COMP_TESTING, DBG_TRACE, ("%s: reducing Tx data rate from %d to %d. " "retransmitPercentage=%d(%d/%d), waitCount=%d, waitRequired=%d, prevRate=%d\n", __FUNCTION__, rateInfo->CurrentTXDataRate, activeRateSet->ucRateSet[rateIndex - 1], retransmitPercentage, totalRetry, totalSend, rateInfo->TxRateIncreaseWaitCount, rateInfo->TxRateIncreaseWaitRequired, rateInfo->PrevTxDataRate)); rateInfo->CurrentTXDataRate = activeRateSet->ucRateSet[rateIndex - 1]; break; } } while (FALSE); HW_RELEASE_HARDWARE_LOCK(MacContext->Hw, FALSE); if (prevTxRate != rateInfo->CurrentTXDataRate) { // Indicate new link speed HwIndicateLinkSpeed(MacContext, rateInfo->CurrentTXDataRate); // Indicate change of link speed to the port so that it // can take any necessary action rateNotification.Header.Type = NotificationOpRateChange; rateNotification.Header.Size = sizeof(OP_RATE_CHANGE_NOTIFICATION); rateNotification.Header.pSourceVNic = NULL; rateNotification.NewRate = rateInfo->CurrentTXDataRate; rateNotification.OldRate = prevTxRate; if (rateIndex == 0) rateNotification.LowestRate = TRUE; else rateNotification.LowestRate = FALSE; VNic11Notify(MacContext->VNic, &rateNotification); } }