netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 2.6.33/5 00/12] WiMAX pull request
@ 2009-11-04 21:40 Inaky Perez-Gonzalez
  2009-11-04 21:40 ` [PATCH 2.6.33/5 01/12] wimax/i2400m: make i2400m->bus_dev_{stop,start}() optional Inaky Perez-Gonzalez
                   ` (12 more replies)
  0 siblings, 13 replies; 14+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
  To: netdev, wimax

The following changes since commit 4a78fd9a736db4c871bc8b583d66b61c38abd299:
  Inaky Perez-Gonzalez (1):
        wimax/i2400m: fix oops caused by race condition when exiting USB kthreads

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/inaky/wimax.git linux-2.6.33.y

Patches follow for reviewing convenience.

Inaky Perez-Gonzalez (12):
      wimax/i2400m: make i2400m->bus_dev_{stop,start}() optional
      wimax/i2400m: SDIO: fix oops on reset when TXing on uninitialized data
      wimax/i2400m: implement passive mode as a module option
      wimax/i2400m: introduce i2400m_reset(), stopping TX and carrier
      wimax/i2400m: fix device getting stuck in IDLE mode
      wimax/i2400m: Fix USB timeout specifications (to ms from HZ)
      wimax/i2400m: correctly identify all iwmc3200-based SKUs
      wimax/i2400m: don't retry SDIO enable in probe() paths
      wimax/i2400m: handle USB stalls
      wimax/i2400m: fix bad assignment of return value in i2400mu_tx_bulk_out
      wimax/i2400m: fix SDIO debugfs dentry name
      wimax/i2400m: fix inverted value in i2400ms_bus_setup()

 drivers/net/wimax/i2400m/control.c     |   14 +++++-
 drivers/net/wimax/i2400m/debugfs.c     |    2 +-
 drivers/net/wimax/i2400m/driver.c      |   36 +++++++++++---
 drivers/net/wimax/i2400m/fw.c          |    4 +-
 drivers/net/wimax/i2400m/i2400m-sdio.h |   11 ++++
 drivers/net/wimax/i2400m/i2400m.h      |   15 +++---
 drivers/net/wimax/i2400m/netdev.c      |   25 +++++++--
 drivers/net/wimax/i2400m/rx.c          |    4 +-
 drivers/net/wimax/i2400m/sdio.c        |   81 ++++++++++++++------------------
 drivers/net/wimax/i2400m/usb-fw.c      |   25 +++++++++-
 drivers/net/wimax/i2400m/usb-rx.c      |   23 +++++++++-
 drivers/net/wimax/i2400m/usb-tx.c      |   24 +++++++++-
 drivers/net/wimax/i2400m/usb.c         |   61 +++++++++++++++++++++---
 13 files changed, 240 insertions(+), 85 deletions(-)

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 2.6.33/5 01/12] wimax/i2400m: make i2400m->bus_dev_{stop,start}() optional
  2009-11-04 21:40 [PATCH 2.6.33/5 00/12] WiMAX pull request Inaky Perez-Gonzalez
@ 2009-11-04 21:40 ` Inaky Perez-Gonzalez
  2009-11-04 21:40 ` [PATCH 2.6.33/5 02/12] wimax/i2400m: SDIO: fix oops on reset when TXing on uninitialized data Inaky Perez-Gonzalez
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
  To: netdev, wimax

In coming commits, the i2400m SDIO driver will not use
i2400m->bus_dev_stop().

Thus changed to check before calling, as an empty stub has more
overhead than a call to check if the function pointer is non-NULL.

Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/driver.c |   14 +++++++++-----
 drivers/net/wimax/i2400m/i2400m.h |   14 +++++++-------
 2 files changed, 16 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
index cc900b9..cc58a86 100644
--- a/drivers/net/wimax/i2400m/driver.c
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -384,9 +384,11 @@ retry:
 		dev_err(dev, "cannot create workqueue\n");
 		goto error_create_workqueue;
 	}
-	result = i2400m->bus_dev_start(i2400m);
-	if (result < 0)
-		goto error_bus_dev_start;
+	if (i2400m->bus_dev_start) {
+		result = i2400m->bus_dev_start(i2400m);
+		if (result < 0)
+			goto error_bus_dev_start;
+	}
 	i2400m->ready = 1;
 	wmb();		/* see i2400m->ready's documentation  */
 	/* process pending reports from the device */
@@ -413,7 +415,8 @@ error_check_mac_addr:
 	wmb();		/* see i2400m->ready's documentation  */
 	flush_workqueue(i2400m->work_queue);
 error_fw_check:
-	i2400m->bus_dev_stop(i2400m);
+	if (i2400m->bus_dev_stop)
+		i2400m->bus_dev_stop(i2400m);
 error_bus_dev_start:
 	destroy_workqueue(i2400m->work_queue);
 error_create_workqueue:
@@ -480,7 +483,8 @@ void __i2400m_dev_stop(struct i2400m *i2400m)
 	wmb();		/* see i2400m->ready's documentation  */
 	flush_workqueue(i2400m->work_queue);
 
-	i2400m->bus_dev_stop(i2400m);
+	if (i2400m->bus_dev_stop)
+		i2400m->bus_dev_stop(i2400m);
 	destroy_workqueue(i2400m->work_queue);
 	i2400m_rx_release(i2400m);
 	i2400m_tx_release(i2400m);
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h
index 55bca43..5eee985 100644
--- a/drivers/net/wimax/i2400m/i2400m.h
+++ b/drivers/net/wimax/i2400m/i2400m.h
@@ -245,19 +245,19 @@ struct i2400m_barker_db;
  *     all the host resources created to  handle communication with
  *     the device.
  *
- * @bus_dev_start: [fill] Function called by the bus-generic code
- *     [i2400m_dev_start()] to setup the bus-specific communications
- *     to the the device. See LIFE CYCLE above.
+ * @bus_dev_start: [optional fill] Function called by the bus-generic
+ *     code [i2400m_dev_start()] to do things needed to start the
+ *     device. See LIFE CYCLE above.
  *
  *     NOTE: Doesn't need to upload the firmware, as that is taken
  *     care of by the bus-generic code.
  *
- * @bus_dev_stop: [fill] Function called by the bus-generic code
- *     [i2400m_dev_stop()] to shutdown the bus-specific communications
- *     to the the device. See LIFE CYCLE above.
+ * @bus_dev_stop: [optional fill] Function called by the bus-generic
+ *     code [i2400m_dev_stop()] to do things needed for stopping the
+ *     device. See LIFE CYCLE above.
  *
  *     This function does not need to reset the device, just tear down
- *     all the host resources created to  handle communication with
+ *     all the host resources created to handle communication with
  *     the device.
  *
  * @bus_tx_kick: [fill] Function called by the bus-generic code to let
-- 
1.6.2.5


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 2.6.33/5 02/12] wimax/i2400m: SDIO: fix oops on reset when TXing on uninitialized data
  2009-11-04 21:40 [PATCH 2.6.33/5 00/12] WiMAX pull request Inaky Perez-Gonzalez
  2009-11-04 21:40 ` [PATCH 2.6.33/5 01/12] wimax/i2400m: make i2400m->bus_dev_{stop,start}() optional Inaky Perez-Gonzalez
@ 2009-11-04 21:40 ` Inaky Perez-Gonzalez
  2009-11-04 21:40 ` [PATCH 2.6.33/5 03/12] wimax/i2400m: implement passive mode as a module option Inaky Perez-Gonzalez
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
  To: netdev, wimax

Currently the SDIO part of the TX resources were initialized/released
with bus_dev_{start,stop}.

The generic code's TX subsystem is destroyed afterwards, so there is a
window from the bus-TX destruction to the generic-TX destruction where
the generic-TX code might call into bus-TX to do transactions.

The SDIO code cannot really cope with this (whereas in USB, how it is
laid out, it correctly ignores it). In any case, it made no sense for
the SDIO TX code to be in i2400m->bus_dev_start/stop(), so moved to
i2400m->bus_setup/release(), which also takes care of the oops.

Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/sdio.c |   43 ++++++++------------------------------
 1 files changed, 9 insertions(+), 34 deletions(-)

diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c
index 14e66f0..ec17892 100644
--- a/drivers/net/wimax/i2400m/sdio.c
+++ b/drivers/net/wimax/i2400m/sdio.c
@@ -46,15 +46,6 @@
  * i2400ms_bus_reset()            Called by i2400m->bus_reset
  *   __i2400ms_reset()
  *     __i2400ms_send_barker()
- *
- * i2400ms_bus_dev_start()        Called by i2400m_dev_start() [who is
- *   i2400ms_tx_setup()           called by i2400m_setup()]
- *   i2400ms_rx_setup()
- *
- * i2400ms_bus_dev_stop()         Called by i2400m_dev_stop() [who is
- *   i2400ms_rx_release()         is called by i2400m_release()]
- *   i2400ms_tx_release()
- *
  */
 
 #include <linux/debugfs.h>
@@ -191,12 +182,17 @@ int i2400ms_bus_setup(struct i2400m *i2400m)
 		goto error_func_enable;
 	}
 
+	result = i2400ms_tx_setup(i2400ms);
+	if (result < 0)
+		goto error_tx_setup;
 	result = i2400ms_rx_setup(i2400ms);
 	if (result < 0)
 		goto error_rx_setup;
 	return 0;
 
 error_rx_setup:
+	i2400ms_tx_release(i2400ms);
+error_tx_setup:
 	sdio_claim_host(func);
 	sdio_disable_func(func);
 	sdio_release_host(func);
@@ -218,6 +214,7 @@ void i2400ms_bus_release(struct i2400m *i2400m)
 	struct sdio_func *func = i2400ms->func;
 
 	i2400ms_rx_release(i2400ms);
+	i2400ms_tx_release(i2400ms);
 	sdio_claim_host(func);
 	sdio_disable_func(func);
 	sdio_release_host(func);
@@ -235,36 +232,14 @@ void i2400ms_bus_release(struct i2400m *i2400m)
 static
 int i2400ms_bus_dev_start(struct i2400m *i2400m)
 {
-	int result;
 	struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m);
 	struct sdio_func *func = i2400ms->func;
 	struct device *dev = &func->dev;
 
 	d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
 	msleep(200);
-	result = i2400ms_tx_setup(i2400ms);
-	if (result < 0)
-		goto error_tx_setup;
-	d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result);
-	return result;
-
-error_tx_setup:
-	i2400ms_tx_release(i2400ms);
-	d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
-	return result;
-}
-
-
-static
-void i2400ms_bus_dev_stop(struct i2400m *i2400m)
-{
-	struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m);
-	struct sdio_func *func = i2400ms->func;
-	struct device *dev = &func->dev;
-
-	d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
-	i2400ms_tx_release(i2400ms);
-	d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
+	d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, 0);
+	return 0;
 }
 
 
@@ -506,7 +481,7 @@ int i2400ms_probe(struct sdio_func *func,
 	i2400m->bus_pl_size_max = I2400MS_PL_SIZE_MAX;
 	i2400m->bus_setup = i2400ms_bus_setup;
 	i2400m->bus_dev_start = i2400ms_bus_dev_start;
-	i2400m->bus_dev_stop = i2400ms_bus_dev_stop;
+	i2400m->bus_dev_stop = NULL;
 	i2400m->bus_release = i2400ms_bus_release;
 	i2400m->bus_tx_kick = i2400ms_bus_tx_kick;
 	i2400m->bus_reset = i2400ms_bus_reset;
-- 
1.6.2.5


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 2.6.33/5 03/12] wimax/i2400m: implement passive mode as a module option
  2009-11-04 21:40 [PATCH 2.6.33/5 00/12] WiMAX pull request Inaky Perez-Gonzalez
  2009-11-04 21:40 ` [PATCH 2.6.33/5 01/12] wimax/i2400m: make i2400m->bus_dev_{stop,start}() optional Inaky Perez-Gonzalez
  2009-11-04 21:40 ` [PATCH 2.6.33/5 02/12] wimax/i2400m: SDIO: fix oops on reset when TXing on uninitialized data Inaky Perez-Gonzalez
@ 2009-11-04 21:40 ` Inaky Perez-Gonzalez
  2009-11-04 21:40 ` [PATCH 2.6.33/5 04/12] wimax/i2400m: introduce i2400m_reset(), stopping TX and carrier Inaky Perez-Gonzalez
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
  To: netdev, wimax

Some versions of the user space Intel WiMAX daemon need to have full
control over the device initialization sequence. By setting the module
option i2400.passive_mode to 1, the driver defers all device
configuration and initialization to user space.

Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/control.c |   10 ++++++++++
 1 files changed, 10 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c
index 8fe70e7..b69fd88 100644
--- a/drivers/net/wimax/i2400m/control.c
+++ b/drivers/net/wimax/i2400m/control.c
@@ -82,6 +82,13 @@
 #define D_SUBMODULE control
 #include "debug-levels.h"
 
+int i2400m_passive_mode;	/* 0 (passive mode disabled) by default */
+module_param_named(passive_mode, i2400m_passive_mode, int, 0644);
+MODULE_PARM_DESC(passive_mode,
+		 "If true, the driver will not do any device setup "
+		 "and leave it up to user space, who must be properly "
+		 "setup.");
+
 
 /*
  * Return if a TLV is of a give type and size
@@ -1335,6 +1342,8 @@ int i2400m_dev_initialize(struct i2400m *i2400m)
 	unsigned argc = 0;
 
 	d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
+	if (i2400m_passive_mode)
+		goto out_passive;
 	/* Disable idle mode? (enabled by default) */
 	if (i2400m_idle_mode_disabled) {
 		if (i2400m_le_v1_3(i2400m)) {
@@ -1377,6 +1386,7 @@ int i2400m_dev_initialize(struct i2400m *i2400m)
 	result = i2400m_set_init_config(i2400m, args, argc);
 	if (result < 0)
 		goto error;
+out_passive:
 	/*
 	 * Update state: Here it just calls a get state; parsing the
 	 * result (System State TLV and RF Status TLV [done in the rx
-- 
1.6.2.5


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 2.6.33/5 04/12] wimax/i2400m: introduce i2400m_reset(), stopping TX and carrier
  2009-11-04 21:40 [PATCH 2.6.33/5 00/12] WiMAX pull request Inaky Perez-Gonzalez
                   ` (2 preceding siblings ...)
  2009-11-04 21:40 ` [PATCH 2.6.33/5 03/12] wimax/i2400m: implement passive mode as a module option Inaky Perez-Gonzalez
@ 2009-11-04 21:40 ` Inaky Perez-Gonzalez
  2009-11-04 21:40 ` [PATCH 2.6.33/5 05/12] wimax/i2400m: fix device getting stuck in IDLE mode Inaky Perez-Gonzalez
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
  To: netdev, wimax

Currently the i2400m driver was resetting by just calling
i2400m->bus_reset(). However, this was missing stopping the TX queue
and downing the carrier. This was causing, for the corner case of the
driver reseting a device that refuses to go out of idle mode, that a
few packets would be queued and more than one reset would go through,
making the recovery a wee bit messy.

To avoid introducing the same cleanup in all the bus-specific driver,
introduced a i2400m_reset() function that takes care of house cleaning
and then calling the bus-level reset implementation.

The bulk of the changes in all files are just to rename the call from
i2400m->bus_reset() to i2400m_reset().

Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/control.c |    4 ++--
 drivers/net/wimax/i2400m/debugfs.c |    2 +-
 drivers/net/wimax/i2400m/driver.c  |   22 ++++++++++++++++++++--
 drivers/net/wimax/i2400m/fw.c      |    4 ++--
 drivers/net/wimax/i2400m/i2400m.h  |    1 +
 drivers/net/wimax/i2400m/netdev.c  |    8 +++++---
 drivers/net/wimax/i2400m/rx.c      |    4 ++--
 drivers/net/wimax/i2400m/sdio.c    |    9 +--------
 drivers/net/wimax/i2400m/usb.c     |    2 +-
 9 files changed, 35 insertions(+), 21 deletions(-)

diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c
index b69fd88..9449455 100644
--- a/drivers/net/wimax/i2400m/control.c
+++ b/drivers/net/wimax/i2400m/control.c
@@ -54,7 +54,7 @@
  *   i2400m_set_init_config()
  *   i2400m_cmd_get_state()
  * i2400m_dev_shutdown()        Called by i2400m_dev_stop()
- *   i2400m->bus_reset()
+ *   i2400m_reset()
  *
  * i2400m_{cmd,get,set}_*()
  *   i2400m_msg_to_dev()
@@ -343,7 +343,7 @@ void i2400m_report_tlv_system_state(struct i2400m *i2400m,
 		/* Huh? just in case, shut it down */
 		dev_err(dev, "HW BUG? unknown state %u: shutting down\n",
 			i2400m_state);
-		i2400m->bus_reset(i2400m, I2400M_RT_WARM);
+		i2400m_reset(i2400m, I2400M_RT_WARM);
 		break;
 	};
 	d_fnend(3, dev, "(i2400m %p ss %p [%u]) = void\n",
diff --git a/drivers/net/wimax/i2400m/debugfs.c b/drivers/net/wimax/i2400m/debugfs.c
index 9b81af3..b1aec3e 100644
--- a/drivers/net/wimax/i2400m/debugfs.c
+++ b/drivers/net/wimax/i2400m/debugfs.c
@@ -214,7 +214,7 @@ int debugfs_i2400m_reset_set(void *data, u64 val)
 	case I2400M_RT_WARM:
 	case I2400M_RT_COLD:
 	case I2400M_RT_BUS:
-		result = i2400m->bus_reset(i2400m, rt);
+		result = i2400m_reset(i2400m, rt);
 		if (result >= 0)
 			result = 0;
 	default:
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
index cc58a86..96a615f 100644
--- a/drivers/net/wimax/i2400m/driver.c
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -255,7 +255,7 @@ int i2400m_op_reset(struct wimax_dev *wimax_dev)
 	mutex_lock(&i2400m->init_mutex);
 	i2400m->reset_ctx = &ctx;
 	mutex_unlock(&i2400m->init_mutex);
-	result = i2400m->bus_reset(i2400m, I2400M_RT_WARM);
+	result = i2400m_reset(i2400m, I2400M_RT_WARM);
 	if (result < 0)
 		goto out;
 	result = wait_for_completion_timeout(&ctx.completion, 4*HZ);
@@ -710,7 +710,7 @@ out_unlock:
 	mutex_unlock(&i2400m->init_mutex);
 	if (result == -EUCLEAN) {
 		/* ops, need to clean up [w/ init_mutex not held] */
-		result = i2400m->bus_reset(i2400m, I2400M_RT_BUS);
+		result = i2400m_reset(i2400m, I2400M_RT_BUS);
 		if (result >= 0)
 			result = -ENODEV;
 	}
@@ -815,6 +815,24 @@ void i2400m_init(struct i2400m *i2400m)
 EXPORT_SYMBOL_GPL(i2400m_init);
 
 
+int i2400m_reset(struct i2400m *i2400m, enum i2400m_reset_type rt)
+{
+	struct net_device *net_dev = i2400m->wimax_dev.net_dev;
+
+	/*
+	 * Make sure we stop TXs and down the carrier before
+	 * resetting; this is needed to avoid things like
+	 * i2400m_wake_tx() scheduling stuff in parallel.
+	 */
+	if (net_dev->reg_state == NETREG_REGISTERED) {
+		netif_tx_disable(net_dev);
+		netif_carrier_off(net_dev);
+	}
+	return i2400m->bus_reset(i2400m, rt);
+}
+EXPORT_SYMBOL_GPL(i2400m_reset);
+
+
 /**
  * i2400m_setup - bus-generic setup function for the i2400m device
  *
diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c
index fda54bf..64cdfeb 100644
--- a/drivers/net/wimax/i2400m/fw.c
+++ b/drivers/net/wimax/i2400m/fw.c
@@ -130,7 +130,7 @@
  * i2400m_fw_dnload
  *   i2400m_bootrom_init
  *     i2400m_bm_cmd
- *     i2400m->bus_reset
+ *     i2400m_reset
  *   i2400m_dnload_init
  *     i2400m_dnload_init_signed
  *     i2400m_dnload_init_nonsigned
@@ -902,7 +902,7 @@ do_reboot:
 	d_printf(4, dev, "device reboot: reboot command [%d # left]\n",
 		 count);
 	if ((flags & I2400M_BRI_NO_REBOOT) == 0)
-		i2400m->bus_reset(i2400m, I2400M_RT_WARM);
+		i2400m_reset(i2400m, I2400M_RT_WARM);
 	result = i2400m_bm_cmd(i2400m, NULL, 0, &ack, sizeof(ack),
 			       I2400M_BM_CMD_RAW);
 	flags &= ~I2400M_BRI_NO_REBOOT;
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h
index 5eee985..04df9bb 100644
--- a/drivers/net/wimax/i2400m/i2400m.h
+++ b/drivers/net/wimax/i2400m/i2400m.h
@@ -717,6 +717,7 @@ unsigned i2400m_brh_get_signature(const struct i2400m_bootrom_header *hdr)
  * Driver / device setup and internal functions
  */
 extern void i2400m_init(struct i2400m *);
+extern int i2400m_reset(struct i2400m *, enum i2400m_reset_type);
 extern void i2400m_netdev_setup(struct net_device *net_dev);
 extern int i2400m_sysfs_setup(struct device_driver *);
 extern void i2400m_sysfs_release(struct device_driver *);
diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c
index e7d1a51..f67af42 100644
--- a/drivers/net/wimax/i2400m/netdev.c
+++ b/drivers/net/wimax/i2400m/netdev.c
@@ -171,8 +171,9 @@ void i2400m_wake_tx_work(struct work_struct *ws)
 		result = 0;
 	if (result < 0) {
 		dev_err(dev, "WAKE&TX: device didn't get out of idle: "
-			"%d\n", result);
-			goto error;
+			"%d - resetting\n", result);
+		i2400m_reset(i2400m, I2400M_RT_BUS);
+		goto error;
 	}
 	result = wait_event_timeout(i2400m->state_wq,
 				    i2400m->state != I2400M_SS_IDLE, 5 * HZ);
@@ -180,7 +181,8 @@ void i2400m_wake_tx_work(struct work_struct *ws)
 		result = -ETIMEDOUT;
 	if (result < 0) {
 		dev_err(dev, "WAKE&TX: error waiting for device to exit IDLE: "
-			"%d\n", result);
+			"%d - resetting\n", result);
+		i2400m_reset(i2400m, I2400M_RT_BUS);
 		goto error;
 	}
 	msleep(20);	/* device still needs some time or it drops it */
diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c
index 64a44ca..e3d2a9d 100644
--- a/drivers/net/wimax/i2400m/rx.c
+++ b/drivers/net/wimax/i2400m/rx.c
@@ -828,7 +828,7 @@ void i2400m_roq_queue(struct i2400m *i2400m, struct i2400m_roq *roq,
 		dev_err(dev, "SW BUG? queue nsn %d (lbn %u ws %u)\n",
 			nsn, lbn, roq->ws);
 		i2400m_roq_log_dump(i2400m, roq);
-		i2400m->bus_reset(i2400m, I2400M_RT_WARM);
+		i2400m_reset(i2400m, I2400M_RT_WARM);
 	} else {
 		__i2400m_roq_queue(i2400m, roq, skb, lbn, nsn);
 		i2400m_roq_log_add(i2400m, roq, I2400M_RO_TYPE_PACKET,
@@ -894,7 +894,7 @@ void i2400m_roq_queue_update_ws(struct i2400m *i2400m, struct i2400m_roq *roq,
 		dev_err(dev, "SW BUG? queue_update_ws nsn %u (sn %u ws %u)\n",
 			nsn, sn, roq->ws);
 		i2400m_roq_log_dump(i2400m, roq);
-		i2400m->bus_reset(i2400m, I2400M_RT_WARM);
+		i2400m_reset(i2400m, I2400M_RT_WARM);
 	} else {
 		/* if the queue is empty, don't bother as we'd queue
 		 * it and inmediately unqueue it -- just deliver it */
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c
index ec17892..20ab22e 100644
--- a/drivers/net/wimax/i2400m/sdio.c
+++ b/drivers/net/wimax/i2400m/sdio.c
@@ -43,7 +43,7 @@
  *     i2400m_release()
  *     free_netdev(net_dev)
  *
- * i2400ms_bus_reset()            Called by i2400m->bus_reset
+ * i2400ms_bus_reset()            Called by i2400m_reset
  *   __i2400ms_reset()
  *     __i2400ms_send_barker()
  */
@@ -342,13 +342,6 @@ int i2400ms_bus_reset(struct i2400m *i2400m, enum i2400m_reset_type rt)
 					       sizeof(i2400m_COLD_BOOT_BARKER));
 	else if (rt == I2400M_RT_BUS) {
 do_bus_reset:
-		/* call netif_tx_disable() before sending IOE disable,
-		 * so that all the tx from network layer are stopped
-		 * while IOE is being reset. Make sure it is called
-		 * only after register_netdev() was issued.
-		 */
-		if (i2400m->wimax_dev.net_dev->reg_state == NETREG_REGISTERED)
-			netif_tx_disable(i2400m->wimax_dev.net_dev);
 
 		i2400ms_bus_release(i2400m);
 
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c
index 418db12..5e07940 100644
--- a/drivers/net/wimax/i2400m/usb.c
+++ b/drivers/net/wimax/i2400m/usb.c
@@ -58,7 +58,7 @@
  *   i2400mu_rx_release()
  *   i2400mu_tx_release()
  *
- * i2400mu_bus_reset()            Called by i2400m->bus_reset
+ * i2400mu_bus_reset()            Called by i2400m_reset
  *   __i2400mu_reset()
  *     __i2400mu_send_barker()
  *   usb_reset_device()
-- 
1.6.2.5


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 2.6.33/5 05/12] wimax/i2400m: fix device getting stuck in IDLE mode
  2009-11-04 21:40 [PATCH 2.6.33/5 00/12] WiMAX pull request Inaky Perez-Gonzalez
                   ` (3 preceding siblings ...)
  2009-11-04 21:40 ` [PATCH 2.6.33/5 04/12] wimax/i2400m: introduce i2400m_reset(), stopping TX and carrier Inaky Perez-Gonzalez
@ 2009-11-04 21:40 ` Inaky Perez-Gonzalez
  2009-11-04 21:40 ` [PATCH 2.6.33/5 06/12] wimax/i2400m: Fix USB timeout specifications (to ms from HZ) Inaky Perez-Gonzalez
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
  To: netdev, wimax

The i2400m, when conected, will negotiate with the WiMAX basestation
to put the link in IDLE mode when it is not being used. Upon RX/TX
traffic, the link has to be restablished and that might require some
crypto handshakes and maybe a DHCP renew.

This process might take up to 20 (!) seconds and in some cases we were
seeing network watchdog warnings that weren't needed.

So the network watchdog timeout is updated to be slightly above that
20s threshold. As well, the driver itself will double check if the
device is stuck in IDLE mode -- if that happens, the device will be
reset (in this case the queue is also woken up to remove bogus--once
the device is reset--warnings).

Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/netdev.c |   17 ++++++++++++++---
 1 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c
index f67af42..599aa4e 100644
--- a/drivers/net/wimax/i2400m/netdev.c
+++ b/drivers/net/wimax/i2400m/netdev.c
@@ -89,7 +89,10 @@ enum {
 	 * The MTU is 1400 or less
 	 */
 	I2400M_MAX_MTU = 1400,
-	I2400M_TX_TIMEOUT = HZ,
+	/* 20 secs? yep, this is the maximum timeout that the device
+	 * might take to get out of IDLE / negotiate it with the base
+	 * station. We add 1sec for good measure. */
+	I2400M_TX_TIMEOUT = 21 * HZ,
 	I2400M_TX_QLEN = 5,
 };
 
@@ -151,6 +154,7 @@ void i2400m_wake_tx_work(struct work_struct *ws)
 {
 	int result;
 	struct i2400m *i2400m = container_of(ws, struct i2400m, wake_tx_ws);
+	struct net_device *net_dev = i2400m->wimax_dev.net_dev;
 	struct device *dev = i2400m_dev(i2400m);
 	struct sk_buff *skb = i2400m->wake_tx_skb;
 	unsigned long flags;
@@ -166,6 +170,11 @@ void i2400m_wake_tx_work(struct work_struct *ws)
 		dev_err(dev, "WAKE&TX: skb dissapeared!\n");
 		goto out_put;
 	}
+	/* If we have, somehow, lost the connection after this was
+	 * queued, don't do anything; this might be the device got
+	 * reset or just disconnected. */
+	if (unlikely(!netif_carrier_ok(net_dev)))
+		goto out_kfree;
 	result = i2400m_cmd_exit_idle(i2400m);
 	if (result == -EILSEQ)
 		result = 0;
@@ -176,7 +185,8 @@ void i2400m_wake_tx_work(struct work_struct *ws)
 		goto error;
 	}
 	result = wait_event_timeout(i2400m->state_wq,
-				    i2400m->state != I2400M_SS_IDLE, 5 * HZ);
+				    i2400m->state != I2400M_SS_IDLE,
+				    net_dev->watchdog_timeo - HZ/2);
 	if (result == 0)
 		result = -ETIMEDOUT;
 	if (result < 0) {
@@ -187,8 +197,9 @@ void i2400m_wake_tx_work(struct work_struct *ws)
 	}
 	msleep(20);	/* device still needs some time or it drops it */
 	result = i2400m_tx(i2400m, skb->data, skb->len, I2400M_PT_DATA);
-	netif_wake_queue(i2400m->wimax_dev.net_dev);
 error:
+	netif_wake_queue(net_dev);
+out_kfree:
 	kfree_skb(skb);	/* refcount transferred by _hard_start_xmit() */
 out_put:
 	i2400m_put(i2400m);
-- 
1.6.2.5


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 2.6.33/5 06/12] wimax/i2400m: Fix USB timeout specifications (to ms from HZ)
  2009-11-04 21:40 [PATCH 2.6.33/5 00/12] WiMAX pull request Inaky Perez-Gonzalez
                   ` (4 preceding siblings ...)
  2009-11-04 21:40 ` [PATCH 2.6.33/5 05/12] wimax/i2400m: fix device getting stuck in IDLE mode Inaky Perez-Gonzalez
@ 2009-11-04 21:40 ` Inaky Perez-Gonzalez
  2009-11-04 21:40 ` [PATCH 2.6.33/5 07/12] wimax/i2400m: correctly identify all iwmc3200-based SKUs Inaky Perez-Gonzalez
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
  To: netdev, wimax

The USB code was incorrectly specifiying timeouts to be in jiffies vs
msecs. On top of that, lower it to 200ms, as 1s is really too long
(doesn't allow the watchdog to trip a reset if the device timesout too
often).

Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/usb-fw.c |    2 +-
 drivers/net/wimax/i2400m/usb-rx.c |    2 +-
 drivers/net/wimax/i2400m/usb-tx.c |    2 +-
 drivers/net/wimax/i2400m/usb.c    |    2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wimax/i2400m/usb-fw.c b/drivers/net/wimax/i2400m/usb-fw.c
index b59aee0..8ec8b6d 100644
--- a/drivers/net/wimax/i2400m/usb-fw.c
+++ b/drivers/net/wimax/i2400m/usb-fw.c
@@ -102,7 +102,7 @@ ssize_t i2400mu_tx_bulk_out(struct i2400mu *i2400mu, void *buf, size_t buf_size)
 	epd = usb_get_epd(i2400mu->usb_iface, i2400mu->endpoint_cfg.bulk_out);
 	pipe = usb_sndbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress);
 retry:
-	result = usb_bulk_msg(i2400mu->usb_dev, pipe, buf, buf_size, &len, HZ);
+	result = usb_bulk_msg(i2400mu->usb_dev, pipe, buf, buf_size, &len, 200);
 	switch (result) {
 	case 0:
 		if (len != buf_size) {
diff --git a/drivers/net/wimax/i2400m/usb-rx.c b/drivers/net/wimax/i2400m/usb-rx.c
index 245587f..22d127b 100644
--- a/drivers/net/wimax/i2400m/usb-rx.c
+++ b/drivers/net/wimax/i2400m/usb-rx.c
@@ -214,7 +214,7 @@ retry:
 	}
 	result = usb_bulk_msg(
 		i2400mu->usb_dev, usb_pipe, rx_skb->data + rx_skb->len,
-		rx_size, &read_size, HZ);
+		rx_size, &read_size, 200);
 	usb_mark_last_busy(i2400mu->usb_dev);
 	switch (result) {
 	case 0:
diff --git a/drivers/net/wimax/i2400m/usb-tx.c b/drivers/net/wimax/i2400m/usb-tx.c
index a3c46e9..6cdf003 100644
--- a/drivers/net/wimax/i2400m/usb-tx.c
+++ b/drivers/net/wimax/i2400m/usb-tx.c
@@ -105,7 +105,7 @@ int i2400mu_tx(struct i2400mu *i2400mu, struct i2400m_msg_hdr *tx_msg,
 	usb_pipe = usb_sndbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress);
 retry:
 	result = usb_bulk_msg(i2400mu->usb_dev, usb_pipe,
-			      tx_msg, tx_msg_size, &sent_size, HZ);
+			      tx_msg, tx_msg_size, &sent_size, 200);
 	usb_mark_last_busy(i2400mu->usb_dev);
 	switch (result) {
 	case 0:
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c
index 5e07940..34df090 100644
--- a/drivers/net/wimax/i2400m/usb.c
+++ b/drivers/net/wimax/i2400m/usb.c
@@ -173,7 +173,7 @@ int __i2400mu_send_barker(struct i2400mu *i2400mu,
 	pipe = usb_sndbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress);
 	memcpy(buffer, barker, barker_size);
 	ret = usb_bulk_msg(i2400mu->usb_dev, pipe, buffer, barker_size,
-			   &actual_len, HZ);
+			   &actual_len, 200);
 	if (ret < 0) {
 		if (ret != -EINVAL)
 			dev_err(dev, "E: barker error: %d\n", ret);
-- 
1.6.2.5


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 2.6.33/5 07/12] wimax/i2400m: correctly identify all iwmc3200-based SKUs
  2009-11-04 21:40 [PATCH 2.6.33/5 00/12] WiMAX pull request Inaky Perez-Gonzalez
                   ` (5 preceding siblings ...)
  2009-11-04 21:40 ` [PATCH 2.6.33/5 06/12] wimax/i2400m: Fix USB timeout specifications (to ms from HZ) Inaky Perez-Gonzalez
@ 2009-11-04 21:40 ` Inaky Perez-Gonzalez
  2009-11-04 21:40 ` [PATCH 2.6.33/5 08/12] wimax/i2400m: don't retry SDIO enable in probe() paths Inaky Perez-Gonzalez
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
  To: netdev, wimax

Different paths of the i2400m SDIO driver need to take care of a few
SKU-specific quirks. For the ones that are common to to all the
iwmc3200 based devices, introduce i2400ms->iwmc3200 [set in
i2400ms_probe()], so it doesn't have to check against the list of
iwmc3200 SKU IDs on each quirk site.

Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/i2400m-sdio.h |    3 +++
 drivers/net/wimax/i2400m/sdio.c        |   16 +++++++++++++---
 2 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wimax/i2400m/i2400m-sdio.h b/drivers/net/wimax/i2400m/i2400m-sdio.h
index 18218a2..fba482c 100644
--- a/drivers/net/wimax/i2400m/i2400m-sdio.h
+++ b/drivers/net/wimax/i2400m/i2400m-sdio.h
@@ -114,6 +114,9 @@ struct i2400ms {
 	wait_queue_head_t bm_wfa_wq;
 	int bm_wait_result;
 	size_t bm_ack_size;
+
+	/* Device is any of the iwmc3200 SKUs */
+	unsigned iwmc3200:1;
 };
 
 
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c
index 20ab22e..079f900 100644
--- a/drivers/net/wimax/i2400m/sdio.c
+++ b/drivers/net/wimax/i2400m/sdio.c
@@ -105,8 +105,9 @@ static const struct i2400m_poke_table i2400ms_pokes[] = {
  *     error (-ENODEV when it was unable to enable the function).
  */
 static
-int i2400ms_enable_function(struct sdio_func *func, unsigned maxtries)
+int i2400ms_enable_function(struct i2400ms *i2400ms, unsigned maxtries)
 {
+	struct sdio_func *func = i2400ms->func;
 	u64 timeout;
 	int err;
 	struct device *dev = &func->dev;
@@ -126,7 +127,7 @@ int i2400ms_enable_function(struct sdio_func *func, unsigned maxtries)
 		 * platforms (system hang). We explicitly overwrite
 		 * func->enable_timeout here to work around the issue.
 		 */
-		if (func->device == SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX)
+		if (i2400ms->iwmc3200)
 			func->enable_timeout = IWMC3200_IOR_TIMEOUT;
 		err = sdio_enable_func(func);
 		if (0 == err) {
@@ -176,7 +177,7 @@ int i2400ms_bus_setup(struct i2400m *i2400m)
 		goto error_set_blk_size;
 	}
 
-	result = i2400ms_enable_function(func, 1);
+	result = i2400ms_enable_function(i2400ms, 1);
 	if (result < 0) {
 		dev_err(dev, "Cannot enable SDIO function: %d\n", result);
 		goto error_func_enable;
@@ -487,6 +488,15 @@ int i2400ms_probe(struct sdio_func *func,
 	i2400m->bus_bm_mac_addr_impaired = 1;
 	i2400m->bus_bm_pokes_table = &i2400ms_pokes[0];
 
+	switch (func->device) {
+	case SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX:
+	case SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX_2G5:
+		i2400ms->iwmc3200 = 1;
+		break;
+	default:
+		i2400ms->iwmc3200 = 0;
+	}
+
 	result = i2400m_setup(i2400m, I2400M_BRI_NO_REBOOT);
 	if (result < 0) {
 		dev_err(dev, "cannot setup device: %d\n", result);
-- 
1.6.2.5


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 2.6.33/5 08/12] wimax/i2400m: don't retry SDIO enable in probe() paths
  2009-11-04 21:40 [PATCH 2.6.33/5 00/12] WiMAX pull request Inaky Perez-Gonzalez
                   ` (6 preceding siblings ...)
  2009-11-04 21:40 ` [PATCH 2.6.33/5 07/12] wimax/i2400m: correctly identify all iwmc3200-based SKUs Inaky Perez-Gonzalez
@ 2009-11-04 21:40 ` Inaky Perez-Gonzalez
  2009-11-04 21:40 ` [PATCH 2.6.33/5 09/12] wimax/i2400m: handle USB stalls Inaky Perez-Gonzalez
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
  To: netdev, wimax

The iwmc3200 has a quirk where retrying SDIO enable during the probe()
path causes bad interactions with the TOP function controller that
causes a reset storm. The workaround is simply not to retry an SDIO
enable in said path (and still do in the reset / reinitialization
paths).

The driver does so by checking i2400ms->debugfs_dentry to see if it
has been initialized; if not, it is in the probe() path. Document said
fact in i2400ms->debugfs_entry.

Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/i2400m-sdio.h |    8 ++++++++
 drivers/net/wimax/i2400m/sdio.c        |   13 ++++++++++++-
 2 files changed, 20 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wimax/i2400m/i2400m-sdio.h b/drivers/net/wimax/i2400m/i2400m-sdio.h
index fba482c..b9c4bed 100644
--- a/drivers/net/wimax/i2400m/i2400m-sdio.h
+++ b/drivers/net/wimax/i2400m/i2400m-sdio.h
@@ -100,6 +100,14 @@ enum {
  * @tx_workqueue: workqeueue used for data TX; we don't use the
  *     system's workqueue as that might cause deadlocks with code in
  *     the bus-generic driver.
+ *
+ * @debugfs_dentry: dentry for the SDIO specific debugfs files
+ *
+ *     Note this value is set to NULL upon destruction; this is
+ *     because some routinges use it to determine if we are inside the
+ *     probe() path or some other path. When debugfs is disabled,
+ *     creation sets the dentry to '(void*) -ENODEV', which is valid
+ *     for the test.
  */
 struct i2400ms {
 	struct i2400m i2400m;		/* FIRST! See doc */
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c
index 079f900..e8ad85c 100644
--- a/drivers/net/wimax/i2400m/sdio.c
+++ b/drivers/net/wimax/i2400m/sdio.c
@@ -159,6 +159,10 @@ function_enabled:
 /*
  * Setup minimal device communication infrastructure needed to at
  * least be able to update the firmware.
+ *
+ * Note the ugly trick: if we are in the probe path
+ * (i2400ms->debugfs_dentry == NULL), we only retry function
+ * enablement one, to avoid racing with the iwmc3200 top controller.
  */
 static
 int i2400ms_bus_setup(struct i2400m *i2400m)
@@ -168,6 +172,7 @@ int i2400ms_bus_setup(struct i2400m *i2400m)
 		container_of(i2400m, struct i2400ms, i2400m);
 	struct device *dev = i2400m_dev(i2400m);
 	struct sdio_func *func = i2400ms->func;
+	int retries;
 
 	sdio_claim_host(func);
 	result = sdio_set_block_size(func, I2400MS_BLK_SIZE);
@@ -177,7 +182,11 @@ int i2400ms_bus_setup(struct i2400m *i2400m)
 		goto error_set_blk_size;
 	}
 
-	result = i2400ms_enable_function(i2400ms, 1);
+	if (i2400ms->iwmc3200 && i2400ms->debugfs_dentry == NULL)
+		retries = 0;
+	else
+		retries = 1;
+	result = i2400ms_enable_function(i2400ms, retries);
 	if (result < 0) {
 		dev_err(dev, "Cannot enable SDIO function: %d\n", result);
 		goto error_func_enable;
@@ -415,6 +424,7 @@ int i2400ms_debugfs_add(struct i2400ms *i2400ms)
 
 error:
 	debugfs_remove_recursive(i2400ms->debugfs_dentry);
+	i2400ms->debugfs_dentry = NULL;
 	return result;
 }
 
@@ -531,6 +541,7 @@ void i2400ms_remove(struct sdio_func *func)
 
 	d_fnstart(3, dev, "SDIO func %p\n", func);
 	debugfs_remove_recursive(i2400ms->debugfs_dentry);
+	i2400ms->debugfs_dentry = NULL;
 	i2400m_release(i2400m);
 	sdio_set_drvdata(func, NULL);
 	free_netdev(net_dev);
-- 
1.6.2.5


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 2.6.33/5 09/12] wimax/i2400m: handle USB stalls
  2009-11-04 21:40 [PATCH 2.6.33/5 00/12] WiMAX pull request Inaky Perez-Gonzalez
                   ` (7 preceding siblings ...)
  2009-11-04 21:40 ` [PATCH 2.6.33/5 08/12] wimax/i2400m: don't retry SDIO enable in probe() paths Inaky Perez-Gonzalez
@ 2009-11-04 21:40 ` Inaky Perez-Gonzalez
  2009-11-04 21:40 ` [PATCH 2.6.33/5 10/12] wimax/i2400m: fix bad assignment of return value in i2400mu_tx_bulk_out Inaky Perez-Gonzalez
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
  To: netdev, wimax

When the device stalls, clear it and retry; if it keeps failing too
often, reset the device.

This specially happens when running on virtual machines; the real
hardware doesn't seem to trip on stalls too much, except for a few
reports in the mailing list (still to be confirmed this is the cause,
although it seems likely.

NOTE: it is not clear if the URB has to be resubmitted fully or start
only at the offset of the first transaction sent. Can't find
documentation to clarify one end or the other.

Tests that just resubmit the whole URB seemed to work in my
environment.

Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/usb-fw.c |   22 ++++++++++++++
 drivers/net/wimax/i2400m/usb-rx.c |   21 +++++++++++++
 drivers/net/wimax/i2400m/usb-tx.c |   22 ++++++++++++++
 drivers/net/wimax/i2400m/usb.c    |   57 +++++++++++++++++++++++++++++++++----
 4 files changed, 116 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wimax/i2400m/usb-fw.c b/drivers/net/wimax/i2400m/usb-fw.c
index 8ec8b6d..d8f6ce2 100644
--- a/drivers/net/wimax/i2400m/usb-fw.c
+++ b/drivers/net/wimax/i2400m/usb-fw.c
@@ -113,6 +113,28 @@ retry:
 		}
 		result = len;
 		break;
+	case -EPIPE:
+		/*
+		 * Stall -- maybe the device is choking with our
+		 * requests. Clear it and give it some time. If they
+		 * happen to often, it might be another symptom, so we
+		 * reset.
+		 *
+		 * No error handling for usb_clear_halt(0; if it
+		 * works, the retry works; if it fails, this switch
+		 * does the error handling for us.
+		 */
+		if (edc_inc(&i2400mu->urb_edc,
+			    10 * EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) {
+			dev_err(dev, "BM-CMD: too many stalls in "
+				"URB; resetting device\n");
+			usb_queue_reset_device(i2400mu->usb_iface);
+			/* fallthrough */
+		} else {
+			usb_clear_halt(i2400mu->usb_dev, pipe);
+			msleep(10);	/* give the device some time */
+			goto retry;
+		}
 	case -EINVAL:			/* while removing driver */
 	case -ENODEV:			/* dev disconnect ... */
 	case -ENOENT:			/* just ignore it */
diff --git a/drivers/net/wimax/i2400m/usb-rx.c b/drivers/net/wimax/i2400m/usb-rx.c
index 22d127b..ba1b023 100644
--- a/drivers/net/wimax/i2400m/usb-rx.c
+++ b/drivers/net/wimax/i2400m/usb-rx.c
@@ -222,6 +222,26 @@ retry:
 			goto retry;	/* ZLP, just resubmit */
 		skb_put(rx_skb, read_size);
 		break;
+	case -EPIPE:
+		/*
+		 * Stall -- maybe the device is choking with our
+		 * requests. Clear it and give it some time. If they
+		 * happen to often, it might be another symptom, so we
+		 * reset.
+		 *
+		 * No error handling for usb_clear_halt(0; if it
+		 * works, the retry works; if it fails, this switch
+		 * does the error handling for us.
+		 */
+		if (edc_inc(&i2400mu->urb_edc,
+			    10 * EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) {
+			dev_err(dev, "BM-CMD: too many stalls in "
+				"URB; resetting device\n");
+			goto do_reset;
+		}
+		usb_clear_halt(i2400mu->usb_dev, usb_pipe);
+		msleep(10);	/* give the device some time */
+		goto retry;
 	case -EINVAL:			/* while removing driver */
 	case -ENODEV:			/* dev disconnect ... */
 	case -ENOENT:			/* just ignore it */
@@ -283,6 +303,7 @@ out:
 error_reset:
 	dev_err(dev, "RX: maximum errors in URB exceeded; "
 		"resetting device\n");
+do_reset:
 	usb_queue_reset_device(i2400mu->usb_iface);
 	rx_skb = ERR_PTR(result);
 	goto out;
diff --git a/drivers/net/wimax/i2400m/usb-tx.c b/drivers/net/wimax/i2400m/usb-tx.c
index 6cdf003..c65b997 100644
--- a/drivers/net/wimax/i2400m/usb-tx.c
+++ b/drivers/net/wimax/i2400m/usb-tx.c
@@ -115,6 +115,28 @@ retry:
 			result = -EIO;
 		}
 		break;
+	case -EPIPE:
+		/*
+		 * Stall -- maybe the device is choking with our
+		 * requests. Clear it and give it some time. If they
+		 * happen to often, it might be another symptom, so we
+		 * reset.
+		 *
+		 * No error handling for usb_clear_halt(0; if it
+		 * works, the retry works; if it fails, this switch
+		 * does the error handling for us.
+		 */
+		if (edc_inc(&i2400mu->urb_edc,
+			    10 * EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) {
+			dev_err(dev, "BM-CMD: too many stalls in "
+				"URB; resetting device\n");
+			usb_queue_reset_device(i2400mu->usb_iface);
+			/* fallthrough */
+		} else {
+			usb_clear_halt(i2400mu->usb_dev, usb_pipe);
+			msleep(10);	/* give the device some time */
+			goto retry;
+		}
 	case -EINVAL:			/* while removing driver */
 	case -ENODEV:			/* dev disconnect ... */
 	case -ENOENT:			/* just ignore it */
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c
index 34df090..47e84ef 100644
--- a/drivers/net/wimax/i2400m/usb.c
+++ b/drivers/net/wimax/i2400m/usb.c
@@ -172,14 +172,59 @@ int __i2400mu_send_barker(struct i2400mu *i2400mu,
 	epd = usb_get_epd(i2400mu->usb_iface, endpoint);
 	pipe = usb_sndbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress);
 	memcpy(buffer, barker, barker_size);
+retry:
 	ret = usb_bulk_msg(i2400mu->usb_dev, pipe, buffer, barker_size,
 			   &actual_len, 200);
-	if (ret < 0) {
-		if (ret != -EINVAL)
-			dev_err(dev, "E: barker error: %d\n", ret);
-	} else if (actual_len != barker_size) {
-		dev_err(dev, "E: only %d bytes transmitted\n", actual_len);
-		ret = -EIO;
+	switch (ret) {
+	case 0:
+		if (actual_len != barker_size) {	/* Too short? drop it */
+			dev_err(dev, "E: %s: short write (%d B vs %zu "
+				"expected)\n",
+				__func__, actual_len, barker_size);
+			ret = -EIO;
+		}
+		break;
+	case -EPIPE:
+		/*
+		 * Stall -- maybe the device is choking with our
+		 * requests. Clear it and give it some time. If they
+		 * happen to often, it might be another symptom, so we
+		 * reset.
+		 *
+		 * No error handling for usb_clear_halt(0; if it
+		 * works, the retry works; if it fails, this switch
+		 * does the error handling for us.
+		 */
+		if (edc_inc(&i2400mu->urb_edc,
+			    10 * EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) {
+			dev_err(dev, "E: %s: too many stalls in "
+				"URB; resetting device\n", __func__);
+			usb_queue_reset_device(i2400mu->usb_iface);
+			/* fallthrough */
+		} else {
+			usb_clear_halt(i2400mu->usb_dev, pipe);
+			msleep(10);	/* give the device some time */
+			goto retry;
+		}
+	case -EINVAL:			/* while removing driver */
+	case -ENODEV:			/* dev disconnect ... */
+	case -ENOENT:			/* just ignore it */
+	case -ESHUTDOWN:		/* and exit */
+	case -ECONNRESET:
+		ret = -ESHUTDOWN;
+		break;
+	default:			/* Some error? */
+		if (edc_inc(&i2400mu->urb_edc,
+			    EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) {
+			dev_err(dev, "E: %s: maximum errors in URB "
+				"exceeded; resetting device\n",
+				__func__);
+			usb_queue_reset_device(i2400mu->usb_iface);
+		} else {
+			dev_warn(dev, "W: %s: cannot send URB: %d\n",
+				 __func__, ret);
+			goto retry;
+		}
 	}
 	kfree(buffer);
 error_kzalloc:
-- 
1.6.2.5


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 2.6.33/5 10/12] wimax/i2400m: fix bad assignment of return value in i2400mu_tx_bulk_out
  2009-11-04 21:40 [PATCH 2.6.33/5 00/12] WiMAX pull request Inaky Perez-Gonzalez
                   ` (8 preceding siblings ...)
  2009-11-04 21:40 ` [PATCH 2.6.33/5 09/12] wimax/i2400m: handle USB stalls Inaky Perez-Gonzalez
@ 2009-11-04 21:40 ` Inaky Perez-Gonzalez
  2009-11-04 21:40 ` [PATCH 2.6.33/5 11/12] wimax/i2400m: fix SDIO debugfs dentry name Inaky Perez-Gonzalez
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
  To: netdev, wimax

The function was always setting the return value to the amount of
bytes transferred, overwriting the error code in error paths.

Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/usb-fw.c |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wimax/i2400m/usb-fw.c b/drivers/net/wimax/i2400m/usb-fw.c
index d8f6ce2..ce6b993 100644
--- a/drivers/net/wimax/i2400m/usb-fw.c
+++ b/drivers/net/wimax/i2400m/usb-fw.c
@@ -157,7 +157,6 @@ retry:
 			result);
 		goto retry;
 	}
-	result = len;
 	if (do_autopm)
 		usb_autopm_put_interface(i2400mu->usb_iface);
 	return result;
-- 
1.6.2.5


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 2.6.33/5 11/12] wimax/i2400m: fix SDIO debugfs dentry name
  2009-11-04 21:40 [PATCH 2.6.33/5 00/12] WiMAX pull request Inaky Perez-Gonzalez
                   ` (9 preceding siblings ...)
  2009-11-04 21:40 ` [PATCH 2.6.33/5 10/12] wimax/i2400m: fix bad assignment of return value in i2400mu_tx_bulk_out Inaky Perez-Gonzalez
@ 2009-11-04 21:40 ` Inaky Perez-Gonzalez
  2009-11-04 21:40 ` [PATCH 2.6.33/5 12/12] wimax/i2400m: fix inverted value in i2400ms_bus_setup() Inaky Perez-Gonzalez
  2009-11-05  4:37 ` [PATCH 2.6.33/5 00/12] WiMAX pull request Inaky Perez-Gonzalez
  12 siblings, 0 replies; 14+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
  To: netdev, wimax

The SDIO specific debugfs dentry was being misnamed "i2400m-usb"
instead of "i2400m-sdio".

Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/sdio.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c
index e8ad85c..b06d526 100644
--- a/drivers/net/wimax/i2400m/sdio.c
+++ b/drivers/net/wimax/i2400m/sdio.c
@@ -407,7 +407,7 @@ int i2400ms_debugfs_add(struct i2400ms *i2400ms)
 	int result;
 	struct dentry *dentry = i2400ms->i2400m.wimax_dev.debugfs_dentry;
 
-	dentry = debugfs_create_dir("i2400m-usb", dentry);
+	dentry = debugfs_create_dir("i2400m-sdio", dentry);
 	result = PTR_ERR(dentry);
 	if (IS_ERR(dentry)) {
 		if (result == -ENODEV)
-- 
1.6.2.5


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 2.6.33/5 12/12] wimax/i2400m: fix inverted value in i2400ms_bus_setup()
  2009-11-04 21:40 [PATCH 2.6.33/5 00/12] WiMAX pull request Inaky Perez-Gonzalez
                   ` (10 preceding siblings ...)
  2009-11-04 21:40 ` [PATCH 2.6.33/5 11/12] wimax/i2400m: fix SDIO debugfs dentry name Inaky Perez-Gonzalez
@ 2009-11-04 21:40 ` Inaky Perez-Gonzalez
  2009-11-05  4:37 ` [PATCH 2.6.33/5 00/12] WiMAX pull request Inaky Perez-Gonzalez
  12 siblings, 0 replies; 14+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
  To: netdev, wimax

Fix inverted setting of 'retries'; when we are in the probe() path, we
should retry to enable the function only once; otherwise until it
times out.

Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/sdio.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c
index b06d526..76a50ac 100644
--- a/drivers/net/wimax/i2400m/sdio.c
+++ b/drivers/net/wimax/i2400m/sdio.c
@@ -183,9 +183,9 @@ int i2400ms_bus_setup(struct i2400m *i2400m)
 	}
 
 	if (i2400ms->iwmc3200 && i2400ms->debugfs_dentry == NULL)
-		retries = 0;
-	else
 		retries = 1;
+	else
+		retries = 0;
 	result = i2400ms_enable_function(i2400ms, retries);
 	if (result < 0) {
 		dev_err(dev, "Cannot enable SDIO function: %d\n", result);
-- 
1.6.2.5


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH 2.6.33/5 00/12] WiMAX pull request
  2009-11-04 21:40 [PATCH 2.6.33/5 00/12] WiMAX pull request Inaky Perez-Gonzalez
                   ` (11 preceding siblings ...)
  2009-11-04 21:40 ` [PATCH 2.6.33/5 12/12] wimax/i2400m: fix inverted value in i2400ms_bus_setup() Inaky Perez-Gonzalez
@ 2009-11-05  4:37 ` Inaky Perez-Gonzalez
  12 siblings, 0 replies; 14+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-11-05  4:37 UTC (permalink / raw)
  To: netdev; +Cc: wimax

On Wed, 2009-11-04 at 13:40 -0800, Inaky Perez-Gonzalez wrote:
> The following changes since commit 4a78fd9a736db4c871bc8b583d66b61c38abd299:
>   Inaky Perez-Gonzalez (1):
>         wimax/i2400m: fix oops caused by race condition when exiting USB kthreads

Hmm, this is supposed to be batch #5 of the patch series, but somehow my
scripts to break'em up took a life of their own and overwrote the
subject. Sorry for that!



^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2009-11-05  4:39 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-11-04 21:40 [PATCH 2.6.33/5 00/12] WiMAX pull request Inaky Perez-Gonzalez
2009-11-04 21:40 ` [PATCH 2.6.33/5 01/12] wimax/i2400m: make i2400m->bus_dev_{stop,start}() optional Inaky Perez-Gonzalez
2009-11-04 21:40 ` [PATCH 2.6.33/5 02/12] wimax/i2400m: SDIO: fix oops on reset when TXing on uninitialized data Inaky Perez-Gonzalez
2009-11-04 21:40 ` [PATCH 2.6.33/5 03/12] wimax/i2400m: implement passive mode as a module option Inaky Perez-Gonzalez
2009-11-04 21:40 ` [PATCH 2.6.33/5 04/12] wimax/i2400m: introduce i2400m_reset(), stopping TX and carrier Inaky Perez-Gonzalez
2009-11-04 21:40 ` [PATCH 2.6.33/5 05/12] wimax/i2400m: fix device getting stuck in IDLE mode Inaky Perez-Gonzalez
2009-11-04 21:40 ` [PATCH 2.6.33/5 06/12] wimax/i2400m: Fix USB timeout specifications (to ms from HZ) Inaky Perez-Gonzalez
2009-11-04 21:40 ` [PATCH 2.6.33/5 07/12] wimax/i2400m: correctly identify all iwmc3200-based SKUs Inaky Perez-Gonzalez
2009-11-04 21:40 ` [PATCH 2.6.33/5 08/12] wimax/i2400m: don't retry SDIO enable in probe() paths Inaky Perez-Gonzalez
2009-11-04 21:40 ` [PATCH 2.6.33/5 09/12] wimax/i2400m: handle USB stalls Inaky Perez-Gonzalez
2009-11-04 21:40 ` [PATCH 2.6.33/5 10/12] wimax/i2400m: fix bad assignment of return value in i2400mu_tx_bulk_out Inaky Perez-Gonzalez
2009-11-04 21:40 ` [PATCH 2.6.33/5 11/12] wimax/i2400m: fix SDIO debugfs dentry name Inaky Perez-Gonzalez
2009-11-04 21:40 ` [PATCH 2.6.33/5 12/12] wimax/i2400m: fix inverted value in i2400ms_bus_setup() Inaky Perez-Gonzalez
2009-11-05  4:37 ` [PATCH 2.6.33/5 00/12] WiMAX pull request Inaky Perez-Gonzalez

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).