*
*****************************************************************************/
-/*
- * 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 <linux/kernel.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/etherdevice.h>
#include <linux/if_arp.h>
-#include <net/ieee80211_radiotap.h>
#include <net/mac80211.h>
#include <asm/div64.h>
******************************************************************************/
/* module parameters */
-static int iwl4965_param_disable_hw_scan;
-static int iwl4965_param_debug;
-static int iwl4965_param_disable; /* def: enable radio */
-static int iwl4965_param_antenna; /* def: 0 = both antennas (use diversity) */
-int iwl4965_param_hwcrypto; /* def: using software encryption */
-static int iwl4965_param_qos_enable = 1;
-int iwl4965_param_queues_num = IWL_MAX_NUM_QUEUES;
+static int iwl4965_param_disable_hw_scan; /* def: 0 = use 4965's h/w scan */
+static int iwl4965_param_debug; /* def: 0 = minimal debug log messages */
+static int iwl4965_param_disable; /* def: enable radio */
+static int iwl4965_param_antenna; /* def: 0 = both antennas (use diversity) */
+int iwl4965_param_hwcrypto; /* def: using software encryption */
+static int iwl4965_param_qos_enable = 1; /* def: 1 = use quality of service */
+int iwl4965_param_queues_num = IWL_MAX_NUM_QUEUES; /* def: 16 Tx queues */
+int iwl4965_param_amsdu_size_8K; /* def: enable 8K amsdu size */
/*
* module name, copyright, version, etc.
#define VS
#endif
-#define IWLWIFI_VERSION "1.1.19k" VD VS
+#define IWLWIFI_VERSION "1.2.22k" VD VS
#define DRV_COPYRIGHT "Copyright(c) 2003-2007 Intel Corporation"
#define DRV_VERSION IWLWIFI_VERSION
*
* 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 4965 operates with up to 17 queues: One receive queue, one transmit
+ * queue (#4) for sending commands to the device firmware, and 15 other
+ * Tx queues that may be mapped to prioritized Tx DMA/FIFO channels.
+ *
+ * See more detailed info in iwl-4965-hw.h.
***************************************************/
static int iwl4965_queue_space(const struct iwl4965_queue *q)
return s;
}
-/* XXX: n_bd must be power-of-two size */
+/**
+ * iwl4965_queue_inc_wrap - increment queue index, wrap back to beginning
+ * @index -- current index
+ * @n_bd -- total number of entries in queue (must be power of 2)
+ */
static inline int iwl4965_queue_inc_wrap(int index, int n_bd)
{
return ++index & (n_bd - 1);
}
-/* XXX: n_bd must be power-of-two size */
+/**
+ * iwl4965_queue_dec_wrap - decrement queue index, wrap back to end
+ * @index -- current index
+ * @n_bd -- total number of entries in queue (must be power of 2)
+ */
static inline int iwl4965_queue_dec_wrap(int index, int n_bd)
{
return --index & (n_bd - 1);
static inline u8 get_cmd_index(struct iwl4965_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);
}
+/**
+ * iwl4965_queue_init - Initialize queue's high/low-water and read/write indexes
+ */
static int iwl4965_queue_init(struct iwl4965_priv *priv, struct iwl4965_queue *q,
int count, int slots_num, u32 id)
{
return 0;
}
+/**
+ * iwl4965_tx_queue_alloc - Alloc driver data and TFD CB for one Tx/cmd queue
+ */
static int iwl4965_tx_queue_alloc(struct iwl4965_priv *priv,
struct iwl4965_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);
} 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);
return -ENOMEM;
}
+/**
+ * iwl4965_tx_queue_init - Allocate and initialize one tx/cmd queue
+ */
int iwl4965_tx_queue_init(struct iwl4965_priv *priv,
struct iwl4965_tx_queue *txq, int slots_num, u32 txq_id)
{
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 normal Tx queues (all other queues), no super-size command
+ * space is needed.
+ */
len = sizeof(struct iwl4965_cmd) * slots_num;
if (txq_id == IWL_CMD_QUEUE_NUM)
len += IWL_MAX_SCAN_SIZE;
if (!txq->cmd)
return -ENOMEM;
+ /* Alloc driver data array and TFD circular buffer */
rc = iwl4965_tx_queue_alloc(priv, txq, txq_id);
if (rc) {
pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
/* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
* iwl4965_queue_inc_wrap and iwl4965_queue_dec_wrap are broken. */
BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
+
+ /* Initialize queue's high/low-water marks, and head/tail indexes */
iwl4965_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
+ /* Tell device where to find queue */
iwl4965_hw_tx_queue_init(priv, txq);
return 0;
* @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 iwl4965_tx_queue_free(struct iwl4965_priv *priv, struct iwl4965_tx_queue *txq)
{
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 iwl4965_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 iwl4965_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 iwl4965_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 */
+/**
+ * iwl4965_remove_station - Remove driver's knowledge of station.
+ *
+ * NOTE: This does not remove station from device's station table.
+ */
static u8 iwl4965_remove_station(struct iwl4965_priv *priv, const u8 *addr, int is_ap)
{
int index = IWL_INVALID_STATION;
}
#endif
+/**
+ * iwl4965_clear_stations_table - Clear the driver's station table
+ *
+ * NOTE: This does not clear or otherwise alter the device's station table.
+ */
static void iwl4965_clear_stations_table(struct iwl4965_priv *priv)
{
unsigned long flags;
spin_unlock_irqrestore(&priv->sta_lock, flags);
}
-u8 iwl4965_add_station_flags(struct iwl4965_priv *priv, const u8 *addr, int is_ap, u8 flags)
+/**
+ * iwl4965_add_station_flags - Add station to tables in driver and device
+ */
+u8 iwl4965_add_station_flags(struct iwl4965_priv *priv, const u8 *addr,
+ int is_ap, u8 flags, void *ht_data)
{
int i;
int index = IWL_INVALID_STATION;
}
- /* These two conditions has the same outcome but keep them separate
- since they have different meaning */
+ /* These two conditions have the same outcome, but keep them separate
+ since they have different meanings */
if (unlikely(index == IWL_INVALID_STATION)) {
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
return index;
station->used = 1;
priv->num_stations++;
+ /* Set up the REPLY_ADD_STA command to send to device */
memset(&station->sta, 0, sizeof(struct iwl4965_addsta_cmd));
memcpy(station->sta.sta.addr, addr, ETH_ALEN);
station->sta.mode = 0;
/* BCAST station and IBSS stations do not work in HT mode */
if (index != priv->hw_setting.bcast_sta_id &&
priv->iw_mode != IEEE80211_IF_TYPE_IBSS)
- iwl4965_set_ht_add_station(priv, index);
+ iwl4965_set_ht_add_station(priv, index,
+ (struct ieee80211_ht_info *) ht_data);
#endif /*CONFIG_IWL4965_HT*/
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+
+ /* Add station to device's station table */
iwl4965_send_add_station(priv, &station->sta, flags);
return index;
fix_size, q->write_ptr, idx, IWL_CMD_QUEUE_NUM);
txq->need_update = 1;
+
+ /* Set up entry in queue's byte count circular buffer */
ret = iwl4965_tx_queue_update_wr_ptr(priv, txq, 0);
+
+ /* Increment and update queue's write index */
q->write_ptr = iwl4965_queue_inc_wrap(q->write_ptr, q->n_bd);
iwl4965_tx_queue_update_write_ptr(priv, txq);
* iwl4965_rxon_add_station - add station into station table.
*
* there is only one AP station with id= IWL_AP_ID
- * NOTE: mutex must be held before calling the this fnction
-*/
+ * NOTE: mutex must be held before calling this fnction
+ */
static int iwl4965_rxon_add_station(struct iwl4965_priv *priv,
const u8 *addr, int is_ap)
{
u8 sta_id;
- sta_id = iwl4965_add_station_flags(priv, addr, is_ap, 0);
+ /* Add station to device's station table */
+#ifdef CONFIG_IWL4965_HT
+ struct ieee80211_conf *conf = &priv->hw->conf;
+ struct ieee80211_ht_info *cur_ht_config = &conf->ht_conf;
+
+ if ((is_ap) &&
+ (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) &&
+ (priv->iw_mode == IEEE80211_IF_TYPE_STA))
+ sta_id = iwl4965_add_station_flags(priv, addr, is_ap,
+ 0, cur_ht_config);
+ else
+#endif /* CONFIG_IWL4965_HT */
+ sta_id = iwl4965_add_station_flags(priv, addr, is_ap,
+ 0, NULL);
+
+ /* Set up default rate scaling table in device's station table */
iwl4965_add_station(priv, addr, is_ap);
return sta_id;
* NOTE: Does not commit to the hardware; it sets appropriate bit fields
* in the staging RXON flag structure based on the phymode
*/
-static int iwl4965_set_rxon_channel(struct iwl4965_priv *priv, u8 phymode, u16 channel)
+static int iwl4965_set_rxon_channel(struct iwl4965_priv *priv, u8 phymode,
+ u16 channel)
{
if (!iwl4965_get_channel_info(priv, phymode, channel)) {
IWL_DEBUG_INFO("Could not set channel to %d [%d]\n",
}
/**
- * iwl4965_full_rxon_required - determine if RXON_ASSOC can be used in RXON commit
+ * iwl4965_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 iwl4965_full_rxon_required(struct iwl4965_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.
{
int i = 0;
+ /* 4965 HT rate format */
if (plcp & RATE_MCS_HT_MSK) {
i = (plcp & 0xff);
if ((i >= IWL_FIRST_OFDM_RATE) &&
(i <= IWL_LAST_OFDM_RATE))
return i;
+
+ /* 4965 legacy rate format, search for match in table */
} else {
for (i = 0; i < ARRAY_SIZE(iwl4965_rates); i++)
if (iwl4965_rates[i].plcp == (plcp &0xFF))
/**
* iwl4965_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.
*/
int iwl4965_eeprom_init(struct iwl4965_priv *priv)
{
- u16 *e = (u16 *)&priv->eeprom;
+ __le16 *e = (__le16 *)&priv->eeprom;
u32 gp = iwl4965_read32(priv, CSR_EEPROM_GP);
u32 r;
int sz = sizeof(priv->eeprom);
return -ENOENT;
}
+ /* Make sure driver (instead of uCode) is allowed to read EEPROM */
rc = iwl4965_eeprom_acquire_semaphore(priv);
if (rc < 0) {
IWL_ERROR("Failed to acquire EEPROM semaphore.\n");
rc = -ETIMEDOUT;
goto done;
}
- e[addr / 2] = le16_to_cpu(r >> 16);
+ e[addr / 2] = cpu_to_le16(r >> 16);
}
rc = 0;
/**
* iwl4965_report_frame - dump frame to syslog during debug sessions
*
- * hack this function to show different aspects of received frames,
+ * You may 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. iwl4965_rx_frame_stats)
- * is 3945-specific and gives bad output for 4965. Need to split the
- * functionality, keep common stuff here.
+ * TODO: This was originally written for 3945, need to audit for
+ * proper operation with 4965.
*/
void iwl4965_report_frame(struct iwl4965_priv *priv,
struct iwl4965_rx_packet *pkt,
#ifdef CONFIG_IWL4965_HT
void static iwl4965_set_ht_capab(struct ieee80211_hw *hw,
- struct ieee80211_ht_capability *ht_cap,
- u8 use_wide_chan);
+ struct ieee80211_ht_cap *ht_cap,
+ u8 use_current_config);
#endif
/**
int len = 0;
u8 *pos = NULL;
u16 active_rates, ret_rates, cck_rates, active_rate_basic;
+#ifdef CONFIG_IWL4965_HT
+ struct ieee80211_hw_mode *mode;
+#endif /* CONFIG_IWL4965_HT */
/* Make sure there is enough space for the probe request,
* two mandatory IEs and the data */
len += 2 + *pos;
#ifdef CONFIG_IWL4965_HT
- if (is_direct && priv->is_ht_enabled) {
- u8 use_wide_chan = 1;
-
- if (priv->channel_width != IWL_CHANNEL_WIDTH_40MHZ)
- use_wide_chan = 0;
+ mode = priv->hw->conf.mode;
+ if (mode->ht_info.ht_supported) {
pos += (*pos) + 1;
*pos++ = WLAN_EID_HT_CAPABILITY;
- *pos++ = sizeof(struct ieee80211_ht_capability);
- iwl4965_set_ht_capab(NULL, (struct ieee80211_ht_capability *)pos,
- use_wide_chan);
- len += 2 + sizeof(struct ieee80211_ht_capability);
+ *pos++ = sizeof(struct ieee80211_ht_cap);
+ iwl4965_set_ht_capab(priv->hw,
+ (struct ieee80211_ht_cap *)pos, 0);
+ len += 2 + sizeof(struct ieee80211_ht_cap);
}
#endif /*CONFIG_IWL4965_HT */
QOS_PARAM_FLG_UPDATE_EDCA_MSK;
#ifdef CONFIG_IWL4965_HT
- if (priv->is_ht_enabled && priv->current_assoc_ht.is_ht)
+ if (priv->current_ht_config.is_ht)
priv->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
#endif /* CONFIG_IWL4965_HT */
static int iwl4965_send_power_mode(struct iwl4965_priv *priv, u32 mode)
{
- u32 final_mode = mode;
+ u32 uninitialized_var(final_mode);
int rc;
struct iwl4965_powertable_cmd cmd;
static int iwl4965_set_mode(struct iwl4965_priv *priv, int mode)
{
- if (!iwl4965_is_ready_rf(priv))
- return -EAGAIN;
-
if (mode == IEEE80211_IF_TYPE_IBSS) {
const struct iwl4965_channel_info *ch_info;
}
}
- cancel_delayed_work(&priv->scan_check);
- if (iwl4965_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;
iwl4965_connection_init_rx_config(priv);
iwl4965_clear_stations_table(priv);
+ /* dont commit rxon if rf-kill is on*/
+ if (!iwl4965_is_ready_rf(priv))
+ return -EAGAIN;
+
+ cancel_delayed_work(&priv->scan_check);
+ if (iwl4965_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;
+ }
+
iwl4965_commit_rxon(priv);
return 0;
tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
}
+ if (ieee80211_is_back_request(fc))
+ tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK;
+
+
cmd->cmd.tx.sta_id = std_id;
if (ieee80211_get_morefrag(hdr))
tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
cmd->cmd.tx.next_frame_len = 0;
}
-static int iwl4965_get_sta_id(struct iwl4965_priv *priv, struct ieee80211_hdr *hdr)
+/**
+ * iwl4965_get_sta_id - Find station's index within station table
+ *
+ * If new IBSS station, create new entry in station table
+ */
+static int iwl4965_get_sta_id(struct iwl4965_priv *priv,
+ struct ieee80211_hdr *hdr)
{
int sta_id;
u16 fc = le16_to_cpu(hdr->frame_control);
DECLARE_MAC_BUF(mac);
- /* 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;
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:
sta_id = iwl4965_hw_find_station(priv, hdr->addr1);
if (sta_id != IWL_INVALID_STATION)
return sta_id;
- sta_id = iwl4965_add_station_flags(priv, hdr->addr1, 0, CMD_ASYNC);
+ /* Create new station table entry */
+ sta_id = iwl4965_add_station_flags(priv, hdr->addr1,
+ 0, CMD_ASYNC, NULL);
if (sta_id != IWL_INVALID_STATION)
return sta_id;
struct iwl4965_queue *q = NULL;
dma_addr_t phys_addr;
dma_addr_t txcmd_phys;
+ dma_addr_t scratch_phys;
struct iwl4965_cmd *out_cmd = NULL;
u16 len, idx, len_org;
u8 id, hdr_len, unicast;
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;
}
IWL_DEBUG_TX("Sending REASSOC frame\n");
#endif
- if (!iwl4965_is_associated(priv) &&
+ /* drop all data frame if we are not associated */
+ if (!iwl4965_is_associated(priv) && !priv->assoc_id &&
((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
IWL_DEBUG_DROP("Dropping - !iwl4965_is_associated\n");
goto drop_unlock;
spin_unlock_irqrestore(&priv->lock, flags);
hdr_len = ieee80211_get_hdrlen(fc);
+
+ /* Find (or create) index into station table for destination station */
sta_id = iwl4965_get_sta_id(priv, hdr);
if (sta_id == IWL_INVALID_STATION) {
DECLARE_MAC_BUF(mac);
#endif /* CONFIG_IWL4965_HT_AGG */
#endif /* CONFIG_IWL4965_HT */
}
+
+ /* 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 iwl4965_tx_info));
txq->txb[q->write_ptr].skb[0] = skb;
memcpy(&(txq->txb[q->write_ptr].status.control),
ctl, sizeof(struct ieee80211_tx_control));
+
+ /* Set up 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 iwl4965_cmd_header) + hdr_len;
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 iwl4965_cmd) * idx +
offsetof(struct iwl4965_cmd, hdr);
+ /* Add buffer containing Tx command and MAC(!) header to TFD's
+ * first entry */
iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len);
if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
iwl4965_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,
iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len);
}
+ /* Tell 4965 about any 2-byte padding after MAC header */
if (len_org)
out_cmd->cmd.tx.tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
+ /* Total # bytes to be transmitted */
len = (u16)skb->len;
out_cmd->cmd.tx.len = cpu_to_le16(len);
/* set is_hcca to 0; it probably will never be implemented */
iwl4965_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0);
- iwl4965_tx_cmd(priv, out_cmd, sta_id, txcmd_phys,
- hdr, hdr_len, ctl, NULL);
+ scratch_phys = txcmd_phys + sizeof(struct iwl4965_cmd_header) +
+ offsetof(struct iwl4965_tx_cmd, scratch);
+ out_cmd->cmd.tx.dram_lsb_ptr = cpu_to_le32(scratch_phys);
+ out_cmd->cmd.tx.dram_msb_ptr = iwl_get_dma_hi_address(scratch_phys);
+
+#ifdef CONFIG_IWL4965_HT_AGG
+#ifdef CONFIG_IWL4965_HT
+ /* TODO: move this functionality to rate scaling */
+ iwl4965_tl_get_stats(priv, hdr);
+#endif /* CONFIG_IWL4965_HT_AGG */
+#endif /*CONFIG_IWL4965_HT */
+
if (!ieee80211_get_morefrag(hdr)) {
txq->need_update = 1;
iwl4965_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr,
ieee80211_get_hdrlen(fc));
+ /* Set up entry for this TFD in Tx byte-count array */
iwl4965_tx_queue_update_wr_ptr(priv, txq, len);
+ /* Tell device the write index *just past* this latest filled TFD */
q->write_ptr = iwl4965_queue_inc_wrap(q->write_ptr, q->n_bd);
rc = iwl4965_tx_queue_update_write_ptr(priv, txq);
spin_unlock_irqrestore(&priv->lock, flags);
}
}
-void iwl4965_handle_data_packet_monitor(struct iwl4965_priv *priv,
- struct iwl4965_rx_mem_buffer *rxb,
- void *data, short len,
- struct ieee80211_rx_status *stats,
- u16 phy_flags)
-{
- struct iwl4965_rt_rx_hdr *iwl4965_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(*iwl4965_rt)) {
- IWL_DEBUG_DROP("Dropping too large packet in monitor\n");
- return;
- }
-
- /* copy the frame data to write after where the radiotap header goes */
- iwl4965_rt = (void *)rxb->skb->data;
- memmove(iwl4965_rt->payload, data, len);
-
- iwl4965_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
- iwl4965_rt->rt_hdr.it_pad = 0; /* always good to zero */
-
- /* total header + data */
- iwl4965_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*iwl4965_rt));
-
- /* Set the size of the skb to the size of the frame */
- skb_put(rxb->skb, sizeof(*iwl4965_rt) + len);
-
- /* Big bitfield of all the fields we provide in radiotap */
- iwl4965_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 */
- iwl4965_rt->rt_flags = 0;
-
- iwl4965_rt->rt_tsf = cpu_to_le64(tsf);
-
- /* Convert to dBm */
- iwl4965_rt->rt_dbmsignal = signal;
- iwl4965_rt->rt_dbmnoise = noise;
-
- /* Convert the channel frequency and set the flags */
- iwl4965_rt->rt_channelMHz = cpu_to_le16(stats->freq);
- if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK))
- iwl4965_rt->rt_chbitmask =
- cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ));
- else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK)
- iwl4965_rt->rt_chbitmask =
- cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ));
- else /* 802.11g */
- iwl4965_rt->rt_chbitmask =
- cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ));
-
- rate = iwl4965_rate_index_from_plcp(rate);
- if (rate == -1)
- iwl4965_rt->rt_rate = 0;
- else
- iwl4965_rt->rt_rate = iwl4965_rates[rate].ieee;
-
- /* antenna number */
- iwl4965_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)
- iwl4965_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
}
/**
- * iwl4965_tx_queue_reclaim - Reclaim Tx queue entries no more used by NIC.
+ * iwl4965_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd
*
- * 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.
+ * 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 the stack that feeds us.
*/
int iwl4965_tx_queue_reclaim(struct iwl4965_priv *priv, int txq_id, int index)
{
return le32_to_cpu(*scd_ssn) & MAX_SN;
}
+
+/**
+ * iwl4965_tx_status_reply_tx - Handle Tx rspnse for frames in aggregation queue
+ */
static int iwl4965_tx_status_reply_tx(struct iwl4965_priv *priv,
struct iwl4965_ht_agg *agg,
struct iwl4965_tx_resp *tx_resp,
u16 seq;
if (agg->wait_for_ba)
- IWL_DEBUG_TX_REPLY("got tx repsons w/o back\n");
+ IWL_DEBUG_TX_REPLY("got tx response w/o block-ack\n");
agg->frame_count = tx_resp->frame_count;
agg->start_idx = start_idx;
agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
agg->bitmap0 = agg->bitmap1 = 0;
+ /* # frames attempted by Tx command */
if (agg->frame_count == 1) {
+ /* Only one frame was attempted; no block-ack will arrive */
struct iwl4965_tx_queue *txq ;
status = le32_to_cpu(frame_status[0]);
agg->wait_for_ba = 0;
} else {
+ /* Two or more frames were attempted; expect block-ack */
u64 bitmap = 0;
int start = agg->start_idx;
+ /* Construct bit-map of pending frames within Tx window */
for (i = 0; i < agg->frame_count; i++) {
u16 sc;
status = le32_to_cpu(frame_status[i]);
#endif
#endif
+/**
+ * iwl4965_rx_reply_tx - Handle standard (non-aggregation) Tx response
+ */
static void iwl4965_rx_reply_tx(struct iwl4965_priv *priv,
struct iwl4965_rx_mem_buffer *rxb)
{
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");
(priv->last_scan_jiffies, jiffies)));
priv->last_scan_jiffies = jiffies;
+ priv->next_scan_jiffies = 0;
}
/* Service SCAN_COMPLETE_NOTIFICATION (0x84) */
}
priv->last_scan_jiffies = jiffies;
+ priv->next_scan_jiffies = 0;
IWL_DEBUG_INFO("Setting scan to off\n");
clear_bit(STATUS_SCANNING, &priv->status);
iwl4965_rx_pm_debug_statistics_notif;
priv->rx_handlers[BEACON_NOTIFICATION] = iwl4965_rx_beacon_notif;
- /* NOTE: iwl4965_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] = iwl4965_hw_rx_statistics;
priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl4965_hw_rx_statistics;
priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl4965_rx_card_state_notif;
priv->rx_handlers[REPLY_TX] = iwl4965_rx_reply_tx;
- /* Setup hardware specific Rx handlers */
+ /* Set up hardware specific Rx handlers */
iwl4965_hw_rx_handler_setup(priv);
}
/*
* Rx theory of operation
*
- * The host allocates 32 DMA target addresses and passes the host address
- * to the firmware at register IWL_RFDS_TABLE_LOWER + N * RFD_SIZE where N is
- * 0 to 31
+ * Driver allocates a circular buffer of Receive Buffer Descriptors (RBDs),
+ * each of which point to Receive Buffers to be filled by 4965. These get
+ * used not only for Rx frames, but for any command response or notification
+ * from the 4965. The driver and 4965 manage the Rx buffers by means
+ * of indexes into the circular buffer.
*
* Rx Queue Indexes
* The host/firmware share two index registers for managing the Rx buffers.
* 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.
*
* Driver sequence:
*
- * iwl4965_rx_queue_alloc() Allocates rx_free
- * iwl4965_rx_replenish() Replenishes rx_free list from rx_used, and calls
+ * iwl4965_rx_queue_alloc() Allocates rx_free
+ * iwl4965_rx_replenish() Replenishes rx_free list from rx_used, and calls
* iwl4965_rx_queue_restock
- * iwl4965_rx_queue_restock() Moves available buffers from rx_free into Rx
+ * iwl4965_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 iwl4965_rx_replenish
*
* -- enable interrupts --
- * ISR - iwl4965_rx() Detach iwl4965_rx_mem_buffers from pool up to the
+ * ISR - iwl4965_rx() Detach iwl4965_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 iwl4965_rx_queue_restock to refill any empty
/**
* iwl4965_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 iwl4965_rx_queue_update_write_ptr(struct iwl4965_priv *priv, struct iwl4965_rx_queue *q)
{
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 = iwl4965_read32(priv, CSR_UCODE_DRV_GP1);
if (rc)
goto exit_unlock;
+ /* Device expects a multiple of 8 */
iwl4965_write_direct32(priv, FH_RSCSR_CHNL0_WPTR,
q->write & ~0x7);
iwl4965_release_nic_access(priv);
+
+ /* Else device is assumed to be awake */
} else
+ /* Device expects a multiple of 8 */
iwl4965_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7);
}
/**
- * iwl4965_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.
+ * iwl4965_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr
*/
static inline __le32 iwl4965_dma_addr2rbd_ptr(struct iwl4965_priv *priv,
dma_addr_t dma_addr)
/**
* iwl4965_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
spin_lock_irqsave(&rxq->lock, flags);
write = rxq->write & ~0x7;
while ((iwl4965_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 iwl4965_rx_mem_buffer, list);
list_del(element);
+
+ /* Point to Rx buffer via next RBD in circular buffer */
rxq->bd[rxq->write] = iwl4965_dma_addr2rbd_ptr(priv, rxb->dma_addr);
rxq->queue[rxq->write] = rxb;
rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
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);
* Also restock the Rx queue via iwl4965_rx_queue_restock.
* This is called as a scheduled work item (except for during initialization)
*/
-void iwl4965_rx_replenish(void *data)
+static void iwl4965_rx_allocate(struct iwl4965_priv *priv)
{
- struct iwl4965_priv *priv = data;
struct iwl4965_rx_queue *rxq = &priv->rxq;
struct list_head *element;
struct iwl4965_rx_mem_buffer *rxb;
while (!list_empty(&rxq->rx_used)) {
element = rxq->rx_used.next;
rxb = list_entry(element, struct iwl4965_rx_mem_buffer, list);
+
+ /* Alloc a new receive buffer */
rxb->skb =
- alloc_skb(IWL_RX_BUF_SIZE, __GFP_NOWARN | GFP_ATOMIC);
+ alloc_skb(priv->hw_setting.rx_buf_size,
+ __GFP_NOWARN | GFP_ATOMIC);
if (!rxb->skb) {
if (net_ratelimit())
printk(KERN_CRIT DRV_NAME
}
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);
+ priv->hw_setting.rx_buf_size, PCI_DMA_FROMDEVICE);
list_add_tail(&rxb->list, &rxq->rx_free);
rxq->free_count++;
}
spin_unlock_irqrestore(&rxq->lock, flags);
+}
+
+/*
+ * this should be called while priv->lock is locked
+*/
+static void __iwl4965_rx_replenish(void *data)
+{
+ struct iwl4965_priv *priv = data;
+
+ iwl4965_rx_allocate(priv);
+ iwl4965_rx_queue_restock(priv);
+}
+
+
+void iwl4965_rx_replenish(void *data)
+{
+ struct iwl4965_priv *priv = data;
+ unsigned long flags;
+
+ iwl4965_rx_allocate(priv);
spin_lock_irqsave(&priv->lock, flags);
iwl4965_rx_queue_restock(priv);
}
/* 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
+ * 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
*/
if (rxq->pool[i].skb != NULL) {
pci_unmap_single(priv->pci_dev,
rxq->pool[i].dma_addr,
- IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ priv->hw_setting.rx_buf_size,
+ PCI_DMA_FROMDEVICE);
dev_kfree_skb(rxq->pool[i].skb);
}
}
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;
if (rxq->pool[i].skb != NULL) {
pci_unmap_single(priv->pci_dev,
rxq->pool[i].dma_addr,
- IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ priv->hw_setting.rx_buf_size,
+ PCI_DMA_FROMDEVICE);
priv->alloc_rxb_skb--;
dev_kfree_skb(rxq->pool[i].skb);
rxq->pool[i].skb = NULL;
}
/**
- * iwl4965_rx_handle - Main entry function for receiving responses from the uCode
+ * iwl4965_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,
u32 r, i;
int reclaim;
unsigned long flags;
+ u8 fill_rx = 0;
+ u32 count = 0;
+ /* uCode's read index (stored in shared DRAM) indicates the last Rx
+ * buffer that the driver may process (last buffer filled by ucode). */
r = iwl4965_hw_get_rx_read(priv);
i = rxq->read;
if (i == r)
IWL_DEBUG(IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d\n", r, i);
+ if (iwl4965_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2))
+ fill_rx = 1;
+
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);
rxq->queue[i] = NULL;
pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
- IWL_RX_BUF_SIZE,
+ priv->hw_setting.rx_buf_size,
PCI_DMA_FROMDEVICE);
pkt = (struct iwl4965_rx_packet *)rxb->skb->data;
}
if (reclaim) {
- /* Invoke any callbacks, transfer the skb to caller,
- * and fire off the (possibly) blocking iwl4965_send_cmd()
+ /* Invoke any callbacks, transfer the skb to caller, and
+ * fire off the (possibly) blocking iwl4965_send_cmd()
* as we reclaim the driver command queue */
if (rxb && rxb->skb)
iwl4965_tx_cmd_complete(priv, rxb);
}
pci_unmap_single(priv->pci_dev, rxb->dma_addr,
- IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ priv->hw_setting.rx_buf_size,
+ PCI_DMA_FROMDEVICE);
spin_lock_irqsave(&rxq->lock, flags);
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 wont assert. */
+ if (fill_rx) {
+ count++;
+ if (count >= 8) {
+ priv->rxq.read = i;
+ __iwl4965_rx_replenish(priv);
+ count = 0;
+ }
+ }
}
/* Backtrack one entry */
iwl4965_rx_queue_restock(priv);
}
+/**
+ * iwl4965_tx_queue_update_write_ptr - Send new write index to hardware
+ */
static int iwl4965_tx_queue_update_write_ptr(struct iwl4965_priv *priv,
struct iwl4965_tx_queue *txq)
{
#ifdef CONFIG_IWL4965_DEBUG
if (iwl4965_debug_level & IWL_DL_ISR) {
- inta_mask = iwl4965_read32(priv, CSR_INT_MASK); /* just for debug */
+ /* just for debug */
+ inta_mask = iwl4965_read32(priv, CSR_INT_MASK);
IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
inta, inta_mask, inta_fh);
}
/* Safely ignore these bits for debug checks below */
inta &= ~(CSR_INT_BIT_MAC_CLK_ACTV | CSR_INT_BIT_ALIVE);
- /* HW RF KILL switch toggled (4965 only) */
+ /* HW RF KILL switch toggled */
if (inta & CSR_INT_BIT_RF_KILL) {
int hw_rf_kill = 0;
if (!(iwl4965_read32(priv, CSR_GP_CNTRL) &
handled |= CSR_INT_BIT_RF_KILL;
}
- /* Chip got too hot and stopped itself (4965 only) */
+ /* Chip got too hot and stopped itself */
if (inta & CSR_INT_BIT_CT_KILL) {
IWL_ERROR("Microcode CT kill error detected.\n");
handled |= CSR_INT_BIT_CT_KILL;
};
/* 5.2 GHz bands */
-static const u8 iwl4965_eeprom_band_2[] = {
+static const u8 iwl4965_eeprom_band_2[] = { /* 4915-5080MHz */
183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16
};
-static const u8 iwl4965_eeprom_band_3[] = { /* 5205-5320MHz */
+static const u8 iwl4965_eeprom_band_3[] = { /* 5170-5320MHz */
34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
};
36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157
};
-static void iwl4965_init_band_reference(const struct iwl4965_priv *priv, int band,
+static void iwl4965_init_band_reference(const struct iwl4965_priv *priv,
+ int band,
int *eeprom_ch_count,
const struct iwl4965_eeprom_channel
**eeprom_ch_info,
*eeprom_ch_info = priv->eeprom.band_1_channels;
*eeprom_ch_index = iwl4965_eeprom_band_1;
break;
- case 2: /* 5.2GHz band */
+ case 2: /* 4.9GHz band */
*eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_2);
*eeprom_ch_info = priv->eeprom.band_2_channels;
*eeprom_ch_index = iwl4965_eeprom_band_2;
*eeprom_ch_info = priv->eeprom.band_3_channels;
*eeprom_ch_index = iwl4965_eeprom_band_3;
break;
- case 4: /* 5.2GHz band */
+ case 4: /* 5.5GHz band */
*eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_4);
*eeprom_ch_info = priv->eeprom.band_4_channels;
*eeprom_ch_index = iwl4965_eeprom_band_4;
break;
- case 5: /* 5.2GHz band */
+ case 5: /* 5.7GHz band */
*eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_5);
*eeprom_ch_info = priv->eeprom.band_5_channels;
*eeprom_ch_index = iwl4965_eeprom_band_5;
break;
- case 6:
+ case 6: /* 2.4GHz FAT channels */
*eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_6);
*eeprom_ch_info = priv->eeprom.band_24_channels;
*eeprom_ch_index = iwl4965_eeprom_band_6;
break;
- case 7:
+ case 7: /* 5 GHz FAT channels */
*eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_7);
*eeprom_ch_info = priv->eeprom.band_52_channels;
*eeprom_ch_index = iwl4965_eeprom_band_7;
}
}
+/**
+ * iwl4965_get_channel_info - Find driver's private channel info
+ *
+ * Based on band and channel number.
+ */
const struct iwl4965_channel_info *iwl4965_get_channel_info(const struct iwl4965_priv *priv,
int phymode, u16 channel)
{
#define CHECK_AND_PRINT(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \
? # x " " : "")
+/**
+ * iwl4965_init_channel_map - Set up driver's info for all possible channels
+ */
static int iwl4965_init_channel_map(struct iwl4965_priv *priv)
{
int eeprom_ch_count = 0;
}
}
+ /* Two additional EEPROM bands for 2.4 and 5 GHz FAT channels */
for (band = 6; band <= 7; band++) {
int phymode;
u8 fat_extension_chan;
iwl4965_init_band_reference(priv, band, &eeprom_ch_count,
&eeprom_ch_info, &eeprom_ch_index);
+ /* EEPROM band 6 is 2.4, band 7 is 5 GHz */
phymode = (band == 6) ? MODE_IEEE80211B : MODE_IEEE80211A;
+
/* Loop through each band adding each of the channels */
for (ch = 0; ch < eeprom_ch_count; ch++) {
else
fat_extension_chan = HT_IE_EXT_CHANNEL_ABOVE;
+ /* Set up driver's info for lower half */
iwl4965_set_fat_chan_info(priv, phymode,
eeprom_ch_index[ch],
&(eeprom_ch_info[ch]),
fat_extension_chan);
+ /* Set up driver's info for upper half */
iwl4965_set_fat_chan_info(priv, phymode,
(eeprom_ch_index[ch] + 4),
&(eeprom_ch_info[ch]),
scan_ch->channel = channels[i].chan;
- ch_info = iwl4965_get_channel_info(priv, phymode, scan_ch->channel);
+ ch_info = iwl4965_get_channel_info(priv, phymode,
+ scan_ch->channel);
if (!is_channel_valid(ch_info)) {
IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n",
scan_ch->channel);
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; */
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;
*/
}
A = 0,
B = 1,
G = 2,
- A_11N = 3,
- G_11N = 4,
};
- int mode_count = 5;
+ int mode_count = 3;
if (priv->modes) {
IWL_DEBUG_INFO("Geography modes already initialized.\n");
modes[A].num_rates = 8; /* just OFDM */
modes[A].rates = &rates[4];
modes[A].num_channels = 0;
+#ifdef CONFIG_IWL4965_HT
+ iwl4965_init_ht_hw_capab(&modes[A].ht_info, MODE_IEEE80211A);
+#endif
modes[B].mode = MODE_IEEE80211B;
modes[B].channels = channels;
modes[G].rates = rates;
modes[G].num_rates = 12; /* OFDM & CCK */
modes[G].num_channels = 0;
-
- modes[G_11N].mode = MODE_IEEE80211G;
- modes[G_11N].channels = channels;
- modes[G_11N].num_rates = 13; /* OFDM & CCK */
- modes[G_11N].rates = rates;
- modes[G_11N].num_channels = 0;
-
- modes[A_11N].mode = MODE_IEEE80211A;
- modes[A_11N].channels = &channels[ARRAY_SIZE(iwl4965_eeprom_band_1)];
- modes[A_11N].rates = &rates[4];
- modes[A_11N].num_rates = 9; /* just OFDM */
- modes[A_11N].num_channels = 0;
+#ifdef CONFIG_IWL4965_HT
+ iwl4965_init_ht_hw_capab(&modes[G].ht_info, MODE_IEEE80211G);
+#endif
priv->ieee_channels = channels;
priv->ieee_rates = rates;
if (is_channel_a_band(ch)) {
geo_ch = &modes[A].channels[modes[A].num_channels++];
- modes[A_11N].num_channels++;
} else {
geo_ch = &modes[B].channels[modes[B].num_channels++];
modes[G].num_channels++;
- modes[G_11N].num_channels++;
}
geo_ch->freq = ieee80211chan2mhz(ch->channel);
* iwl4965_verify_inst_full - verify runtime uCode image in card vs. host,
* looking at all data.
*/
-static int iwl4965_verify_inst_full(struct iwl4965_priv *priv, __le32 * image, u32 len)
+static int iwl4965_verify_inst_full(struct iwl4965_priv *priv, __le32 *image,
+ u32 len)
{
u32 val;
u32 save_len = len;
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 = iwl4965_verify_inst_full(priv, image, len);
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 35:4 for 4965.
* NOTE: iwl4965_initialize_alive_start() will replace these values,
* after the "initialize" uCode has run, to point to
* runtime/protocol instructions and backup data cache. */
iwl4965_write32(priv, CSR_RESET, 0);
}
+static int iwl4965_alloc_fw_desc(struct pci_dev *pci_dev, struct fw_desc *desc)
+{
+ desc->v_addr = pci_alloc_consistent(pci_dev, desc->len, &desc->p_addr);
+ return (desc->v_addr != NULL) ? 0 : -ENOMEM;
+}
+
/**
* iwl4965_read_ucode - Read uCode images from disk file.
*
static int iwl4965_read_ucode(struct iwl4965_priv *priv)
{
struct iwl4965_ucode *ucode;
- int rc = 0;
+ int ret;
const struct firmware *ucode_raw;
const char *name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode";
u8 *src;
/* 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;
}
/* 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;
}
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;
+ ("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;
+ ("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;
+ ("uCode boot instr len %d too large to fit in\n",
+ boot_size);
+ ret = -EINVAL;
goto err_release;
}
* 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));
+ iwl4965_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));
+ iwl4965_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));
-
+ iwl4965_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup);
/* 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;
+ iwl4965_alloc_fw_desc(priv->pci_dev, &priv->ucode_init);
+
+ priv->ucode_init_data.len = init_data_size;
+ iwl4965_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;
+ iwl4965_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);
* NOTE: Copy into backup buffer will be done in iwl4965_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);
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);
}
if (init_data_size) {
src = &ucode->data[inst_size + data_size + init_size];
len = priv->ucode_init_data.len;
- IWL_DEBUG_INFO("Copying (but not loading) init data len %d\n",
- (int)len);
+ IWL_DEBUG_INFO("Copying (but not loading) init data len %Zd\n",
+ len);
memcpy(priv->ucode_init_data.v_addr, src, len);
}
/* Bootstrap instructions (5th block) */
src = &ucode->data[inst_size + data_size + init_size + init_data_size];
len = priv->ucode_boot.len;
- IWL_DEBUG_INFO("Copying (but not loading) boot instr len %d\n",
- (int)len);
+ IWL_DEBUG_INFO("Copying (but not loading) boot instr len %Zd\n", len);
memcpy(priv->ucode_boot.v_addr, src, len);
/* We have our copies now, allow OS release its copies */
err_pci_alloc:
IWL_ERROR("failed to allocate pci memory\n");
- rc = -ENOMEM;
+ ret = -ENOMEM;
iwl4965_dealloc_ucode_pci(priv);
err_release:
release_firmware(ucode_raw);
error:
- return rc;
+ return ret;
}
goto restart;
}
- /* After the ALIVE response, we can process host commands */
+ /* After the ALIVE response, we can send host commands to 4965 uCode */
set_bit(STATUS_ALIVE, &priv->status);
/* Clear out the uCode error bit if it is set */
memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
}
- /* Configure BT coexistence */
+ /* Configure Bluetooth device coexistence support */
iwl4965_send_bt_config(priv);
/* Configure the adapter for unassociated operation */
STATUS_FW_ERROR;
spin_lock_irqsave(&priv->lock, flags);
- iwl4965_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+ iwl4965_clear_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
spin_unlock_irqrestore(&priv->lock, flags);
iwl4965_hw_txq_ctx_stop(priv);
/* start card; "initialize" will load runtime ucode */
iwl4965_nic_start(priv);
- /* MAC Address location in EEPROM same for 3945/4965 */
+ /* MAC Address location in EEPROM is same for 3945/4965 */
get_eeprom_mac(priv, priv->mac_addr);
IWL_DEBUG_INFO("MAC address: %s\n",
print_mac(mac, priv->mac_addr));
mutex_unlock(&priv->mutex);
}
+#define IWL_DELAY_NEXT_SCAN (HZ*2)
+
static void iwl4965_bg_post_associate(struct work_struct *data)
{
struct iwl4965_priv *priv = container_of(data, struct iwl4965_priv,
mutex_lock(&priv->mutex);
- if (!priv->interface_id || !priv->is_open) {
+ if (!priv->vif || !priv->is_open) {
mutex_unlock(&priv->mutex);
return;
}
priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
#ifdef CONFIG_IWL4965_HT
- if (priv->is_ht_enabled && priv->current_assoc_ht.is_ht)
- iwl4965_set_rxon_ht(priv, &priv->current_assoc_ht);
- else {
- priv->active_rate_ht[0] = 0;
- priv->active_rate_ht[1] = 0;
- priv->current_channel_width = IWL_CHANNEL_WIDTH_20MHZ;
- }
+ if (priv->current_ht_config.is_ht)
+ iwl4965_set_rxon_ht(priv, &priv->current_ht_config);
#endif /* CONFIG_IWL4965_HT*/
iwl4965_set_rxon_chain(priv);
priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
#ifdef CONFIG_IWL4965_QOS
iwl4965_activate_qos(priv, 0);
#endif /* CONFIG_IWL4965_QOS */
+ /* we have just associated, don't start scan too early */
+ priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN;
mutex_unlock(&priv->mutex);
}
mutex_unlock(&priv->mutex);
}
+static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
+
static void iwl4965_bg_scan_completed(struct work_struct *work)
{
struct iwl4965_priv *priv =
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
+ if (test_bit(STATUS_CONF_PENDING, &priv->status))
+ iwl4965_mac_config(priv->hw, ieee80211_get_hw_conf(priv->hw));
+
ieee80211_scan_completed(priv->hw);
/* Since setting the TXPOWER may have been deferred while
* RXON_FILTER_ASSOC_MSK BIT
*/
priv->is_open = 0;
+ if (!iwl4965_is_ready_rf(priv)) {
+ IWL_DEBUG_MAC80211("leave - RF not ready\n");
+ mutex_unlock(&priv->mutex);
+ return;
+ }
+
iwl4965_scan_cancel_timeout(priv, 100);
cancel_delayed_work(&priv->post_associate);
priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
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 0;
}
spin_lock_irqsave(&priv->lock, flags);
- priv->interface_id = conf->if_id;
+ priv->vif = conf->vif;
spin_unlock_irqrestore(&priv->lock, flags);
struct iwl4965_priv *priv = hw->priv;
const struct iwl4965_channel_info *ch_info;
unsigned long flags;
+ int ret = 0;
mutex_lock(&priv->mutex);
IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel);
+ priv->add_radiotap = !!(conf->flags & IEEE80211_CONF_RADIOTAP);
+
if (!iwl4965_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(!iwl4965_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;
}
conf->channel, conf->phymode);
IWL_DEBUG_MAC80211("leave - invalid channel\n");
spin_unlock_irqrestore(&priv->lock, flags);
- mutex_unlock(&priv->mutex);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
#ifdef CONFIG_IWL4965_HT
#ifdef IEEE80211_CONF_CHANNEL_SWITCH
if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) {
iwl4965_hw_channel_switch(priv, conf->channel);
- mutex_unlock(&priv->mutex);
- return 0;
+ goto out;
}
#endif
if (!conf->radio_enabled) {
IWL_DEBUG_MAC80211("leave - radio disabled\n");
- mutex_unlock(&priv->mutex);
- return 0;
+ goto out;
}
if (iwl4965_is_rfkill(priv)) {
IWL_DEBUG_MAC80211("leave - RF kill\n");
- mutex_unlock(&priv->mutex);
- return -EIO;
+ ret = -EIO;
+ goto out;
}
iwl4965_set_rate(priv);
IWL_DEBUG_MAC80211("leave\n");
mutex_unlock(&priv->mutex);
-
- return 0;
+out:
+ clear_bit(STATUS_CONF_PENDING, &priv->status);
+ return ret;
}
static void iwl4965_config_ap(struct iwl4965_priv *priv)
* clear sta table, add BCAST sta... */
}
-static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, int if_id,
+static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
struct ieee80211_if_conf *conf)
{
struct iwl4965_priv *priv = hw->priv;
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));
return 0;
}
- if (priv->interface_id != if_id) {
- IWL_DEBUG_MAC80211("leave - interface_id != if_id\n");
+ if (priv->vif != vif) {
+ IWL_DEBUG_MAC80211("leave - priv->vif != vif\n");
mutex_unlock(&priv->mutex);
return 0;
}
priv->ibss_beacon = conf->beacon;
}
+ if (iwl4965_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
iwl4965_commit_rxon(priv);
}
+ done:
spin_lock_irqsave(&priv->lock, flags);
if (!conf->ssid_len)
memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
mutex_lock(&priv->mutex);
- iwl4965_scan_cancel_timeout(priv, 100);
- cancel_delayed_work(&priv->post_associate);
- priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwl4965_commit_rxon(priv);
-
- if (priv->interface_id == conf->if_id) {
- priv->interface_id = 0;
+ if (iwl4965_is_ready_rf(priv)) {
+ iwl4965_scan_cancel_timeout(priv, 100);
+ cancel_delayed_work(&priv->post_associate);
+ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwl4965_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;
IWL_DEBUG_MAC80211("leave\n");
}
-static void iwl4965_mac_erp_ie_changed(struct ieee80211_hw *hw,
- u8 changes, int cts_protection, int preamble)
+
+static void iwl4965_bss_info_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *bss_conf,
+ u32 changes)
{
struct iwl4965_priv *priv = hw->priv;
- if (changes & IEEE80211_ERP_CHANGE_PREAMBLE) {
- if (preamble == WLAN_ERP_PREAMBLE_SHORT)
+ if (changes & BSS_CHANGED_ERP_PREAMBLE) {
+ if (bss_conf->use_short_preamble)
priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
else
priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
}
- if (changes & IEEE80211_ERP_CHANGE_PROTECTION) {
- if (cts_protection && (priv->phymode != MODE_IEEE80211A))
+ if (changes & BSS_CHANGED_ERP_CTS_PROT) {
+ if (bss_conf->use_cts_prot && (priv->phymode != MODE_IEEE80211A))
priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK;
else
priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
}
+ if (changes & BSS_CHANGED_ASSOC) {
+ /*
+ * TODO:
+ * do stuff instead of sniffing assoc resp
+ */
+ }
+
if (iwl4965_is_associated(priv))
iwl4965_send_rxon_assoc(priv);
}
-#define IWL_DELAY_NEXT_SCAN (HZ*2)
static int iwl4965_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
{
int rc = 0;
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 ",
iwl4965_escape_essid(ssid, len), (int)len);
priv->one_direct_scan = 1;
#ifdef CONFIG_IWL4965_QOS
unsigned long flags;
int q;
-#endif /* CONFIG_IWL_QOS */
+#endif /* CONFIG_IWL4965_QOS */
IWL_DEBUG_MAC80211("enter\n");
priv->lq_mngr.lq_ready = 0;
#ifdef CONFIG_IWL4965_HT
spin_lock_irqsave(&priv->lock, flags);
- memset(&priv->current_assoc_ht, 0, sizeof(struct sta_ht_info));
+ memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_info));
spin_unlock_irqrestore(&priv->lock, flags);
#ifdef CONFIG_IWL4965_HT_AGG
/* if (priv->lq_mngr.agg_ctrl.granted_ba)
spin_unlock_irqrestore(&priv->lock, flags);
+ if (!iwl4965_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
*/
return;
}
- if (!iwl4965_is_ready_rf(priv)) {
- IWL_DEBUG_MAC80211("leave - not ready\n");
- mutex_unlock(&priv->mutex);
- return;
- }
-
priv->only_active_channel = 0;
iwl4965_set_rate(priv);
}
#ifdef CONFIG_IWL4965_HT
-union ht_cap_info {
- struct {
- u16 advanced_coding_cap :1;
- u16 supported_chan_width_set :1;
- u16 mimo_power_save_mode :2;
- u16 green_field :1;
- u16 short_GI20 :1;
- u16 short_GI40 :1;
- u16 tx_stbc :1;
- u16 rx_stbc :1;
- u16 beam_forming :1;
- u16 delayed_ba :1;
- u16 maximal_amsdu_size :1;
- u16 cck_mode_at_40MHz :1;
- u16 psmp_support :1;
- u16 stbc_ctrl_frame_support :1;
- u16 sig_txop_protection_support :1;
- };
- u16 val;
-} __attribute__ ((packed));
-
-union ht_param_info{
- struct {
- u8 max_rx_ampdu_factor :2;
- u8 mpdu_density :3;
- u8 reserved :3;
- };
- u8 val;
-} __attribute__ ((packed));
-
-union ht_exra_param_info {
- struct {
- u8 ext_chan_offset :2;
- u8 tx_chan_width :1;
- u8 rifs_mode :1;
- u8 controlled_access_only :1;
- u8 service_interval_granularity :3;
- };
- u8 val;
-} __attribute__ ((packed));
-
-union ht_operation_mode{
- struct {
- u16 op_mode :2;
- u16 non_GF :1;
- u16 reserved :13;
- };
- u16 val;
-} __attribute__ ((packed));
-
-static int sta_ht_info_init(struct ieee80211_ht_capability *ht_cap,
- struct ieee80211_ht_additional_info *ht_extra,
- struct sta_ht_info *ht_info_ap,
- struct sta_ht_info *ht_info)
+static void iwl4965_ht_info_fill(struct ieee80211_conf *conf,
+ struct iwl4965_priv *priv)
{
- union ht_cap_info cap;
- union ht_operation_mode op_mode;
- union ht_param_info param_info;
- union ht_exra_param_info extra_param_info;
+ struct iwl_ht_info *iwl_conf = &priv->current_ht_config;
+ struct ieee80211_ht_info *ht_conf = &conf->ht_conf;
+ struct ieee80211_ht_bss_info *ht_bss_conf = &conf->ht_bss_conf;
IWL_DEBUG_MAC80211("enter: \n");
- if (!ht_info) {
- IWL_DEBUG_MAC80211("leave: ht_info is NULL\n");
- return -1;
+ if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) {
+ iwl_conf->is_ht = 0;
+ return;
}
- if (ht_cap) {
- cap.val = (u16) le16_to_cpu(ht_cap->capabilities_info);
- param_info.val = ht_cap->mac_ht_params_info;
- ht_info->is_ht = 1;
- if (cap.short_GI20)
- ht_info->sgf |= 0x1;
- if (cap.short_GI40)
- ht_info->sgf |= 0x2;
- ht_info->is_green_field = cap.green_field;
- ht_info->max_amsdu_size = cap.maximal_amsdu_size;
- ht_info->supported_chan_width = cap.supported_chan_width_set;
- ht_info->tx_mimo_ps_mode = cap.mimo_power_save_mode;
- memcpy(ht_info->supp_rates, ht_cap->supported_mcs_set, 16);
-
- ht_info->ampdu_factor = param_info.max_rx_ampdu_factor;
- ht_info->mpdu_density = param_info.mpdu_density;
-
- IWL_DEBUG_MAC80211("SISO mask 0x%X MIMO mask 0x%X \n",
- ht_cap->supported_mcs_set[0],
- ht_cap->supported_mcs_set[1]);
-
- if (ht_info_ap) {
- ht_info->control_channel = ht_info_ap->control_channel;
- ht_info->extension_chan_offset =
- ht_info_ap->extension_chan_offset;
- ht_info->tx_chan_width = ht_info_ap->tx_chan_width;
- ht_info->operating_mode = ht_info_ap->operating_mode;
- }
-
- if (ht_extra) {
- extra_param_info.val = ht_extra->ht_param;
- ht_info->control_channel = ht_extra->control_chan;
- ht_info->extension_chan_offset =
- extra_param_info.ext_chan_offset;
- ht_info->tx_chan_width = extra_param_info.tx_chan_width;
- op_mode.val = (u16)
- le16_to_cpu(ht_extra->operation_mode);
- ht_info->operating_mode = op_mode.op_mode;
- IWL_DEBUG_MAC80211("control channel %d\n",
- ht_extra->control_chan);
- }
- } else
- ht_info->is_ht = 0;
-
+ iwl_conf->is_ht = 1;
+ priv->ps_mode = (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2);
+
+ if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20)
+ iwl_conf->sgf |= 0x1;
+ if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40)
+ iwl_conf->sgf |= 0x2;
+
+ iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD);
+ iwl_conf->max_amsdu_size =
+ !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU);
+ iwl_conf->supported_chan_width =
+ !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH);
+ iwl_conf->tx_mimo_ps_mode =
+ (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2);
+ memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16);
+
+ iwl_conf->control_channel = ht_bss_conf->primary_channel;
+ iwl_conf->extension_chan_offset =
+ ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_SEC_OFFSET;
+ iwl_conf->tx_chan_width =
+ !!(ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_WIDTH);
+ iwl_conf->ht_protection =
+ ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_HT_PROTECTION;
+ iwl_conf->non_GF_STA_present =
+ !!(ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_NON_GF_STA_PRSNT);
+
+ IWL_DEBUG_MAC80211("control channel %d\n",
+ iwl_conf->control_channel);
IWL_DEBUG_MAC80211("leave\n");
- return 0;
}
static int iwl4965_mac_conf_ht(struct ieee80211_hw *hw,
- struct ieee80211_ht_capability *ht_cap,
- struct ieee80211_ht_additional_info *ht_extra)
+ struct ieee80211_conf *conf)
{
struct iwl4965_priv *priv = hw->priv;
- int rs;
IWL_DEBUG_MAC80211("enter: \n");
- rs = sta_ht_info_init(ht_cap, ht_extra, NULL, &priv->current_assoc_ht);
+ iwl4965_ht_info_fill(conf, priv);
iwl4965_set_rxon_chain(priv);
if (priv && priv->assoc_id &&
spin_unlock_irqrestore(&priv->lock, flags);
}
- IWL_DEBUG_MAC80211("leave: control channel %d\n",
- ht_extra->control_chan);
- return rs;
-
+ IWL_DEBUG_MAC80211("leave:\n");
+ return 0;
}
static void iwl4965_set_ht_capab(struct ieee80211_hw *hw,
- struct ieee80211_ht_capability *ht_cap,
- u8 use_wide_chan)
+ struct ieee80211_ht_cap *ht_cap,
+ u8 use_current_config)
{
- union ht_cap_info cap;
- union ht_param_info param_info;
-
- memset(&cap, 0, sizeof(union ht_cap_info));
- memset(¶m_info, 0, sizeof(union ht_param_info));
-
- cap.maximal_amsdu_size = HT_IE_MAX_AMSDU_SIZE_4K;
- cap.green_field = 1;
- cap.short_GI20 = 1;
- cap.short_GI40 = 1;
- cap.supported_chan_width_set = use_wide_chan;
- cap.mimo_power_save_mode = 0x3;
+ struct ieee80211_conf *conf = &hw->conf;
+ struct ieee80211_hw_mode *mode = conf->mode;
- param_info.max_rx_ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF;
- param_info.mpdu_density = CFG_HT_MPDU_DENSITY_DEF;
- ht_cap->capabilities_info = (__le16) cpu_to_le16(cap.val);
- ht_cap->mac_ht_params_info = (u8) param_info.val;
-
- ht_cap->supported_mcs_set[0] = 0xff;
- ht_cap->supported_mcs_set[1] = 0xff;
- ht_cap->supported_mcs_set[4] =
- (cap.supported_chan_width_set) ? 0x1: 0x0;
+ if (use_current_config) {
+ ht_cap->cap_info = cpu_to_le16(conf->ht_conf.cap);
+ memcpy(ht_cap->supp_mcs_set,
+ conf->ht_conf.supp_mcs_set, 16);
+ } else {
+ ht_cap->cap_info = cpu_to_le16(mode->ht_info.cap);
+ memcpy(ht_cap->supp_mcs_set,
+ mode->ht_info.supp_mcs_set, 16);
+ }
+ ht_cap->ampdu_params_info =
+ (mode->ht_info.ampdu_factor & IEEE80211_HT_CAP_AMPDU_FACTOR) |
+ ((mode->ht_info.ampdu_density << 2) &
+ IEEE80211_HT_CAP_AMPDU_DENSITY);
}
-static void iwl4965_mac_get_ht_capab(struct ieee80211_hw *hw,
- struct ieee80211_ht_capability *ht_cap)
-{
- u8 use_wide_channel = 1;
- struct iwl4965_priv *priv = hw->priv;
-
- IWL_DEBUG_MAC80211("enter: \n");
- if (priv->channel_width != IWL_CHANNEL_WIDTH_40MHZ)
- use_wide_channel = 0;
-
- /* no fat tx allowed on 2.4GHZ */
- if (priv->phymode != MODE_IEEE80211A)
- use_wide_channel = 0;
-
- iwl4965_set_ht_capab(hw, ht_cap, use_wide_channel);
- IWL_DEBUG_MAC80211("leave: \n");
-}
#endif /*CONFIG_IWL4965_HT*/
/*****************************************************************************
.get_tsf = iwl4965_mac_get_tsf,
.reset_tsf = iwl4965_mac_reset_tsf,
.beacon_update = iwl4965_mac_beacon_update,
- .erp_ie_changed = iwl4965_mac_erp_ie_changed,
+ .bss_info_changed = iwl4965_bss_info_changed,
#ifdef CONFIG_IWL4965_HT
.conf_ht = iwl4965_mac_conf_ht,
- .get_ht_capab = iwl4965_mac_get_ht_capab,
+ .ampdu_action = iwl4965_mac_ampdu_action,
#ifdef CONFIG_IWL4965_HT_AGG
.ht_tx_agg_start = iwl4965_mac_ht_tx_agg_start,
.ht_tx_agg_stop = iwl4965_mac_ht_tx_agg_stop,
- .ht_rx_agg_start = iwl4965_mac_ht_rx_agg_start,
- .ht_rx_agg_stop = iwl4965_mac_ht_rx_agg_stop,
#endif /* CONFIG_IWL4965_HT_AGG */
#endif /* CONFIG_IWL4965_HT */
.hw_scan = iwl4965_mac_hw_scan
struct ieee80211_hw *hw;
int i;
+ /* Disabling hardware scan means that mac80211 will perform scans
+ * "the hard way", rather than using device's scan. */
if (iwl4965_param_disable_hw_scan) {
IWL_DEBUG_INFO("Disabling hw_scan\n");
iwl4965_hw_ops.hw_scan = NULL;
/* Tell mac80211 our Tx characteristics */
hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
+ /* Default value; 4 EDCA QOS priorities */
hw->queues = 4;
#ifdef CONFIG_IWL4965_HT
#ifdef CONFIG_IWL4965_HT_AGG
+ /* Enhanced value; more queues, to support 11n aggregation */
hw->queues = 16;
#endif /* CONFIG_IWL4965_HT_AGG */
#endif /* CONFIG_IWL4965_HT */
pci_set_master(pdev);
+ /* Clear the driver's (not device's) station table */
iwl4965_clear_stations_table(priv);
priv->data_retry_limit = -1;
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;
/* Initialize module parameter values here */
+ /* Disable radio (SW RF KILL) via parameter when loading driver */
if (iwl4965_param_disable) {
set_bit(STATUS_RF_KILL_SW, &priv->status);
IWL_DEBUG_INFO("Radio disabled.\n");
priv->ps_mode = 0;
priv->use_ant_b_for_management_frame = 1; /* start with ant B */
- priv->is_ht_enabled = 1;
- priv->channel_width = IWL_CHANNEL_WIDTH_40MHZ;
priv->valid_antenna = 0x7; /* assume all 3 connected */
priv->ps_mode = IWL_MIMO_PS_NONE;
+ /* Choose which receivers/antennas to use */
iwl4965_set_rxon_chain(priv);
printk(KERN_INFO DRV_NAME
/* QoS */
module_param_named(qos_enable, iwl4965_param_qos_enable, int, 0444);
MODULE_PARM_DESC(qos_enable, "enable all QoS functionality");
+module_param_named(amsdu_size_8K, iwl4965_param_amsdu_size_8K, int, 0444);
+MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size");
module_exit(iwl4965_exit);
module_init(iwl4965_init);