headers: remove sched.h from interrupt.h
[safe/jmp/linux-2.6] / drivers / net / wireless / iwlwifi / iwl-agn.c
index 24c1ae6..313d3e5 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/pci.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
+#include <linux/sched.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
 #include <linux/wireless.h>
@@ -533,16 +534,12 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv,
 
        if (palive->ver_subtype == INITIALIZE_SUBTYPE) {
                IWL_DEBUG_INFO(priv, "Initialization Alive received.\n");
-               set_bit(STATUS_INIT_UCODE_ALIVE, &priv->status);
-               wake_up_interruptible(&priv->wait_command_queue);
                memcpy(&priv->card_alive_init,
                       &pkt->u.alive_frame,
                       sizeof(struct iwl_init_alive_resp));
                pwork = &priv->init_alive_start;
        } else {
                IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
-               set_bit(STATUS_RT_UCODE_ALIVE, &priv->status);
-               wake_up_interruptible(&priv->wait_command_queue);
                memcpy(&priv->card_alive, &pkt->u.alive_frame,
                       sizeof(struct iwl_alive_resp));
                pwork = &priv->alive_start;
@@ -1530,6 +1527,191 @@ static int iwl_read_ucode(struct iwl_priv *priv)
        return ret;
 }
 
+#ifdef CONFIG_IWLWIFI_DEBUG
+static const char *desc_lookup_text[] = {
+       "OK",
+       "FAIL",
+       "BAD_PARAM",
+       "BAD_CHECKSUM",
+       "NMI_INTERRUPT_WDG",
+       "SYSASSERT",
+       "FATAL_ERROR",
+       "BAD_COMMAND",
+       "HW_ERROR_TUNE_LOCK",
+       "HW_ERROR_TEMPERATURE",
+       "ILLEGAL_CHAN_FREQ",
+       "VCC_NOT_STABLE",
+       "FH_ERROR",
+       "NMI_INTERRUPT_HOST",
+       "NMI_INTERRUPT_ACTION_PT",
+       "NMI_INTERRUPT_UNKNOWN",
+       "UCODE_VERSION_MISMATCH",
+       "HW_ERROR_ABS_LOCK",
+       "HW_ERROR_CAL_LOCK_FAIL",
+       "NMI_INTERRUPT_INST_ACTION_PT",
+       "NMI_INTERRUPT_DATA_ACTION_PT",
+       "NMI_TRM_HW_ER",
+       "NMI_INTERRUPT_TRM",
+       "NMI_INTERRUPT_BREAK_POINT"
+       "DEBUG_0",
+       "DEBUG_1",
+       "DEBUG_2",
+       "DEBUG_3",
+       "UNKNOWN"
+};
+
+static const char *desc_lookup(int i)
+{
+       int max = ARRAY_SIZE(desc_lookup_text) - 1;
+
+       if (i < 0 || i > max)
+               i = max;
+
+       return desc_lookup_text[i];
+}
+
+#define ERROR_START_OFFSET  (1 * sizeof(u32))
+#define ERROR_ELEM_SIZE     (7 * sizeof(u32))
+
+void iwl_dump_nic_error_log(struct iwl_priv *priv)
+{
+       u32 data2, line;
+       u32 desc, time, count, base, data1;
+       u32 blink1, blink2, ilink1, ilink2;
+
+       if (priv->ucode_type == UCODE_INIT)
+               base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
+       else
+               base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
+
+       if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
+               IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base);
+               return;
+       }
+
+       count = iwl_read_targ_mem(priv, base);
+
+       if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
+               IWL_ERR(priv, "Start IWL Error Log Dump:\n");
+               IWL_ERR(priv, "Status: 0x%08lX, count: %d\n",
+                       priv->status, count);
+       }
+
+       desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32));
+       blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32));
+       blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32));
+       ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32));
+       ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32));
+       data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32));
+       data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32));
+       line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32));
+       time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32));
+
+       IWL_ERR(priv, "Desc                               Time       "
+               "data1      data2      line\n");
+       IWL_ERR(priv, "%-28s (#%02d) %010u 0x%08X 0x%08X %u\n",
+               desc_lookup(desc), desc, time, data1, data2, line);
+       IWL_ERR(priv, "blink1  blink2  ilink1  ilink2\n");
+       IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2,
+               ilink1, ilink2);
+
+}
+
+#define EVENT_START_OFFSET  (4 * sizeof(u32))
+
+/**
+ * iwl_print_event_log - Dump error event log to syslog
+ *
+ */
+static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
+                               u32 num_events, u32 mode)
+{
+       u32 i;
+       u32 base;       /* SRAM byte address of event log header */
+       u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
+       u32 ptr;        /* SRAM byte address of log data */
+       u32 ev, time, data; /* event log data */
+
+       if (num_events == 0)
+               return;
+       if (priv->ucode_type == UCODE_INIT)
+               base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
+       else
+               base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+
+       if (mode == 0)
+               event_size = 2 * sizeof(u32);
+       else
+               event_size = 3 * sizeof(u32);
+
+       ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
+
+       /* "time" is actually "data" for mode 0 (no timestamp).
+       * place event id # at far right for easier visual parsing. */
+       for (i = 0; i < num_events; i++) {
+               ev = iwl_read_targ_mem(priv, ptr);
+               ptr += sizeof(u32);
+               time = iwl_read_targ_mem(priv, ptr);
+               ptr += sizeof(u32);
+               if (mode == 0) {
+                       /* data, ev */
+                       IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev);
+               } else {
+                       data = iwl_read_targ_mem(priv, ptr);
+                       ptr += sizeof(u32);
+                       IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
+                                       time, data, ev);
+               }
+       }
+}
+
+void iwl_dump_nic_event_log(struct iwl_priv *priv)
+{
+       u32 base;       /* SRAM byte address of event log header */
+       u32 capacity;   /* event log capacity in # entries */
+       u32 mode;       /* 0 - no timestamp, 1 - timestamp recorded */
+       u32 num_wraps;  /* # times uCode wrapped to top of log */
+       u32 next_entry; /* index of next entry to be written by uCode */
+       u32 size;       /* # entries that we'll print */
+
+       if (priv->ucode_type == UCODE_INIT)
+               base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
+       else
+               base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+
+       if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
+               IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base);
+               return;
+       }
+
+       /* event log header */
+       capacity = iwl_read_targ_mem(priv, base);
+       mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
+       num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
+       next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
+
+       size = num_wraps ? capacity : next_entry;
+
+       /* bail out if nothing in log */
+       if (size == 0) {
+               IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n");
+               return;
+       }
+
+       IWL_ERR(priv, "Start IWL Event Log Dump: display count %d, wraps %d\n",
+                       size, num_wraps);
+
+       /* if uCode has wrapped back to top of log, start at the oldest entry,
+        * i.e the next one that uCode would fill. */
+       if (num_wraps)
+               iwl_print_event_log(priv, next_entry,
+                                       capacity - next_entry, mode);
+       /* (then/else) start at top of log */
+       iwl_print_event_log(priv, 0, next_entry, mode);
+
+}
+#endif
+
 /**
  * iwl_alive_start - called after REPLY_ALIVE notification received
  *                   from protocol/runtime uCode (initialization uCode's
@@ -1610,7 +1792,7 @@ static void iwl_alive_start(struct iwl_priv *priv)
        set_bit(STATUS_READY, &priv->status);
        wake_up_interruptible(&priv->wait_command_queue);
 
-       iwl_power_update_mode(priv, 1);
+       iwl_power_update_mode(priv, true);
 
        /* reassociate for ADHOC mode */
        if (priv->vif && (priv->iw_mode == NL80211_IFTYPE_ADHOC)) {
@@ -1784,7 +1966,6 @@ static int __iwl_up(struct iwl_priv *priv)
 {
        int i;
        int ret;
-       unsigned long status;
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
                IWL_WARN(priv, "Exit pending; will not bring the NIC up\n");
@@ -1862,51 +2043,6 @@ static int __iwl_up(struct iwl_priv *priv)
                /* start card; "initialize" will load runtime ucode */
                iwl_nic_start(priv);
 
-               /* Just finish download Init or Runtime uCode image to device
-                * now we wait here for uCode send REPLY_ALIVE notification
-                * to indicate uCode is ready.
-                * 1) For Init uCode image, all iwlagn devices should wait here
-                * on STATUS_INIT_UCODE_ALIVE status bit; if timeout before
-                * receive the REPLY_ALIVE notification, go back and try to
-                * download the Init uCode image again.
-                * 2) For Runtime uCode image, all iwlagn devices except 4965
-                * wait here on STATUS_RT_UCODE_ALIVE status bit; if
-                * timeout before receive the REPLY_ALIVE notification, go back
-                * and download the Runtime uCode image again.
-                * 3) For 4965 Runtime uCode, it will not go through this path,
-                * need to wait for STATUS_RT_UCODE_ALIVE status bit in
-                * iwl4965_init_alive_start() function; if timeout, need to
-                * restart and download Init uCode image.
-                */
-               if (priv->ucode_type == UCODE_INIT)
-                       status = STATUS_INIT_UCODE_ALIVE;
-               else
-                       status = STATUS_RT_UCODE_ALIVE;
-               if (test_bit(status, &priv->status)) {
-                       IWL_WARN(priv,
-                               "%s uCode already alive? "
-                               "Waiting for alive anyway\n",
-                               (status == STATUS_INIT_UCODE_ALIVE)
-                               ? "INIT" : "Runtime");
-                       clear_bit(status, &priv->status);
-               }
-               ret = wait_event_interruptible_timeout(
-                               priv->wait_command_queue,
-                               test_bit(status, &priv->status),
-                               UCODE_ALIVE_TIMEOUT);
-               if (!ret) {
-                       if (!test_bit(status, &priv->status)) {
-                               priv->ucode_type =
-                                       (status == STATUS_INIT_UCODE_ALIVE)
-                                       ? UCODE_NONE : UCODE_INIT;
-                               IWL_ERR(priv,
-                                       "%s timeout after %dms\n",
-                                       (status == STATUS_INIT_UCODE_ALIVE)
-                                       ? "INIT" : "Runtime",
-                                       jiffies_to_msecs(UCODE_ALIVE_TIMEOUT));
-                               continue;
-                       }
-               }
                IWL_DEBUG_INFO(priv, DRV_NAME " is coming up\n");
 
                return 0;
@@ -2125,7 +2261,7 @@ void iwl_post_associate(struct iwl_priv *priv)
         * If chain noise has already been run, then we need to enable
         * power management here */
        if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE)
-               iwl_power_update_mode(priv, 0);
+               iwl_power_update_mode(priv, false);
 
        /* Enable Rx differential gain and sensitivity calibrations */
        iwl_chain_noise_reset(priv);
@@ -2205,7 +2341,7 @@ static void iwl_mac_stop(struct ieee80211_hw *hw)
 
        priv->is_open = 0;
 
-       if (iwl_is_ready_rf(priv)) {
+       if (iwl_is_ready_rf(priv) || test_bit(STATUS_SCAN_HW, &priv->status)) {
                /* stop mac, cancel any scan request and clear
                 * RXON_FILTER_ASSOC_MSK BIT
                 */
@@ -2476,9 +2612,12 @@ static ssize_t store_debug_level(struct device *d,
        ret = strict_strtoul(buf, 0, &val);
        if (ret)
                IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf);
-       else
+       else {
                priv->debug_level = val;
-
+               if (iwl_alloc_traffic_mem(priv))
+                       IWL_ERR(priv,
+                               "Not enough memory to generate traffic log\n");
+       }
        return strnlen(buf, count);
 }
 
@@ -2524,10 +2663,15 @@ static ssize_t store_tx_power(struct device *d,
        ret = strict_strtoul(buf, 10, &val);
        if (ret)
                IWL_INFO(priv, "%s is not in decimal form.\n", buf);
-       else
-               iwl_set_tx_power(priv, val, false);
-
-       return count;
+       else {
+               ret = iwl_set_tx_power(priv, val, false);
+               if (ret)
+                       IWL_ERR(priv, "failed setting tx power (0x%d).\n",
+                               ret);
+               else
+                       ret = count;
+       }
+       return ret;
 }
 
 static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power);
@@ -2612,47 +2756,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 store_power_level(struct device *d,
-                                struct device_attribute *attr,
-                                const char *buf, size_t count)
-{
-       struct iwl_priv *priv = dev_get_drvdata(d);
-       int ret;
-       unsigned long mode;
-
-
-       mutex_lock(&priv->mutex);
-
-       ret = strict_strtoul(buf, 10, &mode);
-       if (ret)
-               goto out;
-
-       ret = iwl_power_set_user_mode(priv, mode);
-       if (ret) {
-               IWL_DEBUG_MAC80211(priv, "failed setting power mode.\n");
-               goto out;
-       }
-       ret = count;
-
- out:
-       mutex_unlock(&priv->mutex);
-       return ret;
-}
-
-static ssize_t show_power_level(struct device *d,
-                               struct device_attribute *attr, char *buf)
-{
-       struct iwl_priv *priv = dev_get_drvdata(d);
-       int level = priv->power_data.power_mode;
-       char *p = buf;
-
-       p += sprintf(p, "%d\n", level);
-       return p - buf + 1;
-}
-
-static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
-                  store_power_level);
-
 
 static ssize_t show_statistics(struct device *d,
                               struct device_attribute *attr, char *buf)
@@ -2745,7 +2848,6 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
 static struct attribute *iwl_sysfs_entries[] = {
        &dev_attr_flags.attr,
        &dev_attr_filter_flags.attr,
-       &dev_attr_power_level.attr,
        &dev_attr_statistics.attr,
        &dev_attr_temperature.attr,
        &dev_attr_tx_power.attr,
@@ -2819,6 +2921,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 #ifdef CONFIG_IWLWIFI_DEBUG
        atomic_set(&priv->restrict_refcnt, 0);
 #endif
+       if (iwl_alloc_traffic_mem(priv))
+               IWL_ERR(priv, "Not enough memory to generate traffic log\n");
 
        /**************************
         * 2. Initializing PCI bus
@@ -3003,6 +3107,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        pci_disable_device(pdev);
  out_ieee80211_free_hw:
        ieee80211_free_hw(priv->hw);
+       iwl_free_traffic_mem(priv);
  out:
        return err;
 }
@@ -3061,6 +3166,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
         * until now... */
        destroy_workqueue(priv->workqueue);
        priv->workqueue = NULL;
+       iwl_free_traffic_mem(priv);
 
        free_irq(priv->pci_dev->irq, priv);
        pci_disable_msi(priv->pci_dev);