Thread: [Madwifi-cvs] revision 2698 committed
Status: Beta
Brought to you by:
otaku
From: Nick K. <svn...@ma...> - 2007-08-31 02:54:28
|
Project : madwifi Revision : 2698 Author : mickflemm (Nick Kossifidis) Date : 2007-08-31 04:54:16 +0200 (Fri, 31 Aug 2007) Log Message : * Sorted functions inside ath5k_base.c in sections for better readability. * Cleaned unused fields/definitions * Use ath5k_ prefix instead of ath_ * Removed sysctl stuff along with countrycode/outdoor/xchanmode etc * Added hw info message during init * Some other minor cleanups Affected Files: * branches/ath5k/ath5k.h updated * branches/ath5k/ath5k_base.c updated * branches/ath5k/ath5k_base.h updated * branches/ath5k/ath5k_hw.c updated * branches/ath5k/ath5k_hw_inivals.c updated * branches/ath5k/ath5k_hw_phy.c updated Modified: branches/ath5k/ath5k.h =================================================================== --- branches/ath5k/ath5k.h 2007-08-30 11:55:21 UTC (rev 2697) +++ branches/ath5k/ath5k.h 2007-08-31 02:54:16 UTC (rev 2698) @@ -9,16 +9,6 @@ #ifndef _ATH5K_H #define _ATH5K_H -/* Set this to 1 to disable regulatory domain restrictions for channel tests. - * WARNING: This is for debuging only and has side effects (eg. scan takes too - * long and results timeouts). It's also illegal to tune to some of the - * supported frequencies in some countries, so use this at your own risk, - * you've been warned. */ -#define CHAN_DEBUG 0 - -/* Uncomment this for debuging (warning that it results in TOO much output) */ -/*#define AR5K_DEBUG 1 */ - #include <linux/types.h> #include <asm/io.h> #include <net/mac80211.h> @@ -126,6 +116,38 @@ /* * Common silicon revision/version values */ +/* + * Common silicon revision/version values + */ +enum ath5k_srev_type { + AR5K_VERSION_VER, + AR5K_VERSION_RAD, +}; + +struct ath5k_srev_name { + const char *sr_name; + enum ath5k_srev_type sr_type; + u_int sr_val; +}; + +#define AR5K_SREV_NAME { \ + { "5210 ", AR5K_VERSION_VER, AR5K_SREV_VER_AR5210 }, \ + { "5311 ", AR5K_VERSION_VER, AR5K_SREV_VER_AR5311 }, \ + { "5311a", AR5K_VERSION_VER, AR5K_SREV_VER_AR5311A },\ + { "5311b", AR5K_VERSION_VER, AR5K_SREV_VER_AR5311B },\ + { "5211 ", AR5K_VERSION_VER, AR5K_SREV_VER_AR5211 }, \ + { "5212 ", AR5K_VERSION_VER, AR5K_SREV_VER_AR5212 }, \ + { "5213 ", AR5K_VERSION_VER, AR5K_SREV_VER_AR5213 }, \ + { "xxxxx", AR5K_VERSION_VER, AR5K_SREV_UNKNOWN }, \ + { "5110 ", AR5K_VERSION_RAD, AR5K_SREV_RAD_5110 }, \ + { "5111 ", AR5K_VERSION_RAD, AR5K_SREV_RAD_5111 }, \ + { "2111 ", AR5K_VERSION_RAD, AR5K_SREV_RAD_2111 }, \ + { "5112 ", AR5K_VERSION_RAD, AR5K_SREV_RAD_5112 }, \ + { "5112a", AR5K_VERSION_RAD, AR5K_SREV_RAD_5112A }, \ + { "2112 ", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112 }, \ + { "2112a", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112A }, \ + { "xxxxx", AR5K_VERSION_RAD, AR5K_SREV_UNKNOWN }, \ +} #define AR5K_SREV_UNKNOWN 0xffff #define AR5K_SREV_VER_AR5210 0x00 @@ -256,10 +278,9 @@ s32 tqi_cw_min; /* Minimum Contention Window */ s32 tqi_cw_max; /* Maximum Contention Window */ u32 tqi_cbr_period; /* Constant bit rate period */ - u32 tqi_cbr_overflow_limit; - u32 tqi_burst_time; - u32 tqi_ready_time; /* Not used */ - u32 tqi_comp_buffer;/* Compression Buffer's phys addr */ + u32 tqi_cbr_overflow_limit; /* XXX: Not used */ + u32 tqi_burst_time; /* XXX: Not used */ + u32 tqi_ready_time; /* XXX: Not used */ }; /* @@ -457,7 +478,7 @@ /* * Atheros descriptor */ -struct ath_desc { +struct ath5k_desc { u32 ds_link; u32 ds_data; u32 ds_ctl0; @@ -632,7 +653,6 @@ /* * Crypto definitions */ - #define AR5K_KEYCACHE_SIZE 8 /***********************\ @@ -806,7 +826,7 @@ #define AR5K_MAX_GPIO 10 #define AR5K_MAX_RF_BANKS 8 -struct ath_hw { +struct ath5k_hw { u32 ah_magic; void *ah_sc; @@ -887,17 +907,17 @@ /* * Function pointers */ - int (*ah_setup_tx_desc)(struct ath_hw *, struct ath_desc *, + int (*ah_setup_tx_desc)(struct ath5k_hw *, struct ath5k_desc *, unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); - bool (*ah_setup_xtx_desc)(struct ath_hw *, struct ath_desc *, + bool (*ah_setup_xtx_desc)(struct ath5k_hw *, struct ath5k_desc *, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); - int (*ah_fill_tx_desc)(struct ath_hw *, struct ath_desc *, + int (*ah_fill_tx_desc)(struct ath5k_hw *, struct ath5k_desc *, unsigned int, bool, bool); - int (*ah_proc_tx_desc)(struct ath_hw *, struct ath_desc *); - int (*ah_proc_rx_desc)(struct ath_hw *, struct ath_desc *); + int (*ah_proc_tx_desc)(struct ath5k_hw *, struct ath5k_desc *); + int (*ah_proc_rx_desc)(struct ath5k_hw *, struct ath5k_desc *); }; /* @@ -905,121 +925,121 @@ */ /* General Functions */ -extern int ath5k_hw_register_timeout(struct ath_hw *hal, u32 reg, u32 flag, u32 val, bool is_set); +extern int ath5k_hw_register_timeout(struct ath5k_hw *hal, u32 reg, u32 flag, u32 val, bool is_set); /* Attach/Detach Functions */ -extern struct ath_hw *ath5k_hw_attach(u16 device, u8 mac_version, void *sc, void __iomem *sh); -extern const struct ath5k_rate_table *ath5k_hw_get_rate_table(struct ath_hw *hal, unsigned int mode); -extern void ath5k_hw_detach(struct ath_hw *hal); +extern struct ath5k_hw *ath5k_hw_attach(u16 device, u8 mac_version, void *sc, void __iomem *sh); +extern const struct ath5k_rate_table *ath5k_hw_get_rate_table(struct ath5k_hw *hal, unsigned int mode); +extern void ath5k_hw_detach(struct ath5k_hw *hal); /* Reset Functions */ -extern int ath5k_hw_reset(struct ath_hw *hal, enum ieee80211_if_types op_mode, struct ieee80211_channel *channel, bool change_channel); +extern int ath5k_hw_reset(struct ath5k_hw *hal, enum ieee80211_if_types op_mode, struct ieee80211_channel *channel, bool change_channel); /* Power management functions */ -extern int ath5k_hw_set_power(struct ath_hw *hal, enum ath5k_power_mode mode, bool set_chip, u16 sleep_duration); +extern int ath5k_hw_set_power(struct ath5k_hw *hal, enum ath5k_power_mode mode, bool set_chip, u16 sleep_duration); /* DMA Related Functions */ -extern void ath5k_hw_start_rx(struct ath_hw *hal); -extern int ath5k_hw_stop_rx_dma(struct ath_hw *hal); -extern u32 ath5k_hw_get_rx_buf(struct ath_hw *hal); -extern void ath5k_hw_put_rx_buf(struct ath_hw *hal, u32 phys_addr); -extern int ath5k_hw_tx_start(struct ath_hw *hal, unsigned int queue); -extern int ath5k_hw_stop_tx_dma(struct ath_hw *hal, unsigned int queue); -extern u32 ath5k_hw_get_tx_buf(struct ath_hw *hal, unsigned int queue); -extern int ath5k_hw_put_tx_buf(struct ath_hw *hal, unsigned int queue, u32 phys_addr); -extern int ath5k_hw_update_tx_triglevel(struct ath_hw *hal, bool increase); +extern void ath5k_hw_start_rx(struct ath5k_hw *hal); +extern int ath5k_hw_stop_rx_dma(struct ath5k_hw *hal); +extern u32 ath5k_hw_get_rx_buf(struct ath5k_hw *hal); +extern void ath5k_hw_put_rx_buf(struct ath5k_hw *hal, u32 phys_addr); +extern int ath5k_hw_tx_start(struct ath5k_hw *hal, unsigned int queue); +extern int ath5k_hw_stop_tx_dma(struct ath5k_hw *hal, unsigned int queue); +extern u32 ath5k_hw_get_tx_buf(struct ath5k_hw *hal, unsigned int queue); +extern int ath5k_hw_put_tx_buf(struct ath5k_hw *hal, unsigned int queue, u32 phys_addr); +extern int ath5k_hw_update_tx_triglevel(struct ath5k_hw *hal, bool increase); /* Interrupt handling */ -extern bool ath5k_hw_is_intr_pending(struct ath_hw *hal); -extern int ath5k_hw_get_isr(struct ath_hw *hal, enum ath5k_int *interrupt_mask); -extern enum ath5k_int ath5k_hw_set_intr(struct ath_hw *hal, enum ath5k_int new_mask); +extern bool ath5k_hw_is_intr_pending(struct ath5k_hw *hal); +extern int ath5k_hw_get_isr(struct ath5k_hw *hal, enum ath5k_int *interrupt_mask); +extern enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *hal, enum ath5k_int new_mask); /* EEPROM access functions */ -extern int ath5k_hw_set_regdomain(struct ath_hw *hal, u16 regdomain); +extern int ath5k_hw_set_regdomain(struct ath5k_hw *hal, u16 regdomain); /* Protocol Control Unit Functions */ -extern int ath5k_hw_set_opmode(struct ath_hw *hal); +extern int ath5k_hw_set_opmode(struct ath5k_hw *hal); /* BSSID Functions */ -extern void ath5k_hw_get_lladdr(struct ath_hw *hal, u8 *mac); -extern int ath5k_hw_set_lladdr(struct ath_hw *hal, const u8 *mac); -extern void ath5k_hw_set_associd(struct ath_hw *hal, const u8 *bssid, u16 assoc_id); -extern int ath5k_hw_set_bssid_mask(struct ath_hw *hal, const u8 *mask); +extern void ath5k_hw_get_lladdr(struct ath5k_hw *hal, u8 *mac); +extern int ath5k_hw_set_lladdr(struct ath5k_hw *hal, const u8 *mac); +extern void ath5k_hw_set_associd(struct ath5k_hw *hal, const u8 *bssid, u16 assoc_id); +extern int ath5k_hw_set_bssid_mask(struct ath5k_hw *hal, const u8 *mask); /* Receive start/stop functions */ -extern void ath5k_hw_start_rx_pcu(struct ath_hw *hal); -extern void ath5k_hw_stop_pcu_recv(struct ath_hw *hal); +extern void ath5k_hw_start_rx_pcu(struct ath5k_hw *hal); +extern void ath5k_hw_stop_pcu_recv(struct ath5k_hw *hal); /* RX Filter functions */ -extern void ath5k_hw_set_mcast_filter(struct ath_hw *hal, u32 filter0, u32 filter1); -extern int ath5k_hw_set_mcast_filterindex(struct ath_hw *hal, u32 index); -extern int ath5k_hw_clear_mcast_filter_idx(struct ath_hw *hal, u32 index); -extern u32 ath5k_hw_get_rx_filter(struct ath_hw *ah); -extern void ath5k_hw_set_rx_filter(struct ath_hw *ah, u32 filter); +extern void ath5k_hw_set_mcast_filter(struct ath5k_hw *hal, u32 filter0, u32 filter1); +extern int ath5k_hw_set_mcast_filterindex(struct ath5k_hw *hal, u32 index); +extern int ath5k_hw_clear_mcast_filter_idx(struct ath5k_hw *hal, u32 index); +extern u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah); +extern void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter); /* Beacon related functions */ -extern u32 ath5k_hw_get_tsf32(struct ath_hw *hal); -extern u64 ath5k_hw_get_tsf64(struct ath_hw *hal); -extern void ath5k_hw_reset_tsf(struct ath_hw *hal); -extern void ath5k_hw_init_beacon(struct ath_hw *hal, u32 next_beacon, u32 interval); -extern int ath5k_hw_set_beacon_timers(struct ath_hw *hal, const struct ath5k_beacon_state *state); -extern void ath5k_hw_reset_beacon(struct ath_hw *hal); -extern int ath5k_hw_wait_for_beacon(struct ath_hw *hal, unsigned long phys_addr); -extern void ath5k_hw_update_mib_counters(struct ath_hw *hal, struct ath5k_mib_stats *statistics); +extern u32 ath5k_hw_get_tsf32(struct ath5k_hw *hal); +extern u64 ath5k_hw_get_tsf64(struct ath5k_hw *hal); +extern void ath5k_hw_reset_tsf(struct ath5k_hw *hal); +extern void ath5k_hw_init_beacon(struct ath5k_hw *hal, u32 next_beacon, u32 interval); +extern int ath5k_hw_set_beacon_timers(struct ath5k_hw *hal, const struct ath5k_beacon_state *state); +extern void ath5k_hw_reset_beacon(struct ath5k_hw *hal); +extern int ath5k_hw_wait_for_beacon(struct ath5k_hw *hal, unsigned long phys_addr); +extern void ath5k_hw_update_mib_counters(struct ath5k_hw *hal, struct ath5k_mib_stats *statistics); /* ACK/CTS Timeouts */ -extern int ath5k_hw_set_ack_timeout(struct ath_hw *hal, unsigned int timeout); -extern unsigned int ath5k_hw_get_ack_timeout(struct ath_hw *hal); -extern int ath5k_hw_set_cts_timeout(struct ath_hw *hal, unsigned int timeout); -extern unsigned int ath5k_hw_get_cts_timeout(struct ath_hw *hal); +extern int ath5k_hw_set_ack_timeout(struct ath5k_hw *hal, unsigned int timeout); +extern unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *hal); +extern int ath5k_hw_set_cts_timeout(struct ath5k_hw *hal, unsigned int timeout); +extern unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *hal); /* Key table (WEP) functions */ -extern int ath5k_hw_reset_key(struct ath_hw *hal, u16 entry); -extern int ath5k_hw_is_key_valid(struct ath_hw *hal, u16 entry); -extern int ath5k_hw_set_key(struct ath_hw *hal, u16 entry, const struct ieee80211_key_conf *key, const u8 *mac); -extern int ath5k_hw_set_key_lladdr(struct ath_hw *hal, u16 entry, const u8 *mac); +extern int ath5k_hw_reset_key(struct ath5k_hw *hal, u16 entry); +extern int ath5k_hw_is_key_valid(struct ath5k_hw *hal, u16 entry); +extern int ath5k_hw_set_key(struct ath5k_hw *hal, u16 entry, const struct ieee80211_key_conf *key, const u8 *mac); +extern int ath5k_hw_set_key_lladdr(struct ath5k_hw *hal, u16 entry, const u8 *mac); /* Queue Control Unit, DFS Control Unit Functions */ -extern int ath5k_hw_setup_tx_queue(struct ath_hw *hal, enum ath5k_tx_queue queue_type, struct ath5k_txq_info *queue_info); -extern int ath5k_hw_setup_tx_queueprops(struct ath_hw *hal, int queue, const struct ath5k_txq_info *queue_info); -extern int ath5k_hw_get_tx_queueprops(struct ath_hw *hal, int queue, struct ath5k_txq_info *queue_info); -extern void ath5k_hw_release_tx_queue(struct ath_hw *hal, unsigned int queue); -extern int ath5k_hw_reset_tx_queue(struct ath_hw *hal, unsigned int queue); -extern u32 ath5k_hw_num_tx_pending(struct ath_hw *hal, unsigned int queue); -extern int ath5k_hw_set_slot_time(struct ath_hw *hal, unsigned int slot_time); -extern unsigned int ath5k_hw_get_slot_time(struct ath_hw *hal); +extern int ath5k_hw_setup_tx_queue(struct ath5k_hw *hal, enum ath5k_tx_queue queue_type, struct ath5k_txq_info *queue_info); +extern int ath5k_hw_setup_tx_queueprops(struct ath5k_hw *hal, int queue, const struct ath5k_txq_info *queue_info); +extern int ath5k_hw_get_tx_queueprops(struct ath5k_hw *hal, int queue, struct ath5k_txq_info *queue_info); +extern void ath5k_hw_release_tx_queue(struct ath5k_hw *hal, unsigned int queue); +extern int ath5k_hw_reset_tx_queue(struct ath5k_hw *hal, unsigned int queue); +extern u32 ath5k_hw_num_tx_pending(struct ath5k_hw *hal, unsigned int queue); +extern int ath5k_hw_set_slot_time(struct ath5k_hw *hal, unsigned int slot_time); +extern unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *hal); /* Hardware Descriptor Functions */ -extern int ath5k_hw_setup_rx_desc(struct ath_hw *hal, struct ath_desc *desc, u32 size, unsigned int flags); +extern int ath5k_hw_setup_rx_desc(struct ath5k_hw *hal, struct ath5k_desc *desc, u32 size, unsigned int flags); /* GPIO Functions */ -extern void ath5k_hw_set_ledstate(struct ath_hw *hal, unsigned int state); -extern int ath5k_hw_set_gpio_output(struct ath_hw *hal, u32 gpio); -extern int ath5k_hw_set_gpio_input(struct ath_hw *hal, u32 gpio); -extern u32 ath5k_hw_get_gpio(struct ath_hw *hal, u32 gpio); -extern int ath5k_hw_set_gpio(struct ath_hw *hal, u32 gpio, u32 val); -extern void ath5k_hw_set_gpio_intr(struct ath_hw *hal, unsigned int gpio, u32 interrupt_level); +extern void ath5k_hw_set_ledstate(struct ath5k_hw *hal, unsigned int state); +extern int ath5k_hw_set_gpio_output(struct ath5k_hw *hal, u32 gpio); +extern int ath5k_hw_set_gpio_input(struct ath5k_hw *hal, u32 gpio); +extern u32 ath5k_hw_get_gpio(struct ath5k_hw *hal, u32 gpio); +extern int ath5k_hw_set_gpio(struct ath5k_hw *hal, u32 gpio, u32 val); +extern void ath5k_hw_set_gpio_intr(struct ath5k_hw *hal, unsigned int gpio, u32 interrupt_level); /* Regulatory Domain/Channels Setup */ -extern u16 ath5k_get_regdomain(struct ath_hw *hal); +extern u16 ath5k_get_regdomain(struct ath5k_hw *hal); /* Misc functions */ -extern void ath5k_hw_dump_state(struct ath_hw *hal); -extern int ath5k_hw_get_capability(struct ath_hw *hal, enum ath5k_capability_type cap_type, u32 capability, u32 *result); +extern void ath5k_hw_dump_state(struct ath5k_hw *hal); +extern int ath5k_hw_get_capability(struct ath5k_hw *hal, enum ath5k_capability_type cap_type, u32 capability, u32 *result); /* Initial register settings functions */ -extern int ath5k_hw_write_initvals(struct ath_hw *hal, u8 mode, bool change_channel); +extern int ath5k_hw_write_initvals(struct ath5k_hw *hal, u8 mode, bool change_channel); /* Initialize RF */ -extern int ath5k_hw_rfregs(struct ath_hw *hal, struct ieee80211_channel *channel, unsigned int mode); -extern int ath5k_hw_rfgain(struct ath_hw *hal, unsigned int freq); -extern enum ath5k_rfgain ath5k_hw_get_rf_gain(struct ath_hw *hal); -extern int ath5k_hw_set_rfgain_opt(struct ath_hw *hal); +extern int ath5k_hw_rfregs(struct ath5k_hw *hal, struct ieee80211_channel *channel, unsigned int mode); +extern int ath5k_hw_rfgain(struct ath5k_hw *hal, unsigned int freq); +extern enum ath5k_rfgain ath5k_hw_get_rf_gain(struct ath5k_hw *hal); +extern int ath5k_hw_set_rfgain_opt(struct ath5k_hw *hal); /* PHY/RF channel functions */ -extern bool ath5k_channel_ok(struct ath_hw *hal, u16 freq, unsigned int flags); -extern int ath5k_hw_channel(struct ath_hw *hal, struct ieee80211_channel *channel); +extern bool ath5k_channel_ok(struct ath5k_hw *hal, u16 freq, unsigned int flags); +extern int ath5k_hw_channel(struct ath5k_hw *hal, struct ieee80211_channel *channel); /* PHY calibration */ -extern int ath5k_hw_phy_calibrate(struct ath_hw *hal, struct ieee80211_channel *channel); -extern int ath5k_hw_phy_disable(struct ath_hw *hal); +extern int ath5k_hw_phy_calibrate(struct ath5k_hw *hal, struct ieee80211_channel *channel); +extern int ath5k_hw_phy_disable(struct ath5k_hw *hal); /* Misc PHY functions */ -extern u16 ath5k_hw_radio_revision(struct ath_hw *hal, unsigned int chan); -extern void ath5k_hw_set_def_antenna(struct ath_hw *hal, unsigned int ant); -extern unsigned int ath5k_hw_get_def_antenna(struct ath_hw *hal); +extern u16 ath5k_hw_radio_revision(struct ath5k_hw *hal, unsigned int chan); +extern void ath5k_hw_set_def_antenna(struct ath5k_hw *hal, unsigned int ant); +extern unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *hal); /* TX power setup */ -extern int ath5k_hw_txpower(struct ath_hw *hal, struct ieee80211_channel *channel, unsigned int txpower); -extern int ath5k_hw_set_txpower_limit(struct ath_hw *hal, unsigned int power); +extern int ath5k_hw_txpower(struct ath5k_hw *hal, struct ieee80211_channel *channel, unsigned int txpower); +extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *hal, unsigned int power); -static inline u32 ath5k_hw_reg_read(struct ath_hw *hal, u16 reg) +static inline u32 ath5k_hw_reg_read(struct ath5k_hw *hal, u16 reg) { return ioread32(hal->ah_sh + reg); } -static inline void ath5k_hw_reg_write(struct ath_hw *hal, u32 val, u16 reg) +static inline void ath5k_hw_reg_write(struct ath5k_hw *hal, u32 val, u16 reg) { iowrite32(val, hal->ah_sh + reg); } Modified: branches/ath5k/ath5k_base.c =================================================================== --- branches/ath5k/ath5k_base.c 2007-08-30 11:55:21 UTC (rev 2697) +++ branches/ath5k/ath5k_base.c 2007-08-31 02:54:16 UTC (rev 2698) @@ -7,8 +7,6 @@ * This file is released under GPLv2 */ -#define ATH_PCI_VERSION "0.9.5.0-BSD" - #include <linux/version.h> #include <linux/module.h> #include <linux/delay.h> @@ -21,19 +19,13 @@ #include <net/ieee80211_radiotap.h> -#include <asm/unaligned.h> - #include "ath5k_base.h" #include "ath5k_reg.h" -#define ATH_DEBUG_MODES 0 /* Show found modes in the log? */ -#define ATH_DUMP_SKB 0 /* show skb contents */ +#define ATH5K_DEBUG_MODES 0 /* Show found modes in the log? */ +#define ATH5K_DUMP_SKB 0 /* show skb contents */ #define AR_DEBUG 1 -/* unaligned little endian access */ -#define LE_READ_2(_p) (le16_to_cpu(get_unaligned((__le16 *)(_p)))) -#define LE_READ_4(_p) (le32_to_cpu(get_unaligned((__le32 *)(_p)))) - #if AR_DEBUG #define DPRINTF(sc, _m, _fmt...) do { \ if (unlikely(((sc)->debug & (_m)) && net_ratelimit())) \ @@ -41,80 +33,41 @@ } while (0) #else static inline int __attribute__ ((format (printf, 3, 4))) -DPRINTF(struct ath_softc *sc, unsigned int m, const char *fmt, ...) +DPRINTF(struct ath5k_softc *sc, unsigned int m, const char *fmt, ...) { return 0; } #endif enum { - ATH_DEBUG_XMIT = 0x00000001, /* basic xmit operation */ - ATH_DEBUG_RESET = 0x00000020, /* reset processing */ - ATH_DEBUG_MODE = 0x00000040, /* mode init/setup */ - ATH_DEBUG_BEACON = 0x00000080, /* beacon handling */ - ATH_DEBUG_INTR = 0x00001000, /* ISR */ - ATH_DEBUG_BEACON_PROC = 0x00008000, /* beacon ISR proc */ - ATH_DEBUG_CALIBRATE = 0x00010000, /* periodic calibration */ - ATH_DEBUG_LED = 0x00100000, /* led management */ - ATH_DEBUG_FATAL = 0x80000000, /* fatal errors */ - ATH_DEBUG_ANY = 0xffffffff + ATH5K_DEBUG_XMIT = 0x00000001, /* basic xmit operation */ + ATH5K_DEBUG_RESET = 0x00000020, /* reset processing */ + ATH5K_DEBUG_MODE = 0x00000040, /* mode init/setup */ + ATH5K_DEBUG_BEACON = 0x00000080, /* beacon handling */ + ATH5K_DEBUG_INTR = 0x00001000, /* ISR */ + ATH5K_DEBUG_BEACON_PROC = 0x00008000, /* beacon ISR proc */ + ATH5K_DEBUG_CALIBRATE = 0x00010000, /* periodic calibration */ + ATH5K_DEBUG_LED = 0x00100000, /* led management */ + ATH5K_DEBUG_FATAL = 0x80000000, /* fatal errors */ + ATH5K_DEBUG_ANY = 0xffffffff }; enum { - ATH_LED_TX, - ATH_LED_RX, + ATH5K_LED_TX, + ATH5K_LED_RX, }; -static int ath_calinterval = ATH_SHORT_CALIB; +static int ath_calinterval = 1; /* 1 second */ -static int countrycode = CTRY_DEFAULT; -static int outdoor = true; -static int xchanmode = true; -module_param(countrycode, int, 0); -MODULE_PARM_DESC(countrycode, "Override default country code"); -module_param(outdoor, int, 0); -MODULE_PARM_DESC(outdoor, "Enable/disable outdoor use"); -module_param(xchanmode, int, 0); -MODULE_PARM_DESC(xchanmode, "Enable/disable extended channel mode"); #if AR_DEBUG static unsigned int ath_debug; module_param_named(debug, ath_debug, uint, 0); #endif -/* - * User a static table of PCI id's for now. While this is the - * "new way" to do things, we may want to switch back to having - * the HAL check them by defining a probe method. - */ -static struct pci_device_id ath_pci_id_table[] __devinitdata = { - { PCI_VDEVICE(ATHEROS, 0x0207), .driver_data = AR5K_AR5210 }, /* 5210 early */ - { PCI_VDEVICE(ATHEROS, 0x0007), .driver_data = AR5K_AR5210 }, /* 5210 */ - { PCI_VDEVICE(ATHEROS, 0x0011), .driver_data = AR5K_AR5211 }, /* 5311 */ - { PCI_VDEVICE(ATHEROS, 0x0012), .driver_data = AR5K_AR5211 }, /* 5211 */ - { PCI_VDEVICE(ATHEROS, 0x0013), .driver_data = AR5K_AR5212 }, /* 5212 */ - { PCI_VDEVICE(3COM_2, 0x0013), .driver_data = AR5K_AR5212 }, /* 3com 5212 */ - { PCI_VDEVICE(3COM, 0x0013), .driver_data = AR5K_AR5212 }, /* 3com 3CRDAG675 5212 */ - { PCI_VDEVICE(ATHEROS, 0x1014), .driver_data = AR5K_AR5212 }, /* IBM minipci 5212 */ - { PCI_VDEVICE(ATHEROS, 0x0014), .driver_data = AR5K_AR5212 }, - { PCI_VDEVICE(ATHEROS, 0x0015), .driver_data = AR5K_AR5212 }, - { PCI_VDEVICE(ATHEROS, 0x0016), .driver_data = AR5K_AR5212 }, - { PCI_VDEVICE(ATHEROS, 0x0017), .driver_data = AR5K_AR5212 }, - { PCI_VDEVICE(ATHEROS, 0x0018), .driver_data = AR5K_AR5212 }, - { PCI_VDEVICE(ATHEROS, 0x0019), .driver_data = AR5K_AR5212 }, - { PCI_VDEVICE(ATHEROS, 0x001a), .driver_data = AR5K_AR5212 }, /* 2413 Griffin-lite */ - { PCI_VDEVICE(ATHEROS, 0x001b), .driver_data = AR5K_AR5212 }, /* 5413 Eagle */ - { PCI_VDEVICE(ATHEROS, 0x001c), .driver_data = AR5K_AR5212 }, /* 5424 Condor (PCI-E)*/ - { 0 } -}; -MODULE_DEVICE_TABLE(pci, ath_pci_id_table); - -static void ath_led_event(struct ath_softc *, int); -static int ath_reset(struct ieee80211_hw *); - #if AR_DEBUG -static void ath_printrxbuf(struct ath_buf *bf, int done) +static void ath_printrxbuf(struct ath5k_buf *bf, int done) { - struct ath_desc *ds = bf->desc; + struct ath5k_desc *ds = bf->desc; printk(KERN_DEBUG "R (%p %llx) %08x %08x %08x %08x %08x %08x %c\n", ds, (unsigned long long)bf->daddr, @@ -123,9 +76,9 @@ !done ? ' ' : (ds->ds_rxstat.rs_status == 0) ? '*' : '!'); } -static void ath_printtxbuf(struct ath_buf *bf, int done) +static void ath_printtxbuf(struct ath5k_buf *bf, int done) { - struct ath_desc *ds = bf->desc; + struct ath5k_desc *ds = bf->desc; printk(KERN_DEBUG "T (%p %llx) %08x %08x %08x %08x %08x %08x %08x " "%08x %c\n", ds, (unsigned long long)bf->daddr, ds->ds_link, @@ -135,107 +88,1120 @@ } #endif -#if ATH_DUMP_SKB -static inline void ath_dump_skb(struct sk_buff *skb, const char *prefix) +#if ATH5K_DUMP_SKB +static inline void ath5k_dump_skb(struct sk_buff *skb, const char *prefix) { print_hex_dump_bytes(prefix, DUMP_PREFIX_NONE, skb->data, min(200U, skb->len)); } #else -static inline void ath_dump_skb(struct sk_buff *skb, const char *prefix) {} +static inline void ath5k_dump_skb(struct sk_buff *skb, const char *prefix) {} #endif -static inline void ath_cleanup_txbuf(struct ath_softc *sc, struct ath_buf *bf) + + + +/******************\ +* Internal defines * +\******************/ + +/* Module info */ +MODULE_AUTHOR("Jiri Slaby"); +MODULE_DESCRIPTION("Support for Atheros 802.11 wireless LAN cards."); +MODULE_SUPPORTED_DEVICE("Atheros WLAN cards"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION("0.1 (EXPERIMENTAL)"); + +/* Known PCI ids */ +static struct pci_device_id ar5k_pci_ids[] __devinitdata = { + { PCI_VDEVICE(ATHEROS, 0x0207), .driver_data = AR5K_AR5210 }, /* 5210 early */ + { PCI_VDEVICE(ATHEROS, 0x0007), .driver_data = AR5K_AR5210 }, /* 5210 */ +// { PCI_VDEVICE(ATHEROS, 0x0011), .driver_data = AR5K_AR5211 }, /* 5311 */ + { PCI_VDEVICE(ATHEROS, 0x0012), .driver_data = AR5K_AR5211 }, /* 5211 */ + { PCI_VDEVICE(ATHEROS, 0x0013), .driver_data = AR5K_AR5212 }, /* 5212 */ + { PCI_VDEVICE(3COM_2, 0x0013), .driver_data = AR5K_AR5212 }, /* 3com 5212 */ + { PCI_VDEVICE(3COM, 0x0013), .driver_data = AR5K_AR5212 }, /* 3com 3CRDAG675 5212 */ + { PCI_VDEVICE(ATHEROS, 0x1014), .driver_data = AR5K_AR5212 }, /* IBM minipci 5212 */ + { PCI_VDEVICE(ATHEROS, 0x0014), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ + { PCI_VDEVICE(ATHEROS, 0x0015), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ + { PCI_VDEVICE(ATHEROS, 0x0016), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ + { PCI_VDEVICE(ATHEROS, 0x0017), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ + { PCI_VDEVICE(ATHEROS, 0x0018), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ + { PCI_VDEVICE(ATHEROS, 0x0019), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ + { PCI_VDEVICE(ATHEROS, 0x001a), .driver_data = AR5K_AR5212 }, /* 2413 Griffin-lite */ + { PCI_VDEVICE(ATHEROS, 0x001b), .driver_data = AR5K_AR5212 }, /* 5413 Eagle */ +// { PCI_VDEVICE(ATHEROS, 0x001c), .driver_data = AR5K_AR5212 }, /* 5424 Condor (PCI-E)*/ + { 0 } +}; +MODULE_DEVICE_TABLE(pci, ar5k_pci_ids); + + +/* + * PCI stack related functions + */ +static int __devinit ath5k_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id); +static void __devexit ath5k_pci_remove(struct pci_dev *pdev); +#ifdef CONFIG_PM +static int ath5k_pci_suspend(struct pci_dev *pdev, + pm_message_t state); +static int ath5k_pci_resume(struct pci_dev *pdev); +#else +#define ath_pci_suspend NULL +#define ath_pci_resume NULL +#endif /* CONFIG_PM */ + + +static struct pci_driver ath5k_pci_drv = { + .name = "ath5k_pci", + .id_table = ar5k_pci_ids, + .probe = ath5k_pci_probe, + .remove = __devexit_p(ath5k_pci_remove), +#ifdef CONFIG_PM + .suspend = ath5k_pci_suspend, + .resume = ath5k_pci_resume, +#endif +}; + + +/* + * MAC 802.11 related functions + */ +static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_control *ctl); +static int ath5k_reset(struct ieee80211_hw *hw); +static int ath5k_open(struct ieee80211_hw *hw); +static int ath5k_stop(struct ieee80211_hw *hw); +static int ath5k_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf); +static void ath5k_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf); +static int ath5k_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf); +static int ath5k_config_interface(struct ieee80211_hw *hw, int if_id, + struct ieee80211_if_conf *conf); +static void ath5k_set_multicast_list(struct ieee80211_hw *hw, + unsigned short flags, int mc_count); +static int ath5k_set_key(struct ieee80211_hw *hw, set_key_cmd cmd, + u8 *addr, struct ieee80211_key_conf *key, int aid); +static int ath5k_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats); +static int ath5k_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats); +static u64 ath5k_get_tsf(struct ieee80211_hw *hw); +static void ath5k_reset_tsf(struct ieee80211_hw *hw); +static int ath5k_beacon_update(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct ieee80211_tx_control *ctl); + +static struct ieee80211_ops ath5k_ops = { + .tx = ath5k_tx, + .reset = ath5k_reset, + .open = ath5k_open, + .stop = ath5k_stop, + .add_interface = ath5k_add_interface, + .remove_interface = ath5k_remove_interface, + .config = ath5k_config, + .config_interface = ath5k_config_interface, + .set_multicast_list = ath5k_set_multicast_list, + .set_key = ath5k_set_key, + .get_stats = ath5k_get_stats, + .conf_tx = NULL, + .get_tx_stats = ath5k_get_tx_stats, + .get_tsf = ath5k_get_tsf, + .reset_tsf = ath5k_reset_tsf, + .beacon_update = ath5k_beacon_update, +}; + + +/* + * Module init/exit functions + */ +static int __init +ath5k_pci_init(void) { - BUG_ON(!bf); - if (!bf->skb) - return; - pci_unmap_single(sc->pdev, bf->skbaddr, bf->skb->len, - PCI_DMA_TODEVICE); - dev_kfree_skb(bf->skb); - bf->skb = NULL; + int error; + + error = pci_register_driver(&ath5k_pci_drv); + if (error) { + printk(KERN_ERR "ath5k: can't register pci driver\n"); + return error; + } + return 0; } +module_init(ath5k_pci_init); -static void ath_tasklet_reset(unsigned long data) +static void __exit +ath5k_pci_exit(void) { - struct ath_softc *sc = (void *)data; + pci_unregister_driver(&ath5k_pci_drv); +} +module_exit(ath5k_pci_exit); - ath_reset(sc->hw); + +/* + * Internal functions + */ +/* Attach detach */ +static int ath5k_attach(struct pci_dev *pdev, + struct ieee80211_hw *hw); +static void ath5k_detach(struct pci_dev *pdev, + struct ieee80211_hw *hw); +/* Channel/mode setup */ +static unsigned int ath5k_copy_rates(struct ieee80211_rate *rates, + const struct ath5k_rate_table *rt, + unsigned int max); +static unsigned int ath5k_copy_channels(struct ath5k_hw *ah, + struct ieee80211_channel *channels, + unsigned int mode, + unsigned int max); +static int ath5k_getchannels(struct ieee80211_hw *hw); +static int ath5k_chan_set(struct ath5k_softc *sc, + struct ieee80211_channel *chan); +static void ath5k_setcurmode(struct ath5k_softc *sc, + unsigned int mode); +static u32 ath5k_calc_rx_filter(struct ath5k_softc *sc); +/* Descriptor setup */ +static int ath5k_desc_alloc(struct ath5k_softc *sc, + struct pci_dev *pdev); +static void ath5k_desc_free(struct ath5k_softc *sc, + struct pci_dev *pdev); +/* Buffers setup */ +static int ath5k_rxbuf_setup(struct ath5k_softc *sc, + struct ath5k_buf *bf); +static int ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, + struct ieee80211_tx_control *ctl); +static inline void ath5k_txbuf_free(struct ath5k_softc *sc, + struct ath5k_buf *bf); +/* Queues setup */ +static struct ath5k_txq * ath5k_txq_setup(struct ath5k_softc *sc, int qtype, + int subtype); +static int ath5k_beaconq_setup(struct ath5k_hw *ah); +static int ath5k_beaconq_config(struct ath5k_softc *sc); +static void ath5k_tx_draintxq(struct ath5k_softc *sc, struct ath5k_txq *txq); +static void ath5k_draintxq(struct ath5k_softc *sc); +static void ath5k_tx_cleanup(struct ath5k_softc *sc); +/* Rx handling */ +static int ath5k_rx_start(struct ath5k_softc *sc); +static void ath5k_rx_stop(struct ath5k_softc *sc); +static unsigned int ath5k_rx_decrypted(struct ath5k_softc *sc, + struct ath5k_desc *ds, struct sk_buff *skb); +static void ath5k_rx_tasklet(unsigned long data); +/* Tx handling */ +static void ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq); +static void ath5k_tx_tasklet(unsigned long data); +/* Beacon handling */ +static int ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, + struct ieee80211_tx_control *ctl); +static void ath5k_beacon_send(struct ath5k_softc *sc); +static void ath5k_beacon_timers_setup(struct ath5k_softc *sc); +static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp); +/* Interrupt handling */ +static int ath5k_init(struct ath5k_softc *sc); +static int ath5k_stop_locked(struct ath5k_softc *sc); +static int ath5k_stop_hw(struct ath5k_softc *sc); +static irqreturn_t ath5k_intr(int irq, void *dev_id); +static void ath5k_reset_tasklet(unsigned long data); +static inline void ath5k_update_txpow(struct ath5k_softc *sc); +static void ath5k_calibrate(unsigned long data); +/* LED functions */ +static void ath5k_led_off(unsigned long data); +static void ath5k_led_blink(struct ath5k_softc *sc, unsigned int on, + unsigned int off); +static void ath5k_led_event(struct ath5k_softc *sc, int event); + + +/********************\ +* PCI Initialization * +\********************/ + +/* Probe for supported devices */ +static int __devinit +ath5k_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + void __iomem *mem; + struct ath5k_softc *sc; + struct ieee80211_hw *hw; + u32 val; + int error; + u8 csz; + + if (pci_enable_device(pdev)){ + error = -ENODEV; + goto err; + } + + /* XXX 32-bit addressing only */ + if (pci_set_dma_mask(pdev, 0xffffffff)) { + dev_err(&pdev->dev, "32-bit DMA not available\n"); + error = -EIO; + goto err_dis; + } + + /* + * Cache line size is used to size and align various + * structures used to communicate with the hardware. + */ + pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz); + if (csz == 0) { + /* + * Linux 2.4.18 (at least) writes the cache line size + * register as a 16-bit wide register which is wrong. + * We must have this setup properly for rx buffer + * DMA to work so force a reasonable value here if it + * comes up zero. + */ + csz = L1_CACHE_BYTES / sizeof(u32); + pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz); + } + /* + * The default setting of latency timer yields poor results, + * set it to the value used by other systems. It may be worth + * tweaking this setting more. + */ + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8); + + /* Enable bus mastering */ + pci_set_master(pdev); + + /* + * Disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state. + * + * Code taken from ipw2100 driver - jg + */ + pci_read_config_dword(pdev, 0x40, &val); + if ((val & 0x0000ff00) != 0) + pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); + + if (pci_request_region(pdev, 0, "ath5k")) { + dev_err(&pdev->dev, "cannot reserve PCI memory region\n"); + error = -ENOMEM; + goto err_dis; + } + + mem = pci_iomap(pdev, 0, 0); + if (!mem) { + dev_err(&pdev->dev, "cannot remap PCI memory region\n") ; + error = -EIO; + goto err_reg; + } + + /* + * Allocate hw (mac80211 main struct) + * and hw->priv (driver private data) + */ + hw = ieee80211_alloc_hw(sizeof(struct ath5k_softc), &ath5k_ops); + if (!hw) { + dev_err(&pdev->dev, "cannot allocate driver private data\n"); + error = -ENOMEM; + goto err_map; + } + sc = hw->priv; + sc->hw = hw; + + /* Initialize driver private data */ + + /* + * XXX: In case we support ahb bus in the future we + * have to make this a void pointer to the (abstract) + * device struct. + */ + sc->pdev = pdev; + + /* Convert cache line size to bytes */ + sc->cachelsz = csz * sizeof(u32); + + /* So we can unmap it on detach */ + sc->iobase = mem; + + /* Initialize device */ + sc->ah = ath5k_hw_attach(pdev->device, id->driver_data, + sc, sc->iobase); + if (IS_ERR(sc->ah)) { + error = PTR_ERR(sc->ah); + goto err_free; + } + + /* Set pci driver private data */ + pci_set_drvdata(pdev, hw); + + /* Setup interrupt handler */ + __set_bit(ATH5K_STAT_INVALID, sc->status); + + error = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath5k", sc); + if(error) { + dev_err(&pdev->dev, "request_irq failed\n"); + goto err_ah; + } + + /* Finish private driver data initialization */ + error = ath5k_attach(pdev, hw); + if(error){ + dev_err(&pdev->dev, "unable to initialize driver data !\n"); + goto err_irq; + } + + /* ready to process interrupts */ + __clear_bit(ATH5K_STAT_INVALID, sc->status); + + return 0; + +err_irq: + free_irq(pdev->irq, sc); +err_ah: + ath5k_hw_detach(sc->ah); +err_free: + ieee80211_free_hw(hw); +err_map: + pci_iounmap(pdev, mem); +err_reg: + pci_release_region(pdev, 0); +err_dis: + pci_disable_device(pdev); +err: + return error; } -static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) +static void __devexit +ath5k_pci_remove(struct pci_dev *pdev) { - struct ieee80211_tx_status txs = {}; - struct ath_buf *bf, *bf0; - struct ath_desc *ds; - struct sk_buff *skb; + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath5k_softc *sc = hw->priv; + + ath5k_detach(pdev, hw); + ath5k_hw_detach(sc->ah); + free_irq(pdev->irq, sc); + pci_iounmap(pdev, sc->iobase); + pci_release_region(pdev, 0); + pci_disable_device(pdev); + ieee80211_free_hw(hw); +} + +#ifdef CONFIG_PM +static int +ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath5k_softc *sc = hw->priv; + + if (test_bit(ATH5K_STAT_LEDSOFT, sc->status)) + ath5k_hw_set_gpio(sc->ah, sc->led_pin, 1); + + ath5k_stop_hw(sc); + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + + return 0; +} + +static int +ath5k_pci_resume(struct pci_dev *pdev) +{ + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath5k_softc *sc = hw->priv; + int error; + + error = pci_set_power_state(pdev, PCI_D0); + if (error) + return error; + + error = pci_enable_device(pdev); + if (error) + return error; + + pci_restore_state(pdev); + /* + * Suspend/Resume resets the PCI configuration space, so we have to + * re-disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state + */ + pci_write_config_byte(pdev, 0x41, 0); + + ath5k_init(sc); + if (test_bit(ATH5K_STAT_LEDSOFT, sc->status)) { + ath5k_hw_set_gpio_output(sc->ah, sc->led_pin); + ath5k_hw_set_gpio(sc->ah, sc->led_pin, 0); + } + + return 0; +} +#endif /* CONFIG_PM */ + + + +/***********************\ +* Driver Initialization * +\***********************/ + +static int +ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) +{ + struct ath5k_softc *sc = hw->priv; + struct ath5k_hw *ah = sc->ah; + unsigned int i; + int error; + + /* + * Newer MACs have multirate support + */ + if (ah->ah_version == AR5K_AR5212) + __set_bit(ATH5K_STAT_MRRETRY, sc->status); + + /* + * Reset the key cache since some parts do not + * reset the contents on initial power up. + */ + for (i = 0; i < AR5K_KEYCACHE_SIZE; i++) + ath5k_hw_reset_key(ah, i); + + /* + * Collect the channel list using the default country + * code and including outdoor channels. The 802.11 layer + * is resposible for filtering this list based on settings + * like the phy mode. + */ + error = ath5k_getchannels(hw); + if (error) { + dev_err(&pdev->dev, "can't get channels\n"); + goto err; + } + + /* NB: setup here so ath_rate_update is happy */ + if (test_bit(MODE_IEEE80211A, ah->ah_modes)) + ath5k_setcurmode(sc, MODE_IEEE80211A); + else + ath5k_setcurmode(sc, MODE_IEEE80211B); + + /* + * Allocate tx+rx descriptors and populate the lists. + */ + error = ath5k_desc_alloc(sc, pdev); + if (error) { + dev_err(&pdev->dev, "can't allocate descriptors\n"); + goto err; + } + + /* + * Allocate hardware transmit queues: one queue for + * beacon frames and one data queue for each QoS + * priority. Note that the hal handles reseting + * these queues at the needed time. + */ + error = ath5k_beaconq_setup(ah); + if (error < 0) { + dev_err(&pdev->dev, "can't setup a beacon xmit queue\n"); + goto err_desc; + } + sc->bhalq = error; + + sc->txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BK); + if (IS_ERR(sc->txq)) { + dev_err(&pdev->dev, "can't setup xmit queue\n"); + error = PTR_ERR(sc->txq); + goto err_bhal; + } + + tasklet_init(&sc->rxtq, ath5k_rx_tasklet, (unsigned long)sc); + tasklet_init(&sc->txtq, ath5k_tx_tasklet, (unsigned long)sc); + tasklet_init(&sc->restq, ath5k_reset_tasklet, (unsigned long)sc); + setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc); + setup_timer(&sc->led_tim, ath5k_led_off, (unsigned long)sc); + + sc->led_on = 0; /* low true */ + /* + * Auto-enable soft led processing for IBM cards and for + * 5211 minipci cards. Users can also manually enable/disable + * support with a sysctl. + */ + if (pdev->device == PCI_DEVICE_ID_ATHEROS_AR5212_IBM || + pdev->device == PCI_DEVICE_ID_ATHEROS_AR5211) { + __set_bit(ATH5K_STAT_LEDSOFT, sc->status); + sc->led_pin = 0; + } + /* Enable softled on PIN1 on HP Compaq nc6xx, nc4000 & nx5000 laptops */ + if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ) { + __set_bit(ATH5K_STAT_LEDSOFT, sc->status); + sc->led_pin = 0; + } + if (test_bit(ATH5K_STAT_LEDSOFT, sc->status)) { + ath5k_hw_set_gpio_output(ah, sc->led_pin); + ath5k_hw_set_gpio(ah, sc->led_pin, !sc->led_on); + } + + /* Set MAC address */ + ath5k_hw_get_lladdr(ah, hw->wiphy->perm_addr); + if (ath5k_hw_hasbssidmask(ah)) { + memset(sc->bssidmask, 0xff, ETH_ALEN); + ath5k_hw_set_bssid_mask(ah, sc->bssidmask); + } + + /* Set misc mac80211 parameters */ + hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_WEP_INCLUDE_IV | + IEEE80211_HW_DATA_NULLFUNC_ACK; + + hw->extra_tx_headroom = 2; + hw->channel_change_time = 5000; + hw->max_rssi = 127; /* FIXME: get a real value for this. */ + sc->opmode = IEEE80211_IF_TYPE_STA; + + mutex_init(&sc->lock); + spin_lock_init(&sc->rxbuflock); + spin_lock_init(&sc->txbuflock); + + /* Register device on mac80211 stack */ + SET_IEEE80211_DEV(hw, &pdev->dev); + error = ieee80211_register_hw(hw); + if (error) { + dev_err(&pdev->dev, "can't register with protocol stack!\n"); + goto err_queues; + } + + return 0; +err_queues: + ath5k_tx_cleanup(sc); +err_bhal: + ath5k_hw_release_tx_queue(ah, sc->bhalq); +err_desc: + ath5k_desc_free(sc, pdev); +err: + return error; +} + +static void +ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw) +{ + struct ath5k_softc *sc = hw->priv; + + /* + * NB: the order of these is important: + * o call the 802.11 layer before detaching the hal to + * insure callbacks into the driver to delete global + * key cache entries can be handled + * o reclaim the tx queue data structures after calling + * the 802.11 layer as we'll get called back to reclaim + * node state and potentially want to use them + * o to cleanup the tx queues the hal is called, so detach + * it last + * Other than that, it's straightforward... + */ + ieee80211_unregister_hw(hw); + ath5k_desc_free(sc, pdev); + ath5k_tx_cleanup(sc); + ath5k_hw_release_tx_queue(sc->ah, sc->bhalq); + + /* + * NB: can't reclaim these until after ieee80211_ifdetach + * returns because we'll get called back to reclaim node + * state and potentially want to use them. + */ +} + + +/********************\ +* Channel/mode setup * +\********************/ + +/* + * Convert IEEE channel number to MHz frequency. + */ +static inline short +ath5k_ieee2mhz(short chan) +{ + if (chan <= 14 || chan >= 27) + return ieee80211chan2mhz(chan); + else + return 2212 + chan * 20; +} + +static unsigned int +ath5k_copy_rates(struct ieee80211_rate *rates, + const struct ath5k_rate_table *rt, unsigned int max) +{ + unsigned int i, count; + + if (rt == NULL) + return 0; + + for (i = 0, count = 0; i < rt->rate_count && max > 0; i++) { + if (!rt->rates[i].valid) + continue; + rates->rate = rt->rates[i].rate_kbps / 100; + rates->val = rt->rates[i].rate_code; + rates->flags = rt->rates[i].modulation; + rates++; + count++; + max--; + } + + return count; +} + +static unsigned int +ath5k_copy_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels, + unsigned int mode, unsigned int max) +{ + static const struct { unsigned int mode, mask, chan; } map[] = { + [MODE_IEEE80211A] = + { CHANNEL_OFDM, CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_A }, + [MODE_ATHEROS_TURBO] = + { CHANNEL_OFDM | CHANNEL_TURBO, + CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_T }, + [MODE_IEEE80211B] = + { CHANNEL_CCK, CHANNEL_CCK, CHANNEL_B }, + [MODE_IEEE80211G] = + { CHANNEL_OFDM, CHANNEL_OFDM, CHANNEL_G }, + [MODE_ATHEROS_TURBOG] = + { CHANNEL_OFDM | CHANNEL_TURBO, + CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_TG }, + }; + static const struct ath5k_regchannel chans_2ghz[] = + IEEE80211_CHANNELS_2GHZ; + static const struct ath5k_regchannel chans_5ghz[] = + IEEE80211_CHANNELS_5GHZ; + const struct ath5k_regchannel *chans; + enum ath5k_regdom dmn; + unsigned int i, count, size, chfreq, all, f, ch; + + if (!test_bit(mode, ah->ah_modes)) + return 0; + + all = ah->ah_regdomain == DMN_DEFAULT || CHAN_DEBUG == 1; + + switch (mode) { + case MODE_IEEE80211A: + case MODE_ATHEROS_TURBO: + /* 1..220, but 2GHz frequencies are filtered by check_channel */ + size = all ? 220 : ARRAY_SIZE(chans_5ghz); + chans = chans_5ghz; + dmn = ath5k_regdom2flag(ah->ah_regdomain, + IEEE80211_CHANNELS_5GHZ_MIN); + chfreq = CHANNEL_5GHZ; + break; + case MODE_IEEE80211B: + case MODE_IEEE80211G: + case MODE_ATHEROS_TURBOG: + size = all ? 26 : ARRAY_SIZE(chans_2ghz); + chans = chans_2ghz; + dmn = ath5k_regdom2flag(ah->ah_regdomain, + IEEE80211_CHANNELS_2GHZ_MIN); + chfreq = CHANNEL_2GHZ; + break; + default: + printk(KERN_WARNING "bad mode, not copying channels\n"); + return 0; + } + + for (i = 0, count = 0; i < size && max > 0; i++) { + ch = all ? i + 1 : chans[i].chan; + f = ath5k_ieee2mhz(ch); + /* Check if channel is supported by the chipset */ + if (!ath5k_channel_ok(ah, f, chfreq)) + continue; + + /* Match regulation domain */ + if (!all && !(IEEE80211_DMN(chans[i].domain) & + IEEE80211_DMN(dmn))) + continue; + + if (!all && (chans[i].mode & map[mode].mask) != map[mode].mode) + continue; + + /* Write channel and increment counter */ + channels->chan = ch; + channels->freq = f; + channels->val = map[mode].chan; + channels++; + count++; + max--; + } + + return count; +} + +#if ATH5K_DEBUG_MODES +static void +ath5k_dump_modes(struct ieee80211_hw_mode *modes) +{ + unsigned int m, i; + + for (m = 0; m < NUM_IEEE80211_MODES; m++) { + printk(KERN_DEBUG "Mode %u: channels %d, rates %d\n", m, + modes[m].num_channels, modes[m].num_rates); + printk(KERN_DEBUG " channels:\n"); + for (i = 0; i < modes[m].num_channels; i++) + printk(KERN_DEBUG " %3d %d %.4x %.4x\n", + modes[m].channels[i].chan, + modes[m].channels[i].freq, + modes[m].channels[i].val, + modes[m].channels[i].flag); + printk(KERN_DEBUG " rates:\n"); + for (i = 0; i < modes[m].num_rates; i++) + printk(KERN_DEBUG " %4d %.4x %.4x %.4x\n", + modes[m].rates[i].rate, + modes[m].rates[i].val, + modes[m].rates[i].flags, + modes[m].rates[i].val2); + } +} +#else +static inline void +ath5k_dump_modes(struct ieee80211_hw_mode *modes) {} +#endif + +static int +ath5k_getchannels(struct ieee80211_hw *hw) +{ + struct ath5k_softc *sc = hw->priv; + struct ath5k_hw *ah = sc->ah; + struct ieee80211_hw_mode *modes = sc->modes; + unsigned int i, max; + int error; + enum { + A = MODE_IEEE80211A, + B = MODE_IEEE80211G, /* this is not a typo, but workaround */ + G = MODE_IEEE80211B, /* to prefer g over b */ + T = MODE_ATHEROS_TURBO, + TG = MODE_ATHEROS_TURBOG, + }; + + BUILD_BUG_ON(ARRAY_SIZE(sc->modes) < 5); + + modes[A].mode = MODE_IEEE80211A; + modes[B].mode = MODE_IEEE80211B; + modes[G].mode = MODE_IEEE80211G; + + max = ARRAY_SIZE(sc->rates); + modes[A].rates = sc->rates; + max -= modes[A].num_rates = ath5k_copy_rates(modes[A].rates, + ath5k_hw_get_rate_table(ah, MODE_IEEE80211A), max); + modes[B].rates = &modes[A].rates[modes[A].num_rates]; + max -= modes[B].num_rates = ath5k_copy_rates(modes[B].rates, + ath5k_hw_get_rate_table(ah, MODE_IEEE80211B), max); + modes[G].rates = &modes[B].rates[modes[B].num_rates]; + max -= modes[G].num_rates = ath5k_copy_rates(modes[G].rates, + ath5k_hw_get_rate_table(ah, MODE_IEEE80211G), max); + + if (!max) + printk(KERN_WARNING "yet another rates found, but there is not " + "sufficient space to store them\n"); + + max = ARRAY_SIZE(sc->channels); + modes[A].channels = sc->channels; + max -= modes[A].num_channels = ath5k_copy_channels(ah, modes[A].channels, + MODE_IEEE80211A, max); + modes[B].channels = &modes[A].channels[modes[A].num_channels]; + max -= modes[B].num_channels = ath5k_copy_channels(ah, modes[B].channels, + MODE_IEEE80211B, max); + modes[G].channels = &modes[B].channels[modes[B].num_channels]; + max -= modes[G].num_channels = ath5k_copy_channels(ah, modes[G].channels, + MODE_IEEE80211G, max); + + if (!max) + printk(KERN_WARNING "yet another modes found, but there is not " + "sufficient space to store them\n"); + + for (i = 0; i < ARRAY_SIZE(sc->modes); i++) + if (modes[i].num_channels) { + error = ieee80211_register_hwmode(hw, &modes[i]); + if (error) { + printk(KERN_ERR "can't register hwmode %u\n",i); + goto err; + } + } + ath5k_dump_modes(modes); + + return 0; +err: + return error; +} + +/* + * Set/change channels. If the channel is really being changed, + * it's done by reseting the chip. To accomplish this we must + * first cleanup any pending DMA, then restart stuff after a la + * ath_init. + */ +static int +ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan) +{ + struct ath5k_hw *ah = sc->ah; int ret; - spin_lock(&txq->lock); - list_for_each_entry_safe(bf, bf0, &txq->q, list) { - ds = bf->desc; + DPRINTF(sc, ATH5K_DEBUG_RESET, "%s: %u (%u MHz) -> %u (%u MHz)\n", + __func__, sc->curchan->chan, sc->curchan->freq, + chan->chan, chan->freq); - /* TODO only one segment */ - pci_dma_sync_single_for_cpu(sc->pdev, sc->desc_daddr, - sc->desc_len, PCI_DMA_FROMDEVICE); - ret = sc->ah->ah_proc_tx_desc(sc->ah, ds); - if (unlikely(ret == -EINPROGRESS)) - break; - else if (unlikely(ret)) { - printk(KERN_ERR "ath: error %d while processing " - "queue %u\n", ret, txq->qnum); - break; + if (chan->freq != sc->curchan->freq || chan->val != sc->curchan->val) { + /* + * To switch channels clear any pending DMA operations; + * wait long enough for the RX fifo to drain, reset the + * hardware at the new frequency, and then re-enable + * the relevant bits of the h/w. + */ + ath5k_hw_set_intr(ah, 0); /* disable interrupts */ + ath5k_draintxq(sc); /* clear pending tx frames */ + ath5k_rx_stop(sc); /* turn off frame recv */ + ret = ath5k_hw_reset(ah, sc->opmode, chan, true); + if (ret) { + printk(KERN_ERR "%s: unable to reset channel %u " + "(%u Mhz)\n", __func__, chan->chan, chan->freq); + return ret; } + sc->curchan = chan; + ath5k_update_txpow(sc); - skb = bf->skb; - bf->skb = NULL; - pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, - PCI_DMA_TODEVICE); + /* + * Re-enable rx framework. + */ + ret = ath5k_rx_start(sc); + if (ret) { + printk(KERN_ERR "%s: unable to restart recv logic\n", + __func__); + return ret; + } - txs.control = bf->ctl; - txs.retry_count = ds->ds_txstat.ts_shortretry + - ds->ds_txstat.ts_longretry / 6; - if (unlikely(ds->ds_txstat.ts_status)) { - sc->ll_stats.dot11ACKFailureCount++; - if (ds->ds_txstat.ts_status & AR5K_TXERR_XRETRY) - txs.excessive_retries = 1; - else if (ds->ds_txstat.ts_status & AR5K_TXERR_FILT) - txs.flags |= IEEE80211_TX_STATUS_TX_FILTERED; - } else { - txs.flags |= IEEE80211_TX_STATUS_ACK; - txs.ack_signal = ds->ds_txstat.ts_rssi; + /* + * Change channels and update the h/w rate map + * if we're switching; e.g. 11a to 11b/g. + * + * XXX needed? + */ +/* ath_chan_change(sc, chan); */ + + /* + * Re-enable interrupts. + */ + ath5k_hw_set_intr(ah, sc->imask); + } + + return 0; +} + +/* XXX: Why do all this stuff just for LEDs ? */ +static void +ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode) +{ + if (unlikely(test_bit(ATH5K_STAT_LEDSOFT, sc->status))) { + /* from Atheros NDIS driver, w/ permission */ + static const struct { + u16 rate; /* tx/rx 802.11 rate */ + u16 timeOn; /* LED on time (ms) */ + u16 timeOff; /* LED off time (ms) */ + } blinkrates[] = { + { 108, 40, 10 }, + { 96, 44, 11 }, + { 72, 50, 13 }, + { 48, 57, 14 }, + { 36, 67, 16 }, + { 24, 80, 20 }, + { 22, 100, 25 }, + { 18, 133, 34 }, + { 12, 160, 40 }, + { 10, 200, 50 }, + { 6, 240, 58 }, + { 4, 267, 66 }, + { 2, 400, 100 }, + { 0, 500, 130 } + }; + const struct ath5k_rate_table *rt = + ath5k_hw_get_rate_table(sc->ah, mode); + unsigned int i, j; + + BUG_ON(rt == NULL); + + memset(sc->hwmap, 0, sizeof(sc->hwmap)); + for (i = 0; i < 32; i++) { + u8 ix = rt->rate_code_to_index[i]; + if (ix == 0xff) { + sc->hwmap[i].ledon = msecs_to_jiffies(500); + sc->hwmap[i].ledoff = msecs_to_jiffies(130); + continue; + } + sc->hwmap[i].txflags = IEEE80211_RADIOTAP_F_DATAPAD; + if (SHPREAMBLE_FLAG(ix) || rt->rates[ix].modulation == + IEEE80211_RATE_OFDM) + sc->hwmap[i].txflags |= + IEEE80211_RADIOTAP_F_SHORTPRE; + /* receive frames include FCS */ + sc->hwmap[i].rxflags = sc->hwmap[i].txflags | + IEEE80211_RADIOTAP_F_FCS; + /* setup blink rate table to avoid per-packet lookup */ + for (j = 0; j < ARRAY_SIZE(blinkrates) - 1; j++) + if (blinkrates[j].rate == /* XXX why 7f? */ + (rt->rates[ix].dot11_rate&0x7f)) + break; + + sc->hwmap[i].ledon = msecs_to_jiffies(blinkrates[j]. + timeOn); + sc->hwmap[i].ledoff = msecs_to_jiffies(blinkrates[j]. + timeOff); } + } - ieee80211_tx_status(sc->hw, skb, &txs); - sc->tx_stats.data[txq->qnum].count++; + sc->curmode = mode; +} - spin_lock(&sc->txbuflock); - sc->tx_stats.data[txq->qnum].len--; - list_move_tail(&bf->list, &sc->txbuf); - sc->txbuf_len++; - spin_unlock(&sc->txbuflock); +/* + * Calculate the receive filter according to the + * operating mode and state: + * + * o always accept unicast, broadcast, and multicast traffic + * o maintain current state of phy error reception (the hal + * may enable phy error frames for noise immunity work) + * o probe request frames are accepted only when operating in + * hostap, adhoc, or monitor modes + * o enable promiscuous mode according to the interface state + * o accept beacons: + * - when operating in adhoc mode so the 802.11 layer creates + * node table entries for peers, + * - when operating in station mode for collecting rssi data when + * the station is otherwise quiet, or + * - when scanning + * o accept any additional packets specified by sc_rxfilter + */ +static u32 +ath5k_calc_rx_filter(struct ath5k_softc *sc) +{ + struct ath5k_hw *ah = sc->ah; + unsigned int opmode = sc->opmode; + u32 rfilt; + + rfilt = (ath5k_hw_get_rx_filter(ah) & AR5K_RX_FILTER_PHYERR) | + AR5K_RX_FILTER_UCAST | AR5K_RX_FILTER_BCAST | + AR5K_RX_FILTER_MCAST | AR5K_RX_FILTER_RADARERR; + + if (sc->opmode == IEEE80211_IF_TYPE_MNTR) + rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON | + AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM; + if (opmode != IEEE80211_IF_TYPE_STA) + rfilt |= AR5K_RX_FILTER_PROBEREQ; + if (opmode != IEEE80211_IF_TYPE_AP && test_bit(ATH5K_STAT_PROMISC, + sc->status)) + rfilt |= AR5K_RX_FILTER_PROM; + if (opmode == IEEE80211_IF_TYPE_STA || opmode == IEEE80211_IF_TYPE_IBSS) + rfilt |= AR5K_RX_FILTER_BEACON; + + return rfilt; +} + +static void +ath5k_mode_init(struct ath5k_softc *sc) +{ + struct ath5k_hw *ah = sc->ah; + u32 rfilt; + + /* configure rx filter */ + rfilt = ath5k_calc_rx_filter(sc); + ath5k_hw_set_rx_filter(ah, rfilt); + + if (ath5k_hw_hasbssidmask(ah)) + ath5k_hw_set_bssid_mask(ah, sc->bssidmask); + + /* configure operational mode */ + ath5k_hw_set_opmode(ah); + + ath5k_hw_set_mcast_filter(ah, 0, 0); + DPRINTF(sc, ATH5K_DEBUG_MODE, "%s: RX filter 0x%x\n", __func__, rfilt); +} + + + +/*******************\ +* Descriptors setup * +\*******************/ + +static int +ath5k_desc_alloc(struct ath5k_softc *sc, struct pci_dev *pdev) +{ + struct ath5k_desc *ds; + struct ath5k_buf *bf; + dma_addr_t da; + unsigned int i; + int ret; + + /* allocate descriptors */ + sc->desc_len = sizeof(struct ath5k_desc) * + (ATH5K_TXBUF + ATH5K_RXBUF + ATH5K_BCBUF + 1); + sc->desc = pci_alloc_consistent(pdev, sc->desc_len, &sc->desc_daddr); + if (sc->desc == NULL) { + dev_err(&pdev->dev, "can't allocate descriptors\n"); + ret = -ENOMEM; + goto err; } - if (likely(list_empty(&txq->q))) - txq->link = NULL; - spin_unlock(&txq->lock); - if (sc->txbuf_len > ATH_TXBUF / 5) - ieee80211_wake_queues(sc->hw); + ds = sc->desc; + da = sc->desc_daddr; + DPRINTF(sc, ATH5K_DEBUG_ANY, "%s: DMA map: %p (%zu) -> %llx\n", + __func__, ds, sc->desc_len, (unsigned long long)sc->desc_daddr); + + bf = kcalloc(1 + ATH5K_TXBUF + ATH5K_RXBUF + ATH5K_BCBUF, + sizeof(struct ath5k_buf), GFP_KERNEL); + if (bf == NULL) { + dev_err(&pdev->dev, "can't allocate bufptr\n"); + ret = -ENOMEM; + goto err_free; + } + sc->bufptr = bf; + + INIT_LIST_HEAD(&sc->rxbuf); + for (i = 0; i < ATH5K_RXBUF; i++, bf++, ds++, da += sizeof(*ds)) { + bf->desc = ds; + bf->daddr = da; + list_add_tail(&bf->list, &sc->rxbuf); + } + + INIT_LIST_HEAD(&sc->txbuf); + sc->txbuf_len = ATH5K_TXBUF; + for (i = 0; i < ATH5K_TXBUF; i++, bf++, ds += 1, + da += 1 * sizeof(*ds)) { + bf->desc = ds; + bf->daddr = da; + list_add_tail(&bf->list, &sc->txbuf); + } + + /* beacon buffer */ + bf->desc = ds; + bf->daddr = da; + sc->bbuf = bf; + + return 0; +err_free: + pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr); +err: + sc->desc = NULL; + return ret; } -static void ath_tasklet_tx(unsigned long data) +static void +ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev) { - struct ath_softc *sc = (void *)data; + struct ath5k_buf *bf; - ath_tx_processq(sc, sc->txq); + ath5k_txbuf_free(sc, sc->bbuf); + list_for_each_entry(bf, &sc->txbuf, list) + ath5k_txbuf_free(sc, bf); + list_for_each_entry(bf, &sc->rxbuf, list) + ath5k_txbuf_free(sc, bf); - ath_led_event(sc, ATH_LED_TX); + /* Free memory associated with all descriptors */ + pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr); + + kfree(sc->bufptr); + sc->bufptr = NULL; } -static int ath_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf) + +/***************\ +* Buffers setup * +\***************/ + +static int +ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) { - struct ath_hw *ah = sc->ah; + struct ath5k_hw *ah = sc->ah; struct sk_buff *skb = bf->skb; - struct ath_desc *ds; + struct ath5k_desc *ds; if (likely(skb == NULL)) { unsigned int off; @@ -246,7 +1212,7 @@ */ skb = dev_alloc_skb(sc->rxbufsize + sc->cachelsz - 1); if (unlikely(skb == NULL)) { - printk(KERN_ERR "ath: can't alloc skbuff of size %u\n", + printk(KERN_ERR "ath5k: can't alloc skbuff of size %u\n", sc->rxbufsize + sc->cachelsz - 1); return -ENOMEM; } @@ -298,9 +1264,337 @@ return 0; } -static unsigned int ath_rx_decrypted(struct ath_softc *sc, - struct ath_desc *ds, struct sk_buff *skb) +static int +ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, + struct ieee80211_tx_control *ctl) { + struct ath5k_hw *ah = sc->ah; + struct ath5k_txq *txq = sc->txq; + struct ath5k_desc *ds = bf->desc; + struct sk_buff *skb = bf->skb; + unsigned int hdrpad, pktlen, flags, keyidx = AR5K_TXKEYIX_INVALID; + int ret; + + flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK; + bf->ctl = *ctl; + /* XXX endianness */ + bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + + if (ctl->flags & IEEE80211_TXCTL_NO_ACK) + flags |= AR5K_TXDESC_NOACK; + + if ((ieee80211_get_hdrlen_from_skb(skb) & 3) && net_ratelimit()) + printk(KERN_DEBUG "tx len is not %%4: %u\n", + ieee80211_get_hdrlen_from_skb(skb)); + + hdrpad = 0; + pktlen = skb->len - hdrpad + FCS_LEN; + + if (ctl->key_idx != HW_KEY_IDX_INVALID) { + keyidx = ctl->key_idx; + pktlen += ctl->icv_len; + } + + ret = ah->ah_setup_tx_desc(ah, ds, pktlen, + ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, + 0xffff, ctl->tx_rate, ctl->retry_limit, keyidx, 0, flags, 0, 0); + if (ret) + goto err_unmap; + + ds->ds_link = 0; + ds->ds_data = bf->skbaddr; + + ret = ah->ah_fill_tx_desc(ah, ds, skb->len, true, true); + if (ret) + goto err_unmap; + + spin_lock_bh(&txq->lock); + list_add_tail(&bf->list, &txq->q); + sc->tx_stats.data[txq->qnum].len++; + ... [truncated message content] |