]> err.no Git - linux-2.6/blobdiff - drivers/net/wireless/iwlwifi/iwl-3945.c
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux...
[linux-2.6] / drivers / net / wireless / iwlwifi / iwl-3945.c
index 63e832cdba7500fddeb2c94d76ff3e8a98ed9ae3..598e4eef4f4080181a3cd089a617ba62ed453356 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -39,6 +39,7 @@
 #include <asm/unaligned.h>
 #include <net/mac80211.h>
 
+#include "iwl-3945-core.h"
 #include "iwl-3945.h"
 #include "iwl-helpers.h"
 #include "iwl-3945-rs.h"
@@ -226,14 +227,126 @@ __le32 iwl3945_get_antenna_flags(const struct iwl3945_priv *priv)
        return 0;               /* "diversity" is default if error */
 }
 
+#ifdef CONFIG_IWL3945_DEBUG
+#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";
+}
+#else
+static inline const char *iwl3945_get_tx_fail_reason(u32 status)
+{
+       return "";
+}
+#endif
+
+
+/**
+ * iwl3945_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 the stack that feeds us.
+ */
+static void 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;
+       struct iwl3945_tx_info *tx_info;
+
+       BUG_ON(txq_id == IWL_CMD_QUEUE_NUM);
+
+       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)) {
+
+               tx_info = &txq->txb[txq->q.read_ptr];
+               ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0],
+                                           &tx_info->status);
+               tx_info->skb[0] = NULL;
+               iwl3945_hw_txq_free_tfd(priv, txq);
+       }
+
+       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);
+}
+
+/**
+ * iwl3945_rx_reply_tx - Handle Tx response
+ */
+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);
+       int rate_idx;
+
+       if ((index >= txq->q.n_bd) || (iwl3945_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->rts_retry_count = tx_resp->failure_rts; */
+       tx_status->flags = ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ?
+                               IEEE80211_TX_STATUS_ACK : 0;
+
+       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);
+
+       rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate);
+       tx_status->control.tx_rate = &priv->ieee_rates[rate_idx];
+       IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
+       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");
+}
+
+
+
 /*****************************************************************************
  *
  * Intel PRO/Wireless 3945ABG/BG Network Connection
  *
  *  RX handler implementations
  *
- *  Used by iwl-base.c
- *
  *****************************************************************************/
 
 void iwl3945_hw_rx_statistics(struct iwl3945_priv *priv, struct iwl3945_rx_mem_buffer *rxb)
@@ -245,6 +358,8 @@ void iwl3945_hw_rx_statistics(struct iwl3945_priv *priv, struct iwl3945_rx_mem_b
 
        memcpy(&priv->statistics, pkt->u.raw, sizeof(priv->statistics));
 
+       iwl3945_led_background(priv);
+
        priv->last_statistics_time = jiffies;
 }
 
@@ -409,7 +524,7 @@ static void iwl3945_add_radiotap(struct iwl3945_priv *priv,
        s8 noise = 0;
        int rate = stats->rate_idx;
        u64 tsf = stats->mactime;
-       __le16 phy_flags_hw = rx_hdr->phy_flags;
+       __le16 phy_flags_hw = rx_hdr->phy_flags, antenna;
 
        struct iwl3945_rt_rx_hdr {
                struct ieee80211_radiotap_header rt_hdr;
@@ -481,8 +596,8 @@ static void iwl3945_add_radiotap(struct iwl3945_priv *priv,
                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;
+       antenna = phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK;
+       iwl3945_rt->rt_antenna = le16_to_cpu(antenna) >> 4;
 
        /* set the preamble flag if we have it */
        if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
@@ -527,6 +642,10 @@ static void iwl3945_handle_data_packet(struct iwl3945_priv *priv, int is_data,
        if (priv->add_radiotap)
                iwl3945_add_radiotap(priv, rxb->skb, rx_hdr, stats);
 
+#ifdef CONFIG_IWL3945_LEDS
+       if (is_data)
+               priv->rxtxpackets += len;
+#endif
        ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
        rxb->skb = NULL;
 }
@@ -550,12 +669,12 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv,
        rx_status.antenna = 0;
        rx_status.flag = 0;
        rx_status.mactime = le64_to_cpu(rx_end->timestamp);
-       rx_status.freq = ieee80211chan2mhz(le16_to_cpu(rx_hdr->channel));
+       rx_status.freq =
+               ieee80211_frequency_to_channel(le16_to_cpu(rx_hdr->channel));
        rx_status.band = (rx_hdr->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
                                IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
 
        rx_status.rate_idx = iwl3945_hwrate_to_plcp_idx(rx_hdr->rate);
-
        if (rx_status.band == IEEE80211_BAND_5GHZ)
                rx_status.rate_idx -= IWL_FIRST_OFDM_RATE;
 
@@ -867,7 +986,7 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv,
        priv->stations[sta_id].current_rate.rate_n_flags = rate;
 
        if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
-           (sta_id != IWL3945_BROADCAST_ID) &&
+           (sta_id != priv->hw_setting.bcast_sta_id) &&
                (sta_id != IWL_MULTICAST_ID))
                priv->stations[IWL_STA_ID].current_rate.rate_n_flags = rate;
 
@@ -1154,19 +1273,19 @@ int iwl3945_hw_nic_init(struct iwl3945_priv *priv)
        if (rev_id & PCI_CFG_REV_ID_BIT_RTP)
                IWL_DEBUG_INFO("RTP type \n");
        else if (rev_id & PCI_CFG_REV_ID_BIT_BASIC_SKU) {
-               IWL_DEBUG_INFO("ALM-MB type\n");
+               IWL_DEBUG_INFO("3945 RADIO-MB type\n");
                iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG,
-                           CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MB);
+                           CSR39_HW_IF_CONFIG_REG_BIT_3945_MB);
        } else {
-               IWL_DEBUG_INFO("ALM-MM type\n");
+               IWL_DEBUG_INFO("3945 RADIO-MM type\n");
                iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG,
-                           CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MM);
+                           CSR39_HW_IF_CONFIG_REG_BIT_3945_MM);
        }
 
        if (EEPROM_SKU_CAP_OP_MODE_MRC == priv->eeprom.sku_cap) {
                IWL_DEBUG_INFO("SKU OP mode is mrc\n");
                iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG,
-                           CSR_HW_IF_CONFIG_REG_BIT_SKU_MRC);
+                           CSR39_HW_IF_CONFIG_REG_BIT_SKU_MRC);
        } else
                IWL_DEBUG_INFO("SKU OP mode is basic\n");
 
@@ -1174,24 +1293,24 @@ int iwl3945_hw_nic_init(struct iwl3945_priv *priv)
                IWL_DEBUG_INFO("3945ABG revision is 0x%X\n",
                               priv->eeprom.board_revision);
                iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG,
-                           CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE);
+                           CSR39_HW_IF_CONFIG_REG_BIT_BOARD_TYPE);
        } else {
                IWL_DEBUG_INFO("3945ABG revision is 0x%X\n",
                               priv->eeprom.board_revision);
                iwl3945_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
-                             CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE);
+                             CSR39_HW_IF_CONFIG_REG_BIT_BOARD_TYPE);
        }
 
        if (priv->eeprom.almgor_m_version <= 1) {
                iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG,
-                           CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A);
+                           CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A);
                IWL_DEBUG_INFO("Card M type A version is 0x%X\n",
                               priv->eeprom.almgor_m_version);
        } else {
                IWL_DEBUG_INFO("Card M type B version is 0x%X\n",
                               priv->eeprom.almgor_m_version);
                iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG,
-                           CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B);
+                           CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B);
        }
        spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -2482,7 +2601,7 @@ unsigned int iwl3945_hw_get_beacon_cmd(struct iwl3945_priv *priv,
        tx_beacon_cmd = (struct iwl3945_tx_beacon_cmd *)&frame->u;
        memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));
 
-       tx_beacon_cmd->tx.sta_id = IWL3945_BROADCAST_ID;
+       tx_beacon_cmd->tx.sta_id = priv->hw_setting.bcast_sta_id;
        tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
 
        frame_size = iwl3945_fill_beacon_frame(priv,
@@ -2509,6 +2628,7 @@ unsigned int iwl3945_hw_get_beacon_cmd(struct iwl3945_priv *priv,
 
 void iwl3945_hw_rx_handler_setup(struct iwl3945_priv *priv)
 {
+       priv->rx_handlers[REPLY_TX] = iwl3945_rx_reply_tx;
        priv->rx_handlers[REPLY_3945_RX] = iwl3945_rx_reply_rx;
 }
 
@@ -2523,9 +2643,25 @@ void iwl3945_hw_cancel_deferred_work(struct iwl3945_priv *priv)
        cancel_delayed_work(&priv->thermal_periodic);
 }
 
+static struct iwl_3945_cfg iwl3945_bg_cfg = {
+       .name = "3945BG",
+       .fw_name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode",
+       .sku = IWL_SKU_G,
+};
+
+static struct iwl_3945_cfg iwl3945_abg_cfg = {
+       .name = "3945ABG",
+       .fw_name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode",
+       .sku = IWL_SKU_A|IWL_SKU_G,
+};
+
 struct pci_device_id iwl3945_hw_card_ids[] = {
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4222)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4227)},
+       {IWL_PCI_DEVICE(0x4222, 0x1005, iwl3945_bg_cfg)},
+       {IWL_PCI_DEVICE(0x4222, 0x1034, iwl3945_bg_cfg)},
+       {IWL_PCI_DEVICE(0x4222, 0x1044, iwl3945_bg_cfg)},
+       {IWL_PCI_DEVICE(0x4227, 0x1014, iwl3945_bg_cfg)},
+       {IWL_PCI_DEVICE(0x4222, PCI_ANY_ID, iwl3945_abg_cfg)},
+       {IWL_PCI_DEVICE(0x4227, PCI_ANY_ID, iwl3945_abg_cfg)},
        {0}
 };