diff options
121 files changed, 2687 insertions, 2220 deletions
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index e559dc960552..2517364d3ebe 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c | |||
@@ -121,6 +121,14 @@ static struct fwentry firmwares[] = { | |||
121 | [BOARD_505A] = { "atmel_at76c505a-rfmd2958.bin" }, | 121 | [BOARD_505A] = { "atmel_at76c505a-rfmd2958.bin" }, |
122 | [BOARD_505AMX] = { "atmel_at76c505amx-rfmd.bin" }, | 122 | [BOARD_505AMX] = { "atmel_at76c505amx-rfmd.bin" }, |
123 | }; | 123 | }; |
124 | MODULE_FIRMWARE("atmel_at76c503-i3861.bin"); | ||
125 | MODULE_FIRMWARE("atmel_at76c503-i3863.bin"); | ||
126 | MODULE_FIRMWARE("atmel_at76c503-rfmd.bin"); | ||
127 | MODULE_FIRMWARE("atmel_at76c503-rfmd-acc.bin"); | ||
128 | MODULE_FIRMWARE("atmel_at76c505-rfmd.bin"); | ||
129 | MODULE_FIRMWARE("atmel_at76c505-rfmd2958.bin"); | ||
130 | MODULE_FIRMWARE("atmel_at76c505a-rfmd2958.bin"); | ||
131 | MODULE_FIRMWARE("atmel_at76c505amx-rfmd.bin"); | ||
124 | 132 | ||
125 | #define USB_DEVICE_DATA(__ops) .driver_info = (kernel_ulong_t)(__ops) | 133 | #define USB_DEVICE_DATA(__ops) .driver_info = (kernel_ulong_t)(__ops) |
126 | 134 | ||
@@ -524,20 +532,6 @@ static char *hex2str(void *buf, int len) | |||
524 | return ret; | 532 | return ret; |
525 | } | 533 | } |
526 | 534 | ||
527 | #define MAC2STR_BUFFERS 4 | ||
528 | |||
529 | static inline char *mac2str(u8 *mac) | ||
530 | { | ||
531 | static atomic_t a = ATOMIC_INIT(0); | ||
532 | static char bufs[MAC2STR_BUFFERS][6 * 3]; | ||
533 | char *str; | ||
534 | |||
535 | str = bufs[atomic_inc_return(&a) & (MAC2STR_BUFFERS - 1)]; | ||
536 | sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x", | ||
537 | mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); | ||
538 | return str; | ||
539 | } | ||
540 | |||
541 | /* LED trigger */ | 535 | /* LED trigger */ |
542 | static int tx_activity; | 536 | static int tx_activity; |
543 | static void at76_ledtrig_tx_timerfunc(unsigned long data); | 537 | static void at76_ledtrig_tx_timerfunc(unsigned long data); |
@@ -973,13 +967,13 @@ static void at76_dump_mib_mac_addr(struct at76_priv *priv) | |||
973 | goto exit; | 967 | goto exit; |
974 | } | 968 | } |
975 | 969 | ||
976 | at76_dbg(DBG_MIB, "%s: MIB MAC_ADDR: mac_addr %s res 0x%x 0x%x", | 970 | at76_dbg(DBG_MIB, "%s: MIB MAC_ADDR: mac_addr %pM res 0x%x 0x%x", |
977 | wiphy_name(priv->hw->wiphy), | 971 | wiphy_name(priv->hw->wiphy), |
978 | mac2str(m->mac_addr), m->res[0], m->res[1]); | 972 | m->mac_addr, m->res[0], m->res[1]); |
979 | for (i = 0; i < ARRAY_SIZE(m->group_addr); i++) | 973 | for (i = 0; i < ARRAY_SIZE(m->group_addr); i++) |
980 | at76_dbg(DBG_MIB, "%s: MIB MAC_ADDR: group addr %d: %s, " | 974 | at76_dbg(DBG_MIB, "%s: MIB MAC_ADDR: group addr %d: %pM, " |
981 | "status %d", wiphy_name(priv->hw->wiphy), i, | 975 | "status %d", wiphy_name(priv->hw->wiphy), i, |
982 | mac2str(m->group_addr[i]), m->group_addr_status[i]); | 976 | m->group_addr[i], m->group_addr_status[i]); |
983 | exit: | 977 | exit: |
984 | kfree(m); | 978 | kfree(m); |
985 | } | 979 | } |
@@ -1042,7 +1036,7 @@ static void at76_dump_mib_mac_mgmt(struct at76_priv *priv) | |||
1042 | at76_dbg(DBG_MIB, "%s: MIB MAC_MGMT: beacon_period %d CFP_max_duration " | 1036 | at76_dbg(DBG_MIB, "%s: MIB MAC_MGMT: beacon_period %d CFP_max_duration " |
1043 | "%d medium_occupancy_limit %d station_id 0x%x ATIM_window %d " | 1037 | "%d medium_occupancy_limit %d station_id 0x%x ATIM_window %d " |
1044 | "CFP_mode %d privacy_opt_impl %d DTIM_period %d CFP_period %d " | 1038 | "CFP_mode %d privacy_opt_impl %d DTIM_period %d CFP_period %d " |
1045 | "current_bssid %s current_essid %s current_bss_type %d " | 1039 | "current_bssid %pM current_essid %s current_bss_type %d " |
1046 | "pm_mode %d ibss_change %d res %d " | 1040 | "pm_mode %d ibss_change %d res %d " |
1047 | "multi_domain_capability_implemented %d " | 1041 | "multi_domain_capability_implemented %d " |
1048 | "international_roaming %d country_string %.3s", | 1042 | "international_roaming %d country_string %.3s", |
@@ -1051,7 +1045,7 @@ static void at76_dump_mib_mac_mgmt(struct at76_priv *priv) | |||
1051 | le16_to_cpu(m->medium_occupancy_limit), | 1045 | le16_to_cpu(m->medium_occupancy_limit), |
1052 | le16_to_cpu(m->station_id), le16_to_cpu(m->ATIM_window), | 1046 | le16_to_cpu(m->station_id), le16_to_cpu(m->ATIM_window), |
1053 | m->CFP_mode, m->privacy_option_implemented, m->DTIM_period, | 1047 | m->CFP_mode, m->privacy_option_implemented, m->DTIM_period, |
1054 | m->CFP_period, mac2str(m->current_bssid), | 1048 | m->CFP_period, m->current_bssid, |
1055 | hex2str(m->current_essid, IW_ESSID_MAX_SIZE), | 1049 | hex2str(m->current_essid, IW_ESSID_MAX_SIZE), |
1056 | m->current_bss_type, m->power_mgmt_mode, m->ibss_change, | 1050 | m->current_bss_type, m->power_mgmt_mode, m->ibss_change, |
1057 | m->res, m->multi_domain_capability_implemented, | 1051 | m->res, m->multi_domain_capability_implemented, |
@@ -1080,7 +1074,7 @@ static void at76_dump_mib_mac(struct at76_priv *priv) | |||
1080 | "cwmin %d cwmax %d short_retry_time %d long_retry_time %d " | 1074 | "cwmin %d cwmax %d short_retry_time %d long_retry_time %d " |
1081 | "scan_type %d scan_channel %d probe_delay %u " | 1075 | "scan_type %d scan_channel %d probe_delay %u " |
1082 | "min_channel_time %d max_channel_time %d listen_int %d " | 1076 | "min_channel_time %d max_channel_time %d listen_int %d " |
1083 | "desired_ssid %s desired_bssid %s desired_bsstype %d", | 1077 | "desired_ssid %s desired_bssid %pM desired_bsstype %d", |
1084 | wiphy_name(priv->hw->wiphy), | 1078 | wiphy_name(priv->hw->wiphy), |
1085 | le32_to_cpu(m->max_tx_msdu_lifetime), | 1079 | le32_to_cpu(m->max_tx_msdu_lifetime), |
1086 | le32_to_cpu(m->max_rx_lifetime), | 1080 | le32_to_cpu(m->max_rx_lifetime), |
@@ -1092,7 +1086,7 @@ static void at76_dump_mib_mac(struct at76_priv *priv) | |||
1092 | le16_to_cpu(m->max_channel_time), | 1086 | le16_to_cpu(m->max_channel_time), |
1093 | le16_to_cpu(m->listen_interval), | 1087 | le16_to_cpu(m->listen_interval), |
1094 | hex2str(m->desired_ssid, IW_ESSID_MAX_SIZE), | 1088 | hex2str(m->desired_ssid, IW_ESSID_MAX_SIZE), |
1095 | mac2str(m->desired_bssid), m->desired_bsstype); | 1089 | m->desired_bssid, m->desired_bsstype); |
1096 | exit: | 1090 | exit: |
1097 | kfree(m); | 1091 | kfree(m); |
1098 | } | 1092 | } |
@@ -1194,6 +1188,9 @@ static int at76_start_monitor(struct at76_priv *priv) | |||
1194 | scan.channel = priv->channel; | 1188 | scan.channel = priv->channel; |
1195 | scan.scan_type = SCAN_TYPE_PASSIVE; | 1189 | scan.scan_type = SCAN_TYPE_PASSIVE; |
1196 | scan.international_scan = 0; | 1190 | scan.international_scan = 0; |
1191 | scan.min_channel_time = cpu_to_le16(priv->scan_min_time); | ||
1192 | scan.max_channel_time = cpu_to_le16(priv->scan_max_time); | ||
1193 | scan.probe_delay = cpu_to_le16(0); | ||
1197 | 1194 | ||
1198 | ret = at76_set_card_command(priv->udev, CMD_SCAN, &scan, sizeof(scan)); | 1195 | ret = at76_set_card_command(priv->udev, CMD_SCAN, &scan, sizeof(scan)); |
1199 | if (ret >= 0) | 1196 | if (ret >= 0) |
@@ -2284,9 +2281,9 @@ static int at76_init_new_device(struct at76_priv *priv, | |||
2284 | 2281 | ||
2285 | priv->mac80211_registered = 1; | 2282 | priv->mac80211_registered = 1; |
2286 | 2283 | ||
2287 | printk(KERN_INFO "%s: USB %s, MAC %s, firmware %d.%d.%d-%d\n", | 2284 | printk(KERN_INFO "%s: USB %s, MAC %pM, firmware %d.%d.%d-%d\n", |
2288 | wiphy_name(priv->hw->wiphy), | 2285 | wiphy_name(priv->hw->wiphy), |
2289 | dev_name(&interface->dev), mac2str(priv->mac_addr), | 2286 | dev_name(&interface->dev), priv->mac_addr, |
2290 | priv->fw_version.major, priv->fw_version.minor, | 2287 | priv->fw_version.major, priv->fw_version.minor, |
2291 | priv->fw_version.patch, priv->fw_version.build); | 2288 | priv->fw_version.patch, priv->fw_version.build); |
2292 | printk(KERN_INFO "%s: regulatory domain 0x%02x: %s\n", | 2289 | printk(KERN_INFO "%s: regulatory domain 0x%02x: %s\n", |
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index 5e19a7330d39..9e05648356fe 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h | |||
@@ -21,8 +21,28 @@ | |||
21 | #include <linux/if_ether.h> | 21 | #include <linux/if_ether.h> |
22 | #include <net/mac80211.h> | 22 | #include <net/mac80211.h> |
23 | 23 | ||
24 | /* | ||
25 | * The key cache is used for h/w cipher state and also for | ||
26 | * tracking station state such as the current tx antenna. | ||
27 | * We also setup a mapping table between key cache slot indices | ||
28 | * and station state to short-circuit node lookups on rx. | ||
29 | * Different parts have different size key caches. We handle | ||
30 | * up to ATH_KEYMAX entries (could dynamically allocate state). | ||
31 | */ | ||
32 | #define ATH_KEYMAX 128 /* max key cache size we handle */ | ||
33 | |||
24 | static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | 34 | static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; |
25 | 35 | ||
36 | struct ath_ani { | ||
37 | bool caldone; | ||
38 | int16_t noise_floor; | ||
39 | unsigned int longcal_timer; | ||
40 | unsigned int shortcal_timer; | ||
41 | unsigned int resetcal_timer; | ||
42 | unsigned int checkani_timer; | ||
43 | struct timer_list timer; | ||
44 | }; | ||
45 | |||
26 | enum ath_device_state { | 46 | enum ath_device_state { |
27 | ATH_HW_UNAVAILABLE, | 47 | ATH_HW_UNAVAILABLE, |
28 | ATH_HW_INITIALIZED, | 48 | ATH_HW_INITIALIZED, |
@@ -66,6 +86,8 @@ struct ath_common { | |||
66 | int debug_mask; | 86 | int debug_mask; |
67 | enum ath_device_state state; | 87 | enum ath_device_state state; |
68 | 88 | ||
89 | struct ath_ani ani; | ||
90 | |||
69 | u16 cachelsz; | 91 | u16 cachelsz; |
70 | u16 curaid; | 92 | u16 curaid; |
71 | u8 macaddr[ETH_ALEN]; | 93 | u8 macaddr[ETH_ALEN]; |
@@ -75,6 +97,12 @@ struct ath_common { | |||
75 | u8 tx_chainmask; | 97 | u8 tx_chainmask; |
76 | u8 rx_chainmask; | 98 | u8 rx_chainmask; |
77 | 99 | ||
100 | u32 rx_bufsize; | ||
101 | |||
102 | u32 keymax; | ||
103 | DECLARE_BITMAP(keymap, ATH_KEYMAX); | ||
104 | u8 splitmic; | ||
105 | |||
78 | struct ath_regulatory regulatory; | 106 | struct ath_regulatory regulatory; |
79 | const struct ath_ops *ops; | 107 | const struct ath_ops *ops; |
80 | const struct ath_bus_ops *bus_ops; | 108 | const struct ath_bus_ops *bus_ops; |
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index cb3dc892d697..a4c086f069b1 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c | |||
@@ -323,10 +323,13 @@ static inline void ath5k_txbuf_free(struct ath5k_softc *sc, | |||
323 | static inline void ath5k_rxbuf_free(struct ath5k_softc *sc, | 323 | static inline void ath5k_rxbuf_free(struct ath5k_softc *sc, |
324 | struct ath5k_buf *bf) | 324 | struct ath5k_buf *bf) |
325 | { | 325 | { |
326 | struct ath5k_hw *ah = sc->ah; | ||
327 | struct ath_common *common = ath5k_hw_common(ah); | ||
328 | |||
326 | BUG_ON(!bf); | 329 | BUG_ON(!bf); |
327 | if (!bf->skb) | 330 | if (!bf->skb) |
328 | return; | 331 | return; |
329 | pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize, | 332 | pci_unmap_single(sc->pdev, bf->skbaddr, common->rx_bufsize, |
330 | PCI_DMA_FROMDEVICE); | 333 | PCI_DMA_FROMDEVICE); |
331 | dev_kfree_skb_any(bf->skb); | 334 | dev_kfree_skb_any(bf->skb); |
332 | bf->skb = NULL; | 335 | bf->skb = NULL; |
@@ -1181,17 +1184,18 @@ struct sk_buff *ath5k_rx_skb_alloc(struct ath5k_softc *sc, dma_addr_t *skb_addr) | |||
1181 | * fake physical layer header at the start. | 1184 | * fake physical layer header at the start. |
1182 | */ | 1185 | */ |
1183 | skb = ath_rxbuf_alloc(common, | 1186 | skb = ath_rxbuf_alloc(common, |
1184 | sc->rxbufsize + common->cachelsz - 1, | 1187 | common->rx_bufsize, |
1185 | GFP_ATOMIC); | 1188 | GFP_ATOMIC); |
1186 | 1189 | ||
1187 | if (!skb) { | 1190 | if (!skb) { |
1188 | ATH5K_ERR(sc, "can't alloc skbuff of size %u\n", | 1191 | ATH5K_ERR(sc, "can't alloc skbuff of size %u\n", |
1189 | sc->rxbufsize + common->cachelsz - 1); | 1192 | common->rx_bufsize); |
1190 | return NULL; | 1193 | return NULL; |
1191 | } | 1194 | } |
1192 | 1195 | ||
1193 | *skb_addr = pci_map_single(sc->pdev, | 1196 | *skb_addr = pci_map_single(sc->pdev, |
1194 | skb->data, sc->rxbufsize, PCI_DMA_FROMDEVICE); | 1197 | skb->data, common->rx_bufsize, |
1198 | PCI_DMA_FROMDEVICE); | ||
1195 | if (unlikely(pci_dma_mapping_error(sc->pdev, *skb_addr))) { | 1199 | if (unlikely(pci_dma_mapping_error(sc->pdev, *skb_addr))) { |
1196 | ATH5K_ERR(sc, "%s: DMA mapping failed\n", __func__); | 1200 | ATH5K_ERR(sc, "%s: DMA mapping failed\n", __func__); |
1197 | dev_kfree_skb(skb); | 1201 | dev_kfree_skb(skb); |
@@ -1631,10 +1635,10 @@ ath5k_rx_start(struct ath5k_softc *sc) | |||
1631 | struct ath5k_buf *bf; | 1635 | struct ath5k_buf *bf; |
1632 | int ret; | 1636 | int ret; |
1633 | 1637 | ||
1634 | sc->rxbufsize = roundup(IEEE80211_MAX_LEN, common->cachelsz); | 1638 | common->rx_bufsize = roundup(IEEE80211_MAX_LEN, common->cachelsz); |
1635 | 1639 | ||
1636 | ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rxbufsize %u\n", | 1640 | ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rx_bufsize %u\n", |
1637 | common->cachelsz, sc->rxbufsize); | 1641 | common->cachelsz, common->rx_bufsize); |
1638 | 1642 | ||
1639 | spin_lock_bh(&sc->rxbuflock); | 1643 | spin_lock_bh(&sc->rxbuflock); |
1640 | sc->rxlink = NULL; | 1644 | sc->rxlink = NULL; |
@@ -1679,6 +1683,8 @@ static unsigned int | |||
1679 | ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds, | 1683 | ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds, |
1680 | struct sk_buff *skb, struct ath5k_rx_status *rs) | 1684 | struct sk_buff *skb, struct ath5k_rx_status *rs) |
1681 | { | 1685 | { |
1686 | struct ath5k_hw *ah = sc->ah; | ||
1687 | struct ath_common *common = ath5k_hw_common(ah); | ||
1682 | struct ieee80211_hdr *hdr = (void *)skb->data; | 1688 | struct ieee80211_hdr *hdr = (void *)skb->data; |
1683 | unsigned int keyix, hlen; | 1689 | unsigned int keyix, hlen; |
1684 | 1690 | ||
@@ -1695,7 +1701,7 @@ ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds, | |||
1695 | skb->len >= hlen + 4) { | 1701 | skb->len >= hlen + 4) { |
1696 | keyix = skb->data[hlen + 3] >> 6; | 1702 | keyix = skb->data[hlen + 3] >> 6; |
1697 | 1703 | ||
1698 | if (test_bit(keyix, sc->keymap)) | 1704 | if (test_bit(keyix, common->keymap)) |
1699 | return RX_FLAG_DECRYPTED; | 1705 | return RX_FLAG_DECRYPTED; |
1700 | } | 1706 | } |
1701 | 1707 | ||
@@ -1769,6 +1775,8 @@ ath5k_tasklet_rx(unsigned long data) | |||
1769 | struct sk_buff *skb, *next_skb; | 1775 | struct sk_buff *skb, *next_skb; |
1770 | dma_addr_t next_skb_addr; | 1776 | dma_addr_t next_skb_addr; |
1771 | struct ath5k_softc *sc = (void *)data; | 1777 | struct ath5k_softc *sc = (void *)data; |
1778 | struct ath5k_hw *ah = sc->ah; | ||
1779 | struct ath_common *common = ath5k_hw_common(ah); | ||
1772 | struct ath5k_buf *bf; | 1780 | struct ath5k_buf *bf; |
1773 | struct ath5k_desc *ds; | 1781 | struct ath5k_desc *ds; |
1774 | int ret; | 1782 | int ret; |
@@ -1846,7 +1854,7 @@ accept: | |||
1846 | if (!next_skb) | 1854 | if (!next_skb) |
1847 | goto next; | 1855 | goto next; |
1848 | 1856 | ||
1849 | pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize, | 1857 | pci_unmap_single(sc->pdev, bf->skbaddr, common->rx_bufsize, |
1850 | PCI_DMA_FROMDEVICE); | 1858 | PCI_DMA_FROMDEVICE); |
1851 | skb_put(skb, rs.rs_datalen); | 1859 | skb_put(skb, rs.rs_datalen); |
1852 | 1860 | ||
@@ -3032,6 +3040,8 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
3032 | struct ieee80211_key_conf *key) | 3040 | struct ieee80211_key_conf *key) |
3033 | { | 3041 | { |
3034 | struct ath5k_softc *sc = hw->priv; | 3042 | struct ath5k_softc *sc = hw->priv; |
3043 | struct ath5k_hw *ah = sc->ah; | ||
3044 | struct ath_common *common = ath5k_hw_common(ah); | ||
3035 | int ret = 0; | 3045 | int ret = 0; |
3036 | 3046 | ||
3037 | if (modparam_nohwcrypt) | 3047 | if (modparam_nohwcrypt) |
@@ -3064,14 +3074,14 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
3064 | ATH5K_ERR(sc, "can't set the key\n"); | 3074 | ATH5K_ERR(sc, "can't set the key\n"); |
3065 | goto unlock; | 3075 | goto unlock; |
3066 | } | 3076 | } |
3067 | __set_bit(key->keyidx, sc->keymap); | 3077 | __set_bit(key->keyidx, common->keymap); |
3068 | key->hw_key_idx = key->keyidx; | 3078 | key->hw_key_idx = key->keyidx; |
3069 | key->flags |= (IEEE80211_KEY_FLAG_GENERATE_IV | | 3079 | key->flags |= (IEEE80211_KEY_FLAG_GENERATE_IV | |
3070 | IEEE80211_KEY_FLAG_GENERATE_MMIC); | 3080 | IEEE80211_KEY_FLAG_GENERATE_MMIC); |
3071 | break; | 3081 | break; |
3072 | case DISABLE_KEY: | 3082 | case DISABLE_KEY: |
3073 | ath5k_hw_reset_key(sc->ah, key->keyidx); | 3083 | ath5k_hw_reset_key(sc->ah, key->keyidx); |
3074 | __clear_bit(key->keyidx, sc->keymap); | 3084 | __clear_bit(key->keyidx, common->keymap); |
3075 | break; | 3085 | break; |
3076 | default: | 3086 | default: |
3077 | ret = -EINVAL; | 3087 | ret = -EINVAL; |
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index b14ba07e9157..b72338c9bde7 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h | |||
@@ -153,8 +153,6 @@ struct ath5k_softc { | |||
153 | 153 | ||
154 | enum ath5k_int imask; /* interrupt mask copy */ | 154 | enum ath5k_int imask; /* interrupt mask copy */ |
155 | 155 | ||
156 | DECLARE_BITMAP(keymap, AR5K_KEYCACHE_SIZE); /* key use bit map */ | ||
157 | |||
158 | u8 bssidmask[ETH_ALEN]; | 156 | u8 bssidmask[ETH_ALEN]; |
159 | 157 | ||
160 | unsigned int led_pin, /* GPIO pin for driving LED */ | 158 | unsigned int led_pin, /* GPIO pin for driving LED */ |
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 895990751d36..721ec5ee381d 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c | |||
@@ -3025,8 +3025,6 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, | |||
3025 | ATH5K_ERR(ah->ah_sc, "invalid tx power: %u\n", txpower); | 3025 | ATH5K_ERR(ah->ah_sc, "invalid tx power: %u\n", txpower); |
3026 | return -EINVAL; | 3026 | return -EINVAL; |
3027 | } | 3027 | } |
3028 | if (txpower == 0) | ||
3029 | txpower = AR5K_TUNE_DEFAULT_TXPOWER; | ||
3030 | 3028 | ||
3031 | /* Reset TX power values */ | 3029 | /* Reset TX power values */ |
3032 | memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower)); | 3030 | memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower)); |
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index b735fb399fb1..006364f76bb4 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig | |||
@@ -1,5 +1,7 @@ | |||
1 | config ATH9K_HW | 1 | config ATH9K_HW |
2 | tristate | 2 | tristate |
3 | config ATH9K_COMMON | ||
4 | tristate | ||
3 | 5 | ||
4 | config ATH9K | 6 | config ATH9K |
5 | tristate "Atheros 802.11n wireless cards support" | 7 | tristate "Atheros 802.11n wireless cards support" |
@@ -8,6 +10,7 @@ config ATH9K | |||
8 | select MAC80211_LEDS | 10 | select MAC80211_LEDS |
9 | select LEDS_CLASS | 11 | select LEDS_CLASS |
10 | select NEW_LEDS | 12 | select NEW_LEDS |
13 | select ATH9K_COMMON | ||
11 | ---help--- | 14 | ---help--- |
12 | This module adds support for wireless adapters based on | 15 | This module adds support for wireless adapters based on |
13 | Atheros IEEE 802.11n AR5008, AR9001 and AR9002 family | 16 | Atheros IEEE 802.11n AR5008, AR9001 and AR9002 family |
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 8caf2a8f8953..e53f9680a385 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile | |||
@@ -23,3 +23,6 @@ ath9k_hw-y:= hw.o \ | |||
23 | mac.o \ | 23 | mac.o \ |
24 | 24 | ||
25 | obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o | 25 | obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o |
26 | |||
27 | obj-$(CONFIG_ATH9K_COMMON) += ath9k_common.o | ||
28 | ath9k_common-y:= common.o | ||
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 13dd0202d6b5..d9bcc3abb425 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -19,14 +19,16 @@ | |||
19 | 19 | ||
20 | #include <linux/etherdevice.h> | 20 | #include <linux/etherdevice.h> |
21 | #include <linux/device.h> | 21 | #include <linux/device.h> |
22 | #include <net/mac80211.h> | ||
23 | #include <linux/leds.h> | 22 | #include <linux/leds.h> |
24 | 23 | ||
25 | #include "hw.h" | ||
26 | #include "rc.h" | 24 | #include "rc.h" |
27 | #include "debug.h" | 25 | #include "debug.h" |
28 | #include "../ath.h" | 26 | #include "common.h" |
29 | #include "../debug.h" | 27 | |
28 | /* | ||
29 | * Header for the ath9k.ko driver core *only* -- hw code nor any other driver | ||
30 | * should rely on this file or its contents. | ||
31 | */ | ||
30 | 32 | ||
31 | struct ath_node; | 33 | struct ath_node; |
32 | 34 | ||
@@ -99,18 +101,6 @@ enum buffer_type { | |||
99 | BUF_XRETRY = BIT(5), | 101 | BUF_XRETRY = BIT(5), |
100 | }; | 102 | }; |
101 | 103 | ||
102 | struct ath_buf_state { | ||
103 | int bfs_nframes; | ||
104 | u16 bfs_al; | ||
105 | u16 bfs_frmlen; | ||
106 | int bfs_seqno; | ||
107 | int bfs_tidno; | ||
108 | int bfs_retries; | ||
109 | u8 bf_type; | ||
110 | u32 bfs_keyix; | ||
111 | enum ath9k_key_type bfs_keytype; | ||
112 | }; | ||
113 | |||
114 | #define bf_nframes bf_state.bfs_nframes | 104 | #define bf_nframes bf_state.bfs_nframes |
115 | #define bf_al bf_state.bfs_al | 105 | #define bf_al bf_state.bfs_al |
116 | #define bf_frmlen bf_state.bfs_frmlen | 106 | #define bf_frmlen bf_state.bfs_frmlen |
@@ -125,21 +115,6 @@ struct ath_buf_state { | |||
125 | #define bf_isretried(bf) (bf->bf_state.bf_type & BUF_RETRY) | 115 | #define bf_isretried(bf) (bf->bf_state.bf_type & BUF_RETRY) |
126 | #define bf_isxretried(bf) (bf->bf_state.bf_type & BUF_XRETRY) | 116 | #define bf_isxretried(bf) (bf->bf_state.bf_type & BUF_XRETRY) |
127 | 117 | ||
128 | struct ath_buf { | ||
129 | struct list_head list; | ||
130 | struct ath_buf *bf_lastbf; /* last buf of this unit (a frame or | ||
131 | an aggregate) */ | ||
132 | struct ath_buf *bf_next; /* next subframe in the aggregate */ | ||
133 | struct sk_buff *bf_mpdu; /* enclosing frame structure */ | ||
134 | struct ath_desc *bf_desc; /* virtual addr of desc */ | ||
135 | dma_addr_t bf_daddr; /* physical addr of desc */ | ||
136 | dma_addr_t bf_buf_addr; /* physical addr of data buffer */ | ||
137 | bool bf_stale; | ||
138 | u16 bf_flags; | ||
139 | struct ath_buf_state bf_state; | ||
140 | dma_addr_t bf_dmacontext; | ||
141 | }; | ||
142 | |||
143 | struct ath_descdma { | 118 | struct ath_descdma { |
144 | struct ath_desc *dd_desc; | 119 | struct ath_desc *dd_desc; |
145 | dma_addr_t dd_desc_paddr; | 120 | dma_addr_t dd_desc_paddr; |
@@ -159,13 +134,9 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, | |||
159 | 134 | ||
160 | #define ATH_MAX_ANTENNA 3 | 135 | #define ATH_MAX_ANTENNA 3 |
161 | #define ATH_RXBUF 512 | 136 | #define ATH_RXBUF 512 |
162 | #define WME_NUM_TID 16 | ||
163 | #define ATH_TXBUF 512 | 137 | #define ATH_TXBUF 512 |
164 | #define ATH_TXMAXTRY 13 | 138 | #define ATH_TXMAXTRY 13 |
165 | #define ATH_MGT_TXMAXTRY 4 | 139 | #define ATH_MGT_TXMAXTRY 4 |
166 | #define WME_BA_BMP_SIZE 64 | ||
167 | #define WME_MAX_BA WME_BA_BMP_SIZE | ||
168 | #define ATH_TID_MAX_BUFS (2 * WME_MAX_BA) | ||
169 | 140 | ||
170 | #define TID_TO_WME_AC(_tid) \ | 141 | #define TID_TO_WME_AC(_tid) \ |
171 | ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \ | 142 | ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \ |
@@ -173,12 +144,6 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, | |||
173 | (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \ | 144 | (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \ |
174 | WME_AC_VO) | 145 | WME_AC_VO) |
175 | 146 | ||
176 | #define WME_AC_BE 0 | ||
177 | #define WME_AC_BK 1 | ||
178 | #define WME_AC_VI 2 | ||
179 | #define WME_AC_VO 3 | ||
180 | #define WME_NUM_AC 4 | ||
181 | |||
182 | #define ADDBA_EXCHANGE_ATTEMPTS 10 | 147 | #define ADDBA_EXCHANGE_ATTEMPTS 10 |
183 | #define ATH_AGGR_DELIM_SZ 4 | 148 | #define ATH_AGGR_DELIM_SZ 4 |
184 | #define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */ | 149 | #define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */ |
@@ -252,30 +217,6 @@ struct ath_txq { | |||
252 | #define AGGR_ADDBA_COMPLETE BIT(2) | 217 | #define AGGR_ADDBA_COMPLETE BIT(2) |
253 | #define AGGR_ADDBA_PROGRESS BIT(3) | 218 | #define AGGR_ADDBA_PROGRESS BIT(3) |
254 | 219 | ||
255 | struct ath_atx_tid { | ||
256 | struct list_head list; | ||
257 | struct list_head buf_q; | ||
258 | struct ath_node *an; | ||
259 | struct ath_atx_ac *ac; | ||
260 | struct ath_buf *tx_buf[ATH_TID_MAX_BUFS]; | ||
261 | u16 seq_start; | ||
262 | u16 seq_next; | ||
263 | u16 baw_size; | ||
264 | int tidno; | ||
265 | int baw_head; /* first un-acked tx buffer */ | ||
266 | int baw_tail; /* next unused tx buffer slot */ | ||
267 | int sched; | ||
268 | int paused; | ||
269 | u8 state; | ||
270 | }; | ||
271 | |||
272 | struct ath_atx_ac { | ||
273 | int sched; | ||
274 | int qnum; | ||
275 | struct list_head list; | ||
276 | struct list_head tid_q; | ||
277 | }; | ||
278 | |||
279 | struct ath_tx_control { | 220 | struct ath_tx_control { |
280 | struct ath_txq *txq; | 221 | struct ath_txq *txq; |
281 | int if_id; | 222 | int if_id; |
@@ -286,29 +227,6 @@ struct ath_tx_control { | |||
286 | #define ATH_TX_XRETRY 0x02 | 227 | #define ATH_TX_XRETRY 0x02 |
287 | #define ATH_TX_BAR 0x04 | 228 | #define ATH_TX_BAR 0x04 |
288 | 229 | ||
289 | #define ATH_RSSI_LPF_LEN 10 | ||
290 | #define RSSI_LPF_THRESHOLD -20 | ||
291 | #define ATH_RSSI_EP_MULTIPLIER (1<<7) | ||
292 | #define ATH_EP_MUL(x, mul) ((x) * (mul)) | ||
293 | #define ATH_RSSI_IN(x) (ATH_EP_MUL((x), ATH_RSSI_EP_MULTIPLIER)) | ||
294 | #define ATH_LPF_RSSI(x, y, len) \ | ||
295 | ((x != ATH_RSSI_DUMMY_MARKER) ? (((x) * ((len) - 1) + (y)) / (len)) : (y)) | ||
296 | #define ATH_RSSI_LPF(x, y) do { \ | ||
297 | if ((y) >= RSSI_LPF_THRESHOLD) \ | ||
298 | x = ATH_LPF_RSSI((x), ATH_RSSI_IN((y)), ATH_RSSI_LPF_LEN); \ | ||
299 | } while (0) | ||
300 | #define ATH_EP_RND(x, mul) \ | ||
301 | ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) | ||
302 | |||
303 | struct ath_node { | ||
304 | struct ath_softc *an_sc; | ||
305 | struct ath_atx_tid tid[WME_NUM_TID]; | ||
306 | struct ath_atx_ac ac[WME_NUM_AC]; | ||
307 | u16 maxampdu; | ||
308 | u8 mpdudensity; | ||
309 | int last_rssi; | ||
310 | }; | ||
311 | |||
312 | struct ath_tx { | 230 | struct ath_tx { |
313 | u16 seq_no; | 231 | u16 seq_no; |
314 | u32 txqsetup; | 232 | u32 txqsetup; |
@@ -323,7 +241,6 @@ struct ath_rx { | |||
323 | u8 defant; | 241 | u8 defant; |
324 | u8 rxotherant; | 242 | u8 rxotherant; |
325 | u32 *rxlink; | 243 | u32 *rxlink; |
326 | int bufsize; | ||
327 | unsigned int rxfilter; | 244 | unsigned int rxfilter; |
328 | spinlock_t rxflushlock; | 245 | spinlock_t rxflushlock; |
329 | spinlock_t rxbuflock; | 246 | spinlock_t rxbuflock; |
@@ -434,16 +351,6 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp); | |||
434 | #define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */ | 351 | #define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */ |
435 | #define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */ | 352 | #define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */ |
436 | 353 | ||
437 | struct ath_ani { | ||
438 | bool caldone; | ||
439 | int16_t noise_floor; | ||
440 | unsigned int longcal_timer; | ||
441 | unsigned int shortcal_timer; | ||
442 | unsigned int resetcal_timer; | ||
443 | unsigned int checkani_timer; | ||
444 | struct timer_list timer; | ||
445 | }; | ||
446 | |||
447 | /* Defines the BT AR_BT_COEX_WGHT used */ | 354 | /* Defines the BT AR_BT_COEX_WGHT used */ |
448 | enum ath_stomp_type { | 355 | enum ath_stomp_type { |
449 | ATH_BTCOEX_NO_STOMP, | 356 | ATH_BTCOEX_NO_STOMP, |
@@ -503,18 +410,7 @@ struct ath_led { | |||
503 | #define ATH_CHAN_MAX 255 | 410 | #define ATH_CHAN_MAX 255 |
504 | #define IEEE80211_WEP_NKID 4 /* number of key ids */ | 411 | #define IEEE80211_WEP_NKID 4 /* number of key ids */ |
505 | 412 | ||
506 | /* | ||
507 | * The key cache is used for h/w cipher state and also for | ||
508 | * tracking station state such as the current tx antenna. | ||
509 | * We also setup a mapping table between key cache slot indices | ||
510 | * and station state to short-circuit node lookups on rx. | ||
511 | * Different parts have different size key caches. We handle | ||
512 | * up to ATH_KEYMAX entries (could dynamically allocate state). | ||
513 | */ | ||
514 | #define ATH_KEYMAX 128 /* max key cache size we handle */ | ||
515 | |||
516 | #define ATH_TXPOWER_MAX 100 /* .5 dBm units */ | 413 | #define ATH_TXPOWER_MAX 100 /* .5 dBm units */ |
517 | #define ATH_RSSI_DUMMY_MARKER 0x127 | ||
518 | #define ATH_RATE_DUMMY_MARKER 0 | 414 | #define ATH_RATE_DUMMY_MARKER 0 |
519 | 415 | ||
520 | #define SC_OP_INVALID BIT(0) | 416 | #define SC_OP_INVALID BIT(0) |
@@ -573,9 +469,6 @@ struct ath_softc { | |||
573 | u16 curtxpow; | 469 | u16 curtxpow; |
574 | u8 nbcnvifs; | 470 | u8 nbcnvifs; |
575 | u16 nvifs; | 471 | u16 nvifs; |
576 | u32 keymax; | ||
577 | DECLARE_BITMAP(keymap, ATH_KEYMAX); | ||
578 | u8 splitmic; | ||
579 | bool ps_enabled; | 472 | bool ps_enabled; |
580 | unsigned long ps_usecount; | 473 | unsigned long ps_usecount; |
581 | enum ath9k_int imask; | 474 | enum ath9k_int imask; |
@@ -601,7 +494,6 @@ struct ath_softc { | |||
601 | 494 | ||
602 | int beacon_interval; | 495 | int beacon_interval; |
603 | 496 | ||
604 | struct ath_ani ani; | ||
605 | #ifdef CONFIG_ATH9K_DEBUG | 497 | #ifdef CONFIG_ATH9K_DEBUG |
606 | struct ath9k_debug debug; | 498 | struct ath9k_debug debug; |
607 | #endif | 499 | #endif |
@@ -620,6 +512,7 @@ struct ath_wiphy { | |||
620 | ATH_WIPHY_PAUSED, | 512 | ATH_WIPHY_PAUSED, |
621 | ATH_WIPHY_SCAN, | 513 | ATH_WIPHY_SCAN, |
622 | } state; | 514 | } state; |
515 | bool idle; | ||
623 | int chan_idx; | 516 | int chan_idx; |
624 | int chan_is_ht; | 517 | int chan_is_ht; |
625 | }; | 518 | }; |
@@ -654,8 +547,9 @@ void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw, | |||
654 | void ath_update_chainmask(struct ath_softc *sc, int is_ht); | 547 | void ath_update_chainmask(struct ath_softc *sc, int is_ht); |
655 | int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, | 548 | int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, |
656 | struct ath9k_channel *hchan); | 549 | struct ath9k_channel *hchan); |
657 | void ath_radio_enable(struct ath_softc *sc); | 550 | |
658 | void ath_radio_disable(struct ath_softc *sc); | 551 | void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw); |
552 | void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw); | ||
659 | 553 | ||
660 | #ifdef CONFIG_PCI | 554 | #ifdef CONFIG_PCI |
661 | int ath_pci_init(void); | 555 | int ath_pci_init(void); |
@@ -691,6 +585,10 @@ void ath9k_wiphy_pause_all_forced(struct ath_softc *sc, | |||
691 | bool ath9k_wiphy_scanning(struct ath_softc *sc); | 585 | bool ath9k_wiphy_scanning(struct ath_softc *sc); |
692 | void ath9k_wiphy_work(struct work_struct *work); | 586 | void ath9k_wiphy_work(struct work_struct *work); |
693 | bool ath9k_all_wiphys_idle(struct ath_softc *sc); | 587 | bool ath9k_all_wiphys_idle(struct ath_softc *sc); |
588 | void ath9k_set_wiphy_idle(struct ath_wiphy *aphy, bool idle); | ||
589 | |||
590 | void ath_mac80211_stop_queue(struct ath_softc *sc, u16 skb_queue); | ||
591 | void ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue); | ||
694 | 592 | ||
695 | int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype); | 593 | int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype); |
696 | #endif /* ATH9K_H */ | 594 | #endif /* ATH9K_H */ |
diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c new file mode 100644 index 000000000000..2f1e1612e2ad --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common.c | |||
@@ -0,0 +1,286 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2009 Atheros Communications Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | /* | ||
18 | * Module for common driver code between ath9k and ath9k_htc | ||
19 | */ | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/module.h> | ||
23 | |||
24 | #include "common.h" | ||
25 | |||
26 | MODULE_AUTHOR("Atheros Communications"); | ||
27 | MODULE_DESCRIPTION("Shared library for Atheros wireless 802.11n LAN cards."); | ||
28 | MODULE_LICENSE("Dual BSD/GPL"); | ||
29 | |||
30 | /* Common RX processing */ | ||
31 | |||
32 | /* Assumes you've already done the endian to CPU conversion */ | ||
33 | static bool ath9k_rx_accept(struct ath_common *common, | ||
34 | struct sk_buff *skb, | ||
35 | struct ieee80211_rx_status *rxs, | ||
36 | struct ath_rx_status *rx_stats, | ||
37 | bool *decrypt_error) | ||
38 | { | ||
39 | struct ath_hw *ah = common->ah; | ||
40 | struct ieee80211_hdr *hdr; | ||
41 | __le16 fc; | ||
42 | |||
43 | hdr = (struct ieee80211_hdr *) skb->data; | ||
44 | fc = hdr->frame_control; | ||
45 | |||
46 | if (!rx_stats->rs_datalen) | ||
47 | return false; | ||
48 | /* | ||
49 | * rs_status follows rs_datalen so if rs_datalen is too large | ||
50 | * we can take a hint that hardware corrupted it, so ignore | ||
51 | * those frames. | ||
52 | */ | ||
53 | if (rx_stats->rs_datalen > common->rx_bufsize) | ||
54 | return false; | ||
55 | |||
56 | /* | ||
57 | * rs_more indicates chained descriptors which can be used | ||
58 | * to link buffers together for a sort of scatter-gather | ||
59 | * operation. | ||
60 | * | ||
61 | * The rx_stats->rs_status will not be set until the end of the | ||
62 | * chained descriptors so it can be ignored if rs_more is set. The | ||
63 | * rs_more will be false at the last element of the chained | ||
64 | * descriptors. | ||
65 | */ | ||
66 | if (!rx_stats->rs_more && rx_stats->rs_status != 0) { | ||
67 | if (rx_stats->rs_status & ATH9K_RXERR_CRC) | ||
68 | rxs->flag |= RX_FLAG_FAILED_FCS_CRC; | ||
69 | if (rx_stats->rs_status & ATH9K_RXERR_PHY) | ||
70 | return false; | ||
71 | |||
72 | if (rx_stats->rs_status & ATH9K_RXERR_DECRYPT) { | ||
73 | *decrypt_error = true; | ||
74 | } else if (rx_stats->rs_status & ATH9K_RXERR_MIC) { | ||
75 | if (ieee80211_is_ctl(fc)) | ||
76 | /* | ||
77 | * Sometimes, we get invalid | ||
78 | * MIC failures on valid control frames. | ||
79 | * Remove these mic errors. | ||
80 | */ | ||
81 | rx_stats->rs_status &= ~ATH9K_RXERR_MIC; | ||
82 | else | ||
83 | rxs->flag |= RX_FLAG_MMIC_ERROR; | ||
84 | } | ||
85 | /* | ||
86 | * Reject error frames with the exception of | ||
87 | * decryption and MIC failures. For monitor mode, | ||
88 | * we also ignore the CRC error. | ||
89 | */ | ||
90 | if (ah->opmode == NL80211_IFTYPE_MONITOR) { | ||
91 | if (rx_stats->rs_status & | ||
92 | ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | | ||
93 | ATH9K_RXERR_CRC)) | ||
94 | return false; | ||
95 | } else { | ||
96 | if (rx_stats->rs_status & | ||
97 | ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) { | ||
98 | return false; | ||
99 | } | ||
100 | } | ||
101 | } | ||
102 | return true; | ||
103 | } | ||
104 | |||
105 | static u8 ath9k_process_rate(struct ath_common *common, | ||
106 | struct ieee80211_hw *hw, | ||
107 | struct ath_rx_status *rx_stats, | ||
108 | struct ieee80211_rx_status *rxs, | ||
109 | struct sk_buff *skb) | ||
110 | { | ||
111 | struct ieee80211_supported_band *sband; | ||
112 | enum ieee80211_band band; | ||
113 | unsigned int i = 0; | ||
114 | |||
115 | band = hw->conf.channel->band; | ||
116 | sband = hw->wiphy->bands[band]; | ||
117 | |||
118 | if (rx_stats->rs_rate & 0x80) { | ||
119 | /* HT rate */ | ||
120 | rxs->flag |= RX_FLAG_HT; | ||
121 | if (rx_stats->rs_flags & ATH9K_RX_2040) | ||
122 | rxs->flag |= RX_FLAG_40MHZ; | ||
123 | if (rx_stats->rs_flags & ATH9K_RX_GI) | ||
124 | rxs->flag |= RX_FLAG_SHORT_GI; | ||
125 | return rx_stats->rs_rate & 0x7f; | ||
126 | } | ||
127 | |||
128 | for (i = 0; i < sband->n_bitrates; i++) { | ||
129 | if (sband->bitrates[i].hw_value == rx_stats->rs_rate) | ||
130 | return i; | ||
131 | if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) { | ||
132 | rxs->flag |= RX_FLAG_SHORTPRE; | ||
133 | return i; | ||
134 | } | ||
135 | } | ||
136 | |||
137 | /* No valid hardware bitrate found -- we should not get here */ | ||
138 | ath_print(common, ATH_DBG_XMIT, "unsupported hw bitrate detected " | ||
139 | "0x%02x using 1 Mbit\n", rx_stats->rs_rate); | ||
140 | if ((common->debug_mask & ATH_DBG_XMIT)) | ||
141 | print_hex_dump_bytes("", DUMP_PREFIX_NONE, skb->data, skb->len); | ||
142 | |||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | static void ath9k_process_rssi(struct ath_common *common, | ||
147 | struct ieee80211_hw *hw, | ||
148 | struct sk_buff *skb, | ||
149 | struct ath_rx_status *rx_stats) | ||
150 | { | ||
151 | struct ath_hw *ah = common->ah; | ||
152 | struct ieee80211_sta *sta; | ||
153 | struct ieee80211_hdr *hdr; | ||
154 | struct ath_node *an; | ||
155 | int last_rssi = ATH_RSSI_DUMMY_MARKER; | ||
156 | __le16 fc; | ||
157 | |||
158 | hdr = (struct ieee80211_hdr *)skb->data; | ||
159 | fc = hdr->frame_control; | ||
160 | |||
161 | rcu_read_lock(); | ||
162 | /* | ||
163 | * XXX: use ieee80211_find_sta! This requires quite a bit of work | ||
164 | * under the current ath9k virtual wiphy implementation as we have | ||
165 | * no way of tying a vif to wiphy. Typically vifs are attached to | ||
166 | * at least one sdata of a wiphy on mac80211 but with ath9k virtual | ||
167 | * wiphy you'd have to iterate over every wiphy and each sdata. | ||
168 | */ | ||
169 | sta = ieee80211_find_sta_by_hw(hw, hdr->addr2); | ||
170 | if (sta) { | ||
171 | an = (struct ath_node *) sta->drv_priv; | ||
172 | if (rx_stats->rs_rssi != ATH9K_RSSI_BAD && | ||
173 | !rx_stats->rs_moreaggr) | ||
174 | ATH_RSSI_LPF(an->last_rssi, rx_stats->rs_rssi); | ||
175 | last_rssi = an->last_rssi; | ||
176 | } | ||
177 | rcu_read_unlock(); | ||
178 | |||
179 | if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) | ||
180 | rx_stats->rs_rssi = ATH_EP_RND(last_rssi, | ||
181 | ATH_RSSI_EP_MULTIPLIER); | ||
182 | if (rx_stats->rs_rssi < 0) | ||
183 | rx_stats->rs_rssi = 0; | ||
184 | else if (rx_stats->rs_rssi > 127) | ||
185 | rx_stats->rs_rssi = 127; | ||
186 | |||
187 | /* Update Beacon RSSI, this is used by ANI. */ | ||
188 | if (ieee80211_is_beacon(fc)) | ||
189 | ah->stats.avgbrssi = rx_stats->rs_rssi; | ||
190 | } | ||
191 | |||
192 | /* | ||
193 | * For Decrypt or Demic errors, we only mark packet status here and always push | ||
194 | * up the frame up to let mac80211 handle the actual error case, be it no | ||
195 | * decryption key or real decryption error. This let us keep statistics there. | ||
196 | */ | ||
197 | int ath9k_cmn_rx_skb_preprocess(struct ath_common *common, | ||
198 | struct ieee80211_hw *hw, | ||
199 | struct sk_buff *skb, | ||
200 | struct ath_rx_status *rx_stats, | ||
201 | struct ieee80211_rx_status *rx_status, | ||
202 | bool *decrypt_error) | ||
203 | { | ||
204 | struct ath_hw *ah = common->ah; | ||
205 | |||
206 | memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); | ||
207 | if (!ath9k_rx_accept(common, skb, rx_status, rx_stats, decrypt_error)) | ||
208 | return -EINVAL; | ||
209 | |||
210 | ath9k_process_rssi(common, hw, skb, rx_stats); | ||
211 | |||
212 | rx_status->rate_idx = ath9k_process_rate(common, hw, | ||
213 | rx_stats, rx_status, skb); | ||
214 | rx_status->mactime = ath9k_hw_extend_tsf(ah, rx_stats->rs_tstamp); | ||
215 | rx_status->band = hw->conf.channel->band; | ||
216 | rx_status->freq = hw->conf.channel->center_freq; | ||
217 | rx_status->noise = common->ani.noise_floor; | ||
218 | rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + rx_stats->rs_rssi; | ||
219 | rx_status->antenna = rx_stats->rs_antenna; | ||
220 | rx_status->flag |= RX_FLAG_TSFT; | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | EXPORT_SYMBOL(ath9k_cmn_rx_skb_preprocess); | ||
225 | |||
226 | void ath9k_cmn_rx_skb_postprocess(struct ath_common *common, | ||
227 | struct sk_buff *skb, | ||
228 | struct ath_rx_status *rx_stats, | ||
229 | struct ieee80211_rx_status *rxs, | ||
230 | bool decrypt_error) | ||
231 | { | ||
232 | struct ath_hw *ah = common->ah; | ||
233 | struct ieee80211_hdr *hdr; | ||
234 | int hdrlen, padsize; | ||
235 | u8 keyix; | ||
236 | __le16 fc; | ||
237 | |||
238 | /* see if any padding is done by the hw and remove it */ | ||
239 | hdr = (struct ieee80211_hdr *) skb->data; | ||
240 | hdrlen = ieee80211_get_hdrlen_from_skb(skb); | ||
241 | fc = hdr->frame_control; | ||
242 | |||
243 | /* The MAC header is padded to have 32-bit boundary if the | ||
244 | * packet payload is non-zero. The general calculation for | ||
245 | * padsize would take into account odd header lengths: | ||
246 | * padsize = (4 - hdrlen % 4) % 4; However, since only | ||
247 | * even-length headers are used, padding can only be 0 or 2 | ||
248 | * bytes and we can optimize this a bit. In addition, we must | ||
249 | * not try to remove padding from short control frames that do | ||
250 | * not have payload. */ | ||
251 | padsize = hdrlen & 3; | ||
252 | if (padsize && hdrlen >= 24) { | ||
253 | memmove(skb->data + padsize, skb->data, hdrlen); | ||
254 | skb_pull(skb, padsize); | ||
255 | } | ||
256 | |||
257 | keyix = rx_stats->rs_keyix; | ||
258 | |||
259 | if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) { | ||
260 | rxs->flag |= RX_FLAG_DECRYPTED; | ||
261 | } else if (ieee80211_has_protected(fc) | ||
262 | && !decrypt_error && skb->len >= hdrlen + 4) { | ||
263 | keyix = skb->data[hdrlen + 3] >> 6; | ||
264 | |||
265 | if (test_bit(keyix, common->keymap)) | ||
266 | rxs->flag |= RX_FLAG_DECRYPTED; | ||
267 | } | ||
268 | if (ah->sw_mgmt_crypto && | ||
269 | (rxs->flag & RX_FLAG_DECRYPTED) && | ||
270 | ieee80211_is_mgmt(fc)) | ||
271 | /* Use software decrypt for management frames. */ | ||
272 | rxs->flag &= ~RX_FLAG_DECRYPTED; | ||
273 | } | ||
274 | EXPORT_SYMBOL(ath9k_cmn_rx_skb_postprocess); | ||
275 | |||
276 | static int __init ath9k_cmn_init(void) | ||
277 | { | ||
278 | return 0; | ||
279 | } | ||
280 | module_init(ath9k_cmn_init); | ||
281 | |||
282 | static void __exit ath9k_cmn_exit(void) | ||
283 | { | ||
284 | return; | ||
285 | } | ||
286 | module_exit(ath9k_cmn_exit); | ||
diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h new file mode 100644 index 000000000000..292e3d860c0e --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common.h | |||
@@ -0,0 +1,123 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2009 Atheros Communications Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include <net/mac80211.h> | ||
18 | |||
19 | #include "../ath.h" | ||
20 | #include "../debug.h" | ||
21 | |||
22 | #include "hw.h" | ||
23 | |||
24 | /* Common header for Atheros 802.11n base driver cores */ | ||
25 | |||
26 | #define WME_NUM_TID 16 | ||
27 | #define WME_BA_BMP_SIZE 64 | ||
28 | #define WME_MAX_BA WME_BA_BMP_SIZE | ||
29 | #define ATH_TID_MAX_BUFS (2 * WME_MAX_BA) | ||
30 | |||
31 | #define WME_AC_BE 0 | ||
32 | #define WME_AC_BK 1 | ||
33 | #define WME_AC_VI 2 | ||
34 | #define WME_AC_VO 3 | ||
35 | #define WME_NUM_AC 4 | ||
36 | |||
37 | #define ATH_RSSI_DUMMY_MARKER 0x127 | ||
38 | #define ATH_RSSI_LPF_LEN 10 | ||
39 | #define RSSI_LPF_THRESHOLD -20 | ||
40 | #define ATH_RSSI_EP_MULTIPLIER (1<<7) | ||
41 | #define ATH_EP_MUL(x, mul) ((x) * (mul)) | ||
42 | #define ATH_RSSI_IN(x) (ATH_EP_MUL((x), ATH_RSSI_EP_MULTIPLIER)) | ||
43 | #define ATH_LPF_RSSI(x, y, len) \ | ||
44 | ((x != ATH_RSSI_DUMMY_MARKER) ? (((x) * ((len) - 1) + (y)) / (len)) : (y)) | ||
45 | #define ATH_RSSI_LPF(x, y) do { \ | ||
46 | if ((y) >= RSSI_LPF_THRESHOLD) \ | ||
47 | x = ATH_LPF_RSSI((x), ATH_RSSI_IN((y)), ATH_RSSI_LPF_LEN); \ | ||
48 | } while (0) | ||
49 | #define ATH_EP_RND(x, mul) \ | ||
50 | ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) | ||
51 | |||
52 | struct ath_atx_ac { | ||
53 | int sched; | ||
54 | int qnum; | ||
55 | struct list_head list; | ||
56 | struct list_head tid_q; | ||
57 | }; | ||
58 | |||
59 | struct ath_buf_state { | ||
60 | int bfs_nframes; | ||
61 | u16 bfs_al; | ||
62 | u16 bfs_frmlen; | ||
63 | int bfs_seqno; | ||
64 | int bfs_tidno; | ||
65 | int bfs_retries; | ||
66 | u8 bf_type; | ||
67 | u32 bfs_keyix; | ||
68 | enum ath9k_key_type bfs_keytype; | ||
69 | }; | ||
70 | |||
71 | struct ath_buf { | ||
72 | struct list_head list; | ||
73 | struct ath_buf *bf_lastbf; /* last buf of this unit (a frame or | ||
74 | an aggregate) */ | ||
75 | struct ath_buf *bf_next; /* next subframe in the aggregate */ | ||
76 | struct sk_buff *bf_mpdu; /* enclosing frame structure */ | ||
77 | struct ath_desc *bf_desc; /* virtual addr of desc */ | ||
78 | dma_addr_t bf_daddr; /* physical addr of desc */ | ||
79 | dma_addr_t bf_buf_addr; /* physical addr of data buffer */ | ||
80 | bool bf_stale; | ||
81 | u16 bf_flags; | ||
82 | struct ath_buf_state bf_state; | ||
83 | dma_addr_t bf_dmacontext; | ||
84 | }; | ||
85 | |||
86 | struct ath_atx_tid { | ||
87 | struct list_head list; | ||
88 | struct list_head buf_q; | ||
89 | struct ath_node *an; | ||
90 | struct ath_atx_ac *ac; | ||
91 | struct ath_buf *tx_buf[ATH_TID_MAX_BUFS]; | ||
92 | u16 seq_start; | ||
93 | u16 seq_next; | ||
94 | u16 baw_size; | ||
95 | int tidno; | ||
96 | int baw_head; /* first un-acked tx buffer */ | ||
97 | int baw_tail; /* next unused tx buffer slot */ | ||
98 | int sched; | ||
99 | int paused; | ||
100 | u8 state; | ||
101 | }; | ||
102 | |||
103 | struct ath_node { | ||
104 | struct ath_common *common; | ||
105 | struct ath_atx_tid tid[WME_NUM_TID]; | ||
106 | struct ath_atx_ac ac[WME_NUM_AC]; | ||
107 | u16 maxampdu; | ||
108 | u8 mpdudensity; | ||
109 | int last_rssi; | ||
110 | }; | ||
111 | |||
112 | int ath9k_cmn_rx_skb_preprocess(struct ath_common *common, | ||
113 | struct ieee80211_hw *hw, | ||
114 | struct sk_buff *skb, | ||
115 | struct ath_rx_status *rx_stats, | ||
116 | struct ieee80211_rx_status *rx_status, | ||
117 | bool *decrypt_error); | ||
118 | |||
119 | void ath9k_cmn_rx_skb_postprocess(struct ath_common *common, | ||
120 | struct sk_buff *skb, | ||
121 | struct ath_rx_status *rx_stats, | ||
122 | struct ieee80211_rx_status *rxs, | ||
123 | bool decrypt_error); | ||
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 111ff049f75d..b25eedf67e0b 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c | |||
@@ -3710,6 +3710,21 @@ void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting) | |||
3710 | } | 3710 | } |
3711 | EXPORT_SYMBOL(ath9k_hw_set_tsfadjust); | 3711 | EXPORT_SYMBOL(ath9k_hw_set_tsfadjust); |
3712 | 3712 | ||
3713 | /* | ||
3714 | * Extend 15-bit time stamp from rx descriptor to | ||
3715 | * a full 64-bit TSF using the current h/w TSF. | ||
3716 | */ | ||
3717 | u64 ath9k_hw_extend_tsf(struct ath_hw *ah, u32 rstamp) | ||
3718 | { | ||
3719 | u64 tsf; | ||
3720 | |||
3721 | tsf = ath9k_hw_gettsf64(ah); | ||
3722 | if ((tsf & 0x7fff) < rstamp) | ||
3723 | tsf -= 0x8000; | ||
3724 | return (tsf & ~0x7fff) | rstamp; | ||
3725 | } | ||
3726 | EXPORT_SYMBOL(ath9k_hw_extend_tsf); | ||
3727 | |||
3713 | bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us) | 3728 | bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us) |
3714 | { | 3729 | { |
3715 | if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) { | 3730 | if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) { |
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index c7b0c4d5f75a..abaa2f09a3bc 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h | |||
@@ -432,7 +432,7 @@ struct ath9k_hw_version { | |||
432 | * Using de Bruijin sequence to to look up 1's index in a 32 bit number | 432 | * Using de Bruijin sequence to to look up 1's index in a 32 bit number |
433 | * debruijn32 = 0000 0111 0111 1100 1011 0101 0011 0001 | 433 | * debruijn32 = 0000 0111 0111 1100 1011 0101 0011 0001 |
434 | */ | 434 | */ |
435 | #define debruijn32 0x077CB531UL | 435 | #define debruijn32 0x077CB531U |
436 | 436 | ||
437 | struct ath_gen_timer_configuration { | 437 | struct ath_gen_timer_configuration { |
438 | u32 next_addr; | 438 | u32 next_addr; |
@@ -689,6 +689,7 @@ u64 ath9k_hw_gettsf64(struct ath_hw *ah); | |||
689 | void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); | 689 | void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); |
690 | void ath9k_hw_reset_tsf(struct ath_hw *ah); | 690 | void ath9k_hw_reset_tsf(struct ath_hw *ah); |
691 | void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting); | 691 | void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting); |
692 | u64 ath9k_hw_extend_tsf(struct ath_hw *ah, u32 rstamp); | ||
692 | bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us); | 693 | bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us); |
693 | void ath9k_hw_set11nmac2040(struct ath_hw *ah); | 694 | void ath9k_hw_set11nmac2040(struct ath_hw *ah); |
694 | void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period); | 695 | void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period); |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 9fefc51aec17..3c02b977a613 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -405,34 +405,34 @@ static void ath_ani_calibrate(unsigned long data) | |||
405 | ath9k_ps_wakeup(sc); | 405 | ath9k_ps_wakeup(sc); |
406 | 406 | ||
407 | /* Long calibration runs independently of short calibration. */ | 407 | /* Long calibration runs independently of short calibration. */ |
408 | if ((timestamp - sc->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) { | 408 | if ((timestamp - common->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) { |
409 | longcal = true; | 409 | longcal = true; |
410 | ath_print(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies); | 410 | ath_print(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies); |
411 | sc->ani.longcal_timer = timestamp; | 411 | common->ani.longcal_timer = timestamp; |
412 | } | 412 | } |
413 | 413 | ||
414 | /* Short calibration applies only while caldone is false */ | 414 | /* Short calibration applies only while caldone is false */ |
415 | if (!sc->ani.caldone) { | 415 | if (!common->ani.caldone) { |
416 | if ((timestamp - sc->ani.shortcal_timer) >= short_cal_interval) { | 416 | if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) { |
417 | shortcal = true; | 417 | shortcal = true; |
418 | ath_print(common, ATH_DBG_ANI, | 418 | ath_print(common, ATH_DBG_ANI, |
419 | "shortcal @%lu\n", jiffies); | 419 | "shortcal @%lu\n", jiffies); |
420 | sc->ani.shortcal_timer = timestamp; | 420 | common->ani.shortcal_timer = timestamp; |
421 | sc->ani.resetcal_timer = timestamp; | 421 | common->ani.resetcal_timer = timestamp; |
422 | } | 422 | } |
423 | } else { | 423 | } else { |
424 | if ((timestamp - sc->ani.resetcal_timer) >= | 424 | if ((timestamp - common->ani.resetcal_timer) >= |
425 | ATH_RESTART_CALINTERVAL) { | 425 | ATH_RESTART_CALINTERVAL) { |
426 | sc->ani.caldone = ath9k_hw_reset_calvalid(ah); | 426 | common->ani.caldone = ath9k_hw_reset_calvalid(ah); |
427 | if (sc->ani.caldone) | 427 | if (common->ani.caldone) |
428 | sc->ani.resetcal_timer = timestamp; | 428 | common->ani.resetcal_timer = timestamp; |
429 | } | 429 | } |
430 | } | 430 | } |
431 | 431 | ||
432 | /* Verify whether we must check ANI */ | 432 | /* Verify whether we must check ANI */ |
433 | if ((timestamp - sc->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) { | 433 | if ((timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) { |
434 | aniflag = true; | 434 | aniflag = true; |
435 | sc->ani.checkani_timer = timestamp; | 435 | common->ani.checkani_timer = timestamp; |
436 | } | 436 | } |
437 | 437 | ||
438 | /* Skip all processing if there's nothing to do. */ | 438 | /* Skip all processing if there's nothing to do. */ |
@@ -443,21 +443,21 @@ static void ath_ani_calibrate(unsigned long data) | |||
443 | 443 | ||
444 | /* Perform calibration if necessary */ | 444 | /* Perform calibration if necessary */ |
445 | if (longcal || shortcal) { | 445 | if (longcal || shortcal) { |
446 | sc->ani.caldone = | 446 | common->ani.caldone = |
447 | ath9k_hw_calibrate(ah, | 447 | ath9k_hw_calibrate(ah, |
448 | ah->curchan, | 448 | ah->curchan, |
449 | common->rx_chainmask, | 449 | common->rx_chainmask, |
450 | longcal); | 450 | longcal); |
451 | 451 | ||
452 | if (longcal) | 452 | if (longcal) |
453 | sc->ani.noise_floor = ath9k_hw_getchan_noise(ah, | 453 | common->ani.noise_floor = ath9k_hw_getchan_noise(ah, |
454 | ah->curchan); | 454 | ah->curchan); |
455 | 455 | ||
456 | ath_print(common, ATH_DBG_ANI, | 456 | ath_print(common, ATH_DBG_ANI, |
457 | " calibrate chan %u/%x nf: %d\n", | 457 | " calibrate chan %u/%x nf: %d\n", |
458 | ah->curchan->channel, | 458 | ah->curchan->channel, |
459 | ah->curchan->channelFlags, | 459 | ah->curchan->channelFlags, |
460 | sc->ani.noise_floor); | 460 | common->ani.noise_floor); |
461 | } | 461 | } |
462 | } | 462 | } |
463 | 463 | ||
@@ -473,21 +473,21 @@ set_timer: | |||
473 | cal_interval = ATH_LONG_CALINTERVAL; | 473 | cal_interval = ATH_LONG_CALINTERVAL; |
474 | if (sc->sc_ah->config.enable_ani) | 474 | if (sc->sc_ah->config.enable_ani) |
475 | cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL); | 475 | cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL); |
476 | if (!sc->ani.caldone) | 476 | if (!common->ani.caldone) |
477 | cal_interval = min(cal_interval, (u32)short_cal_interval); | 477 | cal_interval = min(cal_interval, (u32)short_cal_interval); |
478 | 478 | ||
479 | mod_timer(&sc->ani.timer, jiffies + msecs_to_jiffies(cal_interval)); | 479 | mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval)); |
480 | } | 480 | } |
481 | 481 | ||
482 | static void ath_start_ani(struct ath_softc *sc) | 482 | static void ath_start_ani(struct ath_common *common) |
483 | { | 483 | { |
484 | unsigned long timestamp = jiffies_to_msecs(jiffies); | 484 | unsigned long timestamp = jiffies_to_msecs(jiffies); |
485 | 485 | ||
486 | sc->ani.longcal_timer = timestamp; | 486 | common->ani.longcal_timer = timestamp; |
487 | sc->ani.shortcal_timer = timestamp; | 487 | common->ani.shortcal_timer = timestamp; |
488 | sc->ani.checkani_timer = timestamp; | 488 | common->ani.checkani_timer = timestamp; |
489 | 489 | ||
490 | mod_timer(&sc->ani.timer, | 490 | mod_timer(&common->ani.timer, |
491 | jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); | 491 | jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); |
492 | } | 492 | } |
493 | 493 | ||
@@ -733,10 +733,11 @@ static u32 ath_get_extchanmode(struct ath_softc *sc, | |||
733 | return chanmode; | 733 | return chanmode; |
734 | } | 734 | } |
735 | 735 | ||
736 | static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key, | 736 | static int ath_setkey_tkip(struct ath_common *common, u16 keyix, const u8 *key, |
737 | struct ath9k_keyval *hk, const u8 *addr, | 737 | struct ath9k_keyval *hk, const u8 *addr, |
738 | bool authenticator) | 738 | bool authenticator) |
739 | { | 739 | { |
740 | struct ath_hw *ah = common->ah; | ||
740 | const u8 *key_rxmic; | 741 | const u8 *key_rxmic; |
741 | const u8 *key_txmic; | 742 | const u8 *key_txmic; |
742 | 743 | ||
@@ -756,42 +757,42 @@ static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key, | |||
756 | memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); | 757 | memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); |
757 | memcpy(hk->kv_txmic, key_rxmic, sizeof(hk->kv_mic)); | 758 | memcpy(hk->kv_txmic, key_rxmic, sizeof(hk->kv_mic)); |
758 | } | 759 | } |
759 | return ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, addr); | 760 | return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr); |
760 | } | 761 | } |
761 | if (!sc->splitmic) { | 762 | if (!common->splitmic) { |
762 | /* TX and RX keys share the same key cache entry. */ | 763 | /* TX and RX keys share the same key cache entry. */ |
763 | memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); | 764 | memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); |
764 | memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic)); | 765 | memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic)); |
765 | return ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, addr); | 766 | return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr); |
766 | } | 767 | } |
767 | 768 | ||
768 | /* Separate key cache entries for TX and RX */ | 769 | /* Separate key cache entries for TX and RX */ |
769 | 770 | ||
770 | /* TX key goes at first index, RX key at +32. */ | 771 | /* TX key goes at first index, RX key at +32. */ |
771 | memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); | 772 | memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); |
772 | if (!ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, NULL)) { | 773 | if (!ath9k_hw_set_keycache_entry(ah, keyix, hk, NULL)) { |
773 | /* TX MIC entry failed. No need to proceed further */ | 774 | /* TX MIC entry failed. No need to proceed further */ |
774 | ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, | 775 | ath_print(common, ATH_DBG_FATAL, |
775 | "Setting TX MIC Key Failed\n"); | 776 | "Setting TX MIC Key Failed\n"); |
776 | return 0; | 777 | return 0; |
777 | } | 778 | } |
778 | 779 | ||
779 | memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); | 780 | memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); |
780 | /* XXX delete tx key on failure? */ | 781 | /* XXX delete tx key on failure? */ |
781 | return ath9k_hw_set_keycache_entry(sc->sc_ah, keyix + 32, hk, addr); | 782 | return ath9k_hw_set_keycache_entry(ah, keyix + 32, hk, addr); |
782 | } | 783 | } |
783 | 784 | ||
784 | static int ath_reserve_key_cache_slot_tkip(struct ath_softc *sc) | 785 | static int ath_reserve_key_cache_slot_tkip(struct ath_common *common) |
785 | { | 786 | { |
786 | int i; | 787 | int i; |
787 | 788 | ||
788 | for (i = IEEE80211_WEP_NKID; i < sc->keymax / 2; i++) { | 789 | for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) { |
789 | if (test_bit(i, sc->keymap) || | 790 | if (test_bit(i, common->keymap) || |
790 | test_bit(i + 64, sc->keymap)) | 791 | test_bit(i + 64, common->keymap)) |
791 | continue; /* At least one part of TKIP key allocated */ | 792 | continue; /* At least one part of TKIP key allocated */ |
792 | if (sc->splitmic && | 793 | if (common->splitmic && |
793 | (test_bit(i + 32, sc->keymap) || | 794 | (test_bit(i + 32, common->keymap) || |
794 | test_bit(i + 64 + 32, sc->keymap))) | 795 | test_bit(i + 64 + 32, common->keymap))) |
795 | continue; /* At least one part of TKIP key allocated */ | 796 | continue; /* At least one part of TKIP key allocated */ |
796 | 797 | ||
797 | /* Found a free slot for a TKIP key */ | 798 | /* Found a free slot for a TKIP key */ |
@@ -800,60 +801,60 @@ static int ath_reserve_key_cache_slot_tkip(struct ath_softc *sc) | |||
800 | return -1; | 801 | return -1; |
801 | } | 802 | } |
802 | 803 | ||
803 | static int ath_reserve_key_cache_slot(struct ath_softc *sc) | 804 | static int ath_reserve_key_cache_slot(struct ath_common *common) |
804 | { | 805 | { |
805 | int i; | 806 | int i; |
806 | 807 | ||
807 | /* First, try to find slots that would not be available for TKIP. */ | 808 | /* First, try to find slots that would not be available for TKIP. */ |
808 | if (sc->splitmic) { | 809 | if (common->splitmic) { |
809 | for (i = IEEE80211_WEP_NKID; i < sc->keymax / 4; i++) { | 810 | for (i = IEEE80211_WEP_NKID; i < common->keymax / 4; i++) { |
810 | if (!test_bit(i, sc->keymap) && | 811 | if (!test_bit(i, common->keymap) && |
811 | (test_bit(i + 32, sc->keymap) || | 812 | (test_bit(i + 32, common->keymap) || |
812 | test_bit(i + 64, sc->keymap) || | 813 | test_bit(i + 64, common->keymap) || |
813 | test_bit(i + 64 + 32, sc->keymap))) | 814 | test_bit(i + 64 + 32, common->keymap))) |
814 | return i; | 815 | return i; |
815 | if (!test_bit(i + 32, sc->keymap) && | 816 | if (!test_bit(i + 32, common->keymap) && |
816 | (test_bit(i, sc->keymap) || | 817 | (test_bit(i, common->keymap) || |
817 | test_bit(i + 64, sc->keymap) || | 818 | test_bit(i + 64, common->keymap) || |
818 | test_bit(i + 64 + 32, sc->keymap))) | 819 | test_bit(i + 64 + 32, common->keymap))) |
819 | return i + 32; | 820 | return i + 32; |
820 | if (!test_bit(i + 64, sc->keymap) && | 821 | if (!test_bit(i + 64, common->keymap) && |
821 | (test_bit(i , sc->keymap) || | 822 | (test_bit(i , common->keymap) || |
822 | test_bit(i + 32, sc->keymap) || | 823 | test_bit(i + 32, common->keymap) || |
823 | test_bit(i + 64 + 32, sc->keymap))) | 824 | test_bit(i + 64 + 32, common->keymap))) |
824 | return i + 64; | 825 | return i + 64; |
825 | if (!test_bit(i + 64 + 32, sc->keymap) && | 826 | if (!test_bit(i + 64 + 32, common->keymap) && |
826 | (test_bit(i, sc->keymap) || | 827 | (test_bit(i, common->keymap) || |
827 | test_bit(i + 32, sc->keymap) || | 828 | test_bit(i + 32, common->keymap) || |
828 | test_bit(i + 64, sc->keymap))) | 829 | test_bit(i + 64, common->keymap))) |
829 | return i + 64 + 32; | 830 | return i + 64 + 32; |
830 | } | 831 | } |
831 | } else { | 832 | } else { |
832 | for (i = IEEE80211_WEP_NKID; i < sc->keymax / 2; i++) { | 833 | for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) { |
833 | if (!test_bit(i, sc->keymap) && | 834 | if (!test_bit(i, common->keymap) && |
834 | test_bit(i + 64, sc->keymap)) | 835 | test_bit(i + 64, common->keymap)) |
835 | return i; | 836 | return i; |
836 | if (test_bit(i, sc->keymap) && | 837 | if (test_bit(i, common->keymap) && |
837 | !test_bit(i + 64, sc->keymap)) | 838 | !test_bit(i + 64, common->keymap)) |
838 | return i + 64; | 839 | return i + 64; |
839 | } | 840 | } |
840 | } | 841 | } |
841 | 842 | ||
842 | /* No partially used TKIP slots, pick any available slot */ | 843 | /* No partially used TKIP slots, pick any available slot */ |
843 | for (i = IEEE80211_WEP_NKID; i < sc->keymax; i++) { | 844 | for (i = IEEE80211_WEP_NKID; i < common->keymax; i++) { |
844 | /* Do not allow slots that could be needed for TKIP group keys | 845 | /* Do not allow slots that could be needed for TKIP group keys |
845 | * to be used. This limitation could be removed if we know that | 846 | * to be used. This limitation could be removed if we know that |
846 | * TKIP will not be used. */ | 847 | * TKIP will not be used. */ |
847 | if (i >= 64 && i < 64 + IEEE80211_WEP_NKID) | 848 | if (i >= 64 && i < 64 + IEEE80211_WEP_NKID) |
848 | continue; | 849 | continue; |
849 | if (sc->splitmic) { | 850 | if (common->splitmic) { |
850 | if (i >= 32 && i < 32 + IEEE80211_WEP_NKID) | 851 | if (i >= 32 && i < 32 + IEEE80211_WEP_NKID) |
851 | continue; | 852 | continue; |
852 | if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID) | 853 | if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID) |
853 | continue; | 854 | continue; |
854 | } | 855 | } |
855 | 856 | ||
856 | if (!test_bit(i, sc->keymap)) | 857 | if (!test_bit(i, common->keymap)) |
857 | return i; /* Found a free slot for a key */ | 858 | return i; /* Found a free slot for a key */ |
858 | } | 859 | } |
859 | 860 | ||
@@ -861,11 +862,12 @@ static int ath_reserve_key_cache_slot(struct ath_softc *sc) | |||
861 | return -1; | 862 | return -1; |
862 | } | 863 | } |
863 | 864 | ||
864 | static int ath_key_config(struct ath_softc *sc, | 865 | static int ath_key_config(struct ath_common *common, |
865 | struct ieee80211_vif *vif, | 866 | struct ieee80211_vif *vif, |
866 | struct ieee80211_sta *sta, | 867 | struct ieee80211_sta *sta, |
867 | struct ieee80211_key_conf *key) | 868 | struct ieee80211_key_conf *key) |
868 | { | 869 | { |
870 | struct ath_hw *ah = common->ah; | ||
869 | struct ath9k_keyval hk; | 871 | struct ath9k_keyval hk; |
870 | const u8 *mac = NULL; | 872 | const u8 *mac = NULL; |
871 | int ret = 0; | 873 | int ret = 0; |
@@ -911,48 +913,50 @@ static int ath_key_config(struct ath_softc *sc, | |||
911 | mac = sta->addr; | 913 | mac = sta->addr; |
912 | 914 | ||
913 | if (key->alg == ALG_TKIP) | 915 | if (key->alg == ALG_TKIP) |
914 | idx = ath_reserve_key_cache_slot_tkip(sc); | 916 | idx = ath_reserve_key_cache_slot_tkip(common); |
915 | else | 917 | else |
916 | idx = ath_reserve_key_cache_slot(sc); | 918 | idx = ath_reserve_key_cache_slot(common); |
917 | if (idx < 0) | 919 | if (idx < 0) |
918 | return -ENOSPC; /* no free key cache entries */ | 920 | return -ENOSPC; /* no free key cache entries */ |
919 | } | 921 | } |
920 | 922 | ||
921 | if (key->alg == ALG_TKIP) | 923 | if (key->alg == ALG_TKIP) |
922 | ret = ath_setkey_tkip(sc, idx, key->key, &hk, mac, | 924 | ret = ath_setkey_tkip(common, idx, key->key, &hk, mac, |
923 | vif->type == NL80211_IFTYPE_AP); | 925 | vif->type == NL80211_IFTYPE_AP); |
924 | else | 926 | else |
925 | ret = ath9k_hw_set_keycache_entry(sc->sc_ah, idx, &hk, mac); | 927 | ret = ath9k_hw_set_keycache_entry(ah, idx, &hk, mac); |
926 | 928 | ||
927 | if (!ret) | 929 | if (!ret) |
928 | return -EIO; | 930 | return -EIO; |
929 | 931 | ||
930 | set_bit(idx, sc->keymap); | 932 | set_bit(idx, common->keymap); |
931 | if (key->alg == ALG_TKIP) { | 933 | if (key->alg == ALG_TKIP) { |
932 | set_bit(idx + 64, sc->keymap); | 934 | set_bit(idx + 64, common->keymap); |
933 | if (sc->splitmic) { | 935 | if (common->splitmic) { |
934 | set_bit(idx + 32, sc->keymap); | 936 | set_bit(idx + 32, common->keymap); |
935 | set_bit(idx + 64 + 32, sc->keymap); | 937 | set_bit(idx + 64 + 32, common->keymap); |
936 | } | 938 | } |
937 | } | 939 | } |
938 | 940 | ||
939 | return idx; | 941 | return idx; |
940 | } | 942 | } |
941 | 943 | ||
942 | static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key) | 944 | static void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf *key) |
943 | { | 945 | { |
944 | ath9k_hw_keyreset(sc->sc_ah, key->hw_key_idx); | 946 | struct ath_hw *ah = common->ah; |
947 | |||
948 | ath9k_hw_keyreset(ah, key->hw_key_idx); | ||
945 | if (key->hw_key_idx < IEEE80211_WEP_NKID) | 949 | if (key->hw_key_idx < IEEE80211_WEP_NKID) |
946 | return; | 950 | return; |
947 | 951 | ||
948 | clear_bit(key->hw_key_idx, sc->keymap); | 952 | clear_bit(key->hw_key_idx, common->keymap); |
949 | if (key->alg != ALG_TKIP) | 953 | if (key->alg != ALG_TKIP) |
950 | return; | 954 | return; |
951 | 955 | ||
952 | clear_bit(key->hw_key_idx + 64, sc->keymap); | 956 | clear_bit(key->hw_key_idx + 64, common->keymap); |
953 | if (sc->splitmic) { | 957 | if (common->splitmic) { |
954 | clear_bit(key->hw_key_idx + 32, sc->keymap); | 958 | clear_bit(key->hw_key_idx + 32, common->keymap); |
955 | clear_bit(key->hw_key_idx + 64 + 32, sc->keymap); | 959 | clear_bit(key->hw_key_idx + 64 + 32, common->keymap); |
956 | } | 960 | } |
957 | } | 961 | } |
958 | 962 | ||
@@ -1023,12 +1027,12 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, | |||
1023 | /* Reset rssi stats */ | 1027 | /* Reset rssi stats */ |
1024 | sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; | 1028 | sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; |
1025 | 1029 | ||
1026 | ath_start_ani(sc); | 1030 | ath_start_ani(common); |
1027 | } else { | 1031 | } else { |
1028 | ath_print(common, ATH_DBG_CONFIG, "Bss Info DISASSOC\n"); | 1032 | ath_print(common, ATH_DBG_CONFIG, "Bss Info DISASSOC\n"); |
1029 | common->curaid = 0; | 1033 | common->curaid = 0; |
1030 | /* Stop ANI */ | 1034 | /* Stop ANI */ |
1031 | del_timer_sync(&sc->ani.timer); | 1035 | del_timer_sync(&common->ani.timer); |
1032 | } | 1036 | } |
1033 | } | 1037 | } |
1034 | 1038 | ||
@@ -1200,11 +1204,11 @@ fail: | |||
1200 | ath_deinit_leds(sc); | 1204 | ath_deinit_leds(sc); |
1201 | } | 1205 | } |
1202 | 1206 | ||
1203 | void ath_radio_enable(struct ath_softc *sc) | 1207 | void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) |
1204 | { | 1208 | { |
1205 | struct ath_hw *ah = sc->sc_ah; | 1209 | struct ath_hw *ah = sc->sc_ah; |
1206 | struct ath_common *common = ath9k_hw_common(ah); | 1210 | struct ath_common *common = ath9k_hw_common(ah); |
1207 | struct ieee80211_channel *channel = sc->hw->conf.channel; | 1211 | struct ieee80211_channel *channel = hw->conf.channel; |
1208 | int r; | 1212 | int r; |
1209 | 1213 | ||
1210 | ath9k_ps_wakeup(sc); | 1214 | ath9k_ps_wakeup(sc); |
@@ -1241,18 +1245,18 @@ void ath_radio_enable(struct ath_softc *sc) | |||
1241 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | 1245 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); |
1242 | ath9k_hw_set_gpio(ah, ah->led_pin, 0); | 1246 | ath9k_hw_set_gpio(ah, ah->led_pin, 0); |
1243 | 1247 | ||
1244 | ieee80211_wake_queues(sc->hw); | 1248 | ieee80211_wake_queues(hw); |
1245 | ath9k_ps_restore(sc); | 1249 | ath9k_ps_restore(sc); |
1246 | } | 1250 | } |
1247 | 1251 | ||
1248 | void ath_radio_disable(struct ath_softc *sc) | 1252 | void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) |
1249 | { | 1253 | { |
1250 | struct ath_hw *ah = sc->sc_ah; | 1254 | struct ath_hw *ah = sc->sc_ah; |
1251 | struct ieee80211_channel *channel = sc->hw->conf.channel; | 1255 | struct ieee80211_channel *channel = hw->conf.channel; |
1252 | int r; | 1256 | int r; |
1253 | 1257 | ||
1254 | ath9k_ps_wakeup(sc); | 1258 | ath9k_ps_wakeup(sc); |
1255 | ieee80211_stop_queues(sc->hw); | 1259 | ieee80211_stop_queues(hw); |
1256 | 1260 | ||
1257 | /* Disable LED */ | 1261 | /* Disable LED */ |
1258 | ath9k_hw_set_gpio(ah, ah->led_pin, 1); | 1262 | ath9k_hw_set_gpio(ah, ah->led_pin, 1); |
@@ -1266,7 +1270,7 @@ void ath_radio_disable(struct ath_softc *sc) | |||
1266 | ath_flushrecv(sc); /* flush recv queue */ | 1270 | ath_flushrecv(sc); /* flush recv queue */ |
1267 | 1271 | ||
1268 | if (!ah->curchan) | 1272 | if (!ah->curchan) |
1269 | ah->curchan = ath_get_curchannel(sc, sc->hw); | 1273 | ah->curchan = ath_get_curchannel(sc, hw); |
1270 | 1274 | ||
1271 | spin_lock_bh(&sc->sc_resetlock); | 1275 | spin_lock_bh(&sc->sc_resetlock); |
1272 | r = ath9k_hw_reset(ah, ah->curchan, false); | 1276 | r = ath9k_hw_reset(ah, ah->curchan, false); |
@@ -1679,19 +1683,19 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, | |||
1679 | } | 1683 | } |
1680 | 1684 | ||
1681 | /* Get the hardware key cache size. */ | 1685 | /* Get the hardware key cache size. */ |
1682 | sc->keymax = ah->caps.keycache_size; | 1686 | common->keymax = ah->caps.keycache_size; |
1683 | if (sc->keymax > ATH_KEYMAX) { | 1687 | if (common->keymax > ATH_KEYMAX) { |
1684 | ath_print(common, ATH_DBG_ANY, | 1688 | ath_print(common, ATH_DBG_ANY, |
1685 | "Warning, using only %u entries in %u key cache\n", | 1689 | "Warning, using only %u entries in %u key cache\n", |
1686 | ATH_KEYMAX, sc->keymax); | 1690 | ATH_KEYMAX, common->keymax); |
1687 | sc->keymax = ATH_KEYMAX; | 1691 | common->keymax = ATH_KEYMAX; |
1688 | } | 1692 | } |
1689 | 1693 | ||
1690 | /* | 1694 | /* |
1691 | * Reset the key cache since some parts do not | 1695 | * Reset the key cache since some parts do not |
1692 | * reset the contents on initial power up. | 1696 | * reset the contents on initial power up. |
1693 | */ | 1697 | */ |
1694 | for (i = 0; i < sc->keymax; i++) | 1698 | for (i = 0; i < common->keymax; i++) |
1695 | ath9k_hw_keyreset(ah, (u16) i); | 1699 | ath9k_hw_keyreset(ah, (u16) i); |
1696 | 1700 | ||
1697 | /* default to MONITOR mode */ | 1701 | /* default to MONITOR mode */ |
@@ -1761,8 +1765,8 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, | |||
1761 | /* Initializes the noise floor to a reasonable default value. | 1765 | /* Initializes the noise floor to a reasonable default value. |
1762 | * Later on this will be updated during ANI processing. */ | 1766 | * Later on this will be updated during ANI processing. */ |
1763 | 1767 | ||
1764 | sc->ani.noise_floor = ATH_DEFAULT_NOISE_FLOOR; | 1768 | common->ani.noise_floor = ATH_DEFAULT_NOISE_FLOOR; |
1765 | setup_timer(&sc->ani.timer, ath_ani_calibrate, (unsigned long)sc); | 1769 | setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc); |
1766 | 1770 | ||
1767 | if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, | 1771 | if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, |
1768 | ATH9K_CIPHER_TKIP, NULL)) { | 1772 | ATH9K_CIPHER_TKIP, NULL)) { |
@@ -1788,7 +1792,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, | |||
1788 | ATH9K_CIPHER_MIC, NULL) | 1792 | ATH9K_CIPHER_MIC, NULL) |
1789 | && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT, | 1793 | && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT, |
1790 | 0, NULL)) | 1794 | 0, NULL)) |
1791 | sc->splitmic = 1; | 1795 | common->splitmic = 1; |
1792 | 1796 | ||
1793 | /* turn on mcast key search if possible */ | 1797 | /* turn on mcast key search if possible */ |
1794 | if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL)) | 1798 | if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL)) |
@@ -2634,7 +2638,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, | |||
2634 | if (conf->type == NL80211_IFTYPE_AP || | 2638 | if (conf->type == NL80211_IFTYPE_AP || |
2635 | conf->type == NL80211_IFTYPE_ADHOC || | 2639 | conf->type == NL80211_IFTYPE_ADHOC || |
2636 | conf->type == NL80211_IFTYPE_MONITOR) | 2640 | conf->type == NL80211_IFTYPE_MONITOR) |
2637 | ath_start_ani(sc); | 2641 | ath_start_ani(common); |
2638 | 2642 | ||
2639 | out: | 2643 | out: |
2640 | mutex_unlock(&sc->mutex); | 2644 | mutex_unlock(&sc->mutex); |
@@ -2655,7 +2659,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, | |||
2655 | mutex_lock(&sc->mutex); | 2659 | mutex_lock(&sc->mutex); |
2656 | 2660 | ||
2657 | /* Stop ANI */ | 2661 | /* Stop ANI */ |
2658 | del_timer_sync(&sc->ani.timer); | 2662 | del_timer_sync(&common->ani.timer); |
2659 | 2663 | ||
2660 | /* Reclaim beacon resources */ | 2664 | /* Reclaim beacon resources */ |
2661 | if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) || | 2665 | if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) || |
@@ -2688,23 +2692,38 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) | |||
2688 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 2692 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
2689 | struct ieee80211_conf *conf = &hw->conf; | 2693 | struct ieee80211_conf *conf = &hw->conf; |
2690 | struct ath_hw *ah = sc->sc_ah; | 2694 | struct ath_hw *ah = sc->sc_ah; |
2691 | bool all_wiphys_idle = false, disable_radio = false; | 2695 | bool disable_radio; |
2692 | 2696 | ||
2693 | mutex_lock(&sc->mutex); | 2697 | mutex_lock(&sc->mutex); |
2694 | 2698 | ||
2695 | /* Leave this as the first check */ | 2699 | /* |
2700 | * Leave this as the first check because we need to turn on the | ||
2701 | * radio if it was disabled before prior to processing the rest | ||
2702 | * of the changes. Likewise we must only disable the radio towards | ||
2703 | * the end. | ||
2704 | */ | ||
2696 | if (changed & IEEE80211_CONF_CHANGE_IDLE) { | 2705 | if (changed & IEEE80211_CONF_CHANGE_IDLE) { |
2706 | bool enable_radio; | ||
2707 | bool all_wiphys_idle; | ||
2708 | bool idle = !!(conf->flags & IEEE80211_CONF_IDLE); | ||
2697 | 2709 | ||
2698 | spin_lock_bh(&sc->wiphy_lock); | 2710 | spin_lock_bh(&sc->wiphy_lock); |
2699 | all_wiphys_idle = ath9k_all_wiphys_idle(sc); | 2711 | all_wiphys_idle = ath9k_all_wiphys_idle(sc); |
2712 | ath9k_set_wiphy_idle(aphy, idle); | ||
2713 | |||
2714 | if (!idle && all_wiphys_idle) | ||
2715 | enable_radio = true; | ||
2716 | |||
2717 | /* | ||
2718 | * After we unlock here its possible another wiphy | ||
2719 | * can be re-renabled so to account for that we will | ||
2720 | * only disable the radio toward the end of this routine | ||
2721 | * if by then all wiphys are still idle. | ||
2722 | */ | ||
2700 | spin_unlock_bh(&sc->wiphy_lock); | 2723 | spin_unlock_bh(&sc->wiphy_lock); |
2701 | 2724 | ||
2702 | if (conf->flags & IEEE80211_CONF_IDLE){ | 2725 | if (enable_radio) { |
2703 | if (all_wiphys_idle) | 2726 | ath_radio_enable(sc, hw); |
2704 | disable_radio = true; | ||
2705 | } | ||
2706 | else if (all_wiphys_idle) { | ||
2707 | ath_radio_enable(sc); | ||
2708 | ath_print(common, ATH_DBG_CONFIG, | 2727 | ath_print(common, ATH_DBG_CONFIG, |
2709 | "not-idle: enabling radio\n"); | 2728 | "not-idle: enabling radio\n"); |
2710 | } | 2729 | } |
@@ -2779,9 +2798,13 @@ skip_chan_change: | |||
2779 | if (changed & IEEE80211_CONF_CHANGE_POWER) | 2798 | if (changed & IEEE80211_CONF_CHANGE_POWER) |
2780 | sc->config.txpowlimit = 2 * conf->power_level; | 2799 | sc->config.txpowlimit = 2 * conf->power_level; |
2781 | 2800 | ||
2801 | spin_lock_bh(&sc->wiphy_lock); | ||
2802 | disable_radio = ath9k_all_wiphys_idle(sc); | ||
2803 | spin_unlock_bh(&sc->wiphy_lock); | ||
2804 | |||
2782 | if (disable_radio) { | 2805 | if (disable_radio) { |
2783 | ath_print(common, ATH_DBG_CONFIG, "idle: disabling radio\n"); | 2806 | ath_print(common, ATH_DBG_CONFIG, "idle: disabling radio\n"); |
2784 | ath_radio_disable(sc); | 2807 | ath_radio_disable(sc, hw); |
2785 | } | 2808 | } |
2786 | 2809 | ||
2787 | mutex_unlock(&sc->mutex); | 2810 | mutex_unlock(&sc->mutex); |
@@ -2898,7 +2921,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw, | |||
2898 | 2921 | ||
2899 | switch (cmd) { | 2922 | switch (cmd) { |
2900 | case SET_KEY: | 2923 | case SET_KEY: |
2901 | ret = ath_key_config(sc, vif, sta, key); | 2924 | ret = ath_key_config(common, vif, sta, key); |
2902 | if (ret >= 0) { | 2925 | if (ret >= 0) { |
2903 | key->hw_key_idx = ret; | 2926 | key->hw_key_idx = ret; |
2904 | /* push IV and Michael MIC generation to stack */ | 2927 | /* push IV and Michael MIC generation to stack */ |
@@ -2911,7 +2934,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw, | |||
2911 | } | 2934 | } |
2912 | break; | 2935 | break; |
2913 | case DISABLE_KEY: | 2936 | case DISABLE_KEY: |
2914 | ath_key_delete(sc, key); | 2937 | ath_key_delete(common, key); |
2915 | break; | 2938 | break; |
2916 | default: | 2939 | default: |
2917 | ret = -EINVAL; | 2940 | ret = -EINVAL; |
diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h index fa21a628ddd0..94cb9f8d2446 100644 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h | |||
@@ -19,6 +19,8 @@ | |||
19 | #ifndef RC_H | 19 | #ifndef RC_H |
20 | #define RC_H | 20 | #define RC_H |
21 | 21 | ||
22 | #include "hw.h" | ||
23 | |||
22 | struct ath_softc; | 24 | struct ath_softc; |
23 | 25 | ||
24 | #define ATH_RATE_MAX 30 | 26 | #define ATH_RATE_MAX 30 |
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 355dd1834e1d..477365e5ae69 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c | |||
@@ -48,6 +48,7 @@ static struct ieee80211_hw * ath_get_virt_hw(struct ath_softc *sc, | |||
48 | static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf) | 48 | static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf) |
49 | { | 49 | { |
50 | struct ath_hw *ah = sc->sc_ah; | 50 | struct ath_hw *ah = sc->sc_ah; |
51 | struct ath_common *common = ath9k_hw_common(ah); | ||
51 | struct ath_desc *ds; | 52 | struct ath_desc *ds; |
52 | struct sk_buff *skb; | 53 | struct sk_buff *skb; |
53 | 54 | ||
@@ -62,11 +63,13 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf) | |||
62 | BUG_ON(skb == NULL); | 63 | BUG_ON(skb == NULL); |
63 | ds->ds_vdata = skb->data; | 64 | ds->ds_vdata = skb->data; |
64 | 65 | ||
65 | /* setup rx descriptors. The rx.bufsize here tells the harware | 66 | /* |
67 | * setup rx descriptors. The rx_bufsize here tells the hardware | ||
66 | * how much data it can DMA to us and that we are prepared | 68 | * how much data it can DMA to us and that we are prepared |
67 | * to process */ | 69 | * to process |
70 | */ | ||
68 | ath9k_hw_setuprxdesc(ah, ds, | 71 | ath9k_hw_setuprxdesc(ah, ds, |
69 | sc->rx.bufsize, | 72 | common->rx_bufsize, |
70 | 0); | 73 | 0); |
71 | 74 | ||
72 | if (sc->rx.rxlink == NULL) | 75 | if (sc->rx.rxlink == NULL) |
@@ -86,190 +89,6 @@ static void ath_setdefantenna(struct ath_softc *sc, u32 antenna) | |||
86 | sc->rx.rxotherant = 0; | 89 | sc->rx.rxotherant = 0; |
87 | } | 90 | } |
88 | 91 | ||
89 | /* | ||
90 | * Extend 15-bit time stamp from rx descriptor to | ||
91 | * a full 64-bit TSF using the current h/w TSF. | ||
92 | */ | ||
93 | static u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp) | ||
94 | { | ||
95 | u64 tsf; | ||
96 | |||
97 | tsf = ath9k_hw_gettsf64(sc->sc_ah); | ||
98 | if ((tsf & 0x7fff) < rstamp) | ||
99 | tsf -= 0x8000; | ||
100 | return (tsf & ~0x7fff) | rstamp; | ||
101 | } | ||
102 | |||
103 | /* | ||
104 | * For Decrypt or Demic errors, we only mark packet status here and always push | ||
105 | * up the frame up to let mac80211 handle the actual error case, be it no | ||
106 | * decryption key or real decryption error. This let us keep statistics there. | ||
107 | */ | ||
108 | static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, | ||
109 | struct ieee80211_rx_status *rx_status, bool *decrypt_error, | ||
110 | struct ath_softc *sc) | ||
111 | { | ||
112 | struct ieee80211_hdr *hdr; | ||
113 | u8 ratecode; | ||
114 | __le16 fc; | ||
115 | struct ieee80211_hw *hw; | ||
116 | struct ieee80211_sta *sta; | ||
117 | struct ath_node *an; | ||
118 | int last_rssi = ATH_RSSI_DUMMY_MARKER; | ||
119 | |||
120 | |||
121 | hdr = (struct ieee80211_hdr *)skb->data; | ||
122 | fc = hdr->frame_control; | ||
123 | memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); | ||
124 | hw = ath_get_virt_hw(sc, hdr); | ||
125 | |||
126 | if (ds->ds_rxstat.rs_more) { | ||
127 | /* | ||
128 | * Frame spans multiple descriptors; this cannot happen yet | ||
129 | * as we don't support jumbograms. If not in monitor mode, | ||
130 | * discard the frame. Enable this if you want to see | ||
131 | * error frames in Monitor mode. | ||
132 | */ | ||
133 | if (sc->sc_ah->opmode != NL80211_IFTYPE_MONITOR) | ||
134 | goto rx_next; | ||
135 | } else if (ds->ds_rxstat.rs_status != 0) { | ||
136 | if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC) | ||
137 | rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; | ||
138 | if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY) | ||
139 | goto rx_next; | ||
140 | |||
141 | if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) { | ||
142 | *decrypt_error = true; | ||
143 | } else if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC) { | ||
144 | if (ieee80211_is_ctl(fc)) | ||
145 | /* | ||
146 | * Sometimes, we get invalid | ||
147 | * MIC failures on valid control frames. | ||
148 | * Remove these mic errors. | ||
149 | */ | ||
150 | ds->ds_rxstat.rs_status &= ~ATH9K_RXERR_MIC; | ||
151 | else | ||
152 | rx_status->flag |= RX_FLAG_MMIC_ERROR; | ||
153 | } | ||
154 | /* | ||
155 | * Reject error frames with the exception of | ||
156 | * decryption and MIC failures. For monitor mode, | ||
157 | * we also ignore the CRC error. | ||
158 | */ | ||
159 | if (sc->sc_ah->opmode == NL80211_IFTYPE_MONITOR) { | ||
160 | if (ds->ds_rxstat.rs_status & | ||
161 | ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | | ||
162 | ATH9K_RXERR_CRC)) | ||
163 | goto rx_next; | ||
164 | } else { | ||
165 | if (ds->ds_rxstat.rs_status & | ||
166 | ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) { | ||
167 | goto rx_next; | ||
168 | } | ||
169 | } | ||
170 | } | ||
171 | |||
172 | ratecode = ds->ds_rxstat.rs_rate; | ||
173 | |||
174 | if (ratecode & 0x80) { | ||
175 | /* HT rate */ | ||
176 | rx_status->flag |= RX_FLAG_HT; | ||
177 | if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040) | ||
178 | rx_status->flag |= RX_FLAG_40MHZ; | ||
179 | if (ds->ds_rxstat.rs_flags & ATH9K_RX_GI) | ||
180 | rx_status->flag |= RX_FLAG_SHORT_GI; | ||
181 | rx_status->rate_idx = ratecode & 0x7f; | ||
182 | } else { | ||
183 | int i = 0, cur_band, n_rates; | ||
184 | |||
185 | cur_band = hw->conf.channel->band; | ||
186 | n_rates = sc->sbands[cur_band].n_bitrates; | ||
187 | |||
188 | for (i = 0; i < n_rates; i++) { | ||
189 | if (sc->sbands[cur_band].bitrates[i].hw_value == | ||
190 | ratecode) { | ||
191 | rx_status->rate_idx = i; | ||
192 | break; | ||
193 | } | ||
194 | |||
195 | if (sc->sbands[cur_band].bitrates[i].hw_value_short == | ||
196 | ratecode) { | ||
197 | rx_status->rate_idx = i; | ||
198 | rx_status->flag |= RX_FLAG_SHORTPRE; | ||
199 | break; | ||
200 | } | ||
201 | } | ||
202 | } | ||
203 | |||
204 | rcu_read_lock(); | ||
205 | /* XXX: use ieee80211_find_sta! */ | ||
206 | sta = ieee80211_find_sta_by_hw(sc->hw, hdr->addr2); | ||
207 | if (sta) { | ||
208 | an = (struct ath_node *) sta->drv_priv; | ||
209 | if (ds->ds_rxstat.rs_rssi != ATH9K_RSSI_BAD && | ||
210 | !ds->ds_rxstat.rs_moreaggr) | ||
211 | ATH_RSSI_LPF(an->last_rssi, ds->ds_rxstat.rs_rssi); | ||
212 | last_rssi = an->last_rssi; | ||
213 | } | ||
214 | rcu_read_unlock(); | ||
215 | |||
216 | if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) | ||
217 | ds->ds_rxstat.rs_rssi = ATH_EP_RND(last_rssi, | ||
218 | ATH_RSSI_EP_MULTIPLIER); | ||
219 | if (ds->ds_rxstat.rs_rssi < 0) | ||
220 | ds->ds_rxstat.rs_rssi = 0; | ||
221 | else if (ds->ds_rxstat.rs_rssi > 127) | ||
222 | ds->ds_rxstat.rs_rssi = 127; | ||
223 | |||
224 | /* Update Beacon RSSI, this is used by ANI. */ | ||
225 | if (ieee80211_is_beacon(fc)) | ||
226 | sc->sc_ah->stats.avgbrssi = ds->ds_rxstat.rs_rssi; | ||
227 | |||
228 | rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp); | ||
229 | rx_status->band = hw->conf.channel->band; | ||
230 | rx_status->freq = hw->conf.channel->center_freq; | ||
231 | rx_status->noise = sc->ani.noise_floor; | ||
232 | rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + ds->ds_rxstat.rs_rssi; | ||
233 | rx_status->antenna = ds->ds_rxstat.rs_antenna; | ||
234 | |||
235 | /* | ||
236 | * Theory for reporting quality: | ||
237 | * | ||
238 | * At a hardware RSSI of 45 you will be able to use MCS 7 reliably. | ||
239 | * At a hardware RSSI of 45 you will be able to use MCS 15 reliably. | ||
240 | * At a hardware RSSI of 35 you should be able use 54 Mbps reliably. | ||
241 | * | ||
242 | * MCS 7 is the highets MCS index usable by a 1-stream device. | ||
243 | * MCS 15 is the highest MCS index usable by a 2-stream device. | ||
244 | * | ||
245 | * All ath9k devices are either 1-stream or 2-stream. | ||
246 | * | ||
247 | * How many bars you see is derived from the qual reporting. | ||
248 | * | ||
249 | * A more elaborate scheme can be used here but it requires tables | ||
250 | * of SNR/throughput for each possible mode used. For the MCS table | ||
251 | * you can refer to the wireless wiki: | ||
252 | * | ||
253 | * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n | ||
254 | * | ||
255 | */ | ||
256 | if (conf_is_ht(&hw->conf)) | ||
257 | rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 45; | ||
258 | else | ||
259 | rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 35; | ||
260 | |||
261 | /* rssi can be more than 45 though, anything above that | ||
262 | * should be considered at 100% */ | ||
263 | if (rx_status->qual > 100) | ||
264 | rx_status->qual = 100; | ||
265 | |||
266 | rx_status->flag |= RX_FLAG_TSFT; | ||
267 | |||
268 | return 1; | ||
269 | rx_next: | ||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | static void ath_opmode_init(struct ath_softc *sc) | 92 | static void ath_opmode_init(struct ath_softc *sc) |
274 | { | 93 | { |
275 | struct ath_hw *ah = sc->sc_ah; | 94 | struct ath_hw *ah = sc->sc_ah; |
@@ -307,11 +126,11 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) | |||
307 | sc->sc_flags &= ~SC_OP_RXFLUSH; | 126 | sc->sc_flags &= ~SC_OP_RXFLUSH; |
308 | spin_lock_init(&sc->rx.rxbuflock); | 127 | spin_lock_init(&sc->rx.rxbuflock); |
309 | 128 | ||
310 | sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN, | 129 | common->rx_bufsize = roundup(IEEE80211_MAX_MPDU_LEN, |
311 | min(common->cachelsz, (u16)64)); | 130 | min(common->cachelsz, (u16)64)); |
312 | 131 | ||
313 | ath_print(common, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n", | 132 | ath_print(common, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n", |
314 | common->cachelsz, sc->rx.bufsize); | 133 | common->cachelsz, common->rx_bufsize); |
315 | 134 | ||
316 | /* Initialize rx descriptors */ | 135 | /* Initialize rx descriptors */ |
317 | 136 | ||
@@ -324,7 +143,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) | |||
324 | } | 143 | } |
325 | 144 | ||
326 | list_for_each_entry(bf, &sc->rx.rxbuf, list) { | 145 | list_for_each_entry(bf, &sc->rx.rxbuf, list) { |
327 | skb = ath_rxbuf_alloc(common, sc->rx.bufsize, GFP_KERNEL); | 146 | skb = ath_rxbuf_alloc(common, common->rx_bufsize, GFP_KERNEL); |
328 | if (skb == NULL) { | 147 | if (skb == NULL) { |
329 | error = -ENOMEM; | 148 | error = -ENOMEM; |
330 | goto err; | 149 | goto err; |
@@ -332,7 +151,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) | |||
332 | 151 | ||
333 | bf->bf_mpdu = skb; | 152 | bf->bf_mpdu = skb; |
334 | bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, | 153 | bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, |
335 | sc->rx.bufsize, | 154 | common->rx_bufsize, |
336 | DMA_FROM_DEVICE); | 155 | DMA_FROM_DEVICE); |
337 | if (unlikely(dma_mapping_error(sc->dev, | 156 | if (unlikely(dma_mapping_error(sc->dev, |
338 | bf->bf_buf_addr))) { | 157 | bf->bf_buf_addr))) { |
@@ -356,6 +175,8 @@ err: | |||
356 | 175 | ||
357 | void ath_rx_cleanup(struct ath_softc *sc) | 176 | void ath_rx_cleanup(struct ath_softc *sc) |
358 | { | 177 | { |
178 | struct ath_hw *ah = sc->sc_ah; | ||
179 | struct ath_common *common = ath9k_hw_common(ah); | ||
359 | struct sk_buff *skb; | 180 | struct sk_buff *skb; |
360 | struct ath_buf *bf; | 181 | struct ath_buf *bf; |
361 | 182 | ||
@@ -363,7 +184,7 @@ void ath_rx_cleanup(struct ath_softc *sc) | |||
363 | skb = bf->bf_mpdu; | 184 | skb = bf->bf_mpdu; |
364 | if (skb) { | 185 | if (skb) { |
365 | dma_unmap_single(sc->dev, bf->bf_buf_addr, | 186 | dma_unmap_single(sc->dev, bf->bf_buf_addr, |
366 | sc->rx.bufsize, DMA_FROM_DEVICE); | 187 | common->rx_bufsize, DMA_FROM_DEVICE); |
367 | dev_kfree_skb(skb); | 188 | dev_kfree_skb(skb); |
368 | } | 189 | } |
369 | } | 190 | } |
@@ -616,8 +437,9 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) | |||
616 | } | 437 | } |
617 | } | 438 | } |
618 | 439 | ||
619 | static void ath_rx_send_to_mac80211(struct ath_softc *sc, struct sk_buff *skb, | 440 | static void ath_rx_send_to_mac80211(struct ieee80211_hw *hw, |
620 | struct ieee80211_rx_status *rx_status) | 441 | struct ath_softc *sc, struct sk_buff *skb, |
442 | struct ieee80211_rx_status *rxs) | ||
621 | { | 443 | { |
622 | struct ieee80211_hdr *hdr; | 444 | struct ieee80211_hdr *hdr; |
623 | 445 | ||
@@ -637,19 +459,14 @@ static void ath_rx_send_to_mac80211(struct ath_softc *sc, struct sk_buff *skb, | |||
637 | if (aphy == NULL) | 459 | if (aphy == NULL) |
638 | continue; | 460 | continue; |
639 | nskb = skb_copy(skb, GFP_ATOMIC); | 461 | nskb = skb_copy(skb, GFP_ATOMIC); |
640 | if (nskb) { | 462 | if (!nskb) |
641 | memcpy(IEEE80211_SKB_RXCB(nskb), rx_status, | 463 | continue; |
642 | sizeof(*rx_status)); | 464 | ieee80211_rx(aphy->hw, nskb); |
643 | ieee80211_rx(aphy->hw, nskb); | ||
644 | } | ||
645 | } | 465 | } |
646 | memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status)); | ||
647 | ieee80211_rx(sc->hw, skb); | 466 | ieee80211_rx(sc->hw, skb); |
648 | } else { | 467 | } else |
649 | /* Deliver unicast frames based on receiver address */ | 468 | /* Deliver unicast frames based on receiver address */ |
650 | memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status)); | 469 | ieee80211_rx(hw, skb); |
651 | ieee80211_rx(ath_get_virt_hw(sc, hdr), skb); | ||
652 | } | ||
653 | } | 470 | } |
654 | 471 | ||
655 | int ath_rx_tasklet(struct ath_softc *sc, int flush) | 472 | int ath_rx_tasklet(struct ath_softc *sc, int flush) |
@@ -660,15 +477,20 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) | |||
660 | 477 | ||
661 | struct ath_buf *bf; | 478 | struct ath_buf *bf; |
662 | struct ath_desc *ds; | 479 | struct ath_desc *ds; |
480 | struct ath_rx_status *rx_stats; | ||
663 | struct sk_buff *skb = NULL, *requeue_skb; | 481 | struct sk_buff *skb = NULL, *requeue_skb; |
664 | struct ieee80211_rx_status rx_status; | 482 | struct ieee80211_rx_status *rxs; |
665 | struct ath_hw *ah = sc->sc_ah; | 483 | struct ath_hw *ah = sc->sc_ah; |
666 | struct ath_common *common = ath9k_hw_common(ah); | 484 | struct ath_common *common = ath9k_hw_common(ah); |
485 | /* | ||
486 | * The hw can techncically differ from common->hw when using ath9k | ||
487 | * virtual wiphy so to account for that we iterate over the active | ||
488 | * wiphys and find the appropriate wiphy and therefore hw. | ||
489 | */ | ||
490 | struct ieee80211_hw *hw = NULL; | ||
667 | struct ieee80211_hdr *hdr; | 491 | struct ieee80211_hdr *hdr; |
668 | int hdrlen, padsize, retval; | 492 | int retval; |
669 | bool decrypt_error = false; | 493 | bool decrypt_error = false; |
670 | u8 keyix; | ||
671 | __le16 fc; | ||
672 | 494 | ||
673 | spin_lock_bh(&sc->rx.rxbuflock); | 495 | spin_lock_bh(&sc->rx.rxbuflock); |
674 | 496 | ||
@@ -740,9 +562,15 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) | |||
740 | * 2. requeueing the same buffer to h/w | 562 | * 2. requeueing the same buffer to h/w |
741 | */ | 563 | */ |
742 | dma_sync_single_for_cpu(sc->dev, bf->bf_buf_addr, | 564 | dma_sync_single_for_cpu(sc->dev, bf->bf_buf_addr, |
743 | sc->rx.bufsize, | 565 | common->rx_bufsize, |
744 | DMA_FROM_DEVICE); | 566 | DMA_FROM_DEVICE); |
745 | 567 | ||
568 | hdr = (struct ieee80211_hdr *) skb->data; | ||
569 | rxs = IEEE80211_SKB_RXCB(skb); | ||
570 | |||
571 | hw = ath_get_virt_hw(sc, hdr); | ||
572 | rx_stats = &ds->ds_rxstat; | ||
573 | |||
746 | /* | 574 | /* |
747 | * If we're asked to flush receive queue, directly | 575 | * If we're asked to flush receive queue, directly |
748 | * chain it back at the queue without processing it. | 576 | * chain it back at the queue without processing it. |
@@ -750,19 +578,14 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) | |||
750 | if (flush) | 578 | if (flush) |
751 | goto requeue; | 579 | goto requeue; |
752 | 580 | ||
753 | if (!ds->ds_rxstat.rs_datalen) | 581 | retval = ath9k_cmn_rx_skb_preprocess(common, hw, skb, rx_stats, |
754 | goto requeue; | 582 | rxs, &decrypt_error); |
755 | 583 | if (retval) | |
756 | /* The status portion of the descriptor could get corrupted. */ | ||
757 | if (sc->rx.bufsize < ds->ds_rxstat.rs_datalen) | ||
758 | goto requeue; | ||
759 | |||
760 | if (!ath_rx_prepare(skb, ds, &rx_status, &decrypt_error, sc)) | ||
761 | goto requeue; | 584 | goto requeue; |
762 | 585 | ||
763 | /* Ensure we always have an skb to requeue once we are done | 586 | /* Ensure we always have an skb to requeue once we are done |
764 | * processing the current buffer's skb */ | 587 | * processing the current buffer's skb */ |
765 | requeue_skb = ath_rxbuf_alloc(common, sc->rx.bufsize, GFP_ATOMIC); | 588 | requeue_skb = ath_rxbuf_alloc(common, common->rx_bufsize, GFP_ATOMIC); |
766 | 589 | ||
767 | /* If there is no memory we ignore the current RX'd frame, | 590 | /* If there is no memory we ignore the current RX'd frame, |
768 | * tell hardware it can give us a new frame using the old | 591 | * tell hardware it can give us a new frame using the old |
@@ -773,60 +596,26 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) | |||
773 | 596 | ||
774 | /* Unmap the frame */ | 597 | /* Unmap the frame */ |
775 | dma_unmap_single(sc->dev, bf->bf_buf_addr, | 598 | dma_unmap_single(sc->dev, bf->bf_buf_addr, |
776 | sc->rx.bufsize, | 599 | common->rx_bufsize, |
777 | DMA_FROM_DEVICE); | 600 | DMA_FROM_DEVICE); |
778 | 601 | ||
779 | skb_put(skb, ds->ds_rxstat.rs_datalen); | 602 | skb_put(skb, rx_stats->rs_datalen); |
780 | |||
781 | /* see if any padding is done by the hw and remove it */ | ||
782 | hdr = (struct ieee80211_hdr *)skb->data; | ||
783 | hdrlen = ieee80211_get_hdrlen_from_skb(skb); | ||
784 | fc = hdr->frame_control; | ||
785 | |||
786 | /* The MAC header is padded to have 32-bit boundary if the | ||
787 | * packet payload is non-zero. The general calculation for | ||
788 | * padsize would take into account odd header lengths: | ||
789 | * padsize = (4 - hdrlen % 4) % 4; However, since only | ||
790 | * even-length headers are used, padding can only be 0 or 2 | ||
791 | * bytes and we can optimize this a bit. In addition, we must | ||
792 | * not try to remove padding from short control frames that do | ||
793 | * not have payload. */ | ||
794 | padsize = hdrlen & 3; | ||
795 | if (padsize && hdrlen >= 24) { | ||
796 | memmove(skb->data + padsize, skb->data, hdrlen); | ||
797 | skb_pull(skb, padsize); | ||
798 | } | ||
799 | |||
800 | keyix = ds->ds_rxstat.rs_keyix; | ||
801 | 603 | ||
802 | if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) { | 604 | ath9k_cmn_rx_skb_postprocess(common, skb, rx_stats, |
803 | rx_status.flag |= RX_FLAG_DECRYPTED; | 605 | rxs, decrypt_error); |
804 | } else if (ieee80211_has_protected(fc) | ||
805 | && !decrypt_error && skb->len >= hdrlen + 4) { | ||
806 | keyix = skb->data[hdrlen + 3] >> 6; | ||
807 | |||
808 | if (test_bit(keyix, sc->keymap)) | ||
809 | rx_status.flag |= RX_FLAG_DECRYPTED; | ||
810 | } | ||
811 | if (ah->sw_mgmt_crypto && | ||
812 | (rx_status.flag & RX_FLAG_DECRYPTED) && | ||
813 | ieee80211_is_mgmt(fc)) { | ||
814 | /* Use software decrypt for management frames. */ | ||
815 | rx_status.flag &= ~RX_FLAG_DECRYPTED; | ||
816 | } | ||
817 | 606 | ||
818 | /* We will now give hardware our shiny new allocated skb */ | 607 | /* We will now give hardware our shiny new allocated skb */ |
819 | bf->bf_mpdu = requeue_skb; | 608 | bf->bf_mpdu = requeue_skb; |
820 | bf->bf_buf_addr = dma_map_single(sc->dev, requeue_skb->data, | 609 | bf->bf_buf_addr = dma_map_single(sc->dev, requeue_skb->data, |
821 | sc->rx.bufsize, | 610 | common->rx_bufsize, |
822 | DMA_FROM_DEVICE); | 611 | DMA_FROM_DEVICE); |
823 | if (unlikely(dma_mapping_error(sc->dev, | 612 | if (unlikely(dma_mapping_error(sc->dev, |
824 | bf->bf_buf_addr))) { | 613 | bf->bf_buf_addr))) { |
825 | dev_kfree_skb_any(requeue_skb); | 614 | dev_kfree_skb_any(requeue_skb); |
826 | bf->bf_mpdu = NULL; | 615 | bf->bf_mpdu = NULL; |
827 | ath_print(common, ATH_DBG_FATAL, | 616 | ath_print(common, ATH_DBG_FATAL, |
828 | "dma_mapping_error() on RX\n"); | 617 | "dma_mapping_error() on RX\n"); |
829 | ath_rx_send_to_mac80211(sc, skb, &rx_status); | 618 | ath_rx_send_to_mac80211(hw, sc, skb, rxs); |
830 | break; | 619 | break; |
831 | } | 620 | } |
832 | bf->bf_dmacontext = bf->bf_buf_addr; | 621 | bf->bf_dmacontext = bf->bf_buf_addr; |
@@ -837,7 +626,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) | |||
837 | */ | 626 | */ |
838 | if (sc->rx.defant != ds->ds_rxstat.rs_antenna) { | 627 | if (sc->rx.defant != ds->ds_rxstat.rs_antenna) { |
839 | if (++sc->rx.rxotherant >= 3) | 628 | if (++sc->rx.rxotherant >= 3) |
840 | ath_setdefantenna(sc, ds->ds_rxstat.rs_antenna); | 629 | ath_setdefantenna(sc, rx_stats->rs_antenna); |
841 | } else { | 630 | } else { |
842 | sc->rx.rxotherant = 0; | 631 | sc->rx.rxotherant = 0; |
843 | } | 632 | } |
@@ -847,7 +636,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) | |||
847 | SC_OP_WAIT_FOR_PSPOLL_DATA))) | 636 | SC_OP_WAIT_FOR_PSPOLL_DATA))) |
848 | ath_rx_ps(sc, skb); | 637 | ath_rx_ps(sc, skb); |
849 | 638 | ||
850 | ath_rx_send_to_mac80211(sc, skb, &rx_status); | 639 | ath_rx_send_to_mac80211(hw, sc, skb, rxs); |
851 | 640 | ||
852 | requeue: | 641 | requeue: |
853 | list_move_tail(&bf->list, &sc->rx.rxbuf); | 642 | list_move_tail(&bf->list, &sc->rx.rxbuf); |
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 061e12ce0b24..49ec25f020f0 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h | |||
@@ -971,10 +971,10 @@ enum { | |||
971 | #define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_S 4 | 971 | #define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_S 4 |
972 | #define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF 0x00000080 | 972 | #define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF 0x00000080 |
973 | #define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF_S 7 | 973 | #define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF_S 7 |
974 | #define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB 0x00000400 | ||
975 | #define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB_S 10 | ||
974 | #define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB 0x00001000 | 976 | #define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB 0x00001000 |
975 | #define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB_S 12 | 977 | #define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB_S 12 |
976 | #define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB 0x00001000 | ||
977 | #define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB_S 1 | ||
978 | #define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB 0x00008000 | 978 | #define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB 0x00008000 |
979 | #define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB_S 15 | 979 | #define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB_S 15 |
980 | #define AR_GPIO_RTC_RESET_OVERRIDE_ENABLE 0x00010000 | 980 | #define AR_GPIO_RTC_RESET_OVERRIDE_ENABLE 0x00010000 |
diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c index bc7d173b6fae..0a36b572294c 100644 --- a/drivers/net/wireless/ath/ath9k/virtual.c +++ b/drivers/net/wireless/ath/ath9k/virtual.c | |||
@@ -298,6 +298,7 @@ static void ath9k_wiphy_unpause_channel(struct ath_softc *sc) | |||
298 | void ath9k_wiphy_chan_work(struct work_struct *work) | 298 | void ath9k_wiphy_chan_work(struct work_struct *work) |
299 | { | 299 | { |
300 | struct ath_softc *sc = container_of(work, struct ath_softc, chan_work); | 300 | struct ath_softc *sc = container_of(work, struct ath_softc, chan_work); |
301 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
301 | struct ath_wiphy *aphy = sc->next_wiphy; | 302 | struct ath_wiphy *aphy = sc->next_wiphy; |
302 | 303 | ||
303 | if (aphy == NULL) | 304 | if (aphy == NULL) |
@@ -313,6 +314,10 @@ void ath9k_wiphy_chan_work(struct work_struct *work) | |||
313 | /* XXX: remove me eventually */ | 314 | /* XXX: remove me eventually */ |
314 | ath9k_update_ichannel(sc, aphy->hw, | 315 | ath9k_update_ichannel(sc, aphy->hw, |
315 | &sc->sc_ah->channels[sc->chan_idx]); | 316 | &sc->sc_ah->channels[sc->chan_idx]); |
317 | |||
318 | /* sync hw configuration for hw code */ | ||
319 | common->hw = aphy->hw; | ||
320 | |||
316 | ath_update_chainmask(sc, sc->chan_is_ht); | 321 | ath_update_chainmask(sc, sc->chan_is_ht); |
317 | if (ath_set_channel(sc, aphy->hw, | 322 | if (ath_set_channel(sc, aphy->hw, |
318 | &sc->sc_ah->channels[sc->chan_idx]) < 0) { | 323 | &sc->sc_ah->channels[sc->chan_idx]) < 0) { |
@@ -521,8 +526,9 @@ int ath9k_wiphy_select(struct ath_wiphy *aphy) | |||
521 | * frame being completed) | 526 | * frame being completed) |
522 | */ | 527 | */ |
523 | spin_unlock_bh(&sc->wiphy_lock); | 528 | spin_unlock_bh(&sc->wiphy_lock); |
524 | ath_radio_disable(sc); | 529 | ath_radio_disable(sc, aphy->hw); |
525 | ath_radio_enable(sc); | 530 | ath_radio_enable(sc, aphy->hw); |
531 | /* Only the primary wiphy hw is used for queuing work */ | ||
526 | ieee80211_queue_work(aphy->sc->hw, | 532 | ieee80211_queue_work(aphy->sc->hw, |
527 | &aphy->sc->chan_work); | 533 | &aphy->sc->chan_work); |
528 | return -EBUSY; /* previous select still in progress */ | 534 | return -EBUSY; /* previous select still in progress */ |
@@ -668,15 +674,78 @@ void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int) | |||
668 | bool ath9k_all_wiphys_idle(struct ath_softc *sc) | 674 | bool ath9k_all_wiphys_idle(struct ath_softc *sc) |
669 | { | 675 | { |
670 | unsigned int i; | 676 | unsigned int i; |
671 | if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) { | 677 | if (!sc->pri_wiphy->idle) |
672 | return false; | 678 | return false; |
673 | } | ||
674 | for (i = 0; i < sc->num_sec_wiphy; i++) { | 679 | for (i = 0; i < sc->num_sec_wiphy; i++) { |
675 | struct ath_wiphy *aphy = sc->sec_wiphy[i]; | 680 | struct ath_wiphy *aphy = sc->sec_wiphy[i]; |
676 | if (!aphy) | 681 | if (!aphy) |
677 | continue; | 682 | continue; |
678 | if (aphy->state != ATH_WIPHY_INACTIVE) | 683 | if (!aphy->idle) |
679 | return false; | 684 | return false; |
680 | } | 685 | } |
681 | return true; | 686 | return true; |
682 | } | 687 | } |
688 | |||
689 | /* caller must hold wiphy_lock */ | ||
690 | void ath9k_set_wiphy_idle(struct ath_wiphy *aphy, bool idle) | ||
691 | { | ||
692 | struct ath_softc *sc = aphy->sc; | ||
693 | |||
694 | aphy->idle = idle; | ||
695 | ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG, | ||
696 | "Marking %s as %s\n", | ||
697 | wiphy_name(aphy->hw->wiphy), | ||
698 | idle ? "idle" : "not-idle"); | ||
699 | } | ||
700 | /* Only bother starting a queue on an active virtual wiphy */ | ||
701 | void ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue) | ||
702 | { | ||
703 | struct ieee80211_hw *hw = sc->pri_wiphy->hw; | ||
704 | unsigned int i; | ||
705 | |||
706 | spin_lock_bh(&sc->wiphy_lock); | ||
707 | |||
708 | /* Start the primary wiphy */ | ||
709 | if (sc->pri_wiphy->state == ATH_WIPHY_ACTIVE) { | ||
710 | ieee80211_wake_queue(hw, skb_queue); | ||
711 | goto unlock; | ||
712 | } | ||
713 | |||
714 | /* Now start the secondary wiphy queues */ | ||
715 | for (i = 0; i < sc->num_sec_wiphy; i++) { | ||
716 | struct ath_wiphy *aphy = sc->sec_wiphy[i]; | ||
717 | if (!aphy) | ||
718 | continue; | ||
719 | if (aphy->state != ATH_WIPHY_ACTIVE) | ||
720 | continue; | ||
721 | |||
722 | hw = aphy->hw; | ||
723 | ieee80211_wake_queue(hw, skb_queue); | ||
724 | break; | ||
725 | } | ||
726 | |||
727 | unlock: | ||
728 | spin_unlock_bh(&sc->wiphy_lock); | ||
729 | } | ||
730 | |||
731 | /* Go ahead and propagate information to all virtual wiphys, it won't hurt */ | ||
732 | void ath_mac80211_stop_queue(struct ath_softc *sc, u16 skb_queue) | ||
733 | { | ||
734 | struct ieee80211_hw *hw = sc->pri_wiphy->hw; | ||
735 | unsigned int i; | ||
736 | |||
737 | spin_lock_bh(&sc->wiphy_lock); | ||
738 | |||
739 | /* Stop the primary wiphy */ | ||
740 | ieee80211_stop_queue(hw, skb_queue); | ||
741 | |||
742 | /* Now stop the secondary wiphy queues */ | ||
743 | for (i = 0; i < sc->num_sec_wiphy; i++) { | ||
744 | struct ath_wiphy *aphy = sc->sec_wiphy[i]; | ||
745 | if (!aphy) | ||
746 | continue; | ||
747 | hw = aphy->hw; | ||
748 | ieee80211_stop_queue(hw, skb_queue); | ||
749 | } | ||
750 | spin_unlock_bh(&sc->wiphy_lock); | ||
751 | } | ||
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 8e052f406c35..86b54ddd01cb 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c | |||
@@ -267,7 +267,10 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
267 | struct ath_node *an = NULL; | 267 | struct ath_node *an = NULL; |
268 | struct sk_buff *skb; | 268 | struct sk_buff *skb; |
269 | struct ieee80211_sta *sta; | 269 | struct ieee80211_sta *sta; |
270 | struct ieee80211_hw *hw; | ||
270 | struct ieee80211_hdr *hdr; | 271 | struct ieee80211_hdr *hdr; |
272 | struct ieee80211_tx_info *tx_info; | ||
273 | struct ath_tx_info_priv *tx_info_priv; | ||
271 | struct ath_atx_tid *tid = NULL; | 274 | struct ath_atx_tid *tid = NULL; |
272 | struct ath_buf *bf_next, *bf_last = bf->bf_lastbf; | 275 | struct ath_buf *bf_next, *bf_last = bf->bf_lastbf; |
273 | struct ath_desc *ds = bf_last->bf_desc; | 276 | struct ath_desc *ds = bf_last->bf_desc; |
@@ -280,10 +283,14 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
280 | skb = bf->bf_mpdu; | 283 | skb = bf->bf_mpdu; |
281 | hdr = (struct ieee80211_hdr *)skb->data; | 284 | hdr = (struct ieee80211_hdr *)skb->data; |
282 | 285 | ||
286 | tx_info = IEEE80211_SKB_CB(skb); | ||
287 | tx_info_priv = (struct ath_tx_info_priv *) tx_info->rate_driver_data[0]; | ||
288 | hw = tx_info_priv->aphy->hw; | ||
289 | |||
283 | rcu_read_lock(); | 290 | rcu_read_lock(); |
284 | 291 | ||
285 | /* XXX: use ieee80211_find_sta! */ | 292 | /* XXX: use ieee80211_find_sta! */ |
286 | sta = ieee80211_find_sta_by_hw(sc->hw, hdr->addr1); | 293 | sta = ieee80211_find_sta_by_hw(hw, hdr->addr1); |
287 | if (!sta) { | 294 | if (!sta) { |
288 | rcu_read_unlock(); | 295 | rcu_read_unlock(); |
289 | return; | 296 | return; |
@@ -908,9 +915,10 @@ int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype) | |||
908 | struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb) | 915 | struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb) |
909 | { | 916 | { |
910 | struct ath_txq *txq = NULL; | 917 | struct ath_txq *txq = NULL; |
918 | u16 skb_queue = skb_get_queue_mapping(skb); | ||
911 | int qnum; | 919 | int qnum; |
912 | 920 | ||
913 | qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc); | 921 | qnum = ath_get_hal_qnum(skb_queue, sc); |
914 | txq = &sc->tx.txq[qnum]; | 922 | txq = &sc->tx.txq[qnum]; |
915 | 923 | ||
916 | spin_lock_bh(&txq->axq_lock); | 924 | spin_lock_bh(&txq->axq_lock); |
@@ -919,7 +927,7 @@ struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb) | |||
919 | ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_XMIT, | 927 | ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_XMIT, |
920 | "TX queue: %d is full, depth: %d\n", | 928 | "TX queue: %d is full, depth: %d\n", |
921 | qnum, txq->axq_depth); | 929 | qnum, txq->axq_depth); |
922 | ieee80211_stop_queue(sc->hw, skb_get_queue_mapping(skb)); | 930 | ath_mac80211_stop_queue(sc, skb_queue); |
923 | txq->stopped = 1; | 931 | txq->stopped = 1; |
924 | spin_unlock_bh(&txq->axq_lock); | 932 | spin_unlock_bh(&txq->axq_lock); |
925 | return NULL; | 933 | return NULL; |
@@ -1569,7 +1577,7 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, | |||
1569 | 1577 | ||
1570 | bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3); | 1578 | bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3); |
1571 | 1579 | ||
1572 | if (conf_is_ht(&sc->hw->conf) && !is_pae(skb)) | 1580 | if (conf_is_ht(&hw->conf) && !is_pae(skb)) |
1573 | bf->bf_state.bf_type |= BUF_HT; | 1581 | bf->bf_state.bf_type |= BUF_HT; |
1574 | 1582 | ||
1575 | bf->bf_flags = setup_tx_flags(sc, skb, txctl->txq); | 1583 | bf->bf_flags = setup_tx_flags(sc, skb, txctl->txq); |
@@ -1698,8 +1706,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, | |||
1698 | * on the queue */ | 1706 | * on the queue */ |
1699 | spin_lock_bh(&txq->axq_lock); | 1707 | spin_lock_bh(&txq->axq_lock); |
1700 | if (sc->tx.txq[txq->axq_qnum].axq_depth > 1) { | 1708 | if (sc->tx.txq[txq->axq_qnum].axq_depth > 1) { |
1701 | ieee80211_stop_queue(sc->hw, | 1709 | ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb)); |
1702 | skb_get_queue_mapping(skb)); | ||
1703 | txq->stopped = 1; | 1710 | txq->stopped = 1; |
1704 | } | 1711 | } |
1705 | spin_unlock_bh(&txq->axq_lock); | 1712 | spin_unlock_bh(&txq->axq_lock); |
@@ -1939,7 +1946,7 @@ static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq) | |||
1939 | sc->tx.txq[txq->axq_qnum].axq_depth <= (ATH_TXBUF - 20)) { | 1946 | sc->tx.txq[txq->axq_qnum].axq_depth <= (ATH_TXBUF - 20)) { |
1940 | qnum = ath_get_mac80211_qnum(txq->axq_qnum, sc); | 1947 | qnum = ath_get_mac80211_qnum(txq->axq_qnum, sc); |
1941 | if (qnum != -1) { | 1948 | if (qnum != -1) { |
1942 | ieee80211_wake_queue(sc->hw, qnum); | 1949 | ath_mac80211_start_queue(sc, qnum); |
1943 | txq->stopped = 0; | 1950 | txq->stopped = 0; |
1944 | } | 1951 | } |
1945 | } | 1952 | } |
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index cce188837d10..3edbbcf0f548 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c | |||
@@ -99,6 +99,22 @@ static struct { | |||
99 | { ATMEL_FW_TYPE_506, "atmel_at76c506", "bin" }, | 99 | { ATMEL_FW_TYPE_506, "atmel_at76c506", "bin" }, |
100 | { ATMEL_FW_TYPE_NONE, NULL, NULL } | 100 | { ATMEL_FW_TYPE_NONE, NULL, NULL } |
101 | }; | 101 | }; |
102 | MODULE_FIRMWARE("atmel_at76c502-wpa.bin"); | ||
103 | MODULE_FIRMWARE("atmel_at76c502.bin"); | ||
104 | MODULE_FIRMWARE("atmel_at76c502d-wpa.bin"); | ||
105 | MODULE_FIRMWARE("atmel_at76c502d.bin"); | ||
106 | MODULE_FIRMWARE("atmel_at76c502e-wpa.bin"); | ||
107 | MODULE_FIRMWARE("atmel_at76c502e.bin"); | ||
108 | MODULE_FIRMWARE("atmel_at76c502_3com-wpa.bin"); | ||
109 | MODULE_FIRMWARE("atmel_at76c502_3com.bin"); | ||
110 | MODULE_FIRMWARE("atmel_at76c504-wpa.bin"); | ||
111 | MODULE_FIRMWARE("atmel_at76c504.bin"); | ||
112 | MODULE_FIRMWARE("atmel_at76c504_2958-wpa.bin"); | ||
113 | MODULE_FIRMWARE("atmel_at76c504_2958.bin"); | ||
114 | MODULE_FIRMWARE("atmel_at76c504a_2958-wpa.bin"); | ||
115 | MODULE_FIRMWARE("atmel_at76c504a_2958.bin"); | ||
116 | MODULE_FIRMWARE("atmel_at76c506-wpa.bin"); | ||
117 | MODULE_FIRMWARE("atmel_at76c506.bin"); | ||
102 | 118 | ||
103 | #define MAX_SSID_LENGTH 32 | 119 | #define MAX_SSID_LENGTH 32 |
104 | #define MGMT_JIFFIES (256 * HZ / 100) | 120 | #define MGMT_JIFFIES (256 * HZ / 100) |
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index de4e804bedf0..b5cd7f57055b 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c | |||
@@ -1157,18 +1157,17 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot) | |||
1157 | } | 1157 | } |
1158 | 1158 | ||
1159 | static int dma_tx_fragment(struct b43_dmaring *ring, | 1159 | static int dma_tx_fragment(struct b43_dmaring *ring, |
1160 | struct sk_buff **in_skb) | 1160 | struct sk_buff *skb) |
1161 | { | 1161 | { |
1162 | struct sk_buff *skb = *in_skb; | ||
1163 | const struct b43_dma_ops *ops = ring->ops; | 1162 | const struct b43_dma_ops *ops = ring->ops; |
1164 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1163 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1164 | struct b43_private_tx_info *priv_info = b43_get_priv_tx_info(info); | ||
1165 | u8 *header; | 1165 | u8 *header; |
1166 | int slot, old_top_slot, old_used_slots; | 1166 | int slot, old_top_slot, old_used_slots; |
1167 | int err; | 1167 | int err; |
1168 | struct b43_dmadesc_generic *desc; | 1168 | struct b43_dmadesc_generic *desc; |
1169 | struct b43_dmadesc_meta *meta; | 1169 | struct b43_dmadesc_meta *meta; |
1170 | struct b43_dmadesc_meta *meta_hdr; | 1170 | struct b43_dmadesc_meta *meta_hdr; |
1171 | struct sk_buff *bounce_skb; | ||
1172 | u16 cookie; | 1171 | u16 cookie; |
1173 | size_t hdrsize = b43_txhdr_size(ring->dev); | 1172 | size_t hdrsize = b43_txhdr_size(ring->dev); |
1174 | 1173 | ||
@@ -1212,34 +1211,28 @@ static int dma_tx_fragment(struct b43_dmaring *ring, | |||
1212 | 1211 | ||
1213 | meta->skb = skb; | 1212 | meta->skb = skb; |
1214 | meta->is_last_fragment = 1; | 1213 | meta->is_last_fragment = 1; |
1214 | priv_info->bouncebuffer = NULL; | ||
1215 | 1215 | ||
1216 | meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); | 1216 | meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); |
1217 | /* create a bounce buffer in zone_dma on mapping failure. */ | 1217 | /* create a bounce buffer in zone_dma on mapping failure. */ |
1218 | if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) { | 1218 | if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) { |
1219 | bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA); | 1219 | priv_info->bouncebuffer = kmalloc(skb->len, GFP_ATOMIC | GFP_DMA); |
1220 | if (!bounce_skb) { | 1220 | if (!priv_info->bouncebuffer) { |
1221 | ring->current_slot = old_top_slot; | 1221 | ring->current_slot = old_top_slot; |
1222 | ring->used_slots = old_used_slots; | 1222 | ring->used_slots = old_used_slots; |
1223 | err = -ENOMEM; | 1223 | err = -ENOMEM; |
1224 | goto out_unmap_hdr; | 1224 | goto out_unmap_hdr; |
1225 | } | 1225 | } |
1226 | memcpy(priv_info->bouncebuffer, skb->data, skb->len); | ||
1226 | 1227 | ||
1227 | memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len); | 1228 | meta->dmaaddr = map_descbuffer(ring, priv_info->bouncebuffer, skb->len, 1); |
1228 | memcpy(bounce_skb->cb, skb->cb, sizeof(skb->cb)); | ||
1229 | bounce_skb->dev = skb->dev; | ||
1230 | skb_set_queue_mapping(bounce_skb, skb_get_queue_mapping(skb)); | ||
1231 | info = IEEE80211_SKB_CB(bounce_skb); | ||
1232 | |||
1233 | dev_kfree_skb_any(skb); | ||
1234 | skb = bounce_skb; | ||
1235 | *in_skb = bounce_skb; | ||
1236 | meta->skb = skb; | ||
1237 | meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); | ||
1238 | if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) { | 1229 | if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) { |
1230 | kfree(priv_info->bouncebuffer); | ||
1231 | priv_info->bouncebuffer = NULL; | ||
1239 | ring->current_slot = old_top_slot; | 1232 | ring->current_slot = old_top_slot; |
1240 | ring->used_slots = old_used_slots; | 1233 | ring->used_slots = old_used_slots; |
1241 | err = -EIO; | 1234 | err = -EIO; |
1242 | goto out_free_bounce; | 1235 | goto out_unmap_hdr; |
1243 | } | 1236 | } |
1244 | } | 1237 | } |
1245 | 1238 | ||
@@ -1256,8 +1249,6 @@ static int dma_tx_fragment(struct b43_dmaring *ring, | |||
1256 | ops->poke_tx(ring, next_slot(ring, slot)); | 1249 | ops->poke_tx(ring, next_slot(ring, slot)); |
1257 | return 0; | 1250 | return 0; |
1258 | 1251 | ||
1259 | out_free_bounce: | ||
1260 | dev_kfree_skb_any(skb); | ||
1261 | out_unmap_hdr: | 1252 | out_unmap_hdr: |
1262 | unmap_descbuffer(ring, meta_hdr->dmaaddr, | 1253 | unmap_descbuffer(ring, meta_hdr->dmaaddr, |
1263 | hdrsize, 1); | 1254 | hdrsize, 1); |
@@ -1362,11 +1353,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) | |||
1362 | * static, so we don't need to store it per frame. */ | 1353 | * static, so we don't need to store it per frame. */ |
1363 | ring->queue_prio = skb_get_queue_mapping(skb); | 1354 | ring->queue_prio = skb_get_queue_mapping(skb); |
1364 | 1355 | ||
1365 | /* dma_tx_fragment might reallocate the skb, so invalidate pointers pointing | 1356 | err = dma_tx_fragment(ring, skb); |
1366 | * into the skb data or cb now. */ | ||
1367 | hdr = NULL; | ||
1368 | info = NULL; | ||
1369 | err = dma_tx_fragment(ring, &skb); | ||
1370 | if (unlikely(err == -ENOKEY)) { | 1357 | if (unlikely(err == -ENOKEY)) { |
1371 | /* Drop this packet, as we don't have the encryption key | 1358 | /* Drop this packet, as we don't have the encryption key |
1372 | * anymore and must not transmit it unencrypted. */ | 1359 | * anymore and must not transmit it unencrypted. */ |
@@ -1413,12 +1400,17 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, | |||
1413 | B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); | 1400 | B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); |
1414 | desc = ops->idx2desc(ring, slot, &meta); | 1401 | desc = ops->idx2desc(ring, slot, &meta); |
1415 | 1402 | ||
1416 | if (meta->skb) | 1403 | if (meta->skb) { |
1417 | unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, | 1404 | struct b43_private_tx_info *priv_info = |
1418 | 1); | 1405 | b43_get_priv_tx_info(IEEE80211_SKB_CB(meta->skb)); |
1419 | else | 1406 | |
1407 | unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1); | ||
1408 | kfree(priv_info->bouncebuffer); | ||
1409 | priv_info->bouncebuffer = NULL; | ||
1410 | } else { | ||
1420 | unmap_descbuffer(ring, meta->dmaaddr, | 1411 | unmap_descbuffer(ring, meta->dmaaddr, |
1421 | b43_txhdr_size(dev), 1); | 1412 | b43_txhdr_size(dev), 1); |
1413 | } | ||
1422 | 1414 | ||
1423 | if (meta->is_last_fragment) { | 1415 | if (meta->is_last_fragment) { |
1424 | struct ieee80211_tx_info *info; | 1416 | struct ieee80211_tx_info *info; |
diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 3105f235303a..7d2550269ede 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c | |||
@@ -761,7 +761,11 @@ data_ready: | |||
761 | rx_error: | 761 | rx_error: |
762 | if (err_msg) | 762 | if (err_msg) |
763 | b43dbg(q->dev->wl, "PIO RX error: %s\n", err_msg); | 763 | b43dbg(q->dev->wl, "PIO RX error: %s\n", err_msg); |
764 | b43_piorx_write16(q, B43_PIO_RXCTL, B43_PIO_RXCTL_DATARDY); | 764 | if (q->rev >= 8) |
765 | b43_piorx_write32(q, B43_PIO8_RXCTL, B43_PIO8_RXCTL_DATARDY); | ||
766 | else | ||
767 | b43_piorx_write16(q, B43_PIO_RXCTL, B43_PIO_RXCTL_DATARDY); | ||
768 | |||
765 | return 1; | 769 | return 1; |
766 | } | 770 | } |
767 | 771 | ||
diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h index 3530de871873..d23ff9fe0c9e 100644 --- a/drivers/net/wireless/b43/xmit.h +++ b/drivers/net/wireless/b43/xmit.h | |||
@@ -2,6 +2,8 @@ | |||
2 | #define B43_XMIT_H_ | 2 | #define B43_XMIT_H_ |
3 | 3 | ||
4 | #include "main.h" | 4 | #include "main.h" |
5 | #include <net/mac80211.h> | ||
6 | |||
5 | 7 | ||
6 | #define _b43_declare_plcp_hdr(size) \ | 8 | #define _b43_declare_plcp_hdr(size) \ |
7 | struct b43_plcp_hdr##size { \ | 9 | struct b43_plcp_hdr##size { \ |
@@ -332,4 +334,21 @@ static inline u8 b43_kidx_to_raw(struct b43_wldev *dev, u8 firmware_kidx) | |||
332 | return raw_kidx; | 334 | return raw_kidx; |
333 | } | 335 | } |
334 | 336 | ||
337 | /* struct b43_private_tx_info - TX info private to b43. | ||
338 | * The structure is placed in (struct ieee80211_tx_info *)->rate_driver_data | ||
339 | * | ||
340 | * @bouncebuffer: DMA Bouncebuffer (if used) | ||
341 | */ | ||
342 | struct b43_private_tx_info { | ||
343 | void *bouncebuffer; | ||
344 | }; | ||
345 | |||
346 | static inline struct b43_private_tx_info * | ||
347 | b43_get_priv_tx_info(struct ieee80211_tx_info *info) | ||
348 | { | ||
349 | BUILD_BUG_ON(sizeof(struct b43_private_tx_info) > | ||
350 | sizeof(info->rate_driver_data)); | ||
351 | return (struct b43_private_tx_info *)info->rate_driver_data; | ||
352 | } | ||
353 | |||
335 | #endif /* B43_XMIT_H_ */ | 354 | #endif /* B43_XMIT_H_ */ |
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 6e2fc0cb6f8a..b7408370cf82 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c | |||
@@ -8462,6 +8462,12 @@ static int ipw2100_get_firmware(struct ipw2100_priv *priv, | |||
8462 | return 0; | 8462 | return 0; |
8463 | } | 8463 | } |
8464 | 8464 | ||
8465 | MODULE_FIRMWARE(IPW2100_FW_NAME("-i")); | ||
8466 | #ifdef CONFIG_IPW2100_MONITOR | ||
8467 | MODULE_FIRMWARE(IPW2100_FW_NAME("-p")); | ||
8468 | #endif | ||
8469 | MODULE_FIRMWARE(IPW2100_FW_NAME("")); | ||
8470 | |||
8465 | static void ipw2100_release_firmware(struct ipw2100_priv *priv, | 8471 | static void ipw2100_release_firmware(struct ipw2100_priv *priv, |
8466 | struct ipw2100_fw *fw) | 8472 | struct ipw2100_fw *fw) |
8467 | { | 8473 | { |
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 5c6ff58732d5..9b398db2d740 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c | |||
@@ -80,6 +80,11 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION); | |||
80 | MODULE_VERSION(DRV_VERSION); | 80 | MODULE_VERSION(DRV_VERSION); |
81 | MODULE_AUTHOR(DRV_COPYRIGHT); | 81 | MODULE_AUTHOR(DRV_COPYRIGHT); |
82 | MODULE_LICENSE("GPL"); | 82 | MODULE_LICENSE("GPL"); |
83 | MODULE_FIRMWARE("ipw2200-ibss.fw"); | ||
84 | #ifdef CONFIG_IPW2200_MONITOR | ||
85 | MODULE_FIRMWARE("ipw2200-sniffer.fw"); | ||
86 | #endif | ||
87 | MODULE_FIRMWARE("ipw2200-bss.fw"); | ||
83 | 88 | ||
84 | static int cmdlog = 0; | 89 | static int cmdlog = 0; |
85 | static int debug = 0; | 90 | static int debug = 0; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 09a7bd2c0be4..26a1134f84a2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c | |||
@@ -564,7 +564,7 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, | |||
564 | return; | 564 | return; |
565 | } | 565 | } |
566 | 566 | ||
567 | skb = alloc_skb(IWL_LINK_HDR_MAX, GFP_ATOMIC); | 567 | skb = alloc_skb(IWL_LINK_HDR_MAX * 2, GFP_ATOMIC); |
568 | if (!skb) { | 568 | if (!skb) { |
569 | IWL_ERR(priv, "alloc_skb failed\n"); | 569 | IWL_ERR(priv, "alloc_skb failed\n"); |
570 | return; | 570 | return; |
@@ -575,6 +575,7 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, | |||
575 | (struct ieee80211_hdr *)rxb_addr(rxb), | 575 | (struct ieee80211_hdr *)rxb_addr(rxb), |
576 | le32_to_cpu(rx_end->status), stats); | 576 | le32_to_cpu(rx_end->status), stats); |
577 | 577 | ||
578 | skb_reserve(skb, IWL_LINK_HDR_MAX); | ||
578 | skb_add_rx_frag(skb, 0, rxb->page, | 579 | skb_add_rx_frag(skb, 0, rxb->page, |
579 | (void *)rx_hdr->payload - (void *)pkt, len); | 580 | (void *)rx_hdr->payload - (void *)pkt, len); |
580 | 581 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 1ff465ad40d8..1d22ea390c00 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c | |||
@@ -1449,14 +1449,14 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) | |||
1449 | is_ht40 = is_ht40_channel(priv->staging_rxon.flags); | 1449 | is_ht40 = is_ht40_channel(priv->staging_rxon.flags); |
1450 | 1450 | ||
1451 | if (is_ht40 && | 1451 | if (is_ht40 && |
1452 | (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK)) | 1452 | (priv->staging_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK)) |
1453 | ctrl_chan_high = 1; | 1453 | ctrl_chan_high = 1; |
1454 | 1454 | ||
1455 | cmd.band = band; | 1455 | cmd.band = band; |
1456 | cmd.expect_beacon = 0; | 1456 | cmd.expect_beacon = 0; |
1457 | cmd.channel = cpu_to_le16(channel); | 1457 | cmd.channel = cpu_to_le16(channel); |
1458 | cmd.rxon_flags = priv->active_rxon.flags; | 1458 | cmd.rxon_flags = priv->staging_rxon.flags; |
1459 | cmd.rxon_filter_flags = priv->active_rxon.filter_flags; | 1459 | cmd.rxon_filter_flags = priv->staging_rxon.filter_flags; |
1460 | cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); | 1460 | cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); |
1461 | if (ch_info) | 1461 | if (ch_info) |
1462 | cmd.expect_beacon = is_channel_radar(ch_info); | 1462 | cmd.expect_beacon = is_channel_radar(ch_info); |
@@ -1473,8 +1473,10 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) | |||
1473 | return rc; | 1473 | return rc; |
1474 | } | 1474 | } |
1475 | 1475 | ||
1476 | rc = iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd); | 1476 | priv->switch_rxon.channel = cpu_to_le16(channel); |
1477 | return rc; | 1477 | priv->switch_rxon.switch_in_progress = true; |
1478 | |||
1479 | return iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd); | ||
1478 | } | 1480 | } |
1479 | 1481 | ||
1480 | /** | 1482 | /** |
@@ -2228,7 +2230,7 @@ struct iwl_cfg iwl4965_agn_cfg = { | |||
2228 | .num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES, | 2230 | .num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES, |
2229 | .mod_params = &iwl4965_mod_params, | 2231 | .mod_params = &iwl4965_mod_params, |
2230 | .valid_tx_ant = ANT_AB, | 2232 | .valid_tx_ant = ANT_AB, |
2231 | .valid_rx_ant = ANT_AB, | 2233 | .valid_rx_ant = ANT_ABC, |
2232 | .pll_cfg_val = 0, | 2234 | .pll_cfg_val = 0, |
2233 | .set_l0s = true, | 2235 | .set_l0s = true, |
2234 | .use_bsm = true, | 2236 | .use_bsm = true, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 910217f0ad8a..6eaf26b07636 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c | |||
@@ -661,9 +661,13 @@ int iwl5000_alive_notify(struct iwl_priv *priv) | |||
661 | iwl_txq_ctx_activate(priv, i); | 661 | iwl_txq_ctx_activate(priv, i); |
662 | iwl5000_tx_queue_set_status(priv, &priv->txq[i], ac, 0); | 662 | iwl5000_tx_queue_set_status(priv, &priv->txq[i], ac, 0); |
663 | } | 663 | } |
664 | /* TODO - need to initialize those FIFOs inside the loop above, | 664 | |
665 | * not only mark them as active */ | 665 | /* |
666 | iwl_txq_ctx_activate(priv, 4); | 666 | * TODO - need to initialize these queues and map them to FIFOs |
667 | * in the loop above, not only mark them as active. We do this | ||
668 | * because we want the first aggregation queue to be queue #10, | ||
669 | * but do not use 8 or 9 otherwise yet. | ||
670 | */ | ||
667 | iwl_txq_ctx_activate(priv, 7); | 671 | iwl_txq_ctx_activate(priv, 7); |
668 | iwl_txq_ctx_activate(priv, 8); | 672 | iwl_txq_ctx_activate(priv, 8); |
669 | iwl_txq_ctx_activate(priv, 9); | 673 | iwl_txq_ctx_activate(priv, 9); |
@@ -1387,8 +1391,8 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv, u16 channel) | |||
1387 | priv->active_rxon.channel, channel); | 1391 | priv->active_rxon.channel, channel); |
1388 | cmd.band = priv->band == IEEE80211_BAND_2GHZ; | 1392 | cmd.band = priv->band == IEEE80211_BAND_2GHZ; |
1389 | cmd.channel = cpu_to_le16(channel); | 1393 | cmd.channel = cpu_to_le16(channel); |
1390 | cmd.rxon_flags = priv->active_rxon.flags; | 1394 | cmd.rxon_flags = priv->staging_rxon.flags; |
1391 | cmd.rxon_filter_flags = priv->active_rxon.filter_flags; | 1395 | cmd.rxon_filter_flags = priv->staging_rxon.filter_flags; |
1392 | cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); | 1396 | cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); |
1393 | ch_info = iwl_get_channel_info(priv, priv->band, channel); | 1397 | ch_info = iwl_get_channel_info(priv, priv->band, channel); |
1394 | if (ch_info) | 1398 | if (ch_info) |
@@ -1398,6 +1402,8 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv, u16 channel) | |||
1398 | priv->active_rxon.channel, channel); | 1402 | priv->active_rxon.channel, channel); |
1399 | return -EFAULT; | 1403 | return -EFAULT; |
1400 | } | 1404 | } |
1405 | priv->switch_rxon.channel = cpu_to_le16(channel); | ||
1406 | priv->switch_rxon.switch_in_progress = true; | ||
1401 | 1407 | ||
1402 | return iwl_send_cmd_sync(priv, &hcmd); | 1408 | return iwl_send_cmd_sync(priv, &hcmd); |
1403 | } | 1409 | } |
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 70e117f8d0c4..f732f6d194a0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c | |||
@@ -90,11 +90,7 @@ static void iwl6000_nic_config(struct iwl_priv *priv) | |||
90 | CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); | 90 | CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); |
91 | 91 | ||
92 | /* no locking required for register write */ | 92 | /* no locking required for register write */ |
93 | if (priv->cfg->pa_type == IWL_PA_HYBRID) { | 93 | if (priv->cfg->pa_type == IWL_PA_INTERNAL) { |
94 | /* 2x2 hybrid phy type */ | ||
95 | iwl_write32(priv, CSR_GP_DRIVER_REG, | ||
96 | CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_HYB); | ||
97 | } else if (priv->cfg->pa_type == IWL_PA_INTERNAL) { | ||
98 | /* 2x2 IPA phy type */ | 94 | /* 2x2 IPA phy type */ |
99 | iwl_write32(priv, CSR_GP_DRIVER_REG, | 95 | iwl_write32(priv, CSR_GP_DRIVER_REG, |
100 | CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA); | 96 | CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA); |
@@ -166,9 +162,7 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) | |||
166 | BIT(IWL_CALIB_XTAL) | | 162 | BIT(IWL_CALIB_XTAL) | |
167 | BIT(IWL_CALIB_LO) | | 163 | BIT(IWL_CALIB_LO) | |
168 | BIT(IWL_CALIB_TX_IQ) | | 164 | BIT(IWL_CALIB_TX_IQ) | |
169 | BIT(IWL_CALIB_TX_IQ_PERD) | | ||
170 | BIT(IWL_CALIB_BASE_BAND); | 165 | BIT(IWL_CALIB_BASE_BAND); |
171 | |||
172 | return 0; | 166 | return 0; |
173 | } | 167 | } |
174 | 168 | ||
@@ -188,8 +182,8 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, u16 channel) | |||
188 | 182 | ||
189 | cmd.band = priv->band == IEEE80211_BAND_2GHZ; | 183 | cmd.band = priv->band == IEEE80211_BAND_2GHZ; |
190 | cmd.channel = cpu_to_le16(channel); | 184 | cmd.channel = cpu_to_le16(channel); |
191 | cmd.rxon_flags = priv->active_rxon.flags; | 185 | cmd.rxon_flags = priv->staging_rxon.flags; |
192 | cmd.rxon_filter_flags = priv->active_rxon.filter_flags; | 186 | cmd.rxon_filter_flags = priv->staging_rxon.filter_flags; |
193 | cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); | 187 | cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); |
194 | ch_info = iwl_get_channel_info(priv, priv->band, channel); | 188 | ch_info = iwl_get_channel_info(priv, priv->band, channel); |
195 | if (ch_info) | 189 | if (ch_info) |
@@ -199,6 +193,8 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, u16 channel) | |||
199 | priv->active_rxon.channel, channel); | 193 | priv->active_rxon.channel, channel); |
200 | return -EFAULT; | 194 | return -EFAULT; |
201 | } | 195 | } |
196 | priv->switch_rxon.channel = cpu_to_le16(channel); | ||
197 | priv->switch_rxon.switch_in_progress = true; | ||
202 | 198 | ||
203 | return iwl_send_cmd_sync(priv, &hcmd); | 199 | return iwl_send_cmd_sync(priv, &hcmd); |
204 | } | 200 | } |
@@ -279,98 +275,6 @@ static struct iwl_ops iwl6050_ops = { | |||
279 | .led = &iwlagn_led_ops, | 275 | .led = &iwlagn_led_ops, |
280 | }; | 276 | }; |
281 | 277 | ||
282 | |||
283 | /* | ||
284 | * "h": Hybrid configuration, use both internal and external Power Amplifier | ||
285 | */ | ||
286 | struct iwl_cfg iwl6000h_2agn_cfg = { | ||
287 | .name = "6000 Series 2x2 AGN", | ||
288 | .fw_name_pre = IWL6000_FW_PRE, | ||
289 | .ucode_api_max = IWL6000_UCODE_API_MAX, | ||
290 | .ucode_api_min = IWL6000_UCODE_API_MIN, | ||
291 | .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, | ||
292 | .ops = &iwl6000_ops, | ||
293 | .eeprom_size = OTP_LOW_IMAGE_SIZE, | ||
294 | .eeprom_ver = EEPROM_6000_EEPROM_VERSION, | ||
295 | .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, | ||
296 | .num_of_queues = IWL50_NUM_QUEUES, | ||
297 | .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, | ||
298 | .mod_params = &iwl50_mod_params, | ||
299 | .valid_tx_ant = ANT_AB, | ||
300 | .valid_rx_ant = ANT_AB, | ||
301 | .pll_cfg_val = 0, | ||
302 | .set_l0s = true, | ||
303 | .use_bsm = false, | ||
304 | .pa_type = IWL_PA_HYBRID, | ||
305 | .max_ll_items = OTP_MAX_LL_ITEMS_6x00, | ||
306 | .shadow_ram_support = true, | ||
307 | .ht_greenfield_support = true, | ||
308 | .led_compensation = 51, | ||
309 | .use_rts_for_ht = true, /* use rts/cts protection */ | ||
310 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, | ||
311 | .supports_idle = true, | ||
312 | .adv_thermal_throttle = true, | ||
313 | .support_ct_kill_exit = true, | ||
314 | }; | ||
315 | |||
316 | struct iwl_cfg iwl6000h_2abg_cfg = { | ||
317 | .name = "6000 Series 2x2 ABG", | ||
318 | .fw_name_pre = IWL6000_FW_PRE, | ||
319 | .ucode_api_max = IWL6000_UCODE_API_MAX, | ||
320 | .ucode_api_min = IWL6000_UCODE_API_MIN, | ||
321 | .sku = IWL_SKU_A|IWL_SKU_G, | ||
322 | .ops = &iwl6000_ops, | ||
323 | .eeprom_size = OTP_LOW_IMAGE_SIZE, | ||
324 | .eeprom_ver = EEPROM_6000_EEPROM_VERSION, | ||
325 | .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, | ||
326 | .num_of_queues = IWL50_NUM_QUEUES, | ||
327 | .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, | ||
328 | .mod_params = &iwl50_mod_params, | ||
329 | .valid_tx_ant = ANT_AB, | ||
330 | .valid_rx_ant = ANT_AB, | ||
331 | .pll_cfg_val = 0, | ||
332 | .set_l0s = true, | ||
333 | .use_bsm = false, | ||
334 | .pa_type = IWL_PA_HYBRID, | ||
335 | .max_ll_items = OTP_MAX_LL_ITEMS_6x00, | ||
336 | .shadow_ram_support = true, | ||
337 | .ht_greenfield_support = true, | ||
338 | .led_compensation = 51, | ||
339 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, | ||
340 | .supports_idle = true, | ||
341 | .adv_thermal_throttle = true, | ||
342 | .support_ct_kill_exit = true, | ||
343 | }; | ||
344 | |||
345 | struct iwl_cfg iwl6000h_2bg_cfg = { | ||
346 | .name = "6000 Series 2x2 BG", | ||
347 | .fw_name_pre = IWL6000_FW_PRE, | ||
348 | .ucode_api_max = IWL6000_UCODE_API_MAX, | ||
349 | .ucode_api_min = IWL6000_UCODE_API_MIN, | ||
350 | .sku = IWL_SKU_G, | ||
351 | .ops = &iwl6000_ops, | ||
352 | .eeprom_size = OTP_LOW_IMAGE_SIZE, | ||
353 | .eeprom_ver = EEPROM_6000_EEPROM_VERSION, | ||
354 | .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, | ||
355 | .num_of_queues = IWL50_NUM_QUEUES, | ||
356 | .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, | ||
357 | .mod_params = &iwl50_mod_params, | ||
358 | .valid_tx_ant = ANT_AB, | ||
359 | .valid_rx_ant = ANT_AB, | ||
360 | .pll_cfg_val = 0, | ||
361 | .set_l0s = true, | ||
362 | .use_bsm = false, | ||
363 | .pa_type = IWL_PA_HYBRID, | ||
364 | .max_ll_items = OTP_MAX_LL_ITEMS_6x00, | ||
365 | .shadow_ram_support = true, | ||
366 | .ht_greenfield_support = true, | ||
367 | .led_compensation = 51, | ||
368 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, | ||
369 | .supports_idle = true, | ||
370 | .adv_thermal_throttle = true, | ||
371 | .support_ct_kill_exit = true, | ||
372 | }; | ||
373 | |||
374 | /* | 278 | /* |
375 | * "i": Internal configuration, use internal Power Amplifier | 279 | * "i": Internal configuration, use internal Power Amplifier |
376 | */ | 280 | */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index b5fe8f87aa7e..da0b38e866ba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -122,6 +122,17 @@ int iwl_commit_rxon(struct iwl_priv *priv) | |||
122 | return -EINVAL; | 122 | return -EINVAL; |
123 | } | 123 | } |
124 | 124 | ||
125 | /* | ||
126 | * receive commit_rxon request | ||
127 | * abort any previous channel switch if still in process | ||
128 | */ | ||
129 | if (priv->switch_rxon.switch_in_progress && | ||
130 | (priv->switch_rxon.channel != priv->staging_rxon.channel)) { | ||
131 | IWL_DEBUG_11H(priv, "abort channel switch on %d\n", | ||
132 | le16_to_cpu(priv->switch_rxon.channel)); | ||
133 | priv->switch_rxon.switch_in_progress = false; | ||
134 | } | ||
135 | |||
125 | /* If we don't need to send a full RXON, we can use | 136 | /* If we don't need to send a full RXON, we can use |
126 | * iwl_rxon_assoc_cmd which is used to reconfigure filter | 137 | * iwl_rxon_assoc_cmd which is used to reconfigure filter |
127 | * and other flags for the current radio configuration. */ | 138 | * and other flags for the current radio configuration. */ |
@@ -133,6 +144,7 @@ int iwl_commit_rxon(struct iwl_priv *priv) | |||
133 | } | 144 | } |
134 | 145 | ||
135 | memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); | 146 | memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); |
147 | iwl_print_rx_config_cmd(priv); | ||
136 | return 0; | 148 | return 0; |
137 | } | 149 | } |
138 | 150 | ||
@@ -228,6 +240,7 @@ int iwl_commit_rxon(struct iwl_priv *priv) | |||
228 | } | 240 | } |
229 | memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); | 241 | memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); |
230 | } | 242 | } |
243 | iwl_print_rx_config_cmd(priv); | ||
231 | 244 | ||
232 | iwl_init_sensitivity(priv); | 245 | iwl_init_sensitivity(priv); |
233 | 246 | ||
@@ -1071,6 +1084,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) | |||
1071 | u32 inta = 0; | 1084 | u32 inta = 0; |
1072 | u32 handled = 0; | 1085 | u32 handled = 0; |
1073 | unsigned long flags; | 1086 | unsigned long flags; |
1087 | u32 i; | ||
1074 | #ifdef CONFIG_IWLWIFI_DEBUG | 1088 | #ifdef CONFIG_IWLWIFI_DEBUG |
1075 | u32 inta_mask; | 1089 | u32 inta_mask; |
1076 | #endif | 1090 | #endif |
@@ -1181,12 +1195,8 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) | |||
1181 | if (inta & CSR_INT_BIT_WAKEUP) { | 1195 | if (inta & CSR_INT_BIT_WAKEUP) { |
1182 | IWL_DEBUG_ISR(priv, "Wakeup interrupt\n"); | 1196 | IWL_DEBUG_ISR(priv, "Wakeup interrupt\n"); |
1183 | iwl_rx_queue_update_write_ptr(priv, &priv->rxq); | 1197 | iwl_rx_queue_update_write_ptr(priv, &priv->rxq); |
1184 | iwl_txq_update_write_ptr(priv, &priv->txq[0]); | 1198 | for (i = 0; i < priv->hw_params.max_txq_num; i++) |
1185 | iwl_txq_update_write_ptr(priv, &priv->txq[1]); | 1199 | iwl_txq_update_write_ptr(priv, &priv->txq[i]); |
1186 | iwl_txq_update_write_ptr(priv, &priv->txq[2]); | ||
1187 | iwl_txq_update_write_ptr(priv, &priv->txq[3]); | ||
1188 | iwl_txq_update_write_ptr(priv, &priv->txq[4]); | ||
1189 | iwl_txq_update_write_ptr(priv, &priv->txq[5]); | ||
1190 | 1200 | ||
1191 | priv->isr_stats.wakeup++; | 1201 | priv->isr_stats.wakeup++; |
1192 | 1202 | ||
@@ -1653,6 +1663,7 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, | |||
1653 | u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ | 1663 | u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ |
1654 | u32 ptr; /* SRAM byte address of log data */ | 1664 | u32 ptr; /* SRAM byte address of log data */ |
1655 | u32 ev, time, data; /* event log data */ | 1665 | u32 ev, time, data; /* event log data */ |
1666 | unsigned long reg_flags; | ||
1656 | 1667 | ||
1657 | if (num_events == 0) | 1668 | if (num_events == 0) |
1658 | return; | 1669 | return; |
@@ -1668,27 +1679,39 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, | |||
1668 | 1679 | ||
1669 | ptr = base + EVENT_START_OFFSET + (start_idx * event_size); | 1680 | ptr = base + EVENT_START_OFFSET + (start_idx * event_size); |
1670 | 1681 | ||
1682 | /* Make sure device is powered up for SRAM reads */ | ||
1683 | spin_lock_irqsave(&priv->reg_lock, reg_flags); | ||
1684 | iwl_grab_nic_access(priv); | ||
1685 | |||
1686 | /* Set starting address; reads will auto-increment */ | ||
1687 | _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr); | ||
1688 | rmb(); | ||
1689 | |||
1671 | /* "time" is actually "data" for mode 0 (no timestamp). | 1690 | /* "time" is actually "data" for mode 0 (no timestamp). |
1672 | * place event id # at far right for easier visual parsing. */ | 1691 | * place event id # at far right for easier visual parsing. */ |
1673 | for (i = 0; i < num_events; i++) { | 1692 | for (i = 0; i < num_events; i++) { |
1674 | ev = iwl_read_targ_mem(priv, ptr); | 1693 | ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); |
1675 | ptr += sizeof(u32); | 1694 | time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); |
1676 | time = iwl_read_targ_mem(priv, ptr); | ||
1677 | ptr += sizeof(u32); | ||
1678 | if (mode == 0) { | 1695 | if (mode == 0) { |
1679 | /* data, ev */ | 1696 | /* data, ev */ |
1680 | trace_iwlwifi_dev_ucode_event(priv, 0, time, ev); | 1697 | trace_iwlwifi_dev_ucode_event(priv, 0, time, ev); |
1681 | IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev); | 1698 | IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev); |
1682 | } else { | 1699 | } else { |
1683 | data = iwl_read_targ_mem(priv, ptr); | 1700 | data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); |
1684 | ptr += sizeof(u32); | ||
1685 | IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n", | 1701 | IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n", |
1686 | time, data, ev); | 1702 | time, data, ev); |
1687 | trace_iwlwifi_dev_ucode_event(priv, time, data, ev); | 1703 | trace_iwlwifi_dev_ucode_event(priv, time, data, ev); |
1688 | } | 1704 | } |
1689 | } | 1705 | } |
1706 | |||
1707 | /* Allow device to power down */ | ||
1708 | iwl_release_nic_access(priv); | ||
1709 | spin_unlock_irqrestore(&priv->reg_lock, reg_flags); | ||
1690 | } | 1710 | } |
1691 | 1711 | ||
1712 | /* For sanity check only. Actual size is determined by uCode, typ. 512 */ | ||
1713 | #define MAX_EVENT_LOG_SIZE (512) | ||
1714 | |||
1692 | void iwl_dump_nic_event_log(struct iwl_priv *priv) | 1715 | void iwl_dump_nic_event_log(struct iwl_priv *priv) |
1693 | { | 1716 | { |
1694 | u32 base; /* SRAM byte address of event log header */ | 1717 | u32 base; /* SRAM byte address of event log header */ |
@@ -1714,6 +1737,18 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv) | |||
1714 | num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); | 1737 | num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); |
1715 | next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32))); | 1738 | next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32))); |
1716 | 1739 | ||
1740 | if (capacity > MAX_EVENT_LOG_SIZE) { | ||
1741 | IWL_ERR(priv, "Log capacity %d is bogus, limit to %d entries\n", | ||
1742 | capacity, MAX_EVENT_LOG_SIZE); | ||
1743 | capacity = MAX_EVENT_LOG_SIZE; | ||
1744 | } | ||
1745 | |||
1746 | if (next_entry > MAX_EVENT_LOG_SIZE) { | ||
1747 | IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n", | ||
1748 | next_entry, MAX_EVENT_LOG_SIZE); | ||
1749 | next_entry = MAX_EVENT_LOG_SIZE; | ||
1750 | } | ||
1751 | |||
1717 | size = num_wraps ? capacity : next_entry; | 1752 | size = num_wraps ? capacity : next_entry; |
1718 | 1753 | ||
1719 | /* bail out if nothing in log */ | 1754 | /* bail out if nothing in log */ |
@@ -1899,19 +1934,17 @@ static void __iwl_down(struct iwl_priv *priv) | |||
1899 | 1934 | ||
1900 | /* device going down, Stop using ICT table */ | 1935 | /* device going down, Stop using ICT table */ |
1901 | iwl_disable_ict(priv); | 1936 | iwl_disable_ict(priv); |
1902 | spin_lock_irqsave(&priv->lock, flags); | ||
1903 | iwl_clear_bit(priv, CSR_GP_CNTRL, | ||
1904 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | ||
1905 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1906 | 1937 | ||
1907 | iwl_txq_ctx_stop(priv); | 1938 | iwl_txq_ctx_stop(priv); |
1908 | iwl_rxq_stop(priv); | 1939 | iwl_rxq_stop(priv); |
1909 | 1940 | ||
1910 | iwl_write_prph(priv, APMG_CLK_DIS_REG, | 1941 | /* Power-down device's busmaster DMA clocks */ |
1911 | APMG_CLK_VAL_DMA_CLK_RQT); | 1942 | iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT); |
1912 | |||
1913 | udelay(5); | 1943 | udelay(5); |
1914 | 1944 | ||
1945 | /* Make sure (redundant) we've released our request to stay awake */ | ||
1946 | iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | ||
1947 | |||
1915 | /* Stop the device, and put it in low power state */ | 1948 | /* Stop the device, and put it in low power state */ |
1916 | priv->cfg->ops->lib->apm_ops.stop(priv); | 1949 | priv->cfg->ops->lib->apm_ops.stop(priv); |
1917 | 1950 | ||
@@ -3439,14 +3472,6 @@ static struct pci_device_id iwl_hw_card_ids[] = { | |||
3439 | {IWL_PCI_DEVICE(0x423D, PCI_ANY_ID, iwl5150_agn_cfg)}, | 3472 | {IWL_PCI_DEVICE(0x423D, PCI_ANY_ID, iwl5150_agn_cfg)}, |
3440 | 3473 | ||
3441 | /* 6x00 Series */ | 3474 | /* 6x00 Series */ |
3442 | {IWL_PCI_DEVICE(0x008D, 0x1301, iwl6000h_2agn_cfg)}, | ||
3443 | {IWL_PCI_DEVICE(0x008D, 0x1321, iwl6000h_2agn_cfg)}, | ||
3444 | {IWL_PCI_DEVICE(0x008D, 0x1326, iwl6000h_2abg_cfg)}, | ||
3445 | {IWL_PCI_DEVICE(0x008D, 0x1306, iwl6000h_2abg_cfg)}, | ||
3446 | {IWL_PCI_DEVICE(0x008D, 0x1307, iwl6000h_2bg_cfg)}, | ||
3447 | {IWL_PCI_DEVICE(0x008E, 0x1311, iwl6000h_2agn_cfg)}, | ||
3448 | {IWL_PCI_DEVICE(0x008E, 0x1316, iwl6000h_2abg_cfg)}, | ||
3449 | |||
3450 | {IWL_PCI_DEVICE(0x422B, 0x1101, iwl6000_3agn_cfg)}, | 3475 | {IWL_PCI_DEVICE(0x422B, 0x1101, iwl6000_3agn_cfg)}, |
3451 | {IWL_PCI_DEVICE(0x422B, 0x1121, iwl6000_3agn_cfg)}, | 3476 | {IWL_PCI_DEVICE(0x422B, 0x1121, iwl6000_3agn_cfg)}, |
3452 | {IWL_PCI_DEVICE(0x422C, 0x1301, iwl6000i_2agn_cfg)}, | 3477 | {IWL_PCI_DEVICE(0x422C, 0x1301, iwl6000i_2agn_cfg)}, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index b62c90ec9e1e..2857287be4fd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h | |||
@@ -2566,9 +2566,10 @@ struct iwl_scan_channel { | |||
2566 | /** | 2566 | /** |
2567 | * struct iwl_ssid_ie - directed scan network information element | 2567 | * struct iwl_ssid_ie - directed scan network information element |
2568 | * | 2568 | * |
2569 | * Up to 4 of these may appear in REPLY_SCAN_CMD, selected by "type" field | 2569 | * Up to 20 of these may appear in REPLY_SCAN_CMD (Note: Only 4 are in |
2570 | * in struct iwl_scan_channel; each channel may select different ssids from | 2570 | * 3945 SCAN api), selected by "type" bit field in struct iwl_scan_channel; |
2571 | * among the 4 entries. SSID IEs get transmitted in reverse order of entry. | 2571 | * each channel may select different ssids from among the 20 (4) entries. |
2572 | * SSID IEs get transmitted in reverse order of entry. | ||
2572 | */ | 2573 | */ |
2573 | struct iwl_ssid_ie { | 2574 | struct iwl_ssid_ie { |
2574 | u8 id; | 2575 | u8 id; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index e0b5b4aef41d..d09e74815323 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c | |||
@@ -1316,19 +1316,24 @@ void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) | |||
1316 | struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon; | 1316 | struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon; |
1317 | struct iwl_csa_notification *csa = &(pkt->u.csa_notif); | 1317 | struct iwl_csa_notification *csa = &(pkt->u.csa_notif); |
1318 | 1318 | ||
1319 | if (!le32_to_cpu(csa->status)) { | 1319 | if (priv->switch_rxon.switch_in_progress) { |
1320 | rxon->channel = csa->channel; | 1320 | if (!le32_to_cpu(csa->status) && |
1321 | priv->staging_rxon.channel = csa->channel; | 1321 | (csa->channel == priv->switch_rxon.channel)) { |
1322 | IWL_DEBUG_11H(priv, "CSA notif: channel %d\n", | 1322 | rxon->channel = csa->channel; |
1323 | le16_to_cpu(csa->channel)); | 1323 | priv->staging_rxon.channel = csa->channel; |
1324 | } else | 1324 | IWL_DEBUG_11H(priv, "CSA notif: channel %d\n", |
1325 | IWL_ERR(priv, "CSA notif (fail) : channel %d\n", | 1325 | le16_to_cpu(csa->channel)); |
1326 | le16_to_cpu(csa->channel)); | 1326 | } else |
1327 | IWL_ERR(priv, "CSA notif (fail) : channel %d\n", | ||
1328 | le16_to_cpu(csa->channel)); | ||
1329 | |||
1330 | priv->switch_rxon.switch_in_progress = false; | ||
1331 | } | ||
1327 | } | 1332 | } |
1328 | EXPORT_SYMBOL(iwl_rx_csa); | 1333 | EXPORT_SYMBOL(iwl_rx_csa); |
1329 | 1334 | ||
1330 | #ifdef CONFIG_IWLWIFI_DEBUG | 1335 | #ifdef CONFIG_IWLWIFI_DEBUG |
1331 | static void iwl_print_rx_config_cmd(struct iwl_priv *priv) | 1336 | void iwl_print_rx_config_cmd(struct iwl_priv *priv) |
1332 | { | 1337 | { |
1333 | struct iwl_rxon_cmd *rxon = &priv->staging_rxon; | 1338 | struct iwl_rxon_cmd *rxon = &priv->staging_rxon; |
1334 | 1339 | ||
@@ -1346,6 +1351,7 @@ static void iwl_print_rx_config_cmd(struct iwl_priv *priv) | |||
1346 | IWL_DEBUG_RADIO(priv, "u8[6] bssid_addr: %pM\n", rxon->bssid_addr); | 1351 | IWL_DEBUG_RADIO(priv, "u8[6] bssid_addr: %pM\n", rxon->bssid_addr); |
1347 | IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); | 1352 | IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); |
1348 | } | 1353 | } |
1354 | EXPORT_SYMBOL(iwl_print_rx_config_cmd); | ||
1349 | #endif | 1355 | #endif |
1350 | /** | 1356 | /** |
1351 | * iwl_irq_handle_error - called for HW or SW error interrupt from card | 1357 | * iwl_irq_handle_error - called for HW or SW error interrupt from card |
@@ -2310,12 +2316,6 @@ static void iwl_ht_conf(struct iwl_priv *priv, | |||
2310 | >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; | 2316 | >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; |
2311 | maxstreams += 1; | 2317 | maxstreams += 1; |
2312 | 2318 | ||
2313 | ht_conf->sm_ps = | ||
2314 | (u8)((ht_cap->cap & IEEE80211_HT_CAP_SM_PS) | ||
2315 | >> 2); | ||
2316 | IWL_DEBUG_MAC80211(priv, "sm_ps: 0x%x\n", | ||
2317 | ht_conf->sm_ps); | ||
2318 | |||
2319 | if ((ht_cap->mcs.rx_mask[1] == 0) && | 2319 | if ((ht_cap->mcs.rx_mask[1] == 0) && |
2320 | (ht_cap->mcs.rx_mask[2] == 0)) | 2320 | (ht_cap->mcs.rx_mask[2] == 0)) |
2321 | ht_conf->single_chain_sufficient = true; | 2321 | ht_conf->single_chain_sufficient = true; |
@@ -2689,14 +2689,6 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) | |||
2689 | goto set_ch_out; | 2689 | goto set_ch_out; |
2690 | } | 2690 | } |
2691 | 2691 | ||
2692 | if (iwl_is_associated(priv) && | ||
2693 | (le16_to_cpu(priv->active_rxon.channel) != ch) && | ||
2694 | priv->cfg->ops->lib->set_channel_switch) { | ||
2695 | ret = priv->cfg->ops->lib->set_channel_switch(priv, | ||
2696 | ch); | ||
2697 | goto out; | ||
2698 | } | ||
2699 | |||
2700 | spin_lock_irqsave(&priv->lock, flags); | 2692 | spin_lock_irqsave(&priv->lock, flags); |
2701 | 2693 | ||
2702 | /* Configure HT40 channels */ | 2694 | /* Configure HT40 channels */ |
@@ -2731,6 +2723,22 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) | |||
2731 | 2723 | ||
2732 | iwl_set_flags_for_band(priv, conf->channel->band); | 2724 | iwl_set_flags_for_band(priv, conf->channel->band); |
2733 | spin_unlock_irqrestore(&priv->lock, flags); | 2725 | spin_unlock_irqrestore(&priv->lock, flags); |
2726 | if (iwl_is_associated(priv) && | ||
2727 | (le16_to_cpu(priv->active_rxon.channel) != ch) && | ||
2728 | priv->cfg->ops->lib->set_channel_switch) { | ||
2729 | iwl_set_rate(priv); | ||
2730 | /* | ||
2731 | * at this point, staging_rxon has the | ||
2732 | * configuration for channel switch | ||
2733 | */ | ||
2734 | ret = priv->cfg->ops->lib->set_channel_switch(priv, | ||
2735 | ch); | ||
2736 | if (!ret) { | ||
2737 | iwl_print_rx_config_cmd(priv); | ||
2738 | goto out; | ||
2739 | } | ||
2740 | priv->switch_rxon.switch_in_progress = false; | ||
2741 | } | ||
2734 | set_ch_out: | 2742 | set_ch_out: |
2735 | /* The list of supported rates and rate mask can be different | 2743 | /* The list of supported rates and rate mask can be different |
2736 | * for each band; since the band may have changed, reset | 2744 | * for each band; since the band may have changed, reset |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 9574d8f33537..3f97036ac29b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h | |||
@@ -579,6 +579,7 @@ int iwl_pci_resume(struct pci_dev *pdev); | |||
579 | #ifdef CONFIG_IWLWIFI_DEBUG | 579 | #ifdef CONFIG_IWLWIFI_DEBUG |
580 | void iwl_dump_nic_event_log(struct iwl_priv *priv); | 580 | void iwl_dump_nic_event_log(struct iwl_priv *priv); |
581 | void iwl_dump_nic_error_log(struct iwl_priv *priv); | 581 | void iwl_dump_nic_error_log(struct iwl_priv *priv); |
582 | void iwl_print_rx_config_cmd(struct iwl_priv *priv); | ||
582 | #else | 583 | #else |
583 | static inline void iwl_dump_nic_event_log(struct iwl_priv *priv) | 584 | static inline void iwl_dump_nic_event_log(struct iwl_priv *priv) |
584 | { | 585 | { |
@@ -587,6 +588,10 @@ static inline void iwl_dump_nic_event_log(struct iwl_priv *priv) | |||
587 | static inline void iwl_dump_nic_error_log(struct iwl_priv *priv) | 588 | static inline void iwl_dump_nic_error_log(struct iwl_priv *priv) |
588 | { | 589 | { |
589 | } | 590 | } |
591 | |||
592 | static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv) | ||
593 | { | ||
594 | } | ||
590 | #endif | 595 | #endif |
591 | 596 | ||
592 | void iwl_clear_isr_stats(struct iwl_priv *priv); | 597 | void iwl_clear_isr_stats(struct iwl_priv *priv); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index cb2642c18da4..9dea8fa08c0e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h | |||
@@ -324,8 +324,9 @@ struct iwl_channel_info { | |||
324 | #define IWL_MIN_NUM_QUEUES 10 | 324 | #define IWL_MIN_NUM_QUEUES 10 |
325 | 325 | ||
326 | /* | 326 | /* |
327 | * uCode queue management definitions ... | 327 | * Queue #4 is the command queue for 3945/4965/5x00/1000/6x00, |
328 | * Queue #4 is the command queue for 3945/4965/5x00/1000/6x00. | 328 | * the driver maps it into the appropriate device FIFO for the |
329 | * uCode. | ||
329 | */ | 330 | */ |
330 | #define IWL_CMD_QUEUE_NUM 4 | 331 | #define IWL_CMD_QUEUE_NUM 4 |
331 | 332 | ||
@@ -926,13 +927,11 @@ enum iwl_access_mode { | |||
926 | /** | 927 | /** |
927 | * enum iwl_pa_type - Power Amplifier type | 928 | * enum iwl_pa_type - Power Amplifier type |
928 | * @IWL_PA_SYSTEM: based on uCode configuration | 929 | * @IWL_PA_SYSTEM: based on uCode configuration |
929 | * @IWL_PA_HYBRID: use both Internal and external PA | ||
930 | * @IWL_PA_INTERNAL: use Internal only | 930 | * @IWL_PA_INTERNAL: use Internal only |
931 | */ | 931 | */ |
932 | enum iwl_pa_type { | 932 | enum iwl_pa_type { |
933 | IWL_PA_SYSTEM = 0, | 933 | IWL_PA_SYSTEM = 0, |
934 | IWL_PA_HYBRID = 1, | 934 | IWL_PA_INTERNAL = 1, |
935 | IWL_PA_INTERNAL = 2, | ||
936 | }; | 935 | }; |
937 | 936 | ||
938 | /* interrupt statistics */ | 937 | /* interrupt statistics */ |
@@ -993,6 +992,17 @@ struct traffic_stats { | |||
993 | }; | 992 | }; |
994 | #endif | 993 | #endif |
995 | 994 | ||
995 | /* | ||
996 | * iwl_switch_rxon: "channel switch" structure | ||
997 | * | ||
998 | * @ switch_in_progress: channel switch in progress | ||
999 | * @ channel: new channel | ||
1000 | */ | ||
1001 | struct iwl_switch_rxon { | ||
1002 | bool switch_in_progress; | ||
1003 | __le16 channel; | ||
1004 | }; | ||
1005 | |||
996 | struct iwl_priv { | 1006 | struct iwl_priv { |
997 | 1007 | ||
998 | /* ieee device used by generic ieee processing code */ | 1008 | /* ieee device used by generic ieee processing code */ |
@@ -1086,7 +1096,7 @@ struct iwl_priv { | |||
1086 | const struct iwl_rxon_cmd active_rxon; | 1096 | const struct iwl_rxon_cmd active_rxon; |
1087 | struct iwl_rxon_cmd staging_rxon; | 1097 | struct iwl_rxon_cmd staging_rxon; |
1088 | 1098 | ||
1089 | struct iwl_rxon_cmd recovery_rxon; | 1099 | struct iwl_switch_rxon switch_rxon; |
1090 | 1100 | ||
1091 | /* 1st responses from initialize and runtime uCode images. | 1101 | /* 1st responses from initialize and runtime uCode images. |
1092 | * 4965's initialize alive response contains some calibration data. */ | 1102 | * 4965's initialize alive response contains some calibration data. */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 905645d15a9b..e8002c1d3eba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c | |||
@@ -199,13 +199,13 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) | |||
199 | } | 199 | } |
200 | 200 | ||
201 | if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { | 201 | if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { |
202 | IWL_DEBUG_INFO(priv, "Command %s aborted: RF KILL Switch\n", | 202 | IWL_ERR(priv, "Command %s aborted: RF KILL Switch\n", |
203 | get_cmd_string(cmd->id)); | 203 | get_cmd_string(cmd->id)); |
204 | ret = -ECANCELED; | 204 | ret = -ECANCELED; |
205 | goto fail; | 205 | goto fail; |
206 | } | 206 | } |
207 | if (test_bit(STATUS_FW_ERROR, &priv->status)) { | 207 | if (test_bit(STATUS_FW_ERROR, &priv->status)) { |
208 | IWL_DEBUG_INFO(priv, "Command %s failed: FW Error\n", | 208 | IWL_ERR(priv, "Command %s failed: FW Error\n", |
209 | get_cmd_string(cmd->id)); | 209 | get_cmd_string(cmd->id)); |
210 | ret = -EIO; | 210 | ret = -EIO; |
211 | goto fail; | 211 | goto fail; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index 0a078b082833..d0a358c9d96b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h | |||
@@ -200,6 +200,26 @@ static inline int _iwl_grab_nic_access(struct iwl_priv *priv) | |||
200 | 200 | ||
201 | /* this bit wakes up the NIC */ | 201 | /* this bit wakes up the NIC */ |
202 | _iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | 202 | _iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); |
203 | |||
204 | /* | ||
205 | * These bits say the device is running, and should keep running for | ||
206 | * at least a short while (at least as long as MAC_ACCESS_REQ stays 1), | ||
207 | * but they do not indicate that embedded SRAM is restored yet; | ||
208 | * 3945 and 4965 have volatile SRAM, and must save/restore contents | ||
209 | * to/from host DRAM when sleeping/waking for power-saving. | ||
210 | * Each direction takes approximately 1/4 millisecond; with this | ||
211 | * overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a | ||
212 | * series of register accesses are expected (e.g. reading Event Log), | ||
213 | * to keep device from sleeping. | ||
214 | * | ||
215 | * CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that | ||
216 | * SRAM is okay/restored. We don't check that here because this call | ||
217 | * is just for hardware register access; but GP1 MAC_SLEEP check is a | ||
218 | * good idea before accessing 3945/4965 SRAM (e.g. reading Event Log). | ||
219 | * | ||
220 | * 5000 series and later (including 1000 series) have non-volatile SRAM, | ||
221 | * and do not save/restore SRAM when power cycling. | ||
222 | */ | ||
203 | ret = _iwl_poll_bit(priv, CSR_GP_CNTRL, | 223 | ret = _iwl_poll_bit(priv, CSR_GP_CNTRL, |
204 | CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, | 224 | CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, |
205 | (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | | 225 | (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | |
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index d393e8f02102..6d95832db06d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h | |||
@@ -254,7 +254,8 @@ | |||
254 | * device. A queue maps to only one (selectable by driver) Tx DMA channel, | 254 | * device. A queue maps to only one (selectable by driver) Tx DMA channel, |
255 | * but one DMA channel may take input from several queues. | 255 | * but one DMA channel may take input from several queues. |
256 | * | 256 | * |
257 | * Tx DMA channels have dedicated purposes. For 4965, they are used as follows: | 257 | * Tx DMA channels have dedicated purposes. For 4965, they are used as follows |
258 | * (cf. default_queue_to_tx_fifo in iwl-4965.c): | ||
258 | * | 259 | * |
259 | * 0 -- EDCA BK (background) frames, lowest priority | 260 | * 0 -- EDCA BK (background) frames, lowest priority |
260 | * 1 -- EDCA BE (best effort) frames, normal priority | 261 | * 1 -- EDCA BE (best effort) frames, normal priority |
@@ -265,9 +266,21 @@ | |||
265 | * 6 -- HCCA long frames | 266 | * 6 -- HCCA long frames |
266 | * 7 -- not used by driver (device-internal only) | 267 | * 7 -- not used by driver (device-internal only) |
267 | * | 268 | * |
269 | * For 5000 series and up, they are used slightly differently | ||
270 | * (cf. iwl5000_default_queue_to_tx_fifo in iwl-5000.c): | ||
271 | * | ||
272 | * 0 -- EDCA BK (background) frames, lowest priority | ||
273 | * 1 -- EDCA BE (best effort) frames, normal priority | ||
274 | * 2 -- EDCA VI (video) frames, higher priority | ||
275 | * 3 -- EDCA VO (voice) and management frames, highest priority | ||
276 | * 4 -- (TBD) | ||
277 | * 5 -- HCCA short frames | ||
278 | * 6 -- HCCA long frames | ||
279 | * 7 -- Commands | ||
280 | * | ||
268 | * Driver should normally map queues 0-6 to Tx DMA/FIFO channels 0-6. | 281 | * Driver should normally map queues 0-6 to Tx DMA/FIFO channels 0-6. |
269 | * In addition, driver can map queues 7-15 to Tx DMA/FIFO channels 0-3 to | 282 | * In addition, driver can map the remaining queues to Tx DMA/FIFO |
270 | * support 11n aggregation via EDCA DMA channels. | 283 | * channels 0-3 to support 11n aggregation via EDCA DMA channels. |
271 | * | 284 | * |
272 | * The driver sets up each queue to work in one of two modes: | 285 | * The driver sets up each queue to work in one of two modes: |
273 | * | 286 | * |
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index e5339c9ad13e..61b3b0e6ed73 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c | |||
@@ -140,6 +140,8 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q) | |||
140 | reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); | 140 | reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); |
141 | 141 | ||
142 | if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { | 142 | if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { |
143 | IWL_DEBUG_INFO(priv, "Rx queue requesting wakeup, GP1 = 0x%x\n", | ||
144 | reg); | ||
143 | iwl_set_bit(priv, CSR_GP_CNTRL, | 145 | iwl_set_bit(priv, CSR_GP_CNTRL, |
144 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | 146 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); |
145 | goto exit_unlock; | 147 | goto exit_unlock; |
@@ -937,12 +939,13 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, | |||
937 | iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) | 939 | iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) |
938 | return; | 940 | return; |
939 | 941 | ||
940 | skb = alloc_skb(IWL_LINK_HDR_MAX, GFP_ATOMIC); | 942 | skb = alloc_skb(IWL_LINK_HDR_MAX * 2, GFP_ATOMIC); |
941 | if (!skb) { | 943 | if (!skb) { |
942 | IWL_ERR(priv, "alloc_skb failed\n"); | 944 | IWL_ERR(priv, "alloc_skb failed\n"); |
943 | return; | 945 | return; |
944 | } | 946 | } |
945 | 947 | ||
948 | skb_reserve(skb, IWL_LINK_HDR_MAX); | ||
946 | skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len); | 949 | skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len); |
947 | 950 | ||
948 | /* mac80211 currently doesn't support paged SKB. Convert it to | 951 | /* mac80211 currently doesn't support paged SKB. Convert it to |
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 1eb0d0bf1fe4..a2b2b8315ff9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c | |||
@@ -581,6 +581,7 @@ static void iwl_bg_request_scan(struct work_struct *data) | |||
581 | u8 rate; | 581 | u8 rate; |
582 | bool is_active = false; | 582 | bool is_active = false; |
583 | int chan_mod; | 583 | int chan_mod; |
584 | u8 active_chains; | ||
584 | 585 | ||
585 | conf = ieee80211_get_hw_conf(priv->hw); | 586 | conf = ieee80211_get_hw_conf(priv->hw); |
586 | 587 | ||
@@ -734,9 +735,22 @@ static void iwl_bg_request_scan(struct work_struct *data) | |||
734 | rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]); | 735 | rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]); |
735 | scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags); | 736 | scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags); |
736 | 737 | ||
738 | /* In power save mode use one chain, otherwise use all chains */ | ||
739 | if (test_bit(STATUS_POWER_PMI, &priv->status)) { | ||
740 | /* rx_ant has been set to all valid chains previously */ | ||
741 | active_chains = rx_ant & | ||
742 | ((u8)(priv->chain_noise_data.active_chains)); | ||
743 | if (!active_chains) | ||
744 | active_chains = rx_ant; | ||
745 | |||
746 | IWL_DEBUG_SCAN(priv, "chain_noise_data.active_chains: %u\n", | ||
747 | priv->chain_noise_data.active_chains); | ||
748 | |||
749 | rx_ant = first_antenna(active_chains); | ||
750 | } | ||
737 | /* MIMO is not used here, but value is required */ | 751 | /* MIMO is not used here, but value is required */ |
738 | rx_chain |= ANT_ABC << RXON_RX_CHAIN_VALID_POS; | 752 | rx_chain |= priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS; |
739 | rx_chain |= ANT_ABC << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS; | 753 | rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS; |
740 | rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS; | 754 | rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS; |
741 | rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS; | 755 | rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS; |
742 | scan->rx_chain = cpu_to_le16(rx_chain); | 756 | scan->rx_chain = cpu_to_le16(rx_chain); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 05e75109d842..9370e062000d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c | |||
@@ -96,7 +96,8 @@ int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq) | |||
96 | reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); | 96 | reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); |
97 | 97 | ||
98 | if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { | 98 | if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { |
99 | IWL_DEBUG_INFO(priv, "Requesting wakeup, GP1 = 0x%x\n", reg); | 99 | IWL_DEBUG_INFO(priv, "Tx queue %d requesting wakeup, GP1 = 0x%x\n", |
100 | txq_id, reg); | ||
100 | iwl_set_bit(priv, CSR_GP_CNTRL, | 101 | iwl_set_bit(priv, CSR_GP_CNTRL, |
101 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | 102 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); |
102 | return ret; | 103 | return ret; |
@@ -364,8 +365,13 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq, | |||
364 | 365 | ||
365 | txq->need_update = 0; | 366 | txq->need_update = 0; |
366 | 367 | ||
367 | /* aggregation TX queues will get their ID when aggregation begins */ | 368 | /* |
368 | if (txq_id <= IWL_TX_FIFO_AC3) | 369 | * Aggregation TX queues will get their ID when aggregation begins; |
370 | * they overwrite the setting done here. The command FIFO doesn't | ||
371 | * need an swq_id so don't set one to catch errors, all others can | ||
372 | * be set up to the identity mapping. | ||
373 | */ | ||
374 | if (txq_id != IWL_CMD_QUEUE_NUM) | ||
369 | txq->swq_id = txq_id; | 375 | txq->swq_id = txq_id; |
370 | 376 | ||
371 | /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise | 377 | /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise |
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 23b31e6dcacd..05f118529fea 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c | |||
@@ -1570,6 +1570,7 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx, | |||
1570 | u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ | 1570 | u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ |
1571 | u32 ptr; /* SRAM byte address of log data */ | 1571 | u32 ptr; /* SRAM byte address of log data */ |
1572 | u32 ev, time, data; /* event log data */ | 1572 | u32 ev, time, data; /* event log data */ |
1573 | unsigned long reg_flags; | ||
1573 | 1574 | ||
1574 | if (num_events == 0) | 1575 | if (num_events == 0) |
1575 | return; | 1576 | return; |
@@ -1583,26 +1584,38 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx, | |||
1583 | 1584 | ||
1584 | ptr = base + EVENT_START_OFFSET + (start_idx * event_size); | 1585 | ptr = base + EVENT_START_OFFSET + (start_idx * event_size); |
1585 | 1586 | ||
1587 | /* Make sure device is powered up for SRAM reads */ | ||
1588 | spin_lock_irqsave(&priv->reg_lock, reg_flags); | ||
1589 | iwl_grab_nic_access(priv); | ||
1590 | |||
1591 | /* Set starting address; reads will auto-increment */ | ||
1592 | _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr); | ||
1593 | rmb(); | ||
1594 | |||
1586 | /* "time" is actually "data" for mode 0 (no timestamp). | 1595 | /* "time" is actually "data" for mode 0 (no timestamp). |
1587 | * place event id # at far right for easier visual parsing. */ | 1596 | * place event id # at far right for easier visual parsing. */ |
1588 | for (i = 0; i < num_events; i++) { | 1597 | for (i = 0; i < num_events; i++) { |
1589 | ev = iwl_read_targ_mem(priv, ptr); | 1598 | ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); |
1590 | ptr += sizeof(u32); | 1599 | time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); |
1591 | time = iwl_read_targ_mem(priv, ptr); | ||
1592 | ptr += sizeof(u32); | ||
1593 | if (mode == 0) { | 1600 | if (mode == 0) { |
1594 | /* data, ev */ | 1601 | /* data, ev */ |
1595 | IWL_ERR(priv, "0x%08x\t%04u\n", time, ev); | 1602 | IWL_ERR(priv, "0x%08x\t%04u\n", time, ev); |
1596 | trace_iwlwifi_dev_ucode_event(priv, 0, time, ev); | 1603 | trace_iwlwifi_dev_ucode_event(priv, 0, time, ev); |
1597 | } else { | 1604 | } else { |
1598 | data = iwl_read_targ_mem(priv, ptr); | 1605 | data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); |
1599 | ptr += sizeof(u32); | ||
1600 | IWL_ERR(priv, "%010u\t0x%08x\t%04u\n", time, data, ev); | 1606 | IWL_ERR(priv, "%010u\t0x%08x\t%04u\n", time, data, ev); |
1601 | trace_iwlwifi_dev_ucode_event(priv, time, data, ev); | 1607 | trace_iwlwifi_dev_ucode_event(priv, time, data, ev); |
1602 | } | 1608 | } |
1603 | } | 1609 | } |
1610 | |||
1611 | /* Allow device to power down */ | ||
1612 | iwl_release_nic_access(priv); | ||
1613 | spin_unlock_irqrestore(&priv->reg_lock, reg_flags); | ||
1604 | } | 1614 | } |
1605 | 1615 | ||
1616 | /* For sanity check only. Actual size is determined by uCode, typ. 512 */ | ||
1617 | #define IWL3945_MAX_EVENT_LOG_SIZE (512) | ||
1618 | |||
1606 | void iwl3945_dump_nic_event_log(struct iwl_priv *priv) | 1619 | void iwl3945_dump_nic_event_log(struct iwl_priv *priv) |
1607 | { | 1620 | { |
1608 | u32 base; /* SRAM byte address of event log header */ | 1621 | u32 base; /* SRAM byte address of event log header */ |
@@ -1624,6 +1637,18 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv) | |||
1624 | num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); | 1637 | num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); |
1625 | next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32))); | 1638 | next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32))); |
1626 | 1639 | ||
1640 | if (capacity > IWL3945_MAX_EVENT_LOG_SIZE) { | ||
1641 | IWL_ERR(priv, "Log capacity %d is bogus, limit to %d entries\n", | ||
1642 | capacity, IWL3945_MAX_EVENT_LOG_SIZE); | ||
1643 | capacity = IWL3945_MAX_EVENT_LOG_SIZE; | ||
1644 | } | ||
1645 | |||
1646 | if (next_entry > IWL3945_MAX_EVENT_LOG_SIZE) { | ||
1647 | IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n", | ||
1648 | next_entry, IWL3945_MAX_EVENT_LOG_SIZE); | ||
1649 | next_entry = IWL3945_MAX_EVENT_LOG_SIZE; | ||
1650 | } | ||
1651 | |||
1627 | size = num_wraps ? capacity : next_entry; | 1652 | size = num_wraps ? capacity : next_entry; |
1628 | 1653 | ||
1629 | /* bail out if nothing in log */ | 1654 | /* bail out if nothing in log */ |
@@ -2575,9 +2600,8 @@ static void __iwl3945_down(struct iwl_priv *priv) | |||
2575 | iwl3945_hw_txq_ctx_stop(priv); | 2600 | iwl3945_hw_txq_ctx_stop(priv); |
2576 | iwl3945_hw_rxq_stop(priv); | 2601 | iwl3945_hw_rxq_stop(priv); |
2577 | 2602 | ||
2578 | iwl_write_prph(priv, APMG_CLK_DIS_REG, | 2603 | /* Power-down device's busmaster DMA clocks */ |
2579 | APMG_CLK_VAL_DMA_CLK_RQT); | 2604 | iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT); |
2580 | |||
2581 | udelay(5); | 2605 | udelay(5); |
2582 | 2606 | ||
2583 | /* Stop the device, and put it in low power state */ | 2607 | /* Stop the device, and put it in low power state */ |
diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c index cf86294f719b..a7ec7eac9137 100644 --- a/drivers/net/wireless/iwmc3200wifi/sdio.c +++ b/drivers/net/wireless/iwmc3200wifi/sdio.c | |||
@@ -399,6 +399,9 @@ static struct iwm_if_ops if_sdio_ops = { | |||
399 | .calib_lmac_name = "iwmc3200wifi-calib-sdio.bin", | 399 | .calib_lmac_name = "iwmc3200wifi-calib-sdio.bin", |
400 | .lmac_name = "iwmc3200wifi-lmac-sdio.bin", | 400 | .lmac_name = "iwmc3200wifi-lmac-sdio.bin", |
401 | }; | 401 | }; |
402 | MODULE_FIRMWARE("iwmc3200wifi-umac-sdio.bin"); | ||
403 | MODULE_FIRMWARE("iwmc3200wifi-calib-sdio.bin"); | ||
404 | MODULE_FIRMWARE("iwmc3200wifi-lmac-sdio.bin"); | ||
402 | 405 | ||
403 | static int iwm_sdio_probe(struct sdio_func *func, | 406 | static int iwm_sdio_probe(struct sdio_func *func, |
404 | const struct sdio_device_id *id) | 407 | const struct sdio_device_id *id) |
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 465742f19ecb..875516db319c 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c | |||
@@ -48,6 +48,7 @@ | |||
48 | MODULE_AUTHOR("Holger Schurig <hs4233@mail.mn-solutions.de>"); | 48 | MODULE_AUTHOR("Holger Schurig <hs4233@mail.mn-solutions.de>"); |
49 | MODULE_DESCRIPTION("Driver for Marvell 83xx compact flash WLAN cards"); | 49 | MODULE_DESCRIPTION("Driver for Marvell 83xx compact flash WLAN cards"); |
50 | MODULE_LICENSE("GPL"); | 50 | MODULE_LICENSE("GPL"); |
51 | MODULE_FIRMWARE("libertas_cs_helper.fw"); | ||
51 | 52 | ||
52 | 53 | ||
53 | 54 | ||
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 9716728a33cb..09fcfad742e7 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c | |||
@@ -99,6 +99,12 @@ static struct if_sdio_model if_sdio_models[] = { | |||
99 | .firmware = "sd8688.bin", | 99 | .firmware = "sd8688.bin", |
100 | }, | 100 | }, |
101 | }; | 101 | }; |
102 | MODULE_FIRMWARE("sd8385_helper.bin"); | ||
103 | MODULE_FIRMWARE("sd8385.bin"); | ||
104 | MODULE_FIRMWARE("sd8686_helper.bin"); | ||
105 | MODULE_FIRMWARE("sd8686.bin"); | ||
106 | MODULE_FIRMWARE("sd8688_helper.bin"); | ||
107 | MODULE_FIRMWARE("sd8688.bin"); | ||
102 | 108 | ||
103 | struct if_sdio_packet { | 109 | struct if_sdio_packet { |
104 | struct if_sdio_packet *next; | 110 | struct if_sdio_packet *next; |
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index d6a48dd3652c..bf4bfbae6227 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c | |||
@@ -902,6 +902,10 @@ static int if_spi_calculate_fw_names(u16 card_id, | |||
902 | chip_id_to_device_name[i].name); | 902 | chip_id_to_device_name[i].name); |
903 | return 0; | 903 | return 0; |
904 | } | 904 | } |
905 | MODULE_FIRMWARE("libertas/gspi8385_hlp.bin"); | ||
906 | MODULE_FIRMWARE("libertas/gspi8385.bin"); | ||
907 | MODULE_FIRMWARE("libertas/gspi8686_hlp.bin"); | ||
908 | MODULE_FIRMWARE("libertas/gspi8686.bin"); | ||
905 | 909 | ||
906 | static int __devinit if_spi_probe(struct spi_device *spi) | 910 | static int __devinit if_spi_probe(struct spi_device *spi) |
907 | { | 911 | { |
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index f12d667ba100..65e174595d12 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c | |||
@@ -28,6 +28,8 @@ | |||
28 | static char *lbs_fw_name = "usb8388.bin"; | 28 | static char *lbs_fw_name = "usb8388.bin"; |
29 | module_param_named(fw_name, lbs_fw_name, charp, 0644); | 29 | module_param_named(fw_name, lbs_fw_name, charp, 0644); |
30 | 30 | ||
31 | MODULE_FIRMWARE("usb8388.bin"); | ||
32 | |||
31 | static struct usb_device_id if_usb_table[] = { | 33 | static struct usb_device_id if_usb_table[] = { |
32 | /* Enter the device signature inside */ | 34 | /* Enter the device signature inside */ |
33 | { USB_DEVICE(0x1286, 0x2001) }, | 35 | { USB_DEVICE(0x1286, 0x2001) }, |
diff --git a/drivers/net/wireless/libertas_tf/if_usb.c b/drivers/net/wireless/libertas_tf/if_usb.c index 392337b37b1d..3691c307e674 100644 --- a/drivers/net/wireless/libertas_tf/if_usb.c +++ b/drivers/net/wireless/libertas_tf/if_usb.c | |||
@@ -23,6 +23,8 @@ | |||
23 | static char *lbtf_fw_name = "lbtf_usb.bin"; | 23 | static char *lbtf_fw_name = "lbtf_usb.bin"; |
24 | module_param_named(fw_name, lbtf_fw_name, charp, 0644); | 24 | module_param_named(fw_name, lbtf_fw_name, charp, 0644); |
25 | 25 | ||
26 | MODULE_FIRMWARE("lbtf_usb.bin"); | ||
27 | |||
26 | static struct usb_device_id if_usb_table[] = { | 28 | static struct usb_device_id if_usb_table[] = { |
27 | /* Enter the device signature inside */ | 29 | /* Enter the device signature inside */ |
28 | { USB_DEVICE(0x1286, 0x2001) }, | 30 | { USB_DEVICE(0x1286, 0x2001) }, |
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 2ebfee4da3fa..9e64dd43a3be 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c | |||
@@ -400,6 +400,9 @@ static int mwl8k_request_firmware(struct mwl8k_priv *priv) | |||
400 | return 0; | 400 | return 0; |
401 | } | 401 | } |
402 | 402 | ||
403 | MODULE_FIRMWARE("mwl8k/helper_8687.fw"); | ||
404 | MODULE_FIRMWARE("mwl8k/fmimage_8687.fw"); | ||
405 | |||
403 | struct mwl8k_cmd_pkt { | 406 | struct mwl8k_cmd_pkt { |
404 | __le16 code; | 407 | __le16 code; |
405 | __le16 length; | 408 | __le16 length; |
diff --git a/drivers/net/wireless/orinoco/fw.c b/drivers/net/wireless/orinoco/fw.c index 1257250a1e22..cfa72962052b 100644 --- a/drivers/net/wireless/orinoco/fw.c +++ b/drivers/net/wireless/orinoco/fw.c | |||
@@ -28,6 +28,12 @@ static const struct fw_info orinoco_fw[] = { | |||
28 | { NULL, "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 }, | 28 | { NULL, "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 }, |
29 | { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", NULL, 0x00003100, 512 } | 29 | { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", NULL, 0x00003100, 512 } |
30 | }; | 30 | }; |
31 | MODULE_FIRMWARE("agere_sta_fw.bin"); | ||
32 | MODULE_FIRMWARE("agere_ap_fw.bin"); | ||
33 | MODULE_FIRMWARE("prism_sta_fw.bin"); | ||
34 | MODULE_FIRMWARE("prism_ap_fw.bin"); | ||
35 | MODULE_FIRMWARE("symbol_sp24t_prim_fw"); | ||
36 | MODULE_FIRMWARE("symbol_sp24t_sec_fw"); | ||
31 | 37 | ||
32 | /* Structure used to access fields in FW | 38 | /* Structure used to access fields in FW |
33 | * Make sure LE decoding macros are used | 39 | * Make sure LE decoding macros are used |
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c index e26d7b3ceab5..3e6a71ce5b54 100644 --- a/drivers/net/wireless/prism54/islpci_dev.c +++ b/drivers/net/wireless/prism54/islpci_dev.c | |||
@@ -40,6 +40,9 @@ | |||
40 | #define ISL3877_IMAGE_FILE "isl3877" | 40 | #define ISL3877_IMAGE_FILE "isl3877" |
41 | #define ISL3886_IMAGE_FILE "isl3886" | 41 | #define ISL3886_IMAGE_FILE "isl3886" |
42 | #define ISL3890_IMAGE_FILE "isl3890" | 42 | #define ISL3890_IMAGE_FILE "isl3890" |
43 | MODULE_FIRMWARE(ISL3877_IMAGE_FILE); | ||
44 | MODULE_FIRMWARE(ISL3886_IMAGE_FILE); | ||
45 | MODULE_FIRMWARE(ISL3890_IMAGE_FILE); | ||
43 | 46 | ||
44 | static int prism54_bring_down(islpci_private *); | 47 | static int prism54_bring_down(islpci_private *); |
45 | static int islpci_alloc_memory(islpci_private *); | 48 | static int islpci_alloc_memory(islpci_private *); |
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 88cd58eb3b9f..595e4414d770 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c | |||
@@ -2074,7 +2074,7 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id) | |||
2074 | del_timer(&local->timer); | 2074 | del_timer(&local->timer); |
2075 | local->timer.expires = jiffies + HZ * 5; | 2075 | local->timer.expires = jiffies + HZ * 5; |
2076 | local->timer.data = (long)local; | 2076 | local->timer.data = (long)local; |
2077 | if (status == CCS_START_NETWORK) { | 2077 | if (cmd == CCS_START_NETWORK) { |
2078 | DEBUG(0, | 2078 | DEBUG(0, |
2079 | "ray_cs interrupt network \"%s\" start failed\n", | 2079 | "ray_cs interrupt network \"%s\" start failed\n", |
2080 | local->sparm.b4.a_current_ess_id); | 2080 | local->sparm.b4.a_current_ess_id); |
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 54175b6fa86c..aa1880add186 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c | |||
@@ -1072,6 +1072,8 @@ static int set_auth_mode(struct usbnet *usbdev, u32 wpa_version, | |||
1072 | auth_mode = NDIS_80211_AUTH_SHARED; | 1072 | auth_mode = NDIS_80211_AUTH_SHARED; |
1073 | else if (auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) | 1073 | else if (auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) |
1074 | auth_mode = NDIS_80211_AUTH_OPEN; | 1074 | auth_mode = NDIS_80211_AUTH_OPEN; |
1075 | else if (auth_type == NL80211_AUTHTYPE_AUTOMATIC) | ||
1076 | auth_mode = NDIS_80211_AUTH_AUTO_SWITCH; | ||
1075 | else | 1077 | else |
1076 | return -ENOTSUPP; | 1078 | return -ENOTSUPP; |
1077 | 1079 | ||
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 798f625e38f7..6e68bc7efd4e 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | <http://rt2x00.serialmonkey.com> | 3 | <http://rt2x00.serialmonkey.com> |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify | 5 | This program is free software; you can redistribute it and/or modify |
@@ -1341,6 +1341,7 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) | |||
1341 | value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); | 1341 | value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); |
1342 | rt2x00pci_register_read(rt2x00dev, CSR0, ®); | 1342 | rt2x00pci_register_read(rt2x00dev, CSR0, ®); |
1343 | rt2x00_set_chip_rf(rt2x00dev, value, reg); | 1343 | rt2x00_set_chip_rf(rt2x00dev, value, reg); |
1344 | rt2x00_print_chip(rt2x00dev); | ||
1344 | 1345 | ||
1345 | if (!rt2x00_rf(&rt2x00dev->chip, RF2420) && | 1346 | if (!rt2x00_rf(&rt2x00dev->chip, RF2420) && |
1346 | !rt2x00_rf(&rt2x00dev->chip, RF2421)) { | 1347 | !rt2x00_rf(&rt2x00dev->chip, RF2421)) { |
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h index ccd644104ad1..6c21ef66dfe0 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.h +++ b/drivers/net/wireless/rt2x00/rt2400pci.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | <http://rt2x00.serialmonkey.com> | 3 | <http://rt2x00.serialmonkey.com> |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify | 5 | This program is free software; you can redistribute it and/or modify |
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 2e872ac69826..9a31e5e7b8df 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | <http://rt2x00.serialmonkey.com> | 3 | <http://rt2x00.serialmonkey.com> |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify | 5 | This program is free software; you can redistribute it and/or modify |
@@ -1505,6 +1505,7 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) | |||
1505 | value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); | 1505 | value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); |
1506 | rt2x00pci_register_read(rt2x00dev, CSR0, ®); | 1506 | rt2x00pci_register_read(rt2x00dev, CSR0, ®); |
1507 | rt2x00_set_chip_rf(rt2x00dev, value, reg); | 1507 | rt2x00_set_chip_rf(rt2x00dev, value, reg); |
1508 | rt2x00_print_chip(rt2x00dev); | ||
1508 | 1509 | ||
1509 | if (!rt2x00_rf(&rt2x00dev->chip, RF2522) && | 1510 | if (!rt2x00_rf(&rt2x00dev->chip, RF2522) && |
1510 | !rt2x00_rf(&rt2x00dev->chip, RF2523) && | 1511 | !rt2x00_rf(&rt2x00dev->chip, RF2523) && |
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h index 54d37957883c..b0075674c09b 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.h +++ b/drivers/net/wireless/rt2x00/rt2500pci.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | <http://rt2x00.serialmonkey.com> | 3 | <http://rt2x00.serialmonkey.com> |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify | 5 | This program is free software; you can redistribute it and/or modify |
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 22dd6d9e2981..b2de43e4f656 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | <http://rt2x00.serialmonkey.com> | 3 | <http://rt2x00.serialmonkey.com> |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify | 5 | This program is free software; you can redistribute it and/or modify |
@@ -716,139 +716,6 @@ static void rt2500usb_reset_tuner(struct rt2x00_dev *rt2x00dev, | |||
716 | } | 716 | } |
717 | 717 | ||
718 | /* | 718 | /* |
719 | * NOTE: This function is directly ported from legacy driver, but | ||
720 | * despite it being declared it was never called. Although link tuning | ||
721 | * sounds like a good idea, and usually works well for the other drivers, | ||
722 | * it does _not_ work with rt2500usb. Enabling this function will result | ||
723 | * in TX capabilities only until association kicks in. Immediately | ||
724 | * after the successful association all TX frames will be kept in the | ||
725 | * hardware queue and never transmitted. | ||
726 | */ | ||
727 | #if 0 | ||
728 | static void rt2500usb_link_tuner(struct rt2x00_dev *rt2x00dev) | ||
729 | { | ||
730 | int rssi = rt2x00_get_link_rssi(&rt2x00dev->link); | ||
731 | u16 bbp_thresh; | ||
732 | u16 vgc_bound; | ||
733 | u16 sens; | ||
734 | u16 r24; | ||
735 | u16 r25; | ||
736 | u16 r61; | ||
737 | u16 r17_sens; | ||
738 | u8 r17; | ||
739 | u8 up_bound; | ||
740 | u8 low_bound; | ||
741 | |||
742 | /* | ||
743 | * Read current r17 value, as well as the sensitivity values | ||
744 | * for the r17 register. | ||
745 | */ | ||
746 | rt2500usb_bbp_read(rt2x00dev, 17, &r17); | ||
747 | rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R17, &r17_sens); | ||
748 | |||
749 | rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC, &vgc_bound); | ||
750 | up_bound = rt2x00_get_field16(vgc_bound, EEPROM_BBPTUNE_VGCUPPER); | ||
751 | low_bound = rt2x00_get_field16(vgc_bound, EEPROM_BBPTUNE_VGCLOWER); | ||
752 | |||
753 | /* | ||
754 | * If we are not associated, we should go straight to the | ||
755 | * dynamic CCA tuning. | ||
756 | */ | ||
757 | if (!rt2x00dev->intf_associated) | ||
758 | goto dynamic_cca_tune; | ||
759 | |||
760 | /* | ||
761 | * Determine the BBP tuning threshold and correctly | ||
762 | * set BBP 24, 25 and 61. | ||
763 | */ | ||
764 | rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE, &bbp_thresh); | ||
765 | bbp_thresh = rt2x00_get_field16(bbp_thresh, EEPROM_BBPTUNE_THRESHOLD); | ||
766 | |||
767 | rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24, &r24); | ||
768 | rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R25, &r25); | ||
769 | rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R61, &r61); | ||
770 | |||
771 | if ((rssi + bbp_thresh) > 0) { | ||
772 | r24 = rt2x00_get_field16(r24, EEPROM_BBPTUNE_R24_HIGH); | ||
773 | r25 = rt2x00_get_field16(r25, EEPROM_BBPTUNE_R25_HIGH); | ||
774 | r61 = rt2x00_get_field16(r61, EEPROM_BBPTUNE_R61_HIGH); | ||
775 | } else { | ||
776 | r24 = rt2x00_get_field16(r24, EEPROM_BBPTUNE_R24_LOW); | ||
777 | r25 = rt2x00_get_field16(r25, EEPROM_BBPTUNE_R25_LOW); | ||
778 | r61 = rt2x00_get_field16(r61, EEPROM_BBPTUNE_R61_LOW); | ||
779 | } | ||
780 | |||
781 | rt2500usb_bbp_write(rt2x00dev, 24, r24); | ||
782 | rt2500usb_bbp_write(rt2x00dev, 25, r25); | ||
783 | rt2500usb_bbp_write(rt2x00dev, 61, r61); | ||
784 | |||
785 | /* | ||
786 | * A too low RSSI will cause too much false CCA which will | ||
787 | * then corrupt the R17 tuning. To remidy this the tuning should | ||
788 | * be stopped (While making sure the R17 value will not exceed limits) | ||
789 | */ | ||
790 | if (rssi >= -40) { | ||
791 | if (r17 != 0x60) | ||
792 | rt2500usb_bbp_write(rt2x00dev, 17, 0x60); | ||
793 | return; | ||
794 | } | ||
795 | |||
796 | /* | ||
797 | * Special big-R17 for short distance | ||
798 | */ | ||
799 | if (rssi >= -58) { | ||
800 | sens = rt2x00_get_field16(r17_sens, EEPROM_BBPTUNE_R17_LOW); | ||
801 | if (r17 != sens) | ||
802 | rt2500usb_bbp_write(rt2x00dev, 17, sens); | ||
803 | return; | ||
804 | } | ||
805 | |||
806 | /* | ||
807 | * Special mid-R17 for middle distance | ||
808 | */ | ||
809 | if (rssi >= -74) { | ||
810 | sens = rt2x00_get_field16(r17_sens, EEPROM_BBPTUNE_R17_HIGH); | ||
811 | if (r17 != sens) | ||
812 | rt2500usb_bbp_write(rt2x00dev, 17, sens); | ||
813 | return; | ||
814 | } | ||
815 | |||
816 | /* | ||
817 | * Leave short or middle distance condition, restore r17 | ||
818 | * to the dynamic tuning range. | ||
819 | */ | ||
820 | low_bound = 0x32; | ||
821 | if (rssi < -77) | ||
822 | up_bound -= (-77 - rssi); | ||
823 | |||
824 | if (up_bound < low_bound) | ||
825 | up_bound = low_bound; | ||
826 | |||
827 | if (r17 > up_bound) { | ||
828 | rt2500usb_bbp_write(rt2x00dev, 17, up_bound); | ||
829 | rt2x00dev->link.vgc_level = up_bound; | ||
830 | return; | ||
831 | } | ||
832 | |||
833 | dynamic_cca_tune: | ||
834 | |||
835 | /* | ||
836 | * R17 is inside the dynamic tuning range, | ||
837 | * start tuning the link based on the false cca counter. | ||
838 | */ | ||
839 | if (rt2x00dev->link.qual.false_cca > 512 && r17 < up_bound) { | ||
840 | rt2500usb_bbp_write(rt2x00dev, 17, ++r17); | ||
841 | rt2x00dev->link.vgc_level = r17; | ||
842 | } else if (rt2x00dev->link.qual.false_cca < 100 && r17 > low_bound) { | ||
843 | rt2500usb_bbp_write(rt2x00dev, 17, --r17); | ||
844 | rt2x00dev->link.vgc_level = r17; | ||
845 | } | ||
846 | } | ||
847 | #else | ||
848 | #define rt2500usb_link_tuner NULL | ||
849 | #endif | ||
850 | |||
851 | /* | ||
852 | * Initialization functions. | 719 | * Initialization functions. |
853 | */ | 720 | */ |
854 | static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev) | 721 | static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev) |
@@ -1542,6 +1409,7 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev) | |||
1542 | value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); | 1409 | value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); |
1543 | rt2500usb_register_read(rt2x00dev, MAC_CSR0, ®); | 1410 | rt2500usb_register_read(rt2x00dev, MAC_CSR0, ®); |
1544 | rt2x00_set_chip(rt2x00dev, RT2570, value, reg); | 1411 | rt2x00_set_chip(rt2x00dev, RT2570, value, reg); |
1412 | rt2x00_print_chip(rt2x00dev); | ||
1545 | 1413 | ||
1546 | if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0) || | 1414 | if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0) || |
1547 | rt2x00_check_rev(&rt2x00dev->chip, 0x0000000f, 0)) { | 1415 | rt2x00_check_rev(&rt2x00dev->chip, 0x0000000f, 0)) { |
@@ -1910,7 +1778,6 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { | |||
1910 | .rfkill_poll = rt2500usb_rfkill_poll, | 1778 | .rfkill_poll = rt2500usb_rfkill_poll, |
1911 | .link_stats = rt2500usb_link_stats, | 1779 | .link_stats = rt2500usb_link_stats, |
1912 | .reset_tuner = rt2500usb_reset_tuner, | 1780 | .reset_tuner = rt2500usb_reset_tuner, |
1913 | .link_tuner = rt2500usb_link_tuner, | ||
1914 | .write_tx_desc = rt2500usb_write_tx_desc, | 1781 | .write_tx_desc = rt2500usb_write_tx_desc, |
1915 | .write_tx_data = rt2x00usb_write_tx_data, | 1782 | .write_tx_data = rt2x00usb_write_tx_data, |
1916 | .write_beacon = rt2500usb_write_beacon, | 1783 | .write_beacon = rt2500usb_write_beacon, |
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h index b01edca42583..341a70454635 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.h +++ b/drivers/net/wireless/rt2x00/rt2500usb.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | <http://rt2x00.serialmonkey.com> | 3 | <http://rt2x00.serialmonkey.com> |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify | 5 | This program is free software; you can redistribute it and/or modify |
diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index d9b6a72e6d27..c5fe867665e6 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h | |||
@@ -1,5 +1,12 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | Copyright (C) 2009 Alban Browaeys <prahal@yahoo.com> | ||
4 | Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org> | ||
5 | Copyright (C) 2009 Luis Correia <luis.f.correia@gmail.com> | ||
6 | Copyright (C) 2009 Mattias Nissler <mattias.nissler@gmx.de> | ||
7 | Copyright (C) 2009 Mark Asselstine <asselsm@gmail.com> | ||
8 | Copyright (C) 2009 Xose Vazquez Perez <xose.vazquez@gmail.com> | ||
9 | Copyright (C) 2009 Bart Zolnierkiewicz <bzolnier@gmail.com> | ||
3 | <http://rt2x00.serialmonkey.com> | 10 | <http://rt2x00.serialmonkey.com> |
4 | 11 | ||
5 | This program is free software; you can redistribute it and/or modify | 12 | This program is free software; you can redistribute it and/or modify |
@@ -362,6 +369,35 @@ | |||
362 | #define RF_CSR_CFG_BUSY FIELD32(0x00020000) | 369 | #define RF_CSR_CFG_BUSY FIELD32(0x00020000) |
363 | 370 | ||
364 | /* | 371 | /* |
372 | * EFUSE_CSR: RT30x0 EEPROM | ||
373 | */ | ||
374 | #define EFUSE_CTRL 0x0580 | ||
375 | #define EFUSE_CTRL_ADDRESS_IN FIELD32(0x03fe0000) | ||
376 | #define EFUSE_CTRL_MODE FIELD32(0x000000c0) | ||
377 | #define EFUSE_CTRL_KICK FIELD32(0x40000000) | ||
378 | #define EFUSE_CTRL_PRESENT FIELD32(0x80000000) | ||
379 | |||
380 | /* | ||
381 | * EFUSE_DATA0 | ||
382 | */ | ||
383 | #define EFUSE_DATA0 0x0590 | ||
384 | |||
385 | /* | ||
386 | * EFUSE_DATA1 | ||
387 | */ | ||
388 | #define EFUSE_DATA1 0x0594 | ||
389 | |||
390 | /* | ||
391 | * EFUSE_DATA2 | ||
392 | */ | ||
393 | #define EFUSE_DATA2 0x0598 | ||
394 | |||
395 | /* | ||
396 | * EFUSE_DATA3 | ||
397 | */ | ||
398 | #define EFUSE_DATA3 0x059c | ||
399 | |||
400 | /* | ||
365 | * MAC Control/Status Registers(CSR). | 401 | * MAC Control/Status Registers(CSR). |
366 | * Some values are set in TU, whereas 1 TU == 1024 us. | 402 | * Some values are set in TU, whereas 1 TU == 1024 us. |
367 | */ | 403 | */ |
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 5c7d74a6f16e..e94f1e13fea9 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c | |||
@@ -1,9 +1,15 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2009 Bartlomiej Zolnierkiewicz | 2 | Copyright (C) 2009 Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> |
3 | 3 | Copyright (C) 2009 Gertjan van Wingerde <gwingerde@gmail.com> | |
4 | Based on the original rt2800pci.c and rt2800usb.c: | 4 | |
5 | 5 | Based on the original rt2800pci.c and rt2800usb.c. | |
6 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 6 | Copyright (C) 2009 Ivo van Doorn <IvDoorn@gmail.com> |
7 | Copyright (C) 2009 Alban Browaeys <prahal@yahoo.com> | ||
8 | Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org> | ||
9 | Copyright (C) 2009 Luis Correia <luis.f.correia@gmail.com> | ||
10 | Copyright (C) 2009 Mattias Nissler <mattias.nissler@gmx.de> | ||
11 | Copyright (C) 2009 Mark Asselstine <asselsm@gmail.com> | ||
12 | Copyright (C) 2009 Xose Vazquez Perez <xose.vazquez@gmail.com> | ||
7 | <http://rt2x00.serialmonkey.com> | 13 | <http://rt2x00.serialmonkey.com> |
8 | 14 | ||
9 | This program is free software; you can redistribute it and/or modify | 15 | This program is free software; you can redistribute it and/or modify |
@@ -555,7 +561,8 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, | |||
555 | rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); | 561 | rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); |
556 | rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); | 562 | rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); |
557 | rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, conf->sync); | 563 | rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, conf->sync); |
558 | rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); | 564 | rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, |
565 | (conf->sync == TSF_SYNC_BEACON)); | ||
559 | rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); | 566 | rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); |
560 | } | 567 | } |
561 | 568 | ||
@@ -769,7 +776,7 @@ static void rt2800_config_channel_rt3x(struct rt2x00_dev *rt2x00dev, | |||
769 | u8 rfcsr; | 776 | u8 rfcsr; |
770 | 777 | ||
771 | rt2800_rfcsr_write(rt2x00dev, 2, rf->rf1); | 778 | rt2800_rfcsr_write(rt2x00dev, 2, rf->rf1); |
772 | rt2800_rfcsr_write(rt2x00dev, 2, rf->rf3); | 779 | rt2800_rfcsr_write(rt2x00dev, 3, rf->rf3); |
773 | 780 | ||
774 | rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr); | 781 | rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr); |
775 | rt2x00_set_field8(&rfcsr, RFCSR6_R, rf->rf2); | 782 | rt2x00_set_field8(&rfcsr, RFCSR6_R, rf->rf2); |
@@ -801,10 +808,15 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, | |||
801 | unsigned int tx_pin; | 808 | unsigned int tx_pin; |
802 | u8 bbp; | 809 | u8 bbp; |
803 | 810 | ||
804 | if (rt2x00_rev(&rt2x00dev->chip) != RT3070_VERSION) | 811 | if ((rt2x00_rt(&rt2x00dev->chip, RT3070) || |
805 | rt2800_config_channel_rt2x(rt2x00dev, conf, rf, info); | 812 | rt2x00_rt(&rt2x00dev->chip, RT3090)) && |
806 | else | 813 | (rt2x00_rf(&rt2x00dev->chip, RF2020) || |
814 | rt2x00_rf(&rt2x00dev->chip, RF3020) || | ||
815 | rt2x00_rf(&rt2x00dev->chip, RF3021) || | ||
816 | rt2x00_rf(&rt2x00dev->chip, RF3022))) | ||
807 | rt2800_config_channel_rt3x(rt2x00dev, conf, rf, info); | 817 | rt2800_config_channel_rt3x(rt2x00dev, conf, rf, info); |
818 | else | ||
819 | rt2800_config_channel_rt2x(rt2x00dev, conf, rf, info); | ||
808 | 820 | ||
809 | /* | 821 | /* |
810 | * Change BBP settings | 822 | * Change BBP settings |
@@ -1084,7 +1096,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) | |||
1084 | 1096 | ||
1085 | if (rt2x00_intf_is_usb(rt2x00dev)) { | 1097 | if (rt2x00_intf_is_usb(rt2x00dev)) { |
1086 | /* | 1098 | /* |
1087 | * Wait untill BBP and RF are ready. | 1099 | * Wait until BBP and RF are ready. |
1088 | */ | 1100 | */ |
1089 | for (i = 0; i < REGISTER_BUSY_COUNT; i++) { | 1101 | for (i = 0; i < REGISTER_BUSY_COUNT; i++) { |
1090 | rt2800_register_read(rt2x00dev, MAC_CSR0, ®); | 1102 | rt2800_register_read(rt2x00dev, MAC_CSR0, ®); |
@@ -1659,6 +1671,466 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) | |||
1659 | } | 1671 | } |
1660 | EXPORT_SYMBOL_GPL(rt2800_init_rfcsr); | 1672 | EXPORT_SYMBOL_GPL(rt2800_init_rfcsr); |
1661 | 1673 | ||
1674 | int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev) | ||
1675 | { | ||
1676 | u32 reg; | ||
1677 | |||
1678 | rt2800_register_read(rt2x00dev, EFUSE_CTRL, ®); | ||
1679 | |||
1680 | return rt2x00_get_field32(reg, EFUSE_CTRL_PRESENT); | ||
1681 | } | ||
1682 | EXPORT_SYMBOL_GPL(rt2800_efuse_detect); | ||
1683 | |||
1684 | static void rt2800_efuse_read(struct rt2x00_dev *rt2x00dev, unsigned int i) | ||
1685 | { | ||
1686 | u32 reg; | ||
1687 | |||
1688 | mutex_lock(&rt2x00dev->csr_mutex); | ||
1689 | |||
1690 | rt2800_register_read_lock(rt2x00dev, EFUSE_CTRL, ®); | ||
1691 | rt2x00_set_field32(®, EFUSE_CTRL_ADDRESS_IN, i); | ||
1692 | rt2x00_set_field32(®, EFUSE_CTRL_MODE, 0); | ||
1693 | rt2x00_set_field32(®, EFUSE_CTRL_KICK, 1); | ||
1694 | rt2800_register_write_lock(rt2x00dev, EFUSE_CTRL, reg); | ||
1695 | |||
1696 | /* Wait until the EEPROM has been loaded */ | ||
1697 | rt2800_regbusy_read(rt2x00dev, EFUSE_CTRL, EFUSE_CTRL_KICK, ®); | ||
1698 | |||
1699 | /* Apparently the data is read from end to start */ | ||
1700 | rt2800_register_read_lock(rt2x00dev, EFUSE_DATA3, | ||
1701 | (u32 *)&rt2x00dev->eeprom[i]); | ||
1702 | rt2800_register_read_lock(rt2x00dev, EFUSE_DATA2, | ||
1703 | (u32 *)&rt2x00dev->eeprom[i + 2]); | ||
1704 | rt2800_register_read_lock(rt2x00dev, EFUSE_DATA1, | ||
1705 | (u32 *)&rt2x00dev->eeprom[i + 4]); | ||
1706 | rt2800_register_read_lock(rt2x00dev, EFUSE_DATA0, | ||
1707 | (u32 *)&rt2x00dev->eeprom[i + 6]); | ||
1708 | |||
1709 | mutex_unlock(&rt2x00dev->csr_mutex); | ||
1710 | } | ||
1711 | |||
1712 | void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev) | ||
1713 | { | ||
1714 | unsigned int i; | ||
1715 | |||
1716 | for (i = 0; i < EEPROM_SIZE / sizeof(u16); i += 8) | ||
1717 | rt2800_efuse_read(rt2x00dev, i); | ||
1718 | } | ||
1719 | EXPORT_SYMBOL_GPL(rt2800_read_eeprom_efuse); | ||
1720 | |||
1721 | int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) | ||
1722 | { | ||
1723 | u16 word; | ||
1724 | u8 *mac; | ||
1725 | u8 default_lna_gain; | ||
1726 | |||
1727 | /* | ||
1728 | * Start validation of the data that has been read. | ||
1729 | */ | ||
1730 | mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); | ||
1731 | if (!is_valid_ether_addr(mac)) { | ||
1732 | random_ether_addr(mac); | ||
1733 | EEPROM(rt2x00dev, "MAC: %pM\n", mac); | ||
1734 | } | ||
1735 | |||
1736 | rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); | ||
1737 | if (word == 0xffff) { | ||
1738 | rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2); | ||
1739 | rt2x00_set_field16(&word, EEPROM_ANTENNA_TXPATH, 1); | ||
1740 | rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2820); | ||
1741 | rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); | ||
1742 | EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word); | ||
1743 | } else if (rt2x00_rev(&rt2x00dev->chip) < RT2883_VERSION) { | ||
1744 | /* | ||
1745 | * There is a max of 2 RX streams for RT28x0 series | ||
1746 | */ | ||
1747 | if (rt2x00_get_field16(word, EEPROM_ANTENNA_RXPATH) > 2) | ||
1748 | rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2); | ||
1749 | rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); | ||
1750 | } | ||
1751 | |||
1752 | rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word); | ||
1753 | if (word == 0xffff) { | ||
1754 | rt2x00_set_field16(&word, EEPROM_NIC_HW_RADIO, 0); | ||
1755 | rt2x00_set_field16(&word, EEPROM_NIC_DYNAMIC_TX_AGC, 0); | ||
1756 | rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_BG, 0); | ||
1757 | rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_A, 0); | ||
1758 | rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0); | ||
1759 | rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_BG, 0); | ||
1760 | rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_A, 0); | ||
1761 | rt2x00_set_field16(&word, EEPROM_NIC_WPS_PBC, 0); | ||
1762 | rt2x00_set_field16(&word, EEPROM_NIC_BW40M_BG, 0); | ||
1763 | rt2x00_set_field16(&word, EEPROM_NIC_BW40M_A, 0); | ||
1764 | rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word); | ||
1765 | EEPROM(rt2x00dev, "NIC: 0x%04x\n", word); | ||
1766 | } | ||
1767 | |||
1768 | rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word); | ||
1769 | if ((word & 0x00ff) == 0x00ff) { | ||
1770 | rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0); | ||
1771 | rt2x00_set_field16(&word, EEPROM_FREQ_LED_MODE, | ||
1772 | LED_MODE_TXRX_ACTIVITY); | ||
1773 | rt2x00_set_field16(&word, EEPROM_FREQ_LED_POLARITY, 0); | ||
1774 | rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word); | ||
1775 | rt2x00_eeprom_write(rt2x00dev, EEPROM_LED1, 0x5555); | ||
1776 | rt2x00_eeprom_write(rt2x00dev, EEPROM_LED2, 0x2221); | ||
1777 | rt2x00_eeprom_write(rt2x00dev, EEPROM_LED3, 0xa9f8); | ||
1778 | EEPROM(rt2x00dev, "Freq: 0x%04x\n", word); | ||
1779 | } | ||
1780 | |||
1781 | /* | ||
1782 | * During the LNA validation we are going to use | ||
1783 | * lna0 as correct value. Note that EEPROM_LNA | ||
1784 | * is never validated. | ||
1785 | */ | ||
1786 | rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &word); | ||
1787 | default_lna_gain = rt2x00_get_field16(word, EEPROM_LNA_A0); | ||
1788 | |||
1789 | rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &word); | ||
1790 | if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET0)) > 10) | ||
1791 | rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET0, 0); | ||
1792 | if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET1)) > 10) | ||
1793 | rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET1, 0); | ||
1794 | rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG, word); | ||
1795 | |||
1796 | rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &word); | ||
1797 | if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG2_OFFSET2)) > 10) | ||
1798 | rt2x00_set_field16(&word, EEPROM_RSSI_BG2_OFFSET2, 0); | ||
1799 | if (rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0x00 || | ||
1800 | rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0xff) | ||
1801 | rt2x00_set_field16(&word, EEPROM_RSSI_BG2_LNA_A1, | ||
1802 | default_lna_gain); | ||
1803 | rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG2, word); | ||
1804 | |||
1805 | rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &word); | ||
1806 | if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET0)) > 10) | ||
1807 | rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET0, 0); | ||
1808 | if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET1)) > 10) | ||
1809 | rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET1, 0); | ||
1810 | rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A, word); | ||
1811 | |||
1812 | rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &word); | ||
1813 | if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A2_OFFSET2)) > 10) | ||
1814 | rt2x00_set_field16(&word, EEPROM_RSSI_A2_OFFSET2, 0); | ||
1815 | if (rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0x00 || | ||
1816 | rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0xff) | ||
1817 | rt2x00_set_field16(&word, EEPROM_RSSI_A2_LNA_A2, | ||
1818 | default_lna_gain); | ||
1819 | rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word); | ||
1820 | |||
1821 | return 0; | ||
1822 | } | ||
1823 | EXPORT_SYMBOL_GPL(rt2800_validate_eeprom); | ||
1824 | |||
1825 | int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) | ||
1826 | { | ||
1827 | u32 reg; | ||
1828 | u16 value; | ||
1829 | u16 eeprom; | ||
1830 | |||
1831 | /* | ||
1832 | * Read EEPROM word for configuration. | ||
1833 | */ | ||
1834 | rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); | ||
1835 | |||
1836 | /* | ||
1837 | * Identify RF chipset. | ||
1838 | */ | ||
1839 | value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); | ||
1840 | rt2800_register_read(rt2x00dev, MAC_CSR0, ®); | ||
1841 | |||
1842 | rt2x00_set_chip_rf(rt2x00dev, value, reg); | ||
1843 | |||
1844 | if (rt2x00_intf_is_usb(rt2x00dev)) { | ||
1845 | struct rt2x00_chip *chip = &rt2x00dev->chip; | ||
1846 | |||
1847 | /* | ||
1848 | * The check for rt2860 is not a typo, some rt2870 hardware | ||
1849 | * identifies itself as rt2860 in the CSR register. | ||
1850 | */ | ||
1851 | if (rt2x00_check_rev(chip, 0xfff00000, 0x28600000) || | ||
1852 | rt2x00_check_rev(chip, 0xfff00000, 0x28700000) || | ||
1853 | rt2x00_check_rev(chip, 0xfff00000, 0x28800000)) { | ||
1854 | rt2x00_set_chip_rt(rt2x00dev, RT2870); | ||
1855 | } else if (rt2x00_check_rev(chip, 0xffff0000, 0x30700000)) { | ||
1856 | rt2x00_set_chip_rt(rt2x00dev, RT3070); | ||
1857 | } else { | ||
1858 | ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); | ||
1859 | return -ENODEV; | ||
1860 | } | ||
1861 | } | ||
1862 | rt2x00_print_chip(rt2x00dev); | ||
1863 | |||
1864 | if (!rt2x00_rf(&rt2x00dev->chip, RF2820) && | ||
1865 | !rt2x00_rf(&rt2x00dev->chip, RF2850) && | ||
1866 | !rt2x00_rf(&rt2x00dev->chip, RF2720) && | ||
1867 | !rt2x00_rf(&rt2x00dev->chip, RF2750) && | ||
1868 | !rt2x00_rf(&rt2x00dev->chip, RF3020) && | ||
1869 | !rt2x00_rf(&rt2x00dev->chip, RF2020) && | ||
1870 | !rt2x00_rf(&rt2x00dev->chip, RF3021) && | ||
1871 | !rt2x00_rf(&rt2x00dev->chip, RF3022)) { | ||
1872 | ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); | ||
1873 | return -ENODEV; | ||
1874 | } | ||
1875 | |||
1876 | /* | ||
1877 | * Identify default antenna configuration. | ||
1878 | */ | ||
1879 | rt2x00dev->default_ant.tx = | ||
1880 | rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH); | ||
1881 | rt2x00dev->default_ant.rx = | ||
1882 | rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH); | ||
1883 | |||
1884 | /* | ||
1885 | * Read frequency offset and RF programming sequence. | ||
1886 | */ | ||
1887 | rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); | ||
1888 | rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); | ||
1889 | |||
1890 | /* | ||
1891 | * Read external LNA informations. | ||
1892 | */ | ||
1893 | rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); | ||
1894 | |||
1895 | if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A)) | ||
1896 | __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); | ||
1897 | if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG)) | ||
1898 | __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); | ||
1899 | |||
1900 | /* | ||
1901 | * Detect if this device has an hardware controlled radio. | ||
1902 | */ | ||
1903 | if (rt2x00_get_field16(eeprom, EEPROM_NIC_HW_RADIO)) | ||
1904 | __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); | ||
1905 | |||
1906 | /* | ||
1907 | * Store led settings, for correct led behaviour. | ||
1908 | */ | ||
1909 | #ifdef CONFIG_RT2X00_LIB_LEDS | ||
1910 | rt2800_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); | ||
1911 | rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC); | ||
1912 | rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY); | ||
1913 | |||
1914 | rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &rt2x00dev->led_mcu_reg); | ||
1915 | #endif /* CONFIG_RT2X00_LIB_LEDS */ | ||
1916 | |||
1917 | return 0; | ||
1918 | } | ||
1919 | EXPORT_SYMBOL_GPL(rt2800_init_eeprom); | ||
1920 | |||
1921 | /* | ||
1922 | * RF value list for rt28x0 | ||
1923 | * Supports: 2.4 GHz (all) & 5.2 GHz (RF2850 & RF2750) | ||
1924 | */ | ||
1925 | static const struct rf_channel rf_vals[] = { | ||
1926 | { 1, 0x18402ecc, 0x184c0786, 0x1816b455, 0x1800510b }, | ||
1927 | { 2, 0x18402ecc, 0x184c0786, 0x18168a55, 0x1800519f }, | ||
1928 | { 3, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800518b }, | ||
1929 | { 4, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800519f }, | ||
1930 | { 5, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800518b }, | ||
1931 | { 6, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800519f }, | ||
1932 | { 7, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800518b }, | ||
1933 | { 8, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800519f }, | ||
1934 | { 9, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800518b }, | ||
1935 | { 10, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800519f }, | ||
1936 | { 11, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800518b }, | ||
1937 | { 12, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800519f }, | ||
1938 | { 13, 0x18402ecc, 0x184c079e, 0x18168a55, 0x1800518b }, | ||
1939 | { 14, 0x18402ecc, 0x184c07a2, 0x18168a55, 0x18005193 }, | ||
1940 | |||
1941 | /* 802.11 UNI / HyperLan 2 */ | ||
1942 | { 36, 0x18402ecc, 0x184c099a, 0x18158a55, 0x180ed1a3 }, | ||
1943 | { 38, 0x18402ecc, 0x184c099e, 0x18158a55, 0x180ed193 }, | ||
1944 | { 40, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed183 }, | ||
1945 | { 44, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed1a3 }, | ||
1946 | { 46, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed18b }, | ||
1947 | { 48, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed19b }, | ||
1948 | { 52, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed193 }, | ||
1949 | { 54, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed1a3 }, | ||
1950 | { 56, 0x18402ec8, 0x184c068e, 0x18158a55, 0x180ed18b }, | ||
1951 | { 60, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed183 }, | ||
1952 | { 62, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed193 }, | ||
1953 | { 64, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed1a3 }, | ||
1954 | |||
1955 | /* 802.11 HyperLan 2 */ | ||
1956 | { 100, 0x18402ec8, 0x184c06b2, 0x18178a55, 0x180ed783 }, | ||
1957 | { 102, 0x18402ec8, 0x184c06b2, 0x18578a55, 0x180ed793 }, | ||
1958 | { 104, 0x18402ec8, 0x185c06b2, 0x18578a55, 0x180ed1a3 }, | ||
1959 | { 108, 0x18402ecc, 0x185c0a32, 0x18578a55, 0x180ed193 }, | ||
1960 | { 110, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed183 }, | ||
1961 | { 112, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed19b }, | ||
1962 | { 116, 0x18402ecc, 0x184c0a3a, 0x18178a55, 0x180ed1a3 }, | ||
1963 | { 118, 0x18402ecc, 0x184c0a3e, 0x18178a55, 0x180ed193 }, | ||
1964 | { 120, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed183 }, | ||
1965 | { 124, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed193 }, | ||
1966 | { 126, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed15b }, | ||
1967 | { 128, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed1a3 }, | ||
1968 | { 132, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed18b }, | ||
1969 | { 134, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed193 }, | ||
1970 | { 136, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed19b }, | ||
1971 | { 140, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed183 }, | ||
1972 | |||
1973 | /* 802.11 UNII */ | ||
1974 | { 149, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed1a7 }, | ||
1975 | { 151, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed187 }, | ||
1976 | { 153, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed18f }, | ||
1977 | { 157, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed19f }, | ||
1978 | { 159, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed1a7 }, | ||
1979 | { 161, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed187 }, | ||
1980 | { 165, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed197 }, | ||
1981 | { 167, 0x18402ec4, 0x184c03d2, 0x18179855, 0x1815531f }, | ||
1982 | { 169, 0x18402ec4, 0x184c03d2, 0x18179855, 0x18155327 }, | ||
1983 | { 171, 0x18402ec4, 0x184c03d6, 0x18179855, 0x18155307 }, | ||
1984 | { 173, 0x18402ec4, 0x184c03d6, 0x18179855, 0x1815530f }, | ||
1985 | |||
1986 | /* 802.11 Japan */ | ||
1987 | { 184, 0x15002ccc, 0x1500491e, 0x1509be55, 0x150c0a0b }, | ||
1988 | { 188, 0x15002ccc, 0x15004922, 0x1509be55, 0x150c0a13 }, | ||
1989 | { 192, 0x15002ccc, 0x15004926, 0x1509be55, 0x150c0a1b }, | ||
1990 | { 196, 0x15002ccc, 0x1500492a, 0x1509be55, 0x150c0a23 }, | ||
1991 | { 208, 0x15002ccc, 0x1500493a, 0x1509be55, 0x150c0a13 }, | ||
1992 | { 212, 0x15002ccc, 0x1500493e, 0x1509be55, 0x150c0a1b }, | ||
1993 | { 216, 0x15002ccc, 0x15004982, 0x1509be55, 0x150c0a23 }, | ||
1994 | }; | ||
1995 | |||
1996 | /* | ||
1997 | * RF value list for rt3070 | ||
1998 | * Supports: 2.4 GHz | ||
1999 | */ | ||
2000 | static const struct rf_channel rf_vals_302x[] = { | ||
2001 | {1, 241, 2, 2 }, | ||
2002 | {2, 241, 2, 7 }, | ||
2003 | {3, 242, 2, 2 }, | ||
2004 | {4, 242, 2, 7 }, | ||
2005 | {5, 243, 2, 2 }, | ||
2006 | {6, 243, 2, 7 }, | ||
2007 | {7, 244, 2, 2 }, | ||
2008 | {8, 244, 2, 7 }, | ||
2009 | {9, 245, 2, 2 }, | ||
2010 | {10, 245, 2, 7 }, | ||
2011 | {11, 246, 2, 2 }, | ||
2012 | {12, 246, 2, 7 }, | ||
2013 | {13, 247, 2, 2 }, | ||
2014 | {14, 248, 2, 4 }, | ||
2015 | }; | ||
2016 | |||
2017 | int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) | ||
2018 | { | ||
2019 | struct rt2x00_chip *chip = &rt2x00dev->chip; | ||
2020 | struct hw_mode_spec *spec = &rt2x00dev->spec; | ||
2021 | struct channel_info *info; | ||
2022 | char *tx_power1; | ||
2023 | char *tx_power2; | ||
2024 | unsigned int i; | ||
2025 | u16 eeprom; | ||
2026 | |||
2027 | /* | ||
2028 | * Initialize all hw fields. | ||
2029 | */ | ||
2030 | rt2x00dev->hw->flags = | ||
2031 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | | ||
2032 | IEEE80211_HW_SIGNAL_DBM | | ||
2033 | IEEE80211_HW_SUPPORTS_PS | | ||
2034 | IEEE80211_HW_PS_NULLFUNC_STACK; | ||
2035 | |||
2036 | if (rt2x00_intf_is_usb(rt2x00dev)) | ||
2037 | rt2x00dev->hw->extra_tx_headroom = | ||
2038 | TXINFO_DESC_SIZE + TXWI_DESC_SIZE; | ||
2039 | else if (rt2x00_intf_is_pci(rt2x00dev)) | ||
2040 | rt2x00dev->hw->extra_tx_headroom = TXWI_DESC_SIZE; | ||
2041 | |||
2042 | SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); | ||
2043 | SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, | ||
2044 | rt2x00_eeprom_addr(rt2x00dev, | ||
2045 | EEPROM_MAC_ADDR_0)); | ||
2046 | |||
2047 | rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); | ||
2048 | |||
2049 | /* | ||
2050 | * Initialize hw_mode information. | ||
2051 | */ | ||
2052 | spec->supported_bands = SUPPORT_BAND_2GHZ; | ||
2053 | spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; | ||
2054 | |||
2055 | if (rt2x00_rf(chip, RF2820) || | ||
2056 | rt2x00_rf(chip, RF2720) || | ||
2057 | (rt2x00_intf_is_pci(rt2x00dev) && rt2x00_rf(chip, RF3052))) { | ||
2058 | spec->num_channels = 14; | ||
2059 | spec->channels = rf_vals; | ||
2060 | } else if (rt2x00_rf(chip, RF2850) || rt2x00_rf(chip, RF2750)) { | ||
2061 | spec->supported_bands |= SUPPORT_BAND_5GHZ; | ||
2062 | spec->num_channels = ARRAY_SIZE(rf_vals); | ||
2063 | spec->channels = rf_vals; | ||
2064 | } else if (rt2x00_rf(chip, RF3020) || | ||
2065 | rt2x00_rf(chip, RF2020) || | ||
2066 | rt2x00_rf(chip, RF3021) || | ||
2067 | rt2x00_rf(chip, RF3022)) { | ||
2068 | spec->num_channels = ARRAY_SIZE(rf_vals_302x); | ||
2069 | spec->channels = rf_vals_302x; | ||
2070 | } | ||
2071 | |||
2072 | /* | ||
2073 | * Initialize HT information. | ||
2074 | */ | ||
2075 | spec->ht.ht_supported = true; | ||
2076 | spec->ht.cap = | ||
2077 | IEEE80211_HT_CAP_SUP_WIDTH_20_40 | | ||
2078 | IEEE80211_HT_CAP_GRN_FLD | | ||
2079 | IEEE80211_HT_CAP_SGI_20 | | ||
2080 | IEEE80211_HT_CAP_SGI_40 | | ||
2081 | IEEE80211_HT_CAP_TX_STBC | | ||
2082 | IEEE80211_HT_CAP_RX_STBC | | ||
2083 | IEEE80211_HT_CAP_PSMP_SUPPORT; | ||
2084 | spec->ht.ampdu_factor = 3; | ||
2085 | spec->ht.ampdu_density = 4; | ||
2086 | spec->ht.mcs.tx_params = | ||
2087 | IEEE80211_HT_MCS_TX_DEFINED | | ||
2088 | IEEE80211_HT_MCS_TX_RX_DIFF | | ||
2089 | ((rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) - 1) << | ||
2090 | IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); | ||
2091 | |||
2092 | switch (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH)) { | ||
2093 | case 3: | ||
2094 | spec->ht.mcs.rx_mask[2] = 0xff; | ||
2095 | case 2: | ||
2096 | spec->ht.mcs.rx_mask[1] = 0xff; | ||
2097 | case 1: | ||
2098 | spec->ht.mcs.rx_mask[0] = 0xff; | ||
2099 | spec->ht.mcs.rx_mask[4] = 0x1; /* MCS32 */ | ||
2100 | break; | ||
2101 | } | ||
2102 | |||
2103 | /* | ||
2104 | * Create channel information array | ||
2105 | */ | ||
2106 | info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL); | ||
2107 | if (!info) | ||
2108 | return -ENOMEM; | ||
2109 | |||
2110 | spec->channels_info = info; | ||
2111 | |||
2112 | tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1); | ||
2113 | tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2); | ||
2114 | |||
2115 | for (i = 0; i < 14; i++) { | ||
2116 | info[i].tx_power1 = TXPOWER_G_FROM_DEV(tx_power1[i]); | ||
2117 | info[i].tx_power2 = TXPOWER_G_FROM_DEV(tx_power2[i]); | ||
2118 | } | ||
2119 | |||
2120 | if (spec->num_channels > 14) { | ||
2121 | tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A1); | ||
2122 | tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A2); | ||
2123 | |||
2124 | for (i = 14; i < spec->num_channels; i++) { | ||
2125 | info[i].tx_power1 = TXPOWER_A_FROM_DEV(tx_power1[i]); | ||
2126 | info[i].tx_power2 = TXPOWER_A_FROM_DEV(tx_power2[i]); | ||
2127 | } | ||
2128 | } | ||
2129 | |||
2130 | return 0; | ||
2131 | } | ||
2132 | EXPORT_SYMBOL_GPL(rt2800_probe_hw_mode); | ||
2133 | |||
1662 | /* | 2134 | /* |
1663 | * IEEE80211 stack callback functions. | 2135 | * IEEE80211 stack callback functions. |
1664 | */ | 2136 | */ |
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index 5eea8fcba6cc..535ce22f2ac8 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h | |||
@@ -23,6 +23,8 @@ | |||
23 | struct rt2800_ops { | 23 | struct rt2800_ops { |
24 | void (*register_read)(struct rt2x00_dev *rt2x00dev, | 24 | void (*register_read)(struct rt2x00_dev *rt2x00dev, |
25 | const unsigned int offset, u32 *value); | 25 | const unsigned int offset, u32 *value); |
26 | void (*register_read_lock)(struct rt2x00_dev *rt2x00dev, | ||
27 | const unsigned int offset, u32 *value); | ||
26 | void (*register_write)(struct rt2x00_dev *rt2x00dev, | 28 | void (*register_write)(struct rt2x00_dev *rt2x00dev, |
27 | const unsigned int offset, u32 value); | 29 | const unsigned int offset, u32 value); |
28 | void (*register_write_lock)(struct rt2x00_dev *rt2x00dev, | 30 | void (*register_write_lock)(struct rt2x00_dev *rt2x00dev, |
@@ -49,6 +51,15 @@ static inline void rt2800_register_read(struct rt2x00_dev *rt2x00dev, | |||
49 | rt2800ops->register_read(rt2x00dev, offset, value); | 51 | rt2800ops->register_read(rt2x00dev, offset, value); |
50 | } | 52 | } |
51 | 53 | ||
54 | static inline void rt2800_register_read_lock(struct rt2x00_dev *rt2x00dev, | ||
55 | const unsigned int offset, | ||
56 | u32 *value) | ||
57 | { | ||
58 | const struct rt2800_ops *rt2800ops = rt2x00dev->priv; | ||
59 | |||
60 | rt2800ops->register_read_lock(rt2x00dev, offset, value); | ||
61 | } | ||
62 | |||
52 | static inline void rt2800_register_write(struct rt2x00_dev *rt2x00dev, | 63 | static inline void rt2800_register_write(struct rt2x00_dev *rt2x00dev, |
53 | const unsigned int offset, | 64 | const unsigned int offset, |
54 | u32 value) | 65 | u32 value) |
@@ -129,6 +140,12 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev); | |||
129 | int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev); | 140 | int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev); |
130 | int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev); | 141 | int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev); |
131 | 142 | ||
143 | int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev); | ||
144 | void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev); | ||
145 | int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev); | ||
146 | int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev); | ||
147 | int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev); | ||
148 | |||
132 | extern const struct ieee80211_ops rt2800_mac80211_ops; | 149 | extern const struct ieee80211_ops rt2800_mac80211_ops; |
133 | 150 | ||
134 | #endif /* RT2800LIB_H */ | 151 | #endif /* RT2800LIB_H */ |
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 3c5b875cdee8..87a5094ae953 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c | |||
@@ -1,5 +1,12 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | Copyright (C) 2009 Alban Browaeys <prahal@yahoo.com> | ||
4 | Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org> | ||
5 | Copyright (C) 2009 Luis Correia <luis.f.correia@gmail.com> | ||
6 | Copyright (C) 2009 Mattias Nissler <mattias.nissler@gmx.de> | ||
7 | Copyright (C) 2009 Mark Asselstine <asselsm@gmail.com> | ||
8 | Copyright (C) 2009 Xose Vazquez Perez <xose.vazquez@gmail.com> | ||
9 | Copyright (C) 2009 Bart Zolnierkiewicz <bzolnier@gmail.com> | ||
3 | <http://rt2x00.serialmonkey.com> | 10 | <http://rt2x00.serialmonkey.com> |
4 | 11 | ||
5 | This program is free software; you can redistribute it and/or modify | 12 | This program is free software; you can redistribute it and/or modify |
@@ -145,43 +152,25 @@ static void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev) | |||
145 | EEPROM_SIZE / sizeof(u16)); | 152 | EEPROM_SIZE / sizeof(u16)); |
146 | } | 153 | } |
147 | 154 | ||
148 | static void rt2800pci_efuse_read(struct rt2x00_dev *rt2x00dev, | 155 | static int rt2800pci_efuse_detect(struct rt2x00_dev *rt2x00dev) |
149 | unsigned int i) | ||
150 | { | 156 | { |
151 | u32 reg; | 157 | return rt2800_efuse_detect(rt2x00dev); |
152 | |||
153 | rt2800_register_read(rt2x00dev, EFUSE_CTRL, ®); | ||
154 | rt2x00_set_field32(®, EFUSE_CTRL_ADDRESS_IN, i); | ||
155 | rt2x00_set_field32(®, EFUSE_CTRL_MODE, 0); | ||
156 | rt2x00_set_field32(®, EFUSE_CTRL_KICK, 1); | ||
157 | rt2800_register_write(rt2x00dev, EFUSE_CTRL, reg); | ||
158 | |||
159 | /* Wait until the EEPROM has been loaded */ | ||
160 | rt2800_regbusy_read(rt2x00dev, EFUSE_CTRL, EFUSE_CTRL_KICK, ®); | ||
161 | |||
162 | /* Apparently the data is read from end to start */ | ||
163 | rt2800_register_read(rt2x00dev, EFUSE_DATA3, | ||
164 | (u32 *)&rt2x00dev->eeprom[i]); | ||
165 | rt2800_register_read(rt2x00dev, EFUSE_DATA2, | ||
166 | (u32 *)&rt2x00dev->eeprom[i + 2]); | ||
167 | rt2800_register_read(rt2x00dev, EFUSE_DATA1, | ||
168 | (u32 *)&rt2x00dev->eeprom[i + 4]); | ||
169 | rt2800_register_read(rt2x00dev, EFUSE_DATA0, | ||
170 | (u32 *)&rt2x00dev->eeprom[i + 6]); | ||
171 | } | 158 | } |
172 | 159 | ||
173 | static void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev) | 160 | static inline void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev) |
174 | { | 161 | { |
175 | unsigned int i; | 162 | rt2800_read_eeprom_efuse(rt2x00dev); |
176 | |||
177 | for (i = 0; i < EEPROM_SIZE / sizeof(u16); i += 8) | ||
178 | rt2800pci_efuse_read(rt2x00dev, i); | ||
179 | } | 163 | } |
180 | #else | 164 | #else |
181 | static inline void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev) | 165 | static inline void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev) |
182 | { | 166 | { |
183 | } | 167 | } |
184 | 168 | ||
169 | static inline int rt2800pci_efuse_detect(struct rt2x00_dev *rt2x00dev) | ||
170 | { | ||
171 | return 0; | ||
172 | } | ||
173 | |||
185 | static inline void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev) | 174 | static inline void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev) |
186 | { | 175 | { |
187 | } | 176 | } |
@@ -1079,379 +1068,28 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance) | |||
1079 | */ | 1068 | */ |
1080 | static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) | 1069 | static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) |
1081 | { | 1070 | { |
1082 | u16 word; | ||
1083 | u8 *mac; | ||
1084 | u8 default_lna_gain; | ||
1085 | |||
1086 | /* | 1071 | /* |
1087 | * Read EEPROM into buffer | 1072 | * Read EEPROM into buffer |
1088 | */ | 1073 | */ |
1089 | switch(rt2x00dev->chip.rt) { | 1074 | switch (rt2x00dev->chip.rt) { |
1090 | case RT2880: | 1075 | case RT2880: |
1091 | case RT3052: | 1076 | case RT3052: |
1092 | rt2800pci_read_eeprom_soc(rt2x00dev); | 1077 | rt2800pci_read_eeprom_soc(rt2x00dev); |
1093 | break; | 1078 | break; |
1094 | case RT3090: | ||
1095 | rt2800pci_read_eeprom_efuse(rt2x00dev); | ||
1096 | break; | ||
1097 | default: | 1079 | default: |
1098 | rt2800pci_read_eeprom_pci(rt2x00dev); | 1080 | if (rt2800pci_efuse_detect(rt2x00dev)) |
1099 | break; | 1081 | rt2800pci_read_eeprom_efuse(rt2x00dev); |
1100 | } | 1082 | else |
1101 | 1083 | rt2800pci_read_eeprom_pci(rt2x00dev); | |
1102 | /* | ||
1103 | * Start validation of the data that has been read. | ||
1104 | */ | ||
1105 | mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); | ||
1106 | if (!is_valid_ether_addr(mac)) { | ||
1107 | random_ether_addr(mac); | ||
1108 | EEPROM(rt2x00dev, "MAC: %pM\n", mac); | ||
1109 | } | ||
1110 | |||
1111 | rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); | ||
1112 | if (word == 0xffff) { | ||
1113 | rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2); | ||
1114 | rt2x00_set_field16(&word, EEPROM_ANTENNA_TXPATH, 1); | ||
1115 | rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2820); | ||
1116 | rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); | ||
1117 | EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word); | ||
1118 | } else if (rt2x00_rev(&rt2x00dev->chip) < RT2883_VERSION) { | ||
1119 | /* | ||
1120 | * There is a max of 2 RX streams for RT2860 series | ||
1121 | */ | ||
1122 | if (rt2x00_get_field16(word, EEPROM_ANTENNA_RXPATH) > 2) | ||
1123 | rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2); | ||
1124 | rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); | ||
1125 | } | ||
1126 | |||
1127 | rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word); | ||
1128 | if (word == 0xffff) { | ||
1129 | rt2x00_set_field16(&word, EEPROM_NIC_HW_RADIO, 0); | ||
1130 | rt2x00_set_field16(&word, EEPROM_NIC_DYNAMIC_TX_AGC, 0); | ||
1131 | rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_BG, 0); | ||
1132 | rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_A, 0); | ||
1133 | rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0); | ||
1134 | rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_BG, 0); | ||
1135 | rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_A, 0); | ||
1136 | rt2x00_set_field16(&word, EEPROM_NIC_WPS_PBC, 0); | ||
1137 | rt2x00_set_field16(&word, EEPROM_NIC_BW40M_BG, 0); | ||
1138 | rt2x00_set_field16(&word, EEPROM_NIC_BW40M_A, 0); | ||
1139 | rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word); | ||
1140 | EEPROM(rt2x00dev, "NIC: 0x%04x\n", word); | ||
1141 | } | ||
1142 | |||
1143 | rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word); | ||
1144 | if ((word & 0x00ff) == 0x00ff) { | ||
1145 | rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0); | ||
1146 | rt2x00_set_field16(&word, EEPROM_FREQ_LED_MODE, | ||
1147 | LED_MODE_TXRX_ACTIVITY); | ||
1148 | rt2x00_set_field16(&word, EEPROM_FREQ_LED_POLARITY, 0); | ||
1149 | rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word); | ||
1150 | rt2x00_eeprom_write(rt2x00dev, EEPROM_LED1, 0x5555); | ||
1151 | rt2x00_eeprom_write(rt2x00dev, EEPROM_LED2, 0x2221); | ||
1152 | rt2x00_eeprom_write(rt2x00dev, EEPROM_LED3, 0xa9f8); | ||
1153 | EEPROM(rt2x00dev, "Freq: 0x%04x\n", word); | ||
1154 | } | ||
1155 | |||
1156 | /* | ||
1157 | * During the LNA validation we are going to use | ||
1158 | * lna0 as correct value. Note that EEPROM_LNA | ||
1159 | * is never validated. | ||
1160 | */ | ||
1161 | rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &word); | ||
1162 | default_lna_gain = rt2x00_get_field16(word, EEPROM_LNA_A0); | ||
1163 | |||
1164 | rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &word); | ||
1165 | if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET0)) > 10) | ||
1166 | rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET0, 0); | ||
1167 | if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET1)) > 10) | ||
1168 | rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET1, 0); | ||
1169 | rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG, word); | ||
1170 | |||
1171 | rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &word); | ||
1172 | if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG2_OFFSET2)) > 10) | ||
1173 | rt2x00_set_field16(&word, EEPROM_RSSI_BG2_OFFSET2, 0); | ||
1174 | if (rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0x00 || | ||
1175 | rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0xff) | ||
1176 | rt2x00_set_field16(&word, EEPROM_RSSI_BG2_LNA_A1, | ||
1177 | default_lna_gain); | ||
1178 | rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG2, word); | ||
1179 | |||
1180 | rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &word); | ||
1181 | if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET0)) > 10) | ||
1182 | rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET0, 0); | ||
1183 | if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET1)) > 10) | ||
1184 | rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET1, 0); | ||
1185 | rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A, word); | ||
1186 | |||
1187 | rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &word); | ||
1188 | if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A2_OFFSET2)) > 10) | ||
1189 | rt2x00_set_field16(&word, EEPROM_RSSI_A2_OFFSET2, 0); | ||
1190 | if (rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0x00 || | ||
1191 | rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0xff) | ||
1192 | rt2x00_set_field16(&word, EEPROM_RSSI_A2_LNA_A2, | ||
1193 | default_lna_gain); | ||
1194 | rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word); | ||
1195 | |||
1196 | return 0; | ||
1197 | } | ||
1198 | |||
1199 | static int rt2800pci_init_eeprom(struct rt2x00_dev *rt2x00dev) | ||
1200 | { | ||
1201 | u32 reg; | ||
1202 | u16 value; | ||
1203 | u16 eeprom; | ||
1204 | |||
1205 | /* | ||
1206 | * Read EEPROM word for configuration. | ||
1207 | */ | ||
1208 | rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); | ||
1209 | |||
1210 | /* | ||
1211 | * Identify RF chipset. | ||
1212 | */ | ||
1213 | value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); | ||
1214 | rt2800_register_read(rt2x00dev, MAC_CSR0, ®); | ||
1215 | rt2x00_set_chip_rf(rt2x00dev, value, reg); | ||
1216 | |||
1217 | if (!rt2x00_rf(&rt2x00dev->chip, RF2820) && | ||
1218 | !rt2x00_rf(&rt2x00dev->chip, RF2850) && | ||
1219 | !rt2x00_rf(&rt2x00dev->chip, RF2720) && | ||
1220 | !rt2x00_rf(&rt2x00dev->chip, RF2750) && | ||
1221 | !rt2x00_rf(&rt2x00dev->chip, RF3020) && | ||
1222 | !rt2x00_rf(&rt2x00dev->chip, RF2020) && | ||
1223 | !rt2x00_rf(&rt2x00dev->chip, RF3021) && | ||
1224 | !rt2x00_rf(&rt2x00dev->chip, RF3022)) { | ||
1225 | ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); | ||
1226 | return -ENODEV; | ||
1227 | } | ||
1228 | |||
1229 | /* | ||
1230 | * Identify default antenna configuration. | ||
1231 | */ | ||
1232 | rt2x00dev->default_ant.tx = | ||
1233 | rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH); | ||
1234 | rt2x00dev->default_ant.rx = | ||
1235 | rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH); | ||
1236 | |||
1237 | /* | ||
1238 | * Read frequency offset and RF programming sequence. | ||
1239 | */ | ||
1240 | rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); | ||
1241 | rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); | ||
1242 | |||
1243 | /* | ||
1244 | * Read external LNA informations. | ||
1245 | */ | ||
1246 | rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); | ||
1247 | |||
1248 | if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A)) | ||
1249 | __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); | ||
1250 | if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG)) | ||
1251 | __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); | ||
1252 | |||
1253 | /* | ||
1254 | * Detect if this device has an hardware controlled radio. | ||
1255 | */ | ||
1256 | if (rt2x00_get_field16(eeprom, EEPROM_NIC_HW_RADIO)) | ||
1257 | __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); | ||
1258 | |||
1259 | /* | ||
1260 | * Store led settings, for correct led behaviour. | ||
1261 | */ | ||
1262 | #ifdef CONFIG_RT2X00_LIB_LEDS | ||
1263 | rt2800_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); | ||
1264 | rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC); | ||
1265 | rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY); | ||
1266 | |||
1267 | rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &rt2x00dev->led_mcu_reg); | ||
1268 | #endif /* CONFIG_RT2X00_LIB_LEDS */ | ||
1269 | |||
1270 | return 0; | ||
1271 | } | ||
1272 | |||
1273 | /* | ||
1274 | * RF value list for rt2860 | ||
1275 | * Supports: 2.4 GHz (all) & 5.2 GHz (RF2850 & RF2750) | ||
1276 | */ | ||
1277 | static const struct rf_channel rf_vals[] = { | ||
1278 | { 1, 0x18402ecc, 0x184c0786, 0x1816b455, 0x1800510b }, | ||
1279 | { 2, 0x18402ecc, 0x184c0786, 0x18168a55, 0x1800519f }, | ||
1280 | { 3, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800518b }, | ||
1281 | { 4, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800519f }, | ||
1282 | { 5, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800518b }, | ||
1283 | { 6, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800519f }, | ||
1284 | { 7, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800518b }, | ||
1285 | { 8, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800519f }, | ||
1286 | { 9, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800518b }, | ||
1287 | { 10, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800519f }, | ||
1288 | { 11, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800518b }, | ||
1289 | { 12, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800519f }, | ||
1290 | { 13, 0x18402ecc, 0x184c079e, 0x18168a55, 0x1800518b }, | ||
1291 | { 14, 0x18402ecc, 0x184c07a2, 0x18168a55, 0x18005193 }, | ||
1292 | |||
1293 | /* 802.11 UNI / HyperLan 2 */ | ||
1294 | { 36, 0x18402ecc, 0x184c099a, 0x18158a55, 0x180ed1a3 }, | ||
1295 | { 38, 0x18402ecc, 0x184c099e, 0x18158a55, 0x180ed193 }, | ||
1296 | { 40, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed183 }, | ||
1297 | { 44, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed1a3 }, | ||
1298 | { 46, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed18b }, | ||
1299 | { 48, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed19b }, | ||
1300 | { 52, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed193 }, | ||
1301 | { 54, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed1a3 }, | ||
1302 | { 56, 0x18402ec8, 0x184c068e, 0x18158a55, 0x180ed18b }, | ||
1303 | { 60, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed183 }, | ||
1304 | { 62, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed193 }, | ||
1305 | { 64, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed1a3 }, | ||
1306 | |||
1307 | /* 802.11 HyperLan 2 */ | ||
1308 | { 100, 0x18402ec8, 0x184c06b2, 0x18178a55, 0x180ed783 }, | ||
1309 | { 102, 0x18402ec8, 0x184c06b2, 0x18578a55, 0x180ed793 }, | ||
1310 | { 104, 0x18402ec8, 0x185c06b2, 0x18578a55, 0x180ed1a3 }, | ||
1311 | { 108, 0x18402ecc, 0x185c0a32, 0x18578a55, 0x180ed193 }, | ||
1312 | { 110, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed183 }, | ||
1313 | { 112, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed19b }, | ||
1314 | { 116, 0x18402ecc, 0x184c0a3a, 0x18178a55, 0x180ed1a3 }, | ||
1315 | { 118, 0x18402ecc, 0x184c0a3e, 0x18178a55, 0x180ed193 }, | ||
1316 | { 120, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed183 }, | ||
1317 | { 124, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed193 }, | ||
1318 | { 126, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed15b }, | ||
1319 | { 128, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed1a3 }, | ||
1320 | { 132, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed18b }, | ||
1321 | { 134, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed193 }, | ||
1322 | { 136, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed19b }, | ||
1323 | { 140, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed183 }, | ||
1324 | |||
1325 | /* 802.11 UNII */ | ||
1326 | { 149, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed1a7 }, | ||
1327 | { 151, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed187 }, | ||
1328 | { 153, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed18f }, | ||
1329 | { 157, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed19f }, | ||
1330 | { 159, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed1a7 }, | ||
1331 | { 161, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed187 }, | ||
1332 | { 165, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed197 }, | ||
1333 | |||
1334 | /* 802.11 Japan */ | ||
1335 | { 184, 0x15002ccc, 0x1500491e, 0x1509be55, 0x150c0a0b }, | ||
1336 | { 188, 0x15002ccc, 0x15004922, 0x1509be55, 0x150c0a13 }, | ||
1337 | { 192, 0x15002ccc, 0x15004926, 0x1509be55, 0x150c0a1b }, | ||
1338 | { 196, 0x15002ccc, 0x1500492a, 0x1509be55, 0x150c0a23 }, | ||
1339 | { 208, 0x15002ccc, 0x1500493a, 0x1509be55, 0x150c0a13 }, | ||
1340 | { 212, 0x15002ccc, 0x1500493e, 0x1509be55, 0x150c0a1b }, | ||
1341 | { 216, 0x15002ccc, 0x15004982, 0x1509be55, 0x150c0a23 }, | ||
1342 | }; | ||
1343 | |||
1344 | static int rt2800pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) | ||
1345 | { | ||
1346 | struct hw_mode_spec *spec = &rt2x00dev->spec; | ||
1347 | struct channel_info *info; | ||
1348 | char *tx_power1; | ||
1349 | char *tx_power2; | ||
1350 | unsigned int i; | ||
1351 | u16 eeprom; | ||
1352 | |||
1353 | /* | ||
1354 | * Initialize all hw fields. | ||
1355 | */ | ||
1356 | rt2x00dev->hw->flags = | ||
1357 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | | ||
1358 | IEEE80211_HW_SIGNAL_DBM | | ||
1359 | IEEE80211_HW_SUPPORTS_PS | | ||
1360 | IEEE80211_HW_PS_NULLFUNC_STACK; | ||
1361 | rt2x00dev->hw->extra_tx_headroom = TXWI_DESC_SIZE; | ||
1362 | |||
1363 | SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); | ||
1364 | SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, | ||
1365 | rt2x00_eeprom_addr(rt2x00dev, | ||
1366 | EEPROM_MAC_ADDR_0)); | ||
1367 | |||
1368 | rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); | ||
1369 | |||
1370 | /* | ||
1371 | * Initialize hw_mode information. | ||
1372 | */ | ||
1373 | spec->supported_bands = SUPPORT_BAND_2GHZ; | ||
1374 | spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; | ||
1375 | |||
1376 | if (rt2x00_rf(&rt2x00dev->chip, RF2820) || | ||
1377 | rt2x00_rf(&rt2x00dev->chip, RF2720) || | ||
1378 | rt2x00_rf(&rt2x00dev->chip, RF3020) || | ||
1379 | rt2x00_rf(&rt2x00dev->chip, RF3021) || | ||
1380 | rt2x00_rf(&rt2x00dev->chip, RF3022) || | ||
1381 | rt2x00_rf(&rt2x00dev->chip, RF2020) || | ||
1382 | rt2x00_rf(&rt2x00dev->chip, RF3052)) { | ||
1383 | spec->num_channels = 14; | ||
1384 | spec->channels = rf_vals; | ||
1385 | } else if (rt2x00_rf(&rt2x00dev->chip, RF2850) || | ||
1386 | rt2x00_rf(&rt2x00dev->chip, RF2750)) { | ||
1387 | spec->supported_bands |= SUPPORT_BAND_5GHZ; | ||
1388 | spec->num_channels = ARRAY_SIZE(rf_vals); | ||
1389 | spec->channels = rf_vals; | ||
1390 | } | ||
1391 | |||
1392 | /* | ||
1393 | * Initialize HT information. | ||
1394 | */ | ||
1395 | spec->ht.ht_supported = true; | ||
1396 | spec->ht.cap = | ||
1397 | IEEE80211_HT_CAP_SUP_WIDTH_20_40 | | ||
1398 | IEEE80211_HT_CAP_GRN_FLD | | ||
1399 | IEEE80211_HT_CAP_SGI_20 | | ||
1400 | IEEE80211_HT_CAP_SGI_40 | | ||
1401 | IEEE80211_HT_CAP_TX_STBC | | ||
1402 | IEEE80211_HT_CAP_RX_STBC | | ||
1403 | IEEE80211_HT_CAP_PSMP_SUPPORT; | ||
1404 | spec->ht.ampdu_factor = 3; | ||
1405 | spec->ht.ampdu_density = 4; | ||
1406 | spec->ht.mcs.tx_params = | ||
1407 | IEEE80211_HT_MCS_TX_DEFINED | | ||
1408 | IEEE80211_HT_MCS_TX_RX_DIFF | | ||
1409 | ((rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) - 1) << | ||
1410 | IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); | ||
1411 | |||
1412 | switch (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH)) { | ||
1413 | case 3: | ||
1414 | spec->ht.mcs.rx_mask[2] = 0xff; | ||
1415 | case 2: | ||
1416 | spec->ht.mcs.rx_mask[1] = 0xff; | ||
1417 | case 1: | ||
1418 | spec->ht.mcs.rx_mask[0] = 0xff; | ||
1419 | spec->ht.mcs.rx_mask[4] = 0x1; /* MCS32 */ | ||
1420 | break; | 1084 | break; |
1421 | } | 1085 | } |
1422 | 1086 | ||
1423 | /* | 1087 | return rt2800_validate_eeprom(rt2x00dev); |
1424 | * Create channel information array | ||
1425 | */ | ||
1426 | info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL); | ||
1427 | if (!info) | ||
1428 | return -ENOMEM; | ||
1429 | |||
1430 | spec->channels_info = info; | ||
1431 | |||
1432 | tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1); | ||
1433 | tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2); | ||
1434 | |||
1435 | for (i = 0; i < 14; i++) { | ||
1436 | info[i].tx_power1 = TXPOWER_G_FROM_DEV(tx_power1[i]); | ||
1437 | info[i].tx_power2 = TXPOWER_G_FROM_DEV(tx_power2[i]); | ||
1438 | } | ||
1439 | |||
1440 | if (spec->num_channels > 14) { | ||
1441 | tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A1); | ||
1442 | tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A2); | ||
1443 | |||
1444 | for (i = 14; i < spec->num_channels; i++) { | ||
1445 | info[i].tx_power1 = TXPOWER_A_FROM_DEV(tx_power1[i]); | ||
1446 | info[i].tx_power2 = TXPOWER_A_FROM_DEV(tx_power2[i]); | ||
1447 | } | ||
1448 | } | ||
1449 | |||
1450 | return 0; | ||
1451 | } | 1088 | } |
1452 | 1089 | ||
1453 | static const struct rt2800_ops rt2800pci_rt2800_ops = { | 1090 | static const struct rt2800_ops rt2800pci_rt2800_ops = { |
1454 | .register_read = rt2x00pci_register_read, | 1091 | .register_read = rt2x00pci_register_read, |
1092 | .register_read_lock = rt2x00pci_register_read, /* same for PCI */ | ||
1455 | .register_write = rt2x00pci_register_write, | 1093 | .register_write = rt2x00pci_register_write, |
1456 | .register_write_lock = rt2x00pci_register_write, /* same for PCI */ | 1094 | .register_write_lock = rt2x00pci_register_write, /* same for PCI */ |
1457 | 1095 | ||
@@ -1465,8 +1103,6 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev) | |||
1465 | { | 1103 | { |
1466 | int retval; | 1104 | int retval; |
1467 | 1105 | ||
1468 | rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI); | ||
1469 | |||
1470 | rt2x00dev->priv = (void *)&rt2800pci_rt2800_ops; | 1106 | rt2x00dev->priv = (void *)&rt2800pci_rt2800_ops; |
1471 | 1107 | ||
1472 | /* | 1108 | /* |
@@ -1476,14 +1112,14 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev) | |||
1476 | if (retval) | 1112 | if (retval) |
1477 | return retval; | 1113 | return retval; |
1478 | 1114 | ||
1479 | retval = rt2800pci_init_eeprom(rt2x00dev); | 1115 | retval = rt2800_init_eeprom(rt2x00dev); |
1480 | if (retval) | 1116 | if (retval) |
1481 | return retval; | 1117 | return retval; |
1482 | 1118 | ||
1483 | /* | 1119 | /* |
1484 | * Initialize hw specifications. | 1120 | * Initialize hw specifications. |
1485 | */ | 1121 | */ |
1486 | retval = rt2800pci_probe_hw_mode(rt2x00dev); | 1122 | retval = rt2800_probe_hw_mode(rt2x00dev); |
1487 | if (retval) | 1123 | if (retval) |
1488 | return retval; | 1124 | return retval; |
1489 | 1125 | ||
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.h b/drivers/net/wireless/rt2x00/rt2800pci.h index 1dbf13270cda..afc8e7da27cb 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.h +++ b/drivers/net/wireless/rt2x00/rt2800pci.h | |||
@@ -1,5 +1,12 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | Copyright (C) 2009 Alban Browaeys <prahal@yahoo.com> | ||
4 | Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org> | ||
5 | Copyright (C) 2009 Luis Correia <luis.f.correia@gmail.com> | ||
6 | Copyright (C) 2009 Mattias Nissler <mattias.nissler@gmx.de> | ||
7 | Copyright (C) 2009 Mark Asselstine <asselsm@gmail.com> | ||
8 | Copyright (C) 2009 Xose Vazquez Perez <xose.vazquez@gmail.com> | ||
9 | Copyright (C) 2009 Bart Zolnierkiewicz <bzolnier@gmail.com> | ||
3 | <http://rt2x00.serialmonkey.com> | 10 | <http://rt2x00.serialmonkey.com> |
4 | 11 | ||
5 | This program is free software; you can redistribute it and/or modify | 12 | This program is free software; you can redistribute it and/or modify |
@@ -56,34 +63,6 @@ | |||
56 | #define TX_DTX_IDX(__x) TX_DTX_IDX0 + ((__x) * TX_QUEUE_REG_OFFSET) | 63 | #define TX_DTX_IDX(__x) TX_DTX_IDX0 + ((__x) * TX_QUEUE_REG_OFFSET) |
57 | 64 | ||
58 | /* | 65 | /* |
59 | * EFUSE_CSR: RT3090 EEPROM | ||
60 | */ | ||
61 | #define EFUSE_CTRL 0x0580 | ||
62 | #define EFUSE_CTRL_ADDRESS_IN FIELD32(0x03fe0000) | ||
63 | #define EFUSE_CTRL_MODE FIELD32(0x000000c0) | ||
64 | #define EFUSE_CTRL_KICK FIELD32(0x40000000) | ||
65 | |||
66 | /* | ||
67 | * EFUSE_DATA0 | ||
68 | */ | ||
69 | #define EFUSE_DATA0 0x0590 | ||
70 | |||
71 | /* | ||
72 | * EFUSE_DATA1 | ||
73 | */ | ||
74 | #define EFUSE_DATA1 0x0594 | ||
75 | |||
76 | /* | ||
77 | * EFUSE_DATA2 | ||
78 | */ | ||
79 | #define EFUSE_DATA2 0x0598 | ||
80 | |||
81 | /* | ||
82 | * EFUSE_DATA3 | ||
83 | */ | ||
84 | #define EFUSE_DATA3 0x059c | ||
85 | |||
86 | /* | ||
87 | * 8051 firmware image. | 66 | * 8051 firmware image. |
88 | */ | 67 | */ |
89 | #define FIRMWARE_RT2860 "rt2860.bin" | 68 | #define FIRMWARE_RT2860 "rt2860.bin" |
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index ce2e893856c1..b1d63935f44d 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c | |||
@@ -1,5 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | Copyright (C) 2009 Mattias Nissler <mattias.nissler@gmx.de> | ||
4 | Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org> | ||
5 | Copyright (C) 2009 Xose Vazquez Perez <xose.vazquez@gmail.com> | ||
6 | Copyright (C) 2009 Axel Kollhofer <rain_maker@root-forum.org> | ||
3 | <http://rt2x00.serialmonkey.com> | 7 | <http://rt2x00.serialmonkey.com> |
4 | 8 | ||
5 | This program is free software; you can redistribute it and/or modify | 9 | This program is free software; you can redistribute it and/or modify |
@@ -594,16 +598,16 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry, | |||
594 | rt2x00_desc_read(rxwi, 2, &rxwi2); | 598 | rt2x00_desc_read(rxwi, 2, &rxwi2); |
595 | rt2x00_desc_read(rxwi, 3, &rxwi3); | 599 | rt2x00_desc_read(rxwi, 3, &rxwi3); |
596 | 600 | ||
597 | if (rt2x00_get_field32(rxd0, RXD_W0_CRC_ERROR)) | 601 | if (rt2x00_get_field32(rxd0, RXINFO_W0_CRC_ERROR)) |
598 | rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; | 602 | rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; |
599 | 603 | ||
600 | if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) { | 604 | if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) { |
601 | rxdesc->cipher = rt2x00_get_field32(rxwi0, RXWI_W0_UDF); | 605 | rxdesc->cipher = rt2x00_get_field32(rxwi0, RXWI_W0_UDF); |
602 | rxdesc->cipher_status = | 606 | rxdesc->cipher_status = |
603 | rt2x00_get_field32(rxd0, RXD_W0_CIPHER_ERROR); | 607 | rt2x00_get_field32(rxd0, RXINFO_W0_CIPHER_ERROR); |
604 | } | 608 | } |
605 | 609 | ||
606 | if (rt2x00_get_field32(rxd0, RXD_W0_DECRYPTED)) { | 610 | if (rt2x00_get_field32(rxd0, RXINFO_W0_DECRYPTED)) { |
607 | /* | 611 | /* |
608 | * Hardware has stripped IV/EIV data from 802.11 frame during | 612 | * Hardware has stripped IV/EIV data from 802.11 frame during |
609 | * decryption. Unfortunately the descriptor doesn't contain | 613 | * decryption. Unfortunately the descriptor doesn't contain |
@@ -618,10 +622,10 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry, | |||
618 | rxdesc->flags |= RX_FLAG_MMIC_ERROR; | 622 | rxdesc->flags |= RX_FLAG_MMIC_ERROR; |
619 | } | 623 | } |
620 | 624 | ||
621 | if (rt2x00_get_field32(rxd0, RXD_W0_MY_BSS)) | 625 | if (rt2x00_get_field32(rxd0, RXINFO_W0_MY_BSS)) |
622 | rxdesc->dev_flags |= RXDONE_MY_BSS; | 626 | rxdesc->dev_flags |= RXDONE_MY_BSS; |
623 | 627 | ||
624 | if (rt2x00_get_field32(rxd0, RXD_W0_L2PAD)) { | 628 | if (rt2x00_get_field32(rxd0, RXINFO_W0_L2PAD)) { |
625 | rxdesc->dev_flags |= RXDONE_L2PAD; | 629 | rxdesc->dev_flags |= RXDONE_L2PAD; |
626 | skbdesc->flags |= SKBDESC_L2_PADDED; | 630 | skbdesc->flags |= SKBDESC_L2_PADDED; |
627 | } | 631 | } |
@@ -667,400 +671,18 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry, | |||
667 | */ | 671 | */ |
668 | static int rt2800usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) | 672 | static int rt2800usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) |
669 | { | 673 | { |
670 | u16 word; | 674 | if (rt2800_efuse_detect(rt2x00dev)) |
671 | u8 *mac; | 675 | rt2800_read_eeprom_efuse(rt2x00dev); |
672 | u8 default_lna_gain; | 676 | else |
673 | 677 | rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom, | |
674 | rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom, EEPROM_SIZE); | 678 | EEPROM_SIZE); |
675 | |||
676 | /* | ||
677 | * Start validation of the data that has been read. | ||
678 | */ | ||
679 | mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); | ||
680 | if (!is_valid_ether_addr(mac)) { | ||
681 | random_ether_addr(mac); | ||
682 | EEPROM(rt2x00dev, "MAC: %pM\n", mac); | ||
683 | } | ||
684 | |||
685 | rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); | ||
686 | if (word == 0xffff) { | ||
687 | rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2); | ||
688 | rt2x00_set_field16(&word, EEPROM_ANTENNA_TXPATH, 1); | ||
689 | rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2820); | ||
690 | rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); | ||
691 | EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word); | ||
692 | } else if (rt2x00_rev(&rt2x00dev->chip) < RT2883_VERSION) { | ||
693 | /* | ||
694 | * There is a max of 2 RX streams for RT2870 series | ||
695 | */ | ||
696 | if (rt2x00_get_field16(word, EEPROM_ANTENNA_RXPATH) > 2) | ||
697 | rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2); | ||
698 | rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); | ||
699 | } | ||
700 | |||
701 | rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word); | ||
702 | if (word == 0xffff) { | ||
703 | rt2x00_set_field16(&word, EEPROM_NIC_HW_RADIO, 0); | ||
704 | rt2x00_set_field16(&word, EEPROM_NIC_DYNAMIC_TX_AGC, 0); | ||
705 | rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_BG, 0); | ||
706 | rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_A, 0); | ||
707 | rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0); | ||
708 | rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_BG, 0); | ||
709 | rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_A, 0); | ||
710 | rt2x00_set_field16(&word, EEPROM_NIC_WPS_PBC, 0); | ||
711 | rt2x00_set_field16(&word, EEPROM_NIC_BW40M_BG, 0); | ||
712 | rt2x00_set_field16(&word, EEPROM_NIC_BW40M_A, 0); | ||
713 | rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word); | ||
714 | EEPROM(rt2x00dev, "NIC: 0x%04x\n", word); | ||
715 | } | ||
716 | |||
717 | rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word); | ||
718 | if ((word & 0x00ff) == 0x00ff) { | ||
719 | rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0); | ||
720 | rt2x00_set_field16(&word, EEPROM_FREQ_LED_MODE, | ||
721 | LED_MODE_TXRX_ACTIVITY); | ||
722 | rt2x00_set_field16(&word, EEPROM_FREQ_LED_POLARITY, 0); | ||
723 | rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word); | ||
724 | rt2x00_eeprom_write(rt2x00dev, EEPROM_LED1, 0x5555); | ||
725 | rt2x00_eeprom_write(rt2x00dev, EEPROM_LED2, 0x2221); | ||
726 | rt2x00_eeprom_write(rt2x00dev, EEPROM_LED3, 0xa9f8); | ||
727 | EEPROM(rt2x00dev, "Freq: 0x%04x\n", word); | ||
728 | } | ||
729 | |||
730 | /* | ||
731 | * During the LNA validation we are going to use | ||
732 | * lna0 as correct value. Note that EEPROM_LNA | ||
733 | * is never validated. | ||
734 | */ | ||
735 | rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &word); | ||
736 | default_lna_gain = rt2x00_get_field16(word, EEPROM_LNA_A0); | ||
737 | |||
738 | rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &word); | ||
739 | if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET0)) > 10) | ||
740 | rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET0, 0); | ||
741 | if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET1)) > 10) | ||
742 | rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET1, 0); | ||
743 | rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG, word); | ||
744 | |||
745 | rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &word); | ||
746 | if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG2_OFFSET2)) > 10) | ||
747 | rt2x00_set_field16(&word, EEPROM_RSSI_BG2_OFFSET2, 0); | ||
748 | if (rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0x00 || | ||
749 | rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0xff) | ||
750 | rt2x00_set_field16(&word, EEPROM_RSSI_BG2_LNA_A1, | ||
751 | default_lna_gain); | ||
752 | rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG2, word); | ||
753 | |||
754 | rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &word); | ||
755 | if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET0)) > 10) | ||
756 | rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET0, 0); | ||
757 | if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET1)) > 10) | ||
758 | rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET1, 0); | ||
759 | rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A, word); | ||
760 | |||
761 | rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &word); | ||
762 | if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A2_OFFSET2)) > 10) | ||
763 | rt2x00_set_field16(&word, EEPROM_RSSI_A2_OFFSET2, 0); | ||
764 | if (rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0x00 || | ||
765 | rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0xff) | ||
766 | rt2x00_set_field16(&word, EEPROM_RSSI_A2_LNA_A2, | ||
767 | default_lna_gain); | ||
768 | rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word); | ||
769 | |||
770 | return 0; | ||
771 | } | ||
772 | |||
773 | static int rt2800usb_init_eeprom(struct rt2x00_dev *rt2x00dev) | ||
774 | { | ||
775 | u32 reg; | ||
776 | u16 value; | ||
777 | u16 eeprom; | ||
778 | |||
779 | /* | ||
780 | * Read EEPROM word for configuration. | ||
781 | */ | ||
782 | rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); | ||
783 | |||
784 | /* | ||
785 | * Identify RF chipset. | ||
786 | */ | ||
787 | value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); | ||
788 | rt2800_register_read(rt2x00dev, MAC_CSR0, ®); | ||
789 | rt2x00_set_chip(rt2x00dev, RT2870, value, reg); | ||
790 | |||
791 | /* | ||
792 | * The check for rt2860 is not a typo, some rt2870 hardware | ||
793 | * identifies itself as rt2860 in the CSR register. | ||
794 | */ | ||
795 | if (!rt2x00_check_rev(&rt2x00dev->chip, 0xfff00000, 0x28600000) && | ||
796 | !rt2x00_check_rev(&rt2x00dev->chip, 0xfff00000, 0x28700000) && | ||
797 | !rt2x00_check_rev(&rt2x00dev->chip, 0xfff00000, 0x28800000) && | ||
798 | !rt2x00_check_rev(&rt2x00dev->chip, 0xffff0000, 0x30700000)) { | ||
799 | ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); | ||
800 | return -ENODEV; | ||
801 | } | ||
802 | |||
803 | if (!rt2x00_rf(&rt2x00dev->chip, RF2820) && | ||
804 | !rt2x00_rf(&rt2x00dev->chip, RF2850) && | ||
805 | !rt2x00_rf(&rt2x00dev->chip, RF2720) && | ||
806 | !rt2x00_rf(&rt2x00dev->chip, RF2750) && | ||
807 | !rt2x00_rf(&rt2x00dev->chip, RF3020) && | ||
808 | !rt2x00_rf(&rt2x00dev->chip, RF2020)) { | ||
809 | ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); | ||
810 | return -ENODEV; | ||
811 | } | ||
812 | |||
813 | /* | ||
814 | * Identify default antenna configuration. | ||
815 | */ | ||
816 | rt2x00dev->default_ant.tx = | ||
817 | rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH); | ||
818 | rt2x00dev->default_ant.rx = | ||
819 | rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH); | ||
820 | |||
821 | /* | ||
822 | * Read frequency offset and RF programming sequence. | ||
823 | */ | ||
824 | rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); | ||
825 | rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); | ||
826 | |||
827 | /* | ||
828 | * Read external LNA informations. | ||
829 | */ | ||
830 | rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); | ||
831 | |||
832 | if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A)) | ||
833 | __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); | ||
834 | if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG)) | ||
835 | __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); | ||
836 | |||
837 | /* | ||
838 | * Detect if this device has an hardware controlled radio. | ||
839 | */ | ||
840 | if (rt2x00_get_field16(eeprom, EEPROM_NIC_HW_RADIO)) | ||
841 | __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); | ||
842 | |||
843 | /* | ||
844 | * Store led settings, for correct led behaviour. | ||
845 | */ | ||
846 | #ifdef CONFIG_RT2X00_LIB_LEDS | ||
847 | rt2800_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); | ||
848 | rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC); | ||
849 | rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY); | ||
850 | |||
851 | rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, | ||
852 | &rt2x00dev->led_mcu_reg); | ||
853 | #endif /* CONFIG_RT2X00_LIB_LEDS */ | ||
854 | |||
855 | return 0; | ||
856 | } | ||
857 | |||
858 | /* | ||
859 | * RF value list for rt2870 | ||
860 | * Supports: 2.4 GHz (all) & 5.2 GHz (RF2850 & RF2750) | ||
861 | */ | ||
862 | static const struct rf_channel rf_vals[] = { | ||
863 | { 1, 0x18402ecc, 0x184c0786, 0x1816b455, 0x1800510b }, | ||
864 | { 2, 0x18402ecc, 0x184c0786, 0x18168a55, 0x1800519f }, | ||
865 | { 3, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800518b }, | ||
866 | { 4, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800519f }, | ||
867 | { 5, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800518b }, | ||
868 | { 6, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800519f }, | ||
869 | { 7, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800518b }, | ||
870 | { 8, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800519f }, | ||
871 | { 9, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800518b }, | ||
872 | { 10, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800519f }, | ||
873 | { 11, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800518b }, | ||
874 | { 12, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800519f }, | ||
875 | { 13, 0x18402ecc, 0x184c079e, 0x18168a55, 0x1800518b }, | ||
876 | { 14, 0x18402ecc, 0x184c07a2, 0x18168a55, 0x18005193 }, | ||
877 | |||
878 | /* 802.11 UNI / HyperLan 2 */ | ||
879 | { 36, 0x18402ecc, 0x184c099a, 0x18158a55, 0x180ed1a3 }, | ||
880 | { 38, 0x18402ecc, 0x184c099e, 0x18158a55, 0x180ed193 }, | ||
881 | { 40, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed183 }, | ||
882 | { 44, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed1a3 }, | ||
883 | { 46, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed18b }, | ||
884 | { 48, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed19b }, | ||
885 | { 52, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed193 }, | ||
886 | { 54, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed1a3 }, | ||
887 | { 56, 0x18402ec8, 0x184c068e, 0x18158a55, 0x180ed18b }, | ||
888 | { 60, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed183 }, | ||
889 | { 62, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed193 }, | ||
890 | { 64, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed1a3 }, | ||
891 | |||
892 | /* 802.11 HyperLan 2 */ | ||
893 | { 100, 0x18402ec8, 0x184c06b2, 0x18178a55, 0x180ed783 }, | ||
894 | { 102, 0x18402ec8, 0x184c06b2, 0x18578a55, 0x180ed793 }, | ||
895 | { 104, 0x18402ec8, 0x185c06b2, 0x18578a55, 0x180ed1a3 }, | ||
896 | { 108, 0x18402ecc, 0x185c0a32, 0x18578a55, 0x180ed193 }, | ||
897 | { 110, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed183 }, | ||
898 | { 112, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed19b }, | ||
899 | { 116, 0x18402ecc, 0x184c0a3a, 0x18178a55, 0x180ed1a3 }, | ||
900 | { 118, 0x18402ecc, 0x184c0a3e, 0x18178a55, 0x180ed193 }, | ||
901 | { 120, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed183 }, | ||
902 | { 124, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed193 }, | ||
903 | { 126, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed15b }, | ||
904 | { 128, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed1a3 }, | ||
905 | { 132, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed18b }, | ||
906 | { 134, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed193 }, | ||
907 | { 136, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed19b }, | ||
908 | { 140, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed183 }, | ||
909 | |||
910 | /* 802.11 UNII */ | ||
911 | { 149, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed1a7 }, | ||
912 | { 151, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed187 }, | ||
913 | { 153, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed18f }, | ||
914 | { 157, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed19f }, | ||
915 | { 159, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed1a7 }, | ||
916 | { 161, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed187 }, | ||
917 | { 165, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed197 }, | ||
918 | { 167, 0x18402ec4, 0x184c03d2, 0x18179855, 0x1815531f }, | ||
919 | { 169, 0x18402ec4, 0x184c03d2, 0x18179855, 0x18155327 }, | ||
920 | { 171, 0x18402ec4, 0x184c03d6, 0x18179855, 0x18155307 }, | ||
921 | { 173, 0x18402ec4, 0x184c03d6, 0x18179855, 0x1815530f }, | ||
922 | |||
923 | /* 802.11 Japan */ | ||
924 | { 184, 0x15002ccc, 0x1500491e, 0x1509be55, 0x150c0a0b }, | ||
925 | { 188, 0x15002ccc, 0x15004922, 0x1509be55, 0x150c0a13 }, | ||
926 | { 192, 0x15002ccc, 0x15004926, 0x1509be55, 0x150c0a1b }, | ||
927 | { 196, 0x15002ccc, 0x1500492a, 0x1509be55, 0x150c0a23 }, | ||
928 | { 208, 0x15002ccc, 0x1500493a, 0x1509be55, 0x150c0a13 }, | ||
929 | { 212, 0x15002ccc, 0x1500493e, 0x1509be55, 0x150c0a1b }, | ||
930 | { 216, 0x15002ccc, 0x15004982, 0x1509be55, 0x150c0a23 }, | ||
931 | }; | ||
932 | |||
933 | /* | ||
934 | * RF value list for rt3070 | ||
935 | * Supports: 2.4 GHz | ||
936 | */ | ||
937 | static const struct rf_channel rf_vals_3070[] = { | ||
938 | {1, 241, 2, 2 }, | ||
939 | {2, 241, 2, 7 }, | ||
940 | {3, 242, 2, 2 }, | ||
941 | {4, 242, 2, 7 }, | ||
942 | {5, 243, 2, 2 }, | ||
943 | {6, 243, 2, 7 }, | ||
944 | {7, 244, 2, 2 }, | ||
945 | {8, 244, 2, 7 }, | ||
946 | {9, 245, 2, 2 }, | ||
947 | {10, 245, 2, 7 }, | ||
948 | {11, 246, 2, 2 }, | ||
949 | {12, 246, 2, 7 }, | ||
950 | {13, 247, 2, 2 }, | ||
951 | {14, 248, 2, 4 }, | ||
952 | }; | ||
953 | |||
954 | static int rt2800usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) | ||
955 | { | ||
956 | struct hw_mode_spec *spec = &rt2x00dev->spec; | ||
957 | struct channel_info *info; | ||
958 | char *tx_power1; | ||
959 | char *tx_power2; | ||
960 | unsigned int i; | ||
961 | u16 eeprom; | ||
962 | |||
963 | /* | ||
964 | * Initialize all hw fields. | ||
965 | */ | ||
966 | rt2x00dev->hw->flags = | ||
967 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | | ||
968 | IEEE80211_HW_SIGNAL_DBM | | ||
969 | IEEE80211_HW_SUPPORTS_PS | | ||
970 | IEEE80211_HW_PS_NULLFUNC_STACK; | ||
971 | rt2x00dev->hw->extra_tx_headroom = TXINFO_DESC_SIZE + TXWI_DESC_SIZE; | ||
972 | |||
973 | SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); | ||
974 | SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, | ||
975 | rt2x00_eeprom_addr(rt2x00dev, | ||
976 | EEPROM_MAC_ADDR_0)); | ||
977 | |||
978 | rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); | ||
979 | |||
980 | /* | ||
981 | * Initialize HT information. | ||
982 | */ | ||
983 | spec->ht.ht_supported = true; | ||
984 | spec->ht.cap = | ||
985 | IEEE80211_HT_CAP_SUP_WIDTH_20_40 | | ||
986 | IEEE80211_HT_CAP_GRN_FLD | | ||
987 | IEEE80211_HT_CAP_SGI_20 | | ||
988 | IEEE80211_HT_CAP_SGI_40 | | ||
989 | IEEE80211_HT_CAP_TX_STBC | | ||
990 | IEEE80211_HT_CAP_RX_STBC | | ||
991 | IEEE80211_HT_CAP_PSMP_SUPPORT; | ||
992 | spec->ht.ampdu_factor = 3; | ||
993 | spec->ht.ampdu_density = 4; | ||
994 | spec->ht.mcs.tx_params = | ||
995 | IEEE80211_HT_MCS_TX_DEFINED | | ||
996 | IEEE80211_HT_MCS_TX_RX_DIFF | | ||
997 | ((rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) - 1) << | ||
998 | IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); | ||
999 | |||
1000 | switch (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH)) { | ||
1001 | case 3: | ||
1002 | spec->ht.mcs.rx_mask[2] = 0xff; | ||
1003 | case 2: | ||
1004 | spec->ht.mcs.rx_mask[1] = 0xff; | ||
1005 | case 1: | ||
1006 | spec->ht.mcs.rx_mask[0] = 0xff; | ||
1007 | spec->ht.mcs.rx_mask[4] = 0x1; /* MCS32 */ | ||
1008 | break; | ||
1009 | } | ||
1010 | |||
1011 | /* | ||
1012 | * Initialize hw_mode information. | ||
1013 | */ | ||
1014 | spec->supported_bands = SUPPORT_BAND_2GHZ; | ||
1015 | spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; | ||
1016 | |||
1017 | if (rt2x00_rf(&rt2x00dev->chip, RF2820) || | ||
1018 | rt2x00_rf(&rt2x00dev->chip, RF2720)) { | ||
1019 | spec->num_channels = 14; | ||
1020 | spec->channels = rf_vals; | ||
1021 | } else if (rt2x00_rf(&rt2x00dev->chip, RF2850) || | ||
1022 | rt2x00_rf(&rt2x00dev->chip, RF2750)) { | ||
1023 | spec->supported_bands |= SUPPORT_BAND_5GHZ; | ||
1024 | spec->num_channels = ARRAY_SIZE(rf_vals); | ||
1025 | spec->channels = rf_vals; | ||
1026 | } else if (rt2x00_rf(&rt2x00dev->chip, RF3020) || | ||
1027 | rt2x00_rf(&rt2x00dev->chip, RF2020)) { | ||
1028 | spec->num_channels = ARRAY_SIZE(rf_vals_3070); | ||
1029 | spec->channels = rf_vals_3070; | ||
1030 | } | ||
1031 | |||
1032 | /* | ||
1033 | * Create channel information array | ||
1034 | */ | ||
1035 | info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL); | ||
1036 | if (!info) | ||
1037 | return -ENOMEM; | ||
1038 | |||
1039 | spec->channels_info = info; | ||
1040 | |||
1041 | tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1); | ||
1042 | tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2); | ||
1043 | |||
1044 | for (i = 0; i < 14; i++) { | ||
1045 | info[i].tx_power1 = TXPOWER_G_FROM_DEV(tx_power1[i]); | ||
1046 | info[i].tx_power2 = TXPOWER_G_FROM_DEV(tx_power2[i]); | ||
1047 | } | ||
1048 | |||
1049 | if (spec->num_channels > 14) { | ||
1050 | tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A1); | ||
1051 | tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A2); | ||
1052 | |||
1053 | for (i = 14; i < spec->num_channels; i++) { | ||
1054 | info[i].tx_power1 = TXPOWER_A_FROM_DEV(tx_power1[i]); | ||
1055 | info[i].tx_power2 = TXPOWER_A_FROM_DEV(tx_power2[i]); | ||
1056 | } | ||
1057 | } | ||
1058 | 679 | ||
1059 | return 0; | 680 | return rt2800_validate_eeprom(rt2x00dev); |
1060 | } | 681 | } |
1061 | 682 | ||
1062 | static const struct rt2800_ops rt2800usb_rt2800_ops = { | 683 | static const struct rt2800_ops rt2800usb_rt2800_ops = { |
1063 | .register_read = rt2x00usb_register_read, | 684 | .register_read = rt2x00usb_register_read, |
685 | .register_read_lock = rt2x00usb_register_read_lock, | ||
1064 | .register_write = rt2x00usb_register_write, | 686 | .register_write = rt2x00usb_register_write, |
1065 | .register_write_lock = rt2x00usb_register_write_lock, | 687 | .register_write_lock = rt2x00usb_register_write_lock, |
1066 | 688 | ||
@@ -1074,8 +696,6 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) | |||
1074 | { | 696 | { |
1075 | int retval; | 697 | int retval; |
1076 | 698 | ||
1077 | rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_USB); | ||
1078 | |||
1079 | rt2x00dev->priv = (void *)&rt2800usb_rt2800_ops; | 699 | rt2x00dev->priv = (void *)&rt2800usb_rt2800_ops; |
1080 | 700 | ||
1081 | /* | 701 | /* |
@@ -1085,14 +705,14 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) | |||
1085 | if (retval) | 705 | if (retval) |
1086 | return retval; | 706 | return retval; |
1087 | 707 | ||
1088 | retval = rt2800usb_init_eeprom(rt2x00dev); | 708 | retval = rt2800_init_eeprom(rt2x00dev); |
1089 | if (retval) | 709 | if (retval) |
1090 | return retval; | 710 | return retval; |
1091 | 711 | ||
1092 | /* | 712 | /* |
1093 | * Initialize hw specifications. | 713 | * Initialize hw specifications. |
1094 | */ | 714 | */ |
1095 | retval = rt2800usb_probe_hw_mode(rt2x00dev); | 715 | retval = rt2800_probe_hw_mode(rt2x00dev); |
1096 | if (retval) | 716 | if (retval) |
1097 | return retval; | 717 | return retval; |
1098 | 718 | ||
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h index c9d7d40ee5fb..1e4340a182ef 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.h +++ b/drivers/net/wireless/rt2x00/rt2800usb.h | |||
@@ -1,5 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | Copyright (C) 2009 Mattias Nissler <mattias.nissler@gmx.de> | ||
4 | Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org> | ||
5 | Copyright (C) 2009 Xose Vazquez Perez <xose.vazquez@gmail.com> | ||
6 | Copyright (C) 2009 Axel Kollhofer <rain_maker@root-forum.org> | ||
3 | <http://rt2x00.serialmonkey.com> | 7 | <http://rt2x00.serialmonkey.com> |
4 | 8 | ||
5 | This program is free software; you can redistribute it and/or modify | 9 | This program is free software; you can redistribute it and/or modify |
@@ -111,25 +115,25 @@ | |||
111 | * AMSDU: rx with 802.3 header, not 802.11 header. | 115 | * AMSDU: rx with 802.3 header, not 802.11 header. |
112 | */ | 116 | */ |
113 | 117 | ||
114 | #define RXD_W0_BA FIELD32(0x00000001) | 118 | #define RXINFO_W0_BA FIELD32(0x00000001) |
115 | #define RXD_W0_DATA FIELD32(0x00000002) | 119 | #define RXINFO_W0_DATA FIELD32(0x00000002) |
116 | #define RXD_W0_NULLDATA FIELD32(0x00000004) | 120 | #define RXINFO_W0_NULLDATA FIELD32(0x00000004) |
117 | #define RXD_W0_FRAG FIELD32(0x00000008) | 121 | #define RXINFO_W0_FRAG FIELD32(0x00000008) |
118 | #define RXD_W0_UNICAST_TO_ME FIELD32(0x00000010) | 122 | #define RXINFO_W0_UNICAST_TO_ME FIELD32(0x00000010) |
119 | #define RXD_W0_MULTICAST FIELD32(0x00000020) | 123 | #define RXINFO_W0_MULTICAST FIELD32(0x00000020) |
120 | #define RXD_W0_BROADCAST FIELD32(0x00000040) | 124 | #define RXINFO_W0_BROADCAST FIELD32(0x00000040) |
121 | #define RXD_W0_MY_BSS FIELD32(0x00000080) | 125 | #define RXINFO_W0_MY_BSS FIELD32(0x00000080) |
122 | #define RXD_W0_CRC_ERROR FIELD32(0x00000100) | 126 | #define RXINFO_W0_CRC_ERROR FIELD32(0x00000100) |
123 | #define RXD_W0_CIPHER_ERROR FIELD32(0x00000600) | 127 | #define RXINFO_W0_CIPHER_ERROR FIELD32(0x00000600) |
124 | #define RXD_W0_AMSDU FIELD32(0x00000800) | 128 | #define RXINFO_W0_AMSDU FIELD32(0x00000800) |
125 | #define RXD_W0_HTC FIELD32(0x00001000) | 129 | #define RXINFO_W0_HTC FIELD32(0x00001000) |
126 | #define RXD_W0_RSSI FIELD32(0x00002000) | 130 | #define RXINFO_W0_RSSI FIELD32(0x00002000) |
127 | #define RXD_W0_L2PAD FIELD32(0x00004000) | 131 | #define RXINFO_W0_L2PAD FIELD32(0x00004000) |
128 | #define RXD_W0_AMPDU FIELD32(0x00008000) | 132 | #define RXINFO_W0_AMPDU FIELD32(0x00008000) |
129 | #define RXD_W0_DECRYPTED FIELD32(0x00010000) | 133 | #define RXINFO_W0_DECRYPTED FIELD32(0x00010000) |
130 | #define RXD_W0_PLCP_RSSI FIELD32(0x00020000) | 134 | #define RXINFO_W0_PLCP_RSSI FIELD32(0x00020000) |
131 | #define RXD_W0_CIPHER_ALG FIELD32(0x00040000) | 135 | #define RXINFO_W0_CIPHER_ALG FIELD32(0x00040000) |
132 | #define RXD_W0_LAST_AMSDU FIELD32(0x00080000) | 136 | #define RXINFO_W0_LAST_AMSDU FIELD32(0x00080000) |
133 | #define RXD_W0_PLCP_SIGNAL FIELD32(0xfff00000) | 137 | #define RXINFO_W0_PLCP_SIGNAL FIELD32(0xfff00000) |
134 | 138 | ||
135 | #endif /* RT2800USB_H */ | 139 | #endif /* RT2800USB_H */ |
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index c83dbaefd57a..1cbb7ac2f32f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | Copyright (C) 2004 - 2009 Gertjan van Wingerde <gwingerde@gmail.com> | ||
3 | <http://rt2x00.serialmonkey.com> | 4 | <http://rt2x00.serialmonkey.com> |
4 | 5 | ||
5 | This program is free software; you can redistribute it and/or modify | 6 | This program is free software; you can redistribute it and/or modify |
@@ -171,6 +172,7 @@ struct rt2x00_chip { | |||
171 | #define RT3052 0x3052 /* WSOC */ | 172 | #define RT3052 0x3052 /* WSOC */ |
172 | #define RT3090 0x3090 /* 2.4GHz PCIe */ | 173 | #define RT3090 0x3090 /* 2.4GHz PCIe */ |
173 | #define RT2870 0x1600 | 174 | #define RT2870 0x1600 |
175 | #define RT3070 0x1800 | ||
174 | 176 | ||
175 | u16 rf; | 177 | u16 rf; |
176 | u32 rev; | 178 | u32 rev; |
@@ -313,13 +315,6 @@ struct link { | |||
313 | struct avg_val avg_rssi; | 315 | struct avg_val avg_rssi; |
314 | 316 | ||
315 | /* | 317 | /* |
316 | * Currently precalculated percentages of successful | ||
317 | * TX and RX frames. | ||
318 | */ | ||
319 | int rx_percentage; | ||
320 | int tx_percentage; | ||
321 | |||
322 | /* | ||
323 | * Work structure for scheduling periodic link tuning. | 318 | * Work structure for scheduling periodic link tuning. |
324 | */ | 319 | */ |
325 | struct delayed_work work; | 320 | struct delayed_work work; |
@@ -911,10 +906,6 @@ static inline void rt2x00_eeprom_write(struct rt2x00_dev *rt2x00dev, | |||
911 | static inline void rt2x00_set_chip(struct rt2x00_dev *rt2x00dev, | 906 | static inline void rt2x00_set_chip(struct rt2x00_dev *rt2x00dev, |
912 | const u16 rt, const u16 rf, const u32 rev) | 907 | const u16 rt, const u16 rf, const u32 rev) |
913 | { | 908 | { |
914 | INFO(rt2x00dev, | ||
915 | "Chipset detected - rt: %04x, rf: %04x, rev: %08x.\n", | ||
916 | rt, rf, rev); | ||
917 | |||
918 | rt2x00dev->chip.rt = rt; | 909 | rt2x00dev->chip.rt = rt; |
919 | rt2x00dev->chip.rf = rf; | 910 | rt2x00dev->chip.rf = rf; |
920 | rt2x00dev->chip.rev = rev; | 911 | rt2x00dev->chip.rev = rev; |
@@ -932,6 +923,13 @@ static inline void rt2x00_set_chip_rf(struct rt2x00_dev *rt2x00dev, | |||
932 | rt2x00_set_chip(rt2x00dev, rt2x00dev->chip.rt, rf, rev); | 923 | rt2x00_set_chip(rt2x00dev, rt2x00dev->chip.rt, rf, rev); |
933 | } | 924 | } |
934 | 925 | ||
926 | static inline void rt2x00_print_chip(struct rt2x00_dev *rt2x00dev) | ||
927 | { | ||
928 | INFO(rt2x00dev, | ||
929 | "Chipset detected - rt: %04x, rf: %04x, rev: %08x.\n", | ||
930 | rt2x00dev->chip.rt, rt2x00dev->chip.rf, rt2x00dev->chip.rev); | ||
931 | } | ||
932 | |||
935 | static inline char rt2x00_rt(const struct rt2x00_chip *chipset, const u16 chip) | 933 | static inline char rt2x00_rt(const struct rt2x00_chip *chipset, const u16 chip) |
936 | { | 934 | { |
937 | return (chipset->rt == chip); | 935 | return (chipset->rt == chip); |
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 40a201e2e151..098315a271ca 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | <http://rt2x00.serialmonkey.com> | 3 | <http://rt2x00.serialmonkey.com> |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify | 5 | This program is free software; you can redistribute it and/or modify |
diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c index de36837dcf86..d291c7862e10 100644 --- a/drivers/net/wireless/rt2x00/rt2x00crypto.c +++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | <http://rt2x00.serialmonkey.com> | 3 | <http://rt2x00.serialmonkey.com> |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify | 5 | This program is free software; you can redistribute it and/or modify |
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index 7b3ee8c2eaef..e6b0fbbc3fc7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | <http://rt2x00.serialmonkey.com> | 3 | <http://rt2x00.serialmonkey.com> |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify | 5 | This program is free software; you can redistribute it and/or modify |
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.h b/drivers/net/wireless/rt2x00/rt2x00debug.h index 035cbc98c593..fa11409cb5c6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.h +++ b/drivers/net/wireless/rt2x00/rt2x00debug.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | <http://rt2x00.serialmonkey.com> | 3 | <http://rt2x00.serialmonkey.com> |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify | 5 | This program is free software; you can redistribute it and/or modify |
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 73bbec58341e..6c6d0ac35549 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | <http://rt2x00.serialmonkey.com> | 3 | <http://rt2x00.serialmonkey.com> |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify | 5 | This program is free software; you can redistribute it and/or modify |
@@ -430,7 +430,6 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, | |||
430 | 430 | ||
431 | rx_status->mactime = rxdesc.timestamp; | 431 | rx_status->mactime = rxdesc.timestamp; |
432 | rx_status->rate_idx = rate_idx; | 432 | rx_status->rate_idx = rate_idx; |
433 | rx_status->qual = rt2x00link_calculate_signal(rt2x00dev, rxdesc.rssi); | ||
434 | rx_status->signal = rxdesc.rssi; | 433 | rx_status->signal = rxdesc.rssi; |
435 | rx_status->noise = rxdesc.noise; | 434 | rx_status->noise = rxdesc.noise; |
436 | rx_status->flag = rxdesc.flags; | 435 | rx_status->flag = rxdesc.flags; |
diff --git a/drivers/net/wireless/rt2x00/rt2x00dump.h b/drivers/net/wireless/rt2x00/rt2x00dump.h index fdedb5122928..727019a748e7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dump.h +++ b/drivers/net/wireless/rt2x00/rt2x00dump.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | <http://rt2x00.serialmonkey.com> | 3 | <http://rt2x00.serialmonkey.com> |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify | 5 | This program is free software; you can redistribute it and/or modify |
diff --git a/drivers/net/wireless/rt2x00/rt2x00firmware.c b/drivers/net/wireless/rt2x00/rt2x00firmware.c index d2deea2f2679..34beb00c4347 100644 --- a/drivers/net/wireless/rt2x00/rt2x00firmware.c +++ b/drivers/net/wireless/rt2x00/rt2x00firmware.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | Copyright (C) 2004 - 2009 Gertjan van Wingerde <gwingerde@gmail.com> | ||
3 | <http://rt2x00.serialmonkey.com> | 4 | <http://rt2x00.serialmonkey.com> |
4 | 5 | ||
5 | This program is free software; you can redistribute it and/or modify | 6 | This program is free software; you can redistribute it and/or modify |
diff --git a/drivers/net/wireless/rt2x00/rt2x00ht.c b/drivers/net/wireless/rt2x00/rt2x00ht.c index e3cec839e540..1056c92143a8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00ht.c +++ b/drivers/net/wireless/rt2x00/rt2x00ht.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | <http://rt2x00.serialmonkey.com> | 3 | <http://rt2x00.serialmonkey.com> |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify | 5 | This program is free software; you can redistribute it and/or modify |
diff --git a/drivers/net/wireless/rt2x00/rt2x00leds.c b/drivers/net/wireless/rt2x00/rt2x00leds.c index 49671fed91d7..ca585e34d00e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00leds.c +++ b/drivers/net/wireless/rt2x00/rt2x00leds.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | <http://rt2x00.serialmonkey.com> | 3 | <http://rt2x00.serialmonkey.com> |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify | 5 | This program is free software; you can redistribute it and/or modify |
diff --git a/drivers/net/wireless/rt2x00/rt2x00leds.h b/drivers/net/wireless/rt2x00/rt2x00leds.h index 8e03c045e037..3b46f0c3332a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00leds.h +++ b/drivers/net/wireless/rt2x00/rt2x00leds.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | <http://rt2x00.serialmonkey.com> | 3 | <http://rt2x00.serialmonkey.com> |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify | 5 | This program is free software; you can redistribute it and/or modify |
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 567f029a8cda..c1f48acaee41 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | Copyright (C) 2004 - 2009 Gertjan van Wingerde <gwingerde@gmail.com> | ||
3 | <http://rt2x00.serialmonkey.com> | 4 | <http://rt2x00.serialmonkey.com> |
4 | 5 | ||
5 | This program is free software; you can redistribute it and/or modify | 6 | This program is free software; you can redistribute it and/or modify |
@@ -223,19 +224,6 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev, | |||
223 | struct rxdone_entry_desc *rxdesc); | 224 | struct rxdone_entry_desc *rxdesc); |
224 | 225 | ||
225 | /** | 226 | /** |
226 | * rt2x00link_calculate_signal - Calculate signal quality | ||
227 | * @rt2x00dev: Pointer to &struct rt2x00_dev. | ||
228 | * @rssi: RX Frame RSSI | ||
229 | * | ||
230 | * Calculate the signal quality of a frame based on the rssi | ||
231 | * measured during the receiving of the frame and the global | ||
232 | * link quality statistics measured since the start of the | ||
233 | * link tuning. The result is a value between 0 and 100 which | ||
234 | * is an indication of the signal quality. | ||
235 | */ | ||
236 | int rt2x00link_calculate_signal(struct rt2x00_dev *rt2x00dev, int rssi); | ||
237 | |||
238 | /** | ||
239 | * rt2x00link_start_tuner - Start periodic link tuner work | 227 | * rt2x00link_start_tuner - Start periodic link tuner work |
240 | * @rt2x00dev: Pointer to &struct rt2x00_dev. | 228 | * @rt2x00dev: Pointer to &struct rt2x00_dev. |
241 | * | 229 | * |
diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index c708d0be9155..0efbf5a6c254 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | <http://rt2x00.serialmonkey.com> | 3 | <http://rt2x00.serialmonkey.com> |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify | 5 | This program is free software; you can redistribute it and/or modify |
@@ -36,24 +36,6 @@ | |||
36 | #define DEFAULT_RSSI -128 | 36 | #define DEFAULT_RSSI -128 |
37 | 37 | ||
38 | /* | 38 | /* |
39 | * When no TX/RX percentage could be calculated due to lack of | ||
40 | * frames on the air, we fallback to a percentage of 50%. | ||
41 | * This will assure we will get at least get some decent value | ||
42 | * when the link tuner starts. | ||
43 | * The value will be dropped and overwritten with the correct (measured) | ||
44 | * value anyway during the first run of the link tuner. | ||
45 | */ | ||
46 | #define DEFAULT_PERCENTAGE 50 | ||
47 | |||
48 | /* | ||
49 | * Small helper macro for percentage calculation | ||
50 | * This is a very simple macro with the only catch that it will | ||
51 | * produce a default value in case no total value was provided. | ||
52 | */ | ||
53 | #define PERCENTAGE(__value, __total) \ | ||
54 | ( (__total) ? (((__value) * 100) / (__total)) : (DEFAULT_PERCENTAGE) ) | ||
55 | |||
56 | /* | ||
57 | * Helper struct and macro to work with moving/walking averages. | 39 | * Helper struct and macro to work with moving/walking averages. |
58 | * When adding a value to the average value the following calculation | 40 | * When adding a value to the average value the following calculation |
59 | * is needed: | 41 | * is needed: |
@@ -91,27 +73,6 @@ | |||
91 | __new; \ | 73 | __new; \ |
92 | }) | 74 | }) |
93 | 75 | ||
94 | /* | ||
95 | * For calculating the Signal quality we have determined | ||
96 | * the total number of success and failed RX and TX frames. | ||
97 | * With the addition of the average RSSI value we can determine | ||
98 | * the link quality using the following algorithm: | ||
99 | * | ||
100 | * rssi_percentage = (avg_rssi * 100) / rssi_offset | ||
101 | * rx_percentage = (rx_success * 100) / rx_total | ||
102 | * tx_percentage = (tx_success * 100) / tx_total | ||
103 | * avg_signal = ((WEIGHT_RSSI * avg_rssi) + | ||
104 | * (WEIGHT_TX * tx_percentage) + | ||
105 | * (WEIGHT_RX * rx_percentage)) / 100 | ||
106 | * | ||
107 | * This value should then be checked to not be greater then 100. | ||
108 | * This means the values of WEIGHT_RSSI, WEIGHT_RX, WEIGHT_TX must | ||
109 | * sum up to 100 as well. | ||
110 | */ | ||
111 | #define WEIGHT_RSSI 20 | ||
112 | #define WEIGHT_RX 40 | ||
113 | #define WEIGHT_TX 40 | ||
114 | |||
115 | static int rt2x00link_antenna_get_link_rssi(struct rt2x00_dev *rt2x00dev) | 76 | static int rt2x00link_antenna_get_link_rssi(struct rt2x00_dev *rt2x00dev) |
116 | { | 77 | { |
117 | struct link_ant *ant = &rt2x00dev->link.ant; | 78 | struct link_ant *ant = &rt2x00dev->link.ant; |
@@ -304,46 +265,6 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev, | |||
304 | ant->rssi_ant = MOVING_AVERAGE(ant->rssi_ant, rxdesc->rssi); | 265 | ant->rssi_ant = MOVING_AVERAGE(ant->rssi_ant, rxdesc->rssi); |
305 | } | 266 | } |
306 | 267 | ||
307 | static void rt2x00link_precalculate_signal(struct rt2x00_dev *rt2x00dev) | ||
308 | { | ||
309 | struct link *link = &rt2x00dev->link; | ||
310 | struct link_qual *qual = &rt2x00dev->link.qual; | ||
311 | |||
312 | link->rx_percentage = | ||
313 | PERCENTAGE(qual->rx_success, qual->rx_failed + qual->rx_success); | ||
314 | link->tx_percentage = | ||
315 | PERCENTAGE(qual->tx_success, qual->tx_failed + qual->tx_success); | ||
316 | } | ||
317 | |||
318 | int rt2x00link_calculate_signal(struct rt2x00_dev *rt2x00dev, int rssi) | ||
319 | { | ||
320 | struct link *link = &rt2x00dev->link; | ||
321 | int rssi_percentage = 0; | ||
322 | int signal; | ||
323 | |||
324 | /* | ||
325 | * We need a positive value for the RSSI. | ||
326 | */ | ||
327 | if (rssi < 0) | ||
328 | rssi += rt2x00dev->rssi_offset; | ||
329 | |||
330 | /* | ||
331 | * Calculate the different percentages, | ||
332 | * which will be used for the signal. | ||
333 | */ | ||
334 | rssi_percentage = PERCENTAGE(rssi, rt2x00dev->rssi_offset); | ||
335 | |||
336 | /* | ||
337 | * Add the individual percentages and use the WEIGHT | ||
338 | * defines to calculate the current link signal. | ||
339 | */ | ||
340 | signal = ((WEIGHT_RSSI * rssi_percentage) + | ||
341 | (WEIGHT_TX * link->tx_percentage) + | ||
342 | (WEIGHT_RX * link->rx_percentage)) / 100; | ||
343 | |||
344 | return max_t(int, signal, 100); | ||
345 | } | ||
346 | |||
347 | void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev) | 268 | void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev) |
348 | { | 269 | { |
349 | struct link *link = &rt2x00dev->link; | 270 | struct link *link = &rt2x00dev->link; |
@@ -357,9 +278,6 @@ void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev) | |||
357 | if (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count) | 278 | if (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count) |
358 | return; | 279 | return; |
359 | 280 | ||
360 | link->rx_percentage = DEFAULT_PERCENTAGE; | ||
361 | link->tx_percentage = DEFAULT_PERCENTAGE; | ||
362 | |||
363 | rt2x00link_reset_tuner(rt2x00dev, false); | 281 | rt2x00link_reset_tuner(rt2x00dev, false); |
364 | 282 | ||
365 | if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) | 283 | if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) |
@@ -448,12 +366,6 @@ static void rt2x00link_tuner(struct work_struct *work) | |||
448 | rt2x00dev->ops->lib->link_tuner(rt2x00dev, qual, link->count); | 366 | rt2x00dev->ops->lib->link_tuner(rt2x00dev, qual, link->count); |
449 | 367 | ||
450 | /* | 368 | /* |
451 | * Precalculate a portion of the link signal which is | ||
452 | * in based on the tx/rx success/failure counters. | ||
453 | */ | ||
454 | rt2x00link_precalculate_signal(rt2x00dev); | ||
455 | |||
456 | /* | ||
457 | * Send a signal to the led to update the led signal strength. | 369 | * Send a signal to the led to update the led signal strength. |
458 | */ | 370 | */ |
459 | rt2x00leds_led_quality(rt2x00dev, qual->rssi); | 371 | rt2x00leds_led_quality(rt2x00dev, qual->rssi); |
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 929b85f34f38..eed093d34532 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | <http://rt2x00.serialmonkey.com> | 3 | <http://rt2x00.serialmonkey.com> |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify | 5 | This program is free software; you can redistribute it and/or modify |
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index cdd5154bd4c0..0feb4d0e4668 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | <http://rt2x00.serialmonkey.com> | 3 | <http://rt2x00.serialmonkey.com> |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify | 5 | This program is free software; you can redistribute it and/or modify |
@@ -310,6 +310,8 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) | |||
310 | rt2x00dev->irq = pci_dev->irq; | 310 | rt2x00dev->irq = pci_dev->irq; |
311 | rt2x00dev->name = pci_name(pci_dev); | 311 | rt2x00dev->name = pci_name(pci_dev); |
312 | 312 | ||
313 | rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI); | ||
314 | |||
313 | /* | 315 | /* |
314 | * Determine RT chipset by reading PCI header. | 316 | * Determine RT chipset by reading PCI header. |
315 | */ | 317 | */ |
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h index ae33eebe9a6f..d4f9449ab0a4 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | <http://rt2x00.serialmonkey.com> | 3 | <http://rt2x00.serialmonkey.com> |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify | 5 | This program is free software; you can redistribute it and/or modify |
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 577029efe320..02972a036bce 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | Copyright (C) 2004 - 2009 Gertjan van Wingerde <gwingerde@gmail.com> | ||
3 | <http://rt2x00.serialmonkey.com> | 4 | <http://rt2x00.serialmonkey.com> |
4 | 5 | ||
5 | This program is free software; you can redistribute it and/or modify | 6 | This program is free software; you can redistribute it and/or modify |
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index a5591fb2b191..97c7895c0ece 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | <http://rt2x00.serialmonkey.com> | 3 | <http://rt2x00.serialmonkey.com> |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify | 5 | This program is free software; you can redistribute it and/or modify |
diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h index 983e52e127a7..603bfc0adaa3 100644 --- a/drivers/net/wireless/rt2x00/rt2x00reg.h +++ b/drivers/net/wireless/rt2x00/rt2x00reg.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | <http://rt2x00.serialmonkey.com> | 3 | <http://rt2x00.serialmonkey.com> |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify | 5 | This program is free software; you can redistribute it and/or modify |
diff --git a/drivers/net/wireless/rt2x00/rt2x00soc.c b/drivers/net/wireless/rt2x00/rt2x00soc.c index 539568c48953..19e684f8ffa1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00soc.c +++ b/drivers/net/wireless/rt2x00/rt2x00soc.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | Copyright (C) 2004 - 2009 Felix Fietkau <nbd@openwrt.org> | ||
3 | <http://rt2x00.serialmonkey.com> | 4 | <http://rt2x00.serialmonkey.com> |
4 | 5 | ||
5 | This program is free software; you can redistribute it and/or modify | 6 | This program is free software; you can redistribute it and/or modify |
@@ -93,6 +94,11 @@ int rt2x00soc_probe(struct platform_device *pdev, | |||
93 | rt2x00dev->irq = platform_get_irq(pdev, 0); | 94 | rt2x00dev->irq = platform_get_irq(pdev, 0); |
94 | rt2x00dev->name = pdev->dev.driver->name; | 95 | rt2x00dev->name = pdev->dev.driver->name; |
95 | 96 | ||
97 | /* | ||
98 | * SoC devices mimic PCI behavior. | ||
99 | */ | ||
100 | rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI); | ||
101 | |||
96 | rt2x00_set_chip_rt(rt2x00dev, chipset); | 102 | rt2x00_set_chip_rt(rt2x00dev, chipset); |
97 | 103 | ||
98 | retval = rt2x00soc_alloc_reg(rt2x00dev); | 104 | retval = rt2x00soc_alloc_reg(rt2x00dev); |
diff --git a/drivers/net/wireless/rt2x00/rt2x00soc.h b/drivers/net/wireless/rt2x00/rt2x00soc.h index 5cf114ac2b9c..8a3416624af5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00soc.h +++ b/drivers/net/wireless/rt2x00/rt2x00soc.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | <http://rt2x00.serialmonkey.com> | 3 | <http://rt2x00.serialmonkey.com> |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify | 5 | This program is free software; you can redistribute it and/or modify |
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index c9cbdaa1073f..0a751e73aa0f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | <http://rt2x00.serialmonkey.com> | 3 | <http://rt2x00.serialmonkey.com> |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify | 5 | This program is free software; you can redistribute it and/or modify |
@@ -653,6 +653,8 @@ int rt2x00usb_probe(struct usb_interface *usb_intf, | |||
653 | rt2x00dev->ops = ops; | 653 | rt2x00dev->ops = ops; |
654 | rt2x00dev->hw = hw; | 654 | rt2x00dev->hw = hw; |
655 | 655 | ||
656 | rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_USB); | ||
657 | |||
656 | retval = rt2x00usb_alloc_reg(rt2x00dev); | 658 | retval = rt2x00usb_alloc_reg(rt2x00dev); |
657 | if (retval) | 659 | if (retval) |
658 | goto exit_free_device; | 660 | goto exit_free_device; |
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index 9943e428bc21..3da6841b5d42 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | <http://rt2x00.serialmonkey.com> | 3 | <http://rt2x00.serialmonkey.com> |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify | 5 | This program is free software; you can redistribute it and/or modify |
@@ -26,6 +26,8 @@ | |||
26 | #ifndef RT2X00USB_H | 26 | #ifndef RT2X00USB_H |
27 | #define RT2X00USB_H | 27 | #define RT2X00USB_H |
28 | 28 | ||
29 | #include <linux/usb.h> | ||
30 | |||
29 | #define to_usb_device_intf(d) \ | 31 | #define to_usb_device_intf(d) \ |
30 | ({ \ | 32 | ({ \ |
31 | struct usb_interface *intf = to_usb_interface(d); \ | 33 | struct usb_interface *intf = to_usb_interface(d); \ |
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index b20e3eac9d67..bf04605896c7 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | <http://rt2x00.serialmonkey.com> | 3 | <http://rt2x00.serialmonkey.com> |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify | 5 | This program is free software; you can redistribute it and/or modify |
@@ -51,7 +51,7 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); | |||
51 | * These indirect registers work with busy bits, | 51 | * These indirect registers work with busy bits, |
52 | * and we will try maximal REGISTER_BUSY_COUNT times to access | 52 | * and we will try maximal REGISTER_BUSY_COUNT times to access |
53 | * the register while taking a REGISTER_BUSY_DELAY us delay | 53 | * the register while taking a REGISTER_BUSY_DELAY us delay |
54 | * between each attampt. When the busy bit is still set at that time, | 54 | * between each attempt. When the busy bit is still set at that time, |
55 | * the access attempt is considered to have failed, | 55 | * the access attempt is considered to have failed, |
56 | * and we will print an error. | 56 | * and we will print an error. |
57 | */ | 57 | */ |
@@ -386,7 +386,7 @@ static int rt61pci_config_shared_key(struct rt2x00_dev *rt2x00dev, | |||
386 | * The driver does not support the IV/EIV generation | 386 | * The driver does not support the IV/EIV generation |
387 | * in hardware. However it doesn't support the IV/EIV | 387 | * in hardware. However it doesn't support the IV/EIV |
388 | * inside the ieee80211 frame either, but requires it | 388 | * inside the ieee80211 frame either, but requires it |
389 | * to be provided seperately for the descriptor. | 389 | * to be provided separately for the descriptor. |
390 | * rt2x00lib will cut the IV/EIV data out of all frames | 390 | * rt2x00lib will cut the IV/EIV data out of all frames |
391 | * given to us by mac80211, but we must tell mac80211 | 391 | * given to us by mac80211, but we must tell mac80211 |
392 | * to generate the IV/EIV data. | 392 | * to generate the IV/EIV data. |
@@ -397,7 +397,7 @@ static int rt61pci_config_shared_key(struct rt2x00_dev *rt2x00dev, | |||
397 | /* | 397 | /* |
398 | * SEC_CSR0 contains only single-bit fields to indicate | 398 | * SEC_CSR0 contains only single-bit fields to indicate |
399 | * a particular key is valid. Because using the FIELD32() | 399 | * a particular key is valid. Because using the FIELD32() |
400 | * defines directly will cause a lot of overhead we use | 400 | * defines directly will cause a lot of overhead, we use |
401 | * a calculation to determine the correct bit directly. | 401 | * a calculation to determine the correct bit directly. |
402 | */ | 402 | */ |
403 | mask = 1 << key->hw_key_idx; | 403 | mask = 1 << key->hw_key_idx; |
@@ -425,11 +425,11 @@ static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev, | |||
425 | /* | 425 | /* |
426 | * rt2x00lib can't determine the correct free | 426 | * rt2x00lib can't determine the correct free |
427 | * key_idx for pairwise keys. We have 2 registers | 427 | * key_idx for pairwise keys. We have 2 registers |
428 | * with key valid bits. The goal is simple, read | 428 | * with key valid bits. The goal is simple: read |
429 | * the first register, if that is full move to | 429 | * the first register. If that is full, move to |
430 | * the next register. | 430 | * the next register. |
431 | * When both registers are full, we drop the key, | 431 | * When both registers are full, we drop the key. |
432 | * otherwise we use the first invalid entry. | 432 | * Otherwise, we use the first invalid entry. |
433 | */ | 433 | */ |
434 | rt2x00pci_register_read(rt2x00dev, SEC_CSR2, ®); | 434 | rt2x00pci_register_read(rt2x00dev, SEC_CSR2, ®); |
435 | if (reg && reg == ~0) { | 435 | if (reg && reg == ~0) { |
@@ -464,8 +464,8 @@ static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev, | |||
464 | &addr_entry, sizeof(addr_entry)); | 464 | &addr_entry, sizeof(addr_entry)); |
465 | 465 | ||
466 | /* | 466 | /* |
467 | * Enable pairwise lookup table for given BSS idx, | 467 | * Enable pairwise lookup table for given BSS idx. |
468 | * without this received frames will not be decrypted | 468 | * Without this, received frames will not be decrypted |
469 | * by the hardware. | 469 | * by the hardware. |
470 | */ | 470 | */ |
471 | rt2x00pci_register_read(rt2x00dev, SEC_CSR4, ®); | 471 | rt2x00pci_register_read(rt2x00dev, SEC_CSR4, ®); |
@@ -487,7 +487,7 @@ static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev, | |||
487 | /* | 487 | /* |
488 | * SEC_CSR2 and SEC_CSR3 contain only single-bit fields to indicate | 488 | * SEC_CSR2 and SEC_CSR3 contain only single-bit fields to indicate |
489 | * a particular key is valid. Because using the FIELD32() | 489 | * a particular key is valid. Because using the FIELD32() |
490 | * defines directly will cause a lot of overhead we use | 490 | * defines directly will cause a lot of overhead, we use |
491 | * a calculation to determine the correct bit directly. | 491 | * a calculation to determine the correct bit directly. |
492 | */ | 492 | */ |
493 | if (key->hw_key_idx < 32) { | 493 | if (key->hw_key_idx < 32) { |
@@ -556,7 +556,7 @@ static void rt61pci_config_intf(struct rt2x00_dev *rt2x00dev, | |||
556 | if (flags & CONFIG_UPDATE_TYPE) { | 556 | if (flags & CONFIG_UPDATE_TYPE) { |
557 | /* | 557 | /* |
558 | * Clear current synchronisation setup. | 558 | * Clear current synchronisation setup. |
559 | * For the Beacon base registers we only need to clear | 559 | * For the Beacon base registers, we only need to clear |
560 | * the first byte since that byte contains the VALID and OWNER | 560 | * the first byte since that byte contains the VALID and OWNER |
561 | * bits which (when set to 0) will invalidate the entire beacon. | 561 | * bits which (when set to 0) will invalidate the entire beacon. |
562 | */ | 562 | */ |
@@ -1168,8 +1168,8 @@ static int rt61pci_check_firmware(struct rt2x00_dev *rt2x00dev, | |||
1168 | return FW_BAD_LENGTH; | 1168 | return FW_BAD_LENGTH; |
1169 | 1169 | ||
1170 | /* | 1170 | /* |
1171 | * The last 2 bytes in the firmware array are the crc checksum itself, | 1171 | * The last 2 bytes in the firmware array are the crc checksum itself. |
1172 | * this means that we should never pass those 2 bytes to the crc | 1172 | * This means that we should never pass those 2 bytes to the crc |
1173 | * algorithm. | 1173 | * algorithm. |
1174 | */ | 1174 | */ |
1175 | fw_crc = (data[len - 2] << 8 | data[len - 1]); | 1175 | fw_crc = (data[len - 2] << 8 | data[len - 1]); |
@@ -1986,7 +1986,7 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry, | |||
1986 | 1986 | ||
1987 | /* | 1987 | /* |
1988 | * Hardware has stripped IV/EIV data from 802.11 frame during | 1988 | * Hardware has stripped IV/EIV data from 802.11 frame during |
1989 | * decryption. It has provided the data seperately but rt2x00lib | 1989 | * decryption. It has provided the data separately but rt2x00lib |
1990 | * should decide if it should be reinserted. | 1990 | * should decide if it should be reinserted. |
1991 | */ | 1991 | */ |
1992 | rxdesc->flags |= RX_FLAG_IV_STRIPPED; | 1992 | rxdesc->flags |= RX_FLAG_IV_STRIPPED; |
@@ -2042,7 +2042,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) | |||
2042 | * During each loop we will compare the freshly read | 2042 | * During each loop we will compare the freshly read |
2043 | * STA_CSR4 register value with the value read from | 2043 | * STA_CSR4 register value with the value read from |
2044 | * the previous loop. If the 2 values are equal then | 2044 | * the previous loop. If the 2 values are equal then |
2045 | * we should stop processing because the chance it | 2045 | * we should stop processing because the chance is |
2046 | * quite big that the device has been unplugged and | 2046 | * quite big that the device has been unplugged and |
2047 | * we risk going into an endless loop. | 2047 | * we risk going into an endless loop. |
2048 | */ | 2048 | */ |
@@ -2300,6 +2300,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) | |||
2300 | value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); | 2300 | value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); |
2301 | rt2x00pci_register_read(rt2x00dev, MAC_CSR0, ®); | 2301 | rt2x00pci_register_read(rt2x00dev, MAC_CSR0, ®); |
2302 | rt2x00_set_chip_rf(rt2x00dev, value, reg); | 2302 | rt2x00_set_chip_rf(rt2x00dev, value, reg); |
2303 | rt2x00_print_chip(rt2x00dev); | ||
2303 | 2304 | ||
2304 | if (!rt2x00_rf(&rt2x00dev->chip, RF5225) && | 2305 | if (!rt2x00_rf(&rt2x00dev->chip, RF5225) && |
2305 | !rt2x00_rf(&rt2x00dev->chip, RF5325) && | 2306 | !rt2x00_rf(&rt2x00dev->chip, RF5325) && |
@@ -2330,7 +2331,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) | |||
2330 | __set_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags); | 2331 | __set_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags); |
2331 | 2332 | ||
2332 | /* | 2333 | /* |
2333 | * Detect if this device has an hardware controlled radio. | 2334 | * Detect if this device has a hardware controlled radio. |
2334 | */ | 2335 | */ |
2335 | if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) | 2336 | if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) |
2336 | __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); | 2337 | __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); |
@@ -2355,7 +2356,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) | |||
2355 | __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); | 2356 | __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); |
2356 | 2357 | ||
2357 | /* | 2358 | /* |
2358 | * When working with a RF2529 chip without double antenna | 2359 | * When working with a RF2529 chip without double antenna, |
2359 | * the antenna settings should be gathered from the NIC | 2360 | * the antenna settings should be gathered from the NIC |
2360 | * eeprom word. | 2361 | * eeprom word. |
2361 | */ | 2362 | */ |
@@ -2668,7 +2669,7 @@ static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, | |||
2668 | 2669 | ||
2669 | /* | 2670 | /* |
2670 | * We only need to perform additional register initialization | 2671 | * We only need to perform additional register initialization |
2671 | * for WMM queues/ | 2672 | * for WMM queues. |
2672 | */ | 2673 | */ |
2673 | if (queue_idx >= 4) | 2674 | if (queue_idx >= 4) |
2674 | return 0; | 2675 | return 0; |
diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h index 93eb699165cc..6f33f7f5668c 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.h +++ b/drivers/net/wireless/rt2x00/rt61pci.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | <http://rt2x00.serialmonkey.com> | 3 | <http://rt2x00.serialmonkey.com> |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify | 5 | This program is free software; you can redistribute it and/or modify |
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 14e7bb210075..5bbcf6626f7d 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | <http://rt2x00.serialmonkey.com> | 3 | <http://rt2x00.serialmonkey.com> |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify | 5 | This program is free software; you can redistribute it and/or modify |
@@ -1825,6 +1825,7 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) | |||
1825 | value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); | 1825 | value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); |
1826 | rt2x00usb_register_read(rt2x00dev, MAC_CSR0, ®); | 1826 | rt2x00usb_register_read(rt2x00dev, MAC_CSR0, ®); |
1827 | rt2x00_set_chip(rt2x00dev, RT2571, value, reg); | 1827 | rt2x00_set_chip(rt2x00dev, RT2571, value, reg); |
1828 | rt2x00_print_chip(rt2x00dev); | ||
1828 | 1829 | ||
1829 | if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0x25730) || | 1830 | if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0x25730) || |
1830 | rt2x00_check_rev(&rt2x00dev->chip, 0x0000000f, 0)) { | 1831 | rt2x00_check_rev(&rt2x00dev->chip, 0x0000000f, 0)) { |
diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h index 81fe0be51c42..e783a099a8f1 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.h +++ b/drivers/net/wireless/rt2x00/rt73usb.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | <http://rt2x00.serialmonkey.com> | 3 | <http://rt2x00.serialmonkey.com> |
4 | 4 | ||
5 | This program is free software; you can redistribute it and/or modify | 5 | This program is free software; you can redistribute it and/or modify |
diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index da3bf1cebc08..d03a07e1be7c 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c | |||
@@ -1431,3 +1431,4 @@ MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core"); | |||
1431 | MODULE_LICENSE("GPL"); | 1431 | MODULE_LICENSE("GPL"); |
1432 | MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>"); | 1432 | MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>"); |
1433 | MODULE_ALIAS("spi:wl1251"); | 1433 | MODULE_ALIAS("spi:wl1251"); |
1434 | MODULE_FIRMWARE(WL1251_FW_NAME); | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index d2149fcd3cf1..00ddcc2d37c1 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c | |||
@@ -1979,3 +1979,4 @@ module_exit(wl1271_exit); | |||
1979 | MODULE_LICENSE("GPL"); | 1979 | MODULE_LICENSE("GPL"); |
1980 | MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>"); | 1980 | MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>"); |
1981 | MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); | 1981 | MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); |
1982 | MODULE_FIRMWARE(WL1271_FW_NAME); | ||
diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c index bc81974a2bc7..33c8be7ec8e6 100644 --- a/drivers/net/wireless/zd1201.c +++ b/drivers/net/wireless/zd1201.c | |||
@@ -112,6 +112,9 @@ exit: | |||
112 | return err; | 112 | return err; |
113 | } | 113 | } |
114 | 114 | ||
115 | MODULE_FIRMWARE("zd1201-ap.fw"); | ||
116 | MODULE_FIRMWARE("zd1201.fw"); | ||
117 | |||
115 | static void zd1201_usbfree(struct urb *urb) | 118 | static void zd1201_usbfree(struct urb *urb) |
116 | { | 119 | { |
117 | struct zd1201 *zd = urb->context; | 120 | struct zd1201 *zd = urb->context; |
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index d46f20a57b7d..ac19ecd19cfe 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c | |||
@@ -318,6 +318,13 @@ error: | |||
318 | return r; | 318 | return r; |
319 | } | 319 | } |
320 | 320 | ||
321 | MODULE_FIRMWARE(FW_ZD1211B_PREFIX "ur"); | ||
322 | MODULE_FIRMWARE(FW_ZD1211_PREFIX "ur"); | ||
323 | MODULE_FIRMWARE(FW_ZD1211B_PREFIX "ub"); | ||
324 | MODULE_FIRMWARE(FW_ZD1211_PREFIX "ub"); | ||
325 | MODULE_FIRMWARE(FW_ZD1211B_PREFIX "uphr"); | ||
326 | MODULE_FIRMWARE(FW_ZD1211_PREFIX "uphr"); | ||
327 | |||
321 | /* Read data from device address space using "firmware interface" which does | 328 | /* Read data from device address space using "firmware interface" which does |
322 | * not require firmware to be loaded. */ | 329 | * not require firmware to be loaded. */ |
323 | int zd_usb_read_fw(struct zd_usb *usb, zd_addr_t addr, u8 *data, u16 len) | 330 | int zd_usb_read_fw(struct zd_usb *usb, zd_addr_t addr, u8 *data, u16 len) |
diff --git a/drivers/net/znet.c b/drivers/net/znet.c index b42347333750..443c4eee28c1 100644 --- a/drivers/net/znet.c +++ b/drivers/net/znet.c | |||
@@ -103,8 +103,7 @@ | |||
103 | #include <asm/io.h> | 103 | #include <asm/io.h> |
104 | #include <asm/dma.h> | 104 | #include <asm/dma.h> |
105 | 105 | ||
106 | /* This include could be elsewhere, since it is not wireless specific */ | 106 | #include <linux/i82593.h> |
107 | #include "wireless/i82593.h" | ||
108 | 107 | ||
109 | static char version[] __initdata = "znet.c:v1.02 9/23/94 becker@scyld.com\n"; | 108 | static char version[] __initdata = "znet.c:v1.02 9/23/94 becker@scyld.com\n"; |
110 | 109 | ||
diff --git a/drivers/staging/arlan/Kconfig b/drivers/staging/arlan/Kconfig index 0585ed8b4d3e..5e42b81f97b0 100644 --- a/drivers/staging/arlan/Kconfig +++ b/drivers/staging/arlan/Kconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | config ARLAN | 1 | config ARLAN |
2 | tristate "Aironet Arlan 655 & IC2200 DS support" | 2 | tristate "Aironet Arlan 655 & IC2200 DS support" |
3 | depends on ISA && !64BIT | 3 | depends on ISA && !64BIT && WLAN |
4 | select WIRELESS_EXT | 4 | select WIRELESS_EXT |
5 | ---help--- | 5 | ---help--- |
6 | Aironet makes Arlan, a class of wireless LAN adapters. These use the | 6 | Aironet makes Arlan, a class of wireless LAN adapters. These use the |
diff --git a/drivers/staging/netwave/Kconfig b/drivers/staging/netwave/Kconfig index c0c996c0550a..8033e8171f9e 100644 --- a/drivers/staging/netwave/Kconfig +++ b/drivers/staging/netwave/Kconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | config PCMCIA_NETWAVE | 1 | config PCMCIA_NETWAVE |
2 | tristate "Xircom Netwave AirSurfer Pcmcia wireless support" | 2 | tristate "Xircom Netwave AirSurfer Pcmcia wireless support" |
3 | depends on PCMCIA | 3 | depends on PCMCIA && WLAN |
4 | select WIRELESS_EXT | 4 | select WIRELESS_EXT |
5 | select WEXT_PRIV | 5 | select WEXT_PRIV |
6 | help | 6 | help |
diff --git a/drivers/staging/wavelan/Kconfig b/drivers/staging/wavelan/Kconfig index 786060e025c0..af655668c2a7 100644 --- a/drivers/staging/wavelan/Kconfig +++ b/drivers/staging/wavelan/Kconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | config WAVELAN | 1 | config WAVELAN |
2 | tristate "AT&T/Lucent old WaveLAN & DEC RoamAbout DS ISA support" | 2 | tristate "AT&T/Lucent old WaveLAN & DEC RoamAbout DS ISA support" |
3 | depends on ISA | 3 | depends on ISA && WLAN |
4 | select WIRELESS_EXT | 4 | select WIRELESS_EXT |
5 | select WEXT_SPY | 5 | select WEXT_SPY |
6 | select WEXT_PRIV | 6 | select WEXT_PRIV |
@@ -25,7 +25,7 @@ config WAVELAN | |||
25 | 25 | ||
26 | config PCMCIA_WAVELAN | 26 | config PCMCIA_WAVELAN |
27 | tristate "AT&T/Lucent old WaveLAN Pcmcia wireless support" | 27 | tristate "AT&T/Lucent old WaveLAN Pcmcia wireless support" |
28 | depends on PCMCIA | 28 | depends on PCMCIA && WLAN |
29 | select WIRELESS_EXT | 29 | select WIRELESS_EXT |
30 | select WEXT_SPY | 30 | select WEXT_SPY |
31 | select WEXT_PRIV | 31 | select WEXT_PRIV |
diff --git a/drivers/staging/wavelan/wavelan_cs.p.h b/drivers/staging/wavelan/wavelan_cs.p.h index 81d91531c4f9..8fbfaa8a5a67 100644 --- a/drivers/staging/wavelan/wavelan_cs.p.h +++ b/drivers/staging/wavelan/wavelan_cs.p.h | |||
@@ -446,7 +446,7 @@ | |||
446 | #include <pcmcia/ds.h> | 446 | #include <pcmcia/ds.h> |
447 | 447 | ||
448 | /* Wavelan declarations */ | 448 | /* Wavelan declarations */ |
449 | #include "i82593.h" /* Definitions for the Intel chip */ | 449 | #include <linux/i82593.h> /* Definitions for the Intel chip */ |
450 | 450 | ||
451 | #include "wavelan_cs.h" /* Others bits of the hardware */ | 451 | #include "wavelan_cs.h" /* Others bits of the hardware */ |
452 | 452 | ||
diff --git a/drivers/staging/wavelan/i82593.h b/include/linux/i82593.h index afac5c7a323d..afac5c7a323d 100644 --- a/drivers/staging/wavelan/i82593.h +++ b/include/linux/i82593.h | |||
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 0aa831467493..49b1abd2fe97 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h | |||
@@ -115,7 +115,7 @@ | |||
115 | #define IEEE80211_MAX_SSID_LEN 32 | 115 | #define IEEE80211_MAX_SSID_LEN 32 |
116 | 116 | ||
117 | #define IEEE80211_MAX_MESH_ID_LEN 32 | 117 | #define IEEE80211_MAX_MESH_ID_LEN 32 |
118 | #define IEEE80211_MESH_CONFIG_LEN 24 | 118 | #define IEEE80211_MESH_CONFIG_LEN 7 |
119 | 119 | ||
120 | #define IEEE80211_QOS_CTL_LEN 2 | 120 | #define IEEE80211_QOS_CTL_LEN 2 |
121 | #define IEEE80211_QOS_CTL_TID_MASK 0x000F | 121 | #define IEEE80211_QOS_CTL_TID_MASK 0x000F |
@@ -554,6 +554,20 @@ struct ieee80211_tim_ie { | |||
554 | u8 virtual_map[1]; | 554 | u8 virtual_map[1]; |
555 | } __attribute__ ((packed)); | 555 | } __attribute__ ((packed)); |
556 | 556 | ||
557 | /** | ||
558 | * struct ieee80211_rann_ie | ||
559 | * | ||
560 | * This structure refers to "Root Announcement information element" | ||
561 | */ | ||
562 | struct ieee80211_rann_ie { | ||
563 | u8 rann_flags; | ||
564 | u8 rann_hopcount; | ||
565 | u8 rann_ttl; | ||
566 | u8 rann_addr[6]; | ||
567 | u32 rann_seq; | ||
568 | u32 rann_metric; | ||
569 | } __attribute__ ((packed)); | ||
570 | |||
557 | #define WLAN_SA_QUERY_TR_ID_LEN 2 | 571 | #define WLAN_SA_QUERY_TR_ID_LEN 2 |
558 | 572 | ||
559 | struct ieee80211_mgmt { | 573 | struct ieee80211_mgmt { |
@@ -1070,6 +1084,7 @@ enum ieee80211_eid { | |||
1070 | WLAN_EID_PREQ = 68, | 1084 | WLAN_EID_PREQ = 68, |
1071 | WLAN_EID_PREP = 69, | 1085 | WLAN_EID_PREP = 69, |
1072 | WLAN_EID_PERR = 70, | 1086 | WLAN_EID_PERR = 70, |
1087 | WLAN_EID_RANN = 49, /* compatible with FreeBSD */ | ||
1073 | /* 802.11h */ | 1088 | /* 802.11h */ |
1074 | WLAN_EID_PWR_CONSTRAINT = 32, | 1089 | WLAN_EID_PWR_CONSTRAINT = 32, |
1075 | WLAN_EID_PWR_CAPABILITY = 33, | 1090 | WLAN_EID_PWR_CAPABILITY = 33, |
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 50afca3dcff1..45db17f81aa3 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h | |||
@@ -160,6 +160,11 @@ | |||
160 | * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons, | 160 | * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons, |
161 | * partial scan results may be available | 161 | * partial scan results may be available |
162 | * | 162 | * |
163 | * @NL80211_CMD_GET_SURVEY: get survey resuls, e.g. channel occupation | ||
164 | * or noise level | ||
165 | * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to | ||
166 | * NL80211_CMD_GET_SURVEY and on the "scan" multicast group) | ||
167 | * | ||
163 | * @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain | 168 | * @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain |
164 | * has been changed and provides details of the request information | 169 | * has been changed and provides details of the request information |
165 | * that caused the change such as who initiated the regulatory request | 170 | * that caused the change such as who initiated the regulatory request |
@@ -341,6 +346,9 @@ enum nl80211_commands { | |||
341 | 346 | ||
342 | NL80211_CMD_SET_WIPHY_NETNS, | 347 | NL80211_CMD_SET_WIPHY_NETNS, |
343 | 348 | ||
349 | NL80211_CMD_GET_SURVEY, | ||
350 | NL80211_CMD_NEW_SURVEY_RESULTS, | ||
351 | |||
344 | /* add new commands above here */ | 352 | /* add new commands above here */ |
345 | 353 | ||
346 | /* used to define NL80211_CMD_MAX below */ | 354 | /* used to define NL80211_CMD_MAX below */ |
@@ -584,6 +592,12 @@ enum nl80211_commands { | |||
584 | * changed then the list changed and the dump should be repeated | 592 | * changed then the list changed and the dump should be repeated |
585 | * completely from scratch. | 593 | * completely from scratch. |
586 | * | 594 | * |
595 | * @NL80211_ATTR_4ADDR: Use 4-address frames on a virtual interface | ||
596 | * | ||
597 | * @NL80211_ATTR_SURVEY_INFO: survey information about a channel, part of | ||
598 | * the survey response for %NL80211_CMD_GET_SURVEY, nested attribute | ||
599 | * containing info as possible, see &enum survey_info. | ||
600 | * | ||
587 | * @NL80211_ATTR_MAX: highest attribute number currently defined | 601 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
588 | * @__NL80211_ATTR_AFTER_LAST: internal use | 602 | * @__NL80211_ATTR_AFTER_LAST: internal use |
589 | */ | 603 | */ |
@@ -714,6 +728,10 @@ enum nl80211_attrs { | |||
714 | 728 | ||
715 | NL80211_ATTR_PID, | 729 | NL80211_ATTR_PID, |
716 | 730 | ||
731 | NL80211_ATTR_4ADDR, | ||
732 | |||
733 | NL80211_ATTR_SURVEY_INFO, | ||
734 | |||
717 | /* add attributes here, update the policy in nl80211.c */ | 735 | /* add attributes here, update the policy in nl80211.c */ |
718 | 736 | ||
719 | __NL80211_ATTR_AFTER_LAST, | 737 | __NL80211_ATTR_AFTER_LAST, |
@@ -895,14 +913,14 @@ enum nl80211_sta_info { | |||
895 | * | 913 | * |
896 | * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active | 914 | * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active |
897 | * @NL80211_MPATH_FLAG_RESOLVING: the mesh path discovery process is running | 915 | * @NL80211_MPATH_FLAG_RESOLVING: the mesh path discovery process is running |
898 | * @NL80211_MPATH_FLAG_DSN_VALID: the mesh path contains a valid DSN | 916 | * @NL80211_MPATH_FLAG_SN_VALID: the mesh path contains a valid SN |
899 | * @NL80211_MPATH_FLAG_FIXED: the mesh path has been manually set | 917 | * @NL80211_MPATH_FLAG_FIXED: the mesh path has been manually set |
900 | * @NL80211_MPATH_FLAG_RESOLVED: the mesh path discovery process succeeded | 918 | * @NL80211_MPATH_FLAG_RESOLVED: the mesh path discovery process succeeded |
901 | */ | 919 | */ |
902 | enum nl80211_mpath_flags { | 920 | enum nl80211_mpath_flags { |
903 | NL80211_MPATH_FLAG_ACTIVE = 1<<0, | 921 | NL80211_MPATH_FLAG_ACTIVE = 1<<0, |
904 | NL80211_MPATH_FLAG_RESOLVING = 1<<1, | 922 | NL80211_MPATH_FLAG_RESOLVING = 1<<1, |
905 | NL80211_MPATH_FLAG_DSN_VALID = 1<<2, | 923 | NL80211_MPATH_FLAG_SN_VALID = 1<<2, |
906 | NL80211_MPATH_FLAG_FIXED = 1<<3, | 924 | NL80211_MPATH_FLAG_FIXED = 1<<3, |
907 | NL80211_MPATH_FLAG_RESOLVED = 1<<4, | 925 | NL80211_MPATH_FLAG_RESOLVED = 1<<4, |
908 | }; | 926 | }; |
@@ -915,7 +933,7 @@ enum nl80211_mpath_flags { | |||
915 | * | 933 | * |
916 | * @__NL80211_MPATH_INFO_INVALID: attribute number 0 is reserved | 934 | * @__NL80211_MPATH_INFO_INVALID: attribute number 0 is reserved |
917 | * @NL80211_ATTR_MPATH_FRAME_QLEN: number of queued frames for this destination | 935 | * @NL80211_ATTR_MPATH_FRAME_QLEN: number of queued frames for this destination |
918 | * @NL80211_ATTR_MPATH_DSN: destination sequence number | 936 | * @NL80211_ATTR_MPATH_SN: destination sequence number |
919 | * @NL80211_ATTR_MPATH_METRIC: metric (cost) of this mesh path | 937 | * @NL80211_ATTR_MPATH_METRIC: metric (cost) of this mesh path |
920 | * @NL80211_ATTR_MPATH_EXPTIME: expiration time for the path, in msec from now | 938 | * @NL80211_ATTR_MPATH_EXPTIME: expiration time for the path, in msec from now |
921 | * @NL80211_ATTR_MPATH_FLAGS: mesh path flags, enumerated in | 939 | * @NL80211_ATTR_MPATH_FLAGS: mesh path flags, enumerated in |
@@ -926,7 +944,7 @@ enum nl80211_mpath_flags { | |||
926 | enum nl80211_mpath_info { | 944 | enum nl80211_mpath_info { |
927 | __NL80211_MPATH_INFO_INVALID, | 945 | __NL80211_MPATH_INFO_INVALID, |
928 | NL80211_MPATH_INFO_FRAME_QLEN, | 946 | NL80211_MPATH_INFO_FRAME_QLEN, |
929 | NL80211_MPATH_INFO_DSN, | 947 | NL80211_MPATH_INFO_SN, |
930 | NL80211_MPATH_INFO_METRIC, | 948 | NL80211_MPATH_INFO_METRIC, |
931 | NL80211_MPATH_INFO_EXPTIME, | 949 | NL80211_MPATH_INFO_EXPTIME, |
932 | NL80211_MPATH_INFO_FLAGS, | 950 | NL80211_MPATH_INFO_FLAGS, |
@@ -1117,6 +1135,26 @@ enum nl80211_reg_rule_flags { | |||
1117 | }; | 1135 | }; |
1118 | 1136 | ||
1119 | /** | 1137 | /** |
1138 | * enum nl80211_survey_info - survey information | ||
1139 | * | ||
1140 | * These attribute types are used with %NL80211_ATTR_SURVEY_INFO | ||
1141 | * when getting information about a survey. | ||
1142 | * | ||
1143 | * @__NL80211_SURVEY_INFO_INVALID: attribute number 0 is reserved | ||
1144 | * @NL80211_SURVEY_INFO_FREQUENCY: center frequency of channel | ||
1145 | * @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm) | ||
1146 | */ | ||
1147 | enum nl80211_survey_info { | ||
1148 | __NL80211_SURVEY_INFO_INVALID, | ||
1149 | NL80211_SURVEY_INFO_FREQUENCY, | ||
1150 | NL80211_SURVEY_INFO_NOISE, | ||
1151 | |||
1152 | /* keep last */ | ||
1153 | __NL80211_SURVEY_INFO_AFTER_LAST, | ||
1154 | NL80211_SURVEY_INFO_MAX = __NL80211_SURVEY_INFO_AFTER_LAST - 1 | ||
1155 | }; | ||
1156 | |||
1157 | /** | ||
1120 | * enum nl80211_mntr_flags - monitor configuration flags | 1158 | * enum nl80211_mntr_flags - monitor configuration flags |
1121 | * | 1159 | * |
1122 | * Monitor configuration flags. | 1160 | * Monitor configuration flags. |
@@ -1196,6 +1234,8 @@ enum nl80211_mntr_flags { | |||
1196 | * @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs) | 1234 | * @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs) |
1197 | * that it takes for an HWMP information element to propagate across the mesh | 1235 | * that it takes for an HWMP information element to propagate across the mesh |
1198 | * | 1236 | * |
1237 | * @NL80211_MESHCONF_ROOTMODE: whether root mode is enabled or not | ||
1238 | * | ||
1199 | * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute | 1239 | * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute |
1200 | * | 1240 | * |
1201 | * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use | 1241 | * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use |
@@ -1215,6 +1255,7 @@ enum nl80211_meshconf_params { | |||
1215 | NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, | 1255 | NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, |
1216 | NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, | 1256 | NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, |
1217 | NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, | 1257 | NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, |
1258 | NL80211_MESHCONF_HWMP_ROOTMODE, | ||
1218 | 1259 | ||
1219 | /* keep last */ | 1260 | /* keep last */ |
1220 | __NL80211_MESHCONF_ATTR_AFTER_LAST, | 1261 | __NL80211_MESHCONF_ATTR_AFTER_LAST, |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index ff67865de231..21710fc17eaf 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -206,10 +206,12 @@ struct ieee80211_supported_band { | |||
206 | * struct vif_params - describes virtual interface parameters | 206 | * struct vif_params - describes virtual interface parameters |
207 | * @mesh_id: mesh ID to use | 207 | * @mesh_id: mesh ID to use |
208 | * @mesh_id_len: length of the mesh ID | 208 | * @mesh_id_len: length of the mesh ID |
209 | * @use_4addr: use 4-address frames | ||
209 | */ | 210 | */ |
210 | struct vif_params { | 211 | struct vif_params { |
211 | u8 *mesh_id; | 212 | u8 *mesh_id; |
212 | int mesh_id_len; | 213 | int mesh_id_len; |
214 | int use_4addr; | ||
213 | }; | 215 | }; |
214 | 216 | ||
215 | /** | 217 | /** |
@@ -233,6 +235,35 @@ struct key_params { | |||
233 | }; | 235 | }; |
234 | 236 | ||
235 | /** | 237 | /** |
238 | * enum survey_info_flags - survey information flags | ||
239 | * | ||
240 | * Used by the driver to indicate which info in &struct survey_info | ||
241 | * it has filled in during the get_survey(). | ||
242 | */ | ||
243 | enum survey_info_flags { | ||
244 | SURVEY_INFO_NOISE_DBM = 1<<0, | ||
245 | }; | ||
246 | |||
247 | /** | ||
248 | * struct survey_info - channel survey response | ||
249 | * | ||
250 | * Used by dump_survey() to report back per-channel survey information. | ||
251 | * | ||
252 | * @channel: the channel this survey record reports, mandatory | ||
253 | * @filled: bitflag of flags from &enum survey_info_flags | ||
254 | * @noise: channel noise in dBm. This and all following fields are | ||
255 | * optional | ||
256 | * | ||
257 | * This structure can later be expanded with things like | ||
258 | * channel duty cycle etc. | ||
259 | */ | ||
260 | struct survey_info { | ||
261 | struct ieee80211_channel *channel; | ||
262 | u32 filled; | ||
263 | s8 noise; | ||
264 | }; | ||
265 | |||
266 | /** | ||
236 | * struct beacon_parameters - beacon parameters | 267 | * struct beacon_parameters - beacon parameters |
237 | * | 268 | * |
238 | * Used to configure the beacon for an interface. | 269 | * Used to configure the beacon for an interface. |
@@ -418,7 +449,7 @@ enum monitor_flags { | |||
418 | * in during get_station() or dump_station(). | 449 | * in during get_station() or dump_station(). |
419 | * | 450 | * |
420 | * MPATH_INFO_FRAME_QLEN: @frame_qlen filled | 451 | * MPATH_INFO_FRAME_QLEN: @frame_qlen filled |
421 | * MPATH_INFO_DSN: @dsn filled | 452 | * MPATH_INFO_SN: @sn filled |
422 | * MPATH_INFO_METRIC: @metric filled | 453 | * MPATH_INFO_METRIC: @metric filled |
423 | * MPATH_INFO_EXPTIME: @exptime filled | 454 | * MPATH_INFO_EXPTIME: @exptime filled |
424 | * MPATH_INFO_DISCOVERY_TIMEOUT: @discovery_timeout filled | 455 | * MPATH_INFO_DISCOVERY_TIMEOUT: @discovery_timeout filled |
@@ -427,7 +458,7 @@ enum monitor_flags { | |||
427 | */ | 458 | */ |
428 | enum mpath_info_flags { | 459 | enum mpath_info_flags { |
429 | MPATH_INFO_FRAME_QLEN = BIT(0), | 460 | MPATH_INFO_FRAME_QLEN = BIT(0), |
430 | MPATH_INFO_DSN = BIT(1), | 461 | MPATH_INFO_SN = BIT(1), |
431 | MPATH_INFO_METRIC = BIT(2), | 462 | MPATH_INFO_METRIC = BIT(2), |
432 | MPATH_INFO_EXPTIME = BIT(3), | 463 | MPATH_INFO_EXPTIME = BIT(3), |
433 | MPATH_INFO_DISCOVERY_TIMEOUT = BIT(4), | 464 | MPATH_INFO_DISCOVERY_TIMEOUT = BIT(4), |
@@ -442,7 +473,7 @@ enum mpath_info_flags { | |||
442 | * | 473 | * |
443 | * @filled: bitfield of flags from &enum mpath_info_flags | 474 | * @filled: bitfield of flags from &enum mpath_info_flags |
444 | * @frame_qlen: number of queued frames for this destination | 475 | * @frame_qlen: number of queued frames for this destination |
445 | * @dsn: destination sequence number | 476 | * @sn: target sequence number |
446 | * @metric: metric (cost) of this mesh path | 477 | * @metric: metric (cost) of this mesh path |
447 | * @exptime: expiration time for the mesh path from now, in msecs | 478 | * @exptime: expiration time for the mesh path from now, in msecs |
448 | * @flags: mesh path flags | 479 | * @flags: mesh path flags |
@@ -456,7 +487,7 @@ enum mpath_info_flags { | |||
456 | struct mpath_info { | 487 | struct mpath_info { |
457 | u32 filled; | 488 | u32 filled; |
458 | u32 frame_qlen; | 489 | u32 frame_qlen; |
459 | u32 dsn; | 490 | u32 sn; |
460 | u32 metric; | 491 | u32 metric; |
461 | u32 exptime; | 492 | u32 exptime; |
462 | u32 discovery_timeout; | 493 | u32 discovery_timeout; |
@@ -506,6 +537,7 @@ struct mesh_config { | |||
506 | u32 dot11MeshHWMPactivePathTimeout; | 537 | u32 dot11MeshHWMPactivePathTimeout; |
507 | u16 dot11MeshHWMPpreqMinInterval; | 538 | u16 dot11MeshHWMPpreqMinInterval; |
508 | u16 dot11MeshHWMPnetDiameterTraversalTime; | 539 | u16 dot11MeshHWMPnetDiameterTraversalTime; |
540 | u8 dot11MeshHWMPRootMode; | ||
509 | }; | 541 | }; |
510 | 542 | ||
511 | /** | 543 | /** |
@@ -941,6 +973,8 @@ struct cfg80211_bitrate_mask { | |||
941 | * @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting | 973 | * @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting |
942 | * functions to adjust rfkill hw state | 974 | * functions to adjust rfkill hw state |
943 | * | 975 | * |
976 | * @dump_survey: get site survey information. | ||
977 | * | ||
944 | * @testmode_cmd: run a test mode command | 978 | * @testmode_cmd: run a test mode command |
945 | */ | 979 | */ |
946 | struct cfg80211_ops { | 980 | struct cfg80211_ops { |
@@ -1060,6 +1094,9 @@ struct cfg80211_ops { | |||
1060 | const u8 *peer, | 1094 | const u8 *peer, |
1061 | const struct cfg80211_bitrate_mask *mask); | 1095 | const struct cfg80211_bitrate_mask *mask); |
1062 | 1096 | ||
1097 | int (*dump_survey)(struct wiphy *wiphy, struct net_device *netdev, | ||
1098 | int idx, struct survey_info *info); | ||
1099 | |||
1063 | /* some temporary stuff to finish wext */ | 1100 | /* some temporary stuff to finish wext */ |
1064 | int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev, | 1101 | int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev, |
1065 | bool enabled, int timeout); | 1102 | bool enabled, int timeout); |
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 4d5543af3123..a10d508b07e1 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig | |||
@@ -194,6 +194,19 @@ config MAC80211_VERBOSE_MPL_DEBUG | |||
194 | 194 | ||
195 | Do not select this option. | 195 | Do not select this option. |
196 | 196 | ||
197 | config MAC80211_VERBOSE_MHWMP_DEBUG | ||
198 | bool "Verbose mesh HWMP routing debugging" | ||
199 | depends on MAC80211_DEBUG_MENU | ||
200 | depends on MAC80211_MESH | ||
201 | ---help--- | ||
202 | Selecting this option causes mac80211 to print out very | ||
203 | verbose mesh routing (HWMP) debugging messages (when mac80211 | ||
204 | is taking part in a mesh network). | ||
205 | It should not be selected on production systems as those | ||
206 | messages are remotely triggerable. | ||
207 | |||
208 | Do not select this option. | ||
209 | |||
197 | config MAC80211_DEBUG_COUNTERS | 210 | config MAC80211_DEBUG_COUNTERS |
198 | bool "Extra statistics for TX/RX debugging" | 211 | bool "Extra statistics for TX/RX debugging" |
199 | depends on MAC80211_DEBUG_MENU | 212 | depends on MAC80211_DEBUG_MENU |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 56319b51d170..7f18c8fa1880 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -36,6 +36,24 @@ static bool nl80211_type_check(enum nl80211_iftype type) | |||
36 | } | 36 | } |
37 | } | 37 | } |
38 | 38 | ||
39 | static bool nl80211_params_check(enum nl80211_iftype type, | ||
40 | struct vif_params *params) | ||
41 | { | ||
42 | if (!nl80211_type_check(type)) | ||
43 | return false; | ||
44 | |||
45 | if (params->use_4addr > 0) { | ||
46 | switch(type) { | ||
47 | case NL80211_IFTYPE_AP_VLAN: | ||
48 | case NL80211_IFTYPE_STATION: | ||
49 | break; | ||
50 | default: | ||
51 | return false; | ||
52 | } | ||
53 | } | ||
54 | return true; | ||
55 | } | ||
56 | |||
39 | static int ieee80211_add_iface(struct wiphy *wiphy, char *name, | 57 | static int ieee80211_add_iface(struct wiphy *wiphy, char *name, |
40 | enum nl80211_iftype type, u32 *flags, | 58 | enum nl80211_iftype type, u32 *flags, |
41 | struct vif_params *params) | 59 | struct vif_params *params) |
@@ -45,7 +63,7 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name, | |||
45 | struct ieee80211_sub_if_data *sdata; | 63 | struct ieee80211_sub_if_data *sdata; |
46 | int err; | 64 | int err; |
47 | 65 | ||
48 | if (!nl80211_type_check(type)) | 66 | if (!nl80211_params_check(type, params)) |
49 | return -EINVAL; | 67 | return -EINVAL; |
50 | 68 | ||
51 | err = ieee80211_if_add(local, name, &dev, type, params); | 69 | err = ieee80211_if_add(local, name, &dev, type, params); |
@@ -75,7 +93,7 @@ static int ieee80211_change_iface(struct wiphy *wiphy, | |||
75 | if (netif_running(dev)) | 93 | if (netif_running(dev)) |
76 | return -EBUSY; | 94 | return -EBUSY; |
77 | 95 | ||
78 | if (!nl80211_type_check(type)) | 96 | if (!nl80211_params_check(type, params)) |
79 | return -EINVAL; | 97 | return -EINVAL; |
80 | 98 | ||
81 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 99 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
@@ -89,6 +107,9 @@ static int ieee80211_change_iface(struct wiphy *wiphy, | |||
89 | params->mesh_id_len, | 107 | params->mesh_id_len, |
90 | params->mesh_id); | 108 | params->mesh_id); |
91 | 109 | ||
110 | if (params->use_4addr >= 0) | ||
111 | sdata->use_4addr = !!params->use_4addr; | ||
112 | |||
92 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags) | 113 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags) |
93 | return 0; | 114 | return 0; |
94 | 115 | ||
@@ -806,6 +827,13 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
806 | return -EINVAL; | 827 | return -EINVAL; |
807 | } | 828 | } |
808 | 829 | ||
830 | if (vlansdata->use_4addr) { | ||
831 | if (vlansdata->u.vlan.sta) | ||
832 | return -EBUSY; | ||
833 | |||
834 | rcu_assign_pointer(vlansdata->u.vlan.sta, sta); | ||
835 | } | ||
836 | |||
809 | sta->sdata = vlansdata; | 837 | sta->sdata = vlansdata; |
810 | ieee80211_send_layer2_update(sta); | 838 | ieee80211_send_layer2_update(sta); |
811 | } | 839 | } |
@@ -907,7 +935,7 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, | |||
907 | pinfo->generation = mesh_paths_generation; | 935 | pinfo->generation = mesh_paths_generation; |
908 | 936 | ||
909 | pinfo->filled = MPATH_INFO_FRAME_QLEN | | 937 | pinfo->filled = MPATH_INFO_FRAME_QLEN | |
910 | MPATH_INFO_DSN | | 938 | MPATH_INFO_SN | |
911 | MPATH_INFO_METRIC | | 939 | MPATH_INFO_METRIC | |
912 | MPATH_INFO_EXPTIME | | 940 | MPATH_INFO_EXPTIME | |
913 | MPATH_INFO_DISCOVERY_TIMEOUT | | 941 | MPATH_INFO_DISCOVERY_TIMEOUT | |
@@ -915,7 +943,7 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, | |||
915 | MPATH_INFO_FLAGS; | 943 | MPATH_INFO_FLAGS; |
916 | 944 | ||
917 | pinfo->frame_qlen = mpath->frame_queue.qlen; | 945 | pinfo->frame_qlen = mpath->frame_queue.qlen; |
918 | pinfo->dsn = mpath->dsn; | 946 | pinfo->sn = mpath->sn; |
919 | pinfo->metric = mpath->metric; | 947 | pinfo->metric = mpath->metric; |
920 | if (time_before(jiffies, mpath->exp_time)) | 948 | if (time_before(jiffies, mpath->exp_time)) |
921 | pinfo->exptime = jiffies_to_msecs(mpath->exp_time - jiffies); | 949 | pinfo->exptime = jiffies_to_msecs(mpath->exp_time - jiffies); |
@@ -927,8 +955,8 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, | |||
927 | pinfo->flags |= NL80211_MPATH_FLAG_ACTIVE; | 955 | pinfo->flags |= NL80211_MPATH_FLAG_ACTIVE; |
928 | if (mpath->flags & MESH_PATH_RESOLVING) | 956 | if (mpath->flags & MESH_PATH_RESOLVING) |
929 | pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING; | 957 | pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING; |
930 | if (mpath->flags & MESH_PATH_DSN_VALID) | 958 | if (mpath->flags & MESH_PATH_SN_VALID) |
931 | pinfo->flags |= NL80211_MPATH_FLAG_DSN_VALID; | 959 | pinfo->flags |= NL80211_MPATH_FLAG_SN_VALID; |
932 | if (mpath->flags & MESH_PATH_FIXED) | 960 | if (mpath->flags & MESH_PATH_FIXED) |
933 | pinfo->flags |= NL80211_MPATH_FLAG_FIXED; | 961 | pinfo->flags |= NL80211_MPATH_FLAG_FIXED; |
934 | if (mpath->flags & MESH_PATH_RESOLVING) | 962 | if (mpath->flags & MESH_PATH_RESOLVING) |
@@ -1001,7 +1029,10 @@ static int ieee80211_set_mesh_params(struct wiphy *wiphy, | |||
1001 | { | 1029 | { |
1002 | struct mesh_config *conf; | 1030 | struct mesh_config *conf; |
1003 | struct ieee80211_sub_if_data *sdata; | 1031 | struct ieee80211_sub_if_data *sdata; |
1032 | struct ieee80211_if_mesh *ifmsh; | ||
1033 | |||
1004 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1034 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1035 | ifmsh = &sdata->u.mesh; | ||
1005 | 1036 | ||
1006 | /* Set the config options which we are interested in setting */ | 1037 | /* Set the config options which we are interested in setting */ |
1007 | conf = &(sdata->u.mesh.mshcfg); | 1038 | conf = &(sdata->u.mesh.mshcfg); |
@@ -1036,6 +1067,10 @@ static int ieee80211_set_mesh_params(struct wiphy *wiphy, | |||
1036 | mask)) | 1067 | mask)) |
1037 | conf->dot11MeshHWMPnetDiameterTraversalTime = | 1068 | conf->dot11MeshHWMPnetDiameterTraversalTime = |
1038 | nconf->dot11MeshHWMPnetDiameterTraversalTime; | 1069 | nconf->dot11MeshHWMPnetDiameterTraversalTime; |
1070 | if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_ROOTMODE, mask)) { | ||
1071 | conf->dot11MeshHWMPRootMode = nconf->dot11MeshHWMPRootMode; | ||
1072 | ieee80211_mesh_root_setup(ifmsh); | ||
1073 | } | ||
1039 | return 0; | 1074 | return 0; |
1040 | } | 1075 | } |
1041 | 1076 | ||
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 8782264f49e7..472b2039906c 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c | |||
@@ -149,6 +149,8 @@ IEEE80211_IF_FILE(path_refresh_time, | |||
149 | u.mesh.mshcfg.path_refresh_time, DEC); | 149 | u.mesh.mshcfg.path_refresh_time, DEC); |
150 | IEEE80211_IF_FILE(min_discovery_timeout, | 150 | IEEE80211_IF_FILE(min_discovery_timeout, |
151 | u.mesh.mshcfg.min_discovery_timeout, DEC); | 151 | u.mesh.mshcfg.min_discovery_timeout, DEC); |
152 | IEEE80211_IF_FILE(dot11MeshHWMPRootMode, | ||
153 | u.mesh.mshcfg.dot11MeshHWMPRootMode, DEC); | ||
152 | #endif | 154 | #endif |
153 | 155 | ||
154 | 156 | ||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 1ef767366b77..b63b99fb2fd3 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -208,6 +208,9 @@ struct ieee80211_if_wds { | |||
208 | 208 | ||
209 | struct ieee80211_if_vlan { | 209 | struct ieee80211_if_vlan { |
210 | struct list_head list; | 210 | struct list_head list; |
211 | |||
212 | /* used for all tx if the VLAN is configured to 4-addr mode */ | ||
213 | struct sta_info *sta; | ||
211 | }; | 214 | }; |
212 | 215 | ||
213 | struct mesh_stats { | 216 | struct mesh_stats { |
@@ -352,6 +355,7 @@ struct ieee80211_if_mesh { | |||
352 | struct work_struct work; | 355 | struct work_struct work; |
353 | struct timer_list housekeeping_timer; | 356 | struct timer_list housekeeping_timer; |
354 | struct timer_list mesh_path_timer; | 357 | struct timer_list mesh_path_timer; |
358 | struct timer_list mesh_path_root_timer; | ||
355 | struct sk_buff_head skb_queue; | 359 | struct sk_buff_head skb_queue; |
356 | 360 | ||
357 | unsigned long timers_running; | 361 | unsigned long timers_running; |
@@ -361,23 +365,23 @@ struct ieee80211_if_mesh { | |||
361 | u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN]; | 365 | u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN]; |
362 | size_t mesh_id_len; | 366 | size_t mesh_id_len; |
363 | /* Active Path Selection Protocol Identifier */ | 367 | /* Active Path Selection Protocol Identifier */ |
364 | u8 mesh_pp_id[4]; | 368 | u8 mesh_pp_id; |
365 | /* Active Path Selection Metric Identifier */ | 369 | /* Active Path Selection Metric Identifier */ |
366 | u8 mesh_pm_id[4]; | 370 | u8 mesh_pm_id; |
367 | /* Congestion Control Mode Identifier */ | 371 | /* Congestion Control Mode Identifier */ |
368 | u8 mesh_cc_id[4]; | 372 | u8 mesh_cc_id; |
369 | /* Synchronization Protocol Identifier */ | 373 | /* Synchronization Protocol Identifier */ |
370 | u8 mesh_sp_id[4]; | 374 | u8 mesh_sp_id; |
371 | /* Authentication Protocol Identifier */ | 375 | /* Authentication Protocol Identifier */ |
372 | u8 mesh_auth_id[4]; | 376 | u8 mesh_auth_id; |
373 | /* Local mesh Destination Sequence Number */ | 377 | /* Local mesh Sequence Number */ |
374 | u32 dsn; | 378 | u32 sn; |
375 | /* Last used PREQ ID */ | 379 | /* Last used PREQ ID */ |
376 | u32 preq_id; | 380 | u32 preq_id; |
377 | atomic_t mpaths; | 381 | atomic_t mpaths; |
378 | /* Timestamp of last DSN update */ | 382 | /* Timestamp of last SN update */ |
379 | unsigned long last_dsn_update; | 383 | unsigned long last_sn_update; |
380 | /* Timestamp of last DSN sent */ | 384 | /* Timestamp of last SN sent */ |
381 | unsigned long last_preq; | 385 | unsigned long last_preq; |
382 | struct mesh_rmc *rmc; | 386 | struct mesh_rmc *rmc; |
383 | spinlock_t mesh_preq_queue_lock; | 387 | spinlock_t mesh_preq_queue_lock; |
@@ -457,6 +461,8 @@ struct ieee80211_sub_if_data { | |||
457 | int force_unicast_rateidx; /* forced TX rateidx for unicast frames */ | 461 | int force_unicast_rateidx; /* forced TX rateidx for unicast frames */ |
458 | int max_ratectrl_rateidx; /* max TX rateidx for rate control */ | 462 | int max_ratectrl_rateidx; /* max TX rateidx for rate control */ |
459 | 463 | ||
464 | bool use_4addr; /* use 4-address frames */ | ||
465 | |||
460 | union { | 466 | union { |
461 | struct ieee80211_if_ap ap; | 467 | struct ieee80211_if_ap ap; |
462 | struct ieee80211_if_wds wds; | 468 | struct ieee80211_if_wds wds; |
@@ -799,6 +805,7 @@ struct ieee802_11_elems { | |||
799 | u8 *preq; | 805 | u8 *preq; |
800 | u8 *prep; | 806 | u8 *prep; |
801 | u8 *perr; | 807 | u8 *perr; |
808 | struct ieee80211_rann_ie *rann; | ||
802 | u8 *ch_switch_elem; | 809 | u8 *ch_switch_elem; |
803 | u8 *country_elem; | 810 | u8 *country_elem; |
804 | u8 *pwr_constr_elem; | 811 | u8 *pwr_constr_elem; |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 8495161b99b8..1f02b0610e82 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -752,6 +752,7 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, | |||
752 | ieee80211_mandatory_rates(sdata->local, | 752 | ieee80211_mandatory_rates(sdata->local, |
753 | sdata->local->hw.conf.channel->band); | 753 | sdata->local->hw.conf.channel->band); |
754 | sdata->drop_unencrypted = 0; | 754 | sdata->drop_unencrypted = 0; |
755 | sdata->use_4addr = 0; | ||
755 | 756 | ||
756 | return 0; | 757 | return 0; |
757 | } | 758 | } |
@@ -819,6 +820,9 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
819 | params->mesh_id_len, | 820 | params->mesh_id_len, |
820 | params->mesh_id); | 821 | params->mesh_id); |
821 | 822 | ||
823 | if (params && params->use_4addr >= 0) | ||
824 | sdata->use_4addr = !!params->use_4addr; | ||
825 | |||
822 | mutex_lock(&local->iflist_mtx); | 826 | mutex_lock(&local->iflist_mtx); |
823 | list_add_tail_rcu(&sdata->list, &local->interfaces); | 827 | list_add_tail_rcu(&sdata->list, &local->interfaces); |
824 | mutex_unlock(&local->iflist_mtx); | 828 | mutex_unlock(&local->iflist_mtx); |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 9a733890eb47..bbd56b087899 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2008 open80211s Ltd. | 2 | * Copyright (c) 2008, 2009 open80211s Ltd. |
3 | * Authors: Luis Carlos Cobo <luisca@cozybit.com> | 3 | * Authors: Luis Carlos Cobo <luisca@cozybit.com> |
4 | * Javier Cardona <javier@cozybit.com> | 4 | * Javier Cardona <javier@cozybit.com> |
5 | * | 5 | * |
@@ -14,18 +14,20 @@ | |||
14 | 14 | ||
15 | #define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ) | 15 | #define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ) |
16 | #define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ) | 16 | #define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ) |
17 | #define IEEE80211_MESH_RANN_INTERVAL (1 * HZ) | ||
17 | 18 | ||
18 | #define PP_OFFSET 1 /* Path Selection Protocol */ | 19 | #define MESHCONF_PP_OFFSET 0 /* Path Selection Protocol */ |
19 | #define PM_OFFSET 5 /* Path Selection Metric */ | 20 | #define MESHCONF_PM_OFFSET 1 /* Path Selection Metric */ |
20 | #define CC_OFFSET 9 /* Congestion Control Mode */ | 21 | #define MESHCONF_CC_OFFSET 2 /* Congestion Control Mode */ |
21 | #define SP_OFFSET 13 /* Synchronization Protocol */ | 22 | #define MESHCONF_SP_OFFSET 3 /* Synchronization Protocol */ |
22 | #define AUTH_OFFSET 17 /* Authentication Protocol */ | 23 | #define MESHCONF_AUTH_OFFSET 4 /* Authentication Protocol */ |
23 | #define CAPAB_OFFSET 22 | 24 | #define MESHCONF_CAPAB_OFFSET 6 |
24 | #define CAPAB_ACCEPT_PLINKS 0x80 | 25 | #define MESHCONF_CAPAB_ACCEPT_PLINKS 0x01 |
25 | #define CAPAB_FORWARDING 0x10 | 26 | #define MESHCONF_CAPAB_FORWARDING 0x08 |
26 | 27 | ||
27 | #define TMR_RUNNING_HK 0 | 28 | #define TMR_RUNNING_HK 0 |
28 | #define TMR_RUNNING_MP 1 | 29 | #define TMR_RUNNING_MP 1 |
30 | #define TMR_RUNNING_MPR 2 | ||
29 | 31 | ||
30 | int mesh_allocated; | 32 | int mesh_allocated; |
31 | static struct kmem_cache *rm_cache; | 33 | static struct kmem_cache *rm_cache; |
@@ -85,11 +87,12 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat | |||
85 | */ | 87 | */ |
86 | if (ifmsh->mesh_id_len == ie->mesh_id_len && | 88 | if (ifmsh->mesh_id_len == ie->mesh_id_len && |
87 | memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 && | 89 | memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 && |
88 | memcmp(ifmsh->mesh_pp_id, ie->mesh_config + PP_OFFSET, 4) == 0 && | 90 | (ifmsh->mesh_pp_id == *(ie->mesh_config + MESHCONF_PP_OFFSET))&& |
89 | memcmp(ifmsh->mesh_pm_id, ie->mesh_config + PM_OFFSET, 4) == 0 && | 91 | (ifmsh->mesh_pm_id == *(ie->mesh_config + MESHCONF_PM_OFFSET))&& |
90 | memcmp(ifmsh->mesh_cc_id, ie->mesh_config + CC_OFFSET, 4) == 0 && | 92 | (ifmsh->mesh_cc_id == *(ie->mesh_config + MESHCONF_CC_OFFSET))&& |
91 | memcmp(ifmsh->mesh_sp_id, ie->mesh_config + SP_OFFSET, 4) == 0 && | 93 | (ifmsh->mesh_sp_id == *(ie->mesh_config + MESHCONF_SP_OFFSET))&& |
92 | memcmp(ifmsh->mesh_auth_id, ie->mesh_config + AUTH_OFFSET, 4) == 0) | 94 | (ifmsh->mesh_auth_id == *(ie->mesh_config + |
95 | MESHCONF_AUTH_OFFSET))) | ||
93 | return true; | 96 | return true; |
94 | 97 | ||
95 | return false; | 98 | return false; |
@@ -102,7 +105,8 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat | |||
102 | */ | 105 | */ |
103 | bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie) | 106 | bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie) |
104 | { | 107 | { |
105 | return (*(ie->mesh_config + CAPAB_OFFSET) & CAPAB_ACCEPT_PLINKS) != 0; | 108 | return (*(ie->mesh_config + MESHCONF_CAPAB_OFFSET) & |
109 | MESHCONF_CAPAB_ACCEPT_PLINKS) != 0; | ||
106 | } | 110 | } |
107 | 111 | ||
108 | /** | 112 | /** |
@@ -128,18 +132,11 @@ void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata) | |||
128 | 132 | ||
129 | void mesh_ids_set_default(struct ieee80211_if_mesh *sta) | 133 | void mesh_ids_set_default(struct ieee80211_if_mesh *sta) |
130 | { | 134 | { |
131 | u8 oui[3] = {0x00, 0x0F, 0xAC}; | 135 | sta->mesh_pp_id = 0; /* HWMP */ |
132 | 136 | sta->mesh_pm_id = 0; /* Airtime */ | |
133 | memcpy(sta->mesh_pp_id, oui, sizeof(oui)); | 137 | sta->mesh_cc_id = 0; /* Disabled */ |
134 | memcpy(sta->mesh_pm_id, oui, sizeof(oui)); | 138 | sta->mesh_sp_id = 0; /* Neighbor Offset */ |
135 | memcpy(sta->mesh_cc_id, oui, sizeof(oui)); | 139 | sta->mesh_auth_id = 0; /* Disabled */ |
136 | memcpy(sta->mesh_sp_id, oui, sizeof(oui)); | ||
137 | memcpy(sta->mesh_auth_id, oui, sizeof(oui)); | ||
138 | sta->mesh_pp_id[sizeof(oui)] = 0; | ||
139 | sta->mesh_pm_id[sizeof(oui)] = 0; | ||
140 | sta->mesh_cc_id[sizeof(oui)] = 0xff; | ||
141 | sta->mesh_sp_id[sizeof(oui)] = 0xff; | ||
142 | sta->mesh_auth_id[sizeof(oui)] = 0x0; | ||
143 | } | 140 | } |
144 | 141 | ||
145 | int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) | 142 | int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) |
@@ -228,6 +225,7 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | |||
228 | struct ieee80211_supported_band *sband; | 225 | struct ieee80211_supported_band *sband; |
229 | u8 *pos; | 226 | u8 *pos; |
230 | int len, i, rate; | 227 | int len, i, rate; |
228 | u8 neighbors; | ||
231 | 229 | ||
232 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 230 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
233 | len = sband->n_bitrates; | 231 | len = sband->n_bitrates; |
@@ -251,6 +249,13 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | |||
251 | } | 249 | } |
252 | } | 250 | } |
253 | 251 | ||
252 | if (sband->band == IEEE80211_BAND_2GHZ) { | ||
253 | pos = skb_put(skb, 2 + 1); | ||
254 | *pos++ = WLAN_EID_DS_PARAMS; | ||
255 | *pos++ = 1; | ||
256 | *pos++ = ieee80211_frequency_to_channel(local->hw.conf.channel->center_freq); | ||
257 | } | ||
258 | |||
254 | pos = skb_put(skb, 2 + sdata->u.mesh.mesh_id_len); | 259 | pos = skb_put(skb, 2 + sdata->u.mesh.mesh_id_len); |
255 | *pos++ = WLAN_EID_MESH_ID; | 260 | *pos++ = WLAN_EID_MESH_ID; |
256 | *pos++ = sdata->u.mesh.mesh_id_len; | 261 | *pos++ = sdata->u.mesh.mesh_id_len; |
@@ -260,37 +265,33 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | |||
260 | pos = skb_put(skb, 2 + IEEE80211_MESH_CONFIG_LEN); | 265 | pos = skb_put(skb, 2 + IEEE80211_MESH_CONFIG_LEN); |
261 | *pos++ = WLAN_EID_MESH_CONFIG; | 266 | *pos++ = WLAN_EID_MESH_CONFIG; |
262 | *pos++ = IEEE80211_MESH_CONFIG_LEN; | 267 | *pos++ = IEEE80211_MESH_CONFIG_LEN; |
263 | /* Version */ | ||
264 | *pos++ = 1; | ||
265 | 268 | ||
266 | /* Active path selection protocol ID */ | 269 | /* Active path selection protocol ID */ |
267 | memcpy(pos, sdata->u.mesh.mesh_pp_id, 4); | 270 | *pos++ = sdata->u.mesh.mesh_pp_id; |
268 | pos += 4; | ||
269 | 271 | ||
270 | /* Active path selection metric ID */ | 272 | /* Active path selection metric ID */ |
271 | memcpy(pos, sdata->u.mesh.mesh_pm_id, 4); | 273 | *pos++ = sdata->u.mesh.mesh_pm_id; |
272 | pos += 4; | ||
273 | 274 | ||
274 | /* Congestion control mode identifier */ | 275 | /* Congestion control mode identifier */ |
275 | memcpy(pos, sdata->u.mesh.mesh_cc_id, 4); | 276 | *pos++ = sdata->u.mesh.mesh_cc_id; |
276 | pos += 4; | ||
277 | 277 | ||
278 | /* Synchronization protocol identifier */ | 278 | /* Synchronization protocol identifier */ |
279 | memcpy(pos, sdata->u.mesh.mesh_sp_id, 4); | 279 | *pos++ = sdata->u.mesh.mesh_sp_id; |
280 | pos += 4; | ||
281 | 280 | ||
282 | /* Authentication Protocol identifier */ | 281 | /* Authentication Protocol identifier */ |
283 | memcpy(pos, sdata->u.mesh.mesh_auth_id, 4); | 282 | *pos++ = sdata->u.mesh.mesh_auth_id; |
284 | pos += 4; | ||
285 | 283 | ||
286 | /* Mesh Formation Info */ | 284 | /* Mesh Formation Info - number of neighbors */ |
287 | memset(pos, 0x00, 1); | 285 | neighbors = atomic_read(&sdata->u.mesh.mshstats.estab_plinks); |
288 | pos += 1; | 286 | /* Number of neighbor mesh STAs or 15 whichever is smaller */ |
287 | neighbors = (neighbors > 15) ? 15 : neighbors; | ||
288 | *pos++ = neighbors << 1; | ||
289 | 289 | ||
290 | /* Mesh capability */ | 290 | /* Mesh capability */ |
291 | sdata->u.mesh.accepting_plinks = mesh_plink_availables(sdata); | 291 | sdata->u.mesh.accepting_plinks = mesh_plink_availables(sdata); |
292 | *pos = CAPAB_FORWARDING; | 292 | *pos = MESHCONF_CAPAB_FORWARDING; |
293 | *pos++ |= sdata->u.mesh.accepting_plinks ? CAPAB_ACCEPT_PLINKS : 0x00; | 293 | *pos++ |= sdata->u.mesh.accepting_plinks ? |
294 | MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; | ||
294 | *pos++ = 0x00; | 295 | *pos++ = 0x00; |
295 | 296 | ||
296 | return; | 297 | return; |
@@ -355,6 +356,34 @@ static void ieee80211_mesh_path_timer(unsigned long data) | |||
355 | ieee80211_queue_work(&local->hw, &ifmsh->work); | 356 | ieee80211_queue_work(&local->hw, &ifmsh->work); |
356 | } | 357 | } |
357 | 358 | ||
359 | static void ieee80211_mesh_path_root_timer(unsigned long data) | ||
360 | { | ||
361 | struct ieee80211_sub_if_data *sdata = | ||
362 | (struct ieee80211_sub_if_data *) data; | ||
363 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
364 | struct ieee80211_local *local = sdata->local; | ||
365 | |||
366 | set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); | ||
367 | |||
368 | if (local->quiescing) { | ||
369 | set_bit(TMR_RUNNING_MPR, &ifmsh->timers_running); | ||
370 | return; | ||
371 | } | ||
372 | |||
373 | ieee80211_queue_work(&local->hw, &ifmsh->work); | ||
374 | } | ||
375 | |||
376 | void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh) | ||
377 | { | ||
378 | if (ifmsh->mshcfg.dot11MeshHWMPRootMode) | ||
379 | set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); | ||
380 | else { | ||
381 | clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); | ||
382 | /* stop running timer */ | ||
383 | del_timer_sync(&ifmsh->mesh_path_root_timer); | ||
384 | } | ||
385 | } | ||
386 | |||
358 | /** | 387 | /** |
359 | * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame | 388 | * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame |
360 | * @hdr: 802.11 frame header | 389 | * @hdr: 802.11 frame header |
@@ -448,6 +477,15 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, | |||
448 | round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); | 477 | round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); |
449 | } | 478 | } |
450 | 479 | ||
480 | static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata) | ||
481 | { | ||
482 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
483 | |||
484 | mesh_path_tx_root_frame(sdata); | ||
485 | mod_timer(&ifmsh->mesh_path_root_timer, | ||
486 | round_jiffies(jiffies + IEEE80211_MESH_RANN_INTERVAL)); | ||
487 | } | ||
488 | |||
451 | #ifdef CONFIG_PM | 489 | #ifdef CONFIG_PM |
452 | void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) | 490 | void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) |
453 | { | 491 | { |
@@ -462,6 +500,8 @@ void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) | |||
462 | set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); | 500 | set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); |
463 | if (del_timer_sync(&ifmsh->mesh_path_timer)) | 501 | if (del_timer_sync(&ifmsh->mesh_path_timer)) |
464 | set_bit(TMR_RUNNING_MP, &ifmsh->timers_running); | 502 | set_bit(TMR_RUNNING_MP, &ifmsh->timers_running); |
503 | if (del_timer_sync(&ifmsh->mesh_path_root_timer)) | ||
504 | set_bit(TMR_RUNNING_MPR, &ifmsh->timers_running); | ||
465 | } | 505 | } |
466 | 506 | ||
467 | void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) | 507 | void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) |
@@ -472,6 +512,9 @@ void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) | |||
472 | add_timer(&ifmsh->housekeeping_timer); | 512 | add_timer(&ifmsh->housekeeping_timer); |
473 | if (test_and_clear_bit(TMR_RUNNING_MP, &ifmsh->timers_running)) | 513 | if (test_and_clear_bit(TMR_RUNNING_MP, &ifmsh->timers_running)) |
474 | add_timer(&ifmsh->mesh_path_timer); | 514 | add_timer(&ifmsh->mesh_path_timer); |
515 | if (test_and_clear_bit(TMR_RUNNING_MPR, &ifmsh->timers_running)) | ||
516 | add_timer(&ifmsh->mesh_path_root_timer); | ||
517 | ieee80211_mesh_root_setup(ifmsh); | ||
475 | } | 518 | } |
476 | #endif | 519 | #endif |
477 | 520 | ||
@@ -481,6 +524,7 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | |||
481 | struct ieee80211_local *local = sdata->local; | 524 | struct ieee80211_local *local = sdata->local; |
482 | 525 | ||
483 | set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); | 526 | set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); |
527 | ieee80211_mesh_root_setup(ifmsh); | ||
484 | ieee80211_queue_work(&local->hw, &ifmsh->work); | 528 | ieee80211_queue_work(&local->hw, &ifmsh->work); |
485 | sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; | 529 | sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; |
486 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | | 530 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | |
@@ -491,6 +535,7 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | |||
491 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) | 535 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) |
492 | { | 536 | { |
493 | del_timer_sync(&sdata->u.mesh.housekeeping_timer); | 537 | del_timer_sync(&sdata->u.mesh.housekeeping_timer); |
538 | del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); | ||
494 | /* | 539 | /* |
495 | * If the timer fired while we waited for it, it will have | 540 | * If the timer fired while we waited for it, it will have |
496 | * requeued the work. Now the work will be running again | 541 | * requeued the work. Now the work will be running again |
@@ -561,7 +606,7 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, | |||
561 | struct ieee80211_rx_status *rx_status) | 606 | struct ieee80211_rx_status *rx_status) |
562 | { | 607 | { |
563 | switch (mgmt->u.action.category) { | 608 | switch (mgmt->u.action.category) { |
564 | case PLINK_CATEGORY: | 609 | case MESH_PLINK_CATEGORY: |
565 | mesh_rx_plink_frame(sdata, mgmt, len, rx_status); | 610 | mesh_rx_plink_frame(sdata, mgmt, len, rx_status); |
566 | break; | 611 | break; |
567 | case MESH_PATH_SEL_CATEGORY: | 612 | case MESH_PATH_SEL_CATEGORY: |
@@ -628,6 +673,9 @@ static void ieee80211_mesh_work(struct work_struct *work) | |||
628 | 673 | ||
629 | if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags)) | 674 | if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags)) |
630 | ieee80211_mesh_housekeeping(sdata, ifmsh); | 675 | ieee80211_mesh_housekeeping(sdata, ifmsh); |
676 | |||
677 | if (test_and_clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags)) | ||
678 | ieee80211_mesh_rootpath(sdata); | ||
631 | } | 679 | } |
632 | 680 | ||
633 | void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) | 681 | void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) |
@@ -673,7 +721,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) | |||
673 | MESH_MIN_DISCOVERY_TIMEOUT; | 721 | MESH_MIN_DISCOVERY_TIMEOUT; |
674 | ifmsh->accepting_plinks = true; | 722 | ifmsh->accepting_plinks = true; |
675 | ifmsh->preq_id = 0; | 723 | ifmsh->preq_id = 0; |
676 | ifmsh->dsn = 0; | 724 | ifmsh->sn = 0; |
677 | atomic_set(&ifmsh->mpaths, 0); | 725 | atomic_set(&ifmsh->mpaths, 0); |
678 | mesh_rmc_init(sdata); | 726 | mesh_rmc_init(sdata); |
679 | ifmsh->last_preq = jiffies; | 727 | ifmsh->last_preq = jiffies; |
@@ -684,6 +732,9 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) | |||
684 | setup_timer(&ifmsh->mesh_path_timer, | 732 | setup_timer(&ifmsh->mesh_path_timer, |
685 | ieee80211_mesh_path_timer, | 733 | ieee80211_mesh_path_timer, |
686 | (unsigned long) sdata); | 734 | (unsigned long) sdata); |
735 | setup_timer(&ifmsh->mesh_path_root_timer, | ||
736 | ieee80211_mesh_path_root_timer, | ||
737 | (unsigned long) sdata); | ||
687 | INIT_LIST_HEAD(&ifmsh->preq_queue.list); | 738 | INIT_LIST_HEAD(&ifmsh->preq_queue.list); |
688 | spin_lock_init(&ifmsh->mesh_preq_queue_lock); | 739 | spin_lock_init(&ifmsh->mesh_preq_queue_lock); |
689 | } | 740 | } |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index dd1c19319f0a..bd0e1cbb9a1e 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2008 open80211s Ltd. | 2 | * Copyright (c) 2008, 2009 open80211s Ltd. |
3 | * Authors: Luis Carlos Cobo <luisca@cozybit.com> | 3 | * Authors: Luis Carlos Cobo <luisca@cozybit.com> |
4 | * Javier Cardona <javier@cozybit.com> | 4 | * Javier Cardona <javier@cozybit.com> |
5 | * | 5 | * |
@@ -26,7 +26,7 @@ | |||
26 | * | 26 | * |
27 | * @MESH_PATH_ACTIVE: the mesh path can be used for forwarding | 27 | * @MESH_PATH_ACTIVE: the mesh path can be used for forwarding |
28 | * @MESH_PATH_RESOLVING: the discovery process is running for this mesh path | 28 | * @MESH_PATH_RESOLVING: the discovery process is running for this mesh path |
29 | * @MESH_PATH_DSN_VALID: the mesh path contains a valid destination sequence | 29 | * @MESH_PATH_SN_VALID: the mesh path contains a valid destination sequence |
30 | * number | 30 | * number |
31 | * @MESH_PATH_FIXED: the mesh path has been manually set and should not be | 31 | * @MESH_PATH_FIXED: the mesh path has been manually set and should not be |
32 | * modified | 32 | * modified |
@@ -38,7 +38,7 @@ | |||
38 | enum mesh_path_flags { | 38 | enum mesh_path_flags { |
39 | MESH_PATH_ACTIVE = BIT(0), | 39 | MESH_PATH_ACTIVE = BIT(0), |
40 | MESH_PATH_RESOLVING = BIT(1), | 40 | MESH_PATH_RESOLVING = BIT(1), |
41 | MESH_PATH_DSN_VALID = BIT(2), | 41 | MESH_PATH_SN_VALID = BIT(2), |
42 | MESH_PATH_FIXED = BIT(3), | 42 | MESH_PATH_FIXED = BIT(3), |
43 | MESH_PATH_RESOLVED = BIT(4), | 43 | MESH_PATH_RESOLVED = BIT(4), |
44 | }; | 44 | }; |
@@ -53,11 +53,13 @@ enum mesh_path_flags { | |||
53 | * to grow. | 53 | * to grow. |
54 | * @MESH_WORK_GROW_MPP_TABLE: the mesh portals table is full and needs to | 54 | * @MESH_WORK_GROW_MPP_TABLE: the mesh portals table is full and needs to |
55 | * grow | 55 | * grow |
56 | * @MESH_WORK_ROOT: the mesh root station needs to send a frame | ||
56 | */ | 57 | */ |
57 | enum mesh_deferred_task_flags { | 58 | enum mesh_deferred_task_flags { |
58 | MESH_WORK_HOUSEKEEPING, | 59 | MESH_WORK_HOUSEKEEPING, |
59 | MESH_WORK_GROW_MPATH_TABLE, | 60 | MESH_WORK_GROW_MPATH_TABLE, |
60 | MESH_WORK_GROW_MPP_TABLE, | 61 | MESH_WORK_GROW_MPP_TABLE, |
62 | MESH_WORK_ROOT, | ||
61 | }; | 63 | }; |
62 | 64 | ||
63 | /** | 65 | /** |
@@ -70,7 +72,7 @@ enum mesh_deferred_task_flags { | |||
70 | * @timer: mesh path discovery timer | 72 | * @timer: mesh path discovery timer |
71 | * @frame_queue: pending queue for frames sent to this destination while the | 73 | * @frame_queue: pending queue for frames sent to this destination while the |
72 | * path is unresolved | 74 | * path is unresolved |
73 | * @dsn: destination sequence number of the destination | 75 | * @sn: target sequence number |
74 | * @metric: current metric to this destination | 76 | * @metric: current metric to this destination |
75 | * @hop_count: hops to destination | 77 | * @hop_count: hops to destination |
76 | * @exp_time: in jiffies, when the path will expire or when it expired | 78 | * @exp_time: in jiffies, when the path will expire or when it expired |
@@ -94,7 +96,7 @@ struct mesh_path { | |||
94 | struct timer_list timer; | 96 | struct timer_list timer; |
95 | struct sk_buff_head frame_queue; | 97 | struct sk_buff_head frame_queue; |
96 | struct rcu_head rcu; | 98 | struct rcu_head rcu; |
97 | u32 dsn; | 99 | u32 sn; |
98 | u32 metric; | 100 | u32 metric; |
99 | u8 hop_count; | 101 | u8 hop_count; |
100 | unsigned long exp_time; | 102 | unsigned long exp_time; |
@@ -174,7 +176,7 @@ struct mesh_rmc { | |||
174 | #define MESH_CFG_CMP_LEN (IEEE80211_MESH_CONFIG_LEN - 2) | 176 | #define MESH_CFG_CMP_LEN (IEEE80211_MESH_CONFIG_LEN - 2) |
175 | 177 | ||
176 | /* Default values, timeouts in ms */ | 178 | /* Default values, timeouts in ms */ |
177 | #define MESH_TTL 5 | 179 | #define MESH_TTL 31 |
178 | #define MESH_MAX_RETR 3 | 180 | #define MESH_MAX_RETR 3 |
179 | #define MESH_RET_T 100 | 181 | #define MESH_RET_T 100 |
180 | #define MESH_CONF_T 100 | 182 | #define MESH_CONF_T 100 |
@@ -206,8 +208,14 @@ struct mesh_rmc { | |||
206 | #define MESH_MAX_MPATHS 1024 | 208 | #define MESH_MAX_MPATHS 1024 |
207 | 209 | ||
208 | /* Pending ANA approval */ | 210 | /* Pending ANA approval */ |
209 | #define PLINK_CATEGORY 30 | 211 | #define MESH_PLINK_CATEGORY 30 |
210 | #define MESH_PATH_SEL_CATEGORY 32 | 212 | #define MESH_PATH_SEL_CATEGORY 32 |
213 | #define MESH_PATH_SEL_ACTION 0 | ||
214 | |||
215 | /* PERR reason codes */ | ||
216 | #define PEER_RCODE_UNSPECIFIED 11 | ||
217 | #define PERR_RCODE_NO_ROUTE 12 | ||
218 | #define PERR_RCODE_DEST_UNREACH 13 | ||
211 | 219 | ||
212 | /* Public interfaces */ | 220 | /* Public interfaces */ |
213 | /* Various */ | 221 | /* Various */ |
@@ -234,6 +242,7 @@ ieee80211_rx_result | |||
234 | ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); | 242 | ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); |
235 | void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); | 243 | void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); |
236 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata); | 244 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata); |
245 | void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh); | ||
237 | 246 | ||
238 | /* Mesh paths */ | 247 | /* Mesh paths */ |
239 | int mesh_nexthop_lookup(struct sk_buff *skb, | 248 | int mesh_nexthop_lookup(struct sk_buff *skb, |
@@ -274,8 +283,8 @@ void mesh_mpp_table_grow(void); | |||
274 | u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, | 283 | u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, |
275 | struct mesh_table *tbl); | 284 | struct mesh_table *tbl); |
276 | /* Mesh paths */ | 285 | /* Mesh paths */ |
277 | int mesh_path_error_tx(u8 *dest, __le32 dest_dsn, u8 *ra, | 286 | int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, __le16 target_rcode, |
278 | struct ieee80211_sub_if_data *sdata); | 287 | u8 *ra, struct ieee80211_sub_if_data *sdata); |
279 | void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta); | 288 | void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta); |
280 | void mesh_path_flush_pending(struct mesh_path *mpath); | 289 | void mesh_path_flush_pending(struct mesh_path *mpath); |
281 | void mesh_path_tx_pending(struct mesh_path *mpath); | 290 | void mesh_path_tx_pending(struct mesh_path *mpath); |
@@ -288,6 +297,7 @@ void mesh_path_discard_frame(struct sk_buff *skb, | |||
288 | struct ieee80211_sub_if_data *sdata); | 297 | struct ieee80211_sub_if_data *sdata); |
289 | void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata); | 298 | void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata); |
290 | void mesh_path_restart(struct ieee80211_sub_if_data *sdata); | 299 | void mesh_path_restart(struct ieee80211_sub_if_data *sdata); |
300 | void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata); | ||
291 | 301 | ||
292 | extern int mesh_paths_generation; | 302 | extern int mesh_paths_generation; |
293 | 303 | ||
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 29b82e98effa..5c67e7b8790f 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2008 open80211s Ltd. | 2 | * Copyright (c) 2008, 2009 open80211s Ltd. |
3 | * Author: Luis Carlos Cobo <luisca@cozybit.com> | 3 | * Author: Luis Carlos Cobo <luisca@cozybit.com> |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
@@ -9,6 +9,12 @@ | |||
9 | 9 | ||
10 | #include "mesh.h" | 10 | #include "mesh.h" |
11 | 11 | ||
12 | #ifdef CONFIG_MAC80211_VERBOSE_MHWMP_DEBUG | ||
13 | #define mhwmp_dbg(fmt, args...) printk(KERN_DEBUG "Mesh HWMP: " fmt, ##args) | ||
14 | #else | ||
15 | #define mhwmp_dbg(fmt, args...) do { (void)(0); } while (0) | ||
16 | #endif | ||
17 | |||
12 | #define TEST_FRAME_LEN 8192 | 18 | #define TEST_FRAME_LEN 8192 |
13 | #define MAX_METRIC 0xffffffff | 19 | #define MAX_METRIC 0xffffffff |
14 | #define ARITH_SHIFT 8 | 20 | #define ARITH_SHIFT 8 |
@@ -21,6 +27,12 @@ | |||
21 | #define MP_F_DO 0x1 | 27 | #define MP_F_DO 0x1 |
22 | /* Reply and forward */ | 28 | /* Reply and forward */ |
23 | #define MP_F_RF 0x2 | 29 | #define MP_F_RF 0x2 |
30 | /* Unknown Sequence Number */ | ||
31 | #define MP_F_USN 0x01 | ||
32 | /* Reason code Present */ | ||
33 | #define MP_F_RCODE 0x02 | ||
34 | |||
35 | static void mesh_queue_preq(struct mesh_path *, u8); | ||
24 | 36 | ||
25 | static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae) | 37 | static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae) |
26 | { | 38 | { |
@@ -29,6 +41,13 @@ static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae) | |||
29 | return get_unaligned_le32(preq_elem + offset); | 41 | return get_unaligned_le32(preq_elem + offset); |
30 | } | 42 | } |
31 | 43 | ||
44 | static inline u32 u16_field_get(u8 *preq_elem, int offset, bool ae) | ||
45 | { | ||
46 | if (ae) | ||
47 | offset += 6; | ||
48 | return get_unaligned_le16(preq_elem + offset); | ||
49 | } | ||
50 | |||
32 | /* HWMP IE processing macros */ | 51 | /* HWMP IE processing macros */ |
33 | #define AE_F (1<<6) | 52 | #define AE_F (1<<6) |
34 | #define AE_F_SET(x) (*x & AE_F) | 53 | #define AE_F_SET(x) (*x & AE_F) |
@@ -37,30 +56,33 @@ static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae) | |||
37 | #define PREQ_IE_TTL(x) (*(x + 2)) | 56 | #define PREQ_IE_TTL(x) (*(x + 2)) |
38 | #define PREQ_IE_PREQ_ID(x) u32_field_get(x, 3, 0) | 57 | #define PREQ_IE_PREQ_ID(x) u32_field_get(x, 3, 0) |
39 | #define PREQ_IE_ORIG_ADDR(x) (x + 7) | 58 | #define PREQ_IE_ORIG_ADDR(x) (x + 7) |
40 | #define PREQ_IE_ORIG_DSN(x) u32_field_get(x, 13, 0); | 59 | #define PREQ_IE_ORIG_SN(x) u32_field_get(x, 13, 0); |
41 | #define PREQ_IE_LIFETIME(x) u32_field_get(x, 17, AE_F_SET(x)); | 60 | #define PREQ_IE_LIFETIME(x) u32_field_get(x, 17, AE_F_SET(x)); |
42 | #define PREQ_IE_METRIC(x) u32_field_get(x, 21, AE_F_SET(x)); | 61 | #define PREQ_IE_METRIC(x) u32_field_get(x, 21, AE_F_SET(x)); |
43 | #define PREQ_IE_DST_F(x) (*(AE_F_SET(x) ? x + 32 : x + 26)) | 62 | #define PREQ_IE_TARGET_F(x) (*(AE_F_SET(x) ? x + 32 : x + 26)) |
44 | #define PREQ_IE_DST_ADDR(x) (AE_F_SET(x) ? x + 33 : x + 27) | 63 | #define PREQ_IE_TARGET_ADDR(x) (AE_F_SET(x) ? x + 33 : x + 27) |
45 | #define PREQ_IE_DST_DSN(x) u32_field_get(x, 33, AE_F_SET(x)); | 64 | #define PREQ_IE_TARGET_SN(x) u32_field_get(x, 33, AE_F_SET(x)); |
46 | 65 | ||
47 | 66 | ||
48 | #define PREP_IE_FLAGS(x) PREQ_IE_FLAGS(x) | 67 | #define PREP_IE_FLAGS(x) PREQ_IE_FLAGS(x) |
49 | #define PREP_IE_HOPCOUNT(x) PREQ_IE_HOPCOUNT(x) | 68 | #define PREP_IE_HOPCOUNT(x) PREQ_IE_HOPCOUNT(x) |
50 | #define PREP_IE_TTL(x) PREQ_IE_TTL(x) | 69 | #define PREP_IE_TTL(x) PREQ_IE_TTL(x) |
51 | #define PREP_IE_ORIG_ADDR(x) (x + 3) | 70 | #define PREP_IE_ORIG_ADDR(x) (x + 3) |
52 | #define PREP_IE_ORIG_DSN(x) u32_field_get(x, 9, 0); | 71 | #define PREP_IE_ORIG_SN(x) u32_field_get(x, 9, 0); |
53 | #define PREP_IE_LIFETIME(x) u32_field_get(x, 13, AE_F_SET(x)); | 72 | #define PREP_IE_LIFETIME(x) u32_field_get(x, 13, AE_F_SET(x)); |
54 | #define PREP_IE_METRIC(x) u32_field_get(x, 17, AE_F_SET(x)); | 73 | #define PREP_IE_METRIC(x) u32_field_get(x, 17, AE_F_SET(x)); |
55 | #define PREP_IE_DST_ADDR(x) (AE_F_SET(x) ? x + 27 : x + 21) | 74 | #define PREP_IE_TARGET_ADDR(x) (AE_F_SET(x) ? x + 27 : x + 21) |
56 | #define PREP_IE_DST_DSN(x) u32_field_get(x, 27, AE_F_SET(x)); | 75 | #define PREP_IE_TARGET_SN(x) u32_field_get(x, 27, AE_F_SET(x)); |
57 | 76 | ||
58 | #define PERR_IE_DST_ADDR(x) (x + 2) | 77 | #define PERR_IE_TTL(x) (*(x)) |
59 | #define PERR_IE_DST_DSN(x) u32_field_get(x, 8, 0); | 78 | #define PERR_IE_TARGET_FLAGS(x) (*(x + 2)) |
79 | #define PERR_IE_TARGET_ADDR(x) (x + 3) | ||
80 | #define PERR_IE_TARGET_SN(x) u32_field_get(x, 9, 0); | ||
81 | #define PERR_IE_TARGET_RCODE(x) u16_field_get(x, 13, 0); | ||
60 | 82 | ||
61 | #define MSEC_TO_TU(x) (x*1000/1024) | 83 | #define MSEC_TO_TU(x) (x*1000/1024) |
62 | #define DSN_GT(x, y) ((long) (y) - (long) (x) < 0) | 84 | #define SN_GT(x, y) ((long) (y) - (long) (x) < 0) |
63 | #define DSN_LT(x, y) ((long) (x) - (long) (y) < 0) | 85 | #define SN_LT(x, y) ((long) (x) - (long) (y) < 0) |
64 | 86 | ||
65 | #define net_traversal_jiffies(s) \ | 87 | #define net_traversal_jiffies(s) \ |
66 | msecs_to_jiffies(s->u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime) | 88 | msecs_to_jiffies(s->u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime) |
@@ -75,13 +97,15 @@ static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae) | |||
75 | enum mpath_frame_type { | 97 | enum mpath_frame_type { |
76 | MPATH_PREQ = 0, | 98 | MPATH_PREQ = 0, |
77 | MPATH_PREP, | 99 | MPATH_PREP, |
78 | MPATH_PERR | 100 | MPATH_PERR, |
101 | MPATH_RANN | ||
79 | }; | 102 | }; |
80 | 103 | ||
81 | static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, | 104 | static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, |
82 | u8 *orig_addr, __le32 orig_dsn, u8 dst_flags, u8 *dst, | 105 | u8 *orig_addr, __le32 orig_sn, u8 target_flags, u8 *target, |
83 | __le32 dst_dsn, u8 *da, u8 hop_count, u8 ttl, __le32 lifetime, | 106 | __le32 target_sn, u8 *da, u8 hop_count, u8 ttl,__le32 lifetime, |
84 | __le32 metric, __le32 preq_id, struct ieee80211_sub_if_data *sdata) | 107 | __le32 metric, __le32 preq_id, |
108 | struct ieee80211_sub_if_data *sdata) | ||
85 | { | 109 | { |
86 | struct ieee80211_local *local = sdata->local; | 110 | struct ieee80211_local *local = sdata->local; |
87 | struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); | 111 | struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); |
@@ -103,21 +127,30 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, | |||
103 | 127 | ||
104 | memcpy(mgmt->da, da, ETH_ALEN); | 128 | memcpy(mgmt->da, da, ETH_ALEN); |
105 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 129 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
106 | /* BSSID is left zeroed, wildcard value */ | 130 | /* BSSID == SA */ |
131 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | ||
107 | mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; | 132 | mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; |
108 | mgmt->u.action.u.mesh_action.action_code = action; | 133 | mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION; |
109 | 134 | ||
110 | switch (action) { | 135 | switch (action) { |
111 | case MPATH_PREQ: | 136 | case MPATH_PREQ: |
137 | mhwmp_dbg("sending PREQ to %pM\n", target); | ||
112 | ie_len = 37; | 138 | ie_len = 37; |
113 | pos = skb_put(skb, 2 + ie_len); | 139 | pos = skb_put(skb, 2 + ie_len); |
114 | *pos++ = WLAN_EID_PREQ; | 140 | *pos++ = WLAN_EID_PREQ; |
115 | break; | 141 | break; |
116 | case MPATH_PREP: | 142 | case MPATH_PREP: |
143 | mhwmp_dbg("sending PREP to %pM\n", target); | ||
117 | ie_len = 31; | 144 | ie_len = 31; |
118 | pos = skb_put(skb, 2 + ie_len); | 145 | pos = skb_put(skb, 2 + ie_len); |
119 | *pos++ = WLAN_EID_PREP; | 146 | *pos++ = WLAN_EID_PREP; |
120 | break; | 147 | break; |
148 | case MPATH_RANN: | ||
149 | mhwmp_dbg("sending RANN from %pM\n", orig_addr); | ||
150 | ie_len = sizeof(struct ieee80211_rann_ie); | ||
151 | pos = skb_put(skb, 2 + ie_len); | ||
152 | *pos++ = WLAN_EID_RANN; | ||
153 | break; | ||
121 | default: | 154 | default: |
122 | kfree_skb(skb); | 155 | kfree_skb(skb); |
123 | return -ENOTSUPP; | 156 | return -ENOTSUPP; |
@@ -133,20 +166,24 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, | |||
133 | } | 166 | } |
134 | memcpy(pos, orig_addr, ETH_ALEN); | 167 | memcpy(pos, orig_addr, ETH_ALEN); |
135 | pos += ETH_ALEN; | 168 | pos += ETH_ALEN; |
136 | memcpy(pos, &orig_dsn, 4); | 169 | memcpy(pos, &orig_sn, 4); |
137 | pos += 4; | ||
138 | memcpy(pos, &lifetime, 4); | ||
139 | pos += 4; | 170 | pos += 4; |
171 | if (action != MPATH_RANN) { | ||
172 | memcpy(pos, &lifetime, 4); | ||
173 | pos += 4; | ||
174 | } | ||
140 | memcpy(pos, &metric, 4); | 175 | memcpy(pos, &metric, 4); |
141 | pos += 4; | 176 | pos += 4; |
142 | if (action == MPATH_PREQ) { | 177 | if (action == MPATH_PREQ) { |
143 | /* destination count */ | 178 | /* destination count */ |
144 | *pos++ = 1; | 179 | *pos++ = 1; |
145 | *pos++ = dst_flags; | 180 | *pos++ = target_flags; |
181 | } | ||
182 | if (action != MPATH_RANN) { | ||
183 | memcpy(pos, target, ETH_ALEN); | ||
184 | pos += ETH_ALEN; | ||
185 | memcpy(pos, &target_sn, 4); | ||
146 | } | 186 | } |
147 | memcpy(pos, dst, ETH_ALEN); | ||
148 | pos += ETH_ALEN; | ||
149 | memcpy(pos, &dst_dsn, 4); | ||
150 | 187 | ||
151 | ieee80211_tx_skb(sdata, skb, 1); | 188 | ieee80211_tx_skb(sdata, skb, 1); |
152 | return 0; | 189 | return 0; |
@@ -155,11 +192,13 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, | |||
155 | /** | 192 | /** |
156 | * mesh_send_path error - Sends a PERR mesh management frame | 193 | * mesh_send_path error - Sends a PERR mesh management frame |
157 | * | 194 | * |
158 | * @dst: broken destination | 195 | * @target: broken destination |
159 | * @dst_dsn: dsn of the broken destination | 196 | * @target_sn: SN of the broken destination |
197 | * @target_rcode: reason code for this PERR | ||
160 | * @ra: node this frame is addressed to | 198 | * @ra: node this frame is addressed to |
161 | */ | 199 | */ |
162 | int mesh_path_error_tx(u8 *dst, __le32 dst_dsn, u8 *ra, | 200 | int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, |
201 | __le16 target_rcode, u8 *ra, | ||
163 | struct ieee80211_sub_if_data *sdata) | 202 | struct ieee80211_sub_if_data *sdata) |
164 | { | 203 | { |
165 | struct ieee80211_local *local = sdata->local; | 204 | struct ieee80211_local *local = sdata->local; |
@@ -184,18 +223,30 @@ int mesh_path_error_tx(u8 *dst, __le32 dst_dsn, u8 *ra, | |||
184 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 223 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
185 | /* BSSID is left zeroed, wildcard value */ | 224 | /* BSSID is left zeroed, wildcard value */ |
186 | mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; | 225 | mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; |
187 | mgmt->u.action.u.mesh_action.action_code = MPATH_PERR; | 226 | mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION; |
188 | ie_len = 12; | 227 | ie_len = 15; |
189 | pos = skb_put(skb, 2 + ie_len); | 228 | pos = skb_put(skb, 2 + ie_len); |
190 | *pos++ = WLAN_EID_PERR; | 229 | *pos++ = WLAN_EID_PERR; |
191 | *pos++ = ie_len; | 230 | *pos++ = ie_len; |
192 | /* mode flags, reserved */ | 231 | /* ttl */ |
193 | *pos++ = 0; | 232 | *pos++ = MESH_TTL; |
194 | /* number of destinations */ | 233 | /* number of destinations */ |
195 | *pos++ = 1; | 234 | *pos++ = 1; |
196 | memcpy(pos, dst, ETH_ALEN); | 235 | /* |
236 | * flags bit, bit 1 is unset if we know the sequence number and | ||
237 | * bit 2 is set if we have a reason code | ||
238 | */ | ||
239 | *pos = 0; | ||
240 | if (!target_sn) | ||
241 | *pos |= MP_F_USN; | ||
242 | if (target_rcode) | ||
243 | *pos |= MP_F_RCODE; | ||
244 | pos++; | ||
245 | memcpy(pos, target, ETH_ALEN); | ||
197 | pos += ETH_ALEN; | 246 | pos += ETH_ALEN; |
198 | memcpy(pos, &dst_dsn, 4); | 247 | memcpy(pos, &target_sn, 4); |
248 | pos += 4; | ||
249 | memcpy(pos, &target_rcode, 2); | ||
199 | 250 | ||
200 | ieee80211_tx_skb(sdata, skb, 1); | 251 | ieee80211_tx_skb(sdata, skb, 1); |
201 | return 0; | 252 | return 0; |
@@ -269,18 +320,17 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local, | |||
269 | */ | 320 | */ |
270 | static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, | 321 | static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, |
271 | struct ieee80211_mgmt *mgmt, | 322 | struct ieee80211_mgmt *mgmt, |
272 | u8 *hwmp_ie) | 323 | u8 *hwmp_ie, enum mpath_frame_type action) |
273 | { | 324 | { |
274 | struct ieee80211_local *local = sdata->local; | 325 | struct ieee80211_local *local = sdata->local; |
275 | struct mesh_path *mpath; | 326 | struct mesh_path *mpath; |
276 | struct sta_info *sta; | 327 | struct sta_info *sta; |
277 | bool fresh_info; | 328 | bool fresh_info; |
278 | u8 *orig_addr, *ta; | 329 | u8 *orig_addr, *ta; |
279 | u32 orig_dsn, orig_metric; | 330 | u32 orig_sn, orig_metric; |
280 | unsigned long orig_lifetime, exp_time; | 331 | unsigned long orig_lifetime, exp_time; |
281 | u32 last_hop_metric, new_metric; | 332 | u32 last_hop_metric, new_metric; |
282 | bool process = true; | 333 | bool process = true; |
283 | u8 action = mgmt->u.action.u.mesh_action.action_code; | ||
284 | 334 | ||
285 | rcu_read_lock(); | 335 | rcu_read_lock(); |
286 | sta = sta_info_get(local, mgmt->sa); | 336 | sta = sta_info_get(local, mgmt->sa); |
@@ -296,7 +346,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, | |||
296 | switch (action) { | 346 | switch (action) { |
297 | case MPATH_PREQ: | 347 | case MPATH_PREQ: |
298 | orig_addr = PREQ_IE_ORIG_ADDR(hwmp_ie); | 348 | orig_addr = PREQ_IE_ORIG_ADDR(hwmp_ie); |
299 | orig_dsn = PREQ_IE_ORIG_DSN(hwmp_ie); | 349 | orig_sn = PREQ_IE_ORIG_SN(hwmp_ie); |
300 | orig_lifetime = PREQ_IE_LIFETIME(hwmp_ie); | 350 | orig_lifetime = PREQ_IE_LIFETIME(hwmp_ie); |
301 | orig_metric = PREQ_IE_METRIC(hwmp_ie); | 351 | orig_metric = PREQ_IE_METRIC(hwmp_ie); |
302 | break; | 352 | break; |
@@ -309,7 +359,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, | |||
309 | * information from both PREQ and PREP frames. | 359 | * information from both PREQ and PREP frames. |
310 | */ | 360 | */ |
311 | orig_addr = PREP_IE_ORIG_ADDR(hwmp_ie); | 361 | orig_addr = PREP_IE_ORIG_ADDR(hwmp_ie); |
312 | orig_dsn = PREP_IE_ORIG_DSN(hwmp_ie); | 362 | orig_sn = PREP_IE_ORIG_SN(hwmp_ie); |
313 | orig_lifetime = PREP_IE_LIFETIME(hwmp_ie); | 363 | orig_lifetime = PREP_IE_LIFETIME(hwmp_ie); |
314 | orig_metric = PREP_IE_METRIC(hwmp_ie); | 364 | orig_metric = PREP_IE_METRIC(hwmp_ie); |
315 | break; | 365 | break; |
@@ -335,9 +385,9 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, | |||
335 | if (mpath->flags & MESH_PATH_FIXED) | 385 | if (mpath->flags & MESH_PATH_FIXED) |
336 | fresh_info = false; | 386 | fresh_info = false; |
337 | else if ((mpath->flags & MESH_PATH_ACTIVE) && | 387 | else if ((mpath->flags & MESH_PATH_ACTIVE) && |
338 | (mpath->flags & MESH_PATH_DSN_VALID)) { | 388 | (mpath->flags & MESH_PATH_SN_VALID)) { |
339 | if (DSN_GT(mpath->dsn, orig_dsn) || | 389 | if (SN_GT(mpath->sn, orig_sn) || |
340 | (mpath->dsn == orig_dsn && | 390 | (mpath->sn == orig_sn && |
341 | action == MPATH_PREQ && | 391 | action == MPATH_PREQ && |
342 | new_metric > mpath->metric)) { | 392 | new_metric > mpath->metric)) { |
343 | process = false; | 393 | process = false; |
@@ -356,9 +406,9 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, | |||
356 | 406 | ||
357 | if (fresh_info) { | 407 | if (fresh_info) { |
358 | mesh_path_assign_nexthop(mpath, sta); | 408 | mesh_path_assign_nexthop(mpath, sta); |
359 | mpath->flags |= MESH_PATH_DSN_VALID; | 409 | mpath->flags |= MESH_PATH_SN_VALID; |
360 | mpath->metric = new_metric; | 410 | mpath->metric = new_metric; |
361 | mpath->dsn = orig_dsn; | 411 | mpath->sn = orig_sn; |
362 | mpath->exp_time = time_after(mpath->exp_time, exp_time) | 412 | mpath->exp_time = time_after(mpath->exp_time, exp_time) |
363 | ? mpath->exp_time : exp_time; | 413 | ? mpath->exp_time : exp_time; |
364 | mesh_path_activate(mpath); | 414 | mesh_path_activate(mpath); |
@@ -397,7 +447,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, | |||
397 | 447 | ||
398 | if (fresh_info) { | 448 | if (fresh_info) { |
399 | mesh_path_assign_nexthop(mpath, sta); | 449 | mesh_path_assign_nexthop(mpath, sta); |
400 | mpath->flags &= ~MESH_PATH_DSN_VALID; | 450 | mpath->flags &= ~MESH_PATH_SN_VALID; |
401 | mpath->metric = last_hop_metric; | 451 | mpath->metric = last_hop_metric; |
402 | mpath->exp_time = time_after(mpath->exp_time, exp_time) | 452 | mpath->exp_time = time_after(mpath->exp_time, exp_time) |
403 | ? mpath->exp_time : exp_time; | 453 | ? mpath->exp_time : exp_time; |
@@ -419,44 +469,47 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, | |||
419 | { | 469 | { |
420 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 470 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
421 | struct mesh_path *mpath; | 471 | struct mesh_path *mpath; |
422 | u8 *dst_addr, *orig_addr; | 472 | u8 *target_addr, *orig_addr; |
423 | u8 dst_flags, ttl; | 473 | u8 target_flags, ttl; |
424 | u32 orig_dsn, dst_dsn, lifetime; | 474 | u32 orig_sn, target_sn, lifetime; |
425 | bool reply = false; | 475 | bool reply = false; |
426 | bool forward = true; | 476 | bool forward = true; |
427 | 477 | ||
428 | /* Update destination DSN, if present */ | 478 | /* Update target SN, if present */ |
429 | dst_addr = PREQ_IE_DST_ADDR(preq_elem); | 479 | target_addr = PREQ_IE_TARGET_ADDR(preq_elem); |
430 | orig_addr = PREQ_IE_ORIG_ADDR(preq_elem); | 480 | orig_addr = PREQ_IE_ORIG_ADDR(preq_elem); |
431 | dst_dsn = PREQ_IE_DST_DSN(preq_elem); | 481 | target_sn = PREQ_IE_TARGET_SN(preq_elem); |
432 | orig_dsn = PREQ_IE_ORIG_DSN(preq_elem); | 482 | orig_sn = PREQ_IE_ORIG_SN(preq_elem); |
433 | dst_flags = PREQ_IE_DST_F(preq_elem); | 483 | target_flags = PREQ_IE_TARGET_F(preq_elem); |
434 | 484 | ||
435 | if (memcmp(dst_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) { | 485 | mhwmp_dbg("received PREQ from %pM\n", orig_addr); |
486 | |||
487 | if (memcmp(target_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) { | ||
488 | mhwmp_dbg("PREQ is for us\n"); | ||
436 | forward = false; | 489 | forward = false; |
437 | reply = true; | 490 | reply = true; |
438 | metric = 0; | 491 | metric = 0; |
439 | if (time_after(jiffies, ifmsh->last_dsn_update + | 492 | if (time_after(jiffies, ifmsh->last_sn_update + |
440 | net_traversal_jiffies(sdata)) || | 493 | net_traversal_jiffies(sdata)) || |
441 | time_before(jiffies, ifmsh->last_dsn_update)) { | 494 | time_before(jiffies, ifmsh->last_sn_update)) { |
442 | dst_dsn = ++ifmsh->dsn; | 495 | target_sn = ++ifmsh->sn; |
443 | ifmsh->last_dsn_update = jiffies; | 496 | ifmsh->last_sn_update = jiffies; |
444 | } | 497 | } |
445 | } else { | 498 | } else { |
446 | rcu_read_lock(); | 499 | rcu_read_lock(); |
447 | mpath = mesh_path_lookup(dst_addr, sdata); | 500 | mpath = mesh_path_lookup(target_addr, sdata); |
448 | if (mpath) { | 501 | if (mpath) { |
449 | if ((!(mpath->flags & MESH_PATH_DSN_VALID)) || | 502 | if ((!(mpath->flags & MESH_PATH_SN_VALID)) || |
450 | DSN_LT(mpath->dsn, dst_dsn)) { | 503 | SN_LT(mpath->sn, target_sn)) { |
451 | mpath->dsn = dst_dsn; | 504 | mpath->sn = target_sn; |
452 | mpath->flags |= MESH_PATH_DSN_VALID; | 505 | mpath->flags |= MESH_PATH_SN_VALID; |
453 | } else if ((!(dst_flags & MP_F_DO)) && | 506 | } else if ((!(target_flags & MP_F_DO)) && |
454 | (mpath->flags & MESH_PATH_ACTIVE)) { | 507 | (mpath->flags & MESH_PATH_ACTIVE)) { |
455 | reply = true; | 508 | reply = true; |
456 | metric = mpath->metric; | 509 | metric = mpath->metric; |
457 | dst_dsn = mpath->dsn; | 510 | target_sn = mpath->sn; |
458 | if (dst_flags & MP_F_RF) | 511 | if (target_flags & MP_F_RF) |
459 | dst_flags |= MP_F_DO; | 512 | target_flags |= MP_F_DO; |
460 | else | 513 | else |
461 | forward = false; | 514 | forward = false; |
462 | } | 515 | } |
@@ -467,13 +520,14 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, | |||
467 | if (reply) { | 520 | if (reply) { |
468 | lifetime = PREQ_IE_LIFETIME(preq_elem); | 521 | lifetime = PREQ_IE_LIFETIME(preq_elem); |
469 | ttl = ifmsh->mshcfg.dot11MeshTTL; | 522 | ttl = ifmsh->mshcfg.dot11MeshTTL; |
470 | if (ttl != 0) | 523 | if (ttl != 0) { |
471 | mesh_path_sel_frame_tx(MPATH_PREP, 0, dst_addr, | 524 | mhwmp_dbg("replying to the PREQ\n"); |
472 | cpu_to_le32(dst_dsn), 0, orig_addr, | 525 | mesh_path_sel_frame_tx(MPATH_PREP, 0, target_addr, |
473 | cpu_to_le32(orig_dsn), mgmt->sa, 0, ttl, | 526 | cpu_to_le32(target_sn), 0, orig_addr, |
527 | cpu_to_le32(orig_sn), mgmt->sa, 0, ttl, | ||
474 | cpu_to_le32(lifetime), cpu_to_le32(metric), | 528 | cpu_to_le32(lifetime), cpu_to_le32(metric), |
475 | 0, sdata); | 529 | 0, sdata); |
476 | else | 530 | } else |
477 | ifmsh->mshstats.dropped_frames_ttl++; | 531 | ifmsh->mshstats.dropped_frames_ttl++; |
478 | } | 532 | } |
479 | 533 | ||
@@ -487,13 +541,14 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, | |||
487 | ifmsh->mshstats.dropped_frames_ttl++; | 541 | ifmsh->mshstats.dropped_frames_ttl++; |
488 | return; | 542 | return; |
489 | } | 543 | } |
544 | mhwmp_dbg("forwarding the PREQ from %pM\n", orig_addr); | ||
490 | --ttl; | 545 | --ttl; |
491 | flags = PREQ_IE_FLAGS(preq_elem); | 546 | flags = PREQ_IE_FLAGS(preq_elem); |
492 | preq_id = PREQ_IE_PREQ_ID(preq_elem); | 547 | preq_id = PREQ_IE_PREQ_ID(preq_elem); |
493 | hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1; | 548 | hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1; |
494 | mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr, | 549 | mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr, |
495 | cpu_to_le32(orig_dsn), dst_flags, dst_addr, | 550 | cpu_to_le32(orig_sn), target_flags, target_addr, |
496 | cpu_to_le32(dst_dsn), sdata->dev->broadcast, | 551 | cpu_to_le32(target_sn), sdata->dev->broadcast, |
497 | hopcount, ttl, cpu_to_le32(lifetime), | 552 | hopcount, ttl, cpu_to_le32(lifetime), |
498 | cpu_to_le32(metric), cpu_to_le32(preq_id), | 553 | cpu_to_le32(metric), cpu_to_le32(preq_id), |
499 | sdata); | 554 | sdata); |
@@ -508,10 +563,12 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, | |||
508 | u8 *prep_elem, u32 metric) | 563 | u8 *prep_elem, u32 metric) |
509 | { | 564 | { |
510 | struct mesh_path *mpath; | 565 | struct mesh_path *mpath; |
511 | u8 *dst_addr, *orig_addr; | 566 | u8 *target_addr, *orig_addr; |
512 | u8 ttl, hopcount, flags; | 567 | u8 ttl, hopcount, flags; |
513 | u8 next_hop[ETH_ALEN]; | 568 | u8 next_hop[ETH_ALEN]; |
514 | u32 dst_dsn, orig_dsn, lifetime; | 569 | u32 target_sn, orig_sn, lifetime; |
570 | |||
571 | mhwmp_dbg("received PREP from %pM\n", PREP_IE_ORIG_ADDR(prep_elem)); | ||
515 | 572 | ||
516 | /* Note that we divert from the draft nomenclature and denominate | 573 | /* Note that we divert from the draft nomenclature and denominate |
517 | * destination to what the draft refers to as origininator. So in this | 574 | * destination to what the draft refers to as origininator. So in this |
@@ -519,8 +576,8 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, | |||
519 | * which corresponds with the originator of the PREQ which this PREP | 576 | * which corresponds with the originator of the PREQ which this PREP |
520 | * replies | 577 | * replies |
521 | */ | 578 | */ |
522 | dst_addr = PREP_IE_DST_ADDR(prep_elem); | 579 | target_addr = PREP_IE_TARGET_ADDR(prep_elem); |
523 | if (memcmp(dst_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) | 580 | if (memcmp(target_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) |
524 | /* destination, no forwarding required */ | 581 | /* destination, no forwarding required */ |
525 | return; | 582 | return; |
526 | 583 | ||
@@ -531,7 +588,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, | |||
531 | } | 588 | } |
532 | 589 | ||
533 | rcu_read_lock(); | 590 | rcu_read_lock(); |
534 | mpath = mesh_path_lookup(dst_addr, sdata); | 591 | mpath = mesh_path_lookup(target_addr, sdata); |
535 | if (mpath) | 592 | if (mpath) |
536 | spin_lock_bh(&mpath->state_lock); | 593 | spin_lock_bh(&mpath->state_lock); |
537 | else | 594 | else |
@@ -547,13 +604,13 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, | |||
547 | lifetime = PREP_IE_LIFETIME(prep_elem); | 604 | lifetime = PREP_IE_LIFETIME(prep_elem); |
548 | hopcount = PREP_IE_HOPCOUNT(prep_elem) + 1; | 605 | hopcount = PREP_IE_HOPCOUNT(prep_elem) + 1; |
549 | orig_addr = PREP_IE_ORIG_ADDR(prep_elem); | 606 | orig_addr = PREP_IE_ORIG_ADDR(prep_elem); |
550 | dst_dsn = PREP_IE_DST_DSN(prep_elem); | 607 | target_sn = PREP_IE_TARGET_SN(prep_elem); |
551 | orig_dsn = PREP_IE_ORIG_DSN(prep_elem); | 608 | orig_sn = PREP_IE_ORIG_SN(prep_elem); |
552 | 609 | ||
553 | mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr, | 610 | mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr, |
554 | cpu_to_le32(orig_dsn), 0, dst_addr, | 611 | cpu_to_le32(orig_sn), 0, target_addr, |
555 | cpu_to_le32(dst_dsn), mpath->next_hop->sta.addr, hopcount, ttl, | 612 | cpu_to_le32(target_sn), mpath->next_hop->sta.addr, hopcount, |
556 | cpu_to_le32(lifetime), cpu_to_le32(metric), | 613 | ttl, cpu_to_le32(lifetime), cpu_to_le32(metric), |
557 | 0, sdata); | 614 | 0, sdata); |
558 | rcu_read_unlock(); | 615 | rcu_read_unlock(); |
559 | 616 | ||
@@ -570,25 +627,39 @@ fail: | |||
570 | static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, | 627 | static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, |
571 | struct ieee80211_mgmt *mgmt, u8 *perr_elem) | 628 | struct ieee80211_mgmt *mgmt, u8 *perr_elem) |
572 | { | 629 | { |
630 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
573 | struct mesh_path *mpath; | 631 | struct mesh_path *mpath; |
574 | u8 *ta, *dst_addr; | 632 | u8 ttl; |
575 | u32 dst_dsn; | 633 | u8 *ta, *target_addr; |
634 | u8 target_flags; | ||
635 | u32 target_sn; | ||
636 | u16 target_rcode; | ||
576 | 637 | ||
577 | ta = mgmt->sa; | 638 | ta = mgmt->sa; |
578 | dst_addr = PERR_IE_DST_ADDR(perr_elem); | 639 | ttl = PERR_IE_TTL(perr_elem); |
579 | dst_dsn = PERR_IE_DST_DSN(perr_elem); | 640 | if (ttl <= 1) { |
641 | ifmsh->mshstats.dropped_frames_ttl++; | ||
642 | return; | ||
643 | } | ||
644 | ttl--; | ||
645 | target_flags = PERR_IE_TARGET_FLAGS(perr_elem); | ||
646 | target_addr = PERR_IE_TARGET_ADDR(perr_elem); | ||
647 | target_sn = PERR_IE_TARGET_SN(perr_elem); | ||
648 | target_rcode = PERR_IE_TARGET_RCODE(perr_elem); | ||
649 | |||
580 | rcu_read_lock(); | 650 | rcu_read_lock(); |
581 | mpath = mesh_path_lookup(dst_addr, sdata); | 651 | mpath = mesh_path_lookup(target_addr, sdata); |
582 | if (mpath) { | 652 | if (mpath) { |
583 | spin_lock_bh(&mpath->state_lock); | 653 | spin_lock_bh(&mpath->state_lock); |
584 | if (mpath->flags & MESH_PATH_ACTIVE && | 654 | if (mpath->flags & MESH_PATH_ACTIVE && |
585 | memcmp(ta, mpath->next_hop->sta.addr, ETH_ALEN) == 0 && | 655 | memcmp(ta, mpath->next_hop->sta.addr, ETH_ALEN) == 0 && |
586 | (!(mpath->flags & MESH_PATH_DSN_VALID) || | 656 | (!(mpath->flags & MESH_PATH_SN_VALID) || |
587 | DSN_GT(dst_dsn, mpath->dsn))) { | 657 | SN_GT(target_sn, mpath->sn))) { |
588 | mpath->flags &= ~MESH_PATH_ACTIVE; | 658 | mpath->flags &= ~MESH_PATH_ACTIVE; |
589 | mpath->dsn = dst_dsn; | 659 | mpath->sn = target_sn; |
590 | spin_unlock_bh(&mpath->state_lock); | 660 | spin_unlock_bh(&mpath->state_lock); |
591 | mesh_path_error_tx(dst_addr, cpu_to_le32(dst_dsn), | 661 | mesh_path_error_tx(ttl, target_addr, cpu_to_le32(target_sn), |
662 | cpu_to_le16(target_rcode), | ||
592 | sdata->dev->broadcast, sdata); | 663 | sdata->dev->broadcast, sdata); |
593 | } else | 664 | } else |
594 | spin_unlock_bh(&mpath->state_lock); | 665 | spin_unlock_bh(&mpath->state_lock); |
@@ -596,6 +667,56 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, | |||
596 | rcu_read_unlock(); | 667 | rcu_read_unlock(); |
597 | } | 668 | } |
598 | 669 | ||
670 | static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, | ||
671 | struct ieee80211_mgmt *mgmt, | ||
672 | struct ieee80211_rann_ie *rann) | ||
673 | { | ||
674 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
675 | struct mesh_path *mpath; | ||
676 | u8 *ta; | ||
677 | u8 ttl, flags, hopcount; | ||
678 | u8 *orig_addr; | ||
679 | u32 orig_sn, metric; | ||
680 | |||
681 | ta = mgmt->sa; | ||
682 | ttl = rann->rann_ttl; | ||
683 | if (ttl <= 1) { | ||
684 | ifmsh->mshstats.dropped_frames_ttl++; | ||
685 | return; | ||
686 | } | ||
687 | ttl--; | ||
688 | flags = rann->rann_flags; | ||
689 | orig_addr = rann->rann_addr; | ||
690 | orig_sn = rann->rann_seq; | ||
691 | hopcount = rann->rann_hopcount; | ||
692 | hopcount++; | ||
693 | metric = rann->rann_metric; | ||
694 | mhwmp_dbg("received RANN from %pM\n", orig_addr); | ||
695 | |||
696 | rcu_read_lock(); | ||
697 | mpath = mesh_path_lookup(orig_addr, sdata); | ||
698 | if (!mpath) { | ||
699 | mesh_path_add(orig_addr, sdata); | ||
700 | mpath = mesh_path_lookup(orig_addr, sdata); | ||
701 | if (!mpath) { | ||
702 | rcu_read_unlock(); | ||
703 | sdata->u.mesh.mshstats.dropped_frames_no_route++; | ||
704 | return; | ||
705 | } | ||
706 | mesh_queue_preq(mpath, | ||
707 | PREQ_Q_F_START | PREQ_Q_F_REFRESH); | ||
708 | } | ||
709 | if (mpath->sn < orig_sn) { | ||
710 | mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr, | ||
711 | cpu_to_le32(orig_sn), | ||
712 | 0, NULL, 0, sdata->dev->broadcast, | ||
713 | hopcount, ttl, 0, | ||
714 | cpu_to_le32(metric + mpath->metric), | ||
715 | 0, sdata); | ||
716 | mpath->sn = orig_sn; | ||
717 | } | ||
718 | rcu_read_unlock(); | ||
719 | } | ||
599 | 720 | ||
600 | 721 | ||
601 | void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, | 722 | void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, |
@@ -614,34 +735,34 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, | |||
614 | ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable, | 735 | ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable, |
615 | len - baselen, &elems); | 736 | len - baselen, &elems); |
616 | 737 | ||
617 | switch (mgmt->u.action.u.mesh_action.action_code) { | 738 | if (elems.preq) { |
618 | case MPATH_PREQ: | 739 | if (elems.preq_len != 37) |
619 | if (!elems.preq || elems.preq_len != 37) | ||
620 | /* Right now we support just 1 destination and no AE */ | 740 | /* Right now we support just 1 destination and no AE */ |
621 | return; | 741 | return; |
622 | last_hop_metric = hwmp_route_info_get(sdata, mgmt, elems.preq); | 742 | last_hop_metric = hwmp_route_info_get(sdata, mgmt, elems.preq, |
623 | if (!last_hop_metric) | 743 | MPATH_PREQ); |
624 | return; | 744 | if (last_hop_metric) |
625 | hwmp_preq_frame_process(sdata, mgmt, elems.preq, last_hop_metric); | 745 | hwmp_preq_frame_process(sdata, mgmt, elems.preq, |
626 | break; | 746 | last_hop_metric); |
627 | case MPATH_PREP: | 747 | } |
628 | if (!elems.prep || elems.prep_len != 31) | 748 | if (elems.prep) { |
749 | if (elems.prep_len != 31) | ||
629 | /* Right now we support no AE */ | 750 | /* Right now we support no AE */ |
630 | return; | 751 | return; |
631 | last_hop_metric = hwmp_route_info_get(sdata, mgmt, elems.prep); | 752 | last_hop_metric = hwmp_route_info_get(sdata, mgmt, elems.prep, |
632 | if (!last_hop_metric) | 753 | MPATH_PREP); |
633 | return; | 754 | if (last_hop_metric) |
634 | hwmp_prep_frame_process(sdata, mgmt, elems.prep, last_hop_metric); | 755 | hwmp_prep_frame_process(sdata, mgmt, elems.prep, |
635 | break; | 756 | last_hop_metric); |
636 | case MPATH_PERR: | 757 | } |
637 | if (!elems.perr || elems.perr_len != 12) | 758 | if (elems.perr) { |
759 | if (elems.perr_len != 15) | ||
638 | /* Right now we support only one destination per PERR */ | 760 | /* Right now we support only one destination per PERR */ |
639 | return; | 761 | return; |
640 | hwmp_perr_frame_process(sdata, mgmt, elems.perr); | 762 | hwmp_perr_frame_process(sdata, mgmt, elems.perr); |
641 | default: | ||
642 | return; | ||
643 | } | 763 | } |
644 | 764 | if (elems.rann) | |
765 | hwmp_rann_frame_process(sdata, mgmt, elems.rann); | ||
645 | } | 766 | } |
646 | 767 | ||
647 | /** | 768 | /** |
@@ -661,7 +782,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags) | |||
661 | 782 | ||
662 | preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_ATOMIC); | 783 | preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_ATOMIC); |
663 | if (!preq_node) { | 784 | if (!preq_node) { |
664 | printk(KERN_DEBUG "Mesh HWMP: could not allocate PREQ node\n"); | 785 | mhwmp_dbg("could not allocate PREQ node\n"); |
665 | return; | 786 | return; |
666 | } | 787 | } |
667 | 788 | ||
@@ -670,7 +791,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags) | |||
670 | spin_unlock(&ifmsh->mesh_preq_queue_lock); | 791 | spin_unlock(&ifmsh->mesh_preq_queue_lock); |
671 | kfree(preq_node); | 792 | kfree(preq_node); |
672 | if (printk_ratelimit()) | 793 | if (printk_ratelimit()) |
673 | printk(KERN_DEBUG "Mesh HWMP: PREQ node queue full\n"); | 794 | mhwmp_dbg("PREQ node queue full\n"); |
674 | return; | 795 | return; |
675 | } | 796 | } |
676 | 797 | ||
@@ -705,7 +826,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata) | |||
705 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 826 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
706 | struct mesh_preq_queue *preq_node; | 827 | struct mesh_preq_queue *preq_node; |
707 | struct mesh_path *mpath; | 828 | struct mesh_path *mpath; |
708 | u8 ttl, dst_flags; | 829 | u8 ttl, target_flags; |
709 | u32 lifetime; | 830 | u32 lifetime; |
710 | 831 | ||
711 | spin_lock_bh(&ifmsh->mesh_preq_queue_lock); | 832 | spin_lock_bh(&ifmsh->mesh_preq_queue_lock); |
@@ -747,11 +868,11 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata) | |||
747 | 868 | ||
748 | ifmsh->last_preq = jiffies; | 869 | ifmsh->last_preq = jiffies; |
749 | 870 | ||
750 | if (time_after(jiffies, ifmsh->last_dsn_update + | 871 | if (time_after(jiffies, ifmsh->last_sn_update + |
751 | net_traversal_jiffies(sdata)) || | 872 | net_traversal_jiffies(sdata)) || |
752 | time_before(jiffies, ifmsh->last_dsn_update)) { | 873 | time_before(jiffies, ifmsh->last_sn_update)) { |
753 | ++ifmsh->dsn; | 874 | ++ifmsh->sn; |
754 | sdata->u.mesh.last_dsn_update = jiffies; | 875 | sdata->u.mesh.last_sn_update = jiffies; |
755 | } | 876 | } |
756 | lifetime = default_lifetime(sdata); | 877 | lifetime = default_lifetime(sdata); |
757 | ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; | 878 | ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; |
@@ -762,14 +883,14 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata) | |||
762 | } | 883 | } |
763 | 884 | ||
764 | if (preq_node->flags & PREQ_Q_F_REFRESH) | 885 | if (preq_node->flags & PREQ_Q_F_REFRESH) |
765 | dst_flags = MP_F_DO; | 886 | target_flags = MP_F_DO; |
766 | else | 887 | else |
767 | dst_flags = MP_F_RF; | 888 | target_flags = MP_F_RF; |
768 | 889 | ||
769 | spin_unlock_bh(&mpath->state_lock); | 890 | spin_unlock_bh(&mpath->state_lock); |
770 | mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->dev->dev_addr, | 891 | mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->dev->dev_addr, |
771 | cpu_to_le32(ifmsh->dsn), dst_flags, mpath->dst, | 892 | cpu_to_le32(ifmsh->sn), target_flags, mpath->dst, |
772 | cpu_to_le32(mpath->dsn), sdata->dev->broadcast, 0, | 893 | cpu_to_le32(mpath->sn), sdata->dev->broadcast, 0, |
773 | ttl, cpu_to_le32(lifetime), 0, | 894 | ttl, cpu_to_le32(lifetime), 0, |
774 | cpu_to_le32(ifmsh->preq_id++), sdata); | 895 | cpu_to_le32(ifmsh->preq_id++), sdata); |
775 | mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout); | 896 | mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout); |
@@ -796,15 +917,15 @@ int mesh_nexthop_lookup(struct sk_buff *skb, | |||
796 | struct sk_buff *skb_to_free = NULL; | 917 | struct sk_buff *skb_to_free = NULL; |
797 | struct mesh_path *mpath; | 918 | struct mesh_path *mpath; |
798 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 919 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
799 | u8 *dst_addr = hdr->addr3; | 920 | u8 *target_addr = hdr->addr3; |
800 | int err = 0; | 921 | int err = 0; |
801 | 922 | ||
802 | rcu_read_lock(); | 923 | rcu_read_lock(); |
803 | mpath = mesh_path_lookup(dst_addr, sdata); | 924 | mpath = mesh_path_lookup(target_addr, sdata); |
804 | 925 | ||
805 | if (!mpath) { | 926 | if (!mpath) { |
806 | mesh_path_add(dst_addr, sdata); | 927 | mesh_path_add(target_addr, sdata); |
807 | mpath = mesh_path_lookup(dst_addr, sdata); | 928 | mpath = mesh_path_lookup(target_addr, sdata); |
808 | if (!mpath) { | 929 | if (!mpath) { |
809 | sdata->u.mesh.mshstats.dropped_frames_no_route++; | 930 | sdata->u.mesh.mshstats.dropped_frames_no_route++; |
810 | err = -ENOSPC; | 931 | err = -ENOSPC; |
@@ -882,3 +1003,14 @@ void mesh_path_timer(unsigned long data) | |||
882 | endmpathtimer: | 1003 | endmpathtimer: |
883 | rcu_read_unlock(); | 1004 | rcu_read_unlock(); |
884 | } | 1005 | } |
1006 | |||
1007 | void | ||
1008 | mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata) | ||
1009 | { | ||
1010 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
1011 | |||
1012 | mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->dev->dev_addr, | ||
1013 | cpu_to_le32(++ifmsh->sn), | ||
1014 | 0, NULL, 0, sdata->dev->broadcast, | ||
1015 | 0, MESH_TTL, 0, 0, 0, sdata); | ||
1016 | } | ||
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 751c4d0e2b36..5399e7a9ec6e 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2008 open80211s Ltd. | 2 | * Copyright (c) 2008, 2009 open80211s Ltd. |
3 | * Author: Luis Carlos Cobo <luisca@cozybit.com> | 3 | * Author: Luis Carlos Cobo <luisca@cozybit.com> |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
@@ -463,10 +463,11 @@ void mesh_plink_broken(struct sta_info *sta) | |||
463 | mpath->flags & MESH_PATH_ACTIVE && | 463 | mpath->flags & MESH_PATH_ACTIVE && |
464 | !(mpath->flags & MESH_PATH_FIXED)) { | 464 | !(mpath->flags & MESH_PATH_FIXED)) { |
465 | mpath->flags &= ~MESH_PATH_ACTIVE; | 465 | mpath->flags &= ~MESH_PATH_ACTIVE; |
466 | ++mpath->dsn; | 466 | ++mpath->sn; |
467 | spin_unlock_bh(&mpath->state_lock); | 467 | spin_unlock_bh(&mpath->state_lock); |
468 | mesh_path_error_tx(mpath->dst, | 468 | mesh_path_error_tx(MESH_TTL, mpath->dst, |
469 | cpu_to_le32(mpath->dsn), | 469 | cpu_to_le32(mpath->sn), |
470 | PERR_RCODE_DEST_UNREACH, | ||
470 | sdata->dev->broadcast, sdata); | 471 | sdata->dev->broadcast, sdata); |
471 | } else | 472 | } else |
472 | spin_unlock_bh(&mpath->state_lock); | 473 | spin_unlock_bh(&mpath->state_lock); |
@@ -601,7 +602,7 @@ void mesh_path_discard_frame(struct sk_buff *skb, | |||
601 | { | 602 | { |
602 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 603 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
603 | struct mesh_path *mpath; | 604 | struct mesh_path *mpath; |
604 | u32 dsn = 0; | 605 | u32 sn = 0; |
605 | 606 | ||
606 | if (memcmp(hdr->addr4, sdata->dev->dev_addr, ETH_ALEN) != 0) { | 607 | if (memcmp(hdr->addr4, sdata->dev->dev_addr, ETH_ALEN) != 0) { |
607 | u8 *ra, *da; | 608 | u8 *ra, *da; |
@@ -610,8 +611,9 @@ void mesh_path_discard_frame(struct sk_buff *skb, | |||
610 | ra = hdr->addr1; | 611 | ra = hdr->addr1; |
611 | mpath = mesh_path_lookup(da, sdata); | 612 | mpath = mesh_path_lookup(da, sdata); |
612 | if (mpath) | 613 | if (mpath) |
613 | dsn = ++mpath->dsn; | 614 | sn = ++mpath->sn; |
614 | mesh_path_error_tx(skb->data, cpu_to_le32(dsn), ra, sdata); | 615 | mesh_path_error_tx(MESH_TTL, skb->data, cpu_to_le32(sn), |
616 | PERR_RCODE_NO_ROUTE, ra, sdata); | ||
615 | } | 617 | } |
616 | 618 | ||
617 | kfree_skb(skb); | 619 | kfree_skb(skb); |
@@ -646,7 +648,7 @@ void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop) | |||
646 | { | 648 | { |
647 | spin_lock_bh(&mpath->state_lock); | 649 | spin_lock_bh(&mpath->state_lock); |
648 | mesh_path_assign_nexthop(mpath, next_hop); | 650 | mesh_path_assign_nexthop(mpath, next_hop); |
649 | mpath->dsn = 0xffff; | 651 | mpath->sn = 0xffff; |
650 | mpath->metric = 0; | 652 | mpath->metric = 0; |
651 | mpath->hop_count = 0; | 653 | mpath->hop_count = 0; |
652 | mpath->exp_time = 0; | 654 | mpath->exp_time = 0; |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index ffcbad75e09b..f21329afdae3 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2008 open80211s Ltd. | 2 | * Copyright (c) 2008, 2009 open80211s Ltd. |
3 | * Author: Luis Carlos Cobo <luisca@cozybit.com> | 3 | * Author: Luis Carlos Cobo <luisca@cozybit.com> |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
@@ -18,9 +18,8 @@ | |||
18 | #define mpl_dbg(fmt, args...) do { (void)(0); } while (0) | 18 | #define mpl_dbg(fmt, args...) do { (void)(0); } while (0) |
19 | #endif | 19 | #endif |
20 | 20 | ||
21 | #define PLINK_GET_FRAME_SUBTYPE(p) (p) | 21 | #define PLINK_GET_LLID(p) (p + 4) |
22 | #define PLINK_GET_LLID(p) (p + 1) | 22 | #define PLINK_GET_PLID(p) (p + 6) |
23 | #define PLINK_GET_PLID(p) (p + 3) | ||
24 | 23 | ||
25 | #define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \ | 24 | #define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \ |
26 | jiffies + HZ * t / 1000)) | 25 | jiffies + HZ * t / 1000)) |
@@ -65,6 +64,7 @@ void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata) | |||
65 | { | 64 | { |
66 | atomic_inc(&sdata->u.mesh.mshstats.estab_plinks); | 65 | atomic_inc(&sdata->u.mesh.mshstats.estab_plinks); |
67 | mesh_accept_plinks_update(sdata); | 66 | mesh_accept_plinks_update(sdata); |
67 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | ||
68 | } | 68 | } |
69 | 69 | ||
70 | static inline | 70 | static inline |
@@ -72,12 +72,13 @@ void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) | |||
72 | { | 72 | { |
73 | atomic_dec(&sdata->u.mesh.mshstats.estab_plinks); | 73 | atomic_dec(&sdata->u.mesh.mshstats.estab_plinks); |
74 | mesh_accept_plinks_update(sdata); | 74 | mesh_accept_plinks_update(sdata); |
75 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | ||
75 | } | 76 | } |
76 | 77 | ||
77 | /** | 78 | /** |
78 | * mesh_plink_fsm_restart - restart a mesh peer link finite state machine | 79 | * mesh_plink_fsm_restart - restart a mesh peer link finite state machine |
79 | * | 80 | * |
80 | * @sta: mes peer link to restart | 81 | * @sta: mesh peer link to restart |
81 | * | 82 | * |
82 | * Locking: this function must be called holding sta->lock | 83 | * Locking: this function must be called holding sta->lock |
83 | */ | 84 | */ |
@@ -152,6 +153,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
152 | struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); | 153 | struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); |
153 | struct ieee80211_mgmt *mgmt; | 154 | struct ieee80211_mgmt *mgmt; |
154 | bool include_plid = false; | 155 | bool include_plid = false; |
156 | static const u8 meshpeeringproto[] = { 0x00, 0x0F, 0xAC, 0x2A }; | ||
155 | u8 *pos; | 157 | u8 *pos; |
156 | int ie_len; | 158 | int ie_len; |
157 | 159 | ||
@@ -169,7 +171,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
169 | memcpy(mgmt->da, da, ETH_ALEN); | 171 | memcpy(mgmt->da, da, ETH_ALEN); |
170 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 172 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
171 | /* BSSID is left zeroed, wildcard value */ | 173 | /* BSSID is left zeroed, wildcard value */ |
172 | mgmt->u.action.category = PLINK_CATEGORY; | 174 | mgmt->u.action.category = MESH_PLINK_CATEGORY; |
173 | mgmt->u.action.u.plink_action.action_code = action; | 175 | mgmt->u.action.u.plink_action.action_code = action; |
174 | 176 | ||
175 | if (action == PLINK_CLOSE) | 177 | if (action == PLINK_CLOSE) |
@@ -179,7 +181,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
179 | if (action == PLINK_CONFIRM) { | 181 | if (action == PLINK_CONFIRM) { |
180 | pos = skb_put(skb, 4); | 182 | pos = skb_put(skb, 4); |
181 | /* two-byte status code followed by two-byte AID */ | 183 | /* two-byte status code followed by two-byte AID */ |
182 | memset(pos, 0, 4); | 184 | memset(pos, 0, 2); |
185 | memcpy(pos + 2, &plid, 2); | ||
183 | } | 186 | } |
184 | mesh_mgmt_ies_add(skb, sdata); | 187 | mesh_mgmt_ies_add(skb, sdata); |
185 | } | 188 | } |
@@ -187,18 +190,18 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
187 | /* Add Peer Link Management element */ | 190 | /* Add Peer Link Management element */ |
188 | switch (action) { | 191 | switch (action) { |
189 | case PLINK_OPEN: | 192 | case PLINK_OPEN: |
190 | ie_len = 3; | 193 | ie_len = 6; |
191 | break; | 194 | break; |
192 | case PLINK_CONFIRM: | 195 | case PLINK_CONFIRM: |
193 | ie_len = 5; | 196 | ie_len = 8; |
194 | include_plid = true; | 197 | include_plid = true; |
195 | break; | 198 | break; |
196 | case PLINK_CLOSE: | 199 | case PLINK_CLOSE: |
197 | default: | 200 | default: |
198 | if (!plid) | 201 | if (!plid) |
199 | ie_len = 5; | 202 | ie_len = 8; |
200 | else { | 203 | else { |
201 | ie_len = 7; | 204 | ie_len = 10; |
202 | include_plid = true; | 205 | include_plid = true; |
203 | } | 206 | } |
204 | break; | 207 | break; |
@@ -207,7 +210,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
207 | pos = skb_put(skb, 2 + ie_len); | 210 | pos = skb_put(skb, 2 + ie_len); |
208 | *pos++ = WLAN_EID_PEER_LINK; | 211 | *pos++ = WLAN_EID_PEER_LINK; |
209 | *pos++ = ie_len; | 212 | *pos++ = ie_len; |
210 | *pos++ = action; | 213 | memcpy(pos, meshpeeringproto, sizeof(meshpeeringproto)); |
214 | pos += 4; | ||
211 | memcpy(pos, &llid, 2); | 215 | memcpy(pos, &llid, 2); |
212 | if (include_plid) { | 216 | if (include_plid) { |
213 | pos += 2; | 217 | pos += 2; |
@@ -395,6 +399,17 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
395 | u8 ie_len; | 399 | u8 ie_len; |
396 | u8 *baseaddr; | 400 | u8 *baseaddr; |
397 | __le16 plid, llid, reason; | 401 | __le16 plid, llid, reason; |
402 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG | ||
403 | static const char *mplstates[] = { | ||
404 | [PLINK_LISTEN] = "LISTEN", | ||
405 | [PLINK_OPN_SNT] = "OPN-SNT", | ||
406 | [PLINK_OPN_RCVD] = "OPN-RCVD", | ||
407 | [PLINK_CNF_RCVD] = "CNF_RCVD", | ||
408 | [PLINK_ESTAB] = "ESTAB", | ||
409 | [PLINK_HOLDING] = "HOLDING", | ||
410 | [PLINK_BLOCKED] = "BLOCKED" | ||
411 | }; | ||
412 | #endif | ||
398 | 413 | ||
399 | /* need action_code, aux */ | 414 | /* need action_code, aux */ |
400 | if (len < IEEE80211_MIN_ACTION_SIZE + 3) | 415 | if (len < IEEE80211_MIN_ACTION_SIZE + 3) |
@@ -417,12 +432,13 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
417 | return; | 432 | return; |
418 | } | 433 | } |
419 | 434 | ||
420 | ftype = *((u8 *)PLINK_GET_FRAME_SUBTYPE(elems.peer_link)); | 435 | ftype = mgmt->u.action.u.plink_action.action_code; |
421 | ie_len = elems.peer_link_len; | 436 | ie_len = elems.peer_link_len; |
422 | if ((ftype == PLINK_OPEN && ie_len != 3) || | 437 | if ((ftype == PLINK_OPEN && ie_len != 6) || |
423 | (ftype == PLINK_CONFIRM && ie_len != 5) || | 438 | (ftype == PLINK_CONFIRM && ie_len != 8) || |
424 | (ftype == PLINK_CLOSE && ie_len != 5 && ie_len != 7)) { | 439 | (ftype == PLINK_CLOSE && ie_len != 8 && ie_len != 10)) { |
425 | mpl_dbg("Mesh plink: incorrect plink ie length\n"); | 440 | mpl_dbg("Mesh plink: incorrect plink ie length %d %d\n", |
441 | ftype, ie_len); | ||
426 | return; | 442 | return; |
427 | } | 443 | } |
428 | 444 | ||
@@ -434,7 +450,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
434 | * from the point of view of this host. | 450 | * from the point of view of this host. |
435 | */ | 451 | */ |
436 | memcpy(&plid, PLINK_GET_LLID(elems.peer_link), 2); | 452 | memcpy(&plid, PLINK_GET_LLID(elems.peer_link), 2); |
437 | if (ftype == PLINK_CONFIRM || (ftype == PLINK_CLOSE && ie_len == 7)) | 453 | if (ftype == PLINK_CONFIRM || (ftype == PLINK_CLOSE && ie_len == 10)) |
438 | memcpy(&llid, PLINK_GET_PLID(elems.peer_link), 2); | 454 | memcpy(&llid, PLINK_GET_PLID(elems.peer_link), 2); |
439 | 455 | ||
440 | rcu_read_lock(); | 456 | rcu_read_lock(); |
@@ -532,8 +548,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
532 | } | 548 | } |
533 | } | 549 | } |
534 | 550 | ||
535 | mpl_dbg("Mesh plink (peer, state, llid, plid, event): %pM %d %d %d %d\n", | 551 | mpl_dbg("Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d\n", |
536 | mgmt->sa, sta->plink_state, | 552 | mgmt->sa, mplstates[sta->plink_state], |
537 | le16_to_cpu(sta->llid), le16_to_cpu(sta->plid), | 553 | le16_to_cpu(sta->llid), le16_to_cpu(sta->plid), |
538 | event); | 554 | event); |
539 | reason = 0; | 555 | reason = 0; |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index dcc14e99227c..2af306f67d78 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -1898,7 +1898,6 @@ ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, | |||
1898 | fc = le16_to_cpu(mgmt->frame_control); | 1898 | fc = le16_to_cpu(mgmt->frame_control); |
1899 | 1899 | ||
1900 | switch (fc & IEEE80211_FCTL_STYPE) { | 1900 | switch (fc & IEEE80211_FCTL_STYPE) { |
1901 | case IEEE80211_STYPE_PROBE_REQ: | ||
1902 | case IEEE80211_STYPE_PROBE_RESP: | 1901 | case IEEE80211_STYPE_PROBE_RESP: |
1903 | case IEEE80211_STYPE_BEACON: | 1902 | case IEEE80211_STYPE_BEACON: |
1904 | case IEEE80211_STYPE_AUTH: | 1903 | case IEEE80211_STYPE_AUTH: |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 28316b2a585f..6bce97ee2534 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -507,7 +507,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | |||
507 | 507 | ||
508 | if (ieee80211_is_action(hdr->frame_control)) { | 508 | if (ieee80211_is_action(hdr->frame_control)) { |
509 | mgmt = (struct ieee80211_mgmt *)hdr; | 509 | mgmt = (struct ieee80211_mgmt *)hdr; |
510 | if (mgmt->u.action.category != PLINK_CATEGORY) | 510 | if (mgmt->u.action.category != MESH_PLINK_CATEGORY) |
511 | return RX_DROP_MONITOR; | 511 | return RX_DROP_MONITOR; |
512 | return RX_CONTINUE; | 512 | return RX_CONTINUE; |
513 | } | 513 | } |
@@ -1181,6 +1181,13 @@ __ieee80211_data_to_8023(struct ieee80211_rx_data *rx) | |||
1181 | { | 1181 | { |
1182 | struct net_device *dev = rx->dev; | 1182 | struct net_device *dev = rx->dev; |
1183 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1183 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1184 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | ||
1185 | |||
1186 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->use_4addr && | ||
1187 | ieee80211_has_a4(hdr->frame_control)) | ||
1188 | return -1; | ||
1189 | if (sdata->use_4addr && is_multicast_ether_addr(hdr->addr1)) | ||
1190 | return -1; | ||
1184 | 1191 | ||
1185 | return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type); | 1192 | return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type); |
1186 | } | 1193 | } |
@@ -1229,7 +1236,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) | |||
1229 | if ((sdata->vif.type == NL80211_IFTYPE_AP || | 1236 | if ((sdata->vif.type == NL80211_IFTYPE_AP || |
1230 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && | 1237 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && |
1231 | !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) && | 1238 | !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) && |
1232 | (rx->flags & IEEE80211_RX_RA_MATCH)) { | 1239 | (rx->flags & IEEE80211_RX_RA_MATCH) && !rx->sdata->use_4addr) { |
1233 | if (is_multicast_ether_addr(ehdr->h_dest)) { | 1240 | if (is_multicast_ether_addr(ehdr->h_dest)) { |
1234 | /* | 1241 | /* |
1235 | * send multicast frames both to higher layers in | 1242 | * send multicast frames both to higher layers in |
@@ -1534,6 +1541,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) | |||
1534 | { | 1541 | { |
1535 | struct net_device *dev = rx->dev; | 1542 | struct net_device *dev = rx->dev; |
1536 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 1543 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
1544 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1537 | __le16 fc = hdr->frame_control; | 1545 | __le16 fc = hdr->frame_control; |
1538 | int err; | 1546 | int err; |
1539 | 1547 | ||
@@ -1543,6 +1551,14 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) | |||
1543 | if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) | 1551 | if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) |
1544 | return RX_DROP_MONITOR; | 1552 | return RX_DROP_MONITOR; |
1545 | 1553 | ||
1554 | /* | ||
1555 | * Allow the cooked monitor interface of an AP to see 4-addr frames so | ||
1556 | * that a 4-addr station can be detected and moved into a separate VLAN | ||
1557 | */ | ||
1558 | if (ieee80211_has_a4(hdr->frame_control) && | ||
1559 | sdata->vif.type == NL80211_IFTYPE_AP) | ||
1560 | return RX_DROP_MONITOR; | ||
1561 | |||
1546 | err = __ieee80211_data_to_8023(rx); | 1562 | err = __ieee80211_data_to_8023(rx); |
1547 | if (unlikely(err)) | 1563 | if (unlikely(err)) |
1548 | return RX_DROP_UNUSABLE; | 1564 | return RX_DROP_UNUSABLE; |
@@ -1983,7 +1999,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, | |||
1983 | 1999 | ||
1984 | switch (sdata->vif.type) { | 2000 | switch (sdata->vif.type) { |
1985 | case NL80211_IFTYPE_STATION: | 2001 | case NL80211_IFTYPE_STATION: |
1986 | if (!bssid) | 2002 | if (!bssid && !sdata->use_4addr) |
1987 | return 0; | 2003 | return 0; |
1988 | if (!multicast && | 2004 | if (!multicast && |
1989 | compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) { | 2005 | compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) { |
@@ -2425,9 +2441,21 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
2425 | goto drop; | 2441 | goto drop; |
2426 | 2442 | ||
2427 | if (status->flag & RX_FLAG_HT) { | 2443 | if (status->flag & RX_FLAG_HT) { |
2428 | /* rate_idx is MCS index */ | 2444 | /* |
2429 | if (WARN_ON(status->rate_idx < 0 || | 2445 | * rate_idx is MCS index, which can be [0-76] as documented on: |
2430 | status->rate_idx >= 76)) | 2446 | * |
2447 | * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n | ||
2448 | * | ||
2449 | * Anything else would be some sort of driver or hardware error. | ||
2450 | * The driver should catch hardware errors. | ||
2451 | */ | ||
2452 | if (WARN((status->rate_idx < 0 || | ||
2453 | status->rate_idx > 76), | ||
2454 | "Rate marked as an HT rate but passed " | ||
2455 | "status->rate_idx is not " | ||
2456 | "an MCS index [0-76]: %d (0x%02x)\n", | ||
2457 | status->rate_idx, | ||
2458 | status->rate_idx)) | ||
2431 | goto drop; | 2459 | goto drop; |
2432 | /* HT rates are not in the table - use the highest legacy rate | 2460 | /* HT rates are not in the table - use the highest legacy rate |
2433 | * for now since other parts of mac80211 may not yet be fully | 2461 | * for now since other parts of mac80211 may not yet be fully |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index be59456e8a42..396a94806de9 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -509,6 +509,9 @@ static void __sta_info_unlink(struct sta_info **sta) | |||
509 | local->num_sta--; | 509 | local->num_sta--; |
510 | local->sta_generation++; | 510 | local->sta_generation++; |
511 | 511 | ||
512 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
513 | rcu_assign_pointer(sdata->u.vlan.sta, NULL); | ||
514 | |||
512 | if (local->ops->sta_notify) { | 515 | if (local->ops->sta_notify) { |
513 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 516 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
514 | sdata = container_of(sdata->bss, | 517 | sdata = container_of(sdata->bss, |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index bfaa43e096d2..3ad053f6de12 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -1051,7 +1051,10 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, | |||
1051 | 1051 | ||
1052 | hdr = (struct ieee80211_hdr *) skb->data; | 1052 | hdr = (struct ieee80211_hdr *) skb->data; |
1053 | 1053 | ||
1054 | tx->sta = sta_info_get(local, hdr->addr1); | 1054 | if ((sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && sdata->use_4addr) |
1055 | tx->sta = rcu_dereference(sdata->u.vlan.sta); | ||
1056 | if (!tx->sta) | ||
1057 | tx->sta = sta_info_get(local, hdr->addr1); | ||
1055 | 1058 | ||
1056 | if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) && | 1059 | if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) && |
1057 | (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)) { | 1060 | (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)) { |
@@ -1613,7 +1616,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1613 | const u8 *encaps_data; | 1616 | const u8 *encaps_data; |
1614 | int encaps_len, skip_header_bytes; | 1617 | int encaps_len, skip_header_bytes; |
1615 | int nh_pos, h_pos; | 1618 | int nh_pos, h_pos; |
1616 | struct sta_info *sta; | 1619 | struct sta_info *sta = NULL; |
1617 | u32 sta_flags = 0; | 1620 | u32 sta_flags = 0; |
1618 | 1621 | ||
1619 | if (unlikely(skb->len < ETH_HLEN)) { | 1622 | if (unlikely(skb->len < ETH_HLEN)) { |
@@ -1630,8 +1633,25 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1630 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); | 1633 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); |
1631 | 1634 | ||
1632 | switch (sdata->vif.type) { | 1635 | switch (sdata->vif.type) { |
1633 | case NL80211_IFTYPE_AP: | ||
1634 | case NL80211_IFTYPE_AP_VLAN: | 1636 | case NL80211_IFTYPE_AP_VLAN: |
1637 | rcu_read_lock(); | ||
1638 | if (sdata->use_4addr) | ||
1639 | sta = rcu_dereference(sdata->u.vlan.sta); | ||
1640 | if (sta) { | ||
1641 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); | ||
1642 | /* RA TA DA SA */ | ||
1643 | memcpy(hdr.addr1, sta->sta.addr, ETH_ALEN); | ||
1644 | memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); | ||
1645 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | ||
1646 | memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); | ||
1647 | hdrlen = 30; | ||
1648 | sta_flags = get_sta_flags(sta); | ||
1649 | } | ||
1650 | rcu_read_unlock(); | ||
1651 | if (sta) | ||
1652 | break; | ||
1653 | /* fall through */ | ||
1654 | case NL80211_IFTYPE_AP: | ||
1635 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); | 1655 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); |
1636 | /* DA BSSID SA */ | 1656 | /* DA BSSID SA */ |
1637 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | 1657 | memcpy(hdr.addr1, skb->data, ETH_ALEN); |
@@ -1705,12 +1725,21 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1705 | break; | 1725 | break; |
1706 | #endif | 1726 | #endif |
1707 | case NL80211_IFTYPE_STATION: | 1727 | case NL80211_IFTYPE_STATION: |
1708 | fc |= cpu_to_le16(IEEE80211_FCTL_TODS); | ||
1709 | /* BSSID SA DA */ | ||
1710 | memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN); | 1728 | memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN); |
1711 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); | 1729 | if (sdata->use_4addr && ethertype != ETH_P_PAE) { |
1712 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | 1730 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); |
1713 | hdrlen = 24; | 1731 | /* RA TA DA SA */ |
1732 | memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); | ||
1733 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | ||
1734 | memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); | ||
1735 | hdrlen = 30; | ||
1736 | } else { | ||
1737 | fc |= cpu_to_le16(IEEE80211_FCTL_TODS); | ||
1738 | /* BSSID SA DA */ | ||
1739 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); | ||
1740 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | ||
1741 | hdrlen = 24; | ||
1742 | } | ||
1714 | break; | 1743 | break; |
1715 | case NL80211_IFTYPE_ADHOC: | 1744 | case NL80211_IFTYPE_ADHOC: |
1716 | /* DA SA BSSID */ | 1745 | /* DA SA BSSID */ |
@@ -2119,7 +2148,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2119 | cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); | 2148 | cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); |
2120 | memset(mgmt->da, 0xff, ETH_ALEN); | 2149 | memset(mgmt->da, 0xff, ETH_ALEN); |
2121 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 2150 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
2122 | /* BSSID is left zeroed, wildcard value */ | 2151 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); |
2123 | mgmt->u.beacon.beacon_int = | 2152 | mgmt->u.beacon.beacon_int = |
2124 | cpu_to_le16(sdata->vif.bss_conf.beacon_int); | 2153 | cpu_to_le16(sdata->vif.bss_conf.beacon_int); |
2125 | mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */ | 2154 | mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */ |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index aedbaaa067e6..da86e1592f8c 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -685,6 +685,10 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | |||
685 | elems->perr = pos; | 685 | elems->perr = pos; |
686 | elems->perr_len = elen; | 686 | elems->perr_len = elen; |
687 | break; | 687 | break; |
688 | case WLAN_EID_RANN: | ||
689 | if (elen >= sizeof(struct ieee80211_rann_ie)) | ||
690 | elems->rann = (void *)pos; | ||
691 | break; | ||
688 | case WLAN_EID_CHANNEL_SWITCH: | 692 | case WLAN_EID_CHANNEL_SWITCH: |
689 | elems->ch_switch_elem = pos; | 693 | elems->ch_switch_elem = pos; |
690 | elems->ch_switch_elem_len = elen; | 694 | elems->ch_switch_elem_len = elen; |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 8ed62b6c172b..37264d56bace 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -138,6 +138,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
138 | [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, | 138 | [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, |
139 | [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, | 139 | [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, |
140 | [NL80211_ATTR_PID] = { .type = NLA_U32 }, | 140 | [NL80211_ATTR_PID] = { .type = NLA_U32 }, |
141 | [NL80211_ATTR_4ADDR] = { .type = NLA_U8 }, | ||
141 | }; | 142 | }; |
142 | 143 | ||
143 | /* policy for the attributes */ | 144 | /* policy for the attributes */ |
@@ -151,6 +152,26 @@ nl80211_key_policy[NL80211_KEY_MAX + 1] __read_mostly = { | |||
151 | [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, | 152 | [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, |
152 | }; | 153 | }; |
153 | 154 | ||
155 | /* ifidx get helper */ | ||
156 | static int nl80211_get_ifidx(struct netlink_callback *cb) | ||
157 | { | ||
158 | int res; | ||
159 | |||
160 | res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, | ||
161 | nl80211_fam.attrbuf, nl80211_fam.maxattr, | ||
162 | nl80211_policy); | ||
163 | if (res) | ||
164 | return res; | ||
165 | |||
166 | if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]) | ||
167 | return -EINVAL; | ||
168 | |||
169 | res = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]); | ||
170 | if (!res) | ||
171 | return -EINVAL; | ||
172 | return res; | ||
173 | } | ||
174 | |||
154 | /* IE validation */ | 175 | /* IE validation */ |
155 | static bool is_valid_ie_attr(const struct nlattr *attr) | 176 | static bool is_valid_ie_attr(const struct nlattr *attr) |
156 | { | 177 | { |
@@ -987,6 +1008,13 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
987 | change = true; | 1008 | change = true; |
988 | } | 1009 | } |
989 | 1010 | ||
1011 | if (info->attrs[NL80211_ATTR_4ADDR]) { | ||
1012 | params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); | ||
1013 | change = true; | ||
1014 | } else { | ||
1015 | params.use_4addr = -1; | ||
1016 | } | ||
1017 | |||
990 | if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { | 1018 | if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { |
991 | if (ntype != NL80211_IFTYPE_MONITOR) { | 1019 | if (ntype != NL80211_IFTYPE_MONITOR) { |
992 | err = -EINVAL; | 1020 | err = -EINVAL; |
@@ -1053,6 +1081,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1053 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | 1081 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); |
1054 | } | 1082 | } |
1055 | 1083 | ||
1084 | if (info->attrs[NL80211_ATTR_4ADDR]) | ||
1085 | params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); | ||
1086 | |||
1056 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? | 1087 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? |
1057 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, | 1088 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, |
1058 | &flags); | 1089 | &flags); |
@@ -1682,20 +1713,10 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
1682 | int sta_idx = cb->args[1]; | 1713 | int sta_idx = cb->args[1]; |
1683 | int err; | 1714 | int err; |
1684 | 1715 | ||
1685 | if (!ifidx) { | 1716 | if (!ifidx) |
1686 | err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, | 1717 | ifidx = nl80211_get_ifidx(cb); |
1687 | nl80211_fam.attrbuf, nl80211_fam.maxattr, | 1718 | if (ifidx < 0) |
1688 | nl80211_policy); | 1719 | return ifidx; |
1689 | if (err) | ||
1690 | return err; | ||
1691 | |||
1692 | if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]) | ||
1693 | return -EINVAL; | ||
1694 | |||
1695 | ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]); | ||
1696 | if (!ifidx) | ||
1697 | return -EINVAL; | ||
1698 | } | ||
1699 | 1720 | ||
1700 | rtnl_lock(); | 1721 | rtnl_lock(); |
1701 | 1722 | ||
@@ -1800,7 +1821,7 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | |||
1800 | } | 1821 | } |
1801 | 1822 | ||
1802 | /* | 1823 | /* |
1803 | * Get vlan interface making sure it is on the right wiphy. | 1824 | * Get vlan interface making sure it is running and on the right wiphy. |
1804 | */ | 1825 | */ |
1805 | static int get_vlan(struct genl_info *info, | 1826 | static int get_vlan(struct genl_info *info, |
1806 | struct cfg80211_registered_device *rdev, | 1827 | struct cfg80211_registered_device *rdev, |
@@ -1818,6 +1839,8 @@ static int get_vlan(struct genl_info *info, | |||
1818 | return -EINVAL; | 1839 | return -EINVAL; |
1819 | if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy) | 1840 | if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy) |
1820 | return -EINVAL; | 1841 | return -EINVAL; |
1842 | if (!netif_running(*vlan)) | ||
1843 | return -ENETDOWN; | ||
1821 | } | 1844 | } |
1822 | return 0; | 1845 | return 0; |
1823 | } | 1846 | } |
@@ -2105,9 +2128,9 @@ static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq, | |||
2105 | if (pinfo->filled & MPATH_INFO_FRAME_QLEN) | 2128 | if (pinfo->filled & MPATH_INFO_FRAME_QLEN) |
2106 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_FRAME_QLEN, | 2129 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_FRAME_QLEN, |
2107 | pinfo->frame_qlen); | 2130 | pinfo->frame_qlen); |
2108 | if (pinfo->filled & MPATH_INFO_DSN) | 2131 | if (pinfo->filled & MPATH_INFO_SN) |
2109 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_DSN, | 2132 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_SN, |
2110 | pinfo->dsn); | 2133 | pinfo->sn); |
2111 | if (pinfo->filled & MPATH_INFO_METRIC) | 2134 | if (pinfo->filled & MPATH_INFO_METRIC) |
2112 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_METRIC, | 2135 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_METRIC, |
2113 | pinfo->metric); | 2136 | pinfo->metric); |
@@ -2145,20 +2168,10 @@ static int nl80211_dump_mpath(struct sk_buff *skb, | |||
2145 | int path_idx = cb->args[1]; | 2168 | int path_idx = cb->args[1]; |
2146 | int err; | 2169 | int err; |
2147 | 2170 | ||
2148 | if (!ifidx) { | 2171 | if (!ifidx) |
2149 | err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, | 2172 | ifidx = nl80211_get_ifidx(cb); |
2150 | nl80211_fam.attrbuf, nl80211_fam.maxattr, | 2173 | if (ifidx < 0) |
2151 | nl80211_policy); | 2174 | return ifidx; |
2152 | if (err) | ||
2153 | return err; | ||
2154 | |||
2155 | if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]) | ||
2156 | return -EINVAL; | ||
2157 | |||
2158 | ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]); | ||
2159 | if (!ifidx) | ||
2160 | return -EINVAL; | ||
2161 | } | ||
2162 | 2175 | ||
2163 | rtnl_lock(); | 2176 | rtnl_lock(); |
2164 | 2177 | ||
@@ -2605,6 +2618,8 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, | |||
2605 | cur_params.dot11MeshHWMPpreqMinInterval); | 2618 | cur_params.dot11MeshHWMPpreqMinInterval); |
2606 | NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, | 2619 | NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, |
2607 | cur_params.dot11MeshHWMPnetDiameterTraversalTime); | 2620 | cur_params.dot11MeshHWMPnetDiameterTraversalTime); |
2621 | NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_ROOTMODE, | ||
2622 | cur_params.dot11MeshHWMPRootMode); | ||
2608 | nla_nest_end(msg, pinfoattr); | 2623 | nla_nest_end(msg, pinfoattr); |
2609 | genlmsg_end(msg, hdr); | 2624 | genlmsg_end(msg, hdr); |
2610 | err = genlmsg_reply(msg, info); | 2625 | err = genlmsg_reply(msg, info); |
@@ -2715,6 +2730,10 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) | |||
2715 | dot11MeshHWMPnetDiameterTraversalTime, | 2730 | dot11MeshHWMPnetDiameterTraversalTime, |
2716 | mask, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, | 2731 | mask, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, |
2717 | nla_get_u16); | 2732 | nla_get_u16); |
2733 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, | ||
2734 | dot11MeshHWMPRootMode, mask, | ||
2735 | NL80211_MESHCONF_HWMP_ROOTMODE, | ||
2736 | nla_get_u8); | ||
2718 | 2737 | ||
2719 | /* Apply changes */ | 2738 | /* Apply changes */ |
2720 | err = rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask); | 2739 | err = rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask); |
@@ -3181,21 +3200,11 @@ static int nl80211_dump_scan(struct sk_buff *skb, | |||
3181 | int start = cb->args[1], idx = 0; | 3200 | int start = cb->args[1], idx = 0; |
3182 | int err; | 3201 | int err; |
3183 | 3202 | ||
3184 | if (!ifidx) { | 3203 | if (!ifidx) |
3185 | err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, | 3204 | ifidx = nl80211_get_ifidx(cb); |
3186 | nl80211_fam.attrbuf, nl80211_fam.maxattr, | 3205 | if (ifidx < 0) |
3187 | nl80211_policy); | 3206 | return ifidx; |
3188 | if (err) | 3207 | cb->args[0] = ifidx; |
3189 | return err; | ||
3190 | |||
3191 | if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]) | ||
3192 | return -EINVAL; | ||
3193 | |||
3194 | ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]); | ||
3195 | if (!ifidx) | ||
3196 | return -EINVAL; | ||
3197 | cb->args[0] = ifidx; | ||
3198 | } | ||
3199 | 3208 | ||
3200 | dev = dev_get_by_index(sock_net(skb->sk), ifidx); | 3209 | dev = dev_get_by_index(sock_net(skb->sk), ifidx); |
3201 | if (!dev) | 3210 | if (!dev) |
@@ -3238,6 +3247,106 @@ static int nl80211_dump_scan(struct sk_buff *skb, | |||
3238 | return err; | 3247 | return err; |
3239 | } | 3248 | } |
3240 | 3249 | ||
3250 | static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq, | ||
3251 | int flags, struct net_device *dev, | ||
3252 | struct survey_info *survey) | ||
3253 | { | ||
3254 | void *hdr; | ||
3255 | struct nlattr *infoattr; | ||
3256 | |||
3257 | /* Survey without a channel doesn't make sense */ | ||
3258 | if (!survey->channel) | ||
3259 | return -EINVAL; | ||
3260 | |||
3261 | hdr = nl80211hdr_put(msg, pid, seq, flags, | ||
3262 | NL80211_CMD_NEW_SURVEY_RESULTS); | ||
3263 | if (!hdr) | ||
3264 | return -ENOMEM; | ||
3265 | |||
3266 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | ||
3267 | |||
3268 | infoattr = nla_nest_start(msg, NL80211_ATTR_SURVEY_INFO); | ||
3269 | if (!infoattr) | ||
3270 | goto nla_put_failure; | ||
3271 | |||
3272 | NLA_PUT_U32(msg, NL80211_SURVEY_INFO_FREQUENCY, | ||
3273 | survey->channel->center_freq); | ||
3274 | if (survey->filled & SURVEY_INFO_NOISE_DBM) | ||
3275 | NLA_PUT_U8(msg, NL80211_SURVEY_INFO_NOISE, | ||
3276 | survey->noise); | ||
3277 | |||
3278 | nla_nest_end(msg, infoattr); | ||
3279 | |||
3280 | return genlmsg_end(msg, hdr); | ||
3281 | |||
3282 | nla_put_failure: | ||
3283 | genlmsg_cancel(msg, hdr); | ||
3284 | return -EMSGSIZE; | ||
3285 | } | ||
3286 | |||
3287 | static int nl80211_dump_survey(struct sk_buff *skb, | ||
3288 | struct netlink_callback *cb) | ||
3289 | { | ||
3290 | struct survey_info survey; | ||
3291 | struct cfg80211_registered_device *dev; | ||
3292 | struct net_device *netdev; | ||
3293 | int ifidx = cb->args[0]; | ||
3294 | int survey_idx = cb->args[1]; | ||
3295 | int res; | ||
3296 | |||
3297 | if (!ifidx) | ||
3298 | ifidx = nl80211_get_ifidx(cb); | ||
3299 | if (ifidx < 0) | ||
3300 | return ifidx; | ||
3301 | cb->args[0] = ifidx; | ||
3302 | |||
3303 | rtnl_lock(); | ||
3304 | |||
3305 | netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); | ||
3306 | if (!netdev) { | ||
3307 | res = -ENODEV; | ||
3308 | goto out_rtnl; | ||
3309 | } | ||
3310 | |||
3311 | dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); | ||
3312 | if (IS_ERR(dev)) { | ||
3313 | res = PTR_ERR(dev); | ||
3314 | goto out_rtnl; | ||
3315 | } | ||
3316 | |||
3317 | if (!dev->ops->dump_survey) { | ||
3318 | res = -EOPNOTSUPP; | ||
3319 | goto out_err; | ||
3320 | } | ||
3321 | |||
3322 | while (1) { | ||
3323 | res = dev->ops->dump_survey(&dev->wiphy, netdev, survey_idx, | ||
3324 | &survey); | ||
3325 | if (res == -ENOENT) | ||
3326 | break; | ||
3327 | if (res) | ||
3328 | goto out_err; | ||
3329 | |||
3330 | if (nl80211_send_survey(skb, | ||
3331 | NETLINK_CB(cb->skb).pid, | ||
3332 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | ||
3333 | netdev, | ||
3334 | &survey) < 0) | ||
3335 | goto out; | ||
3336 | survey_idx++; | ||
3337 | } | ||
3338 | |||
3339 | out: | ||
3340 | cb->args[1] = survey_idx; | ||
3341 | res = skb->len; | ||
3342 | out_err: | ||
3343 | cfg80211_unlock_rdev(dev); | ||
3344 | out_rtnl: | ||
3345 | rtnl_unlock(); | ||
3346 | |||
3347 | return res; | ||
3348 | } | ||
3349 | |||
3241 | static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type) | 3350 | static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type) |
3242 | { | 3351 | { |
3243 | return auth_type <= NL80211_AUTHTYPE_MAX; | 3352 | return auth_type <= NL80211_AUTHTYPE_MAX; |
@@ -4315,6 +4424,11 @@ static struct genl_ops nl80211_ops[] = { | |||
4315 | .policy = nl80211_policy, | 4424 | .policy = nl80211_policy, |
4316 | .flags = GENL_ADMIN_PERM, | 4425 | .flags = GENL_ADMIN_PERM, |
4317 | }, | 4426 | }, |
4427 | { | ||
4428 | .cmd = NL80211_CMD_GET_SURVEY, | ||
4429 | .policy = nl80211_policy, | ||
4430 | .dumpit = nl80211_dump_survey, | ||
4431 | }, | ||
4318 | }; | 4432 | }; |
4319 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 4433 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
4320 | .name = "mlme", | 4434 | .name = "mlme", |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 3fc2df86278f..5aa39f7cf9b9 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -320,7 +320,9 @@ int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr, | |||
320 | break; | 320 | break; |
321 | case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): | 321 | case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): |
322 | if (unlikely(iftype != NL80211_IFTYPE_WDS && | 322 | if (unlikely(iftype != NL80211_IFTYPE_WDS && |
323 | iftype != NL80211_IFTYPE_MESH_POINT)) | 323 | iftype != NL80211_IFTYPE_MESH_POINT && |
324 | iftype != NL80211_IFTYPE_AP_VLAN && | ||
325 | iftype != NL80211_IFTYPE_STATION)) | ||
324 | return -1; | 326 | return -1; |
325 | if (iftype == NL80211_IFTYPE_MESH_POINT) { | 327 | if (iftype == NL80211_IFTYPE_MESH_POINT) { |
326 | struct ieee80211s_hdr *meshdr = | 328 | struct ieee80211s_hdr *meshdr = |