diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2010-01-29 14:54:56 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-03-02 14:31:51 -0500 |
commit | b08dfd0435333818a03b38867c556ebcbb3abc02 (patch) | |
tree | 578ce4b1dead6f1c605d252955eae26d09d6fabc /drivers | |
parent | 535765179fd4e8af26b69d2240d7ec33702a370a (diff) |
iwlwifi: load firmware asynchronously before mac80211 registration
At the wireless summit in Portland we discussed a way of
loading firmware asynchronously from ->probe() before
registration to mac80211, in order to register with the
wireless subsystems with complete information in cases
where firmware is required to know parameters.
This is not yet the case in iwlwifi, but for some new
features we're working on it will be the case since
those will only be supported by new firmware images.
Hence, to start with, convert iwlwifi to load firmware
asynchronously from probe, unbinding the device when
firmware loading fails, and only registering with the
wireless subsystems after firmware has been loaded
successfully.
Future patches will hook into this to register the
new firmware capabilities, depending on the firmware
API version.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 157 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-dev.h | 2 |
2 files changed, 81 insertions, 78 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 6aeb82b6992f..47b021477967 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -1463,59 +1463,66 @@ static void iwl_nic_start(struct iwl_priv *priv) | |||
1463 | } | 1463 | } |
1464 | 1464 | ||
1465 | 1465 | ||
1466 | static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context); | ||
1467 | static int iwl_mac_setup_register(struct iwl_priv *priv); | ||
1468 | |||
1469 | static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first) | ||
1470 | { | ||
1471 | const char *name_pre = priv->cfg->fw_name_pre; | ||
1472 | |||
1473 | if (first) | ||
1474 | priv->fw_index = priv->cfg->ucode_api_max; | ||
1475 | else | ||
1476 | priv->fw_index--; | ||
1477 | |||
1478 | if (priv->fw_index < priv->cfg->ucode_api_min) { | ||
1479 | IWL_ERR(priv, "no suitable firmware found!\n"); | ||
1480 | return -ENOENT; | ||
1481 | } | ||
1482 | |||
1483 | sprintf(priv->firmware_name, "%s%d%s", | ||
1484 | name_pre, priv->fw_index, ".ucode"); | ||
1485 | |||
1486 | IWL_DEBUG_INFO(priv, "attempting to load firmware '%s'\n", | ||
1487 | priv->firmware_name); | ||
1488 | |||
1489 | return request_firmware_nowait(THIS_MODULE, 1, priv->firmware_name, | ||
1490 | &priv->pci_dev->dev, GFP_KERNEL, priv, | ||
1491 | iwl_ucode_callback); | ||
1492 | } | ||
1493 | |||
1466 | /** | 1494 | /** |
1467 | * iwl_read_ucode - Read uCode images from disk file. | 1495 | * iwl_ucode_callback - callback when firmware was loaded |
1468 | * | 1496 | * |
1469 | * Copy into buffers for card to fetch via bus-mastering | 1497 | * If loaded successfully, copies the firmware into buffers |
1498 | * for the card to fetch (via DMA). | ||
1470 | */ | 1499 | */ |
1471 | static int iwl_read_ucode(struct iwl_priv *priv) | 1500 | static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) |
1472 | { | 1501 | { |
1502 | struct iwl_priv *priv = context; | ||
1473 | struct iwl_ucode_header *ucode; | 1503 | struct iwl_ucode_header *ucode; |
1474 | int ret = -EINVAL, index; | ||
1475 | const struct firmware *ucode_raw; | ||
1476 | const char *name_pre = priv->cfg->fw_name_pre; | ||
1477 | const unsigned int api_max = priv->cfg->ucode_api_max; | 1504 | const unsigned int api_max = priv->cfg->ucode_api_max; |
1478 | const unsigned int api_min = priv->cfg->ucode_api_min; | 1505 | const unsigned int api_min = priv->cfg->ucode_api_min; |
1479 | char buf[25]; | ||
1480 | u8 *src; | 1506 | u8 *src; |
1481 | size_t len; | 1507 | size_t len; |
1482 | u32 api_ver, build; | 1508 | u32 api_ver, build; |
1483 | u32 inst_size, data_size, init_size, init_data_size, boot_size; | 1509 | u32 inst_size, data_size, init_size, init_data_size, boot_size; |
1510 | int err; | ||
1484 | u16 eeprom_ver; | 1511 | u16 eeprom_ver; |
1485 | 1512 | ||
1486 | /* Ask kernel firmware_class module to get the boot firmware off disk. | 1513 | if (!ucode_raw) { |
1487 | * request_firmware() is synchronous, file is in memory on return. */ | 1514 | IWL_ERR(priv, "request for firmware file '%s' failed.\n", |
1488 | for (index = api_max; index >= api_min; index--) { | 1515 | priv->firmware_name); |
1489 | sprintf(buf, "%s%d%s", name_pre, index, ".ucode"); | 1516 | goto try_again; |
1490 | ret = request_firmware(&ucode_raw, buf, &priv->pci_dev->dev); | ||
1491 | if (ret < 0) { | ||
1492 | IWL_ERR(priv, "%s firmware file req failed: %d\n", | ||
1493 | buf, ret); | ||
1494 | if (ret == -ENOENT) | ||
1495 | continue; | ||
1496 | else | ||
1497 | goto error; | ||
1498 | } else { | ||
1499 | if (index < api_max) | ||
1500 | IWL_ERR(priv, "Loaded firmware %s, " | ||
1501 | "which is deprecated. " | ||
1502 | "Please use API v%u instead.\n", | ||
1503 | buf, api_max); | ||
1504 | |||
1505 | IWL_DEBUG_INFO(priv, "Got firmware '%s' file (%zd bytes) from disk\n", | ||
1506 | buf, ucode_raw->size); | ||
1507 | break; | ||
1508 | } | ||
1509 | } | 1517 | } |
1510 | 1518 | ||
1511 | if (ret < 0) | 1519 | IWL_DEBUG_INFO(priv, "Loaded firmware file '%s' (%zd bytes).\n", |
1512 | goto error; | 1520 | priv->firmware_name, ucode_raw->size); |
1513 | 1521 | ||
1514 | /* Make sure that we got at least the v1 header! */ | 1522 | /* Make sure that we got at least the v1 header! */ |
1515 | if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) { | 1523 | if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) { |
1516 | IWL_ERR(priv, "File size way too small!\n"); | 1524 | IWL_ERR(priv, "File size way too small!\n"); |
1517 | ret = -EINVAL; | 1525 | goto try_again; |
1518 | goto err_release; | ||
1519 | } | 1526 | } |
1520 | 1527 | ||
1521 | /* Data from ucode file: header followed by uCode images */ | 1528 | /* Data from ucode file: header followed by uCode images */ |
@@ -1540,10 +1547,9 @@ static int iwl_read_ucode(struct iwl_priv *priv) | |||
1540 | IWL_ERR(priv, "Driver unable to support your firmware API. " | 1547 | IWL_ERR(priv, "Driver unable to support your firmware API. " |
1541 | "Driver supports v%u, firmware is v%u.\n", | 1548 | "Driver supports v%u, firmware is v%u.\n", |
1542 | api_max, api_ver); | 1549 | api_max, api_ver); |
1543 | priv->ucode_ver = 0; | 1550 | goto try_again; |
1544 | ret = -EINVAL; | ||
1545 | goto err_release; | ||
1546 | } | 1551 | } |
1552 | |||
1547 | if (api_ver != api_max) | 1553 | if (api_ver != api_max) |
1548 | IWL_ERR(priv, "Firmware has old API version. Expected v%u, " | 1554 | IWL_ERR(priv, "Firmware has old API version. Expected v%u, " |
1549 | "got v%u. New firmware can be obtained " | 1555 | "got v%u. New firmware can be obtained " |
@@ -1585,6 +1591,12 @@ static int iwl_read_ucode(struct iwl_priv *priv) | |||
1585 | IWL_DEBUG_INFO(priv, "f/w package hdr boot inst size = %u\n", | 1591 | IWL_DEBUG_INFO(priv, "f/w package hdr boot inst size = %u\n", |
1586 | boot_size); | 1592 | boot_size); |
1587 | 1593 | ||
1594 | /* | ||
1595 | * For any of the failures below (before allocating pci memory) | ||
1596 | * we will try to load a version with a smaller API -- maybe the | ||
1597 | * user just got a corrupted version of the latest API. | ||
1598 | */ | ||
1599 | |||
1588 | /* Verify size of file vs. image size info in file's header */ | 1600 | /* Verify size of file vs. image size info in file's header */ |
1589 | if (ucode_raw->size != | 1601 | if (ucode_raw->size != |
1590 | priv->cfg->ops->ucode->get_header_size(api_ver) + | 1602 | priv->cfg->ops->ucode->get_header_size(api_ver) + |
@@ -1594,41 +1606,35 @@ static int iwl_read_ucode(struct iwl_priv *priv) | |||
1594 | IWL_DEBUG_INFO(priv, | 1606 | IWL_DEBUG_INFO(priv, |
1595 | "uCode file size %d does not match expected size\n", | 1607 | "uCode file size %d does not match expected size\n", |
1596 | (int)ucode_raw->size); | 1608 | (int)ucode_raw->size); |
1597 | ret = -EINVAL; | 1609 | goto try_again; |
1598 | goto err_release; | ||
1599 | } | 1610 | } |
1600 | 1611 | ||
1601 | /* Verify that uCode images will fit in card's SRAM */ | 1612 | /* Verify that uCode images will fit in card's SRAM */ |
1602 | if (inst_size > priv->hw_params.max_inst_size) { | 1613 | if (inst_size > priv->hw_params.max_inst_size) { |
1603 | IWL_DEBUG_INFO(priv, "uCode instr len %d too large to fit in\n", | 1614 | IWL_DEBUG_INFO(priv, "uCode instr len %d too large to fit in\n", |
1604 | inst_size); | 1615 | inst_size); |
1605 | ret = -EINVAL; | 1616 | goto try_again; |
1606 | goto err_release; | ||
1607 | } | 1617 | } |
1608 | 1618 | ||
1609 | if (data_size > priv->hw_params.max_data_size) { | 1619 | if (data_size > priv->hw_params.max_data_size) { |
1610 | IWL_DEBUG_INFO(priv, "uCode data len %d too large to fit in\n", | 1620 | IWL_DEBUG_INFO(priv, "uCode data len %d too large to fit in\n", |
1611 | data_size); | 1621 | data_size); |
1612 | ret = -EINVAL; | 1622 | goto try_again; |
1613 | goto err_release; | ||
1614 | } | 1623 | } |
1615 | if (init_size > priv->hw_params.max_inst_size) { | 1624 | if (init_size > priv->hw_params.max_inst_size) { |
1616 | IWL_INFO(priv, "uCode init instr len %d too large to fit in\n", | 1625 | IWL_INFO(priv, "uCode init instr len %d too large to fit in\n", |
1617 | init_size); | 1626 | init_size); |
1618 | ret = -EINVAL; | 1627 | goto try_again; |
1619 | goto err_release; | ||
1620 | } | 1628 | } |
1621 | if (init_data_size > priv->hw_params.max_data_size) { | 1629 | if (init_data_size > priv->hw_params.max_data_size) { |
1622 | IWL_INFO(priv, "uCode init data len %d too large to fit in\n", | 1630 | IWL_INFO(priv, "uCode init data len %d too large to fit in\n", |
1623 | init_data_size); | 1631 | init_data_size); |
1624 | ret = -EINVAL; | 1632 | goto try_again; |
1625 | goto err_release; | ||
1626 | } | 1633 | } |
1627 | if (boot_size > priv->hw_params.max_bsm_size) { | 1634 | if (boot_size > priv->hw_params.max_bsm_size) { |
1628 | IWL_INFO(priv, "uCode boot instr len %d too large to fit in\n", | 1635 | IWL_INFO(priv, "uCode boot instr len %d too large to fit in\n", |
1629 | boot_size); | 1636 | boot_size); |
1630 | ret = -EINVAL; | 1637 | goto try_again; |
1631 | goto err_release; | ||
1632 | } | 1638 | } |
1633 | 1639 | ||
1634 | /* Allocate ucode buffers for card's bus-master loading ... */ | 1640 | /* Allocate ucode buffers for card's bus-master loading ... */ |
@@ -1712,20 +1718,36 @@ static int iwl_read_ucode(struct iwl_priv *priv) | |||
1712 | IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n", len); | 1718 | IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n", len); |
1713 | memcpy(priv->ucode_boot.v_addr, src, len); | 1719 | memcpy(priv->ucode_boot.v_addr, src, len); |
1714 | 1720 | ||
1721 | /************************************************** | ||
1722 | * This is still part of probe() in a sense... | ||
1723 | * | ||
1724 | * 9. Setup and register with mac80211 and debugfs | ||
1725 | **************************************************/ | ||
1726 | err = iwl_mac_setup_register(priv); | ||
1727 | if (err) | ||
1728 | goto out_unbind; | ||
1729 | |||
1730 | err = iwl_dbgfs_register(priv, DRV_NAME); | ||
1731 | if (err) | ||
1732 | IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err); | ||
1733 | |||
1715 | /* We have our copies now, allow OS release its copies */ | 1734 | /* We have our copies now, allow OS release its copies */ |
1716 | release_firmware(ucode_raw); | 1735 | release_firmware(ucode_raw); |
1717 | return 0; | 1736 | return; |
1737 | |||
1738 | try_again: | ||
1739 | /* try next, if any */ | ||
1740 | if (iwl_request_firmware(priv, false)) | ||
1741 | goto out_unbind; | ||
1742 | release_firmware(ucode_raw); | ||
1743 | return; | ||
1718 | 1744 | ||
1719 | err_pci_alloc: | 1745 | err_pci_alloc: |
1720 | IWL_ERR(priv, "failed to allocate pci memory\n"); | 1746 | IWL_ERR(priv, "failed to allocate pci memory\n"); |
1721 | ret = -ENOMEM; | ||
1722 | iwl_dealloc_ucode_pci(priv); | 1747 | iwl_dealloc_ucode_pci(priv); |
1723 | 1748 | out_unbind: | |
1724 | err_release: | 1749 | device_release_driver(&priv->pci_dev->dev); |
1725 | release_firmware(ucode_raw); | 1750 | release_firmware(ucode_raw); |
1726 | |||
1727 | error: | ||
1728 | return ret; | ||
1729 | } | 1751 | } |
1730 | 1752 | ||
1731 | static const char *desc_lookup_text[] = { | 1753 | static const char *desc_lookup_text[] = { |
@@ -2667,21 +2689,7 @@ static int iwl_mac_start(struct ieee80211_hw *hw) | |||
2667 | 2689 | ||
2668 | /* we should be verifying the device is ready to be opened */ | 2690 | /* we should be verifying the device is ready to be opened */ |
2669 | mutex_lock(&priv->mutex); | 2691 | mutex_lock(&priv->mutex); |
2670 | |||
2671 | /* fetch ucode file from disk, alloc and copy to bus-master buffers ... | ||
2672 | * ucode filename and max sizes are card-specific. */ | ||
2673 | |||
2674 | if (!priv->ucode_code.len) { | ||
2675 | ret = iwl_read_ucode(priv); | ||
2676 | if (ret) { | ||
2677 | IWL_ERR(priv, "Could not read microcode: %d\n", ret); | ||
2678 | mutex_unlock(&priv->mutex); | ||
2679 | return ret; | ||
2680 | } | ||
2681 | } | ||
2682 | |||
2683 | ret = __iwl_up(priv); | 2692 | ret = __iwl_up(priv); |
2684 | |||
2685 | mutex_unlock(&priv->mutex); | 2693 | mutex_unlock(&priv->mutex); |
2686 | 2694 | ||
2687 | if (ret) | 2695 | if (ret) |
@@ -3654,17 +3662,10 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
3654 | iwl_power_initialize(priv); | 3662 | iwl_power_initialize(priv); |
3655 | iwl_tt_initialize(priv); | 3663 | iwl_tt_initialize(priv); |
3656 | 3664 | ||
3657 | /************************************************** | 3665 | err = iwl_request_firmware(priv, true); |
3658 | * 9. Setup and register with mac80211 and debugfs | ||
3659 | **************************************************/ | ||
3660 | err = iwl_mac_setup_register(priv); | ||
3661 | if (err) | 3666 | if (err) |
3662 | goto out_remove_sysfs; | 3667 | goto out_remove_sysfs; |
3663 | 3668 | ||
3664 | err = iwl_dbgfs_register(priv, DRV_NAME); | ||
3665 | if (err) | ||
3666 | IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err); | ||
3667 | |||
3668 | return 0; | 3669 | return 0; |
3669 | 3670 | ||
3670 | out_remove_sysfs: | 3671 | out_remove_sysfs: |
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index ab891b958042..6054c5fba0c1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h | |||
@@ -1132,6 +1132,7 @@ struct iwl_priv { | |||
1132 | u8 rev_id; | 1132 | u8 rev_id; |
1133 | 1133 | ||
1134 | /* uCode images, save to reload in case of failure */ | 1134 | /* uCode images, save to reload in case of failure */ |
1135 | int fw_index; /* firmware we're trying to load */ | ||
1135 | u32 ucode_ver; /* version of ucode, copy of | 1136 | u32 ucode_ver; /* version of ucode, copy of |
1136 | iwl_ucode.ver */ | 1137 | iwl_ucode.ver */ |
1137 | struct fw_desc ucode_code; /* runtime inst */ | 1138 | struct fw_desc ucode_code; /* runtime inst */ |
@@ -1142,6 +1143,7 @@ struct iwl_priv { | |||
1142 | struct fw_desc ucode_boot; /* bootstrap inst */ | 1143 | struct fw_desc ucode_boot; /* bootstrap inst */ |
1143 | enum ucode_type ucode_type; | 1144 | enum ucode_type ucode_type; |
1144 | u8 ucode_write_complete; /* the image write is complete */ | 1145 | u8 ucode_write_complete; /* the image write is complete */ |
1146 | char firmware_name[25]; | ||
1145 | 1147 | ||
1146 | 1148 | ||
1147 | struct iwl_rxon_time_cmd rxon_timing; | 1149 | struct iwl_rxon_time_cmd rxon_timing; |