wimax: allow specifying debug levels as command line option
[safe/jmp/linux-2.6] / drivers / net / wimax / i2400m / sdio.c
index 74de174..2d2cc5a 100644 (file)
@@ -58,6 +58,7 @@
  */
 
 #include <linux/debugfs.h>
+#include <linux/mmc/sdio_ids.h>
 #include <linux/mmc/sdio.h>
 #include <linux/mmc/sdio_func.h>
 #include "i2400m-sdio.h"
 static int ioe_timeout = 2;
 module_param(ioe_timeout, int, 0);
 
+static char i2400ms_debug_params[128];
+module_param_string(debug, i2400ms_debug_params, sizeof(i2400ms_debug_params),
+                   0644);
+MODULE_PARM_DESC(debug,
+                "String of space-separated NAME:VALUE pairs, where NAMEs "
+                "are the different debug submodules and VALUE are the "
+                "initial debug value to set.");
+
 /* Our firmware file name list */
 static const char *i2400ms_bus_fw_names[] = {
 #define I2400MS_FW_FILE_NAME "i2400m-fw-sdio-1.3.sbcf"
@@ -94,17 +103,23 @@ static const struct i2400m_poke_table i2400ms_pokes[] = {
  * when we ask it to explicitly doing). Tries until a timeout is
  * reached.
  *
+ * The @maxtries argument indicates how many times (at most) it should
+ * be tried to enable the function. 0 means forever. This acts along
+ * with the timeout (ie: it'll stop trying as soon as the maximum
+ * number of tries is reached _or_ as soon as the timeout is reached).
+ *
  * The reverse of this is...sdio_disable_function()
  *
  * Returns: 0 if the SDIO function was enabled, < 0 errno code on
  *     error (-ENODEV when it was unable to enable the function).
  */
 static
-int i2400ms_enable_function(struct sdio_func *func)
+int i2400ms_enable_function(struct sdio_func *func, unsigned maxtries)
 {
        u64 timeout;
        int err;
        struct device *dev = &func->dev;
+       unsigned tries = 0;
 
        d_fnstart(3, dev, "(func %p)\n", func);
        /* Setup timeout (FIXME: This needs to read the CIS table to
@@ -114,6 +129,14 @@ int i2400ms_enable_function(struct sdio_func *func)
        err = -ENODEV;
        while (err != 0 && time_before64(get_jiffies_64(), timeout)) {
                sdio_claim_host(func);
+               /*
+                * There is a sillicon bug on the IWMC3200, where the
+                * IOE timeout will cause problems on Moorestown
+                * platforms (system hang). We explicitly overwrite
+                * func->enable_timeout here to work around the issue.
+                */
+               if (func->device == SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX)
+                       func->enable_timeout = IWMC3200_IOR_TIMEOUT;
                err = sdio_enable_func(func);
                if (0 == err) {
                        sdio_release_host(func);
@@ -121,8 +144,11 @@ int i2400ms_enable_function(struct sdio_func *func)
                        goto function_enabled;
                }
                d_printf(2, dev, "SDIO function failed to enable: %d\n", err);
-               sdio_disable_func(func);
                sdio_release_host(func);
+               if (maxtries > 0 && ++tries >= maxtries) {
+                       err = -ETIME;
+                       break;
+               }
                msleep(I2400MS_INIT_SLEEP_INTERVAL);
        }
        /* If timed out, device is not there yet -- get -ENODEV so
@@ -156,19 +182,14 @@ int i2400ms_bus_dev_start(struct i2400m *i2400m)
 
        d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
        msleep(200);
-       result = i2400ms_rx_setup(i2400ms);
-       if (result < 0)
-               goto error_rx_setup;
        result = i2400ms_tx_setup(i2400ms);
        if (result < 0)
                goto error_tx_setup;
        d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result);
        return result;
 
-       i2400ms_tx_release(i2400ms);
 error_tx_setup:
-       i2400ms_rx_release(i2400ms);
-error_rx_setup:
+       i2400ms_tx_release(i2400ms);
        d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
        return result;
 }
@@ -182,7 +203,6 @@ void i2400ms_bus_dev_stop(struct i2400m *i2400m)
        struct device *dev = &func->dev;
 
        d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
-       i2400ms_rx_release(i2400ms);
        i2400ms_tx_release(i2400ms);
        d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
 }
@@ -238,18 +258,17 @@ error_kzalloc:
  * Warm reset:
  *
  * The device will be fully reset internally, but won't be
- * disconnected from the USB bus (so no reenumeration will
+ * disconnected from the bus (so no reenumeration will
  * happen). Firmware upload will be neccessary.
  *
- * The device will send a reboot barker in the notification endpoint
- * that will trigger the driver to reinitialize the state
- * automatically from notif.c:i2400m_notification_grok() into
- * i2400m_dev_bootstrap_delayed().
+ * The device will send a reboot barker that will trigger the driver
+ * to reinitialize the state via __i2400m_dev_reset_handle.
+ *
  *
- * Cold and bus (USB) reset:
+ * Cold and bus reset:
  *
  * The device will be fully reset internally, disconnected from the
- * USB bus an a reenumeration will happen. Firmware upload will be
+ * bus an a reenumeration will happen. Firmware upload will be
  * neccessary. Thus, we don't do any locking or struct
  * reinitialization, as we are going to be fully disconnected and
  * reenumerated.
@@ -296,6 +315,7 @@ do_bus_reset:
                if (i2400m->wimax_dev.net_dev->reg_state == NETREG_REGISTERED)
                        netif_tx_disable(i2400m->wimax_dev.net_dev);
 
+               i2400ms_rx_release(i2400ms);
                sdio_claim_host(i2400ms->func);
                sdio_disable_func(i2400ms->func);
                sdio_release_host(i2400ms->func);
@@ -303,7 +323,9 @@ do_bus_reset:
                /* Wait for the device to settle */
                msleep(40);
 
-               result = i2400ms_enable_function(i2400ms->func);
+               result = i2400ms_enable_function(i2400ms->func, 0);
+               if (result >= 0)
+                       i2400ms_rx_setup(i2400ms);
        } else
                BUG();
        if (result < 0 && rt != I2400M_RT_BUS) {
@@ -373,6 +395,10 @@ error:
 }
 
 
+static struct device_type i2400ms_type = {
+       .name   = "wimax",
+};
+
 /*
  * Probe a i2400m interface and register it
  *
@@ -414,6 +440,7 @@ int i2400ms_probe(struct sdio_func *func,
                goto error_alloc_netdev;
        }
        SET_NETDEV_DEV(net_dev, dev);
+       SET_NETDEV_DEVTYPE(net_dev, &i2400ms_type);
        i2400m = net_dev_to_i2400m(net_dev);
        i2400ms = container_of(i2400m, struct i2400ms, i2400m);
        i2400m->wimax_dev.net_dev = net_dev;
@@ -428,7 +455,7 @@ int i2400ms_probe(struct sdio_func *func,
        i2400m->bus_reset = i2400ms_bus_reset;
        /* The iwmc3200-wimax sometimes requires the driver to try
         * hard when we paint it into a corner. */
-       i2400m->bus_bm_retries = I3200_BOOT_RETRIES;
+       i2400m->bus_bm_retries = I2400M_SDIO_BOOT_RETRIES;
        i2400m->bus_bm_cmd_send = i2400ms_bus_bm_cmd_send;
        i2400m->bus_bm_wait_for_ack = i2400ms_bus_bm_wait_for_ack;
        i2400m->bus_fw_names = i2400ms_bus_fw_names;
@@ -443,12 +470,28 @@ int i2400ms_probe(struct sdio_func *func,
                goto error_set_blk_size;
        }
 
-       result = i2400ms_enable_function(i2400ms->func);
+       result = i2400ms_enable_function(i2400ms->func, 1);
        if (result < 0) {
                dev_err(dev, "Cannot enable SDIO function: %d\n", result);
                goto error_func_enable;
        }
 
+       /*
+        * Before we are enabling the device interrupt register, make
+        * sure the buffer used during bootmode operation is setup so
+        * when the first D2H data interrupt comes, the memory is
+        * available for copying the D2H data.
+        */
+       result = i2400m_bm_buf_alloc(i2400m);
+       if (result < 0) {
+               dev_err(dev, "cannot allocate SDIO bootmode buffer\n");
+               goto error_bootmode_buf_setup;
+       }
+
+       result = i2400ms_rx_setup(i2400ms);
+       if (result < 0)
+               goto error_rx_setup;
+
        result = i2400m_setup(i2400m, I2400M_BRI_NO_REBOOT);
        if (result < 0) {
                dev_err(dev, "cannot setup device: %d\n", result);
@@ -466,6 +509,10 @@ int i2400ms_probe(struct sdio_func *func,
 error_debugfs_add:
        i2400m_release(i2400m);
 error_setup:
+       i2400ms_rx_release(i2400ms);
+error_rx_setup:
+       i2400m_bm_buf_free(i2400m);
+error_bootmode_buf_setup:
        sdio_claim_host(func);
        sdio_disable_func(func);
        sdio_release_host(func);
@@ -488,6 +535,7 @@ void i2400ms_remove(struct sdio_func *func)
 
        d_fnstart(3, dev, "SDIO func %p\n", func);
        debugfs_remove_recursive(i2400ms->debugfs_dentry);
+       i2400ms_rx_release(i2400ms);
        i2400m_release(i2400m);
        sdio_set_drvdata(func, NULL);
        sdio_claim_host(func);
@@ -497,15 +545,12 @@ void i2400ms_remove(struct sdio_func *func)
        d_fnend(3, dev, "SDIO func %p\n", func);
 }
 
-enum {
-       I2400MS_INTEL_VID = 0x89,
-};
-
 static
 const struct sdio_device_id i2400ms_sdio_ids[] = {
-       /* Intel: i2400m WiMAX over SDIO */
-       { SDIO_DEVICE(I2400MS_INTEL_VID, 0x1402) },
-       { },                    /* end: all zeroes */
+       /* Intel: i2400m WiMAX (iwmc3200) over SDIO */
+       { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL,
+                     SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX) },
+       { /* end: all zeroes */ },
 };
 MODULE_DEVICE_TABLE(sdio, i2400ms_sdio_ids);
 
@@ -522,6 +567,8 @@ struct sdio_driver i2400m_sdio_driver = {
 static
 int __init i2400ms_driver_init(void)
 {
+       d_parse_params(D_LEVEL, D_LEVEL_SIZE, i2400ms_debug_params,
+                      "i2400m_sdio.debug");
        return sdio_register_driver(&i2400m_sdio_driver);
 }
 module_init(i2400ms_driver_init);