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

📄 iwl-4965.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	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 + -