mirror of
https://github.com/torvalds/linux.git
synced 2024-11-17 01:22:07 +00:00
[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: Peter Jones <pjones@redhat.com> Signed-off-by: Ben M Cahill <ben.m.cahill@intel.com> Signed-off-by: Zhu Yi <yi.zhu@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
4bfdb91dcf
commit
397ae121ee
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user