Subject: [PATCH] orinoco: reduce stack usage in firmware download path From: Andrey Borzenkov orinoco_dl_firmware and symbol_dl_mage allocate large local variables (1K); at least orinoco fails with panic or hung kernel if 4K stacks is enabled. Allocate large buffers dynamically at run time. Signed-off-by: Andrey Borzenkov --- drivers/net/wireless/orinoco.c | 50 ++++++++++++++++++++++++++-------------- 1 files changed, 32 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 9a2fcc0..2b87d0b 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -458,7 +458,7 @@ orinoco_dl_firmware(struct orinoco_private *priv, int ap) { /* Plug Data Area (PDA) */ - __le16 pda[512] = { 0 }; + __le16 *pda; hermes_t *hw = &priv->hw; const struct firmware *fw_entry; @@ -467,7 +467,11 @@ orinoco_dl_firmware(struct orinoco_private *priv, const unsigned char *end; const char *firmware; struct net_device *dev = priv->ndev; - int err; + int err = 0; + + pda = kzalloc(fw->pda_size, GFP_KERNEL); + if (!pda) + return -ENOMEM; if (ap) firmware = fw->ap_fw; @@ -478,17 +482,17 @@ orinoco_dl_firmware(struct orinoco_private *priv, dev->name, firmware); /* Read current plug data */ - err = hermes_read_pda(hw, pda, fw->pda_addr, - min_t(u16, fw->pda_size, sizeof(pda)), 0); + err = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 0); printk(KERN_DEBUG "%s: Read PDA returned %d\n", dev->name, err); if (err) - return err; + goto free; err = request_firmware(&fw_entry, firmware, priv->dev); if (err) { printk(KERN_ERR "%s: Cannot find firmware %s\n", dev->name, firmware); - return -ENOENT; + err = -ENOENT; + goto free; } hdr = (const struct orinoco_fw_header *) fw_entry->data; @@ -532,6 +536,9 @@ orinoco_dl_firmware(struct orinoco_private *priv, abort: release_firmware(fw_entry); + +free: + kfree(pda); return err; } @@ -549,12 +556,16 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, int secondary) { hermes_t *hw = &priv->hw; - int ret; + int ret = 0; const unsigned char *ptr; const unsigned char *first_block; /* Plug Data Area (PDA) */ - __le16 pda[256]; + __le16 *pda; + + pda = kzalloc(fw->pda_size, GFP_KERNEL); + if (!pda) + return -ENOMEM; /* Binary block begins after the 0x1A marker */ ptr = image; @@ -563,22 +574,22 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, /* Read the PDA from EEPROM */ if (secondary) { - ret = hermes_read_pda(hw, pda, fw->pda_addr, sizeof(pda), 1); + ret = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 1); if (ret) - return ret; + goto free; } /* Stop the firmware, so that it can be safely rewritten */ if (priv->stop_fw) { ret = priv->stop_fw(priv, 1); if (ret) - return ret; + goto free; } /* Program the adapter with new firmware */ ret = hermes_program(hw, first_block, end); if (ret) - return ret; + goto free; /* Write the PDA to the adapter */ if (secondary) { @@ -586,28 +597,31 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, ptr = first_block + len; ret = hermes_apply_pda(hw, ptr, pda); if (ret) - return ret; + goto free; } /* Run the firmware */ if (priv->stop_fw) { ret = priv->stop_fw(priv, 0); if (ret) - return ret; + goto free; } /* Reset hermes chip and make sure it responds */ ret = hermes_init(hw); /* hermes_reset() should return 0 with the secondary firmware */ - if (secondary && ret != 0) - return -ENODEV; + if (secondary && ret != 0) { + ret = -ENODEV; + goto free; + } /* And this should work with any firmware */ if (!hermes_present(hw)) - return -ENODEV; + ret = -ENODEV; - return 0; +free: + return ret; }