X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fnet%2Fwireless%2Fiwlwifi%2Fiwl3945-base.c;h=5ee1ad69898b6f36aed5b84a2270b9431274e1ab;hb=897e1cf29e05e3373bf380a417d085cd3389a3c0;hp=e14e1333535fbc557c169f6de3a6e41c738bf076;hpb=bb8c093bdea62f2ae371b98ebff81b0407852faf;p=linux-2.6 diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index e14e133353..8c2036850c 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -27,16 +27,6 @@ * *****************************************************************************/ -/* - * NOTE: This file (iwl-base.c) is used to build to multiple hardware targets - * by defining IWL to either 3945 or 4965. The Makefile used when building - * the base targets will create base-3945.o and base-4965.o - * - * The eventual goal is to move as many of the #if IWL / #endif blocks out of - * this file and into the hardware specific implementation files (iwl-XXXX.c) - * and leave only the common (non #ifdef sprinkled) code in this file - */ - #include #include #include @@ -56,6 +46,7 @@ #include +#include "iwl-3945-core.h" #include "iwl-3945.h" #include "iwl-helpers.h" @@ -73,13 +64,13 @@ static int iwl3945_tx_queue_update_write_ptr(struct iwl3945_priv *priv, ******************************************************************************/ /* module parameters */ -static int iwl3945_param_disable_hw_scan; -static int iwl3945_param_debug; -static int iwl3945_param_disable; /* def: enable radio */ -static int iwl3945_param_antenna; /* def: 0 = both antennas (use diversity) */ -int iwl3945_param_hwcrypto; /* def: using software encryption */ -static int iwl3945_param_qos_enable = 1; -int iwl3945_param_queues_num = IWL_MAX_NUM_QUEUES; +static int iwl3945_param_disable_hw_scan; /* def: 0 = use 3945's h/w scan */ +static int iwl3945_param_debug; /* def: 0 = minimal debug log messages */ +static int iwl3945_param_disable; /* def: 0 = enable radio */ +static int iwl3945_param_antenna; /* def: 0 = both antennas (use diversity) */ +int iwl3945_param_hwcrypto; /* def: 0 = use software encryption */ +static int iwl3945_param_qos_enable = 1; /* def: 1 = use quality of service */ +int iwl3945_param_queues_num = IWL_MAX_NUM_QUEUES; /* def: 8 Tx queues */ /* * module name, copyright, version, etc. @@ -101,15 +92,10 @@ int iwl3945_param_queues_num = IWL_MAX_NUM_QUEUES; #define VS #endif -#define IWLWIFI_VERSION "1.1.19k" VD VS -#define DRV_COPYRIGHT "Copyright(c) 2003-2007 Intel Corporation" +#define IWLWIFI_VERSION "1.2.26k" VD VS +#define DRV_COPYRIGHT "Copyright(c) 2003-2008 Intel Corporation" #define DRV_VERSION IWLWIFI_VERSION -/* Change firmware file name, using "-" and incrementing number, - * *only* when uCode interface or architecture changes so that it - * is not compatible with earlier drivers. - * This number will also appear in << 8 position of 1st dword of uCode file */ -#define IWL3945_UCODE_API "-1" MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_VERSION(DRV_VERSION); @@ -126,16 +112,10 @@ static __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr) return NULL; } -static const struct ieee80211_hw_mode *iwl3945_get_hw_mode( - struct iwl3945_priv *priv, int mode) +static const struct ieee80211_supported_band *iwl3945_get_band( + struct iwl3945_priv *priv, enum ieee80211_band band) { - int i; - - for (i = 0; i < 3; i++) - if (priv->modes[i].mode == mode) - return &priv->modes[i]; - - return NULL; + return priv->hw->wiphy->bands[band]; } static int iwl3945_is_empty_essid(const char *essid, int essid_len) @@ -178,36 +158,32 @@ static const char *iwl3945_escape_essid(const char *essid, u8 essid_len) return escaped; } -static void iwl3945_print_hex_dump(int level, void *p, u32 len) -{ -#ifdef CONFIG_IWL3945_DEBUG - if (!(iwl3945_debug_level & level)) - return; - - print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1, - p, len, 1); -#endif -} - /*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** * DMA services * * Theory of operation * - * A queue is a circular buffers with 'Read' and 'Write' pointers. - * 2 empty entries always kept in the buffer to protect from overflow. + * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer + * of buffer descriptors, each of which points to one or more data buffers for + * the device to read from or fill. Driver and device exchange status of each + * queue via "read" and "write" pointers. Driver keeps minimum of 2 empty + * entries in each circular buffer, to protect against confusing empty and full + * queue states. + * + * The device reads or writes the data in the queues via the device's several + * DMA/FIFO channels. Each queue is mapped to a single DMA channel. * * For Tx queue, there are low mark and high mark limits. If, after queuing * the packet for Tx, free space become < low mark, Tx queue stopped. When * reclaiming packets (on 'tx done IRQ), if free space become > high mark, * Tx queue resumed. * - * The IWL operates with six queues, one receive queue in the device's - * sram, one transmit queue for sending commands to the device firmware, - * and four transmit queues for data. + * The 3945 operates with six queues: One receive queue, one transmit queue + * (#4) for sending commands to the device firmware, and four transmit queues + * (#0-3) for data tx via EDCA. An additional 2 HCCA queues are unused. ***************************************************/ -static int iwl3945_queue_space(const struct iwl3945_queue *q) +int iwl3945_queue_space(const struct iwl3945_queue *q) { int s = q->read_ptr - q->write_ptr; @@ -223,33 +199,27 @@ static int iwl3945_queue_space(const struct iwl3945_queue *q) return s; } -/* XXX: n_bd must be power-of-two size */ -static inline int iwl3945_queue_inc_wrap(int index, int n_bd) -{ - return ++index & (n_bd - 1); -} - -/* XXX: n_bd must be power-of-two size */ -static inline int iwl3945_queue_dec_wrap(int index, int n_bd) -{ - return --index & (n_bd - 1); -} - -static inline int x2_queue_used(const struct iwl3945_queue *q, int i) +int iwl3945_x2_queue_used(const struct iwl3945_queue *q, int i) { return q->write_ptr > q->read_ptr ? (i >= q->read_ptr && i < q->write_ptr) : !(i < q->read_ptr && i >= q->write_ptr); } + static inline u8 get_cmd_index(struct iwl3945_queue *q, u32 index, int is_huge) { + /* This is for scan command, the big buffer at end of command array */ if (is_huge) - return q->n_window; + return q->n_window; /* must be power of 2 */ + /* Otherwise, use normal size buffers */ return index & (q->n_window - 1); } +/** + * iwl3945_queue_init - Initialize queue's high/low-water and read/write indexes + */ static int iwl3945_queue_init(struct iwl3945_priv *priv, struct iwl3945_queue *q, int count, int slots_num, u32 id) { @@ -257,8 +227,8 @@ static int iwl3945_queue_init(struct iwl3945_priv *priv, struct iwl3945_queue *q q->n_window = slots_num; q->id = id; - /* count must be power-of-two size, otherwise iwl3945_queue_inc_wrap - * and iwl3945_queue_dec_wrap are broken. */ + /* count must be power-of-two size, otherwise iwl_queue_inc_wrap + * and iwl_queue_dec_wrap are broken. */ BUG_ON(!is_power_of_2(count)); /* slots_num must be power-of-two size, otherwise @@ -278,11 +248,16 @@ static int iwl3945_queue_init(struct iwl3945_priv *priv, struct iwl3945_queue *q return 0; } +/** + * iwl3945_tx_queue_alloc - Alloc driver data and TFD CB for one Tx/cmd queue + */ static int iwl3945_tx_queue_alloc(struct iwl3945_priv *priv, struct iwl3945_tx_queue *txq, u32 id) { struct pci_dev *dev = priv->pci_dev; + /* Driver private data, only for Tx (not command) queues, + * not shared with device. */ if (id != IWL_CMD_QUEUE_NUM) { txq->txb = kmalloc(sizeof(txq->txb[0]) * TFD_QUEUE_SIZE_MAX, GFP_KERNEL); @@ -294,6 +269,8 @@ static int iwl3945_tx_queue_alloc(struct iwl3945_priv *priv, } else txq->txb = NULL; + /* Circular buffer of transmit frame descriptors (TFDs), + * shared with device */ txq->bd = pci_alloc_consistent(dev, sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX, &txq->q.dma_addr); @@ -316,6 +293,9 @@ static int iwl3945_tx_queue_alloc(struct iwl3945_priv *priv, return -ENOMEM; } +/** + * iwl3945_tx_queue_init - Allocate and initialize one tx/cmd queue + */ int iwl3945_tx_queue_init(struct iwl3945_priv *priv, struct iwl3945_tx_queue *txq, int slots_num, u32 txq_id) { @@ -323,9 +303,14 @@ int iwl3945_tx_queue_init(struct iwl3945_priv *priv, int len; int rc = 0; - /* allocate command space + one big command for scan since scan - * command is very huge the system will not have two scan at the - * same time */ + /* + * Alloc buffer array for commands (Tx or other types of commands). + * For the command queue (#4), allocate command space + one big + * command for scan, since scan command is very huge; the system will + * not have two scans at the same time, so only one is needed. + * For data Tx queues (all other queues), no super-size command + * space is needed. + */ len = sizeof(struct iwl3945_cmd) * slots_num; if (txq_id == IWL_CMD_QUEUE_NUM) len += IWL_MAX_SCAN_SIZE; @@ -333,6 +318,7 @@ int iwl3945_tx_queue_init(struct iwl3945_priv *priv, if (!txq->cmd) return -ENOMEM; + /* Alloc driver data array and TFD circular buffer */ rc = iwl3945_tx_queue_alloc(priv, txq, txq_id); if (rc) { pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd); @@ -342,10 +328,13 @@ int iwl3945_tx_queue_init(struct iwl3945_priv *priv, txq->need_update = 0; /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise - * iwl3945_queue_inc_wrap and iwl3945_queue_dec_wrap are broken. */ + * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */ BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); + + /* Initialize queue high/low-water, head/tail indexes */ iwl3945_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); + /* Tell device where to find queue, enable DMA channel. */ iwl3945_hw_tx_queue_init(priv, txq); return 0; @@ -356,8 +345,8 @@ int iwl3945_tx_queue_init(struct iwl3945_priv *priv, * @txq: Transmit queue to deallocate. * * Empty queue by removing and destroying all BD's. - * Free all buffers. txq itself is not freed. - * + * Free all buffers. + * 0-fill, but do not free "txq" descriptor structure. */ void iwl3945_tx_queue_free(struct iwl3945_priv *priv, struct iwl3945_tx_queue *txq) { @@ -370,42 +359,45 @@ void iwl3945_tx_queue_free(struct iwl3945_priv *priv, struct iwl3945_tx_queue *t /* first, empty all BD's */ for (; q->write_ptr != q->read_ptr; - q->read_ptr = iwl3945_queue_inc_wrap(q->read_ptr, q->n_bd)) + q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) iwl3945_hw_txq_free_tfd(priv, txq); len = sizeof(struct iwl3945_cmd) * q->n_window; if (q->id == IWL_CMD_QUEUE_NUM) len += IWL_MAX_SCAN_SIZE; + /* De-alloc array of command/tx buffers */ pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd); - /* free buffers belonging to queue itself */ + /* De-alloc circular buffer of TFDs */ if (txq->q.n_bd) pci_free_consistent(dev, sizeof(struct iwl3945_tfd_frame) * txq->q.n_bd, txq->bd, txq->q.dma_addr); + /* De-alloc array of per-TFD driver data */ if (txq->txb) { kfree(txq->txb); txq->txb = NULL; } - /* 0 fill whole structure */ + /* 0-fill queue descriptor structure */ memset(txq, 0, sizeof(*txq)); } const u8 iwl3945_broadcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /*************** STATION TABLE MANAGEMENT **** - * - * NOTE: This needs to be overhauled to better synchronize between - * how the iwl-4965.c is using iwl3945_hw_find_station vs. iwl-3945.c - * - * mac80211 should also be examined to determine if sta_info is duplicating + * mac80211 should be examined to determine if sta_info is duplicating * the functionality provided here */ /**************************************************************/ #if 0 /* temporary disable till we add real remove station */ +/** + * iwl3945_remove_station - Remove driver's knowledge of station. + * + * NOTE: This does not remove station from device's station table. + */ static u8 iwl3945_remove_station(struct iwl3945_priv *priv, const u8 *addr, int is_ap) { int index = IWL_INVALID_STATION; @@ -442,6 +434,12 @@ out: return 0; } #endif + +/** + * iwl3945_clear_stations_table - Clear the driver's station table + * + * NOTE: This does not clear or otherwise alter the device's station table. + */ static void iwl3945_clear_stations_table(struct iwl3945_priv *priv) { unsigned long flags; @@ -454,7 +452,9 @@ static void iwl3945_clear_stations_table(struct iwl3945_priv *priv) spin_unlock_irqrestore(&priv->sta_lock, flags); } - +/** + * iwl3945_add_station - Add station to station tables in driver and device + */ u8 iwl3945_add_station(struct iwl3945_priv *priv, const u8 *addr, int is_ap, u8 flags) { int i; @@ -500,13 +500,14 @@ u8 iwl3945_add_station(struct iwl3945_priv *priv, const u8 *addr, int is_ap, u8 station->used = 1; priv->num_stations++; + /* Set up the REPLY_ADD_STA command to send to device */ memset(&station->sta, 0, sizeof(struct iwl3945_addsta_cmd)); memcpy(station->sta.sta.addr, addr, ETH_ALEN); station->sta.mode = 0; station->sta.sta.sta_id = index; station->sta.station_flags = 0; - if (priv->phymode == MODE_IEEE80211A) + if (priv->band == IEEE80211_BAND_5GHZ) rate = IWL_RATE_6M_PLCP; else rate = IWL_RATE_1M_PLCP; @@ -518,6 +519,8 @@ u8 iwl3945_add_station(struct iwl3945_priv *priv, const u8 *addr, int is_ap, u8 le16_to_cpu(station->sta.rate_n_flags); spin_unlock_irqrestore(&priv->sta_lock, flags_spin); + + /* Add station to device's station table */ iwl3945_send_add_station(priv, &station->sta, flags); return index; @@ -644,6 +647,12 @@ static int iwl3945_enqueue_hcmd(struct iwl3945_priv *priv, struct iwl3945_host_c BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && !(cmd->meta.flags & CMD_SIZE_HUGE)); + + if (iwl3945_is_rfkill(priv)) { + IWL_DEBUG_INFO("Not sending command - RF KILL"); + return -EIO; + } + if (iwl3945_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) { IWL_ERROR("No space for Tx\n"); return -ENOSPC; @@ -687,7 +696,9 @@ static int iwl3945_enqueue_hcmd(struct iwl3945_priv *priv, struct iwl3945_host_c fix_size, q->write_ptr, idx, IWL_CMD_QUEUE_NUM); txq->need_update = 1; - q->write_ptr = iwl3945_queue_inc_wrap(q->write_ptr, q->n_bd); + + /* Increment and update queue's write index */ + q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); ret = iwl3945_tx_queue_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->hcmd_lock, flags); @@ -843,35 +854,37 @@ int iwl3945_send_statistics_request(struct iwl3945_priv *priv) /** * iwl3945_set_rxon_channel - Set the phymode and channel values in staging RXON - * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz - * @channel: Any channel valid for the requested phymode + * @band: 2.4 or 5 GHz band + * @channel: Any channel valid for the requested band - * In addition to setting the staging RXON, priv->phymode is also set. + * In addition to setting the staging RXON, priv->band is also set. * * NOTE: Does not commit to the hardware; it sets appropriate bit fields - * in the staging RXON flag structure based on the phymode + * in the staging RXON flag structure based on the band */ -static int iwl3945_set_rxon_channel(struct iwl3945_priv *priv, u8 phymode, u16 channel) +static int iwl3945_set_rxon_channel(struct iwl3945_priv *priv, + enum ieee80211_band band, + u16 channel) { - if (!iwl3945_get_channel_info(priv, phymode, channel)) { + if (!iwl3945_get_channel_info(priv, band, channel)) { IWL_DEBUG_INFO("Could not set channel to %d [%d]\n", - channel, phymode); + channel, band); return -EINVAL; } if ((le16_to_cpu(priv->staging_rxon.channel) == channel) && - (priv->phymode == phymode)) + (priv->band == band)) return 0; priv->staging_rxon.channel = cpu_to_le16(channel); - if (phymode == MODE_IEEE80211A) + if (band == IEEE80211_BAND_5GHZ) priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK; else priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK; - priv->phymode = phymode; + priv->band = band; - IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, phymode); + IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, band); return 0; } @@ -956,12 +969,12 @@ static int iwl3945_check_rxon_cmd(struct iwl3945_rxon_cmd *rxon) } /** - * iwl3945_full_rxon_required - determine if RXON_ASSOC can be used in RXON commit + * iwl3945_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed * @priv: staging_rxon is compared to active_rxon * - * If the RXON structure is changing sufficient to require a new - * tune or to clear and reset the RXON_FILTER_ASSOC_MSK then return 1 - * to indicate a new tune is required. + * If the RXON structure is changing enough to require a new tune, + * or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that + * a new tune (full RXON command, rather than RXON_ASSOC cmd) is required. */ static int iwl3945_full_rxon_required(struct iwl3945_priv *priv) { @@ -1159,8 +1172,7 @@ static int iwl3945_commit_rxon(struct iwl3945_priv *priv) return -EIO; } - /* Init the hardware's rate fallback order based on the - * phymode */ + /* Init the hardware's rate fallback order based on the band */ rc = iwl3945_init_hw_rate_table(priv); if (rc) { IWL_ERROR("Error setting HW rate table: %02X\n", rc); @@ -1235,7 +1247,7 @@ static int iwl3945_card_state_sync_callback(struct iwl3945_priv *priv, /* * CARD_STATE_CMD * - * Use: Sets the internal card state to enable, disable, or halt + * Use: Sets the device's internal card state to enable, disable, or halt * * When in the 'enable' state the card operates as normal. * When in the 'disable' state, the card enters into a low power mode. @@ -1452,16 +1464,6 @@ unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv, return priv->ibss_beacon->len; } -static int iwl3945_rate_index_from_plcp(int plcp) -{ - int i = 0; - - for (i = 0; i < IWL_RATE_COUNT; i++) - if (iwl3945_rates[i].plcp == plcp) - return i; - return -1; -} - static u8 iwl3945_rate_get_lowest_plcp(int rate_mask) { u8 i; @@ -1522,10 +1524,24 @@ static void get_eeprom_mac(struct iwl3945_priv *priv, u8 *mac) memcpy(mac, priv->eeprom.mac_address, 6); } +/* + * Clear the OWNER_MSK, to establish driver (instead of uCode running on + * embedded controller) as EEPROM reader; each read is a series of pulses + * to/from the EEPROM chip, not a single event, so even reads could conflict + * if they weren't arbitrated by some ownership mechanism. Here, the driver + * simply claims ownership, which should be safe when this function is called + * (i.e. before loading uCode!). + */ +static inline int iwl3945_eeprom_acquire_semaphore(struct iwl3945_priv *priv) +{ + _iwl3945_clear_bit(priv, CSR_EEPROM_GP, CSR_EEPROM_GP_IF_OWNER_MSK); + return 0; +} + /** * iwl3945_eeprom_init - read EEPROM contents * - * Load the EEPROM from adapter into priv->eeprom + * Load the EEPROM contents from adapter into priv->eeprom * * NOTE: This routine uses the non-debug IO access functions. */ @@ -1550,6 +1566,7 @@ int iwl3945_eeprom_init(struct iwl3945_priv *priv) return -ENOENT; } + /* Make sure driver (instead of uCode) is allowed to read EEPROM */ rc = iwl3945_eeprom_acquire_semaphore(priv); if (rc < 0) { IWL_ERROR("Failed to acquire EEPROM semaphore.\n"); @@ -1573,162 +1590,12 @@ int iwl3945_eeprom_init(struct iwl3945_priv *priv) IWL_ERROR("Time out reading EEPROM[%d]", addr); return -ETIMEDOUT; } - e[addr / 2] = le16_to_cpu(r >> 16); + e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); } return 0; } -/****************************************************************************** - * - * Misc. internal state and helper functions - * - ******************************************************************************/ -#ifdef CONFIG_IWL3945_DEBUG - -/** - * iwl3945_report_frame - dump frame to syslog during debug sessions - * - * hack this function to show different aspects of received frames, - * including selective frame dumps. - * group100 parameter selects whether to show 1 out of 100 good frames. - * - * TODO: ieee80211_hdr stuff is common to 3945 and 4965, so frame type - * info output is okay, but some of this stuff (e.g. iwl3945_rx_frame_stats) - * is 3945-specific and gives bad output for 4965. Need to split the - * functionality, keep common stuff here. - */ -void iwl3945_report_frame(struct iwl3945_priv *priv, - struct iwl3945_rx_packet *pkt, - struct ieee80211_hdr *header, int group100) -{ - u32 to_us; - u32 print_summary = 0; - u32 print_dump = 0; /* set to 1 to dump all frames' contents */ - u32 hundred = 0; - u32 dataframe = 0; - u16 fc; - u16 seq_ctl; - u16 channel; - u16 phy_flags; - int rate_sym; - u16 length; - u16 status; - u16 bcn_tmr; - u32 tsf_low; - u64 tsf; - u8 rssi; - u8 agc; - u16 sig_avg; - u16 noise_diff; - struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); - struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); - struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); - u8 *data = IWL_RX_DATA(pkt); - - /* MAC header */ - fc = le16_to_cpu(header->frame_control); - seq_ctl = le16_to_cpu(header->seq_ctrl); - - /* metadata */ - channel = le16_to_cpu(rx_hdr->channel); - phy_flags = le16_to_cpu(rx_hdr->phy_flags); - rate_sym = rx_hdr->rate; - length = le16_to_cpu(rx_hdr->len); - - /* end-of-frame status and timestamp */ - status = le32_to_cpu(rx_end->status); - bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp); - tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff; - tsf = le64_to_cpu(rx_end->timestamp); - - /* signal statistics */ - rssi = rx_stats->rssi; - agc = rx_stats->agc; - sig_avg = le16_to_cpu(rx_stats->sig_avg); - noise_diff = le16_to_cpu(rx_stats->noise_diff); - - to_us = !compare_ether_addr(header->addr1, priv->mac_addr); - - /* if data frame is to us and all is good, - * (optionally) print summary for only 1 out of every 100 */ - if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) == - (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) { - dataframe = 1; - if (!group100) - print_summary = 1; /* print each frame */ - else if (priv->framecnt_to_us < 100) { - priv->framecnt_to_us++; - print_summary = 0; - } else { - priv->framecnt_to_us = 0; - print_summary = 1; - hundred = 1; - } - } else { - /* print summary for all other frames */ - print_summary = 1; - } - - if (print_summary) { - char *title; - u32 rate; - - if (hundred) - title = "100Frames"; - else if (fc & IEEE80211_FCTL_RETRY) - title = "Retry"; - else if (ieee80211_is_assoc_response(fc)) - title = "AscRsp"; - else if (ieee80211_is_reassoc_response(fc)) - title = "RasRsp"; - else if (ieee80211_is_probe_response(fc)) { - title = "PrbRsp"; - print_dump = 1; /* dump frame contents */ - } else if (ieee80211_is_beacon(fc)) { - title = "Beacon"; - print_dump = 1; /* dump frame contents */ - } else if (ieee80211_is_atim(fc)) - title = "ATIM"; - else if (ieee80211_is_auth(fc)) - title = "Auth"; - else if (ieee80211_is_deauth(fc)) - title = "DeAuth"; - else if (ieee80211_is_disassoc(fc)) - title = "DisAssoc"; - else - title = "Frame"; - - rate = iwl3945_rate_index_from_plcp(rate_sym); - if (rate == -1) - rate = 0; - else - rate = iwl3945_rates[rate].ieee / 2; - - /* print frame summary. - * MAC addresses show just the last byte (for brevity), - * but you can hack it to show more, if you'd like to. */ - if (dataframe) - IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, " - "len=%u, rssi=%d, chnl=%d, rate=%u, \n", - title, fc, header->addr1[5], - length, rssi, channel, rate); - else { - /* src/dst addresses assume managed mode */ - IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, " - "src=0x%02x, rssi=%u, tim=%lu usec, " - "phy=0x%02x, chnl=%d\n", - title, fc, header->addr1[5], - header->addr3[5], rssi, - tsf_low - priv->scan_start_tsf, - phy_flags, channel); - } - } - if (print_dump) - iwl3945_print_hex_dump(IWL_DL_RX, data, length); -} -#endif - static void iwl3945_unset_hw_setting(struct iwl3945_priv *priv) { if (priv->hw_setting.shared_virt) @@ -1864,7 +1731,6 @@ static u16 iwl3945_fill_probe_req(struct iwl3945_priv *priv, /* * QoS support */ -#ifdef CONFIG_IWL3945_QOS static int iwl3945_send_qos_params_command(struct iwl3945_priv *priv, struct iwl3945_qosparam_cmd *qos) { @@ -1993,7 +1859,6 @@ static void iwl3945_activate_qos(struct iwl3945_priv *priv, u8 force) } } -#endif /* CONFIG_IWL3945_QOS */ /* * Power management (not Tx power!) functions */ @@ -2139,7 +2004,7 @@ static int iwl3945_update_power_cmd(struct iwl3945_priv *priv, static int iwl3945_send_power_mode(struct iwl3945_priv *priv, u32 mode) { - u32 final_mode = mode; + u32 uninitialized_var(final_mode); int rc; struct iwl3945_powertable_cmd cmd; @@ -2193,39 +2058,13 @@ int iwl3945_is_network_packet(struct iwl3945_priv *priv, struct ieee80211_hdr *h return !compare_ether_addr(header->addr2, priv->bssid); /* packets to our adapter go through */ return !compare_ether_addr(header->addr1, priv->mac_addr); + default: + return 1; } return 1; } -#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x - -static const char *iwl3945_get_tx_fail_reason(u32 status) -{ - switch (status & TX_STATUS_MSK) { - case TX_STATUS_SUCCESS: - return "SUCCESS"; - TX_STATUS_ENTRY(SHORT_LIMIT); - TX_STATUS_ENTRY(LONG_LIMIT); - TX_STATUS_ENTRY(FIFO_UNDERRUN); - TX_STATUS_ENTRY(MGMNT_ABORT); - TX_STATUS_ENTRY(NEXT_FRAG); - TX_STATUS_ENTRY(LIFE_EXPIRE); - TX_STATUS_ENTRY(DEST_PS); - TX_STATUS_ENTRY(ABORTED); - TX_STATUS_ENTRY(BT_RETRY); - TX_STATUS_ENTRY(STA_INVALID); - TX_STATUS_ENTRY(FRAG_DROPPED); - TX_STATUS_ENTRY(TID_DISABLE); - TX_STATUS_ENTRY(FRAME_FLUSHED); - TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL); - TX_STATUS_ENTRY(TX_LOCKED); - TX_STATUS_ENTRY(NO_BEACON_ON_RADAR); - } - - return "UNKNOWN"; -} - /** * iwl3945_scan_cancel - Cancel any currently executing HW scan * @@ -2410,9 +2249,10 @@ static int iwl3945_set_rxon_hwcrypto(struct iwl3945_priv *priv, int hw_decrypt) return 0; } -static void iwl3945_set_flags_for_phymode(struct iwl3945_priv *priv, u8 phymode) +static void iwl3945_set_flags_for_phymode(struct iwl3945_priv *priv, + enum ieee80211_band band) { - if (phymode == MODE_IEEE80211A) { + if (band == IEEE80211_BAND_5GHZ) { priv->staging_rxon.flags &= ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_CCK_MSK); @@ -2464,6 +2304,9 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv) priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK | RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK; break; + default: + IWL_ERROR("Unsupported interface type %d\n", priv->iw_mode); + break; } #if 0 @@ -2475,7 +2318,7 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv) priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; #endif - ch_info = iwl3945_get_channel_info(priv, priv->phymode, + ch_info = iwl3945_get_channel_info(priv, priv->band, le16_to_cpu(priv->staging_rxon.channel)); if (!ch_info) @@ -2491,11 +2334,11 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv) priv->staging_rxon.channel = cpu_to_le16(ch_info->channel); if (is_channel_a_band(ch_info)) - priv->phymode = MODE_IEEE80211A; + priv->band = IEEE80211_BAND_5GHZ; else - priv->phymode = MODE_IEEE80211G; + priv->band = IEEE80211_BAND_2GHZ; - iwl3945_set_flags_for_phymode(priv, priv->phymode); + iwl3945_set_flags_for_phymode(priv, priv->band); priv->staging_rxon.ofdm_basic_rates = (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; @@ -2505,14 +2348,11 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv) static int iwl3945_set_mode(struct iwl3945_priv *priv, int mode) { - if (!iwl3945_is_ready_rf(priv)) - return -EAGAIN; - if (mode == IEEE80211_IF_TYPE_IBSS) { const struct iwl3945_channel_info *ch_info; ch_info = iwl3945_get_channel_info(priv, - priv->phymode, + priv->band, le16_to_cpu(priv->staging_rxon.channel)); if (!ch_info || !is_channel_ibss(ch_info)) { @@ -2522,13 +2362,6 @@ static int iwl3945_set_mode(struct iwl3945_priv *priv, int mode) } } - cancel_delayed_work(&priv->scan_check); - if (iwl3945_scan_cancel_timeout(priv, 100)) { - IWL_WARNING("Aborted scan still in progress after 100ms\n"); - IWL_DEBUG_MAC80211("leaving - scan abort failed.\n"); - return -EAGAIN; - } - priv->iw_mode = mode; iwl3945_connection_init_rx_config(priv); @@ -2536,6 +2369,17 @@ static int iwl3945_set_mode(struct iwl3945_priv *priv, int mode) iwl3945_clear_stations_table(priv); + /* dont commit rxon if rf-kill is on*/ + if (!iwl3945_is_ready_rf(priv)) + return -EAGAIN; + + cancel_delayed_work(&priv->scan_check); + if (iwl3945_scan_cancel_timeout(priv, 100)) { + IWL_WARNING("Aborted scan still in progress after 100ms\n"); + IWL_DEBUG_MAC80211("leaving - scan abort failed.\n"); + return -EAGAIN; + } + iwl3945_commit_rxon(priv); return 0; @@ -2642,29 +2486,35 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv, cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(3); else cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(2); - } else + } else { cmd->cmd.tx.timeout.pm_frame_timeout = 0; +#ifdef CONFIG_IWL3945_LEDS + priv->rxtxpackets += le16_to_cpu(cmd->cmd.tx.len); +#endif + } cmd->cmd.tx.driver_txop = 0; cmd->cmd.tx.tx_flags = tx_flags; cmd->cmd.tx.next_frame_len = 0; } +/** + * iwl3945_get_sta_id - Find station's index within station table + */ static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *hdr) { int sta_id; u16 fc = le16_to_cpu(hdr->frame_control); - /* If this frame is broadcast or not data then use the broadcast - * station id */ + /* If this frame is broadcast or management, use broadcast station id */ if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) || is_multicast_ether_addr(hdr->addr1)) return priv->hw_setting.bcast_sta_id; switch (priv->iw_mode) { - /* If this frame is part of a BSS network (we're a station), then - * we use the AP's station id */ + /* If we are a client station in a BSS network, use the special + * AP station entry (that's the only station we communicate with) */ case IEEE80211_IF_TYPE_STA: return IWL_AP_ID; @@ -2675,11 +2525,12 @@ static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *h return sta_id; return priv->hw_setting.bcast_sta_id; - /* If this frame is part of a IBSS network, then we use the - * target specific station id */ + /* If this frame is going out to an IBSS network, find the station, + * or create a new station table entry */ case IEEE80211_IF_TYPE_IBSS: { DECLARE_MAC_BUF(mac); + /* Create new station table entry */ sta_id = iwl3945_hw_find_station(priv, hdr->addr1); if (sta_id != IWL_INVALID_STATION) return sta_id; @@ -2732,12 +2583,12 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, goto drop_unlock; } - if (!priv->interface_id) { - IWL_DEBUG_DROP("Dropping - !priv->interface_id\n"); + if (!priv->vif) { + IWL_DEBUG_DROP("Dropping - !priv->vif\n"); goto drop_unlock; } - if ((ctl->tx_rate & 0xFF) == IWL_INVALID_RATE) { + if ((ctl->tx_rate->hw_value & 0xFF) == IWL_INVALID_RATE) { IWL_ERROR("ERROR: No TX rate available.\n"); goto drop_unlock; } @@ -2756,7 +2607,9 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, IWL_DEBUG_TX("Sending REASSOC frame\n"); #endif - if (!iwl3945_is_associated(priv) && + /* drop all data frame if we are not associated */ + if ((!iwl3945_is_associated(priv) || + ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id)) && ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) { IWL_DEBUG_DROP("Dropping - !iwl3945_is_associated\n"); goto drop_unlock; @@ -2765,6 +2618,8 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, spin_unlock_irqrestore(&priv->lock, flags); hdr_len = ieee80211_get_hdrlen(fc); + + /* Find (or create) index into station table for destination station */ sta_id = iwl3945_get_sta_id(priv, hdr); if (sta_id == IWL_INVALID_STATION) { DECLARE_MAC_BUF(mac); @@ -2786,30 +2641,52 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, __constant_cpu_to_le16(IEEE80211_SCTL_FRAG)); seq_number += 0x10; } + + /* Descriptor for chosen Tx queue */ txq = &priv->txq[txq_id]; q = &txq->q; spin_lock_irqsave(&priv->lock, flags); + /* Set up first empty TFD within this queue's circular TFD buffer */ tfd = &txq->bd[q->write_ptr]; memset(tfd, 0, sizeof(*tfd)); control_flags = (u32 *) tfd; idx = get_cmd_index(q, q->write_ptr, 0); + /* Set up driver data for this TFD */ memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl3945_tx_info)); txq->txb[q->write_ptr].skb[0] = skb; memcpy(&(txq->txb[q->write_ptr].status.control), ctl, sizeof(struct ieee80211_tx_control)); + + /* Init first empty entry in queue's array of Tx/cmd buffers */ out_cmd = &txq->cmd[idx]; memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr)); memset(&out_cmd->cmd.tx, 0, sizeof(out_cmd->cmd.tx)); + + /* + * Set up the Tx-command (not MAC!) header. + * Store the chosen Tx queue and TFD index within the sequence field; + * after Tx, uCode's Tx response will return this value so driver can + * locate the frame within the tx queue and do post-tx processing. + */ out_cmd->hdr.cmd = REPLY_TX; out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) | INDEX_TO_SEQ(q->write_ptr))); - /* copy frags header */ + + /* Copy MAC header from skb into command buffer */ memcpy(out_cmd->cmd.tx.hdr, hdr, hdr_len); - /* hdr = (struct ieee80211_hdr *)out_cmd->cmd.tx.hdr; */ + /* + * Use the first empty entry in this queue's command buffer array + * to contain the Tx command and MAC header concatenated together + * (payload data will be in another buffer). + * Size of this varies, due to varying MAC header length. + * If end is not dword aligned, we'll have 2 extra bytes at the end + * of the MAC header (device reads on dword boundaries). + * We'll tell device about this padding later. + */ len = priv->hw_setting.tx_cmd_len + sizeof(struct iwl3945_cmd_header) + hdr_len; @@ -2821,15 +2698,20 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, else len_org = 0; + /* Physical address of this Tx command's header (not MAC header!), + * within command buffer array. */ txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl3945_cmd) * idx + offsetof(struct iwl3945_cmd, hdr); + /* Add buffer containing Tx command and MAC(!) header to TFD's + * first entry */ iwl3945_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) iwl3945_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0); - /* 802.11 null functions have no payload... */ + /* Set up TFD's 2nd entry to point directly to remainder of skb, + * if any (802.11 null frames have no payload). */ len = skb->len - hdr_len; if (len) { phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len, @@ -2837,13 +2719,16 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, iwl3945_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len); } - /* If there is no payload, then only one TFD is used */ if (!len) + /* If there is no payload, then we use only one Tx buffer */ *control_flags = TFD_CTL_COUNT_SET(1); else + /* Else use 2 buffers. + * Tell 3945 about any padding after MAC header */ *control_flags = TFD_CTL_COUNT_SET(2) | TFD_CTL_PAD_SET(U32_PAD(len)); + /* Total # bytes to be transmitted */ len = (u16)skb->len; out_cmd->cmd.tx.len = cpu_to_le16(len); @@ -2873,7 +2758,8 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, iwl3945_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr, ieee80211_get_hdrlen(fc)); - q->write_ptr = iwl3945_queue_inc_wrap(q->write_ptr, q->n_bd); + /* Tell device the write index *just past* this latest filled TFD */ + q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); rc = iwl3945_tx_queue_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->lock, flags); @@ -2902,12 +2788,12 @@ drop: static void iwl3945_set_rate(struct iwl3945_priv *priv) { - const struct ieee80211_hw_mode *hw = NULL; + const struct ieee80211_supported_band *sband = NULL; struct ieee80211_rate *rate; int i; - hw = iwl3945_get_hw_mode(priv, priv->phymode); - if (!hw) { + sband = iwl3945_get_band(priv, priv->band); + if (!sband) { IWL_ERROR("Failed to set rate: unable to get hw mode\n"); return; } @@ -2915,24 +2801,17 @@ static void iwl3945_set_rate(struct iwl3945_priv *priv) priv->active_rate = 0; priv->active_rate_basic = 0; - IWL_DEBUG_RATE("Setting rates for 802.11%c\n", - hw->mode == MODE_IEEE80211A ? - 'a' : ((hw->mode == MODE_IEEE80211B) ? 'b' : 'g')); - - for (i = 0; i < hw->num_rates; i++) { - rate = &(hw->rates[i]); - if ((rate->val < IWL_RATE_COUNT) && - (rate->flags & IEEE80211_RATE_SUPPORTED)) { - IWL_DEBUG_RATE("Adding rate index %d (plcp %d)%s\n", - rate->val, iwl3945_rates[rate->val].plcp, - (rate->flags & IEEE80211_RATE_BASIC) ? - "*" : ""); - priv->active_rate |= (1 << rate->val); - if (rate->flags & IEEE80211_RATE_BASIC) - priv->active_rate_basic |= (1 << rate->val); - } else - IWL_DEBUG_RATE("Not adding rate %d (plcp %d)\n", - rate->val, iwl3945_rates[rate->val].plcp); + IWL_DEBUG_RATE("Setting rates for %s GHz\n", + sband->band == IEEE80211_BAND_2GHZ ? "2.4" : "5"); + + for (i = 0; i < sband->n_bitrates; i++) { + rate = &sband->bitrates[i]; + if ((rate->hw_value < IWL_RATE_COUNT) && + !(rate->flags & IEEE80211_CHAN_DISABLED)) { + IWL_DEBUG_RATE("Adding rate index %d (plcp %d)\n", + rate->hw_value, iwl3945_rates[rate->hw_value].plcp); + priv->active_rate |= (1 << rate->hw_value); + } } IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n", @@ -3042,94 +2921,6 @@ void iwl3945_set_decrypted_flag(struct iwl3945_priv *priv, struct sk_buff *skb, } } -void iwl3945_handle_data_packet_monitor(struct iwl3945_priv *priv, - struct iwl3945_rx_mem_buffer *rxb, - void *data, short len, - struct ieee80211_rx_status *stats, - u16 phy_flags) -{ - struct iwl3945_rt_rx_hdr *iwl3945_rt; - - /* First cache any information we need before we overwrite - * the information provided in the skb from the hardware */ - s8 signal = stats->ssi; - s8 noise = 0; - int rate = stats->rate; - u64 tsf = stats->mactime; - __le16 phy_flags_hw = cpu_to_le16(phy_flags); - - /* We received data from the HW, so stop the watchdog */ - if (len > IWL_RX_BUF_SIZE - sizeof(*iwl3945_rt)) { - IWL_DEBUG_DROP("Dropping too large packet in monitor\n"); - return; - } - - /* copy the frame data to write after where the radiotap header goes */ - iwl3945_rt = (void *)rxb->skb->data; - memmove(iwl3945_rt->payload, data, len); - - iwl3945_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; - iwl3945_rt->rt_hdr.it_pad = 0; /* always good to zero */ - - /* total header + data */ - iwl3945_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*iwl3945_rt)); - - /* Set the size of the skb to the size of the frame */ - skb_put(rxb->skb, sizeof(*iwl3945_rt) + len); - - /* Big bitfield of all the fields we provide in radiotap */ - iwl3945_rt->rt_hdr.it_present = - cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) | - (1 << IEEE80211_RADIOTAP_FLAGS) | - (1 << IEEE80211_RADIOTAP_RATE) | - (1 << IEEE80211_RADIOTAP_CHANNEL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | - (1 << IEEE80211_RADIOTAP_ANTENNA)); - - /* Zero the flags, we'll add to them as we go */ - iwl3945_rt->rt_flags = 0; - - iwl3945_rt->rt_tsf = cpu_to_le64(tsf); - - /* Convert to dBm */ - iwl3945_rt->rt_dbmsignal = signal; - iwl3945_rt->rt_dbmnoise = noise; - - /* Convert the channel frequency and set the flags */ - iwl3945_rt->rt_channelMHz = cpu_to_le16(stats->freq); - if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK)) - iwl3945_rt->rt_chbitmask = - cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ)); - else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK) - iwl3945_rt->rt_chbitmask = - cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ)); - else /* 802.11g */ - iwl3945_rt->rt_chbitmask = - cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ)); - - rate = iwl3945_rate_index_from_plcp(rate); - if (rate == -1) - iwl3945_rt->rt_rate = 0; - else - iwl3945_rt->rt_rate = iwl3945_rates[rate].ieee; - - /* antenna number */ - iwl3945_rt->rt_antenna = - le16_to_cpu(phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4; - - /* set the preamble flag if we have it */ - if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) - iwl3945_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; - - IWL_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len); - - stats->flag |= RX_FLAG_RADIOTAP; - ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); - rxb->skb = NULL; -} - - #define IWL_PACKET_RETRY_TIME HZ int iwl3945_is_duplicate_packet(struct iwl3945_priv *priv, struct ieee80211_hdr *header) @@ -3328,124 +3119,6 @@ static int iwl3945_get_measurement(struct iwl3945_priv *priv, } #endif -static void iwl3945_txstatus_to_ieee(struct iwl3945_priv *priv, - struct iwl3945_tx_info *tx_sta) -{ - - tx_sta->status.ack_signal = 0; - tx_sta->status.excessive_retries = 0; - tx_sta->status.queue_length = 0; - tx_sta->status.queue_number = 0; - - if (in_interrupt()) - ieee80211_tx_status_irqsafe(priv->hw, - tx_sta->skb[0], &(tx_sta->status)); - else - ieee80211_tx_status(priv->hw, - tx_sta->skb[0], &(tx_sta->status)); - - tx_sta->skb[0] = NULL; -} - -/** - * iwl3945_tx_queue_reclaim - Reclaim Tx queue entries no more used by NIC. - * - * When FW advances 'R' index, all entries between old and - * new 'R' index need to be reclaimed. As result, some free space - * forms. If there is enough free space (> low mark), wake Tx queue. - */ -static int iwl3945_tx_queue_reclaim(struct iwl3945_priv *priv, int txq_id, int index) -{ - struct iwl3945_tx_queue *txq = &priv->txq[txq_id]; - struct iwl3945_queue *q = &txq->q; - int nfreed = 0; - - if ((index >= q->n_bd) || (x2_queue_used(q, index) == 0)) { - IWL_ERROR("Read index for DMA queue txq id (%d), index %d, " - "is out of range [0-%d] %d %d.\n", txq_id, - index, q->n_bd, q->write_ptr, q->read_ptr); - return 0; - } - - for (index = iwl3945_queue_inc_wrap(index, q->n_bd); - q->read_ptr != index; - q->read_ptr = iwl3945_queue_inc_wrap(q->read_ptr, q->n_bd)) { - if (txq_id != IWL_CMD_QUEUE_NUM) { - iwl3945_txstatus_to_ieee(priv, - &(txq->txb[txq->q.read_ptr])); - iwl3945_hw_txq_free_tfd(priv, txq); - } else if (nfreed > 1) { - IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index, - q->write_ptr, q->read_ptr); - queue_work(priv->workqueue, &priv->restart); - } - nfreed++; - } - - if (iwl3945_queue_space(q) > q->low_mark && (txq_id >= 0) && - (txq_id != IWL_CMD_QUEUE_NUM) && - priv->mac80211_registered) - ieee80211_wake_queue(priv->hw, txq_id); - - - return nfreed; -} - -static int iwl3945_is_tx_success(u32 status) -{ - return (status & 0xFF) == 0x1; -} - -/****************************************************************************** - * - * Generic RX handler implementations - * - ******************************************************************************/ -static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv, - struct iwl3945_rx_mem_buffer *rxb) -{ - struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data; - u16 sequence = le16_to_cpu(pkt->hdr.sequence); - int txq_id = SEQ_TO_QUEUE(sequence); - int index = SEQ_TO_INDEX(sequence); - struct iwl3945_tx_queue *txq = &priv->txq[txq_id]; - struct ieee80211_tx_status *tx_status; - struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; - u32 status = le32_to_cpu(tx_resp->status); - - if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) { - IWL_ERROR("Read index for DMA queue txq_id (%d) index %d " - "is out of range [0-%d] %d %d\n", txq_id, - index, txq->q.n_bd, txq->q.write_ptr, - txq->q.read_ptr); - return; - } - - tx_status = &(txq->txb[txq->q.read_ptr].status); - - tx_status->retry_count = tx_resp->failure_frame; - tx_status->queue_number = status; - tx_status->queue_length = tx_resp->bt_kill_count; - tx_status->queue_length |= tx_resp->failure_rts; - - tx_status->flags = - iwl3945_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0; - - tx_status->control.tx_rate = iwl3945_rate_index_from_plcp(tx_resp->rate); - - IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) plcp rate %d retries %d\n", - txq_id, iwl3945_get_tx_fail_reason(status), status, - tx_resp->rate, tx_resp->failure_frame); - - IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); - if (index != -1) - iwl3945_tx_queue_reclaim(priv, txq_id, index); - - if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) - IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); -} - - static void iwl3945_rx_reply_alive(struct iwl3945_priv *priv, struct iwl3945_rx_mem_buffer *rxb) { @@ -3565,7 +3238,7 @@ static void iwl3945_bg_beacon_update(struct work_struct *work) struct sk_buff *beacon; /* Pull updated AP beacon from mac80211. will fail if not in AP mode */ - beacon = ieee80211_beacon_get(priv->hw, priv->interface_id, NULL); + beacon = ieee80211_beacon_get(priv->hw, priv->vif, NULL); if (!beacon) { IWL_ERROR("update beacon failed\n"); @@ -3657,6 +3330,7 @@ static void iwl3945_rx_scan_results_notif(struct iwl3945_priv *priv, (priv->last_scan_jiffies, jiffies))); priv->last_scan_jiffies = jiffies; + priv->next_scan_jiffies = 0; } /* Service SCAN_COMPLETE_NOTIFICATION (0x84) */ @@ -3699,6 +3373,7 @@ static void iwl3945_rx_scan_complete_notif(struct iwl3945_priv *priv, } priv->last_scan_jiffies = jiffies; + priv->next_scan_jiffies = 0; IWL_DEBUG_INFO("Setting scan to off\n"); clear_bit(STATUS_SCANNING, &priv->status); @@ -3775,13 +3450,10 @@ static void iwl3945_setup_rx_handlers(struct iwl3945_priv *priv) iwl3945_rx_pm_debug_statistics_notif; priv->rx_handlers[BEACON_NOTIFICATION] = iwl3945_rx_beacon_notif; - /* NOTE: iwl3945_rx_statistics is different based on whether - * the build is for the 3945 or the 4965. See the - * corresponding implementation in iwl-XXXX.c - * - * The same handler is used for both the REPLY to a - * discrete statistics request from the host as well as - * for the periodic statistics notification from the uCode + /* + * The same handler is used for both the REPLY to a discrete + * statistics request from the host as well as for the periodic + * statistics notifications (after received beacons) from the uCode. */ priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl3945_hw_rx_statistics; priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl3945_hw_rx_statistics; @@ -3793,12 +3465,43 @@ static void iwl3945_setup_rx_handlers(struct iwl3945_priv *priv) priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] = iwl3945_rx_scan_complete_notif; priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl3945_rx_card_state_notif; - priv->rx_handlers[REPLY_TX] = iwl3945_rx_reply_tx; - /* Setup hardware specific Rx handlers */ + /* Set up hardware specific Rx handlers */ iwl3945_hw_rx_handler_setup(priv); } +/** + * iwl3945_cmd_queue_reclaim - Reclaim CMD queue entries + * When FW advances 'R' index, all entries between old and new 'R' index + * need to be reclaimed. + */ +static void iwl3945_cmd_queue_reclaim(struct iwl3945_priv *priv, + int txq_id, int index) +{ + struct iwl3945_tx_queue *txq = &priv->txq[txq_id]; + struct iwl3945_queue *q = &txq->q; + int nfreed = 0; + + if ((index >= q->n_bd) || (iwl3945_x2_queue_used(q, index) == 0)) { + IWL_ERROR("Read index for DMA queue txq id (%d), index %d, " + "is out of range [0-%d] %d %d.\n", txq_id, + index, q->n_bd, q->write_ptr, q->read_ptr); + return; + } + + for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index; + q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { + if (nfreed > 1) { + IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index, + q->write_ptr, q->read_ptr); + queue_work(priv->workqueue, &priv->restart); + break; + } + nfreed++; + } +} + + /** * iwl3945_tx_cmd_complete - Pull unused buffers off the queue and reclaim them * @rxb: Rx buffer to reclaim @@ -3818,12 +3521,6 @@ static void iwl3945_tx_cmd_complete(struct iwl3945_priv *priv, int cmd_index; struct iwl3945_cmd *cmd; - /* If a Tx command is being handled and it isn't in the actual - * command queue then there a command routing bug has been introduced - * in the queue management code. */ - if (txq_id != IWL_CMD_QUEUE_NUM) - IWL_ERROR("Error wrong command queue %d command id 0x%X\n", - txq_id, pkt->hdr.cmd); BUG_ON(txq_id != IWL_CMD_QUEUE_NUM); cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge); @@ -3837,7 +3534,7 @@ static void iwl3945_tx_cmd_complete(struct iwl3945_priv *priv, !cmd->meta.u.callback(priv, cmd, rxb->skb)) rxb->skb = NULL; - iwl3945_tx_queue_reclaim(priv, txq_id, index); + iwl3945_cmd_queue_reclaim(priv, txq_id, index); if (!(cmd->meta.flags & CMD_ASYNC)) { clear_bit(STATUS_HCMD_ACTIVE, &priv->status); @@ -3867,10 +3564,10 @@ static void iwl3945_tx_cmd_complete(struct iwl3945_priv *priv, * The queue is empty (no good data) if WRITE = READ - 1, and is full if * WRITE = READ. * - * During initialization the host sets up the READ queue position to the first + * During initialization, the host sets up the READ queue position to the first * INDEX position, and WRITE to the last (READ - 1 wrapped) * - * When the firmware places a packet in a buffer it will advance the READ index + * When the firmware places a packet in a buffer, it will advance the READ index * and fire the RX interrupt. The driver can then query the READ index and * process as many packets as possible, moving the WRITE index forward as it * resets the Rx queue buffers with new memory. @@ -3892,16 +3589,16 @@ static void iwl3945_tx_cmd_complete(struct iwl3945_priv *priv, * * Driver sequence: * - * iwl3945_rx_queue_alloc() Allocates rx_free - * iwl3945_rx_replenish() Replenishes rx_free list from rx_used, and calls + * iwl3945_rx_queue_alloc() Allocates rx_free + * iwl3945_rx_replenish() Replenishes rx_free list from rx_used, and calls * iwl3945_rx_queue_restock - * iwl3945_rx_queue_restock() Moves available buffers from rx_free into Rx + * iwl3945_rx_queue_restock() Moves available buffers from rx_free into Rx * queue, updates firmware pointers, and updates * the WRITE index. If insufficient rx_free buffers * are available, schedules iwl3945_rx_replenish * * -- enable interrupts -- - * ISR - iwl3945_rx() Detach iwl3945_rx_mem_buffers from pool up to the + * ISR - iwl3945_rx() Detach iwl3945_rx_mem_buffers from pool up to the * READ INDEX, detaching the SKB from the pool. * Moves the packet buffer from queue to rx_used. * Calls iwl3945_rx_queue_restock to refill any empty @@ -3927,12 +3624,6 @@ static int iwl3945_rx_queue_space(const struct iwl3945_rx_queue *q) /** * iwl3945_rx_queue_update_write_ptr - Update the write pointer for the RX queue - * - * NOTE: This function has 3945 and 4965 specific code sections - * but is declared in base due to the majority of the - * implementation being the same (only a numeric constant is - * different) - * */ int iwl3945_rx_queue_update_write_ptr(struct iwl3945_priv *priv, struct iwl3945_rx_queue *q) { @@ -3945,6 +3636,7 @@ int iwl3945_rx_queue_update_write_ptr(struct iwl3945_priv *priv, struct iwl3945_ if (q->need_update == 0) goto exit_unlock; + /* If power-saving is in use, make sure device is awake */ if (test_bit(STATUS_POWER_PMI, &priv->status)) { reg = iwl3945_read32(priv, CSR_UCODE_DRV_GP1); @@ -3958,10 +3650,14 @@ int iwl3945_rx_queue_update_write_ptr(struct iwl3945_priv *priv, struct iwl3945_ if (rc) goto exit_unlock; + /* Device expects a multiple of 8 */ iwl3945_write_direct32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7); iwl3945_release_nic_access(priv); + + /* Else device is assumed to be awake */ } else + /* Device expects a multiple of 8 */ iwl3945_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7); @@ -3973,9 +3669,7 @@ int iwl3945_rx_queue_update_write_ptr(struct iwl3945_priv *priv, struct iwl3945_ } /** - * iwl3945_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer pointer. - * - * NOTE: This function has 3945 and 4965 specific code paths in it. + * iwl3945_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr */ static inline __le32 iwl3945_dma_addr2rbd_ptr(struct iwl3945_priv *priv, dma_addr_t dma_addr) @@ -3986,9 +3680,9 @@ static inline __le32 iwl3945_dma_addr2rbd_ptr(struct iwl3945_priv *priv, /** * iwl3945_rx_queue_restock - refill RX queue from pre-allocated pool * - * If there are slots in the RX queue that need to be restocked, + * If there are slots in the RX queue that need to be restocked, * and we have free pre-allocated buffers, fill the ranks as much - * as we can pulling from rx_free. + * as we can, pulling from rx_free. * * This moves the 'write' index forward to catch up with 'processed', and * also updates the memory address in the firmware to reference the new @@ -4005,9 +3699,12 @@ static int iwl3945_rx_queue_restock(struct iwl3945_priv *priv) spin_lock_irqsave(&rxq->lock, flags); write = rxq->write & ~0x7; while ((iwl3945_rx_queue_space(rxq) > 0) && (rxq->free_count)) { + /* Get next free Rx buffer, remove from free list */ element = rxq->rx_free.next; rxb = list_entry(element, struct iwl3945_rx_mem_buffer, list); list_del(element); + + /* Point to Rx buffer via next RBD in circular buffer */ rxq->bd[rxq->write] = iwl3945_dma_addr2rbd_ptr(priv, rxb->dma_addr); rxq->queue[rxq->write] = rxb; rxq->write = (rxq->write + 1) & RX_QUEUE_MASK; @@ -4020,7 +3717,8 @@ static int iwl3945_rx_queue_restock(struct iwl3945_priv *priv) queue_work(priv->workqueue, &priv->rx_replenish); - /* If we've added more space for the firmware to place data, tell it */ + /* If we've added more space for the firmware to place data, tell it. + * Increment device's write pointer in multiples of 8. */ if ((write != (rxq->write & ~0x7)) || (abs(rxq->write - rxq->read) > 7)) { spin_lock_irqsave(&rxq->lock, flags); @@ -4042,9 +3740,8 @@ static int iwl3945_rx_queue_restock(struct iwl3945_priv *priv) * Also restock the Rx queue via iwl3945_rx_queue_restock. * This is called as a scheduled work item (except for during initialization) */ -void iwl3945_rx_replenish(void *data) +static void iwl3945_rx_allocate(struct iwl3945_priv *priv) { - struct iwl3945_priv *priv = data; struct iwl3945_rx_queue *rxq = &priv->rxq; struct list_head *element; struct iwl3945_rx_mem_buffer *rxb; @@ -4053,6 +3750,8 @@ void iwl3945_rx_replenish(void *data) while (!list_empty(&rxq->rx_used)) { element = rxq->rx_used.next; rxb = list_entry(element, struct iwl3945_rx_mem_buffer, list); + + /* Alloc a new receive buffer */ rxb->skb = alloc_skb(IWL_RX_BUF_SIZE, __GFP_NOWARN | GFP_ATOMIC); if (!rxb->skb) { @@ -4064,8 +3763,19 @@ void iwl3945_rx_replenish(void *data) * more buffers it will schedule replenish */ break; } + + /* If radiotap head is required, reserve some headroom here. + * The physical head count is a variable rx_stats->phy_count. + * We reserve 4 bytes here. Plus these extra bytes, the + * headroom of the physical head should be enough for the + * radiotap head that iwl3945 supported. See iwl3945_rt. + */ + skb_reserve(rxb->skb, 4); + priv->alloc_rxb_skb++; list_del(element); + + /* Get physical address of RB/SKB */ rxb->dma_addr = pci_map_single(priv->pci_dev, rxb->skb->data, IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); @@ -4073,23 +3783,43 @@ void iwl3945_rx_replenish(void *data) rxq->free_count++; } spin_unlock_irqrestore(&rxq->lock, flags); - - spin_lock_irqsave(&priv->lock, flags); - iwl3945_rx_queue_restock(priv); - spin_unlock_irqrestore(&priv->lock, flags); } -/* Assumes that the skb field of the buffers in 'pool' is kept accurate. - * If an SKB has been detached, the POOL needs to have it's SKB set to NULL - * This free routine walks the list of POOL entries and if SKB is set to - * non NULL it is unmapped and freed +/* + * this should be called while priv->lock is locked */ -static void iwl3945_rx_queue_free(struct iwl3945_priv *priv, struct iwl3945_rx_queue *rxq) +static void __iwl3945_rx_replenish(void *data) { - int i; - for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { - if (rxq->pool[i].skb != NULL) { - pci_unmap_single(priv->pci_dev, + struct iwl3945_priv *priv = data; + + iwl3945_rx_allocate(priv); + iwl3945_rx_queue_restock(priv); +} + + +void iwl3945_rx_replenish(void *data) +{ + struct iwl3945_priv *priv = data; + unsigned long flags; + + iwl3945_rx_allocate(priv); + + spin_lock_irqsave(&priv->lock, flags); + iwl3945_rx_queue_restock(priv); + spin_unlock_irqrestore(&priv->lock, flags); +} + +/* Assumes that the skb field of the buffers in 'pool' is kept accurate. + * If an SKB has been detached, the POOL needs to have its SKB set to NULL + * This free routine walks the list of POOL entries and if SKB is set to + * non NULL it is unmapped and freed + */ +static void iwl3945_rx_queue_free(struct iwl3945_priv *priv, struct iwl3945_rx_queue *rxq) +{ + int i; + for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { + if (rxq->pool[i].skb != NULL) { + pci_unmap_single(priv->pci_dev, rxq->pool[i].dma_addr, IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); dev_kfree_skb(rxq->pool[i].skb); @@ -4110,12 +3840,16 @@ int iwl3945_rx_queue_alloc(struct iwl3945_priv *priv) spin_lock_init(&rxq->lock); INIT_LIST_HEAD(&rxq->rx_free); INIT_LIST_HEAD(&rxq->rx_used); + + /* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */ rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr); if (!rxq->bd) return -ENOMEM; + /* Fill the rx_used queue with _all_ of the Rx buffers */ for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) list_add_tail(&rxq->pool[i].list, &rxq->rx_used); + /* Set us so that we have processed and used all buffers, but have * not restocked the Rx queue with fresh buffers */ rxq->read = rxq->write = 0; @@ -4173,13 +3907,13 @@ static u8 ratio2dB[100] = { * Conversion assumes that levels are voltages (20*log), not powers (10*log). */ int iwl3945_calc_db_from_ratio(int sig_ratio) { - /* Anything above 1000:1 just report as 60 dB */ - if (sig_ratio > 1000) + /* 1000:1 or higher just report as 60 dB */ + if (sig_ratio >= 1000) return 60; - /* Above 100:1, divide by 10 and use table, + /* 100:1 or higher, divide by 10 and use table, * add 20 dB to make up for divide by 10 */ - if (sig_ratio > 100) + if (sig_ratio >= 100) return (20 + (int)ratio2dB[sig_ratio/10]); /* We shouldn't see this */ @@ -4232,7 +3966,7 @@ int iwl3945_calc_sig_qual(int rssi_dbm, int noise_dbm) } /** - * iwl3945_rx_handle - Main entry function for receiving responses from the uCode + * iwl3945_rx_handle - Main entry function for receiving responses from uCode * * Uses the priv->rx_handlers callback function array to invoke * the appropriate handlers, including command responses, @@ -4246,10 +3980,16 @@ static void iwl3945_rx_handle(struct iwl3945_priv *priv) u32 r, i; int reclaim; unsigned long flags; + u8 fill_rx = 0; + u32 count = 8; + /* uCode's read index (stored in shared DRAM) indicates the last Rx + * buffer that the driver may process (last buffer filled by ucode). */ r = iwl3945_hw_get_rx_read(priv); i = rxq->read; + if (iwl3945_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2)) + fill_rx = 1; /* Rx interrupt, but nothing sent from uCode */ if (i == r) IWL_DEBUG(IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d\n", r, i); @@ -4257,7 +3997,7 @@ static void iwl3945_rx_handle(struct iwl3945_priv *priv) while (i != r) { rxb = rxq->queue[i]; - /* If an RXB doesn't have a queue slot associated with it + /* If an RXB doesn't have a Rx queue slot associated with it, * then a bug has been introduced in the queue refilling * routines -- catch it here */ BUG_ON(rxb == NULL); @@ -4296,8 +4036,8 @@ static void iwl3945_rx_handle(struct iwl3945_priv *priv) } if (reclaim) { - /* Invoke any callbacks, transfer the skb to caller, - * and fire off the (possibly) blocking iwl3945_send_cmd() + /* Invoke any callbacks, transfer the skb to caller, and + * fire off the (possibly) blocking iwl3945_send_cmd() * as we reclaim the driver command queue */ if (rxb && rxb->skb) iwl3945_tx_cmd_complete(priv, rxb); @@ -4320,6 +4060,16 @@ static void iwl3945_rx_handle(struct iwl3945_priv *priv) list_add_tail(&rxb->list, &priv->rxq.rx_used); spin_unlock_irqrestore(&rxq->lock, flags); i = (i + 1) & RX_QUEUE_MASK; + /* If there are a lot of unused frames, + * restock the Rx queue so ucode won't assert. */ + if (fill_rx) { + count++; + if (count >= 8) { + priv->rxq.read = i; + __iwl3945_rx_replenish(priv); + count = 0; + } + } } /* Backtrack one entry */ @@ -4327,6 +4077,9 @@ static void iwl3945_rx_handle(struct iwl3945_priv *priv) iwl3945_rx_queue_restock(priv); } +/** + * iwl3945_tx_queue_update_write_ptr - Send new write index to hardware + */ static int iwl3945_tx_queue_update_write_ptr(struct iwl3945_priv *priv, struct iwl3945_tx_queue *txq) { @@ -4400,6 +4153,16 @@ static void iwl3945_enable_interrupts(struct iwl3945_priv *priv) iwl3945_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK); } + +/* call this function to flush any scheduled tasklet */ +static inline void iwl_synchronize_irq(struct iwl3945_priv *priv) +{ + /* wait to make sure we flush pedding tasklet*/ + synchronize_irq(priv->pci_dev->irq); + tasklet_kill(&priv->irq_tasklet); +} + + static inline void iwl3945_disable_interrupts(struct iwl3945_priv *priv) { clear_bit(STATUS_INT_ENABLED, &priv->status); @@ -4461,8 +4224,7 @@ static void iwl3945_dump_nic_error_log(struct iwl3945_priv *priv) if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { IWL_ERROR("Start IWL Error Log Dump:\n"); - IWL_ERROR("Status: 0x%08lX, Config: %08X count: %d\n", - priv->status, priv->config, count); + IWL_ERROR("Status: 0x%08lX, count: %d\n", priv->status, count); } IWL_ERROR("Desc Time asrtPC blink2 " @@ -4494,7 +4256,7 @@ static void iwl3945_dump_nic_error_log(struct iwl3945_priv *priv) } -#define EVENT_START_OFFSET (4 * sizeof(u32)) +#define EVENT_START_OFFSET (6 * sizeof(u32)) /** * iwl3945_print_event_log - Dump error event log to syslog @@ -4671,7 +4433,8 @@ static void iwl3945_irq_tasklet(struct iwl3945_priv *priv) #ifdef CONFIG_IWL3945_DEBUG if (iwl3945_debug_level & IWL_DL_ISR) { - inta_mask = iwl3945_read32(priv, CSR_INT_MASK); /* just for debug */ + /* just for debug */ + inta_mask = iwl3945_read32(priv, CSR_INT_MASK); IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", inta, inta_mask, inta_fh); } @@ -4681,9 +4444,9 @@ static void iwl3945_irq_tasklet(struct iwl3945_priv *priv) * atomic, make sure that inta covers all the interrupts that * we've discovered, even if FH interrupt came in just after * reading CSR_INT. */ - if (inta_fh & CSR_FH_INT_RX_MASK) + if (inta_fh & CSR39_FH_INT_RX_MASK) inta |= CSR_INT_BIT_FH_RX; - if (inta_fh & CSR_FH_INT_TX_MASK) + if (inta_fh & CSR39_FH_INT_TX_MASK) inta |= CSR_INT_BIT_FH_TX; /* Now service all interrupt bits discovered above. */ @@ -4705,8 +4468,9 @@ static void iwl3945_irq_tasklet(struct iwl3945_priv *priv) #ifdef CONFIG_IWL3945_DEBUG if (iwl3945_debug_level & (IWL_DL_ISR)) { /* NIC fires this, but we don't use it, redundant with WAKEUP */ - if (inta & CSR_INT_BIT_MAC_CLK_ACTV) - IWL_DEBUG_ISR("Microcode started or stopped.\n"); + if (inta & CSR_INT_BIT_SCD) + IWL_DEBUG_ISR("Scheduler finished to transmit " + "the frame/frames.\n"); /* Alive notification via Rx interrupt will do the real work */ if (inta & CSR_INT_BIT_ALIVE) @@ -4714,7 +4478,7 @@ static void iwl3945_irq_tasklet(struct iwl3945_priv *priv) } #endif /* Safely ignore these bits for debug checks below */ - inta &= ~(CSR_INT_BIT_MAC_CLK_ACTV | CSR_INT_BIT_ALIVE); + inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE); /* HW RF KILL switch toggled (4965 only) */ if (inta & CSR_INT_BIT_RF_KILL) { @@ -4730,7 +4494,7 @@ static void iwl3945_irq_tasklet(struct iwl3945_priv *priv) /* Queue restart only if RF_KILL switch was set to "kill" * when we loaded driver, and is now set to "enable". * After we're Alive, RF_KILL gets handled by - * iwl_rx_card_state_notif() */ + * iwl3945_rx_card_state_notif() */ if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) { clear_bit(STATUS_RF_KILL_HW, &priv->status); queue_work(priv->workqueue, &priv->restart); @@ -4798,7 +4562,9 @@ static void iwl3945_irq_tasklet(struct iwl3945_priv *priv) } /* Re-enable all interrupts */ - iwl3945_enable_interrupts(priv); + /* only Re-enable if disabled by irq */ + if (test_bit(STATUS_INT_ENABLED, &priv->status)) + iwl3945_enable_interrupts(priv); #ifdef CONFIG_IWL3945_DEBUG if (iwl3945_debug_level & (IWL_DL_ISR)) { @@ -4850,8 +4616,11 @@ static irqreturn_t iwl3945_isr(int irq, void *data) IWL_DEBUG_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", inta, inta_mask, inta_fh); + inta &= ~CSR_INT_BIT_SCD; + /* iwl3945_irq_tasklet() will service interrupts and re-enable them */ - tasklet_schedule(&priv->irq_tasklet); + if (likely(inta || inta_fh)) + tasklet_schedule(&priv->irq_tasklet); unplugged: spin_unlock(&priv->lock); @@ -4859,7 +4628,9 @@ unplugged: none: /* re-enable interrupts here since we don't have anything to service. */ - iwl3945_enable_interrupts(priv); + /* only Re-enable if disabled by irq */ + if (test_bit(STATUS_INT_ENABLED, &priv->status)) + iwl3945_enable_interrupts(priv); spin_unlock(&priv->lock); return IRQ_NONE; } @@ -4901,11 +4672,11 @@ static const u8 iwl3945_eeprom_band_1[14] = { }; /* 5.2 GHz bands */ -static const u8 iwl3945_eeprom_band_2[] = { +static const u8 iwl3945_eeprom_band_2[] = { /* 4915-5080MHz */ 183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16 }; -static const u8 iwl3945_eeprom_band_3[] = { /* 5205-5320MHz */ +static const u8 iwl3945_eeprom_band_3[] = { /* 5170-5320MHz */ 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 }; @@ -4929,7 +4700,7 @@ static void iwl3945_init_band_reference(const struct iwl3945_priv *priv, int ban *eeprom_ch_info = priv->eeprom.band_1_channels; *eeprom_ch_index = iwl3945_eeprom_band_1; break; - case 2: /* 5.2GHz band */ + case 2: /* 4.9GHz band */ *eeprom_ch_count = ARRAY_SIZE(iwl3945_eeprom_band_2); *eeprom_ch_info = priv->eeprom.band_2_channels; *eeprom_ch_index = iwl3945_eeprom_band_2; @@ -4939,12 +4710,12 @@ static void iwl3945_init_band_reference(const struct iwl3945_priv *priv, int ban *eeprom_ch_info = priv->eeprom.band_3_channels; *eeprom_ch_index = iwl3945_eeprom_band_3; break; - case 4: /* 5.2GHz band */ + case 4: /* 5.5GHz band */ *eeprom_ch_count = ARRAY_SIZE(iwl3945_eeprom_band_4); *eeprom_ch_info = priv->eeprom.band_4_channels; *eeprom_ch_index = iwl3945_eeprom_band_4; break; - case 5: /* 5.2GHz band */ + case 5: /* 5.7GHz band */ *eeprom_ch_count = ARRAY_SIZE(iwl3945_eeprom_band_5); *eeprom_ch_info = priv->eeprom.band_5_channels; *eeprom_ch_index = iwl3945_eeprom_band_5; @@ -4955,25 +4726,30 @@ static void iwl3945_init_band_reference(const struct iwl3945_priv *priv, int ban } } +/** + * iwl3945_get_channel_info - Find driver's private channel info + * + * Based on band and channel number. + */ const struct iwl3945_channel_info *iwl3945_get_channel_info(const struct iwl3945_priv *priv, - int phymode, u16 channel) + enum ieee80211_band band, u16 channel) { int i; - switch (phymode) { - case MODE_IEEE80211A: + switch (band) { + case IEEE80211_BAND_5GHZ: for (i = 14; i < priv->channel_count; i++) { if (priv->channel_info[i].channel == channel) return &priv->channel_info[i]; } break; - case MODE_IEEE80211B: - case MODE_IEEE80211G: + case IEEE80211_BAND_2GHZ: if (channel >= 1 && channel <= 14) return &priv->channel_info[channel - 1]; break; - + case IEEE80211_NUM_BANDS: + WARN_ON(1); } return NULL; @@ -4982,6 +4758,9 @@ const struct iwl3945_channel_info *iwl3945_get_channel_info(const struct iwl3945 #define CHECK_AND_PRINT(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \ ? # x " " : "") +/** + * iwl3945_init_channel_map - Set up driver's info for all possible channels + */ static int iwl3945_init_channel_map(struct iwl3945_priv *priv) { int eeprom_ch_count = 0; @@ -5033,8 +4812,8 @@ static int iwl3945_init_channel_map(struct iwl3945_priv *priv) /* Loop through each band adding each of the channels */ for (ch = 0; ch < eeprom_ch_count; ch++) { ch_info->channel = eeprom_ch_index[ch]; - ch_info->phymode = (band == 1) ? MODE_IEEE80211B : - MODE_IEEE80211A; + ch_info->band = (band == 1) ? IEEE80211_BAND_2GHZ : + IEEE80211_BAND_5GHZ; /* permanently store EEPROM's channel regulatory flags * and max power in channel info database. */ @@ -5061,11 +4840,12 @@ static int iwl3945_init_channel_map(struct iwl3945_priv *priv) ch_info->scan_power = eeprom_ch_info[ch].max_power_avg; ch_info->min_power = 0; - IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x" + IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%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(VALID), CHECK_AND_PRINT(IBSS), CHECK_AND_PRINT(ACTIVE), CHECK_AND_PRINT(RADAR), @@ -5091,12 +4871,22 @@ static int iwl3945_init_channel_map(struct iwl3945_priv *priv) } } + /* Set up txpower settings in driver for all channels */ if (iwl3945_txpower_set_from_eeprom(priv)) return -EIO; return 0; } +/* + * iwl3945_free_channel_map - undo allocations in iwl3945_init_channel_map + */ +static void iwl3945_free_channel_map(struct iwl3945_priv *priv) +{ + kfree(priv->channel_info); + priv->channel_count = 0; +} + /* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after * sending probe req. This should be set long enough to hear probe responses * from more than one AP. */ @@ -5120,18 +4910,20 @@ static int iwl3945_init_channel_map(struct iwl3945_priv *priv) #define IWL_PASSIVE_DWELL_BASE (100) #define IWL_CHANNEL_TUNE_TIME 5 -static inline u16 iwl3945_get_active_dwell_time(struct iwl3945_priv *priv, int phymode) +static inline u16 iwl3945_get_active_dwell_time(struct iwl3945_priv *priv, + enum ieee80211_band band) { - if (phymode == MODE_IEEE80211A) + if (band == IEEE80211_BAND_5GHZ) return IWL_ACTIVE_DWELL_TIME_52; else return IWL_ACTIVE_DWELL_TIME_24; } -static u16 iwl3945_get_passive_dwell_time(struct iwl3945_priv *priv, int phymode) +static u16 iwl3945_get_passive_dwell_time(struct iwl3945_priv *priv, + enum ieee80211_band band) { - u16 active = iwl3945_get_active_dwell_time(priv, phymode); - u16 passive = (phymode != MODE_IEEE80211A) ? + u16 active = iwl3945_get_active_dwell_time(priv, band); + u16 passive = (band == IEEE80211_BAND_2GHZ) ? IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 : IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52; @@ -5151,28 +4943,29 @@ static u16 iwl3945_get_passive_dwell_time(struct iwl3945_priv *priv, int phymode return passive; } -static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, int phymode, +static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, + enum ieee80211_band band, u8 is_active, u8 direct_mask, struct iwl3945_scan_channel *scan_ch) { const struct ieee80211_channel *channels = NULL; - const struct ieee80211_hw_mode *hw_mode; + const struct ieee80211_supported_band *sband; const struct iwl3945_channel_info *ch_info; u16 passive_dwell = 0; u16 active_dwell = 0; int added, i; - hw_mode = iwl3945_get_hw_mode(priv, phymode); - if (!hw_mode) + sband = iwl3945_get_band(priv, band); + if (!sband) return 0; - channels = hw_mode->channels; + channels = sband->channels; - active_dwell = iwl3945_get_active_dwell_time(priv, phymode); - passive_dwell = iwl3945_get_passive_dwell_time(priv, phymode); + active_dwell = iwl3945_get_active_dwell_time(priv, band); + passive_dwell = iwl3945_get_passive_dwell_time(priv, band); - for (i = 0, added = 0; i < hw_mode->num_channels; i++) { - if (channels[i].chan == + for (i = 0, added = 0; i < sband->n_channels; i++) { + if (channels[i].hw_value == le16_to_cpu(priv->active_rxon.channel)) { if (iwl3945_is_associated(priv)) { IWL_DEBUG_SCAN @@ -5183,9 +4976,9 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, int phymode, } else if (priv->only_active_channel) continue; - scan_ch->channel = channels[i].chan; + scan_ch->channel = channels[i].hw_value; - ch_info = iwl3945_get_channel_info(priv, phymode, scan_ch->channel); + ch_info = iwl3945_get_channel_info(priv, band, scan_ch->channel); if (!is_channel_valid(ch_info)) { IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n", scan_ch->channel); @@ -5193,7 +4986,7 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, int phymode, } if (!is_active || is_channel_passive(ch_info) || - !(channels[i].flag & IEEE80211_CHAN_W_ACTIVE_SCAN)) + (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) scan_ch->type = 0; /* passive */ else scan_ch->type = 1; /* active */ @@ -5207,18 +5000,18 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, int phymode, scan_ch->active_dwell = cpu_to_le16(active_dwell); scan_ch->passive_dwell = cpu_to_le16(passive_dwell); - /* Set power levels to defaults */ + /* Set txpower levels to defaults */ scan_ch->tpc.dsp_atten = 110; /* scan_pwr_info->tpc.dsp_atten; */ /*scan_pwr_info->tpc.tx_gain; */ - if (phymode == MODE_IEEE80211A) + if (band == IEEE80211_BAND_5GHZ) scan_ch->tpc.tx_gain = ((1 << 5) | (3 << 3)) | 3; else { scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3)); /* NOTE: if we were doing 6Mb OFDM for scans we'd use - * power level - scan_ch->tpc.tx_gain = ((1<<5) | (2 << 3)) | 3; + * power level: + * scan_ch->tpc.tx_gain = ((1 << 5) | (2 << 3)) | 3; */ } @@ -5236,41 +5029,23 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, int phymode, return added; } -static void iwl3945_reset_channel_flag(struct iwl3945_priv *priv) -{ - int i, j; - for (i = 0; i < 3; i++) { - struct ieee80211_hw_mode *hw_mode = (void *)&priv->modes[i]; - for (j = 0; j < hw_mode->num_channels; j++) - hw_mode->channels[j].flag = hw_mode->channels[j].val; - } -} - static void iwl3945_init_hw_rates(struct iwl3945_priv *priv, struct ieee80211_rate *rates) { int i; for (i = 0; i < IWL_RATE_COUNT; i++) { - rates[i].rate = iwl3945_rates[i].ieee * 5; - rates[i].val = i; /* Rate scaling will work on indexes */ - rates[i].val2 = i; - rates[i].flags = IEEE80211_RATE_SUPPORTED; - /* Only OFDM have the bits-per-symbol set */ - if ((i <= IWL_LAST_OFDM_RATE) && (i >= IWL_FIRST_OFDM_RATE)) - rates[i].flags |= IEEE80211_RATE_OFDM; - else { + rates[i].bitrate = iwl3945_rates[i].ieee * 5; + rates[i].hw_value = i; /* Rate scaling will work on indexes */ + rates[i].hw_value_short = i; + rates[i].flags = 0; + if ((i > IWL_LAST_OFDM_RATE) || (i < IWL_FIRST_OFDM_RATE)) { /* - * If CCK 1M then set rate flag to CCK else CCK_2 - * which is CCK | PREAMBLE2 + * If CCK != 1M then set short preamble rate flag. */ rates[i].flags |= (iwl3945_rates[i].plcp == 10) ? - IEEE80211_RATE_CCK : IEEE80211_RATE_CCK_2; + 0 : IEEE80211_RATE_SHORT_PREAMBLE; } - - /* Set up which ones are basic rates... */ - if (IWL_BASIC_RATES_MASK & (1 << i)) - rates[i].flags |= IEEE80211_RATE_BASIC; } } @@ -5280,148 +5055,132 @@ static void iwl3945_init_hw_rates(struct iwl3945_priv *priv, static int iwl3945_init_geos(struct iwl3945_priv *priv) { struct iwl3945_channel_info *ch; - struct ieee80211_hw_mode *modes; + struct ieee80211_supported_band *sband; struct ieee80211_channel *channels; struct ieee80211_channel *geo_ch; struct ieee80211_rate *rates; int i = 0; - enum { - A = 0, - B = 1, - G = 2, - }; - int mode_count = 3; - if (priv->modes) { + if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates || + priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) { IWL_DEBUG_INFO("Geography modes already initialized.\n"); set_bit(STATUS_GEO_CONFIGURED, &priv->status); return 0; } - modes = kzalloc(sizeof(struct ieee80211_hw_mode) * mode_count, - GFP_KERNEL); - if (!modes) - return -ENOMEM; - channels = kzalloc(sizeof(struct ieee80211_channel) * priv->channel_count, GFP_KERNEL); - if (!channels) { - kfree(modes); + if (!channels) return -ENOMEM; - } - rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_MAX_RATES + 1)), + rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_RATE_COUNT + 1)), GFP_KERNEL); if (!rates) { - kfree(modes); kfree(channels); return -ENOMEM; } - /* 0 = 802.11a - * 1 = 802.11b - * 2 = 802.11g - */ - /* 5.2GHz channels start after the 2.4GHz channels */ - modes[A].mode = MODE_IEEE80211A; - modes[A].channels = &channels[ARRAY_SIZE(iwl3945_eeprom_band_1)]; - modes[A].rates = &rates[4]; - modes[A].num_rates = 8; /* just OFDM */ - modes[A].num_channels = 0; - - modes[B].mode = MODE_IEEE80211B; - modes[B].channels = channels; - modes[B].rates = rates; - modes[B].num_rates = 4; /* just CCK */ - modes[B].num_channels = 0; - - modes[G].mode = MODE_IEEE80211G; - modes[G].channels = channels; - modes[G].rates = rates; - modes[G].num_rates = 12; /* OFDM & CCK */ - modes[G].num_channels = 0; + sband = &priv->bands[IEEE80211_BAND_5GHZ]; + sband->channels = &channels[ARRAY_SIZE(iwl3945_eeprom_band_1)]; + /* just OFDM */ + sband->bitrates = &rates[IWL_FIRST_OFDM_RATE]; + sband->n_bitrates = IWL_RATE_COUNT - IWL_FIRST_OFDM_RATE; + + sband = &priv->bands[IEEE80211_BAND_2GHZ]; + sband->channels = channels; + /* OFDM & CCK */ + sband->bitrates = rates; + sband->n_bitrates = IWL_RATE_COUNT; priv->ieee_channels = channels; priv->ieee_rates = rates; iwl3945_init_hw_rates(priv, rates); - for (i = 0, geo_ch = channels; i < priv->channel_count; i++) { + for (i = 0; i < priv->channel_count; i++) { ch = &priv->channel_info[i]; - if (!is_channel_valid(ch)) { - IWL_DEBUG_INFO("Channel %d [%sGHz] is restricted -- " - "skipping.\n", - ch->channel, is_channel_a_band(ch) ? - "5.2" : "2.4"); + /* FIXME: might be removed if scan is OK*/ + if (!is_channel_valid(ch)) continue; - } if (is_channel_a_band(ch)) - geo_ch = &modes[A].channels[modes[A].num_channels++]; - else { - geo_ch = &modes[B].channels[modes[B].num_channels++]; - modes[G].num_channels++; - } + sband = &priv->bands[IEEE80211_BAND_5GHZ]; + else + sband = &priv->bands[IEEE80211_BAND_2GHZ]; - geo_ch->freq = ieee80211chan2mhz(ch->channel); - geo_ch->chan = ch->channel; - geo_ch->power_level = ch->max_power_avg; - geo_ch->antenna_max = 0xff; + geo_ch = &sband->channels[sband->n_channels++]; + + geo_ch->center_freq = ieee80211_channel_to_frequency(ch->channel); + geo_ch->max_power = ch->max_power_avg; + geo_ch->max_antenna_gain = 0xff; + geo_ch->hw_value = ch->channel; if (is_channel_valid(ch)) { - geo_ch->flag = IEEE80211_CHAN_W_SCAN; - if (ch->flags & EEPROM_CHANNEL_IBSS) - geo_ch->flag |= IEEE80211_CHAN_W_IBSS; + if (!(ch->flags & EEPROM_CHANNEL_IBSS)) + geo_ch->flags |= IEEE80211_CHAN_NO_IBSS; - if (ch->flags & EEPROM_CHANNEL_ACTIVE) - geo_ch->flag |= IEEE80211_CHAN_W_ACTIVE_SCAN; + if (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) + geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN; if (ch->flags & EEPROM_CHANNEL_RADAR) - geo_ch->flag |= IEEE80211_CHAN_W_RADAR_DETECT; + geo_ch->flags |= IEEE80211_CHAN_RADAR; if (ch->max_power_avg > priv->max_channel_txpower_limit) priv->max_channel_txpower_limit = ch->max_power_avg; + } else { + geo_ch->flags |= IEEE80211_CHAN_DISABLED; } - geo_ch->val = geo_ch->flag; + /* Save flags for reg domain usage */ + geo_ch->orig_flags = geo_ch->flags; + + IWL_DEBUG_INFO("Channel %d Freq=%d[%sGHz] %s flag=0%X\n", + ch->channel, geo_ch->center_freq, + is_channel_a_band(ch) ? "5.2" : "2.4", + geo_ch->flags & IEEE80211_CHAN_DISABLED ? + "restricted" : "valid", + geo_ch->flags); } - if ((modes[A].num_channels == 0) && priv->is_abg) { + if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) && + priv->cfg->sku & IWL_SKU_A) { printk(KERN_INFO DRV_NAME ": Incorrectly detected BG card as ABG. Please send " "your PCI ID 0x%04X:0x%04X to maintainer.\n", priv->pci_dev->device, priv->pci_dev->subsystem_device); - priv->is_abg = 0; + priv->cfg->sku &= ~IWL_SKU_A; } printk(KERN_INFO DRV_NAME ": Tunable channels: %d 802.11bg, %d 802.11a channels\n", - modes[G].num_channels, modes[A].num_channels); + priv->bands[IEEE80211_BAND_2GHZ].n_channels, + priv->bands[IEEE80211_BAND_5GHZ].n_channels); - /* - * NOTE: We register these in preference of order -- the - * stack doesn't currently (as of 7.0.6 / Apr 24 '07) pick - * a phymode based on rates or AP capabilities but seems to - * configure it purely on if the channel being configured - * is supported by a mode -- and the first match is taken - */ - - if (modes[G].num_channels) - ieee80211_register_hwmode(priv->hw, &modes[G]); - if (modes[B].num_channels) - ieee80211_register_hwmode(priv->hw, &modes[B]); - if (modes[A].num_channels) - ieee80211_register_hwmode(priv->hw, &modes[A]); + if (priv->bands[IEEE80211_BAND_2GHZ].n_channels) + priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = + &priv->bands[IEEE80211_BAND_2GHZ]; + if (priv->bands[IEEE80211_BAND_5GHZ].n_channels) + priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = + &priv->bands[IEEE80211_BAND_5GHZ]; - priv->modes = modes; set_bit(STATUS_GEO_CONFIGURED, &priv->status); return 0; } +/* + * iwl3945_free_geos - undo allocations in iwl3945_init_geos + */ +static void iwl3945_free_geos(struct iwl3945_priv *priv) +{ + kfree(priv->ieee_channels); + kfree(priv->ieee_rates); + clear_bit(STATUS_GEO_CONFIGURED, &priv->status); +} + /****************************************************************************** * * uCode download functions @@ -5430,48 +5189,12 @@ static int iwl3945_init_geos(struct iwl3945_priv *priv) static void iwl3945_dealloc_ucode_pci(struct iwl3945_priv *priv) { - if (priv->ucode_code.v_addr != NULL) { - pci_free_consistent(priv->pci_dev, - priv->ucode_code.len, - priv->ucode_code.v_addr, - priv->ucode_code.p_addr); - priv->ucode_code.v_addr = NULL; - } - if (priv->ucode_data.v_addr != NULL) { - pci_free_consistent(priv->pci_dev, - priv->ucode_data.len, - priv->ucode_data.v_addr, - priv->ucode_data.p_addr); - priv->ucode_data.v_addr = NULL; - } - if (priv->ucode_data_backup.v_addr != NULL) { - pci_free_consistent(priv->pci_dev, - priv->ucode_data_backup.len, - priv->ucode_data_backup.v_addr, - priv->ucode_data_backup.p_addr); - priv->ucode_data_backup.v_addr = NULL; - } - if (priv->ucode_init.v_addr != NULL) { - pci_free_consistent(priv->pci_dev, - priv->ucode_init.len, - priv->ucode_init.v_addr, - priv->ucode_init.p_addr); - priv->ucode_init.v_addr = NULL; - } - if (priv->ucode_init_data.v_addr != NULL) { - pci_free_consistent(priv->pci_dev, - priv->ucode_init_data.len, - priv->ucode_init_data.v_addr, - priv->ucode_init_data.p_addr); - priv->ucode_init_data.v_addr = NULL; - } - if (priv->ucode_boot.v_addr != NULL) { - pci_free_consistent(priv->pci_dev, - priv->ucode_boot.len, - priv->ucode_boot.v_addr, - priv->ucode_boot.p_addr); - priv->ucode_boot.v_addr = NULL; - } + iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code); + iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data); + iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data_backup); + iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init); + iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init_data); + iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot); } /** @@ -5602,8 +5325,9 @@ static int iwl3945_verify_ucode(struct iwl3945_priv *priv) IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n"); - /* Show first several data entries in instruction SRAM. - * Selection of bootstrap image is arbitrary. */ + /* Since nothing seems to match, show first several data entries in + * instruction SRAM, so maybe visual inspection will give a clue. + * Selection of bootstrap image (vs. other images) is arbitrary. */ image = (__le32 *)priv->ucode_boot.v_addr; len = priv->ucode_boot.len; rc = iwl3945_verify_inst_full(priv, image, len); @@ -5695,7 +5419,7 @@ static int iwl3945_load_bsm(struct iwl3945_priv *priv) return -EINVAL; /* Tell bootstrap uCode where to find the "Initialize" uCode - * in host DRAM ... bits 31:0 for 3945, bits 35:4 for 4965. + * in host DRAM ... host DRAM physical address bits 31:0 for 3945. * NOTE: iwl3945_initialize_alive_start() will replace these values, * after the "initialize" uCode has run, to point to * runtime/protocol instructions and backup data cache. */ @@ -5775,19 +5499,20 @@ static void iwl3945_nic_start(struct iwl3945_priv *priv) static int iwl3945_read_ucode(struct iwl3945_priv *priv) { struct iwl3945_ucode *ucode; - int rc = 0; + int ret = 0; const struct firmware *ucode_raw; /* firmware file name contains uCode/driver compatibility version */ - const char *name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode"; + const char *name = priv->cfg->fw_name; u8 *src; size_t len; u32 ver, inst_size, data_size, init_size, init_data_size, boot_size; /* Ask kernel firmware_class module to get the boot firmware off disk. * request_firmware() is synchronous, file is in memory on return. */ - rc = request_firmware(&ucode_raw, name, &priv->pci_dev->dev); - if (rc < 0) { - IWL_ERROR("%s firmware file req failed: Reason %d\n", name, rc); + ret = request_firmware(&ucode_raw, name, &priv->pci_dev->dev); + if (ret < 0) { + IWL_ERROR("%s firmware file req failed: Reason %d\n", + name, ret); goto error; } @@ -5797,7 +5522,7 @@ static int iwl3945_read_ucode(struct iwl3945_priv *priv) /* Make sure that we got at least our header! */ if (ucode_raw->size < sizeof(*ucode)) { IWL_ERROR("File size way too small!\n"); - rc = -EINVAL; + ret = -EINVAL; goto err_release; } @@ -5825,43 +5550,40 @@ static int iwl3945_read_ucode(struct iwl3945_priv *priv) IWL_DEBUG_INFO("uCode file size %d too small\n", (int)ucode_raw->size); - rc = -EINVAL; + ret = -EINVAL; goto err_release; } /* Verify that uCode images will fit in card's SRAM */ if (inst_size > IWL_MAX_INST_SIZE) { - IWL_DEBUG_INFO("uCode instr len %d too large to fit in card\n", - (int)inst_size); - rc = -EINVAL; + IWL_DEBUG_INFO("uCode instr len %d too large to fit in\n", + inst_size); + ret = -EINVAL; goto err_release; } if (data_size > IWL_MAX_DATA_SIZE) { - IWL_DEBUG_INFO("uCode data len %d too large to fit in card\n", - (int)data_size); - rc = -EINVAL; + IWL_DEBUG_INFO("uCode data len %d too large to fit in\n", + data_size); + ret = -EINVAL; goto err_release; } if (init_size > IWL_MAX_INST_SIZE) { - IWL_DEBUG_INFO - ("uCode init instr len %d too large to fit in card\n", - (int)init_size); - rc = -EINVAL; + IWL_DEBUG_INFO("uCode init instr len %d too large to fit in\n", + init_size); + ret = -EINVAL; goto err_release; } if (init_data_size > IWL_MAX_DATA_SIZE) { - IWL_DEBUG_INFO - ("uCode init data len %d too large to fit in card\n", - (int)init_data_size); - rc = -EINVAL; + IWL_DEBUG_INFO("uCode init data len %d too large to fit in\n", + init_data_size); + ret = -EINVAL; goto err_release; } if (boot_size > IWL_MAX_BSM_SIZE) { - IWL_DEBUG_INFO - ("uCode boot instr len %d too large to fit in bsm\n", - (int)boot_size); - rc = -EINVAL; + IWL_DEBUG_INFO("uCode boot instr len %d too large to fit in\n", + boot_size); + ret = -EINVAL; goto err_release; } @@ -5871,56 +5593,45 @@ static int iwl3945_read_ucode(struct iwl3945_priv *priv) * 1) unmodified from disk * 2) backup cache for save/restore during power-downs */ priv->ucode_code.len = inst_size; - priv->ucode_code.v_addr = - pci_alloc_consistent(priv->pci_dev, - priv->ucode_code.len, - &(priv->ucode_code.p_addr)); + iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_code); priv->ucode_data.len = data_size; - priv->ucode_data.v_addr = - pci_alloc_consistent(priv->pci_dev, - priv->ucode_data.len, - &(priv->ucode_data.p_addr)); + iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data); priv->ucode_data_backup.len = data_size; - priv->ucode_data_backup.v_addr = - pci_alloc_consistent(priv->pci_dev, - priv->ucode_data_backup.len, - &(priv->ucode_data_backup.p_addr)); + iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup); + if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr || + !priv->ucode_data_backup.v_addr) + goto err_pci_alloc; /* Initialization instructions and data */ - priv->ucode_init.len = init_size; - priv->ucode_init.v_addr = - pci_alloc_consistent(priv->pci_dev, - priv->ucode_init.len, - &(priv->ucode_init.p_addr)); - - priv->ucode_init_data.len = init_data_size; - priv->ucode_init_data.v_addr = - pci_alloc_consistent(priv->pci_dev, - priv->ucode_init_data.len, - &(priv->ucode_init_data.p_addr)); + if (init_size && init_data_size) { + priv->ucode_init.len = init_size; + iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init); + + priv->ucode_init_data.len = init_data_size; + iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init_data); + + if (!priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr) + goto err_pci_alloc; + } /* Bootstrap (instructions only, no data) */ - priv->ucode_boot.len = boot_size; - priv->ucode_boot.v_addr = - pci_alloc_consistent(priv->pci_dev, - priv->ucode_boot.len, - &(priv->ucode_boot.p_addr)); + if (boot_size) { + priv->ucode_boot.len = boot_size; + iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_boot); - if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr || - !priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr || - !priv->ucode_boot.v_addr || !priv->ucode_data_backup.v_addr) - goto err_pci_alloc; + if (!priv->ucode_boot.v_addr) + goto err_pci_alloc; + } /* Copy images into buffers for card's bus-master reads ... */ /* Runtime instructions (first block of data in file) */ src = &ucode->data[0]; len = priv->ucode_code.len; - IWL_DEBUG_INFO("Copying (but not loading) uCode instr len %d\n", - (int)len); + IWL_DEBUG_INFO("Copying (but not loading) uCode instr len %Zd\n", len); memcpy(priv->ucode_code.v_addr, src, len); IWL_DEBUG_INFO("uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n", priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr); @@ -5929,8 +5640,7 @@ static int iwl3945_read_ucode(struct iwl3945_priv *priv) * NOTE: Copy into backup buffer will be done in iwl3945_up() */ src = &ucode->data[inst_size]; len = priv->ucode_data.len; - IWL_DEBUG_INFO("Copying (but not loading) uCode data len %d\n", - (int)len); + IWL_DEBUG_INFO("Copying (but not loading) uCode data len %Zd\n", len); memcpy(priv->ucode_data.v_addr, src, len); memcpy(priv->ucode_data_backup.v_addr, src, len); @@ -5938,8 +5648,8 @@ static int iwl3945_read_ucode(struct iwl3945_priv *priv) if (init_size) { src = &ucode->data[inst_size + data_size]; len = priv->ucode_init.len; - IWL_DEBUG_INFO("Copying (but not loading) init instr len %d\n", - (int)len); + IWL_DEBUG_INFO("Copying (but not loading) init instr len %Zd\n", + len); memcpy(priv->ucode_init.v_addr, src, len); } @@ -5965,14 +5675,14 @@ static int iwl3945_read_ucode(struct iwl3945_priv *priv) err_pci_alloc: IWL_ERROR("failed to allocate pci memory\n"); - rc = -ENOMEM; + ret = -ENOMEM; iwl3945_dealloc_ucode_pci(priv); err_release: release_firmware(ucode_raw); error: - return rc; + return ret; } @@ -6028,12 +5738,8 @@ static int iwl3945_set_ucode_ptrs(struct iwl3945_priv *priv) * * Called after REPLY_ALIVE notification received from "initialize" uCode. * - * The 4965 "initialize" ALIVE reply contains calibration data for: - * Voltage, temperature, and MIMO tx gain correction, now stored in priv - * (3945 does not contain this data). - * * Tell "initialize" uCode to go ahead and load the runtime uCode. -*/ + */ static void iwl3945_init_alive_start(struct iwl3945_priv *priv) { /* Check alive response for "valid" sign from uCode */ @@ -6128,44 +5834,16 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv) } else set_bit(STATUS_RF_KILL_HW, &priv->status); - /* After the ALIVE response, we can process host commands */ + /* After the ALIVE response, we can send commands to 3945 uCode */ set_bit(STATUS_ALIVE, &priv->status); /* Clear out the uCode error bit if it is set */ clear_bit(STATUS_FW_ERROR, &priv->status); - rc = iwl3945_init_channel_map(priv); - if (rc) { - IWL_ERROR("initializing regulatory failed: %d\n", rc); - return; - } - - iwl3945_init_geos(priv); - if (iwl3945_is_rfkill(priv)) return; - if (!priv->mac80211_registered) { - /* Unlock so any user space entry points can call back into - * the driver without a deadlock... */ - mutex_unlock(&priv->mutex); - iwl3945_rate_control_register(priv->hw); - rc = ieee80211_register_hw(priv->hw); - priv->hw->conf.beacon_int = 100; - mutex_lock(&priv->mutex); - - if (rc) { - iwl3945_rate_control_unregister(priv->hw); - IWL_ERROR("Failed to register network " - "device (error %d)\n", rc); - return; - } - - priv->mac80211_registered = 1; - - iwl3945_reset_channel_flag(priv); - } else - ieee80211_start_queues(priv->hw); + ieee80211_start_queues(priv->hw); priv->active_rate = priv->rates_mask; priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; @@ -6185,7 +5863,7 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv) memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); } - /* Configure BT coexistence */ + /* Configure Bluetooth device coexistence support */ iwl3945_send_bt_config(priv); /* Configure the adapter for unassociated operation */ @@ -6193,11 +5871,14 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv) /* At this point, the NIC is initialized and operational */ priv->notif_missed_beacons = 0; - set_bit(STATUS_READY, &priv->status); iwl3945_reg_txpower_periodic(priv); IWL_DEBUG_INFO("ALIVE processing complete.\n"); + set_bit(STATUS_READY, &priv->status); + wake_up_interruptible(&priv->wait_command_queue); + + iwl3945_led_register(priv); if (priv->error_recovering) iwl3945_error_recovery(priv); @@ -6223,6 +5904,7 @@ static void __iwl3945_down(struct iwl3945_priv *priv) if (!exit_pending) set_bit(STATUS_EXIT_PENDING, &priv->status); + iwl3945_led_unregister(priv); iwl3945_clear_stations_table(priv); /* Unblock any waiting calls */ @@ -6237,7 +5919,10 @@ static void __iwl3945_down(struct iwl3945_priv *priv) iwl3945_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); /* tell the device to stop sending interrupts */ + spin_lock_irqsave(&priv->lock, flags); iwl3945_disable_interrupts(priv); + spin_unlock_irqrestore(&priv->lock, flags); + iwl_synchronize_irq(priv); if (priv->mac80211_registered) ieee80211_stop_queues(priv->hw); @@ -6249,6 +5934,8 @@ static void __iwl3945_down(struct iwl3945_priv *priv) STATUS_RF_KILL_HW | test_bit(STATUS_RF_KILL_SW, &priv->status) << STATUS_RF_KILL_SW | + test_bit(STATUS_GEO_CONFIGURED, &priv->status) << + STATUS_GEO_CONFIGURED | test_bit(STATUS_IN_SUSPEND, &priv->status) << STATUS_IN_SUSPEND; goto exit; @@ -6260,6 +5947,8 @@ static void __iwl3945_down(struct iwl3945_priv *priv) STATUS_RF_KILL_HW | test_bit(STATUS_RF_KILL_SW, &priv->status) << STATUS_RF_KILL_SW | + test_bit(STATUS_GEO_CONFIGURED, &priv->status) << + STATUS_GEO_CONFIGURED | test_bit(STATUS_IN_SUSPEND, &priv->status) << STATUS_IN_SUSPEND | test_bit(STATUS_FW_ERROR, &priv->status) << @@ -6310,7 +5999,6 @@ static void iwl3945_down(struct iwl3945_priv *priv) static int __iwl3945_up(struct iwl3945_priv *priv) { - DECLARE_MAC_BUF(mac); int rc, i; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { @@ -6321,7 +6009,7 @@ static int __iwl3945_up(struct iwl3945_priv *priv) if (test_bit(STATUS_RF_KILL_SW, &priv->status)) { IWL_WARNING("Radio disabled by SW RF kill (module " "parameter)\n"); - return 0; + return -ENODEV; } if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) { @@ -6329,6 +6017,18 @@ static int __iwl3945_up(struct iwl3945_priv *priv) return -EIO; } + /* If platform's RF_KILL switch is NOT set to KILL */ + if (iwl3945_read32(priv, CSR_GP_CNTRL) & + CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) + clear_bit(STATUS_RF_KILL_HW, &priv->status); + else { + set_bit(STATUS_RF_KILL_HW, &priv->status); + if (!test_bit(STATUS_IN_SUSPEND, &priv->status)) { + IWL_WARNING("Radio disabled by HW RF Kill switch\n"); + return -ENODEV; + } + } + iwl3945_write32(priv, CSR_INT, 0xFFFFFFFF); rc = iwl3945_hw_nic_init(priv); @@ -6354,7 +6054,11 @@ static int __iwl3945_up(struct iwl3945_priv *priv) * This will be used to initialize the on-board processor's * data SRAM for a clean start when the runtime program first loads. */ memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr, - priv->ucode_data.len); + priv->ucode_data.len); + + /* We return success when we resume from suspend and rf_kill is on. */ + if (test_bit(STATUS_RF_KILL_HW, &priv->status)) + return 0; for (i = 0; i < MAX_HW_RESTARTS; i++) { @@ -6373,13 +6077,6 @@ static int __iwl3945_up(struct iwl3945_priv *priv) /* start card; "initialize" will load runtime ucode */ iwl3945_nic_start(priv); - /* MAC Address location in EEPROM same for 3945/4965 */ - get_eeprom_mac(priv, priv->mac_addr); - IWL_DEBUG_INFO("MAC address: %s\n", - print_mac(mac, priv->mac_addr)); - - SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); - IWL_DEBUG_INFO(DRV_NAME " is coming up\n"); return 0; @@ -6493,7 +6190,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data) struct iwl3945_scan_cmd *scan; struct ieee80211_conf *conf = NULL; u8 direct_mask; - int phymode; + enum ieee80211_band band; conf = ieee80211_get_hw_conf(priv->hw); @@ -6613,7 +6310,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data) * that based on the direct_mask added to each channel entry */ scan->tx_cmd.len = cpu_to_le16( iwl3945_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data, - IWL_MAX_SCAN_SIZE - sizeof(scan), 0)); + IWL_MAX_SCAN_SIZE - sizeof(*scan), 0)); scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id; scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; @@ -6625,13 +6322,13 @@ static void iwl3945_bg_request_scan(struct work_struct *data) scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; scan->tx_cmd.rate = IWL_RATE_1M_PLCP; scan->good_CRC_th = 0; - phymode = MODE_IEEE80211G; + band = IEEE80211_BAND_2GHZ; break; case 1: scan->tx_cmd.rate = IWL_RATE_6M_PLCP; scan->good_CRC_th = IWL_GOOD_CRC_TH; - phymode = MODE_IEEE80211A; + band = IEEE80211_BAND_5GHZ; break; default: @@ -6645,18 +6342,23 @@ static void iwl3945_bg_request_scan(struct work_struct *data) if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) scan->filter_flags = RXON_FILTER_PROMISC_MSK; - if (direct_mask) + if (direct_mask) { IWL_DEBUG_SCAN ("Initiating direct scan for %s.\n", iwl3945_escape_essid(priv->essid, priv->essid_len)); - else + scan->channel_count = + iwl3945_get_channels_for_scan( + priv, band, 1, /* active */ + direct_mask, + (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); + } else { IWL_DEBUG_SCAN("Initiating indirect scan.\n"); - - scan->channel_count = - iwl3945_get_channels_for_scan( - priv, phymode, 1, /* active */ - direct_mask, - (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); + scan->channel_count = + iwl3945_get_channels_for_scan( + priv, band, 0, /* passive */ + direct_mask, + (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); + } cmd.len += le16_to_cpu(scan->tx_cmd.len) + scan->channel_count * sizeof(struct iwl3945_scan_channel); @@ -6716,6 +6418,8 @@ static void iwl3945_bg_rx_replenish(struct work_struct *data) mutex_unlock(&priv->mutex); } +#define IWL_DELAY_NEXT_SCAN (HZ*2) + static void iwl3945_bg_post_associate(struct work_struct *data) { struct iwl3945_priv *priv = container_of(data, struct iwl3945_priv, @@ -6740,7 +6444,7 @@ static void iwl3945_bg_post_associate(struct work_struct *data) mutex_lock(&priv->mutex); - if (!priv->interface_id || !priv->is_open) { + if (!priv->vif || !priv->is_open) { mutex_unlock(&priv->mutex); return; } @@ -6797,7 +6501,7 @@ static void iwl3945_bg_post_associate(struct work_struct *data) iwl3945_add_station(priv, iwl3945_broadcast_addr, 0, 0); iwl3945_add_station(priv, priv->bssid, 0, 0); iwl3945_sync_sta(priv, IWL_STA_ID, - (priv->phymode == MODE_IEEE80211A)? + (priv->band == IEEE80211_BAND_5GHZ) ? IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP, CMD_ASYNC); iwl3945_rate_scale_init(priv->hw, IWL_STA_ID); @@ -6813,9 +6517,10 @@ static void iwl3945_bg_post_associate(struct work_struct *data) iwl3945_sequence_reset(priv); -#ifdef CONFIG_IWL3945_QOS iwl3945_activate_qos(priv, 0); -#endif /* CONFIG_IWL3945_QOS */ + + /* we have just associated, don't start scan too early */ + priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN; mutex_unlock(&priv->mutex); } @@ -6834,6 +6539,8 @@ static void iwl3945_bg_abort_scan(struct work_struct *work) mutex_unlock(&priv->mutex); } +static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf); + static void iwl3945_bg_scan_completed(struct work_struct *work) { struct iwl3945_priv *priv = @@ -6844,6 +6551,9 @@ static void iwl3945_bg_scan_completed(struct work_struct *work) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; + if (test_bit(STATUS_CONF_PENDING, &priv->status)) + iwl3945_mac_config(priv->hw, ieee80211_get_hw_conf(priv->hw)); + ieee80211_scan_completed(priv->hw); /* Since setting the TXPOWER may have been deferred while @@ -6859,23 +6569,83 @@ static void iwl3945_bg_scan_completed(struct work_struct *work) * *****************************************************************************/ +#define UCODE_READY_TIMEOUT (2 * HZ) + static int iwl3945_mac_start(struct ieee80211_hw *hw) { struct iwl3945_priv *priv = hw->priv; + int ret; IWL_DEBUG_MAC80211("enter\n"); + if (pci_enable_device(priv->pci_dev)) { + IWL_ERROR("Fail to pci_enable_device\n"); + return -ENODEV; + } + pci_restore_state(priv->pci_dev); + pci_enable_msi(priv->pci_dev); + + ret = request_irq(priv->pci_dev->irq, iwl3945_isr, IRQF_SHARED, + DRV_NAME, priv); + if (ret) { + IWL_ERROR("Error allocating IRQ %d\n", priv->pci_dev->irq); + goto out_disable_msi; + } + /* we should be verifying the device is ready to be opened */ mutex_lock(&priv->mutex); - priv->is_open = 1; + memset(&priv->staging_rxon, 0, sizeof(struct iwl3945_rxon_cmd)); + /* fetch ucode file from disk, alloc and copy to bus-master buffers ... + * ucode filename and max sizes are card-specific. */ + + if (!priv->ucode_code.len) { + ret = iwl3945_read_ucode(priv); + if (ret) { + IWL_ERROR("Could not read microcode: %d\n", ret); + mutex_unlock(&priv->mutex); + goto out_release_irq; + } + } - if (!iwl3945_is_rfkill(priv)) - ieee80211_start_queues(priv->hw); + ret = __iwl3945_up(priv); mutex_unlock(&priv->mutex); + + if (ret) + goto out_release_irq; + + IWL_DEBUG_INFO("Start UP work.\n"); + + if (test_bit(STATUS_IN_SUSPEND, &priv->status)) + return 0; + + /* Wait for START_ALIVE from ucode. Otherwise callbacks from + * mac80211 will not be run successfully. */ + ret = wait_event_interruptible_timeout(priv->wait_command_queue, + test_bit(STATUS_READY, &priv->status), + UCODE_READY_TIMEOUT); + if (!ret) { + if (!test_bit(STATUS_READY, &priv->status)) { + IWL_ERROR("Wait for START_ALIVE timeout after %dms.\n", + jiffies_to_msecs(UCODE_READY_TIMEOUT)); + ret = -ETIMEDOUT; + goto out_release_irq; + } + } + + priv->is_open = 1; IWL_DEBUG_MAC80211("leave\n"); return 0; + +out_release_irq: + free_irq(priv->pci_dev->irq, priv); +out_disable_msi: + pci_disable_msi(priv->pci_dev); + pci_disable_device(priv->pci_dev); + priv->is_open = 0; + IWL_DEBUG_MAC80211("leave - failed\n"); + return ret; } static void iwl3945_mac_stop(struct ieee80211_hw *hw) @@ -6884,17 +6654,30 @@ static void iwl3945_mac_stop(struct ieee80211_hw *hw) IWL_DEBUG_MAC80211("enter\n"); + if (!priv->is_open) { + IWL_DEBUG_MAC80211("leave - skip\n"); + return; + } - mutex_lock(&priv->mutex); - /* stop mac, cancel any scan request and clear - * RXON_FILTER_ASSOC_MSK BIT - */ priv->is_open = 0; - iwl3945_scan_cancel_timeout(priv, 100); - cancel_delayed_work(&priv->post_associate); - priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl3945_commit_rxon(priv); - mutex_unlock(&priv->mutex); + + if (iwl3945_is_ready_rf(priv)) { + /* stop mac, cancel any scan request and clear + * RXON_FILTER_ASSOC_MSK BIT + */ + mutex_lock(&priv->mutex); + iwl3945_scan_cancel_timeout(priv, 100); + cancel_delayed_work(&priv->post_associate); + mutex_unlock(&priv->mutex); + } + + iwl3945_down(priv); + + flush_workqueue(priv->workqueue); + free_irq(priv->pci_dev->irq, priv); + pci_disable_msi(priv->pci_dev); + pci_save_state(priv->pci_dev); + pci_disable_device(priv->pci_dev); IWL_DEBUG_MAC80211("leave\n"); } @@ -6912,7 +6695,7 @@ static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, } IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, - ctl->tx_rate); + ctl->tx_rate->bitrate); if (iwl3945_tx_skb(priv, skb, ctl)) dev_kfree_skb_any(skb); @@ -6928,15 +6711,15 @@ static int iwl3945_mac_add_interface(struct ieee80211_hw *hw, unsigned long flags; DECLARE_MAC_BUF(mac); - IWL_DEBUG_MAC80211("enter: id %d, type %d\n", conf->if_id, conf->type); + IWL_DEBUG_MAC80211("enter: type %d\n", conf->type); - if (priv->interface_id) { - IWL_DEBUG_MAC80211("leave - interface_id != 0\n"); + if (priv->vif) { + IWL_DEBUG_MAC80211("leave - vif != NULL\n"); return -EOPNOTSUPP; } spin_lock_irqsave(&priv->lock, flags); - priv->interface_id = conf->if_id; + priv->vif = conf->vif; spin_unlock_irqrestore(&priv->lock, flags); @@ -6947,11 +6730,12 @@ static int iwl3945_mac_add_interface(struct ieee80211_hw *hw, memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); } - iwl3945_set_mode(priv, conf->type); + if (iwl3945_is_ready(priv)) + iwl3945_set_mode(priv, conf->type); - IWL_DEBUG_MAC80211("leave\n"); mutex_unlock(&priv->mutex); + IWL_DEBUG_MAC80211("leave\n"); return 0; } @@ -6967,40 +6751,43 @@ static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co struct iwl3945_priv *priv = hw->priv; const struct iwl3945_channel_info *ch_info; unsigned long flags; + int ret = 0; mutex_lock(&priv->mutex); - IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel); + IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel->hw_value); + + priv->add_radiotap = !!(conf->flags & IEEE80211_CONF_RADIOTAP); if (!iwl3945_is_ready(priv)) { IWL_DEBUG_MAC80211("leave - not ready\n"); - mutex_unlock(&priv->mutex); - return -EIO; + ret = -EIO; + goto out; } - /* TODO: Figure out how to get ieee80211_local->sta_scanning w/ only - * what is exposed through include/ declarations */ if (unlikely(!iwl3945_param_disable_hw_scan && test_bit(STATUS_SCANNING, &priv->status))) { IWL_DEBUG_MAC80211("leave - scanning\n"); + set_bit(STATUS_CONF_PENDING, &priv->status); mutex_unlock(&priv->mutex); return 0; } spin_lock_irqsave(&priv->lock, flags); - ch_info = iwl3945_get_channel_info(priv, conf->phymode, conf->channel); + ch_info = iwl3945_get_channel_info(priv, conf->channel->band, + conf->channel->hw_value); if (!is_channel_valid(ch_info)) { IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this SKU.\n", - conf->channel, conf->phymode); + conf->channel->hw_value, conf->channel->band); IWL_DEBUG_MAC80211("leave - invalid channel\n"); spin_unlock_irqrestore(&priv->lock, flags); - mutex_unlock(&priv->mutex); - return -EINVAL; + ret = -EINVAL; + goto out; } - iwl3945_set_rxon_channel(priv, conf->phymode, conf->channel); + iwl3945_set_rxon_channel(priv, conf->channel->band, conf->channel->hw_value); - iwl3945_set_flags_for_phymode(priv, conf->phymode); + iwl3945_set_flags_for_phymode(priv, conf->channel->band); /* The list of supported rates and rate mask can be different * for each phymode; since the phymode may have changed, reset @@ -7012,8 +6799,7 @@ static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co #ifdef IEEE80211_CONF_CHANNEL_SWITCH if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) { iwl3945_hw_channel_switch(priv, conf->channel); - mutex_unlock(&priv->mutex); - return 0; + goto out; } #endif @@ -7021,14 +6807,13 @@ static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co if (!conf->radio_enabled) { IWL_DEBUG_MAC80211("leave - radio disabled\n"); - mutex_unlock(&priv->mutex); - return 0; + goto out; } if (iwl3945_is_rfkill(priv)) { IWL_DEBUG_MAC80211("leave - RF kill\n"); - mutex_unlock(&priv->mutex); - return -EIO; + ret = -EIO; + goto out; } iwl3945_set_rate(priv); @@ -7041,16 +6826,17 @@ static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co IWL_DEBUG_MAC80211("leave\n"); +out: + clear_bit(STATUS_CONF_PENDING, &priv->status); mutex_unlock(&priv->mutex); - - return 0; + return ret; } static void iwl3945_config_ap(struct iwl3945_priv *priv) { int rc = 0; - if (priv->status & STATUS_EXIT_PENDING) + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; /* The following should be done only at AP bring up */ @@ -7103,7 +6889,8 @@ static void iwl3945_config_ap(struct iwl3945_priv *priv) * clear sta table, add BCAST sta... */ } -static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, int if_id, +static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, struct ieee80211_if_conf *conf) { struct iwl3945_priv *priv = hw->priv; @@ -7114,6 +6901,12 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, int if_id, if (conf == NULL) return -EIO; + if (priv->vif != vif) { + IWL_DEBUG_MAC80211("leave - priv->vif != vif\n"); + mutex_unlock(&priv->mutex); + return 0; + } + /* XXX: this MUST use conf->mac_addr */ if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && @@ -7123,9 +6916,11 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, int if_id, return 0; } + if (!iwl3945_is_alive(priv)) + return -EAGAIN; + mutex_lock(&priv->mutex); - IWL_DEBUG_MAC80211("enter: interface id %d\n", if_id); if (conf->bssid) IWL_DEBUG_MAC80211("bssid: %s\n", print_mac(mac, conf->bssid)); @@ -7136,17 +6931,6 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, int if_id, if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { */ - if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) { - IWL_DEBUG_MAC80211("leave - scanning\n"); - mutex_unlock(&priv->mutex); - return 0; - } - - if (priv->interface_id != if_id) { - IWL_DEBUG_MAC80211("leave - interface_id != if_id\n"); - mutex_unlock(&priv->mutex); - return 0; - } if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { if (!conf->bssid) { @@ -7161,6 +6945,9 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, int if_id, priv->ibss_beacon = conf->beacon; } + if (iwl3945_is_rfkill(priv)) + goto done; + if (conf->bssid && !is_zero_ether_addr(conf->bssid) && !is_multicast_ether_addr(conf->bssid)) { /* If there is currently a HW scan going on in the background @@ -7195,6 +6982,7 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, int if_id, iwl3945_commit_rxon(priv); } + done: spin_lock_irqsave(&priv->lock, flags); if (!conf->ssid_len) memset(priv->essid, 0, IW_ESSID_MAX_SIZE); @@ -7231,13 +7019,14 @@ static void iwl3945_mac_remove_interface(struct ieee80211_hw *hw, mutex_lock(&priv->mutex); - iwl3945_scan_cancel_timeout(priv, 100); - cancel_delayed_work(&priv->post_associate); - priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl3945_commit_rxon(priv); - - if (priv->interface_id == conf->if_id) { - priv->interface_id = 0; + if (iwl3945_is_ready_rf(priv)) { + iwl3945_scan_cancel_timeout(priv, 100); + cancel_delayed_work(&priv->post_associate); + priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwl3945_commit_rxon(priv); + } + if (priv->vif == conf->vif) { + priv->vif = NULL; memset(priv->bssid, 0, ETH_ALEN); memset(priv->essid, 0, IW_ESSID_MAX_SIZE); priv->essid_len = 0; @@ -7245,10 +7034,8 @@ static void iwl3945_mac_remove_interface(struct ieee80211_hw *hw, mutex_unlock(&priv->mutex); IWL_DEBUG_MAC80211("leave\n"); - } -#define IWL_DELAY_NEXT_SCAN (HZ*2) static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) { int rc = 0; @@ -7272,16 +7059,20 @@ static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) goto out_unlock; } + /* we don't schedule scan within next_scan_jiffies period */ + if (priv->next_scan_jiffies && + time_after(priv->next_scan_jiffies, jiffies)) { + rc = -EAGAIN; + goto out_unlock; + } /* if we just finished scan ask for delay */ - if (priv->last_scan_jiffies && - time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, - jiffies)) { + if (priv->last_scan_jiffies && time_after(priv->last_scan_jiffies + + IWL_DELAY_NEXT_SCAN, jiffies)) { rc = -EAGAIN; goto out_unlock; } if (len) { - IWL_DEBUG_SCAN("direct scan for " - "%s [%d]\n ", + IWL_DEBUG_SCAN("direct scan for %s [%d]\n ", iwl3945_escape_essid(ssid, len), (int)len); priv->one_direct_scan = 1; @@ -7367,10 +7158,8 @@ static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, int queue, const struct ieee80211_tx_queue_params *params) { struct iwl3945_priv *priv = hw->priv; -#ifdef CONFIG_IWL3945_QOS unsigned long flags; int q; -#endif /* CONFIG_IWL_QOS */ IWL_DEBUG_MAC80211("enter\n"); @@ -7384,7 +7173,6 @@ static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, int queue, return 0; } -#ifdef CONFIG_IWL3945_QOS if (!priv->qos_data.qos_enable) { priv->qos_data.qos_active = 0; IWL_DEBUG_MAC80211("leave - qos not enabled\n"); @@ -7398,7 +7186,7 @@ static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, int queue, priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max); priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs; priv->qos_data.def_qos_parm.ac[q].edca_txop = - cpu_to_le16((params->burst_time * 100)); + cpu_to_le16((params->txop * 32)); priv->qos_data.def_qos_parm.ac[q].reserved1 = 0; priv->qos_data.qos_active = 1; @@ -7413,8 +7201,6 @@ static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, int queue, mutex_unlock(&priv->mutex); -#endif /*CONFIG_IWL3945_QOS */ - IWL_DEBUG_MAC80211("leave\n"); return 0; } @@ -7479,9 +7265,8 @@ static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw) mutex_lock(&priv->mutex); IWL_DEBUG_MAC80211("enter\n"); -#ifdef CONFIG_IWL3945_QOS iwl3945_reset_qos(priv); -#endif + cancel_delayed_work(&priv->post_associate); spin_lock_irqsave(&priv->lock, flags); @@ -7503,6 +7288,12 @@ static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw) spin_unlock_irqrestore(&priv->lock, flags); + if (!iwl3945_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211("leave - not ready\n"); + mutex_unlock(&priv->mutex); + return; + } + /* we are restarting association process * clear RXON_FILTER_ASSOC_MSK bit */ @@ -7520,12 +7311,6 @@ static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw) return; } - if (!iwl3945_is_ready_rf(priv)) { - IWL_DEBUG_MAC80211("leave - not ready\n"); - mutex_unlock(&priv->mutex); - return; - } - priv->only_active_channel = 0; iwl3945_set_rate(priv); @@ -7569,9 +7354,7 @@ static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk IWL_DEBUG_MAC80211("leave\n"); spin_unlock_irqrestore(&priv->lock, flags); -#ifdef CONFIG_IWL3945_QOS iwl3945_reset_qos(priv); -#endif queue_work(priv->workqueue, &priv->post_associate.work); @@ -7772,65 +7555,6 @@ static ssize_t store_filter_flags(struct device *d, static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags, store_filter_flags); -static ssize_t show_tune(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data; - - return sprintf(buf, "0x%04X\n", - (priv->phymode << 8) | - le16_to_cpu(priv->active_rxon.channel)); -} - -static void iwl3945_set_flags_for_phymode(struct iwl3945_priv *priv, u8 phymode); - -static ssize_t store_tune(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data; - char *p = (char *)buf; - u16 tune = simple_strtoul(p, &p, 0); - u8 phymode = (tune >> 8) & 0xff; - u16 channel = tune & 0xff; - - IWL_DEBUG_INFO("Tune request to:%d channel:%d\n", phymode, channel); - - mutex_lock(&priv->mutex); - if ((le16_to_cpu(priv->staging_rxon.channel) != channel) || - (priv->phymode != phymode)) { - const struct iwl3945_channel_info *ch_info; - - ch_info = iwl3945_get_channel_info(priv, phymode, channel); - if (!ch_info) { - IWL_WARNING("Requested invalid phymode/channel " - "combination: %d %d\n", phymode, channel); - mutex_unlock(&priv->mutex); - return -EINVAL; - } - - /* Cancel any currently running scans... */ - if (iwl3945_scan_cancel_timeout(priv, 100)) - IWL_WARNING("Could not cancel scan.\n"); - else { - IWL_DEBUG_INFO("Committing phymode and " - "rxon.channel = %d %d\n", - phymode, channel); - - iwl3945_set_rxon_channel(priv, phymode, channel); - iwl3945_set_flags_for_phymode(priv, phymode); - - iwl3945_set_rate(priv); - iwl3945_commit_rxon(priv); - } - } - mutex_unlock(&priv->mutex); - - return count; -} - -static DEVICE_ATTR(tune, S_IWUSR | S_IRUGO, show_tune, store_tune); - #ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT static ssize_t show_measurement(struct device *d, @@ -7904,31 +7628,6 @@ static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR, show_measurement, store_measurement); #endif /* CONFIG_IWL3945_SPECTRUM_MEASUREMENT */ -static ssize_t show_rate(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl3945_priv *priv = dev_get_drvdata(d); - unsigned long flags; - int i; - - spin_lock_irqsave(&priv->sta_lock, flags); - if (priv->iw_mode == IEEE80211_IF_TYPE_STA) - i = priv->stations[IWL_AP_ID].current_rate.s.rate; - else - i = priv->stations[IWL_STA_ID].current_rate.s.rate; - spin_unlock_irqrestore(&priv->sta_lock, flags); - - i = iwl3945_rate_index_from_plcp(i); - if (i == -1) - return sprintf(buf, "0\n"); - - return sprintf(buf, "%d%s\n", - (iwl3945_rates[i].ieee >> 1), - (iwl3945_rates[i].ieee & 0x1) ? ".5" : ""); -} - -static DEVICE_ATTR(rate, S_IRUSR, show_rate, NULL); - static ssize_t store_retry_rate(struct device *d, struct device_attribute *attr, const char *buf, size_t count) @@ -8045,73 +7744,8 @@ static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, static ssize_t show_channels(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl3945_priv *priv = dev_get_drvdata(d); - int len = 0, i; - struct ieee80211_channel *channels = NULL; - const struct ieee80211_hw_mode *hw_mode = NULL; - int count = 0; - - if (!iwl3945_is_ready(priv)) - return -EAGAIN; - - hw_mode = iwl3945_get_hw_mode(priv, MODE_IEEE80211G); - if (!hw_mode) - hw_mode = iwl3945_get_hw_mode(priv, MODE_IEEE80211B); - if (hw_mode) { - channels = hw_mode->channels; - count = hw_mode->num_channels; - } - - len += - sprintf(&buf[len], - "Displaying %d channels in 2.4GHz band " - "(802.11bg):\n", count); - - for (i = 0; i < count; i++) - len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n", - channels[i].chan, - channels[i].power_level, - channels[i]. - flag & IEEE80211_CHAN_W_RADAR_DETECT ? - " (IEEE 802.11h required)" : "", - (!(channels[i].flag & IEEE80211_CHAN_W_IBSS) - || (channels[i]. - flag & - IEEE80211_CHAN_W_RADAR_DETECT)) ? "" : - ", IBSS", - channels[i]. - flag & IEEE80211_CHAN_W_ACTIVE_SCAN ? - "active/passive" : "passive only"); - - hw_mode = iwl3945_get_hw_mode(priv, MODE_IEEE80211A); - if (hw_mode) { - channels = hw_mode->channels; - count = hw_mode->num_channels; - } else { - channels = NULL; - count = 0; - } - - len += sprintf(&buf[len], "Displaying %d channels in 5.2GHz band " - "(802.11a):\n", count); - - for (i = 0; i < count; i++) - len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n", - channels[i].chan, - channels[i].power_level, - channels[i]. - flag & IEEE80211_CHAN_W_RADAR_DETECT ? - " (IEEE 802.11h required)" : "", - (!(channels[i].flag & IEEE80211_CHAN_W_IBSS) - || (channels[i]. - flag & - IEEE80211_CHAN_W_RADAR_DETECT)) ? "" : - ", IBSS", - channels[i]. - flag & IEEE80211_CHAN_W_ACTIVE_SCAN ? - "active/passive" : "passive only"); - - return len; + /* all this shit doesn't belong into sysfs anyway */ + return 0; } static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL); @@ -8284,14 +7918,12 @@ static struct attribute *iwl3945_sysfs_entries[] = { &dev_attr_measurement.attr, #endif &dev_attr_power_level.attr, - &dev_attr_rate.attr, &dev_attr_retry_rate.attr, &dev_attr_rf_kill.attr, &dev_attr_rs_window.attr, &dev_attr_statistics.attr, &dev_attr_status.attr, &dev_attr_temperature.attr, - &dev_attr_tune.attr, &dev_attr_tx_power.attr, NULL @@ -8324,11 +7956,15 @@ static struct ieee80211_ops iwl3945_hw_ops = { static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int err = 0; - u32 pci_id; struct iwl3945_priv *priv; struct ieee80211_hw *hw; + struct iwl_3945_cfg *cfg = (struct iwl_3945_cfg *)(ent->driver_data); int i; + unsigned long flags; + DECLARE_MAC_BUF(mac); + /* Disabling hardware scan means that mac80211 will perform scans + * "the hard way", rather than using device's scan. */ if (iwl3945_param_disable_hw_scan) { IWL_DEBUG_INFO("Disabling hw_scan\n"); iwl3945_hw_ops.hw_scan = NULL; @@ -8359,6 +7995,9 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e priv->hw = hw; priv->pci_dev = pdev; + priv->cfg = cfg; + + /* Select antenna (may be helpful if only one antenna is connected) */ priv->antenna = (enum iwl3945_antenna)iwl3945_param_antenna; #ifdef CONFIG_IWL3945_DEBUG iwl3945_debug_level = iwl3945_param_debug; @@ -8380,6 +8019,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e /* Tell mac80211 our Tx characteristics */ hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; + /* 4 EDCA QOS priorities */ hw->queues = 4; spin_lock_init(&priv->lock); @@ -8400,12 +8040,13 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e pci_set_master(pdev); + /* Clear the driver's (not device's) station table */ iwl3945_clear_stations_table(priv); priv->data_retry_limit = -1; priv->ieee_channels = NULL; priv->ieee_rates = NULL; - priv->phymode = -1; + priv->band = IEEE80211_BAND_2GHZ; err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (!err) @@ -8419,9 +8060,11 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e err = pci_request_regions(pdev, DRV_NAME); if (err) goto out_pci_disable_device; + /* We disable the RETRY_TIMEOUT register (0x41) to keep * PCI Tx retries from interfering with C3 CPU state */ pci_write_config_byte(pdev, 0x41, 0x00); + priv->hw_base = pci_iomap(pdev, 0, 0); if (!priv->hw_base) { err = -ENODEV; @@ -8434,6 +8077,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e /* Initialize module parameter values here */ + /* Disable radio (SW RF KILL) via parameter when loading driver */ if (iwl3945_param_disable) { set_bit(STATUS_RF_KILL_SW, &priv->status); IWL_DEBUG_INFO("Radio disabled.\n"); @@ -8441,41 +8085,15 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e priv->iw_mode = IEEE80211_IF_TYPE_STA; - pci_id = - (priv->pci_dev->device << 16) | priv->pci_dev->subsystem_device; - - switch (pci_id) { - case 0x42221005: /* 0x4222 0x8086 0x1005 is BG SKU */ - case 0x42221034: /* 0x4222 0x8086 0x1034 is BG SKU */ - case 0x42271014: /* 0x4227 0x8086 0x1014 is BG SKU */ - case 0x42221044: /* 0x4222 0x8086 0x1044 is BG SKU */ - priv->is_abg = 0; - break; - - /* - * Rest are assumed ABG SKU -- if this is not the - * case then the card will get the wrong 'Detected' - * line in the kernel log however the code that - * initializes the GEO table will detect no A-band - * channels and remove the is_abg mask. - */ - default: - priv->is_abg = 1; - break; - } - printk(KERN_INFO DRV_NAME - ": Detected Intel PRO/Wireless 3945%sBG Network Connection\n", - priv->is_abg ? "A" : ""); + ": Detected Intel Wireless WiFi Link %s\n", priv->cfg->name); /* Device-specific setup */ if (iwl3945_hw_set_hw_setting(priv)) { IWL_ERROR("failed to set hw settings\n"); - mutex_unlock(&priv->mutex); goto out_iounmap; } -#ifdef CONFIG_IWL3945_QOS if (iwl3945_param_qos_enable) priv->qos_data.qos_enable = 1; @@ -8483,9 +8101,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e priv->qos_data.qos_active = 0; priv->qos_data.qos_cap.val = 0; -#endif /* CONFIG_IWL3945_QOS */ - iwl3945_set_rxon_channel(priv, MODE_IEEE80211G, 6); + iwl3945_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6); iwl3945_setup_deferred_work(priv); iwl3945_setup_rx_handlers(priv); @@ -8494,52 +8111,72 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e priv->power_mode = IWL_POWER_AC; priv->user_txpower_limit = IWL_DEFAULT_TX_POWER; + spin_lock_irqsave(&priv->lock, flags); iwl3945_disable_interrupts(priv); - - pci_enable_msi(pdev); - - err = request_irq(pdev->irq, iwl3945_isr, IRQF_SHARED, DRV_NAME, priv); - if (err) { - IWL_ERROR("Error allocating IRQ %d\n", pdev->irq); - goto out_disable_msi; - } - - mutex_lock(&priv->mutex); + spin_unlock_irqrestore(&priv->lock, flags); err = sysfs_create_group(&pdev->dev.kobj, &iwl3945_attribute_group); if (err) { IWL_ERROR("failed to create sysfs device attributes\n"); - mutex_unlock(&priv->mutex); goto out_release_irq; } - /* fetch ucode file from disk, alloc and copy to bus-master buffers ... - * ucode filename and max sizes are card-specific. */ - err = iwl3945_read_ucode(priv); + /* nic init */ + iwl3945_set_bit(priv, CSR_GIO_CHICKEN_BITS, + CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); + + iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + err = iwl3945_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + if (err < 0) { + IWL_DEBUG_INFO("Failed to init the card\n"); + goto out_remove_sysfs; + } + /* Read the EEPROM */ + err = iwl3945_eeprom_init(priv); if (err) { - IWL_ERROR("Could not read microcode: %d\n", err); - mutex_unlock(&priv->mutex); - goto out_pci_alloc; + IWL_ERROR("Unable to init EEPROM\n"); + goto out_remove_sysfs; } + /* MAC Address location in EEPROM same for 3945/4965 */ + get_eeprom_mac(priv, priv->mac_addr); + IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr)); + SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); - mutex_unlock(&priv->mutex); + err = iwl3945_init_channel_map(priv); + if (err) { + IWL_ERROR("initializing regulatory failed: %d\n", err); + goto out_remove_sysfs; + } - IWL_DEBUG_INFO("Queueing UP work.\n"); + err = iwl3945_init_geos(priv); + if (err) { + IWL_ERROR("initializing geos failed: %d\n", err); + goto out_free_channel_map; + } - queue_work(priv->workqueue, &priv->up); + err = ieee80211_register_hw(priv->hw); + if (err) { + IWL_ERROR("Failed to register network device (error %d)\n", err); + goto out_free_geos; + } - return 0; + priv->hw->conf.beacon_int = 100; + priv->mac80211_registered = 1; + pci_save_state(pdev); + pci_disable_device(pdev); - out_pci_alloc: - iwl3945_dealloc_ucode_pci(priv); + return 0; + out_free_geos: + iwl3945_free_geos(priv); + out_free_channel_map: + iwl3945_free_channel_map(priv); + out_remove_sysfs: sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group); out_release_irq: - free_irq(pdev->irq, priv); - - out_disable_msi: - pci_disable_msi(pdev); destroy_workqueue(priv->workqueue); priv->workqueue = NULL; iwl3945_unset_hw_setting(priv); @@ -8557,11 +8194,12 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e return err; } -static void iwl3945_pci_remove(struct pci_dev *pdev) +static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) { struct iwl3945_priv *priv = pci_get_drvdata(pdev); struct list_head *p, *q; int i; + unsigned long flags; if (!priv) return; @@ -8572,6 +8210,15 @@ static void iwl3945_pci_remove(struct pci_dev *pdev) iwl3945_down(priv); + /* make sure we flush any pending irq or + * tasklet for the driver + */ + spin_lock_irqsave(&priv->lock, flags); + iwl3945_disable_interrupts(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + iwl_synchronize_irq(priv); + /* Free MAC hash list for ADHOC */ for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) { list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) { @@ -8593,7 +8240,6 @@ static void iwl3945_pci_remove(struct pci_dev *pdev) if (priv->mac80211_registered) { ieee80211_unregister_hw(priv->hw); - iwl3945_rate_control_unregister(priv->hw); } /*netif_stop_queue(dev); */ @@ -8605,17 +8251,13 @@ static void iwl3945_pci_remove(struct pci_dev *pdev) destroy_workqueue(priv->workqueue); priv->workqueue = NULL; - free_irq(pdev->irq, priv); - pci_disable_msi(pdev); pci_iounmap(pdev, priv->hw_base); pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); - kfree(priv->channel_info); - - kfree(priv->ieee_channels); - kfree(priv->ieee_rates); + iwl3945_free_channel_map(priv); + iwl3945_free_geos(priv); if (priv->ibss_beacon) dev_kfree_skb(priv->ibss_beacon); @@ -8629,89 +8271,27 @@ static int iwl3945_pci_suspend(struct pci_dev *pdev, pm_message_t state) { struct iwl3945_priv *priv = pci_get_drvdata(pdev); - set_bit(STATUS_IN_SUSPEND, &priv->status); - - /* Take down the device; powers it off, etc. */ - iwl3945_down(priv); - - if (priv->mac80211_registered) - ieee80211_stop_queues(priv->hw); + if (priv->is_open) { + set_bit(STATUS_IN_SUSPEND, &priv->status); + iwl3945_mac_stop(priv->hw); + priv->is_open = 1; + } - pci_save_state(pdev); - pci_disable_device(pdev); pci_set_power_state(pdev, PCI_D3hot); return 0; } -static void iwl3945_resume(struct iwl3945_priv *priv) -{ - unsigned long flags; - - /* The following it a temporary work around due to the - * suspend / resume not fully initializing the NIC correctly. - * Without all of the following, resume will not attempt to take - * down the NIC (it shouldn't really need to) and will just try - * and bring the NIC back up. However that fails during the - * ucode verification process. This then causes iwl3945_down to be - * called *after* iwl3945_hw_nic_init() has succeeded -- which - * then lets the next init sequence succeed. So, we've - * replicated all of that NIC init code here... */ - - iwl3945_write32(priv, CSR_INT, 0xFFFFFFFF); - - iwl3945_hw_nic_init(priv); - - iwl3945_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - iwl3945_write32(priv, CSR_UCODE_DRV_GP1_CLR, - CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - iwl3945_write32(priv, CSR_INT, 0xFFFFFFFF); - iwl3945_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - iwl3945_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - - /* tell the device to stop sending interrupts */ - iwl3945_disable_interrupts(priv); - - spin_lock_irqsave(&priv->lock, flags); - iwl3945_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - - if (!iwl3945_grab_nic_access(priv)) { - iwl3945_write_prph(priv, APMG_CLK_DIS_REG, - APMG_CLK_VAL_DMA_CLK_RQT); - iwl3945_release_nic_access(priv); - } - spin_unlock_irqrestore(&priv->lock, flags); - - udelay(5); - - iwl3945_hw_nic_reset(priv); - - /* Bring the device back up */ - clear_bit(STATUS_IN_SUSPEND, &priv->status); - queue_work(priv->workqueue, &priv->up); -} - static int iwl3945_pci_resume(struct pci_dev *pdev) { struct iwl3945_priv *priv = pci_get_drvdata(pdev); - int err; - - printk(KERN_INFO "Coming out of suspend...\n"); pci_set_power_state(pdev, PCI_D0); - err = pci_enable_device(pdev); - 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_restore_state won't help - * here since it only restores the first 64 bytes pci config header. - */ - pci_write_config_byte(pdev, 0x41, 0x00); - iwl3945_resume(priv); + if (priv->is_open) + iwl3945_mac_start(priv->hw); + clear_bit(STATUS_IN_SUSPEND, &priv->status); return 0; } @@ -8740,21 +8320,35 @@ static int __init iwl3945_init(void) int ret; printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n"); printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n"); + + ret = iwl3945_rate_control_register(); + if (ret) { + IWL_ERROR("Unable to register rate control algorithm: %d\n", ret); + return ret; + } + ret = pci_register_driver(&iwl3945_driver); if (ret) { IWL_ERROR("Unable to initialize PCI module\n"); - return ret; + goto error_register; } #ifdef CONFIG_IWL3945_DEBUG ret = driver_create_file(&iwl3945_driver.driver, &driver_attr_debug_level); if (ret) { IWL_ERROR("Unable to create driver sysfs file\n"); - pci_unregister_driver(&iwl3945_driver); - return ret; + goto error_debug; } #endif return ret; + +#ifdef CONFIG_IWL3945_DEBUG +error_debug: + pci_unregister_driver(&iwl3945_driver); +#endif +error_register: + iwl3945_rate_control_unregister(); + return ret; } static void __exit iwl3945_exit(void) @@ -8763,6 +8357,7 @@ static void __exit iwl3945_exit(void) driver_remove_file(&iwl3945_driver.driver, &driver_attr_debug_level); #endif pci_unregister_driver(&iwl3945_driver); + iwl3945_rate_control_unregister(); } module_param_named(antenna, iwl3945_param_antenna, int, 0444);