* [2.6.31 00/21] WiMAX pull request
@ 2009-06-11 21:35 Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 01/21] wimax/i2400m: introduce module parameter to disable entering power save Inaky Perez-Gonzalez
` (21 more replies)
0 siblings, 22 replies; 23+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-06-11 21:35 UTC (permalink / raw)
To: netdev, wimax
This pull requests contains a long set of fixes to bugs and issues
found while debugging the SDIO version of the i2400m WiMAX
device. Most of them are in the generic part of the i2400m, and thus,
apply to both the USB and SDIO versions:
- tweaks and fixes to the firmware loader to ensure it can recover
the device from corner cases we can get it into and that it can
support more different varities of hardware
- SDIO driver improvements: support bus-level reset, make RX fully
IRQ driven (even in firmware load mode)
- misc validation/debug assists
- fix panics caused by some corner cases in the TX code
- miscellaneous small cleanups in code and documentation
- compiler warnings in the sh4 architecture
The following changes since commit 0ed586d075ef65c0268982e5b7f36d0ffaa95547:
Roel Kluin (1):
atl1c: WAKE_MCAST tested twice, not WAKE_UCAST
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/inaky/wimax.git linux-2.6.31.y
Patches follow for reviewing convenience.
Cindy H Kao (2):
wimax/i2400m: when bootstrap fails, reinitialize the bootrom
wimax/i2400m: use -EL3RST to indicate device reset instead of -ERESTARTSYS
Dirk Brandewie (4):
wimax/i2400m: Change d_printf() level for secure boot messages
wimax/i2400m/sdio: Implement I2400M_RT_BUS reset type
wimax/i2400m: move boot time poke table out of common driver
wimax/i2400m/sdio: Add device specific poke table.
Inaky Perez-Gonzalez (15):
wimax/i2400m: introduce module parameter to disable entering power save
wimax/i2400m: don't call netif_start_queue() in _tx_msg_sent()
wimax/i2400m: i2400m's work queue should be initialized before RX support
wimax/i2400m: i2400m_schedule_work() doesn't need i2400m->work_queue
wimax/i2400m: rename misleading I2400M_PL_PAD to I2400M_PL_ALIGN
wimax/i2400m: fix panic/warnings caused by missed check on empty TX message
wimax/i2400m: fix panic due to missed corner cases on tail_room calculation
wimax/i2400m: don't reset device on i2400m_dev_shutdown()
wimax/i2400m: fix oops when the TX FIFO fills up due to a missing check
wimax/i2400m: if a device reboot happens during probe, handle it
wimax/i2400m: Allow bus-specific driver to specify retry count
wimax/i2400m: don't reset device when bootrom init retries are exceeded
wimax/i2400m/sdio: Move all the RX code to a unified, IRQ based receive routine
wimax: fix warning caused by not checking retval of rfkill_set_hw_state()
wimax: fix gcc warnings in sh4 when calling BUG()
drivers/net/wimax/i2400m/control.c | 24 +++++---
drivers/net/wimax/i2400m/driver.c | 40 ++++++++----
drivers/net/wimax/i2400m/fw.c | 58 ++++++-----------
drivers/net/wimax/i2400m/i2400m-sdio.h | 9 +++
drivers/net/wimax/i2400m/i2400m.h | 43 +++++++++++++
drivers/net/wimax/i2400m/op-rfkill.c | 4 +-
drivers/net/wimax/i2400m/rx.c | 4 +-
drivers/net/wimax/i2400m/sdio-fw.c | 109 ++++++++++++++------------------
drivers/net/wimax/i2400m/sdio-rx.c | 47 +++++++++++---
drivers/net/wimax/i2400m/sdio.c | 50 ++++++++++++---
drivers/net/wimax/i2400m/tx.c | 75 ++++++++++++++++++++--
drivers/net/wimax/i2400m/usb.c | 5 +-
include/linux/wimax/i2400m.h | 2 +-
net/wimax/op-rfkill.c | 3 +-
14 files changed, 320 insertions(+), 153 deletions(-)
^ permalink raw reply [flat|nested] 23+ messages in thread
* [2.6.31 01/21] wimax/i2400m: introduce module parameter to disable entering power save
2009-06-11 21:35 [2.6.31 00/21] WiMAX pull request Inaky Perez-Gonzalez
@ 2009-06-11 21:35 ` Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 02/21] wimax/i2400m: don't call netif_start_queue() in _tx_msg_sent() Inaky Perez-Gonzalez
` (20 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-06-11 21:35 UTC (permalink / raw)
To: netdev, wimax
The i2400m driver waits for the device to report being ready for
entering power save before asking it to do so. This module parameter
allows control of said operation; if disabled, the driver won't ask
the device to enter power save mode.
This is useful in setups where power saving is not so important or
when the overhead imposed by network reentry after power save is not
acceptable; by combining this with parameter 'idle_mode_disabled', the
driver will always maintain both the connection and the device in
active state.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/control.c | 11 +++++++++--
drivers/net/wimax/i2400m/driver.c | 8 ++++++++
drivers/net/wimax/i2400m/i2400m.h | 1 +
3 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c
index bd193ae..89cdfe4 100644
--- a/drivers/net/wimax/i2400m/control.c
+++ b/drivers/net/wimax/i2400m/control.c
@@ -505,8 +505,15 @@ void i2400m_report_hook(struct i2400m *i2400m,
* it. */
case I2400M_MT_REPORT_POWERSAVE_READY: /* zzzzz */
if (l3l4_hdr->status == cpu_to_le16(I2400M_MS_DONE_OK)) {
- d_printf(1, dev, "ready for powersave, requesting\n");
- i2400m_cmd_enter_powersave(i2400m);
+ if (i2400m_power_save_disabled)
+ d_printf(1, dev, "ready for powersave, "
+ "not requesting (disabled by module "
+ "parameter)\n");
+ else {
+ d_printf(1, dev, "ready for powersave, "
+ "requesting\n");
+ i2400m_cmd_enter_powersave(i2400m);
+ }
}
break;
};
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
index ef16c57..86dd18a 100644
--- a/drivers/net/wimax/i2400m/driver.c
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -82,6 +82,14 @@ module_param_named(rx_reorder_disabled, i2400m_rx_reorder_disabled, int, 0644);
MODULE_PARM_DESC(rx_reorder_disabled,
"If true, RX reordering will be disabled.");
+int i2400m_power_save_disabled; /* 0 (power saving enabled) by default */
+module_param_named(power_save_disabled, i2400m_power_save_disabled, int, 0644);
+MODULE_PARM_DESC(power_save_disabled,
+ "If true, the driver will not tell the device to enter "
+ "power saving mode when it reports it is ready for it. "
+ "False by default (so the device is told to do power "
+ "saving).");
+
/**
* i2400m_queue_work - schedule work on a i2400m's queue
*
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h
index 434ba31..8dba246 100644
--- a/drivers/net/wimax/i2400m/i2400m.h
+++ b/drivers/net/wimax/i2400m/i2400m.h
@@ -709,6 +709,7 @@ static const __le32 i2400m_SBOOT_BARKER[4] = {
cpu_to_le32(I2400M_SBOOT_BARKER)
};
+extern int i2400m_power_save_disabled;
/*
* Utility functions
--
1.6.2.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [2.6.31 02/21] wimax/i2400m: don't call netif_start_queue() in _tx_msg_sent()
2009-06-11 21:35 [2.6.31 00/21] WiMAX pull request Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 01/21] wimax/i2400m: introduce module parameter to disable entering power save Inaky Perez-Gonzalez
@ 2009-06-11 21:35 ` Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 03/21] wimax/i2400m: i2400m's work queue should be initialized before RX support Inaky Perez-Gonzalez
` (19 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-06-11 21:35 UTC (permalink / raw)
To: netdev, wimax
Reported and fixed by Cindy H Kao.
When the device is stopped __i2400m_dev_stop() stops the network
queue.
However, when this is done in the middle of heavy network operation,
when the bus-specific subdriver is still wrapping up and it reports a
sent TX transaction with _tx_msg_sent() right after the device was
stopped, the queue was being started again, which was causing a stream
of oopsen and finally a panic.
In any case, said call has no place there. It's a left over from an
early implementation that was discarded later on.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/tx.c | 1 -
1 files changed, 0 insertions(+), 1 deletions(-)
diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c
index 613a88f..8ef724d 100644
--- a/drivers/net/wimax/i2400m/tx.c
+++ b/drivers/net/wimax/i2400m/tx.c
@@ -773,7 +773,6 @@ void i2400m_tx_msg_sent(struct i2400m *i2400m)
n = i2400m->tx_out / I2400M_TX_BUF_SIZE;
i2400m->tx_out %= I2400M_TX_BUF_SIZE;
i2400m->tx_in -= n * I2400M_TX_BUF_SIZE;
- netif_start_queue(i2400m->wimax_dev.net_dev);
spin_unlock_irqrestore(&i2400m->tx_lock, flags);
d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
}
--
1.6.2.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [2.6.31 03/21] wimax/i2400m: i2400m's work queue should be initialized before RX support
2009-06-11 21:35 [2.6.31 00/21] WiMAX pull request Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 01/21] wimax/i2400m: introduce module parameter to disable entering power save Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 02/21] wimax/i2400m: don't call netif_start_queue() in _tx_msg_sent() Inaky Perez-Gonzalez
@ 2009-06-11 21:35 ` Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 04/21] wimax/i2400m: i2400m_schedule_work() doesn't need i2400m->work_queue Inaky Perez-Gonzalez
` (18 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-06-11 21:35 UTC (permalink / raw)
To: netdev, wimax
RX support is the only user of the work-queue, to process
reports/notifications from the device. Thus, it needs the work queue
to be initialized first.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/driver.c | 21 ++++++++++++++-------
1 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
index 86dd18a..006eb12 100644
--- a/drivers/net/wimax/i2400m/driver.c
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -385,6 +385,11 @@ error:
* Uploads firmware and brings up all the resources needed to be able
* to communicate with the device.
*
+ * The workqueue has to be setup early, at least before RX handling
+ * (it's only real user for now) so it can process reports as they
+ * arrive. We also want to destroy it if we retry, to make sure it is
+ * flushed...easier like this.
+ *
* TX needs to be setup before the bus-specific code (otherwise on
* shutdown, the bus-tx code could try to access it).
*/
@@ -410,15 +415,15 @@ retry:
result = i2400m_rx_setup(i2400m);
if (result < 0)
goto error_rx_setup;
- result = i2400m->bus_dev_start(i2400m);
- if (result < 0)
- goto error_bus_dev_start;
i2400m->work_queue = create_singlethread_workqueue(wimax_dev->name);
if (i2400m->work_queue == NULL) {
result = -ENOMEM;
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;
result = i2400m_firmware_check(i2400m); /* fw versions ok? */
if (result < 0)
goto error_fw_check;
@@ -440,10 +445,10 @@ retry:
error_dev_initialize:
error_check_mac_addr:
error_fw_check:
- destroy_workqueue(i2400m->work_queue);
-error_create_workqueue:
i2400m->bus_dev_stop(i2400m);
error_bus_dev_start:
+ destroy_workqueue(i2400m->work_queue);
+error_create_workqueue:
i2400m_rx_release(i2400m);
error_rx_setup:
i2400m_tx_release(i2400m);
@@ -479,7 +484,9 @@ int i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri bm_flags)
*
* Returns: 0 if ok, < 0 errno code on error.
*
- * Releases all the resources allocated to communicate with the device.
+ * Releases all the resources allocated to communicate with the
+ * device. Note we cannot destroy the workqueue earlier as until RX is
+ * fully destroyed, it could still try to schedule jobs.
*/
static
void __i2400m_dev_stop(struct i2400m *i2400m)
@@ -491,8 +498,8 @@ void __i2400m_dev_stop(struct i2400m *i2400m)
wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING);
i2400m_dev_shutdown(i2400m);
i2400m->ready = 0;
- destroy_workqueue(i2400m->work_queue);
i2400m->bus_dev_stop(i2400m);
+ destroy_workqueue(i2400m->work_queue);
i2400m_rx_release(i2400m);
i2400m_tx_release(i2400m);
wimax_state_change(wimax_dev, WIMAX_ST_DOWN);
--
1.6.2.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [2.6.31 04/21] wimax/i2400m: i2400m_schedule_work() doesn't need i2400m->work_queue
2009-06-11 21:35 [2.6.31 00/21] WiMAX pull request Inaky Perez-Gonzalez
` (2 preceding siblings ...)
2009-06-11 21:35 ` [2.6.31 03/21] wimax/i2400m: i2400m's work queue should be initialized before RX support Inaky Perez-Gonzalez
@ 2009-06-11 21:35 ` Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 05/21] wimax/i2400m: Change d_printf() level for secure boot messages Inaky Perez-Gonzalez
` (17 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-06-11 21:35 UTC (permalink / raw)
To: netdev, wimax
By mistake, the BUG_ON() check was left in there and it will fail when
called if i2400m->work_queue is still not setup.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/driver.c | 1 -
1 files changed, 0 insertions(+), 1 deletions(-)
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
index 006eb12..897794c 100644
--- a/drivers/net/wimax/i2400m/driver.c
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -180,7 +180,6 @@ int i2400m_schedule_work(struct i2400m *i2400m,
int result;
struct i2400m_work *iw;
- BUG_ON(i2400m->work_queue == NULL);
result = -ENOMEM;
iw = kzalloc(sizeof(*iw), gfp_flags);
if (iw == NULL)
--
1.6.2.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [2.6.31 05/21] wimax/i2400m: Change d_printf() level for secure boot messages
2009-06-11 21:35 [2.6.31 00/21] WiMAX pull request Inaky Perez-Gonzalez
` (3 preceding siblings ...)
2009-06-11 21:35 ` [2.6.31 04/21] wimax/i2400m: i2400m_schedule_work() doesn't need i2400m->work_queue Inaky Perez-Gonzalez
@ 2009-06-11 21:35 ` Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 06/21] wimax/i2400m/sdio: Implement I2400M_RT_BUS reset type Inaky Perez-Gonzalez
` (16 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-06-11 21:35 UTC (permalink / raw)
To: netdev, wimax; +Cc: Dirk Brandewie
From: Dirk Brandewie <dirk.j.brandewie@intel.com>
Changing debug level of print out to support validation engineers
getting the messages they need.
Signed-off-by: <dirk.j.brandewie@intel.com>
---
drivers/net/wimax/i2400m/fw.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c
index 675c6ce..7ee1b99 100644
--- a/drivers/net/wimax/i2400m/fw.c
+++ b/drivers/net/wimax/i2400m/fw.c
@@ -532,14 +532,14 @@ int i2400m_dnload_finalize(struct i2400m *i2400m,
cmd = (void *) bcf + offset;
if (i2400m->sboot == 0) {
struct i2400m_bootrom_header jump_ack;
- d_printf(3, dev, "unsecure boot, jumping to 0x%08x\n",
+ d_printf(1, dev, "unsecure boot, jumping to 0x%08x\n",
le32_to_cpu(cmd->target_addr));
i2400m_brh_set_opcode(cmd, I2400M_BRH_JUMP);
cmd->data_size = 0;
ret = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd),
&jump_ack, sizeof(jump_ack), 0);
} else {
- d_printf(3, dev, "secure boot, jumping to 0x%08x\n",
+ d_printf(1, dev, "secure boot, jumping to 0x%08x\n",
le32_to_cpu(cmd->target_addr));
cmd_buf = i2400m->bm_cmd_buf;
memcpy(&cmd_buf->cmd, cmd, sizeof(*cmd));
--
1.6.2.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [2.6.31 06/21] wimax/i2400m/sdio: Implement I2400M_RT_BUS reset type
2009-06-11 21:35 [2.6.31 00/21] WiMAX pull request Inaky Perez-Gonzalez
` (4 preceding siblings ...)
2009-06-11 21:35 ` [2.6.31 05/21] wimax/i2400m: Change d_printf() level for secure boot messages Inaky Perez-Gonzalez
@ 2009-06-11 21:35 ` Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 07/21] wimax/i2400m: rename misleading I2400M_PL_PAD to I2400M_PL_ALIGN Inaky Perez-Gonzalez
` (15 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-06-11 21:35 UTC (permalink / raw)
To: netdev, wimax; +Cc: Dirk Brandewie
From: Dirk Brandewie <dirk.j.brandewie@intel.com>
This reset type causes the WiMAX function to be disabled and
re-enabled, which will force the WiMAX device to reset and enter boot
mode.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
Signed-off-by: Dirk Brandewie <dirk.j.brandewie@intel.com>
---
drivers/net/wimax/i2400m/i2400m-sdio.h | 2 ++
drivers/net/wimax/i2400m/sdio.c | 20 +++++++++++++++++---
2 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wimax/i2400m/i2400m-sdio.h b/drivers/net/wimax/i2400m/i2400m-sdio.h
index 08c2fb7..2071721 100644
--- a/drivers/net/wimax/i2400m/i2400m-sdio.h
+++ b/drivers/net/wimax/i2400m/i2400m-sdio.h
@@ -78,6 +78,8 @@ enum {
/* The number of ticks to wait for the device to signal that
* it is ready */
I2400MS_INIT_SLEEP_INTERVAL = 10,
+ /* How long to wait for the device to settle after reset */
+ I2400MS_SETTLE_TIME = 40,
};
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c
index 777c981..d6fac5c 100644
--- a/drivers/net/wimax/i2400m/sdio.c
+++ b/drivers/net/wimax/i2400m/sdio.c
@@ -255,7 +255,7 @@ error_kzalloc:
static
int i2400ms_bus_reset(struct i2400m *i2400m, enum i2400m_reset_type rt)
{
- int result;
+ int result = 0;
struct i2400ms *i2400ms =
container_of(i2400m, struct i2400ms, i2400m);
struct device *dev = i2400m_dev(i2400m);
@@ -280,8 +280,22 @@ 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:
- dev_err(dev, "FIXME: SDIO bus reset not implemented\n");
- result = rt == I2400M_RT_WARM ? -ENODEV : -ENOSYS;
+ /* 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);
+
+ sdio_claim_host(i2400ms->func);
+ sdio_disable_func(i2400ms->func);
+ sdio_release_host(i2400ms->func);
+
+ /* Wait for the device to settle */
+ msleep(40);
+
+ result = i2400ms_enable_function(i2400ms->func);
} else
BUG();
if (result < 0 && rt != I2400M_RT_BUS) {
--
1.6.2.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [2.6.31 07/21] wimax/i2400m: rename misleading I2400M_PL_PAD to I2400M_PL_ALIGN
2009-06-11 21:35 [2.6.31 00/21] WiMAX pull request Inaky Perez-Gonzalez
` (5 preceding siblings ...)
2009-06-11 21:35 ` [2.6.31 06/21] wimax/i2400m/sdio: Implement I2400M_RT_BUS reset type Inaky Perez-Gonzalez
@ 2009-06-11 21:35 ` Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 08/21] wimax/i2400m: fix panic/warnings caused by missed check on empty TX message Inaky Perez-Gonzalez
` (14 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-06-11 21:35 UTC (permalink / raw)
To: netdev, wimax
The constant is being use as an alignment factor, not as a padding
factor; made reading/reviewing the code quite confusing.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/fw.c | 2 +-
drivers/net/wimax/i2400m/rx.c | 4 ++--
drivers/net/wimax/i2400m/tx.c | 4 ++--
include/linux/wimax/i2400m.h | 2 +-
4 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c
index 7ee1b99..26924f1 100644
--- a/drivers/net/wimax/i2400m/fw.c
+++ b/drivers/net/wimax/i2400m/fw.c
@@ -397,7 +397,7 @@ static int i2400m_download_chunk(struct i2400m *i2400m, const void *chunk,
unsigned int direct, unsigned int do_csum)
{
int ret;
- size_t chunk_len = ALIGN(__chunk_len, I2400M_PL_PAD);
+ size_t chunk_len = ALIGN(__chunk_len, I2400M_PL_ALIGN);
struct device *dev = i2400m_dev(i2400m);
struct {
struct i2400m_bootrom_header cmd;
diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c
index 7643850..07c32e6 100644
--- a/drivers/net/wimax/i2400m/rx.c
+++ b/drivers/net/wimax/i2400m/rx.c
@@ -1148,7 +1148,7 @@ int i2400m_rx(struct i2400m *i2400m, struct sk_buff *skb)
num_pls = le16_to_cpu(msg_hdr->num_pls);
pl_itr = sizeof(*msg_hdr) + /* Check payload descriptor(s) */
num_pls * sizeof(msg_hdr->pld[0]);
- pl_itr = ALIGN(pl_itr, I2400M_PL_PAD);
+ pl_itr = ALIGN(pl_itr, I2400M_PL_ALIGN);
if (pl_itr > skb->len) { /* got all the payload descriptors? */
dev_err(dev, "RX: HW BUG? message too short (%u bytes) for "
"%u payload descriptors (%zu each, total %zu)\n",
@@ -1166,7 +1166,7 @@ int i2400m_rx(struct i2400m *i2400m, struct sk_buff *skb)
single_last = num_pls == 1 || i == num_pls - 1;
i2400m_rx_payload(i2400m, skb, single_last, &msg_hdr->pld[i],
skb->data + pl_itr);
- pl_itr += ALIGN(pl_size, I2400M_PL_PAD);
+ pl_itr += ALIGN(pl_size, I2400M_PL_ALIGN);
cond_resched(); /* Don't monopolize */
}
kfree_skb(skb);
diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c
index 8ef724d..a635fd7 100644
--- a/drivers/net/wimax/i2400m/tx.c
+++ b/drivers/net/wimax/i2400m/tx.c
@@ -491,7 +491,7 @@ void i2400m_tx_close(struct i2400m *i2400m)
*/
hdr_size = sizeof(*tx_msg)
+ le16_to_cpu(tx_msg->num_pls) * sizeof(tx_msg->pld[0]);
- hdr_size = ALIGN(hdr_size, I2400M_PL_PAD);
+ hdr_size = ALIGN(hdr_size, I2400M_PL_ALIGN);
tx_msg->offset = I2400M_TX_PLD_SIZE - hdr_size;
tx_msg_moved = (void *) tx_msg + tx_msg->offset;
memmove(tx_msg_moved, tx_msg, hdr_size);
@@ -574,7 +574,7 @@ int i2400m_tx(struct i2400m *i2400m, const void *buf, size_t buf_len,
d_fnstart(3, dev, "(i2400m %p skb %p [%zu bytes] pt %u)\n",
i2400m, buf, buf_len, pl_type);
- padded_len = ALIGN(buf_len, I2400M_PL_PAD);
+ padded_len = ALIGN(buf_len, I2400M_PL_ALIGN);
d_printf(5, dev, "padded_len %zd buf_len %zd\n", padded_len, buf_len);
/* If there is no current TX message, create one; if the
* current one is out of payload slots or we have a singleton,
diff --git a/include/linux/wimax/i2400m.h b/include/linux/wimax/i2400m.h
index d5148a7..433693e 100644
--- a/include/linux/wimax/i2400m.h
+++ b/include/linux/wimax/i2400m.h
@@ -266,7 +266,7 @@ enum i2400m_ro_type {
/* Misc constants */
enum {
- I2400M_PL_PAD = 16, /* Payload data size alignment */
+ I2400M_PL_ALIGN = 16, /* Payload data size alignment */
I2400M_PL_SIZE_MAX = 0x3EFF,
I2400M_MAX_PLS_IN_MSG = 60,
/* protocol barkers: sync sequences; for notifications they
--
1.6.2.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [2.6.31 08/21] wimax/i2400m: fix panic/warnings caused by missed check on empty TX message
2009-06-11 21:35 [2.6.31 00/21] WiMAX pull request Inaky Perez-Gonzalez
` (6 preceding siblings ...)
2009-06-11 21:35 ` [2.6.31 07/21] wimax/i2400m: rename misleading I2400M_PL_PAD to I2400M_PL_ALIGN Inaky Perez-Gonzalez
@ 2009-06-11 21:35 ` Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 09/21] wimax/i2400m: fix panic due to missed corner cases on tail_room calculation Inaky Perez-Gonzalez
` (13 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-06-11 21:35 UTC (permalink / raw)
To: netdev, wimax
In some situations, when a new TX message header is started, there
might be no space for data payloads. In this case the message is left
with zero payloads and the i2400m_tx_close() function has just to mark
it as "to skip". If it tries to go ahead it will overwrite things
because there is no space to add padding as defined by the
bus-specific layer. This can cause buffer overruns and in some stress
cases, panics.
Found and diagnosed by Cindy H. Kao.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/tx.c | 10 +++++++++-
1 files changed, 9 insertions(+), 1 deletions(-)
diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c
index a635fd7..7c46c05 100644
--- a/drivers/net/wimax/i2400m/tx.c
+++ b/drivers/net/wimax/i2400m/tx.c
@@ -474,10 +474,18 @@ void i2400m_tx_close(struct i2400m *i2400m)
struct i2400m_msg_hdr *tx_msg_moved;
size_t aligned_size, padding, hdr_size;
void *pad_buf;
+ unsigned num_pls;
if (tx_msg->size & I2400M_TX_SKIP) /* a skipper? nothing to do */
goto out;
-
+ num_pls = le16_to_cpu(tx_msg->num_pls);
+ /* We can get this situation when a new message was started
+ * and there was no space to add payloads before hitting the
+ tail (and taking padding into consideration). */
+ if (num_pls == 0) {
+ tx_msg->size |= I2400M_TX_SKIP;
+ goto out;
+ }
/* Relocate the message header
*
* Find the current header size, align it to 16 and if we need
--
1.6.2.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [2.6.31 09/21] wimax/i2400m: fix panic due to missed corner cases on tail_room calculation
2009-06-11 21:35 [2.6.31 00/21] WiMAX pull request Inaky Perez-Gonzalez
` (7 preceding siblings ...)
2009-06-11 21:35 ` [2.6.31 08/21] wimax/i2400m: fix panic/warnings caused by missed check on empty TX message Inaky Perez-Gonzalez
@ 2009-06-11 21:35 ` Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 10/21] wimax/i2400m: don't reset device on i2400m_dev_shutdown() Inaky Perez-Gonzalez
` (12 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-06-11 21:35 UTC (permalink / raw)
To: netdev, wimax
i2400m_tx_skip_tail() needs to handle the special case of being called
when the tail room that is left over in the FIFO is zero.
This happens when a TX message header was opened at the very end of
the FIFO (without payloads). The i2400m_tx_close() code already marked
said TX message (header) to be skipped and this function should be
doing nothing.
It is called anyway because it is part of a common "corner case" path
handling which takes care of more cases than only this one.
The tail room computation was also improved to take care of the case
when tx_in is at the end of the buffer boundary; tail_room has to be
modded (%) to the buffer size. To do that in a single well-documented
place, __i2400m_tx_tail_room() is introduced and used.
Treat i2400m->tx_in == 0 as a corner case and handle it accordingly.
Found and diagnosed by Cindy H. Kao.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/tx.c | 58 +++++++++++++++++++++++++++++++++++++++-
1 files changed, 56 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c
index 7c46c05..4295dcf 100644
--- a/drivers/net/wimax/i2400m/tx.c
+++ b/drivers/net/wimax/i2400m/tx.c
@@ -278,6 +278,48 @@ enum {
#define TAIL_FULL ((void *)~(unsigned long)NULL)
/*
+ * Calculate how much tail room is available
+ *
+ * Note the trick here. This path is ONLY caleed for Case A (see
+ * i2400m_tx_fifo_push() below), where we have:
+ *
+ * Case A
+ * N ___________
+ * | tail room |
+ * | |
+ * |<- IN ->|
+ * | |
+ * | data |
+ * | |
+ * |<- OUT ->|
+ * | |
+ * | head room |
+ * 0 -----------
+ *
+ * When calculating the tail_room, tx_in might get to be zero if
+ * i2400m->tx_in is right at the end of the buffer (really full
+ * buffer) if there is no head room. In this case, tail_room would be
+ * I2400M_TX_BUF_SIZE, although it is actually zero. Hence the final
+ * mod (%) operation. However, when doing this kind of optimization,
+ * i2400m->tx_in being zero would fail, so we treat is an a special
+ * case.
+ */
+static inline
+size_t __i2400m_tx_tail_room(struct i2400m *i2400m)
+{
+ size_t tail_room;
+ size_t tx_in;
+
+ if (unlikely(i2400m->tx_in) == 0)
+ return I2400M_TX_BUF_SIZE;
+ tx_in = i2400m->tx_in % I2400M_TX_BUF_SIZE;
+ tail_room = I2400M_TX_BUF_SIZE - tx_in;
+ tail_room %= I2400M_TX_BUF_SIZE;
+ return tail_room;
+}
+
+
+/*
* Allocate @size bytes in the TX fifo, return a pointer to it
*
* @i2400m: device descriptor
@@ -338,7 +380,7 @@ void *i2400m_tx_fifo_push(struct i2400m *i2400m, size_t size, size_t padding)
return NULL;
}
/* Is there space at the tail? */
- tail_room = I2400M_TX_BUF_SIZE - i2400m->tx_in % I2400M_TX_BUF_SIZE;
+ tail_room = __i2400m_tx_tail_room(i2400m);
if (tail_room < needed_size) {
if (i2400m->tx_out % I2400M_TX_BUF_SIZE
< i2400m->tx_in % I2400M_TX_BUF_SIZE) {
@@ -367,17 +409,29 @@ void *i2400m_tx_fifo_push(struct i2400m *i2400m, size_t size, size_t padding)
* (I2400M_PL_PAD for the payloads, I2400M_TX_PLD_SIZE for the
* header).
*
+ * Tail room can get to be zero if a message was opened when there was
+ * space only for a header. _tx_close() will mark it as to-skip (as it
+ * will have no payloads) and there will be no more space to flush, so
+ * nothing has to be done here. This is probably cheaper than ensuring
+ * in _tx_new() that there is some space for payloads...as we could
+ * always possibly hit the same problem if the payload wouldn't fit.
+ *
* Note:
*
* Assumes i2400m->tx_lock is taken, and we use that as a barrier
+ *
+ * This path is only taken for Case A FIFO situations [see
+ * i2400m_tx_fifo_push()]
*/
static
void i2400m_tx_skip_tail(struct i2400m *i2400m)
{
struct device *dev = i2400m_dev(i2400m);
size_t tx_in = i2400m->tx_in % I2400M_TX_BUF_SIZE;
- size_t tail_room = I2400M_TX_BUF_SIZE - tx_in;
+ size_t tail_room = __i2400m_tx_tail_room(i2400m);
struct i2400m_msg_hdr *msg = i2400m->tx_buf + tx_in;
+ if (unlikely(tail_room == 0))
+ return;
BUG_ON(tail_room < sizeof(*msg));
msg->size = tail_room | I2400M_TX_SKIP;
d_printf(2, dev, "skip tail: skipping %zu bytes @%zu\n",
--
1.6.2.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [2.6.31 10/21] wimax/i2400m: don't reset device on i2400m_dev_shutdown()
2009-06-11 21:35 [2.6.31 00/21] WiMAX pull request Inaky Perez-Gonzalez
` (8 preceding siblings ...)
2009-06-11 21:35 ` [2.6.31 09/21] wimax/i2400m: fix panic due to missed corner cases on tail_room calculation Inaky Perez-Gonzalez
@ 2009-06-11 21:35 ` Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 11/21] wimax/i2400m: fix oops when the TX FIFO fills up due to a missing check Inaky Perez-Gonzalez
` (11 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-06-11 21:35 UTC (permalink / raw)
To: netdev, wimax
i2400m_dev_shutdown() tried to reset the device to put it in a known
state before shutting down.
But that turned out to be pointless. We reach this case in two paths:
1 - when the device resets, to clean up state
2 - when the driver is unloaded, for the same
however, in both cases it is pointless; in (1) the device is already
reset, why do it again? in (2) we can't -- the USB stack, for example,
doesn't allow communicating with the device when the driver is being
unbound and if the device is disconnected, the device is gone already.
So just remove it. Leave the function as a placeholder for future
cleanups that will be done from data allocated by the driver during
device operation.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/control.c | 10 +++++-----
1 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c
index 89cdfe4..d8e0cdf 100644
--- a/drivers/net/wimax/i2400m/control.c
+++ b/drivers/net/wimax/i2400m/control.c
@@ -1396,16 +1396,16 @@ error:
*
* @i2400m: device descriptor
*
- * Gracefully stops the device, moving it to the lowest power
- * consumption state possible.
+ * Release resources acquired during the running of the device; in
+ * theory, should also tell the device to go to sleep, switch off the
+ * radio, all that, but at this point, in most cases (driver
+ * disconnection, reset handling) we can't even talk to the device.
*/
void i2400m_dev_shutdown(struct i2400m *i2400m)
{
- int result = -ENODEV;
struct device *dev = i2400m_dev(i2400m);
d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
- result = i2400m->bus_reset(i2400m, I2400M_RT_WARM);
- d_fnend(3, dev, "(i2400m %p) = void [%d]\n", i2400m, result);
+ d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
return;
}
--
1.6.2.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [2.6.31 11/21] wimax/i2400m: fix oops when the TX FIFO fills up due to a missing check
2009-06-11 21:35 [2.6.31 00/21] WiMAX pull request Inaky Perez-Gonzalez
` (9 preceding siblings ...)
2009-06-11 21:35 ` [2.6.31 10/21] wimax/i2400m: don't reset device on i2400m_dev_shutdown() Inaky Perez-Gonzalez
@ 2009-06-11 21:35 ` Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 12/21] wimax/i2400m: if a device reboot happens during probe, handle it Inaky Perez-Gonzalez
` (10 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-06-11 21:35 UTC (permalink / raw)
To: netdev, wimax
When the TX FIFO filled up and i2400m_tx_new() failed to allocate a
new TX message header, a missing check for said condition was causing a
kernel oops when trying to dereference a NULL i2400m->tx_msg pointer.
Found and diagnosed by Cindy H. Kao.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/tx.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c
index 4295dcf..fa16ccf 100644
--- a/drivers/net/wimax/i2400m/tx.c
+++ b/drivers/net/wimax/i2400m/tx.c
@@ -653,6 +653,8 @@ try_new:
i2400m_tx_close(i2400m);
i2400m_tx_new(i2400m);
}
+ if (i2400m->tx_msg == NULL)
+ goto error_tx_new;
if (i2400m->tx_msg->size + padded_len > I2400M_TX_BUF_SIZE / 2) {
d_printf(2, dev, "TX: message too big, going new\n");
i2400m_tx_close(i2400m);
--
1.6.2.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [2.6.31 12/21] wimax/i2400m: if a device reboot happens during probe, handle it
2009-06-11 21:35 [2.6.31 00/21] WiMAX pull request Inaky Perez-Gonzalez
` (10 preceding siblings ...)
2009-06-11 21:35 ` [2.6.31 11/21] wimax/i2400m: fix oops when the TX FIFO fills up due to a missing check Inaky Perez-Gonzalez
@ 2009-06-11 21:35 ` Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 13/21] wimax/i2400m: Allow bus-specific driver to specify retry count Inaky Perez-Gonzalez
` (9 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-06-11 21:35 UTC (permalink / raw)
To: netdev, wimax
When a device reboot happens when we are under probe, with init_mutex
taken, make sure we can recover. Have dev_reset_handle set boot mode
and i2400m_msg_to_dev() will see it and fail gracefully instead of
timing out.
Found and diagnosed by Cindy H. Kao.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/control.c | 1 +
drivers/net/wimax/i2400m/driver.c | 2 ++
drivers/net/wimax/i2400m/fw.c | 2 ++
3 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c
index d8e0cdf..f9399f2 100644
--- a/drivers/net/wimax/i2400m/control.c
+++ b/drivers/net/wimax/i2400m/control.c
@@ -695,6 +695,7 @@ struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m,
d_fnstart(3, dev, "(i2400m %p buf %p len %zu)\n",
i2400m, buf, buf_len);
+ rmb(); /* Make sure we see what i2400m_dev_reset_handle() */
if (i2400m->boot_mode)
return ERR_PTR(-ENODEV);
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
index 897794c..e8d022d 100644
--- a/drivers/net/wimax/i2400m/driver.c
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -610,6 +610,8 @@ out:
*/
int i2400m_dev_reset_handle(struct i2400m *i2400m)
{
+ i2400m->boot_mode = 1;
+ wmb(); /* Make sure i2400m_msg_to_dev() sees boot_mode */
return i2400m_schedule_work(i2400m, __i2400m_dev_reset_handle,
GFP_ATOMIC);
}
diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c
index 26924f1..01c926e 100644
--- a/drivers/net/wimax/i2400m/fw.c
+++ b/drivers/net/wimax/i2400m/fw.c
@@ -985,6 +985,7 @@ int i2400m_fw_dnload(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf,
d_fnstart(5, dev, "(i2400m %p bcf %p size %zu)\n",
i2400m, bcf, bcf_size);
i2400m->boot_mode = 1;
+ wmb(); /* Make sure other readers see it */
hw_reboot:
if (count-- == 0) {
ret = -ERESTARTSYS;
@@ -1033,6 +1034,7 @@ hw_reboot:
d_printf(2, dev, "fw %s successfully uploaded\n",
i2400m->fw_name);
i2400m->boot_mode = 0;
+ wmb(); /* Make sure i2400m_msg_to_dev() sees boot_mode */
error_dnload_finalize:
error_dnload_bcf:
error_dnload_init:
--
1.6.2.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [2.6.31 13/21] wimax/i2400m: Allow bus-specific driver to specify retry count
2009-06-11 21:35 [2.6.31 00/21] WiMAX pull request Inaky Perez-Gonzalez
` (11 preceding siblings ...)
2009-06-11 21:35 ` [2.6.31 12/21] wimax/i2400m: if a device reboot happens during probe, handle it Inaky Perez-Gonzalez
@ 2009-06-11 21:35 ` Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 14/21] wimax/i2400m: move boot time poke table out of common driver Inaky Perez-Gonzalez
` (8 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-06-11 21:35 UTC (permalink / raw)
To: netdev, wimax
The code that sets up the i2400m (firmware load and general driver
setup after it) includes a couple of retry loops.
The SDIO device sometimes can get in more complicated corners than the
USB one (due to its interaction with other SDIO functions), that
require trying a few more times.
To solve that, without having a failing USB device taking longer to be
considered dead, allow the retry counts to be specified by the
bus-specific driver, which the general driver takes as a parameter.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/driver.c | 2 +-
drivers/net/wimax/i2400m/fw.c | 2 +-
drivers/net/wimax/i2400m/i2400m.h | 14 ++++++++++++++
drivers/net/wimax/i2400m/sdio.c | 3 +++
drivers/net/wimax/i2400m/usb.c | 1 +
5 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
index e8d022d..8d8628e 100644
--- a/drivers/net/wimax/i2400m/driver.c
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -399,7 +399,7 @@ int __i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri flags)
struct wimax_dev *wimax_dev = &i2400m->wimax_dev;
struct net_device *net_dev = wimax_dev->net_dev;
struct device *dev = i2400m_dev(i2400m);
- int times = 3;
+ int times = i2400m->bus_bm_retries;
d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
retry:
diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c
index 01c926e..c48fa24 100644
--- a/drivers/net/wimax/i2400m/fw.c
+++ b/drivers/net/wimax/i2400m/fw.c
@@ -980,7 +980,7 @@ int i2400m_fw_dnload(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf,
{
int ret = 0;
struct device *dev = i2400m_dev(i2400m);
- int count = I2400M_BOOT_RETRIES;
+ int count = i2400m->bus_bm_retries;
d_fnstart(5, dev, "(i2400m %p bcf %p size %zu)\n",
i2400m, bcf, bcf_size);
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h
index 8dba246..59cd783 100644
--- a/drivers/net/wimax/i2400m/i2400m.h
+++ b/drivers/net/wimax/i2400m/i2400m.h
@@ -150,6 +150,7 @@
enum {
/* Firmware uploading */
I2400M_BOOT_RETRIES = 3,
+ I3200_BOOT_RETRIES = 3,
/* Size of the Boot Mode Command buffer */
I2400M_BM_CMD_BUF_SIZE = 16 * 1024,
I2400M_BM_ACK_BUF_SIZE = 256,
@@ -224,6 +225,17 @@ struct i2400m_roq;
* process, so it cannot rely on common infrastructure being laid
* out.
*
+ * @bus_bm_retries: [fill] How many times shall a firmware upload /
+ * device initialization be retried? Different models of the same
+ * device might need different values, hence it is set by the
+ * bus-specific driver. Note this value is used in two places,
+ * i2400m_fw_dnload() and __i2400m_dev_start(); they won't become
+ * multiplicative (__i2400m_dev_start() calling N times
+ * i2400m_fw_dnload() and this trying N times to download the
+ * firmware), as if __i2400m_dev_start() only retries if the
+ * firmware crashed while initializing the device (not in a
+ * general case).
+ *
* @bus_bm_cmd_send: [fill] Function called to send a boot-mode
* command. Flags are defined in 'enum i2400m_bm_cmd_flags'. This
* is synchronous and has to return 0 if ok or < 0 errno code in
@@ -399,6 +411,8 @@ struct i2400m {
size_t bus_tx_block_size;
size_t bus_pl_size_max;
+ unsigned bus_bm_retries;
+
int (*bus_dev_start)(struct i2400m *);
void (*bus_dev_stop)(struct i2400m *);
void (*bus_tx_kick)(struct i2400m *);
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c
index d6fac5c..afde897 100644
--- a/drivers/net/wimax/i2400m/sdio.c
+++ b/drivers/net/wimax/i2400m/sdio.c
@@ -418,6 +418,9 @@ int i2400ms_probe(struct sdio_func *func,
i2400m->bus_dev_stop = i2400ms_bus_dev_stop;
i2400m->bus_tx_kick = i2400ms_bus_tx_kick;
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_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;
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c
index 1785132..ebc05da 100644
--- a/drivers/net/wimax/i2400m/usb.c
+++ b/drivers/net/wimax/i2400m/usb.c
@@ -399,6 +399,7 @@ int i2400mu_probe(struct usb_interface *iface,
i2400m->bus_dev_stop = i2400mu_bus_dev_stop;
i2400m->bus_tx_kick = i2400mu_bus_tx_kick;
i2400m->bus_reset = i2400mu_bus_reset;
+ i2400m->bus_bm_retries = I2400M_BOOT_RETRIES;
i2400m->bus_bm_cmd_send = i2400mu_bus_bm_cmd_send;
i2400m->bus_bm_wait_for_ack = i2400mu_bus_bm_wait_for_ack;
i2400m->bus_fw_names = i2400mu_bus_fw_names;
--
1.6.2.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [2.6.31 14/21] wimax/i2400m: move boot time poke table out of common driver
2009-06-11 21:35 [2.6.31 00/21] WiMAX pull request Inaky Perez-Gonzalez
` (12 preceding siblings ...)
2009-06-11 21:35 ` [2.6.31 13/21] wimax/i2400m: Allow bus-specific driver to specify retry count Inaky Perez-Gonzalez
@ 2009-06-11 21:35 ` Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 15/21] wimax/i2400m/sdio: Add device specific poke table Inaky Perez-Gonzalez
` (7 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-06-11 21:35 UTC (permalink / raw)
To: netdev, wimax; +Cc: Dirk Brandewie
From: Dirk Brandewie <dirk.j.brandewie@intel.com>
This change moves the table of "pokes" performed on the device at boot
time to the bus specific portion of the driver.
Different models of the i2400m device supported by this driver require
different poke tables, thus having a single table that works for all
is impossible. For that, the table is moved to the bus-specific
driver, who can decide which table to use based on the specifics of
the device and point the generic driver to it.
Signed-off-by: Dirk Brandewie <dirk.j.brandewie@intel.com>
---
drivers/net/wimax/i2400m/fw.c | 45 ++++++++++--------------------------
drivers/net/wimax/i2400m/i2400m.h | 28 +++++++++++++++++++++++
2 files changed, 41 insertions(+), 32 deletions(-)
diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c
index c48fa24..349344a 100644
--- a/drivers/net/wimax/i2400m/fw.c
+++ b/drivers/net/wimax/i2400m/fw.c
@@ -770,40 +770,21 @@ error_read_mac:
static
int i2400m_dnload_init_nonsigned(struct i2400m *i2400m)
{
-#define POKE(a, d) { \
- .address = cpu_to_le32(a), \
- .data = cpu_to_le32(d) \
-}
- static const struct {
- __le32 address;
- __le32 data;
- } i2400m_pokes[] = {
- POKE(0x081A58, 0xA7810230),
- POKE(0x080040, 0x00000000),
- POKE(0x080048, 0x00000082),
- POKE(0x08004C, 0x0000081F),
- POKE(0x080054, 0x00000085),
- POKE(0x080058, 0x00000180),
- POKE(0x08005C, 0x00000018),
- POKE(0x080060, 0x00000010),
- POKE(0x080574, 0x00000001),
- POKE(0x080550, 0x00000005),
- POKE(0xAE0000, 0x00000000),
- };
-#undef POKE
- unsigned i;
- int ret;
+ unsigned i = 0;
+ int ret = 0;
struct device *dev = i2400m_dev(i2400m);
-
- dev_warn(dev, "WARNING!!! non-signed boot UNTESTED PATH!\n");
-
d_fnstart(5, dev, "(i2400m %p)\n", i2400m);
- for (i = 0; i < ARRAY_SIZE(i2400m_pokes); i++) {
- ret = i2400m_download_chunk(i2400m, &i2400m_pokes[i].data,
- sizeof(i2400m_pokes[i].data),
- i2400m_pokes[i].address, 1, 1);
- if (ret < 0)
- break;
+ if (i2400m->bus_bm_pokes_table) {
+ while (i2400m->bus_bm_pokes_table[i].address) {
+ ret = i2400m_download_chunk(
+ i2400m,
+ &i2400m->bus_bm_pokes_table[i].data,
+ sizeof(i2400m->bus_bm_pokes_table[i].data),
+ i2400m->bus_bm_pokes_table[i].address, 1, 1);
+ if (ret < 0)
+ break;
+ i++;
+ }
}
d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, ret);
return ret;
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h
index 59cd783..1fe5da4 100644
--- a/drivers/net/wimax/i2400m/i2400m.h
+++ b/drivers/net/wimax/i2400m/i2400m.h
@@ -156,6 +156,27 @@ enum {
I2400M_BM_ACK_BUF_SIZE = 256,
};
+/**
+ * struct i2400m_poke_table - Hardware poke table for the Intel 2400m
+ *
+ * This structure will be used to create a device specific poke table
+ * to put the device in a consistant state at boot time.
+ *
+ * @address: The device address to poke
+ *
+ * @data: The data value to poke to the device address
+ *
+ */
+struct i2400m_poke_table{
+ __le32 address;
+ __le32 data;
+};
+
+#define I2400M_FW_POKE(a, d) { \
+ .address = cpu_to_le32(a), \
+ .data = cpu_to_le32(d) \
+}
+
/**
* i2400m_reset_type - methods to reset a device
@@ -264,6 +285,12 @@ struct i2400m_roq;
* address provided in boot mode is kind of broken and needs to
* be re-read later on.
*
+ * @bus_bm_pokes_table: [fill/optional] A table of device addresses
+ * and values that will be poked at device init time to move the
+ * device to the correct state for the type of boot/firmware being
+ * used. This table MUST be terminated with (0x000000,
+ * 0x00000000) or bad things will happen.
+ *
*
* @wimax_dev: WiMAX generic device for linkage into the kernel WiMAX
* stack. Due to the way a net_device is allocated, we need to
@@ -424,6 +451,7 @@ struct i2400m {
struct i2400m_bootrom_header *, size_t);
const char **bus_fw_names;
unsigned bus_bm_mac_addr_impaired:1;
+ const struct i2400m_poke_table *bus_bm_pokes_table;
spinlock_t tx_lock; /* protect TX state */
void *tx_buf;
--
1.6.2.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [2.6.31 15/21] wimax/i2400m/sdio: Add device specific poke table.
2009-06-11 21:35 [2.6.31 00/21] WiMAX pull request Inaky Perez-Gonzalez
` (13 preceding siblings ...)
2009-06-11 21:35 ` [2.6.31 14/21] wimax/i2400m: move boot time poke table out of common driver Inaky Perez-Gonzalez
@ 2009-06-11 21:35 ` Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 16/21] wimax/i2400m: don't reset device when bootrom init retries are exceeded Inaky Perez-Gonzalez
` (6 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-06-11 21:35 UTC (permalink / raw)
To: netdev, wimax; +Cc: Dirk Brandewie
From: Dirk Brandewie <dirk.j.brandewie@intel.com>
Add a poke table for the SDIO device (as it is different than USB).
Signed-off-by: Dirk Brandewie <dirk.j.brandewie@intel.com>
---
drivers/net/wimax/i2400m/sdio.c | 9 +++++++++
1 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c
index afde897..74de174 100644
--- a/drivers/net/wimax/i2400m/sdio.c
+++ b/drivers/net/wimax/i2400m/sdio.c
@@ -78,6 +78,14 @@ static const char *i2400ms_bus_fw_names[] = {
};
+static const struct i2400m_poke_table i2400ms_pokes[] = {
+ I2400M_FW_POKE(0x6BE260, 0x00000088),
+ I2400M_FW_POKE(0x080550, 0x00000005),
+ I2400M_FW_POKE(0xAE0000, 0x00000000),
+ I2400M_FW_POKE(0x000000, 0x00000000), /* MUST be 0 terminated or bad
+ * things will happen */
+};
+
/*
* Enable the SDIO function
*
@@ -425,6 +433,7 @@ int i2400ms_probe(struct sdio_func *func,
i2400m->bus_bm_wait_for_ack = i2400ms_bus_bm_wait_for_ack;
i2400m->bus_fw_names = i2400ms_bus_fw_names;
i2400m->bus_bm_mac_addr_impaired = 1;
+ i2400m->bus_bm_pokes_table = &i2400ms_pokes[0];
sdio_claim_host(func);
result = sdio_set_block_size(func, I2400MS_BLK_SIZE);
--
1.6.2.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [2.6.31 16/21] wimax/i2400m: don't reset device when bootrom init retries are exceeded
2009-06-11 21:35 [2.6.31 00/21] WiMAX pull request Inaky Perez-Gonzalez
` (14 preceding siblings ...)
2009-06-11 21:35 ` [2.6.31 15/21] wimax/i2400m/sdio: Add device specific poke table Inaky Perez-Gonzalez
@ 2009-06-11 21:35 ` Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 17/21] wimax/i2400m/sdio: Move all the RX code to a unified, IRQ based receive routine Inaky Perez-Gonzalez
` (5 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-06-11 21:35 UTC (permalink / raw)
To: netdev, wimax
When i2400m_bootrom_init() fails to put the device into a state of
being ready to accept firmware, the driver was currently trying to
reset it if it failed to do so. This is not too useful; as part of
trying to put the device in the right state a few resets have already
been tried.
At this point, things are probably fried out and an extra reset might
do more harm than good (for example causing reseting of other
functions in the same composite device).
So it is left up to the callers to determine the error path to take
(at the end this is always i2400m_setup(), who depending on how many
retries are left, might give up on the device).
>From a fix by Cindy H. Kao.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/fw.c | 3 +--
1 files changed, 1 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c
index 349344a..e81750e 100644
--- a/drivers/net/wimax/i2400m/fw.c
+++ b/drivers/net/wimax/i2400m/fw.c
@@ -696,8 +696,7 @@ error_dev_gone:
return result;
error_timeout:
- dev_err(dev, "Timed out waiting for reboot ack, resetting\n");
- i2400m->bus_reset(i2400m, I2400M_RT_BUS);
+ dev_err(dev, "Timed out waiting for reboot ack\n");
result = -ETIMEDOUT;
goto exit_timeout;
}
--
1.6.2.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [2.6.31 17/21] wimax/i2400m/sdio: Move all the RX code to a unified, IRQ based receive routine
2009-06-11 21:35 [2.6.31 00/21] WiMAX pull request Inaky Perez-Gonzalez
` (15 preceding siblings ...)
2009-06-11 21:35 ` [2.6.31 16/21] wimax/i2400m: don't reset device when bootrom init retries are exceeded Inaky Perez-Gonzalez
@ 2009-06-11 21:35 ` Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 18/21] wimax/i2400m: when bootstrap fails, reinitialize the bootrom Inaky Perez-Gonzalez
` (4 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-06-11 21:35 UTC (permalink / raw)
To: netdev, wimax; +Cc: Dirk Brandewie
The current SDIO code was working in polling mode for boot-mode
(firmware load) mode. This was causing issues on some hardware.
Moved all the RX code to use a unified IRQ handler that based on the
type of data the device is sending can discriminate and decide which
is the right destination.
As well, all the reads from the device are made to be at least the
block size (256); the driver will ignore the rest when not needed.
Signed-off-by: Dirk Brandewie <dirk.j.brandewie@intel.com>
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/i2400m-sdio.h | 7 ++
drivers/net/wimax/i2400m/sdio-fw.c | 109 ++++++++++++++------------------
drivers/net/wimax/i2400m/sdio-rx.c | 47 +++++++++++---
drivers/net/wimax/i2400m/sdio.c | 18 +++--
4 files changed, 101 insertions(+), 80 deletions(-)
diff --git a/drivers/net/wimax/i2400m/i2400m-sdio.h b/drivers/net/wimax/i2400m/i2400m-sdio.h
index 2071721..9c4e318 100644
--- a/drivers/net/wimax/i2400m/i2400m-sdio.h
+++ b/drivers/net/wimax/i2400m/i2400m-sdio.h
@@ -107,6 +107,10 @@ struct i2400ms {
char tx_wq_name[32];
struct dentry *debugfs_dentry;
+
+ wait_queue_head_t bm_wfa_wq;
+ int bm_wait_result;
+ size_t bm_ack_size;
};
@@ -131,4 +135,7 @@ extern ssize_t i2400ms_bus_bm_cmd_send(struct i2400m *,
extern ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *,
struct i2400m_bootrom_header *,
size_t);
+extern void i2400ms_bus_bm_release(struct i2400m *);
+extern int i2400ms_bus_bm_setup(struct i2400m *);
+
#endif /* #ifndef __I2400M_SDIO_H__ */
diff --git a/drivers/net/wimax/i2400m/sdio-fw.c b/drivers/net/wimax/i2400m/sdio-fw.c
index 3487205..7d6ec0f 100644
--- a/drivers/net/wimax/i2400m/sdio-fw.c
+++ b/drivers/net/wimax/i2400m/sdio-fw.c
@@ -46,17 +46,24 @@
* Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
* - SDIO rehash for changes in the bus-driver model
*
+ * Dirk Brandewie <dirk.j.brandewie@intel.com>
+ * - Make it IRQ based, not polling
+ *
* THE PROCEDURE
*
* See fw.c for the generic description of this procedure.
*
* This file implements only the SDIO specifics. It boils down to how
* to send a command and waiting for an acknowledgement from the
- * device. We do polled reads.
+ * device.
+ *
+ * All this code is sequential -- all i2400ms_bus_bm_*() functions are
+ * executed in the same thread, except i2400ms_bm_irq() [on its own by
+ * the SDIO driver]. This makes it possible to avoid locking.
*
* COMMAND EXECUTION
*
- * THe generic firmware upload code will call i2400m_bus_bm_cmd_send()
+ * The generic firmware upload code will call i2400m_bus_bm_cmd_send()
* to send commands.
*
* The SDIO devices expects things in 256 byte blocks, so it will pad
@@ -64,12 +71,15 @@
*
* ACK RECEPTION
*
- * This works in polling mode -- the fw loader says when to wait for
- * data and for that it calls i2400ms_bus_bm_wait_for_ack().
+ * This works in IRQ mode -- the fw loader says when to wait for data
+ * and for that it calls i2400ms_bus_bm_wait_for_ack().
*
- * This will poll the device for data until it is received. We need to
- * receive at least as much bytes as where asked for (although it'll
- * always be a multiple of 256 bytes).
+ * This checks if there is any data available (RX size > 0); if not,
+ * waits for the IRQ handler to notify about it. Once there is data,
+ * it is read and passed to the caller. Doing it this way we don't
+ * need much coordination/locking, and it makes it much more difficult
+ * for an interrupt to be lost and the wait_for_ack() function getting
+ * stuck even when data is pending.
*/
#include <linux/mmc/sdio_func.h>
#include "i2400m-sdio.h"
@@ -78,6 +88,7 @@
#define D_SUBMODULE fw
#include "sdio-debug-levels.h"
+
/*
* Send a boot-mode command to the SDIO function
*
@@ -139,7 +150,7 @@ error_too_big:
/*
- * Read an ack from the device's boot-mode (polling)
+ * Read an ack from the device's boot-mode
*
* @i2400m:
* @_ack: pointer to where to store the read data
@@ -150,75 +161,49 @@ error_too_big:
* The ACK for a BM command is always at least sizeof(*ack) bytes, so
* check for that. We don't need to check for device reboots
*
- * NOTE: We do an artificial timeout of 1 sec over the SDIO timeout;
- * this way we have control over it...there is no way that I know
- * of setting an SDIO transaction timeout.
*/
ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *i2400m,
struct i2400m_bootrom_header *ack,
size_t ack_size)
{
- int result;
- ssize_t rx_size;
- u64 timeout;
+ ssize_t result;
struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m);
struct sdio_func *func = i2400ms->func;
struct device *dev = &func->dev;
+ int size;
BUG_ON(sizeof(*ack) > ack_size);
d_fnstart(5, dev, "(i2400m %p ack %p size %zu)\n",
i2400m, ack, ack_size);
- timeout = get_jiffies_64() + 2 * HZ;
- sdio_claim_host(func);
- while (1) {
- if (time_after64(get_jiffies_64(), timeout)) {
- rx_size = -ETIMEDOUT;
- dev_err(dev, "timeout waiting for ack data\n");
- goto error_timedout;
- }
+ spin_lock(&i2400m->rx_lock);
+ i2400ms->bm_ack_size = -EINPROGRESS;
+ spin_unlock(&i2400m->rx_lock);
- /* Find the RX size, check if it fits or not -- it if
- * doesn't fit, fail, as we have no way to dispose of
- * the extra data. */
- rx_size = __i2400ms_rx_get_size(i2400ms);
- if (rx_size < 0)
- goto error_rx_get_size;
- result = -ENOSPC; /* Check it fits */
- if (rx_size < sizeof(*ack)) {
- rx_size = -EIO;
- dev_err(dev, "HW BUG? received is too small (%zu vs "
- "%zu needed)\n", sizeof(*ack), rx_size);
- goto error_too_small;
- }
- if (rx_size > I2400M_BM_ACK_BUF_SIZE) {
- dev_err(dev, "SW BUG? BM_ACK_BUF is too small (%u vs "
- "%zu needed)\n", I2400M_BM_ACK_BUF_SIZE,
- rx_size);
- goto error_too_small;
- }
+ result = wait_event_timeout(i2400ms->bm_wfa_wq,
+ i2400ms->bm_ack_size != -EINPROGRESS,
+ 2 * HZ);
+ if (result == 0) {
+ result = -ETIMEDOUT;
+ dev_err(dev, "BM: error waiting for an ack\n");
+ goto error_timeout;
+ }
- /* Read it */
- result = sdio_memcpy_fromio(func, i2400m->bm_ack_buf,
- I2400MS_DATA_ADDR, rx_size);
- if (result == -ETIMEDOUT || result == -ETIME)
- continue;
- if (result < 0) {
- dev_err(dev, "BM SDIO receive (%zu B) failed: %d\n",
- rx_size, result);
- goto error_read;
- } else
- break;
+ spin_lock(&i2400m->rx_lock);
+ result = i2400ms->bm_ack_size;
+ BUG_ON(result == -EINPROGRESS);
+ if (result < 0) /* so we exit when rx_release() is called */
+ dev_err(dev, "BM: %s failed: %zd\n", __func__, result);
+ else {
+ size = min(ack_size, i2400ms->bm_ack_size);
+ memcpy(ack, i2400m->bm_ack_buf, size);
}
- rx_size = min((ssize_t)ack_size, rx_size);
- memcpy(ack, i2400m->bm_ack_buf, rx_size);
-error_read:
-error_too_small:
-error_rx_get_size:
-error_timedout:
- sdio_release_host(func);
- d_fnend(5, dev, "(i2400m %p ack %p size %zu) = %ld\n",
- i2400m, ack, ack_size, (long) rx_size);
- return rx_size;
+ i2400ms->bm_ack_size = -EINPROGRESS;
+ spin_unlock(&i2400m->rx_lock);
+
+error_timeout:
+ d_fnend(5, dev, "(i2400m %p ack %p size %zu) = %zd\n",
+ i2400m, ack, ack_size, result);
+ return result;
}
diff --git a/drivers/net/wimax/i2400m/sdio-rx.c b/drivers/net/wimax/i2400m/sdio-rx.c
index a3008b9..321bead 100644
--- a/drivers/net/wimax/i2400m/sdio-rx.c
+++ b/drivers/net/wimax/i2400m/sdio-rx.c
@@ -69,6 +69,13 @@
#define D_SUBMODULE rx
#include "sdio-debug-levels.h"
+static const __le32 i2400m_ACK_BARKER[4] = {
+ __constant_cpu_to_le32(I2400M_ACK_BARKER),
+ __constant_cpu_to_le32(I2400M_ACK_BARKER),
+ __constant_cpu_to_le32(I2400M_ACK_BARKER),
+ __constant_cpu_to_le32(I2400M_ACK_BARKER)
+};
+
/*
* Read and return the amount of bytes available for RX
@@ -131,25 +138,35 @@ void i2400ms_rx(struct i2400ms *i2400ms)
ret = rx_size;
goto error_get_size;
}
+
ret = -ENOMEM;
skb = alloc_skb(rx_size, GFP_ATOMIC);
if (NULL == skb) {
dev_err(dev, "RX: unable to alloc skb\n");
goto error_alloc_skb;
}
-
ret = sdio_memcpy_fromio(func, skb->data,
I2400MS_DATA_ADDR, rx_size);
if (ret < 0) {
dev_err(dev, "RX: SDIO data read failed: %d\n", ret);
goto error_memcpy_fromio;
}
- /* Check if device has reset */
- if (!memcmp(skb->data, i2400m_NBOOT_BARKER,
- sizeof(i2400m_NBOOT_BARKER))
- || !memcmp(skb->data, i2400m_SBOOT_BARKER,
- sizeof(i2400m_SBOOT_BARKER))) {
+
+ rmb(); /* make sure we get boot_mode from dev_reset_handle */
+ if (i2400m->boot_mode == 1) {
+ spin_lock(&i2400m->rx_lock);
+ i2400ms->bm_ack_size = rx_size;
+ spin_unlock(&i2400m->rx_lock);
+ memcpy(i2400m->bm_ack_buf, skb->data, rx_size);
+ wake_up(&i2400ms->bm_wfa_wq);
+ dev_err(dev, "RX: SDIO boot mode message\n");
+ kfree_skb(skb);
+ } else if (unlikely(!memcmp(skb->data, i2400m_NBOOT_BARKER,
+ sizeof(i2400m_NBOOT_BARKER))
+ || !memcmp(skb->data, i2400m_SBOOT_BARKER,
+ sizeof(i2400m_SBOOT_BARKER)))) {
ret = i2400m_dev_reset_handle(i2400m);
+ dev_err(dev, "RX: SDIO reboot barker\n");
kfree_skb(skb);
} else {
skb_put(skb, rx_size);
@@ -179,7 +196,6 @@ void i2400ms_irq(struct sdio_func *func)
{
int ret;
struct i2400ms *i2400ms = sdio_get_drvdata(func);
- struct i2400m *i2400m = &i2400ms->i2400m;
struct device *dev = &func->dev;
int val;
@@ -194,10 +210,7 @@ void i2400ms_irq(struct sdio_func *func)
goto error_no_irq;
}
sdio_writeb(func, 1, I2400MS_INTR_CLEAR_ADDR, &ret);
- if (WARN_ON(i2400m->boot_mode != 0))
- dev_err(dev, "RX: SW BUG? boot mode and IRQ is up?\n");
- else
- i2400ms_rx(i2400ms);
+ i2400ms_rx(i2400ms);
error_no_irq:
d_fnend(6, dev, "(i2400ms %p) = void\n", i2400ms);
return;
@@ -214,8 +227,15 @@ int i2400ms_rx_setup(struct i2400ms *i2400ms)
int result;
struct sdio_func *func = i2400ms->func;
struct device *dev = &func->dev;
+ struct i2400m *i2400m = &i2400ms->i2400m;
d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms);
+
+ init_waitqueue_head(&i2400ms->bm_wfa_wq);
+ spin_lock(&i2400m->rx_lock);
+ i2400ms->bm_wait_result = -EINPROGRESS;
+ spin_unlock(&i2400m->rx_lock);
+
sdio_claim_host(func);
result = sdio_claim_irq(func, i2400ms_irq);
if (result < 0) {
@@ -245,8 +265,13 @@ void i2400ms_rx_release(struct i2400ms *i2400ms)
int result;
struct sdio_func *func = i2400ms->func;
struct device *dev = &func->dev;
+ struct i2400m *i2400m = &i2400ms->i2400m;
d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms);
+ spin_lock(&i2400m->rx_lock);
+ i2400ms->bm_ack_size = -EINTR;
+ spin_unlock(&i2400m->rx_lock);
+ wake_up_all(&i2400ms->bm_wfa_wq);
sdio_claim_host(func);
sdio_writeb(func, 0, I2400MS_INTR_ENABLE_ADDR, &result);
sdio_release_irq(func);
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c
index 74de174..2538825 100644
--- a/drivers/net/wimax/i2400m/sdio.c
+++ b/drivers/net/wimax/i2400m/sdio.c
@@ -156,19 +156,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 +177,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);
}
@@ -296,6 +290,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);
@@ -304,6 +299,8 @@ do_bus_reset:
msleep(40);
result = i2400ms_enable_function(i2400ms->func);
+ if (result >= 0)
+ i2400ms_rx_setup(i2400ms);
} else
BUG();
if (result < 0 && rt != I2400M_RT_BUS) {
@@ -449,6 +446,10 @@ int i2400ms_probe(struct sdio_func *func,
goto error_func_enable;
}
+ 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 +467,8 @@ int i2400ms_probe(struct sdio_func *func,
error_debugfs_add:
i2400m_release(i2400m);
error_setup:
+ i2400ms_rx_release(i2400ms);
+error_rx_setup:
sdio_claim_host(func);
sdio_disable_func(func);
sdio_release_host(func);
@@ -488,6 +491,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);
--
1.6.2.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [2.6.31 18/21] wimax/i2400m: when bootstrap fails, reinitialize the bootrom
2009-06-11 21:35 [2.6.31 00/21] WiMAX pull request Inaky Perez-Gonzalez
` (16 preceding siblings ...)
2009-06-11 21:35 ` [2.6.31 17/21] wimax/i2400m/sdio: Move all the RX code to a unified, IRQ based receive routine Inaky Perez-Gonzalez
@ 2009-06-11 21:35 ` Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 19/21] wimax/i2400m: use -EL3RST to indicate device reset instead of -ERESTARTSYS Inaky Perez-Gonzalez
` (3 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-06-11 21:35 UTC (permalink / raw)
To: netdev, wimax; +Cc: Cindy H Kao
From: Cindy H Kao <cindy.h.kao@intel.com>
When a device reset happens during firmware load [in
i2400m_dev_bootstrap()], __i2400m_dev_start() will retry a number of
times. However, for those retries to be able to accomplish anything,
the device's bootrom has to be reinitialized.
Thus, on the retry path, pass the I2400M_MAC_REINIT to the firmware
load code.
Signed-off-by: Cindy H Kao <cindy.h.kao@intel.com>
---
drivers/net/wimax/i2400m/driver.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
index 8d8628e..2a093c5 100644
--- a/drivers/net/wimax/i2400m/driver.c
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -454,7 +454,7 @@ error_rx_setup:
error_tx_setup:
error_bootstrap:
if (result == -ERESTARTSYS && times-- > 0) {
- flags = I2400M_BRI_SOFT;
+ flags = I2400M_BRI_SOFT|I2400M_BRI_MAC_REINIT;
goto retry;
}
d_fnend(3, dev, "(net_dev %p [i2400m %p]) = %d\n",
--
1.6.2.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [2.6.31 19/21] wimax/i2400m: use -EL3RST to indicate device reset instead of -ERESTARTSYS
2009-06-11 21:35 [2.6.31 00/21] WiMAX pull request Inaky Perez-Gonzalez
` (17 preceding siblings ...)
2009-06-11 21:35 ` [2.6.31 18/21] wimax/i2400m: when bootstrap fails, reinitialize the bootrom Inaky Perez-Gonzalez
@ 2009-06-11 21:35 ` Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 20/21] wimax: fix warning caused by not checking retval of rfkill_set_hw_state() Inaky Perez-Gonzalez
` (2 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-06-11 21:35 UTC (permalink / raw)
To: netdev, wimax; +Cc: Cindy H Kao
From: Cindy H Kao <cindy.h.kao@intel.com>
When the i2400m device resets, the driver code will force some
functions to return a -ERESTARTSYS error code, which can is used by
the caller to determine which recovery actions to take.
However, in certain situations the only thing that can be done is to
bubble up said error code to user space, for handling.
However, -ERESTARSYS was a poor choice, as it is supposed to be used
by the kernel only.
As such, replace -ERESTARTSYS with -EL3RST; as well, in
i2400m_msg_to_dev(), when the device is in boot mode (following a
recent reset), return -EL3RST instead of -ENODEV (meaning the device
is in bootrom mode after a reset, not that the device was
disconnected, and thus, normal commands cannot be executed).
Signed-off-by: Cindy H Kao <cindy.h.kao@intel.com>
---
drivers/net/wimax/i2400m/control.c | 2 +-
drivers/net/wimax/i2400m/driver.c | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c
index f9399f2..0730868 100644
--- a/drivers/net/wimax/i2400m/control.c
+++ b/drivers/net/wimax/i2400m/control.c
@@ -697,7 +697,7 @@ struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m,
rmb(); /* Make sure we see what i2400m_dev_reset_handle() */
if (i2400m->boot_mode)
- return ERR_PTR(-ENODEV);
+ return ERR_PTR(-EL3RST);
msg_l3l4_hdr = buf;
/* Check msg & payload consistency */
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
index 2a093c5..304f044 100644
--- a/drivers/net/wimax/i2400m/driver.c
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -453,7 +453,7 @@ error_rx_setup:
i2400m_tx_release(i2400m);
error_tx_setup:
error_bootstrap:
- if (result == -ERESTARTSYS && times-- > 0) {
+ if (result == -EL3RST && times-- > 0) {
flags = I2400M_BRI_SOFT|I2400M_BRI_MAC_REINIT;
goto retry;
}
@@ -560,7 +560,7 @@ void __i2400m_dev_reset_handle(struct work_struct *ws)
* i2400m_dev_stop() [we are shutting down anyway, so
* ignore it] or we are resetting somewhere else. */
dev_err(dev, "device rebooted\n");
- i2400m_msg_to_dev_cancel_wait(i2400m, -ERESTARTSYS);
+ i2400m_msg_to_dev_cancel_wait(i2400m, -EL3RST);
complete(&i2400m->msg_completion);
goto out;
}
--
1.6.2.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [2.6.31 20/21] wimax: fix warning caused by not checking retval of rfkill_set_hw_state()
2009-06-11 21:35 [2.6.31 00/21] WiMAX pull request Inaky Perez-Gonzalez
` (18 preceding siblings ...)
2009-06-11 21:35 ` [2.6.31 19/21] wimax/i2400m: use -EL3RST to indicate device reset instead of -ERESTARTSYS Inaky Perez-Gonzalez
@ 2009-06-11 21:35 ` Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 21/21] wimax: fix gcc warnings in sh4 when calling BUG() Inaky Perez-Gonzalez
2009-06-12 0:20 ` [2.6.31 00/21] WiMAX pull request David Miller
21 siblings, 0 replies; 23+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-06-11 21:35 UTC (permalink / raw)
To: netdev, wimax
Caused by an API update. The return value can be safely ignored, as
there is notthing we can do with it.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
net/wimax/op-rfkill.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/net/wimax/op-rfkill.c b/net/wimax/op-rfkill.c
index bb102e4..70ef4df 100644
--- a/net/wimax/op-rfkill.c
+++ b/net/wimax/op-rfkill.c
@@ -113,7 +113,8 @@ void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev,
else
wimax_state = WIMAX_ST_RADIO_OFF;
- rfkill_set_hw_state(wimax_dev->rfkill, state == WIMAX_RF_OFF);
+ result = rfkill_set_hw_state(wimax_dev->rfkill,
+ state == WIMAX_RF_OFF);
__wimax_state_change(wimax_dev, wimax_state);
}
--
1.6.2.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [2.6.31 21/21] wimax: fix gcc warnings in sh4 when calling BUG()
2009-06-11 21:35 [2.6.31 00/21] WiMAX pull request Inaky Perez-Gonzalez
` (19 preceding siblings ...)
2009-06-11 21:35 ` [2.6.31 20/21] wimax: fix warning caused by not checking retval of rfkill_set_hw_state() Inaky Perez-Gonzalez
@ 2009-06-11 21:35 ` Inaky Perez-Gonzalez
2009-06-12 0:20 ` [2.6.31 00/21] WiMAX pull request David Miller
21 siblings, 0 replies; 23+ messages in thread
From: Inaky Perez-Gonzalez @ 2009-06-11 21:35 UTC (permalink / raw)
To: netdev, wimax
SH4's BUG() seems to confuse the compiler as it is considered to
return; thus, some functions would trigger usage of uninitialized
variables or non-void functions returning void.
Work around by initializing/returning.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/op-rfkill.c | 4 +++-
drivers/net/wimax/i2400m/usb.c | 4 +++-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wimax/i2400m/op-rfkill.c b/drivers/net/wimax/i2400m/op-rfkill.c
index 487ec58..43927b5 100644
--- a/drivers/net/wimax/i2400m/op-rfkill.c
+++ b/drivers/net/wimax/i2400m/op-rfkill.c
@@ -54,8 +54,10 @@ int i2400m_radio_is(struct i2400m *i2400m, enum wimax_rf_state state)
/* state == WIMAX_RF_ON */
return i2400m->state != I2400M_SS_RF_OFF
&& i2400m->state != I2400M_SS_RF_SHUTDOWN;
- else
+ else {
BUG();
+ return -EINVAL; /* shut gcc warnings on certain arches */
+ }
}
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c
index ebc05da..cfdaf69 100644
--- a/drivers/net/wimax/i2400m/usb.c
+++ b/drivers/net/wimax/i2400m/usb.c
@@ -254,8 +254,10 @@ do_bus_reset:
dev_err(dev, "USB reset failed (%d), giving up!\n",
result);
}
- } else
+ } else {
+ result = -EINVAL; /* shut gcc up in certain arches */
BUG();
+ }
if (result < 0
&& result != -EINVAL /* device is gone */
&& rt != I2400M_RT_BUS) {
--
1.6.2.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [2.6.31 00/21] WiMAX pull request
2009-06-11 21:35 [2.6.31 00/21] WiMAX pull request Inaky Perez-Gonzalez
` (20 preceding siblings ...)
2009-06-11 21:35 ` [2.6.31 21/21] wimax: fix gcc warnings in sh4 when calling BUG() Inaky Perez-Gonzalez
@ 2009-06-12 0:20 ` David Miller
21 siblings, 0 replies; 23+ messages in thread
From: David Miller @ 2009-06-12 0:20 UTC (permalink / raw)
To: inaky; +Cc: netdev, wimax
From: Inaky Perez-Gonzalez <inaky@linux.intel.com>
Date: Thu, 11 Jun 2009 14:35:37 -0700
> This pull requests contains a long set of fixes to bugs and issues
> found while debugging the SDIO version of the i2400m WiMAX
> device. Most of them are in the generic part of the i2400m, and thus,
> apply to both the USB and SDIO versions:
...
> git://git.kernel.org/pub/scm/linux/kernel/git/inaky/wimax.git linux-2.6.31.y
Pulled, thanks a lot.
^ permalink raw reply [flat|nested] 23+ messages in thread
end of thread, other threads:[~2009-06-12 0:20 UTC | newest]
Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-06-11 21:35 [2.6.31 00/21] WiMAX pull request Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 01/21] wimax/i2400m: introduce module parameter to disable entering power save Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 02/21] wimax/i2400m: don't call netif_start_queue() in _tx_msg_sent() Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 03/21] wimax/i2400m: i2400m's work queue should be initialized before RX support Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 04/21] wimax/i2400m: i2400m_schedule_work() doesn't need i2400m->work_queue Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 05/21] wimax/i2400m: Change d_printf() level for secure boot messages Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 06/21] wimax/i2400m/sdio: Implement I2400M_RT_BUS reset type Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 07/21] wimax/i2400m: rename misleading I2400M_PL_PAD to I2400M_PL_ALIGN Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 08/21] wimax/i2400m: fix panic/warnings caused by missed check on empty TX message Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 09/21] wimax/i2400m: fix panic due to missed corner cases on tail_room calculation Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 10/21] wimax/i2400m: don't reset device on i2400m_dev_shutdown() Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 11/21] wimax/i2400m: fix oops when the TX FIFO fills up due to a missing check Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 12/21] wimax/i2400m: if a device reboot happens during probe, handle it Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 13/21] wimax/i2400m: Allow bus-specific driver to specify retry count Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 14/21] wimax/i2400m: move boot time poke table out of common driver Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 15/21] wimax/i2400m/sdio: Add device specific poke table Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 16/21] wimax/i2400m: don't reset device when bootrom init retries are exceeded Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 17/21] wimax/i2400m/sdio: Move all the RX code to a unified, IRQ based receive routine Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 18/21] wimax/i2400m: when bootstrap fails, reinitialize the bootrom Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 19/21] wimax/i2400m: use -EL3RST to indicate device reset instead of -ERESTARTSYS Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 20/21] wimax: fix warning caused by not checking retval of rfkill_set_hw_state() Inaky Perez-Gonzalez
2009-06-11 21:35 ` [2.6.31 21/21] wimax: fix gcc warnings in sh4 when calling BUG() Inaky Perez-Gonzalez
2009-06-12 0:20 ` [2.6.31 00/21] WiMAX pull request David Miller
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).