diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 133 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-commands.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-dev.h | 58 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl3945-base.c | 4 |
4 files changed, 187 insertions, 9 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 65ae636eae3e..97184e14a775 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -1505,9 +1505,13 @@ static void iwl_nic_start(struct iwl_priv *priv) | |||
1505 | iwl_write32(priv, CSR_RESET, 0); | 1505 | iwl_write32(priv, CSR_RESET, 0); |
1506 | } | 1506 | } |
1507 | 1507 | ||
1508 | struct iwlagn_ucode_capabilities { | ||
1509 | u32 max_probe_length; | ||
1510 | }; | ||
1508 | 1511 | ||
1509 | static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context); | 1512 | static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context); |
1510 | static int iwl_mac_setup_register(struct iwl_priv *priv); | 1513 | static int iwl_mac_setup_register(struct iwl_priv *priv, |
1514 | struct iwlagn_ucode_capabilities *capa); | ||
1511 | 1515 | ||
1512 | static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first) | 1516 | static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first) |
1513 | { | 1517 | { |
@@ -1619,6 +1623,114 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, | |||
1619 | return 0; | 1623 | return 0; |
1620 | } | 1624 | } |
1621 | 1625 | ||
1626 | static int iwlagn_wanted_ucode_alternative = 1; | ||
1627 | |||
1628 | static int iwlagn_load_firmware(struct iwl_priv *priv, | ||
1629 | const struct firmware *ucode_raw, | ||
1630 | struct iwlagn_firmware_pieces *pieces, | ||
1631 | struct iwlagn_ucode_capabilities *capa) | ||
1632 | { | ||
1633 | struct iwl_tlv_ucode_header *ucode = (void *)ucode_raw->data; | ||
1634 | struct iwl_ucode_tlv *tlv; | ||
1635 | size_t len = ucode_raw->size; | ||
1636 | const u8 *data; | ||
1637 | int wanted_alternative = iwlagn_wanted_ucode_alternative, tmp; | ||
1638 | u64 alternatives; | ||
1639 | |||
1640 | if (len < sizeof(*ucode)) | ||
1641 | return -EINVAL; | ||
1642 | |||
1643 | if (ucode->magic != cpu_to_le32(IWL_TLV_UCODE_MAGIC)) | ||
1644 | return -EINVAL; | ||
1645 | |||
1646 | /* | ||
1647 | * Check which alternatives are present, and "downgrade" | ||
1648 | * when the chosen alternative is not present, warning | ||
1649 | * the user when that happens. Some files may not have | ||
1650 | * any alternatives, so don't warn in that case. | ||
1651 | */ | ||
1652 | alternatives = le64_to_cpu(ucode->alternatives); | ||
1653 | tmp = wanted_alternative; | ||
1654 | if (wanted_alternative > 63) | ||
1655 | wanted_alternative = 63; | ||
1656 | while (wanted_alternative && !(alternatives & BIT(wanted_alternative))) | ||
1657 | wanted_alternative--; | ||
1658 | if (wanted_alternative && wanted_alternative != tmp) | ||
1659 | IWL_WARN(priv, | ||
1660 | "uCode alternative %d not available, choosing %d\n", | ||
1661 | tmp, wanted_alternative); | ||
1662 | |||
1663 | priv->ucode_ver = le32_to_cpu(ucode->ver); | ||
1664 | pieces->build = le32_to_cpu(ucode->build); | ||
1665 | data = ucode->data; | ||
1666 | |||
1667 | len -= sizeof(*ucode); | ||
1668 | |||
1669 | while (len >= sizeof(*tlv)) { | ||
1670 | u32 tlv_len; | ||
1671 | enum iwl_ucode_tlv_type tlv_type; | ||
1672 | u16 tlv_alt; | ||
1673 | const u8 *tlv_data; | ||
1674 | |||
1675 | len -= sizeof(*tlv); | ||
1676 | tlv = (void *)data; | ||
1677 | |||
1678 | tlv_len = le32_to_cpu(tlv->length); | ||
1679 | tlv_type = le16_to_cpu(tlv->type); | ||
1680 | tlv_alt = le16_to_cpu(tlv->alternative); | ||
1681 | tlv_data = tlv->data; | ||
1682 | |||
1683 | if (len < tlv_len) | ||
1684 | return -EINVAL; | ||
1685 | len -= ALIGN(tlv_len, 4); | ||
1686 | data += sizeof(*tlv) + ALIGN(tlv_len, 4); | ||
1687 | |||
1688 | /* | ||
1689 | * Alternative 0 is always valid. | ||
1690 | * | ||
1691 | * Skip alternative TLVs that are not selected. | ||
1692 | */ | ||
1693 | if (tlv_alt != 0 && tlv_alt != wanted_alternative) | ||
1694 | continue; | ||
1695 | |||
1696 | switch (tlv_type) { | ||
1697 | case IWL_UCODE_TLV_INST: | ||
1698 | pieces->inst = tlv_data; | ||
1699 | pieces->inst_size = tlv_len; | ||
1700 | break; | ||
1701 | case IWL_UCODE_TLV_DATA: | ||
1702 | pieces->data = tlv_data; | ||
1703 | pieces->data_size = tlv_len; | ||
1704 | break; | ||
1705 | case IWL_UCODE_TLV_INIT: | ||
1706 | pieces->init = tlv_data; | ||
1707 | pieces->init_size = tlv_len; | ||
1708 | break; | ||
1709 | case IWL_UCODE_TLV_INIT_DATA: | ||
1710 | pieces->init_data = tlv_data; | ||
1711 | pieces->init_data_size = tlv_len; | ||
1712 | break; | ||
1713 | case IWL_UCODE_TLV_BOOT: | ||
1714 | pieces->boot = tlv_data; | ||
1715 | pieces->boot_size = tlv_len; | ||
1716 | break; | ||
1717 | case IWL_UCODE_TLV_PROBE_MAX_LEN: | ||
1718 | if (tlv_len != 4) | ||
1719 | return -EINVAL; | ||
1720 | capa->max_probe_length = | ||
1721 | le32_to_cpup((__le32 *)tlv_data); | ||
1722 | break; | ||
1723 | default: | ||
1724 | break; | ||
1725 | } | ||
1726 | } | ||
1727 | |||
1728 | if (len) | ||
1729 | return -EINVAL; | ||
1730 | |||
1731 | return 0; | ||
1732 | } | ||
1733 | |||
1622 | /** | 1734 | /** |
1623 | * iwl_ucode_callback - callback when firmware was loaded | 1735 | * iwl_ucode_callback - callback when firmware was loaded |
1624 | * | 1736 | * |
@@ -1636,6 +1748,9 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | |||
1636 | u32 api_ver; | 1748 | u32 api_ver; |
1637 | char buildstr[25]; | 1749 | char buildstr[25]; |
1638 | u32 build; | 1750 | u32 build; |
1751 | struct iwlagn_ucode_capabilities ucode_capa = { | ||
1752 | .max_probe_length = 200, | ||
1753 | }; | ||
1639 | 1754 | ||
1640 | memset(&pieces, 0, sizeof(pieces)); | 1755 | memset(&pieces, 0, sizeof(pieces)); |
1641 | 1756 | ||
@@ -1660,7 +1775,8 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | |||
1660 | if (ucode->ver) | 1775 | if (ucode->ver) |
1661 | err = iwlagn_load_legacy_firmware(priv, ucode_raw, &pieces); | 1776 | err = iwlagn_load_legacy_firmware(priv, ucode_raw, &pieces); |
1662 | else | 1777 | else |
1663 | err = -EINVAL; | 1778 | err = iwlagn_load_firmware(priv, ucode_raw, &pieces, |
1779 | &ucode_capa); | ||
1664 | 1780 | ||
1665 | if (err) | 1781 | if (err) |
1666 | goto try_again; | 1782 | goto try_again; |
@@ -1757,7 +1873,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | |||
1757 | goto try_again; | 1873 | goto try_again; |
1758 | } | 1874 | } |
1759 | 1875 | ||
1760 | |||
1761 | /* Allocate ucode buffers for card's bus-master loading ... */ | 1876 | /* Allocate ucode buffers for card's bus-master loading ... */ |
1762 | 1877 | ||
1763 | /* Runtime instructions and 2 copies of data: | 1878 | /* Runtime instructions and 2 copies of data: |
@@ -1841,7 +1956,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | |||
1841 | * | 1956 | * |
1842 | * 9. Setup and register with mac80211 and debugfs | 1957 | * 9. Setup and register with mac80211 and debugfs |
1843 | **************************************************/ | 1958 | **************************************************/ |
1844 | err = iwl_mac_setup_register(priv); | 1959 | err = iwl_mac_setup_register(priv, &ucode_capa); |
1845 | if (err) | 1960 | if (err) |
1846 | goto out_unbind; | 1961 | goto out_unbind; |
1847 | 1962 | ||
@@ -2716,7 +2831,8 @@ void iwl_post_associate(struct iwl_priv *priv) | |||
2716 | * Not a mac80211 entry point function, but it fits in with all the | 2831 | * Not a mac80211 entry point function, but it fits in with all the |
2717 | * other mac80211 functions grouped here. | 2832 | * other mac80211 functions grouped here. |
2718 | */ | 2833 | */ |
2719 | static int iwl_mac_setup_register(struct iwl_priv *priv) | 2834 | static int iwl_mac_setup_register(struct iwl_priv *priv, |
2835 | struct iwlagn_ucode_capabilities *capa) | ||
2720 | { | 2836 | { |
2721 | int ret; | 2837 | int ret; |
2722 | struct ieee80211_hw *hw = priv->hw; | 2838 | struct ieee80211_hw *hw = priv->hw; |
@@ -2751,7 +2867,7 @@ static int iwl_mac_setup_register(struct iwl_priv *priv) | |||
2751 | 2867 | ||
2752 | hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX; | 2868 | hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX; |
2753 | /* we create the 802.11 header and a zero-length SSID element */ | 2869 | /* we create the 802.11 header and a zero-length SSID element */ |
2754 | hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2; | 2870 | hw->wiphy->max_scan_ie_len = capa->max_probe_length - 24 - 2; |
2755 | 2871 | ||
2756 | /* Default value; 4 EDCA QOS priorities */ | 2872 | /* Default value; 4 EDCA QOS priorities */ |
2757 | hw->queues = 4; | 2873 | hw->queues = 4; |
@@ -3974,3 +4090,8 @@ MODULE_PARM_DESC(fw_restart, "restart firmware in case of error"); | |||
3974 | module_param_named( | 4090 | module_param_named( |
3975 | disable_hw_scan, iwlagn_mod_params.disable_hw_scan, int, S_IRUGO); | 4091 | disable_hw_scan, iwlagn_mod_params.disable_hw_scan, int, S_IRUGO); |
3976 | MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); | 4092 | MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); |
4093 | |||
4094 | module_param_named(ucode_alternative, iwlagn_wanted_ucode_alternative, int, | ||
4095 | S_IRUGO); | ||
4096 | MODULE_PARM_DESC(ucode_alternative, | ||
4097 | "specify ucode alternative to use from ucode file"); | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 0086019b7a15..449d41f058b8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h | |||
@@ -2668,7 +2668,6 @@ struct iwl_ssid_ie { | |||
2668 | #define IWL_GOOD_CRC_TH_NEVER cpu_to_le16(0xffff) | 2668 | #define IWL_GOOD_CRC_TH_NEVER cpu_to_le16(0xffff) |
2669 | #define IWL_MAX_SCAN_SIZE 1024 | 2669 | #define IWL_MAX_SCAN_SIZE 1024 |
2670 | #define IWL_MAX_CMD_SIZE 4096 | 2670 | #define IWL_MAX_CMD_SIZE 4096 |
2671 | #define IWL_MAX_PROBE_REQUEST 200 | ||
2672 | 2671 | ||
2673 | /* | 2672 | /* |
2674 | * REPLY_SCAN_CMD = 0x80 (command) | 2673 | * REPLY_SCAN_CMD = 0x80 (command) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index fe938d9e43cb..19a5c895f1a2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h | |||
@@ -518,7 +518,7 @@ struct fw_desc { | |||
518 | u32 len; /* bytes */ | 518 | u32 len; /* bytes */ |
519 | }; | 519 | }; |
520 | 520 | ||
521 | /* uCode file layout */ | 521 | /* v1/v2 uCode file layout */ |
522 | struct iwl_ucode_header { | 522 | struct iwl_ucode_header { |
523 | __le32 ver; /* major/minor/API/serial */ | 523 | __le32 ver; /* major/minor/API/serial */ |
524 | union { | 524 | union { |
@@ -542,6 +542,62 @@ struct iwl_ucode_header { | |||
542 | } u; | 542 | } u; |
543 | }; | 543 | }; |
544 | 544 | ||
545 | /* | ||
546 | * new TLV uCode file layout | ||
547 | * | ||
548 | * The new TLV file format contains TLVs, that each specify | ||
549 | * some piece of data. To facilitate "groups", for example | ||
550 | * different instruction image with different capabilities, | ||
551 | * bundled with the same init image, an alternative mechanism | ||
552 | * is provided: | ||
553 | * When the alternative field is 0, that means that the item | ||
554 | * is always valid. When it is non-zero, then it is only | ||
555 | * valid in conjunction with items of the same alternative, | ||
556 | * in which case the driver (user) selects one alternative | ||
557 | * to use. | ||
558 | */ | ||
559 | |||
560 | enum iwl_ucode_tlv_type { | ||
561 | IWL_UCODE_TLV_INVALID = 0, /* unused */ | ||
562 | IWL_UCODE_TLV_INST = 1, | ||
563 | IWL_UCODE_TLV_DATA = 2, | ||
564 | IWL_UCODE_TLV_INIT = 3, | ||
565 | IWL_UCODE_TLV_INIT_DATA = 4, | ||
566 | IWL_UCODE_TLV_BOOT = 5, | ||
567 | IWL_UCODE_TLV_PROBE_MAX_LEN = 6, /* a u32 value */ | ||
568 | }; | ||
569 | |||
570 | struct iwl_ucode_tlv { | ||
571 | __le16 type; /* see above */ | ||
572 | __le16 alternative; /* see comment */ | ||
573 | __le32 length; /* not including type/length fields */ | ||
574 | u8 data[0]; | ||
575 | } __attribute__ ((packed)); | ||
576 | |||
577 | #define IWL_TLV_UCODE_MAGIC 0x0a4c5749 | ||
578 | |||
579 | struct iwl_tlv_ucode_header { | ||
580 | /* | ||
581 | * The TLV style ucode header is distinguished from | ||
582 | * the v1/v2 style header by first four bytes being | ||
583 | * zero, as such is an invalid combination of | ||
584 | * major/minor/API/serial versions. | ||
585 | */ | ||
586 | __le32 zero; | ||
587 | __le32 magic; | ||
588 | u8 human_readable[64]; | ||
589 | __le32 ver; /* major/minor/API/serial */ | ||
590 | __le32 build; | ||
591 | __le64 alternatives; /* bitmask of valid alternatives */ | ||
592 | /* | ||
593 | * The data contained herein has a TLV layout, | ||
594 | * see above for the TLV header and types. | ||
595 | * Note that each TLV is padded to a length | ||
596 | * that is a multiple of 4 for alignment. | ||
597 | */ | ||
598 | u8 data[0]; | ||
599 | }; | ||
600 | |||
545 | struct iwl4965_ibss_seq { | 601 | struct iwl4965_ibss_seq { |
546 | u8 mac[ETH_ALEN]; | 602 | u8 mac[ETH_ALEN]; |
547 | u16 seq_num; | 603 | u16 seq_num; |
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 59c85f55e625..77ab00b98778 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c | |||
@@ -3875,6 +3875,8 @@ err: | |||
3875 | return ret; | 3875 | return ret; |
3876 | } | 3876 | } |
3877 | 3877 | ||
3878 | #define IWL3945_MAX_PROBE_REQUEST 200 | ||
3879 | |||
3878 | static int iwl3945_setup_mac(struct iwl_priv *priv) | 3880 | static int iwl3945_setup_mac(struct iwl_priv *priv) |
3879 | { | 3881 | { |
3880 | int ret; | 3882 | int ret; |
@@ -3900,7 +3902,7 @@ static int iwl3945_setup_mac(struct iwl_priv *priv) | |||
3900 | 3902 | ||
3901 | hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX_3945; | 3903 | hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX_3945; |
3902 | /* we create the 802.11 header and a zero-length SSID element */ | 3904 | /* we create the 802.11 header and a zero-length SSID element */ |
3903 | hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2; | 3905 | hw->wiphy->max_scan_ie_len = IWL3945_MAX_PROBE_REQUEST - 24 - 2; |
3904 | 3906 | ||
3905 | /* Default value; 4 EDCA QOS priorities */ | 3907 | /* Default value; 4 EDCA QOS priorities */ |
3906 | hw->queues = 4; | 3908 | hw->queues = 4; |