diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 165 |
1 files changed, 127 insertions, 38 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 3368cfd25a99..66c83b24884f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -859,6 +859,24 @@ int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) | |||
859 | return 0; | 859 | return 0; |
860 | } | 860 | } |
861 | 861 | ||
862 | static void iwl_bg_tx_flush(struct work_struct *work) | ||
863 | { | ||
864 | struct iwl_priv *priv = | ||
865 | container_of(work, struct iwl_priv, tx_flush); | ||
866 | |||
867 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | ||
868 | return; | ||
869 | |||
870 | /* do nothing if rf-kill is on */ | ||
871 | if (!iwl_is_ready_rf(priv)) | ||
872 | return; | ||
873 | |||
874 | if (priv->cfg->ops->lib->txfifo_flush) { | ||
875 | IWL_DEBUG_INFO(priv, "device request: flush all tx frames\n"); | ||
876 | iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL); | ||
877 | } | ||
878 | } | ||
879 | |||
862 | /** | 880 | /** |
863 | * iwl_setup_rx_handlers - Initialize Rx handler callbacks | 881 | * iwl_setup_rx_handlers - Initialize Rx handler callbacks |
864 | * | 882 | * |
@@ -1806,12 +1824,21 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, | |||
1806 | const u8 *data; | 1824 | const u8 *data; |
1807 | int wanted_alternative = iwlagn_wanted_ucode_alternative, tmp; | 1825 | int wanted_alternative = iwlagn_wanted_ucode_alternative, tmp; |
1808 | u64 alternatives; | 1826 | u64 alternatives; |
1827 | u32 tlv_len; | ||
1828 | enum iwl_ucode_tlv_type tlv_type; | ||
1829 | const u8 *tlv_data; | ||
1830 | int ret = 0; | ||
1809 | 1831 | ||
1810 | if (len < sizeof(*ucode)) | 1832 | if (len < sizeof(*ucode)) { |
1833 | IWL_ERR(priv, "uCode has invalid length: %zd\n", len); | ||
1811 | return -EINVAL; | 1834 | return -EINVAL; |
1835 | } | ||
1812 | 1836 | ||
1813 | if (ucode->magic != cpu_to_le32(IWL_TLV_UCODE_MAGIC)) | 1837 | if (ucode->magic != cpu_to_le32(IWL_TLV_UCODE_MAGIC)) { |
1838 | IWL_ERR(priv, "invalid uCode magic: 0X%x\n", | ||
1839 | le32_to_cpu(ucode->magic)); | ||
1814 | return -EINVAL; | 1840 | return -EINVAL; |
1841 | } | ||
1815 | 1842 | ||
1816 | /* | 1843 | /* |
1817 | * Check which alternatives are present, and "downgrade" | 1844 | * Check which alternatives are present, and "downgrade" |
@@ -1836,11 +1863,9 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, | |||
1836 | 1863 | ||
1837 | len -= sizeof(*ucode); | 1864 | len -= sizeof(*ucode); |
1838 | 1865 | ||
1839 | while (len >= sizeof(*tlv)) { | 1866 | while (len >= sizeof(*tlv) && !ret) { |
1840 | u32 tlv_len; | ||
1841 | enum iwl_ucode_tlv_type tlv_type; | ||
1842 | u16 tlv_alt; | 1867 | u16 tlv_alt; |
1843 | const u8 *tlv_data; | 1868 | u32 fixed_tlv_size = 4; |
1844 | 1869 | ||
1845 | len -= sizeof(*tlv); | 1870 | len -= sizeof(*tlv); |
1846 | tlv = (void *)data; | 1871 | tlv = (void *)data; |
@@ -1850,8 +1875,11 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, | |||
1850 | tlv_alt = le16_to_cpu(tlv->alternative); | 1875 | tlv_alt = le16_to_cpu(tlv->alternative); |
1851 | tlv_data = tlv->data; | 1876 | tlv_data = tlv->data; |
1852 | 1877 | ||
1853 | if (len < tlv_len) | 1878 | if (len < tlv_len) { |
1879 | IWL_ERR(priv, "invalid TLV len: %zd/%u\n", | ||
1880 | len, tlv_len); | ||
1854 | return -EINVAL; | 1881 | return -EINVAL; |
1882 | } | ||
1855 | len -= ALIGN(tlv_len, 4); | 1883 | len -= ALIGN(tlv_len, 4); |
1856 | data += sizeof(*tlv) + ALIGN(tlv_len, 4); | 1884 | data += sizeof(*tlv) + ALIGN(tlv_len, 4); |
1857 | 1885 | ||
@@ -1885,56 +1913,77 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, | |||
1885 | pieces->boot_size = tlv_len; | 1913 | pieces->boot_size = tlv_len; |
1886 | break; | 1914 | break; |
1887 | case IWL_UCODE_TLV_PROBE_MAX_LEN: | 1915 | case IWL_UCODE_TLV_PROBE_MAX_LEN: |
1888 | if (tlv_len != 4) | 1916 | if (tlv_len != fixed_tlv_size) |
1889 | return -EINVAL; | 1917 | ret = -EINVAL; |
1890 | capa->max_probe_length = | 1918 | else |
1891 | le32_to_cpup((__le32 *)tlv_data); | 1919 | capa->max_probe_length = |
1920 | le32_to_cpup((__le32 *)tlv_data); | ||
1892 | break; | 1921 | break; |
1893 | case IWL_UCODE_TLV_INIT_EVTLOG_PTR: | 1922 | case IWL_UCODE_TLV_INIT_EVTLOG_PTR: |
1894 | if (tlv_len != 4) | 1923 | if (tlv_len != fixed_tlv_size) |
1895 | return -EINVAL; | 1924 | ret = -EINVAL; |
1896 | pieces->init_evtlog_ptr = | 1925 | else |
1897 | le32_to_cpup((__le32 *)tlv_data); | 1926 | pieces->init_evtlog_ptr = |
1927 | le32_to_cpup((__le32 *)tlv_data); | ||
1898 | break; | 1928 | break; |
1899 | case IWL_UCODE_TLV_INIT_EVTLOG_SIZE: | 1929 | case IWL_UCODE_TLV_INIT_EVTLOG_SIZE: |
1900 | if (tlv_len != 4) | 1930 | if (tlv_len != fixed_tlv_size) |
1901 | return -EINVAL; | 1931 | ret = -EINVAL; |
1902 | pieces->init_evtlog_size = | 1932 | else |
1903 | le32_to_cpup((__le32 *)tlv_data); | 1933 | pieces->init_evtlog_size = |
1934 | le32_to_cpup((__le32 *)tlv_data); | ||
1904 | break; | 1935 | break; |
1905 | case IWL_UCODE_TLV_INIT_ERRLOG_PTR: | 1936 | case IWL_UCODE_TLV_INIT_ERRLOG_PTR: |
1906 | if (tlv_len != 4) | 1937 | if (tlv_len != fixed_tlv_size) |
1907 | return -EINVAL; | 1938 | ret = -EINVAL; |
1908 | pieces->init_errlog_ptr = | 1939 | else |
1909 | le32_to_cpup((__le32 *)tlv_data); | 1940 | pieces->init_errlog_ptr = |
1941 | le32_to_cpup((__le32 *)tlv_data); | ||
1910 | break; | 1942 | break; |
1911 | case IWL_UCODE_TLV_RUNT_EVTLOG_PTR: | 1943 | case IWL_UCODE_TLV_RUNT_EVTLOG_PTR: |
1912 | if (tlv_len != 4) | 1944 | if (tlv_len != fixed_tlv_size) |
1913 | return -EINVAL; | 1945 | ret = -EINVAL; |
1914 | pieces->inst_evtlog_ptr = | 1946 | else |
1915 | le32_to_cpup((__le32 *)tlv_data); | 1947 | pieces->inst_evtlog_ptr = |
1948 | le32_to_cpup((__le32 *)tlv_data); | ||
1916 | break; | 1949 | break; |
1917 | case IWL_UCODE_TLV_RUNT_EVTLOG_SIZE: | 1950 | case IWL_UCODE_TLV_RUNT_EVTLOG_SIZE: |
1918 | if (tlv_len != 4) | 1951 | if (tlv_len != fixed_tlv_size) |
1919 | return -EINVAL; | 1952 | ret = -EINVAL; |
1920 | pieces->inst_evtlog_size = | 1953 | else |
1921 | le32_to_cpup((__le32 *)tlv_data); | 1954 | pieces->inst_evtlog_size = |
1955 | le32_to_cpup((__le32 *)tlv_data); | ||
1922 | break; | 1956 | break; |
1923 | case IWL_UCODE_TLV_RUNT_ERRLOG_PTR: | 1957 | case IWL_UCODE_TLV_RUNT_ERRLOG_PTR: |
1924 | if (tlv_len != 4) | 1958 | if (tlv_len != fixed_tlv_size) |
1925 | return -EINVAL; | 1959 | ret = -EINVAL; |
1926 | pieces->inst_errlog_ptr = | 1960 | else |
1927 | le32_to_cpup((__le32 *)tlv_data); | 1961 | pieces->inst_errlog_ptr = |
1962 | le32_to_cpup((__le32 *)tlv_data); | ||
1963 | break; | ||
1964 | case IWL_UCODE_TLV_ENHANCE_SENS_TBL: | ||
1965 | if (tlv_len) | ||
1966 | ret = -EINVAL; | ||
1967 | else | ||
1968 | priv->enhance_sensitivity_table = true; | ||
1928 | break; | 1969 | break; |
1929 | default: | 1970 | default: |
1971 | IWL_WARN(priv, "unknown TLV: %d\n", tlv_type); | ||
1930 | break; | 1972 | break; |
1931 | } | 1973 | } |
1932 | } | 1974 | } |
1933 | 1975 | ||
1934 | if (len) | 1976 | if (len) { |
1935 | return -EINVAL; | 1977 | IWL_ERR(priv, "invalid TLV after parsing: %zd\n", len); |
1978 | iwl_print_hex_dump(priv, IWL_DL_FW, (u8 *)data, len); | ||
1979 | ret = -EINVAL; | ||
1980 | } else if (ret) { | ||
1981 | IWL_ERR(priv, "TLV %d has invalid size: %u\n", | ||
1982 | tlv_type, tlv_len); | ||
1983 | iwl_print_hex_dump(priv, IWL_DL_FW, (u8 *)tlv_data, tlv_len); | ||
1984 | } | ||
1936 | 1985 | ||
1937 | return 0; | 1986 | return ret; |
1938 | } | 1987 | } |
1939 | 1988 | ||
1940 | /** | 1989 | /** |
@@ -3614,6 +3663,44 @@ out_exit: | |||
3614 | IWL_DEBUG_MAC80211(priv, "leave\n"); | 3663 | IWL_DEBUG_MAC80211(priv, "leave\n"); |
3615 | } | 3664 | } |
3616 | 3665 | ||
3666 | static void iwl_mac_flush(struct ieee80211_hw *hw, bool drop) | ||
3667 | { | ||
3668 | struct iwl_priv *priv = hw->priv; | ||
3669 | |||
3670 | mutex_lock(&priv->mutex); | ||
3671 | IWL_DEBUG_MAC80211(priv, "enter\n"); | ||
3672 | |||
3673 | /* do not support "flush" */ | ||
3674 | if (!priv->cfg->ops->lib->txfifo_flush) | ||
3675 | goto done; | ||
3676 | |||
3677 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { | ||
3678 | IWL_DEBUG_TX(priv, "Aborting flush due to device shutdown\n"); | ||
3679 | goto done; | ||
3680 | } | ||
3681 | if (iwl_is_rfkill(priv)) { | ||
3682 | IWL_DEBUG_TX(priv, "Aborting flush due to RF Kill\n"); | ||
3683 | goto done; | ||
3684 | } | ||
3685 | |||
3686 | /* | ||
3687 | * mac80211 will not push any more frames for transmit | ||
3688 | * until the flush is completed | ||
3689 | */ | ||
3690 | if (drop) { | ||
3691 | IWL_DEBUG_MAC80211(priv, "send flush command\n"); | ||
3692 | if (priv->cfg->ops->lib->txfifo_flush(priv, IWL_DROP_ALL)) { | ||
3693 | IWL_ERR(priv, "flush request fail\n"); | ||
3694 | goto done; | ||
3695 | } | ||
3696 | } | ||
3697 | IWL_DEBUG_MAC80211(priv, "wait transmit/flush all frames\n"); | ||
3698 | iwlagn_wait_tx_queue_empty(priv); | ||
3699 | done: | ||
3700 | mutex_unlock(&priv->mutex); | ||
3701 | IWL_DEBUG_MAC80211(priv, "leave\n"); | ||
3702 | } | ||
3703 | |||
3617 | /***************************************************************************** | 3704 | /***************************************************************************** |
3618 | * | 3705 | * |
3619 | * driver setup and teardown | 3706 | * driver setup and teardown |
@@ -3630,6 +3717,7 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) | |||
3630 | INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish); | 3717 | INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish); |
3631 | INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update); | 3718 | INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update); |
3632 | INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work); | 3719 | INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work); |
3720 | INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush); | ||
3633 | INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); | 3721 | INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); |
3634 | INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); | 3722 | INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); |
3635 | 3723 | ||
@@ -3787,6 +3875,7 @@ static struct ieee80211_ops iwl_hw_ops = { | |||
3787 | .sta_add = iwlagn_mac_sta_add, | 3875 | .sta_add = iwlagn_mac_sta_add, |
3788 | .sta_remove = iwl_mac_sta_remove, | 3876 | .sta_remove = iwl_mac_sta_remove, |
3789 | .channel_switch = iwl_mac_channel_switch, | 3877 | .channel_switch = iwl_mac_channel_switch, |
3878 | .flush = iwl_mac_flush, | ||
3790 | }; | 3879 | }; |
3791 | 3880 | ||
3792 | static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | 3881 | static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |