📄 iwl-4965.c
字号:
IWL_DEBUG_INFO("HW Revision ID = 0x%X\n", rev_id); iwl4965_nic_set_pwr_src(priv, 1); spin_lock_irqsave(&priv->lock, flags); if ((rev_id & 0x80) == 0x80 && (rev_id & 0x7f) < 8) { pci_read_config_dword(priv->pci_dev, PCI_REG_WUM8, &val); /* Enable No Snoop field */ pci_write_config_dword(priv->pci_dev, PCI_REG_WUM8, val & ~(1 << 11)); } spin_unlock_irqrestore(&priv->lock, flags); /* Read the EEPROM */ rc = iwl_eeprom_init(priv); if (rc) return rc; if (priv->eeprom.calib_version < EEPROM_TX_POWER_VERSION_NEW) { IWL_ERROR("Older EEPROM detected! Aborting.\n"); return -EINVAL; } pci_read_config_byte(priv->pci_dev, PCI_LINK_CTRL, &val_link); /* disable L1 entry -- workaround for pre-B1 */ pci_write_config_byte(priv->pci_dev, PCI_LINK_CTRL, val_link & ~0x02); spin_lock_irqsave(&priv->lock, flags); /* set CSR_HW_CONFIG_REG for uCode use */ iwl_set_bit(priv, CSR_SW_VER, CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R | CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); rc = iwl_grab_restricted_access(priv); if (rc < 0) { spin_unlock_irqrestore(&priv->lock, flags); IWL_DEBUG_INFO("Failed to init the card\n"); return rc; } iwl_read_restricted_reg(priv, APMG_PS_CTRL_REG); iwl_set_bits_restricted_reg(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); udelay(5); iwl_clear_bits_restricted_reg(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); iwl_release_restricted_access(priv); spin_unlock_irqrestore(&priv->lock, flags); iwl_hw_card_show_info(priv); /* end nic_init */ /* Allocate the RX queue, or reset if it is already allocated */ if (!rxq->bd) { rc = iwl_rx_queue_alloc(priv); if (rc) { IWL_ERROR("Unable to initialize Rx queue\n"); return -ENOMEM; } } else iwl_rx_queue_reset(priv, rxq); iwl_rx_replenish(priv); iwl4965_rx_init(priv, rxq); spin_lock_irqsave(&priv->lock, flags); rxq->need_update = 1; iwl_rx_queue_update_write_ptr(priv, rxq); spin_unlock_irqrestore(&priv->lock, flags); rc = iwl4965_txq_ctx_reset(priv); if (rc) return rc; if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_SW_RF_KILL_ENABLE) IWL_DEBUG_RF_KILL("SW RF KILL supported in EEPROM.\n"); if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_HW_RF_KILL_ENABLE) IWL_DEBUG_RF_KILL("HW RF KILL supported in EEPROM.\n"); set_bit(STATUS_INIT, &priv->status); return 0;}int iwl_hw_nic_stop_master(struct iwl_priv *priv){ int rc = 0; u32 reg_val; unsigned long flags; spin_lock_irqsave(&priv->lock, flags); /* set stop master bit */ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); reg_val = iwl_read32(priv, CSR_GP_CNTRL); if (CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE == (reg_val & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE)) IWL_DEBUG_INFO("Card in power save, master is already " "stopped\n"); else { rc = iwl_poll_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED, CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); if (rc < 0) { spin_unlock_irqrestore(&priv->lock, flags); return rc; } } spin_unlock_irqrestore(&priv->lock, flags); IWL_DEBUG_INFO("stop master\n"); return rc;}void iwl_hw_txq_ctx_stop(struct iwl_priv *priv){ int txq_id; unsigned long flags; /* reset TFD queues */ for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) { spin_lock_irqsave(&priv->lock, flags); if (iwl_grab_restricted_access(priv)) { spin_unlock_irqrestore(&priv->lock, flags); continue; } iwl_write_restricted(priv, IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), 0x0); iwl_poll_restricted_bit(priv, IWL_FH_TSSR_TX_STATUS_REG, IWL_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE (txq_id), 200); iwl_release_restricted_access(priv); spin_unlock_irqrestore(&priv->lock, flags); } iwl_hw_txq_ctx_free(priv);}int iwl_hw_nic_reset(struct iwl_priv *priv){ int rc = 0; unsigned long flags; iwl_hw_nic_stop_master(priv); spin_lock_irqsave(&priv->lock, flags); iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); udelay(10); iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); rc = iwl_poll_bit(priv, CSR_RESET, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25); udelay(10); rc = iwl_grab_restricted_access(priv); if (!rc) { iwl_write_restricted_reg(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT); udelay(10); iwl_set_bits_restricted_reg(priv, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_L1_ACT_DIS); iwl_release_restricted_access(priv); } clear_bit(STATUS_HCMD_ACTIVE, &priv->status); wake_up_interruptible(&priv->wait_command_queue); spin_unlock_irqrestore(&priv->lock, flags); return rc;}#define REG_RECALIB_PERIOD (60)/** * iwl4965_bg_statistics_periodic - Timer callback to queue statistics * * This callback is provided in order to queue the statistics_work * in work_queue context (v. softirq) * * This timer function is continually reset to execute within * REG_RECALIB_PERIOD seconds since the last STATISTICS_NOTIFICATION * was received. We need to ensure we receive the statistics in order * to update the temperature used for calibrating the TXPOWER. However, * we can't send the statistics command from softirq context (which * is the context which timers run at) so we have to queue off the * statistics_work to actually send the command to the hardware. */static void iwl4965_bg_statistics_periodic(unsigned long data){ struct iwl_priv *priv = (struct iwl_priv *)data; queue_work(priv->workqueue, &priv->statistics_work);}/** * iwl4965_bg_statistics_work - Send the statistics request to the hardware. * * This is queued by iwl_bg_statistics_periodic. */static void iwl4965_bg_statistics_work(struct work_struct *work){ struct iwl_priv *priv = container_of(work, struct iwl_priv, statistics_work); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; mutex_lock(&priv->mutex); iwl_send_statistics_request(priv); mutex_unlock(&priv->mutex);}#define CT_LIMIT_CONST 259#define TM_CT_KILL_THRESHOLD 110void iwl4965_rf_kill_ct_config(struct iwl_priv *priv){ struct iwl_ct_kill_config cmd; u32 R1, R2, R3; u32 temp_th; u32 crit_temperature; unsigned long flags; int rc = 0; spin_lock_irqsave(&priv->lock, flags); iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); spin_unlock_irqrestore(&priv->lock, flags); if (priv->statistics.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK) { R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[1]); R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[1]); R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[1]); } else { R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[0]); R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[0]); R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[0]); } temp_th = CELSIUS_TO_KELVIN(TM_CT_KILL_THRESHOLD); crit_temperature = ((temp_th * (R3-R1))/CT_LIMIT_CONST) + R2; cmd.critical_temperature_R = cpu_to_le32(crit_temperature); rc = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, sizeof(cmd), &cmd); if (rc) IWL_ERROR("REPLY_CT_KILL_CONFIG_CMD failed\n"); else IWL_DEBUG_INFO("REPLY_CT_KILL_CONFIG_CMD succeeded\n");}#ifdef CONFIG_IWLWIFI_SENSITIVITY/* "false alarms" are signals that our DSP tries to lock onto, * but then determines that they are either noise, or transmissions * from a distant wireless network (also "noise", really) that get * "stepped on" by stronger transmissions within our own network. * This algorithm attempts to set a sensitivity level that is high * enough to receive all of our own network traffic, but not so * high that our DSP gets too busy trying to lock onto non-network * activity/noise. */static int iwl4965_sens_energy_cck(struct iwl_priv *priv, u32 norm_fa, u32 rx_enable_time, struct statistics_general_data *rx_info){ u32 max_nrg_cck = 0; int i = 0; u8 max_silence_rssi = 0; u32 silence_ref = 0; u8 silence_rssi_a = 0; u8 silence_rssi_b = 0; u8 silence_rssi_c = 0; u32 val; /* "false_alarms" values below are cross-multiplications to assess the * numbers of false alarms within the measured period of actual Rx * (Rx is off when we're txing), vs the min/max expected false alarms * (some should be expected if rx is sensitive enough) in a * hypothetical listening period of 200 time units (TU), 204.8 msec: * * MIN_FA/fixed-time < false_alarms/actual-rx-time < MAX_FA/beacon-time * * */ u32 false_alarms = norm_fa * 200 * 1024; u32 max_false_alarms = MAX_FA_CCK * rx_enable_time; u32 min_false_alarms = MIN_FA_CCK * rx_enable_time; struct iwl_sensitivity_data *data = NULL; data = &(priv->sensitivity_data); data->nrg_auto_corr_silence_diff = 0; /* Find max silence rssi among all 3 receivers. * This is background noise, which may include transmissions from other * networks, measured during silence before our network's beacon */ silence_rssi_a = (u8)((rx_info->beacon_silence_rssi_a & ALL_BAND_FILTER)>>8); silence_rssi_b = (u8)((rx_info->beacon_silence_rssi_b & ALL_BAND_FILTER)>>8); silence_rssi_c = (u8)((rx_info->beacon_silence_rssi_c & ALL_BAND_FILTER)>>8); val = max(silence_rssi_b, silence_rssi_c); max_silence_rssi = max(silence_rssi_a, (u8) val); /* Store silence rssi in 20-beacon history table */ data->nrg_silence_rssi[data->nrg_silence_idx] = max_silence_rssi; data->nrg_silence_idx++; if (data->nrg_silence_idx >= NRG_NUM_PREV_STAT_L) data->nrg_silence_idx = 0; /* Find max silence rssi across 20 beacon history */ for (i = 0; i < NRG_NUM_PREV_STAT_L; i++) { val = data->nrg_silence_rssi[i]; silence_ref = max(silence_ref, val); } IWL_DEBUG_CALIB("silence a %u, b %u, c %u, 20-bcn max %u\n", silence_rssi_a, silence_rssi_b, silence_rssi_c, silence_ref); /* Find max rx energy (min value!) among all 3 receivers, * measured during beacon frame. * Save it in 10-beacon history table. */ i = data->nrg_energy_idx; val = min(rx_info->beacon_energy_b, rx_info->beacon_energy_c); data->nrg_value[i] = min(rx_info->beacon_energy_a, val); data->nrg_energy_idx++; if (data->nrg_energy_idx >= 10) data->nrg_energy_idx = 0; /* Find min rx energy (max value) across 10 beacon history. * This is the minimum signal level that we want to receive well. * Add backoff (margin so we don't miss slightly lower energy frames). * This establishes an upper bound (min value) for energy threshold. */ max_nrg_cck = data->nrg_value[0]; for (i = 1; i < 10; i++) max_nrg_cck = (u32) max(max_nrg_cck, (data->nrg_value[i])); max_nrg_cck += 6; IWL_DEBUG_CALIB("rx energy a %u, b %u, c %u, 10-bcn max/min %u\n", rx_info->beacon_energy_a, rx_info->beacon_energy_b, rx_info->beacon_energy_c, max_nrg_cck - 6); /* Count number of consecutive beacons with fewer-than-desired * false alarms. */ if (false_alarms < min_false_alarms) data->num_in_cck_no_fa++; else data->num_in_cck_no_fa = 0; IWL_DEBUG_CALIB("consecutive bcns with few false alarms = %u\n", data->num_in_cck_no_fa); /* If we got too many false alarms this time, reduce sensitivity */ if (false_alarms > max_false_alarms) { IWL_DEBUG_CALIB("norm FA %u > max FA %u\n", false_alarms, max_false_alarms); IWL_DEBUG_CALIB("... reducing sensitivity\n"); data->nrg_curr_state = IWL_FA_TOO_MANY; if (data->auto_corr_cck > AUTO_CORR_MAX_TH_CCK) { /* Store for "fewer than desired" on later beacon */ data->nrg_silence_ref = silence_ref; /* increase energy threshold (reduce nrg value) * to decrease sensitivity */ if (data->nrg_th_cck > (NRG_MAX_CCK + NRG_STEP_CCK)) data->nrg_th_cck = data->nrg_th_cck - NRG_STEP_CCK; } /* increase auto_corr values to decrease sensitivity */ if (data->auto_corr_cck < AUTO_CORR_MAX_TH_CCK) data->auto_corr_cck = AUTO_CORR_MAX_TH_CCK + 1; else { val = data->auto_corr_cck + AUTO_CORR_STEP_CCK; data->auto_corr_cck = min((u32)AUTO_CORR_MAX_CCK, val); } val = data->auto_corr_cck_mrc + AUTO_CORR_STEP_CCK; data->auto_corr_cck_mrc = min((u32)AUTO_CORR_MAX_CCK_MRC, val); /* Else if we got fewer than desired, increase sensitivity */ } else if (false_alarms < min_false_alarms) { data->nrg_curr_state = IWL_FA_TOO_FEW; /* Compare silence level with silence level for most recent * healthy number or too many false alarms */ data->nrg_auto_corr_silence_diff = (s32)data->nrg_silence_ref - (s32)silence_ref; IWL_DEBUG_CALIB("norm FA %u < min FA %u, silence diff %d\n", false_alarms, min_false_alarms, data->nrg_auto_corr_silence_diff); /* Increase value to increase sensitivity, but only if: * 1a) previous beacon did *not* have *too many* false alarms * 1b) AND there's a significant difference in Rx levels * from a previous beacon with too many, or healthy # FAs * OR 2) We've seen a lot of beacons (100) with too few * false alarms */ if ((data->nrg_prev_state != IWL_FA_TOO_MANY) && ((data->nrg_auto_corr_silence_diff > NRG_DIFF) || (data->num_in_cck_no_fa > MAX_NUMBER_CCK_NO_FA))) { IWL_DEBUG_CALIB("... increasing sensitivity\n"); /* Increase nrg value to increase sensitivity */ val = data->nrg_th_cck + NRG_STEP_CCK; data->nrg_th_cck = min((u32)NRG_MIN_CCK, val); /* Decrease auto_corr values to increase sensitivity */ val = data->auto_corr_cck - AUTO_CORR_STEP_CCK; data->auto_corr_cck = max((u32)AUTO_CORR_MIN_CCK, val); val = data->auto_corr_cck_mrc - AUTO_CORR_STEP_CCK; data->auto_corr_cck_mrc = max((u32)AUTO_CORR_MIN_CCK_MRC, val); } else IWL_DEBUG_CALIB("... but not changing sensitivity\n"); /* Else we got a healthy number of false alarms, keep status quo */ } else { IWL_DEBUG_CALIB(" FA in safe zone\n"); data->nrg_curr_state = IWL_FA_GOOD_RANGE; /* Store for use in "fewer than desired" with later beacon */ data->nrg_silence_ref = silence_ref; /* If previous beacon had too many false alarms, * give it some extra margin by reducing sensitivity again * (but don't go below measured energy of desired Rx) */ if (IWL_FA_TOO_MANY == data->nrg_prev_state) { IWL_DEBUG_CALIB("... increasing margin\n"); data->nrg_th_cck -= NRG_MARGIN; } } /* Make sure the energy threshold does not go above the measured * energy of the desired Rx signals (reduced by backoff margin), * or else we might start missing Rx frames. * Lower value is higher energy, so we use max()! */ data->nrg_th_cck = max(max_nrg_cck, data->nrg_th_cck); IWL_DEBUG_CALIB("new nrg_th_cck %u\n", data->nrg_th_cck); data->nrg_prev_state = data->nrg_curr_state;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -