Commit 70458259 authored by Andrey Borzenkov's avatar Andrey Borzenkov Committed by John W. Linville

orinoco: reduce stack usage in firmware download path

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.

Tested-By: Andrey Borzenkov <arvidjaar@mail.ru> for Agere case

Signed-off-by: Andrey Borzenkov < arvidjaar@mail.ru>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 8bdd5b9c
...@@ -433,7 +433,7 @@ struct fw_info { ...@@ -433,7 +433,7 @@ struct fw_info {
const static struct fw_info orinoco_fw[] = { const static struct fw_info orinoco_fw[] = {
{ "", "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 }, { "", "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 },
{ "", "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 }, { "", "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 },
{ "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", "", 0x00003100, 0x100 } { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", "", 0x00003100, 512 }
}; };
/* Structure used to access fields in FW /* Structure used to access fields in FW
...@@ -458,7 +458,7 @@ orinoco_dl_firmware(struct orinoco_private *priv, ...@@ -458,7 +458,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
int ap) int ap)
{ {
/* Plug Data Area (PDA) */ /* Plug Data Area (PDA) */
__le16 pda[512] = { 0 }; __le16 *pda;
hermes_t *hw = &priv->hw; hermes_t *hw = &priv->hw;
const struct firmware *fw_entry; const struct firmware *fw_entry;
...@@ -467,7 +467,11 @@ orinoco_dl_firmware(struct orinoco_private *priv, ...@@ -467,7 +467,11 @@ orinoco_dl_firmware(struct orinoco_private *priv,
const unsigned char *end; const unsigned char *end;
const char *firmware; const char *firmware;
struct net_device *dev = priv->ndev; struct net_device *dev = priv->ndev;
int err; int err = 0;
pda = kzalloc(fw->pda_size, GFP_KERNEL);
if (!pda)
return -ENOMEM;
if (ap) if (ap)
firmware = fw->ap_fw; firmware = fw->ap_fw;
...@@ -478,17 +482,17 @@ orinoco_dl_firmware(struct orinoco_private *priv, ...@@ -478,17 +482,17 @@ orinoco_dl_firmware(struct orinoco_private *priv,
dev->name, firmware); dev->name, firmware);
/* Read current plug data */ /* Read current plug data */
err = hermes_read_pda(hw, pda, fw->pda_addr, err = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 0);
min_t(u16, fw->pda_size, sizeof(pda)), 0);
printk(KERN_DEBUG "%s: Read PDA returned %d\n", dev->name, err); printk(KERN_DEBUG "%s: Read PDA returned %d\n", dev->name, err);
if (err) if (err)
return err; goto free;
err = request_firmware(&fw_entry, firmware, priv->dev); err = request_firmware(&fw_entry, firmware, priv->dev);
if (err) { if (err) {
printk(KERN_ERR "%s: Cannot find firmware %s\n", printk(KERN_ERR "%s: Cannot find firmware %s\n",
dev->name, firmware); dev->name, firmware);
return -ENOENT; err = -ENOENT;
goto free;
} }
hdr = (const struct orinoco_fw_header *) fw_entry->data; hdr = (const struct orinoco_fw_header *) fw_entry->data;
...@@ -532,6 +536,9 @@ orinoco_dl_firmware(struct orinoco_private *priv, ...@@ -532,6 +536,9 @@ orinoco_dl_firmware(struct orinoco_private *priv,
abort: abort:
release_firmware(fw_entry); release_firmware(fw_entry);
free:
kfree(pda);
return err; return err;
} }
...@@ -549,12 +556,12 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, ...@@ -549,12 +556,12 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw,
int secondary) int secondary)
{ {
hermes_t *hw = &priv->hw; hermes_t *hw = &priv->hw;
int ret; int ret = 0;
const unsigned char *ptr; const unsigned char *ptr;
const unsigned char *first_block; const unsigned char *first_block;
/* Plug Data Area (PDA) */ /* Plug Data Area (PDA) */
__le16 pda[256]; __le16 *pda = NULL;
/* Binary block begins after the 0x1A marker */ /* Binary block begins after the 0x1A marker */
ptr = image; ptr = image;
...@@ -563,28 +570,33 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, ...@@ -563,28 +570,33 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw,
/* Read the PDA from EEPROM */ /* Read the PDA from EEPROM */
if (secondary) { if (secondary) {
ret = hermes_read_pda(hw, pda, fw->pda_addr, sizeof(pda), 1); pda = kzalloc(fw->pda_size, GFP_KERNEL);
if (!pda)
return -ENOMEM;
ret = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 1);
if (ret) if (ret)
return ret; goto free;
} }
/* Stop the firmware, so that it can be safely rewritten */ /* Stop the firmware, so that it can be safely rewritten */
if (priv->stop_fw) { if (priv->stop_fw) {
ret = priv->stop_fw(priv, 1); ret = priv->stop_fw(priv, 1);
if (ret) if (ret)
return ret; goto free;
} }
/* Program the adapter with new firmware */ /* Program the adapter with new firmware */
ret = hermes_program(hw, first_block, end); ret = hermes_program(hw, first_block, end);
if (ret) if (ret)
return ret; goto free;
/* Write the PDA to the adapter */ /* Write the PDA to the adapter */
if (secondary) { if (secondary) {
size_t len = hermes_blocks_length(first_block); size_t len = hermes_blocks_length(first_block);
ptr = first_block + len; ptr = first_block + len;
ret = hermes_apply_pda(hw, ptr, pda); ret = hermes_apply_pda(hw, ptr, pda);
kfree(pda);
if (ret) if (ret)
return ret; return ret;
} }
...@@ -608,6 +620,10 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, ...@@ -608,6 +620,10 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw,
return -ENODEV; return -ENODEV;
return 0; return 0;
free:
kfree(pda);
return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment