提交 397ae121 编写于 作者: Z Zhu Yi 提交者: John W. Linville

[PATCH] ipw2200: Scale firmware loading watchdog with the firmware size

I can't really help with why restarts happen, but the following patch
greatly increases the likelihood that a firmware reload will succeed
afterward on my thinkpad. It addresses two issues. First, sysfs module
loading and hotplug are asynchronous, and as such file operations on the
"loading" and "data" files are racy when you load 2 firmwares in quick
succession. Second, the timeout for DMAing the firmware needs to scale
with the size of the firmware being loaded. That is, the watchdog needs
to be on throughput, not on time alone.

I no longer get the firmware load errors, though this is at best a hacky
workaround for a racy interface. (Obviously, this does nothing to address
the fatal errors in firmware which cause reloads; it just causes the
initial loading and the reloads to work more often.)
Signed-off-by: NPeter Jones <pjones@redhat.com>
Signed-off-by: NBen M Cahill <ben.m.cahill@intel.com>
Signed-off-by: NZhu Yi <yi.zhu@intel.com>
Signed-off-by: NJohn W. Linville <linville@tuxdriver.com>
上级 4bfdb91d
......@@ -2772,22 +2772,25 @@ static int ipw_fw_dma_add_buffer(struct ipw_priv *priv,
static int ipw_fw_dma_wait(struct ipw_priv *priv)
{
u32 current_index = 0;
u32 current_index = 0, previous_index;
u32 watchdog = 0;
IPW_DEBUG_FW(">> : \n");
current_index = ipw_fw_dma_command_block_index(priv);
IPW_DEBUG_FW_INFO("sram_desc.last_cb_index:0x%8X\n",
IPW_DEBUG_FW_INFO("sram_desc.last_cb_index:0x%08X\n",
(int)priv->sram_desc.last_cb_index);
while (current_index < priv->sram_desc.last_cb_index) {
udelay(50);
previous_index = current_index;
current_index = ipw_fw_dma_command_block_index(priv);
watchdog++;
if (watchdog > 400) {
if (previous_index < current_index) {
watchdog = 0;
continue;
}
if (++watchdog > 400) {
IPW_DEBUG_FW_INFO("Timeout\n");
ipw_fw_dma_dump_command_block(priv);
ipw_fw_dma_abort(priv);
......@@ -3276,55 +3279,31 @@ static int ipw_load(struct ipw_priv *priv)
const struct firmware *firmware = NULL;
const struct firmware *ucode = NULL;
#endif
char *ucode_name;
char *fw_name;
int rc = 0, retries = 3;
#ifdef CONFIG_PM
if (!fw_loaded) {
#endif
rc = ipw_get_fw(priv, &bootfw, IPW_FW_NAME("boot"));
if (rc)
goto error;
switch (priv->ieee->iw_mode) {
case IW_MODE_ADHOC:
rc = ipw_get_fw(priv, &ucode,
IPW_FW_NAME("ibss_ucode"));
if (rc)
goto error;
rc = ipw_get_fw(priv, &firmware, IPW_FW_NAME("ibss"));
break;
switch (priv->ieee->iw_mode) {
case IW_MODE_ADHOC:
ucode_name = IPW_FW_NAME("ibss_ucode");
fw_name = IPW_FW_NAME("ibss");
break;
#ifdef CONFIG_IPW2200_MONITOR
case IW_MODE_MONITOR:
rc = ipw_get_fw(priv, &ucode,
IPW_FW_NAME("sniffer_ucode"));
if (rc)
goto error;
rc = ipw_get_fw(priv, &firmware,
IPW_FW_NAME("sniffer"));
break;
case IW_MODE_MONITOR:
ucode_name = IPW_FW_NAME("sniffer_ucode");
fw_name = IPW_FW_NAME("sniffer");
break;
#endif
case IW_MODE_INFRA:
rc = ipw_get_fw(priv, &ucode, IPW_FW_NAME("bss_ucode"));
if (rc)
goto error;
rc = ipw_get_fw(priv, &firmware, IPW_FW_NAME("bss"));
break;
default:
rc = -EINVAL;
}
if (rc)
goto error;
#ifdef CONFIG_PM
fw_loaded = 1;
case IW_MODE_INFRA:
ucode_name = IPW_FW_NAME("bss_ucode");
fw_name = IPW_FW_NAME("bss");
break;
default:
rc = -EINVAL;
}
#endif
if (rc < 0)
goto error;
if (!priv->rxq)
priv->rxq = ipw_rx_queue_alloc(priv);
......@@ -3346,7 +3325,7 @@ static int ipw_load(struct ipw_priv *priv)
ipw_stop_nic(priv);
rc = ipw_reset_nic(priv);
if (rc) {
if (rc < 0) {
IPW_ERROR("Unable to reset NIC\n");
goto error;
}
......@@ -3354,6 +3333,15 @@ static int ipw_load(struct ipw_priv *priv)
ipw_zero_memory(priv, IPW_NIC_SRAM_LOWER_BOUND,
IPW_NIC_SRAM_UPPER_BOUND - IPW_NIC_SRAM_LOWER_BOUND);
#ifdef CONFIG_PM
if (!fw_loaded) {
#endif
rc = ipw_get_fw(priv, &bootfw, IPW_FW_NAME("boot"));
if (rc < 0)
goto error;
#ifdef CONFIG_PM
}
#endif
/* DMA the initial boot firmware into the device */
rc = ipw_load_firmware(priv, bootfw->data + sizeof(struct fw_header),
bootfw->size - sizeof(struct fw_header));
......@@ -3377,6 +3365,16 @@ static int ipw_load(struct ipw_priv *priv)
/* ack fw init done interrupt */
ipw_write32(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE);
#ifdef CONFIG_PM
if (!fw_loaded) {
#endif
rc = ipw_get_fw(priv, &ucode, ucode_name);
if (rc < 0)
goto error;
#ifdef CONFIG_PM
}
#endif
/* DMA the ucode into the device */
rc = ipw_load_ucode(priv, ucode->data + sizeof(struct fw_header),
ucode->size - sizeof(struct fw_header));
......@@ -3388,6 +3386,16 @@ static int ipw_load(struct ipw_priv *priv)
/* stop nic */
ipw_stop_nic(priv);
#ifdef CONFIG_PM
if (!fw_loaded) {
#endif
rc = ipw_get_fw(priv, &firmware, fw_name);
if (rc < 0)
goto error;
#ifdef CONFIG_PM
}
#endif
/* DMA bss firmware into the device */
rc = ipw_load_firmware(priv, firmware->data +
sizeof(struct fw_header),
......@@ -3397,10 +3405,14 @@ static int ipw_load(struct ipw_priv *priv)
goto error;
}
#ifdef CONFIG_PM
fw_loaded = 1;
#endif
ipw_write32(priv, IPW_EEPROM_LOAD_DISABLE, 0);
rc = ipw_queue_reset(priv);
if (rc) {
if (rc < 0) {
IPW_ERROR("Unable to initialize queues\n");
goto error;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册