📄 if_ath.c.svn-base
字号:
/*- * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification. * 2. Redistributions in binary form must reproduce at minimum a disclaimer * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any * redistribution must be conditioned upon including a substantially * similar Disclaimer requirement for further binary redistribution. * 3. Neither the names of the above-listed copyright holders nor the names * of any contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU General Public License ("GPL") version 2 as published by the Free * Software Foundation. * * NO WARRANTY * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * * $Id$ *//* * Driver for the Atheros Wireless LAN controller. * * This software is derived from work of Atsushi Onoe; his contribution * is greatly appreciated. */#include "if_ath_debug.h"#include "opt_ah.h"#ifndef AUTOCONF_INCLUDED#include <linux/config.h>#endif#include <linux/version.h>#include <linux/module.h>#include <linux/init.h>#include <linux/skbuff.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/random.h>#include <linux/delay.h>#include <linux/cache.h>#include <linux/bitops.h>#include <linux/types.h>#include <linux/sysctl.h>#include <linux/proc_fs.h>#include <linux/if_arp.h>#include <linux/rtnetlink.h>#include <linux/time.h>#include <asm/uaccess.h>#include "if_ethersubr.h" /* for ETHER_IS_MULTICAST */#include "if_media.h"#include "if_llc.h"#include <net80211/ieee80211_radiotap.h>#include <net80211/ieee80211_var.h>#include <net80211/ieee80211_monitor.h>#include <net80211/ieee80211_rate.h>#ifdef USE_HEADERLEN_RESV#include <net80211/if_llc.h>#endif#include "net80211/if_athproto.h"#include "if_athvar.h"#include "ah_desc.h"#include "ah_devid.h" /* XXX to identify chipset */#ifdef ATH_PCI /* PCI BUS */#include "if_ath_pci.h"#endif /* PCI BUS */#ifdef ATH_AHB /* AHB BUS */#include "if_ath_ahb.h"#endif /* AHB BUS */#include "ah.h"#include "if_ath_hal.h"#include "if_ath_radar.h"#ifdef ATH_TX99_DIAG#include "ath_tx99.h"#endif#include "ah_os.h"#ifndef MAX# define MAX(a, b) (((a) > (b))? (a) : (b))#endif#ifndef MIN# define MIN(a, b) (((a) < (b))? (a) : (b))#endif/* unaligned little endian access */#define LE_READ_2(p) \ ((u_int16_t) \ ((((u_int8_t *)(p))[0] ) | (((u_int8_t *)(p))[1] << 8)))#define LE_READ_4(p) \ ((u_int32_t) \ ((((u_int8_t *)(p))[0] ) | (((u_int8_t *)(p))[1] << 8) | \ (((u_int8_t *)(p))[2] << 16) | (((u_int8_t *)(p))[3] << 24)))/* Default rate control algorithm */#ifdef CONFIG_ATHEROS_RATE_DEFAULT#define DEF_RATE_CTL CONFIG_ATHEROS_RATE_DEFAULT#else#define DEF_RATE_CTL "sample"#endifenum { ATH_LED_TX, ATH_LED_RX, ATH_LED_POLL,};static struct ieee80211vap *ath_vap_create(struct ieee80211com *, const char *, int, int, struct net_device *);static void ath_vap_delete(struct ieee80211vap *);static int ath_init(struct net_device *);static int ath_reset(struct net_device *);static void ath_fatal_tasklet(TQUEUE_ARG);static void ath_rxorn_tasklet(TQUEUE_ARG);static void ath_bmiss_tasklet(TQUEUE_ARG);static void ath_bstuck_tasklet(TQUEUE_ARG);static int ath_stop_locked(struct net_device *);static int ath_stop(struct net_device *);static ieee80211_keyix_t ath_key_alloc(struct ieee80211vap *, const struct ieee80211_key *);static int ath_key_delete(struct ieee80211vap *, const struct ieee80211_key *, struct ieee80211_node *);static int ath_key_set(struct ieee80211vap *, const struct ieee80211_key *, const u_int8_t mac[IEEE80211_ADDR_LEN]);static void ath_key_update_begin(struct ieee80211vap *);static void ath_key_update_end(struct ieee80211vap *);static void ath_mode_init(struct net_device *);static void ath_setslottime(struct ath_softc *);static void ath_setctstimeout(struct ath_softc *);static void ath_setacktimeout(struct ath_softc *);static void ath_updateslot(struct net_device *);static int ath_beaconq_setup(struct ath_softc *);static int ath_beacon_alloc(struct ath_softc *, struct ieee80211_node *);#ifdef ATH_SUPERG_DYNTURBOstatic void ath_beacon_dturbo_update(struct ieee80211vap *, int *, u_int8_t);static void ath_beacon_dturbo_config(struct ieee80211vap *, u_int32_t);static void ath_turbo_switch_mode(unsigned long);static int ath_check_beacon_done(struct ath_softc *);#endifstatic void ath_beacon_send(struct ath_softc *, int *, uint64_t hw_tsf);static void ath_beacon_return(struct ath_softc *, struct ath_buf *);static void ath_beacon_free(struct ath_softc *);static void ath_beacon_config(struct ath_softc *, struct ieee80211vap *);static int ath_desc_alloc(struct ath_softc *);static void ath_desc_free(struct ath_softc *);static struct ieee80211_node *ath_node_alloc(struct ieee80211vap *);static void ath_node_cleanup(struct ieee80211_node *);static void ath_node_free(struct ieee80211_node *);static u_int8_t ath_node_getrssi(const struct ieee80211_node *);static struct sk_buff *ath_rxbuf_take_skb(struct ath_softc *, struct ath_buf *);static int ath_rxbuf_init(struct ath_softc *, struct ath_buf *);static int ath_recv_mgmt(struct ieee80211vap *, struct ieee80211_node *, struct sk_buff *, int, int, u_int64_t);static void ath_setdefantenna(struct ath_softc *, u_int);static struct ath_txq *ath_txq_setup(struct ath_softc *, int, int);static void ath_rx_tasklet(TQUEUE_ARG);static int ath_hardstart(struct sk_buff *, struct net_device *);static int ath_mgtstart(struct ieee80211com *, struct sk_buff *);#ifdef ATH_SUPERG_COMPstatic u_int32_t ath_get_icvlen(struct ieee80211_key *);static u_int32_t ath_get_ivlen(struct ieee80211_key *);static void ath_setup_comp(struct ieee80211_node *, int);static void ath_comp_set(struct ieee80211vap *, struct ieee80211_node *, int);#endifstatic int ath_tx_setup(struct ath_softc *, int, int);static int ath_wme_update(struct ieee80211com *);static void ath_uapsd_flush(struct ieee80211_node *);static void ath_tx_cleanupq(struct ath_softc *, struct ath_txq *);static void ath_tx_cleanup(struct ath_softc *);static void ath_tx_uapsdqueue(struct ath_softc *, struct ath_node *, struct ath_buf *);static int ath_tx_start(struct net_device *, struct ieee80211_node *, struct ath_buf *, struct sk_buff *, int);static void ath_tx_tasklet_q0(TQUEUE_ARG);static void ath_tx_tasklet_q0123(TQUEUE_ARG);static void ath_tx_tasklet(TQUEUE_ARG);static void ath_tx_timeout(struct net_device *);static void ath_tx_draintxq(struct ath_softc *, struct ath_txq *);static int ath_chan_set(struct ath_softc *, struct ieee80211_channel *);static void ath_draintxq(struct ath_softc *);static void ath_tx_txqaddbuf(struct ath_softc *, struct ieee80211_node *, struct ath_txq *, struct ath_buf *, int);static void ath_stoprecv(struct ath_softc *);static int ath_startrecv(struct ath_softc *);static void ath_flushrecv(struct ath_softc *);static void ath_chan_change(struct ath_softc *, struct ieee80211_channel *);static void ath_calibrate(unsigned long);static int ath_newstate(struct ieee80211vap *, enum ieee80211_state, int);static void ath_scan_start(struct ieee80211com *);static void ath_scan_end(struct ieee80211com *);static void ath_set_channel(struct ieee80211com *);static void ath_set_coverageclass(struct ieee80211com *);static u_int ath_mhz2ieee(struct ieee80211com *, u_int, u_int);#ifdef ATH_SUPERG_FFstatic int athff_can_aggregate(struct ath_softc *, struct ether_header *, struct ath_node *, struct sk_buff *, u_int16_t, int *);#endifstatic struct net_device_stats *ath_getstats(struct net_device *);static void ath_setup_stationkey(struct ieee80211_node *);static void ath_setup_stationwepkey(struct ieee80211_node *);static void ath_setup_keycacheslot(struct ath_softc *, struct ieee80211_node *);static void ath_newassoc(struct ieee80211_node *, int);static int ath_getchannels(struct net_device *, u_int, HAL_BOOL, HAL_BOOL);static void ath_led_event(struct ath_softc *, int);static void ath_update_txpow(struct ath_softc *);#ifdef ATH_REVERSE_ENGINEERING/* Reverse engineering utility commands */static void ath_registers_dump(struct ieee80211com *ic);static void ath_registers_dump_delta(struct ieee80211com *ic);static void ath_registers_mark(struct ieee80211com *ic);static unsigned int ath_read_register(struct ieee80211com *ic, unsigned int address, unsigned int *value);static unsigned int ath_write_register(struct ieee80211com *ic, unsigned int address, unsigned int value);static void ath_ar5212_registers_dump(struct ath_softc *sc);#endif /* #ifdef ATH_REVERSE_ENGINEERING */static int ath_set_mac_address(struct net_device *, void *);static int ath_change_mtu(struct net_device *, int);static int ath_ioctl(struct net_device *, struct ifreq *, int);static int ath_rate_setup(struct net_device *, u_int);static void ath_setup_subrates(struct net_device *);#ifdef ATH_SUPERG_XRstatic int ath_xr_rate_setup(struct net_device *);static void ath_grppoll_txq_setup(struct ath_softc *, int, int);static void ath_grppoll_start(struct ieee80211vap *, int);static void ath_grppoll_stop(struct ieee80211vap *);static u_int8_t ath_node_move_data(const struct ieee80211_node *);static void ath_grppoll_txq_update(struct ath_softc *, int);static void ath_grppoll_period_update(struct ath_softc *);#endifstatic void ath_setcurmode(struct ath_softc *, enum ieee80211_phymode);static void ath_dynamic_sysctl_register(struct ath_softc *);static void ath_dynamic_sysctl_unregister(struct ath_softc *);static void ath_announce(struct net_device *);static int ath_descdma_setup(struct ath_softc *, struct ath_descdma *, ath_bufhead *, const char *, int, int);static void ath_descdma_cleanup(struct ath_softc *, struct ath_descdma *, ath_bufhead *, int);static const char *ath_get_hal_status_desc(HAL_STATUS status);static int ath_rcv_dev_event(struct notifier_block *, unsigned long, void *);static void ath_return_txbuf(struct ath_softc *sc, struct ath_buf **buf);static void ath_return_txbuf_locked(struct ath_softc *sc, struct ath_buf **buf);static void ath_return_txbuf_list(struct ath_softc *sc, ath_bufhead *bfhead);static void ath_return_txbuf_list_locked(struct ath_softc *sc, ath_bufhead *bfhead);static struct ath_buf *cleanup_ath_buf(struct ath_softc *sc, struct ath_buf *buf, int direction);/* Regulatory agency testing - continuous transmit support */static void txcont_on(struct ieee80211com *ic);static void txcont_off(struct ieee80211com *ic);static int ath_get_txcont(struct ieee80211com *);static void ath_set_txcont(struct ieee80211com *, int);static int ath_get_txcont_power(struct ieee80211com *);static void ath_set_txcont_power(struct ieee80211com *, unsigned int);static unsigned int ath_get_txcont_rate(struct ieee80211com *);static void ath_set_txcont_rate(struct ieee80211com *ic, unsigned int new_rate);/* 802.11h DFS support functions */static void ath_dfs_cac_completed(unsigned long);static void ath_interrupt_dfs_cac(struct ath_softc *sc, const char *reason);static inline int ath_chan_unavail(struct ath_softc *sc);#define ath_cac_running_dbgmsg(_sc) \ _ath_cac_running_dbgmsg((_sc), __func__)#define ath_chan_unavail_dbgmsg(_sc) \ _ath_chan_unavail_dbgmsg((_sc), __func__)static inline int _ath_cac_running_dbgmsg(struct ath_softc *sc, const char *func);static inline int _ath_chan_unavail_dbgmsg(struct ath_softc *sc, const char *func);/* 802.11h DFS testing functions */static int ath_get_dfs_testmode(struct ieee80211com *);static void ath_set_dfs_testmode(struct ieee80211com *, int);static unsigned int ath_get_dfs_excl_period(struct ieee80211com *);static void ath_set_dfs_excl_period(struct ieee80211com *, unsigned int seconds);static unsigned int ath_get_dfs_cac_time(struct ieee80211com *);static void ath_set_dfs_cac_time(struct ieee80211com *, unsigned int seconds);static unsigned int ath_test_radar(struct ieee80211com *);static unsigned int ath_dump_hal_map(struct ieee80211com *ic);static u_int32_t ath_get_clamped_maxtxpower(struct ath_softc *sc);static u_int32_t ath_set_clamped_maxtxpower(struct ath_softc *sc, u_int32_t new_clamped_maxtxpower);static void ath_scanbufs(struct ath_softc *sc);static int ath_debug_iwpriv(struct ieee80211com *ic, unsigned int param, unsigned int value);static u_int32_t ath_get_real_maxtxpower(struct ath_softc *sc);static int ath_txq_check(struct ath_softc *sc, struct ath_txq *txq, const char *msg);static int ath_countrycode = CTRY_DEFAULT; /* country code */static int ath_outdoor = AH_FALSE; /* enable outdoor use */static int ath_xchanmode = AH_TRUE; /* enable extended channels */static int ath_maxvaps = ATH_MAXVAPS_DEFAULT; /* set default maximum vaps */static char *autocreate = "sta";static char *ratectl = DEF_RATE_CTL;static int rfkill = 0;static int hal_tpc = 0;static int intmit = 0;static int countrycode = CTRY_DEFAULT;static int maxvaps = ATH_MAXVAPS_DEFAULT;static int outdoor = 0;static int xchanmode = 0;static int beacon_cal = 1;static const char *hal_status_desc[] = { "No error", "No hardware present or device not yet supported", "Memory allocation failed", "Hardware didn't respond as expected", "EEPROM magic number invalid", "EEPROM version invalid", "EEPROM unreadable", "EEPROM checksum invalid", "EEPROM read problem", "EEPROM mac address invalid", "EEPROM size not supported", "Attempt to change write-locked EEPROM", "Invalid parameter to function", "Hardware revision not supported", "Hardware self-test failed", "Operation incomplete"};static struct notifier_block ath_event_block = { .notifier_call = ath_rcv_dev_event};#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,52))MODULE_PARM(beacon_cal, "i");MODULE_PARM(countrycode, "i");MODULE_PARM(maxvaps, "i");MODULE_PARM(outdoor, "i");MODULE_PARM(xchanmode, "i");MODULE_PARM(rfkill, "i");#ifdef ATH_CAP_TPCMODULE_PARM(hal_tpc, "i");#endifMODULE_PARM(autocreate, "s");MODULE_PARM(ratectl, "s");MODULE_PARM(intmit, "i");#else#include <linux/moduleparam.h>module_param(beacon_cal, int, 0600);module_param(countrycode, int, 0600);module_param(maxvaps, int, 0600);module_param(outdoor, int, 0600);module_param(xchanmode, int, 0600);module_param(rfkill, int, 0600);#ifdef ATH_CAP_TPCmodule_param(hal_tpc, int, 0600);#endifmodule_param(autocreate, charp, 0600);module_param(ratectl, charp, 0600);module_param(intmit, int, 0600);#endifMODULE_PARM_DESC(countrycode, "Override default country code. Default is 0.");MODULE_PARM_DESC(maxvaps, "Maximum VAPs. Default is 4.");MODULE_PARM_DESC(outdoor, "Enable/disable outdoor use. Default is 0.");MODULE_PARM_DESC(xchanmode, "Enable/disable extended channel mode.");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -