diff options
author | Andrey Borzenkov <arvidjaar@newmail.ru> | 2008-10-10 13:26:30 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-10-22 18:09:32 -0400 |
commit | 70458259936e723a4ac02c85bdbaf08dc69edfbe (patch) | |
tree | 0a39aff47887da2f3506430a4cb6799aa290d320 | |
parent | 8bdd5b9c6bd53add260756b6673a0545fbdbba21 (diff) |
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: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/orinoco.c | 42 |
1 files changed, 29 insertions, 13 deletions
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 50904771f291..e0512e49d6d3 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c | |||
@@ -433,7 +433,7 @@ struct fw_info { | |||
433 | const static struct fw_info orinoco_fw[] = { | 433 | const static struct fw_info orinoco_fw[] = { |
434 | { "", "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 }, | 434 | { "", "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 }, |
435 | { "", "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 }, | 435 | { "", "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 }, |
436 | { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", "", 0x00003100, 0x100 } | 436 | { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", "", 0x00003100, 512 } |
437 | }; | 437 | }; |
438 | 438 | ||
439 | /* Structure used to access fields in FW | 439 | /* Structure used to access fields in FW |
@@ -458,7 +458,7 @@ orinoco_dl_firmware(struct orinoco_private *priv, | |||
458 | int ap) | 458 | int ap) |
459 | { | 459 | { |
460 | /* Plug Data Area (PDA) */ | 460 | /* Plug Data Area (PDA) */ |
461 | __le16 pda[512] = { 0 }; | 461 | __le16 *pda; |
462 | 462 | ||
463 | hermes_t *hw = &priv->hw; | 463 | hermes_t *hw = &priv->hw; |
464 | const struct firmware *fw_entry; | 464 | const struct firmware *fw_entry; |
@@ -467,7 +467,11 @@ orinoco_dl_firmware(struct orinoco_private *priv, | |||
467 | const unsigned char *end; | 467 | const unsigned char *end; |
468 | const char *firmware; | 468 | const char *firmware; |
469 | struct net_device *dev = priv->ndev; | 469 | struct net_device *dev = priv->ndev; |
470 | int err; | 470 | int err = 0; |
471 | |||
472 | pda = kzalloc(fw->pda_size, GFP_KERNEL); | ||
473 | if (!pda) | ||
474 | return -ENOMEM; | ||
471 | 475 | ||
472 | if (ap) | 476 | if (ap) |
473 | firmware = fw->ap_fw; | 477 | firmware = fw->ap_fw; |
@@ -478,17 +482,17 @@ orinoco_dl_firmware(struct orinoco_private *priv, | |||
478 | dev->name, firmware); | 482 | dev->name, firmware); |
479 | 483 | ||
480 | /* Read current plug data */ | 484 | /* Read current plug data */ |
481 | err = hermes_read_pda(hw, pda, fw->pda_addr, | 485 | err = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 0); |
482 | min_t(u16, fw->pda_size, sizeof(pda)), 0); | ||
483 | printk(KERN_DEBUG "%s: Read PDA returned %d\n", dev->name, err); | 486 | printk(KERN_DEBUG "%s: Read PDA returned %d\n", dev->name, err); |
484 | if (err) | 487 | if (err) |
485 | return err; | 488 | goto free; |
486 | 489 | ||
487 | err = request_firmware(&fw_entry, firmware, priv->dev); | 490 | err = request_firmware(&fw_entry, firmware, priv->dev); |
488 | if (err) { | 491 | if (err) { |
489 | printk(KERN_ERR "%s: Cannot find firmware %s\n", | 492 | printk(KERN_ERR "%s: Cannot find firmware %s\n", |
490 | dev->name, firmware); | 493 | dev->name, firmware); |
491 | return -ENOENT; | 494 | err = -ENOENT; |
495 | goto free; | ||
492 | } | 496 | } |
493 | 497 | ||
494 | hdr = (const struct orinoco_fw_header *) fw_entry->data; | 498 | hdr = (const struct orinoco_fw_header *) fw_entry->data; |
@@ -532,6 +536,9 @@ orinoco_dl_firmware(struct orinoco_private *priv, | |||
532 | 536 | ||
533 | abort: | 537 | abort: |
534 | release_firmware(fw_entry); | 538 | release_firmware(fw_entry); |
539 | |||
540 | free: | ||
541 | kfree(pda); | ||
535 | return err; | 542 | return err; |
536 | } | 543 | } |
537 | 544 | ||
@@ -549,12 +556,12 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, | |||
549 | int secondary) | 556 | int secondary) |
550 | { | 557 | { |
551 | hermes_t *hw = &priv->hw; | 558 | hermes_t *hw = &priv->hw; |
552 | int ret; | 559 | int ret = 0; |
553 | const unsigned char *ptr; | 560 | const unsigned char *ptr; |
554 | const unsigned char *first_block; | 561 | const unsigned char *first_block; |
555 | 562 | ||
556 | /* Plug Data Area (PDA) */ | 563 | /* Plug Data Area (PDA) */ |
557 | __le16 pda[256]; | 564 | __le16 *pda = NULL; |
558 | 565 | ||
559 | /* Binary block begins after the 0x1A marker */ | 566 | /* Binary block begins after the 0x1A marker */ |
560 | ptr = image; | 567 | ptr = image; |
@@ -563,28 +570,33 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, | |||
563 | 570 | ||
564 | /* Read the PDA from EEPROM */ | 571 | /* Read the PDA from EEPROM */ |
565 | if (secondary) { | 572 | if (secondary) { |
566 | ret = hermes_read_pda(hw, pda, fw->pda_addr, sizeof(pda), 1); | 573 | pda = kzalloc(fw->pda_size, GFP_KERNEL); |
574 | if (!pda) | ||
575 | return -ENOMEM; | ||
576 | |||
577 | ret = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 1); | ||
567 | if (ret) | 578 | if (ret) |
568 | return ret; | 579 | goto free; |
569 | } | 580 | } |
570 | 581 | ||
571 | /* Stop the firmware, so that it can be safely rewritten */ | 582 | /* Stop the firmware, so that it can be safely rewritten */ |
572 | if (priv->stop_fw) { | 583 | if (priv->stop_fw) { |
573 | ret = priv->stop_fw(priv, 1); | 584 | ret = priv->stop_fw(priv, 1); |
574 | if (ret) | 585 | if (ret) |
575 | return ret; | 586 | goto free; |
576 | } | 587 | } |
577 | 588 | ||
578 | /* Program the adapter with new firmware */ | 589 | /* Program the adapter with new firmware */ |
579 | ret = hermes_program(hw, first_block, end); | 590 | ret = hermes_program(hw, first_block, end); |
580 | if (ret) | 591 | if (ret) |
581 | return ret; | 592 | goto free; |
582 | 593 | ||
583 | /* Write the PDA to the adapter */ | 594 | /* Write the PDA to the adapter */ |
584 | if (secondary) { | 595 | if (secondary) { |
585 | size_t len = hermes_blocks_length(first_block); | 596 | size_t len = hermes_blocks_length(first_block); |
586 | ptr = first_block + len; | 597 | ptr = first_block + len; |
587 | ret = hermes_apply_pda(hw, ptr, pda); | 598 | ret = hermes_apply_pda(hw, ptr, pda); |
599 | kfree(pda); | ||
588 | if (ret) | 600 | if (ret) |
589 | return ret; | 601 | return ret; |
590 | } | 602 | } |
@@ -608,6 +620,10 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, | |||
608 | return -ENODEV; | 620 | return -ENODEV; |
609 | 621 | ||
610 | return 0; | 622 | return 0; |
623 | |||
624 | free: | ||
625 | kfree(pda); | ||
626 | return ret; | ||
611 | } | 627 | } |
612 | 628 | ||
613 | 629 | ||