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

📄 iwl-4965.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/****************************************************************************** * * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * * Contact Information: * James P. Ketrenos <ipw2100-admin@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/#include <linux/kernel.h>#include <linux/module.h>#include <linux/version.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/dma-mapping.h>#include <linux/delay.h>#include <linux/skbuff.h>#include <linux/netdevice.h>#include <linux/wireless.h>#include <net/mac80211.h>#include <linux/etherdevice.h>#define IWL 4965#include "iwlwifi.h"#include "iwl-4965.h"#include "iwl-helpers.h"#define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np)    \	[IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP,      \				    IWL_RATE_SISO_##s##M_PLCP, \				    IWL_RATE_MIMO_##s##M_PLCP, \				    IWL_RATE_##r##M_IEEE,      \				    IWL_RATE_##ip##M_INDEX,    \				    IWL_RATE_##in##M_INDEX,    \				    IWL_RATE_##rp##M_INDEX,    \				    IWL_RATE_##rn##M_INDEX,    \				    IWL_RATE_##pp##M_INDEX,    \				    IWL_RATE_##np##M_INDEX }/* * Parameter order: *   rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate * * If there isn't a valid next or previous rate then INV is used which * maps to IWL_RATE_INVALID * */const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = {	IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2),    /*  1mbps */	IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5),          /*  2mbps */	IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11),        /*5.5mbps */	IWL_DECLARE_RATE_INFO(11, INV, 9, 12, 9, 12, 5, 18),      /* 11mbps */	IWL_DECLARE_RATE_INFO(6, 6, 5, 9, 5, 11, 5, 11),        /*  6mbps */	IWL_DECLARE_RATE_INFO(9, 6, 6, 11, 6, 11, 5, 11),       /*  9mbps */	IWL_DECLARE_RATE_INFO(12, 12, 11, 18, 11, 18, 11, 18),   /* 12mbps */	IWL_DECLARE_RATE_INFO(18, 18, 12, 24, 12, 24, 11, 24),   /* 18mbps */	IWL_DECLARE_RATE_INFO(24, 24, 18, 36, 18, 36, 18, 36),   /* 24mbps */	IWL_DECLARE_RATE_INFO(36, 36, 24, 48, 24, 48, 24, 48),   /* 36mbps */	IWL_DECLARE_RATE_INFO(48, 48, 36, 54, 36, 54, 36, 54),   /* 48mbps */	IWL_DECLARE_RATE_INFO(54, 54, 48, INV, 48, INV, 48, INV),/* 54mbps */	IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */};static int is_fat_channel(__le32 rxon_flags){	return (rxon_flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) ||		(rxon_flags & RXON_FLG_CHANNEL_MODE_MIXED_MSK);}static u8 is_single_stream(struct iwl_priv *priv){#ifdef CONFIG_IWLWIFI_HT	if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht ||	    (priv->active_rate_ht[1] == 0) ||	    (priv->ps_mode == IWL_MIMO_PS_STATIC))		return 1;#else	return 1;#endif	/*CONFIG_IWLWIFI_HT */	return 0;}/* * Determine how many receiver/antenna chains to use. * More provides better reception via diversity.  Fewer saves power. * MIMO (dual stream) requires at least 2, but works better with 3. * This does not determine *which* chains to use, just how many. */static int iwl4965_get_rx_chain_counter(struct iwl_priv *priv,					u8 *idle_state, u8 *rx_state){	u8 is_single = is_single_stream(priv);	u8 is_cam = test_bit(STATUS_POWER_PMI, &priv->status) ? 0 : 1;	/* # of Rx chains to use when expecting MIMO. */	if (is_single || (!is_cam && (priv->ps_mode == IWL_MIMO_PS_STATIC)))		*rx_state = 2;	else		*rx_state = 3;	/* # Rx chains when idling and maybe trying to save power */	switch (priv->ps_mode) {	case IWL_MIMO_PS_STATIC:	case IWL_MIMO_PS_DYNAMIC:		*idle_state = (is_cam) ? 2 : 1;		break;	case IWL_MIMO_PS_NONE:		*idle_state = (is_cam) ? *rx_state : 1;		break;	default:		*idle_state = 1;		break;	}	return 0;}int iwl_hw_rxq_stop(struct iwl_priv *priv){	int rc;	unsigned long flags;	spin_lock_irqsave(&priv->lock, flags);	rc = iwl_grab_restricted_access(priv);	if (rc) {		spin_unlock_irqrestore(&priv->lock, flags);		return rc;	}	/* stop HW */	iwl_write_restricted(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);	rc = iwl_poll_restricted_bit(priv, FH_MEM_RSSR_RX_STATUS_REG,				     (1 << 24), 1000);	if (rc < 0)		IWL_ERROR("Can't stop Rx DMA.\n");	iwl_release_restricted_access(priv);	spin_unlock_irqrestore(&priv->lock, flags);	return 0;}u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr){	int i;	int start = 0;	int ret = IWL_INVALID_STATION;	unsigned long flags;	DECLARE_MAC_BUF(mac);	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) ||	    (priv->iw_mode == IEEE80211_IF_TYPE_AP))		start = IWL_STA_ID;	if (is_broadcast_ether_addr(addr))		return IWL4965_BROADCAST_ID;	spin_lock_irqsave(&priv->sta_lock, flags);	for (i = start; i < priv->hw_setting.max_stations; i++)		if ((priv->stations[i].used) &&		    (!compare_ether_addr		     (priv->stations[i].sta.sta.addr, addr))) {			ret = i;			goto out;		}	IWL_DEBUG_ASSOC_LIMIT("can not find STA %s total %d\n",			print_mac(mac, addr), priv->num_stations); out:	spin_unlock_irqrestore(&priv->sta_lock, flags);	return ret;}static int iwl4965_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max){	int rc = 0;	unsigned long flags;	spin_lock_irqsave(&priv->lock, flags);	rc = iwl_grab_restricted_access(priv);	if (rc) {		spin_unlock_irqrestore(&priv->lock, flags);		return rc;	}	if (!pwr_max) {		u32 val;		rc = pci_read_config_dword(priv->pci_dev, PCI_POWER_SOURCE,					   &val);		if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT)			iwl_set_bits_mask_restricted_reg(				priv, APMG_PS_CTRL_REG,				APMG_PS_CTRL_VAL_PWR_SRC_VAUX,				~APMG_PS_CTRL_MSK_PWR_SRC);	} else		iwl_set_bits_mask_restricted_reg(			priv, APMG_PS_CTRL_REG,			APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,			~APMG_PS_CTRL_MSK_PWR_SRC);	iwl_release_restricted_access(priv);	spin_unlock_irqrestore(&priv->lock, flags);	return rc;}static int iwl4965_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq){	int rc;	unsigned long flags;	spin_lock_irqsave(&priv->lock, flags);	rc = iwl_grab_restricted_access(priv);	if (rc) {		spin_unlock_irqrestore(&priv->lock, flags);		return rc;	}	/* stop HW */	iwl_write_restricted(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);	iwl_write_restricted(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);	iwl_write_restricted(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG,			     rxq->dma_addr >> 8);	iwl_write_restricted(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG,			     (priv->hw_setting.shared_phys +			      offsetof(struct iwl_shared, val0)) >> 4);	iwl_write_restricted(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG,			     FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |			     FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |			     IWL_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K |			     /*0x10 << 4 | */			     (RX_QUEUE_SIZE_LOG <<			      FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT));	/*	 * iwl_write32(priv,CSR_INT_COAL_REG,0);	 */	iwl_release_restricted_access(priv);	spin_unlock_irqrestore(&priv->lock, flags);	return 0;}static int iwl4965_kw_init(struct iwl_priv *priv){	unsigned long flags;	int rc;	spin_lock_irqsave(&priv->lock, flags);	rc = iwl_grab_restricted_access(priv);	if (rc)		goto out;	iwl_write_restricted(priv, IWL_FH_KW_MEM_ADDR_REG,			     priv->kw.dma_addr >> 4);	iwl_release_restricted_access(priv);out:	spin_unlock_irqrestore(&priv->lock, flags);	return rc;}static int iwl4965_kw_alloc(struct iwl_priv *priv){	struct pci_dev *dev = priv->pci_dev;	struct iwl_kw *kw = &priv->kw;	kw->size = IWL4965_KW_SIZE;	/* TBW need set somewhere else */	kw->v_addr = pci_alloc_consistent(dev, kw->size, &kw->dma_addr);	if (!kw->v_addr)		return -ENOMEM;	return 0;}#define CHECK_AND_PRINT(x) ((eeprom_ch->flags & EEPROM_CHANNEL_##x) \			    ? # x " " : "")int iwl4965_set_fat_chan_info(struct iwl_priv *priv, int phymode, u16 channel,			      const struct iwl_eeprom_channel *eeprom_ch,			      u8 fat_extension_channel){	struct iwl_channel_info *ch_info;	ch_info = (struct iwl_channel_info *)			iwl_get_channel_info(priv, phymode, channel);	if (!is_channel_valid(ch_info))		return -1;	IWL_DEBUG_INFO("FAT Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x"			" %ddBm): Ad-Hoc %ssupported\n",			ch_info->channel,			is_channel_a_band(ch_info) ?			"5.2" : "2.4",			CHECK_AND_PRINT(IBSS),			CHECK_AND_PRINT(ACTIVE),			CHECK_AND_PRINT(RADAR),			CHECK_AND_PRINT(WIDE),			CHECK_AND_PRINT(NARROW),			CHECK_AND_PRINT(DFS),			eeprom_ch->flags,			eeprom_ch->max_power_avg,			((eeprom_ch->flags & EEPROM_CHANNEL_IBSS)			 && !(eeprom_ch->flags & EEPROM_CHANNEL_RADAR)) ?			"" : "not ");	ch_info->fat_eeprom = *eeprom_ch;	ch_info->fat_max_power_avg = eeprom_ch->max_power_avg;	ch_info->fat_curr_txpow = eeprom_ch->max_power_avg;	ch_info->fat_min_power = 0;	ch_info->fat_scan_power = eeprom_ch->max_power_avg;	ch_info->fat_flags = eeprom_ch->flags;	ch_info->fat_extension_channel = fat_extension_channel;	return 0;}static void iwl4965_kw_free(struct iwl_priv *priv){	struct pci_dev *dev = priv->pci_dev;	struct iwl_kw *kw = &priv->kw;	if (kw->v_addr) {		pci_free_consistent(dev, kw->size, kw->v_addr, kw->dma_addr);		memset(kw, 0, sizeof(*kw));	}}/** * iwl4965_txq_ctx_reset - Reset TX queue context * Destroys all DMA structures and initialise them again * * @param priv * @return error code */static int iwl4965_txq_ctx_reset(struct iwl_priv *priv){	int rc = 0;	int txq_id, slots_num;	unsigned long flags;	iwl4965_kw_free(priv);	iwl_hw_txq_ctx_free(priv);	/* Tx CMD queue */	rc = iwl4965_kw_alloc(priv);	if (rc) {		IWL_ERROR("Keep Warm allocation failed");		goto error_kw;	}	spin_lock_irqsave(&priv->lock, flags);	rc = iwl_grab_restricted_access(priv);	if (unlikely(rc)) {		IWL_ERROR("TX reset failed");		spin_unlock_irqrestore(&priv->lock, flags);		goto error_reset;	}	iwl_write_restricted_reg(priv, SCD_TXFACT, 0);	iwl_release_restricted_access(priv);	spin_unlock_irqrestore(&priv->lock, flags);	rc = iwl4965_kw_init(priv);	if (rc) {		IWL_ERROR("kw_init failed\n");		goto error_reset;	}	/* Tx queue(s) */	for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) {		slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?					TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;		rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,				       txq_id);		if (rc) {			IWL_ERROR("Tx %d queue init failed\n", txq_id);			goto error;		}	}	return rc; error:	iwl_hw_txq_ctx_free(priv); error_reset:	iwl4965_kw_free(priv); error_kw:	return rc;}int iwl_hw_nic_init(struct iwl_priv *priv){	int rc;	unsigned long flags;	struct iwl_rx_queue *rxq = &priv->rxq;	u8 rev_id;	u32 val;	u8 val_link;	iwl_power_init_handle(priv);	/* nic_init */	spin_lock_irqsave(&priv->lock, flags);	iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,		    CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);	iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);	rc = iwl_poll_bit(priv, CSR_GP_CNTRL,			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);	if (rc < 0) {		spin_unlock_irqrestore(&priv->lock, flags);		IWL_DEBUG_INFO("Failed to init the card\n");		return rc;	}	rc = iwl_grab_restricted_access(priv);	if (rc) {		spin_unlock_irqrestore(&priv->lock, flags);		return rc;	}	iwl_read_restricted_reg(priv, APMG_CLK_CTRL_REG);	iwl_write_restricted_reg(priv, APMG_CLK_CTRL_REG,				 APMG_CLK_VAL_DMA_CLK_RQT |				 APMG_CLK_VAL_BSM_CLK_RQT);	iwl_read_restricted_reg(priv, APMG_CLK_CTRL_REG);	udelay(20);	iwl_set_bits_restricted_reg(priv, APMG_PCIDEV_STT_REG,				    APMG_PCIDEV_STT_VAL_L1_ACT_DIS);	iwl_release_restricted_access(priv);	iwl_write32(priv, CSR_INT_COALESCING, 512 / 32);	spin_unlock_irqrestore(&priv->lock, flags);	/* Determine HW type */	rc = pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id);	if (rc)		return rc;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -