]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - drivers/net/wireless/iwlwifi/iwl3945-base.c
iwlwifi: turn off device when not used.
[linux-2.6.git] / drivers / net / wireless / iwlwifi / iwl3945-base.c
index 2238c9f2018cdf345903115d70449cf7bd49c846..adf4ebe6bb78816aba436dc23844d6ce27d83245 100644 (file)
@@ -41,7 +41,6 @@
 #include <linux/if_arp.h>
 
 #include <net/ieee80211_radiotap.h>
-#include <net/lib80211.h>
 #include <net/mac80211.h>
 
 #include <asm/div64.h>
@@ -456,9 +455,6 @@ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv,
                        tx->timeout.pm_frame_timeout = cpu_to_le16(2);
        } else {
                tx->timeout.pm_frame_timeout = 0;
-#ifdef CONFIG_IWLWIFI_LEDS
-               priv->rxtxpackets += le16_to_cpu(cmd->cmd.tx.len);
-#endif
        }
 
        tx->driver_txop = 0;
@@ -1134,6 +1130,7 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority)
        struct iwl_rx_queue *rxq = &priv->rxq;
        struct list_head *element;
        struct iwl_rx_mem_buffer *rxb;
+       struct sk_buff *skb;
        unsigned long flags;
 
        while (1) {
@@ -1143,25 +1140,39 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority)
                        spin_unlock_irqrestore(&rxq->lock, flags);
                        return;
                }
-
-               element = rxq->rx_used.next;
-               rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
-               list_del(element);
                spin_unlock_irqrestore(&rxq->lock, flags);
 
+               if (rxq->free_count > RX_LOW_WATERMARK)
+                       priority |= __GFP_NOWARN;
                /* Alloc a new receive buffer */
-               rxb->skb =
-                   alloc_skb(priv->hw_params.rx_buf_size,
-                               priority);
-               if (!rxb->skb) {
+               skb = alloc_skb(priv->hw_params.rx_buf_size, priority);
+               if (!skb) {
                        if (net_ratelimit())
-                               IWL_CRIT(priv, ": Can not allocate SKB buffers\n");
+                               IWL_DEBUG_INFO(priv, "Failed to allocate SKB buffer.\n");
+                       if ((rxq->free_count <= RX_LOW_WATERMARK) &&
+                           net_ratelimit())
+                               IWL_CRIT(priv, "Failed to allocate SKB buffer with %s. Only %u free buffers remaining.\n",
+                                        priority == GFP_ATOMIC ?  "GFP_ATOMIC" : "GFP_KERNEL",
+                                        rxq->free_count);
                        /* We don't reschedule replenish work here -- we will
                         * call the restock method and if it still needs
                         * more buffers it will schedule replenish */
                        break;
                }
 
+               spin_lock_irqsave(&rxq->lock, flags);
+               if (list_empty(&rxq->rx_used)) {
+                       spin_unlock_irqrestore(&rxq->lock, flags);
+                       dev_kfree_skb_any(skb);
+                       return;
+               }
+               element = rxq->rx_used.next;
+               rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+               list_del(element);
+               spin_unlock_irqrestore(&rxq->lock, flags);
+
+               rxb->skb = skb;
+
                /* If radiotap head is required, reserve some headroom here.
                 * The physical head count is a variable rx_stats->phy_count.
                 * We reserve 4 bytes here. Plus these extra bytes, the
@@ -1390,6 +1401,9 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
                                PCI_DMA_FROMDEVICE);
                pkt = (struct iwl_rx_packet *)rxb->skb->data;
 
+               trace_iwlwifi_dev_rx(priv, pkt,
+                       le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
+
                /* Reclaim a command buffer only if this packet is a response
                 *   to a (driver-originated) command.
                 * If the packet (e.g. Rx frame) originated from uCode,
@@ -1466,6 +1480,7 @@ static inline void iwl_synchronize_irq(struct iwl_priv *priv)
        tasklet_kill(&priv->irq_tasklet);
 }
 
+#ifdef CONFIG_IWLWIFI_DEBUG
 static const char *desc_lookup(int i)
 {
        switch (i) {
@@ -1489,7 +1504,7 @@ static const char *desc_lookup(int i)
 #define ERROR_START_OFFSET  (1 * sizeof(u32))
 #define ERROR_ELEM_SIZE     (7 * sizeof(u32))
 
-static void iwl3945_dump_nic_error_log(struct iwl_priv *priv)
+void iwl3945_dump_nic_error_log(struct iwl_priv *priv)
 {
        u32 i;
        u32 desc, time, count, base, data1;
@@ -1534,8 +1549,9 @@ static void iwl3945_dump_nic_error_log(struct iwl_priv *priv)
                        "%-13s (#%d) %010u 0x%05X 0x%05X 0x%05X 0x%05X %u\n\n",
                        desc_lookup(desc), desc, time, blink1, blink2,
                        ilink1, ilink2, data1);
+               trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, 0,
+                                       0, blink1, blink2, ilink1, ilink2);
        }
-
 }
 
 #define EVENT_START_OFFSET  (6 * sizeof(u32))
@@ -1575,15 +1591,17 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,
                if (mode == 0) {
                        /* data, ev */
                        IWL_ERR(priv, "0x%08x\t%04u\n", time, ev);
+                       trace_iwlwifi_dev_ucode_event(priv, 0, time, ev);
                } else {
                        data = iwl_read_targ_mem(priv, ptr);
                        ptr += sizeof(u32);
                        IWL_ERR(priv, "%010u\t0x%08x\t%04u\n", time, data, ev);
+                       trace_iwlwifi_dev_ucode_event(priv, time, data, ev);
                }
        }
 }
 
-static void iwl3945_dump_nic_event_log(struct iwl_priv *priv)
+void iwl3945_dump_nic_event_log(struct iwl_priv *priv)
 {
        u32 base;       /* SRAM byte address of event log header */
        u32 capacity;   /* event log capacity in # entries */
@@ -1625,6 +1643,16 @@ static void iwl3945_dump_nic_event_log(struct iwl_priv *priv)
        iwl3945_print_event_log(priv, 0, next_entry, mode);
 
 }
+#else
+void iwl3945_dump_nic_event_log(struct iwl_priv *priv)
+{
+}
+
+void iwl3945_dump_nic_error_log(struct iwl_priv *priv)
+{
+}
+
+#endif
 
 static void iwl3945_irq_tasklet(struct iwl_priv *priv)
 {
@@ -2452,7 +2480,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
 
        iwl3945_reg_txpower_periodic(priv);
 
-       iwl3945_led_register(priv);
+       iwl_leds_init(priv);
 
        IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n");
        set_bit(STATUS_READY, &priv->status);
@@ -2490,7 +2518,6 @@ static void __iwl3945_down(struct iwl_priv *priv)
        if (!exit_pending)
                set_bit(STATUS_EXIT_PENDING, &priv->status);
 
-       iwl3945_led_unregister(priv);
        iwl_clear_stations_table(priv);
 
        /* Unblock any waiting calls */
@@ -2549,10 +2576,8 @@ static void __iwl3945_down(struct iwl_priv *priv)
 
        udelay(5);
 
-       if (exit_pending)
-               priv->cfg->ops->lib->apm_ops.stop(priv);
-       else
-               priv->cfg->ops->lib->apm_ops.reset(priv);
+       /* Stop the device, and put it in low power state */
+       priv->cfg->ops->lib->apm_ops.stop(priv);
 
  exit:
        memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp));
@@ -3125,6 +3150,8 @@ static int iwl3945_mac_start(struct ieee80211_hw *hw)
         * no need to poll the killswitch state anymore */
        cancel_delayed_work(&priv->rfkill_poll);
 
+       iwl_led_start(priv);
+
        priv->is_open = 1;
        IWL_DEBUG_MAC80211(priv, "leave\n");
        return 0;
@@ -3668,21 +3695,6 @@ static ssize_t dump_error_log(struct device *d,
 
 static DEVICE_ATTR(dump_errors, S_IWUSR, NULL, dump_error_log);
 
-static ssize_t dump_event_log(struct device *d,
-                             struct device_attribute *attr,
-                             const char *buf, size_t count)
-{
-       struct iwl_priv *priv = dev_get_drvdata(d);
-       char *p = (char *)buf;
-
-       if (p[0] == '1')
-               iwl3945_dump_nic_event_log(priv);
-
-       return strnlen(buf, count);
-}
-
-static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log);
-
 /*****************************************************************************
  *
  * driver setup and tear down
@@ -3727,7 +3739,6 @@ static struct attribute *iwl3945_sysfs_entries[] = {
        &dev_attr_antenna.attr,
        &dev_attr_channels.attr,
        &dev_attr_dump_errors.attr,
-       &dev_attr_dump_events.attr,
        &dev_attr_flags.attr,
        &dev_attr_filter_flags.attr,
 #ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
@@ -4086,8 +4097,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        pci_set_drvdata(pdev, NULL);
        pci_disable_device(pdev);
  out_ieee80211_free_hw:
-       ieee80211_free_hw(priv->hw);
        iwl_free_traffic_mem(priv);
+       ieee80211_free_hw(priv->hw);
  out:
        return err;
 }
@@ -4215,18 +4226,19 @@ static void __exit iwl3945_exit(void)
 
 MODULE_FIRMWARE(IWL3945_MODULE_FIRMWARE(IWL3945_UCODE_API_MAX));
 
-module_param_named(antenna, iwl3945_mod_params.antenna, int, 0444);
+module_param_named(antenna, iwl3945_mod_params.antenna, int, S_IRUGO);
 MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
-module_param_named(swcrypto, iwl3945_mod_params.sw_crypto, int, 0444);
+module_param_named(swcrypto, iwl3945_mod_params.sw_crypto, int, S_IRUGO);
 MODULE_PARM_DESC(swcrypto,
                 "using software crypto (default 1 [software])\n");
 #ifdef CONFIG_IWLWIFI_DEBUG
-module_param_named(debug, iwl_debug_level, uint, 0644);
+module_param_named(debug, iwl_debug_level, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "debug output mask");
 #endif
-module_param_named(disable_hw_scan, iwl3945_mod_params.disable_hw_scan, int, 0444);
+module_param_named(disable_hw_scan, iwl3945_mod_params.disable_hw_scan,
+                  int, S_IRUGO);
 MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
-module_param_named(fw_restart3945, iwl3945_mod_params.restart_fw, int, 0444);
+module_param_named(fw_restart3945, iwl3945_mod_params.restart_fw, int, S_IRUGO);
 MODULE_PARM_DESC(fw_restart3945, "restart firmware in case of error");
 
 module_exit(iwl3945_exit);