diff options
Diffstat (limited to 'drivers/net/wireless')
156 files changed, 20353 insertions, 3380 deletions
diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index d1b23067619f..073548836413 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig | |||
@@ -25,5 +25,6 @@ config ATH_DEBUG | |||
25 | source "drivers/net/wireless/ath/ath5k/Kconfig" | 25 | source "drivers/net/wireless/ath/ath5k/Kconfig" |
26 | source "drivers/net/wireless/ath/ath9k/Kconfig" | 26 | source "drivers/net/wireless/ath/ath9k/Kconfig" |
27 | source "drivers/net/wireless/ath/carl9170/Kconfig" | 27 | source "drivers/net/wireless/ath/carl9170/Kconfig" |
28 | source "drivers/net/wireless/ath/ath6kl/Kconfig" | ||
28 | 29 | ||
29 | endif | 30 | endif |
diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile index 0e8f528c81c0..d1214696a35b 100644 --- a/drivers/net/wireless/ath/Makefile +++ b/drivers/net/wireless/ath/Makefile | |||
@@ -1,6 +1,7 @@ | |||
1 | obj-$(CONFIG_ATH5K) += ath5k/ | 1 | obj-$(CONFIG_ATH5K) += ath5k/ |
2 | obj-$(CONFIG_ATH9K_HW) += ath9k/ | 2 | obj-$(CONFIG_ATH9K_HW) += ath9k/ |
3 | obj-$(CONFIG_CARL9170) += carl9170/ | 3 | obj-$(CONFIG_CARL9170) += carl9170/ |
4 | obj-$(CONFIG_ATH6KL) += ath6kl/ | ||
4 | 5 | ||
5 | obj-$(CONFIG_ATH_COMMON) += ath.o | 6 | obj-$(CONFIG_ATH_COMMON) += ath.o |
6 | 7 | ||
diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c index a2a167363dbf..e5be7e701816 100644 --- a/drivers/net/wireless/ath/ath5k/ahb.c +++ b/drivers/net/wireless/ath/ath5k/ahb.c | |||
@@ -169,7 +169,7 @@ static int ath_ahb_probe(struct platform_device *pdev) | |||
169 | __set_bit(ATH_STAT_2G_DISABLED, ah->status); | 169 | __set_bit(ATH_STAT_2G_DISABLED, ah->status); |
170 | } | 170 | } |
171 | 171 | ||
172 | ret = ath5k_init_softc(ah, &ath_ahb_bus_ops); | 172 | ret = ath5k_init_ah(ah, &ath_ahb_bus_ops); |
173 | if (ret != 0) { | 173 | if (ret != 0) { |
174 | dev_err(&pdev->dev, "failed to attach device, err=%d\n", ret); | 174 | dev_err(&pdev->dev, "failed to attach device, err=%d\n", ret); |
175 | ret = -ENODEV; | 175 | ret = -ENODEV; |
@@ -214,7 +214,7 @@ static int ath_ahb_remove(struct platform_device *pdev) | |||
214 | __raw_writel(reg, (void __iomem *) AR5K_AR5312_ENABLE); | 214 | __raw_writel(reg, (void __iomem *) AR5K_AR5312_ENABLE); |
215 | } | 215 | } |
216 | 216 | ||
217 | ath5k_deinit_softc(ah); | 217 | ath5k_deinit_ah(ah); |
218 | platform_set_drvdata(pdev, NULL); | 218 | platform_set_drvdata(pdev, NULL); |
219 | ieee80211_free_hw(hw); | 219 | ieee80211_free_hw(hw); |
220 | 220 | ||
diff --git a/drivers/net/wireless/ath/ath5k/ani.c b/drivers/net/wireless/ath/ath5k/ani.c index 603ae15f139b..bea90e6be70e 100644 --- a/drivers/net/wireless/ath/ath5k/ani.c +++ b/drivers/net/wireless/ath/ath5k/ani.c | |||
@@ -15,7 +15,6 @@ | |||
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include "ath5k.h" | 17 | #include "ath5k.h" |
18 | #include "base.h" | ||
19 | #include "reg.h" | 18 | #include "reg.h" |
20 | #include "debug.h" | 19 | #include "debug.h" |
21 | #include "ani.h" | 20 | #include "ani.h" |
diff --git a/drivers/net/wireless/ath/ath5k/ani.h b/drivers/net/wireless/ath/ath5k/ani.h index 034015397093..7358b6c83c6c 100644 --- a/drivers/net/wireless/ath/ath5k/ani.h +++ b/drivers/net/wireless/ath/ath5k/ani.h | |||
@@ -16,6 +16,10 @@ | |||
16 | #ifndef ANI_H | 16 | #ifndef ANI_H |
17 | #define ANI_H | 17 | #define ANI_H |
18 | 18 | ||
19 | #include "../ath.h" | ||
20 | |||
21 | enum ath5k_phy_error_code; | ||
22 | |||
19 | /* these thresholds are relative to the ATH5K_ANI_LISTEN_PERIOD */ | 23 | /* these thresholds are relative to the ATH5K_ANI_LISTEN_PERIOD */ |
20 | #define ATH5K_ANI_LISTEN_PERIOD 100 | 24 | #define ATH5K_ANI_LISTEN_PERIOD 100 |
21 | #define ATH5K_ANI_OFDM_TRIG_HIGH 500 | 25 | #define ATH5K_ANI_OFDM_TRIG_HIGH 500 |
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 277d5cbe0068..fecbcd9a4259 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h | |||
@@ -131,13 +131,6 @@ | |||
131 | #define AR5K_REG_DISABLE_BITS(ah, _reg, _flags) \ | 131 | #define AR5K_REG_DISABLE_BITS(ah, _reg, _flags) \ |
132 | ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) & ~(_flags), _reg) | 132 | ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) & ~(_flags), _reg) |
133 | 133 | ||
134 | /* Access to PHY registers */ | ||
135 | #define AR5K_PHY_READ(ah, _reg) \ | ||
136 | ath5k_hw_reg_read(ah, (ah)->ah_phy + ((_reg) << 2)) | ||
137 | |||
138 | #define AR5K_PHY_WRITE(ah, _reg, _val) \ | ||
139 | ath5k_hw_reg_write(ah, _val, (ah)->ah_phy + ((_reg) << 2)) | ||
140 | |||
141 | /* Access QCU registers per queue */ | 134 | /* Access QCU registers per queue */ |
142 | #define AR5K_REG_READ_Q(ah, _reg, _queue) \ | 135 | #define AR5K_REG_READ_Q(ah, _reg, _queue) \ |
143 | (ath5k_hw_reg_read(ah, _reg) & (1 << _queue)) \ | 136 | (ath5k_hw_reg_read(ah, _reg) & (1 << _queue)) \ |
@@ -166,7 +159,6 @@ | |||
166 | #define AR5K_TUNE_DMA_BEACON_RESP 2 | 159 | #define AR5K_TUNE_DMA_BEACON_RESP 2 |
167 | #define AR5K_TUNE_SW_BEACON_RESP 10 | 160 | #define AR5K_TUNE_SW_BEACON_RESP 10 |
168 | #define AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF 0 | 161 | #define AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF 0 |
169 | #define AR5K_TUNE_RADAR_ALERT false | ||
170 | #define AR5K_TUNE_MIN_TX_FIFO_THRES 1 | 162 | #define AR5K_TUNE_MIN_TX_FIFO_THRES 1 |
171 | #define AR5K_TUNE_MAX_TX_FIFO_THRES ((IEEE80211_MAX_FRAME_LEN / 64) + 1) | 163 | #define AR5K_TUNE_MAX_TX_FIFO_THRES ((IEEE80211_MAX_FRAME_LEN / 64) + 1) |
172 | #define AR5K_TUNE_REGISTER_TIMEOUT 20000 | 164 | #define AR5K_TUNE_REGISTER_TIMEOUT 20000 |
@@ -295,17 +287,6 @@ enum ath5k_radio { | |||
295 | * Common silicon revision/version values | 287 | * Common silicon revision/version values |
296 | */ | 288 | */ |
297 | 289 | ||
298 | enum ath5k_srev_type { | ||
299 | AR5K_VERSION_MAC, | ||
300 | AR5K_VERSION_RAD, | ||
301 | }; | ||
302 | |||
303 | struct ath5k_srev_name { | ||
304 | const char *sr_name; | ||
305 | enum ath5k_srev_type sr_type; | ||
306 | u_int sr_val; | ||
307 | }; | ||
308 | |||
309 | #define AR5K_SREV_UNKNOWN 0xffff | 290 | #define AR5K_SREV_UNKNOWN 0xffff |
310 | 291 | ||
311 | #define AR5K_SREV_AR5210 0x00 /* Crete */ | 292 | #define AR5K_SREV_AR5210 0x00 /* Crete */ |
@@ -424,7 +405,6 @@ enum ath5k_driver_mode { | |||
424 | AR5K_MODE_11A = 0, | 405 | AR5K_MODE_11A = 0, |
425 | AR5K_MODE_11B = 1, | 406 | AR5K_MODE_11B = 1, |
426 | AR5K_MODE_11G = 2, | 407 | AR5K_MODE_11G = 2, |
427 | AR5K_MODE_XR = 0, | ||
428 | AR5K_MODE_MAX = 3 | 408 | AR5K_MODE_MAX = 3 |
429 | }; | 409 | }; |
430 | 410 | ||
@@ -694,33 +674,6 @@ struct ath5k_gain { | |||
694 | #define AR5K_SLOT_TIME_20 880 | 674 | #define AR5K_SLOT_TIME_20 880 |
695 | #define AR5K_SLOT_TIME_MAX 0xffff | 675 | #define AR5K_SLOT_TIME_MAX 0xffff |
696 | 676 | ||
697 | /* channel_flags */ | ||
698 | #define CHANNEL_CW_INT 0x0008 /* Contention Window interference detected */ | ||
699 | #define CHANNEL_CCK 0x0020 /* CCK channel */ | ||
700 | #define CHANNEL_OFDM 0x0040 /* OFDM channel */ | ||
701 | #define CHANNEL_2GHZ 0x0080 /* 2GHz channel. */ | ||
702 | #define CHANNEL_5GHZ 0x0100 /* 5GHz channel */ | ||
703 | #define CHANNEL_PASSIVE 0x0200 /* Only passive scan allowed */ | ||
704 | #define CHANNEL_DYN 0x0400 /* Dynamic CCK-OFDM channel (for g operation) */ | ||
705 | #define CHANNEL_XR 0x0800 /* XR channel */ | ||
706 | |||
707 | #define CHANNEL_A (CHANNEL_5GHZ | CHANNEL_OFDM) | ||
708 | #define CHANNEL_B (CHANNEL_2GHZ | CHANNEL_CCK) | ||
709 | #define CHANNEL_G (CHANNEL_2GHZ | CHANNEL_OFDM) | ||
710 | #define CHANNEL_X (CHANNEL_5GHZ | CHANNEL_OFDM | CHANNEL_XR) | ||
711 | |||
712 | #define CHANNEL_ALL (CHANNEL_OFDM | CHANNEL_CCK | \ | ||
713 | CHANNEL_2GHZ | CHANNEL_5GHZ) | ||
714 | |||
715 | #define CHANNEL_MODES CHANNEL_ALL | ||
716 | |||
717 | /* | ||
718 | * Used internally for ath5k_hw_reset_tx_queue(). | ||
719 | * Also see struct struct ieee80211_channel. | ||
720 | */ | ||
721 | #define IS_CHAN_XR(_c) ((_c->hw_value & CHANNEL_XR) != 0) | ||
722 | #define IS_CHAN_B(_c) ((_c->hw_value & CHANNEL_B) != 0) | ||
723 | |||
724 | /* | 677 | /* |
725 | * The following structure is used to map 2GHz channels to | 678 | * The following structure is used to map 2GHz channels to |
726 | * 5GHz Atheros channels. | 679 | * 5GHz Atheros channels. |
@@ -977,7 +930,7 @@ enum ath5k_power_mode { | |||
977 | struct ath5k_capabilities { | 930 | struct ath5k_capabilities { |
978 | /* | 931 | /* |
979 | * Supported PHY modes | 932 | * Supported PHY modes |
980 | * (ie. CHANNEL_A, CHANNEL_B, ...) | 933 | * (ie. AR5K_MODE_11A, AR5K_MODE_11B, ...) |
981 | */ | 934 | */ |
982 | DECLARE_BITMAP(cap_mode, AR5K_MODE_MAX); | 935 | DECLARE_BITMAP(cap_mode, AR5K_MODE_MAX); |
983 | 936 | ||
@@ -1013,16 +966,6 @@ struct ath5k_nfcal_hist { | |||
1013 | s16 nfval[ATH5K_NF_CAL_HIST_MAX]; /* last few noise floors */ | 966 | s16 nfval[ATH5K_NF_CAL_HIST_MAX]; /* last few noise floors */ |
1014 | }; | 967 | }; |
1015 | 968 | ||
1016 | /** | ||
1017 | * struct avg_val - Helper structure for average calculation | ||
1018 | * @avg: contains the actual average value | ||
1019 | * @avg_weight: is used internally during calculation to prevent rounding errors | ||
1020 | */ | ||
1021 | struct ath5k_avg_val { | ||
1022 | int avg; | ||
1023 | int avg_weight; | ||
1024 | }; | ||
1025 | |||
1026 | #define ATH5K_LED_MAX_NAME_LEN 31 | 969 | #define ATH5K_LED_MAX_NAME_LEN 31 |
1027 | 970 | ||
1028 | /* | 971 | /* |
@@ -1148,7 +1091,6 @@ struct ath5k_hw { | |||
1148 | bool rx_pending; /* rx tasklet pending */ | 1091 | bool rx_pending; /* rx tasklet pending */ |
1149 | bool tx_pending; /* tx tasklet pending */ | 1092 | bool tx_pending; /* tx tasklet pending */ |
1150 | 1093 | ||
1151 | u8 lladdr[ETH_ALEN]; | ||
1152 | u8 bssidmask[ETH_ALEN]; | 1094 | u8 bssidmask[ETH_ALEN]; |
1153 | 1095 | ||
1154 | unsigned int led_pin, /* GPIO pin for driving LED */ | 1096 | unsigned int led_pin, /* GPIO pin for driving LED */ |
@@ -1156,7 +1098,6 @@ struct ath5k_hw { | |||
1156 | 1098 | ||
1157 | struct work_struct reset_work; /* deferred chip reset */ | 1099 | struct work_struct reset_work; /* deferred chip reset */ |
1158 | 1100 | ||
1159 | unsigned int rxbufsize; /* rx size based on mtu */ | ||
1160 | struct list_head rxbuf; /* receive buffer */ | 1101 | struct list_head rxbuf; /* receive buffer */ |
1161 | spinlock_t rxbuflock; | 1102 | spinlock_t rxbuflock; |
1162 | u32 *rxlink; /* link ptr in last RX desc */ | 1103 | u32 *rxlink; /* link ptr in last RX desc */ |
@@ -1208,10 +1149,8 @@ struct ath5k_hw { | |||
1208 | 1149 | ||
1209 | enum ath5k_version ah_version; | 1150 | enum ath5k_version ah_version; |
1210 | enum ath5k_radio ah_radio; | 1151 | enum ath5k_radio ah_radio; |
1211 | u32 ah_phy; | ||
1212 | u32 ah_mac_srev; | 1152 | u32 ah_mac_srev; |
1213 | u16 ah_mac_version; | 1153 | u16 ah_mac_version; |
1214 | u16 ah_mac_revision; | ||
1215 | u16 ah_phy_revision; | 1154 | u16 ah_phy_revision; |
1216 | u16 ah_radio_5ghz_revision; | 1155 | u16 ah_radio_5ghz_revision; |
1217 | u16 ah_radio_2ghz_revision; | 1156 | u16 ah_radio_2ghz_revision; |
@@ -1279,12 +1218,6 @@ struct ath5k_hw { | |||
1279 | bool txp_setup; | 1218 | bool txp_setup; |
1280 | } ah_txpower; | 1219 | } ah_txpower; |
1281 | 1220 | ||
1282 | struct { | ||
1283 | bool r_enabled; | ||
1284 | int r_last_alert; | ||
1285 | struct ieee80211_channel r_last_channel; | ||
1286 | } ah_radar; | ||
1287 | |||
1288 | struct ath5k_nfcal_hist ah_nfcal_hist; | 1221 | struct ath5k_nfcal_hist ah_nfcal_hist; |
1289 | 1222 | ||
1290 | /* average beacon RSSI in our BSS (used by ANI) */ | 1223 | /* average beacon RSSI in our BSS (used by ANI) */ |
@@ -1327,36 +1260,13 @@ struct ath_bus_ops { | |||
1327 | extern const struct ieee80211_ops ath5k_hw_ops; | 1260 | extern const struct ieee80211_ops ath5k_hw_ops; |
1328 | 1261 | ||
1329 | /* Initialization and detach functions */ | 1262 | /* Initialization and detach functions */ |
1330 | int ath5k_init_softc(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops); | ||
1331 | void ath5k_deinit_softc(struct ath5k_hw *ah); | ||
1332 | int ath5k_hw_init(struct ath5k_hw *ah); | 1263 | int ath5k_hw_init(struct ath5k_hw *ah); |
1333 | void ath5k_hw_deinit(struct ath5k_hw *ah); | 1264 | void ath5k_hw_deinit(struct ath5k_hw *ah); |
1334 | 1265 | ||
1335 | int ath5k_sysfs_register(struct ath5k_hw *ah); | 1266 | int ath5k_sysfs_register(struct ath5k_hw *ah); |
1336 | void ath5k_sysfs_unregister(struct ath5k_hw *ah); | 1267 | void ath5k_sysfs_unregister(struct ath5k_hw *ah); |
1337 | 1268 | ||
1338 | /* base.c */ | ||
1339 | struct ath5k_buf; | ||
1340 | struct ath5k_txq; | ||
1341 | |||
1342 | void ath5k_set_beacon_filter(struct ieee80211_hw *hw, bool enable); | ||
1343 | bool ath5k_any_vif_assoc(struct ath5k_hw *ah); | ||
1344 | void ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb, | ||
1345 | struct ath5k_txq *txq); | ||
1346 | int ath5k_start(struct ieee80211_hw *hw); | ||
1347 | void ath5k_stop(struct ieee80211_hw *hw); | ||
1348 | void ath5k_mode_setup(struct ath5k_hw *ah, struct ieee80211_vif *vif); | ||
1349 | void ath5k_update_bssid_mask_and_opmode(struct ath5k_hw *ah, | ||
1350 | struct ieee80211_vif *vif); | ||
1351 | int ath5k_chan_set(struct ath5k_hw *ah, struct ieee80211_channel *chan); | ||
1352 | void ath5k_beacon_update_timers(struct ath5k_hw *ah, u64 bc_tsf); | ||
1353 | int ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif); | ||
1354 | void ath5k_beacon_config(struct ath5k_hw *ah); | ||
1355 | void ath5k_txbuf_free_skb(struct ath5k_hw *ah, struct ath5k_buf *bf); | ||
1356 | void ath5k_rxbuf_free_skb(struct ath5k_hw *ah, struct ath5k_buf *bf); | ||
1357 | |||
1358 | /*Chip id helper functions */ | 1269 | /*Chip id helper functions */ |
1359 | const char *ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val); | ||
1360 | int ath5k_hw_read_srev(struct ath5k_hw *ah); | 1270 | int ath5k_hw_read_srev(struct ath5k_hw *ah); |
1361 | 1271 | ||
1362 | /* LED functions */ | 1272 | /* LED functions */ |
@@ -1367,7 +1277,7 @@ void ath5k_unregister_leds(struct ath5k_hw *ah); | |||
1367 | 1277 | ||
1368 | 1278 | ||
1369 | /* Reset Functions */ | 1279 | /* Reset Functions */ |
1370 | int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial); | 1280 | int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel); |
1371 | int ath5k_hw_on_hold(struct ath5k_hw *ah); | 1281 | int ath5k_hw_on_hold(struct ath5k_hw *ah); |
1372 | int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, | 1282 | int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, |
1373 | struct ieee80211_channel *channel, bool fast, bool skip_pcu); | 1283 | struct ieee80211_channel *channel, bool fast, bool skip_pcu); |
@@ -1487,13 +1397,13 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel); | |||
1487 | 1397 | ||
1488 | /* PHY functions */ | 1398 | /* PHY functions */ |
1489 | /* Misc PHY functions */ | 1399 | /* Misc PHY functions */ |
1490 | u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan); | 1400 | u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, enum ieee80211_band band); |
1491 | int ath5k_hw_phy_disable(struct ath5k_hw *ah); | 1401 | int ath5k_hw_phy_disable(struct ath5k_hw *ah); |
1492 | /* Gain_F optimization */ | 1402 | /* Gain_F optimization */ |
1493 | enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah); | 1403 | enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah); |
1494 | int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah); | 1404 | int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah); |
1495 | /* PHY/RF channel functions */ | 1405 | /* PHY/RF channel functions */ |
1496 | bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags); | 1406 | bool ath5k_channel_ok(struct ath5k_hw *ah, struct ieee80211_channel *channel); |
1497 | /* PHY calibration */ | 1407 | /* PHY calibration */ |
1498 | void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah); | 1408 | void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah); |
1499 | int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, | 1409 | int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, |
diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index f8a6b380d96d..91627dd2c26a 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include "ath5k.h" | 25 | #include "ath5k.h" |
26 | #include "reg.h" | 26 | #include "reg.h" |
27 | #include "debug.h" | 27 | #include "debug.h" |
28 | #include "base.h" | ||
29 | 28 | ||
30 | /** | 29 | /** |
31 | * ath5k_hw_post - Power On Self Test helper function | 30 | * ath5k_hw_post - Power On Self Test helper function |
@@ -95,7 +94,7 @@ static int ath5k_hw_post(struct ath5k_hw *ah) | |||
95 | /** | 94 | /** |
96 | * ath5k_hw_init - Check if hw is supported and init the needed structs | 95 | * ath5k_hw_init - Check if hw is supported and init the needed structs |
97 | * | 96 | * |
98 | * @ah: The &struct ath5k_hw we got from the driver's init_softc function | 97 | * @ah: The &struct ath5k_hw associated with the device |
99 | * | 98 | * |
100 | * Check if the device is supported, perform a POST and initialize the needed | 99 | * Check if the device is supported, perform a POST and initialize the needed |
101 | * structs. Returns -ENOMEM if we don't have memory for the needed structs, | 100 | * structs. Returns -ENOMEM if we don't have memory for the needed structs, |
@@ -114,7 +113,6 @@ int ath5k_hw_init(struct ath5k_hw *ah) | |||
114 | /* | 113 | /* |
115 | * HW information | 114 | * HW information |
116 | */ | 115 | */ |
117 | ah->ah_radar.r_enabled = AR5K_TUNE_RADAR_ALERT; | ||
118 | ah->ah_bwmode = AR5K_BWMODE_DEFAULT; | 116 | ah->ah_bwmode = AR5K_BWMODE_DEFAULT; |
119 | ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER; | 117 | ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER; |
120 | ah->ah_imr = 0; | 118 | ah->ah_imr = 0; |
@@ -137,9 +135,8 @@ int ath5k_hw_init(struct ath5k_hw *ah) | |||
137 | else | 135 | else |
138 | ah->ah_version = AR5K_AR5212; | 136 | ah->ah_version = AR5K_AR5212; |
139 | 137 | ||
140 | /* Get the MAC revision */ | 138 | /* Get the MAC version */ |
141 | ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER); | 139 | ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER); |
142 | ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV); | ||
143 | 140 | ||
144 | /* Fill the ath5k_hw struct with the needed functions */ | 141 | /* Fill the ath5k_hw struct with the needed functions */ |
145 | ret = ath5k_hw_init_desc_functions(ah); | 142 | ret = ath5k_hw_init_desc_functions(ah); |
@@ -147,7 +144,7 @@ int ath5k_hw_init(struct ath5k_hw *ah) | |||
147 | goto err; | 144 | goto err; |
148 | 145 | ||
149 | /* Bring device out of sleep and reset its units */ | 146 | /* Bring device out of sleep and reset its units */ |
150 | ret = ath5k_hw_nic_wakeup(ah, 0, true); | 147 | ret = ath5k_hw_nic_wakeup(ah, NULL); |
151 | if (ret) | 148 | if (ret) |
152 | goto err; | 149 | goto err; |
153 | 150 | ||
@@ -155,8 +152,7 @@ int ath5k_hw_init(struct ath5k_hw *ah) | |||
155 | ah->ah_phy_revision = ath5k_hw_reg_read(ah, AR5K_PHY_CHIP_ID) & | 152 | ah->ah_phy_revision = ath5k_hw_reg_read(ah, AR5K_PHY_CHIP_ID) & |
156 | 0xffffffff; | 153 | 0xffffffff; |
157 | ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah, | 154 | ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah, |
158 | CHANNEL_5GHZ); | 155 | IEEE80211_BAND_5GHZ); |
159 | ah->ah_phy = AR5K_PHY(0); | ||
160 | 156 | ||
161 | /* Try to identify radio chip based on its srev */ | 157 | /* Try to identify radio chip based on its srev */ |
162 | switch (ah->ah_radio_5ghz_revision & 0xf0) { | 158 | switch (ah->ah_radio_5ghz_revision & 0xf0) { |
@@ -164,14 +160,14 @@ int ath5k_hw_init(struct ath5k_hw *ah) | |||
164 | ah->ah_radio = AR5K_RF5111; | 160 | ah->ah_radio = AR5K_RF5111; |
165 | ah->ah_single_chip = false; | 161 | ah->ah_single_chip = false; |
166 | ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah, | 162 | ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah, |
167 | CHANNEL_2GHZ); | 163 | IEEE80211_BAND_2GHZ); |
168 | break; | 164 | break; |
169 | case AR5K_SREV_RAD_5112: | 165 | case AR5K_SREV_RAD_5112: |
170 | case AR5K_SREV_RAD_2112: | 166 | case AR5K_SREV_RAD_2112: |
171 | ah->ah_radio = AR5K_RF5112; | 167 | ah->ah_radio = AR5K_RF5112; |
172 | ah->ah_single_chip = false; | 168 | ah->ah_single_chip = false; |
173 | ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah, | 169 | ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah, |
174 | CHANNEL_2GHZ); | 170 | IEEE80211_BAND_2GHZ); |
175 | break; | 171 | break; |
176 | case AR5K_SREV_RAD_2413: | 172 | case AR5K_SREV_RAD_2413: |
177 | ah->ah_radio = AR5K_RF2413; | 173 | ah->ah_radio = AR5K_RF2413; |
@@ -208,7 +204,7 @@ int ath5k_hw_init(struct ath5k_hw *ah) | |||
208 | ah->ah_radio = AR5K_RF5111; | 204 | ah->ah_radio = AR5K_RF5111; |
209 | ah->ah_single_chip = false; | 205 | ah->ah_single_chip = false; |
210 | ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah, | 206 | ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah, |
211 | CHANNEL_2GHZ); | 207 | IEEE80211_BAND_2GHZ); |
212 | } else if (ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4) || | 208 | } else if (ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4) || |
213 | ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4) || | 209 | ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4) || |
214 | ah->ah_phy_revision == AR5K_SREV_PHY_2425) { | 210 | ah->ah_phy_revision == AR5K_SREV_PHY_2425) { |
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index c3119a6caace..e9ea38d0fff6 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c | |||
@@ -52,6 +52,7 @@ | |||
52 | #include <linux/uaccess.h> | 52 | #include <linux/uaccess.h> |
53 | #include <linux/slab.h> | 53 | #include <linux/slab.h> |
54 | #include <linux/etherdevice.h> | 54 | #include <linux/etherdevice.h> |
55 | #include <linux/nl80211.h> | ||
55 | 56 | ||
56 | #include <net/ieee80211_radiotap.h> | 57 | #include <net/ieee80211_radiotap.h> |
57 | 58 | ||
@@ -61,6 +62,8 @@ | |||
61 | #include "reg.h" | 62 | #include "reg.h" |
62 | #include "debug.h" | 63 | #include "debug.h" |
63 | #include "ani.h" | 64 | #include "ani.h" |
65 | #include "ath5k.h" | ||
66 | #include "../regd.h" | ||
64 | 67 | ||
65 | #define CREATE_TRACE_POINTS | 68 | #define CREATE_TRACE_POINTS |
66 | #include "trace.h" | 69 | #include "trace.h" |
@@ -272,20 +275,18 @@ static unsigned int | |||
272 | ath5k_setup_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels, | 275 | ath5k_setup_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels, |
273 | unsigned int mode, unsigned int max) | 276 | unsigned int mode, unsigned int max) |
274 | { | 277 | { |
275 | unsigned int count, size, chfreq, freq, ch; | 278 | unsigned int count, size, freq, ch; |
276 | enum ieee80211_band band; | 279 | enum ieee80211_band band; |
277 | 280 | ||
278 | switch (mode) { | 281 | switch (mode) { |
279 | case AR5K_MODE_11A: | 282 | case AR5K_MODE_11A: |
280 | /* 1..220, but 2GHz frequencies are filtered by check_channel */ | 283 | /* 1..220, but 2GHz frequencies are filtered by check_channel */ |
281 | size = 220; | 284 | size = 220; |
282 | chfreq = CHANNEL_5GHZ; | ||
283 | band = IEEE80211_BAND_5GHZ; | 285 | band = IEEE80211_BAND_5GHZ; |
284 | break; | 286 | break; |
285 | case AR5K_MODE_11B: | 287 | case AR5K_MODE_11B: |
286 | case AR5K_MODE_11G: | 288 | case AR5K_MODE_11G: |
287 | size = 26; | 289 | size = 26; |
288 | chfreq = CHANNEL_2GHZ; | ||
289 | band = IEEE80211_BAND_2GHZ; | 290 | band = IEEE80211_BAND_2GHZ; |
290 | break; | 291 | break; |
291 | default: | 292 | default: |
@@ -300,26 +301,19 @@ ath5k_setup_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels, | |||
300 | if (freq == 0) /* mapping failed - not a standard channel */ | 301 | if (freq == 0) /* mapping failed - not a standard channel */ |
301 | continue; | 302 | continue; |
302 | 303 | ||
304 | /* Write channel info, needed for ath5k_channel_ok() */ | ||
305 | channels[count].center_freq = freq; | ||
306 | channels[count].band = band; | ||
307 | channels[count].hw_value = mode; | ||
308 | |||
303 | /* Check if channel is supported by the chipset */ | 309 | /* Check if channel is supported by the chipset */ |
304 | if (!ath5k_channel_ok(ah, freq, chfreq)) | 310 | if (!ath5k_channel_ok(ah, &channels[count])) |
305 | continue; | 311 | continue; |
306 | 312 | ||
307 | if (!modparam_all_channels && | 313 | if (!modparam_all_channels && |
308 | !ath5k_is_standard_channel(ch, band)) | 314 | !ath5k_is_standard_channel(ch, band)) |
309 | continue; | 315 | continue; |
310 | 316 | ||
311 | /* Write channel info and increment counter */ | ||
312 | channels[count].center_freq = freq; | ||
313 | channels[count].band = band; | ||
314 | switch (mode) { | ||
315 | case AR5K_MODE_11A: | ||
316 | case AR5K_MODE_11G: | ||
317 | channels[count].hw_value = chfreq | CHANNEL_OFDM; | ||
318 | break; | ||
319 | case AR5K_MODE_11B: | ||
320 | channels[count].hw_value = CHANNEL_B; | ||
321 | } | ||
322 | |||
323 | count++; | 317 | count++; |
324 | } | 318 | } |
325 | 319 | ||
@@ -2349,7 +2343,7 @@ ath5k_tx_complete_poll_work(struct work_struct *work) | |||
2349 | \*************************/ | 2343 | \*************************/ |
2350 | 2344 | ||
2351 | int __devinit | 2345 | int __devinit |
2352 | ath5k_init_softc(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops) | 2346 | ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops) |
2353 | { | 2347 | { |
2354 | struct ieee80211_hw *hw = ah->hw; | 2348 | struct ieee80211_hw *hw = ah->hw; |
2355 | struct ath_common *common; | 2349 | struct ath_common *common; |
@@ -2867,7 +2861,6 @@ ath5k_init(struct ieee80211_hw *hw) | |||
2867 | } | 2861 | } |
2868 | 2862 | ||
2869 | SET_IEEE80211_PERM_ADDR(hw, mac); | 2863 | SET_IEEE80211_PERM_ADDR(hw, mac); |
2870 | memcpy(&ah->lladdr, mac, ETH_ALEN); | ||
2871 | /* All MAC address bits matter for ACKs */ | 2864 | /* All MAC address bits matter for ACKs */ |
2872 | ath5k_update_bssid_mask_and_opmode(ah, NULL); | 2865 | ath5k_update_bssid_mask_and_opmode(ah, NULL); |
2873 | 2866 | ||
@@ -2903,7 +2896,7 @@ err: | |||
2903 | } | 2896 | } |
2904 | 2897 | ||
2905 | void | 2898 | void |
2906 | ath5k_deinit_softc(struct ath5k_hw *ah) | 2899 | ath5k_deinit_ah(struct ath5k_hw *ah) |
2907 | { | 2900 | { |
2908 | struct ieee80211_hw *hw = ah->hw; | 2901 | struct ieee80211_hw *hw = ah->hw; |
2909 | 2902 | ||
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index a81f28d5bddc..6c94c7ff2350 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h | |||
@@ -38,19 +38,27 @@ | |||
38 | /* | 38 | /* |
39 | * Definitions for the Atheros Wireless LAN controller driver. | 39 | * Definitions for the Atheros Wireless LAN controller driver. |
40 | */ | 40 | */ |
41 | #ifndef _DEV_ATH_ATHVAR_H | 41 | #ifndef _DEV_ATH5K_BASE_H |
42 | #define _DEV_ATH_ATHVAR_H | 42 | #define _DEV_ATH5K_BASE_H |
43 | 43 | ||
44 | #include <linux/interrupt.h> | 44 | struct ieee80211_vif; |
45 | #include <linux/list.h> | 45 | struct ieee80211_hw; |
46 | #include <linux/wireless.h> | 46 | struct ath5k_hw; |
47 | #include <linux/if_ether.h> | 47 | struct ath5k_txq; |
48 | #include <linux/rfkill.h> | 48 | struct ieee80211_channel; |
49 | #include <linux/workqueue.h> | 49 | struct ath_bus_ops; |
50 | enum nl80211_iftype; | ||
50 | 51 | ||
51 | #include "ath5k.h" | 52 | enum ath5k_srev_type { |
52 | #include "../regd.h" | 53 | AR5K_VERSION_MAC, |
53 | #include "../ath.h" | 54 | AR5K_VERSION_RAD, |
55 | }; | ||
56 | |||
57 | struct ath5k_srev_name { | ||
58 | const char *sr_name; | ||
59 | enum ath5k_srev_type sr_type; | ||
60 | u_int sr_val; | ||
61 | }; | ||
54 | 62 | ||
55 | struct ath5k_buf { | 63 | struct ath5k_buf { |
56 | struct list_head list; | 64 | struct list_head list; |
@@ -65,7 +73,6 @@ struct ath5k_vif { | |||
65 | enum nl80211_iftype opmode; | 73 | enum nl80211_iftype opmode; |
66 | int bslot; | 74 | int bslot; |
67 | struct ath5k_buf *bbuf; /* beacon buffer */ | 75 | struct ath5k_buf *bbuf; /* beacon buffer */ |
68 | u8 lladdr[ETH_ALEN]; | ||
69 | }; | 76 | }; |
70 | 77 | ||
71 | struct ath5k_vif_iter_data { | 78 | struct ath5k_vif_iter_data { |
@@ -78,8 +85,30 @@ struct ath5k_vif_iter_data { | |||
78 | enum nl80211_iftype opmode; | 85 | enum nl80211_iftype opmode; |
79 | int n_stas; | 86 | int n_stas; |
80 | }; | 87 | }; |
88 | |||
81 | void ath5k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif); | 89 | void ath5k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif); |
90 | bool ath5k_any_vif_assoc(struct ath5k_hw *ah); | ||
91 | |||
92 | int ath5k_start(struct ieee80211_hw *hw); | ||
93 | void ath5k_stop(struct ieee80211_hw *hw); | ||
94 | |||
95 | void ath5k_beacon_update_timers(struct ath5k_hw *ah, u64 bc_tsf); | ||
96 | int ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif); | ||
97 | void ath5k_beacon_config(struct ath5k_hw *ah); | ||
98 | void ath5k_set_beacon_filter(struct ieee80211_hw *hw, bool enable); | ||
99 | |||
100 | void ath5k_update_bssid_mask_and_opmode(struct ath5k_hw *ah, | ||
101 | struct ieee80211_vif *vif); | ||
102 | int ath5k_chan_set(struct ath5k_hw *ah, struct ieee80211_channel *chan); | ||
103 | void ath5k_txbuf_free_skb(struct ath5k_hw *ah, struct ath5k_buf *bf); | ||
104 | void ath5k_rxbuf_free_skb(struct ath5k_hw *ah, struct ath5k_buf *bf); | ||
105 | void ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb, | ||
106 | struct ath5k_txq *txq); | ||
107 | |||
108 | const char *ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val); | ||
82 | 109 | ||
110 | int ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops); | ||
111 | void ath5k_deinit_ah(struct ath5k_hw *ah); | ||
83 | 112 | ||
84 | /* Check whether BSSID mask is supported */ | 113 | /* Check whether BSSID mask is supported */ |
85 | #define ath5k_hw_hasbssidmask(_ah) (ah->ah_version == AR5K_AR5212) | 114 | #define ath5k_hw_hasbssidmask(_ah) (ah->ah_version == AR5K_AR5212) |
@@ -87,4 +116,4 @@ void ath5k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif); | |||
87 | /* Check whether virtual EOL is supported */ | 116 | /* Check whether virtual EOL is supported */ |
88 | #define ath5k_hw_hasveol(_ah) (ah->ah_version != AR5K_AR5210) | 117 | #define ath5k_hw_hasveol(_ah) (ah->ah_version != AR5K_AR5210) |
89 | 118 | ||
90 | #endif | 119 | #endif /* _DEV_ATH5K_BASE_H */ |
diff --git a/drivers/net/wireless/ath/ath5k/caps.c b/drivers/net/wireless/ath/ath5k/caps.c index eefe670e28a7..810fba96702b 100644 --- a/drivers/net/wireless/ath/ath5k/caps.c +++ b/drivers/net/wireless/ath/ath5k/caps.c | |||
@@ -24,7 +24,7 @@ | |||
24 | #include "ath5k.h" | 24 | #include "ath5k.h" |
25 | #include "reg.h" | 25 | #include "reg.h" |
26 | #include "debug.h" | 26 | #include "debug.h" |
27 | #include "base.h" | 27 | #include "../regd.h" |
28 | 28 | ||
29 | /* | 29 | /* |
30 | * Fill the capabilities struct | 30 | * Fill the capabilities struct |
diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index ccca724de173..fce8c904eea9 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c | |||
@@ -58,19 +58,18 @@ | |||
58 | * THE POSSIBILITY OF SUCH DAMAGES. | 58 | * THE POSSIBILITY OF SUCH DAMAGES. |
59 | */ | 59 | */ |
60 | 60 | ||
61 | #include "base.h" | 61 | #include <linux/module.h> |
62 | #include <linux/seq_file.h> | ||
63 | #include <linux/list.h> | ||
62 | #include "debug.h" | 64 | #include "debug.h" |
65 | #include "ath5k.h" | ||
66 | #include "reg.h" | ||
67 | #include "base.h" | ||
63 | 68 | ||
64 | static unsigned int ath5k_debug; | 69 | static unsigned int ath5k_debug; |
65 | module_param_named(debug, ath5k_debug, uint, 0); | 70 | module_param_named(debug, ath5k_debug, uint, 0); |
66 | 71 | ||
67 | 72 | ||
68 | #ifdef CONFIG_ATH5K_DEBUG | ||
69 | |||
70 | #include <linux/seq_file.h> | ||
71 | #include "reg.h" | ||
72 | #include "ani.h" | ||
73 | |||
74 | static int ath5k_debugfs_open(struct inode *inode, struct file *file) | 73 | static int ath5k_debugfs_open(struct inode *inode, struct file *file) |
75 | { | 74 | { |
76 | file->private_data = inode->i_private; | 75 | file->private_data = inode->i_private; |
@@ -1031,5 +1030,3 @@ ath5k_debug_printtxbuf(struct ath5k_hw *ah, struct ath5k_buf *bf) | |||
1031 | td->tx_stat.tx_status_0, td->tx_stat.tx_status_1, | 1030 | td->tx_stat.tx_status_0, td->tx_stat.tx_status_1, |
1032 | done ? ' ' : (ts.ts_status == 0) ? '*' : '!'); | 1031 | done ? ' ' : (ts.ts_status == 0) ? '*' : '!'); |
1033 | } | 1032 | } |
1034 | |||
1035 | #endif /* ifdef CONFIG_ATH5K_DEBUG */ | ||
diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c index 846535f59efc..7e88dda82221 100644 --- a/drivers/net/wireless/ath/ath5k/desc.c +++ b/drivers/net/wireless/ath/ath5k/desc.c | |||
@@ -24,7 +24,6 @@ | |||
24 | #include "ath5k.h" | 24 | #include "ath5k.h" |
25 | #include "reg.h" | 25 | #include "reg.h" |
26 | #include "debug.h" | 26 | #include "debug.h" |
27 | #include "base.h" | ||
28 | 27 | ||
29 | 28 | ||
30 | /************************\ | 29 | /************************\ |
diff --git a/drivers/net/wireless/ath/ath5k/dma.c b/drivers/net/wireless/ath/ath5k/dma.c index 0d5d4033f12a..2481f9c7f4b6 100644 --- a/drivers/net/wireless/ath/ath5k/dma.c +++ b/drivers/net/wireless/ath/ath5k/dma.c | |||
@@ -35,7 +35,6 @@ | |||
35 | #include "ath5k.h" | 35 | #include "ath5k.h" |
36 | #include "reg.h" | 36 | #include "reg.h" |
37 | #include "debug.h" | 37 | #include "debug.h" |
38 | #include "base.h" | ||
39 | 38 | ||
40 | 39 | ||
41 | /*********\ | 40 | /*********\ |
diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index 9068b9165265..cd708c15b774 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include "ath5k.h" | 26 | #include "ath5k.h" |
27 | #include "reg.h" | 27 | #include "reg.h" |
28 | #include "debug.h" | 28 | #include "debug.h" |
29 | #include "base.h" | ||
30 | 29 | ||
31 | 30 | ||
32 | /******************\ | 31 | /******************\ |
@@ -1780,13 +1779,12 @@ ath5k_eeprom_detach(struct ath5k_hw *ah) | |||
1780 | int | 1779 | int |
1781 | ath5k_eeprom_mode_from_channel(struct ieee80211_channel *channel) | 1780 | ath5k_eeprom_mode_from_channel(struct ieee80211_channel *channel) |
1782 | { | 1781 | { |
1783 | switch (channel->hw_value & CHANNEL_MODES) { | 1782 | switch (channel->hw_value) { |
1784 | case CHANNEL_A: | 1783 | case AR5K_MODE_11A: |
1785 | case CHANNEL_XR: | ||
1786 | return AR5K_EEPROM_MODE_11A; | 1784 | return AR5K_EEPROM_MODE_11A; |
1787 | case CHANNEL_G: | 1785 | case AR5K_MODE_11G: |
1788 | return AR5K_EEPROM_MODE_11G; | 1786 | return AR5K_EEPROM_MODE_11G; |
1789 | case CHANNEL_B: | 1787 | case AR5K_MODE_11B: |
1790 | return AR5K_EEPROM_MODE_11B; | 1788 | return AR5K_EEPROM_MODE_11B; |
1791 | default: | 1789 | default: |
1792 | return -1; | 1790 | return -1; |
diff --git a/drivers/net/wireless/ath/ath5k/gpio.c b/drivers/net/wireless/ath/ath5k/gpio.c index bc90503f4b7a..859297811914 100644 --- a/drivers/net/wireless/ath/ath5k/gpio.c +++ b/drivers/net/wireless/ath/ath5k/gpio.c | |||
@@ -23,7 +23,6 @@ | |||
23 | #include "ath5k.h" | 23 | #include "ath5k.h" |
24 | #include "reg.h" | 24 | #include "reg.h" |
25 | #include "debug.h" | 25 | #include "debug.h" |
26 | #include "base.h" | ||
27 | 26 | ||
28 | /* | 27 | /* |
29 | * Set led state | 28 | * Set led state |
diff --git a/drivers/net/wireless/ath/ath5k/initvals.c b/drivers/net/wireless/ath/ath5k/initvals.c index 5ab607f40e0e..1ffecc0fd3ed 100644 --- a/drivers/net/wireless/ath/ath5k/initvals.c +++ b/drivers/net/wireless/ath/ath5k/initvals.c | |||
@@ -22,7 +22,6 @@ | |||
22 | #include "ath5k.h" | 22 | #include "ath5k.h" |
23 | #include "reg.h" | 23 | #include "reg.h" |
24 | #include "debug.h" | 24 | #include "debug.h" |
25 | #include "base.h" | ||
26 | 25 | ||
27 | /* | 26 | /* |
28 | * Mode-independent initial register writes | 27 | * Mode-independent initial register writes |
diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c index 8c17a00f7dad..c1151c723711 100644 --- a/drivers/net/wireless/ath/ath5k/led.c +++ b/drivers/net/wireless/ath/ath5k/led.c | |||
@@ -41,7 +41,6 @@ | |||
41 | 41 | ||
42 | #include <linux/pci.h> | 42 | #include <linux/pci.h> |
43 | #include "ath5k.h" | 43 | #include "ath5k.h" |
44 | #include "base.h" | ||
45 | 44 | ||
46 | #define ATH_SDEVICE(subv, subd) \ | 45 | #define ATH_SDEVICE(subv, subd) \ |
47 | .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \ | 46 | .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \ |
diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 2a715ca0c5e4..0560234ec3f6 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c | |||
@@ -41,8 +41,10 @@ | |||
41 | * | 41 | * |
42 | */ | 42 | */ |
43 | 43 | ||
44 | #include <net/mac80211.h> | ||
44 | #include <asm/unaligned.h> | 45 | #include <asm/unaligned.h> |
45 | 46 | ||
47 | #include "ath5k.h" | ||
46 | #include "base.h" | 48 | #include "base.h" |
47 | #include "reg.h" | 49 | #include "reg.h" |
48 | 50 | ||
@@ -137,11 +139,8 @@ ath5k_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | |||
137 | /* Any MAC address is fine, all others are included through the | 139 | /* Any MAC address is fine, all others are included through the |
138 | * filter. | 140 | * filter. |
139 | */ | 141 | */ |
140 | memcpy(&ah->lladdr, vif->addr, ETH_ALEN); | ||
141 | ath5k_hw_set_lladdr(ah, vif->addr); | 142 | ath5k_hw_set_lladdr(ah, vif->addr); |
142 | 143 | ||
143 | memcpy(&avf->lladdr, vif->addr, ETH_ALEN); | ||
144 | |||
145 | ath5k_update_bssid_mask_and_opmode(ah, vif); | 144 | ath5k_update_bssid_mask_and_opmode(ah, vif); |
146 | ret = 0; | 145 | ret = 0; |
147 | end: | 146 | end: |
diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c index eaf79b49341e..c1dff2ced044 100644 --- a/drivers/net/wireless/ath/ath5k/pci.c +++ b/drivers/net/wireless/ath/ath5k/pci.c | |||
@@ -261,7 +261,7 @@ ath5k_pci_probe(struct pci_dev *pdev, | |||
261 | ah->iobase = mem; /* So we can unmap it on detach */ | 261 | ah->iobase = mem; /* So we can unmap it on detach */ |
262 | 262 | ||
263 | /* Initialize */ | 263 | /* Initialize */ |
264 | ret = ath5k_init_softc(ah, &ath_pci_bus_ops); | 264 | ret = ath5k_init_ah(ah, &ath_pci_bus_ops); |
265 | if (ret) | 265 | if (ret) |
266 | goto err_free; | 266 | goto err_free; |
267 | 267 | ||
@@ -287,7 +287,7 @@ ath5k_pci_remove(struct pci_dev *pdev) | |||
287 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); | 287 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); |
288 | struct ath5k_hw *ah = hw->priv; | 288 | struct ath5k_hw *ah = hw->priv; |
289 | 289 | ||
290 | ath5k_deinit_softc(ah); | 290 | ath5k_deinit_ah(ah); |
291 | pci_iounmap(pdev, ah->iobase); | 291 | pci_iounmap(pdev, ah->iobase); |
292 | pci_release_region(pdev, 0); | 292 | pci_release_region(pdev, 0); |
293 | pci_disable_device(pdev); | 293 | pci_disable_device(pdev); |
diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 067313845060..a7eafa3edc21 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c | |||
@@ -29,7 +29,6 @@ | |||
29 | #include "ath5k.h" | 29 | #include "ath5k.h" |
30 | #include "reg.h" | 30 | #include "reg.h" |
31 | #include "debug.h" | 31 | #include "debug.h" |
32 | #include "base.h" | ||
33 | 32 | ||
34 | /* | 33 | /* |
35 | * AR5212+ can use higher rates for ack transmission | 34 | * AR5212+ can use higher rates for ack transmission |
@@ -152,7 +151,7 @@ unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah) | |||
152 | case AR5K_BWMODE_DEFAULT: | 151 | case AR5K_BWMODE_DEFAULT: |
153 | default: | 152 | default: |
154 | slot_time = AR5K_INIT_SLOT_TIME_DEFAULT; | 153 | slot_time = AR5K_INIT_SLOT_TIME_DEFAULT; |
155 | if ((channel->hw_value & CHANNEL_CCK) && !ah->ah_short_slot) | 154 | if ((channel->hw_value == AR5K_MODE_11B) && !ah->ah_short_slot) |
156 | slot_time = AR5K_INIT_SLOT_TIME_B; | 155 | slot_time = AR5K_INIT_SLOT_TIME_B; |
157 | break; | 156 | break; |
158 | } | 157 | } |
@@ -183,7 +182,7 @@ unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah) | |||
183 | case AR5K_BWMODE_DEFAULT: | 182 | case AR5K_BWMODE_DEFAULT: |
184 | sifs = AR5K_INIT_SIFS_DEFAULT_BG; | 183 | sifs = AR5K_INIT_SIFS_DEFAULT_BG; |
185 | default: | 184 | default: |
186 | if (channel->hw_value & CHANNEL_5GHZ) | 185 | if (channel->band == IEEE80211_BAND_5GHZ) |
187 | sifs = AR5K_INIT_SIFS_DEFAULT_A; | 186 | sifs = AR5K_INIT_SIFS_DEFAULT_A; |
188 | break; | 187 | break; |
189 | } | 188 | } |
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 81e465e70175..01cb72de44cb 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c | |||
@@ -26,9 +26,9 @@ | |||
26 | 26 | ||
27 | #include "ath5k.h" | 27 | #include "ath5k.h" |
28 | #include "reg.h" | 28 | #include "reg.h" |
29 | #include "base.h" | ||
30 | #include "rfbuffer.h" | 29 | #include "rfbuffer.h" |
31 | #include "rfgain.h" | 30 | #include "rfgain.h" |
31 | #include "../regd.h" | ||
32 | 32 | ||
33 | 33 | ||
34 | /******************\ | 34 | /******************\ |
@@ -38,7 +38,7 @@ | |||
38 | /* | 38 | /* |
39 | * Get the PHY Chip revision | 39 | * Get the PHY Chip revision |
40 | */ | 40 | */ |
41 | u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan) | 41 | u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, enum ieee80211_band band) |
42 | { | 42 | { |
43 | unsigned int i; | 43 | unsigned int i; |
44 | u32 srev; | 44 | u32 srev; |
@@ -47,11 +47,11 @@ u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan) | |||
47 | /* | 47 | /* |
48 | * Set the radio chip access register | 48 | * Set the radio chip access register |
49 | */ | 49 | */ |
50 | switch (chan) { | 50 | switch (band) { |
51 | case CHANNEL_2GHZ: | 51 | case IEEE80211_BAND_2GHZ: |
52 | ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_2GHZ, AR5K_PHY(0)); | 52 | ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_2GHZ, AR5K_PHY(0)); |
53 | break; | 53 | break; |
54 | case CHANNEL_5GHZ: | 54 | case IEEE80211_BAND_5GHZ: |
55 | ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0)); | 55 | ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0)); |
56 | break; | 56 | break; |
57 | default: | 57 | default: |
@@ -84,14 +84,16 @@ u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan) | |||
84 | /* | 84 | /* |
85 | * Check if a channel is supported | 85 | * Check if a channel is supported |
86 | */ | 86 | */ |
87 | bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags) | 87 | bool ath5k_channel_ok(struct ath5k_hw *ah, struct ieee80211_channel *channel) |
88 | { | 88 | { |
89 | u16 freq = channel->center_freq; | ||
90 | |||
89 | /* Check if the channel is in our supported range */ | 91 | /* Check if the channel is in our supported range */ |
90 | if (flags & CHANNEL_2GHZ) { | 92 | if (channel->band == IEEE80211_BAND_2GHZ) { |
91 | if ((freq >= ah->ah_capabilities.cap_range.range_2ghz_min) && | 93 | if ((freq >= ah->ah_capabilities.cap_range.range_2ghz_min) && |
92 | (freq <= ah->ah_capabilities.cap_range.range_2ghz_max)) | 94 | (freq <= ah->ah_capabilities.cap_range.range_2ghz_max)) |
93 | return true; | 95 | return true; |
94 | } else if (flags & CHANNEL_5GHZ) | 96 | } else if (channel->band == IEEE80211_BAND_5GHZ) |
95 | if ((freq >= ah->ah_capabilities.cap_range.range_5ghz_min) && | 97 | if ((freq >= ah->ah_capabilities.cap_range.range_5ghz_min) && |
96 | (freq <= ah->ah_capabilities.cap_range.range_5ghz_max)) | 98 | (freq <= ah->ah_capabilities.cap_range.range_5ghz_max)) |
97 | return true; | 99 | return true; |
@@ -224,7 +226,7 @@ static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah, | |||
224 | ds_coef_exp, ds_coef_man, clock; | 226 | ds_coef_exp, ds_coef_man, clock; |
225 | 227 | ||
226 | BUG_ON(!(ah->ah_version == AR5K_AR5212) || | 228 | BUG_ON(!(ah->ah_version == AR5K_AR5212) || |
227 | !(channel->hw_value & CHANNEL_OFDM)); | 229 | (channel->hw_value == AR5K_MODE_11B)); |
228 | 230 | ||
229 | /* Get coefficient | 231 | /* Get coefficient |
230 | * ALGO: coef = (5 * clock / carrier_freq) / 2 | 232 | * ALGO: coef = (5 * clock / carrier_freq) / 2 |
@@ -298,7 +300,7 @@ static void ath5k_hw_wait_for_synth(struct ath5k_hw *ah, | |||
298 | u32 delay; | 300 | u32 delay; |
299 | delay = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) & | 301 | delay = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) & |
300 | AR5K_PHY_RX_DELAY_M; | 302 | AR5K_PHY_RX_DELAY_M; |
301 | delay = (channel->hw_value & CHANNEL_CCK) ? | 303 | delay = (channel->hw_value == AR5K_MODE_11B) ? |
302 | ((delay << 2) / 22) : (delay / 10); | 304 | ((delay << 2) / 22) : (delay / 10); |
303 | if (ah->ah_bwmode == AR5K_BWMODE_10MHZ) | 305 | if (ah->ah_bwmode == AR5K_BWMODE_10MHZ) |
304 | delay = delay << 1; | 306 | delay = delay << 1; |
@@ -798,9 +800,9 @@ static int ath5k_hw_rfregs_init(struct ath5k_hw *ah, | |||
798 | } | 800 | } |
799 | 801 | ||
800 | /* Set Output and Driver bias current (OB/DB) */ | 802 | /* Set Output and Driver bias current (OB/DB) */ |
801 | if (channel->hw_value & CHANNEL_2GHZ) { | 803 | if (channel->band == IEEE80211_BAND_2GHZ) { |
802 | 804 | ||
803 | if (channel->hw_value & CHANNEL_CCK) | 805 | if (channel->hw_value == AR5K_MODE_11B) |
804 | ee_mode = AR5K_EEPROM_MODE_11B; | 806 | ee_mode = AR5K_EEPROM_MODE_11B; |
805 | else | 807 | else |
806 | ee_mode = AR5K_EEPROM_MODE_11G; | 808 | ee_mode = AR5K_EEPROM_MODE_11G; |
@@ -825,7 +827,7 @@ static int ath5k_hw_rfregs_init(struct ath5k_hw *ah, | |||
825 | AR5K_RF_DB_2GHZ, true); | 827 | AR5K_RF_DB_2GHZ, true); |
826 | 828 | ||
827 | /* RF5111 always needs OB/DB for 5GHz, even if we use 2GHz */ | 829 | /* RF5111 always needs OB/DB for 5GHz, even if we use 2GHz */ |
828 | } else if ((channel->hw_value & CHANNEL_5GHZ) || | 830 | } else if ((channel->band == IEEE80211_BAND_5GHZ) || |
829 | (ah->ah_radio == AR5K_RF5111)) { | 831 | (ah->ah_radio == AR5K_RF5111)) { |
830 | 832 | ||
831 | /* For 11a, Turbo and XR we need to choose | 833 | /* For 11a, Turbo and XR we need to choose |
@@ -857,7 +859,7 @@ static int ath5k_hw_rfregs_init(struct ath5k_hw *ah, | |||
857 | if (ah->ah_radio == AR5K_RF5111) { | 859 | if (ah->ah_radio == AR5K_RF5111) { |
858 | 860 | ||
859 | /* Set gain_F settings according to current step */ | 861 | /* Set gain_F settings according to current step */ |
860 | if (channel->hw_value & CHANNEL_OFDM) { | 862 | if (channel->hw_value != AR5K_MODE_11B) { |
861 | 863 | ||
862 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL, | 864 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL, |
863 | AR5K_PHY_FRAME_CTL_TX_CLIP, | 865 | AR5K_PHY_FRAME_CTL_TX_CLIP, |
@@ -914,7 +916,7 @@ static int ath5k_hw_rfregs_init(struct ath5k_hw *ah, | |||
914 | if (ah->ah_radio == AR5K_RF5112) { | 916 | if (ah->ah_radio == AR5K_RF5112) { |
915 | 917 | ||
916 | /* Set gain_F settings according to current step */ | 918 | /* Set gain_F settings according to current step */ |
917 | if (channel->hw_value & CHANNEL_OFDM) { | 919 | if (channel->hw_value != AR5K_MODE_11B) { |
918 | 920 | ||
919 | ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[0], | 921 | ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[0], |
920 | AR5K_RF_MIXGAIN_OVR, true); | 922 | AR5K_RF_MIXGAIN_OVR, true); |
@@ -1026,7 +1028,7 @@ static int ath5k_hw_rfregs_init(struct ath5k_hw *ah, | |||
1026 | } | 1028 | } |
1027 | 1029 | ||
1028 | if (ah->ah_radio == AR5K_RF5413 && | 1030 | if (ah->ah_radio == AR5K_RF5413 && |
1029 | channel->hw_value & CHANNEL_2GHZ) { | 1031 | channel->band == IEEE80211_BAND_2GHZ) { |
1030 | 1032 | ||
1031 | ath5k_hw_rfb_op(ah, rf_regs, 1, AR5K_RF_DERBY_CHAN_SEL_MODE, | 1033 | ath5k_hw_rfb_op(ah, rf_regs, 1, AR5K_RF_DERBY_CHAN_SEL_MODE, |
1032 | true); | 1034 | true); |
@@ -1138,7 +1140,7 @@ static int ath5k_hw_rf5111_channel(struct ath5k_hw *ah, | |||
1138 | */ | 1140 | */ |
1139 | data0 = data1 = 0; | 1141 | data0 = data1 = 0; |
1140 | 1142 | ||
1141 | if (channel->hw_value & CHANNEL_2GHZ) { | 1143 | if (channel->band == IEEE80211_BAND_2GHZ) { |
1142 | /* Map 2GHz channel to 5GHz Atheros channel ID */ | 1144 | /* Map 2GHz channel to 5GHz Atheros channel ID */ |
1143 | ret = ath5k_hw_rf5111_chan2athchan( | 1145 | ret = ath5k_hw_rf5111_chan2athchan( |
1144 | ieee80211_frequency_to_channel(channel->center_freq), | 1146 | ieee80211_frequency_to_channel(channel->center_freq), |
@@ -1265,10 +1267,9 @@ static int ath5k_hw_channel(struct ath5k_hw *ah, | |||
1265 | int ret; | 1267 | int ret; |
1266 | /* | 1268 | /* |
1267 | * Check bounds supported by the PHY (we don't care about regulatory | 1269 | * Check bounds supported by the PHY (we don't care about regulatory |
1268 | * restrictions at this point). Note: hw_value already has the band | 1270 | * restrictions at this point). |
1269 | * (CHANNEL_2GHZ, or CHANNEL_5GHZ) so we inform ath5k_channel_ok() | 1271 | */ |
1270 | * of the band by that */ | 1272 | if (!ath5k_channel_ok(ah, channel)) { |
1271 | if (!ath5k_channel_ok(ah, channel->center_freq, channel->hw_value)) { | ||
1272 | ATH5K_ERR(ah, | 1273 | ATH5K_ERR(ah, |
1273 | "channel frequency (%u MHz) out of supported " | 1274 | "channel frequency (%u MHz) out of supported " |
1274 | "band range\n", | 1275 | "band range\n", |
@@ -1614,7 +1615,7 @@ int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, | |||
1614 | ret = ath5k_hw_rf511x_iq_calibrate(ah); | 1615 | ret = ath5k_hw_rf511x_iq_calibrate(ah); |
1615 | 1616 | ||
1616 | if ((ah->ah_radio == AR5K_RF5111 || ah->ah_radio == AR5K_RF5112) && | 1617 | if ((ah->ah_radio == AR5K_RF5111 || ah->ah_radio == AR5K_RF5112) && |
1617 | (channel->hw_value & CHANNEL_OFDM)) | 1618 | (channel->hw_value != AR5K_MODE_11B)) |
1618 | ath5k_hw_request_rfgain_probe(ah); | 1619 | ath5k_hw_request_rfgain_probe(ah); |
1619 | 1620 | ||
1620 | return ret; | 1621 | return ret; |
@@ -1641,7 +1642,7 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah, | |||
1641 | /* Convert current frequency to fbin value (the same way channels | 1642 | /* Convert current frequency to fbin value (the same way channels |
1642 | * are stored on EEPROM, check out ath5k_eeprom_bin2freq) and scale | 1643 | * are stored on EEPROM, check out ath5k_eeprom_bin2freq) and scale |
1643 | * up by 2 so we can compare it later */ | 1644 | * up by 2 so we can compare it later */ |
1644 | if (channel->hw_value & CHANNEL_2GHZ) { | 1645 | if (channel->band == IEEE80211_BAND_2GHZ) { |
1645 | chan_fbin = (channel->center_freq - 2300) * 10; | 1646 | chan_fbin = (channel->center_freq - 2300) * 10; |
1646 | freq_band = AR5K_EEPROM_BAND_2GHZ; | 1647 | freq_band = AR5K_EEPROM_BAND_2GHZ; |
1647 | } else { | 1648 | } else { |
@@ -1703,7 +1704,7 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah, | |||
1703 | spur_freq_sigma_delta = (spur_delta_phase >> 10); | 1704 | spur_freq_sigma_delta = (spur_delta_phase >> 10); |
1704 | symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz / 4; | 1705 | symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz / 4; |
1705 | default: | 1706 | default: |
1706 | if (channel->hw_value == CHANNEL_A) { | 1707 | if (channel->band == IEEE80211_BAND_5GHZ) { |
1707 | /* Both sample_freq and chip_freq are 40MHz */ | 1708 | /* Both sample_freq and chip_freq are 40MHz */ |
1708 | spur_delta_phase = (spur_offset << 17) / 25; | 1709 | spur_delta_phase = (spur_offset << 17) / 25; |
1709 | spur_freq_sigma_delta = | 1710 | spur_freq_sigma_delta = |
@@ -2226,15 +2227,20 @@ ath5k_get_chan_pcal_surrounding_piers(struct ath5k_hw *ah, | |||
2226 | idx_l = 0; | 2227 | idx_l = 0; |
2227 | idx_r = 0; | 2228 | idx_r = 0; |
2228 | 2229 | ||
2229 | if (!(channel->hw_value & CHANNEL_OFDM)) { | 2230 | switch (channel->hw_value) { |
2231 | case AR5K_EEPROM_MODE_11A: | ||
2232 | pcinfo = ee->ee_pwr_cal_a; | ||
2233 | mode = AR5K_EEPROM_MODE_11A; | ||
2234 | break; | ||
2235 | case AR5K_EEPROM_MODE_11B: | ||
2230 | pcinfo = ee->ee_pwr_cal_b; | 2236 | pcinfo = ee->ee_pwr_cal_b; |
2231 | mode = AR5K_EEPROM_MODE_11B; | 2237 | mode = AR5K_EEPROM_MODE_11B; |
2232 | } else if (channel->hw_value & CHANNEL_2GHZ) { | 2238 | break; |
2239 | case AR5K_EEPROM_MODE_11G: | ||
2240 | default: | ||
2233 | pcinfo = ee->ee_pwr_cal_g; | 2241 | pcinfo = ee->ee_pwr_cal_g; |
2234 | mode = AR5K_EEPROM_MODE_11G; | 2242 | mode = AR5K_EEPROM_MODE_11G; |
2235 | } else { | 2243 | break; |
2236 | pcinfo = ee->ee_pwr_cal_a; | ||
2237 | mode = AR5K_EEPROM_MODE_11A; | ||
2238 | } | 2244 | } |
2239 | max = ee->ee_n_piers[mode] - 1; | 2245 | max = ee->ee_n_piers[mode] - 1; |
2240 | 2246 | ||
@@ -2303,15 +2309,20 @@ ath5k_get_rate_pcal_data(struct ath5k_hw *ah, | |||
2303 | idx_l = 0; | 2309 | idx_l = 0; |
2304 | idx_r = 0; | 2310 | idx_r = 0; |
2305 | 2311 | ||
2306 | if (!(channel->hw_value & CHANNEL_OFDM)) { | 2312 | switch (channel->hw_value) { |
2313 | case AR5K_MODE_11A: | ||
2314 | rpinfo = ee->ee_rate_tpwr_a; | ||
2315 | mode = AR5K_EEPROM_MODE_11A; | ||
2316 | break; | ||
2317 | case AR5K_MODE_11B: | ||
2307 | rpinfo = ee->ee_rate_tpwr_b; | 2318 | rpinfo = ee->ee_rate_tpwr_b; |
2308 | mode = AR5K_EEPROM_MODE_11B; | 2319 | mode = AR5K_EEPROM_MODE_11B; |
2309 | } else if (channel->hw_value & CHANNEL_2GHZ) { | 2320 | break; |
2321 | case AR5K_MODE_11G: | ||
2322 | default: | ||
2310 | rpinfo = ee->ee_rate_tpwr_g; | 2323 | rpinfo = ee->ee_rate_tpwr_g; |
2311 | mode = AR5K_EEPROM_MODE_11G; | 2324 | mode = AR5K_EEPROM_MODE_11G; |
2312 | } else { | 2325 | break; |
2313 | rpinfo = ee->ee_rate_tpwr_a; | ||
2314 | mode = AR5K_EEPROM_MODE_11A; | ||
2315 | } | 2326 | } |
2316 | max = ee->ee_rate_target_pwr_num[mode] - 1; | 2327 | max = ee->ee_rate_target_pwr_num[mode] - 1; |
2317 | 2328 | ||
@@ -2392,24 +2403,22 @@ ath5k_get_max_ctl_power(struct ath5k_hw *ah, | |||
2392 | 2403 | ||
2393 | ctl_mode = ath_regd_get_band_ctl(regulatory, channel->band); | 2404 | ctl_mode = ath_regd_get_band_ctl(regulatory, channel->band); |
2394 | 2405 | ||
2395 | switch (channel->hw_value & CHANNEL_MODES) { | 2406 | switch (channel->hw_value) { |
2396 | case CHANNEL_A: | 2407 | case AR5K_MODE_11A: |
2397 | if (ah->ah_bwmode == AR5K_BWMODE_40MHZ) | 2408 | if (ah->ah_bwmode == AR5K_BWMODE_40MHZ) |
2398 | ctl_mode |= AR5K_CTL_TURBO; | 2409 | ctl_mode |= AR5K_CTL_TURBO; |
2399 | else | 2410 | else |
2400 | ctl_mode |= AR5K_CTL_11A; | 2411 | ctl_mode |= AR5K_CTL_11A; |
2401 | break; | 2412 | break; |
2402 | case CHANNEL_G: | 2413 | case AR5K_MODE_11G: |
2403 | if (ah->ah_bwmode == AR5K_BWMODE_40MHZ) | 2414 | if (ah->ah_bwmode == AR5K_BWMODE_40MHZ) |
2404 | ctl_mode |= AR5K_CTL_TURBOG; | 2415 | ctl_mode |= AR5K_CTL_TURBOG; |
2405 | else | 2416 | else |
2406 | ctl_mode |= AR5K_CTL_11G; | 2417 | ctl_mode |= AR5K_CTL_11G; |
2407 | break; | 2418 | break; |
2408 | case CHANNEL_B: | 2419 | case AR5K_MODE_11B: |
2409 | ctl_mode |= AR5K_CTL_11B; | 2420 | ctl_mode |= AR5K_CTL_11B; |
2410 | break; | 2421 | break; |
2411 | case CHANNEL_XR: | ||
2412 | /* Fall through */ | ||
2413 | default: | 2422 | default: |
2414 | return; | 2423 | return; |
2415 | } | 2424 | } |
@@ -3292,7 +3301,7 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, | |||
3292 | 3301 | ||
3293 | /* Write OFDM timings on 5212*/ | 3302 | /* Write OFDM timings on 5212*/ |
3294 | if (ah->ah_version == AR5K_AR5212 && | 3303 | if (ah->ah_version == AR5K_AR5212 && |
3295 | channel->hw_value & CHANNEL_OFDM) { | 3304 | channel->hw_value != AR5K_MODE_11B) { |
3296 | 3305 | ||
3297 | ret = ath5k_hw_write_ofdm_timings(ah, channel); | 3306 | ret = ath5k_hw_write_ofdm_timings(ah, channel); |
3298 | if (ret) | 3307 | if (ret) |
diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c index 65f10398999e..776654228eaa 100644 --- a/drivers/net/wireless/ath/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c | |||
@@ -23,7 +23,6 @@ Queue Control Unit, DFS Control Unit Functions | |||
23 | #include "ath5k.h" | 23 | #include "ath5k.h" |
24 | #include "reg.h" | 24 | #include "reg.h" |
25 | #include "debug.h" | 25 | #include "debug.h" |
26 | #include "base.h" | ||
27 | 26 | ||
28 | 27 | ||
29 | /******************\ | 28 | /******************\ |
@@ -185,13 +184,6 @@ int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, | |||
185 | case AR5K_TX_QUEUE_CAB: | 184 | case AR5K_TX_QUEUE_CAB: |
186 | queue = AR5K_TX_QUEUE_ID_CAB; | 185 | queue = AR5K_TX_QUEUE_ID_CAB; |
187 | break; | 186 | break; |
188 | case AR5K_TX_QUEUE_XR_DATA: | ||
189 | if (ah->ah_version != AR5K_AR5212) | ||
190 | ATH5K_ERR(ah, | ||
191 | "XR data queues only supported in" | ||
192 | " 5212!\n"); | ||
193 | queue = AR5K_TX_QUEUE_ID_XR_DATA; | ||
194 | break; | ||
195 | default: | 187 | default: |
196 | return -EINVAL; | 188 | return -EINVAL; |
197 | } | 189 | } |
@@ -544,7 +536,7 @@ int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time) | |||
544 | * | 536 | * |
545 | * Also we have different lowest rate for 802.11a | 537 | * Also we have different lowest rate for 802.11a |
546 | */ | 538 | */ |
547 | if (channel->hw_value & CHANNEL_5GHZ) | 539 | if (channel->band == IEEE80211_BAND_5GHZ) |
548 | rate = &ah->sbands[IEEE80211_BAND_5GHZ].bitrates[0]; | 540 | rate = &ah->sbands[IEEE80211_BAND_5GHZ].bitrates[0]; |
549 | else | 541 | else |
550 | rate = &ah->sbands[IEEE80211_BAND_2GHZ].bitrates[0]; | 542 | rate = &ah->sbands[IEEE80211_BAND_2GHZ].bitrates[0]; |
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 0686c5d8d56e..2abac257b4b4 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c | |||
@@ -30,7 +30,6 @@ | |||
30 | #include <linux/platform_device.h> | 30 | #include <linux/platform_device.h> |
31 | #include "ath5k.h" | 31 | #include "ath5k.h" |
32 | #include "reg.h" | 32 | #include "reg.h" |
33 | #include "base.h" | ||
34 | #include "debug.h" | 33 | #include "debug.h" |
35 | 34 | ||
36 | 35 | ||
@@ -102,12 +101,18 @@ static void ath5k_hw_init_core_clock(struct ath5k_hw *ah) | |||
102 | /* | 101 | /* |
103 | * Set core clock frequency | 102 | * Set core clock frequency |
104 | */ | 103 | */ |
105 | if (channel->hw_value & CHANNEL_5GHZ) | 104 | switch (channel->hw_value) { |
106 | clock = 40; /* 802.11a */ | 105 | case AR5K_MODE_11A: |
107 | else if (channel->hw_value & CHANNEL_CCK) | 106 | clock = 40; |
108 | clock = 22; /* 802.11b */ | 107 | break; |
109 | else | 108 | case AR5K_MODE_11B: |
110 | clock = 44; /* 802.11g */ | 109 | clock = 22; |
110 | break; | ||
111 | case AR5K_MODE_11G: | ||
112 | default: | ||
113 | clock = 44; | ||
114 | break; | ||
115 | } | ||
111 | 116 | ||
112 | /* Use clock multiplier for non-default | 117 | /* Use clock multiplier for non-default |
113 | * bwmode */ | 118 | * bwmode */ |
@@ -581,8 +586,9 @@ int ath5k_hw_on_hold(struct ath5k_hw *ah) | |||
581 | 586 | ||
582 | /* | 587 | /* |
583 | * Bring up MAC + PHY Chips and program PLL | 588 | * Bring up MAC + PHY Chips and program PLL |
589 | * Channel is NULL for the initial wakeup. | ||
584 | */ | 590 | */ |
585 | int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) | 591 | int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel) |
586 | { | 592 | { |
587 | struct pci_dev *pdev = ah->pdev; | 593 | struct pci_dev *pdev = ah->pdev; |
588 | u32 turbo, mode, clock, bus_flags; | 594 | u32 turbo, mode, clock, bus_flags; |
@@ -592,7 +598,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) | |||
592 | mode = 0; | 598 | mode = 0; |
593 | clock = 0; | 599 | clock = 0; |
594 | 600 | ||
595 | if ((ath5k_get_bus_type(ah) != ATH_AHB) || !initial) { | 601 | if ((ath5k_get_bus_type(ah) != ATH_AHB) || channel) { |
596 | /* Wakeup the device */ | 602 | /* Wakeup the device */ |
597 | ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); | 603 | ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); |
598 | if (ret) { | 604 | if (ret) { |
@@ -652,7 +658,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) | |||
652 | 658 | ||
653 | /* On initialization skip PLL programming since we don't have | 659 | /* On initialization skip PLL programming since we don't have |
654 | * a channel / mode set yet */ | 660 | * a channel / mode set yet */ |
655 | if (initial) | 661 | if (!channel) |
656 | return 0; | 662 | return 0; |
657 | 663 | ||
658 | if (ah->ah_version != AR5K_AR5210) { | 664 | if (ah->ah_version != AR5K_AR5210) { |
@@ -668,13 +674,13 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) | |||
668 | clock = AR5K_PHY_PLL_RF5111; /*Zero*/ | 674 | clock = AR5K_PHY_PLL_RF5111; /*Zero*/ |
669 | } | 675 | } |
670 | 676 | ||
671 | if (flags & CHANNEL_2GHZ) { | 677 | if (channel->band == IEEE80211_BAND_2GHZ) { |
672 | mode |= AR5K_PHY_MODE_FREQ_2GHZ; | 678 | mode |= AR5K_PHY_MODE_FREQ_2GHZ; |
673 | clock |= AR5K_PHY_PLL_44MHZ; | 679 | clock |= AR5K_PHY_PLL_44MHZ; |
674 | 680 | ||
675 | if (flags & CHANNEL_CCK) { | 681 | if (channel->hw_value == AR5K_MODE_11B) { |
676 | mode |= AR5K_PHY_MODE_MOD_CCK; | 682 | mode |= AR5K_PHY_MODE_MOD_CCK; |
677 | } else if (flags & CHANNEL_OFDM) { | 683 | } else { |
678 | /* XXX Dynamic OFDM/CCK is not supported by the | 684 | /* XXX Dynamic OFDM/CCK is not supported by the |
679 | * AR5211 so we set MOD_OFDM for plain g (no | 685 | * AR5211 so we set MOD_OFDM for plain g (no |
680 | * CCK headers) operation. We need to test | 686 | * CCK headers) operation. We need to test |
@@ -686,27 +692,16 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) | |||
686 | mode |= AR5K_PHY_MODE_MOD_OFDM; | 692 | mode |= AR5K_PHY_MODE_MOD_OFDM; |
687 | else | 693 | else |
688 | mode |= AR5K_PHY_MODE_MOD_DYN; | 694 | mode |= AR5K_PHY_MODE_MOD_DYN; |
689 | } else { | ||
690 | ATH5K_ERR(ah, | ||
691 | "invalid radio modulation mode\n"); | ||
692 | return -EINVAL; | ||
693 | } | 695 | } |
694 | } else if (flags & CHANNEL_5GHZ) { | 696 | } else if (channel->band == IEEE80211_BAND_5GHZ) { |
695 | mode |= AR5K_PHY_MODE_FREQ_5GHZ; | 697 | mode |= (AR5K_PHY_MODE_FREQ_5GHZ | |
698 | AR5K_PHY_MODE_MOD_OFDM); | ||
696 | 699 | ||
697 | /* Different PLL setting for 5413 */ | 700 | /* Different PLL setting for 5413 */ |
698 | if (ah->ah_radio == AR5K_RF5413) | 701 | if (ah->ah_radio == AR5K_RF5413) |
699 | clock = AR5K_PHY_PLL_40MHZ_5413; | 702 | clock = AR5K_PHY_PLL_40MHZ_5413; |
700 | else | 703 | else |
701 | clock |= AR5K_PHY_PLL_40MHZ; | 704 | clock |= AR5K_PHY_PLL_40MHZ; |
702 | |||
703 | if (flags & CHANNEL_OFDM) | ||
704 | mode |= AR5K_PHY_MODE_MOD_OFDM; | ||
705 | else { | ||
706 | ATH5K_ERR(ah, | ||
707 | "invalid radio modulation mode\n"); | ||
708 | return -EINVAL; | ||
709 | } | ||
710 | } else { | 705 | } else { |
711 | ATH5K_ERR(ah, "invalid radio frequency mode\n"); | 706 | ATH5K_ERR(ah, "invalid radio frequency mode\n"); |
712 | return -EINVAL; | 707 | return -EINVAL; |
@@ -822,7 +817,7 @@ static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah, | |||
822 | u32 data; | 817 | u32 data; |
823 | ath5k_hw_reg_write(ah, AR5K_PHY_CCKTXCTL_WORLD, | 818 | ath5k_hw_reg_write(ah, AR5K_PHY_CCKTXCTL_WORLD, |
824 | AR5K_PHY_CCKTXCTL); | 819 | AR5K_PHY_CCKTXCTL); |
825 | if (channel->hw_value & CHANNEL_5GHZ) | 820 | if (channel->band == IEEE80211_BAND_5GHZ) |
826 | data = 0xffb81020; | 821 | data = 0xffb81020; |
827 | else | 822 | else |
828 | data = 0xffb80d20; | 823 | data = 0xffb80d20; |
@@ -905,7 +900,7 @@ static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah, | |||
905 | /* Set CCK to OFDM power delta on tx power | 900 | /* Set CCK to OFDM power delta on tx power |
906 | * adjustment register */ | 901 | * adjustment register */ |
907 | if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) { | 902 | if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) { |
908 | if (channel->hw_value == CHANNEL_G) | 903 | if (channel->hw_value == AR5K_MODE_11G) |
909 | ath5k_hw_reg_write(ah, | 904 | ath5k_hw_reg_write(ah, |
910 | AR5K_REG_SM((ee->ee_cck_ofdm_gain_delta * -1), | 905 | AR5K_REG_SM((ee->ee_cck_ofdm_gain_delta * -1), |
911 | AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA) | | 906 | AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA) | |
@@ -1084,37 +1079,23 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, | |||
1084 | ret = 0; | 1079 | ret = 0; |
1085 | } | 1080 | } |
1086 | 1081 | ||
1087 | switch (channel->hw_value & CHANNEL_MODES) { | 1082 | mode = channel->hw_value; |
1088 | case CHANNEL_A: | 1083 | switch (mode) { |
1089 | mode = AR5K_MODE_11A; | 1084 | case AR5K_MODE_11A: |
1090 | break; | 1085 | break; |
1091 | case CHANNEL_G: | 1086 | case AR5K_MODE_11G: |
1092 | |||
1093 | if (ah->ah_version <= AR5K_AR5211) { | 1087 | if (ah->ah_version <= AR5K_AR5211) { |
1094 | ATH5K_ERR(ah, | 1088 | ATH5K_ERR(ah, |
1095 | "G mode not available on 5210/5211"); | 1089 | "G mode not available on 5210/5211"); |
1096 | return -EINVAL; | 1090 | return -EINVAL; |
1097 | } | 1091 | } |
1098 | |||
1099 | mode = AR5K_MODE_11G; | ||
1100 | break; | 1092 | break; |
1101 | case CHANNEL_B: | 1093 | case AR5K_MODE_11B: |
1102 | |||
1103 | if (ah->ah_version < AR5K_AR5211) { | 1094 | if (ah->ah_version < AR5K_AR5211) { |
1104 | ATH5K_ERR(ah, | 1095 | ATH5K_ERR(ah, |
1105 | "B mode not available on 5210"); | 1096 | "B mode not available on 5210"); |
1106 | return -EINVAL; | 1097 | return -EINVAL; |
1107 | } | 1098 | } |
1108 | |||
1109 | mode = AR5K_MODE_11B; | ||
1110 | break; | ||
1111 | case CHANNEL_XR: | ||
1112 | if (ah->ah_version == AR5K_AR5211) { | ||
1113 | ATH5K_ERR(ah, | ||
1114 | "XR mode not available on 5211"); | ||
1115 | return -EINVAL; | ||
1116 | } | ||
1117 | mode = AR5K_MODE_XR; | ||
1118 | break; | 1099 | break; |
1119 | default: | 1100 | default: |
1120 | ATH5K_ERR(ah, | 1101 | ATH5K_ERR(ah, |
@@ -1200,7 +1181,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, | |||
1200 | } | 1181 | } |
1201 | 1182 | ||
1202 | /* Wakeup the device */ | 1183 | /* Wakeup the device */ |
1203 | ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, false); | 1184 | ret = ath5k_hw_nic_wakeup(ah, channel); |
1204 | if (ret) | 1185 | if (ret) |
1205 | return ret; | 1186 | return ret; |
1206 | 1187 | ||
diff --git a/drivers/net/wireless/ath/ath5k/rfkill.c b/drivers/net/wireless/ath/ath5k/rfkill.c index 945fc9f21e76..270a319f3aeb 100644 --- a/drivers/net/wireless/ath/ath5k/rfkill.c +++ b/drivers/net/wireless/ath/ath5k/rfkill.c | |||
@@ -33,7 +33,7 @@ | |||
33 | * THE POSSIBILITY OF SUCH DAMAGES. | 33 | * THE POSSIBILITY OF SUCH DAMAGES. |
34 | */ | 34 | */ |
35 | 35 | ||
36 | #include "base.h" | 36 | #include "ath5k.h" |
37 | 37 | ||
38 | 38 | ||
39 | static inline void ath5k_rfkill_disable(struct ath5k_hw *ah) | 39 | static inline void ath5k_rfkill_disable(struct ath5k_hw *ah) |
diff --git a/drivers/net/wireless/ath/ath5k/sysfs.c b/drivers/net/wireless/ath/ath5k/sysfs.c index 0244a36ba958..9364da7bd131 100644 --- a/drivers/net/wireless/ath/ath5k/sysfs.c +++ b/drivers/net/wireless/ath/ath5k/sysfs.c | |||
@@ -1,7 +1,6 @@ | |||
1 | #include <linux/device.h> | 1 | #include <linux/device.h> |
2 | #include <linux/pci.h> | 2 | #include <linux/pci.h> |
3 | 3 | ||
4 | #include "base.h" | ||
5 | #include "ath5k.h" | 4 | #include "ath5k.h" |
6 | #include "reg.h" | 5 | #include "reg.h" |
7 | 6 | ||
diff --git a/drivers/net/wireless/ath/ath5k/trace.h b/drivers/net/wireless/ath/ath5k/trace.h index c741c871f4e9..39f002ed4a88 100644 --- a/drivers/net/wireless/ath/ath5k/trace.h +++ b/drivers/net/wireless/ath/ath5k/trace.h | |||
@@ -2,7 +2,6 @@ | |||
2 | #define __TRACE_ATH5K_H | 2 | #define __TRACE_ATH5K_H |
3 | 3 | ||
4 | #include <linux/tracepoint.h> | 4 | #include <linux/tracepoint.h> |
5 | #include "base.h" | ||
6 | 5 | ||
7 | #ifndef CONFIG_ATH5K_TRACER | 6 | #ifndef CONFIG_ATH5K_TRACER |
8 | #undef TRACE_EVENT | 7 | #undef TRACE_EVENT |
@@ -11,6 +10,8 @@ static inline void trace_ ## name(proto) {} | |||
11 | #endif | 10 | #endif |
12 | 11 | ||
13 | struct sk_buff; | 12 | struct sk_buff; |
13 | struct ath5k_txq; | ||
14 | struct ath5k_tx_status; | ||
14 | 15 | ||
15 | #undef TRACE_SYSTEM | 16 | #undef TRACE_SYSTEM |
16 | #define TRACE_SYSTEM ath5k | 17 | #define TRACE_SYSTEM ath5k |
diff --git a/drivers/net/wireless/ath/ath6kl/Kconfig b/drivers/net/wireless/ath/ath6kl/Kconfig new file mode 100644 index 000000000000..3d5f8be20eac --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/Kconfig | |||
@@ -0,0 +1,15 @@ | |||
1 | config ATH6KL | ||
2 | tristate "Atheros ath6kl support" | ||
3 | depends on MMC | ||
4 | depends on CFG80211 | ||
5 | ---help--- | ||
6 | This module adds support for wireless adapters based on | ||
7 | Atheros AR6003 chipset running over SDIO. If you choose to | ||
8 | build it as a module, it will be called ath6kl. Pls note | ||
9 | that AR6002 and AR6001 are not supported by this driver. | ||
10 | |||
11 | config ATH6KL_DEBUG | ||
12 | bool "Atheros ath6kl debugging" | ||
13 | depends on ATH6KL | ||
14 | ---help--- | ||
15 | Enables debug support | ||
diff --git a/drivers/net/wireless/ath/ath6kl/Makefile b/drivers/net/wireless/ath/ath6kl/Makefile new file mode 100644 index 000000000000..e1bb07ea8e80 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/Makefile | |||
@@ -0,0 +1,35 @@ | |||
1 | #------------------------------------------------------------------------------ | ||
2 | # Copyright (c) 2004-2010 Atheros Communications Inc. | ||
3 | # All rights reserved. | ||
4 | # | ||
5 | # | ||
6 | # | ||
7 | # Permission to use, copy, modify, and/or distribute this software for any | ||
8 | # purpose with or without fee is hereby granted, provided that the above | ||
9 | # copyright notice and this permission notice appear in all copies. | ||
10 | # | ||
11 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
12 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
13 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
14 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
15 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
16 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
17 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
18 | # | ||
19 | # | ||
20 | # | ||
21 | # Author(s): ="Atheros" | ||
22 | #------------------------------------------------------------------------------ | ||
23 | |||
24 | obj-$(CONFIG_ATH6KL) := ath6kl.o | ||
25 | ath6kl-y += debug.o | ||
26 | ath6kl-y += htc_hif.o | ||
27 | ath6kl-y += htc.o | ||
28 | ath6kl-y += bmi.o | ||
29 | ath6kl-y += cfg80211.o | ||
30 | ath6kl-y += init.o | ||
31 | ath6kl-y += main.o | ||
32 | ath6kl-y += txrx.o | ||
33 | ath6kl-y += wmi.o | ||
34 | ath6kl-y += node.o | ||
35 | ath6kl-y += sdio.o | ||
diff --git a/drivers/net/wireless/ath/ath6kl/bmi.c b/drivers/net/wireless/ath/ath6kl/bmi.c new file mode 100644 index 000000000000..84676697d7eb --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/bmi.c | |||
@@ -0,0 +1,692 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004-2011 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 "core.h" | ||
18 | #include "hif-ops.h" | ||
19 | #include "target.h" | ||
20 | #include "debug.h" | ||
21 | |||
22 | static int ath6kl_get_bmi_cmd_credits(struct ath6kl *ar) | ||
23 | { | ||
24 | u32 addr; | ||
25 | unsigned long timeout; | ||
26 | int ret; | ||
27 | |||
28 | ar->bmi.cmd_credits = 0; | ||
29 | |||
30 | /* Read the counter register to get the command credits */ | ||
31 | addr = COUNT_DEC_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 4; | ||
32 | |||
33 | timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT); | ||
34 | while (time_before(jiffies, timeout) && !ar->bmi.cmd_credits) { | ||
35 | |||
36 | /* | ||
37 | * Hit the credit counter with a 4-byte access, the first byte | ||
38 | * read will hit the counter and cause a decrement, while the | ||
39 | * remaining 3 bytes has no effect. The rationale behind this | ||
40 | * is to make all HIF accesses 4-byte aligned. | ||
41 | */ | ||
42 | ret = hif_read_write_sync(ar, addr, | ||
43 | (u8 *)&ar->bmi.cmd_credits, 4, | ||
44 | HIF_RD_SYNC_BYTE_INC); | ||
45 | if (ret) { | ||
46 | ath6kl_err("Unable to decrement the command credit count register: %d\n", | ||
47 | ret); | ||
48 | return ret; | ||
49 | } | ||
50 | |||
51 | /* The counter is only 8 bits. | ||
52 | * Ignore anything in the upper 3 bytes | ||
53 | */ | ||
54 | ar->bmi.cmd_credits &= 0xFF; | ||
55 | } | ||
56 | |||
57 | if (!ar->bmi.cmd_credits) { | ||
58 | ath6kl_err("bmi communication timeout\n"); | ||
59 | return -ETIMEDOUT; | ||
60 | } | ||
61 | |||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static int ath6kl_bmi_get_rx_lkahd(struct ath6kl *ar, bool need_timeout) | ||
66 | { | ||
67 | unsigned long timeout; | ||
68 | u32 rx_word = 0; | ||
69 | int ret = 0; | ||
70 | |||
71 | timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT); | ||
72 | while ((!need_timeout || time_before(jiffies, timeout)) && !rx_word) { | ||
73 | ret = hif_read_write_sync(ar, RX_LOOKAHEAD_VALID_ADDRESS, | ||
74 | (u8 *)&rx_word, sizeof(rx_word), | ||
75 | HIF_RD_SYNC_BYTE_INC); | ||
76 | if (ret) { | ||
77 | ath6kl_err("unable to read RX_LOOKAHEAD_VALID\n"); | ||
78 | return ret; | ||
79 | } | ||
80 | |||
81 | /* all we really want is one bit */ | ||
82 | rx_word &= (1 << ENDPOINT1); | ||
83 | } | ||
84 | |||
85 | if (!rx_word) { | ||
86 | ath6kl_err("bmi_recv_buf FIFO empty\n"); | ||
87 | return -EINVAL; | ||
88 | } | ||
89 | |||
90 | return ret; | ||
91 | } | ||
92 | |||
93 | static int ath6kl_bmi_send_buf(struct ath6kl *ar, u8 *buf, u32 len) | ||
94 | { | ||
95 | int ret; | ||
96 | u32 addr; | ||
97 | |||
98 | ret = ath6kl_get_bmi_cmd_credits(ar); | ||
99 | if (ret) | ||
100 | return ret; | ||
101 | |||
102 | addr = ar->mbox_info.htc_addr; | ||
103 | |||
104 | ret = hif_read_write_sync(ar, addr, buf, len, | ||
105 | HIF_WR_SYNC_BYTE_INC); | ||
106 | if (ret) | ||
107 | ath6kl_err("unable to send the bmi data to the device\n"); | ||
108 | |||
109 | return ret; | ||
110 | } | ||
111 | |||
112 | static int ath6kl_bmi_recv_buf(struct ath6kl *ar, | ||
113 | u8 *buf, u32 len, bool want_timeout) | ||
114 | { | ||
115 | int ret; | ||
116 | u32 addr; | ||
117 | |||
118 | /* | ||
119 | * During normal bootup, small reads may be required. | ||
120 | * Rather than issue an HIF Read and then wait as the Target | ||
121 | * adds successive bytes to the FIFO, we wait here until | ||
122 | * we know that response data is available. | ||
123 | * | ||
124 | * This allows us to cleanly timeout on an unexpected | ||
125 | * Target failure rather than risk problems at the HIF level. | ||
126 | * In particular, this avoids SDIO timeouts and possibly garbage | ||
127 | * data on some host controllers. And on an interconnect | ||
128 | * such as Compact Flash (as well as some SDIO masters) which | ||
129 | * does not provide any indication on data timeout, it avoids | ||
130 | * a potential hang or garbage response. | ||
131 | * | ||
132 | * Synchronization is more difficult for reads larger than the | ||
133 | * size of the MBOX FIFO (128B), because the Target is unable | ||
134 | * to push the 129th byte of data until AFTER the Host posts an | ||
135 | * HIF Read and removes some FIFO data. So for large reads the | ||
136 | * Host proceeds to post an HIF Read BEFORE all the data is | ||
137 | * actually available to read. Fortunately, large BMI reads do | ||
138 | * not occur in practice -- they're supported for debug/development. | ||
139 | * | ||
140 | * So Host/Target BMI synchronization is divided into these cases: | ||
141 | * CASE 1: length < 4 | ||
142 | * Should not happen | ||
143 | * | ||
144 | * CASE 2: 4 <= length <= 128 | ||
145 | * Wait for first 4 bytes to be in FIFO | ||
146 | * If CONSERVATIVE_BMI_READ is enabled, also wait for | ||
147 | * a BMI command credit, which indicates that the ENTIRE | ||
148 | * response is available in the the FIFO | ||
149 | * | ||
150 | * CASE 3: length > 128 | ||
151 | * Wait for the first 4 bytes to be in FIFO | ||
152 | * | ||
153 | * For most uses, a small timeout should be sufficient and we will | ||
154 | * usually see a response quickly; but there may be some unusual | ||
155 | * (debug) cases of BMI_EXECUTE where we want an larger timeout. | ||
156 | * For now, we use an unbounded busy loop while waiting for | ||
157 | * BMI_EXECUTE. | ||
158 | * | ||
159 | * If BMI_EXECUTE ever needs to support longer-latency execution, | ||
160 | * especially in production, this code needs to be enhanced to sleep | ||
161 | * and yield. Also note that BMI_COMMUNICATION_TIMEOUT is currently | ||
162 | * a function of Host processor speed. | ||
163 | */ | ||
164 | if (len >= 4) { /* NB: Currently, always true */ | ||
165 | ret = ath6kl_bmi_get_rx_lkahd(ar, want_timeout); | ||
166 | if (ret) | ||
167 | return ret; | ||
168 | } | ||
169 | |||
170 | addr = ar->mbox_info.htc_addr; | ||
171 | ret = hif_read_write_sync(ar, addr, buf, len, | ||
172 | HIF_RD_SYNC_BYTE_INC); | ||
173 | if (ret) { | ||
174 | ath6kl_err("Unable to read the bmi data from the device: %d\n", | ||
175 | ret); | ||
176 | return ret; | ||
177 | } | ||
178 | |||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | int ath6kl_bmi_done(struct ath6kl *ar) | ||
183 | { | ||
184 | int ret; | ||
185 | u32 cid = BMI_DONE; | ||
186 | |||
187 | if (ar->bmi.done_sent) { | ||
188 | ath6kl_dbg(ATH6KL_DBG_BMI, "bmi done skipped\n"); | ||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | ar->bmi.done_sent = true; | ||
193 | |||
194 | ret = ath6kl_bmi_send_buf(ar, (u8 *)&cid, sizeof(cid)); | ||
195 | if (ret) { | ||
196 | ath6kl_err("Unable to send bmi done: %d\n", ret); | ||
197 | return ret; | ||
198 | } | ||
199 | |||
200 | ath6kl_bmi_cleanup(ar); | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | int ath6kl_bmi_get_target_info(struct ath6kl *ar, | ||
206 | struct ath6kl_bmi_target_info *targ_info) | ||
207 | { | ||
208 | int ret; | ||
209 | u32 cid = BMI_GET_TARGET_INFO; | ||
210 | |||
211 | if (ar->bmi.done_sent) { | ||
212 | ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); | ||
213 | return -EACCES; | ||
214 | } | ||
215 | |||
216 | ret = ath6kl_bmi_send_buf(ar, (u8 *)&cid, sizeof(cid)); | ||
217 | if (ret) { | ||
218 | ath6kl_err("Unable to send get target info: %d\n", ret); | ||
219 | return ret; | ||
220 | } | ||
221 | |||
222 | ret = ath6kl_bmi_recv_buf(ar, (u8 *)&targ_info->version, | ||
223 | sizeof(targ_info->version), true); | ||
224 | if (ret) { | ||
225 | ath6kl_err("Unable to recv target info: %d\n", ret); | ||
226 | return ret; | ||
227 | } | ||
228 | |||
229 | if (le32_to_cpu(targ_info->version) == TARGET_VERSION_SENTINAL) { | ||
230 | /* Determine how many bytes are in the Target's targ_info */ | ||
231 | ret = ath6kl_bmi_recv_buf(ar, | ||
232 | (u8 *)&targ_info->byte_count, | ||
233 | sizeof(targ_info->byte_count), | ||
234 | true); | ||
235 | if (ret) { | ||
236 | ath6kl_err("unable to read target info byte count: %d\n", | ||
237 | ret); | ||
238 | return ret; | ||
239 | } | ||
240 | |||
241 | /* | ||
242 | * The target's targ_info doesn't match the host's targ_info. | ||
243 | * We need to do some backwards compatibility to make this work. | ||
244 | */ | ||
245 | if (le32_to_cpu(targ_info->byte_count) != sizeof(*targ_info)) { | ||
246 | WARN_ON(1); | ||
247 | return -EINVAL; | ||
248 | } | ||
249 | |||
250 | /* Read the remainder of the targ_info */ | ||
251 | ret = ath6kl_bmi_recv_buf(ar, | ||
252 | ((u8 *)targ_info) + | ||
253 | sizeof(targ_info->byte_count), | ||
254 | sizeof(*targ_info) - | ||
255 | sizeof(targ_info->byte_count), | ||
256 | true); | ||
257 | |||
258 | if (ret) { | ||
259 | ath6kl_err("Unable to read target info (%d bytes): %d\n", | ||
260 | targ_info->byte_count, ret); | ||
261 | return ret; | ||
262 | } | ||
263 | } | ||
264 | |||
265 | ath6kl_dbg(ATH6KL_DBG_BMI, "target info (ver: 0x%x type: 0x%x)\n", | ||
266 | targ_info->version, targ_info->type); | ||
267 | |||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len) | ||
272 | { | ||
273 | u32 cid = BMI_READ_MEMORY; | ||
274 | int ret; | ||
275 | u32 offset; | ||
276 | u32 len_remain, rx_len; | ||
277 | u16 size; | ||
278 | |||
279 | if (ar->bmi.done_sent) { | ||
280 | ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); | ||
281 | return -EACCES; | ||
282 | } | ||
283 | |||
284 | size = BMI_DATASZ_MAX + sizeof(cid) + sizeof(addr) + sizeof(len); | ||
285 | if (size > MAX_BMI_CMDBUF_SZ) { | ||
286 | WARN_ON(1); | ||
287 | return -EINVAL; | ||
288 | } | ||
289 | memset(ar->bmi.cmd_buf, 0, size); | ||
290 | |||
291 | ath6kl_dbg(ATH6KL_DBG_BMI, | ||
292 | "bmi read memory: device: addr: 0x%x, len: %d\n", | ||
293 | addr, len); | ||
294 | |||
295 | len_remain = len; | ||
296 | |||
297 | while (len_remain) { | ||
298 | rx_len = (len_remain < BMI_DATASZ_MAX) ? | ||
299 | len_remain : BMI_DATASZ_MAX; | ||
300 | offset = 0; | ||
301 | memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid)); | ||
302 | offset += sizeof(cid); | ||
303 | memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr)); | ||
304 | offset += sizeof(addr); | ||
305 | memcpy(&(ar->bmi.cmd_buf[offset]), &rx_len, sizeof(rx_len)); | ||
306 | offset += sizeof(len); | ||
307 | |||
308 | ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset); | ||
309 | if (ret) { | ||
310 | ath6kl_err("Unable to write to the device: %d\n", | ||
311 | ret); | ||
312 | return ret; | ||
313 | } | ||
314 | ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, rx_len, true); | ||
315 | if (ret) { | ||
316 | ath6kl_err("Unable to read from the device: %d\n", | ||
317 | ret); | ||
318 | return ret; | ||
319 | } | ||
320 | memcpy(&buf[len - len_remain], ar->bmi.cmd_buf, rx_len); | ||
321 | len_remain -= rx_len; addr += rx_len; | ||
322 | } | ||
323 | |||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len) | ||
328 | { | ||
329 | u32 cid = BMI_WRITE_MEMORY; | ||
330 | int ret; | ||
331 | u32 offset; | ||
332 | u32 len_remain, tx_len; | ||
333 | const u32 header = sizeof(cid) + sizeof(addr) + sizeof(len); | ||
334 | u8 aligned_buf[BMI_DATASZ_MAX]; | ||
335 | u8 *src; | ||
336 | |||
337 | if (ar->bmi.done_sent) { | ||
338 | ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); | ||
339 | return -EACCES; | ||
340 | } | ||
341 | |||
342 | if ((BMI_DATASZ_MAX + header) > MAX_BMI_CMDBUF_SZ) { | ||
343 | WARN_ON(1); | ||
344 | return -EINVAL; | ||
345 | } | ||
346 | |||
347 | memset(ar->bmi.cmd_buf, 0, BMI_DATASZ_MAX + header); | ||
348 | |||
349 | ath6kl_dbg(ATH6KL_DBG_BMI, | ||
350 | "bmi write memory: addr: 0x%x, len: %d\n", addr, len); | ||
351 | |||
352 | len_remain = len; | ||
353 | while (len_remain) { | ||
354 | src = &buf[len - len_remain]; | ||
355 | |||
356 | if (len_remain < (BMI_DATASZ_MAX - header)) { | ||
357 | if (len_remain & 3) { | ||
358 | /* align it with 4 bytes */ | ||
359 | len_remain = len_remain + | ||
360 | (4 - (len_remain & 3)); | ||
361 | memcpy(aligned_buf, src, len_remain); | ||
362 | src = aligned_buf; | ||
363 | } | ||
364 | tx_len = len_remain; | ||
365 | } else { | ||
366 | tx_len = (BMI_DATASZ_MAX - header); | ||
367 | } | ||
368 | |||
369 | offset = 0; | ||
370 | memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid)); | ||
371 | offset += sizeof(cid); | ||
372 | memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr)); | ||
373 | offset += sizeof(addr); | ||
374 | memcpy(&(ar->bmi.cmd_buf[offset]), &tx_len, sizeof(tx_len)); | ||
375 | offset += sizeof(tx_len); | ||
376 | memcpy(&(ar->bmi.cmd_buf[offset]), src, tx_len); | ||
377 | offset += tx_len; | ||
378 | |||
379 | ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset); | ||
380 | if (ret) { | ||
381 | ath6kl_err("Unable to write to the device: %d\n", | ||
382 | ret); | ||
383 | return ret; | ||
384 | } | ||
385 | len_remain -= tx_len; addr += tx_len; | ||
386 | } | ||
387 | |||
388 | return 0; | ||
389 | } | ||
390 | |||
391 | int ath6kl_bmi_execute(struct ath6kl *ar, u32 addr, u32 *param) | ||
392 | { | ||
393 | u32 cid = BMI_EXECUTE; | ||
394 | int ret; | ||
395 | u32 offset; | ||
396 | u16 size; | ||
397 | |||
398 | if (ar->bmi.done_sent) { | ||
399 | ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); | ||
400 | return -EACCES; | ||
401 | } | ||
402 | |||
403 | size = sizeof(cid) + sizeof(addr) + sizeof(param); | ||
404 | if (size > MAX_BMI_CMDBUF_SZ) { | ||
405 | WARN_ON(1); | ||
406 | return -EINVAL; | ||
407 | } | ||
408 | memset(ar->bmi.cmd_buf, 0, size); | ||
409 | |||
410 | ath6kl_dbg(ATH6KL_DBG_BMI, "bmi execute: addr: 0x%x, param: %d)\n", | ||
411 | addr, *param); | ||
412 | |||
413 | offset = 0; | ||
414 | memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid)); | ||
415 | offset += sizeof(cid); | ||
416 | memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr)); | ||
417 | offset += sizeof(addr); | ||
418 | memcpy(&(ar->bmi.cmd_buf[offset]), param, sizeof(*param)); | ||
419 | offset += sizeof(*param); | ||
420 | |||
421 | ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset); | ||
422 | if (ret) { | ||
423 | ath6kl_err("Unable to write to the device: %d\n", ret); | ||
424 | return ret; | ||
425 | } | ||
426 | |||
427 | ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, sizeof(*param), false); | ||
428 | if (ret) { | ||
429 | ath6kl_err("Unable to read from the device: %d\n", ret); | ||
430 | return ret; | ||
431 | } | ||
432 | |||
433 | memcpy(param, ar->bmi.cmd_buf, sizeof(*param)); | ||
434 | |||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | int ath6kl_bmi_set_app_start(struct ath6kl *ar, u32 addr) | ||
439 | { | ||
440 | u32 cid = BMI_SET_APP_START; | ||
441 | int ret; | ||
442 | u32 offset; | ||
443 | u16 size; | ||
444 | |||
445 | if (ar->bmi.done_sent) { | ||
446 | ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); | ||
447 | return -EACCES; | ||
448 | } | ||
449 | |||
450 | size = sizeof(cid) + sizeof(addr); | ||
451 | if (size > MAX_BMI_CMDBUF_SZ) { | ||
452 | WARN_ON(1); | ||
453 | return -EINVAL; | ||
454 | } | ||
455 | memset(ar->bmi.cmd_buf, 0, size); | ||
456 | |||
457 | ath6kl_dbg(ATH6KL_DBG_BMI, "bmi set app start: addr: 0x%x\n", addr); | ||
458 | |||
459 | offset = 0; | ||
460 | memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid)); | ||
461 | offset += sizeof(cid); | ||
462 | memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr)); | ||
463 | offset += sizeof(addr); | ||
464 | |||
465 | ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset); | ||
466 | if (ret) { | ||
467 | ath6kl_err("Unable to write to the device: %d\n", ret); | ||
468 | return ret; | ||
469 | } | ||
470 | |||
471 | return 0; | ||
472 | } | ||
473 | |||
474 | int ath6kl_bmi_reg_read(struct ath6kl *ar, u32 addr, u32 *param) | ||
475 | { | ||
476 | u32 cid = BMI_READ_SOC_REGISTER; | ||
477 | int ret; | ||
478 | u32 offset; | ||
479 | u16 size; | ||
480 | |||
481 | if (ar->bmi.done_sent) { | ||
482 | ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); | ||
483 | return -EACCES; | ||
484 | } | ||
485 | |||
486 | size = sizeof(cid) + sizeof(addr); | ||
487 | if (size > MAX_BMI_CMDBUF_SZ) { | ||
488 | WARN_ON(1); | ||
489 | return -EINVAL; | ||
490 | } | ||
491 | memset(ar->bmi.cmd_buf, 0, size); | ||
492 | |||
493 | ath6kl_dbg(ATH6KL_DBG_BMI, "bmi read SOC reg: addr: 0x%x\n", addr); | ||
494 | |||
495 | offset = 0; | ||
496 | memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid)); | ||
497 | offset += sizeof(cid); | ||
498 | memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr)); | ||
499 | offset += sizeof(addr); | ||
500 | |||
501 | ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset); | ||
502 | if (ret) { | ||
503 | ath6kl_err("Unable to write to the device: %d\n", ret); | ||
504 | return ret; | ||
505 | } | ||
506 | |||
507 | ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, sizeof(*param), true); | ||
508 | if (ret) { | ||
509 | ath6kl_err("Unable to read from the device: %d\n", ret); | ||
510 | return ret; | ||
511 | } | ||
512 | memcpy(param, ar->bmi.cmd_buf, sizeof(*param)); | ||
513 | |||
514 | return 0; | ||
515 | } | ||
516 | |||
517 | int ath6kl_bmi_reg_write(struct ath6kl *ar, u32 addr, u32 param) | ||
518 | { | ||
519 | u32 cid = BMI_WRITE_SOC_REGISTER; | ||
520 | int ret; | ||
521 | u32 offset; | ||
522 | u16 size; | ||
523 | |||
524 | if (ar->bmi.done_sent) { | ||
525 | ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); | ||
526 | return -EACCES; | ||
527 | } | ||
528 | |||
529 | size = sizeof(cid) + sizeof(addr) + sizeof(param); | ||
530 | if (size > MAX_BMI_CMDBUF_SZ) { | ||
531 | WARN_ON(1); | ||
532 | return -EINVAL; | ||
533 | } | ||
534 | memset(ar->bmi.cmd_buf, 0, size); | ||
535 | |||
536 | ath6kl_dbg(ATH6KL_DBG_BMI, | ||
537 | "bmi write SOC reg: addr: 0x%x, param: %d\n", | ||
538 | addr, param); | ||
539 | |||
540 | offset = 0; | ||
541 | memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid)); | ||
542 | offset += sizeof(cid); | ||
543 | memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr)); | ||
544 | offset += sizeof(addr); | ||
545 | memcpy(&(ar->bmi.cmd_buf[offset]), ¶m, sizeof(param)); | ||
546 | offset += sizeof(param); | ||
547 | |||
548 | ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset); | ||
549 | if (ret) { | ||
550 | ath6kl_err("Unable to write to the device: %d\n", ret); | ||
551 | return ret; | ||
552 | } | ||
553 | |||
554 | return 0; | ||
555 | } | ||
556 | |||
557 | int ath6kl_bmi_lz_data(struct ath6kl *ar, u8 *buf, u32 len) | ||
558 | { | ||
559 | u32 cid = BMI_LZ_DATA; | ||
560 | int ret; | ||
561 | u32 offset; | ||
562 | u32 len_remain, tx_len; | ||
563 | const u32 header = sizeof(cid) + sizeof(len); | ||
564 | u16 size; | ||
565 | |||
566 | if (ar->bmi.done_sent) { | ||
567 | ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); | ||
568 | return -EACCES; | ||
569 | } | ||
570 | |||
571 | size = BMI_DATASZ_MAX + header; | ||
572 | if (size > MAX_BMI_CMDBUF_SZ) { | ||
573 | WARN_ON(1); | ||
574 | return -EINVAL; | ||
575 | } | ||
576 | memset(ar->bmi.cmd_buf, 0, size); | ||
577 | |||
578 | ath6kl_dbg(ATH6KL_DBG_BMI, "bmi send LZ data: len: %d)\n", | ||
579 | len); | ||
580 | |||
581 | len_remain = len; | ||
582 | while (len_remain) { | ||
583 | tx_len = (len_remain < (BMI_DATASZ_MAX - header)) ? | ||
584 | len_remain : (BMI_DATASZ_MAX - header); | ||
585 | |||
586 | offset = 0; | ||
587 | memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid)); | ||
588 | offset += sizeof(cid); | ||
589 | memcpy(&(ar->bmi.cmd_buf[offset]), &tx_len, sizeof(tx_len)); | ||
590 | offset += sizeof(tx_len); | ||
591 | memcpy(&(ar->bmi.cmd_buf[offset]), &buf[len - len_remain], | ||
592 | tx_len); | ||
593 | offset += tx_len; | ||
594 | |||
595 | ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset); | ||
596 | if (ret) { | ||
597 | ath6kl_err("Unable to write to the device: %d\n", | ||
598 | ret); | ||
599 | return ret; | ||
600 | } | ||
601 | |||
602 | len_remain -= tx_len; | ||
603 | } | ||
604 | |||
605 | return 0; | ||
606 | } | ||
607 | |||
608 | int ath6kl_bmi_lz_stream_start(struct ath6kl *ar, u32 addr) | ||
609 | { | ||
610 | u32 cid = BMI_LZ_STREAM_START; | ||
611 | int ret; | ||
612 | u32 offset; | ||
613 | u16 size; | ||
614 | |||
615 | if (ar->bmi.done_sent) { | ||
616 | ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); | ||
617 | return -EACCES; | ||
618 | } | ||
619 | |||
620 | size = sizeof(cid) + sizeof(addr); | ||
621 | if (size > MAX_BMI_CMDBUF_SZ) { | ||
622 | WARN_ON(1); | ||
623 | return -EINVAL; | ||
624 | } | ||
625 | memset(ar->bmi.cmd_buf, 0, size); | ||
626 | |||
627 | ath6kl_dbg(ATH6KL_DBG_BMI, | ||
628 | "bmi LZ stream start: addr: 0x%x)\n", | ||
629 | addr); | ||
630 | |||
631 | offset = 0; | ||
632 | memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid)); | ||
633 | offset += sizeof(cid); | ||
634 | memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr)); | ||
635 | offset += sizeof(addr); | ||
636 | |||
637 | ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset); | ||
638 | if (ret) { | ||
639 | ath6kl_err("Unable to start LZ stream to the device: %d\n", | ||
640 | ret); | ||
641 | return ret; | ||
642 | } | ||
643 | |||
644 | return 0; | ||
645 | } | ||
646 | |||
647 | int ath6kl_bmi_fast_download(struct ath6kl *ar, u32 addr, u8 *buf, u32 len) | ||
648 | { | ||
649 | int ret; | ||
650 | u32 last_word = 0; | ||
651 | u32 last_word_offset = len & ~0x3; | ||
652 | u32 unaligned_bytes = len & 0x3; | ||
653 | |||
654 | ret = ath6kl_bmi_lz_stream_start(ar, addr); | ||
655 | if (ret) | ||
656 | return ret; | ||
657 | |||
658 | if (unaligned_bytes) { | ||
659 | /* copy the last word into a zero padded buffer */ | ||
660 | memcpy(&last_word, &buf[last_word_offset], unaligned_bytes); | ||
661 | } | ||
662 | |||
663 | ret = ath6kl_bmi_lz_data(ar, buf, last_word_offset); | ||
664 | if (ret) | ||
665 | return ret; | ||
666 | |||
667 | if (unaligned_bytes) | ||
668 | ret = ath6kl_bmi_lz_data(ar, (u8 *)&last_word, 4); | ||
669 | |||
670 | if (!ret) { | ||
671 | /* Close compressed stream and open a new (fake) one. | ||
672 | * This serves mainly to flush Target caches. */ | ||
673 | ret = ath6kl_bmi_lz_stream_start(ar, 0x00); | ||
674 | } | ||
675 | return ret; | ||
676 | } | ||
677 | |||
678 | int ath6kl_bmi_init(struct ath6kl *ar) | ||
679 | { | ||
680 | ar->bmi.cmd_buf = kzalloc(MAX_BMI_CMDBUF_SZ, GFP_ATOMIC); | ||
681 | |||
682 | if (!ar->bmi.cmd_buf) | ||
683 | return -ENOMEM; | ||
684 | |||
685 | return 0; | ||
686 | } | ||
687 | |||
688 | void ath6kl_bmi_cleanup(struct ath6kl *ar) | ||
689 | { | ||
690 | kfree(ar->bmi.cmd_buf); | ||
691 | ar->bmi.cmd_buf = NULL; | ||
692 | } | ||
diff --git a/drivers/net/wireless/ath/ath6kl/bmi.h b/drivers/net/wireless/ath/ath6kl/bmi.h new file mode 100644 index 000000000000..83546d76d979 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/bmi.h | |||
@@ -0,0 +1,250 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004-2011 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 | #ifndef BMI_H | ||
18 | #define BMI_H | ||
19 | |||
20 | /* | ||
21 | * Bootloader Messaging Interface (BMI) | ||
22 | * | ||
23 | * BMI is a very simple messaging interface used during initialization | ||
24 | * to read memory, write memory, execute code, and to define an | ||
25 | * application entry PC. | ||
26 | * | ||
27 | * It is used to download an application to ATH6KL, to provide | ||
28 | * patches to code that is already resident on ATH6KL, and generally | ||
29 | * to examine and modify state. The Host has an opportunity to use | ||
30 | * BMI only once during bootup. Once the Host issues a BMI_DONE | ||
31 | * command, this opportunity ends. | ||
32 | * | ||
33 | * The Host writes BMI requests to mailbox0, and reads BMI responses | ||
34 | * from mailbox0. BMI requests all begin with a command | ||
35 | * (see below for specific commands), and are followed by | ||
36 | * command-specific data. | ||
37 | * | ||
38 | * Flow control: | ||
39 | * The Host can only issue a command once the Target gives it a | ||
40 | * "BMI Command Credit", using ATH6KL Counter #4. As soon as the | ||
41 | * Target has completed a command, it issues another BMI Command | ||
42 | * Credit (so the Host can issue the next command). | ||
43 | * | ||
44 | * BMI handles all required Target-side cache flushing. | ||
45 | */ | ||
46 | |||
47 | #define MAX_BMI_CMDBUF_SZ (BMI_DATASZ_MAX + \ | ||
48 | (sizeof(u32) * 3 /* cmd + addr + len */)) | ||
49 | |||
50 | /* Maximum data size used for BMI transfers */ | ||
51 | #define BMI_DATASZ_MAX 256 | ||
52 | |||
53 | /* BMI Commands */ | ||
54 | |||
55 | #define BMI_NO_COMMAND 0 | ||
56 | |||
57 | #define BMI_DONE 1 | ||
58 | /* | ||
59 | * Semantics: Host is done using BMI | ||
60 | * Request format: | ||
61 | * u32 command (BMI_DONE) | ||
62 | * Response format: none | ||
63 | */ | ||
64 | |||
65 | #define BMI_READ_MEMORY 2 | ||
66 | /* | ||
67 | * Semantics: Host reads ATH6KL memory | ||
68 | * Request format: | ||
69 | * u32 command (BMI_READ_MEMORY) | ||
70 | * u32 address | ||
71 | * u32 length, at most BMI_DATASZ_MAX | ||
72 | * Response format: | ||
73 | * u8 data[length] | ||
74 | */ | ||
75 | |||
76 | #define BMI_WRITE_MEMORY 3 | ||
77 | /* | ||
78 | * Semantics: Host writes ATH6KL memory | ||
79 | * Request format: | ||
80 | * u32 command (BMI_WRITE_MEMORY) | ||
81 | * u32 address | ||
82 | * u32 length, at most BMI_DATASZ_MAX | ||
83 | * u8 data[length] | ||
84 | * Response format: none | ||
85 | */ | ||
86 | |||
87 | #define BMI_EXECUTE 4 | ||
88 | /* | ||
89 | * Semantics: Causes ATH6KL to execute code | ||
90 | * Request format: | ||
91 | * u32 command (BMI_EXECUTE) | ||
92 | * u32 address | ||
93 | * u32 parameter | ||
94 | * Response format: | ||
95 | * u32 return value | ||
96 | */ | ||
97 | |||
98 | #define BMI_SET_APP_START 5 | ||
99 | /* | ||
100 | * Semantics: Set Target application starting address | ||
101 | * Request format: | ||
102 | * u32 command (BMI_SET_APP_START) | ||
103 | * u32 address | ||
104 | * Response format: none | ||
105 | */ | ||
106 | |||
107 | #define BMI_READ_SOC_REGISTER 6 | ||
108 | /* | ||
109 | * Semantics: Read a 32-bit Target SOC register. | ||
110 | * Request format: | ||
111 | * u32 command (BMI_READ_REGISTER) | ||
112 | * u32 address | ||
113 | * Response format: | ||
114 | * u32 value | ||
115 | */ | ||
116 | |||
117 | #define BMI_WRITE_SOC_REGISTER 7 | ||
118 | /* | ||
119 | * Semantics: Write a 32-bit Target SOC register. | ||
120 | * Request format: | ||
121 | * u32 command (BMI_WRITE_REGISTER) | ||
122 | * u32 address | ||
123 | * u32 value | ||
124 | * | ||
125 | * Response format: none | ||
126 | */ | ||
127 | |||
128 | #define BMI_GET_TARGET_ID 8 | ||
129 | #define BMI_GET_TARGET_INFO 8 | ||
130 | /* | ||
131 | * Semantics: Fetch the 4-byte Target information | ||
132 | * Request format: | ||
133 | * u32 command (BMI_GET_TARGET_ID/INFO) | ||
134 | * Response format1 (old firmware): | ||
135 | * u32 TargetVersionID | ||
136 | * Response format2 (newer firmware): | ||
137 | * u32 TARGET_VERSION_SENTINAL | ||
138 | * struct bmi_target_info; | ||
139 | */ | ||
140 | |||
141 | #define TARGET_VERSION_SENTINAL 0xffffffff | ||
142 | #define TARGET_TYPE_AR6003 3 | ||
143 | |||
144 | #define BMI_ROMPATCH_INSTALL 9 | ||
145 | /* | ||
146 | * Semantics: Install a ROM Patch. | ||
147 | * Request format: | ||
148 | * u32 command (BMI_ROMPATCH_INSTALL) | ||
149 | * u32 Target ROM Address | ||
150 | * u32 Target RAM Address or Value (depending on Target Type) | ||
151 | * u32 Size, in bytes | ||
152 | * u32 Activate? 1-->activate; | ||
153 | * 0-->install but do not activate | ||
154 | * Response format: | ||
155 | * u32 PatchID | ||
156 | */ | ||
157 | |||
158 | #define BMI_ROMPATCH_UNINSTALL 10 | ||
159 | /* | ||
160 | * Semantics: Uninstall a previously-installed ROM Patch, | ||
161 | * automatically deactivating, if necessary. | ||
162 | * Request format: | ||
163 | * u32 command (BMI_ROMPATCH_UNINSTALL) | ||
164 | * u32 PatchID | ||
165 | * | ||
166 | * Response format: none | ||
167 | */ | ||
168 | |||
169 | #define BMI_ROMPATCH_ACTIVATE 11 | ||
170 | /* | ||
171 | * Semantics: Activate a list of previously-installed ROM Patches. | ||
172 | * Request format: | ||
173 | * u32 command (BMI_ROMPATCH_ACTIVATE) | ||
174 | * u32 rompatch_count | ||
175 | * u32 PatchID[rompatch_count] | ||
176 | * | ||
177 | * Response format: none | ||
178 | */ | ||
179 | |||
180 | #define BMI_ROMPATCH_DEACTIVATE 12 | ||
181 | /* | ||
182 | * Semantics: Deactivate a list of active ROM Patches. | ||
183 | * Request format: | ||
184 | * u32 command (BMI_ROMPATCH_DEACTIVATE) | ||
185 | * u32 rompatch_count | ||
186 | * u32 PatchID[rompatch_count] | ||
187 | * | ||
188 | * Response format: none | ||
189 | */ | ||
190 | |||
191 | |||
192 | #define BMI_LZ_STREAM_START 13 | ||
193 | /* | ||
194 | * Semantics: Begin an LZ-compressed stream of input | ||
195 | * which is to be uncompressed by the Target to an | ||
196 | * output buffer at address. The output buffer must | ||
197 | * be sufficiently large to hold the uncompressed | ||
198 | * output from the compressed input stream. This BMI | ||
199 | * command should be followed by a series of 1 or more | ||
200 | * BMI_LZ_DATA commands. | ||
201 | * u32 command (BMI_LZ_STREAM_START) | ||
202 | * u32 address | ||
203 | * Note: Not supported on all versions of ROM firmware. | ||
204 | */ | ||
205 | |||
206 | #define BMI_LZ_DATA 14 | ||
207 | /* | ||
208 | * Semantics: Host writes ATH6KL memory with LZ-compressed | ||
209 | * data which is uncompressed by the Target. This command | ||
210 | * must be preceded by a BMI_LZ_STREAM_START command. A series | ||
211 | * of BMI_LZ_DATA commands are considered part of a single | ||
212 | * input stream until another BMI_LZ_STREAM_START is issued. | ||
213 | * Request format: | ||
214 | * u32 command (BMI_LZ_DATA) | ||
215 | * u32 length (of compressed data), | ||
216 | * at most BMI_DATASZ_MAX | ||
217 | * u8 CompressedData[length] | ||
218 | * Response format: none | ||
219 | * Note: Not supported on all versions of ROM firmware. | ||
220 | */ | ||
221 | |||
222 | #define BMI_COMMUNICATION_TIMEOUT 1000 /* in msec */ | ||
223 | |||
224 | struct ath6kl; | ||
225 | struct ath6kl_bmi_target_info { | ||
226 | __le32 byte_count; /* size of this structure */ | ||
227 | __le32 version; /* target version id */ | ||
228 | __le32 type; /* target type */ | ||
229 | } __packed; | ||
230 | |||
231 | int ath6kl_bmi_init(struct ath6kl *ar); | ||
232 | void ath6kl_bmi_cleanup(struct ath6kl *ar); | ||
233 | int ath6kl_bmi_done(struct ath6kl *ar); | ||
234 | int ath6kl_bmi_get_target_info(struct ath6kl *ar, | ||
235 | struct ath6kl_bmi_target_info *targ_info); | ||
236 | int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len); | ||
237 | int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len); | ||
238 | int ath6kl_bmi_execute(struct ath6kl *ar, | ||
239 | u32 addr, u32 *param); | ||
240 | int ath6kl_bmi_set_app_start(struct ath6kl *ar, | ||
241 | u32 addr); | ||
242 | int ath6kl_bmi_reg_read(struct ath6kl *ar, u32 addr, u32 *param); | ||
243 | int ath6kl_bmi_reg_write(struct ath6kl *ar, u32 addr, u32 param); | ||
244 | int ath6kl_bmi_lz_data(struct ath6kl *ar, | ||
245 | u8 *buf, u32 len); | ||
246 | int ath6kl_bmi_lz_stream_start(struct ath6kl *ar, | ||
247 | u32 addr); | ||
248 | int ath6kl_bmi_fast_download(struct ath6kl *ar, | ||
249 | u32 addr, u8 *buf, u32 len); | ||
250 | #endif | ||
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c new file mode 100644 index 000000000000..14559ffb1453 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c | |||
@@ -0,0 +1,1538 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004-2011 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 "core.h" | ||
18 | #include "cfg80211.h" | ||
19 | #include "debug.h" | ||
20 | |||
21 | #define RATETAB_ENT(_rate, _rateid, _flags) { \ | ||
22 | .bitrate = (_rate), \ | ||
23 | .flags = (_flags), \ | ||
24 | .hw_value = (_rateid), \ | ||
25 | } | ||
26 | |||
27 | #define CHAN2G(_channel, _freq, _flags) { \ | ||
28 | .band = IEEE80211_BAND_2GHZ, \ | ||
29 | .hw_value = (_channel), \ | ||
30 | .center_freq = (_freq), \ | ||
31 | .flags = (_flags), \ | ||
32 | .max_antenna_gain = 0, \ | ||
33 | .max_power = 30, \ | ||
34 | } | ||
35 | |||
36 | #define CHAN5G(_channel, _flags) { \ | ||
37 | .band = IEEE80211_BAND_5GHZ, \ | ||
38 | .hw_value = (_channel), \ | ||
39 | .center_freq = 5000 + (5 * (_channel)), \ | ||
40 | .flags = (_flags), \ | ||
41 | .max_antenna_gain = 0, \ | ||
42 | .max_power = 30, \ | ||
43 | } | ||
44 | |||
45 | static struct ieee80211_rate ath6kl_rates[] = { | ||
46 | RATETAB_ENT(10, 0x1, 0), | ||
47 | RATETAB_ENT(20, 0x2, 0), | ||
48 | RATETAB_ENT(55, 0x4, 0), | ||
49 | RATETAB_ENT(110, 0x8, 0), | ||
50 | RATETAB_ENT(60, 0x10, 0), | ||
51 | RATETAB_ENT(90, 0x20, 0), | ||
52 | RATETAB_ENT(120, 0x40, 0), | ||
53 | RATETAB_ENT(180, 0x80, 0), | ||
54 | RATETAB_ENT(240, 0x100, 0), | ||
55 | RATETAB_ENT(360, 0x200, 0), | ||
56 | RATETAB_ENT(480, 0x400, 0), | ||
57 | RATETAB_ENT(540, 0x800, 0), | ||
58 | }; | ||
59 | |||
60 | #define ath6kl_a_rates (ath6kl_rates + 4) | ||
61 | #define ath6kl_a_rates_size 8 | ||
62 | #define ath6kl_g_rates (ath6kl_rates + 0) | ||
63 | #define ath6kl_g_rates_size 12 | ||
64 | |||
65 | static struct ieee80211_channel ath6kl_2ghz_channels[] = { | ||
66 | CHAN2G(1, 2412, 0), | ||
67 | CHAN2G(2, 2417, 0), | ||
68 | CHAN2G(3, 2422, 0), | ||
69 | CHAN2G(4, 2427, 0), | ||
70 | CHAN2G(5, 2432, 0), | ||
71 | CHAN2G(6, 2437, 0), | ||
72 | CHAN2G(7, 2442, 0), | ||
73 | CHAN2G(8, 2447, 0), | ||
74 | CHAN2G(9, 2452, 0), | ||
75 | CHAN2G(10, 2457, 0), | ||
76 | CHAN2G(11, 2462, 0), | ||
77 | CHAN2G(12, 2467, 0), | ||
78 | CHAN2G(13, 2472, 0), | ||
79 | CHAN2G(14, 2484, 0), | ||
80 | }; | ||
81 | |||
82 | static struct ieee80211_channel ath6kl_5ghz_a_channels[] = { | ||
83 | CHAN5G(34, 0), CHAN5G(36, 0), | ||
84 | CHAN5G(38, 0), CHAN5G(40, 0), | ||
85 | CHAN5G(42, 0), CHAN5G(44, 0), | ||
86 | CHAN5G(46, 0), CHAN5G(48, 0), | ||
87 | CHAN5G(52, 0), CHAN5G(56, 0), | ||
88 | CHAN5G(60, 0), CHAN5G(64, 0), | ||
89 | CHAN5G(100, 0), CHAN5G(104, 0), | ||
90 | CHAN5G(108, 0), CHAN5G(112, 0), | ||
91 | CHAN5G(116, 0), CHAN5G(120, 0), | ||
92 | CHAN5G(124, 0), CHAN5G(128, 0), | ||
93 | CHAN5G(132, 0), CHAN5G(136, 0), | ||
94 | CHAN5G(140, 0), CHAN5G(149, 0), | ||
95 | CHAN5G(153, 0), CHAN5G(157, 0), | ||
96 | CHAN5G(161, 0), CHAN5G(165, 0), | ||
97 | CHAN5G(184, 0), CHAN5G(188, 0), | ||
98 | CHAN5G(192, 0), CHAN5G(196, 0), | ||
99 | CHAN5G(200, 0), CHAN5G(204, 0), | ||
100 | CHAN5G(208, 0), CHAN5G(212, 0), | ||
101 | CHAN5G(216, 0), | ||
102 | }; | ||
103 | |||
104 | static struct ieee80211_supported_band ath6kl_band_2ghz = { | ||
105 | .n_channels = ARRAY_SIZE(ath6kl_2ghz_channels), | ||
106 | .channels = ath6kl_2ghz_channels, | ||
107 | .n_bitrates = ath6kl_g_rates_size, | ||
108 | .bitrates = ath6kl_g_rates, | ||
109 | }; | ||
110 | |||
111 | static struct ieee80211_supported_band ath6kl_band_5ghz = { | ||
112 | .n_channels = ARRAY_SIZE(ath6kl_5ghz_a_channels), | ||
113 | .channels = ath6kl_5ghz_a_channels, | ||
114 | .n_bitrates = ath6kl_a_rates_size, | ||
115 | .bitrates = ath6kl_a_rates, | ||
116 | }; | ||
117 | |||
118 | static int ath6kl_set_wpa_version(struct ath6kl *ar, | ||
119 | enum nl80211_wpa_versions wpa_version) | ||
120 | { | ||
121 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: %u\n", __func__, wpa_version); | ||
122 | |||
123 | if (!wpa_version) { | ||
124 | ar->auth_mode = NONE_AUTH; | ||
125 | } else if (wpa_version & NL80211_WPA_VERSION_2) { | ||
126 | ar->auth_mode = WPA2_AUTH; | ||
127 | } else if (wpa_version & NL80211_WPA_VERSION_1) { | ||
128 | ar->auth_mode = WPA_AUTH; | ||
129 | } else { | ||
130 | ath6kl_err("%s: %u not supported\n", __func__, wpa_version); | ||
131 | return -ENOTSUPP; | ||
132 | } | ||
133 | |||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | static int ath6kl_set_auth_type(struct ath6kl *ar, | ||
138 | enum nl80211_auth_type auth_type) | ||
139 | { | ||
140 | |||
141 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, auth_type); | ||
142 | |||
143 | switch (auth_type) { | ||
144 | case NL80211_AUTHTYPE_OPEN_SYSTEM: | ||
145 | ar->dot11_auth_mode = OPEN_AUTH; | ||
146 | break; | ||
147 | case NL80211_AUTHTYPE_SHARED_KEY: | ||
148 | ar->dot11_auth_mode = SHARED_AUTH; | ||
149 | break; | ||
150 | case NL80211_AUTHTYPE_NETWORK_EAP: | ||
151 | ar->dot11_auth_mode = LEAP_AUTH; | ||
152 | break; | ||
153 | |||
154 | case NL80211_AUTHTYPE_AUTOMATIC: | ||
155 | ar->dot11_auth_mode = OPEN_AUTH; | ||
156 | ar->auto_auth_stage = AUTH_OPEN_IN_PROGRESS; | ||
157 | break; | ||
158 | |||
159 | default: | ||
160 | ath6kl_err("%s: 0x%x not spported\n", __func__, auth_type); | ||
161 | return -ENOTSUPP; | ||
162 | } | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static int ath6kl_set_cipher(struct ath6kl *ar, u32 cipher, bool ucast) | ||
168 | { | ||
169 | u8 *ar_cipher = ucast ? &ar->prwise_crypto : &ar->grp_crypto; | ||
170 | u8 *ar_cipher_len = ucast ? &ar->prwise_crypto_len : &ar->grp_crpto_len; | ||
171 | |||
172 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: cipher 0x%x, ucast %u\n", | ||
173 | __func__, cipher, ucast); | ||
174 | |||
175 | switch (cipher) { | ||
176 | case 0: | ||
177 | /* our own hack to use value 0 as no crypto used */ | ||
178 | *ar_cipher = NONE_CRYPT; | ||
179 | *ar_cipher_len = 0; | ||
180 | break; | ||
181 | case WLAN_CIPHER_SUITE_WEP40: | ||
182 | *ar_cipher = WEP_CRYPT; | ||
183 | *ar_cipher_len = 5; | ||
184 | break; | ||
185 | case WLAN_CIPHER_SUITE_WEP104: | ||
186 | *ar_cipher = WEP_CRYPT; | ||
187 | *ar_cipher_len = 13; | ||
188 | break; | ||
189 | case WLAN_CIPHER_SUITE_TKIP: | ||
190 | *ar_cipher = TKIP_CRYPT; | ||
191 | *ar_cipher_len = 0; | ||
192 | break; | ||
193 | case WLAN_CIPHER_SUITE_CCMP: | ||
194 | *ar_cipher = AES_CRYPT; | ||
195 | *ar_cipher_len = 0; | ||
196 | break; | ||
197 | default: | ||
198 | ath6kl_err("cipher 0x%x not supported\n", cipher); | ||
199 | return -ENOTSUPP; | ||
200 | } | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | static void ath6kl_set_key_mgmt(struct ath6kl *ar, u32 key_mgmt) | ||
206 | { | ||
207 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, key_mgmt); | ||
208 | |||
209 | if (key_mgmt == WLAN_AKM_SUITE_PSK) { | ||
210 | if (ar->auth_mode == WPA_AUTH) | ||
211 | ar->auth_mode = WPA_PSK_AUTH; | ||
212 | else if (ar->auth_mode == WPA2_AUTH) | ||
213 | ar->auth_mode = WPA2_PSK_AUTH; | ||
214 | } else if (key_mgmt != WLAN_AKM_SUITE_8021X) { | ||
215 | ar->auth_mode = NONE_AUTH; | ||
216 | } | ||
217 | } | ||
218 | |||
219 | static bool ath6kl_cfg80211_ready(struct ath6kl *ar) | ||
220 | { | ||
221 | if (!test_bit(WMI_READY, &ar->flag)) { | ||
222 | ath6kl_err("wmi is not ready\n"); | ||
223 | return false; | ||
224 | } | ||
225 | |||
226 | if (!test_bit(WLAN_ENABLED, &ar->flag)) { | ||
227 | ath6kl_err("wlan disabled\n"); | ||
228 | return false; | ||
229 | } | ||
230 | |||
231 | return true; | ||
232 | } | ||
233 | |||
234 | static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | ||
235 | struct cfg80211_connect_params *sme) | ||
236 | { | ||
237 | struct ath6kl *ar = ath6kl_priv(dev); | ||
238 | int status; | ||
239 | |||
240 | ar->sme_state = SME_CONNECTING; | ||
241 | |||
242 | if (!ath6kl_cfg80211_ready(ar)) | ||
243 | return -EIO; | ||
244 | |||
245 | if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) { | ||
246 | ath6kl_err("destroy in progress\n"); | ||
247 | return -EBUSY; | ||
248 | } | ||
249 | |||
250 | if (test_bit(SKIP_SCAN, &ar->flag) && | ||
251 | ((sme->channel && sme->channel->center_freq == 0) || | ||
252 | (sme->bssid && is_zero_ether_addr(sme->bssid)))) { | ||
253 | ath6kl_err("SkipScan: channel or bssid invalid\n"); | ||
254 | return -EINVAL; | ||
255 | } | ||
256 | |||
257 | if (down_interruptible(&ar->sem)) { | ||
258 | ath6kl_err("busy, couldn't get access\n"); | ||
259 | return -ERESTARTSYS; | ||
260 | } | ||
261 | |||
262 | if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) { | ||
263 | ath6kl_err("busy, destroy in progress\n"); | ||
264 | up(&ar->sem); | ||
265 | return -EBUSY; | ||
266 | } | ||
267 | |||
268 | if (ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)]) { | ||
269 | /* | ||
270 | * sleep until the command queue drains | ||
271 | */ | ||
272 | wait_event_interruptible_timeout(ar->event_wq, | ||
273 | ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0, | ||
274 | WMI_TIMEOUT); | ||
275 | if (signal_pending(current)) { | ||
276 | ath6kl_err("cmd queue drain timeout\n"); | ||
277 | up(&ar->sem); | ||
278 | return -EINTR; | ||
279 | } | ||
280 | } | ||
281 | |||
282 | if (test_bit(CONNECTED, &ar->flag) && | ||
283 | ar->ssid_len == sme->ssid_len && | ||
284 | !memcmp(ar->ssid, sme->ssid, ar->ssid_len)) { | ||
285 | ar->reconnect_flag = true; | ||
286 | status = ath6kl_wmi_reconnect_cmd(ar->wmi, ar->req_bssid, | ||
287 | ar->ch_hint); | ||
288 | |||
289 | up(&ar->sem); | ||
290 | if (status) { | ||
291 | ath6kl_err("wmi_reconnect_cmd failed\n"); | ||
292 | return -EIO; | ||
293 | } | ||
294 | return 0; | ||
295 | } else if (ar->ssid_len == sme->ssid_len && | ||
296 | !memcmp(ar->ssid, sme->ssid, ar->ssid_len)) { | ||
297 | ath6kl_disconnect(ar); | ||
298 | } | ||
299 | |||
300 | memset(ar->ssid, 0, sizeof(ar->ssid)); | ||
301 | ar->ssid_len = sme->ssid_len; | ||
302 | memcpy(ar->ssid, sme->ssid, sme->ssid_len); | ||
303 | |||
304 | if (sme->channel) | ||
305 | ar->ch_hint = sme->channel->center_freq; | ||
306 | |||
307 | memset(ar->req_bssid, 0, sizeof(ar->req_bssid)); | ||
308 | if (sme->bssid && !is_broadcast_ether_addr(sme->bssid)) | ||
309 | memcpy(ar->req_bssid, sme->bssid, sizeof(ar->req_bssid)); | ||
310 | |||
311 | ath6kl_set_wpa_version(ar, sme->crypto.wpa_versions); | ||
312 | |||
313 | status = ath6kl_set_auth_type(ar, sme->auth_type); | ||
314 | if (status) { | ||
315 | up(&ar->sem); | ||
316 | return status; | ||
317 | } | ||
318 | |||
319 | if (sme->crypto.n_ciphers_pairwise) | ||
320 | ath6kl_set_cipher(ar, sme->crypto.ciphers_pairwise[0], true); | ||
321 | else | ||
322 | ath6kl_set_cipher(ar, 0, true); | ||
323 | |||
324 | ath6kl_set_cipher(ar, sme->crypto.cipher_group, false); | ||
325 | |||
326 | if (sme->crypto.n_akm_suites) | ||
327 | ath6kl_set_key_mgmt(ar, sme->crypto.akm_suites[0]); | ||
328 | |||
329 | if ((sme->key_len) && | ||
330 | (ar->auth_mode == NONE_AUTH) && (ar->prwise_crypto == WEP_CRYPT)) { | ||
331 | struct ath6kl_key *key = NULL; | ||
332 | |||
333 | if (sme->key_idx < WMI_MIN_KEY_INDEX || | ||
334 | sme->key_idx > WMI_MAX_KEY_INDEX) { | ||
335 | ath6kl_err("key index %d out of bounds\n", | ||
336 | sme->key_idx); | ||
337 | up(&ar->sem); | ||
338 | return -ENOENT; | ||
339 | } | ||
340 | |||
341 | key = &ar->keys[sme->key_idx]; | ||
342 | key->key_len = sme->key_len; | ||
343 | memcpy(key->key, sme->key, key->key_len); | ||
344 | key->cipher = ar->prwise_crypto; | ||
345 | ar->def_txkey_index = sme->key_idx; | ||
346 | |||
347 | ath6kl_wmi_addkey_cmd(ar->wmi, sme->key_idx, | ||
348 | ar->prwise_crypto, | ||
349 | GROUP_USAGE | TX_USAGE, | ||
350 | key->key_len, | ||
351 | NULL, | ||
352 | key->key, KEY_OP_INIT_VAL, NULL, | ||
353 | NO_SYNC_WMIFLAG); | ||
354 | } | ||
355 | |||
356 | if (!ar->usr_bss_filter) { | ||
357 | if (ath6kl_wmi_bssfilter_cmd(ar->wmi, ALL_BSS_FILTER, 0) != 0) { | ||
358 | ath6kl_err("couldn't set bss filtering\n"); | ||
359 | up(&ar->sem); | ||
360 | return -EIO; | ||
361 | } | ||
362 | } | ||
363 | |||
364 | ar->nw_type = ar->next_mode; | ||
365 | |||
366 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | ||
367 | "%s: connect called with authmode %d dot11 auth %d" | ||
368 | " PW crypto %d PW crypto len %d GRP crypto %d" | ||
369 | " GRP crypto len %d channel hint %u\n", | ||
370 | __func__, | ||
371 | ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto, | ||
372 | ar->prwise_crypto_len, ar->grp_crypto, | ||
373 | ar->grp_crpto_len, ar->ch_hint); | ||
374 | |||
375 | ar->reconnect_flag = 0; | ||
376 | status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type, | ||
377 | ar->dot11_auth_mode, ar->auth_mode, | ||
378 | ar->prwise_crypto, | ||
379 | ar->prwise_crypto_len, | ||
380 | ar->grp_crypto, ar->grp_crpto_len, | ||
381 | ar->ssid_len, ar->ssid, | ||
382 | ar->req_bssid, ar->ch_hint, | ||
383 | ar->connect_ctrl_flags); | ||
384 | |||
385 | up(&ar->sem); | ||
386 | |||
387 | if (status == -EINVAL) { | ||
388 | memset(ar->ssid, 0, sizeof(ar->ssid)); | ||
389 | ar->ssid_len = 0; | ||
390 | ath6kl_err("invalid request\n"); | ||
391 | return -ENOENT; | ||
392 | } else if (status) { | ||
393 | ath6kl_err("ath6kl_wmi_connect_cmd failed\n"); | ||
394 | return -EIO; | ||
395 | } | ||
396 | |||
397 | if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) && | ||
398 | ((ar->auth_mode == WPA_PSK_AUTH) | ||
399 | || (ar->auth_mode == WPA2_PSK_AUTH))) { | ||
400 | mod_timer(&ar->disconnect_timer, | ||
401 | jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL)); | ||
402 | } | ||
403 | |||
404 | ar->connect_ctrl_flags &= ~CONNECT_DO_WPA_OFFLOAD; | ||
405 | set_bit(CONNECT_PEND, &ar->flag); | ||
406 | |||
407 | return 0; | ||
408 | } | ||
409 | |||
410 | void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel, | ||
411 | u8 *bssid, u16 listen_intvl, | ||
412 | u16 beacon_intvl, | ||
413 | enum network_type nw_type, | ||
414 | u8 beacon_ie_len, u8 assoc_req_len, | ||
415 | u8 assoc_resp_len, u8 *assoc_info) | ||
416 | { | ||
417 | u16 size = 0; | ||
418 | u16 capability = 0; | ||
419 | struct cfg80211_bss *bss = NULL; | ||
420 | struct ieee80211_mgmt *mgmt = NULL; | ||
421 | struct ieee80211_channel *ibss_ch = NULL; | ||
422 | s32 signal = 50 * 100; | ||
423 | u8 ie_buf_len = 0; | ||
424 | unsigned char ie_buf[256]; | ||
425 | unsigned char *ptr_ie_buf = ie_buf; | ||
426 | unsigned char *ieeemgmtbuf = NULL; | ||
427 | u8 source_mac[ETH_ALEN]; | ||
428 | u16 capa_mask; | ||
429 | u16 capa_val; | ||
430 | |||
431 | /* capinfo + listen interval */ | ||
432 | u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16); | ||
433 | |||
434 | /* capinfo + status code + associd */ | ||
435 | u8 assoc_resp_ie_offset = sizeof(u16) + sizeof(u16) + sizeof(u16); | ||
436 | |||
437 | u8 *assoc_req_ie = assoc_info + beacon_ie_len + assoc_req_ie_offset; | ||
438 | u8 *assoc_resp_ie = assoc_info + beacon_ie_len + assoc_req_len + | ||
439 | assoc_resp_ie_offset; | ||
440 | |||
441 | assoc_req_len -= assoc_req_ie_offset; | ||
442 | assoc_resp_len -= assoc_resp_ie_offset; | ||
443 | |||
444 | ar->auto_auth_stage = AUTH_IDLE; | ||
445 | |||
446 | if (nw_type & ADHOC_NETWORK) { | ||
447 | if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) { | ||
448 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | ||
449 | "%s: ath6k not in ibss mode\n", __func__); | ||
450 | return; | ||
451 | } | ||
452 | } | ||
453 | |||
454 | if (nw_type & INFRA_NETWORK) { | ||
455 | if (ar->wdev->iftype != NL80211_IFTYPE_STATION) { | ||
456 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | ||
457 | "%s: ath6k not in station mode\n", __func__); | ||
458 | return; | ||
459 | } | ||
460 | } | ||
461 | |||
462 | if (nw_type & ADHOC_NETWORK) { | ||
463 | capa_mask = WLAN_CAPABILITY_IBSS; | ||
464 | capa_val = WLAN_CAPABILITY_IBSS; | ||
465 | } else { | ||
466 | capa_mask = WLAN_CAPABILITY_ESS; | ||
467 | capa_val = WLAN_CAPABILITY_ESS; | ||
468 | } | ||
469 | |||
470 | /* Before informing the join/connect event, make sure that | ||
471 | * bss entry is present in scan list, if it not present | ||
472 | * construct and insert into scan list, otherwise that | ||
473 | * event will be dropped on the way by cfg80211, due to | ||
474 | * this keys will not be plumbed in case of WEP and | ||
475 | * application will not be aware of join/connect status. */ | ||
476 | bss = cfg80211_get_bss(ar->wdev->wiphy, NULL, bssid, | ||
477 | ar->wdev->ssid, ar->wdev->ssid_len, | ||
478 | capa_mask, capa_val); | ||
479 | |||
480 | /* | ||
481 | * Earlier we were updating the cfg about bss by making a beacon frame | ||
482 | * only if the entry for bss is not there. This can have some issue if | ||
483 | * ROAM event is generated and a heavy traffic is ongoing. The ROAM | ||
484 | * event is handled through a work queue and by the time it really gets | ||
485 | * handled, BSS would have been aged out. So it is better to update the | ||
486 | * cfg about BSS irrespective of its entry being present right now or | ||
487 | * not. | ||
488 | */ | ||
489 | |||
490 | if (nw_type & ADHOC_NETWORK) { | ||
491 | /* construct 802.11 mgmt beacon */ | ||
492 | if (ptr_ie_buf) { | ||
493 | *ptr_ie_buf++ = WLAN_EID_SSID; | ||
494 | *ptr_ie_buf++ = ar->ssid_len; | ||
495 | memcpy(ptr_ie_buf, ar->ssid, ar->ssid_len); | ||
496 | ptr_ie_buf += ar->ssid_len; | ||
497 | |||
498 | *ptr_ie_buf++ = WLAN_EID_IBSS_PARAMS; | ||
499 | *ptr_ie_buf++ = 2; /* length */ | ||
500 | *ptr_ie_buf++ = 0; /* ATIM window */ | ||
501 | *ptr_ie_buf++ = 0; /* ATIM window */ | ||
502 | |||
503 | /* TODO: update ibss params and include supported rates, | ||
504 | * DS param set, extened support rates, wmm. */ | ||
505 | |||
506 | ie_buf_len = ptr_ie_buf - ie_buf; | ||
507 | } | ||
508 | |||
509 | capability |= WLAN_CAPABILITY_IBSS; | ||
510 | |||
511 | if (ar->prwise_crypto == WEP_CRYPT) | ||
512 | capability |= WLAN_CAPABILITY_PRIVACY; | ||
513 | |||
514 | memcpy(source_mac, ar->net_dev->dev_addr, ETH_ALEN); | ||
515 | ptr_ie_buf = ie_buf; | ||
516 | } else { | ||
517 | capability = *(u16 *) (&assoc_info[beacon_ie_len]); | ||
518 | memcpy(source_mac, bssid, ETH_ALEN); | ||
519 | ptr_ie_buf = assoc_req_ie; | ||
520 | ie_buf_len = assoc_req_len; | ||
521 | } | ||
522 | |||
523 | size = offsetof(struct ieee80211_mgmt, u) | ||
524 | + sizeof(mgmt->u.beacon) | ||
525 | + ie_buf_len; | ||
526 | |||
527 | ieeemgmtbuf = kzalloc(size, GFP_ATOMIC); | ||
528 | if (!ieeemgmtbuf) { | ||
529 | ath6kl_err("ieee mgmt buf alloc error\n"); | ||
530 | cfg80211_put_bss(bss); | ||
531 | return; | ||
532 | } | ||
533 | |||
534 | mgmt = (struct ieee80211_mgmt *)ieeemgmtbuf; | ||
535 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
536 | IEEE80211_STYPE_BEACON); | ||
537 | memset(mgmt->da, 0xff, ETH_ALEN); /* broadcast addr */ | ||
538 | memcpy(mgmt->sa, source_mac, ETH_ALEN); | ||
539 | memcpy(mgmt->bssid, bssid, ETH_ALEN); | ||
540 | mgmt->u.beacon.beacon_int = cpu_to_le16(beacon_intvl); | ||
541 | mgmt->u.beacon.capab_info = cpu_to_le16(capability); | ||
542 | memcpy(mgmt->u.beacon.variable, ptr_ie_buf, ie_buf_len); | ||
543 | |||
544 | ibss_ch = ieee80211_get_channel(ar->wdev->wiphy, (int)channel); | ||
545 | |||
546 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | ||
547 | "%s: inform bss with bssid %pM channel %d beacon_intvl %d capability 0x%x\n", | ||
548 | __func__, mgmt->bssid, ibss_ch->hw_value, | ||
549 | beacon_intvl, capability); | ||
550 | |||
551 | bss = cfg80211_inform_bss_frame(ar->wdev->wiphy, | ||
552 | ibss_ch, mgmt, | ||
553 | size, signal, GFP_KERNEL); | ||
554 | kfree(ieeemgmtbuf); | ||
555 | cfg80211_put_bss(bss); | ||
556 | |||
557 | if (nw_type & ADHOC_NETWORK) { | ||
558 | cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL); | ||
559 | return; | ||
560 | } | ||
561 | |||
562 | if (ar->sme_state == SME_CONNECTING) { | ||
563 | /* inform connect result to cfg80211 */ | ||
564 | ar->sme_state = SME_CONNECTED; | ||
565 | cfg80211_connect_result(ar->net_dev, bssid, | ||
566 | assoc_req_ie, assoc_req_len, | ||
567 | assoc_resp_ie, assoc_resp_len, | ||
568 | WLAN_STATUS_SUCCESS, GFP_KERNEL); | ||
569 | } else if (ar->sme_state == SME_CONNECTED) { | ||
570 | /* inform roam event to cfg80211 */ | ||
571 | cfg80211_roamed(ar->net_dev, ibss_ch, bssid, | ||
572 | assoc_req_ie, assoc_req_len, | ||
573 | assoc_resp_ie, assoc_resp_len, GFP_KERNEL); | ||
574 | } | ||
575 | } | ||
576 | |||
577 | static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy, | ||
578 | struct net_device *dev, u16 reason_code) | ||
579 | { | ||
580 | struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev); | ||
581 | |||
582 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__, | ||
583 | reason_code); | ||
584 | |||
585 | if (!ath6kl_cfg80211_ready(ar)) | ||
586 | return -EIO; | ||
587 | |||
588 | if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) { | ||
589 | ath6kl_err("busy, destroy in progress\n"); | ||
590 | return -EBUSY; | ||
591 | } | ||
592 | |||
593 | if (down_interruptible(&ar->sem)) { | ||
594 | ath6kl_err("busy, couldn't get access\n"); | ||
595 | return -ERESTARTSYS; | ||
596 | } | ||
597 | |||
598 | ar->reconnect_flag = 0; | ||
599 | ath6kl_disconnect(ar); | ||
600 | memset(ar->ssid, 0, sizeof(ar->ssid)); | ||
601 | ar->ssid_len = 0; | ||
602 | |||
603 | if (!test_bit(SKIP_SCAN, &ar->flag)) | ||
604 | memset(ar->req_bssid, 0, sizeof(ar->req_bssid)); | ||
605 | |||
606 | up(&ar->sem); | ||
607 | |||
608 | return 0; | ||
609 | } | ||
610 | |||
611 | void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason, | ||
612 | u8 *bssid, u8 assoc_resp_len, | ||
613 | u8 *assoc_info, u16 proto_reason) | ||
614 | { | ||
615 | struct ath6kl_key *key = NULL; | ||
616 | u16 status; | ||
617 | |||
618 | if (ar->scan_req) { | ||
619 | cfg80211_scan_done(ar->scan_req, true); | ||
620 | ar->scan_req = NULL; | ||
621 | } | ||
622 | |||
623 | if (ar->nw_type & ADHOC_NETWORK) { | ||
624 | if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) { | ||
625 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | ||
626 | "%s: ath6k not in ibss mode\n", __func__); | ||
627 | return; | ||
628 | } | ||
629 | memset(bssid, 0, ETH_ALEN); | ||
630 | cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL); | ||
631 | return; | ||
632 | } | ||
633 | |||
634 | if (ar->nw_type & INFRA_NETWORK) { | ||
635 | if (ar->wdev->iftype != NL80211_IFTYPE_STATION) { | ||
636 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | ||
637 | "%s: ath6k not in station mode\n", __func__); | ||
638 | return; | ||
639 | } | ||
640 | } | ||
641 | |||
642 | if (!test_bit(CONNECT_PEND, &ar->flag)) { | ||
643 | if (reason != DISCONNECT_CMD) | ||
644 | ath6kl_wmi_disconnect_cmd(ar->wmi); | ||
645 | |||
646 | return; | ||
647 | } | ||
648 | |||
649 | if (reason == NO_NETWORK_AVAIL) { | ||
650 | /* connect cmd failed */ | ||
651 | ath6kl_wmi_disconnect_cmd(ar->wmi); | ||
652 | return; | ||
653 | } | ||
654 | |||
655 | if (reason != DISCONNECT_CMD) | ||
656 | return; | ||
657 | |||
658 | if (!ar->auto_auth_stage) { | ||
659 | clear_bit(CONNECT_PEND, &ar->flag); | ||
660 | |||
661 | if (ar->sme_state == SME_CONNECTING) { | ||
662 | cfg80211_connect_result(ar->net_dev, | ||
663 | bssid, NULL, 0, | ||
664 | NULL, 0, | ||
665 | WLAN_STATUS_UNSPECIFIED_FAILURE, | ||
666 | GFP_KERNEL); | ||
667 | } else { | ||
668 | cfg80211_disconnected(ar->net_dev, reason, | ||
669 | NULL, 0, GFP_KERNEL); | ||
670 | } | ||
671 | |||
672 | ar->sme_state = SME_DISCONNECTED; | ||
673 | return; | ||
674 | } | ||
675 | |||
676 | if (ar->dot11_auth_mode != OPEN_AUTH) | ||
677 | return; | ||
678 | |||
679 | /* | ||
680 | * If the current auth algorithm is open, try shared and | ||
681 | * make autoAuthStage idle. We do not make it leap for now | ||
682 | * being. | ||
683 | */ | ||
684 | key = &ar->keys[ar->def_txkey_index]; | ||
685 | if (down_interruptible(&ar->sem)) { | ||
686 | ath6kl_err("busy, couldn't get access\n"); | ||
687 | return; | ||
688 | } | ||
689 | |||
690 | ar->dot11_auth_mode = SHARED_AUTH; | ||
691 | ar->auto_auth_stage = AUTH_IDLE; | ||
692 | |||
693 | ath6kl_wmi_addkey_cmd(ar->wmi, | ||
694 | ar->def_txkey_index, | ||
695 | ar->prwise_crypto, | ||
696 | GROUP_USAGE | TX_USAGE, | ||
697 | key->key_len, NULL, | ||
698 | key->key, | ||
699 | KEY_OP_INIT_VAL, NULL, | ||
700 | NO_SYNC_WMIFLAG); | ||
701 | |||
702 | status = ath6kl_wmi_connect_cmd(ar->wmi, | ||
703 | ar->nw_type, | ||
704 | ar->dot11_auth_mode, | ||
705 | ar->auth_mode, | ||
706 | ar->prwise_crypto, | ||
707 | ar->prwise_crypto_len, | ||
708 | ar->grp_crypto, | ||
709 | ar->grp_crpto_len, | ||
710 | ar->ssid_len, | ||
711 | ar->ssid, | ||
712 | ar->req_bssid, | ||
713 | ar->ch_hint, | ||
714 | ar->connect_ctrl_flags); | ||
715 | up(&ar->sem); | ||
716 | } | ||
717 | |||
718 | static inline bool is_ch_11a(u16 ch) | ||
719 | { | ||
720 | return (!((ch >= 2412) && (ch <= 2484))); | ||
721 | } | ||
722 | |||
723 | /* struct ath6kl_node_table::nt_nodelock is locked when calling this */ | ||
724 | void ath6kl_cfg80211_scan_node(struct wiphy *wiphy, struct bss *ni) | ||
725 | { | ||
726 | u16 size; | ||
727 | unsigned char *ieeemgmtbuf = NULL; | ||
728 | struct ieee80211_mgmt *mgmt; | ||
729 | struct ieee80211_channel *channel; | ||
730 | struct ieee80211_supported_band *band; | ||
731 | struct ath6kl_common_ie *cie; | ||
732 | s32 signal; | ||
733 | int freq; | ||
734 | |||
735 | cie = &ni->ni_cie; | ||
736 | |||
737 | if (is_ch_11a(cie->ie_chan)) | ||
738 | band = wiphy->bands[IEEE80211_BAND_5GHZ]; /* 11a */ | ||
739 | else if ((cie->ie_erp) || (cie->ie_xrates)) | ||
740 | band = wiphy->bands[IEEE80211_BAND_2GHZ]; /* 11g */ | ||
741 | else | ||
742 | band = wiphy->bands[IEEE80211_BAND_2GHZ]; /* 11b */ | ||
743 | |||
744 | size = ni->ni_framelen + offsetof(struct ieee80211_mgmt, u); | ||
745 | ieeemgmtbuf = kmalloc(size, GFP_ATOMIC); | ||
746 | if (!ieeemgmtbuf) { | ||
747 | ath6kl_err("ieee mgmt buf alloc error\n"); | ||
748 | return; | ||
749 | } | ||
750 | |||
751 | /* | ||
752 | * TODO: Update target to include 802.11 mac header while sending | ||
753 | * bss info. Target removes 802.11 mac header while sending the bss | ||
754 | * info to host, cfg80211 needs it, for time being just filling the | ||
755 | * da, sa and bssid fields alone. | ||
756 | */ | ||
757 | mgmt = (struct ieee80211_mgmt *)ieeemgmtbuf; | ||
758 | memset(mgmt->da, 0xff, ETH_ALEN); /*broadcast addr */ | ||
759 | memcpy(mgmt->sa, ni->ni_macaddr, ETH_ALEN); | ||
760 | memcpy(mgmt->bssid, ni->ni_macaddr, ETH_ALEN); | ||
761 | memcpy(ieeemgmtbuf + offsetof(struct ieee80211_mgmt, u), | ||
762 | ni->ni_buf, ni->ni_framelen); | ||
763 | |||
764 | freq = cie->ie_chan; | ||
765 | channel = ieee80211_get_channel(wiphy, freq); | ||
766 | signal = ni->ni_snr * 100; | ||
767 | |||
768 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | ||
769 | "%s: bssid %pM ch %d freq %d size %d\n", __func__, | ||
770 | mgmt->bssid, channel->hw_value, freq, size); | ||
771 | cfg80211_inform_bss_frame(wiphy, channel, mgmt, | ||
772 | size, signal, GFP_ATOMIC); | ||
773 | |||
774 | kfree(ieeemgmtbuf); | ||
775 | } | ||
776 | |||
777 | static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, | ||
778 | struct cfg80211_scan_request *request) | ||
779 | { | ||
780 | struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev); | ||
781 | int ret = 0; | ||
782 | |||
783 | if (!ath6kl_cfg80211_ready(ar)) | ||
784 | return -EIO; | ||
785 | |||
786 | if (!ar->usr_bss_filter) { | ||
787 | if (ath6kl_wmi_bssfilter_cmd(ar->wmi, | ||
788 | (test_bit(CONNECTED, &ar->flag) ? | ||
789 | ALL_BUT_BSS_FILTER : | ||
790 | ALL_BSS_FILTER), 0) != 0) { | ||
791 | ath6kl_err("couldn't set bss filtering\n"); | ||
792 | return -EIO; | ||
793 | } | ||
794 | } | ||
795 | |||
796 | if (request->n_ssids && request->ssids[0].ssid_len) { | ||
797 | u8 i; | ||
798 | |||
799 | if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1)) | ||
800 | request->n_ssids = MAX_PROBED_SSID_INDEX - 1; | ||
801 | |||
802 | for (i = 0; i < request->n_ssids; i++) | ||
803 | ath6kl_wmi_probedssid_cmd(ar->wmi, i + 1, | ||
804 | SPECIFIC_SSID_FLAG, | ||
805 | request->ssids[i].ssid_len, | ||
806 | request->ssids[i].ssid); | ||
807 | } | ||
808 | |||
809 | if (ath6kl_wmi_startscan_cmd(ar->wmi, WMI_LONG_SCAN, 0, | ||
810 | false, 0, 0, 0, NULL) != 0) { | ||
811 | ath6kl_err("wmi_startscan_cmd failed\n"); | ||
812 | ret = -EIO; | ||
813 | } | ||
814 | |||
815 | ar->scan_req = request; | ||
816 | |||
817 | return ret; | ||
818 | } | ||
819 | |||
820 | void ath6kl_cfg80211_scan_complete_event(struct ath6kl *ar, int status) | ||
821 | { | ||
822 | int i; | ||
823 | |||
824 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status %d\n", __func__, status); | ||
825 | |||
826 | if (!ar->scan_req) | ||
827 | return; | ||
828 | |||
829 | if ((status == -ECANCELED) || (status == -EBUSY)) { | ||
830 | cfg80211_scan_done(ar->scan_req, true); | ||
831 | goto out; | ||
832 | } | ||
833 | |||
834 | /* Translate data to cfg80211 mgmt format */ | ||
835 | wlan_iterate_nodes(&ar->scan_table, ar->wdev->wiphy); | ||
836 | |||
837 | cfg80211_scan_done(ar->scan_req, false); | ||
838 | |||
839 | if (ar->scan_req->n_ssids && ar->scan_req->ssids[0].ssid_len) { | ||
840 | for (i = 0; i < ar->scan_req->n_ssids; i++) { | ||
841 | ath6kl_wmi_probedssid_cmd(ar->wmi, i + 1, | ||
842 | DISABLE_SSID_FLAG, | ||
843 | 0, NULL); | ||
844 | } | ||
845 | } | ||
846 | |||
847 | out: | ||
848 | ar->scan_req = NULL; | ||
849 | } | ||
850 | |||
851 | static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, | ||
852 | u8 key_index, bool pairwise, | ||
853 | const u8 *mac_addr, | ||
854 | struct key_params *params) | ||
855 | { | ||
856 | struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev); | ||
857 | struct ath6kl_key *key = NULL; | ||
858 | u8 key_usage; | ||
859 | u8 key_type; | ||
860 | int status = 0; | ||
861 | |||
862 | if (!ath6kl_cfg80211_ready(ar)) | ||
863 | return -EIO; | ||
864 | |||
865 | if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) { | ||
866 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | ||
867 | "%s: key index %d out of bounds\n", __func__, | ||
868 | key_index); | ||
869 | return -ENOENT; | ||
870 | } | ||
871 | |||
872 | key = &ar->keys[key_index]; | ||
873 | memset(key, 0, sizeof(struct ath6kl_key)); | ||
874 | |||
875 | if (pairwise) | ||
876 | key_usage = PAIRWISE_USAGE; | ||
877 | else | ||
878 | key_usage = GROUP_USAGE; | ||
879 | |||
880 | if (params) { | ||
881 | if (params->key_len > WLAN_MAX_KEY_LEN || | ||
882 | params->seq_len > sizeof(key->seq)) | ||
883 | return -EINVAL; | ||
884 | |||
885 | key->key_len = params->key_len; | ||
886 | memcpy(key->key, params->key, key->key_len); | ||
887 | key->seq_len = params->seq_len; | ||
888 | memcpy(key->seq, params->seq, key->seq_len); | ||
889 | key->cipher = params->cipher; | ||
890 | } | ||
891 | |||
892 | switch (key->cipher) { | ||
893 | case WLAN_CIPHER_SUITE_WEP40: | ||
894 | case WLAN_CIPHER_SUITE_WEP104: | ||
895 | key_type = WEP_CRYPT; | ||
896 | break; | ||
897 | |||
898 | case WLAN_CIPHER_SUITE_TKIP: | ||
899 | key_type = TKIP_CRYPT; | ||
900 | break; | ||
901 | |||
902 | case WLAN_CIPHER_SUITE_CCMP: | ||
903 | key_type = AES_CRYPT; | ||
904 | break; | ||
905 | |||
906 | default: | ||
907 | return -ENOTSUPP; | ||
908 | } | ||
909 | |||
910 | if (((ar->auth_mode == WPA_PSK_AUTH) | ||
911 | || (ar->auth_mode == WPA2_PSK_AUTH)) | ||
912 | && (key_usage & GROUP_USAGE)) | ||
913 | del_timer(&ar->disconnect_timer); | ||
914 | |||
915 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | ||
916 | "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n", | ||
917 | __func__, key_index, key->key_len, key_type, | ||
918 | key_usage, key->seq_len); | ||
919 | |||
920 | ar->def_txkey_index = key_index; | ||
921 | status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index, | ||
922 | key_type, key_usage, key->key_len, | ||
923 | key->seq, key->key, KEY_OP_INIT_VAL, | ||
924 | (u8 *) mac_addr, SYNC_BOTH_WMIFLAG); | ||
925 | |||
926 | if (status) | ||
927 | return -EIO; | ||
928 | |||
929 | return 0; | ||
930 | } | ||
931 | |||
932 | static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, | ||
933 | u8 key_index, bool pairwise, | ||
934 | const u8 *mac_addr) | ||
935 | { | ||
936 | struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev); | ||
937 | |||
938 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index); | ||
939 | |||
940 | if (!ath6kl_cfg80211_ready(ar)) | ||
941 | return -EIO; | ||
942 | |||
943 | if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) { | ||
944 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | ||
945 | "%s: key index %d out of bounds\n", __func__, | ||
946 | key_index); | ||
947 | return -ENOENT; | ||
948 | } | ||
949 | |||
950 | if (!ar->keys[key_index].key_len) { | ||
951 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | ||
952 | "%s: index %d is empty\n", __func__, key_index); | ||
953 | return 0; | ||
954 | } | ||
955 | |||
956 | ar->keys[key_index].key_len = 0; | ||
957 | |||
958 | return ath6kl_wmi_deletekey_cmd(ar->wmi, key_index); | ||
959 | } | ||
960 | |||
961 | static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, | ||
962 | u8 key_index, bool pairwise, | ||
963 | const u8 *mac_addr, void *cookie, | ||
964 | void (*callback) (void *cookie, | ||
965 | struct key_params *)) | ||
966 | { | ||
967 | struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev); | ||
968 | struct ath6kl_key *key = NULL; | ||
969 | struct key_params params; | ||
970 | |||
971 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index); | ||
972 | |||
973 | if (!ath6kl_cfg80211_ready(ar)) | ||
974 | return -EIO; | ||
975 | |||
976 | if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) { | ||
977 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | ||
978 | "%s: key index %d out of bounds\n", __func__, | ||
979 | key_index); | ||
980 | return -ENOENT; | ||
981 | } | ||
982 | |||
983 | key = &ar->keys[key_index]; | ||
984 | memset(¶ms, 0, sizeof(params)); | ||
985 | params.cipher = key->cipher; | ||
986 | params.key_len = key->key_len; | ||
987 | params.seq_len = key->seq_len; | ||
988 | params.seq = key->seq; | ||
989 | params.key = key->key; | ||
990 | |||
991 | callback(cookie, ¶ms); | ||
992 | |||
993 | return key->key_len ? 0 : -ENOENT; | ||
994 | } | ||
995 | |||
996 | static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy, | ||
997 | struct net_device *ndev, | ||
998 | u8 key_index, bool unicast, | ||
999 | bool multicast) | ||
1000 | { | ||
1001 | struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev); | ||
1002 | struct ath6kl_key *key = NULL; | ||
1003 | int status = 0; | ||
1004 | u8 key_usage; | ||
1005 | |||
1006 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index); | ||
1007 | |||
1008 | if (!ath6kl_cfg80211_ready(ar)) | ||
1009 | return -EIO; | ||
1010 | |||
1011 | if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) { | ||
1012 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | ||
1013 | "%s: key index %d out of bounds\n", | ||
1014 | __func__, key_index); | ||
1015 | return -ENOENT; | ||
1016 | } | ||
1017 | |||
1018 | if (!ar->keys[key_index].key_len) { | ||
1019 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n", | ||
1020 | __func__, key_index); | ||
1021 | return -EINVAL; | ||
1022 | } | ||
1023 | |||
1024 | ar->def_txkey_index = key_index; | ||
1025 | key = &ar->keys[ar->def_txkey_index]; | ||
1026 | key_usage = GROUP_USAGE; | ||
1027 | if (ar->prwise_crypto == WEP_CRYPT) | ||
1028 | key_usage |= TX_USAGE; | ||
1029 | |||
1030 | status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index, | ||
1031 | ar->prwise_crypto, key_usage, | ||
1032 | key->key_len, key->seq, key->key, | ||
1033 | KEY_OP_INIT_VAL, NULL, | ||
1034 | SYNC_BOTH_WMIFLAG); | ||
1035 | if (status) | ||
1036 | return -EIO; | ||
1037 | |||
1038 | return 0; | ||
1039 | } | ||
1040 | |||
1041 | void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl *ar, u8 keyid, | ||
1042 | bool ismcast) | ||
1043 | { | ||
1044 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | ||
1045 | "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast); | ||
1046 | |||
1047 | cfg80211_michael_mic_failure(ar->net_dev, ar->bssid, | ||
1048 | (ismcast ? NL80211_KEYTYPE_GROUP : | ||
1049 | NL80211_KEYTYPE_PAIRWISE), keyid, NULL, | ||
1050 | GFP_KERNEL); | ||
1051 | } | ||
1052 | |||
1053 | static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) | ||
1054 | { | ||
1055 | struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy); | ||
1056 | int ret; | ||
1057 | |||
1058 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__, | ||
1059 | changed); | ||
1060 | |||
1061 | if (!ath6kl_cfg80211_ready(ar)) | ||
1062 | return -EIO; | ||
1063 | |||
1064 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) { | ||
1065 | ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold); | ||
1066 | if (ret != 0) { | ||
1067 | ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n"); | ||
1068 | return -EIO; | ||
1069 | } | ||
1070 | } | ||
1071 | |||
1072 | return 0; | ||
1073 | } | ||
1074 | |||
1075 | /* | ||
1076 | * The type nl80211_tx_power_setting replaces the following | ||
1077 | * data type from 2.6.36 onwards | ||
1078 | */ | ||
1079 | static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, | ||
1080 | enum nl80211_tx_power_setting type, | ||
1081 | int dbm) | ||
1082 | { | ||
1083 | struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy); | ||
1084 | u8 ath6kl_dbm; | ||
1085 | |||
1086 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__, | ||
1087 | type, dbm); | ||
1088 | |||
1089 | if (!ath6kl_cfg80211_ready(ar)) | ||
1090 | return -EIO; | ||
1091 | |||
1092 | switch (type) { | ||
1093 | case NL80211_TX_POWER_AUTOMATIC: | ||
1094 | return 0; | ||
1095 | case NL80211_TX_POWER_LIMITED: | ||
1096 | ar->tx_pwr = ath6kl_dbm = dbm; | ||
1097 | break; | ||
1098 | default: | ||
1099 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n", | ||
1100 | __func__, type); | ||
1101 | return -EOPNOTSUPP; | ||
1102 | } | ||
1103 | |||
1104 | ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, ath6kl_dbm); | ||
1105 | |||
1106 | return 0; | ||
1107 | } | ||
1108 | |||
1109 | static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm) | ||
1110 | { | ||
1111 | struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy); | ||
1112 | |||
1113 | if (!ath6kl_cfg80211_ready(ar)) | ||
1114 | return -EIO; | ||
1115 | |||
1116 | if (test_bit(CONNECTED, &ar->flag)) { | ||
1117 | ar->tx_pwr = 0; | ||
1118 | |||
1119 | if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi) != 0) { | ||
1120 | ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n"); | ||
1121 | return -EIO; | ||
1122 | } | ||
1123 | |||
1124 | wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0, | ||
1125 | 5 * HZ); | ||
1126 | |||
1127 | if (signal_pending(current)) { | ||
1128 | ath6kl_err("target did not respond\n"); | ||
1129 | return -EINTR; | ||
1130 | } | ||
1131 | } | ||
1132 | |||
1133 | *dbm = ar->tx_pwr; | ||
1134 | return 0; | ||
1135 | } | ||
1136 | |||
1137 | static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy, | ||
1138 | struct net_device *dev, | ||
1139 | bool pmgmt, int timeout) | ||
1140 | { | ||
1141 | struct ath6kl *ar = ath6kl_priv(dev); | ||
1142 | struct wmi_power_mode_cmd mode; | ||
1143 | |||
1144 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n", | ||
1145 | __func__, pmgmt, timeout); | ||
1146 | |||
1147 | if (!ath6kl_cfg80211_ready(ar)) | ||
1148 | return -EIO; | ||
1149 | |||
1150 | if (pmgmt) { | ||
1151 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__); | ||
1152 | mode.pwr_mode = REC_POWER; | ||
1153 | } else { | ||
1154 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__); | ||
1155 | mode.pwr_mode = MAX_PERF_POWER; | ||
1156 | } | ||
1157 | |||
1158 | if (ath6kl_wmi_powermode_cmd(ar->wmi, mode.pwr_mode) != 0) { | ||
1159 | ath6kl_err("wmi_powermode_cmd failed\n"); | ||
1160 | return -EIO; | ||
1161 | } | ||
1162 | |||
1163 | return 0; | ||
1164 | } | ||
1165 | |||
1166 | static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy, | ||
1167 | struct net_device *ndev, | ||
1168 | enum nl80211_iftype type, u32 *flags, | ||
1169 | struct vif_params *params) | ||
1170 | { | ||
1171 | struct ath6kl *ar = ath6kl_priv(ndev); | ||
1172 | struct wireless_dev *wdev = ar->wdev; | ||
1173 | |||
1174 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type); | ||
1175 | |||
1176 | if (!ath6kl_cfg80211_ready(ar)) | ||
1177 | return -EIO; | ||
1178 | |||
1179 | switch (type) { | ||
1180 | case NL80211_IFTYPE_STATION: | ||
1181 | ar->next_mode = INFRA_NETWORK; | ||
1182 | break; | ||
1183 | case NL80211_IFTYPE_ADHOC: | ||
1184 | ar->next_mode = ADHOC_NETWORK; | ||
1185 | break; | ||
1186 | default: | ||
1187 | ath6kl_err("invalid interface type %u\n", type); | ||
1188 | return -EOPNOTSUPP; | ||
1189 | } | ||
1190 | |||
1191 | wdev->iftype = type; | ||
1192 | |||
1193 | return 0; | ||
1194 | } | ||
1195 | |||
1196 | static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy, | ||
1197 | struct net_device *dev, | ||
1198 | struct cfg80211_ibss_params *ibss_param) | ||
1199 | { | ||
1200 | struct ath6kl *ar = ath6kl_priv(dev); | ||
1201 | int status; | ||
1202 | |||
1203 | if (!ath6kl_cfg80211_ready(ar)) | ||
1204 | return -EIO; | ||
1205 | |||
1206 | ar->ssid_len = ibss_param->ssid_len; | ||
1207 | memcpy(ar->ssid, ibss_param->ssid, ar->ssid_len); | ||
1208 | |||
1209 | if (ibss_param->channel) | ||
1210 | ar->ch_hint = ibss_param->channel->center_freq; | ||
1211 | |||
1212 | if (ibss_param->channel_fixed) { | ||
1213 | /* | ||
1214 | * TODO: channel_fixed: The channel should be fixed, do not | ||
1215 | * search for IBSSs to join on other channels. Target | ||
1216 | * firmware does not support this feature, needs to be | ||
1217 | * updated. | ||
1218 | */ | ||
1219 | return -EOPNOTSUPP; | ||
1220 | } | ||
1221 | |||
1222 | memset(ar->req_bssid, 0, sizeof(ar->req_bssid)); | ||
1223 | if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid)) | ||
1224 | memcpy(ar->req_bssid, ibss_param->bssid, sizeof(ar->req_bssid)); | ||
1225 | |||
1226 | ath6kl_set_wpa_version(ar, 0); | ||
1227 | |||
1228 | status = ath6kl_set_auth_type(ar, NL80211_AUTHTYPE_OPEN_SYSTEM); | ||
1229 | if (status) | ||
1230 | return status; | ||
1231 | |||
1232 | if (ibss_param->privacy) { | ||
1233 | ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, true); | ||
1234 | ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, false); | ||
1235 | } else { | ||
1236 | ath6kl_set_cipher(ar, 0, true); | ||
1237 | ath6kl_set_cipher(ar, 0, false); | ||
1238 | } | ||
1239 | |||
1240 | ar->nw_type = ar->next_mode; | ||
1241 | |||
1242 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | ||
1243 | "%s: connect called with authmode %d dot11 auth %d" | ||
1244 | " PW crypto %d PW crypto len %d GRP crypto %d" | ||
1245 | " GRP crypto len %d channel hint %u\n", | ||
1246 | __func__, | ||
1247 | ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto, | ||
1248 | ar->prwise_crypto_len, ar->grp_crypto, | ||
1249 | ar->grp_crpto_len, ar->ch_hint); | ||
1250 | |||
1251 | status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type, | ||
1252 | ar->dot11_auth_mode, ar->auth_mode, | ||
1253 | ar->prwise_crypto, | ||
1254 | ar->prwise_crypto_len, | ||
1255 | ar->grp_crypto, ar->grp_crpto_len, | ||
1256 | ar->ssid_len, ar->ssid, | ||
1257 | ar->req_bssid, ar->ch_hint, | ||
1258 | ar->connect_ctrl_flags); | ||
1259 | set_bit(CONNECT_PEND, &ar->flag); | ||
1260 | |||
1261 | return 0; | ||
1262 | } | ||
1263 | |||
1264 | static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy, | ||
1265 | struct net_device *dev) | ||
1266 | { | ||
1267 | struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev); | ||
1268 | |||
1269 | if (!ath6kl_cfg80211_ready(ar)) | ||
1270 | return -EIO; | ||
1271 | |||
1272 | ath6kl_disconnect(ar); | ||
1273 | memset(ar->ssid, 0, sizeof(ar->ssid)); | ||
1274 | ar->ssid_len = 0; | ||
1275 | |||
1276 | return 0; | ||
1277 | } | ||
1278 | |||
1279 | static const u32 cipher_suites[] = { | ||
1280 | WLAN_CIPHER_SUITE_WEP40, | ||
1281 | WLAN_CIPHER_SUITE_WEP104, | ||
1282 | WLAN_CIPHER_SUITE_TKIP, | ||
1283 | WLAN_CIPHER_SUITE_CCMP, | ||
1284 | }; | ||
1285 | |||
1286 | static bool is_rate_legacy(s32 rate) | ||
1287 | { | ||
1288 | static const s32 legacy[] = { 1000, 2000, 5500, 11000, | ||
1289 | 6000, 9000, 12000, 18000, 24000, | ||
1290 | 36000, 48000, 54000 | ||
1291 | }; | ||
1292 | u8 i; | ||
1293 | |||
1294 | for (i = 0; i < ARRAY_SIZE(legacy); i++) | ||
1295 | if (rate == legacy[i]) | ||
1296 | return true; | ||
1297 | |||
1298 | return false; | ||
1299 | } | ||
1300 | |||
1301 | static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi) | ||
1302 | { | ||
1303 | static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000, | ||
1304 | 52000, 58500, 65000, 72200 | ||
1305 | }; | ||
1306 | u8 i; | ||
1307 | |||
1308 | for (i = 0; i < ARRAY_SIZE(ht20); i++) { | ||
1309 | if (rate == ht20[i]) { | ||
1310 | if (i == ARRAY_SIZE(ht20) - 1) | ||
1311 | /* last rate uses sgi */ | ||
1312 | *sgi = true; | ||
1313 | else | ||
1314 | *sgi = false; | ||
1315 | |||
1316 | *mcs = i; | ||
1317 | return true; | ||
1318 | } | ||
1319 | } | ||
1320 | return false; | ||
1321 | } | ||
1322 | |||
1323 | static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi) | ||
1324 | { | ||
1325 | static const s32 ht40[] = { 13500, 27000, 40500, 54000, | ||
1326 | 81000, 108000, 121500, 135000, | ||
1327 | 150000 | ||
1328 | }; | ||
1329 | u8 i; | ||
1330 | |||
1331 | for (i = 0; i < ARRAY_SIZE(ht40); i++) { | ||
1332 | if (rate == ht40[i]) { | ||
1333 | if (i == ARRAY_SIZE(ht40) - 1) | ||
1334 | /* last rate uses sgi */ | ||
1335 | *sgi = true; | ||
1336 | else | ||
1337 | *sgi = false; | ||
1338 | |||
1339 | *mcs = i; | ||
1340 | return true; | ||
1341 | } | ||
1342 | } | ||
1343 | |||
1344 | return false; | ||
1345 | } | ||
1346 | |||
1347 | static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev, | ||
1348 | u8 *mac, struct station_info *sinfo) | ||
1349 | { | ||
1350 | struct ath6kl *ar = ath6kl_priv(dev); | ||
1351 | long left; | ||
1352 | bool sgi; | ||
1353 | s32 rate; | ||
1354 | int ret; | ||
1355 | u8 mcs; | ||
1356 | |||
1357 | if (memcmp(mac, ar->bssid, ETH_ALEN) != 0) | ||
1358 | return -ENOENT; | ||
1359 | |||
1360 | if (down_interruptible(&ar->sem)) | ||
1361 | return -EBUSY; | ||
1362 | |||
1363 | set_bit(STATS_UPDATE_PEND, &ar->flag); | ||
1364 | |||
1365 | ret = ath6kl_wmi_get_stats_cmd(ar->wmi); | ||
1366 | |||
1367 | if (ret != 0) { | ||
1368 | up(&ar->sem); | ||
1369 | return -EIO; | ||
1370 | } | ||
1371 | |||
1372 | left = wait_event_interruptible_timeout(ar->event_wq, | ||
1373 | !test_bit(STATS_UPDATE_PEND, | ||
1374 | &ar->flag), | ||
1375 | WMI_TIMEOUT); | ||
1376 | |||
1377 | up(&ar->sem); | ||
1378 | |||
1379 | if (left == 0) | ||
1380 | return -ETIMEDOUT; | ||
1381 | else if (left < 0) | ||
1382 | return left; | ||
1383 | |||
1384 | if (ar->target_stats.rx_byte) { | ||
1385 | sinfo->rx_bytes = ar->target_stats.rx_byte; | ||
1386 | sinfo->filled |= STATION_INFO_RX_BYTES; | ||
1387 | sinfo->rx_packets = ar->target_stats.rx_pkt; | ||
1388 | sinfo->filled |= STATION_INFO_RX_PACKETS; | ||
1389 | } | ||
1390 | |||
1391 | if (ar->target_stats.tx_byte) { | ||
1392 | sinfo->tx_bytes = ar->target_stats.tx_byte; | ||
1393 | sinfo->filled |= STATION_INFO_TX_BYTES; | ||
1394 | sinfo->tx_packets = ar->target_stats.tx_pkt; | ||
1395 | sinfo->filled |= STATION_INFO_TX_PACKETS; | ||
1396 | } | ||
1397 | |||
1398 | sinfo->signal = ar->target_stats.cs_rssi; | ||
1399 | sinfo->filled |= STATION_INFO_SIGNAL; | ||
1400 | |||
1401 | rate = ar->target_stats.tx_ucast_rate; | ||
1402 | |||
1403 | if (is_rate_legacy(rate)) { | ||
1404 | sinfo->txrate.legacy = rate / 100; | ||
1405 | } else if (is_rate_ht20(rate, &mcs, &sgi)) { | ||
1406 | if (sgi) { | ||
1407 | sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; | ||
1408 | sinfo->txrate.mcs = mcs - 1; | ||
1409 | } else { | ||
1410 | sinfo->txrate.mcs = mcs; | ||
1411 | } | ||
1412 | |||
1413 | sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; | ||
1414 | } else if (is_rate_ht40(rate, &mcs, &sgi)) { | ||
1415 | if (sgi) { | ||
1416 | sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; | ||
1417 | sinfo->txrate.mcs = mcs - 1; | ||
1418 | } else { | ||
1419 | sinfo->txrate.mcs = mcs; | ||
1420 | } | ||
1421 | |||
1422 | sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | ||
1423 | sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; | ||
1424 | } else { | ||
1425 | ath6kl_warn("invalid rate: %d\n", rate); | ||
1426 | return 0; | ||
1427 | } | ||
1428 | |||
1429 | sinfo->filled |= STATION_INFO_TX_BITRATE; | ||
1430 | |||
1431 | return 0; | ||
1432 | } | ||
1433 | |||
1434 | static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev, | ||
1435 | struct cfg80211_pmksa *pmksa) | ||
1436 | { | ||
1437 | struct ath6kl *ar = ath6kl_priv(netdev); | ||
1438 | return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid, | ||
1439 | pmksa->pmkid, true); | ||
1440 | } | ||
1441 | |||
1442 | static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev, | ||
1443 | struct cfg80211_pmksa *pmksa) | ||
1444 | { | ||
1445 | struct ath6kl *ar = ath6kl_priv(netdev); | ||
1446 | return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid, | ||
1447 | pmksa->pmkid, false); | ||
1448 | } | ||
1449 | |||
1450 | static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev) | ||
1451 | { | ||
1452 | struct ath6kl *ar = ath6kl_priv(netdev); | ||
1453 | if (test_bit(CONNECTED, &ar->flag)) | ||
1454 | return ath6kl_wmi_setpmkid_cmd(ar->wmi, ar->bssid, NULL, false); | ||
1455 | return 0; | ||
1456 | } | ||
1457 | |||
1458 | static struct cfg80211_ops ath6kl_cfg80211_ops = { | ||
1459 | .change_virtual_intf = ath6kl_cfg80211_change_iface, | ||
1460 | .scan = ath6kl_cfg80211_scan, | ||
1461 | .connect = ath6kl_cfg80211_connect, | ||
1462 | .disconnect = ath6kl_cfg80211_disconnect, | ||
1463 | .add_key = ath6kl_cfg80211_add_key, | ||
1464 | .get_key = ath6kl_cfg80211_get_key, | ||
1465 | .del_key = ath6kl_cfg80211_del_key, | ||
1466 | .set_default_key = ath6kl_cfg80211_set_default_key, | ||
1467 | .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params, | ||
1468 | .set_tx_power = ath6kl_cfg80211_set_txpower, | ||
1469 | .get_tx_power = ath6kl_cfg80211_get_txpower, | ||
1470 | .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt, | ||
1471 | .join_ibss = ath6kl_cfg80211_join_ibss, | ||
1472 | .leave_ibss = ath6kl_cfg80211_leave_ibss, | ||
1473 | .get_station = ath6kl_get_station, | ||
1474 | .set_pmksa = ath6kl_set_pmksa, | ||
1475 | .del_pmksa = ath6kl_del_pmksa, | ||
1476 | .flush_pmksa = ath6kl_flush_pmksa, | ||
1477 | }; | ||
1478 | |||
1479 | struct wireless_dev *ath6kl_cfg80211_init(struct device *dev) | ||
1480 | { | ||
1481 | int ret = 0; | ||
1482 | struct wireless_dev *wdev; | ||
1483 | |||
1484 | wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); | ||
1485 | if (!wdev) { | ||
1486 | ath6kl_err("couldn't allocate wireless device\n"); | ||
1487 | return NULL; | ||
1488 | } | ||
1489 | |||
1490 | /* create a new wiphy for use with cfg80211 */ | ||
1491 | wdev->wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl)); | ||
1492 | if (!wdev->wiphy) { | ||
1493 | ath6kl_err("couldn't allocate wiphy device\n"); | ||
1494 | kfree(wdev); | ||
1495 | return NULL; | ||
1496 | } | ||
1497 | |||
1498 | /* set device pointer for wiphy */ | ||
1499 | set_wiphy_dev(wdev->wiphy, dev); | ||
1500 | |||
1501 | wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | ||
1502 | BIT(NL80211_IFTYPE_ADHOC); | ||
1503 | /* max num of ssids that can be probed during scanning */ | ||
1504 | wdev->wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX; | ||
1505 | wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz; | ||
1506 | wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz; | ||
1507 | wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | ||
1508 | |||
1509 | wdev->wiphy->cipher_suites = cipher_suites; | ||
1510 | wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); | ||
1511 | |||
1512 | ret = wiphy_register(wdev->wiphy); | ||
1513 | if (ret < 0) { | ||
1514 | ath6kl_err("couldn't register wiphy device\n"); | ||
1515 | wiphy_free(wdev->wiphy); | ||
1516 | kfree(wdev); | ||
1517 | return NULL; | ||
1518 | } | ||
1519 | |||
1520 | return wdev; | ||
1521 | } | ||
1522 | |||
1523 | void ath6kl_cfg80211_deinit(struct ath6kl *ar) | ||
1524 | { | ||
1525 | struct wireless_dev *wdev = ar->wdev; | ||
1526 | |||
1527 | if (ar->scan_req) { | ||
1528 | cfg80211_scan_done(ar->scan_req, true); | ||
1529 | ar->scan_req = NULL; | ||
1530 | } | ||
1531 | |||
1532 | if (!wdev) | ||
1533 | return; | ||
1534 | |||
1535 | wiphy_unregister(wdev->wiphy); | ||
1536 | wiphy_free(wdev->wiphy); | ||
1537 | kfree(wdev); | ||
1538 | } | ||
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h new file mode 100644 index 000000000000..a84adc249c61 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h | |||
@@ -0,0 +1,39 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011 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 | #ifndef ATH6KL_CFG80211_H | ||
18 | #define ATH6KL_CFG80211_H | ||
19 | |||
20 | struct wireless_dev *ath6kl_cfg80211_init(struct device *dev); | ||
21 | void ath6kl_cfg80211_deinit(struct ath6kl *ar); | ||
22 | |||
23 | void ath6kl_cfg80211_scan_complete_event(struct ath6kl *ar, int status); | ||
24 | |||
25 | void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel, | ||
26 | u8 *bssid, u16 listen_intvl, | ||
27 | u16 beacon_intvl, | ||
28 | enum network_type nw_type, | ||
29 | u8 beacon_ie_len, u8 assoc_req_len, | ||
30 | u8 assoc_resp_len, u8 *assoc_info); | ||
31 | |||
32 | void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason, | ||
33 | u8 *bssid, u8 assoc_resp_len, | ||
34 | u8 *assoc_info, u16 proto_reason); | ||
35 | |||
36 | void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl *ar, u8 keyid, | ||
37 | bool ismcast); | ||
38 | |||
39 | #endif /* ATH6KL_CFG80211_H */ | ||
diff --git a/drivers/net/wireless/ath/ath6kl/common.h b/drivers/net/wireless/ath/ath6kl/common.h new file mode 100644 index 000000000000..6b0d45642fe3 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/common.h | |||
@@ -0,0 +1,180 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010-2011 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 | #ifndef COMMON_H | ||
18 | #define COMMON_H | ||
19 | |||
20 | #include <linux/netdevice.h> | ||
21 | |||
22 | #define ATH6KL_MAX_IE 256 | ||
23 | |||
24 | extern int ath6kl_printk(const char *level, const char *fmt, ...); | ||
25 | |||
26 | #define A_CACHE_LINE_PAD 128 | ||
27 | |||
28 | /* | ||
29 | * Reflects the version of binary interface exposed by ATH6KL target | ||
30 | * firmware. Needs to be incremented by 1 for any change in the firmware | ||
31 | * that requires upgrade of the driver on the host side for the change to | ||
32 | * work correctly | ||
33 | */ | ||
34 | #define ATH6KL_ABI_VERSION 1 | ||
35 | |||
36 | #define SIGNAL_QUALITY_METRICS_NUM_MAX 2 | ||
37 | |||
38 | enum { | ||
39 | SIGNAL_QUALITY_METRICS_SNR = 0, | ||
40 | SIGNAL_QUALITY_METRICS_RSSI, | ||
41 | SIGNAL_QUALITY_METRICS_ALL, | ||
42 | }; | ||
43 | |||
44 | /* | ||
45 | * Data Path | ||
46 | */ | ||
47 | |||
48 | #define WMI_MAX_TX_DATA_FRAME_LENGTH \ | ||
49 | (1500 + sizeof(struct wmi_data_hdr) + \ | ||
50 | sizeof(struct ethhdr) + \ | ||
51 | sizeof(struct ath6kl_llc_snap_hdr)) | ||
52 | |||
53 | /* An AMSDU frame */ /* The MAX AMSDU length of AR6003 is 3839 */ | ||
54 | #define WMI_MAX_AMSDU_RX_DATA_FRAME_LENGTH \ | ||
55 | (3840 + sizeof(struct wmi_data_hdr) + \ | ||
56 | sizeof(struct ethhdr) + \ | ||
57 | sizeof(struct ath6kl_llc_snap_hdr)) | ||
58 | |||
59 | #define EPPING_ALIGNMENT_PAD \ | ||
60 | (((sizeof(struct htc_frame_hdr) + 3) & (~0x3)) \ | ||
61 | - sizeof(struct htc_frame_hdr)) | ||
62 | |||
63 | struct ath6kl_llc_snap_hdr { | ||
64 | u8 dsap; | ||
65 | u8 ssap; | ||
66 | u8 cntl; | ||
67 | u8 org_code[3]; | ||
68 | __be16 eth_type; | ||
69 | } __packed; | ||
70 | |||
71 | enum crypto_type { | ||
72 | NONE_CRYPT = 0x01, | ||
73 | WEP_CRYPT = 0x02, | ||
74 | TKIP_CRYPT = 0x04, | ||
75 | AES_CRYPT = 0x08, | ||
76 | }; | ||
77 | |||
78 | #define ATH6KL_NODE_HASHSIZE 32 | ||
79 | /* simple hash is enough for variation of macaddr */ | ||
80 | #define ATH6KL_NODE_HASH(addr) \ | ||
81 | (((const u8 *)(addr))[ETH_ALEN - 1] % \ | ||
82 | ATH6KL_NODE_HASHSIZE) | ||
83 | |||
84 | /* | ||
85 | * Table of ath6kl_node instances. Each ieee80211com | ||
86 | * has at least one for holding the scan candidates. | ||
87 | * When operating as an access point or in ibss mode there | ||
88 | * is a second table for associated stations or neighbors. | ||
89 | */ | ||
90 | struct ath6kl_node_table { | ||
91 | spinlock_t nt_nodelock; /* on node table */ | ||
92 | struct bss *nt_node_first; /* information of all nodes */ | ||
93 | struct bss *nt_node_last; /* information of all nodes */ | ||
94 | struct bss *nt_hash[ATH6KL_NODE_HASHSIZE]; | ||
95 | const char *nt_name; /* for debugging */ | ||
96 | u32 nt_node_age; /* node aging time */ | ||
97 | }; | ||
98 | |||
99 | #define WLAN_NODE_INACT_TIMEOUT_MSEC 120000 | ||
100 | #define WLAN_NODE_INACT_CNT 4 | ||
101 | |||
102 | struct ath6kl_common_ie { | ||
103 | u16 ie_chan; | ||
104 | u8 *ie_tstamp; | ||
105 | u8 *ie_ssid; | ||
106 | u8 *ie_rates; | ||
107 | u8 *ie_xrates; | ||
108 | u8 *ie_country; | ||
109 | u8 *ie_wpa; | ||
110 | u8 *ie_rsn; | ||
111 | u8 *ie_wmm; | ||
112 | u8 *ie_ath; | ||
113 | u16 ie_capInfo; | ||
114 | u16 ie_beaconInt; | ||
115 | u8 *ie_tim; | ||
116 | u8 *ie_chswitch; | ||
117 | u8 ie_erp; | ||
118 | u8 *ie_wsc; | ||
119 | u8 *ie_htcap; | ||
120 | u8 *ie_htop; | ||
121 | }; | ||
122 | |||
123 | struct bss { | ||
124 | u8 ni_macaddr[ETH_ALEN]; | ||
125 | u8 ni_snr; | ||
126 | s16 ni_rssi; | ||
127 | struct bss *ni_list_next; | ||
128 | struct bss *ni_list_prev; | ||
129 | struct bss *ni_hash_next; | ||
130 | struct bss *ni_hash_prev; | ||
131 | struct ath6kl_common_ie ni_cie; | ||
132 | u8 *ni_buf; | ||
133 | u16 ni_framelen; | ||
134 | struct ath6kl_node_table *ni_table; | ||
135 | u32 ni_refcnt; | ||
136 | |||
137 | u32 ni_tstamp; | ||
138 | u32 ni_actcnt; | ||
139 | }; | ||
140 | |||
141 | struct htc_endpoint_credit_dist; | ||
142 | struct ath6kl; | ||
143 | enum htc_credit_dist_reason; | ||
144 | struct htc_credit_state_info; | ||
145 | |||
146 | struct bss *wlan_node_alloc(int wh_size); | ||
147 | void wlan_node_free(struct bss *ni); | ||
148 | void wlan_setup_node(struct ath6kl_node_table *nt, struct bss *ni, | ||
149 | const u8 *mac_addr); | ||
150 | struct bss *wlan_find_node(struct ath6kl_node_table *nt, | ||
151 | const u8 *mac_addr); | ||
152 | void wlan_node_reclaim(struct ath6kl_node_table *nt, struct bss *ni); | ||
153 | void wlan_free_allnodes(struct ath6kl_node_table *nt); | ||
154 | void wlan_iterate_nodes(struct ath6kl_node_table *nt, void *arg); | ||
155 | |||
156 | void wlan_node_table_init(struct ath6kl_node_table *nt); | ||
157 | void wlan_node_table_cleanup(struct ath6kl_node_table *nt); | ||
158 | |||
159 | void wlan_refresh_inactive_nodes(struct ath6kl *ar); | ||
160 | |||
161 | struct bss *wlan_find_ssid_node(struct ath6kl_node_table *nt, u8 *ssid, | ||
162 | u32 ssid_len, bool is_wpa2, bool match_ssid); | ||
163 | |||
164 | void wlan_node_return(struct ath6kl_node_table *nt, struct bss *ni); | ||
165 | |||
166 | int ath6k_setup_credit_dist(void *htc_handle, | ||
167 | struct htc_credit_state_info *cred_info); | ||
168 | void ath6k_credit_distribute(struct htc_credit_state_info *cred_inf, | ||
169 | struct list_head *epdist_list, | ||
170 | enum htc_credit_dist_reason reason); | ||
171 | void ath6k_credit_init(struct htc_credit_state_info *cred_inf, | ||
172 | struct list_head *ep_list, | ||
173 | int tot_credits); | ||
174 | void ath6k_seek_credits(struct htc_credit_state_info *cred_inf, | ||
175 | struct htc_endpoint_credit_dist *ep_dist); | ||
176 | struct ath6kl *ath6kl_core_alloc(struct device *sdev); | ||
177 | int ath6kl_core_init(struct ath6kl *ar); | ||
178 | int ath6kl_unavail_ev(struct ath6kl *ar); | ||
179 | struct sk_buff *ath6kl_buf_alloc(int size); | ||
180 | #endif /* COMMON_H */ | ||
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h new file mode 100644 index 000000000000..74170229523f --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/core.h | |||
@@ -0,0 +1,544 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010-2011 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 | #ifndef CORE_H | ||
18 | #define CORE_H | ||
19 | |||
20 | #include <linux/etherdevice.h> | ||
21 | #include <linux/rtnetlink.h> | ||
22 | #include <linux/firmware.h> | ||
23 | #include <linux/sched.h> | ||
24 | #include <net/cfg80211.h> | ||
25 | #include "htc.h" | ||
26 | #include "wmi.h" | ||
27 | #include "bmi.h" | ||
28 | |||
29 | #define MAX_ATH6KL 1 | ||
30 | #define ATH6KL_MAX_RX_BUFFERS 16 | ||
31 | #define ATH6KL_BUFFER_SIZE 1664 | ||
32 | #define ATH6KL_MAX_AMSDU_RX_BUFFERS 4 | ||
33 | #define ATH6KL_AMSDU_REFILL_THRESHOLD 3 | ||
34 | #define ATH6KL_AMSDU_BUFFER_SIZE (WMI_MAX_AMSDU_RX_DATA_FRAME_LENGTH + 128) | ||
35 | #define MAX_MSDU_SUBFRAME_PAYLOAD_LEN 1508 | ||
36 | #define MIN_MSDU_SUBFRAME_PAYLOAD_LEN 46 | ||
37 | |||
38 | #define USER_SAVEDKEYS_STAT_INIT 0 | ||
39 | #define USER_SAVEDKEYS_STAT_RUN 1 | ||
40 | |||
41 | #define ATH6KL_TX_TIMEOUT 10 | ||
42 | #define ATH6KL_MAX_ENDPOINTS 4 | ||
43 | #define MAX_NODE_NUM 15 | ||
44 | |||
45 | /* MAX_HI_COOKIE_NUM are reserved for high priority traffic */ | ||
46 | #define MAX_DEF_COOKIE_NUM 180 | ||
47 | #define MAX_HI_COOKIE_NUM 18 /* 10% of MAX_COOKIE_NUM */ | ||
48 | #define MAX_COOKIE_NUM (MAX_DEF_COOKIE_NUM + MAX_HI_COOKIE_NUM) | ||
49 | |||
50 | #define MAX_DEFAULT_SEND_QUEUE_DEPTH (MAX_DEF_COOKIE_NUM / WMM_NUM_AC) | ||
51 | |||
52 | #define DISCON_TIMER_INTVAL 10000 /* in msec */ | ||
53 | #define A_DEFAULT_LISTEN_INTERVAL 100 | ||
54 | #define A_MAX_WOW_LISTEN_INTERVAL 1000 | ||
55 | |||
56 | /* AR6003 1.0 definitions */ | ||
57 | #define AR6003_REV1_VERSION 0x300002ba | ||
58 | |||
59 | /* AR6003 2.0 definitions */ | ||
60 | #define AR6003_REV2_VERSION 0x30000384 | ||
61 | #define AR6003_REV2_PATCH_DOWNLOAD_ADDRESS 0x57e910 | ||
62 | #define AR6003_REV2_OTP_FILE "ath6k/AR6003/hw2.0/otp.bin.z77" | ||
63 | #define AR6003_REV2_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athwlan.bin.z77" | ||
64 | #define AR6003_REV2_PATCH_FILE "ath6k/AR6003/hw2.0/data.patch.bin" | ||
65 | #define AR6003_REV2_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.bin" | ||
66 | #define AR6003_REV2_DEFAULT_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.SD31.bin" | ||
67 | |||
68 | /* AR6003 3.0 definitions */ | ||
69 | #define AR6003_REV3_VERSION 0x30000582 | ||
70 | #define AR6003_REV3_OTP_FILE "ath6k/AR6003/hw2.1.1/otp.bin" | ||
71 | #define AR6003_REV3_FIRMWARE_FILE "ath6k/AR6003/hw2.1.1/athwlan.bin" | ||
72 | #define AR6003_REV3_PATCH_FILE "ath6k/AR6003/hw2.1.1/data.patch.bin" | ||
73 | #define AR6003_REV3_BOARD_DATA_FILE "ath6k/AR6003/hw2.1.1/bdata.bin" | ||
74 | #define AR6003_REV3_DEFAULT_BOARD_DATA_FILE \ | ||
75 | "ath6k/AR6003/hw2.1.1/bdata.SD31.bin" | ||
76 | |||
77 | /* Per STA data, used in AP mode */ | ||
78 | #define STA_PS_AWAKE BIT(0) | ||
79 | #define STA_PS_SLEEP BIT(1) | ||
80 | #define STA_PS_POLLED BIT(2) | ||
81 | |||
82 | /* HTC TX packet tagging definitions */ | ||
83 | #define ATH6KL_CONTROL_PKT_TAG HTC_TX_PACKET_TAG_USER_DEFINED | ||
84 | #define ATH6KL_DATA_PKT_TAG (ATH6KL_CONTROL_PKT_TAG + 1) | ||
85 | |||
86 | #define AR6003_CUST_DATA_SIZE 16 | ||
87 | |||
88 | #define AGGR_WIN_IDX(x, y) ((x) % (y)) | ||
89 | #define AGGR_INCR_IDX(x, y) AGGR_WIN_IDX(((x) + 1), (y)) | ||
90 | #define AGGR_DCRM_IDX(x, y) AGGR_WIN_IDX(((x) - 1), (y)) | ||
91 | #define ATH6KL_MAX_SEQ_NO 0xFFF | ||
92 | #define ATH6KL_NEXT_SEQ_NO(x) (((x) + 1) & ATH6KL_MAX_SEQ_NO) | ||
93 | |||
94 | #define NUM_OF_TIDS 8 | ||
95 | #define AGGR_SZ_DEFAULT 8 | ||
96 | |||
97 | #define AGGR_WIN_SZ_MIN 2 | ||
98 | #define AGGR_WIN_SZ_MAX 8 | ||
99 | |||
100 | #define TID_WINDOW_SZ(_x) ((_x) << 1) | ||
101 | |||
102 | #define AGGR_NUM_OF_FREE_NETBUFS 16 | ||
103 | |||
104 | #define AGGR_RX_TIMEOUT 400 /* in ms */ | ||
105 | |||
106 | #define WMI_TIMEOUT (2 * HZ) | ||
107 | |||
108 | #define MBOX_YIELD_LIMIT 99 | ||
109 | |||
110 | /* configuration lags */ | ||
111 | /* | ||
112 | * ATH6KL_CONF_IGNORE_ERP_BARKER: Ignore the barker premable in | ||
113 | * ERP IE of beacon to determine the short premable support when | ||
114 | * sending (Re)Assoc req. | ||
115 | * ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN: Don't send the power | ||
116 | * module state transition failure events which happen during | ||
117 | * scan, to the host. | ||
118 | */ | ||
119 | #define ATH6KL_CONF_IGNORE_ERP_BARKER BIT(0) | ||
120 | #define ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN BIT(1) | ||
121 | #define ATH6KL_CONF_ENABLE_11N BIT(2) | ||
122 | #define ATH6KL_CONF_ENABLE_TX_BURST BIT(3) | ||
123 | |||
124 | enum wlan_low_pwr_state { | ||
125 | WLAN_POWER_STATE_ON, | ||
126 | WLAN_POWER_STATE_CUT_PWR, | ||
127 | WLAN_POWER_STATE_DEEP_SLEEP, | ||
128 | WLAN_POWER_STATE_WOW | ||
129 | }; | ||
130 | |||
131 | enum sme_state { | ||
132 | SME_DISCONNECTED, | ||
133 | SME_CONNECTING, | ||
134 | SME_CONNECTED | ||
135 | }; | ||
136 | |||
137 | struct skb_hold_q { | ||
138 | struct sk_buff *skb; | ||
139 | bool is_amsdu; | ||
140 | u16 seq_no; | ||
141 | }; | ||
142 | |||
143 | struct rxtid { | ||
144 | bool aggr; | ||
145 | bool progress; | ||
146 | bool timer_mon; | ||
147 | u16 win_sz; | ||
148 | u16 seq_next; | ||
149 | u32 hold_q_sz; | ||
150 | struct skb_hold_q *hold_q; | ||
151 | struct sk_buff_head q; | ||
152 | spinlock_t lock; | ||
153 | }; | ||
154 | |||
155 | struct rxtid_stats { | ||
156 | u32 num_into_aggr; | ||
157 | u32 num_dups; | ||
158 | u32 num_oow; | ||
159 | u32 num_mpdu; | ||
160 | u32 num_amsdu; | ||
161 | u32 num_delivered; | ||
162 | u32 num_timeouts; | ||
163 | u32 num_hole; | ||
164 | u32 num_bar; | ||
165 | }; | ||
166 | |||
167 | struct aggr_info { | ||
168 | u8 aggr_sz; | ||
169 | u8 timer_scheduled; | ||
170 | struct timer_list timer; | ||
171 | struct net_device *dev; | ||
172 | struct rxtid rx_tid[NUM_OF_TIDS]; | ||
173 | struct sk_buff_head free_q; | ||
174 | struct rxtid_stats stat[NUM_OF_TIDS]; | ||
175 | }; | ||
176 | |||
177 | struct ath6kl_wep_key { | ||
178 | u8 key_index; | ||
179 | u8 key_len; | ||
180 | u8 key[64]; | ||
181 | }; | ||
182 | |||
183 | #define ATH6KL_KEY_SEQ_LEN 8 | ||
184 | |||
185 | struct ath6kl_key { | ||
186 | u8 key[WLAN_MAX_KEY_LEN]; | ||
187 | u8 key_len; | ||
188 | u8 seq[ATH6KL_KEY_SEQ_LEN]; | ||
189 | u8 seq_len; | ||
190 | u32 cipher; | ||
191 | }; | ||
192 | |||
193 | struct ath6kl_node_mapping { | ||
194 | u8 mac_addr[ETH_ALEN]; | ||
195 | u8 ep_id; | ||
196 | u8 tx_pend; | ||
197 | }; | ||
198 | |||
199 | struct ath6kl_cookie { | ||
200 | struct sk_buff *skb; | ||
201 | u32 map_no; | ||
202 | struct htc_packet htc_pkt; | ||
203 | struct ath6kl_cookie *arc_list_next; | ||
204 | }; | ||
205 | |||
206 | struct ath6kl_sta { | ||
207 | u16 sta_flags; | ||
208 | u8 mac[ETH_ALEN]; | ||
209 | u8 aid; | ||
210 | u8 keymgmt; | ||
211 | u8 ucipher; | ||
212 | u8 auth; | ||
213 | u8 wpa_ie[ATH6KL_MAX_IE]; | ||
214 | struct sk_buff_head psq; | ||
215 | spinlock_t psq_lock; | ||
216 | }; | ||
217 | |||
218 | struct ath6kl_version { | ||
219 | u32 target_ver; | ||
220 | u32 wlan_ver; | ||
221 | u32 abi_ver; | ||
222 | }; | ||
223 | |||
224 | struct ath6kl_bmi { | ||
225 | u32 cmd_credits; | ||
226 | bool done_sent; | ||
227 | u8 *cmd_buf; | ||
228 | }; | ||
229 | |||
230 | struct target_stats { | ||
231 | u64 tx_pkt; | ||
232 | u64 tx_byte; | ||
233 | u64 tx_ucast_pkt; | ||
234 | u64 tx_ucast_byte; | ||
235 | u64 tx_mcast_pkt; | ||
236 | u64 tx_mcast_byte; | ||
237 | u64 tx_bcast_pkt; | ||
238 | u64 tx_bcast_byte; | ||
239 | u64 tx_rts_success_cnt; | ||
240 | u64 tx_pkt_per_ac[4]; | ||
241 | |||
242 | u64 tx_err; | ||
243 | u64 tx_fail_cnt; | ||
244 | u64 tx_retry_cnt; | ||
245 | u64 tx_mult_retry_cnt; | ||
246 | u64 tx_rts_fail_cnt; | ||
247 | |||
248 | u64 rx_pkt; | ||
249 | u64 rx_byte; | ||
250 | u64 rx_ucast_pkt; | ||
251 | u64 rx_ucast_byte; | ||
252 | u64 rx_mcast_pkt; | ||
253 | u64 rx_mcast_byte; | ||
254 | u64 rx_bcast_pkt; | ||
255 | u64 rx_bcast_byte; | ||
256 | u64 rx_frgment_pkt; | ||
257 | |||
258 | u64 rx_err; | ||
259 | u64 rx_crc_err; | ||
260 | u64 rx_key_cache_miss; | ||
261 | u64 rx_decrypt_err; | ||
262 | u64 rx_dupl_frame; | ||
263 | |||
264 | u64 tkip_local_mic_fail; | ||
265 | u64 tkip_cnter_measures_invoked; | ||
266 | u64 tkip_replays; | ||
267 | u64 tkip_fmt_err; | ||
268 | u64 ccmp_fmt_err; | ||
269 | u64 ccmp_replays; | ||
270 | |||
271 | u64 pwr_save_fail_cnt; | ||
272 | |||
273 | u64 cs_bmiss_cnt; | ||
274 | u64 cs_low_rssi_cnt; | ||
275 | u64 cs_connect_cnt; | ||
276 | u64 cs_discon_cnt; | ||
277 | |||
278 | s32 tx_ucast_rate; | ||
279 | s32 rx_ucast_rate; | ||
280 | |||
281 | u32 lq_val; | ||
282 | |||
283 | u32 wow_pkt_dropped; | ||
284 | u16 wow_evt_discarded; | ||
285 | |||
286 | s16 noise_floor_calib; | ||
287 | s16 cs_rssi; | ||
288 | s16 cs_ave_beacon_rssi; | ||
289 | u8 cs_ave_beacon_snr; | ||
290 | u8 cs_last_roam_msec; | ||
291 | u8 cs_snr; | ||
292 | |||
293 | u8 wow_host_pkt_wakeups; | ||
294 | u8 wow_host_evt_wakeups; | ||
295 | |||
296 | u32 arp_received; | ||
297 | u32 arp_matched; | ||
298 | u32 arp_replied; | ||
299 | }; | ||
300 | |||
301 | struct ath6kl_mbox_info { | ||
302 | u32 htc_addr; | ||
303 | u32 htc_ext_addr; | ||
304 | u32 htc_ext_sz; | ||
305 | |||
306 | u32 block_size; | ||
307 | |||
308 | u32 gmbox_addr; | ||
309 | |||
310 | u32 gmbox_sz; | ||
311 | }; | ||
312 | |||
313 | /* | ||
314 | * 802.11i defines an extended IV for use with non-WEP ciphers. | ||
315 | * When the EXTIV bit is set in the key id byte an additional | ||
316 | * 4 bytes immediately follow the IV for TKIP. For CCMP the | ||
317 | * EXTIV bit is likewise set but the 8 bytes represent the | ||
318 | * CCMP header rather than IV+extended-IV. | ||
319 | */ | ||
320 | |||
321 | #define ATH6KL_KEYBUF_SIZE 16 | ||
322 | #define ATH6KL_MICBUF_SIZE (8+8) /* space for both tx and rx */ | ||
323 | |||
324 | #define ATH6KL_KEY_XMIT 0x01 | ||
325 | #define ATH6KL_KEY_RECV 0x02 | ||
326 | #define ATH6KL_KEY_DEFAULT 0x80 /* default xmit key */ | ||
327 | |||
328 | /* | ||
329 | * WPA/RSN get/set key request. Specify the key/cipher | ||
330 | * type and whether the key is to be used for sending and/or | ||
331 | * receiving. The key index should be set only when working | ||
332 | * with global keys (use IEEE80211_KEYIX_NONE for ``no index''). | ||
333 | * Otherwise a unicast/pairwise key is specified by the bssid | ||
334 | * (on a station) or mac address (on an ap). They key length | ||
335 | * must include any MIC key data; otherwise it should be no | ||
336 | * more than ATH6KL_KEYBUF_SIZE. | ||
337 | */ | ||
338 | struct ath6kl_req_key { | ||
339 | u8 ik_type; /* key/cipher type */ | ||
340 | u8 ik_pad; | ||
341 | u16 ik_keyix; /* key index */ | ||
342 | u8 ik_keylen; /* key length in bytes */ | ||
343 | u8 ik_flags; | ||
344 | u8 ik_macaddr[ETH_ALEN]; | ||
345 | u64 ik_keyrsc; /* key receive sequence counter */ | ||
346 | u64 ik_keytsc; /* key transmit sequence counter */ | ||
347 | u8 ik_keydata[ATH6KL_KEYBUF_SIZE + ATH6KL_MICBUF_SIZE]; | ||
348 | }; | ||
349 | |||
350 | /* Flag info */ | ||
351 | #define WMI_ENABLED 0 | ||
352 | #define WMI_READY 1 | ||
353 | #define CONNECTED 2 | ||
354 | #define STATS_UPDATE_PEND 3 | ||
355 | #define CONNECT_PEND 4 | ||
356 | #define WMM_ENABLED 5 | ||
357 | #define NETQ_STOPPED 6 | ||
358 | #define WMI_CTRL_EP_FULL 7 | ||
359 | #define DTIM_EXPIRED 8 | ||
360 | #define DESTROY_IN_PROGRESS 9 | ||
361 | #define NETDEV_REGISTERED 10 | ||
362 | #define SKIP_SCAN 11 | ||
363 | #define WLAN_ENABLED 12 | ||
364 | |||
365 | struct ath6kl { | ||
366 | struct device *dev; | ||
367 | struct net_device *net_dev; | ||
368 | struct ath6kl_bmi bmi; | ||
369 | const struct ath6kl_hif_ops *hif_ops; | ||
370 | struct wmi *wmi; | ||
371 | int tx_pending[ENDPOINT_MAX]; | ||
372 | int total_tx_data_pend; | ||
373 | struct htc_target *htc_target; | ||
374 | void *hif_priv; | ||
375 | spinlock_t lock; | ||
376 | struct semaphore sem; | ||
377 | int ssid_len; | ||
378 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
379 | u8 next_mode; | ||
380 | u8 nw_type; | ||
381 | u8 dot11_auth_mode; | ||
382 | u8 auth_mode; | ||
383 | u8 prwise_crypto; | ||
384 | u8 prwise_crypto_len; | ||
385 | u8 grp_crypto; | ||
386 | u8 grp_crpto_len; | ||
387 | u8 def_txkey_index; | ||
388 | struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1]; | ||
389 | u8 bssid[ETH_ALEN]; | ||
390 | u8 req_bssid[ETH_ALEN]; | ||
391 | u16 ch_hint; | ||
392 | u16 bss_ch; | ||
393 | u16 listen_intvl_b; | ||
394 | u16 listen_intvl_t; | ||
395 | struct ath6kl_version version; | ||
396 | u32 target_type; | ||
397 | u8 tx_pwr; | ||
398 | struct net_device_stats net_stats; | ||
399 | struct target_stats target_stats; | ||
400 | struct ath6kl_node_mapping node_map[MAX_NODE_NUM]; | ||
401 | u8 ibss_ps_enable; | ||
402 | u8 node_num; | ||
403 | u8 next_ep_id; | ||
404 | struct ath6kl_cookie *cookie_list; | ||
405 | u32 cookie_count; | ||
406 | enum htc_endpoint_id ac2ep_map[WMM_NUM_AC]; | ||
407 | bool ac_stream_active[WMM_NUM_AC]; | ||
408 | u8 ac_stream_pri_map[WMM_NUM_AC]; | ||
409 | u8 hiac_stream_active_pri; | ||
410 | u8 ep2ac_map[ENDPOINT_MAX]; | ||
411 | enum htc_endpoint_id ctrl_ep; | ||
412 | struct htc_credit_state_info credit_state_info; | ||
413 | u32 connect_ctrl_flags; | ||
414 | u32 user_key_ctrl; | ||
415 | u8 usr_bss_filter; | ||
416 | struct ath6kl_sta sta_list[AP_MAX_NUM_STA]; | ||
417 | u8 sta_list_index; | ||
418 | struct ath6kl_req_key ap_mode_bkey; | ||
419 | struct sk_buff_head mcastpsq; | ||
420 | spinlock_t mcastpsq_lock; | ||
421 | u8 intra_bss; | ||
422 | struct aggr_info *aggr_cntxt; | ||
423 | struct wmi_ap_mode_stat ap_stats; | ||
424 | u8 ap_country_code[3]; | ||
425 | struct list_head amsdu_rx_buffer_queue; | ||
426 | struct timer_list disconnect_timer; | ||
427 | u8 rx_meta_ver; | ||
428 | struct wireless_dev *wdev; | ||
429 | struct cfg80211_scan_request *scan_req; | ||
430 | struct ath6kl_key keys[WMI_MAX_KEY_INDEX + 1]; | ||
431 | enum sme_state sme_state; | ||
432 | enum wlan_low_pwr_state wlan_pwr_state; | ||
433 | struct wmi_scan_params_cmd sc_params; | ||
434 | #define AR_MCAST_FILTER_MAC_ADDR_SIZE 4 | ||
435 | u8 auto_auth_stage; | ||
436 | |||
437 | u16 conf_flags; | ||
438 | wait_queue_head_t event_wq; | ||
439 | struct ath6kl_mbox_info mbox_info; | ||
440 | |||
441 | struct ath6kl_cookie cookie_mem[MAX_COOKIE_NUM]; | ||
442 | int reconnect_flag; | ||
443 | unsigned long flag; | ||
444 | |||
445 | u8 *fw_board; | ||
446 | size_t fw_board_len; | ||
447 | |||
448 | u8 *fw_otp; | ||
449 | size_t fw_otp_len; | ||
450 | |||
451 | u8 *fw; | ||
452 | size_t fw_len; | ||
453 | |||
454 | u8 *fw_patch; | ||
455 | size_t fw_patch_len; | ||
456 | |||
457 | struct workqueue_struct *ath6kl_wq; | ||
458 | |||
459 | struct ath6kl_node_table scan_table; | ||
460 | }; | ||
461 | |||
462 | static inline void *ath6kl_priv(struct net_device *dev) | ||
463 | { | ||
464 | return wdev_priv(dev->ieee80211_ptr); | ||
465 | } | ||
466 | |||
467 | static inline void ath6kl_deposit_credit_to_ep(struct htc_credit_state_info | ||
468 | *cred_info, | ||
469 | struct htc_endpoint_credit_dist | ||
470 | *ep_dist, int credits) | ||
471 | { | ||
472 | ep_dist->credits += credits; | ||
473 | ep_dist->cred_assngd += credits; | ||
474 | cred_info->cur_free_credits -= credits; | ||
475 | } | ||
476 | |||
477 | void ath6kl_destroy(struct net_device *dev, unsigned int unregister); | ||
478 | int ath6kl_configure_target(struct ath6kl *ar); | ||
479 | void ath6kl_detect_error(unsigned long ptr); | ||
480 | void disconnect_timer_handler(unsigned long ptr); | ||
481 | void init_netdev(struct net_device *dev); | ||
482 | void ath6kl_cookie_init(struct ath6kl *ar); | ||
483 | void ath6kl_cookie_cleanup(struct ath6kl *ar); | ||
484 | void ath6kl_rx(struct htc_target *target, struct htc_packet *packet); | ||
485 | void ath6kl_tx_complete(void *context, struct list_head *packet_queue); | ||
486 | enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target, | ||
487 | struct htc_packet *packet); | ||
488 | void ath6kl_stop_txrx(struct ath6kl *ar); | ||
489 | void ath6kl_cleanup_amsdu_rxbufs(struct ath6kl *ar); | ||
490 | int ath6kl_access_datadiag(struct ath6kl *ar, u32 address, | ||
491 | u8 *data, u32 length, bool read); | ||
492 | int ath6kl_read_reg_diag(struct ath6kl *ar, u32 *address, u32 *data); | ||
493 | void ath6kl_init_profile_info(struct ath6kl *ar); | ||
494 | void ath6kl_tx_data_cleanup(struct ath6kl *ar); | ||
495 | void ath6kl_stop_endpoint(struct net_device *dev, bool keep_profile, | ||
496 | bool get_dbglogs); | ||
497 | |||
498 | struct ath6kl_cookie *ath6kl_alloc_cookie(struct ath6kl *ar); | ||
499 | void ath6kl_free_cookie(struct ath6kl *ar, struct ath6kl_cookie *cookie); | ||
500 | int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev); | ||
501 | |||
502 | struct aggr_info *aggr_init(struct net_device *dev); | ||
503 | void ath6kl_rx_refill(struct htc_target *target, | ||
504 | enum htc_endpoint_id endpoint); | ||
505 | void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count); | ||
506 | struct htc_packet *ath6kl_alloc_amsdu_rxbuf(struct htc_target *target, | ||
507 | enum htc_endpoint_id endpoint, | ||
508 | int len); | ||
509 | void aggr_module_destroy(struct aggr_info *aggr_info); | ||
510 | void aggr_reset_state(struct aggr_info *aggr_info); | ||
511 | |||
512 | struct ath6kl_sta *ath6kl_find_sta(struct ath6kl *ar, u8 * node_addr); | ||
513 | struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid); | ||
514 | |||
515 | void ath6kl_ready_event(void *devt, u8 * datap, u32 sw_ver, u32 abi_ver); | ||
516 | int ath6kl_control_tx(void *devt, struct sk_buff *skb, | ||
517 | enum htc_endpoint_id eid); | ||
518 | void ath6kl_connect_event(struct ath6kl *ar, u16 channel, | ||
519 | u8 *bssid, u16 listen_int, | ||
520 | u16 beacon_int, enum network_type net_type, | ||
521 | u8 beacon_ie_len, u8 assoc_req_len, | ||
522 | u8 assoc_resp_len, u8 *assoc_info); | ||
523 | void ath6kl_disconnect_event(struct ath6kl *ar, u8 reason, | ||
524 | u8 *bssid, u8 assoc_resp_len, | ||
525 | u8 *assoc_info, u16 prot_reason_status); | ||
526 | void ath6kl_tkip_micerr_event(struct ath6kl *ar, u8 keyid, bool ismcast); | ||
527 | void ath6kl_txpwr_rx_evt(void *devt, u8 tx_pwr); | ||
528 | void ath6kl_scan_complete_evt(struct ath6kl *ar, int status); | ||
529 | void ath6kl_tgt_stats_event(struct ath6kl *ar, u8 *ptr, u32 len); | ||
530 | void ath6kl_indicate_tx_activity(void *devt, u8 traffic_class, bool active); | ||
531 | enum htc_endpoint_id ath6kl_ac2_endpoint_id(void *devt, u8 ac); | ||
532 | |||
533 | void ath6kl_pspoll_event(struct ath6kl *ar, u8 aid); | ||
534 | |||
535 | void ath6kl_dtimexpiry_event(struct ath6kl *ar); | ||
536 | void ath6kl_disconnect(struct ath6kl *ar); | ||
537 | void aggr_recv_delba_req_evt(struct ath6kl *ar, u8 tid); | ||
538 | void aggr_recv_addba_req_evt(struct ath6kl *ar, u8 tid, u16 seq_no, | ||
539 | u8 win_sz); | ||
540 | void ath6kl_wakeup_event(void *dev); | ||
541 | void ath6kl_target_failure(struct ath6kl *ar); | ||
542 | |||
543 | void ath6kl_cfg80211_scan_node(struct wiphy *wiphy, struct bss *ni); | ||
544 | #endif /* CORE_H */ | ||
diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c new file mode 100644 index 000000000000..316136c8b903 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/debug.c | |||
@@ -0,0 +1,150 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004-2011 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 "core.h" | ||
18 | #include "debug.h" | ||
19 | |||
20 | int ath6kl_printk(const char *level, const char *fmt, ...) | ||
21 | { | ||
22 | struct va_format vaf; | ||
23 | va_list args; | ||
24 | int rtn; | ||
25 | |||
26 | va_start(args, fmt); | ||
27 | |||
28 | vaf.fmt = fmt; | ||
29 | vaf.va = &args; | ||
30 | |||
31 | rtn = printk("%sath6kl: %pV", level, &vaf); | ||
32 | |||
33 | va_end(args); | ||
34 | |||
35 | return rtn; | ||
36 | } | ||
37 | |||
38 | #ifdef CONFIG_ATH6KL_DEBUG | ||
39 | void ath6kl_dump_registers(struct ath6kl_device *dev, | ||
40 | struct ath6kl_irq_proc_registers *irq_proc_reg, | ||
41 | struct ath6kl_irq_enable_reg *irq_enable_reg) | ||
42 | { | ||
43 | |||
44 | ath6kl_dbg(ATH6KL_DBG_ANY, ("<------- Register Table -------->\n")); | ||
45 | |||
46 | if (irq_proc_reg != NULL) { | ||
47 | ath6kl_dbg(ATH6KL_DBG_ANY, | ||
48 | "Host Int status: 0x%x\n", | ||
49 | irq_proc_reg->host_int_status); | ||
50 | ath6kl_dbg(ATH6KL_DBG_ANY, | ||
51 | "CPU Int status: 0x%x\n", | ||
52 | irq_proc_reg->cpu_int_status); | ||
53 | ath6kl_dbg(ATH6KL_DBG_ANY, | ||
54 | "Error Int status: 0x%x\n", | ||
55 | irq_proc_reg->error_int_status); | ||
56 | ath6kl_dbg(ATH6KL_DBG_ANY, | ||
57 | "Counter Int status: 0x%x\n", | ||
58 | irq_proc_reg->counter_int_status); | ||
59 | ath6kl_dbg(ATH6KL_DBG_ANY, | ||
60 | "Mbox Frame: 0x%x\n", | ||
61 | irq_proc_reg->mbox_frame); | ||
62 | ath6kl_dbg(ATH6KL_DBG_ANY, | ||
63 | "Rx Lookahead Valid: 0x%x\n", | ||
64 | irq_proc_reg->rx_lkahd_valid); | ||
65 | ath6kl_dbg(ATH6KL_DBG_ANY, | ||
66 | "Rx Lookahead 0: 0x%x\n", | ||
67 | irq_proc_reg->rx_lkahd[0]); | ||
68 | ath6kl_dbg(ATH6KL_DBG_ANY, | ||
69 | "Rx Lookahead 1: 0x%x\n", | ||
70 | irq_proc_reg->rx_lkahd[1]); | ||
71 | |||
72 | if (dev->ar->mbox_info.gmbox_addr != 0) { | ||
73 | /* | ||
74 | * If the target supports GMBOX hardware, dump some | ||
75 | * additional state. | ||
76 | */ | ||
77 | ath6kl_dbg(ATH6KL_DBG_ANY, | ||
78 | "GMBOX Host Int status 2: 0x%x\n", | ||
79 | irq_proc_reg->host_int_status2); | ||
80 | ath6kl_dbg(ATH6KL_DBG_ANY, | ||
81 | "GMBOX RX Avail: 0x%x\n", | ||
82 | irq_proc_reg->gmbox_rx_avail); | ||
83 | ath6kl_dbg(ATH6KL_DBG_ANY, | ||
84 | "GMBOX lookahead alias 0: 0x%x\n", | ||
85 | irq_proc_reg->rx_gmbox_lkahd_alias[0]); | ||
86 | ath6kl_dbg(ATH6KL_DBG_ANY, | ||
87 | "GMBOX lookahead alias 1: 0x%x\n", | ||
88 | irq_proc_reg->rx_gmbox_lkahd_alias[1]); | ||
89 | } | ||
90 | |||
91 | } | ||
92 | |||
93 | if (irq_enable_reg != NULL) { | ||
94 | ath6kl_dbg(ATH6KL_DBG_ANY, | ||
95 | "Int status Enable: 0x%x\n", | ||
96 | irq_enable_reg->int_status_en); | ||
97 | ath6kl_dbg(ATH6KL_DBG_ANY, "Counter Int status Enable: 0x%x\n", | ||
98 | irq_enable_reg->cntr_int_status_en); | ||
99 | } | ||
100 | ath6kl_dbg(ATH6KL_DBG_ANY, "<------------------------------->\n"); | ||
101 | } | ||
102 | |||
103 | static void dump_cred_dist(struct htc_endpoint_credit_dist *ep_dist) | ||
104 | { | ||
105 | ath6kl_dbg(ATH6KL_DBG_ANY, | ||
106 | "--- endpoint: %d svc_id: 0x%X ---\n", | ||
107 | ep_dist->endpoint, ep_dist->svc_id); | ||
108 | ath6kl_dbg(ATH6KL_DBG_ANY, " dist_flags : 0x%X\n", | ||
109 | ep_dist->dist_flags); | ||
110 | ath6kl_dbg(ATH6KL_DBG_ANY, " cred_norm : %d\n", | ||
111 | ep_dist->cred_norm); | ||
112 | ath6kl_dbg(ATH6KL_DBG_ANY, " cred_min : %d\n", | ||
113 | ep_dist->cred_min); | ||
114 | ath6kl_dbg(ATH6KL_DBG_ANY, " credits : %d\n", | ||
115 | ep_dist->credits); | ||
116 | ath6kl_dbg(ATH6KL_DBG_ANY, " cred_assngd : %d\n", | ||
117 | ep_dist->cred_assngd); | ||
118 | ath6kl_dbg(ATH6KL_DBG_ANY, " seek_cred : %d\n", | ||
119 | ep_dist->seek_cred); | ||
120 | ath6kl_dbg(ATH6KL_DBG_ANY, " cred_sz : %d\n", | ||
121 | ep_dist->cred_sz); | ||
122 | ath6kl_dbg(ATH6KL_DBG_ANY, " cred_per_msg : %d\n", | ||
123 | ep_dist->cred_per_msg); | ||
124 | ath6kl_dbg(ATH6KL_DBG_ANY, " cred_to_dist : %d\n", | ||
125 | ep_dist->cred_to_dist); | ||
126 | ath6kl_dbg(ATH6KL_DBG_ANY, " txq_depth : %d\n", | ||
127 | get_queue_depth(&((struct htc_endpoint *) | ||
128 | ep_dist->htc_rsvd)->txq)); | ||
129 | ath6kl_dbg(ATH6KL_DBG_ANY, | ||
130 | "----------------------------------\n"); | ||
131 | } | ||
132 | |||
133 | void dump_cred_dist_stats(struct htc_target *target) | ||
134 | { | ||
135 | struct htc_endpoint_credit_dist *ep_list; | ||
136 | |||
137 | if (!AR_DBG_LVL_CHECK(ATH6KL_DBG_TRC)) | ||
138 | return; | ||
139 | |||
140 | list_for_each_entry(ep_list, &target->cred_dist_list, list) | ||
141 | dump_cred_dist(ep_list); | ||
142 | |||
143 | ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:%p dist:%p\n", | ||
144 | target->cred_dist_cntxt, NULL); | ||
145 | ath6kl_dbg(ATH6KL_DBG_TRC, "credit distribution, total : %d, free : %d\n", | ||
146 | target->cred_dist_cntxt->total_avail_credits, | ||
147 | target->cred_dist_cntxt->cur_free_credits); | ||
148 | } | ||
149 | |||
150 | #endif | ||
diff --git a/drivers/net/wireless/ath/ath6kl/debug.h b/drivers/net/wireless/ath/ath6kl/debug.h new file mode 100644 index 000000000000..66b399962f01 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/debug.h | |||
@@ -0,0 +1,105 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011 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 | #ifndef DEBUG_H | ||
18 | #define DEBUG_H | ||
19 | |||
20 | #include "htc_hif.h" | ||
21 | |||
22 | enum ATH6K_DEBUG_MASK { | ||
23 | ATH6KL_DBG_WLAN_CONNECT = BIT(0), /* wlan connect */ | ||
24 | ATH6KL_DBG_WLAN_SCAN = BIT(1), /* wlan scan */ | ||
25 | ATH6KL_DBG_WLAN_TX = BIT(2), /* wlan tx */ | ||
26 | ATH6KL_DBG_WLAN_RX = BIT(3), /* wlan rx */ | ||
27 | ATH6KL_DBG_BMI = BIT(4), /* bmi tracing */ | ||
28 | ATH6KL_DBG_HTC_SEND = BIT(5), /* htc send */ | ||
29 | ATH6KL_DBG_HTC_RECV = BIT(6), /* htc recv */ | ||
30 | ATH6KL_DBG_IRQ = BIT(7), /* interrupt processing */ | ||
31 | ATH6KL_DBG_PM = BIT(8), /* power management */ | ||
32 | ATH6KL_DBG_WLAN_NODE = BIT(9), /* general wlan node tracing */ | ||
33 | ATH6KL_DBG_WMI = BIT(10), /* wmi tracing */ | ||
34 | ATH6KL_DBG_TRC = BIT(11), /* generic func tracing */ | ||
35 | ATH6KL_DBG_SCATTER = BIT(12), /* hif scatter tracing */ | ||
36 | ATH6KL_DBG_WLAN_CFG = BIT(13), /* cfg80211 i/f file tracing */ | ||
37 | ATH6KL_DBG_RAW_BYTES = BIT(14), /* dump tx/rx and wmi frames */ | ||
38 | ATH6KL_DBG_AGGR = BIT(15), /* aggregation */ | ||
39 | ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */ | ||
40 | }; | ||
41 | |||
42 | extern unsigned int debug_mask; | ||
43 | extern int ath6kl_printk(const char *level, const char *fmt, ...) | ||
44 | __attribute__ ((format (printf, 2, 3))); | ||
45 | |||
46 | #define ath6kl_info(fmt, ...) \ | ||
47 | ath6kl_printk(KERN_INFO, fmt, ##__VA_ARGS__) | ||
48 | #define ath6kl_err(fmt, ...) \ | ||
49 | ath6kl_printk(KERN_ERR, fmt, ##__VA_ARGS__) | ||
50 | #define ath6kl_warn(fmt, ...) \ | ||
51 | ath6kl_printk(KERN_WARNING, fmt, ##__VA_ARGS__) | ||
52 | |||
53 | #define AR_DBG_LVL_CHECK(mask) (debug_mask & mask) | ||
54 | |||
55 | #ifdef CONFIG_ATH6KL_DEBUG | ||
56 | #define ath6kl_dbg(mask, fmt, ...) \ | ||
57 | ({ \ | ||
58 | int rtn; \ | ||
59 | if (debug_mask & mask) \ | ||
60 | rtn = ath6kl_printk(KERN_DEBUG, fmt, ##__VA_ARGS__); \ | ||
61 | else \ | ||
62 | rtn = 0; \ | ||
63 | \ | ||
64 | rtn; \ | ||
65 | }) | ||
66 | |||
67 | static inline void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask, | ||
68 | const char *msg, const void *buf, | ||
69 | size_t len) | ||
70 | { | ||
71 | if (debug_mask & mask) { | ||
72 | ath6kl_dbg(mask, "%s\n", msg); | ||
73 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf, len); | ||
74 | } | ||
75 | } | ||
76 | |||
77 | void ath6kl_dump_registers(struct ath6kl_device *dev, | ||
78 | struct ath6kl_irq_proc_registers *irq_proc_reg, | ||
79 | struct ath6kl_irq_enable_reg *irq_en_reg); | ||
80 | void dump_cred_dist_stats(struct htc_target *target); | ||
81 | #else | ||
82 | static inline int ath6kl_dbg(enum ATH6K_DEBUG_MASK dbg_mask, | ||
83 | const char *fmt, ...) | ||
84 | { | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static inline void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask, | ||
89 | const char *msg, const void *buf, | ||
90 | size_t len) | ||
91 | { | ||
92 | } | ||
93 | |||
94 | static inline void ath6kl_dump_registers(struct ath6kl_device *dev, | ||
95 | struct ath6kl_irq_proc_registers *irq_proc_reg, | ||
96 | struct ath6kl_irq_enable_reg *irq_en_reg) | ||
97 | { | ||
98 | |||
99 | } | ||
100 | static inline void dump_cred_dist_stats(struct htc_target *target) | ||
101 | { | ||
102 | } | ||
103 | #endif | ||
104 | |||
105 | #endif | ||
diff --git a/drivers/net/wireless/ath/ath6kl/hif-ops.h b/drivers/net/wireless/ath/ath6kl/hif-ops.h new file mode 100644 index 000000000000..c923979776a0 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/hif-ops.h | |||
@@ -0,0 +1,72 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004-2011 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 | #ifndef HIF_OPS_H | ||
18 | #define HIF_OPS_H | ||
19 | |||
20 | #include "hif.h" | ||
21 | |||
22 | static inline int hif_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf, | ||
23 | u32 len, u32 request) | ||
24 | { | ||
25 | return ar->hif_ops->read_write_sync(ar, addr, buf, len, request); | ||
26 | } | ||
27 | |||
28 | static inline int hif_write_async(struct ath6kl *ar, u32 address, u8 *buffer, | ||
29 | u32 length, u32 request, | ||
30 | struct htc_packet *packet) | ||
31 | { | ||
32 | return ar->hif_ops->write_async(ar, address, buffer, length, | ||
33 | request, packet); | ||
34 | } | ||
35 | static inline void ath6kl_hif_irq_enable(struct ath6kl *ar) | ||
36 | { | ||
37 | return ar->hif_ops->irq_enable(ar); | ||
38 | } | ||
39 | |||
40 | static inline void ath6kl_hif_irq_disable(struct ath6kl *ar) | ||
41 | { | ||
42 | return ar->hif_ops->irq_disable(ar); | ||
43 | } | ||
44 | |||
45 | static inline struct hif_scatter_req *hif_scatter_req_get(struct ath6kl *ar) | ||
46 | { | ||
47 | return ar->hif_ops->scatter_req_get(ar); | ||
48 | } | ||
49 | |||
50 | static inline void hif_scatter_req_add(struct ath6kl *ar, | ||
51 | struct hif_scatter_req *s_req) | ||
52 | { | ||
53 | return ar->hif_ops->scatter_req_add(ar, s_req); | ||
54 | } | ||
55 | |||
56 | static inline int ath6kl_hif_enable_scatter(struct ath6kl *ar) | ||
57 | { | ||
58 | return ar->hif_ops->enable_scatter(ar); | ||
59 | } | ||
60 | |||
61 | static inline int ath6kl_hif_scat_req_rw(struct ath6kl *ar, | ||
62 | struct hif_scatter_req *scat_req) | ||
63 | { | ||
64 | return ar->hif_ops->scat_req_rw(ar, scat_req); | ||
65 | } | ||
66 | |||
67 | static inline void ath6kl_hif_cleanup_scatter(struct ath6kl *ar) | ||
68 | { | ||
69 | return ar->hif_ops->cleanup_scatter(ar); | ||
70 | } | ||
71 | |||
72 | #endif | ||
diff --git a/drivers/net/wireless/ath/ath6kl/hif.h b/drivers/net/wireless/ath/ath6kl/hif.h new file mode 100644 index 000000000000..5ceff54775a1 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/hif.h | |||
@@ -0,0 +1,207 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004-2011 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 | #ifndef HIF_H | ||
18 | #define HIF_H | ||
19 | |||
20 | #include "common.h" | ||
21 | #include "core.h" | ||
22 | |||
23 | #include <linux/scatterlist.h> | ||
24 | |||
25 | #define BUS_REQUEST_MAX_NUM 64 | ||
26 | #define HIF_MBOX_BLOCK_SIZE 128 | ||
27 | #define HIF_MBOX0_BLOCK_SIZE 1 | ||
28 | |||
29 | #define HIF_DMA_BUFFER_SIZE (32 * 1024) | ||
30 | #define CMD53_FIXED_ADDRESS 1 | ||
31 | #define CMD53_INCR_ADDRESS 2 | ||
32 | |||
33 | #define MAX_SCATTER_REQUESTS 4 | ||
34 | #define MAX_SCATTER_ENTRIES_PER_REQ 16 | ||
35 | #define MAX_SCATTER_REQ_TRANSFER_SIZE (32 * 1024) | ||
36 | |||
37 | #define MANUFACTURER_ID_AR6003_BASE 0x300 | ||
38 | /* SDIO manufacturer ID and Codes */ | ||
39 | #define MANUFACTURER_ID_ATH6KL_BASE_MASK 0xFF00 | ||
40 | #define MANUFACTURER_CODE 0x271 /* Atheros */ | ||
41 | |||
42 | /* Mailbox address in SDIO address space */ | ||
43 | #define HIF_MBOX_BASE_ADDR 0x800 | ||
44 | #define HIF_MBOX_WIDTH 0x800 | ||
45 | |||
46 | #define HIF_MBOX_END_ADDR (HTC_MAILBOX_NUM_MAX * HIF_MBOX_WIDTH - 1) | ||
47 | |||
48 | /* version 1 of the chip has only a 12K extended mbox range */ | ||
49 | #define HIF_MBOX0_EXT_BASE_ADDR 0x4000 | ||
50 | #define HIF_MBOX0_EXT_WIDTH (12*1024) | ||
51 | |||
52 | /* GMBOX addresses */ | ||
53 | #define HIF_GMBOX_BASE_ADDR 0x7000 | ||
54 | #define HIF_GMBOX_WIDTH 0x4000 | ||
55 | |||
56 | /* interrupt mode register */ | ||
57 | #define CCCR_SDIO_IRQ_MODE_REG 0xF0 | ||
58 | |||
59 | /* mode to enable special 4-bit interrupt assertion without clock */ | ||
60 | #define SDIO_IRQ_MODE_ASYNC_4BIT_IRQ (1 << 0) | ||
61 | |||
62 | struct bus_request { | ||
63 | struct list_head list; | ||
64 | |||
65 | /* request data */ | ||
66 | u32 address; | ||
67 | |||
68 | u8 *buffer; | ||
69 | u32 length; | ||
70 | u32 request; | ||
71 | struct htc_packet *packet; | ||
72 | int status; | ||
73 | |||
74 | /* this is a scatter request */ | ||
75 | struct hif_scatter_req *scat_req; | ||
76 | }; | ||
77 | |||
78 | /* direction of transfer (read/write) */ | ||
79 | #define HIF_READ 0x00000001 | ||
80 | #define HIF_WRITE 0x00000002 | ||
81 | #define HIF_DIR_MASK (HIF_READ | HIF_WRITE) | ||
82 | |||
83 | /* | ||
84 | * emode - This indicates the whether the command is to be executed in a | ||
85 | * blocking or non-blocking fashion (HIF_SYNCHRONOUS/ | ||
86 | * HIF_ASYNCHRONOUS). The read/write data paths in HTC have been | ||
87 | * implemented using the asynchronous mode allowing the the bus | ||
88 | * driver to indicate the completion of operation through the | ||
89 | * registered callback routine. The requirement primarily comes | ||
90 | * from the contexts these operations get called from (a driver's | ||
91 | * transmit context or the ISR context in case of receive). | ||
92 | * Support for both of these modes is essential. | ||
93 | */ | ||
94 | #define HIF_SYNCHRONOUS 0x00000010 | ||
95 | #define HIF_ASYNCHRONOUS 0x00000020 | ||
96 | #define HIF_EMODE_MASK (HIF_SYNCHRONOUS | HIF_ASYNCHRONOUS) | ||
97 | |||
98 | /* | ||
99 | * dmode - An interface may support different kinds of commands based on | ||
100 | * the tradeoff between the amount of data it can carry and the | ||
101 | * setup time. Byte and Block modes are supported (HIF_BYTE_BASIS/ | ||
102 | * HIF_BLOCK_BASIS). In case of latter, the data is rounded off | ||
103 | * to the nearest block size by padding. The size of the block is | ||
104 | * configurable at compile time using the HIF_BLOCK_SIZE and is | ||
105 | * negotiated with the target during initialization after the | ||
106 | * ATH6KL interrupts are enabled. | ||
107 | */ | ||
108 | #define HIF_BYTE_BASIS 0x00000040 | ||
109 | #define HIF_BLOCK_BASIS 0x00000080 | ||
110 | #define HIF_DMODE_MASK (HIF_BYTE_BASIS | HIF_BLOCK_BASIS) | ||
111 | |||
112 | /* | ||
113 | * amode - This indicates if the address has to be incremented on ATH6KL | ||
114 | * after every read/write operation (HIF?FIXED_ADDRESS/ | ||
115 | * HIF_INCREMENTAL_ADDRESS). | ||
116 | */ | ||
117 | #define HIF_FIXED_ADDRESS 0x00000100 | ||
118 | #define HIF_INCREMENTAL_ADDRESS 0x00000200 | ||
119 | #define HIF_AMODE_MASK (HIF_FIXED_ADDRESS | HIF_INCREMENTAL_ADDRESS) | ||
120 | |||
121 | #define HIF_WR_ASYNC_BYTE_INC \ | ||
122 | (HIF_WRITE | HIF_ASYNCHRONOUS | \ | ||
123 | HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS) | ||
124 | |||
125 | #define HIF_WR_ASYNC_BLOCK_INC \ | ||
126 | (HIF_WRITE | HIF_ASYNCHRONOUS | \ | ||
127 | HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS) | ||
128 | |||
129 | #define HIF_WR_SYNC_BYTE_FIX \ | ||
130 | (HIF_WRITE | HIF_SYNCHRONOUS | \ | ||
131 | HIF_BYTE_BASIS | HIF_FIXED_ADDRESS) | ||
132 | |||
133 | #define HIF_WR_SYNC_BYTE_INC \ | ||
134 | (HIF_WRITE | HIF_SYNCHRONOUS | \ | ||
135 | HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS) | ||
136 | |||
137 | #define HIF_WR_SYNC_BLOCK_INC \ | ||
138 | (HIF_WRITE | HIF_SYNCHRONOUS | \ | ||
139 | HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS) | ||
140 | |||
141 | #define HIF_RD_SYNC_BYTE_INC \ | ||
142 | (HIF_READ | HIF_SYNCHRONOUS | \ | ||
143 | HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS) | ||
144 | |||
145 | #define HIF_RD_SYNC_BYTE_FIX \ | ||
146 | (HIF_READ | HIF_SYNCHRONOUS | \ | ||
147 | HIF_BYTE_BASIS | HIF_FIXED_ADDRESS) | ||
148 | |||
149 | #define HIF_RD_ASYNC_BLOCK_FIX \ | ||
150 | (HIF_READ | HIF_ASYNCHRONOUS | \ | ||
151 | HIF_BLOCK_BASIS | HIF_FIXED_ADDRESS) | ||
152 | |||
153 | #define HIF_RD_SYNC_BLOCK_FIX \ | ||
154 | (HIF_READ | HIF_SYNCHRONOUS | \ | ||
155 | HIF_BLOCK_BASIS | HIF_FIXED_ADDRESS) | ||
156 | |||
157 | struct hif_scatter_item { | ||
158 | u8 *buf; | ||
159 | int len; | ||
160 | struct htc_packet *packet; | ||
161 | }; | ||
162 | |||
163 | struct hif_scatter_req { | ||
164 | struct list_head list; | ||
165 | /* address for the read/write operation */ | ||
166 | u32 addr; | ||
167 | |||
168 | /* request flags */ | ||
169 | u32 req; | ||
170 | |||
171 | /* total length of entire transfer */ | ||
172 | u32 len; | ||
173 | |||
174 | bool virt_scat; | ||
175 | |||
176 | void (*complete) (struct htc_target *, struct hif_scatter_req *); | ||
177 | int status; | ||
178 | int scat_entries; | ||
179 | |||
180 | struct bus_request *busrequest; | ||
181 | struct scatterlist *sgentries; | ||
182 | |||
183 | /* bounce buffer for upper layers to copy to/from */ | ||
184 | u8 *virt_dma_buf; | ||
185 | |||
186 | struct hif_scatter_item scat_list[1]; | ||
187 | }; | ||
188 | |||
189 | struct ath6kl_hif_ops { | ||
190 | int (*read_write_sync)(struct ath6kl *ar, u32 addr, u8 *buf, | ||
191 | u32 len, u32 request); | ||
192 | int (*write_async)(struct ath6kl *ar, u32 address, u8 *buffer, | ||
193 | u32 length, u32 request, struct htc_packet *packet); | ||
194 | |||
195 | void (*irq_enable)(struct ath6kl *ar); | ||
196 | void (*irq_disable)(struct ath6kl *ar); | ||
197 | |||
198 | struct hif_scatter_req *(*scatter_req_get)(struct ath6kl *ar); | ||
199 | void (*scatter_req_add)(struct ath6kl *ar, | ||
200 | struct hif_scatter_req *s_req); | ||
201 | int (*enable_scatter)(struct ath6kl *ar); | ||
202 | int (*scat_req_rw) (struct ath6kl *ar, | ||
203 | struct hif_scatter_req *scat_req); | ||
204 | void (*cleanup_scatter)(struct ath6kl *ar); | ||
205 | }; | ||
206 | |||
207 | #endif | ||
diff --git a/drivers/net/wireless/ath/ath6kl/htc.c b/drivers/net/wireless/ath/ath6kl/htc.c new file mode 100644 index 000000000000..a8dc5c3ea567 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/htc.c | |||
@@ -0,0 +1,2457 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2007-2011 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 "core.h" | ||
18 | #include "htc_hif.h" | ||
19 | #include "debug.h" | ||
20 | #include "hif-ops.h" | ||
21 | #include <asm/unaligned.h> | ||
22 | |||
23 | #define CALC_TXRX_PADDED_LEN(dev, len) (__ALIGN_MASK((len), (dev)->block_mask)) | ||
24 | |||
25 | static void htc_prep_send_pkt(struct htc_packet *packet, u8 flags, int ctrl0, | ||
26 | int ctrl1) | ||
27 | { | ||
28 | struct htc_frame_hdr *hdr; | ||
29 | |||
30 | packet->buf -= HTC_HDR_LENGTH; | ||
31 | hdr = (struct htc_frame_hdr *)packet->buf; | ||
32 | |||
33 | /* Endianess? */ | ||
34 | put_unaligned((u16)packet->act_len, &hdr->payld_len); | ||
35 | hdr->flags = flags; | ||
36 | hdr->eid = packet->endpoint; | ||
37 | hdr->ctrl[0] = ctrl0; | ||
38 | hdr->ctrl[1] = ctrl1; | ||
39 | } | ||
40 | |||
41 | static void htc_reclaim_txctrl_buf(struct htc_target *target, | ||
42 | struct htc_packet *pkt) | ||
43 | { | ||
44 | spin_lock_bh(&target->htc_lock); | ||
45 | list_add_tail(&pkt->list, &target->free_ctrl_txbuf); | ||
46 | spin_unlock_bh(&target->htc_lock); | ||
47 | } | ||
48 | |||
49 | static struct htc_packet *htc_get_control_buf(struct htc_target *target, | ||
50 | bool tx) | ||
51 | { | ||
52 | struct htc_packet *packet = NULL; | ||
53 | struct list_head *buf_list; | ||
54 | |||
55 | buf_list = tx ? &target->free_ctrl_txbuf : &target->free_ctrl_rxbuf; | ||
56 | |||
57 | spin_lock_bh(&target->htc_lock); | ||
58 | |||
59 | if (list_empty(buf_list)) { | ||
60 | spin_unlock_bh(&target->htc_lock); | ||
61 | return NULL; | ||
62 | } | ||
63 | |||
64 | packet = list_first_entry(buf_list, struct htc_packet, list); | ||
65 | list_del(&packet->list); | ||
66 | spin_unlock_bh(&target->htc_lock); | ||
67 | |||
68 | if (tx) | ||
69 | packet->buf = packet->buf_start + HTC_HDR_LENGTH; | ||
70 | |||
71 | return packet; | ||
72 | } | ||
73 | |||
74 | static void htc_tx_comp_update(struct htc_target *target, | ||
75 | struct htc_endpoint *endpoint, | ||
76 | struct htc_packet *packet) | ||
77 | { | ||
78 | packet->completion = NULL; | ||
79 | packet->buf += HTC_HDR_LENGTH; | ||
80 | |||
81 | if (!packet->status) | ||
82 | return; | ||
83 | |||
84 | ath6kl_err("req failed (status:%d, ep:%d, len:%d creds:%d)\n", | ||
85 | packet->status, packet->endpoint, packet->act_len, | ||
86 | packet->info.tx.cred_used); | ||
87 | |||
88 | /* on failure to submit, reclaim credits for this packet */ | ||
89 | spin_lock_bh(&target->tx_lock); | ||
90 | endpoint->cred_dist.cred_to_dist += | ||
91 | packet->info.tx.cred_used; | ||
92 | endpoint->cred_dist.txq_depth = get_queue_depth(&endpoint->txq); | ||
93 | |||
94 | ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:0x%p dist:0x%p\n", | ||
95 | target->cred_dist_cntxt, &target->cred_dist_list); | ||
96 | |||
97 | ath6k_credit_distribute(target->cred_dist_cntxt, | ||
98 | &target->cred_dist_list, | ||
99 | HTC_CREDIT_DIST_SEND_COMPLETE); | ||
100 | |||
101 | spin_unlock_bh(&target->tx_lock); | ||
102 | } | ||
103 | |||
104 | static void htc_tx_complete(struct htc_endpoint *endpoint, | ||
105 | struct list_head *txq) | ||
106 | { | ||
107 | if (list_empty(txq)) | ||
108 | return; | ||
109 | |||
110 | ath6kl_dbg(ATH6KL_DBG_HTC_SEND, | ||
111 | "send complete ep %d, (%d pkts)\n", | ||
112 | endpoint->eid, get_queue_depth(txq)); | ||
113 | |||
114 | ath6kl_tx_complete(endpoint->target->dev->ar, txq); | ||
115 | } | ||
116 | |||
117 | static void htc_tx_comp_handler(struct htc_target *target, | ||
118 | struct htc_packet *packet) | ||
119 | { | ||
120 | struct htc_endpoint *endpoint = &target->endpoint[packet->endpoint]; | ||
121 | struct list_head container; | ||
122 | |||
123 | htc_tx_comp_update(target, endpoint, packet); | ||
124 | INIT_LIST_HEAD(&container); | ||
125 | list_add_tail(&packet->list, &container); | ||
126 | /* do completion */ | ||
127 | htc_tx_complete(endpoint, &container); | ||
128 | } | ||
129 | |||
130 | static void htc_async_tx_scat_complete(struct htc_target *target, | ||
131 | struct hif_scatter_req *scat_req) | ||
132 | { | ||
133 | struct htc_endpoint *endpoint; | ||
134 | struct htc_packet *packet; | ||
135 | struct list_head tx_compq; | ||
136 | int i; | ||
137 | |||
138 | INIT_LIST_HEAD(&tx_compq); | ||
139 | |||
140 | ath6kl_dbg(ATH6KL_DBG_HTC_SEND, | ||
141 | "htc_async_tx_scat_complete total len: %d entries: %d\n", | ||
142 | scat_req->len, scat_req->scat_entries); | ||
143 | |||
144 | if (scat_req->status) | ||
145 | ath6kl_err("send scatter req failed: %d\n", scat_req->status); | ||
146 | |||
147 | packet = scat_req->scat_list[0].packet; | ||
148 | endpoint = &target->endpoint[packet->endpoint]; | ||
149 | |||
150 | /* walk through the scatter list and process */ | ||
151 | for (i = 0; i < scat_req->scat_entries; i++) { | ||
152 | packet = scat_req->scat_list[i].packet; | ||
153 | if (!packet) { | ||
154 | WARN_ON(1); | ||
155 | return; | ||
156 | } | ||
157 | |||
158 | packet->status = scat_req->status; | ||
159 | htc_tx_comp_update(target, endpoint, packet); | ||
160 | list_add_tail(&packet->list, &tx_compq); | ||
161 | } | ||
162 | |||
163 | /* free scatter request */ | ||
164 | hif_scatter_req_add(target->dev->ar, scat_req); | ||
165 | |||
166 | /* complete all packets */ | ||
167 | htc_tx_complete(endpoint, &tx_compq); | ||
168 | } | ||
169 | |||
170 | static int htc_issue_send(struct htc_target *target, struct htc_packet *packet) | ||
171 | { | ||
172 | int status; | ||
173 | bool sync = false; | ||
174 | u32 padded_len, send_len; | ||
175 | |||
176 | if (!packet->completion) | ||
177 | sync = true; | ||
178 | |||
179 | send_len = packet->act_len + HTC_HDR_LENGTH; | ||
180 | |||
181 | ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "%s: transmit len : %d (%s)\n", | ||
182 | __func__, send_len, sync ? "sync" : "async"); | ||
183 | |||
184 | padded_len = CALC_TXRX_PADDED_LEN(target, send_len); | ||
185 | |||
186 | ath6kl_dbg(ATH6KL_DBG_HTC_SEND, | ||
187 | "DevSendPacket, padded len: %d mbox:0x%X (mode:%s)\n", | ||
188 | padded_len, | ||
189 | target->dev->ar->mbox_info.htc_addr, | ||
190 | sync ? "sync" : "async"); | ||
191 | |||
192 | if (sync) { | ||
193 | status = hif_read_write_sync(target->dev->ar, | ||
194 | target->dev->ar->mbox_info.htc_addr, | ||
195 | packet->buf, padded_len, | ||
196 | HIF_WR_SYNC_BLOCK_INC); | ||
197 | |||
198 | packet->status = status; | ||
199 | packet->buf += HTC_HDR_LENGTH; | ||
200 | } else | ||
201 | status = hif_write_async(target->dev->ar, | ||
202 | target->dev->ar->mbox_info.htc_addr, | ||
203 | packet->buf, padded_len, | ||
204 | HIF_WR_ASYNC_BLOCK_INC, packet); | ||
205 | |||
206 | return status; | ||
207 | } | ||
208 | |||
209 | static int htc_check_credits(struct htc_target *target, | ||
210 | struct htc_endpoint *ep, u8 *flags, | ||
211 | enum htc_endpoint_id eid, unsigned int len, | ||
212 | int *req_cred) | ||
213 | { | ||
214 | |||
215 | *req_cred = (len > target->tgt_cred_sz) ? | ||
216 | DIV_ROUND_UP(len, target->tgt_cred_sz) : 1; | ||
217 | |||
218 | ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "creds required:%d got:%d\n", | ||
219 | *req_cred, ep->cred_dist.credits); | ||
220 | |||
221 | if (ep->cred_dist.credits < *req_cred) { | ||
222 | if (eid == ENDPOINT_0) | ||
223 | return -EINVAL; | ||
224 | |||
225 | /* Seek more credits */ | ||
226 | ep->cred_dist.seek_cred = *req_cred - ep->cred_dist.credits; | ||
227 | |||
228 | ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:0x%p dist:0x%p\n", | ||
229 | target->cred_dist_cntxt, &ep->cred_dist); | ||
230 | |||
231 | ath6k_seek_credits(target->cred_dist_cntxt, &ep->cred_dist); | ||
232 | |||
233 | ep->cred_dist.seek_cred = 0; | ||
234 | |||
235 | if (ep->cred_dist.credits < *req_cred) { | ||
236 | ath6kl_dbg(ATH6KL_DBG_HTC_SEND, | ||
237 | "not enough credits for ep %d - leaving packet in queue\n", | ||
238 | eid); | ||
239 | return -EINVAL; | ||
240 | } | ||
241 | } | ||
242 | |||
243 | ep->cred_dist.credits -= *req_cred; | ||
244 | ep->ep_st.cred_cosumd += *req_cred; | ||
245 | |||
246 | /* When we are getting low on credits, ask for more */ | ||
247 | if (ep->cred_dist.credits < ep->cred_dist.cred_per_msg) { | ||
248 | ep->cred_dist.seek_cred = | ||
249 | ep->cred_dist.cred_per_msg - ep->cred_dist.credits; | ||
250 | |||
251 | ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:0x%p dist:0x%p\n", | ||
252 | target->cred_dist_cntxt, &ep->cred_dist); | ||
253 | |||
254 | ath6k_seek_credits(target->cred_dist_cntxt, &ep->cred_dist); | ||
255 | |||
256 | /* see if we were successful in getting more */ | ||
257 | if (ep->cred_dist.credits < ep->cred_dist.cred_per_msg) { | ||
258 | /* tell the target we need credits ASAP! */ | ||
259 | *flags |= HTC_FLAGS_NEED_CREDIT_UPDATE; | ||
260 | ep->ep_st.cred_low_indicate += 1; | ||
261 | ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "host needs credits\n"); | ||
262 | } | ||
263 | } | ||
264 | |||
265 | return 0; | ||
266 | } | ||
267 | |||
268 | static void htc_tx_pkts_get(struct htc_target *target, | ||
269 | struct htc_endpoint *endpoint, | ||
270 | struct list_head *queue) | ||
271 | { | ||
272 | int req_cred; | ||
273 | u8 flags; | ||
274 | struct htc_packet *packet; | ||
275 | unsigned int len; | ||
276 | |||
277 | while (true) { | ||
278 | |||
279 | flags = 0; | ||
280 | |||
281 | if (list_empty(&endpoint->txq)) | ||
282 | break; | ||
283 | packet = list_first_entry(&endpoint->txq, struct htc_packet, | ||
284 | list); | ||
285 | |||
286 | ath6kl_dbg(ATH6KL_DBG_HTC_SEND, | ||
287 | "got head pkt:0x%p , queue depth: %d\n", | ||
288 | packet, get_queue_depth(&endpoint->txq)); | ||
289 | |||
290 | len = CALC_TXRX_PADDED_LEN(target, | ||
291 | packet->act_len + HTC_HDR_LENGTH); | ||
292 | |||
293 | if (htc_check_credits(target, endpoint, &flags, | ||
294 | packet->endpoint, len, &req_cred)) | ||
295 | break; | ||
296 | |||
297 | /* now we can fully move onto caller's queue */ | ||
298 | packet = list_first_entry(&endpoint->txq, struct htc_packet, | ||
299 | list); | ||
300 | list_move_tail(&packet->list, queue); | ||
301 | |||
302 | /* save the number of credits this packet consumed */ | ||
303 | packet->info.tx.cred_used = req_cred; | ||
304 | |||
305 | /* all TX packets are handled asynchronously */ | ||
306 | packet->completion = htc_tx_comp_handler; | ||
307 | packet->context = target; | ||
308 | endpoint->ep_st.tx_issued += 1; | ||
309 | |||
310 | /* save send flags */ | ||
311 | packet->info.tx.flags = flags; | ||
312 | packet->info.tx.seqno = endpoint->seqno; | ||
313 | endpoint->seqno++; | ||
314 | } | ||
315 | } | ||
316 | |||
317 | /* See if the padded tx length falls on a credit boundary */ | ||
318 | static int htc_get_credit_padding(unsigned int cred_sz, int *len, | ||
319 | struct htc_endpoint *ep) | ||
320 | { | ||
321 | int rem_cred, cred_pad; | ||
322 | |||
323 | rem_cred = *len % cred_sz; | ||
324 | |||
325 | /* No padding needed */ | ||
326 | if (!rem_cred) | ||
327 | return 0; | ||
328 | |||
329 | if (!(ep->conn_flags & HTC_FLGS_TX_BNDL_PAD_EN)) | ||
330 | return -1; | ||
331 | |||
332 | /* | ||
333 | * The transfer consumes a "partial" credit, this | ||
334 | * packet cannot be bundled unless we add | ||
335 | * additional "dummy" padding (max 255 bytes) to | ||
336 | * consume the entire credit. | ||
337 | */ | ||
338 | cred_pad = *len < cred_sz ? (cred_sz - *len) : rem_cred; | ||
339 | |||
340 | if ((cred_pad > 0) && (cred_pad <= 255)) | ||
341 | *len += cred_pad; | ||
342 | else | ||
343 | /* The amount of padding is too large, send as non-bundled */ | ||
344 | return -1; | ||
345 | |||
346 | return cred_pad; | ||
347 | } | ||
348 | |||
349 | static int htc_setup_send_scat_list(struct htc_target *target, | ||
350 | struct htc_endpoint *endpoint, | ||
351 | struct hif_scatter_req *scat_req, | ||
352 | int n_scat, | ||
353 | struct list_head *queue) | ||
354 | { | ||
355 | struct htc_packet *packet; | ||
356 | int i, len, rem_scat, cred_pad; | ||
357 | int status = 0; | ||
358 | |||
359 | rem_scat = target->max_tx_bndl_sz; | ||
360 | |||
361 | for (i = 0; i < n_scat; i++) { | ||
362 | scat_req->scat_list[i].packet = NULL; | ||
363 | |||
364 | if (list_empty(queue)) | ||
365 | break; | ||
366 | |||
367 | packet = list_first_entry(queue, struct htc_packet, list); | ||
368 | len = CALC_TXRX_PADDED_LEN(target, | ||
369 | packet->act_len + HTC_HDR_LENGTH); | ||
370 | |||
371 | cred_pad = htc_get_credit_padding(target->tgt_cred_sz, | ||
372 | &len, endpoint); | ||
373 | if (cred_pad < 0) { | ||
374 | status = -EINVAL; | ||
375 | break; | ||
376 | } | ||
377 | |||
378 | if (rem_scat < len) { | ||
379 | /* exceeds what we can transfer */ | ||
380 | status = -ENOSPC; | ||
381 | break; | ||
382 | } | ||
383 | |||
384 | rem_scat -= len; | ||
385 | /* now remove it from the queue */ | ||
386 | packet = list_first_entry(queue, struct htc_packet, list); | ||
387 | list_del(&packet->list); | ||
388 | |||
389 | scat_req->scat_list[i].packet = packet; | ||
390 | /* prepare packet and flag message as part of a send bundle */ | ||
391 | htc_prep_send_pkt(packet, | ||
392 | packet->info.tx.flags | HTC_FLAGS_SEND_BUNDLE, | ||
393 | cred_pad, packet->info.tx.seqno); | ||
394 | scat_req->scat_list[i].buf = packet->buf; | ||
395 | scat_req->scat_list[i].len = len; | ||
396 | |||
397 | scat_req->len += len; | ||
398 | scat_req->scat_entries++; | ||
399 | ath6kl_dbg(ATH6KL_DBG_HTC_SEND, | ||
400 | "%d, adding pkt : 0x%p len:%d (remaining space:%d)\n", | ||
401 | i, packet, len, rem_scat); | ||
402 | } | ||
403 | |||
404 | /* Roll back scatter setup in case of any failure */ | ||
405 | if (status || (scat_req->scat_entries < HTC_MIN_HTC_MSGS_TO_BUNDLE)) { | ||
406 | for (i = scat_req->scat_entries - 1; i >= 0; i--) { | ||
407 | packet = scat_req->scat_list[i].packet; | ||
408 | if (packet) { | ||
409 | packet->buf += HTC_HDR_LENGTH; | ||
410 | list_add(&packet->list, queue); | ||
411 | } | ||
412 | } | ||
413 | return -EINVAL; | ||
414 | } | ||
415 | |||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | /* | ||
420 | * htc_issue_send_bundle: drain a queue and send as bundles | ||
421 | * this function may return without fully draining the queue | ||
422 | * when | ||
423 | * | ||
424 | * 1. scatter resources are exhausted | ||
425 | * 2. a message that will consume a partial credit will stop the | ||
426 | * bundling process early | ||
427 | * 3. we drop below the minimum number of messages for a bundle | ||
428 | */ | ||
429 | static void htc_issue_send_bundle(struct htc_endpoint *endpoint, | ||
430 | struct list_head *queue, | ||
431 | int *sent_bundle, int *n_bundle_pkts) | ||
432 | { | ||
433 | struct htc_target *target = endpoint->target; | ||
434 | struct hif_scatter_req *scat_req = NULL; | ||
435 | int n_scat, n_sent_bundle = 0, tot_pkts_bundle = 0; | ||
436 | |||
437 | while (true) { | ||
438 | n_scat = get_queue_depth(queue); | ||
439 | n_scat = min(n_scat, target->msg_per_bndl_max); | ||
440 | |||
441 | if (n_scat < HTC_MIN_HTC_MSGS_TO_BUNDLE) | ||
442 | /* not enough to bundle */ | ||
443 | break; | ||
444 | |||
445 | scat_req = hif_scatter_req_get(target->dev->ar); | ||
446 | |||
447 | if (!scat_req) { | ||
448 | /* no scatter resources */ | ||
449 | ath6kl_dbg(ATH6KL_DBG_HTC_SEND, | ||
450 | "no more scatter resources\n"); | ||
451 | break; | ||
452 | } | ||
453 | |||
454 | ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "pkts to scatter: %d\n", | ||
455 | n_scat); | ||
456 | |||
457 | scat_req->len = 0; | ||
458 | scat_req->scat_entries = 0; | ||
459 | |||
460 | if (htc_setup_send_scat_list(target, endpoint, scat_req, | ||
461 | n_scat, queue)) { | ||
462 | hif_scatter_req_add(target->dev->ar, scat_req); | ||
463 | break; | ||
464 | } | ||
465 | |||
466 | /* send path is always asynchronous */ | ||
467 | scat_req->complete = htc_async_tx_scat_complete; | ||
468 | n_sent_bundle++; | ||
469 | tot_pkts_bundle += scat_req->scat_entries; | ||
470 | |||
471 | ath6kl_dbg(ATH6KL_DBG_HTC_SEND, | ||
472 | "send scatter total bytes: %d , entries: %d\n", | ||
473 | scat_req->len, scat_req->scat_entries); | ||
474 | ath6kldev_submit_scat_req(target->dev, scat_req, false); | ||
475 | } | ||
476 | |||
477 | *sent_bundle = n_sent_bundle; | ||
478 | *n_bundle_pkts = tot_pkts_bundle; | ||
479 | ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "htc_issue_send_bundle (sent:%d)\n", | ||
480 | n_sent_bundle); | ||
481 | |||
482 | return; | ||
483 | } | ||
484 | |||
485 | static void htc_tx_from_ep_txq(struct htc_target *target, | ||
486 | struct htc_endpoint *endpoint) | ||
487 | { | ||
488 | struct list_head txq; | ||
489 | struct htc_packet *packet; | ||
490 | int bundle_sent; | ||
491 | int n_pkts_bundle; | ||
492 | |||
493 | spin_lock_bh(&target->tx_lock); | ||
494 | |||
495 | endpoint->tx_proc_cnt++; | ||
496 | if (endpoint->tx_proc_cnt > 1) { | ||
497 | endpoint->tx_proc_cnt--; | ||
498 | spin_unlock_bh(&target->tx_lock); | ||
499 | ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "htc_try_send (busy)\n"); | ||
500 | return; | ||
501 | } | ||
502 | |||
503 | /* | ||
504 | * drain the endpoint TX queue for transmission as long | ||
505 | * as we have enough credits. | ||
506 | */ | ||
507 | INIT_LIST_HEAD(&txq); | ||
508 | |||
509 | while (true) { | ||
510 | |||
511 | if (list_empty(&endpoint->txq)) | ||
512 | break; | ||
513 | |||
514 | htc_tx_pkts_get(target, endpoint, &txq); | ||
515 | |||
516 | if (list_empty(&txq)) | ||
517 | break; | ||
518 | |||
519 | spin_unlock_bh(&target->tx_lock); | ||
520 | |||
521 | bundle_sent = 0; | ||
522 | n_pkts_bundle = 0; | ||
523 | |||
524 | while (true) { | ||
525 | /* try to send a bundle on each pass */ | ||
526 | if ((target->tx_bndl_enable) && | ||
527 | (get_queue_depth(&txq) >= | ||
528 | HTC_MIN_HTC_MSGS_TO_BUNDLE)) { | ||
529 | int temp1 = 0, temp2 = 0; | ||
530 | |||
531 | htc_issue_send_bundle(endpoint, &txq, | ||
532 | &temp1, &temp2); | ||
533 | bundle_sent += temp1; | ||
534 | n_pkts_bundle += temp2; | ||
535 | } | ||
536 | |||
537 | if (list_empty(&txq)) | ||
538 | break; | ||
539 | |||
540 | packet = list_first_entry(&txq, struct htc_packet, | ||
541 | list); | ||
542 | list_del(&packet->list); | ||
543 | |||
544 | htc_prep_send_pkt(packet, packet->info.tx.flags, | ||
545 | 0, packet->info.tx.seqno); | ||
546 | htc_issue_send(target, packet); | ||
547 | } | ||
548 | |||
549 | spin_lock_bh(&target->tx_lock); | ||
550 | |||
551 | endpoint->ep_st.tx_bundles += bundle_sent; | ||
552 | endpoint->ep_st.tx_pkt_bundled += n_pkts_bundle; | ||
553 | } | ||
554 | |||
555 | endpoint->tx_proc_cnt = 0; | ||
556 | spin_unlock_bh(&target->tx_lock); | ||
557 | } | ||
558 | |||
559 | static bool htc_try_send(struct htc_target *target, | ||
560 | struct htc_endpoint *endpoint, | ||
561 | struct htc_packet *tx_pkt) | ||
562 | { | ||
563 | struct htc_ep_callbacks ep_cb; | ||
564 | int txq_depth; | ||
565 | bool overflow = false; | ||
566 | |||
567 | ep_cb = endpoint->ep_cb; | ||
568 | |||
569 | spin_lock_bh(&target->tx_lock); | ||
570 | txq_depth = get_queue_depth(&endpoint->txq); | ||
571 | spin_unlock_bh(&target->tx_lock); | ||
572 | |||
573 | if (txq_depth >= endpoint->max_txq_depth) | ||
574 | overflow = true; | ||
575 | |||
576 | if (overflow) | ||
577 | ath6kl_dbg(ATH6KL_DBG_HTC_SEND, | ||
578 | "ep %d, tx queue will overflow :%d , tx depth:%d, max:%d\n", | ||
579 | endpoint->eid, overflow, txq_depth, | ||
580 | endpoint->max_txq_depth); | ||
581 | |||
582 | if (overflow && ep_cb.tx_full) { | ||
583 | ath6kl_dbg(ATH6KL_DBG_HTC_SEND, | ||
584 | "indicating overflowed tx packet: 0x%p\n", tx_pkt); | ||
585 | |||
586 | if (ep_cb.tx_full(endpoint->target, tx_pkt) == | ||
587 | HTC_SEND_FULL_DROP) { | ||
588 | endpoint->ep_st.tx_dropped += 1; | ||
589 | return false; | ||
590 | } | ||
591 | } | ||
592 | |||
593 | spin_lock_bh(&target->tx_lock); | ||
594 | list_add_tail(&tx_pkt->list, &endpoint->txq); | ||
595 | spin_unlock_bh(&target->tx_lock); | ||
596 | |||
597 | htc_tx_from_ep_txq(target, endpoint); | ||
598 | |||
599 | return true; | ||
600 | } | ||
601 | |||
602 | static void htc_chk_ep_txq(struct htc_target *target) | ||
603 | { | ||
604 | struct htc_endpoint *endpoint; | ||
605 | struct htc_endpoint_credit_dist *cred_dist; | ||
606 | |||
607 | /* | ||
608 | * Run through the credit distribution list to see if there are | ||
609 | * packets queued. NOTE: no locks need to be taken since the | ||
610 | * distribution list is not dynamic (cannot be re-ordered) and we | ||
611 | * are not modifying any state. | ||
612 | */ | ||
613 | list_for_each_entry(cred_dist, &target->cred_dist_list, list) { | ||
614 | endpoint = (struct htc_endpoint *)cred_dist->htc_rsvd; | ||
615 | |||
616 | spin_lock_bh(&target->tx_lock); | ||
617 | if (!list_empty(&endpoint->txq)) { | ||
618 | ath6kl_dbg(ATH6KL_DBG_HTC_SEND, | ||
619 | "ep %d has %d credits and %d packets in tx queue\n", | ||
620 | cred_dist->endpoint, | ||
621 | endpoint->cred_dist.credits, | ||
622 | get_queue_depth(&endpoint->txq)); | ||
623 | spin_unlock_bh(&target->tx_lock); | ||
624 | /* | ||
625 | * Try to start the stalled queue, this list is | ||
626 | * ordered by priority. If there are credits | ||
627 | * available the highest priority queue will get a | ||
628 | * chance to reclaim credits from lower priority | ||
629 | * ones. | ||
630 | */ | ||
631 | htc_tx_from_ep_txq(target, endpoint); | ||
632 | spin_lock_bh(&target->tx_lock); | ||
633 | } | ||
634 | spin_unlock_bh(&target->tx_lock); | ||
635 | } | ||
636 | } | ||
637 | |||
638 | static int htc_setup_tx_complete(struct htc_target *target) | ||
639 | { | ||
640 | struct htc_packet *send_pkt = NULL; | ||
641 | int status; | ||
642 | |||
643 | send_pkt = htc_get_control_buf(target, true); | ||
644 | |||
645 | if (!send_pkt) | ||
646 | return -ENOMEM; | ||
647 | |||
648 | if (target->htc_tgt_ver >= HTC_VERSION_2P1) { | ||
649 | struct htc_setup_comp_ext_msg *setup_comp_ext; | ||
650 | u32 flags = 0; | ||
651 | |||
652 | setup_comp_ext = | ||
653 | (struct htc_setup_comp_ext_msg *)send_pkt->buf; | ||
654 | memset(setup_comp_ext, 0, sizeof(*setup_comp_ext)); | ||
655 | setup_comp_ext->msg_id = | ||
656 | cpu_to_le16(HTC_MSG_SETUP_COMPLETE_EX_ID); | ||
657 | |||
658 | if (target->msg_per_bndl_max > 0) { | ||
659 | /* Indicate HTC bundling to the target */ | ||
660 | flags |= HTC_SETUP_COMP_FLG_RX_BNDL_EN; | ||
661 | setup_comp_ext->msg_per_rxbndl = | ||
662 | target->msg_per_bndl_max; | ||
663 | } | ||
664 | |||
665 | memcpy(&setup_comp_ext->flags, &flags, | ||
666 | sizeof(setup_comp_ext->flags)); | ||
667 | set_htc_pkt_info(send_pkt, NULL, (u8 *) setup_comp_ext, | ||
668 | sizeof(struct htc_setup_comp_ext_msg), | ||
669 | ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); | ||
670 | |||
671 | } else { | ||
672 | struct htc_setup_comp_msg *setup_comp; | ||
673 | setup_comp = (struct htc_setup_comp_msg *)send_pkt->buf; | ||
674 | memset(setup_comp, 0, sizeof(struct htc_setup_comp_msg)); | ||
675 | setup_comp->msg_id = cpu_to_le16(HTC_MSG_SETUP_COMPLETE_ID); | ||
676 | set_htc_pkt_info(send_pkt, NULL, (u8 *) setup_comp, | ||
677 | sizeof(struct htc_setup_comp_msg), | ||
678 | ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); | ||
679 | } | ||
680 | |||
681 | /* we want synchronous operation */ | ||
682 | send_pkt->completion = NULL; | ||
683 | htc_prep_send_pkt(send_pkt, 0, 0, 0); | ||
684 | status = htc_issue_send(target, send_pkt); | ||
685 | |||
686 | if (send_pkt != NULL) | ||
687 | htc_reclaim_txctrl_buf(target, send_pkt); | ||
688 | |||
689 | return status; | ||
690 | } | ||
691 | |||
692 | void ath6kl_htc_set_credit_dist(struct htc_target *target, | ||
693 | struct htc_credit_state_info *cred_dist_cntxt, | ||
694 | u16 srvc_pri_order[], int list_len) | ||
695 | { | ||
696 | struct htc_endpoint *endpoint; | ||
697 | int i, ep; | ||
698 | |||
699 | target->cred_dist_cntxt = cred_dist_cntxt; | ||
700 | |||
701 | list_add_tail(&target->endpoint[ENDPOINT_0].cred_dist.list, | ||
702 | &target->cred_dist_list); | ||
703 | |||
704 | for (i = 0; i < list_len; i++) { | ||
705 | for (ep = ENDPOINT_1; ep < ENDPOINT_MAX; ep++) { | ||
706 | endpoint = &target->endpoint[ep]; | ||
707 | if (endpoint->svc_id == srvc_pri_order[i]) { | ||
708 | list_add_tail(&endpoint->cred_dist.list, | ||
709 | &target->cred_dist_list); | ||
710 | break; | ||
711 | } | ||
712 | } | ||
713 | if (ep >= ENDPOINT_MAX) { | ||
714 | WARN_ON(1); | ||
715 | return; | ||
716 | } | ||
717 | } | ||
718 | } | ||
719 | |||
720 | int ath6kl_htc_tx(struct htc_target *target, struct htc_packet *packet) | ||
721 | { | ||
722 | struct htc_endpoint *endpoint; | ||
723 | struct list_head queue; | ||
724 | |||
725 | ath6kl_dbg(ATH6KL_DBG_HTC_SEND, | ||
726 | "htc_tx: ep id: %d, buf: 0x%p, len: %d\n", | ||
727 | packet->endpoint, packet->buf, packet->act_len); | ||
728 | |||
729 | if (packet->endpoint >= ENDPOINT_MAX) { | ||
730 | WARN_ON(1); | ||
731 | return -EINVAL; | ||
732 | } | ||
733 | |||
734 | endpoint = &target->endpoint[packet->endpoint]; | ||
735 | |||
736 | if (!htc_try_send(target, endpoint, packet)) { | ||
737 | packet->status = (target->htc_flags & HTC_OP_STATE_STOPPING) ? | ||
738 | -ECANCELED : -ENOSPC; | ||
739 | INIT_LIST_HEAD(&queue); | ||
740 | list_add(&packet->list, &queue); | ||
741 | htc_tx_complete(endpoint, &queue); | ||
742 | } | ||
743 | |||
744 | return 0; | ||
745 | } | ||
746 | |||
747 | /* flush endpoint TX queue */ | ||
748 | void ath6kl_htc_flush_txep(struct htc_target *target, | ||
749 | enum htc_endpoint_id eid, u16 tag) | ||
750 | { | ||
751 | struct htc_packet *packet, *tmp_pkt; | ||
752 | struct list_head discard_q, container; | ||
753 | struct htc_endpoint *endpoint = &target->endpoint[eid]; | ||
754 | |||
755 | if (!endpoint->svc_id) { | ||
756 | WARN_ON(1); | ||
757 | return; | ||
758 | } | ||
759 | |||
760 | /* initialize the discard queue */ | ||
761 | INIT_LIST_HEAD(&discard_q); | ||
762 | |||
763 | spin_lock_bh(&target->tx_lock); | ||
764 | |||
765 | list_for_each_entry_safe(packet, tmp_pkt, &endpoint->txq, list) { | ||
766 | if ((tag == HTC_TX_PACKET_TAG_ALL) || | ||
767 | (tag == packet->info.tx.tag)) | ||
768 | list_move_tail(&packet->list, &discard_q); | ||
769 | } | ||
770 | |||
771 | spin_unlock_bh(&target->tx_lock); | ||
772 | |||
773 | list_for_each_entry_safe(packet, tmp_pkt, &discard_q, list) { | ||
774 | packet->status = -ECANCELED; | ||
775 | list_del(&packet->list); | ||
776 | ath6kl_dbg(ATH6KL_DBG_TRC, | ||
777 | "flushing tx pkt:0x%p, len:%d, ep:%d tag:0x%X\n", | ||
778 | packet, packet->act_len, | ||
779 | packet->endpoint, packet->info.tx.tag); | ||
780 | |||
781 | INIT_LIST_HEAD(&container); | ||
782 | list_add_tail(&packet->list, &container); | ||
783 | htc_tx_complete(endpoint, &container); | ||
784 | } | ||
785 | |||
786 | } | ||
787 | |||
788 | static void ath6kl_htc_flush_txep_all(struct htc_target *target) | ||
789 | { | ||
790 | struct htc_endpoint *endpoint; | ||
791 | int i; | ||
792 | |||
793 | dump_cred_dist_stats(target); | ||
794 | |||
795 | for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) { | ||
796 | endpoint = &target->endpoint[i]; | ||
797 | if (endpoint->svc_id == 0) | ||
798 | /* not in use.. */ | ||
799 | continue; | ||
800 | ath6kl_htc_flush_txep(target, i, HTC_TX_PACKET_TAG_ALL); | ||
801 | } | ||
802 | } | ||
803 | |||
804 | void ath6kl_htc_indicate_activity_change(struct htc_target *target, | ||
805 | enum htc_endpoint_id eid, bool active) | ||
806 | { | ||
807 | struct htc_endpoint *endpoint = &target->endpoint[eid]; | ||
808 | bool dist = false; | ||
809 | |||
810 | if (endpoint->svc_id == 0) { | ||
811 | WARN_ON(1); | ||
812 | return; | ||
813 | } | ||
814 | |||
815 | spin_lock_bh(&target->tx_lock); | ||
816 | |||
817 | if (active) { | ||
818 | if (!(endpoint->cred_dist.dist_flags & HTC_EP_ACTIVE)) { | ||
819 | endpoint->cred_dist.dist_flags |= HTC_EP_ACTIVE; | ||
820 | dist = true; | ||
821 | } | ||
822 | } else { | ||
823 | if (endpoint->cred_dist.dist_flags & HTC_EP_ACTIVE) { | ||
824 | endpoint->cred_dist.dist_flags &= ~HTC_EP_ACTIVE; | ||
825 | dist = true; | ||
826 | } | ||
827 | } | ||
828 | |||
829 | if (dist) { | ||
830 | endpoint->cred_dist.txq_depth = | ||
831 | get_queue_depth(&endpoint->txq); | ||
832 | |||
833 | ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:0x%p dist:0x%p\n", | ||
834 | target->cred_dist_cntxt, &target->cred_dist_list); | ||
835 | |||
836 | ath6k_credit_distribute(target->cred_dist_cntxt, | ||
837 | &target->cred_dist_list, | ||
838 | HTC_CREDIT_DIST_ACTIVITY_CHANGE); | ||
839 | } | ||
840 | |||
841 | spin_unlock_bh(&target->tx_lock); | ||
842 | |||
843 | if (dist && !active) | ||
844 | htc_chk_ep_txq(target); | ||
845 | } | ||
846 | |||
847 | /* HTC Rx */ | ||
848 | |||
849 | static inline void htc_update_rx_stats(struct htc_endpoint *endpoint, | ||
850 | int n_look_ahds) | ||
851 | { | ||
852 | endpoint->ep_st.rx_pkts++; | ||
853 | if (n_look_ahds == 1) | ||
854 | endpoint->ep_st.rx_lkahds++; | ||
855 | else if (n_look_ahds > 1) | ||
856 | endpoint->ep_st.rx_bundle_lkahd++; | ||
857 | } | ||
858 | |||
859 | static inline bool htc_valid_rx_frame_len(struct htc_target *target, | ||
860 | enum htc_endpoint_id eid, int len) | ||
861 | { | ||
862 | return (eid == target->dev->ar->ctrl_ep) ? | ||
863 | len <= ATH6KL_BUFFER_SIZE : len <= ATH6KL_AMSDU_BUFFER_SIZE; | ||
864 | } | ||
865 | |||
866 | static int htc_add_rxbuf(struct htc_target *target, struct htc_packet *packet) | ||
867 | { | ||
868 | struct list_head queue; | ||
869 | |||
870 | INIT_LIST_HEAD(&queue); | ||
871 | list_add_tail(&packet->list, &queue); | ||
872 | return ath6kl_htc_add_rxbuf_multiple(target, &queue); | ||
873 | } | ||
874 | |||
875 | static void htc_reclaim_rxbuf(struct htc_target *target, | ||
876 | struct htc_packet *packet, | ||
877 | struct htc_endpoint *ep) | ||
878 | { | ||
879 | if (packet->info.rx.rx_flags & HTC_RX_PKT_NO_RECYCLE) { | ||
880 | htc_rxpkt_reset(packet); | ||
881 | packet->status = -ECANCELED; | ||
882 | ep->ep_cb.rx(ep->target, packet); | ||
883 | } else { | ||
884 | htc_rxpkt_reset(packet); | ||
885 | htc_add_rxbuf((void *)(target), packet); | ||
886 | } | ||
887 | } | ||
888 | |||
889 | static void reclaim_rx_ctrl_buf(struct htc_target *target, | ||
890 | struct htc_packet *packet) | ||
891 | { | ||
892 | spin_lock_bh(&target->htc_lock); | ||
893 | list_add_tail(&packet->list, &target->free_ctrl_rxbuf); | ||
894 | spin_unlock_bh(&target->htc_lock); | ||
895 | } | ||
896 | |||
897 | static int dev_rx_pkt(struct htc_target *target, struct htc_packet *packet, | ||
898 | u32 rx_len) | ||
899 | { | ||
900 | struct ath6kl_device *dev = target->dev; | ||
901 | u32 padded_len; | ||
902 | int status; | ||
903 | |||
904 | padded_len = CALC_TXRX_PADDED_LEN(target, rx_len); | ||
905 | |||
906 | if (padded_len > packet->buf_len) { | ||
907 | ath6kl_err("not enough receive space for packet - padlen:%d recvlen:%d bufferlen:%d\n", | ||
908 | padded_len, rx_len, packet->buf_len); | ||
909 | return -ENOMEM; | ||
910 | } | ||
911 | |||
912 | ath6kl_dbg(ATH6KL_DBG_HTC_RECV, | ||
913 | "dev_rx_pkt (0x%p : hdr:0x%X) padded len: %d mbox:0x%X (mode:%s)\n", | ||
914 | packet, packet->info.rx.exp_hdr, | ||
915 | padded_len, dev->ar->mbox_info.htc_addr, "sync"); | ||
916 | |||
917 | status = hif_read_write_sync(dev->ar, | ||
918 | dev->ar->mbox_info.htc_addr, | ||
919 | packet->buf, padded_len, | ||
920 | HIF_RD_SYNC_BLOCK_FIX); | ||
921 | |||
922 | packet->status = status; | ||
923 | |||
924 | return status; | ||
925 | } | ||
926 | |||
927 | /* | ||
928 | * optimization for recv packets, we can indicate a | ||
929 | * "hint" that there are more single-packets to fetch | ||
930 | * on this endpoint. | ||
931 | */ | ||
932 | static void set_rxpkt_indication_flag(u32 lk_ahd, | ||
933 | struct htc_endpoint *endpoint, | ||
934 | struct htc_packet *packet) | ||
935 | { | ||
936 | struct htc_frame_hdr *htc_hdr = (struct htc_frame_hdr *)&lk_ahd; | ||
937 | |||
938 | if (htc_hdr->eid == packet->endpoint) { | ||
939 | if (!list_empty(&endpoint->rx_bufq)) | ||
940 | packet->info.rx.indicat_flags |= | ||
941 | HTC_RX_FLAGS_INDICATE_MORE_PKTS; | ||
942 | } | ||
943 | } | ||
944 | |||
945 | static void chk_rx_water_mark(struct htc_endpoint *endpoint) | ||
946 | { | ||
947 | struct htc_ep_callbacks ep_cb = endpoint->ep_cb; | ||
948 | |||
949 | if (ep_cb.rx_refill_thresh > 0) { | ||
950 | spin_lock_bh(&endpoint->target->rx_lock); | ||
951 | if (get_queue_depth(&endpoint->rx_bufq) | ||
952 | < ep_cb.rx_refill_thresh) { | ||
953 | spin_unlock_bh(&endpoint->target->rx_lock); | ||
954 | ep_cb.rx_refill(endpoint->target, endpoint->eid); | ||
955 | return; | ||
956 | } | ||
957 | spin_unlock_bh(&endpoint->target->rx_lock); | ||
958 | } | ||
959 | } | ||
960 | |||
961 | /* This function is called with rx_lock held */ | ||
962 | static int htc_setup_rxpkts(struct htc_target *target, struct htc_endpoint *ep, | ||
963 | u32 *lk_ahds, struct list_head *queue, int n_msg) | ||
964 | { | ||
965 | struct htc_packet *packet; | ||
966 | /* FIXME: type of lk_ahds can't be right */ | ||
967 | struct htc_frame_hdr *htc_hdr = (struct htc_frame_hdr *)lk_ahds; | ||
968 | struct htc_ep_callbacks ep_cb; | ||
969 | int status = 0, j, full_len; | ||
970 | bool no_recycle; | ||
971 | |||
972 | full_len = CALC_TXRX_PADDED_LEN(target, | ||
973 | le16_to_cpu(htc_hdr->payld_len) + | ||
974 | sizeof(*htc_hdr)); | ||
975 | |||
976 | if (!htc_valid_rx_frame_len(target, ep->eid, full_len)) { | ||
977 | ath6kl_warn("Rx buffer requested with invalid length\n"); | ||
978 | return -EINVAL; | ||
979 | } | ||
980 | |||
981 | ep_cb = ep->ep_cb; | ||
982 | for (j = 0; j < n_msg; j++) { | ||
983 | |||
984 | /* | ||
985 | * Reset flag, any packets allocated using the | ||
986 | * rx_alloc() API cannot be recycled on | ||
987 | * cleanup,they must be explicitly returned. | ||
988 | */ | ||
989 | no_recycle = false; | ||
990 | |||
991 | if (ep_cb.rx_allocthresh && | ||
992 | (full_len > ep_cb.rx_alloc_thresh)) { | ||
993 | ep->ep_st.rx_alloc_thresh_hit += 1; | ||
994 | ep->ep_st.rxalloc_thresh_byte += | ||
995 | le16_to_cpu(htc_hdr->payld_len); | ||
996 | |||
997 | spin_unlock_bh(&target->rx_lock); | ||
998 | no_recycle = true; | ||
999 | |||
1000 | packet = ep_cb.rx_allocthresh(ep->target, ep->eid, | ||
1001 | full_len); | ||
1002 | spin_lock_bh(&target->rx_lock); | ||
1003 | } else { | ||
1004 | /* refill handler is being used */ | ||
1005 | if (list_empty(&ep->rx_bufq)) { | ||
1006 | if (ep_cb.rx_refill) { | ||
1007 | spin_unlock_bh(&target->rx_lock); | ||
1008 | ep_cb.rx_refill(ep->target, ep->eid); | ||
1009 | spin_lock_bh(&target->rx_lock); | ||
1010 | } | ||
1011 | } | ||
1012 | |||
1013 | if (list_empty(&ep->rx_bufq)) | ||
1014 | packet = NULL; | ||
1015 | else { | ||
1016 | packet = list_first_entry(&ep->rx_bufq, | ||
1017 | struct htc_packet, list); | ||
1018 | list_del(&packet->list); | ||
1019 | } | ||
1020 | } | ||
1021 | |||
1022 | if (!packet) { | ||
1023 | target->rx_st_flags |= HTC_RECV_WAIT_BUFFERS; | ||
1024 | target->ep_waiting = ep->eid; | ||
1025 | return -ENOSPC; | ||
1026 | } | ||
1027 | |||
1028 | /* clear flags */ | ||
1029 | packet->info.rx.rx_flags = 0; | ||
1030 | packet->info.rx.indicat_flags = 0; | ||
1031 | packet->status = 0; | ||
1032 | |||
1033 | if (no_recycle) | ||
1034 | /* | ||
1035 | * flag that these packets cannot be | ||
1036 | * recycled, they have to be returned to | ||
1037 | * the user | ||
1038 | */ | ||
1039 | packet->info.rx.rx_flags |= HTC_RX_PKT_NO_RECYCLE; | ||
1040 | |||
1041 | /* Caller needs to free this upon any failure */ | ||
1042 | list_add_tail(&packet->list, queue); | ||
1043 | |||
1044 | if (target->htc_flags & HTC_OP_STATE_STOPPING) { | ||
1045 | status = -ECANCELED; | ||
1046 | break; | ||
1047 | } | ||
1048 | |||
1049 | if (j) { | ||
1050 | packet->info.rx.rx_flags |= HTC_RX_PKT_REFRESH_HDR; | ||
1051 | packet->info.rx.exp_hdr = 0xFFFFFFFF; | ||
1052 | } else | ||
1053 | /* set expected look ahead */ | ||
1054 | packet->info.rx.exp_hdr = *lk_ahds; | ||
1055 | |||
1056 | packet->act_len = le16_to_cpu(htc_hdr->payld_len) + | ||
1057 | HTC_HDR_LENGTH; | ||
1058 | } | ||
1059 | |||
1060 | return status; | ||
1061 | } | ||
1062 | |||
1063 | static int alloc_and_prep_rxpkts(struct htc_target *target, | ||
1064 | u32 lk_ahds[], int msg, | ||
1065 | struct htc_endpoint *endpoint, | ||
1066 | struct list_head *queue) | ||
1067 | { | ||
1068 | int status = 0; | ||
1069 | struct htc_packet *packet, *tmp_pkt; | ||
1070 | struct htc_frame_hdr *htc_hdr; | ||
1071 | int i, n_msg; | ||
1072 | |||
1073 | spin_lock_bh(&target->rx_lock); | ||
1074 | |||
1075 | for (i = 0; i < msg; i++) { | ||
1076 | |||
1077 | htc_hdr = (struct htc_frame_hdr *)&lk_ahds[i]; | ||
1078 | |||
1079 | if (htc_hdr->eid >= ENDPOINT_MAX) { | ||
1080 | ath6kl_err("invalid ep in look-ahead: %d\n", | ||
1081 | htc_hdr->eid); | ||
1082 | status = -ENOMEM; | ||
1083 | break; | ||
1084 | } | ||
1085 | |||
1086 | if (htc_hdr->eid != endpoint->eid) { | ||
1087 | ath6kl_err("invalid ep in look-ahead: %d should be : %d (index:%d)\n", | ||
1088 | htc_hdr->eid, endpoint->eid, i); | ||
1089 | status = -ENOMEM; | ||
1090 | break; | ||
1091 | } | ||
1092 | |||
1093 | if (le16_to_cpu(htc_hdr->payld_len) > HTC_MAX_PAYLOAD_LENGTH) { | ||
1094 | ath6kl_err("payload len %d exceeds max htc : %d !\n", | ||
1095 | htc_hdr->payld_len, | ||
1096 | (u32) HTC_MAX_PAYLOAD_LENGTH); | ||
1097 | status = -ENOMEM; | ||
1098 | break; | ||
1099 | } | ||
1100 | |||
1101 | if (endpoint->svc_id == 0) { | ||
1102 | ath6kl_err("ep %d is not connected !\n", htc_hdr->eid); | ||
1103 | status = -ENOMEM; | ||
1104 | break; | ||
1105 | } | ||
1106 | |||
1107 | if (htc_hdr->flags & HTC_FLG_RX_BNDL_CNT) { | ||
1108 | /* | ||
1109 | * HTC header indicates that every packet to follow | ||
1110 | * has the same padded length so that it can be | ||
1111 | * optimally fetched as a full bundle. | ||
1112 | */ | ||
1113 | n_msg = (htc_hdr->flags & HTC_FLG_RX_BNDL_CNT) >> | ||
1114 | HTC_FLG_RX_BNDL_CNT_S; | ||
1115 | |||
1116 | /* the count doesn't include the starter frame */ | ||
1117 | n_msg++; | ||
1118 | if (n_msg > target->msg_per_bndl_max) { | ||
1119 | status = -ENOMEM; | ||
1120 | break; | ||
1121 | } | ||
1122 | |||
1123 | endpoint->ep_st.rx_bundle_from_hdr += 1; | ||
1124 | ath6kl_dbg(ATH6KL_DBG_HTC_RECV, | ||
1125 | "htc hdr indicates :%d msg can be fetched as a bundle\n", | ||
1126 | n_msg); | ||
1127 | } else | ||
1128 | /* HTC header only indicates 1 message to fetch */ | ||
1129 | n_msg = 1; | ||
1130 | |||
1131 | /* Setup packet buffers for each message */ | ||
1132 | status = htc_setup_rxpkts(target, endpoint, &lk_ahds[i], queue, | ||
1133 | n_msg); | ||
1134 | |||
1135 | /* | ||
1136 | * This is due to unavailabilty of buffers to rx entire data. | ||
1137 | * Return no error so that free buffers from queue can be used | ||
1138 | * to receive partial data. | ||
1139 | */ | ||
1140 | if (status == -ENOSPC) { | ||
1141 | spin_unlock_bh(&target->rx_lock); | ||
1142 | return 0; | ||
1143 | } | ||
1144 | |||
1145 | if (status) | ||
1146 | break; | ||
1147 | } | ||
1148 | |||
1149 | spin_unlock_bh(&target->rx_lock); | ||
1150 | |||
1151 | if (status) { | ||
1152 | list_for_each_entry_safe(packet, tmp_pkt, queue, list) { | ||
1153 | list_del(&packet->list); | ||
1154 | htc_reclaim_rxbuf(target, packet, | ||
1155 | &target->endpoint[packet->endpoint]); | ||
1156 | } | ||
1157 | } | ||
1158 | |||
1159 | return status; | ||
1160 | } | ||
1161 | |||
1162 | static void htc_ctrl_rx(struct htc_target *context, struct htc_packet *packets) | ||
1163 | { | ||
1164 | if (packets->endpoint != ENDPOINT_0) { | ||
1165 | WARN_ON(1); | ||
1166 | return; | ||
1167 | } | ||
1168 | |||
1169 | if (packets->status == -ECANCELED) { | ||
1170 | reclaim_rx_ctrl_buf(context, packets); | ||
1171 | return; | ||
1172 | } | ||
1173 | |||
1174 | if (packets->act_len > 0) { | ||
1175 | ath6kl_err("htc_ctrl_rx, got message with len:%zu\n", | ||
1176 | packets->act_len + HTC_HDR_LENGTH); | ||
1177 | |||
1178 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, | ||
1179 | "Unexpected ENDPOINT 0 Message", | ||
1180 | packets->buf - HTC_HDR_LENGTH, | ||
1181 | packets->act_len + HTC_HDR_LENGTH); | ||
1182 | } | ||
1183 | |||
1184 | htc_reclaim_rxbuf(context, packets, &context->endpoint[0]); | ||
1185 | } | ||
1186 | |||
1187 | static void htc_proc_cred_rpt(struct htc_target *target, | ||
1188 | struct htc_credit_report *rpt, | ||
1189 | int n_entries, | ||
1190 | enum htc_endpoint_id from_ep) | ||
1191 | { | ||
1192 | struct htc_endpoint *endpoint; | ||
1193 | int tot_credits = 0, i; | ||
1194 | bool dist = false; | ||
1195 | |||
1196 | ath6kl_dbg(ATH6KL_DBG_HTC_SEND, | ||
1197 | "htc_proc_cred_rpt, credit report entries:%d\n", n_entries); | ||
1198 | |||
1199 | spin_lock_bh(&target->tx_lock); | ||
1200 | |||
1201 | for (i = 0; i < n_entries; i++, rpt++) { | ||
1202 | if (rpt->eid >= ENDPOINT_MAX) { | ||
1203 | WARN_ON(1); | ||
1204 | spin_unlock_bh(&target->tx_lock); | ||
1205 | return; | ||
1206 | } | ||
1207 | |||
1208 | endpoint = &target->endpoint[rpt->eid]; | ||
1209 | |||
1210 | ath6kl_dbg(ATH6KL_DBG_HTC_SEND, " ep %d got %d credits\n", | ||
1211 | rpt->eid, rpt->credits); | ||
1212 | |||
1213 | endpoint->ep_st.tx_cred_rpt += 1; | ||
1214 | endpoint->ep_st.cred_retnd += rpt->credits; | ||
1215 | |||
1216 | if (from_ep == rpt->eid) { | ||
1217 | /* | ||
1218 | * This credit report arrived on the same endpoint | ||
1219 | * indicating it arrived in an RX packet. | ||
1220 | */ | ||
1221 | endpoint->ep_st.cred_from_rx += rpt->credits; | ||
1222 | endpoint->ep_st.cred_rpt_from_rx += 1; | ||
1223 | } else if (from_ep == ENDPOINT_0) { | ||
1224 | /* credit arrived on endpoint 0 as a NULL message */ | ||
1225 | endpoint->ep_st.cred_from_ep0 += rpt->credits; | ||
1226 | endpoint->ep_st.cred_rpt_ep0 += 1; | ||
1227 | } else { | ||
1228 | endpoint->ep_st.cred_from_other += rpt->credits; | ||
1229 | endpoint->ep_st.cred_rpt_from_other += 1; | ||
1230 | } | ||
1231 | |||
1232 | if (rpt->eid == ENDPOINT_0) | ||
1233 | /* always give endpoint 0 credits back */ | ||
1234 | endpoint->cred_dist.credits += rpt->credits; | ||
1235 | else { | ||
1236 | endpoint->cred_dist.cred_to_dist += rpt->credits; | ||
1237 | dist = true; | ||
1238 | } | ||
1239 | |||
1240 | /* | ||
1241 | * Refresh tx depth for distribution function that will | ||
1242 | * recover these credits NOTE: this is only valid when | ||
1243 | * there are credits to recover! | ||
1244 | */ | ||
1245 | endpoint->cred_dist.txq_depth = | ||
1246 | get_queue_depth(&endpoint->txq); | ||
1247 | |||
1248 | tot_credits += rpt->credits; | ||
1249 | } | ||
1250 | |||
1251 | ath6kl_dbg(ATH6KL_DBG_HTC_SEND, | ||
1252 | "report indicated %d credits to distribute\n", | ||
1253 | tot_credits); | ||
1254 | |||
1255 | if (dist) { | ||
1256 | /* | ||
1257 | * This was a credit return based on a completed send | ||
1258 | * operations note, this is done with the lock held | ||
1259 | */ | ||
1260 | ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:0x%p dist:0x%p\n", | ||
1261 | target->cred_dist_cntxt, &target->cred_dist_list); | ||
1262 | |||
1263 | ath6k_credit_distribute(target->cred_dist_cntxt, | ||
1264 | &target->cred_dist_list, | ||
1265 | HTC_CREDIT_DIST_SEND_COMPLETE); | ||
1266 | } | ||
1267 | |||
1268 | spin_unlock_bh(&target->tx_lock); | ||
1269 | |||
1270 | if (tot_credits) | ||
1271 | htc_chk_ep_txq(target); | ||
1272 | } | ||
1273 | |||
1274 | static int htc_parse_trailer(struct htc_target *target, | ||
1275 | struct htc_record_hdr *record, | ||
1276 | u8 *record_buf, u32 *next_lk_ahds, | ||
1277 | enum htc_endpoint_id endpoint, | ||
1278 | int *n_lk_ahds) | ||
1279 | { | ||
1280 | struct htc_bundle_lkahd_rpt *bundle_lkahd_rpt; | ||
1281 | struct htc_lookahead_report *lk_ahd; | ||
1282 | int len; | ||
1283 | |||
1284 | switch (record->rec_id) { | ||
1285 | case HTC_RECORD_CREDITS: | ||
1286 | len = record->len / sizeof(struct htc_credit_report); | ||
1287 | if (!len) { | ||
1288 | WARN_ON(1); | ||
1289 | return -EINVAL; | ||
1290 | } | ||
1291 | |||
1292 | htc_proc_cred_rpt(target, | ||
1293 | (struct htc_credit_report *) record_buf, | ||
1294 | len, endpoint); | ||
1295 | break; | ||
1296 | case HTC_RECORD_LOOKAHEAD: | ||
1297 | len = record->len / sizeof(*lk_ahd); | ||
1298 | if (!len) { | ||
1299 | WARN_ON(1); | ||
1300 | return -EINVAL; | ||
1301 | } | ||
1302 | |||
1303 | lk_ahd = (struct htc_lookahead_report *) record_buf; | ||
1304 | if ((lk_ahd->pre_valid == ((~lk_ahd->post_valid) & 0xFF)) | ||
1305 | && next_lk_ahds) { | ||
1306 | |||
1307 | ath6kl_dbg(ATH6KL_DBG_HTC_RECV, | ||
1308 | "lk_ahd report found (pre valid:0x%X, post valid:0x%X)\n", | ||
1309 | lk_ahd->pre_valid, lk_ahd->post_valid); | ||
1310 | |||
1311 | /* look ahead bytes are valid, copy them over */ | ||
1312 | memcpy((u8 *)&next_lk_ahds[0], lk_ahd->lk_ahd, 4); | ||
1313 | |||
1314 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Next Look Ahead", | ||
1315 | next_lk_ahds, 4); | ||
1316 | |||
1317 | *n_lk_ahds = 1; | ||
1318 | } | ||
1319 | break; | ||
1320 | case HTC_RECORD_LOOKAHEAD_BUNDLE: | ||
1321 | len = record->len / sizeof(*bundle_lkahd_rpt); | ||
1322 | if (!len || (len > HTC_HOST_MAX_MSG_PER_BUNDLE)) { | ||
1323 | WARN_ON(1); | ||
1324 | return -EINVAL; | ||
1325 | } | ||
1326 | |||
1327 | if (next_lk_ahds) { | ||
1328 | int i; | ||
1329 | |||
1330 | bundle_lkahd_rpt = | ||
1331 | (struct htc_bundle_lkahd_rpt *) record_buf; | ||
1332 | |||
1333 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Bundle lk_ahd", | ||
1334 | record_buf, record->len); | ||
1335 | |||
1336 | for (i = 0; i < len; i++) { | ||
1337 | memcpy((u8 *)&next_lk_ahds[i], | ||
1338 | bundle_lkahd_rpt->lk_ahd, 4); | ||
1339 | bundle_lkahd_rpt++; | ||
1340 | } | ||
1341 | |||
1342 | *n_lk_ahds = i; | ||
1343 | } | ||
1344 | break; | ||
1345 | default: | ||
1346 | ath6kl_err("unhandled record: id:%d len:%d\n", | ||
1347 | record->rec_id, record->len); | ||
1348 | break; | ||
1349 | } | ||
1350 | |||
1351 | return 0; | ||
1352 | |||
1353 | } | ||
1354 | |||
1355 | static int htc_proc_trailer(struct htc_target *target, | ||
1356 | u8 *buf, int len, u32 *next_lk_ahds, | ||
1357 | int *n_lk_ahds, enum htc_endpoint_id endpoint) | ||
1358 | { | ||
1359 | struct htc_record_hdr *record; | ||
1360 | int orig_len; | ||
1361 | int status; | ||
1362 | u8 *record_buf; | ||
1363 | u8 *orig_buf; | ||
1364 | |||
1365 | ath6kl_dbg(ATH6KL_DBG_HTC_RECV, "+htc_proc_trailer (len:%d)\n", len); | ||
1366 | |||
1367 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Recv Trailer", buf, len); | ||
1368 | |||
1369 | orig_buf = buf; | ||
1370 | orig_len = len; | ||
1371 | status = 0; | ||
1372 | |||
1373 | while (len > 0) { | ||
1374 | |||
1375 | if (len < sizeof(struct htc_record_hdr)) { | ||
1376 | status = -ENOMEM; | ||
1377 | break; | ||
1378 | } | ||
1379 | /* these are byte aligned structs */ | ||
1380 | record = (struct htc_record_hdr *) buf; | ||
1381 | len -= sizeof(struct htc_record_hdr); | ||
1382 | buf += sizeof(struct htc_record_hdr); | ||
1383 | |||
1384 | if (record->len > len) { | ||
1385 | ath6kl_err("invalid record len: %d (id:%d) buf has: %d bytes left\n", | ||
1386 | record->len, record->rec_id, len); | ||
1387 | status = -ENOMEM; | ||
1388 | break; | ||
1389 | } | ||
1390 | record_buf = buf; | ||
1391 | |||
1392 | status = htc_parse_trailer(target, record, record_buf, | ||
1393 | next_lk_ahds, endpoint, n_lk_ahds); | ||
1394 | |||
1395 | if (status) | ||
1396 | break; | ||
1397 | |||
1398 | /* advance buffer past this record for next time around */ | ||
1399 | buf += record->len; | ||
1400 | len -= record->len; | ||
1401 | } | ||
1402 | |||
1403 | if (status) | ||
1404 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "BAD Recv Trailer", | ||
1405 | orig_buf, orig_len); | ||
1406 | |||
1407 | return status; | ||
1408 | } | ||
1409 | |||
1410 | static int htc_proc_rxhdr(struct htc_target *target, | ||
1411 | struct htc_packet *packet, | ||
1412 | u32 *next_lkahds, int *n_lkahds) | ||
1413 | { | ||
1414 | int status = 0; | ||
1415 | u16 payload_len; | ||
1416 | u32 lk_ahd; | ||
1417 | struct htc_frame_hdr *htc_hdr = (struct htc_frame_hdr *)packet->buf; | ||
1418 | |||
1419 | if (n_lkahds != NULL) | ||
1420 | *n_lkahds = 0; | ||
1421 | |||
1422 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "HTC Recv PKT", packet->buf, | ||
1423 | packet->act_len); | ||
1424 | |||
1425 | /* | ||
1426 | * NOTE: we cannot assume the alignment of buf, so we use the safe | ||
1427 | * macros to retrieve 16 bit fields. | ||
1428 | */ | ||
1429 | payload_len = le16_to_cpu(get_unaligned(&htc_hdr->payld_len)); | ||
1430 | |||
1431 | memcpy((u8 *)&lk_ahd, packet->buf, sizeof(lk_ahd)); | ||
1432 | |||
1433 | if (packet->info.rx.rx_flags & HTC_RX_PKT_REFRESH_HDR) { | ||
1434 | /* | ||
1435 | * Refresh the expected header and the actual length as it | ||
1436 | * was unknown when this packet was grabbed as part of the | ||
1437 | * bundle. | ||
1438 | */ | ||
1439 | packet->info.rx.exp_hdr = lk_ahd; | ||
1440 | packet->act_len = payload_len + HTC_HDR_LENGTH; | ||
1441 | |||
1442 | /* validate the actual header that was refreshed */ | ||
1443 | if (packet->act_len > packet->buf_len) { | ||
1444 | ath6kl_err("refreshed hdr payload len (%d) in bundled recv is invalid (hdr: 0x%X)\n", | ||
1445 | payload_len, lk_ahd); | ||
1446 | /* | ||
1447 | * Limit this to max buffer just to print out some | ||
1448 | * of the buffer. | ||
1449 | */ | ||
1450 | packet->act_len = min(packet->act_len, packet->buf_len); | ||
1451 | status = -ENOMEM; | ||
1452 | goto fail_rx; | ||
1453 | } | ||
1454 | |||
1455 | if (packet->endpoint != htc_hdr->eid) { | ||
1456 | ath6kl_err("refreshed hdr ep (%d) does not match expected ep (%d)\n", | ||
1457 | htc_hdr->eid, packet->endpoint); | ||
1458 | status = -ENOMEM; | ||
1459 | goto fail_rx; | ||
1460 | } | ||
1461 | } | ||
1462 | |||
1463 | if (lk_ahd != packet->info.rx.exp_hdr) { | ||
1464 | ath6kl_err("htc_proc_rxhdr, lk_ahd mismatch! (pPkt:0x%p flags:0x%X)\n", | ||
1465 | packet, packet->info.rx.rx_flags); | ||
1466 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Expected Message lk_ahd", | ||
1467 | &packet->info.rx.exp_hdr, 4); | ||
1468 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Current Frame Header", | ||
1469 | (u8 *)&lk_ahd, sizeof(lk_ahd)); | ||
1470 | status = -ENOMEM; | ||
1471 | goto fail_rx; | ||
1472 | } | ||
1473 | |||
1474 | if (htc_hdr->flags & HTC_FLG_RX_TRAILER) { | ||
1475 | if (htc_hdr->ctrl[0] < sizeof(struct htc_record_hdr) || | ||
1476 | htc_hdr->ctrl[0] > payload_len) { | ||
1477 | ath6kl_err("htc_proc_rxhdr, invalid hdr (payload len should be :%d, CB[0] is:%d)\n", | ||
1478 | payload_len, htc_hdr->ctrl[0]); | ||
1479 | status = -ENOMEM; | ||
1480 | goto fail_rx; | ||
1481 | } | ||
1482 | |||
1483 | if (packet->info.rx.rx_flags & HTC_RX_PKT_IGNORE_LOOKAHEAD) { | ||
1484 | next_lkahds = NULL; | ||
1485 | n_lkahds = NULL; | ||
1486 | } | ||
1487 | |||
1488 | status = htc_proc_trailer(target, packet->buf + HTC_HDR_LENGTH | ||
1489 | + payload_len - htc_hdr->ctrl[0], | ||
1490 | htc_hdr->ctrl[0], next_lkahds, | ||
1491 | n_lkahds, packet->endpoint); | ||
1492 | |||
1493 | if (status) | ||
1494 | goto fail_rx; | ||
1495 | |||
1496 | packet->act_len -= htc_hdr->ctrl[0]; | ||
1497 | } | ||
1498 | |||
1499 | packet->buf += HTC_HDR_LENGTH; | ||
1500 | packet->act_len -= HTC_HDR_LENGTH; | ||
1501 | |||
1502 | fail_rx: | ||
1503 | if (status) | ||
1504 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "BAD HTC Recv PKT", | ||
1505 | packet->buf, | ||
1506 | packet->act_len < 256 ? packet->act_len : 256); | ||
1507 | else { | ||
1508 | if (packet->act_len > 0) | ||
1509 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, | ||
1510 | "HTC - Application Msg", | ||
1511 | packet->buf, packet->act_len); | ||
1512 | } | ||
1513 | |||
1514 | return status; | ||
1515 | } | ||
1516 | |||
1517 | static void do_rx_completion(struct htc_endpoint *endpoint, | ||
1518 | struct htc_packet *packet) | ||
1519 | { | ||
1520 | ath6kl_dbg(ATH6KL_DBG_HTC_RECV, | ||
1521 | "htc calling ep %d recv callback on packet 0x%p\n", | ||
1522 | endpoint->eid, packet); | ||
1523 | endpoint->ep_cb.rx(endpoint->target, packet); | ||
1524 | } | ||
1525 | |||
1526 | static int htc_issue_rxpkt_bundle(struct htc_target *target, | ||
1527 | struct list_head *rxq, | ||
1528 | struct list_head *sync_compq, | ||
1529 | int *n_pkt_fetched, bool part_bundle) | ||
1530 | { | ||
1531 | struct hif_scatter_req *scat_req; | ||
1532 | struct htc_packet *packet; | ||
1533 | int rem_space = target->max_rx_bndl_sz; | ||
1534 | int n_scat_pkt, status = 0, i, len; | ||
1535 | |||
1536 | n_scat_pkt = get_queue_depth(rxq); | ||
1537 | n_scat_pkt = min(n_scat_pkt, target->msg_per_bndl_max); | ||
1538 | |||
1539 | if ((get_queue_depth(rxq) - n_scat_pkt) > 0) { | ||
1540 | /* | ||
1541 | * We were forced to split this bundle receive operation | ||
1542 | * all packets in this partial bundle must have their | ||
1543 | * lookaheads ignored. | ||
1544 | */ | ||
1545 | part_bundle = true; | ||
1546 | |||
1547 | /* | ||
1548 | * This would only happen if the target ignored our max | ||
1549 | * bundle limit. | ||
1550 | */ | ||
1551 | ath6kl_warn("htc_issue_rxpkt_bundle : partial bundle detected num:%d , %d\n", | ||
1552 | get_queue_depth(rxq), n_scat_pkt); | ||
1553 | } | ||
1554 | |||
1555 | len = 0; | ||
1556 | |||
1557 | ath6kl_dbg(ATH6KL_DBG_HTC_RECV, | ||
1558 | "htc_issue_rxpkt_bundle (numpackets: %d , actual : %d)\n", | ||
1559 | get_queue_depth(rxq), n_scat_pkt); | ||
1560 | |||
1561 | scat_req = hif_scatter_req_get(target->dev->ar); | ||
1562 | |||
1563 | if (scat_req == NULL) | ||
1564 | goto fail_rx_pkt; | ||
1565 | |||
1566 | for (i = 0; i < n_scat_pkt; i++) { | ||
1567 | int pad_len; | ||
1568 | |||
1569 | packet = list_first_entry(rxq, struct htc_packet, list); | ||
1570 | list_del(&packet->list); | ||
1571 | |||
1572 | pad_len = CALC_TXRX_PADDED_LEN(target, | ||
1573 | packet->act_len); | ||
1574 | |||
1575 | if ((rem_space - pad_len) < 0) { | ||
1576 | list_add(&packet->list, rxq); | ||
1577 | break; | ||
1578 | } | ||
1579 | |||
1580 | rem_space -= pad_len; | ||
1581 | |||
1582 | if (part_bundle || (i < (n_scat_pkt - 1))) | ||
1583 | /* | ||
1584 | * Packet 0..n-1 cannot be checked for look-aheads | ||
1585 | * since we are fetching a bundle the last packet | ||
1586 | * however can have it's lookahead used | ||
1587 | */ | ||
1588 | packet->info.rx.rx_flags |= | ||
1589 | HTC_RX_PKT_IGNORE_LOOKAHEAD; | ||
1590 | |||
1591 | /* NOTE: 1 HTC packet per scatter entry */ | ||
1592 | scat_req->scat_list[i].buf = packet->buf; | ||
1593 | scat_req->scat_list[i].len = pad_len; | ||
1594 | |||
1595 | packet->info.rx.rx_flags |= HTC_RX_PKT_PART_OF_BUNDLE; | ||
1596 | |||
1597 | list_add_tail(&packet->list, sync_compq); | ||
1598 | |||
1599 | WARN_ON(!scat_req->scat_list[i].len); | ||
1600 | len += scat_req->scat_list[i].len; | ||
1601 | } | ||
1602 | |||
1603 | scat_req->len = len; | ||
1604 | scat_req->scat_entries = i; | ||
1605 | |||
1606 | status = ath6kldev_submit_scat_req(target->dev, scat_req, true); | ||
1607 | |||
1608 | if (!status) | ||
1609 | *n_pkt_fetched = i; | ||
1610 | |||
1611 | /* free scatter request */ | ||
1612 | hif_scatter_req_add(target->dev->ar, scat_req); | ||
1613 | |||
1614 | fail_rx_pkt: | ||
1615 | |||
1616 | return status; | ||
1617 | } | ||
1618 | |||
1619 | static int htc_proc_fetched_rxpkts(struct htc_target *target, | ||
1620 | struct list_head *comp_pktq, u32 lk_ahds[], | ||
1621 | int *n_lk_ahd) | ||
1622 | { | ||
1623 | struct htc_packet *packet, *tmp_pkt; | ||
1624 | struct htc_endpoint *ep; | ||
1625 | int status = 0; | ||
1626 | |||
1627 | list_for_each_entry_safe(packet, tmp_pkt, comp_pktq, list) { | ||
1628 | list_del(&packet->list); | ||
1629 | ep = &target->endpoint[packet->endpoint]; | ||
1630 | |||
1631 | /* process header for each of the recv packet */ | ||
1632 | status = htc_proc_rxhdr(target, packet, lk_ahds, n_lk_ahd); | ||
1633 | if (status) | ||
1634 | return status; | ||
1635 | |||
1636 | if (list_empty(comp_pktq)) { | ||
1637 | /* | ||
1638 | * Last packet's more packet flag is set | ||
1639 | * based on the lookahead. | ||
1640 | */ | ||
1641 | if (*n_lk_ahd > 0) | ||
1642 | set_rxpkt_indication_flag(lk_ahds[0], | ||
1643 | ep, packet); | ||
1644 | } else | ||
1645 | /* | ||
1646 | * Packets in a bundle automatically have | ||
1647 | * this flag set. | ||
1648 | */ | ||
1649 | packet->info.rx.indicat_flags |= | ||
1650 | HTC_RX_FLAGS_INDICATE_MORE_PKTS; | ||
1651 | |||
1652 | htc_update_rx_stats(ep, *n_lk_ahd); | ||
1653 | |||
1654 | if (packet->info.rx.rx_flags & HTC_RX_PKT_PART_OF_BUNDLE) | ||
1655 | ep->ep_st.rx_bundl += 1; | ||
1656 | |||
1657 | do_rx_completion(ep, packet); | ||
1658 | } | ||
1659 | |||
1660 | return status; | ||
1661 | } | ||
1662 | |||
1663 | static int htc_fetch_rxpkts(struct htc_target *target, | ||
1664 | struct list_head *rx_pktq, | ||
1665 | struct list_head *comp_pktq) | ||
1666 | { | ||
1667 | int fetched_pkts; | ||
1668 | bool part_bundle = false; | ||
1669 | int status = 0; | ||
1670 | |||
1671 | /* now go fetch the list of HTC packets */ | ||
1672 | while (!list_empty(rx_pktq)) { | ||
1673 | fetched_pkts = 0; | ||
1674 | |||
1675 | if (target->rx_bndl_enable && (get_queue_depth(rx_pktq) > 1)) { | ||
1676 | /* | ||
1677 | * There are enough packets to attempt a | ||
1678 | * bundle transfer and recv bundling is | ||
1679 | * allowed. | ||
1680 | */ | ||
1681 | status = htc_issue_rxpkt_bundle(target, rx_pktq, | ||
1682 | comp_pktq, | ||
1683 | &fetched_pkts, | ||
1684 | part_bundle); | ||
1685 | if (status) | ||
1686 | return status; | ||
1687 | |||
1688 | if (!list_empty(rx_pktq)) | ||
1689 | part_bundle = true; | ||
1690 | } | ||
1691 | |||
1692 | if (!fetched_pkts) { | ||
1693 | struct htc_packet *packet; | ||
1694 | |||
1695 | packet = list_first_entry(rx_pktq, struct htc_packet, | ||
1696 | list); | ||
1697 | |||
1698 | list_del(&packet->list); | ||
1699 | |||
1700 | /* fully synchronous */ | ||
1701 | packet->completion = NULL; | ||
1702 | |||
1703 | if (!list_empty(rx_pktq)) | ||
1704 | /* | ||
1705 | * look_aheads in all packet | ||
1706 | * except the last one in the | ||
1707 | * bundle must be ignored | ||
1708 | */ | ||
1709 | packet->info.rx.rx_flags |= | ||
1710 | HTC_RX_PKT_IGNORE_LOOKAHEAD; | ||
1711 | |||
1712 | /* go fetch the packet */ | ||
1713 | status = dev_rx_pkt(target, packet, packet->act_len); | ||
1714 | if (status) | ||
1715 | return status; | ||
1716 | |||
1717 | list_add_tail(&packet->list, comp_pktq); | ||
1718 | } | ||
1719 | } | ||
1720 | |||
1721 | return status; | ||
1722 | } | ||
1723 | |||
1724 | int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target, | ||
1725 | u32 msg_look_ahead[], int *num_pkts) | ||
1726 | { | ||
1727 | struct htc_packet *packets, *tmp_pkt; | ||
1728 | struct htc_endpoint *endpoint; | ||
1729 | struct list_head rx_pktq, comp_pktq; | ||
1730 | int status = 0; | ||
1731 | u32 look_aheads[HTC_HOST_MAX_MSG_PER_BUNDLE]; | ||
1732 | int num_look_ahead = 1; | ||
1733 | enum htc_endpoint_id id; | ||
1734 | int n_fetched = 0; | ||
1735 | |||
1736 | *num_pkts = 0; | ||
1737 | |||
1738 | /* | ||
1739 | * On first entry copy the look_aheads into our temp array for | ||
1740 | * processing | ||
1741 | */ | ||
1742 | memcpy(look_aheads, msg_look_ahead, sizeof(look_aheads)); | ||
1743 | |||
1744 | while (true) { | ||
1745 | |||
1746 | /* | ||
1747 | * First lookahead sets the expected endpoint IDs for all | ||
1748 | * packets in a bundle. | ||
1749 | */ | ||
1750 | id = ((struct htc_frame_hdr *)&look_aheads[0])->eid; | ||
1751 | endpoint = &target->endpoint[id]; | ||
1752 | |||
1753 | if (id >= ENDPOINT_MAX) { | ||
1754 | ath6kl_err("MsgPend, invalid endpoint in look-ahead: %d\n", | ||
1755 | id); | ||
1756 | status = -ENOMEM; | ||
1757 | break; | ||
1758 | } | ||
1759 | |||
1760 | INIT_LIST_HEAD(&rx_pktq); | ||
1761 | INIT_LIST_HEAD(&comp_pktq); | ||
1762 | |||
1763 | /* | ||
1764 | * Try to allocate as many HTC RX packets indicated by the | ||
1765 | * look_aheads. | ||
1766 | */ | ||
1767 | status = alloc_and_prep_rxpkts(target, look_aheads, | ||
1768 | num_look_ahead, endpoint, | ||
1769 | &rx_pktq); | ||
1770 | if (status) | ||
1771 | break; | ||
1772 | |||
1773 | if (get_queue_depth(&rx_pktq) >= 2) | ||
1774 | /* | ||
1775 | * A recv bundle was detected, force IRQ status | ||
1776 | * re-check again | ||
1777 | */ | ||
1778 | target->chk_irq_status_cnt = 1; | ||
1779 | |||
1780 | n_fetched += get_queue_depth(&rx_pktq); | ||
1781 | |||
1782 | num_look_ahead = 0; | ||
1783 | |||
1784 | status = htc_fetch_rxpkts(target, &rx_pktq, &comp_pktq); | ||
1785 | |||
1786 | if (!status) | ||
1787 | chk_rx_water_mark(endpoint); | ||
1788 | |||
1789 | /* Process fetched packets */ | ||
1790 | status = htc_proc_fetched_rxpkts(target, &comp_pktq, | ||
1791 | look_aheads, &num_look_ahead); | ||
1792 | |||
1793 | if (!num_look_ahead || status) | ||
1794 | break; | ||
1795 | |||
1796 | /* | ||
1797 | * For SYNCH processing, if we get here, we are running | ||
1798 | * through the loop again due to a detected lookahead. Set | ||
1799 | * flag that we should re-check IRQ status registers again | ||
1800 | * before leaving IRQ processing, this can net better | ||
1801 | * performance in high throughput situations. | ||
1802 | */ | ||
1803 | target->chk_irq_status_cnt = 1; | ||
1804 | } | ||
1805 | |||
1806 | if (status) { | ||
1807 | ath6kl_err("failed to get pending recv messages: %d\n", | ||
1808 | status); | ||
1809 | /* | ||
1810 | * Cleanup any packets we allocated but didn't use to | ||
1811 | * actually fetch any packets. | ||
1812 | */ | ||
1813 | list_for_each_entry_safe(packets, tmp_pkt, &rx_pktq, list) { | ||
1814 | list_del(&packets->list); | ||
1815 | htc_reclaim_rxbuf(target, packets, | ||
1816 | &target->endpoint[packets->endpoint]); | ||
1817 | } | ||
1818 | |||
1819 | /* cleanup any packets in sync completion queue */ | ||
1820 | list_for_each_entry_safe(packets, tmp_pkt, &comp_pktq, list) { | ||
1821 | list_del(&packets->list); | ||
1822 | htc_reclaim_rxbuf(target, packets, | ||
1823 | &target->endpoint[packets->endpoint]); | ||
1824 | } | ||
1825 | |||
1826 | if (target->htc_flags & HTC_OP_STATE_STOPPING) { | ||
1827 | ath6kl_warn("host is going to stop blocking receiver for htc_stop\n"); | ||
1828 | ath6kldev_rx_control(target->dev, false); | ||
1829 | } | ||
1830 | } | ||
1831 | |||
1832 | /* | ||
1833 | * Before leaving, check to see if host ran out of buffers and | ||
1834 | * needs to stop the receiver. | ||
1835 | */ | ||
1836 | if (target->rx_st_flags & HTC_RECV_WAIT_BUFFERS) { | ||
1837 | ath6kl_warn("host has no rx buffers blocking receiver to prevent overrun\n"); | ||
1838 | ath6kldev_rx_control(target->dev, false); | ||
1839 | } | ||
1840 | *num_pkts = n_fetched; | ||
1841 | |||
1842 | return status; | ||
1843 | } | ||
1844 | |||
1845 | /* | ||
1846 | * Synchronously wait for a control message from the target, | ||
1847 | * This function is used at initialization time ONLY. At init messages | ||
1848 | * on ENDPOINT 0 are expected. | ||
1849 | */ | ||
1850 | static struct htc_packet *htc_wait_for_ctrl_msg(struct htc_target *target) | ||
1851 | { | ||
1852 | struct htc_packet *packet = NULL; | ||
1853 | struct htc_frame_hdr *htc_hdr; | ||
1854 | u32 look_ahead; | ||
1855 | |||
1856 | if (ath6kldev_poll_mboxmsg_rx(target->dev, &look_ahead, | ||
1857 | HTC_TARGET_RESPONSE_TIMEOUT)) | ||
1858 | return NULL; | ||
1859 | |||
1860 | ath6kl_dbg(ATH6KL_DBG_HTC_RECV, | ||
1861 | "htc_wait_for_ctrl_msg: look_ahead : 0x%X\n", look_ahead); | ||
1862 | |||
1863 | htc_hdr = (struct htc_frame_hdr *)&look_ahead; | ||
1864 | |||
1865 | if (htc_hdr->eid != ENDPOINT_0) | ||
1866 | return NULL; | ||
1867 | |||
1868 | packet = htc_get_control_buf(target, false); | ||
1869 | |||
1870 | if (!packet) | ||
1871 | return NULL; | ||
1872 | |||
1873 | packet->info.rx.rx_flags = 0; | ||
1874 | packet->info.rx.exp_hdr = look_ahead; | ||
1875 | packet->act_len = le16_to_cpu(htc_hdr->payld_len) + HTC_HDR_LENGTH; | ||
1876 | |||
1877 | if (packet->act_len > packet->buf_len) | ||
1878 | goto fail_ctrl_rx; | ||
1879 | |||
1880 | /* we want synchronous operation */ | ||
1881 | packet->completion = NULL; | ||
1882 | |||
1883 | /* get the message from the device, this will block */ | ||
1884 | if (dev_rx_pkt(target, packet, packet->act_len)) | ||
1885 | goto fail_ctrl_rx; | ||
1886 | |||
1887 | /* process receive header */ | ||
1888 | packet->status = htc_proc_rxhdr(target, packet, NULL, NULL); | ||
1889 | |||
1890 | if (packet->status) { | ||
1891 | ath6kl_err("htc_wait_for_ctrl_msg, htc_proc_rxhdr failed (status = %d)\n", | ||
1892 | packet->status); | ||
1893 | goto fail_ctrl_rx; | ||
1894 | } | ||
1895 | |||
1896 | return packet; | ||
1897 | |||
1898 | fail_ctrl_rx: | ||
1899 | if (packet != NULL) { | ||
1900 | htc_rxpkt_reset(packet); | ||
1901 | reclaim_rx_ctrl_buf(target, packet); | ||
1902 | } | ||
1903 | |||
1904 | return NULL; | ||
1905 | } | ||
1906 | |||
1907 | int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target, | ||
1908 | struct list_head *pkt_queue) | ||
1909 | { | ||
1910 | struct htc_endpoint *endpoint; | ||
1911 | struct htc_packet *first_pkt; | ||
1912 | bool rx_unblock = false; | ||
1913 | int status = 0, depth; | ||
1914 | |||
1915 | if (list_empty(pkt_queue)) | ||
1916 | return -ENOMEM; | ||
1917 | |||
1918 | first_pkt = list_first_entry(pkt_queue, struct htc_packet, list); | ||
1919 | |||
1920 | if (first_pkt->endpoint >= ENDPOINT_MAX) | ||
1921 | return status; | ||
1922 | |||
1923 | depth = get_queue_depth(pkt_queue); | ||
1924 | |||
1925 | ath6kl_dbg(ATH6KL_DBG_HTC_RECV, | ||
1926 | "htc_add_rxbuf_multiple: ep id: %d, cnt:%d, len: %d\n", | ||
1927 | first_pkt->endpoint, depth, first_pkt->buf_len); | ||
1928 | |||
1929 | endpoint = &target->endpoint[first_pkt->endpoint]; | ||
1930 | |||
1931 | if (target->htc_flags & HTC_OP_STATE_STOPPING) { | ||
1932 | struct htc_packet *packet, *tmp_pkt; | ||
1933 | |||
1934 | /* walk through queue and mark each one canceled */ | ||
1935 | list_for_each_entry_safe(packet, tmp_pkt, pkt_queue, list) { | ||
1936 | packet->status = -ECANCELED; | ||
1937 | list_del(&packet->list); | ||
1938 | do_rx_completion(endpoint, packet); | ||
1939 | } | ||
1940 | |||
1941 | return status; | ||
1942 | } | ||
1943 | |||
1944 | spin_lock_bh(&target->rx_lock); | ||
1945 | |||
1946 | list_splice_tail_init(pkt_queue, &endpoint->rx_bufq); | ||
1947 | |||
1948 | /* check if we are blocked waiting for a new buffer */ | ||
1949 | if (target->rx_st_flags & HTC_RECV_WAIT_BUFFERS) { | ||
1950 | if (target->ep_waiting == first_pkt->endpoint) { | ||
1951 | ath6kl_dbg(ATH6KL_DBG_HTC_RECV, | ||
1952 | "receiver was blocked on ep:%d, unblocking.\n", | ||
1953 | target->ep_waiting); | ||
1954 | target->rx_st_flags &= ~HTC_RECV_WAIT_BUFFERS; | ||
1955 | target->ep_waiting = ENDPOINT_MAX; | ||
1956 | rx_unblock = true; | ||
1957 | } | ||
1958 | } | ||
1959 | |||
1960 | spin_unlock_bh(&target->rx_lock); | ||
1961 | |||
1962 | if (rx_unblock && !(target->htc_flags & HTC_OP_STATE_STOPPING)) | ||
1963 | /* TODO : implement a buffer threshold count? */ | ||
1964 | ath6kldev_rx_control(target->dev, true); | ||
1965 | |||
1966 | return status; | ||
1967 | } | ||
1968 | |||
1969 | void ath6kl_htc_flush_rx_buf(struct htc_target *target) | ||
1970 | { | ||
1971 | struct htc_endpoint *endpoint; | ||
1972 | struct htc_packet *packet, *tmp_pkt; | ||
1973 | int i; | ||
1974 | |||
1975 | for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) { | ||
1976 | endpoint = &target->endpoint[i]; | ||
1977 | if (!endpoint->svc_id) | ||
1978 | /* not in use.. */ | ||
1979 | continue; | ||
1980 | |||
1981 | spin_lock_bh(&target->rx_lock); | ||
1982 | list_for_each_entry_safe(packet, tmp_pkt, | ||
1983 | &endpoint->rx_bufq, list) { | ||
1984 | list_del(&packet->list); | ||
1985 | spin_unlock_bh(&target->rx_lock); | ||
1986 | ath6kl_dbg(ATH6KL_DBG_HTC_RECV, | ||
1987 | "flushing rx pkt:0x%p, len:%d, ep:%d\n", | ||
1988 | packet, packet->buf_len, | ||
1989 | packet->endpoint); | ||
1990 | dev_kfree_skb(packet->pkt_cntxt); | ||
1991 | spin_lock_bh(&target->rx_lock); | ||
1992 | } | ||
1993 | spin_unlock_bh(&target->rx_lock); | ||
1994 | } | ||
1995 | } | ||
1996 | |||
1997 | int ath6kl_htc_conn_service(struct htc_target *target, | ||
1998 | struct htc_service_connect_req *conn_req, | ||
1999 | struct htc_service_connect_resp *conn_resp) | ||
2000 | { | ||
2001 | struct htc_packet *rx_pkt = NULL; | ||
2002 | struct htc_packet *tx_pkt = NULL; | ||
2003 | struct htc_conn_service_resp *resp_msg; | ||
2004 | struct htc_conn_service_msg *conn_msg; | ||
2005 | struct htc_endpoint *endpoint; | ||
2006 | enum htc_endpoint_id assigned_ep = ENDPOINT_MAX; | ||
2007 | unsigned int max_msg_sz = 0; | ||
2008 | int status = 0; | ||
2009 | |||
2010 | ath6kl_dbg(ATH6KL_DBG_TRC, | ||
2011 | "htc_conn_service, target:0x%p service id:0x%X\n", | ||
2012 | target, conn_req->svc_id); | ||
2013 | |||
2014 | if (conn_req->svc_id == HTC_CTRL_RSVD_SVC) { | ||
2015 | /* special case for pseudo control service */ | ||
2016 | assigned_ep = ENDPOINT_0; | ||
2017 | max_msg_sz = HTC_MAX_CTRL_MSG_LEN; | ||
2018 | } else { | ||
2019 | /* allocate a packet to send to the target */ | ||
2020 | tx_pkt = htc_get_control_buf(target, true); | ||
2021 | |||
2022 | if (!tx_pkt) | ||
2023 | return -ENOMEM; | ||
2024 | |||
2025 | conn_msg = (struct htc_conn_service_msg *)tx_pkt->buf; | ||
2026 | memset(conn_msg, 0, sizeof(*conn_msg)); | ||
2027 | conn_msg->msg_id = cpu_to_le16(HTC_MSG_CONN_SVC_ID); | ||
2028 | conn_msg->svc_id = cpu_to_le16(conn_req->svc_id); | ||
2029 | conn_msg->conn_flags = cpu_to_le16(conn_req->conn_flags); | ||
2030 | |||
2031 | set_htc_pkt_info(tx_pkt, NULL, (u8 *) conn_msg, | ||
2032 | sizeof(*conn_msg) + conn_msg->svc_meta_len, | ||
2033 | ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); | ||
2034 | |||
2035 | /* we want synchronous operation */ | ||
2036 | tx_pkt->completion = NULL; | ||
2037 | htc_prep_send_pkt(tx_pkt, 0, 0, 0); | ||
2038 | status = htc_issue_send(target, tx_pkt); | ||
2039 | |||
2040 | if (status) | ||
2041 | goto fail_tx; | ||
2042 | |||
2043 | /* wait for response */ | ||
2044 | rx_pkt = htc_wait_for_ctrl_msg(target); | ||
2045 | |||
2046 | if (!rx_pkt) { | ||
2047 | status = -ENOMEM; | ||
2048 | goto fail_tx; | ||
2049 | } | ||
2050 | |||
2051 | resp_msg = (struct htc_conn_service_resp *)rx_pkt->buf; | ||
2052 | |||
2053 | if ((le16_to_cpu(resp_msg->msg_id) != HTC_MSG_CONN_SVC_RESP_ID) | ||
2054 | || (rx_pkt->act_len < sizeof(*resp_msg))) { | ||
2055 | status = -ENOMEM; | ||
2056 | goto fail_tx; | ||
2057 | } | ||
2058 | |||
2059 | conn_resp->resp_code = resp_msg->status; | ||
2060 | /* check response status */ | ||
2061 | if (resp_msg->status != HTC_SERVICE_SUCCESS) { | ||
2062 | ath6kl_err("target failed service 0x%X connect request (status:%d)\n", | ||
2063 | resp_msg->svc_id, resp_msg->status); | ||
2064 | status = -ENOMEM; | ||
2065 | goto fail_tx; | ||
2066 | } | ||
2067 | |||
2068 | assigned_ep = (enum htc_endpoint_id)resp_msg->eid; | ||
2069 | max_msg_sz = le16_to_cpu(resp_msg->max_msg_sz); | ||
2070 | } | ||
2071 | |||
2072 | if (assigned_ep >= ENDPOINT_MAX || !max_msg_sz) { | ||
2073 | status = -ENOMEM; | ||
2074 | goto fail_tx; | ||
2075 | } | ||
2076 | |||
2077 | endpoint = &target->endpoint[assigned_ep]; | ||
2078 | endpoint->eid = assigned_ep; | ||
2079 | if (endpoint->svc_id) { | ||
2080 | status = -ENOMEM; | ||
2081 | goto fail_tx; | ||
2082 | } | ||
2083 | |||
2084 | /* return assigned endpoint to caller */ | ||
2085 | conn_resp->endpoint = assigned_ep; | ||
2086 | conn_resp->len_max = max_msg_sz; | ||
2087 | |||
2088 | /* setup the endpoint */ | ||
2089 | |||
2090 | /* this marks the endpoint in use */ | ||
2091 | endpoint->svc_id = conn_req->svc_id; | ||
2092 | |||
2093 | endpoint->max_txq_depth = conn_req->max_txq_depth; | ||
2094 | endpoint->len_max = max_msg_sz; | ||
2095 | endpoint->ep_cb = conn_req->ep_cb; | ||
2096 | endpoint->cred_dist.svc_id = conn_req->svc_id; | ||
2097 | endpoint->cred_dist.htc_rsvd = endpoint; | ||
2098 | endpoint->cred_dist.endpoint = assigned_ep; | ||
2099 | endpoint->cred_dist.cred_sz = target->tgt_cred_sz; | ||
2100 | |||
2101 | if (conn_req->max_rxmsg_sz) { | ||
2102 | /* | ||
2103 | * Override cred_per_msg calculation, this optimizes | ||
2104 | * the credit-low indications since the host will actually | ||
2105 | * issue smaller messages in the Send path. | ||
2106 | */ | ||
2107 | if (conn_req->max_rxmsg_sz > max_msg_sz) { | ||
2108 | status = -ENOMEM; | ||
2109 | goto fail_tx; | ||
2110 | } | ||
2111 | endpoint->cred_dist.cred_per_msg = | ||
2112 | conn_req->max_rxmsg_sz / target->tgt_cred_sz; | ||
2113 | } else | ||
2114 | endpoint->cred_dist.cred_per_msg = | ||
2115 | max_msg_sz / target->tgt_cred_sz; | ||
2116 | |||
2117 | if (!endpoint->cred_dist.cred_per_msg) | ||
2118 | endpoint->cred_dist.cred_per_msg = 1; | ||
2119 | |||
2120 | /* save local connection flags */ | ||
2121 | endpoint->conn_flags = conn_req->flags; | ||
2122 | |||
2123 | fail_tx: | ||
2124 | if (tx_pkt) | ||
2125 | htc_reclaim_txctrl_buf(target, tx_pkt); | ||
2126 | |||
2127 | if (rx_pkt) { | ||
2128 | htc_rxpkt_reset(rx_pkt); | ||
2129 | reclaim_rx_ctrl_buf(target, rx_pkt); | ||
2130 | } | ||
2131 | |||
2132 | return status; | ||
2133 | } | ||
2134 | |||
2135 | static void reset_ep_state(struct htc_target *target) | ||
2136 | { | ||
2137 | struct htc_endpoint *endpoint; | ||
2138 | int i; | ||
2139 | |||
2140 | for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) { | ||
2141 | endpoint = &target->endpoint[i]; | ||
2142 | memset(&endpoint->cred_dist, 0, sizeof(endpoint->cred_dist)); | ||
2143 | endpoint->svc_id = 0; | ||
2144 | endpoint->len_max = 0; | ||
2145 | endpoint->max_txq_depth = 0; | ||
2146 | memset(&endpoint->ep_st, 0, | ||
2147 | sizeof(endpoint->ep_st)); | ||
2148 | INIT_LIST_HEAD(&endpoint->rx_bufq); | ||
2149 | INIT_LIST_HEAD(&endpoint->txq); | ||
2150 | endpoint->target = target; | ||
2151 | } | ||
2152 | |||
2153 | /* reset distribution list */ | ||
2154 | INIT_LIST_HEAD(&target->cred_dist_list); | ||
2155 | } | ||
2156 | |||
2157 | int ath6kl_htc_get_rxbuf_num(struct htc_target *target, | ||
2158 | enum htc_endpoint_id endpoint) | ||
2159 | { | ||
2160 | int num; | ||
2161 | |||
2162 | spin_lock_bh(&target->rx_lock); | ||
2163 | num = get_queue_depth(&(target->endpoint[endpoint].rx_bufq)); | ||
2164 | spin_unlock_bh(&target->rx_lock); | ||
2165 | return num; | ||
2166 | } | ||
2167 | |||
2168 | static void htc_setup_msg_bndl(struct htc_target *target) | ||
2169 | { | ||
2170 | /* limit what HTC can handle */ | ||
2171 | target->msg_per_bndl_max = min(HTC_HOST_MAX_MSG_PER_BUNDLE, | ||
2172 | target->msg_per_bndl_max); | ||
2173 | |||
2174 | if (ath6kl_hif_enable_scatter(target->dev->ar)) { | ||
2175 | target->msg_per_bndl_max = 0; | ||
2176 | return; | ||
2177 | } | ||
2178 | |||
2179 | /* limit bundle what the device layer can handle */ | ||
2180 | target->msg_per_bndl_max = min(target->max_scat_entries, | ||
2181 | target->msg_per_bndl_max); | ||
2182 | |||
2183 | ath6kl_dbg(ATH6KL_DBG_TRC, | ||
2184 | "htc bundling allowed. max msg per htc bundle: %d\n", | ||
2185 | target->msg_per_bndl_max); | ||
2186 | |||
2187 | /* Max rx bundle size is limited by the max tx bundle size */ | ||
2188 | target->max_rx_bndl_sz = target->max_xfer_szper_scatreq; | ||
2189 | /* Max tx bundle size if limited by the extended mbox address range */ | ||
2190 | target->max_tx_bndl_sz = min(HIF_MBOX0_EXT_WIDTH, | ||
2191 | target->max_xfer_szper_scatreq); | ||
2192 | |||
2193 | ath6kl_dbg(ATH6KL_DBG_ANY, "max recv: %d max send: %d\n", | ||
2194 | target->max_rx_bndl_sz, target->max_tx_bndl_sz); | ||
2195 | |||
2196 | if (target->max_tx_bndl_sz) | ||
2197 | target->tx_bndl_enable = true; | ||
2198 | |||
2199 | if (target->max_rx_bndl_sz) | ||
2200 | target->rx_bndl_enable = true; | ||
2201 | |||
2202 | if ((target->tgt_cred_sz % target->block_sz) != 0) { | ||
2203 | ath6kl_warn("credit size: %d is not block aligned! Disabling send bundling\n", | ||
2204 | target->tgt_cred_sz); | ||
2205 | |||
2206 | /* | ||
2207 | * Disallow send bundling since the credit size is | ||
2208 | * not aligned to a block size the I/O block | ||
2209 | * padding will spill into the next credit buffer | ||
2210 | * which is fatal. | ||
2211 | */ | ||
2212 | target->tx_bndl_enable = false; | ||
2213 | } | ||
2214 | } | ||
2215 | |||
2216 | int ath6kl_htc_wait_target(struct htc_target *target) | ||
2217 | { | ||
2218 | struct htc_packet *packet = NULL; | ||
2219 | struct htc_ready_ext_msg *rdy_msg; | ||
2220 | struct htc_service_connect_req connect; | ||
2221 | struct htc_service_connect_resp resp; | ||
2222 | int status; | ||
2223 | |||
2224 | /* we should be getting 1 control message that the target is ready */ | ||
2225 | packet = htc_wait_for_ctrl_msg(target); | ||
2226 | |||
2227 | if (!packet) | ||
2228 | return -ENOMEM; | ||
2229 | |||
2230 | /* we controlled the buffer creation so it's properly aligned */ | ||
2231 | rdy_msg = (struct htc_ready_ext_msg *)packet->buf; | ||
2232 | |||
2233 | if ((le16_to_cpu(rdy_msg->ver2_0_info.msg_id) != HTC_MSG_READY_ID) || | ||
2234 | (packet->act_len < sizeof(struct htc_ready_msg))) { | ||
2235 | status = -ENOMEM; | ||
2236 | goto fail_wait_target; | ||
2237 | } | ||
2238 | |||
2239 | if (!rdy_msg->ver2_0_info.cred_cnt || !rdy_msg->ver2_0_info.cred_sz) { | ||
2240 | status = -ENOMEM; | ||
2241 | goto fail_wait_target; | ||
2242 | } | ||
2243 | |||
2244 | target->tgt_creds = le16_to_cpu(rdy_msg->ver2_0_info.cred_cnt); | ||
2245 | target->tgt_cred_sz = le16_to_cpu(rdy_msg->ver2_0_info.cred_sz); | ||
2246 | |||
2247 | ath6kl_dbg(ATH6KL_DBG_HTC_RECV, | ||
2248 | "target ready: credits: %d credit size: %d\n", | ||
2249 | target->tgt_creds, target->tgt_cred_sz); | ||
2250 | |||
2251 | /* check if this is an extended ready message */ | ||
2252 | if (packet->act_len >= sizeof(struct htc_ready_ext_msg)) { | ||
2253 | /* this is an extended message */ | ||
2254 | target->htc_tgt_ver = rdy_msg->htc_ver; | ||
2255 | target->msg_per_bndl_max = rdy_msg->msg_per_htc_bndl; | ||
2256 | } else { | ||
2257 | /* legacy */ | ||
2258 | target->htc_tgt_ver = HTC_VERSION_2P0; | ||
2259 | target->msg_per_bndl_max = 0; | ||
2260 | } | ||
2261 | |||
2262 | ath6kl_dbg(ATH6KL_DBG_TRC, "using htc protocol version : %s (%d)\n", | ||
2263 | (target->htc_tgt_ver == HTC_VERSION_2P0) ? "2.0" : ">= 2.1", | ||
2264 | target->htc_tgt_ver); | ||
2265 | |||
2266 | if (target->msg_per_bndl_max > 0) | ||
2267 | htc_setup_msg_bndl(target); | ||
2268 | |||
2269 | /* setup our pseudo HTC control endpoint connection */ | ||
2270 | memset(&connect, 0, sizeof(connect)); | ||
2271 | memset(&resp, 0, sizeof(resp)); | ||
2272 | connect.ep_cb.rx = htc_ctrl_rx; | ||
2273 | connect.ep_cb.rx_refill = NULL; | ||
2274 | connect.ep_cb.tx_full = NULL; | ||
2275 | connect.max_txq_depth = NUM_CONTROL_BUFFERS; | ||
2276 | connect.svc_id = HTC_CTRL_RSVD_SVC; | ||
2277 | |||
2278 | /* connect fake service */ | ||
2279 | status = ath6kl_htc_conn_service((void *)target, &connect, &resp); | ||
2280 | |||
2281 | if (status) | ||
2282 | ath6kl_hif_cleanup_scatter(target->dev->ar); | ||
2283 | |||
2284 | fail_wait_target: | ||
2285 | if (packet) { | ||
2286 | htc_rxpkt_reset(packet); | ||
2287 | reclaim_rx_ctrl_buf(target, packet); | ||
2288 | } | ||
2289 | |||
2290 | return status; | ||
2291 | } | ||
2292 | |||
2293 | /* | ||
2294 | * Start HTC, enable interrupts and let the target know | ||
2295 | * host has finished setup. | ||
2296 | */ | ||
2297 | int ath6kl_htc_start(struct htc_target *target) | ||
2298 | { | ||
2299 | struct htc_packet *packet; | ||
2300 | int status; | ||
2301 | |||
2302 | /* Disable interrupts at the chip level */ | ||
2303 | ath6kldev_disable_intrs(target->dev); | ||
2304 | |||
2305 | target->htc_flags = 0; | ||
2306 | target->rx_st_flags = 0; | ||
2307 | |||
2308 | /* Push control receive buffers into htc control endpoint */ | ||
2309 | while ((packet = htc_get_control_buf(target, false)) != NULL) { | ||
2310 | status = htc_add_rxbuf(target, packet); | ||
2311 | if (status) | ||
2312 | return status; | ||
2313 | } | ||
2314 | |||
2315 | /* NOTE: the first entry in the distribution list is ENDPOINT_0 */ | ||
2316 | ath6k_credit_init(target->cred_dist_cntxt, &target->cred_dist_list, | ||
2317 | target->tgt_creds); | ||
2318 | |||
2319 | dump_cred_dist_stats(target); | ||
2320 | |||
2321 | /* Indicate to the target of the setup completion */ | ||
2322 | status = htc_setup_tx_complete(target); | ||
2323 | |||
2324 | if (status) | ||
2325 | return status; | ||
2326 | |||
2327 | /* unmask interrupts */ | ||
2328 | status = ath6kldev_unmask_intrs(target->dev); | ||
2329 | |||
2330 | if (status) | ||
2331 | ath6kl_htc_stop(target); | ||
2332 | |||
2333 | return status; | ||
2334 | } | ||
2335 | |||
2336 | /* htc_stop: stop interrupt reception, and flush all queued buffers */ | ||
2337 | void ath6kl_htc_stop(struct htc_target *target) | ||
2338 | { | ||
2339 | spin_lock_bh(&target->htc_lock); | ||
2340 | target->htc_flags |= HTC_OP_STATE_STOPPING; | ||
2341 | spin_unlock_bh(&target->htc_lock); | ||
2342 | |||
2343 | /* | ||
2344 | * Masking interrupts is a synchronous operation, when this | ||
2345 | * function returns all pending HIF I/O has completed, we can | ||
2346 | * safely flush the queues. | ||
2347 | */ | ||
2348 | ath6kldev_mask_intrs(target->dev); | ||
2349 | |||
2350 | ath6kl_htc_flush_txep_all(target); | ||
2351 | |||
2352 | ath6kl_htc_flush_rx_buf(target); | ||
2353 | |||
2354 | reset_ep_state(target); | ||
2355 | } | ||
2356 | |||
2357 | void *ath6kl_htc_create(struct ath6kl *ar) | ||
2358 | { | ||
2359 | struct htc_target *target = NULL; | ||
2360 | struct htc_packet *packet; | ||
2361 | int status = 0, i = 0; | ||
2362 | u32 block_size, ctrl_bufsz; | ||
2363 | |||
2364 | target = kzalloc(sizeof(*target), GFP_KERNEL); | ||
2365 | if (!target) { | ||
2366 | ath6kl_err("unable to allocate memory\n"); | ||
2367 | return NULL; | ||
2368 | } | ||
2369 | |||
2370 | target->dev = kzalloc(sizeof(*target->dev), GFP_KERNEL); | ||
2371 | if (!target->dev) { | ||
2372 | ath6kl_err("unable to allocate memory\n"); | ||
2373 | status = -ENOMEM; | ||
2374 | goto fail_create_htc; | ||
2375 | } | ||
2376 | |||
2377 | spin_lock_init(&target->htc_lock); | ||
2378 | spin_lock_init(&target->rx_lock); | ||
2379 | spin_lock_init(&target->tx_lock); | ||
2380 | |||
2381 | INIT_LIST_HEAD(&target->free_ctrl_txbuf); | ||
2382 | INIT_LIST_HEAD(&target->free_ctrl_rxbuf); | ||
2383 | INIT_LIST_HEAD(&target->cred_dist_list); | ||
2384 | |||
2385 | target->dev->ar = ar; | ||
2386 | target->dev->htc_cnxt = target; | ||
2387 | target->ep_waiting = ENDPOINT_MAX; | ||
2388 | |||
2389 | reset_ep_state(target); | ||
2390 | |||
2391 | status = ath6kldev_setup(target->dev); | ||
2392 | |||
2393 | if (status) | ||
2394 | goto fail_create_htc; | ||
2395 | |||
2396 | block_size = ar->mbox_info.block_size; | ||
2397 | |||
2398 | ctrl_bufsz = (block_size > HTC_MAX_CTRL_MSG_LEN) ? | ||
2399 | (block_size + HTC_HDR_LENGTH) : | ||
2400 | (HTC_MAX_CTRL_MSG_LEN + HTC_HDR_LENGTH); | ||
2401 | |||
2402 | for (i = 0; i < NUM_CONTROL_BUFFERS; i++) { | ||
2403 | packet = kzalloc(sizeof(*packet), GFP_KERNEL); | ||
2404 | if (!packet) | ||
2405 | break; | ||
2406 | |||
2407 | packet->buf_start = kzalloc(ctrl_bufsz, GFP_KERNEL); | ||
2408 | if (!packet->buf_start) { | ||
2409 | kfree(packet); | ||
2410 | break; | ||
2411 | } | ||
2412 | |||
2413 | packet->buf_len = ctrl_bufsz; | ||
2414 | if (i < NUM_CONTROL_RX_BUFFERS) { | ||
2415 | packet->act_len = 0; | ||
2416 | packet->buf = packet->buf_start; | ||
2417 | packet->endpoint = ENDPOINT_0; | ||
2418 | list_add_tail(&packet->list, &target->free_ctrl_rxbuf); | ||
2419 | } else | ||
2420 | list_add_tail(&packet->list, &target->free_ctrl_txbuf); | ||
2421 | } | ||
2422 | |||
2423 | fail_create_htc: | ||
2424 | if (i != NUM_CONTROL_BUFFERS || status) { | ||
2425 | if (target) { | ||
2426 | ath6kl_htc_cleanup(target); | ||
2427 | target = NULL; | ||
2428 | } | ||
2429 | } | ||
2430 | |||
2431 | return target; | ||
2432 | } | ||
2433 | |||
2434 | /* cleanup the HTC instance */ | ||
2435 | void ath6kl_htc_cleanup(struct htc_target *target) | ||
2436 | { | ||
2437 | struct htc_packet *packet, *tmp_packet; | ||
2438 | |||
2439 | ath6kl_hif_cleanup_scatter(target->dev->ar); | ||
2440 | |||
2441 | list_for_each_entry_safe(packet, tmp_packet, | ||
2442 | &target->free_ctrl_txbuf, list) { | ||
2443 | list_del(&packet->list); | ||
2444 | kfree(packet->buf_start); | ||
2445 | kfree(packet); | ||
2446 | } | ||
2447 | |||
2448 | list_for_each_entry_safe(packet, tmp_packet, | ||
2449 | &target->free_ctrl_rxbuf, list) { | ||
2450 | list_del(&packet->list); | ||
2451 | kfree(packet->buf_start); | ||
2452 | kfree(packet); | ||
2453 | } | ||
2454 | |||
2455 | kfree(target->dev); | ||
2456 | kfree(target); | ||
2457 | } | ||
diff --git a/drivers/net/wireless/ath/ath6kl/htc.h b/drivers/net/wireless/ath/ath6kl/htc.h new file mode 100644 index 000000000000..8ce0c2c07ded --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/htc.h | |||
@@ -0,0 +1,607 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004-2011 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 | #ifndef HTC_H | ||
18 | #define HTC_H | ||
19 | |||
20 | #include "common.h" | ||
21 | |||
22 | /* frame header flags */ | ||
23 | |||
24 | /* send direction */ | ||
25 | #define HTC_FLAGS_NEED_CREDIT_UPDATE (1 << 0) | ||
26 | #define HTC_FLAGS_SEND_BUNDLE (1 << 1) | ||
27 | |||
28 | /* receive direction */ | ||
29 | #define HTC_FLG_RX_UNUSED (1 << 0) | ||
30 | #define HTC_FLG_RX_TRAILER (1 << 1) | ||
31 | /* Bundle count maske and shift */ | ||
32 | #define HTC_FLG_RX_BNDL_CNT (0xF0) | ||
33 | #define HTC_FLG_RX_BNDL_CNT_S 4 | ||
34 | |||
35 | #define HTC_HDR_LENGTH (sizeof(struct htc_frame_hdr)) | ||
36 | #define HTC_MAX_PAYLOAD_LENGTH (4096 - sizeof(struct htc_frame_hdr)) | ||
37 | |||
38 | /* HTC control message IDs */ | ||
39 | |||
40 | #define HTC_MSG_READY_ID 1 | ||
41 | #define HTC_MSG_CONN_SVC_ID 2 | ||
42 | #define HTC_MSG_CONN_SVC_RESP_ID 3 | ||
43 | #define HTC_MSG_SETUP_COMPLETE_ID 4 | ||
44 | #define HTC_MSG_SETUP_COMPLETE_EX_ID 5 | ||
45 | |||
46 | #define HTC_MAX_CTRL_MSG_LEN 256 | ||
47 | |||
48 | #define HTC_VERSION_2P0 0x00 | ||
49 | #define HTC_VERSION_2P1 0x01 | ||
50 | |||
51 | #define HTC_SERVICE_META_DATA_MAX_LENGTH 128 | ||
52 | |||
53 | #define HTC_CONN_FLGS_THRESH_LVL_QUAT 0x0 | ||
54 | #define HTC_CONN_FLGS_THRESH_LVL_HALF 0x1 | ||
55 | #define HTC_CONN_FLGS_THRESH_LVL_THREE_QUAT 0x2 | ||
56 | #define HTC_CONN_FLGS_REDUCE_CRED_DRIB 0x4 | ||
57 | #define HTC_CONN_FLGS_THRESH_MASK 0x3 | ||
58 | |||
59 | /* connect response status codes */ | ||
60 | #define HTC_SERVICE_SUCCESS 0 | ||
61 | #define HTC_SERVICE_NOT_FOUND 1 | ||
62 | #define HTC_SERVICE_FAILED 2 | ||
63 | |||
64 | /* no resources (i.e. no more endpoints) */ | ||
65 | #define HTC_SERVICE_NO_RESOURCES 3 | ||
66 | |||
67 | /* specific service is not allowing any more endpoints */ | ||
68 | #define HTC_SERVICE_NO_MORE_EP 4 | ||
69 | |||
70 | /* report record IDs */ | ||
71 | #define HTC_RECORD_NULL 0 | ||
72 | #define HTC_RECORD_CREDITS 1 | ||
73 | #define HTC_RECORD_LOOKAHEAD 2 | ||
74 | #define HTC_RECORD_LOOKAHEAD_BUNDLE 3 | ||
75 | |||
76 | #define HTC_SETUP_COMP_FLG_RX_BNDL_EN (1 << 0) | ||
77 | |||
78 | #define MAKE_SERVICE_ID(group, index) \ | ||
79 | (int)(((int)group << 8) | (int)(index)) | ||
80 | |||
81 | /* NOTE: service ID of 0x0000 is reserved and should never be used */ | ||
82 | #define HTC_CTRL_RSVD_SVC MAKE_SERVICE_ID(RSVD_SERVICE_GROUP, 1) | ||
83 | #define WMI_CONTROL_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 0) | ||
84 | #define WMI_DATA_BE_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 1) | ||
85 | #define WMI_DATA_BK_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 2) | ||
86 | #define WMI_DATA_VI_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 3) | ||
87 | #define WMI_DATA_VO_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 4) | ||
88 | #define WMI_MAX_SERVICES 5 | ||
89 | |||
90 | /* reserved and used to flush ALL packets */ | ||
91 | #define HTC_TX_PACKET_TAG_ALL 0 | ||
92 | #define HTC_SERVICE_TX_PACKET_TAG 1 | ||
93 | #define HTC_TX_PACKET_TAG_USER_DEFINED (HTC_SERVICE_TX_PACKET_TAG + 9) | ||
94 | |||
95 | /* more packets on this endpoint are being fetched */ | ||
96 | #define HTC_RX_FLAGS_INDICATE_MORE_PKTS (1 << 0) | ||
97 | |||
98 | /* TODO.. for BMI */ | ||
99 | #define ENDPOINT1 0 | ||
100 | /* TODO -remove me, but we have to fix BMI first */ | ||
101 | #define HTC_MAILBOX_NUM_MAX 4 | ||
102 | |||
103 | /* enable send bundle padding for this endpoint */ | ||
104 | #define HTC_FLGS_TX_BNDL_PAD_EN (1 << 0) | ||
105 | #define HTC_EP_ACTIVE ((u32) (1u << 31)) | ||
106 | |||
107 | /* HTC operational parameters */ | ||
108 | #define HTC_TARGET_RESPONSE_TIMEOUT 2000 /* in ms */ | ||
109 | #define HTC_TARGET_DEBUG_INTR_MASK 0x01 | ||
110 | #define HTC_TARGET_CREDIT_INTR_MASK 0xF0 | ||
111 | |||
112 | #define HTC_HOST_MAX_MSG_PER_BUNDLE 8 | ||
113 | #define HTC_MIN_HTC_MSGS_TO_BUNDLE 2 | ||
114 | |||
115 | /* packet flags */ | ||
116 | |||
117 | #define HTC_RX_PKT_IGNORE_LOOKAHEAD (1 << 0) | ||
118 | #define HTC_RX_PKT_REFRESH_HDR (1 << 1) | ||
119 | #define HTC_RX_PKT_PART_OF_BUNDLE (1 << 2) | ||
120 | #define HTC_RX_PKT_NO_RECYCLE (1 << 3) | ||
121 | |||
122 | #define NUM_CONTROL_BUFFERS 8 | ||
123 | #define NUM_CONTROL_TX_BUFFERS 2 | ||
124 | #define NUM_CONTROL_RX_BUFFERS (NUM_CONTROL_BUFFERS - NUM_CONTROL_TX_BUFFERS) | ||
125 | |||
126 | #define HTC_RECV_WAIT_BUFFERS (1 << 0) | ||
127 | #define HTC_OP_STATE_STOPPING (1 << 0) | ||
128 | |||
129 | /* | ||
130 | * The frame header length and message formats defined herein were selected | ||
131 | * to accommodate optimal alignment for target processing. This reduces | ||
132 | * code size and improves performance. Any changes to the header length may | ||
133 | * alter the alignment and cause exceptions on the target. When adding to | ||
134 | * the messagestructures insure that fields are properly aligned. | ||
135 | */ | ||
136 | |||
137 | /* HTC frame header | ||
138 | * | ||
139 | * NOTE: do not remove or re-arrange the fields, these are minimally | ||
140 | * required to take advantage of 4-byte lookaheads in some hardware | ||
141 | * implementations. | ||
142 | */ | ||
143 | struct htc_frame_hdr { | ||
144 | u8 eid; | ||
145 | u8 flags; | ||
146 | |||
147 | /* length of data (including trailer) that follows the header */ | ||
148 | __le16 payld_len; | ||
149 | |||
150 | /* end of 4-byte lookahead */ | ||
151 | |||
152 | u8 ctrl[2]; | ||
153 | } __packed; | ||
154 | |||
155 | /* HTC ready message */ | ||
156 | struct htc_ready_msg { | ||
157 | __le16 msg_id; | ||
158 | __le16 cred_cnt; | ||
159 | __le16 cred_sz; | ||
160 | u8 max_ep; | ||
161 | u8 pad; | ||
162 | } __packed; | ||
163 | |||
164 | /* extended HTC ready message */ | ||
165 | struct htc_ready_ext_msg { | ||
166 | struct htc_ready_msg ver2_0_info; | ||
167 | u8 htc_ver; | ||
168 | u8 msg_per_htc_bndl; | ||
169 | } __packed; | ||
170 | |||
171 | /* connect service */ | ||
172 | struct htc_conn_service_msg { | ||
173 | __le16 msg_id; | ||
174 | __le16 svc_id; | ||
175 | __le16 conn_flags; | ||
176 | u8 svc_meta_len; | ||
177 | u8 pad; | ||
178 | } __packed; | ||
179 | |||
180 | /* connect response */ | ||
181 | struct htc_conn_service_resp { | ||
182 | __le16 msg_id; | ||
183 | __le16 svc_id; | ||
184 | u8 status; | ||
185 | u8 eid; | ||
186 | __le16 max_msg_sz; | ||
187 | u8 svc_meta_len; | ||
188 | u8 pad; | ||
189 | } __packed; | ||
190 | |||
191 | struct htc_setup_comp_msg { | ||
192 | __le16 msg_id; | ||
193 | } __packed; | ||
194 | |||
195 | /* extended setup completion message */ | ||
196 | struct htc_setup_comp_ext_msg { | ||
197 | __le16 msg_id; | ||
198 | __le32 flags; | ||
199 | u8 msg_per_rxbndl; | ||
200 | u8 Rsvd[3]; | ||
201 | } __packed; | ||
202 | |||
203 | struct htc_record_hdr { | ||
204 | u8 rec_id; | ||
205 | u8 len; | ||
206 | } __packed; | ||
207 | |||
208 | struct htc_credit_report { | ||
209 | u8 eid; | ||
210 | u8 credits; | ||
211 | } __packed; | ||
212 | |||
213 | /* | ||
214 | * NOTE: The lk_ahd array is guarded by a pre_valid | ||
215 | * and Post Valid guard bytes. The pre_valid bytes must | ||
216 | * equal the inverse of the post_valid byte. | ||
217 | */ | ||
218 | struct htc_lookahead_report { | ||
219 | u8 pre_valid; | ||
220 | u8 lk_ahd[4]; | ||
221 | u8 post_valid; | ||
222 | } __packed; | ||
223 | |||
224 | struct htc_bundle_lkahd_rpt { | ||
225 | u8 lk_ahd[4]; | ||
226 | } __packed; | ||
227 | |||
228 | /* Current service IDs */ | ||
229 | |||
230 | enum htc_service_grp_ids { | ||
231 | RSVD_SERVICE_GROUP = 0, | ||
232 | WMI_SERVICE_GROUP = 1, | ||
233 | |||
234 | HTC_TEST_GROUP = 254, | ||
235 | HTC_SERVICE_GROUP_LAST = 255 | ||
236 | }; | ||
237 | |||
238 | /* ------ endpoint IDS ------ */ | ||
239 | |||
240 | enum htc_endpoint_id { | ||
241 | ENDPOINT_UNUSED = -1, | ||
242 | ENDPOINT_0 = 0, | ||
243 | ENDPOINT_1 = 1, | ||
244 | ENDPOINT_2 = 2, | ||
245 | ENDPOINT_3, | ||
246 | ENDPOINT_4, | ||
247 | ENDPOINT_5, | ||
248 | ENDPOINT_6, | ||
249 | ENDPOINT_7, | ||
250 | ENDPOINT_8, | ||
251 | ENDPOINT_MAX, | ||
252 | }; | ||
253 | |||
254 | struct htc_tx_packet_info { | ||
255 | u16 tag; | ||
256 | int cred_used; | ||
257 | u8 flags; | ||
258 | int seqno; | ||
259 | }; | ||
260 | |||
261 | struct htc_rx_packet_info { | ||
262 | u32 exp_hdr; | ||
263 | u32 rx_flags; | ||
264 | u32 indicat_flags; | ||
265 | }; | ||
266 | |||
267 | struct htc_target; | ||
268 | |||
269 | /* wrapper around endpoint-specific packets */ | ||
270 | struct htc_packet { | ||
271 | struct list_head list; | ||
272 | |||
273 | /* caller's per packet specific context */ | ||
274 | void *pkt_cntxt; | ||
275 | |||
276 | /* | ||
277 | * the true buffer start , the caller can store the real | ||
278 | * buffer start here. In receive callbacks, the HTC layer | ||
279 | * sets buf to the start of the payload past the header. | ||
280 | * This field allows the caller to reset buf when it recycles | ||
281 | * receive packets back to HTC. | ||
282 | */ | ||
283 | u8 *buf_start; | ||
284 | |||
285 | /* | ||
286 | * Pointer to the start of the buffer. In the transmit | ||
287 | * direction this points to the start of the payload. In the | ||
288 | * receive direction, however, the buffer when queued up | ||
289 | * points to the start of the HTC header but when returned | ||
290 | * to the caller points to the start of the payload | ||
291 | */ | ||
292 | u8 *buf; | ||
293 | u32 buf_len; | ||
294 | |||
295 | /* actual length of payload */ | ||
296 | u32 act_len; | ||
297 | |||
298 | /* endpoint that this packet was sent/recv'd from */ | ||
299 | enum htc_endpoint_id endpoint; | ||
300 | |||
301 | /* completion status */ | ||
302 | |||
303 | int status; | ||
304 | union { | ||
305 | struct htc_tx_packet_info tx; | ||
306 | struct htc_rx_packet_info rx; | ||
307 | } info; | ||
308 | |||
309 | void (*completion) (struct htc_target *, struct htc_packet *); | ||
310 | struct htc_target *context; | ||
311 | }; | ||
312 | |||
313 | enum htc_send_full_action { | ||
314 | HTC_SEND_FULL_KEEP = 0, | ||
315 | HTC_SEND_FULL_DROP = 1, | ||
316 | }; | ||
317 | |||
318 | struct htc_ep_callbacks { | ||
319 | void (*rx) (struct htc_target *, struct htc_packet *); | ||
320 | void (*rx_refill) (struct htc_target *, enum htc_endpoint_id endpoint); | ||
321 | enum htc_send_full_action (*tx_full) (struct htc_target *, | ||
322 | struct htc_packet *); | ||
323 | struct htc_packet *(*rx_allocthresh) (struct htc_target *, | ||
324 | enum htc_endpoint_id, int); | ||
325 | int rx_alloc_thresh; | ||
326 | int rx_refill_thresh; | ||
327 | }; | ||
328 | |||
329 | /* service connection information */ | ||
330 | struct htc_service_connect_req { | ||
331 | u16 svc_id; | ||
332 | u16 conn_flags; | ||
333 | struct htc_ep_callbacks ep_cb; | ||
334 | int max_txq_depth; | ||
335 | u32 flags; | ||
336 | unsigned int max_rxmsg_sz; | ||
337 | }; | ||
338 | |||
339 | /* service connection response information */ | ||
340 | struct htc_service_connect_resp { | ||
341 | u8 buf_len; | ||
342 | u8 act_len; | ||
343 | enum htc_endpoint_id endpoint; | ||
344 | unsigned int len_max; | ||
345 | u8 resp_code; | ||
346 | }; | ||
347 | |||
348 | /* endpoint distributionstructure */ | ||
349 | struct htc_endpoint_credit_dist { | ||
350 | struct list_head list; | ||
351 | |||
352 | /* Service ID (set by HTC) */ | ||
353 | u16 svc_id; | ||
354 | |||
355 | /* endpoint for this distributionstruct (set by HTC) */ | ||
356 | enum htc_endpoint_id endpoint; | ||
357 | |||
358 | u32 dist_flags; | ||
359 | |||
360 | /* | ||
361 | * credits for normal operation, anything above this | ||
362 | * indicates the endpoint is over-subscribed. | ||
363 | */ | ||
364 | int cred_norm; | ||
365 | |||
366 | /* floor for credit distribution */ | ||
367 | int cred_min; | ||
368 | |||
369 | int cred_assngd; | ||
370 | |||
371 | /* current credits available */ | ||
372 | int credits; | ||
373 | |||
374 | /* | ||
375 | * pending credits to distribute on this endpoint, this | ||
376 | * is set by HTC when credit reports arrive. The credit | ||
377 | * distribution functions sets this to zero when it distributes | ||
378 | * the credits. | ||
379 | */ | ||
380 | int cred_to_dist; | ||
381 | |||
382 | /* | ||
383 | * the number of credits that the current pending TX packet needs | ||
384 | * to transmit. This is set by HTC when endpoint needs credits in | ||
385 | * order to transmit. | ||
386 | */ | ||
387 | int seek_cred; | ||
388 | |||
389 | /* size in bytes of each credit */ | ||
390 | int cred_sz; | ||
391 | |||
392 | /* credits required for a maximum sized messages */ | ||
393 | int cred_per_msg; | ||
394 | |||
395 | /* reserved for HTC use */ | ||
396 | void *htc_rsvd; | ||
397 | |||
398 | /* | ||
399 | * current depth of TX queue , i.e. messages waiting for credits | ||
400 | * This field is valid only when HTC_CREDIT_DIST_ACTIVITY_CHANGE | ||
401 | * or HTC_CREDIT_DIST_SEND_COMPLETE is indicated on an endpoint | ||
402 | * that has non-zero credits to recover. | ||
403 | */ | ||
404 | int txq_depth; | ||
405 | }; | ||
406 | |||
407 | /* | ||
408 | * credit distibution code that is passed into the distrbution function, | ||
409 | * there are mandatory and optional codes that must be handled | ||
410 | */ | ||
411 | enum htc_credit_dist_reason { | ||
412 | HTC_CREDIT_DIST_SEND_COMPLETE = 0, | ||
413 | HTC_CREDIT_DIST_ACTIVITY_CHANGE = 1, | ||
414 | HTC_CREDIT_DIST_SEEK_CREDITS, | ||
415 | }; | ||
416 | |||
417 | struct htc_credit_state_info { | ||
418 | int total_avail_credits; | ||
419 | int cur_free_credits; | ||
420 | struct list_head lowestpri_ep_dist; | ||
421 | }; | ||
422 | |||
423 | /* endpoint statistics */ | ||
424 | struct htc_endpoint_stats { | ||
425 | /* | ||
426 | * number of times the host set the credit-low flag in a send | ||
427 | * message on this endpoint | ||
428 | */ | ||
429 | u32 cred_low_indicate; | ||
430 | |||
431 | u32 tx_issued; | ||
432 | u32 tx_pkt_bundled; | ||
433 | u32 tx_bundles; | ||
434 | u32 tx_dropped; | ||
435 | |||
436 | /* running count of total credit reports received for this endpoint */ | ||
437 | u32 tx_cred_rpt; | ||
438 | |||
439 | /* credit reports received from this endpoint's RX packets */ | ||
440 | u32 cred_rpt_from_rx; | ||
441 | |||
442 | /* credit reports received from RX packets of other endpoints */ | ||
443 | u32 cred_rpt_from_other; | ||
444 | |||
445 | /* credit reports received from endpoint 0 RX packets */ | ||
446 | u32 cred_rpt_ep0; | ||
447 | |||
448 | /* count of credits received via Rx packets on this endpoint */ | ||
449 | u32 cred_from_rx; | ||
450 | |||
451 | /* count of credits received via another endpoint */ | ||
452 | u32 cred_from_other; | ||
453 | |||
454 | /* count of credits received via another endpoint */ | ||
455 | u32 cred_from_ep0; | ||
456 | |||
457 | /* count of consummed credits */ | ||
458 | u32 cred_cosumd; | ||
459 | |||
460 | /* count of credits returned */ | ||
461 | u32 cred_retnd; | ||
462 | |||
463 | u32 rx_pkts; | ||
464 | |||
465 | /* count of lookahead records found in Rx msg */ | ||
466 | u32 rx_lkahds; | ||
467 | |||
468 | /* count of recv packets received in a bundle */ | ||
469 | u32 rx_bundl; | ||
470 | |||
471 | /* count of number of bundled lookaheads */ | ||
472 | u32 rx_bundle_lkahd; | ||
473 | |||
474 | /* count of the number of bundle indications from the HTC header */ | ||
475 | u32 rx_bundle_from_hdr; | ||
476 | |||
477 | /* the number of times the recv allocation threshold was hit */ | ||
478 | u32 rx_alloc_thresh_hit; | ||
479 | |||
480 | /* total number of bytes */ | ||
481 | u32 rxalloc_thresh_byte; | ||
482 | }; | ||
483 | |||
484 | struct htc_endpoint { | ||
485 | enum htc_endpoint_id eid; | ||
486 | u16 svc_id; | ||
487 | struct list_head txq; | ||
488 | struct list_head rx_bufq; | ||
489 | struct htc_endpoint_credit_dist cred_dist; | ||
490 | struct htc_ep_callbacks ep_cb; | ||
491 | int max_txq_depth; | ||
492 | int len_max; | ||
493 | int tx_proc_cnt; | ||
494 | int rx_proc_cnt; | ||
495 | struct htc_target *target; | ||
496 | u8 seqno; | ||
497 | u32 conn_flags; | ||
498 | struct htc_endpoint_stats ep_st; | ||
499 | }; | ||
500 | |||
501 | struct htc_control_buffer { | ||
502 | struct htc_packet packet; | ||
503 | u8 *buf; | ||
504 | }; | ||
505 | |||
506 | struct ath6kl_device; | ||
507 | |||
508 | /* our HTC target state */ | ||
509 | struct htc_target { | ||
510 | struct htc_endpoint endpoint[ENDPOINT_MAX]; | ||
511 | struct list_head cred_dist_list; | ||
512 | struct list_head free_ctrl_txbuf; | ||
513 | struct list_head free_ctrl_rxbuf; | ||
514 | struct htc_credit_state_info *cred_dist_cntxt; | ||
515 | int tgt_creds; | ||
516 | unsigned int tgt_cred_sz; | ||
517 | spinlock_t htc_lock; | ||
518 | spinlock_t rx_lock; | ||
519 | spinlock_t tx_lock; | ||
520 | struct ath6kl_device *dev; | ||
521 | u32 htc_flags; | ||
522 | u32 rx_st_flags; | ||
523 | enum htc_endpoint_id ep_waiting; | ||
524 | u8 htc_tgt_ver; | ||
525 | |||
526 | /* max messages per bundle for HTC */ | ||
527 | int msg_per_bndl_max; | ||
528 | |||
529 | bool tx_bndl_enable; | ||
530 | int rx_bndl_enable; | ||
531 | int max_rx_bndl_sz; | ||
532 | int max_tx_bndl_sz; | ||
533 | |||
534 | u32 block_sz; | ||
535 | u32 block_mask; | ||
536 | |||
537 | int max_scat_entries; | ||
538 | int max_xfer_szper_scatreq; | ||
539 | |||
540 | int chk_irq_status_cnt; | ||
541 | }; | ||
542 | |||
543 | void *ath6kl_htc_create(struct ath6kl *ar); | ||
544 | void ath6kl_htc_set_credit_dist(struct htc_target *target, | ||
545 | struct htc_credit_state_info *cred_info, | ||
546 | u16 svc_pri_order[], int len); | ||
547 | int ath6kl_htc_wait_target(struct htc_target *target); | ||
548 | int ath6kl_htc_start(struct htc_target *target); | ||
549 | int ath6kl_htc_conn_service(struct htc_target *target, | ||
550 | struct htc_service_connect_req *req, | ||
551 | struct htc_service_connect_resp *resp); | ||
552 | int ath6kl_htc_tx(struct htc_target *target, struct htc_packet *packet); | ||
553 | void ath6kl_htc_stop(struct htc_target *target); | ||
554 | void ath6kl_htc_cleanup(struct htc_target *target); | ||
555 | void ath6kl_htc_flush_txep(struct htc_target *target, | ||
556 | enum htc_endpoint_id endpoint, u16 tag); | ||
557 | void ath6kl_htc_flush_rx_buf(struct htc_target *target); | ||
558 | void ath6kl_htc_indicate_activity_change(struct htc_target *target, | ||
559 | enum htc_endpoint_id endpoint, | ||
560 | bool active); | ||
561 | int ath6kl_htc_get_rxbuf_num(struct htc_target *target, | ||
562 | enum htc_endpoint_id endpoint); | ||
563 | int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target, | ||
564 | struct list_head *pktq); | ||
565 | int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target, | ||
566 | u32 msg_look_ahead[], int *n_pkts); | ||
567 | |||
568 | static inline void set_htc_pkt_info(struct htc_packet *packet, void *context, | ||
569 | u8 *buf, unsigned int len, | ||
570 | enum htc_endpoint_id eid, u16 tag) | ||
571 | { | ||
572 | packet->pkt_cntxt = context; | ||
573 | packet->buf = buf; | ||
574 | packet->act_len = len; | ||
575 | packet->endpoint = eid; | ||
576 | packet->info.tx.tag = tag; | ||
577 | } | ||
578 | |||
579 | static inline void htc_rxpkt_reset(struct htc_packet *packet) | ||
580 | { | ||
581 | packet->buf = packet->buf_start; | ||
582 | packet->act_len = 0; | ||
583 | } | ||
584 | |||
585 | static inline void set_htc_rxpkt_info(struct htc_packet *packet, void *context, | ||
586 | u8 *buf, unsigned long len, | ||
587 | enum htc_endpoint_id eid) | ||
588 | { | ||
589 | packet->pkt_cntxt = context; | ||
590 | packet->buf = buf; | ||
591 | packet->buf_start = buf; | ||
592 | packet->buf_len = len; | ||
593 | packet->endpoint = eid; | ||
594 | } | ||
595 | |||
596 | static inline int get_queue_depth(struct list_head *queue) | ||
597 | { | ||
598 | struct list_head *tmp_list; | ||
599 | int depth = 0; | ||
600 | |||
601 | list_for_each(tmp_list, queue) | ||
602 | depth++; | ||
603 | |||
604 | return depth; | ||
605 | } | ||
606 | |||
607 | #endif | ||
diff --git a/drivers/net/wireless/ath/ath6kl/htc_hif.c b/drivers/net/wireless/ath/ath6kl/htc_hif.c new file mode 100644 index 000000000000..86b1cc7409c2 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/htc_hif.c | |||
@@ -0,0 +1,641 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2007-2011 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 "core.h" | ||
18 | #include "target.h" | ||
19 | #include "hif-ops.h" | ||
20 | #include "htc_hif.h" | ||
21 | #include "debug.h" | ||
22 | |||
23 | #define MAILBOX_FOR_BLOCK_SIZE 1 | ||
24 | |||
25 | #define ATH6KL_TIME_QUANTUM 10 /* in ms */ | ||
26 | |||
27 | static int ath6kldev_cp_scat_dma_buf(struct hif_scatter_req *req, bool from_dma) | ||
28 | { | ||
29 | u8 *buf; | ||
30 | int i; | ||
31 | |||
32 | buf = req->virt_dma_buf; | ||
33 | |||
34 | for (i = 0; i < req->scat_entries; i++) { | ||
35 | |||
36 | if (from_dma) | ||
37 | memcpy(req->scat_list[i].buf, buf, | ||
38 | req->scat_list[i].len); | ||
39 | else | ||
40 | memcpy(buf, req->scat_list[i].buf, | ||
41 | req->scat_list[i].len); | ||
42 | |||
43 | buf += req->scat_list[i].len; | ||
44 | } | ||
45 | |||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | int ath6kldev_rw_comp_handler(void *context, int status) | ||
50 | { | ||
51 | struct htc_packet *packet = context; | ||
52 | |||
53 | ath6kl_dbg(ATH6KL_DBG_HTC_RECV, | ||
54 | "ath6kldev_rw_comp_handler (pkt:0x%p , status: %d\n", | ||
55 | packet, status); | ||
56 | |||
57 | packet->status = status; | ||
58 | packet->completion(packet->context, packet); | ||
59 | |||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | static int ath6kldev_proc_dbg_intr(struct ath6kl_device *dev) | ||
64 | { | ||
65 | u32 dummy; | ||
66 | int status; | ||
67 | |||
68 | ath6kl_err("target debug interrupt\n"); | ||
69 | |||
70 | ath6kl_target_failure(dev->ar); | ||
71 | |||
72 | /* | ||
73 | * read counter to clear the interrupt, the debug error interrupt is | ||
74 | * counter 0. | ||
75 | */ | ||
76 | status = hif_read_write_sync(dev->ar, COUNT_DEC_ADDRESS, | ||
77 | (u8 *)&dummy, 4, HIF_RD_SYNC_BYTE_INC); | ||
78 | if (status) | ||
79 | WARN_ON(1); | ||
80 | |||
81 | return status; | ||
82 | } | ||
83 | |||
84 | /* mailbox recv message polling */ | ||
85 | int ath6kldev_poll_mboxmsg_rx(struct ath6kl_device *dev, u32 *lk_ahd, | ||
86 | int timeout) | ||
87 | { | ||
88 | struct ath6kl_irq_proc_registers *rg; | ||
89 | int status = 0, i; | ||
90 | u8 htc_mbox = 1 << HTC_MAILBOX; | ||
91 | |||
92 | for (i = timeout / ATH6KL_TIME_QUANTUM; i > 0; i--) { | ||
93 | /* this is the standard HIF way, load the reg table */ | ||
94 | status = hif_read_write_sync(dev->ar, HOST_INT_STATUS_ADDRESS, | ||
95 | (u8 *) &dev->irq_proc_reg, | ||
96 | sizeof(dev->irq_proc_reg), | ||
97 | HIF_RD_SYNC_BYTE_INC); | ||
98 | |||
99 | if (status) { | ||
100 | ath6kl_err("failed to read reg table\n"); | ||
101 | return status; | ||
102 | } | ||
103 | |||
104 | /* check for MBOX data and valid lookahead */ | ||
105 | if (dev->irq_proc_reg.host_int_status & htc_mbox) { | ||
106 | if (dev->irq_proc_reg.rx_lkahd_valid & | ||
107 | htc_mbox) { | ||
108 | /* | ||
109 | * Mailbox has a message and the look ahead | ||
110 | * is valid. | ||
111 | */ | ||
112 | rg = &dev->irq_proc_reg; | ||
113 | *lk_ahd = | ||
114 | le32_to_cpu(rg->rx_lkahd[HTC_MAILBOX]); | ||
115 | break; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | /* delay a little */ | ||
120 | mdelay(ATH6KL_TIME_QUANTUM); | ||
121 | ath6kl_dbg(ATH6KL_DBG_HTC_RECV, "retry mbox poll : %d\n", i); | ||
122 | } | ||
123 | |||
124 | if (i == 0) { | ||
125 | ath6kl_err("timeout waiting for recv message\n"); | ||
126 | status = -ETIME; | ||
127 | /* check if the target asserted */ | ||
128 | if (dev->irq_proc_reg.counter_int_status & | ||
129 | ATH6KL_TARGET_DEBUG_INTR_MASK) | ||
130 | /* | ||
131 | * Target failure handler will be called in case of | ||
132 | * an assert. | ||
133 | */ | ||
134 | ath6kldev_proc_dbg_intr(dev); | ||
135 | } | ||
136 | |||
137 | return status; | ||
138 | } | ||
139 | |||
140 | /* | ||
141 | * Disable packet reception (used in case the host runs out of buffers) | ||
142 | * using the interrupt enable registers through the host I/F | ||
143 | */ | ||
144 | int ath6kldev_rx_control(struct ath6kl_device *dev, bool enable_rx) | ||
145 | { | ||
146 | struct ath6kl_irq_enable_reg regs; | ||
147 | int status = 0; | ||
148 | |||
149 | /* take the lock to protect interrupt enable shadows */ | ||
150 | spin_lock_bh(&dev->lock); | ||
151 | |||
152 | if (enable_rx) | ||
153 | dev->irq_en_reg.int_status_en |= | ||
154 | SM(INT_STATUS_ENABLE_MBOX_DATA, 0x01); | ||
155 | else | ||
156 | dev->irq_en_reg.int_status_en &= | ||
157 | ~SM(INT_STATUS_ENABLE_MBOX_DATA, 0x01); | ||
158 | |||
159 | memcpy(®s, &dev->irq_en_reg, sizeof(regs)); | ||
160 | |||
161 | spin_unlock_bh(&dev->lock); | ||
162 | |||
163 | status = hif_read_write_sync(dev->ar, INT_STATUS_ENABLE_ADDRESS, | ||
164 | ®s.int_status_en, | ||
165 | sizeof(struct ath6kl_irq_enable_reg), | ||
166 | HIF_WR_SYNC_BYTE_INC); | ||
167 | |||
168 | return status; | ||
169 | } | ||
170 | |||
171 | int ath6kldev_submit_scat_req(struct ath6kl_device *dev, | ||
172 | struct hif_scatter_req *scat_req, bool read) | ||
173 | { | ||
174 | int status = 0; | ||
175 | |||
176 | if (read) { | ||
177 | scat_req->req = HIF_RD_SYNC_BLOCK_FIX; | ||
178 | scat_req->addr = dev->ar->mbox_info.htc_addr; | ||
179 | } else { | ||
180 | scat_req->req = HIF_WR_ASYNC_BLOCK_INC; | ||
181 | |||
182 | scat_req->addr = | ||
183 | (scat_req->len > HIF_MBOX_WIDTH) ? | ||
184 | dev->ar->mbox_info.htc_ext_addr : | ||
185 | dev->ar->mbox_info.htc_addr; | ||
186 | } | ||
187 | |||
188 | ath6kl_dbg((ATH6KL_DBG_HTC_RECV | ATH6KL_DBG_HTC_SEND), | ||
189 | "ath6kldev_submit_scat_req, entries: %d, total len: %d mbox:0x%X (mode: %s : %s)\n", | ||
190 | scat_req->scat_entries, scat_req->len, | ||
191 | scat_req->addr, !read ? "async" : "sync", | ||
192 | (read) ? "rd" : "wr"); | ||
193 | |||
194 | if (!read && scat_req->virt_scat) { | ||
195 | status = ath6kldev_cp_scat_dma_buf(scat_req, false); | ||
196 | if (status) { | ||
197 | scat_req->status = status; | ||
198 | scat_req->complete(dev->ar->htc_target, scat_req); | ||
199 | return 0; | ||
200 | } | ||
201 | } | ||
202 | |||
203 | status = ath6kl_hif_scat_req_rw(dev->ar, scat_req); | ||
204 | |||
205 | if (read) { | ||
206 | /* in sync mode, we can touch the scatter request */ | ||
207 | scat_req->status = status; | ||
208 | if (!status && scat_req->virt_scat) | ||
209 | scat_req->status = | ||
210 | ath6kldev_cp_scat_dma_buf(scat_req, true); | ||
211 | } | ||
212 | |||
213 | return status; | ||
214 | } | ||
215 | |||
216 | static int ath6kldev_proc_counter_intr(struct ath6kl_device *dev) | ||
217 | { | ||
218 | u8 counter_int_status; | ||
219 | |||
220 | ath6kl_dbg(ATH6KL_DBG_IRQ, "counter interrupt\n"); | ||
221 | |||
222 | counter_int_status = dev->irq_proc_reg.counter_int_status & | ||
223 | dev->irq_en_reg.cntr_int_status_en; | ||
224 | |||
225 | ath6kl_dbg(ATH6KL_DBG_IRQ, | ||
226 | "valid interrupt source(s) in COUNTER_INT_STATUS: 0x%x\n", | ||
227 | counter_int_status); | ||
228 | |||
229 | /* | ||
230 | * NOTE: other modules like GMBOX may use the counter interrupt for | ||
231 | * credit flow control on other counters, we only need to check for | ||
232 | * the debug assertion counter interrupt. | ||
233 | */ | ||
234 | if (counter_int_status & ATH6KL_TARGET_DEBUG_INTR_MASK) | ||
235 | return ath6kldev_proc_dbg_intr(dev); | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static int ath6kldev_proc_err_intr(struct ath6kl_device *dev) | ||
241 | { | ||
242 | int status; | ||
243 | u8 error_int_status; | ||
244 | u8 reg_buf[4]; | ||
245 | |||
246 | ath6kl_dbg(ATH6KL_DBG_IRQ, "error interrupt\n"); | ||
247 | |||
248 | error_int_status = dev->irq_proc_reg.error_int_status & 0x0F; | ||
249 | if (!error_int_status) { | ||
250 | WARN_ON(1); | ||
251 | return -EIO; | ||
252 | } | ||
253 | |||
254 | ath6kl_dbg(ATH6KL_DBG_IRQ, | ||
255 | "valid interrupt source(s) in ERROR_INT_STATUS: 0x%x\n", | ||
256 | error_int_status); | ||
257 | |||
258 | if (MS(ERROR_INT_STATUS_WAKEUP, error_int_status)) | ||
259 | ath6kl_dbg(ATH6KL_DBG_IRQ, "error : wakeup\n"); | ||
260 | |||
261 | if (MS(ERROR_INT_STATUS_RX_UNDERFLOW, error_int_status)) | ||
262 | ath6kl_err("rx underflow\n"); | ||
263 | |||
264 | if (MS(ERROR_INT_STATUS_TX_OVERFLOW, error_int_status)) | ||
265 | ath6kl_err("tx overflow\n"); | ||
266 | |||
267 | /* Clear the interrupt */ | ||
268 | dev->irq_proc_reg.error_int_status &= ~error_int_status; | ||
269 | |||
270 | /* set W1C value to clear the interrupt, this hits the register first */ | ||
271 | reg_buf[0] = error_int_status; | ||
272 | reg_buf[1] = 0; | ||
273 | reg_buf[2] = 0; | ||
274 | reg_buf[3] = 0; | ||
275 | |||
276 | status = hif_read_write_sync(dev->ar, ERROR_INT_STATUS_ADDRESS, | ||
277 | reg_buf, 4, HIF_WR_SYNC_BYTE_FIX); | ||
278 | |||
279 | if (status) | ||
280 | WARN_ON(1); | ||
281 | |||
282 | return status; | ||
283 | } | ||
284 | |||
285 | static int ath6kldev_proc_cpu_intr(struct ath6kl_device *dev) | ||
286 | { | ||
287 | int status; | ||
288 | u8 cpu_int_status; | ||
289 | u8 reg_buf[4]; | ||
290 | |||
291 | ath6kl_dbg(ATH6KL_DBG_IRQ, "cpu interrupt\n"); | ||
292 | |||
293 | cpu_int_status = dev->irq_proc_reg.cpu_int_status & | ||
294 | dev->irq_en_reg.cpu_int_status_en; | ||
295 | if (!cpu_int_status) { | ||
296 | WARN_ON(1); | ||
297 | return -EIO; | ||
298 | } | ||
299 | |||
300 | ath6kl_dbg(ATH6KL_DBG_IRQ, | ||
301 | "valid interrupt source(s) in CPU_INT_STATUS: 0x%x\n", | ||
302 | cpu_int_status); | ||
303 | |||
304 | /* Clear the interrupt */ | ||
305 | dev->irq_proc_reg.cpu_int_status &= ~cpu_int_status; | ||
306 | |||
307 | /* | ||
308 | * Set up the register transfer buffer to hit the register 4 times , | ||
309 | * this is done to make the access 4-byte aligned to mitigate issues | ||
310 | * with host bus interconnects that restrict bus transfer lengths to | ||
311 | * be a multiple of 4-bytes. | ||
312 | */ | ||
313 | |||
314 | /* set W1C value to clear the interrupt, this hits the register first */ | ||
315 | reg_buf[0] = cpu_int_status; | ||
316 | /* the remaining are set to zero which have no-effect */ | ||
317 | reg_buf[1] = 0; | ||
318 | reg_buf[2] = 0; | ||
319 | reg_buf[3] = 0; | ||
320 | |||
321 | status = hif_read_write_sync(dev->ar, CPU_INT_STATUS_ADDRESS, | ||
322 | reg_buf, 4, HIF_WR_SYNC_BYTE_FIX); | ||
323 | |||
324 | if (status) | ||
325 | WARN_ON(1); | ||
326 | |||
327 | return status; | ||
328 | } | ||
329 | |||
330 | /* process pending interrupts synchronously */ | ||
331 | static int proc_pending_irqs(struct ath6kl_device *dev, bool *done) | ||
332 | { | ||
333 | struct ath6kl_irq_proc_registers *rg; | ||
334 | int status = 0; | ||
335 | u8 host_int_status = 0; | ||
336 | u32 lk_ahd = 0; | ||
337 | u8 htc_mbox = 1 << HTC_MAILBOX; | ||
338 | |||
339 | ath6kl_dbg(ATH6KL_DBG_IRQ, "proc_pending_irqs: (dev: 0x%p)\n", dev); | ||
340 | |||
341 | /* | ||
342 | * NOTE: HIF implementation guarantees that the context of this | ||
343 | * call allows us to perform SYNCHRONOUS I/O, that is we can block, | ||
344 | * sleep or call any API that can block or switch thread/task | ||
345 | * contexts. This is a fully schedulable context. | ||
346 | */ | ||
347 | |||
348 | /* | ||
349 | * Process pending intr only when int_status_en is clear, it may | ||
350 | * result in unnecessary bus transaction otherwise. Target may be | ||
351 | * unresponsive at the time. | ||
352 | */ | ||
353 | if (dev->irq_en_reg.int_status_en) { | ||
354 | /* | ||
355 | * Read the first 28 bytes of the HTC register table. This | ||
356 | * will yield us the value of different int status | ||
357 | * registers and the lookahead registers. | ||
358 | * | ||
359 | * length = sizeof(int_status) + sizeof(cpu_int_status) | ||
360 | * + sizeof(error_int_status) + | ||
361 | * sizeof(counter_int_status) + | ||
362 | * sizeof(mbox_frame) + sizeof(rx_lkahd_valid) | ||
363 | * + sizeof(hole) + sizeof(rx_lkahd) + | ||
364 | * sizeof(int_status_en) + | ||
365 | * sizeof(cpu_int_status_en) + | ||
366 | * sizeof(err_int_status_en) + | ||
367 | * sizeof(cntr_int_status_en); | ||
368 | */ | ||
369 | status = hif_read_write_sync(dev->ar, HOST_INT_STATUS_ADDRESS, | ||
370 | (u8 *) &dev->irq_proc_reg, | ||
371 | sizeof(dev->irq_proc_reg), | ||
372 | HIF_RD_SYNC_BYTE_INC); | ||
373 | if (status) | ||
374 | goto out; | ||
375 | |||
376 | if (AR_DBG_LVL_CHECK(ATH6KL_DBG_IRQ)) | ||
377 | ath6kl_dump_registers(dev, &dev->irq_proc_reg, | ||
378 | &dev->irq_en_reg); | ||
379 | |||
380 | /* Update only those registers that are enabled */ | ||
381 | host_int_status = dev->irq_proc_reg.host_int_status & | ||
382 | dev->irq_en_reg.int_status_en; | ||
383 | |||
384 | /* Look at mbox status */ | ||
385 | if (host_int_status & htc_mbox) { | ||
386 | /* | ||
387 | * Mask out pending mbox value, we use "lookAhead as | ||
388 | * the real flag for mbox processing. | ||
389 | */ | ||
390 | host_int_status &= ~htc_mbox; | ||
391 | if (dev->irq_proc_reg.rx_lkahd_valid & | ||
392 | htc_mbox) { | ||
393 | rg = &dev->irq_proc_reg; | ||
394 | lk_ahd = le32_to_cpu(rg->rx_lkahd[HTC_MAILBOX]); | ||
395 | if (!lk_ahd) | ||
396 | ath6kl_err("lookAhead is zero!\n"); | ||
397 | } | ||
398 | } | ||
399 | } | ||
400 | |||
401 | if (!host_int_status && !lk_ahd) { | ||
402 | *done = true; | ||
403 | goto out; | ||
404 | } | ||
405 | |||
406 | if (lk_ahd) { | ||
407 | int fetched = 0; | ||
408 | |||
409 | ath6kl_dbg(ATH6KL_DBG_IRQ, | ||
410 | "pending mailbox msg, lk_ahd: 0x%X\n", lk_ahd); | ||
411 | /* | ||
412 | * Mailbox Interrupt, the HTC layer may issue async | ||
413 | * requests to empty the mailbox. When emptying the recv | ||
414 | * mailbox we use the async handler above called from the | ||
415 | * completion routine of the callers read request. This can | ||
416 | * improve performance by reducing context switching when | ||
417 | * we rapidly pull packets. | ||
418 | */ | ||
419 | status = ath6kl_htc_rxmsg_pending_handler(dev->htc_cnxt, | ||
420 | &lk_ahd, &fetched); | ||
421 | if (status) | ||
422 | goto out; | ||
423 | |||
424 | if (!fetched) | ||
425 | /* | ||
426 | * HTC could not pull any messages out due to lack | ||
427 | * of resources. | ||
428 | */ | ||
429 | dev->htc_cnxt->chk_irq_status_cnt = 0; | ||
430 | } | ||
431 | |||
432 | /* now handle the rest of them */ | ||
433 | ath6kl_dbg(ATH6KL_DBG_IRQ, | ||
434 | "valid interrupt source(s) for other interrupts: 0x%x\n", | ||
435 | host_int_status); | ||
436 | |||
437 | if (MS(HOST_INT_STATUS_CPU, host_int_status)) { | ||
438 | /* CPU Interrupt */ | ||
439 | status = ath6kldev_proc_cpu_intr(dev); | ||
440 | if (status) | ||
441 | goto out; | ||
442 | } | ||
443 | |||
444 | if (MS(HOST_INT_STATUS_ERROR, host_int_status)) { | ||
445 | /* Error Interrupt */ | ||
446 | status = ath6kldev_proc_err_intr(dev); | ||
447 | if (status) | ||
448 | goto out; | ||
449 | } | ||
450 | |||
451 | if (MS(HOST_INT_STATUS_COUNTER, host_int_status)) | ||
452 | /* Counter Interrupt */ | ||
453 | status = ath6kldev_proc_counter_intr(dev); | ||
454 | |||
455 | out: | ||
456 | /* | ||
457 | * An optimization to bypass reading the IRQ status registers | ||
458 | * unecessarily which can re-wake the target, if upper layers | ||
459 | * determine that we are in a low-throughput mode, we can rely on | ||
460 | * taking another interrupt rather than re-checking the status | ||
461 | * registers which can re-wake the target. | ||
462 | * | ||
463 | * NOTE : for host interfaces that makes use of detecting pending | ||
464 | * mbox messages at hif can not use this optimization due to | ||
465 | * possible side effects, SPI requires the host to drain all | ||
466 | * messages from the mailbox before exiting the ISR routine. | ||
467 | */ | ||
468 | |||
469 | ath6kl_dbg(ATH6KL_DBG_IRQ, | ||
470 | "bypassing irq status re-check, forcing done\n"); | ||
471 | |||
472 | if (!dev->htc_cnxt->chk_irq_status_cnt) | ||
473 | *done = true; | ||
474 | |||
475 | ath6kl_dbg(ATH6KL_DBG_IRQ, | ||
476 | "proc_pending_irqs: (done:%d, status=%d\n", *done, status); | ||
477 | |||
478 | return status; | ||
479 | } | ||
480 | |||
481 | /* interrupt handler, kicks off all interrupt processing */ | ||
482 | int ath6kldev_intr_bh_handler(struct ath6kl *ar) | ||
483 | { | ||
484 | struct ath6kl_device *dev = ar->htc_target->dev; | ||
485 | int status = 0; | ||
486 | bool done = false; | ||
487 | |||
488 | /* | ||
489 | * Reset counter used to flag a re-scan of IRQ status registers on | ||
490 | * the target. | ||
491 | */ | ||
492 | dev->htc_cnxt->chk_irq_status_cnt = 0; | ||
493 | |||
494 | /* | ||
495 | * IRQ processing is synchronous, interrupt status registers can be | ||
496 | * re-read. | ||
497 | */ | ||
498 | while (!done) { | ||
499 | status = proc_pending_irqs(dev, &done); | ||
500 | if (status) | ||
501 | break; | ||
502 | } | ||
503 | |||
504 | return status; | ||
505 | } | ||
506 | |||
507 | static int ath6kldev_enable_intrs(struct ath6kl_device *dev) | ||
508 | { | ||
509 | struct ath6kl_irq_enable_reg regs; | ||
510 | int status; | ||
511 | |||
512 | spin_lock_bh(&dev->lock); | ||
513 | |||
514 | /* Enable all but ATH6KL CPU interrupts */ | ||
515 | dev->irq_en_reg.int_status_en = | ||
516 | SM(INT_STATUS_ENABLE_ERROR, 0x01) | | ||
517 | SM(INT_STATUS_ENABLE_CPU, 0x01) | | ||
518 | SM(INT_STATUS_ENABLE_COUNTER, 0x01); | ||
519 | |||
520 | /* | ||
521 | * NOTE: There are some cases where HIF can do detection of | ||
522 | * pending mbox messages which is disabled now. | ||
523 | */ | ||
524 | dev->irq_en_reg.int_status_en |= SM(INT_STATUS_ENABLE_MBOX_DATA, 0x01); | ||
525 | |||
526 | /* Set up the CPU Interrupt status Register */ | ||
527 | dev->irq_en_reg.cpu_int_status_en = 0; | ||
528 | |||
529 | /* Set up the Error Interrupt status Register */ | ||
530 | dev->irq_en_reg.err_int_status_en = | ||
531 | SM(ERROR_STATUS_ENABLE_RX_UNDERFLOW, 0x01) | | ||
532 | SM(ERROR_STATUS_ENABLE_TX_OVERFLOW, 0x1); | ||
533 | |||
534 | /* | ||
535 | * Enable Counter interrupt status register to get fatal errors for | ||
536 | * debugging. | ||
537 | */ | ||
538 | dev->irq_en_reg.cntr_int_status_en = SM(COUNTER_INT_STATUS_ENABLE_BIT, | ||
539 | ATH6KL_TARGET_DEBUG_INTR_MASK); | ||
540 | memcpy(®s, &dev->irq_en_reg, sizeof(regs)); | ||
541 | |||
542 | spin_unlock_bh(&dev->lock); | ||
543 | |||
544 | status = hif_read_write_sync(dev->ar, INT_STATUS_ENABLE_ADDRESS, | ||
545 | ®s.int_status_en, sizeof(regs), | ||
546 | HIF_WR_SYNC_BYTE_INC); | ||
547 | |||
548 | if (status) | ||
549 | ath6kl_err("failed to update interrupt ctl reg err: %d\n", | ||
550 | status); | ||
551 | |||
552 | return status; | ||
553 | } | ||
554 | |||
555 | int ath6kldev_disable_intrs(struct ath6kl_device *dev) | ||
556 | { | ||
557 | struct ath6kl_irq_enable_reg regs; | ||
558 | |||
559 | spin_lock_bh(&dev->lock); | ||
560 | /* Disable all interrupts */ | ||
561 | dev->irq_en_reg.int_status_en = 0; | ||
562 | dev->irq_en_reg.cpu_int_status_en = 0; | ||
563 | dev->irq_en_reg.err_int_status_en = 0; | ||
564 | dev->irq_en_reg.cntr_int_status_en = 0; | ||
565 | memcpy(®s, &dev->irq_en_reg, sizeof(regs)); | ||
566 | spin_unlock_bh(&dev->lock); | ||
567 | |||
568 | return hif_read_write_sync(dev->ar, INT_STATUS_ENABLE_ADDRESS, | ||
569 | ®s.int_status_en, sizeof(regs), | ||
570 | HIF_WR_SYNC_BYTE_INC); | ||
571 | } | ||
572 | |||
573 | /* enable device interrupts */ | ||
574 | int ath6kldev_unmask_intrs(struct ath6kl_device *dev) | ||
575 | { | ||
576 | int status = 0; | ||
577 | |||
578 | /* | ||
579 | * Make sure interrupt are disabled before unmasking at the HIF | ||
580 | * layer. The rationale here is that between device insertion | ||
581 | * (where we clear the interrupts the first time) and when HTC | ||
582 | * is finally ready to handle interrupts, other software can perform | ||
583 | * target "soft" resets. The ATH6KL interrupt enables reset back to an | ||
584 | * "enabled" state when this happens. | ||
585 | */ | ||
586 | ath6kldev_disable_intrs(dev); | ||
587 | |||
588 | /* unmask the host controller interrupts */ | ||
589 | ath6kl_hif_irq_enable(dev->ar); | ||
590 | status = ath6kldev_enable_intrs(dev); | ||
591 | |||
592 | return status; | ||
593 | } | ||
594 | |||
595 | /* disable all device interrupts */ | ||
596 | int ath6kldev_mask_intrs(struct ath6kl_device *dev) | ||
597 | { | ||
598 | /* | ||
599 | * Mask the interrupt at the HIF layer to avoid any stray interrupt | ||
600 | * taken while we zero out our shadow registers in | ||
601 | * ath6kldev_disable_intrs(). | ||
602 | */ | ||
603 | ath6kl_hif_irq_disable(dev->ar); | ||
604 | |||
605 | return ath6kldev_disable_intrs(dev); | ||
606 | } | ||
607 | |||
608 | int ath6kldev_setup(struct ath6kl_device *dev) | ||
609 | { | ||
610 | int status = 0; | ||
611 | |||
612 | spin_lock_init(&dev->lock); | ||
613 | |||
614 | /* | ||
615 | * NOTE: we actually get the block size of a mailbox other than 0, | ||
616 | * for SDIO the block size on mailbox 0 is artificially set to 1. | ||
617 | * So we use the block size that is set for the other 3 mailboxes. | ||
618 | */ | ||
619 | dev->htc_cnxt->block_sz = dev->ar->mbox_info.block_size; | ||
620 | |||
621 | /* must be a power of 2 */ | ||
622 | if ((dev->htc_cnxt->block_sz & (dev->htc_cnxt->block_sz - 1)) != 0) { | ||
623 | WARN_ON(1); | ||
624 | goto fail_setup; | ||
625 | } | ||
626 | |||
627 | /* assemble mask, used for padding to a block */ | ||
628 | dev->htc_cnxt->block_mask = dev->htc_cnxt->block_sz - 1; | ||
629 | |||
630 | ath6kl_dbg(ATH6KL_DBG_TRC, "block size: %d, mbox addr:0x%X\n", | ||
631 | dev->htc_cnxt->block_sz, dev->ar->mbox_info.htc_addr); | ||
632 | |||
633 | ath6kl_dbg(ATH6KL_DBG_TRC, | ||
634 | "hif interrupt processing is sync only\n"); | ||
635 | |||
636 | status = ath6kldev_disable_intrs(dev); | ||
637 | |||
638 | fail_setup: | ||
639 | return status; | ||
640 | |||
641 | } | ||
diff --git a/drivers/net/wireless/ath/ath6kl/htc_hif.h b/drivers/net/wireless/ath/ath6kl/htc_hif.h new file mode 100644 index 000000000000..171ad63d89b0 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/htc_hif.h | |||
@@ -0,0 +1,92 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2007-2011 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 | #ifndef HTC_HIF_H | ||
18 | #define HTC_HIF_H | ||
19 | |||
20 | #include "htc.h" | ||
21 | #include "hif.h" | ||
22 | |||
23 | #define ATH6KL_MAILBOXES 4 | ||
24 | |||
25 | /* HTC runs over mailbox 0 */ | ||
26 | #define HTC_MAILBOX 0 | ||
27 | |||
28 | #define ATH6KL_TARGET_DEBUG_INTR_MASK 0x01 | ||
29 | |||
30 | #define OTHER_INTS_ENABLED (INT_STATUS_ENABLE_ERROR_MASK | \ | ||
31 | INT_STATUS_ENABLE_CPU_MASK | \ | ||
32 | INT_STATUS_ENABLE_COUNTER_MASK) | ||
33 | |||
34 | #define ATH6KL_REG_IO_BUFFER_SIZE 32 | ||
35 | #define ATH6KL_MAX_REG_IO_BUFFERS 8 | ||
36 | #define ATH6KL_SCATTER_ENTRIES_PER_REQ 16 | ||
37 | #define ATH6KL_MAX_TRANSFER_SIZE_PER_SCATTER (16 * 1024) | ||
38 | #define ATH6KL_SCATTER_REQS 4 | ||
39 | |||
40 | #ifndef A_CACHE_LINE_PAD | ||
41 | #define A_CACHE_LINE_PAD 128 | ||
42 | #endif | ||
43 | #define ATH6KL_MIN_SCATTER_ENTRIES_PER_REQ 2 | ||
44 | #define ATH6KL_MIN_TRANSFER_SIZE_PER_SCATTER (4 * 1024) | ||
45 | |||
46 | struct ath6kl_irq_proc_registers { | ||
47 | u8 host_int_status; | ||
48 | u8 cpu_int_status; | ||
49 | u8 error_int_status; | ||
50 | u8 counter_int_status; | ||
51 | u8 mbox_frame; | ||
52 | u8 rx_lkahd_valid; | ||
53 | u8 host_int_status2; | ||
54 | u8 gmbox_rx_avail; | ||
55 | __le32 rx_lkahd[2]; | ||
56 | __le32 rx_gmbox_lkahd_alias[2]; | ||
57 | } __packed; | ||
58 | |||
59 | struct ath6kl_irq_enable_reg { | ||
60 | u8 int_status_en; | ||
61 | u8 cpu_int_status_en; | ||
62 | u8 err_int_status_en; | ||
63 | u8 cntr_int_status_en; | ||
64 | } __packed; | ||
65 | |||
66 | struct ath6kl_device { | ||
67 | spinlock_t lock; | ||
68 | u8 pad1[A_CACHE_LINE_PAD]; | ||
69 | struct ath6kl_irq_proc_registers irq_proc_reg; | ||
70 | u8 pad2[A_CACHE_LINE_PAD]; | ||
71 | struct ath6kl_irq_enable_reg irq_en_reg; | ||
72 | u8 pad3[A_CACHE_LINE_PAD]; | ||
73 | struct htc_target *htc_cnxt; | ||
74 | struct ath6kl *ar; | ||
75 | }; | ||
76 | |||
77 | int ath6kldev_setup(struct ath6kl_device *dev); | ||
78 | int ath6kldev_unmask_intrs(struct ath6kl_device *dev); | ||
79 | int ath6kldev_mask_intrs(struct ath6kl_device *dev); | ||
80 | int ath6kldev_poll_mboxmsg_rx(struct ath6kl_device *dev, | ||
81 | u32 *lk_ahd, int timeout); | ||
82 | int ath6kldev_rx_control(struct ath6kl_device *dev, bool enable_rx); | ||
83 | int ath6kldev_disable_intrs(struct ath6kl_device *dev); | ||
84 | |||
85 | int ath6kldev_rw_comp_handler(void *context, int status); | ||
86 | int ath6kldev_intr_bh_handler(struct ath6kl *ar); | ||
87 | |||
88 | /* Scatter Function and Definitions */ | ||
89 | int ath6kldev_submit_scat_req(struct ath6kl_device *dev, | ||
90 | struct hif_scatter_req *scat_req, bool read); | ||
91 | |||
92 | #endif /*ATH6KL_H_ */ | ||
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c new file mode 100644 index 000000000000..9d10322eac41 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/init.c | |||
@@ -0,0 +1,1303 @@ | |||
1 | |||
2 | /* | ||
3 | * Copyright (c) 2011 Atheros Communications Inc. | ||
4 | * | ||
5 | * Permission to use, copy, modify, and/or distribute this software for any | ||
6 | * purpose with or without fee is hereby granted, provided that the above | ||
7 | * copyright notice and this permission notice appear in all copies. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
16 | */ | ||
17 | |||
18 | #include <linux/mmc/sdio_func.h> | ||
19 | #include "core.h" | ||
20 | #include "cfg80211.h" | ||
21 | #include "target.h" | ||
22 | #include "debug.h" | ||
23 | #include "hif-ops.h" | ||
24 | |||
25 | unsigned int debug_mask; | ||
26 | |||
27 | module_param(debug_mask, uint, 0644); | ||
28 | |||
29 | /* | ||
30 | * Include definitions here that can be used to tune the WLAN module | ||
31 | * behavior. Different customers can tune the behavior as per their needs, | ||
32 | * here. | ||
33 | */ | ||
34 | |||
35 | /* | ||
36 | * This configuration item enable/disable keepalive support. | ||
37 | * Keepalive support: In the absence of any data traffic to AP, null | ||
38 | * frames will be sent to the AP at periodic interval, to keep the association | ||
39 | * active. This configuration item defines the periodic interval. | ||
40 | * Use value of zero to disable keepalive support | ||
41 | * Default: 60 seconds | ||
42 | */ | ||
43 | #define WLAN_CONFIG_KEEP_ALIVE_INTERVAL 60 | ||
44 | |||
45 | /* | ||
46 | * This configuration item sets the value of disconnect timeout | ||
47 | * Firmware delays sending the disconnec event to the host for this | ||
48 | * timeout after is gets disconnected from the current AP. | ||
49 | * If the firmware successly roams within the disconnect timeout | ||
50 | * it sends a new connect event | ||
51 | */ | ||
52 | #define WLAN_CONFIG_DISCONNECT_TIMEOUT 10 | ||
53 | |||
54 | #define CONFIG_AR600x_DEBUG_UART_TX_PIN 8 | ||
55 | |||
56 | enum addr_type { | ||
57 | DATASET_PATCH_ADDR, | ||
58 | APP_LOAD_ADDR, | ||
59 | APP_START_OVERRIDE_ADDR, | ||
60 | }; | ||
61 | |||
62 | #define ATH6KL_DATA_OFFSET 64 | ||
63 | struct sk_buff *ath6kl_buf_alloc(int size) | ||
64 | { | ||
65 | struct sk_buff *skb; | ||
66 | u16 reserved; | ||
67 | |||
68 | /* Add chacheline space at front and back of buffer */ | ||
69 | reserved = (2 * L1_CACHE_BYTES) + ATH6KL_DATA_OFFSET + | ||
70 | sizeof(struct htc_packet); | ||
71 | skb = dev_alloc_skb(size + reserved); | ||
72 | |||
73 | if (skb) | ||
74 | skb_reserve(skb, reserved - L1_CACHE_BYTES); | ||
75 | return skb; | ||
76 | } | ||
77 | |||
78 | void ath6kl_init_profile_info(struct ath6kl *ar) | ||
79 | { | ||
80 | ar->ssid_len = 0; | ||
81 | memset(ar->ssid, 0, sizeof(ar->ssid)); | ||
82 | |||
83 | ar->dot11_auth_mode = OPEN_AUTH; | ||
84 | ar->auth_mode = NONE_AUTH; | ||
85 | ar->prwise_crypto = NONE_CRYPT; | ||
86 | ar->prwise_crypto_len = 0; | ||
87 | ar->grp_crypto = NONE_CRYPT; | ||
88 | ar->grp_crpto_len = 0; | ||
89 | memset(ar->wep_key_list, 0, sizeof(ar->wep_key_list)); | ||
90 | memset(ar->req_bssid, 0, sizeof(ar->req_bssid)); | ||
91 | memset(ar->bssid, 0, sizeof(ar->bssid)); | ||
92 | ar->bss_ch = 0; | ||
93 | ar->nw_type = ar->next_mode = INFRA_NETWORK; | ||
94 | } | ||
95 | |||
96 | static u8 ath6kl_get_fw_iftype(struct ath6kl *ar) | ||
97 | { | ||
98 | switch (ar->nw_type) { | ||
99 | case INFRA_NETWORK: | ||
100 | return HI_OPTION_FW_MODE_BSS_STA; | ||
101 | case ADHOC_NETWORK: | ||
102 | return HI_OPTION_FW_MODE_IBSS; | ||
103 | case AP_NETWORK: | ||
104 | return HI_OPTION_FW_MODE_AP; | ||
105 | default: | ||
106 | ath6kl_err("Unsupported interface type :%d\n", ar->nw_type); | ||
107 | return 0xff; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | static inline u32 ath6kl_get_hi_item_addr(struct ath6kl *ar, | ||
112 | u32 item_offset) | ||
113 | { | ||
114 | u32 addr = 0; | ||
115 | |||
116 | if (ar->target_type == TARGET_TYPE_AR6003) | ||
117 | addr = ATH6KL_HI_START_ADDR + item_offset; | ||
118 | |||
119 | return addr; | ||
120 | } | ||
121 | |||
122 | static int ath6kl_set_host_app_area(struct ath6kl *ar) | ||
123 | { | ||
124 | u32 address, data; | ||
125 | struct host_app_area host_app_area; | ||
126 | |||
127 | /* Fetch the address of the host_app_area_s | ||
128 | * instance in the host interest area */ | ||
129 | address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_app_host_interest)); | ||
130 | address = TARG_VTOP(address); | ||
131 | |||
132 | if (ath6kl_read_reg_diag(ar, &address, &data)) | ||
133 | return -EIO; | ||
134 | |||
135 | address = TARG_VTOP(data); | ||
136 | host_app_area.wmi_protocol_ver = WMI_PROTOCOL_VERSION; | ||
137 | if (ath6kl_access_datadiag(ar, address, | ||
138 | (u8 *)&host_app_area, | ||
139 | sizeof(struct host_app_area), false)) | ||
140 | return -EIO; | ||
141 | |||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | static inline void set_ac2_ep_map(struct ath6kl *ar, | ||
146 | u8 ac, | ||
147 | enum htc_endpoint_id ep) | ||
148 | { | ||
149 | ar->ac2ep_map[ac] = ep; | ||
150 | ar->ep2ac_map[ep] = ac; | ||
151 | } | ||
152 | |||
153 | /* connect to a service */ | ||
154 | static int ath6kl_connectservice(struct ath6kl *ar, | ||
155 | struct htc_service_connect_req *con_req, | ||
156 | char *desc) | ||
157 | { | ||
158 | int status; | ||
159 | struct htc_service_connect_resp response; | ||
160 | |||
161 | memset(&response, 0, sizeof(response)); | ||
162 | |||
163 | status = ath6kl_htc_conn_service(ar->htc_target, con_req, &response); | ||
164 | if (status) { | ||
165 | ath6kl_err("failed to connect to %s service status:%d\n", | ||
166 | desc, status); | ||
167 | return status; | ||
168 | } | ||
169 | |||
170 | switch (con_req->svc_id) { | ||
171 | case WMI_CONTROL_SVC: | ||
172 | if (test_bit(WMI_ENABLED, &ar->flag)) | ||
173 | ath6kl_wmi_set_control_ep(ar->wmi, response.endpoint); | ||
174 | ar->ctrl_ep = response.endpoint; | ||
175 | break; | ||
176 | case WMI_DATA_BE_SVC: | ||
177 | set_ac2_ep_map(ar, WMM_AC_BE, response.endpoint); | ||
178 | break; | ||
179 | case WMI_DATA_BK_SVC: | ||
180 | set_ac2_ep_map(ar, WMM_AC_BK, response.endpoint); | ||
181 | break; | ||
182 | case WMI_DATA_VI_SVC: | ||
183 | set_ac2_ep_map(ar, WMM_AC_VI, response.endpoint); | ||
184 | break; | ||
185 | case WMI_DATA_VO_SVC: | ||
186 | set_ac2_ep_map(ar, WMM_AC_VO, response.endpoint); | ||
187 | break; | ||
188 | default: | ||
189 | ath6kl_err("service id is not mapped %d\n", con_req->svc_id); | ||
190 | return -EINVAL; | ||
191 | } | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | static int ath6kl_init_service_ep(struct ath6kl *ar) | ||
197 | { | ||
198 | struct htc_service_connect_req connect; | ||
199 | |||
200 | memset(&connect, 0, sizeof(connect)); | ||
201 | |||
202 | /* these fields are the same for all service endpoints */ | ||
203 | connect.ep_cb.rx = ath6kl_rx; | ||
204 | connect.ep_cb.rx_refill = ath6kl_rx_refill; | ||
205 | connect.ep_cb.tx_full = ath6kl_tx_queue_full; | ||
206 | |||
207 | /* | ||
208 | * Set the max queue depth so that our ath6kl_tx_queue_full handler | ||
209 | * gets called. | ||
210 | */ | ||
211 | connect.max_txq_depth = MAX_DEFAULT_SEND_QUEUE_DEPTH; | ||
212 | connect.ep_cb.rx_refill_thresh = ATH6KL_MAX_RX_BUFFERS / 4; | ||
213 | if (!connect.ep_cb.rx_refill_thresh) | ||
214 | connect.ep_cb.rx_refill_thresh++; | ||
215 | |||
216 | /* connect to control service */ | ||
217 | connect.svc_id = WMI_CONTROL_SVC; | ||
218 | if (ath6kl_connectservice(ar, &connect, "WMI CONTROL")) | ||
219 | return -EIO; | ||
220 | |||
221 | connect.flags |= HTC_FLGS_TX_BNDL_PAD_EN; | ||
222 | |||
223 | /* | ||
224 | * Limit the HTC message size on the send path, although e can | ||
225 | * receive A-MSDU frames of 4K, we will only send ethernet-sized | ||
226 | * (802.3) frames on the send path. | ||
227 | */ | ||
228 | connect.max_rxmsg_sz = WMI_MAX_TX_DATA_FRAME_LENGTH; | ||
229 | |||
230 | /* | ||
231 | * To reduce the amount of committed memory for larger A_MSDU | ||
232 | * frames, use the recv-alloc threshold mechanism for larger | ||
233 | * packets. | ||
234 | */ | ||
235 | connect.ep_cb.rx_alloc_thresh = ATH6KL_BUFFER_SIZE; | ||
236 | connect.ep_cb.rx_allocthresh = ath6kl_alloc_amsdu_rxbuf; | ||
237 | |||
238 | /* | ||
239 | * For the remaining data services set the connection flag to | ||
240 | * reduce dribbling, if configured to do so. | ||
241 | */ | ||
242 | connect.conn_flags |= HTC_CONN_FLGS_REDUCE_CRED_DRIB; | ||
243 | connect.conn_flags &= ~HTC_CONN_FLGS_THRESH_MASK; | ||
244 | connect.conn_flags |= HTC_CONN_FLGS_THRESH_LVL_HALF; | ||
245 | |||
246 | connect.svc_id = WMI_DATA_BE_SVC; | ||
247 | |||
248 | if (ath6kl_connectservice(ar, &connect, "WMI DATA BE")) | ||
249 | return -EIO; | ||
250 | |||
251 | /* connect to back-ground map this to WMI LOW_PRI */ | ||
252 | connect.svc_id = WMI_DATA_BK_SVC; | ||
253 | if (ath6kl_connectservice(ar, &connect, "WMI DATA BK")) | ||
254 | return -EIO; | ||
255 | |||
256 | /* connect to Video service, map this to to HI PRI */ | ||
257 | connect.svc_id = WMI_DATA_VI_SVC; | ||
258 | if (ath6kl_connectservice(ar, &connect, "WMI DATA VI")) | ||
259 | return -EIO; | ||
260 | |||
261 | /* | ||
262 | * Connect to VO service, this is currently not mapped to a WMI | ||
263 | * priority stream due to historical reasons. WMI originally | ||
264 | * defined 3 priorities over 3 mailboxes We can change this when | ||
265 | * WMI is reworked so that priorities are not dependent on | ||
266 | * mailboxes. | ||
267 | */ | ||
268 | connect.svc_id = WMI_DATA_VO_SVC; | ||
269 | if (ath6kl_connectservice(ar, &connect, "WMI DATA VO")) | ||
270 | return -EIO; | ||
271 | |||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | static void ath6kl_init_control_info(struct ath6kl *ar) | ||
276 | { | ||
277 | u8 ctr; | ||
278 | |||
279 | clear_bit(WMI_ENABLED, &ar->flag); | ||
280 | ath6kl_init_profile_info(ar); | ||
281 | ar->def_txkey_index = 0; | ||
282 | memset(ar->wep_key_list, 0, sizeof(ar->wep_key_list)); | ||
283 | ar->ch_hint = 0; | ||
284 | ar->listen_intvl_t = A_DEFAULT_LISTEN_INTERVAL; | ||
285 | ar->listen_intvl_b = 0; | ||
286 | ar->tx_pwr = 0; | ||
287 | clear_bit(SKIP_SCAN, &ar->flag); | ||
288 | set_bit(WMM_ENABLED, &ar->flag); | ||
289 | ar->intra_bss = 1; | ||
290 | memset(&ar->sc_params, 0, sizeof(ar->sc_params)); | ||
291 | ar->sc_params.short_scan_ratio = WMI_SHORTSCANRATIO_DEFAULT; | ||
292 | ar->sc_params.scan_ctrl_flags = DEFAULT_SCAN_CTRL_FLAGS; | ||
293 | |||
294 | memset((u8 *)ar->sta_list, 0, | ||
295 | AP_MAX_NUM_STA * sizeof(struct ath6kl_sta)); | ||
296 | |||
297 | spin_lock_init(&ar->mcastpsq_lock); | ||
298 | |||
299 | /* Init the PS queues */ | ||
300 | for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) { | ||
301 | spin_lock_init(&ar->sta_list[ctr].psq_lock); | ||
302 | skb_queue_head_init(&ar->sta_list[ctr].psq); | ||
303 | } | ||
304 | |||
305 | skb_queue_head_init(&ar->mcastpsq); | ||
306 | |||
307 | memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3); | ||
308 | } | ||
309 | |||
310 | /* | ||
311 | * Set HTC/Mbox operational parameters, this can only be called when the | ||
312 | * target is in the BMI phase. | ||
313 | */ | ||
314 | static int ath6kl_set_htc_params(struct ath6kl *ar, u32 mbox_isr_yield_val, | ||
315 | u8 htc_ctrl_buf) | ||
316 | { | ||
317 | int status; | ||
318 | u32 blk_size; | ||
319 | |||
320 | blk_size = ar->mbox_info.block_size; | ||
321 | |||
322 | if (htc_ctrl_buf) | ||
323 | blk_size |= ((u32)htc_ctrl_buf) << 16; | ||
324 | |||
325 | /* set the host interest area for the block size */ | ||
326 | status = ath6kl_bmi_write(ar, | ||
327 | ath6kl_get_hi_item_addr(ar, | ||
328 | HI_ITEM(hi_mbox_io_block_sz)), | ||
329 | (u8 *)&blk_size, | ||
330 | 4); | ||
331 | if (status) { | ||
332 | ath6kl_err("bmi_write_memory for IO block size failed\n"); | ||
333 | goto out; | ||
334 | } | ||
335 | |||
336 | ath6kl_dbg(ATH6KL_DBG_TRC, "block size set: %d (target addr:0x%X)\n", | ||
337 | blk_size, | ||
338 | ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_mbox_io_block_sz))); | ||
339 | |||
340 | if (mbox_isr_yield_val) { | ||
341 | /* set the host interest area for the mbox ISR yield limit */ | ||
342 | status = ath6kl_bmi_write(ar, | ||
343 | ath6kl_get_hi_item_addr(ar, | ||
344 | HI_ITEM(hi_mbox_isr_yield_limit)), | ||
345 | (u8 *)&mbox_isr_yield_val, | ||
346 | 4); | ||
347 | if (status) { | ||
348 | ath6kl_err("bmi_write_memory for yield limit failed\n"); | ||
349 | goto out; | ||
350 | } | ||
351 | } | ||
352 | |||
353 | out: | ||
354 | return status; | ||
355 | } | ||
356 | |||
357 | #define REG_DUMP_COUNT_AR6003 60 | ||
358 | #define REGISTER_DUMP_LEN_MAX 60 | ||
359 | |||
360 | static void ath6kl_dump_target_assert_info(struct ath6kl *ar) | ||
361 | { | ||
362 | u32 address; | ||
363 | u32 regdump_loc = 0; | ||
364 | int status; | ||
365 | u32 regdump_val[REGISTER_DUMP_LEN_MAX]; | ||
366 | u32 i; | ||
367 | |||
368 | if (ar->target_type != TARGET_TYPE_AR6003) | ||
369 | return; | ||
370 | |||
371 | /* the reg dump pointer is copied to the host interest area */ | ||
372 | address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_failure_state)); | ||
373 | address = TARG_VTOP(address); | ||
374 | |||
375 | /* read RAM location through diagnostic window */ | ||
376 | status = ath6kl_read_reg_diag(ar, &address, ®dump_loc); | ||
377 | |||
378 | if (status || !regdump_loc) { | ||
379 | ath6kl_err("failed to get ptr to register dump area\n"); | ||
380 | return; | ||
381 | } | ||
382 | |||
383 | ath6kl_dbg(ATH6KL_DBG_TRC, "location of register dump data: 0x%X\n", | ||
384 | regdump_loc); | ||
385 | |||
386 | regdump_loc = TARG_VTOP(regdump_loc); | ||
387 | |||
388 | /* fetch register dump data */ | ||
389 | status = ath6kl_access_datadiag(ar, | ||
390 | regdump_loc, | ||
391 | (u8 *)®dump_val[0], | ||
392 | REG_DUMP_COUNT_AR6003 * (sizeof(u32)), | ||
393 | true); | ||
394 | |||
395 | if (status) { | ||
396 | ath6kl_err("failed to get register dump\n"); | ||
397 | return; | ||
398 | } | ||
399 | ath6kl_dbg(ATH6KL_DBG_TRC, "Register Dump:\n"); | ||
400 | |||
401 | for (i = 0; i < REG_DUMP_COUNT_AR6003; i++) | ||
402 | ath6kl_dbg(ATH6KL_DBG_TRC, " %d : 0x%8.8X\n", | ||
403 | i, regdump_val[i]); | ||
404 | |||
405 | } | ||
406 | |||
407 | void ath6kl_target_failure(struct ath6kl *ar) | ||
408 | { | ||
409 | ath6kl_err("target asserted\n"); | ||
410 | |||
411 | /* try dumping target assertion information (if any) */ | ||
412 | ath6kl_dump_target_assert_info(ar); | ||
413 | |||
414 | } | ||
415 | |||
416 | static int ath6kl_target_config_wlan_params(struct ath6kl *ar) | ||
417 | { | ||
418 | int status = 0; | ||
419 | |||
420 | /* | ||
421 | * Configure the device for rx dot11 header rules. "0,0" are the | ||
422 | * default values. Required if checksum offload is needed. Set | ||
423 | * RxMetaVersion to 2. | ||
424 | */ | ||
425 | if (ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi, | ||
426 | ar->rx_meta_ver, 0, 0)) { | ||
427 | ath6kl_err("unable to set the rx frame format\n"); | ||
428 | status = -EIO; | ||
429 | } | ||
430 | |||
431 | if (ar->conf_flags & ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN) | ||
432 | if ((ath6kl_wmi_pmparams_cmd(ar->wmi, 0, 1, 0, 0, 1, | ||
433 | IGNORE_POWER_SAVE_FAIL_EVENT_DURING_SCAN)) != 0) { | ||
434 | ath6kl_err("unable to set power save fail event policy\n"); | ||
435 | status = -EIO; | ||
436 | } | ||
437 | |||
438 | if (!(ar->conf_flags & ATH6KL_CONF_IGNORE_ERP_BARKER)) | ||
439 | if ((ath6kl_wmi_set_lpreamble_cmd(ar->wmi, 0, | ||
440 | WMI_DONOT_IGNORE_BARKER_IN_ERP)) != 0) { | ||
441 | ath6kl_err("unable to set barker preamble policy\n"); | ||
442 | status = -EIO; | ||
443 | } | ||
444 | |||
445 | if (ath6kl_wmi_set_keepalive_cmd(ar->wmi, | ||
446 | WLAN_CONFIG_KEEP_ALIVE_INTERVAL)) { | ||
447 | ath6kl_err("unable to set keep alive interval\n"); | ||
448 | status = -EIO; | ||
449 | } | ||
450 | |||
451 | if (ath6kl_wmi_disctimeout_cmd(ar->wmi, | ||
452 | WLAN_CONFIG_DISCONNECT_TIMEOUT)) { | ||
453 | ath6kl_err("unable to set disconnect timeout\n"); | ||
454 | status = -EIO; | ||
455 | } | ||
456 | |||
457 | if (!(ar->conf_flags & ATH6KL_CONF_ENABLE_TX_BURST)) | ||
458 | if (ath6kl_wmi_set_wmm_txop(ar->wmi, WMI_TXOP_DISABLED)) { | ||
459 | ath6kl_err("unable to set txop bursting\n"); | ||
460 | status = -EIO; | ||
461 | } | ||
462 | |||
463 | return status; | ||
464 | } | ||
465 | |||
466 | int ath6kl_configure_target(struct ath6kl *ar) | ||
467 | { | ||
468 | u32 param, ram_reserved_size; | ||
469 | u8 fw_iftype; | ||
470 | |||
471 | fw_iftype = ath6kl_get_fw_iftype(ar); | ||
472 | if (fw_iftype == 0xff) | ||
473 | return -EINVAL; | ||
474 | |||
475 | /* Tell target which HTC version it is used*/ | ||
476 | param = HTC_PROTOCOL_VERSION; | ||
477 | if (ath6kl_bmi_write(ar, | ||
478 | ath6kl_get_hi_item_addr(ar, | ||
479 | HI_ITEM(hi_app_host_interest)), | ||
480 | (u8 *)¶m, 4) != 0) { | ||
481 | ath6kl_err("bmi_write_memory for htc version failed\n"); | ||
482 | return -EIO; | ||
483 | } | ||
484 | |||
485 | /* set the firmware mode to STA/IBSS/AP */ | ||
486 | param = 0; | ||
487 | |||
488 | if (ath6kl_bmi_read(ar, | ||
489 | ath6kl_get_hi_item_addr(ar, | ||
490 | HI_ITEM(hi_option_flag)), | ||
491 | (u8 *)¶m, 4) != 0) { | ||
492 | ath6kl_err("bmi_read_memory for setting fwmode failed\n"); | ||
493 | return -EIO; | ||
494 | } | ||
495 | |||
496 | param |= (1 << HI_OPTION_NUM_DEV_SHIFT); | ||
497 | param |= (fw_iftype << HI_OPTION_FW_MODE_SHIFT); | ||
498 | param |= (0 << HI_OPTION_MAC_ADDR_METHOD_SHIFT); | ||
499 | param |= (0 << HI_OPTION_FW_BRIDGE_SHIFT); | ||
500 | |||
501 | if (ath6kl_bmi_write(ar, | ||
502 | ath6kl_get_hi_item_addr(ar, | ||
503 | HI_ITEM(hi_option_flag)), | ||
504 | (u8 *)¶m, | ||
505 | 4) != 0) { | ||
506 | ath6kl_err("bmi_write_memory for setting fwmode failed\n"); | ||
507 | return -EIO; | ||
508 | } | ||
509 | |||
510 | ath6kl_dbg(ATH6KL_DBG_TRC, "firmware mode set\n"); | ||
511 | |||
512 | /* | ||
513 | * Hardcode the address use for the extended board data | ||
514 | * Ideally this should be pre-allocate by the OS at boot time | ||
515 | * But since it is a new feature and board data is loaded | ||
516 | * at init time, we have to workaround this from host. | ||
517 | * It is difficult to patch the firmware boot code, | ||
518 | * but possible in theory. | ||
519 | */ | ||
520 | |||
521 | if (ar->target_type == TARGET_TYPE_AR6003) { | ||
522 | if (ar->version.target_ver == AR6003_REV2_VERSION) { | ||
523 | param = AR6003_REV2_BOARD_EXT_DATA_ADDRESS; | ||
524 | ram_reserved_size = AR6003_REV2_RAM_RESERVE_SIZE; | ||
525 | } else { | ||
526 | param = AR6003_REV3_BOARD_EXT_DATA_ADDRESS; | ||
527 | ram_reserved_size = AR6003_REV3_RAM_RESERVE_SIZE; | ||
528 | } | ||
529 | |||
530 | if (ath6kl_bmi_write(ar, | ||
531 | ath6kl_get_hi_item_addr(ar, | ||
532 | HI_ITEM(hi_board_ext_data)), | ||
533 | (u8 *)¶m, 4) != 0) { | ||
534 | ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n"); | ||
535 | return -EIO; | ||
536 | } | ||
537 | if (ath6kl_bmi_write(ar, | ||
538 | ath6kl_get_hi_item_addr(ar, | ||
539 | HI_ITEM(hi_end_ram_reserve_sz)), | ||
540 | (u8 *)&ram_reserved_size, 4) != 0) { | ||
541 | ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n"); | ||
542 | return -EIO; | ||
543 | } | ||
544 | } | ||
545 | |||
546 | /* set the block size for the target */ | ||
547 | if (ath6kl_set_htc_params(ar, MBOX_YIELD_LIMIT, 0)) | ||
548 | /* use default number of control buffers */ | ||
549 | return -EIO; | ||
550 | |||
551 | return 0; | ||
552 | } | ||
553 | |||
554 | struct ath6kl *ath6kl_core_alloc(struct device *sdev) | ||
555 | { | ||
556 | struct net_device *dev; | ||
557 | struct ath6kl *ar; | ||
558 | struct wireless_dev *wdev; | ||
559 | |||
560 | wdev = ath6kl_cfg80211_init(sdev); | ||
561 | if (!wdev) { | ||
562 | ath6kl_err("ath6kl_cfg80211_init failed\n"); | ||
563 | return NULL; | ||
564 | } | ||
565 | |||
566 | ar = wdev_priv(wdev); | ||
567 | ar->dev = sdev; | ||
568 | ar->wdev = wdev; | ||
569 | wdev->iftype = NL80211_IFTYPE_STATION; | ||
570 | |||
571 | dev = alloc_netdev(0, "wlan%d", ether_setup); | ||
572 | if (!dev) { | ||
573 | ath6kl_err("no memory for network device instance\n"); | ||
574 | ath6kl_cfg80211_deinit(ar); | ||
575 | return NULL; | ||
576 | } | ||
577 | |||
578 | dev->ieee80211_ptr = wdev; | ||
579 | SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy)); | ||
580 | wdev->netdev = dev; | ||
581 | ar->sme_state = SME_DISCONNECTED; | ||
582 | ar->auto_auth_stage = AUTH_IDLE; | ||
583 | |||
584 | init_netdev(dev); | ||
585 | |||
586 | ar->net_dev = dev; | ||
587 | set_bit(WLAN_ENABLED, &ar->flag); | ||
588 | |||
589 | ar->wlan_pwr_state = WLAN_POWER_STATE_ON; | ||
590 | |||
591 | spin_lock_init(&ar->lock); | ||
592 | |||
593 | ath6kl_init_control_info(ar); | ||
594 | init_waitqueue_head(&ar->event_wq); | ||
595 | sema_init(&ar->sem, 1); | ||
596 | clear_bit(DESTROY_IN_PROGRESS, &ar->flag); | ||
597 | |||
598 | INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue); | ||
599 | |||
600 | setup_timer(&ar->disconnect_timer, disconnect_timer_handler, | ||
601 | (unsigned long) dev); | ||
602 | |||
603 | return ar; | ||
604 | } | ||
605 | |||
606 | int ath6kl_unavail_ev(struct ath6kl *ar) | ||
607 | { | ||
608 | ath6kl_destroy(ar->net_dev, 1); | ||
609 | |||
610 | return 0; | ||
611 | } | ||
612 | |||
613 | /* firmware upload */ | ||
614 | static u32 ath6kl_get_load_address(u32 target_ver, enum addr_type type) | ||
615 | { | ||
616 | WARN_ON(target_ver != AR6003_REV2_VERSION && | ||
617 | target_ver != AR6003_REV3_VERSION); | ||
618 | |||
619 | switch (type) { | ||
620 | case DATASET_PATCH_ADDR: | ||
621 | return (target_ver == AR6003_REV2_VERSION) ? | ||
622 | AR6003_REV2_DATASET_PATCH_ADDRESS : | ||
623 | AR6003_REV3_DATASET_PATCH_ADDRESS; | ||
624 | case APP_LOAD_ADDR: | ||
625 | return (target_ver == AR6003_REV2_VERSION) ? | ||
626 | AR6003_REV2_APP_LOAD_ADDRESS : | ||
627 | 0x1234; | ||
628 | case APP_START_OVERRIDE_ADDR: | ||
629 | return (target_ver == AR6003_REV2_VERSION) ? | ||
630 | AR6003_REV2_APP_START_OVERRIDE : | ||
631 | AR6003_REV3_APP_START_OVERRIDE; | ||
632 | default: | ||
633 | return 0; | ||
634 | } | ||
635 | } | ||
636 | |||
637 | static int ath6kl_get_fw(struct ath6kl *ar, const char *filename, | ||
638 | u8 **fw, size_t *fw_len) | ||
639 | { | ||
640 | const struct firmware *fw_entry; | ||
641 | int ret; | ||
642 | |||
643 | ret = request_firmware(&fw_entry, filename, ar->dev); | ||
644 | if (ret) | ||
645 | return ret; | ||
646 | |||
647 | *fw_len = fw_entry->size; | ||
648 | *fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL); | ||
649 | |||
650 | if (*fw == NULL) | ||
651 | ret = -ENOMEM; | ||
652 | |||
653 | release_firmware(fw_entry); | ||
654 | |||
655 | return ret; | ||
656 | } | ||
657 | |||
658 | static int ath6kl_fetch_board_file(struct ath6kl *ar) | ||
659 | { | ||
660 | const char *filename; | ||
661 | int ret; | ||
662 | |||
663 | switch (ar->version.target_ver) { | ||
664 | case AR6003_REV2_VERSION: | ||
665 | filename = AR6003_REV2_BOARD_DATA_FILE; | ||
666 | break; | ||
667 | default: | ||
668 | filename = AR6003_REV3_BOARD_DATA_FILE; | ||
669 | break; | ||
670 | } | ||
671 | |||
672 | ret = ath6kl_get_fw(ar, filename, &ar->fw_board, | ||
673 | &ar->fw_board_len); | ||
674 | if (ret == 0) { | ||
675 | /* managed to get proper board file */ | ||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | /* there was no proper board file, try to use default instead */ | ||
680 | ath6kl_warn("Failed to get board file %s (%d), trying to find default board file.\n", | ||
681 | filename, ret); | ||
682 | |||
683 | switch (ar->version.target_ver) { | ||
684 | case AR6003_REV2_VERSION: | ||
685 | filename = AR6003_REV2_DEFAULT_BOARD_DATA_FILE; | ||
686 | break; | ||
687 | default: | ||
688 | filename = AR6003_REV3_DEFAULT_BOARD_DATA_FILE; | ||
689 | break; | ||
690 | } | ||
691 | |||
692 | ret = ath6kl_get_fw(ar, filename, &ar->fw_board, | ||
693 | &ar->fw_board_len); | ||
694 | if (ret) { | ||
695 | ath6kl_err("Failed to get default board file %s: %d\n", | ||
696 | filename, ret); | ||
697 | return ret; | ||
698 | } | ||
699 | |||
700 | ath6kl_warn("WARNING! No proper board file was not found, instead using a default board file.\n"); | ||
701 | ath6kl_warn("Most likely your hardware won't work as specified. Install correct board file!\n"); | ||
702 | |||
703 | return 0; | ||
704 | } | ||
705 | |||
706 | |||
707 | static int ath6kl_upload_board_file(struct ath6kl *ar) | ||
708 | { | ||
709 | u32 board_address, board_ext_address, param; | ||
710 | int ret; | ||
711 | |||
712 | if (ar->fw_board == NULL) { | ||
713 | ret = ath6kl_fetch_board_file(ar); | ||
714 | if (ret) | ||
715 | return ret; | ||
716 | } | ||
717 | |||
718 | /* Determine where in Target RAM to write Board Data */ | ||
719 | ath6kl_bmi_read(ar, | ||
720 | ath6kl_get_hi_item_addr(ar, | ||
721 | HI_ITEM(hi_board_data)), | ||
722 | (u8 *) &board_address, 4); | ||
723 | ath6kl_dbg(ATH6KL_DBG_TRC, "board data download addr: 0x%x\n", | ||
724 | board_address); | ||
725 | |||
726 | /* determine where in target ram to write extended board data */ | ||
727 | ath6kl_bmi_read(ar, | ||
728 | ath6kl_get_hi_item_addr(ar, | ||
729 | HI_ITEM(hi_board_ext_data)), | ||
730 | (u8 *) &board_ext_address, 4); | ||
731 | |||
732 | ath6kl_dbg(ATH6KL_DBG_TRC, "board file download addr: 0x%x\n", | ||
733 | board_ext_address); | ||
734 | |||
735 | if (board_ext_address == 0) { | ||
736 | ath6kl_err("Failed to get board file target address.\n"); | ||
737 | return -EINVAL; | ||
738 | } | ||
739 | |||
740 | if (ar->fw_board_len == (AR6003_BOARD_DATA_SZ + | ||
741 | AR6003_BOARD_EXT_DATA_SZ)) { | ||
742 | /* write extended board data */ | ||
743 | ret = ath6kl_bmi_write(ar, board_ext_address, | ||
744 | ar->fw_board + AR6003_BOARD_DATA_SZ, | ||
745 | AR6003_BOARD_EXT_DATA_SZ); | ||
746 | |||
747 | if (ret) { | ||
748 | ath6kl_err("Failed to write extended board data: %d\n", | ||
749 | ret); | ||
750 | return ret; | ||
751 | } | ||
752 | |||
753 | /* record that extended board data is initialized */ | ||
754 | param = (AR6003_BOARD_EXT_DATA_SZ << 16) | 1; | ||
755 | ath6kl_bmi_write(ar, | ||
756 | ath6kl_get_hi_item_addr(ar, | ||
757 | HI_ITEM(hi_board_ext_data_config)), | ||
758 | (unsigned char *) ¶m, 4); | ||
759 | } | ||
760 | |||
761 | if (ar->fw_board_len < AR6003_BOARD_DATA_SZ) { | ||
762 | ath6kl_err("Too small board file: %zu\n", ar->fw_board_len); | ||
763 | ret = -EINVAL; | ||
764 | return ret; | ||
765 | } | ||
766 | |||
767 | ret = ath6kl_bmi_write(ar, board_address, ar->fw_board, | ||
768 | AR6003_BOARD_DATA_SZ); | ||
769 | |||
770 | if (ret) { | ||
771 | ath6kl_err("Board file bmi write failed: %d\n", ret); | ||
772 | return ret; | ||
773 | } | ||
774 | |||
775 | /* record the fact that Board Data IS initialized */ | ||
776 | param = 1; | ||
777 | ath6kl_bmi_write(ar, | ||
778 | ath6kl_get_hi_item_addr(ar, | ||
779 | HI_ITEM(hi_board_data_initialized)), | ||
780 | (u8 *)¶m, 4); | ||
781 | |||
782 | return ret; | ||
783 | } | ||
784 | |||
785 | static int ath6kl_upload_otp(struct ath6kl *ar) | ||
786 | { | ||
787 | const char *filename; | ||
788 | u32 address, param; | ||
789 | int ret; | ||
790 | |||
791 | switch (ar->version.target_ver) { | ||
792 | case AR6003_REV2_VERSION: | ||
793 | filename = AR6003_REV2_OTP_FILE; | ||
794 | break; | ||
795 | default: | ||
796 | filename = AR6003_REV3_OTP_FILE; | ||
797 | break; | ||
798 | } | ||
799 | |||
800 | if (ar->fw_otp == NULL) { | ||
801 | ret = ath6kl_get_fw(ar, filename, &ar->fw_otp, | ||
802 | &ar->fw_otp_len); | ||
803 | if (ret) { | ||
804 | ath6kl_err("Failed to get OTP file %s: %d\n", | ||
805 | filename, ret); | ||
806 | return ret; | ||
807 | } | ||
808 | } | ||
809 | |||
810 | address = ath6kl_get_load_address(ar->version.target_ver, | ||
811 | APP_LOAD_ADDR); | ||
812 | |||
813 | ret = ath6kl_bmi_fast_download(ar, address, ar->fw_otp, | ||
814 | ar->fw_otp_len); | ||
815 | if (ret) { | ||
816 | ath6kl_err("Failed to upload OTP file: %d\n", ret); | ||
817 | return ret; | ||
818 | } | ||
819 | |||
820 | /* execute the OTP code */ | ||
821 | param = 0; | ||
822 | address = ath6kl_get_load_address(ar->version.target_ver, | ||
823 | APP_START_OVERRIDE_ADDR); | ||
824 | ath6kl_bmi_execute(ar, address, ¶m); | ||
825 | |||
826 | return ret; | ||
827 | } | ||
828 | |||
829 | static int ath6kl_upload_firmware(struct ath6kl *ar) | ||
830 | { | ||
831 | const char *filename; | ||
832 | u32 address; | ||
833 | int ret; | ||
834 | |||
835 | switch (ar->version.target_ver) { | ||
836 | case AR6003_REV2_VERSION: | ||
837 | filename = AR6003_REV2_FIRMWARE_FILE; | ||
838 | break; | ||
839 | default: | ||
840 | filename = AR6003_REV3_FIRMWARE_FILE; | ||
841 | break; | ||
842 | } | ||
843 | |||
844 | if (ar->fw == NULL) { | ||
845 | ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len); | ||
846 | if (ret) { | ||
847 | ath6kl_err("Failed to get firmware file %s: %d\n", | ||
848 | filename, ret); | ||
849 | return ret; | ||
850 | } | ||
851 | } | ||
852 | |||
853 | address = ath6kl_get_load_address(ar->version.target_ver, | ||
854 | APP_LOAD_ADDR); | ||
855 | |||
856 | ret = ath6kl_bmi_fast_download(ar, address, ar->fw, ar->fw_len); | ||
857 | |||
858 | if (ret) { | ||
859 | ath6kl_err("Failed to write firmware: %d\n", ret); | ||
860 | return ret; | ||
861 | } | ||
862 | |||
863 | /* Set starting address for firmware */ | ||
864 | address = ath6kl_get_load_address(ar->version.target_ver, | ||
865 | APP_START_OVERRIDE_ADDR); | ||
866 | ath6kl_bmi_set_app_start(ar, address); | ||
867 | |||
868 | return ret; | ||
869 | } | ||
870 | |||
871 | static int ath6kl_upload_patch(struct ath6kl *ar) | ||
872 | { | ||
873 | const char *filename; | ||
874 | u32 address, param; | ||
875 | int ret; | ||
876 | |||
877 | switch (ar->version.target_ver) { | ||
878 | case AR6003_REV2_VERSION: | ||
879 | filename = AR6003_REV2_PATCH_FILE; | ||
880 | break; | ||
881 | default: | ||
882 | filename = AR6003_REV3_PATCH_FILE; | ||
883 | break; | ||
884 | } | ||
885 | |||
886 | if (ar->fw_patch == NULL) { | ||
887 | ret = ath6kl_get_fw(ar, filename, &ar->fw_patch, | ||
888 | &ar->fw_patch_len); | ||
889 | if (ret) { | ||
890 | ath6kl_err("Failed to get patch file %s: %d\n", | ||
891 | filename, ret); | ||
892 | return ret; | ||
893 | } | ||
894 | } | ||
895 | |||
896 | address = ath6kl_get_load_address(ar->version.target_ver, | ||
897 | DATASET_PATCH_ADDR); | ||
898 | |||
899 | ret = ath6kl_bmi_write(ar, address, ar->fw_patch, ar->fw_patch_len); | ||
900 | if (ret) { | ||
901 | ath6kl_err("Failed to write patch file: %d\n", ret); | ||
902 | return ret; | ||
903 | } | ||
904 | |||
905 | param = address; | ||
906 | ath6kl_bmi_write(ar, | ||
907 | ath6kl_get_hi_item_addr(ar, | ||
908 | HI_ITEM(hi_dset_list_head)), | ||
909 | (unsigned char *) ¶m, 4); | ||
910 | |||
911 | return 0; | ||
912 | } | ||
913 | |||
914 | static int ath6kl_init_upload(struct ath6kl *ar) | ||
915 | { | ||
916 | u32 param, options, sleep, address; | ||
917 | int status = 0; | ||
918 | |||
919 | if (ar->target_type != TARGET_TYPE_AR6003) | ||
920 | return -EINVAL; | ||
921 | |||
922 | /* temporarily disable system sleep */ | ||
923 | address = MBOX_BASE_ADDRESS + LOCAL_SCRATCH_ADDRESS; | ||
924 | status = ath6kl_bmi_reg_read(ar, address, ¶m); | ||
925 | if (status) | ||
926 | return status; | ||
927 | |||
928 | options = param; | ||
929 | |||
930 | param |= ATH6KL_OPTION_SLEEP_DISABLE; | ||
931 | status = ath6kl_bmi_reg_write(ar, address, param); | ||
932 | if (status) | ||
933 | return status; | ||
934 | |||
935 | address = RTC_BASE_ADDRESS + SYSTEM_SLEEP_ADDRESS; | ||
936 | status = ath6kl_bmi_reg_read(ar, address, ¶m); | ||
937 | if (status) | ||
938 | return status; | ||
939 | |||
940 | sleep = param; | ||
941 | |||
942 | param |= SM(SYSTEM_SLEEP_DISABLE, 1); | ||
943 | status = ath6kl_bmi_reg_write(ar, address, param); | ||
944 | if (status) | ||
945 | return status; | ||
946 | |||
947 | ath6kl_dbg(ATH6KL_DBG_TRC, "old options: %d, old sleep: %d\n", | ||
948 | options, sleep); | ||
949 | |||
950 | /* program analog PLL register */ | ||
951 | status = ath6kl_bmi_reg_write(ar, ATH6KL_ANALOG_PLL_REGISTER, | ||
952 | 0xF9104001); | ||
953 | if (status) | ||
954 | return status; | ||
955 | |||
956 | /* Run at 80/88MHz by default */ | ||
957 | param = SM(CPU_CLOCK_STANDARD, 1); | ||
958 | |||
959 | address = RTC_BASE_ADDRESS + CPU_CLOCK_ADDRESS; | ||
960 | status = ath6kl_bmi_reg_write(ar, address, param); | ||
961 | if (status) | ||
962 | return status; | ||
963 | |||
964 | param = 0; | ||
965 | address = RTC_BASE_ADDRESS + LPO_CAL_ADDRESS; | ||
966 | param = SM(LPO_CAL_ENABLE, 1); | ||
967 | status = ath6kl_bmi_reg_write(ar, address, param); | ||
968 | if (status) | ||
969 | return status; | ||
970 | |||
971 | /* WAR to avoid SDIO CRC err */ | ||
972 | if (ar->version.target_ver == AR6003_REV2_VERSION) { | ||
973 | ath6kl_err("temporary war to avoid sdio crc error\n"); | ||
974 | |||
975 | param = 0x20; | ||
976 | |||
977 | address = GPIO_BASE_ADDRESS + GPIO_PIN10_ADDRESS; | ||
978 | status = ath6kl_bmi_reg_write(ar, address, param); | ||
979 | if (status) | ||
980 | return status; | ||
981 | |||
982 | address = GPIO_BASE_ADDRESS + GPIO_PIN11_ADDRESS; | ||
983 | status = ath6kl_bmi_reg_write(ar, address, param); | ||
984 | if (status) | ||
985 | return status; | ||
986 | |||
987 | address = GPIO_BASE_ADDRESS + GPIO_PIN12_ADDRESS; | ||
988 | status = ath6kl_bmi_reg_write(ar, address, param); | ||
989 | if (status) | ||
990 | return status; | ||
991 | |||
992 | address = GPIO_BASE_ADDRESS + GPIO_PIN13_ADDRESS; | ||
993 | status = ath6kl_bmi_reg_write(ar, address, param); | ||
994 | if (status) | ||
995 | return status; | ||
996 | } | ||
997 | |||
998 | /* write EEPROM data to Target RAM */ | ||
999 | status = ath6kl_upload_board_file(ar); | ||
1000 | if (status) | ||
1001 | return status; | ||
1002 | |||
1003 | /* transfer One time Programmable data */ | ||
1004 | status = ath6kl_upload_otp(ar); | ||
1005 | if (status) | ||
1006 | return status; | ||
1007 | |||
1008 | /* Download Target firmware */ | ||
1009 | status = ath6kl_upload_firmware(ar); | ||
1010 | if (status) | ||
1011 | return status; | ||
1012 | |||
1013 | status = ath6kl_upload_patch(ar); | ||
1014 | if (status) | ||
1015 | return status; | ||
1016 | |||
1017 | /* Restore system sleep */ | ||
1018 | address = RTC_BASE_ADDRESS + SYSTEM_SLEEP_ADDRESS; | ||
1019 | status = ath6kl_bmi_reg_write(ar, address, sleep); | ||
1020 | if (status) | ||
1021 | return status; | ||
1022 | |||
1023 | address = MBOX_BASE_ADDRESS + LOCAL_SCRATCH_ADDRESS; | ||
1024 | param = options | 0x20; | ||
1025 | status = ath6kl_bmi_reg_write(ar, address, param); | ||
1026 | if (status) | ||
1027 | return status; | ||
1028 | |||
1029 | /* Configure GPIO AR6003 UART */ | ||
1030 | param = CONFIG_AR600x_DEBUG_UART_TX_PIN; | ||
1031 | status = ath6kl_bmi_write(ar, | ||
1032 | ath6kl_get_hi_item_addr(ar, | ||
1033 | HI_ITEM(hi_dbg_uart_txpin)), | ||
1034 | (u8 *)¶m, 4); | ||
1035 | |||
1036 | return status; | ||
1037 | } | ||
1038 | |||
1039 | static int ath6kl_init(struct net_device *dev) | ||
1040 | { | ||
1041 | struct ath6kl *ar = ath6kl_priv(dev); | ||
1042 | int status = 0; | ||
1043 | s32 timeleft; | ||
1044 | |||
1045 | if (!ar) | ||
1046 | return -EIO; | ||
1047 | |||
1048 | /* Do we need to finish the BMI phase */ | ||
1049 | if (ath6kl_bmi_done(ar)) { | ||
1050 | status = -EIO; | ||
1051 | goto ath6kl_init_done; | ||
1052 | } | ||
1053 | |||
1054 | /* Indicate that WMI is enabled (although not ready yet) */ | ||
1055 | set_bit(WMI_ENABLED, &ar->flag); | ||
1056 | ar->wmi = ath6kl_wmi_init(ar); | ||
1057 | if (!ar->wmi) { | ||
1058 | ath6kl_err("failed to initialize wmi\n"); | ||
1059 | status = -EIO; | ||
1060 | goto ath6kl_init_done; | ||
1061 | } | ||
1062 | |||
1063 | ath6kl_dbg(ATH6KL_DBG_TRC, "%s: got wmi @ 0x%p.\n", __func__, ar->wmi); | ||
1064 | |||
1065 | wlan_node_table_init(&ar->scan_table); | ||
1066 | |||
1067 | /* | ||
1068 | * The reason we have to wait for the target here is that the | ||
1069 | * driver layer has to init BMI in order to set the host block | ||
1070 | * size. | ||
1071 | */ | ||
1072 | if (ath6kl_htc_wait_target(ar->htc_target)) { | ||
1073 | status = -EIO; | ||
1074 | goto err_node_cleanup; | ||
1075 | } | ||
1076 | |||
1077 | if (ath6kl_init_service_ep(ar)) { | ||
1078 | status = -EIO; | ||
1079 | goto err_cleanup_scatter; | ||
1080 | } | ||
1081 | |||
1082 | /* setup access class priority mappings */ | ||
1083 | ar->ac_stream_pri_map[WMM_AC_BK] = 0; /* lowest */ | ||
1084 | ar->ac_stream_pri_map[WMM_AC_BE] = 1; | ||
1085 | ar->ac_stream_pri_map[WMM_AC_VI] = 2; | ||
1086 | ar->ac_stream_pri_map[WMM_AC_VO] = 3; /* highest */ | ||
1087 | |||
1088 | /* give our connected endpoints some buffers */ | ||
1089 | ath6kl_rx_refill(ar->htc_target, ar->ctrl_ep); | ||
1090 | ath6kl_rx_refill(ar->htc_target, ar->ac2ep_map[WMM_AC_BE]); | ||
1091 | |||
1092 | /* allocate some buffers that handle larger AMSDU frames */ | ||
1093 | ath6kl_refill_amsdu_rxbufs(ar, ATH6KL_MAX_AMSDU_RX_BUFFERS); | ||
1094 | |||
1095 | /* setup credit distribution */ | ||
1096 | ath6k_setup_credit_dist(ar->htc_target, &ar->credit_state_info); | ||
1097 | |||
1098 | ath6kl_cookie_init(ar); | ||
1099 | |||
1100 | /* start HTC */ | ||
1101 | status = ath6kl_htc_start(ar->htc_target); | ||
1102 | |||
1103 | if (status) { | ||
1104 | ath6kl_cookie_cleanup(ar); | ||
1105 | goto err_rxbuf_cleanup; | ||
1106 | } | ||
1107 | |||
1108 | /* Wait for Wmi event to be ready */ | ||
1109 | timeleft = wait_event_interruptible_timeout(ar->event_wq, | ||
1110 | test_bit(WMI_READY, | ||
1111 | &ar->flag), | ||
1112 | WMI_TIMEOUT); | ||
1113 | |||
1114 | if (ar->version.abi_ver != ATH6KL_ABI_VERSION) { | ||
1115 | ath6kl_err("abi version mismatch: host(0x%x), target(0x%x)\n", | ||
1116 | ATH6KL_ABI_VERSION, ar->version.abi_ver); | ||
1117 | status = -EIO; | ||
1118 | goto err_htc_stop; | ||
1119 | } | ||
1120 | |||
1121 | if (!timeleft || signal_pending(current)) { | ||
1122 | ath6kl_err("wmi is not ready or wait was interrupted\n"); | ||
1123 | status = -EIO; | ||
1124 | goto err_htc_stop; | ||
1125 | } | ||
1126 | |||
1127 | ath6kl_dbg(ATH6KL_DBG_TRC, "%s: wmi is ready\n", __func__); | ||
1128 | |||
1129 | /* communicate the wmi protocol verision to the target */ | ||
1130 | if ((ath6kl_set_host_app_area(ar)) != 0) | ||
1131 | ath6kl_err("unable to set the host app area\n"); | ||
1132 | |||
1133 | ar->conf_flags = ATH6KL_CONF_IGNORE_ERP_BARKER | | ||
1134 | ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST; | ||
1135 | |||
1136 | status = ath6kl_target_config_wlan_params(ar); | ||
1137 | if (!status) | ||
1138 | goto ath6kl_init_done; | ||
1139 | |||
1140 | err_htc_stop: | ||
1141 | ath6kl_htc_stop(ar->htc_target); | ||
1142 | err_rxbuf_cleanup: | ||
1143 | ath6kl_htc_flush_rx_buf(ar->htc_target); | ||
1144 | ath6kl_cleanup_amsdu_rxbufs(ar); | ||
1145 | err_cleanup_scatter: | ||
1146 | ath6kl_hif_cleanup_scatter(ar); | ||
1147 | err_node_cleanup: | ||
1148 | wlan_node_table_cleanup(&ar->scan_table); | ||
1149 | ath6kl_wmi_shutdown(ar->wmi); | ||
1150 | clear_bit(WMI_ENABLED, &ar->flag); | ||
1151 | ar->wmi = NULL; | ||
1152 | |||
1153 | ath6kl_init_done: | ||
1154 | return status; | ||
1155 | } | ||
1156 | |||
1157 | int ath6kl_core_init(struct ath6kl *ar) | ||
1158 | { | ||
1159 | int ret = 0; | ||
1160 | struct ath6kl_bmi_target_info targ_info; | ||
1161 | |||
1162 | ar->ath6kl_wq = create_singlethread_workqueue("ath6kl"); | ||
1163 | if (!ar->ath6kl_wq) | ||
1164 | return -ENOMEM; | ||
1165 | |||
1166 | ret = ath6kl_bmi_init(ar); | ||
1167 | if (ret) | ||
1168 | goto err_wq; | ||
1169 | |||
1170 | ret = ath6kl_bmi_get_target_info(ar, &targ_info); | ||
1171 | if (ret) | ||
1172 | goto err_bmi_cleanup; | ||
1173 | |||
1174 | ar->version.target_ver = le32_to_cpu(targ_info.version); | ||
1175 | ar->target_type = le32_to_cpu(targ_info.type); | ||
1176 | ar->wdev->wiphy->hw_version = le32_to_cpu(targ_info.version); | ||
1177 | |||
1178 | ret = ath6kl_configure_target(ar); | ||
1179 | if (ret) | ||
1180 | goto err_bmi_cleanup; | ||
1181 | |||
1182 | ar->htc_target = ath6kl_htc_create(ar); | ||
1183 | |||
1184 | if (!ar->htc_target) { | ||
1185 | ret = -ENOMEM; | ||
1186 | goto err_bmi_cleanup; | ||
1187 | } | ||
1188 | |||
1189 | ar->aggr_cntxt = aggr_init(ar->net_dev); | ||
1190 | if (!ar->aggr_cntxt) { | ||
1191 | ath6kl_err("failed to initialize aggr\n"); | ||
1192 | ret = -ENOMEM; | ||
1193 | goto err_htc_cleanup; | ||
1194 | } | ||
1195 | |||
1196 | ret = ath6kl_init_upload(ar); | ||
1197 | if (ret) | ||
1198 | goto err_htc_cleanup; | ||
1199 | |||
1200 | ret = ath6kl_init(ar->net_dev); | ||
1201 | if (ret) | ||
1202 | goto err_htc_cleanup; | ||
1203 | |||
1204 | /* This runs the init function if registered */ | ||
1205 | ret = register_netdev(ar->net_dev); | ||
1206 | if (ret) { | ||
1207 | ath6kl_err("register_netdev failed\n"); | ||
1208 | ath6kl_destroy(ar->net_dev, 0); | ||
1209 | return ret; | ||
1210 | } | ||
1211 | |||
1212 | set_bit(NETDEV_REGISTERED, &ar->flag); | ||
1213 | |||
1214 | ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n", | ||
1215 | __func__, ar->net_dev->name, ar->net_dev, ar); | ||
1216 | |||
1217 | return ret; | ||
1218 | |||
1219 | err_htc_cleanup: | ||
1220 | ath6kl_htc_cleanup(ar->htc_target); | ||
1221 | err_bmi_cleanup: | ||
1222 | ath6kl_bmi_cleanup(ar); | ||
1223 | err_wq: | ||
1224 | destroy_workqueue(ar->ath6kl_wq); | ||
1225 | return ret; | ||
1226 | } | ||
1227 | |||
1228 | void ath6kl_stop_txrx(struct ath6kl *ar) | ||
1229 | { | ||
1230 | struct net_device *ndev = ar->net_dev; | ||
1231 | |||
1232 | if (!ndev) | ||
1233 | return; | ||
1234 | |||
1235 | set_bit(DESTROY_IN_PROGRESS, &ar->flag); | ||
1236 | |||
1237 | if (down_interruptible(&ar->sem)) { | ||
1238 | ath6kl_err("down_interruptible failed\n"); | ||
1239 | return; | ||
1240 | } | ||
1241 | |||
1242 | if (ar->wlan_pwr_state != WLAN_POWER_STATE_CUT_PWR) | ||
1243 | ath6kl_stop_endpoint(ndev, false, true); | ||
1244 | |||
1245 | clear_bit(WLAN_ENABLED, &ar->flag); | ||
1246 | } | ||
1247 | |||
1248 | /* | ||
1249 | * We need to differentiate between the surprise and planned removal of the | ||
1250 | * device because of the following consideration: | ||
1251 | * | ||
1252 | * - In case of surprise removal, the hcd already frees up the pending | ||
1253 | * for the device and hence there is no need to unregister the function | ||
1254 | * driver inorder to get these requests. For planned removal, the function | ||
1255 | * driver has to explicitly unregister itself to have the hcd return all the | ||
1256 | * pending requests before the data structures for the devices are freed up. | ||
1257 | * Note that as per the current implementation, the function driver will | ||
1258 | * end up releasing all the devices since there is no API to selectively | ||
1259 | * release a particular device. | ||
1260 | * | ||
1261 | * - Certain commands issued to the target can be skipped for surprise | ||
1262 | * removal since they will anyway not go through. | ||
1263 | */ | ||
1264 | void ath6kl_destroy(struct net_device *dev, unsigned int unregister) | ||
1265 | { | ||
1266 | struct ath6kl *ar; | ||
1267 | |||
1268 | if (!dev || !ath6kl_priv(dev)) { | ||
1269 | ath6kl_err("failed to get device structure\n"); | ||
1270 | return; | ||
1271 | } | ||
1272 | |||
1273 | ar = ath6kl_priv(dev); | ||
1274 | |||
1275 | destroy_workqueue(ar->ath6kl_wq); | ||
1276 | |||
1277 | if (ar->htc_target) | ||
1278 | ath6kl_htc_cleanup(ar->htc_target); | ||
1279 | |||
1280 | aggr_module_destroy(ar->aggr_cntxt); | ||
1281 | |||
1282 | ath6kl_cookie_cleanup(ar); | ||
1283 | |||
1284 | ath6kl_cleanup_amsdu_rxbufs(ar); | ||
1285 | |||
1286 | ath6kl_bmi_cleanup(ar); | ||
1287 | |||
1288 | if (unregister && test_bit(NETDEV_REGISTERED, &ar->flag)) { | ||
1289 | unregister_netdev(dev); | ||
1290 | clear_bit(NETDEV_REGISTERED, &ar->flag); | ||
1291 | } | ||
1292 | |||
1293 | free_netdev(dev); | ||
1294 | |||
1295 | wlan_node_table_cleanup(&ar->scan_table); | ||
1296 | |||
1297 | kfree(ar->fw_board); | ||
1298 | kfree(ar->fw_otp); | ||
1299 | kfree(ar->fw); | ||
1300 | kfree(ar->fw_patch); | ||
1301 | |||
1302 | ath6kl_cfg80211_deinit(ar); | ||
1303 | } | ||
diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c new file mode 100644 index 000000000000..c336eae0cf48 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/main.c | |||
@@ -0,0 +1,1337 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004-2011 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 "core.h" | ||
18 | #include "hif-ops.h" | ||
19 | #include "cfg80211.h" | ||
20 | #include "target.h" | ||
21 | #include "debug.h" | ||
22 | |||
23 | struct ath6kl_sta *ath6kl_find_sta(struct ath6kl *ar, u8 *node_addr) | ||
24 | { | ||
25 | struct ath6kl_sta *conn = NULL; | ||
26 | u8 i, max_conn; | ||
27 | |||
28 | max_conn = (ar->nw_type == AP_NETWORK) ? AP_MAX_NUM_STA : 0; | ||
29 | |||
30 | for (i = 0; i < max_conn; i++) { | ||
31 | if (memcmp(node_addr, ar->sta_list[i].mac, ETH_ALEN) == 0) { | ||
32 | conn = &ar->sta_list[i]; | ||
33 | break; | ||
34 | } | ||
35 | } | ||
36 | |||
37 | return conn; | ||
38 | } | ||
39 | |||
40 | struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid) | ||
41 | { | ||
42 | struct ath6kl_sta *conn = NULL; | ||
43 | u8 ctr; | ||
44 | |||
45 | for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) { | ||
46 | if (ar->sta_list[ctr].aid == aid) { | ||
47 | conn = &ar->sta_list[ctr]; | ||
48 | break; | ||
49 | } | ||
50 | } | ||
51 | return conn; | ||
52 | } | ||
53 | |||
54 | static void ath6kl_add_new_sta(struct ath6kl *ar, u8 *mac, u16 aid, u8 *wpaie, | ||
55 | u8 ielen, u8 keymgmt, u8 ucipher, u8 auth) | ||
56 | { | ||
57 | struct ath6kl_sta *sta; | ||
58 | u8 free_slot; | ||
59 | |||
60 | free_slot = aid - 1; | ||
61 | |||
62 | sta = &ar->sta_list[free_slot]; | ||
63 | memcpy(sta->mac, mac, ETH_ALEN); | ||
64 | memcpy(sta->wpa_ie, wpaie, ielen); | ||
65 | sta->aid = aid; | ||
66 | sta->keymgmt = keymgmt; | ||
67 | sta->ucipher = ucipher; | ||
68 | sta->auth = auth; | ||
69 | |||
70 | ar->sta_list_index = ar->sta_list_index | (1 << free_slot); | ||
71 | ar->ap_stats.sta[free_slot].aid = cpu_to_le32(aid); | ||
72 | } | ||
73 | |||
74 | static void ath6kl_sta_cleanup(struct ath6kl *ar, u8 i) | ||
75 | { | ||
76 | struct ath6kl_sta *sta = &ar->sta_list[i]; | ||
77 | |||
78 | /* empty the queued pkts in the PS queue if any */ | ||
79 | spin_lock_bh(&sta->psq_lock); | ||
80 | skb_queue_purge(&sta->psq); | ||
81 | spin_unlock_bh(&sta->psq_lock); | ||
82 | |||
83 | memset(&ar->ap_stats.sta[sta->aid - 1], 0, | ||
84 | sizeof(struct wmi_per_sta_stat)); | ||
85 | memset(sta->mac, 0, ETH_ALEN); | ||
86 | memset(sta->wpa_ie, 0, ATH6KL_MAX_IE); | ||
87 | sta->aid = 0; | ||
88 | sta->sta_flags = 0; | ||
89 | |||
90 | ar->sta_list_index = ar->sta_list_index & ~(1 << i); | ||
91 | |||
92 | } | ||
93 | |||
94 | static u8 ath6kl_remove_sta(struct ath6kl *ar, u8 *mac, u16 reason) | ||
95 | { | ||
96 | u8 i, removed = 0; | ||
97 | |||
98 | if (is_zero_ether_addr(mac)) | ||
99 | return removed; | ||
100 | |||
101 | if (is_broadcast_ether_addr(mac)) { | ||
102 | ath6kl_dbg(ATH6KL_DBG_TRC, "deleting all station\n"); | ||
103 | |||
104 | for (i = 0; i < AP_MAX_NUM_STA; i++) { | ||
105 | if (!is_zero_ether_addr(ar->sta_list[i].mac)) { | ||
106 | ath6kl_sta_cleanup(ar, i); | ||
107 | removed = 1; | ||
108 | } | ||
109 | } | ||
110 | } else { | ||
111 | for (i = 0; i < AP_MAX_NUM_STA; i++) { | ||
112 | if (memcmp(ar->sta_list[i].mac, mac, ETH_ALEN) == 0) { | ||
113 | ath6kl_dbg(ATH6KL_DBG_TRC, | ||
114 | "deleting station %pM aid=%d reason=%d\n", | ||
115 | mac, ar->sta_list[i].aid, reason); | ||
116 | ath6kl_sta_cleanup(ar, i); | ||
117 | removed = 1; | ||
118 | break; | ||
119 | } | ||
120 | } | ||
121 | } | ||
122 | |||
123 | return removed; | ||
124 | } | ||
125 | |||
126 | enum htc_endpoint_id ath6kl_ac2_endpoint_id(void *devt, u8 ac) | ||
127 | { | ||
128 | struct ath6kl *ar = devt; | ||
129 | return ar->ac2ep_map[ac]; | ||
130 | } | ||
131 | |||
132 | struct ath6kl_cookie *ath6kl_alloc_cookie(struct ath6kl *ar) | ||
133 | { | ||
134 | struct ath6kl_cookie *cookie; | ||
135 | |||
136 | cookie = ar->cookie_list; | ||
137 | if (cookie != NULL) { | ||
138 | ar->cookie_list = cookie->arc_list_next; | ||
139 | ar->cookie_count--; | ||
140 | } | ||
141 | |||
142 | return cookie; | ||
143 | } | ||
144 | |||
145 | void ath6kl_cookie_init(struct ath6kl *ar) | ||
146 | { | ||
147 | u32 i; | ||
148 | |||
149 | ar->cookie_list = NULL; | ||
150 | ar->cookie_count = 0; | ||
151 | |||
152 | memset(ar->cookie_mem, 0, sizeof(ar->cookie_mem)); | ||
153 | |||
154 | for (i = 0; i < MAX_COOKIE_NUM; i++) | ||
155 | ath6kl_free_cookie(ar, &ar->cookie_mem[i]); | ||
156 | } | ||
157 | |||
158 | void ath6kl_cookie_cleanup(struct ath6kl *ar) | ||
159 | { | ||
160 | ar->cookie_list = NULL; | ||
161 | ar->cookie_count = 0; | ||
162 | } | ||
163 | |||
164 | void ath6kl_free_cookie(struct ath6kl *ar, struct ath6kl_cookie *cookie) | ||
165 | { | ||
166 | /* Insert first */ | ||
167 | |||
168 | if (!ar || !cookie) | ||
169 | return; | ||
170 | |||
171 | cookie->arc_list_next = ar->cookie_list; | ||
172 | ar->cookie_list = cookie; | ||
173 | ar->cookie_count++; | ||
174 | } | ||
175 | |||
176 | /* set the window address register (using 4-byte register access ). */ | ||
177 | static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr) | ||
178 | { | ||
179 | int status; | ||
180 | u8 addr_val[4]; | ||
181 | s32 i; | ||
182 | |||
183 | /* | ||
184 | * Write bytes 1,2,3 of the register to set the upper address bytes, | ||
185 | * the LSB is written last to initiate the access cycle | ||
186 | */ | ||
187 | |||
188 | for (i = 1; i <= 3; i++) { | ||
189 | /* | ||
190 | * Fill the buffer with the address byte value we want to | ||
191 | * hit 4 times. | ||
192 | */ | ||
193 | memset(addr_val, ((u8 *)&addr)[i], 4); | ||
194 | |||
195 | /* | ||
196 | * Hit each byte of the register address with a 4-byte | ||
197 | * write operation to the same address, this is a harmless | ||
198 | * operation. | ||
199 | */ | ||
200 | status = hif_read_write_sync(ar, reg_addr + i, addr_val, | ||
201 | 4, HIF_WR_SYNC_BYTE_FIX); | ||
202 | if (status) | ||
203 | break; | ||
204 | } | ||
205 | |||
206 | if (status) { | ||
207 | ath6kl_err("failed to write initial bytes of 0x%x to window reg: 0x%X\n", | ||
208 | addr, reg_addr); | ||
209 | return status; | ||
210 | } | ||
211 | |||
212 | /* | ||
213 | * Write the address register again, this time write the whole | ||
214 | * 4-byte value. The effect here is that the LSB write causes the | ||
215 | * cycle to start, the extra 3 byte write to bytes 1,2,3 has no | ||
216 | * effect since we are writing the same values again | ||
217 | */ | ||
218 | status = hif_read_write_sync(ar, reg_addr, (u8 *)(&addr), | ||
219 | 4, HIF_WR_SYNC_BYTE_INC); | ||
220 | |||
221 | if (status) { | ||
222 | ath6kl_err("failed to write 0x%x to window reg: 0x%X\n", | ||
223 | addr, reg_addr); | ||
224 | return status; | ||
225 | } | ||
226 | |||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | /* | ||
231 | * Read from the ATH6KL through its diagnostic window. No cooperation from | ||
232 | * the Target is required for this. | ||
233 | */ | ||
234 | int ath6kl_read_reg_diag(struct ath6kl *ar, u32 *address, u32 *data) | ||
235 | { | ||
236 | int status; | ||
237 | |||
238 | /* set window register to start read cycle */ | ||
239 | status = ath6kl_set_addrwin_reg(ar, WINDOW_READ_ADDR_ADDRESS, | ||
240 | *address); | ||
241 | |||
242 | if (status) | ||
243 | return status; | ||
244 | |||
245 | /* read the data */ | ||
246 | status = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *)data, | ||
247 | sizeof(u32), HIF_RD_SYNC_BYTE_INC); | ||
248 | if (status) { | ||
249 | ath6kl_err("failed to read from window data addr\n"); | ||
250 | return status; | ||
251 | } | ||
252 | |||
253 | return status; | ||
254 | } | ||
255 | |||
256 | |||
257 | /* | ||
258 | * Write to the ATH6KL through its diagnostic window. No cooperation from | ||
259 | * the Target is required for this. | ||
260 | */ | ||
261 | static int ath6kl_write_reg_diag(struct ath6kl *ar, u32 *address, u32 *data) | ||
262 | { | ||
263 | int status; | ||
264 | |||
265 | /* set write data */ | ||
266 | status = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *)data, | ||
267 | sizeof(u32), HIF_WR_SYNC_BYTE_INC); | ||
268 | if (status) { | ||
269 | ath6kl_err("failed to write 0x%x to window data addr\n", *data); | ||
270 | return status; | ||
271 | } | ||
272 | |||
273 | /* set window register, which starts the write cycle */ | ||
274 | return ath6kl_set_addrwin_reg(ar, WINDOW_WRITE_ADDR_ADDRESS, | ||
275 | *address); | ||
276 | } | ||
277 | |||
278 | int ath6kl_access_datadiag(struct ath6kl *ar, u32 address, | ||
279 | u8 *data, u32 length, bool read) | ||
280 | { | ||
281 | u32 count; | ||
282 | int status = 0; | ||
283 | |||
284 | for (count = 0; count < length; count += 4, address += 4) { | ||
285 | if (read) { | ||
286 | status = ath6kl_read_reg_diag(ar, &address, | ||
287 | (u32 *) &data[count]); | ||
288 | if (status) | ||
289 | break; | ||
290 | } else { | ||
291 | status = ath6kl_write_reg_diag(ar, &address, | ||
292 | (u32 *) &data[count]); | ||
293 | if (status) | ||
294 | break; | ||
295 | } | ||
296 | } | ||
297 | |||
298 | return status; | ||
299 | } | ||
300 | |||
301 | static void ath6kl_reset_device(struct ath6kl *ar, u32 target_type, | ||
302 | bool wait_fot_compltn, bool cold_reset) | ||
303 | { | ||
304 | int status = 0; | ||
305 | u32 address; | ||
306 | u32 data; | ||
307 | |||
308 | if (target_type != TARGET_TYPE_AR6003) | ||
309 | return; | ||
310 | |||
311 | data = cold_reset ? RESET_CONTROL_COLD_RST : RESET_CONTROL_MBOX_RST; | ||
312 | |||
313 | address = RTC_BASE_ADDRESS; | ||
314 | status = ath6kl_write_reg_diag(ar, &address, &data); | ||
315 | |||
316 | if (status) | ||
317 | ath6kl_err("failed to reset target\n"); | ||
318 | } | ||
319 | |||
320 | void ath6kl_stop_endpoint(struct net_device *dev, bool keep_profile, | ||
321 | bool get_dbglogs) | ||
322 | { | ||
323 | struct ath6kl *ar = ath6kl_priv(dev); | ||
324 | static u8 bcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | ||
325 | bool discon_issued; | ||
326 | |||
327 | netif_stop_queue(dev); | ||
328 | |||
329 | /* disable the target and the interrupts associated with it */ | ||
330 | if (test_bit(WMI_READY, &ar->flag)) { | ||
331 | discon_issued = (test_bit(CONNECTED, &ar->flag) || | ||
332 | test_bit(CONNECT_PEND, &ar->flag)); | ||
333 | ath6kl_disconnect(ar); | ||
334 | if (!keep_profile) | ||
335 | ath6kl_init_profile_info(ar); | ||
336 | |||
337 | del_timer(&ar->disconnect_timer); | ||
338 | |||
339 | clear_bit(WMI_READY, &ar->flag); | ||
340 | ath6kl_wmi_shutdown(ar->wmi); | ||
341 | clear_bit(WMI_ENABLED, &ar->flag); | ||
342 | ar->wmi = NULL; | ||
343 | |||
344 | /* | ||
345 | * After wmi_shudown all WMI events will be dropped. We | ||
346 | * need to cleanup the buffers allocated in AP mode and | ||
347 | * give disconnect notification to stack, which usually | ||
348 | * happens in the disconnect_event. Simulate the disconnect | ||
349 | * event by calling the function directly. Sometimes | ||
350 | * disconnect_event will be received when the debug logs | ||
351 | * are collected. | ||
352 | */ | ||
353 | if (discon_issued) | ||
354 | ath6kl_disconnect_event(ar, DISCONNECT_CMD, | ||
355 | (ar->nw_type & AP_NETWORK) ? | ||
356 | bcast_mac : ar->bssid, | ||
357 | 0, NULL, 0); | ||
358 | |||
359 | ar->user_key_ctrl = 0; | ||
360 | |||
361 | } else { | ||
362 | ath6kl_dbg(ATH6KL_DBG_TRC, | ||
363 | "%s: wmi is not ready 0x%p 0x%p\n", | ||
364 | __func__, ar, ar->wmi); | ||
365 | |||
366 | /* Shut down WMI if we have started it */ | ||
367 | if (test_bit(WMI_ENABLED, &ar->flag)) { | ||
368 | ath6kl_dbg(ATH6KL_DBG_TRC, | ||
369 | "%s: shut down wmi\n", __func__); | ||
370 | ath6kl_wmi_shutdown(ar->wmi); | ||
371 | clear_bit(WMI_ENABLED, &ar->flag); | ||
372 | ar->wmi = NULL; | ||
373 | } | ||
374 | } | ||
375 | |||
376 | if (ar->htc_target) { | ||
377 | ath6kl_dbg(ATH6KL_DBG_TRC, "%s: shut down htc\n", __func__); | ||
378 | ath6kl_htc_stop(ar->htc_target); | ||
379 | } | ||
380 | |||
381 | /* | ||
382 | * Try to reset the device if we can. The driver may have been | ||
383 | * configure NOT to reset the target during a debug session. | ||
384 | */ | ||
385 | ath6kl_dbg(ATH6KL_DBG_TRC, | ||
386 | "attempting to reset target on instance destroy\n"); | ||
387 | ath6kl_reset_device(ar, ar->target_type, true, true); | ||
388 | } | ||
389 | |||
390 | static void ath6kl_install_static_wep_keys(struct ath6kl *ar) | ||
391 | { | ||
392 | u8 index; | ||
393 | u8 keyusage; | ||
394 | |||
395 | for (index = WMI_MIN_KEY_INDEX; index <= WMI_MAX_KEY_INDEX; index++) { | ||
396 | if (ar->wep_key_list[index].key_len) { | ||
397 | keyusage = GROUP_USAGE; | ||
398 | if (index == ar->def_txkey_index) | ||
399 | keyusage |= TX_USAGE; | ||
400 | |||
401 | ath6kl_wmi_addkey_cmd(ar->wmi, | ||
402 | index, | ||
403 | WEP_CRYPT, | ||
404 | keyusage, | ||
405 | ar->wep_key_list[index].key_len, | ||
406 | NULL, | ||
407 | ar->wep_key_list[index].key, | ||
408 | KEY_OP_INIT_VAL, NULL, | ||
409 | NO_SYNC_WMIFLAG); | ||
410 | } | ||
411 | } | ||
412 | } | ||
413 | |||
414 | static void ath6kl_connect_ap_mode(struct ath6kl *ar, u16 channel, u8 *bssid, | ||
415 | u16 listen_int, u16 beacon_int, | ||
416 | u8 assoc_resp_len, u8 *assoc_info) | ||
417 | { | ||
418 | struct net_device *dev = ar->net_dev; | ||
419 | struct station_info sinfo; | ||
420 | struct ath6kl_req_key *ik; | ||
421 | enum crypto_type keyType = NONE_CRYPT; | ||
422 | |||
423 | if (memcmp(dev->dev_addr, bssid, ETH_ALEN) == 0) { | ||
424 | ik = &ar->ap_mode_bkey; | ||
425 | |||
426 | switch (ar->auth_mode) { | ||
427 | case NONE_AUTH: | ||
428 | if (ar->prwise_crypto == WEP_CRYPT) | ||
429 | ath6kl_install_static_wep_keys(ar); | ||
430 | break; | ||
431 | case WPA_PSK_AUTH: | ||
432 | case WPA2_PSK_AUTH: | ||
433 | case (WPA_PSK_AUTH|WPA2_PSK_AUTH): | ||
434 | switch (ik->ik_type) { | ||
435 | case ATH6KL_CIPHER_TKIP: | ||
436 | keyType = TKIP_CRYPT; | ||
437 | break; | ||
438 | case ATH6KL_CIPHER_AES_CCM: | ||
439 | keyType = AES_CRYPT; | ||
440 | break; | ||
441 | default: | ||
442 | goto skip_key; | ||
443 | } | ||
444 | ath6kl_wmi_addkey_cmd(ar->wmi, ik->ik_keyix, keyType, | ||
445 | GROUP_USAGE, ik->ik_keylen, | ||
446 | (u8 *)&ik->ik_keyrsc, | ||
447 | ik->ik_keydata, | ||
448 | KEY_OP_INIT_VAL, ik->ik_macaddr, | ||
449 | SYNC_BOTH_WMIFLAG); | ||
450 | break; | ||
451 | } | ||
452 | skip_key: | ||
453 | set_bit(CONNECTED, &ar->flag); | ||
454 | return; | ||
455 | } | ||
456 | |||
457 | ath6kl_dbg(ATH6KL_DBG_TRC, "new station %pM aid=%d\n", | ||
458 | bssid, channel); | ||
459 | |||
460 | ath6kl_add_new_sta(ar, bssid, channel, assoc_info, assoc_resp_len, | ||
461 | listen_int & 0xFF, beacon_int, | ||
462 | (listen_int >> 8) & 0xFF); | ||
463 | |||
464 | /* send event to application */ | ||
465 | memset(&sinfo, 0, sizeof(sinfo)); | ||
466 | |||
467 | /* TODO: sinfo.generation */ | ||
468 | /* TODO: need to deliver (Re)AssocReq IEs somehow.. change in | ||
469 | * cfg80211 needed, e.g., by adding those into sinfo | ||
470 | */ | ||
471 | cfg80211_new_sta(ar->net_dev, bssid, &sinfo, GFP_KERNEL); | ||
472 | |||
473 | netif_wake_queue(ar->net_dev); | ||
474 | |||
475 | return; | ||
476 | } | ||
477 | |||
478 | /* Functions for Tx credit handling */ | ||
479 | void ath6k_credit_init(struct htc_credit_state_info *cred_info, | ||
480 | struct list_head *ep_list, | ||
481 | int tot_credits) | ||
482 | { | ||
483 | struct htc_endpoint_credit_dist *cur_ep_dist; | ||
484 | int count; | ||
485 | |||
486 | cred_info->cur_free_credits = tot_credits; | ||
487 | cred_info->total_avail_credits = tot_credits; | ||
488 | |||
489 | list_for_each_entry(cur_ep_dist, ep_list, list) { | ||
490 | if (cur_ep_dist->endpoint == ENDPOINT_0) | ||
491 | continue; | ||
492 | |||
493 | cur_ep_dist->cred_min = cur_ep_dist->cred_per_msg; | ||
494 | |||
495 | if (tot_credits > 4) | ||
496 | if ((cur_ep_dist->svc_id == WMI_DATA_BK_SVC) || | ||
497 | (cur_ep_dist->svc_id == WMI_DATA_BE_SVC)) { | ||
498 | ath6kl_deposit_credit_to_ep(cred_info, | ||
499 | cur_ep_dist, | ||
500 | cur_ep_dist->cred_min); | ||
501 | cur_ep_dist->dist_flags |= HTC_EP_ACTIVE; | ||
502 | } | ||
503 | |||
504 | if (cur_ep_dist->svc_id == WMI_CONTROL_SVC) { | ||
505 | ath6kl_deposit_credit_to_ep(cred_info, cur_ep_dist, | ||
506 | cur_ep_dist->cred_min); | ||
507 | /* | ||
508 | * Control service is always marked active, it | ||
509 | * never goes inactive EVER. | ||
510 | */ | ||
511 | cur_ep_dist->dist_flags |= HTC_EP_ACTIVE; | ||
512 | } else if (cur_ep_dist->svc_id == WMI_DATA_BK_SVC) | ||
513 | /* this is the lowest priority data endpoint */ | ||
514 | cred_info->lowestpri_ep_dist = cur_ep_dist->list; | ||
515 | |||
516 | /* | ||
517 | * Streams have to be created (explicit | implicit) for all | ||
518 | * kinds of traffic. BE endpoints are also inactive in the | ||
519 | * beginning. When BE traffic starts it creates implicit | ||
520 | * streams that redistributes credits. | ||
521 | * | ||
522 | * Note: all other endpoints have minimums set but are | ||
523 | * initially given NO credits. credits will be distributed | ||
524 | * as traffic activity demands | ||
525 | */ | ||
526 | } | ||
527 | |||
528 | WARN_ON(cred_info->cur_free_credits <= 0); | ||
529 | |||
530 | list_for_each_entry(cur_ep_dist, ep_list, list) { | ||
531 | if (cur_ep_dist->endpoint == ENDPOINT_0) | ||
532 | continue; | ||
533 | |||
534 | if (cur_ep_dist->svc_id == WMI_CONTROL_SVC) | ||
535 | cur_ep_dist->cred_norm = cur_ep_dist->cred_per_msg; | ||
536 | else { | ||
537 | /* | ||
538 | * For the remaining data endpoints, we assume that | ||
539 | * each cred_per_msg are the same. We use a simple | ||
540 | * calculation here, we take the remaining credits | ||
541 | * and determine how many max messages this can | ||
542 | * cover and then set each endpoint's normal value | ||
543 | * equal to 3/4 this amount. | ||
544 | */ | ||
545 | count = (cred_info->cur_free_credits / | ||
546 | cur_ep_dist->cred_per_msg) | ||
547 | * cur_ep_dist->cred_per_msg; | ||
548 | count = (count * 3) >> 2; | ||
549 | count = max(count, cur_ep_dist->cred_per_msg); | ||
550 | cur_ep_dist->cred_norm = count; | ||
551 | |||
552 | } | ||
553 | } | ||
554 | } | ||
555 | |||
556 | /* initialize and setup credit distribution */ | ||
557 | int ath6k_setup_credit_dist(void *htc_handle, | ||
558 | struct htc_credit_state_info *cred_info) | ||
559 | { | ||
560 | u16 servicepriority[5]; | ||
561 | |||
562 | memset(cred_info, 0, sizeof(struct htc_credit_state_info)); | ||
563 | |||
564 | servicepriority[0] = WMI_CONTROL_SVC; /* highest */ | ||
565 | servicepriority[1] = WMI_DATA_VO_SVC; | ||
566 | servicepriority[2] = WMI_DATA_VI_SVC; | ||
567 | servicepriority[3] = WMI_DATA_BE_SVC; | ||
568 | servicepriority[4] = WMI_DATA_BK_SVC; /* lowest */ | ||
569 | |||
570 | /* set priority list */ | ||
571 | ath6kl_htc_set_credit_dist(htc_handle, cred_info, servicepriority, 5); | ||
572 | |||
573 | return 0; | ||
574 | } | ||
575 | |||
576 | /* reduce an ep's credits back to a set limit */ | ||
577 | static void ath6k_reduce_credits(struct htc_credit_state_info *cred_info, | ||
578 | struct htc_endpoint_credit_dist *ep_dist, | ||
579 | int limit) | ||
580 | { | ||
581 | int credits; | ||
582 | |||
583 | ep_dist->cred_assngd = limit; | ||
584 | |||
585 | if (ep_dist->credits <= limit) | ||
586 | return; | ||
587 | |||
588 | credits = ep_dist->credits - limit; | ||
589 | ep_dist->credits -= credits; | ||
590 | cred_info->cur_free_credits += credits; | ||
591 | } | ||
592 | |||
593 | static void ath6k_credit_update(struct htc_credit_state_info *cred_info, | ||
594 | struct list_head *epdist_list) | ||
595 | { | ||
596 | struct htc_endpoint_credit_dist *cur_dist_list; | ||
597 | |||
598 | list_for_each_entry(cur_dist_list, epdist_list, list) { | ||
599 | if (cur_dist_list->endpoint == ENDPOINT_0) | ||
600 | continue; | ||
601 | |||
602 | if (cur_dist_list->cred_to_dist > 0) { | ||
603 | cur_dist_list->credits += | ||
604 | cur_dist_list->cred_to_dist; | ||
605 | cur_dist_list->cred_to_dist = 0; | ||
606 | if (cur_dist_list->credits > | ||
607 | cur_dist_list->cred_assngd) | ||
608 | ath6k_reduce_credits(cred_info, | ||
609 | cur_dist_list, | ||
610 | cur_dist_list->cred_assngd); | ||
611 | |||
612 | if (cur_dist_list->credits > | ||
613 | cur_dist_list->cred_norm) | ||
614 | ath6k_reduce_credits(cred_info, cur_dist_list, | ||
615 | cur_dist_list->cred_norm); | ||
616 | |||
617 | if (!(cur_dist_list->dist_flags & HTC_EP_ACTIVE)) { | ||
618 | if (cur_dist_list->txq_depth == 0) | ||
619 | ath6k_reduce_credits(cred_info, | ||
620 | cur_dist_list, 0); | ||
621 | } | ||
622 | } | ||
623 | } | ||
624 | } | ||
625 | |||
626 | /* | ||
627 | * HTC has an endpoint that needs credits, ep_dist is the endpoint in | ||
628 | * question. | ||
629 | */ | ||
630 | void ath6k_seek_credits(struct htc_credit_state_info *cred_info, | ||
631 | struct htc_endpoint_credit_dist *ep_dist) | ||
632 | { | ||
633 | struct htc_endpoint_credit_dist *curdist_list; | ||
634 | int credits = 0; | ||
635 | int need; | ||
636 | |||
637 | if (ep_dist->svc_id == WMI_CONTROL_SVC) | ||
638 | goto out; | ||
639 | |||
640 | if ((ep_dist->svc_id == WMI_DATA_VI_SVC) || | ||
641 | (ep_dist->svc_id == WMI_DATA_VO_SVC)) | ||
642 | if ((ep_dist->cred_assngd >= ep_dist->cred_norm)) | ||
643 | goto out; | ||
644 | |||
645 | /* | ||
646 | * For all other services, we follow a simple algorithm of: | ||
647 | * | ||
648 | * 1. checking the free pool for credits | ||
649 | * 2. checking lower priority endpoints for credits to take | ||
650 | */ | ||
651 | |||
652 | credits = min(cred_info->cur_free_credits, ep_dist->seek_cred); | ||
653 | |||
654 | if (credits >= ep_dist->seek_cred) | ||
655 | goto out; | ||
656 | |||
657 | /* | ||
658 | * We don't have enough in the free pool, try taking away from | ||
659 | * lower priority services The rule for taking away credits: | ||
660 | * | ||
661 | * 1. Only take from lower priority endpoints | ||
662 | * 2. Only take what is allocated above the minimum (never | ||
663 | * starve an endpoint completely) | ||
664 | * 3. Only take what you need. | ||
665 | */ | ||
666 | |||
667 | list_for_each_entry_reverse(curdist_list, | ||
668 | &cred_info->lowestpri_ep_dist, | ||
669 | list) { | ||
670 | if (curdist_list == ep_dist) | ||
671 | break; | ||
672 | |||
673 | need = ep_dist->seek_cred - cred_info->cur_free_credits; | ||
674 | |||
675 | if ((curdist_list->cred_assngd - need) >= | ||
676 | curdist_list->cred_min) { | ||
677 | /* | ||
678 | * The current one has been allocated more than | ||
679 | * it's minimum and it has enough credits assigned | ||
680 | * above it's minimum to fulfill our need try to | ||
681 | * take away just enough to fulfill our need. | ||
682 | */ | ||
683 | ath6k_reduce_credits(cred_info, curdist_list, | ||
684 | curdist_list->cred_assngd - need); | ||
685 | |||
686 | if (cred_info->cur_free_credits >= | ||
687 | ep_dist->seek_cred) | ||
688 | break; | ||
689 | } | ||
690 | |||
691 | if (curdist_list->endpoint == ENDPOINT_0) | ||
692 | break; | ||
693 | } | ||
694 | |||
695 | credits = min(cred_info->cur_free_credits, ep_dist->seek_cred); | ||
696 | |||
697 | out: | ||
698 | /* did we find some credits? */ | ||
699 | if (credits) | ||
700 | ath6kl_deposit_credit_to_ep(cred_info, ep_dist, credits); | ||
701 | |||
702 | ep_dist->seek_cred = 0; | ||
703 | } | ||
704 | |||
705 | /* redistribute credits based on activity change */ | ||
706 | static void ath6k_redistribute_credits(struct htc_credit_state_info *info, | ||
707 | struct list_head *ep_dist_list) | ||
708 | { | ||
709 | struct htc_endpoint_credit_dist *curdist_list; | ||
710 | |||
711 | list_for_each_entry(curdist_list, ep_dist_list, list) { | ||
712 | if (curdist_list->endpoint == ENDPOINT_0) | ||
713 | continue; | ||
714 | |||
715 | if ((curdist_list->svc_id == WMI_DATA_BK_SVC) || | ||
716 | (curdist_list->svc_id == WMI_DATA_BE_SVC)) | ||
717 | curdist_list->dist_flags |= HTC_EP_ACTIVE; | ||
718 | |||
719 | if ((curdist_list->svc_id != WMI_CONTROL_SVC) && | ||
720 | !(curdist_list->dist_flags & HTC_EP_ACTIVE)) { | ||
721 | if (curdist_list->txq_depth == 0) | ||
722 | ath6k_reduce_credits(info, | ||
723 | curdist_list, 0); | ||
724 | else | ||
725 | ath6k_reduce_credits(info, | ||
726 | curdist_list, | ||
727 | curdist_list->cred_min); | ||
728 | } | ||
729 | } | ||
730 | } | ||
731 | |||
732 | /* | ||
733 | * | ||
734 | * This function is invoked whenever endpoints require credit | ||
735 | * distributions. A lock is held while this function is invoked, this | ||
736 | * function shall NOT block. The ep_dist_list is a list of distribution | ||
737 | * structures in prioritized order as defined by the call to the | ||
738 | * htc_set_credit_dist() api. | ||
739 | */ | ||
740 | void ath6k_credit_distribute(struct htc_credit_state_info *cred_info, | ||
741 | struct list_head *ep_dist_list, | ||
742 | enum htc_credit_dist_reason reason) | ||
743 | { | ||
744 | switch (reason) { | ||
745 | case HTC_CREDIT_DIST_SEND_COMPLETE: | ||
746 | ath6k_credit_update(cred_info, ep_dist_list); | ||
747 | break; | ||
748 | case HTC_CREDIT_DIST_ACTIVITY_CHANGE: | ||
749 | ath6k_redistribute_credits(cred_info, ep_dist_list); | ||
750 | break; | ||
751 | default: | ||
752 | break; | ||
753 | } | ||
754 | |||
755 | WARN_ON(cred_info->cur_free_credits > cred_info->total_avail_credits); | ||
756 | WARN_ON(cred_info->cur_free_credits < 0); | ||
757 | } | ||
758 | |||
759 | void disconnect_timer_handler(unsigned long ptr) | ||
760 | { | ||
761 | struct net_device *dev = (struct net_device *)ptr; | ||
762 | struct ath6kl *ar = ath6kl_priv(dev); | ||
763 | |||
764 | ath6kl_init_profile_info(ar); | ||
765 | ath6kl_disconnect(ar); | ||
766 | } | ||
767 | |||
768 | void ath6kl_disconnect(struct ath6kl *ar) | ||
769 | { | ||
770 | if (test_bit(CONNECTED, &ar->flag) || | ||
771 | test_bit(CONNECT_PEND, &ar->flag)) { | ||
772 | ath6kl_wmi_disconnect_cmd(ar->wmi); | ||
773 | /* | ||
774 | * Disconnect command is issued, clear the connect pending | ||
775 | * flag. The connected flag will be cleared in | ||
776 | * disconnect event notification. | ||
777 | */ | ||
778 | clear_bit(CONNECT_PEND, &ar->flag); | ||
779 | } | ||
780 | } | ||
781 | |||
782 | /* WMI Event handlers */ | ||
783 | |||
784 | static const char *get_hw_id_string(u32 id) | ||
785 | { | ||
786 | switch (id) { | ||
787 | case AR6003_REV1_VERSION: | ||
788 | return "1.0"; | ||
789 | case AR6003_REV2_VERSION: | ||
790 | return "2.0"; | ||
791 | case AR6003_REV3_VERSION: | ||
792 | return "2.1.1"; | ||
793 | default: | ||
794 | return "unknown"; | ||
795 | } | ||
796 | } | ||
797 | |||
798 | void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver) | ||
799 | { | ||
800 | struct ath6kl *ar = devt; | ||
801 | struct net_device *dev = ar->net_dev; | ||
802 | |||
803 | memcpy(dev->dev_addr, datap, ETH_ALEN); | ||
804 | ath6kl_dbg(ATH6KL_DBG_TRC, "%s: mac addr = %pM\n", | ||
805 | __func__, dev->dev_addr); | ||
806 | |||
807 | ar->version.wlan_ver = sw_ver; | ||
808 | ar->version.abi_ver = abi_ver; | ||
809 | |||
810 | snprintf(ar->wdev->wiphy->fw_version, | ||
811 | sizeof(ar->wdev->wiphy->fw_version), | ||
812 | "%u.%u.%u.%u", | ||
813 | (ar->version.wlan_ver & 0xf0000000) >> 28, | ||
814 | (ar->version.wlan_ver & 0x0f000000) >> 24, | ||
815 | (ar->version.wlan_ver & 0x00ff0000) >> 16, | ||
816 | (ar->version.wlan_ver & 0x0000ffff)); | ||
817 | |||
818 | /* indicate to the waiting thread that the ready event was received */ | ||
819 | set_bit(WMI_READY, &ar->flag); | ||
820 | wake_up(&ar->event_wq); | ||
821 | |||
822 | ath6kl_info("hw %s fw %s\n", | ||
823 | get_hw_id_string(ar->wdev->wiphy->hw_version), | ||
824 | ar->wdev->wiphy->fw_version); | ||
825 | } | ||
826 | |||
827 | void ath6kl_scan_complete_evt(struct ath6kl *ar, int status) | ||
828 | { | ||
829 | ath6kl_cfg80211_scan_complete_event(ar, status); | ||
830 | |||
831 | if (!ar->usr_bss_filter) | ||
832 | ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0); | ||
833 | |||
834 | ath6kl_dbg(ATH6KL_DBG_WLAN_SCAN, "scan complete: %d\n", status); | ||
835 | } | ||
836 | |||
837 | void ath6kl_connect_event(struct ath6kl *ar, u16 channel, u8 *bssid, | ||
838 | u16 listen_int, u16 beacon_int, | ||
839 | enum network_type net_type, u8 beacon_ie_len, | ||
840 | u8 assoc_req_len, u8 assoc_resp_len, | ||
841 | u8 *assoc_info) | ||
842 | { | ||
843 | unsigned long flags; | ||
844 | |||
845 | if (ar->nw_type == AP_NETWORK) { | ||
846 | ath6kl_connect_ap_mode(ar, channel, bssid, listen_int, | ||
847 | beacon_int, assoc_resp_len, | ||
848 | assoc_info); | ||
849 | return; | ||
850 | } | ||
851 | |||
852 | ath6kl_cfg80211_connect_event(ar, channel, bssid, | ||
853 | listen_int, beacon_int, | ||
854 | net_type, beacon_ie_len, | ||
855 | assoc_req_len, assoc_resp_len, | ||
856 | assoc_info); | ||
857 | |||
858 | memcpy(ar->bssid, bssid, sizeof(ar->bssid)); | ||
859 | ar->bss_ch = channel; | ||
860 | |||
861 | if ((ar->nw_type == INFRA_NETWORK)) | ||
862 | ath6kl_wmi_listeninterval_cmd(ar->wmi, ar->listen_intvl_t, | ||
863 | ar->listen_intvl_b); | ||
864 | |||
865 | netif_wake_queue(ar->net_dev); | ||
866 | |||
867 | /* Update connect & link status atomically */ | ||
868 | spin_lock_irqsave(&ar->lock, flags); | ||
869 | set_bit(CONNECTED, &ar->flag); | ||
870 | clear_bit(CONNECT_PEND, &ar->flag); | ||
871 | netif_carrier_on(ar->net_dev); | ||
872 | spin_unlock_irqrestore(&ar->lock, flags); | ||
873 | |||
874 | aggr_reset_state(ar->aggr_cntxt); | ||
875 | ar->reconnect_flag = 0; | ||
876 | |||
877 | if ((ar->nw_type == ADHOC_NETWORK) && ar->ibss_ps_enable) { | ||
878 | memset(ar->node_map, 0, sizeof(ar->node_map)); | ||
879 | ar->node_num = 0; | ||
880 | ar->next_ep_id = ENDPOINT_2; | ||
881 | } | ||
882 | |||
883 | if (!ar->usr_bss_filter) | ||
884 | ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0); | ||
885 | } | ||
886 | |||
887 | void ath6kl_tkip_micerr_event(struct ath6kl *ar, u8 keyid, bool ismcast) | ||
888 | { | ||
889 | struct ath6kl_sta *sta; | ||
890 | u8 tsc[6]; | ||
891 | /* | ||
892 | * For AP case, keyid will have aid of STA which sent pkt with | ||
893 | * MIC error. Use this aid to get MAC & send it to hostapd. | ||
894 | */ | ||
895 | if (ar->nw_type == AP_NETWORK) { | ||
896 | sta = ath6kl_find_sta_by_aid(ar, (keyid >> 2)); | ||
897 | if (!sta) | ||
898 | return; | ||
899 | |||
900 | ath6kl_dbg(ATH6KL_DBG_TRC, | ||
901 | "ap tkip mic error received from aid=%d\n", keyid); | ||
902 | |||
903 | memset(tsc, 0, sizeof(tsc)); /* FIX: get correct TSC */ | ||
904 | cfg80211_michael_mic_failure(ar->net_dev, sta->mac, | ||
905 | NL80211_KEYTYPE_PAIRWISE, keyid, | ||
906 | tsc, GFP_KERNEL); | ||
907 | } else | ||
908 | ath6kl_cfg80211_tkip_micerr_event(ar, keyid, ismcast); | ||
909 | |||
910 | } | ||
911 | |||
912 | static void ath6kl_update_target_stats(struct ath6kl *ar, u8 *ptr, u32 len) | ||
913 | { | ||
914 | struct wmi_target_stats *tgt_stats = | ||
915 | (struct wmi_target_stats *) ptr; | ||
916 | struct target_stats *stats = &ar->target_stats; | ||
917 | struct tkip_ccmp_stats *ccmp_stats; | ||
918 | struct bss *conn_bss = NULL; | ||
919 | struct cserv_stats *c_stats; | ||
920 | u8 ac; | ||
921 | |||
922 | if (len < sizeof(*tgt_stats)) | ||
923 | return; | ||
924 | |||
925 | /* update the RSSI of the connected bss */ | ||
926 | if (test_bit(CONNECTED, &ar->flag)) { | ||
927 | conn_bss = ath6kl_wmi_find_node(ar->wmi, ar->bssid); | ||
928 | if (conn_bss) { | ||
929 | c_stats = &tgt_stats->cserv_stats; | ||
930 | conn_bss->ni_rssi = | ||
931 | a_sle16_to_cpu(c_stats->cs_ave_beacon_rssi); | ||
932 | conn_bss->ni_snr = | ||
933 | tgt_stats->cserv_stats.cs_ave_beacon_snr; | ||
934 | ath6kl_wmi_node_return(ar->wmi, conn_bss); | ||
935 | } | ||
936 | } | ||
937 | |||
938 | ath6kl_dbg(ATH6KL_DBG_TRC, "updating target stats\n"); | ||
939 | |||
940 | stats->tx_pkt += le32_to_cpu(tgt_stats->stats.tx.pkt); | ||
941 | stats->tx_byte += le32_to_cpu(tgt_stats->stats.tx.byte); | ||
942 | stats->tx_ucast_pkt += le32_to_cpu(tgt_stats->stats.tx.ucast_pkt); | ||
943 | stats->tx_ucast_byte += le32_to_cpu(tgt_stats->stats.tx.ucast_byte); | ||
944 | stats->tx_mcast_pkt += le32_to_cpu(tgt_stats->stats.tx.mcast_pkt); | ||
945 | stats->tx_mcast_byte += le32_to_cpu(tgt_stats->stats.tx.mcast_byte); | ||
946 | stats->tx_bcast_pkt += le32_to_cpu(tgt_stats->stats.tx.bcast_pkt); | ||
947 | stats->tx_bcast_byte += le32_to_cpu(tgt_stats->stats.tx.bcast_byte); | ||
948 | stats->tx_rts_success_cnt += | ||
949 | le32_to_cpu(tgt_stats->stats.tx.rts_success_cnt); | ||
950 | |||
951 | for (ac = 0; ac < WMM_NUM_AC; ac++) | ||
952 | stats->tx_pkt_per_ac[ac] += | ||
953 | le32_to_cpu(tgt_stats->stats.tx.pkt_per_ac[ac]); | ||
954 | |||
955 | stats->tx_err += le32_to_cpu(tgt_stats->stats.tx.err); | ||
956 | stats->tx_fail_cnt += le32_to_cpu(tgt_stats->stats.tx.fail_cnt); | ||
957 | stats->tx_retry_cnt += le32_to_cpu(tgt_stats->stats.tx.retry_cnt); | ||
958 | stats->tx_mult_retry_cnt += | ||
959 | le32_to_cpu(tgt_stats->stats.tx.mult_retry_cnt); | ||
960 | stats->tx_rts_fail_cnt += | ||
961 | le32_to_cpu(tgt_stats->stats.tx.rts_fail_cnt); | ||
962 | stats->tx_ucast_rate = | ||
963 | ath6kl_wmi_get_rate(a_sle32_to_cpu(tgt_stats->stats.tx.ucast_rate)); | ||
964 | |||
965 | stats->rx_pkt += le32_to_cpu(tgt_stats->stats.rx.pkt); | ||
966 | stats->rx_byte += le32_to_cpu(tgt_stats->stats.rx.byte); | ||
967 | stats->rx_ucast_pkt += le32_to_cpu(tgt_stats->stats.rx.ucast_pkt); | ||
968 | stats->rx_ucast_byte += le32_to_cpu(tgt_stats->stats.rx.ucast_byte); | ||
969 | stats->rx_mcast_pkt += le32_to_cpu(tgt_stats->stats.rx.mcast_pkt); | ||
970 | stats->rx_mcast_byte += le32_to_cpu(tgt_stats->stats.rx.mcast_byte); | ||
971 | stats->rx_bcast_pkt += le32_to_cpu(tgt_stats->stats.rx.bcast_pkt); | ||
972 | stats->rx_bcast_byte += le32_to_cpu(tgt_stats->stats.rx.bcast_byte); | ||
973 | stats->rx_frgment_pkt += le32_to_cpu(tgt_stats->stats.rx.frgment_pkt); | ||
974 | stats->rx_err += le32_to_cpu(tgt_stats->stats.rx.err); | ||
975 | stats->rx_crc_err += le32_to_cpu(tgt_stats->stats.rx.crc_err); | ||
976 | stats->rx_key_cache_miss += | ||
977 | le32_to_cpu(tgt_stats->stats.rx.key_cache_miss); | ||
978 | stats->rx_decrypt_err += le32_to_cpu(tgt_stats->stats.rx.decrypt_err); | ||
979 | stats->rx_dupl_frame += le32_to_cpu(tgt_stats->stats.rx.dupl_frame); | ||
980 | stats->rx_ucast_rate = | ||
981 | ath6kl_wmi_get_rate(a_sle32_to_cpu(tgt_stats->stats.rx.ucast_rate)); | ||
982 | |||
983 | ccmp_stats = &tgt_stats->stats.tkip_ccmp_stats; | ||
984 | |||
985 | stats->tkip_local_mic_fail += | ||
986 | le32_to_cpu(ccmp_stats->tkip_local_mic_fail); | ||
987 | stats->tkip_cnter_measures_invoked += | ||
988 | le32_to_cpu(ccmp_stats->tkip_cnter_measures_invoked); | ||
989 | stats->tkip_fmt_err += le32_to_cpu(ccmp_stats->tkip_fmt_err); | ||
990 | |||
991 | stats->ccmp_fmt_err += le32_to_cpu(ccmp_stats->ccmp_fmt_err); | ||
992 | stats->ccmp_replays += le32_to_cpu(ccmp_stats->ccmp_replays); | ||
993 | |||
994 | stats->pwr_save_fail_cnt += | ||
995 | le32_to_cpu(tgt_stats->pm_stats.pwr_save_failure_cnt); | ||
996 | stats->noise_floor_calib = | ||
997 | a_sle32_to_cpu(tgt_stats->noise_floor_calib); | ||
998 | |||
999 | stats->cs_bmiss_cnt += | ||
1000 | le32_to_cpu(tgt_stats->cserv_stats.cs_bmiss_cnt); | ||
1001 | stats->cs_low_rssi_cnt += | ||
1002 | le32_to_cpu(tgt_stats->cserv_stats.cs_low_rssi_cnt); | ||
1003 | stats->cs_connect_cnt += | ||
1004 | le16_to_cpu(tgt_stats->cserv_stats.cs_connect_cnt); | ||
1005 | stats->cs_discon_cnt += | ||
1006 | le16_to_cpu(tgt_stats->cserv_stats.cs_discon_cnt); | ||
1007 | |||
1008 | stats->cs_ave_beacon_rssi = | ||
1009 | a_sle16_to_cpu(tgt_stats->cserv_stats.cs_ave_beacon_rssi); | ||
1010 | |||
1011 | stats->cs_last_roam_msec = | ||
1012 | tgt_stats->cserv_stats.cs_last_roam_msec; | ||
1013 | stats->cs_snr = tgt_stats->cserv_stats.cs_snr; | ||
1014 | stats->cs_rssi = a_sle16_to_cpu(tgt_stats->cserv_stats.cs_rssi); | ||
1015 | |||
1016 | stats->lq_val = le32_to_cpu(tgt_stats->lq_val); | ||
1017 | |||
1018 | stats->wow_pkt_dropped += | ||
1019 | le32_to_cpu(tgt_stats->wow_stats.wow_pkt_dropped); | ||
1020 | stats->wow_host_pkt_wakeups += | ||
1021 | tgt_stats->wow_stats.wow_host_pkt_wakeups; | ||
1022 | stats->wow_host_evt_wakeups += | ||
1023 | tgt_stats->wow_stats.wow_host_evt_wakeups; | ||
1024 | stats->wow_evt_discarded += | ||
1025 | le16_to_cpu(tgt_stats->wow_stats.wow_evt_discarded); | ||
1026 | |||
1027 | if (test_bit(STATS_UPDATE_PEND, &ar->flag)) { | ||
1028 | clear_bit(STATS_UPDATE_PEND, &ar->flag); | ||
1029 | wake_up(&ar->event_wq); | ||
1030 | } | ||
1031 | } | ||
1032 | |||
1033 | static void ath6kl_add_le32(__le32 *var, __le32 val) | ||
1034 | { | ||
1035 | *var = cpu_to_le32(le32_to_cpu(*var) + le32_to_cpu(val)); | ||
1036 | } | ||
1037 | |||
1038 | void ath6kl_tgt_stats_event(struct ath6kl *ar, u8 *ptr, u32 len) | ||
1039 | { | ||
1040 | struct wmi_ap_mode_stat *p = (struct wmi_ap_mode_stat *) ptr; | ||
1041 | struct wmi_ap_mode_stat *ap = &ar->ap_stats; | ||
1042 | struct wmi_per_sta_stat *st_ap, *st_p; | ||
1043 | u8 ac; | ||
1044 | |||
1045 | if (ar->nw_type == AP_NETWORK) { | ||
1046 | if (len < sizeof(*p)) | ||
1047 | return; | ||
1048 | |||
1049 | for (ac = 0; ac < AP_MAX_NUM_STA; ac++) { | ||
1050 | st_ap = &ap->sta[ac]; | ||
1051 | st_p = &p->sta[ac]; | ||
1052 | |||
1053 | ath6kl_add_le32(&st_ap->tx_bytes, st_p->tx_bytes); | ||
1054 | ath6kl_add_le32(&st_ap->tx_pkts, st_p->tx_pkts); | ||
1055 | ath6kl_add_le32(&st_ap->tx_error, st_p->tx_error); | ||
1056 | ath6kl_add_le32(&st_ap->tx_discard, st_p->tx_discard); | ||
1057 | ath6kl_add_le32(&st_ap->rx_bytes, st_p->rx_bytes); | ||
1058 | ath6kl_add_le32(&st_ap->rx_pkts, st_p->rx_pkts); | ||
1059 | ath6kl_add_le32(&st_ap->rx_error, st_p->rx_error); | ||
1060 | ath6kl_add_le32(&st_ap->rx_discard, st_p->rx_discard); | ||
1061 | } | ||
1062 | |||
1063 | } else { | ||
1064 | ath6kl_update_target_stats(ar, ptr, len); | ||
1065 | } | ||
1066 | } | ||
1067 | |||
1068 | void ath6kl_wakeup_event(void *dev) | ||
1069 | { | ||
1070 | struct ath6kl *ar = (struct ath6kl *) dev; | ||
1071 | |||
1072 | wake_up(&ar->event_wq); | ||
1073 | } | ||
1074 | |||
1075 | void ath6kl_txpwr_rx_evt(void *devt, u8 tx_pwr) | ||
1076 | { | ||
1077 | struct ath6kl *ar = (struct ath6kl *) devt; | ||
1078 | |||
1079 | ar->tx_pwr = tx_pwr; | ||
1080 | wake_up(&ar->event_wq); | ||
1081 | } | ||
1082 | |||
1083 | void ath6kl_pspoll_event(struct ath6kl *ar, u8 aid) | ||
1084 | { | ||
1085 | struct ath6kl_sta *conn; | ||
1086 | struct sk_buff *skb; | ||
1087 | bool psq_empty = false; | ||
1088 | |||
1089 | conn = ath6kl_find_sta_by_aid(ar, aid); | ||
1090 | |||
1091 | if (!conn) | ||
1092 | return; | ||
1093 | /* | ||
1094 | * Send out a packet queued on ps queue. When the ps queue | ||
1095 | * becomes empty update the PVB for this station. | ||
1096 | */ | ||
1097 | spin_lock_bh(&conn->psq_lock); | ||
1098 | psq_empty = skb_queue_empty(&conn->psq); | ||
1099 | spin_unlock_bh(&conn->psq_lock); | ||
1100 | |||
1101 | if (psq_empty) | ||
1102 | /* TODO: Send out a NULL data frame */ | ||
1103 | return; | ||
1104 | |||
1105 | spin_lock_bh(&conn->psq_lock); | ||
1106 | skb = skb_dequeue(&conn->psq); | ||
1107 | spin_unlock_bh(&conn->psq_lock); | ||
1108 | |||
1109 | conn->sta_flags |= STA_PS_POLLED; | ||
1110 | ath6kl_data_tx(skb, ar->net_dev); | ||
1111 | conn->sta_flags &= ~STA_PS_POLLED; | ||
1112 | |||
1113 | spin_lock_bh(&conn->psq_lock); | ||
1114 | psq_empty = skb_queue_empty(&conn->psq); | ||
1115 | spin_unlock_bh(&conn->psq_lock); | ||
1116 | |||
1117 | if (psq_empty) | ||
1118 | ath6kl_wmi_set_pvb_cmd(ar->wmi, conn->aid, 0); | ||
1119 | } | ||
1120 | |||
1121 | void ath6kl_dtimexpiry_event(struct ath6kl *ar) | ||
1122 | { | ||
1123 | bool mcastq_empty = false; | ||
1124 | struct sk_buff *skb; | ||
1125 | |||
1126 | /* | ||
1127 | * If there are no associated STAs, ignore the DTIM expiry event. | ||
1128 | * There can be potential race conditions where the last associated | ||
1129 | * STA may disconnect & before the host could clear the 'Indicate | ||
1130 | * DTIM' request to the firmware, the firmware would have just | ||
1131 | * indicated a DTIM expiry event. The race is between 'clear DTIM | ||
1132 | * expiry cmd' going from the host to the firmware & the DTIM | ||
1133 | * expiry event happening from the firmware to the host. | ||
1134 | */ | ||
1135 | if (!ar->sta_list_index) | ||
1136 | return; | ||
1137 | |||
1138 | spin_lock_bh(&ar->mcastpsq_lock); | ||
1139 | mcastq_empty = skb_queue_empty(&ar->mcastpsq); | ||
1140 | spin_unlock_bh(&ar->mcastpsq_lock); | ||
1141 | |||
1142 | if (mcastq_empty) | ||
1143 | return; | ||
1144 | |||
1145 | /* set the STA flag to dtim_expired for the frame to go out */ | ||
1146 | set_bit(DTIM_EXPIRED, &ar->flag); | ||
1147 | |||
1148 | spin_lock_bh(&ar->mcastpsq_lock); | ||
1149 | while ((skb = skb_dequeue(&ar->mcastpsq)) != NULL) { | ||
1150 | spin_unlock_bh(&ar->mcastpsq_lock); | ||
1151 | |||
1152 | ath6kl_data_tx(skb, ar->net_dev); | ||
1153 | |||
1154 | spin_lock_bh(&ar->mcastpsq_lock); | ||
1155 | } | ||
1156 | spin_unlock_bh(&ar->mcastpsq_lock); | ||
1157 | |||
1158 | clear_bit(DTIM_EXPIRED, &ar->flag); | ||
1159 | |||
1160 | /* clear the LSB of the BitMapCtl field of the TIM IE */ | ||
1161 | ath6kl_wmi_set_pvb_cmd(ar->wmi, MCAST_AID, 0); | ||
1162 | } | ||
1163 | |||
1164 | void ath6kl_disconnect_event(struct ath6kl *ar, u8 reason, u8 *bssid, | ||
1165 | u8 assoc_resp_len, u8 *assoc_info, | ||
1166 | u16 prot_reason_status) | ||
1167 | { | ||
1168 | struct bss *wmi_ssid_node = NULL; | ||
1169 | unsigned long flags; | ||
1170 | |||
1171 | if (ar->nw_type == AP_NETWORK) { | ||
1172 | if (!ath6kl_remove_sta(ar, bssid, prot_reason_status)) | ||
1173 | return; | ||
1174 | |||
1175 | /* if no more associated STAs, empty the mcast PS q */ | ||
1176 | if (ar->sta_list_index == 0) { | ||
1177 | spin_lock_bh(&ar->mcastpsq_lock); | ||
1178 | skb_queue_purge(&ar->mcastpsq); | ||
1179 | spin_unlock_bh(&ar->mcastpsq_lock); | ||
1180 | |||
1181 | /* clear the LSB of the TIM IE's BitMapCtl field */ | ||
1182 | if (test_bit(WMI_READY, &ar->flag)) | ||
1183 | ath6kl_wmi_set_pvb_cmd(ar->wmi, MCAST_AID, 0); | ||
1184 | } | ||
1185 | |||
1186 | if (!is_broadcast_ether_addr(bssid)) { | ||
1187 | /* send event to application */ | ||
1188 | cfg80211_del_sta(ar->net_dev, bssid, GFP_KERNEL); | ||
1189 | } | ||
1190 | |||
1191 | clear_bit(CONNECTED, &ar->flag); | ||
1192 | return; | ||
1193 | } | ||
1194 | |||
1195 | ath6kl_cfg80211_disconnect_event(ar, reason, bssid, | ||
1196 | assoc_resp_len, assoc_info, | ||
1197 | prot_reason_status); | ||
1198 | |||
1199 | aggr_reset_state(ar->aggr_cntxt); | ||
1200 | |||
1201 | del_timer(&ar->disconnect_timer); | ||
1202 | |||
1203 | ath6kl_dbg(ATH6KL_DBG_WLAN_CONNECT, | ||
1204 | "disconnect reason is %d\n", reason); | ||
1205 | |||
1206 | /* | ||
1207 | * If the event is due to disconnect cmd from the host, only they | ||
1208 | * the target would stop trying to connect. Under any other | ||
1209 | * condition, target would keep trying to connect. | ||
1210 | */ | ||
1211 | if (reason == DISCONNECT_CMD) { | ||
1212 | if (!ar->usr_bss_filter && test_bit(WMI_READY, &ar->flag)) | ||
1213 | ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0); | ||
1214 | } else { | ||
1215 | set_bit(CONNECT_PEND, &ar->flag); | ||
1216 | if (((reason == ASSOC_FAILED) && | ||
1217 | (prot_reason_status == 0x11)) || | ||
1218 | ((reason == ASSOC_FAILED) && (prot_reason_status == 0x0) | ||
1219 | && (ar->reconnect_flag == 1))) { | ||
1220 | set_bit(CONNECTED, &ar->flag); | ||
1221 | return; | ||
1222 | } | ||
1223 | } | ||
1224 | |||
1225 | if ((reason == NO_NETWORK_AVAIL) && test_bit(WMI_READY, &ar->flag)) { | ||
1226 | ath6kl_wmi_node_free(ar->wmi, bssid); | ||
1227 | |||
1228 | /* | ||
1229 | * In case any other same SSID nodes are present remove it, | ||
1230 | * since those nodes also not available now. | ||
1231 | */ | ||
1232 | do { | ||
1233 | /* | ||
1234 | * Find the nodes based on SSID and remove it | ||
1235 | * | ||
1236 | * Note: This case will not work out for | ||
1237 | * Hidden-SSID | ||
1238 | */ | ||
1239 | wmi_ssid_node = ath6kl_wmi_find_ssid_node(ar->wmi, | ||
1240 | ar->ssid, | ||
1241 | ar->ssid_len, | ||
1242 | false, | ||
1243 | true); | ||
1244 | |||
1245 | if (wmi_ssid_node) | ||
1246 | ath6kl_wmi_node_free(ar->wmi, | ||
1247 | wmi_ssid_node->ni_macaddr); | ||
1248 | |||
1249 | } while (wmi_ssid_node); | ||
1250 | } | ||
1251 | |||
1252 | /* update connect & link status atomically */ | ||
1253 | spin_lock_irqsave(&ar->lock, flags); | ||
1254 | clear_bit(CONNECTED, &ar->flag); | ||
1255 | netif_carrier_off(ar->net_dev); | ||
1256 | spin_unlock_irqrestore(&ar->lock, flags); | ||
1257 | |||
1258 | if ((reason != CSERV_DISCONNECT) || (ar->reconnect_flag != 1)) | ||
1259 | ar->reconnect_flag = 0; | ||
1260 | |||
1261 | if (reason != CSERV_DISCONNECT) | ||
1262 | ar->user_key_ctrl = 0; | ||
1263 | |||
1264 | netif_stop_queue(ar->net_dev); | ||
1265 | memset(ar->bssid, 0, sizeof(ar->bssid)); | ||
1266 | ar->bss_ch = 0; | ||
1267 | |||
1268 | ath6kl_tx_data_cleanup(ar); | ||
1269 | } | ||
1270 | |||
1271 | static int ath6kl_open(struct net_device *dev) | ||
1272 | { | ||
1273 | struct ath6kl *ar = ath6kl_priv(dev); | ||
1274 | unsigned long flags; | ||
1275 | |||
1276 | spin_lock_irqsave(&ar->lock, flags); | ||
1277 | |||
1278 | set_bit(WLAN_ENABLED, &ar->flag); | ||
1279 | |||
1280 | if (test_bit(CONNECTED, &ar->flag)) { | ||
1281 | netif_carrier_on(dev); | ||
1282 | netif_wake_queue(dev); | ||
1283 | } else | ||
1284 | netif_carrier_off(dev); | ||
1285 | |||
1286 | spin_unlock_irqrestore(&ar->lock, flags); | ||
1287 | |||
1288 | return 0; | ||
1289 | } | ||
1290 | |||
1291 | static int ath6kl_close(struct net_device *dev) | ||
1292 | { | ||
1293 | struct ath6kl *ar = ath6kl_priv(dev); | ||
1294 | |||
1295 | netif_stop_queue(dev); | ||
1296 | |||
1297 | ath6kl_disconnect(ar); | ||
1298 | |||
1299 | if (test_bit(WMI_READY, &ar->flag)) { | ||
1300 | if (ath6kl_wmi_scanparams_cmd(ar->wmi, 0xFFFF, 0, 0, 0, 0, 0, 0, | ||
1301 | 0, 0, 0)) | ||
1302 | return -EIO; | ||
1303 | |||
1304 | clear_bit(WLAN_ENABLED, &ar->flag); | ||
1305 | } | ||
1306 | |||
1307 | ath6kl_cfg80211_scan_complete_event(ar, -ECANCELED); | ||
1308 | |||
1309 | return 0; | ||
1310 | } | ||
1311 | |||
1312 | static struct net_device_stats *ath6kl_get_stats(struct net_device *dev) | ||
1313 | { | ||
1314 | struct ath6kl *ar = ath6kl_priv(dev); | ||
1315 | |||
1316 | return &ar->net_stats; | ||
1317 | } | ||
1318 | |||
1319 | static struct net_device_ops ath6kl_netdev_ops = { | ||
1320 | .ndo_open = ath6kl_open, | ||
1321 | .ndo_stop = ath6kl_close, | ||
1322 | .ndo_start_xmit = ath6kl_data_tx, | ||
1323 | .ndo_get_stats = ath6kl_get_stats, | ||
1324 | }; | ||
1325 | |||
1326 | void init_netdev(struct net_device *dev) | ||
1327 | { | ||
1328 | dev->netdev_ops = &ath6kl_netdev_ops; | ||
1329 | dev->watchdog_timeo = ATH6KL_TX_TIMEOUT; | ||
1330 | |||
1331 | dev->needed_headroom = ETH_HLEN; | ||
1332 | dev->needed_headroom += sizeof(struct ath6kl_llc_snap_hdr) + | ||
1333 | sizeof(struct wmi_data_hdr) + HTC_HDR_LENGTH | ||
1334 | + WMI_MAX_TX_META_SZ; | ||
1335 | |||
1336 | return; | ||
1337 | } | ||
diff --git a/drivers/net/wireless/ath/ath6kl/node.c b/drivers/net/wireless/ath/ath6kl/node.c new file mode 100644 index 000000000000..131205c610b9 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/node.c | |||
@@ -0,0 +1,234 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004-2011 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 "htc.h" | ||
18 | #include "wmi.h" | ||
19 | #include "debug.h" | ||
20 | |||
21 | struct bss *wlan_node_alloc(int wh_size) | ||
22 | { | ||
23 | struct bss *ni; | ||
24 | |||
25 | ni = kzalloc(sizeof(struct bss), GFP_ATOMIC); | ||
26 | |||
27 | if ((ni != NULL) && wh_size) { | ||
28 | ni->ni_buf = kmalloc(wh_size, GFP_ATOMIC); | ||
29 | if (ni->ni_buf == NULL) { | ||
30 | kfree(ni); | ||
31 | return NULL; | ||
32 | } | ||
33 | } | ||
34 | |||
35 | return ni; | ||
36 | } | ||
37 | |||
38 | void wlan_node_free(struct bss *ni) | ||
39 | { | ||
40 | kfree(ni->ni_buf); | ||
41 | kfree(ni); | ||
42 | } | ||
43 | |||
44 | void wlan_setup_node(struct ath6kl_node_table *nt, struct bss *ni, | ||
45 | const u8 *mac_addr) | ||
46 | { | ||
47 | int hash; | ||
48 | |||
49 | memcpy(ni->ni_macaddr, mac_addr, ETH_ALEN); | ||
50 | hash = ATH6KL_NODE_HASH(mac_addr); | ||
51 | ni->ni_refcnt = 1; | ||
52 | |||
53 | ni->ni_tstamp = jiffies_to_msecs(jiffies); | ||
54 | ni->ni_actcnt = WLAN_NODE_INACT_CNT; | ||
55 | |||
56 | spin_lock_bh(&nt->nt_nodelock); | ||
57 | |||
58 | /* insert at the end of the node list */ | ||
59 | ni->ni_list_next = NULL; | ||
60 | ni->ni_list_prev = nt->nt_node_last; | ||
61 | if (nt->nt_node_last != NULL) | ||
62 | nt->nt_node_last->ni_list_next = ni; | ||
63 | |||
64 | nt->nt_node_last = ni; | ||
65 | if (nt->nt_node_first == NULL) | ||
66 | nt->nt_node_first = ni; | ||
67 | |||
68 | /* insert into the hash list */ | ||
69 | ni->ni_hash_next = nt->nt_hash[hash]; | ||
70 | if (ni->ni_hash_next != NULL) | ||
71 | nt->nt_hash[hash]->ni_hash_prev = ni; | ||
72 | |||
73 | ni->ni_hash_prev = NULL; | ||
74 | nt->nt_hash[hash] = ni; | ||
75 | |||
76 | spin_unlock_bh(&nt->nt_nodelock); | ||
77 | } | ||
78 | |||
79 | struct bss *wlan_find_node(struct ath6kl_node_table *nt, | ||
80 | const u8 *mac_addr) | ||
81 | { | ||
82 | struct bss *ni, *found_ni = NULL; | ||
83 | int hash; | ||
84 | |||
85 | spin_lock_bh(&nt->nt_nodelock); | ||
86 | |||
87 | hash = ATH6KL_NODE_HASH(mac_addr); | ||
88 | for (ni = nt->nt_hash[hash]; ni; ni = ni->ni_hash_next) { | ||
89 | if (memcmp(ni->ni_macaddr, mac_addr, ETH_ALEN) == 0) { | ||
90 | ni->ni_refcnt++; | ||
91 | found_ni = ni; | ||
92 | break; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | spin_unlock_bh(&nt->nt_nodelock); | ||
97 | |||
98 | return found_ni; | ||
99 | } | ||
100 | |||
101 | void wlan_node_reclaim(struct ath6kl_node_table *nt, struct bss *ni) | ||
102 | { | ||
103 | int hash; | ||
104 | |||
105 | spin_lock_bh(&nt->nt_nodelock); | ||
106 | |||
107 | if (ni->ni_list_prev == NULL) | ||
108 | /* fix list head */ | ||
109 | nt->nt_node_first = ni->ni_list_next; | ||
110 | else | ||
111 | ni->ni_list_prev->ni_list_next = ni->ni_list_next; | ||
112 | |||
113 | if (ni->ni_list_next == NULL) | ||
114 | /* fix list tail */ | ||
115 | nt->nt_node_last = ni->ni_list_prev; | ||
116 | else | ||
117 | ni->ni_list_next->ni_list_prev = ni->ni_list_prev; | ||
118 | |||
119 | if (ni->ni_hash_prev == NULL) { | ||
120 | /* first in list so fix the list head */ | ||
121 | hash = ATH6KL_NODE_HASH(ni->ni_macaddr); | ||
122 | nt->nt_hash[hash] = ni->ni_hash_next; | ||
123 | } else { | ||
124 | ni->ni_hash_prev->ni_hash_next = ni->ni_hash_next; | ||
125 | } | ||
126 | |||
127 | if (ni->ni_hash_next != NULL) | ||
128 | ni->ni_hash_next->ni_hash_prev = ni->ni_hash_prev; | ||
129 | |||
130 | wlan_node_free(ni); | ||
131 | |||
132 | spin_unlock_bh(&nt->nt_nodelock); | ||
133 | } | ||
134 | |||
135 | static void wlan_node_dec_free(struct bss *ni) | ||
136 | { | ||
137 | if ((ni->ni_refcnt--) == 1) | ||
138 | wlan_node_free(ni); | ||
139 | } | ||
140 | |||
141 | void wlan_free_allnodes(struct ath6kl_node_table *nt) | ||
142 | { | ||
143 | struct bss *ni; | ||
144 | |||
145 | while ((ni = nt->nt_node_first) != NULL) | ||
146 | wlan_node_reclaim(nt, ni); | ||
147 | } | ||
148 | |||
149 | void wlan_iterate_nodes(struct ath6kl_node_table *nt, void *arg) | ||
150 | { | ||
151 | struct bss *ni; | ||
152 | |||
153 | spin_lock_bh(&nt->nt_nodelock); | ||
154 | for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) { | ||
155 | ni->ni_refcnt++; | ||
156 | ath6kl_cfg80211_scan_node(arg, ni); | ||
157 | wlan_node_dec_free(ni); | ||
158 | } | ||
159 | spin_unlock_bh(&nt->nt_nodelock); | ||
160 | } | ||
161 | |||
162 | void wlan_node_table_init(struct ath6kl_node_table *nt) | ||
163 | { | ||
164 | ath6kl_dbg(ATH6KL_DBG_WLAN_NODE, "node table = 0x%lx\n", | ||
165 | (unsigned long)nt); | ||
166 | |||
167 | memset(nt, 0, sizeof(struct ath6kl_node_table)); | ||
168 | |||
169 | spin_lock_init(&nt->nt_nodelock); | ||
170 | |||
171 | nt->nt_node_age = WLAN_NODE_INACT_TIMEOUT_MSEC; | ||
172 | } | ||
173 | |||
174 | void wlan_refresh_inactive_nodes(struct ath6kl *ar) | ||
175 | { | ||
176 | struct ath6kl_node_table *nt = &ar->scan_table; | ||
177 | struct bss *bss; | ||
178 | u32 now; | ||
179 | |||
180 | now = jiffies_to_msecs(jiffies); | ||
181 | bss = nt->nt_node_first; | ||
182 | while (bss != NULL) { | ||
183 | /* refresh all nodes except the current bss */ | ||
184 | if (memcmp(ar->bssid, bss->ni_macaddr, ETH_ALEN) != 0) { | ||
185 | if (((now - bss->ni_tstamp) > nt->nt_node_age) | ||
186 | || --bss->ni_actcnt == 0) { | ||
187 | wlan_node_reclaim(nt, bss); | ||
188 | } | ||
189 | } | ||
190 | bss = bss->ni_list_next; | ||
191 | } | ||
192 | } | ||
193 | |||
194 | void wlan_node_table_cleanup(struct ath6kl_node_table *nt) | ||
195 | { | ||
196 | wlan_free_allnodes(nt); | ||
197 | } | ||
198 | |||
199 | struct bss *wlan_find_ssid_node(struct ath6kl_node_table *nt, u8 * ssid, | ||
200 | u32 ssid_len, bool is_wpa2, bool match_ssid) | ||
201 | { | ||
202 | struct bss *ni, *found_ni = NULL; | ||
203 | u8 *ie_ssid; | ||
204 | |||
205 | spin_lock_bh(&nt->nt_nodelock); | ||
206 | |||
207 | for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) { | ||
208 | |||
209 | ie_ssid = ni->ni_cie.ie_ssid; | ||
210 | |||
211 | if ((ie_ssid[1] <= IEEE80211_MAX_SSID_LEN) && | ||
212 | (memcmp(ssid, &ie_ssid[2], ssid_len) == 0)) { | ||
213 | |||
214 | if (match_ssid || | ||
215 | (is_wpa2 && ni->ni_cie.ie_rsn != NULL) || | ||
216 | (!is_wpa2 && ni->ni_cie.ie_wpa != NULL)) { | ||
217 | ni->ni_refcnt++; | ||
218 | found_ni = ni; | ||
219 | break; | ||
220 | } | ||
221 | } | ||
222 | } | ||
223 | |||
224 | spin_unlock_bh(&nt->nt_nodelock); | ||
225 | |||
226 | return found_ni; | ||
227 | } | ||
228 | |||
229 | void wlan_node_return(struct ath6kl_node_table *nt, struct bss *ni) | ||
230 | { | ||
231 | spin_lock_bh(&nt->nt_nodelock); | ||
232 | wlan_node_dec_free(ni); | ||
233 | spin_unlock_bh(&nt->nt_nodelock); | ||
234 | } | ||
diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c new file mode 100644 index 000000000000..34171604cbe4 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/sdio.c | |||
@@ -0,0 +1,912 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004-2011 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 <linux/mmc/card.h> | ||
18 | #include <linux/mmc/mmc.h> | ||
19 | #include <linux/mmc/host.h> | ||
20 | #include <linux/mmc/sdio_func.h> | ||
21 | #include <linux/mmc/sdio_ids.h> | ||
22 | #include <linux/mmc/sdio.h> | ||
23 | #include <linux/mmc/sd.h> | ||
24 | #include "htc_hif.h" | ||
25 | #include "hif-ops.h" | ||
26 | #include "target.h" | ||
27 | #include "debug.h" | ||
28 | |||
29 | struct ath6kl_sdio { | ||
30 | struct sdio_func *func; | ||
31 | |||
32 | spinlock_t lock; | ||
33 | |||
34 | /* free list */ | ||
35 | struct list_head bus_req_freeq; | ||
36 | |||
37 | /* available bus requests */ | ||
38 | struct bus_request bus_req[BUS_REQUEST_MAX_NUM]; | ||
39 | |||
40 | struct ath6kl *ar; | ||
41 | u8 *dma_buffer; | ||
42 | |||
43 | /* scatter request list head */ | ||
44 | struct list_head scat_req; | ||
45 | |||
46 | spinlock_t scat_lock; | ||
47 | bool is_disabled; | ||
48 | atomic_t irq_handling; | ||
49 | const struct sdio_device_id *id; | ||
50 | struct work_struct wr_async_work; | ||
51 | struct list_head wr_asyncq; | ||
52 | spinlock_t wr_async_lock; | ||
53 | }; | ||
54 | |||
55 | #define CMD53_ARG_READ 0 | ||
56 | #define CMD53_ARG_WRITE 1 | ||
57 | #define CMD53_ARG_BLOCK_BASIS 1 | ||
58 | #define CMD53_ARG_FIXED_ADDRESS 0 | ||
59 | #define CMD53_ARG_INCR_ADDRESS 1 | ||
60 | |||
61 | static inline struct ath6kl_sdio *ath6kl_sdio_priv(struct ath6kl *ar) | ||
62 | { | ||
63 | return ar->hif_priv; | ||
64 | } | ||
65 | |||
66 | /* | ||
67 | * Macro to check if DMA buffer is WORD-aligned and DMA-able. | ||
68 | * Most host controllers assume the buffer is DMA'able and will | ||
69 | * bug-check otherwise (i.e. buffers on the stack). virt_addr_valid | ||
70 | * check fails on stack memory. | ||
71 | */ | ||
72 | static inline bool buf_needs_bounce(u8 *buf) | ||
73 | { | ||
74 | return ((unsigned long) buf & 0x3) || !virt_addr_valid(buf); | ||
75 | } | ||
76 | |||
77 | static void ath6kl_sdio_set_mbox_info(struct ath6kl *ar) | ||
78 | { | ||
79 | struct ath6kl_mbox_info *mbox_info = &ar->mbox_info; | ||
80 | |||
81 | /* EP1 has an extended range */ | ||
82 | mbox_info->htc_addr = HIF_MBOX_BASE_ADDR; | ||
83 | mbox_info->htc_ext_addr = HIF_MBOX0_EXT_BASE_ADDR; | ||
84 | mbox_info->htc_ext_sz = HIF_MBOX0_EXT_WIDTH; | ||
85 | mbox_info->block_size = HIF_MBOX_BLOCK_SIZE; | ||
86 | mbox_info->gmbox_addr = HIF_GMBOX_BASE_ADDR; | ||
87 | mbox_info->gmbox_sz = HIF_GMBOX_WIDTH; | ||
88 | } | ||
89 | |||
90 | static inline void ath6kl_sdio_set_cmd53_arg(u32 *arg, u8 rw, u8 func, | ||
91 | u8 mode, u8 opcode, u32 addr, | ||
92 | u16 blksz) | ||
93 | { | ||
94 | *arg = (((rw & 1) << 31) | | ||
95 | ((func & 0x7) << 28) | | ||
96 | ((mode & 1) << 27) | | ||
97 | ((opcode & 1) << 26) | | ||
98 | ((addr & 0x1FFFF) << 9) | | ||
99 | (blksz & 0x1FF)); | ||
100 | } | ||
101 | |||
102 | static inline void ath6kl_sdio_set_cmd52_arg(u32 *arg, u8 write, u8 raw, | ||
103 | unsigned int address, | ||
104 | unsigned char val) | ||
105 | { | ||
106 | const u8 func = 0; | ||
107 | |||
108 | *arg = ((write & 1) << 31) | | ||
109 | ((func & 0x7) << 28) | | ||
110 | ((raw & 1) << 27) | | ||
111 | (1 << 26) | | ||
112 | ((address & 0x1FFFF) << 9) | | ||
113 | (1 << 8) | | ||
114 | (val & 0xFF); | ||
115 | } | ||
116 | |||
117 | static int ath6kl_sdio_func0_cmd52_wr_byte(struct mmc_card *card, | ||
118 | unsigned int address, | ||
119 | unsigned char byte) | ||
120 | { | ||
121 | struct mmc_command io_cmd; | ||
122 | |||
123 | memset(&io_cmd, 0, sizeof(io_cmd)); | ||
124 | ath6kl_sdio_set_cmd52_arg(&io_cmd.arg, 1, 0, address, byte); | ||
125 | io_cmd.opcode = SD_IO_RW_DIRECT; | ||
126 | io_cmd.flags = MMC_RSP_R5 | MMC_CMD_AC; | ||
127 | |||
128 | return mmc_wait_for_cmd(card->host, &io_cmd, 0); | ||
129 | } | ||
130 | |||
131 | static int ath6kl_sdio_io(struct sdio_func *func, u32 request, u32 addr, | ||
132 | u8 *buf, u32 len) | ||
133 | { | ||
134 | int ret = 0; | ||
135 | |||
136 | if (request & HIF_WRITE) { | ||
137 | if (addr >= HIF_MBOX_BASE_ADDR && | ||
138 | addr <= HIF_MBOX_END_ADDR) | ||
139 | addr += (HIF_MBOX_WIDTH - len); | ||
140 | |||
141 | if (addr == HIF_MBOX0_EXT_BASE_ADDR) | ||
142 | addr += HIF_MBOX0_EXT_WIDTH - len; | ||
143 | |||
144 | if (request & HIF_FIXED_ADDRESS) | ||
145 | ret = sdio_writesb(func, addr, buf, len); | ||
146 | else | ||
147 | ret = sdio_memcpy_toio(func, addr, buf, len); | ||
148 | } else { | ||
149 | if (request & HIF_FIXED_ADDRESS) | ||
150 | ret = sdio_readsb(func, buf, addr, len); | ||
151 | else | ||
152 | ret = sdio_memcpy_fromio(func, buf, addr, len); | ||
153 | } | ||
154 | |||
155 | return ret; | ||
156 | } | ||
157 | |||
158 | static struct bus_request *ath6kl_sdio_alloc_busreq(struct ath6kl_sdio *ar_sdio) | ||
159 | { | ||
160 | struct bus_request *bus_req; | ||
161 | unsigned long flag; | ||
162 | |||
163 | spin_lock_irqsave(&ar_sdio->lock, flag); | ||
164 | |||
165 | if (list_empty(&ar_sdio->bus_req_freeq)) { | ||
166 | spin_unlock_irqrestore(&ar_sdio->lock, flag); | ||
167 | return NULL; | ||
168 | } | ||
169 | |||
170 | bus_req = list_first_entry(&ar_sdio->bus_req_freeq, | ||
171 | struct bus_request, list); | ||
172 | list_del(&bus_req->list); | ||
173 | |||
174 | spin_unlock_irqrestore(&ar_sdio->lock, flag); | ||
175 | ath6kl_dbg(ATH6KL_DBG_TRC, "%s: bus request 0x%p\n", __func__, bus_req); | ||
176 | |||
177 | return bus_req; | ||
178 | } | ||
179 | |||
180 | static void ath6kl_sdio_free_bus_req(struct ath6kl_sdio *ar_sdio, | ||
181 | struct bus_request *bus_req) | ||
182 | { | ||
183 | unsigned long flag; | ||
184 | |||
185 | ath6kl_dbg(ATH6KL_DBG_TRC, "%s: bus request 0x%p\n", __func__, bus_req); | ||
186 | |||
187 | spin_lock_irqsave(&ar_sdio->lock, flag); | ||
188 | list_add_tail(&bus_req->list, &ar_sdio->bus_req_freeq); | ||
189 | spin_unlock_irqrestore(&ar_sdio->lock, flag); | ||
190 | } | ||
191 | |||
192 | static void ath6kl_sdio_setup_scat_data(struct hif_scatter_req *scat_req, | ||
193 | struct mmc_data *data) | ||
194 | { | ||
195 | struct scatterlist *sg; | ||
196 | int i; | ||
197 | |||
198 | data->blksz = HIF_MBOX_BLOCK_SIZE; | ||
199 | data->blocks = scat_req->len / HIF_MBOX_BLOCK_SIZE; | ||
200 | |||
201 | ath6kl_dbg(ATH6KL_DBG_SCATTER, | ||
202 | "hif-scatter: (%s) addr: 0x%X, (block len: %d, block count: %d) , (tot:%d,sg:%d)\n", | ||
203 | (scat_req->req & HIF_WRITE) ? "WR" : "RD", scat_req->addr, | ||
204 | data->blksz, data->blocks, scat_req->len, | ||
205 | scat_req->scat_entries); | ||
206 | |||
207 | data->flags = (scat_req->req & HIF_WRITE) ? MMC_DATA_WRITE : | ||
208 | MMC_DATA_READ; | ||
209 | |||
210 | /* fill SG entries */ | ||
211 | sg = scat_req->sgentries; | ||
212 | sg_init_table(sg, scat_req->scat_entries); | ||
213 | |||
214 | /* assemble SG list */ | ||
215 | for (i = 0; i < scat_req->scat_entries; i++, sg++) { | ||
216 | if ((unsigned long)scat_req->scat_list[i].buf & 0x3) | ||
217 | /* | ||
218 | * Some scatter engines can handle unaligned | ||
219 | * buffers, print this as informational only. | ||
220 | */ | ||
221 | ath6kl_dbg(ATH6KL_DBG_SCATTER, | ||
222 | "(%s) scatter buffer is unaligned 0x%p\n", | ||
223 | scat_req->req & HIF_WRITE ? "WR" : "RD", | ||
224 | scat_req->scat_list[i].buf); | ||
225 | |||
226 | ath6kl_dbg(ATH6KL_DBG_SCATTER, "%d: addr:0x%p, len:%d\n", | ||
227 | i, scat_req->scat_list[i].buf, | ||
228 | scat_req->scat_list[i].len); | ||
229 | |||
230 | sg_set_buf(sg, scat_req->scat_list[i].buf, | ||
231 | scat_req->scat_list[i].len); | ||
232 | } | ||
233 | |||
234 | /* set scatter-gather table for request */ | ||
235 | data->sg = scat_req->sgentries; | ||
236 | data->sg_len = scat_req->scat_entries; | ||
237 | } | ||
238 | |||
239 | static int ath6kl_sdio_scat_rw(struct ath6kl_sdio *ar_sdio, | ||
240 | struct bus_request *req) | ||
241 | { | ||
242 | struct mmc_request mmc_req; | ||
243 | struct mmc_command cmd; | ||
244 | struct mmc_data data; | ||
245 | struct hif_scatter_req *scat_req; | ||
246 | u8 opcode, rw; | ||
247 | int status, len; | ||
248 | |||
249 | scat_req = req->scat_req; | ||
250 | |||
251 | if (scat_req->virt_scat) { | ||
252 | len = scat_req->len; | ||
253 | if (scat_req->req & HIF_BLOCK_BASIS) | ||
254 | len = round_down(len, HIF_MBOX_BLOCK_SIZE); | ||
255 | |||
256 | status = ath6kl_sdio_io(ar_sdio->func, scat_req->req, | ||
257 | scat_req->addr, scat_req->virt_dma_buf, | ||
258 | len); | ||
259 | goto scat_complete; | ||
260 | } | ||
261 | |||
262 | memset(&mmc_req, 0, sizeof(struct mmc_request)); | ||
263 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
264 | memset(&data, 0, sizeof(struct mmc_data)); | ||
265 | |||
266 | ath6kl_sdio_setup_scat_data(scat_req, &data); | ||
267 | |||
268 | opcode = (scat_req->req & HIF_FIXED_ADDRESS) ? | ||
269 | CMD53_ARG_FIXED_ADDRESS : CMD53_ARG_INCR_ADDRESS; | ||
270 | |||
271 | rw = (scat_req->req & HIF_WRITE) ? CMD53_ARG_WRITE : CMD53_ARG_READ; | ||
272 | |||
273 | /* Fixup the address so that the last byte will fall on MBOX EOM */ | ||
274 | if (scat_req->req & HIF_WRITE) { | ||
275 | if (scat_req->addr == HIF_MBOX_BASE_ADDR) | ||
276 | scat_req->addr += HIF_MBOX_WIDTH - scat_req->len; | ||
277 | else | ||
278 | /* Uses extended address range */ | ||
279 | scat_req->addr += HIF_MBOX0_EXT_WIDTH - scat_req->len; | ||
280 | } | ||
281 | |||
282 | /* set command argument */ | ||
283 | ath6kl_sdio_set_cmd53_arg(&cmd.arg, rw, ar_sdio->func->num, | ||
284 | CMD53_ARG_BLOCK_BASIS, opcode, scat_req->addr, | ||
285 | data.blocks); | ||
286 | |||
287 | cmd.opcode = SD_IO_RW_EXTENDED; | ||
288 | cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC; | ||
289 | |||
290 | mmc_req.cmd = &cmd; | ||
291 | mmc_req.data = &data; | ||
292 | |||
293 | mmc_set_data_timeout(&data, ar_sdio->func->card); | ||
294 | /* synchronous call to process request */ | ||
295 | mmc_wait_for_req(ar_sdio->func->card->host, &mmc_req); | ||
296 | |||
297 | status = cmd.error ? cmd.error : data.error; | ||
298 | |||
299 | scat_complete: | ||
300 | scat_req->status = status; | ||
301 | |||
302 | if (scat_req->status) | ||
303 | ath6kl_err("Scatter write request failed:%d\n", | ||
304 | scat_req->status); | ||
305 | |||
306 | if (scat_req->req & HIF_ASYNCHRONOUS) | ||
307 | scat_req->complete(ar_sdio->ar->htc_target, scat_req); | ||
308 | |||
309 | return status; | ||
310 | } | ||
311 | |||
312 | static int ath6kl_sdio_alloc_prep_scat_req(struct ath6kl_sdio *ar_sdio, | ||
313 | int n_scat_entry, int n_scat_req, | ||
314 | bool virt_scat) | ||
315 | { | ||
316 | struct hif_scatter_req *s_req; | ||
317 | struct bus_request *bus_req; | ||
318 | int i, scat_req_sz, scat_list_sz, sg_sz, buf_sz; | ||
319 | u8 *virt_buf; | ||
320 | |||
321 | scat_list_sz = (n_scat_entry - 1) * sizeof(struct hif_scatter_item); | ||
322 | scat_req_sz = sizeof(*s_req) + scat_list_sz; | ||
323 | |||
324 | if (!virt_scat) | ||
325 | sg_sz = sizeof(struct scatterlist) * n_scat_entry; | ||
326 | else | ||
327 | buf_sz = 2 * L1_CACHE_BYTES + | ||
328 | ATH6KL_MAX_TRANSFER_SIZE_PER_SCATTER; | ||
329 | |||
330 | for (i = 0; i < n_scat_req; i++) { | ||
331 | /* allocate the scatter request */ | ||
332 | s_req = kzalloc(scat_req_sz, GFP_KERNEL); | ||
333 | if (!s_req) | ||
334 | return -ENOMEM; | ||
335 | |||
336 | if (virt_scat) { | ||
337 | virt_buf = kzalloc(buf_sz, GFP_KERNEL); | ||
338 | if (!virt_buf) { | ||
339 | kfree(s_req); | ||
340 | return -ENOMEM; | ||
341 | } | ||
342 | |||
343 | s_req->virt_dma_buf = | ||
344 | (u8 *)L1_CACHE_ALIGN((unsigned long)virt_buf); | ||
345 | } else { | ||
346 | /* allocate sglist */ | ||
347 | s_req->sgentries = kzalloc(sg_sz, GFP_KERNEL); | ||
348 | |||
349 | if (!s_req->sgentries) { | ||
350 | kfree(s_req); | ||
351 | return -ENOMEM; | ||
352 | } | ||
353 | } | ||
354 | |||
355 | /* allocate a bus request for this scatter request */ | ||
356 | bus_req = ath6kl_sdio_alloc_busreq(ar_sdio); | ||
357 | if (!bus_req) { | ||
358 | kfree(s_req->sgentries); | ||
359 | kfree(s_req->virt_dma_buf); | ||
360 | kfree(s_req); | ||
361 | return -ENOMEM; | ||
362 | } | ||
363 | |||
364 | /* assign the scatter request to this bus request */ | ||
365 | bus_req->scat_req = s_req; | ||
366 | s_req->busrequest = bus_req; | ||
367 | |||
368 | s_req->virt_scat = virt_scat; | ||
369 | |||
370 | /* add it to the scatter pool */ | ||
371 | hif_scatter_req_add(ar_sdio->ar, s_req); | ||
372 | } | ||
373 | |||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | static int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf, | ||
378 | u32 len, u32 request) | ||
379 | { | ||
380 | struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); | ||
381 | u8 *tbuf = NULL; | ||
382 | int ret; | ||
383 | bool bounced = false; | ||
384 | |||
385 | if (request & HIF_BLOCK_BASIS) | ||
386 | len = round_down(len, HIF_MBOX_BLOCK_SIZE); | ||
387 | |||
388 | if (buf_needs_bounce(buf)) { | ||
389 | if (!ar_sdio->dma_buffer) | ||
390 | return -ENOMEM; | ||
391 | tbuf = ar_sdio->dma_buffer; | ||
392 | memcpy(tbuf, buf, len); | ||
393 | bounced = true; | ||
394 | } else | ||
395 | tbuf = buf; | ||
396 | |||
397 | sdio_claim_host(ar_sdio->func); | ||
398 | ret = ath6kl_sdio_io(ar_sdio->func, request, addr, tbuf, len); | ||
399 | if ((request & HIF_READ) && bounced) | ||
400 | memcpy(buf, tbuf, len); | ||
401 | sdio_release_host(ar_sdio->func); | ||
402 | |||
403 | return ret; | ||
404 | } | ||
405 | |||
406 | static void __ath6kl_sdio_write_async(struct ath6kl_sdio *ar_sdio, | ||
407 | struct bus_request *req) | ||
408 | { | ||
409 | if (req->scat_req) | ||
410 | ath6kl_sdio_scat_rw(ar_sdio, req); | ||
411 | else { | ||
412 | void *context; | ||
413 | int status; | ||
414 | |||
415 | status = ath6kl_sdio_read_write_sync(ar_sdio->ar, req->address, | ||
416 | req->buffer, req->length, | ||
417 | req->request); | ||
418 | context = req->packet; | ||
419 | ath6kl_sdio_free_bus_req(ar_sdio, req); | ||
420 | ath6kldev_rw_comp_handler(context, status); | ||
421 | } | ||
422 | } | ||
423 | |||
424 | static void ath6kl_sdio_write_async_work(struct work_struct *work) | ||
425 | { | ||
426 | struct ath6kl_sdio *ar_sdio; | ||
427 | unsigned long flags; | ||
428 | struct bus_request *req, *tmp_req; | ||
429 | |||
430 | ar_sdio = container_of(work, struct ath6kl_sdio, wr_async_work); | ||
431 | sdio_claim_host(ar_sdio->func); | ||
432 | |||
433 | spin_lock_irqsave(&ar_sdio->wr_async_lock, flags); | ||
434 | list_for_each_entry_safe(req, tmp_req, &ar_sdio->wr_asyncq, list) { | ||
435 | list_del(&req->list); | ||
436 | spin_unlock_irqrestore(&ar_sdio->wr_async_lock, flags); | ||
437 | __ath6kl_sdio_write_async(ar_sdio, req); | ||
438 | spin_lock_irqsave(&ar_sdio->wr_async_lock, flags); | ||
439 | } | ||
440 | spin_unlock_irqrestore(&ar_sdio->wr_async_lock, flags); | ||
441 | |||
442 | sdio_release_host(ar_sdio->func); | ||
443 | } | ||
444 | |||
445 | static void ath6kl_sdio_irq_handler(struct sdio_func *func) | ||
446 | { | ||
447 | int status; | ||
448 | struct ath6kl_sdio *ar_sdio; | ||
449 | |||
450 | ar_sdio = sdio_get_drvdata(func); | ||
451 | atomic_set(&ar_sdio->irq_handling, 1); | ||
452 | |||
453 | /* | ||
454 | * Release the host during interrups so we can pick it back up when | ||
455 | * we process commands. | ||
456 | */ | ||
457 | sdio_release_host(ar_sdio->func); | ||
458 | |||
459 | status = ath6kldev_intr_bh_handler(ar_sdio->ar); | ||
460 | sdio_claim_host(ar_sdio->func); | ||
461 | atomic_set(&ar_sdio->irq_handling, 0); | ||
462 | WARN_ON(status && status != -ECANCELED); | ||
463 | } | ||
464 | |||
465 | static int ath6kl_sdio_power_on(struct ath6kl_sdio *ar_sdio) | ||
466 | { | ||
467 | struct sdio_func *func = ar_sdio->func; | ||
468 | int ret = 0; | ||
469 | |||
470 | if (!ar_sdio->is_disabled) | ||
471 | return 0; | ||
472 | |||
473 | sdio_claim_host(func); | ||
474 | |||
475 | ret = sdio_enable_func(func); | ||
476 | if (ret) { | ||
477 | ath6kl_err("Unable to enable sdio func: %d)\n", ret); | ||
478 | sdio_release_host(func); | ||
479 | return ret; | ||
480 | } | ||
481 | |||
482 | sdio_release_host(func); | ||
483 | |||
484 | /* | ||
485 | * Wait for hardware to initialise. It should take a lot less than | ||
486 | * 10 ms but let's be conservative here. | ||
487 | */ | ||
488 | msleep(10); | ||
489 | |||
490 | ar_sdio->is_disabled = false; | ||
491 | |||
492 | return ret; | ||
493 | } | ||
494 | |||
495 | static int ath6kl_sdio_power_off(struct ath6kl_sdio *ar_sdio) | ||
496 | { | ||
497 | int ret; | ||
498 | |||
499 | if (ar_sdio->is_disabled) | ||
500 | return 0; | ||
501 | |||
502 | /* Disable the card */ | ||
503 | sdio_claim_host(ar_sdio->func); | ||
504 | ret = sdio_disable_func(ar_sdio->func); | ||
505 | sdio_release_host(ar_sdio->func); | ||
506 | |||
507 | if (ret) | ||
508 | return ret; | ||
509 | |||
510 | ar_sdio->is_disabled = true; | ||
511 | |||
512 | return ret; | ||
513 | } | ||
514 | |||
515 | static int ath6kl_sdio_write_async(struct ath6kl *ar, u32 address, u8 *buffer, | ||
516 | u32 length, u32 request, | ||
517 | struct htc_packet *packet) | ||
518 | { | ||
519 | struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); | ||
520 | struct bus_request *bus_req; | ||
521 | unsigned long flags; | ||
522 | |||
523 | bus_req = ath6kl_sdio_alloc_busreq(ar_sdio); | ||
524 | |||
525 | if (!bus_req) | ||
526 | return -ENOMEM; | ||
527 | |||
528 | bus_req->address = address; | ||
529 | bus_req->buffer = buffer; | ||
530 | bus_req->length = length; | ||
531 | bus_req->request = request; | ||
532 | bus_req->packet = packet; | ||
533 | |||
534 | spin_lock_irqsave(&ar_sdio->wr_async_lock, flags); | ||
535 | list_add_tail(&bus_req->list, &ar_sdio->wr_asyncq); | ||
536 | spin_unlock_irqrestore(&ar_sdio->wr_async_lock, flags); | ||
537 | queue_work(ar->ath6kl_wq, &ar_sdio->wr_async_work); | ||
538 | |||
539 | return 0; | ||
540 | } | ||
541 | |||
542 | static void ath6kl_sdio_irq_enable(struct ath6kl *ar) | ||
543 | { | ||
544 | struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); | ||
545 | int ret; | ||
546 | |||
547 | sdio_claim_host(ar_sdio->func); | ||
548 | |||
549 | /* Register the isr */ | ||
550 | ret = sdio_claim_irq(ar_sdio->func, ath6kl_sdio_irq_handler); | ||
551 | if (ret) | ||
552 | ath6kl_err("Failed to claim sdio irq: %d\n", ret); | ||
553 | |||
554 | sdio_release_host(ar_sdio->func); | ||
555 | } | ||
556 | |||
557 | static void ath6kl_sdio_irq_disable(struct ath6kl *ar) | ||
558 | { | ||
559 | struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); | ||
560 | int ret; | ||
561 | |||
562 | sdio_claim_host(ar_sdio->func); | ||
563 | |||
564 | /* Mask our function IRQ */ | ||
565 | while (atomic_read(&ar_sdio->irq_handling)) { | ||
566 | sdio_release_host(ar_sdio->func); | ||
567 | schedule_timeout(HZ / 10); | ||
568 | sdio_claim_host(ar_sdio->func); | ||
569 | } | ||
570 | |||
571 | ret = sdio_release_irq(ar_sdio->func); | ||
572 | if (ret) | ||
573 | ath6kl_err("Failed to release sdio irq: %d\n", ret); | ||
574 | |||
575 | sdio_release_host(ar_sdio->func); | ||
576 | } | ||
577 | |||
578 | static struct hif_scatter_req *ath6kl_sdio_scatter_req_get(struct ath6kl *ar) | ||
579 | { | ||
580 | struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); | ||
581 | struct hif_scatter_req *node = NULL; | ||
582 | unsigned long flag; | ||
583 | |||
584 | spin_lock_irqsave(&ar_sdio->scat_lock, flag); | ||
585 | |||
586 | if (!list_empty(&ar_sdio->scat_req)) { | ||
587 | node = list_first_entry(&ar_sdio->scat_req, | ||
588 | struct hif_scatter_req, list); | ||
589 | list_del(&node->list); | ||
590 | } | ||
591 | |||
592 | spin_unlock_irqrestore(&ar_sdio->scat_lock, flag); | ||
593 | |||
594 | return node; | ||
595 | } | ||
596 | |||
597 | static void ath6kl_sdio_scatter_req_add(struct ath6kl *ar, | ||
598 | struct hif_scatter_req *s_req) | ||
599 | { | ||
600 | struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); | ||
601 | unsigned long flag; | ||
602 | |||
603 | spin_lock_irqsave(&ar_sdio->scat_lock, flag); | ||
604 | |||
605 | list_add_tail(&s_req->list, &ar_sdio->scat_req); | ||
606 | |||
607 | spin_unlock_irqrestore(&ar_sdio->scat_lock, flag); | ||
608 | |||
609 | } | ||
610 | |||
611 | /* scatter gather read write request */ | ||
612 | static int ath6kl_sdio_async_rw_scatter(struct ath6kl *ar, | ||
613 | struct hif_scatter_req *scat_req) | ||
614 | { | ||
615 | struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); | ||
616 | u32 request = scat_req->req; | ||
617 | int status = 0; | ||
618 | unsigned long flags; | ||
619 | |||
620 | if (!scat_req->len) | ||
621 | return -EINVAL; | ||
622 | |||
623 | ath6kl_dbg(ATH6KL_DBG_SCATTER, | ||
624 | "hif-scatter: total len: %d scatter entries: %d\n", | ||
625 | scat_req->len, scat_req->scat_entries); | ||
626 | |||
627 | if (request & HIF_SYNCHRONOUS) { | ||
628 | sdio_claim_host(ar_sdio->func); | ||
629 | status = ath6kl_sdio_scat_rw(ar_sdio, scat_req->busrequest); | ||
630 | sdio_release_host(ar_sdio->func); | ||
631 | } else { | ||
632 | spin_lock_irqsave(&ar_sdio->wr_async_lock, flags); | ||
633 | list_add_tail(&scat_req->busrequest->list, &ar_sdio->wr_asyncq); | ||
634 | spin_unlock_irqrestore(&ar_sdio->wr_async_lock, flags); | ||
635 | queue_work(ar->ath6kl_wq, &ar_sdio->wr_async_work); | ||
636 | } | ||
637 | |||
638 | return status; | ||
639 | } | ||
640 | |||
641 | /* clean up scatter support */ | ||
642 | static void ath6kl_sdio_cleanup_scatter(struct ath6kl *ar) | ||
643 | { | ||
644 | struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); | ||
645 | struct hif_scatter_req *s_req, *tmp_req; | ||
646 | unsigned long flag; | ||
647 | |||
648 | /* empty the free list */ | ||
649 | spin_lock_irqsave(&ar_sdio->scat_lock, flag); | ||
650 | list_for_each_entry_safe(s_req, tmp_req, &ar_sdio->scat_req, list) { | ||
651 | list_del(&s_req->list); | ||
652 | spin_unlock_irqrestore(&ar_sdio->scat_lock, flag); | ||
653 | |||
654 | if (s_req->busrequest) | ||
655 | ath6kl_sdio_free_bus_req(ar_sdio, s_req->busrequest); | ||
656 | kfree(s_req->virt_dma_buf); | ||
657 | kfree(s_req->sgentries); | ||
658 | kfree(s_req); | ||
659 | |||
660 | spin_lock_irqsave(&ar_sdio->scat_lock, flag); | ||
661 | } | ||
662 | spin_unlock_irqrestore(&ar_sdio->scat_lock, flag); | ||
663 | } | ||
664 | |||
665 | /* setup of HIF scatter resources */ | ||
666 | static int ath6kl_sdio_enable_scatter(struct ath6kl *ar) | ||
667 | { | ||
668 | struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); | ||
669 | struct htc_target *target = ar->htc_target; | ||
670 | int ret; | ||
671 | bool virt_scat = false; | ||
672 | |||
673 | /* check if host supports scatter and it meets our requirements */ | ||
674 | if (ar_sdio->func->card->host->max_segs < MAX_SCATTER_ENTRIES_PER_REQ) { | ||
675 | ath6kl_err("host only supports scatter of :%d entries, need: %d\n", | ||
676 | ar_sdio->func->card->host->max_segs, | ||
677 | MAX_SCATTER_ENTRIES_PER_REQ); | ||
678 | virt_scat = true; | ||
679 | } | ||
680 | |||
681 | if (!virt_scat) { | ||
682 | ret = ath6kl_sdio_alloc_prep_scat_req(ar_sdio, | ||
683 | MAX_SCATTER_ENTRIES_PER_REQ, | ||
684 | MAX_SCATTER_REQUESTS, virt_scat); | ||
685 | |||
686 | if (!ret) { | ||
687 | ath6kl_dbg(ATH6KL_DBG_ANY, | ||
688 | "hif-scatter enabled: max scatter req : %d entries: %d\n", | ||
689 | MAX_SCATTER_REQUESTS, | ||
690 | MAX_SCATTER_ENTRIES_PER_REQ); | ||
691 | |||
692 | target->max_scat_entries = MAX_SCATTER_ENTRIES_PER_REQ; | ||
693 | target->max_xfer_szper_scatreq = | ||
694 | MAX_SCATTER_REQ_TRANSFER_SIZE; | ||
695 | } else { | ||
696 | ath6kl_sdio_cleanup_scatter(ar); | ||
697 | ath6kl_warn("hif scatter resource setup failed, trying virtual scatter method\n"); | ||
698 | } | ||
699 | } | ||
700 | |||
701 | if (virt_scat || ret) { | ||
702 | ret = ath6kl_sdio_alloc_prep_scat_req(ar_sdio, | ||
703 | ATH6KL_SCATTER_ENTRIES_PER_REQ, | ||
704 | ATH6KL_SCATTER_REQS, virt_scat); | ||
705 | |||
706 | if (ret) { | ||
707 | ath6kl_err("failed to alloc virtual scatter resources !\n"); | ||
708 | ath6kl_sdio_cleanup_scatter(ar); | ||
709 | return ret; | ||
710 | } | ||
711 | |||
712 | ath6kl_dbg(ATH6KL_DBG_ANY, | ||
713 | "Vitual scatter enabled, max_scat_req:%d, entries:%d\n", | ||
714 | ATH6KL_SCATTER_REQS, ATH6KL_SCATTER_ENTRIES_PER_REQ); | ||
715 | |||
716 | target->max_scat_entries = ATH6KL_SCATTER_ENTRIES_PER_REQ; | ||
717 | target->max_xfer_szper_scatreq = | ||
718 | ATH6KL_MAX_TRANSFER_SIZE_PER_SCATTER; | ||
719 | } | ||
720 | |||
721 | return 0; | ||
722 | } | ||
723 | |||
724 | static const struct ath6kl_hif_ops ath6kl_sdio_ops = { | ||
725 | .read_write_sync = ath6kl_sdio_read_write_sync, | ||
726 | .write_async = ath6kl_sdio_write_async, | ||
727 | .irq_enable = ath6kl_sdio_irq_enable, | ||
728 | .irq_disable = ath6kl_sdio_irq_disable, | ||
729 | .scatter_req_get = ath6kl_sdio_scatter_req_get, | ||
730 | .scatter_req_add = ath6kl_sdio_scatter_req_add, | ||
731 | .enable_scatter = ath6kl_sdio_enable_scatter, | ||
732 | .scat_req_rw = ath6kl_sdio_async_rw_scatter, | ||
733 | .cleanup_scatter = ath6kl_sdio_cleanup_scatter, | ||
734 | }; | ||
735 | |||
736 | static int ath6kl_sdio_probe(struct sdio_func *func, | ||
737 | const struct sdio_device_id *id) | ||
738 | { | ||
739 | int ret; | ||
740 | struct ath6kl_sdio *ar_sdio; | ||
741 | struct ath6kl *ar; | ||
742 | int count; | ||
743 | |||
744 | ath6kl_dbg(ATH6KL_DBG_TRC, | ||
745 | "%s: func: 0x%X, vendor id: 0x%X, dev id: 0x%X, block size: 0x%X/0x%X\n", | ||
746 | __func__, func->num, func->vendor, | ||
747 | func->device, func->max_blksize, func->cur_blksize); | ||
748 | |||
749 | ar_sdio = kzalloc(sizeof(struct ath6kl_sdio), GFP_KERNEL); | ||
750 | if (!ar_sdio) | ||
751 | return -ENOMEM; | ||
752 | |||
753 | ar_sdio->dma_buffer = kzalloc(HIF_DMA_BUFFER_SIZE, GFP_KERNEL); | ||
754 | if (!ar_sdio->dma_buffer) { | ||
755 | ret = -ENOMEM; | ||
756 | goto err_hif; | ||
757 | } | ||
758 | |||
759 | ar_sdio->func = func; | ||
760 | sdio_set_drvdata(func, ar_sdio); | ||
761 | |||
762 | ar_sdio->id = id; | ||
763 | ar_sdio->is_disabled = true; | ||
764 | |||
765 | spin_lock_init(&ar_sdio->lock); | ||
766 | spin_lock_init(&ar_sdio->scat_lock); | ||
767 | spin_lock_init(&ar_sdio->wr_async_lock); | ||
768 | |||
769 | INIT_LIST_HEAD(&ar_sdio->scat_req); | ||
770 | INIT_LIST_HEAD(&ar_sdio->bus_req_freeq); | ||
771 | INIT_LIST_HEAD(&ar_sdio->wr_asyncq); | ||
772 | |||
773 | INIT_WORK(&ar_sdio->wr_async_work, ath6kl_sdio_write_async_work); | ||
774 | |||
775 | for (count = 0; count < BUS_REQUEST_MAX_NUM; count++) | ||
776 | ath6kl_sdio_free_bus_req(ar_sdio, &ar_sdio->bus_req[count]); | ||
777 | |||
778 | ar = ath6kl_core_alloc(&ar_sdio->func->dev); | ||
779 | if (!ar) { | ||
780 | ath6kl_err("Failed to alloc ath6kl core\n"); | ||
781 | ret = -ENOMEM; | ||
782 | goto err_dma; | ||
783 | } | ||
784 | |||
785 | ar_sdio->ar = ar; | ||
786 | ar->hif_priv = ar_sdio; | ||
787 | ar->hif_ops = &ath6kl_sdio_ops; | ||
788 | |||
789 | ath6kl_sdio_set_mbox_info(ar); | ||
790 | |||
791 | sdio_claim_host(func); | ||
792 | |||
793 | if ((ar_sdio->id->device & MANUFACTURER_ID_ATH6KL_BASE_MASK) >= | ||
794 | MANUFACTURER_ID_AR6003_BASE) { | ||
795 | /* enable 4-bit ASYNC interrupt on AR6003 or later */ | ||
796 | ret = ath6kl_sdio_func0_cmd52_wr_byte(func->card, | ||
797 | CCCR_SDIO_IRQ_MODE_REG, | ||
798 | SDIO_IRQ_MODE_ASYNC_4BIT_IRQ); | ||
799 | if (ret) { | ||
800 | ath6kl_err("Failed to enable 4-bit async irq mode %d\n", | ||
801 | ret); | ||
802 | sdio_release_host(func); | ||
803 | goto err_dma; | ||
804 | } | ||
805 | |||
806 | ath6kl_dbg(ATH6KL_DBG_TRC, "4-bit async irq mode enabled\n"); | ||
807 | } | ||
808 | |||
809 | /* give us some time to enable, in ms */ | ||
810 | func->enable_timeout = 100; | ||
811 | |||
812 | sdio_release_host(func); | ||
813 | |||
814 | ret = ath6kl_sdio_power_on(ar_sdio); | ||
815 | if (ret) | ||
816 | goto err_dma; | ||
817 | |||
818 | sdio_claim_host(func); | ||
819 | |||
820 | ret = sdio_set_block_size(func, HIF_MBOX_BLOCK_SIZE); | ||
821 | if (ret) { | ||
822 | ath6kl_err("Set sdio block size %d failed: %d)\n", | ||
823 | HIF_MBOX_BLOCK_SIZE, ret); | ||
824 | sdio_release_host(func); | ||
825 | goto err_off; | ||
826 | } | ||
827 | |||
828 | sdio_release_host(func); | ||
829 | |||
830 | ret = ath6kl_core_init(ar); | ||
831 | if (ret) { | ||
832 | ath6kl_err("Failed to init ath6kl core\n"); | ||
833 | goto err_off; | ||
834 | } | ||
835 | |||
836 | return ret; | ||
837 | |||
838 | err_off: | ||
839 | ath6kl_sdio_power_off(ar_sdio); | ||
840 | err_dma: | ||
841 | kfree(ar_sdio->dma_buffer); | ||
842 | err_hif: | ||
843 | kfree(ar_sdio); | ||
844 | |||
845 | return ret; | ||
846 | } | ||
847 | |||
848 | static void ath6kl_sdio_remove(struct sdio_func *func) | ||
849 | { | ||
850 | struct ath6kl_sdio *ar_sdio; | ||
851 | |||
852 | ar_sdio = sdio_get_drvdata(func); | ||
853 | |||
854 | ath6kl_stop_txrx(ar_sdio->ar); | ||
855 | cancel_work_sync(&ar_sdio->wr_async_work); | ||
856 | |||
857 | ath6kl_unavail_ev(ar_sdio->ar); | ||
858 | |||
859 | ath6kl_sdio_power_off(ar_sdio); | ||
860 | |||
861 | kfree(ar_sdio->dma_buffer); | ||
862 | kfree(ar_sdio); | ||
863 | } | ||
864 | |||
865 | static const struct sdio_device_id ath6kl_sdio_devices[] = { | ||
866 | {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x0))}, | ||
867 | {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x1))}, | ||
868 | {}, | ||
869 | }; | ||
870 | |||
871 | MODULE_DEVICE_TABLE(sdio, ath6kl_sdio_devices); | ||
872 | |||
873 | static struct sdio_driver ath6kl_sdio_driver = { | ||
874 | .name = "ath6kl_sdio", | ||
875 | .id_table = ath6kl_sdio_devices, | ||
876 | .probe = ath6kl_sdio_probe, | ||
877 | .remove = ath6kl_sdio_remove, | ||
878 | }; | ||
879 | |||
880 | static int __init ath6kl_sdio_init(void) | ||
881 | { | ||
882 | int ret; | ||
883 | |||
884 | ret = sdio_register_driver(&ath6kl_sdio_driver); | ||
885 | if (ret) | ||
886 | ath6kl_err("sdio driver registration failed: %d\n", ret); | ||
887 | |||
888 | return ret; | ||
889 | } | ||
890 | |||
891 | static void __exit ath6kl_sdio_exit(void) | ||
892 | { | ||
893 | sdio_unregister_driver(&ath6kl_sdio_driver); | ||
894 | } | ||
895 | |||
896 | module_init(ath6kl_sdio_init); | ||
897 | module_exit(ath6kl_sdio_exit); | ||
898 | |||
899 | MODULE_AUTHOR("Atheros Communications, Inc."); | ||
900 | MODULE_DESCRIPTION("Driver support for Atheros AR600x SDIO devices"); | ||
901 | MODULE_LICENSE("Dual BSD/GPL"); | ||
902 | |||
903 | MODULE_FIRMWARE(AR6003_REV2_OTP_FILE); | ||
904 | MODULE_FIRMWARE(AR6003_REV2_FIRMWARE_FILE); | ||
905 | MODULE_FIRMWARE(AR6003_REV2_PATCH_FILE); | ||
906 | MODULE_FIRMWARE(AR6003_REV2_BOARD_DATA_FILE); | ||
907 | MODULE_FIRMWARE(AR6003_REV2_DEFAULT_BOARD_DATA_FILE); | ||
908 | MODULE_FIRMWARE(AR6003_REV3_OTP_FILE); | ||
909 | MODULE_FIRMWARE(AR6003_REV3_FIRMWARE_FILE); | ||
910 | MODULE_FIRMWARE(AR6003_REV3_PATCH_FILE); | ||
911 | MODULE_FIRMWARE(AR6003_REV3_BOARD_DATA_FILE); | ||
912 | MODULE_FIRMWARE(AR6003_REV3_DEFAULT_BOARD_DATA_FILE); | ||
diff --git a/drivers/net/wireless/ath/ath6kl/target.h b/drivers/net/wireless/ath/ath6kl/target.h new file mode 100644 index 000000000000..519a013c9991 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/target.h | |||
@@ -0,0 +1,331 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004-2010 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 | #ifndef TARGET_H | ||
18 | #define TARGET_H | ||
19 | |||
20 | #define AR6003_BOARD_DATA_SZ 1024 | ||
21 | #define AR6003_BOARD_EXT_DATA_SZ 768 | ||
22 | |||
23 | #define RESET_CONTROL_ADDRESS 0x00000000 | ||
24 | #define RESET_CONTROL_COLD_RST 0x00000100 | ||
25 | #define RESET_CONTROL_MBOX_RST 0x00000004 | ||
26 | |||
27 | #define CPU_CLOCK_STANDARD_S 0 | ||
28 | #define CPU_CLOCK_STANDARD 0x00000003 | ||
29 | #define CPU_CLOCK_ADDRESS 0x00000020 | ||
30 | |||
31 | #define CLOCK_CONTROL_ADDRESS 0x00000028 | ||
32 | #define CLOCK_CONTROL_LF_CLK32_S 2 | ||
33 | #define CLOCK_CONTROL_LF_CLK32 0x00000004 | ||
34 | |||
35 | #define SYSTEM_SLEEP_ADDRESS 0x000000c4 | ||
36 | #define SYSTEM_SLEEP_DISABLE_S 0 | ||
37 | #define SYSTEM_SLEEP_DISABLE 0x00000001 | ||
38 | |||
39 | #define LPO_CAL_ADDRESS 0x000000e0 | ||
40 | #define LPO_CAL_ENABLE_S 20 | ||
41 | #define LPO_CAL_ENABLE 0x00100000 | ||
42 | |||
43 | #define GPIO_PIN10_ADDRESS 0x00000050 | ||
44 | #define GPIO_PIN11_ADDRESS 0x00000054 | ||
45 | #define GPIO_PIN12_ADDRESS 0x00000058 | ||
46 | #define GPIO_PIN13_ADDRESS 0x0000005c | ||
47 | |||
48 | #define HOST_INT_STATUS_ADDRESS 0x00000400 | ||
49 | #define HOST_INT_STATUS_ERROR_S 7 | ||
50 | #define HOST_INT_STATUS_ERROR 0x00000080 | ||
51 | |||
52 | #define HOST_INT_STATUS_CPU_S 6 | ||
53 | #define HOST_INT_STATUS_CPU 0x00000040 | ||
54 | |||
55 | #define HOST_INT_STATUS_COUNTER_S 4 | ||
56 | #define HOST_INT_STATUS_COUNTER 0x00000010 | ||
57 | |||
58 | #define CPU_INT_STATUS_ADDRESS 0x00000401 | ||
59 | |||
60 | #define ERROR_INT_STATUS_ADDRESS 0x00000402 | ||
61 | #define ERROR_INT_STATUS_WAKEUP_S 2 | ||
62 | #define ERROR_INT_STATUS_WAKEUP 0x00000004 | ||
63 | |||
64 | #define ERROR_INT_STATUS_RX_UNDERFLOW_S 1 | ||
65 | #define ERROR_INT_STATUS_RX_UNDERFLOW 0x00000002 | ||
66 | |||
67 | #define ERROR_INT_STATUS_TX_OVERFLOW_S 0 | ||
68 | #define ERROR_INT_STATUS_TX_OVERFLOW 0x00000001 | ||
69 | |||
70 | #define COUNTER_INT_STATUS_ADDRESS 0x00000403 | ||
71 | #define COUNTER_INT_STATUS_COUNTER_S 0 | ||
72 | #define COUNTER_INT_STATUS_COUNTER 0x000000ff | ||
73 | |||
74 | #define RX_LOOKAHEAD_VALID_ADDRESS 0x00000405 | ||
75 | |||
76 | #define INT_STATUS_ENABLE_ADDRESS 0x00000418 | ||
77 | #define INT_STATUS_ENABLE_ERROR_S 7 | ||
78 | #define INT_STATUS_ENABLE_ERROR 0x00000080 | ||
79 | |||
80 | #define INT_STATUS_ENABLE_CPU_S 6 | ||
81 | #define INT_STATUS_ENABLE_CPU 0x00000040 | ||
82 | |||
83 | #define INT_STATUS_ENABLE_INT_S 5 | ||
84 | #define INT_STATUS_ENABLE_INT 0x00000020 | ||
85 | #define INT_STATUS_ENABLE_COUNTER_S 4 | ||
86 | #define INT_STATUS_ENABLE_COUNTER 0x00000010 | ||
87 | |||
88 | #define INT_STATUS_ENABLE_MBOX_DATA_S 0 | ||
89 | #define INT_STATUS_ENABLE_MBOX_DATA 0x0000000f | ||
90 | |||
91 | #define CPU_INT_STATUS_ENABLE_ADDRESS 0x00000419 | ||
92 | #define CPU_INT_STATUS_ENABLE_BIT_S 0 | ||
93 | #define CPU_INT_STATUS_ENABLE_BIT 0x000000ff | ||
94 | |||
95 | #define ERROR_STATUS_ENABLE_ADDRESS 0x0000041a | ||
96 | #define ERROR_STATUS_ENABLE_RX_UNDERFLOW_S 1 | ||
97 | #define ERROR_STATUS_ENABLE_RX_UNDERFLOW 0x00000002 | ||
98 | |||
99 | #define ERROR_STATUS_ENABLE_TX_OVERFLOW_S 0 | ||
100 | #define ERROR_STATUS_ENABLE_TX_OVERFLOW 0x00000001 | ||
101 | |||
102 | #define COUNTER_INT_STATUS_ENABLE_ADDRESS 0x0000041b | ||
103 | #define COUNTER_INT_STATUS_ENABLE_BIT_S 0 | ||
104 | #define COUNTER_INT_STATUS_ENABLE_BIT 0x000000ff | ||
105 | |||
106 | #define COUNT_ADDRESS 0x00000420 | ||
107 | |||
108 | #define COUNT_DEC_ADDRESS 0x00000440 | ||
109 | |||
110 | #define WINDOW_DATA_ADDRESS 0x00000474 | ||
111 | #define WINDOW_WRITE_ADDR_ADDRESS 0x00000478 | ||
112 | #define WINDOW_READ_ADDR_ADDRESS 0x0000047c | ||
113 | #define CPU_DBG_SEL_ADDRESS 0x00000483 | ||
114 | #define CPU_DBG_ADDRESS 0x00000484 | ||
115 | |||
116 | #define LOCAL_SCRATCH_ADDRESS 0x000000c0 | ||
117 | #define ATH6KL_OPTION_SLEEP_DISABLE 0x08 | ||
118 | |||
119 | #define RTC_BASE_ADDRESS 0x00004000 | ||
120 | #define GPIO_BASE_ADDRESS 0x00014000 | ||
121 | #define MBOX_BASE_ADDRESS 0x00018000 | ||
122 | #define ANALOG_INTF_BASE_ADDRESS 0x0001c000 | ||
123 | |||
124 | /* real name of the register is unknown */ | ||
125 | #define ATH6KL_ANALOG_PLL_REGISTER (ANALOG_INTF_BASE_ADDRESS + 0x284) | ||
126 | |||
127 | #define SM(f, v) (((v) << f##_S) & f) | ||
128 | #define MS(f, v) (((v) & f) >> f##_S) | ||
129 | |||
130 | /* | ||
131 | * xxx_HOST_INTEREST_ADDRESS is the address in Target RAM of the | ||
132 | * host_interest structure. | ||
133 | * | ||
134 | * Host Interest is shared between Host and Target in order to coordinate | ||
135 | * between the two, and is intended to remain constant (with additions only | ||
136 | * at the end). | ||
137 | */ | ||
138 | #define ATH6KL_HI_START_ADDR 0x00540600 | ||
139 | |||
140 | /* | ||
141 | * These are items that the Host may need to access | ||
142 | * via BMI or via the Diagnostic Window. The position | ||
143 | * of items in this structure must remain constant. | ||
144 | * across firmware revisions! | ||
145 | * | ||
146 | * Types for each item must be fixed size across target and host platforms. | ||
147 | * The structure is used only to calculate offset for each register with | ||
148 | * HI_ITEM() macro, no values are stored to it. | ||
149 | * | ||
150 | * More items may be added at the end. | ||
151 | */ | ||
152 | struct host_interest { | ||
153 | /* | ||
154 | * Pointer to application-defined area, if any. | ||
155 | * Set by Target application during startup. | ||
156 | */ | ||
157 | u32 hi_app_host_interest; /* 0x00 */ | ||
158 | |||
159 | /* Pointer to register dump area, valid after Target crash. */ | ||
160 | u32 hi_failure_state; /* 0x04 */ | ||
161 | |||
162 | /* Pointer to debug logging header */ | ||
163 | u32 hi_dbglog_hdr; /* 0x08 */ | ||
164 | |||
165 | u32 hi_unused1; /* 0x0c */ | ||
166 | |||
167 | /* | ||
168 | * General-purpose flag bits, similar to ATH6KL_OPTION_* flags. | ||
169 | * Can be used by application rather than by OS. | ||
170 | */ | ||
171 | u32 hi_option_flag; /* 0x10 */ | ||
172 | |||
173 | /* | ||
174 | * Boolean that determines whether or not to | ||
175 | * display messages on the serial port. | ||
176 | */ | ||
177 | u32 hi_serial_enable; /* 0x14 */ | ||
178 | |||
179 | /* Start address of DataSet index, if any */ | ||
180 | u32 hi_dset_list_head; /* 0x18 */ | ||
181 | |||
182 | /* Override Target application start address */ | ||
183 | u32 hi_app_start; /* 0x1c */ | ||
184 | |||
185 | /* Clock and voltage tuning */ | ||
186 | u32 hi_skip_clock_init; /* 0x20 */ | ||
187 | u32 hi_core_clock_setting; /* 0x24 */ | ||
188 | u32 hi_cpu_clock_setting; /* 0x28 */ | ||
189 | u32 hi_system_sleep_setting; /* 0x2c */ | ||
190 | u32 hi_xtal_control_setting; /* 0x30 */ | ||
191 | u32 hi_pll_ctrl_setting_24ghz; /* 0x34 */ | ||
192 | u32 hi_pll_ctrl_setting_5ghz; /* 0x38 */ | ||
193 | u32 hi_ref_voltage_trim_setting; /* 0x3c */ | ||
194 | u32 hi_clock_info; /* 0x40 */ | ||
195 | |||
196 | /* | ||
197 | * Flash configuration overrides, used only | ||
198 | * when firmware is not executing from flash. | ||
199 | * (When using flash, modify the global variables | ||
200 | * with equivalent names.) | ||
201 | */ | ||
202 | u32 hi_bank0_addr_value; /* 0x44 */ | ||
203 | u32 hi_bank0_read_value; /* 0x48 */ | ||
204 | u32 hi_bank0_write_value; /* 0x4c */ | ||
205 | u32 hi_bank0_config_value; /* 0x50 */ | ||
206 | |||
207 | /* Pointer to Board Data */ | ||
208 | u32 hi_board_data; /* 0x54 */ | ||
209 | u32 hi_board_data_initialized; /* 0x58 */ | ||
210 | |||
211 | u32 hi_dset_ram_index_tbl; /* 0x5c */ | ||
212 | |||
213 | u32 hi_desired_baud_rate; /* 0x60 */ | ||
214 | u32 hi_dbglog_config; /* 0x64 */ | ||
215 | u32 hi_end_ram_reserve_sz; /* 0x68 */ | ||
216 | u32 hi_mbox_io_block_sz; /* 0x6c */ | ||
217 | |||
218 | u32 hi_num_bpatch_streams; /* 0x70 -- unused */ | ||
219 | u32 hi_mbox_isr_yield_limit; /* 0x74 */ | ||
220 | |||
221 | u32 hi_refclk_hz; /* 0x78 */ | ||
222 | u32 hi_ext_clk_detected; /* 0x7c */ | ||
223 | u32 hi_dbg_uart_txpin; /* 0x80 */ | ||
224 | u32 hi_dbg_uart_rxpin; /* 0x84 */ | ||
225 | u32 hi_hci_uart_baud; /* 0x88 */ | ||
226 | u32 hi_hci_uart_pin_assignments; /* 0x8C */ | ||
227 | /* | ||
228 | * NOTE: byte [0] = tx pin, [1] = rx pin, [2] = rts pin, [3] = cts | ||
229 | * pin | ||
230 | */ | ||
231 | u32 hi_hci_uart_baud_scale_val; /* 0x90 */ | ||
232 | u32 hi_hci_uart_baud_step_val; /* 0x94 */ | ||
233 | |||
234 | u32 hi_allocram_start; /* 0x98 */ | ||
235 | u32 hi_allocram_sz; /* 0x9c */ | ||
236 | u32 hi_hci_bridge_flags; /* 0xa0 */ | ||
237 | u32 hi_hci_uart_support_pins; /* 0xa4 */ | ||
238 | /* | ||
239 | * NOTE: byte [0] = RESET pin (bit 7 is polarity), | ||
240 | * bytes[1]..bytes[3] are for future use | ||
241 | */ | ||
242 | u32 hi_hci_uart_pwr_mgmt_params; /* 0xa8 */ | ||
243 | /* | ||
244 | * 0xa8 - [1]: 0 = UART FC active low, 1 = UART FC active high | ||
245 | * [31:16]: wakeup timeout in ms | ||
246 | */ | ||
247 | |||
248 | /* Pointer to extended board data */ | ||
249 | u32 hi_board_ext_data; /* 0xac */ | ||
250 | u32 hi_board_ext_data_config; /* 0xb0 */ | ||
251 | |||
252 | /* | ||
253 | * Bit [0] : valid | ||
254 | * Bit[31:16: size | ||
255 | */ | ||
256 | /* | ||
257 | * hi_reset_flag is used to do some stuff when target reset. | ||
258 | * such as restore app_start after warm reset or | ||
259 | * preserve host Interest area, or preserve ROM data, literals etc. | ||
260 | */ | ||
261 | u32 hi_reset_flag; /* 0xb4 */ | ||
262 | /* indicate hi_reset_flag is valid */ | ||
263 | u32 hi_reset_flag_valid; /* 0xb8 */ | ||
264 | u32 hi_hci_uart_pwr_mgmt_params_ext; /* 0xbc */ | ||
265 | /* | ||
266 | * 0xbc - [31:0]: idle timeout in ms | ||
267 | */ | ||
268 | /* ACS flags */ | ||
269 | u32 hi_acs_flags; /* 0xc0 */ | ||
270 | u32 hi_console_flags; /* 0xc4 */ | ||
271 | u32 hi_nvram_state; /* 0xc8 */ | ||
272 | u32 hi_option_flag2; /* 0xcc */ | ||
273 | |||
274 | /* If non-zero, override values sent to Host in WMI_READY event. */ | ||
275 | u32 hi_sw_version_override; /* 0xd0 */ | ||
276 | u32 hi_abi_version_override; /* 0xd4 */ | ||
277 | |||
278 | /* | ||
279 | * Percentage of high priority RX traffic to total expected RX traffic - | ||
280 | * applicable only to ar6004 | ||
281 | */ | ||
282 | u32 hi_hp_rx_traffic_ratio; /* 0xd8 */ | ||
283 | |||
284 | /* test applications flags */ | ||
285 | u32 hi_test_apps_related ; /* 0xdc */ | ||
286 | /* location of test script */ | ||
287 | u32 hi_ota_testscript; /* 0xe0 */ | ||
288 | /* location of CAL data */ | ||
289 | u32 hi_cal_data; /* 0xe4 */ | ||
290 | /* Number of packet log buffers */ | ||
291 | u32 hi_pktlog_num_buffers; /* 0xe8 */ | ||
292 | |||
293 | } __packed; | ||
294 | |||
295 | #define HI_ITEM(item) offsetof(struct host_interest, item) | ||
296 | |||
297 | #define HI_OPTION_MAC_ADDR_METHOD_SHIFT 3 | ||
298 | |||
299 | #define HI_OPTION_FW_MODE_IBSS 0x0 | ||
300 | #define HI_OPTION_FW_MODE_BSS_STA 0x1 | ||
301 | #define HI_OPTION_FW_MODE_AP 0x2 | ||
302 | |||
303 | #define HI_OPTION_NUM_DEV_SHIFT 0x9 | ||
304 | |||
305 | #define HI_OPTION_FW_BRIDGE_SHIFT 0x04 | ||
306 | |||
307 | /* Fw Mode/SubMode Mask | ||
308 | |------------------------------------------------------------------------------| | ||
309 | | SUB | SUB | SUB | SUB | | | | | ||
310 | | MODE[3] | MODE[2] | MODE[1] | MODE[0] | MODE[3] | MODE[2] | MODE[1] | MODE[0| | ||
311 | | (2) | (2) | (2) | (2) | (2) | (2) | (2) | (2) | ||
312 | |------------------------------------------------------------------------------| | ||
313 | */ | ||
314 | #define HI_OPTION_FW_MODE_SHIFT 0xC | ||
315 | |||
316 | /* Convert a Target virtual address into a Target physical address */ | ||
317 | #define TARG_VTOP(vaddr) (vaddr & 0x001fffff) | ||
318 | |||
319 | #define AR6003_REV2_APP_START_OVERRIDE 0x944C00 | ||
320 | #define AR6003_REV2_APP_LOAD_ADDRESS 0x543180 | ||
321 | #define AR6003_REV2_BOARD_EXT_DATA_ADDRESS 0x57E500 | ||
322 | #define AR6003_REV2_DATASET_PATCH_ADDRESS 0x57e884 | ||
323 | #define AR6003_REV2_RAM_RESERVE_SIZE 6912 | ||
324 | |||
325 | #define AR6003_REV3_APP_START_OVERRIDE 0x945d00 | ||
326 | #define AR6003_REV3_APP_LOAD_ADDRESS 0x545000 | ||
327 | #define AR6003_REV3_BOARD_EXT_DATA_ADDRESS 0x542330 | ||
328 | #define AR6003_REV3_DATASET_PATCH_ADDRESS 0x57FF74 | ||
329 | #define AR6003_REV3_RAM_RESERVE_SIZE 512 | ||
330 | |||
331 | #endif | ||
diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c new file mode 100644 index 000000000000..167bdb9cf68d --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/txrx.c | |||
@@ -0,0 +1,1457 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004-2011 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 "core.h" | ||
18 | #include "debug.h" | ||
19 | |||
20 | static u8 ath6kl_ibss_map_epid(struct sk_buff *skb, struct net_device *dev, | ||
21 | u32 *map_no) | ||
22 | { | ||
23 | struct ath6kl *ar = ath6kl_priv(dev); | ||
24 | struct ethhdr *eth_hdr; | ||
25 | u32 i, ep_map = -1; | ||
26 | u8 *datap; | ||
27 | |||
28 | *map_no = 0; | ||
29 | datap = skb->data; | ||
30 | eth_hdr = (struct ethhdr *) (datap + sizeof(struct wmi_data_hdr)); | ||
31 | |||
32 | if (is_multicast_ether_addr(eth_hdr->h_dest)) | ||
33 | return ENDPOINT_2; | ||
34 | |||
35 | for (i = 0; i < ar->node_num; i++) { | ||
36 | if (memcmp(eth_hdr->h_dest, ar->node_map[i].mac_addr, | ||
37 | ETH_ALEN) == 0) { | ||
38 | *map_no = i + 1; | ||
39 | ar->node_map[i].tx_pend++; | ||
40 | return ar->node_map[i].ep_id; | ||
41 | } | ||
42 | |||
43 | if ((ep_map == -1) && !ar->node_map[i].tx_pend) | ||
44 | ep_map = i; | ||
45 | } | ||
46 | |||
47 | if (ep_map == -1) { | ||
48 | ep_map = ar->node_num; | ||
49 | ar->node_num++; | ||
50 | if (ar->node_num > MAX_NODE_NUM) | ||
51 | return ENDPOINT_UNUSED; | ||
52 | } | ||
53 | |||
54 | memcpy(ar->node_map[ep_map].mac_addr, eth_hdr->h_dest, ETH_ALEN); | ||
55 | |||
56 | for (i = ENDPOINT_2; i <= ENDPOINT_5; i++) { | ||
57 | if (!ar->tx_pending[i]) { | ||
58 | ar->node_map[ep_map].ep_id = i; | ||
59 | break; | ||
60 | } | ||
61 | |||
62 | /* | ||
63 | * No free endpoint is available, start redistribution on | ||
64 | * the inuse endpoints. | ||
65 | */ | ||
66 | if (i == ENDPOINT_5) { | ||
67 | ar->node_map[ep_map].ep_id = ar->next_ep_id; | ||
68 | ar->next_ep_id++; | ||
69 | if (ar->next_ep_id > ENDPOINT_5) | ||
70 | ar->next_ep_id = ENDPOINT_2; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | *map_no = ep_map + 1; | ||
75 | ar->node_map[ep_map].tx_pend++; | ||
76 | |||
77 | return ar->node_map[ep_map].ep_id; | ||
78 | } | ||
79 | |||
80 | static bool ath6kl_powersave_ap(struct ath6kl *ar, struct sk_buff *skb, | ||
81 | bool *more_data) | ||
82 | { | ||
83 | struct ethhdr *datap = (struct ethhdr *) skb->data; | ||
84 | struct ath6kl_sta *conn = NULL; | ||
85 | bool ps_queued = false, is_psq_empty = false; | ||
86 | |||
87 | if (is_multicast_ether_addr(datap->h_dest)) { | ||
88 | u8 ctr = 0; | ||
89 | bool q_mcast = false; | ||
90 | |||
91 | for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) { | ||
92 | if (ar->sta_list[ctr].sta_flags & STA_PS_SLEEP) { | ||
93 | q_mcast = true; | ||
94 | break; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | if (q_mcast) { | ||
99 | /* | ||
100 | * If this transmit is not because of a Dtim Expiry | ||
101 | * q it. | ||
102 | */ | ||
103 | if (!test_bit(DTIM_EXPIRED, &ar->flag)) { | ||
104 | bool is_mcastq_empty = false; | ||
105 | |||
106 | spin_lock_bh(&ar->mcastpsq_lock); | ||
107 | is_mcastq_empty = | ||
108 | skb_queue_empty(&ar->mcastpsq); | ||
109 | skb_queue_tail(&ar->mcastpsq, skb); | ||
110 | spin_unlock_bh(&ar->mcastpsq_lock); | ||
111 | |||
112 | /* | ||
113 | * If this is the first Mcast pkt getting | ||
114 | * queued indicate to the target to set the | ||
115 | * BitmapControl LSB of the TIM IE. | ||
116 | */ | ||
117 | if (is_mcastq_empty) | ||
118 | ath6kl_wmi_set_pvb_cmd(ar->wmi, | ||
119 | MCAST_AID, 1); | ||
120 | |||
121 | ps_queued = true; | ||
122 | } else { | ||
123 | /* | ||
124 | * This transmit is because of Dtim expiry. | ||
125 | * Determine if MoreData bit has to be set. | ||
126 | */ | ||
127 | spin_lock_bh(&ar->mcastpsq_lock); | ||
128 | if (!skb_queue_empty(&ar->mcastpsq)) | ||
129 | *more_data = true; | ||
130 | spin_unlock_bh(&ar->mcastpsq_lock); | ||
131 | } | ||
132 | } | ||
133 | } else { | ||
134 | conn = ath6kl_find_sta(ar, datap->h_dest); | ||
135 | if (!conn) { | ||
136 | dev_kfree_skb(skb); | ||
137 | |||
138 | /* Inform the caller that the skb is consumed */ | ||
139 | return true; | ||
140 | } | ||
141 | |||
142 | if (conn->sta_flags & STA_PS_SLEEP) { | ||
143 | if (!(conn->sta_flags & STA_PS_POLLED)) { | ||
144 | /* Queue the frames if the STA is sleeping */ | ||
145 | spin_lock_bh(&conn->psq_lock); | ||
146 | is_psq_empty = skb_queue_empty(&conn->psq); | ||
147 | skb_queue_tail(&conn->psq, skb); | ||
148 | spin_unlock_bh(&conn->psq_lock); | ||
149 | |||
150 | /* | ||
151 | * If this is the first pkt getting queued | ||
152 | * for this STA, update the PVB for this | ||
153 | * STA. | ||
154 | */ | ||
155 | if (is_psq_empty) | ||
156 | ath6kl_wmi_set_pvb_cmd(ar->wmi, | ||
157 | conn->aid, 1); | ||
158 | |||
159 | ps_queued = true; | ||
160 | } else { | ||
161 | /* | ||
162 | * This tx is because of a PsPoll. | ||
163 | * Determine if MoreData bit has to be set. | ||
164 | */ | ||
165 | spin_lock_bh(&conn->psq_lock); | ||
166 | if (!skb_queue_empty(&conn->psq)) | ||
167 | *more_data = true; | ||
168 | spin_unlock_bh(&conn->psq_lock); | ||
169 | } | ||
170 | } | ||
171 | } | ||
172 | |||
173 | return ps_queued; | ||
174 | } | ||
175 | |||
176 | /* Tx functions */ | ||
177 | |||
178 | int ath6kl_control_tx(void *devt, struct sk_buff *skb, | ||
179 | enum htc_endpoint_id eid) | ||
180 | { | ||
181 | struct ath6kl *ar = devt; | ||
182 | int status = 0; | ||
183 | struct ath6kl_cookie *cookie = NULL; | ||
184 | |||
185 | spin_lock_bh(&ar->lock); | ||
186 | |||
187 | ath6kl_dbg(ATH6KL_DBG_WLAN_TX, | ||
188 | "%s: skb=0x%p, len=0x%x eid =%d\n", __func__, | ||
189 | skb, skb->len, eid); | ||
190 | |||
191 | if (test_bit(WMI_CTRL_EP_FULL, &ar->flag) && (eid == ar->ctrl_ep)) { | ||
192 | /* | ||
193 | * Control endpoint is full, don't allocate resources, we | ||
194 | * are just going to drop this packet. | ||
195 | */ | ||
196 | cookie = NULL; | ||
197 | ath6kl_err("wmi ctrl ep full, dropping pkt : 0x%p, len:%d\n", | ||
198 | skb, skb->len); | ||
199 | } else | ||
200 | cookie = ath6kl_alloc_cookie(ar); | ||
201 | |||
202 | if (cookie == NULL) { | ||
203 | spin_unlock_bh(&ar->lock); | ||
204 | status = -ENOMEM; | ||
205 | goto fail_ctrl_tx; | ||
206 | } | ||
207 | |||
208 | ar->tx_pending[eid]++; | ||
209 | |||
210 | if (eid != ar->ctrl_ep) | ||
211 | ar->total_tx_data_pend++; | ||
212 | |||
213 | spin_unlock_bh(&ar->lock); | ||
214 | |||
215 | cookie->skb = skb; | ||
216 | cookie->map_no = 0; | ||
217 | set_htc_pkt_info(&cookie->htc_pkt, cookie, skb->data, skb->len, | ||
218 | eid, ATH6KL_CONTROL_PKT_TAG); | ||
219 | |||
220 | /* | ||
221 | * This interface is asynchronous, if there is an error, cleanup | ||
222 | * will happen in the TX completion callback. | ||
223 | */ | ||
224 | ath6kl_htc_tx(ar->htc_target, &cookie->htc_pkt); | ||
225 | |||
226 | return 0; | ||
227 | |||
228 | fail_ctrl_tx: | ||
229 | dev_kfree_skb(skb); | ||
230 | return status; | ||
231 | } | ||
232 | |||
233 | int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) | ||
234 | { | ||
235 | struct ath6kl *ar = ath6kl_priv(dev); | ||
236 | struct ath6kl_cookie *cookie = NULL; | ||
237 | enum htc_endpoint_id eid = ENDPOINT_UNUSED; | ||
238 | u32 map_no = 0; | ||
239 | u16 htc_tag = ATH6KL_DATA_PKT_TAG; | ||
240 | u8 ac = 99 ; /* initialize to unmapped ac */ | ||
241 | bool chk_adhoc_ps_mapping = false, more_data = false; | ||
242 | struct wmi_tx_meta_v2 meta_v2; | ||
243 | int ret; | ||
244 | |||
245 | ath6kl_dbg(ATH6KL_DBG_WLAN_TX, | ||
246 | "%s: skb=0x%p, data=0x%p, len=0x%x\n", __func__, | ||
247 | skb, skb->data, skb->len); | ||
248 | |||
249 | /* If target is not associated */ | ||
250 | if (!test_bit(CONNECTED, &ar->flag)) { | ||
251 | dev_kfree_skb(skb); | ||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | if (!test_bit(WMI_READY, &ar->flag)) | ||
256 | goto fail_tx; | ||
257 | |||
258 | /* AP mode Power saving processing */ | ||
259 | if (ar->nw_type == AP_NETWORK) { | ||
260 | if (ath6kl_powersave_ap(ar, skb, &more_data)) | ||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | if (test_bit(WMI_ENABLED, &ar->flag)) { | ||
265 | memset(&meta_v2, 0, sizeof(meta_v2)); | ||
266 | |||
267 | if (skb_headroom(skb) < dev->needed_headroom) { | ||
268 | WARN_ON(1); | ||
269 | goto fail_tx; | ||
270 | } | ||
271 | |||
272 | if (ath6kl_wmi_dix_2_dot3(ar->wmi, skb)) { | ||
273 | ath6kl_err("ath6kl_wmi_dix_2_dot3 failed\n"); | ||
274 | goto fail_tx; | ||
275 | } | ||
276 | |||
277 | if (ath6kl_wmi_data_hdr_add(ar->wmi, skb, DATA_MSGTYPE, | ||
278 | more_data, 0, 0, NULL)) { | ||
279 | ath6kl_err("wmi_data_hdr_add failed\n"); | ||
280 | goto fail_tx; | ||
281 | } | ||
282 | |||
283 | if ((ar->nw_type == ADHOC_NETWORK) && | ||
284 | ar->ibss_ps_enable && test_bit(CONNECTED, &ar->flag)) | ||
285 | chk_adhoc_ps_mapping = true; | ||
286 | else { | ||
287 | /* get the stream mapping */ | ||
288 | ret = ath6kl_wmi_implicit_create_pstream(ar->wmi, skb, | ||
289 | 0, test_bit(WMM_ENABLED, &ar->flag), &ac); | ||
290 | if (ret) | ||
291 | goto fail_tx; | ||
292 | } | ||
293 | } else | ||
294 | goto fail_tx; | ||
295 | |||
296 | spin_lock_bh(&ar->lock); | ||
297 | |||
298 | if (chk_adhoc_ps_mapping) | ||
299 | eid = ath6kl_ibss_map_epid(skb, dev, &map_no); | ||
300 | else | ||
301 | eid = ar->ac2ep_map[ac]; | ||
302 | |||
303 | if (eid == 0 || eid == ENDPOINT_UNUSED) { | ||
304 | ath6kl_err("eid %d is not mapped!\n", eid); | ||
305 | spin_unlock_bh(&ar->lock); | ||
306 | goto fail_tx; | ||
307 | } | ||
308 | |||
309 | /* allocate resource for this packet */ | ||
310 | cookie = ath6kl_alloc_cookie(ar); | ||
311 | |||
312 | if (!cookie) { | ||
313 | spin_unlock_bh(&ar->lock); | ||
314 | goto fail_tx; | ||
315 | } | ||
316 | |||
317 | /* update counts while the lock is held */ | ||
318 | ar->tx_pending[eid]++; | ||
319 | ar->total_tx_data_pend++; | ||
320 | |||
321 | spin_unlock_bh(&ar->lock); | ||
322 | |||
323 | cookie->skb = skb; | ||
324 | cookie->map_no = map_no; | ||
325 | set_htc_pkt_info(&cookie->htc_pkt, cookie, skb->data, skb->len, | ||
326 | eid, htc_tag); | ||
327 | |||
328 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, skb->data, skb->len); | ||
329 | |||
330 | /* | ||
331 | * HTC interface is asynchronous, if this fails, cleanup will | ||
332 | * happen in the ath6kl_tx_complete callback. | ||
333 | */ | ||
334 | ath6kl_htc_tx(ar->htc_target, &cookie->htc_pkt); | ||
335 | |||
336 | return 0; | ||
337 | |||
338 | fail_tx: | ||
339 | dev_kfree_skb(skb); | ||
340 | |||
341 | ar->net_stats.tx_dropped++; | ||
342 | ar->net_stats.tx_aborted_errors++; | ||
343 | |||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | /* indicate tx activity or inactivity on a WMI stream */ | ||
348 | void ath6kl_indicate_tx_activity(void *devt, u8 traffic_class, bool active) | ||
349 | { | ||
350 | struct ath6kl *ar = devt; | ||
351 | enum htc_endpoint_id eid; | ||
352 | int i; | ||
353 | |||
354 | eid = ar->ac2ep_map[traffic_class]; | ||
355 | |||
356 | if (!test_bit(WMI_ENABLED, &ar->flag)) | ||
357 | goto notify_htc; | ||
358 | |||
359 | spin_lock_bh(&ar->lock); | ||
360 | |||
361 | ar->ac_stream_active[traffic_class] = active; | ||
362 | |||
363 | if (active) { | ||
364 | /* | ||
365 | * Keep track of the active stream with the highest | ||
366 | * priority. | ||
367 | */ | ||
368 | if (ar->ac_stream_pri_map[traffic_class] > | ||
369 | ar->hiac_stream_active_pri) | ||
370 | /* set the new highest active priority */ | ||
371 | ar->hiac_stream_active_pri = | ||
372 | ar->ac_stream_pri_map[traffic_class]; | ||
373 | |||
374 | } else { | ||
375 | /* | ||
376 | * We may have to search for the next active stream | ||
377 | * that is the highest priority. | ||
378 | */ | ||
379 | if (ar->hiac_stream_active_pri == | ||
380 | ar->ac_stream_pri_map[traffic_class]) { | ||
381 | /* | ||
382 | * The highest priority stream just went inactive | ||
383 | * reset and search for the "next" highest "active" | ||
384 | * priority stream. | ||
385 | */ | ||
386 | ar->hiac_stream_active_pri = 0; | ||
387 | |||
388 | for (i = 0; i < WMM_NUM_AC; i++) { | ||
389 | if (ar->ac_stream_active[i] && | ||
390 | (ar->ac_stream_pri_map[i] > | ||
391 | ar->hiac_stream_active_pri)) | ||
392 | /* | ||
393 | * Set the new highest active | ||
394 | * priority. | ||
395 | */ | ||
396 | ar->hiac_stream_active_pri = | ||
397 | ar->ac_stream_pri_map[i]; | ||
398 | } | ||
399 | } | ||
400 | } | ||
401 | |||
402 | spin_unlock_bh(&ar->lock); | ||
403 | |||
404 | notify_htc: | ||
405 | /* notify HTC, this may cause credit distribution changes */ | ||
406 | ath6kl_htc_indicate_activity_change(ar->htc_target, eid, active); | ||
407 | } | ||
408 | |||
409 | enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target, | ||
410 | struct htc_packet *packet) | ||
411 | { | ||
412 | struct ath6kl *ar = target->dev->ar; | ||
413 | enum htc_endpoint_id endpoint = packet->endpoint; | ||
414 | |||
415 | if (endpoint == ar->ctrl_ep) { | ||
416 | /* | ||
417 | * Under normal WMI if this is getting full, then something | ||
418 | * is running rampant the host should not be exhausting the | ||
419 | * WMI queue with too many commands the only exception to | ||
420 | * this is during testing using endpointping. | ||
421 | */ | ||
422 | spin_lock_bh(&ar->lock); | ||
423 | set_bit(WMI_CTRL_EP_FULL, &ar->flag); | ||
424 | spin_unlock_bh(&ar->lock); | ||
425 | ath6kl_err("wmi ctrl ep is full\n"); | ||
426 | return HTC_SEND_FULL_KEEP; | ||
427 | } | ||
428 | |||
429 | if (packet->info.tx.tag == ATH6KL_CONTROL_PKT_TAG) | ||
430 | return HTC_SEND_FULL_KEEP; | ||
431 | |||
432 | if (ar->nw_type == ADHOC_NETWORK) | ||
433 | /* | ||
434 | * In adhoc mode, we cannot differentiate traffic | ||
435 | * priorities so there is no need to continue, however we | ||
436 | * should stop the network. | ||
437 | */ | ||
438 | goto stop_net_queues; | ||
439 | |||
440 | /* | ||
441 | * The last MAX_HI_COOKIE_NUM "batch" of cookies are reserved for | ||
442 | * the highest active stream. | ||
443 | */ | ||
444 | if (ar->ac_stream_pri_map[ar->ep2ac_map[endpoint]] < | ||
445 | ar->hiac_stream_active_pri && | ||
446 | ar->cookie_count <= MAX_HI_COOKIE_NUM) | ||
447 | /* | ||
448 | * Give preference to the highest priority stream by | ||
449 | * dropping the packets which overflowed. | ||
450 | */ | ||
451 | return HTC_SEND_FULL_DROP; | ||
452 | |||
453 | stop_net_queues: | ||
454 | spin_lock_bh(&ar->lock); | ||
455 | set_bit(NETQ_STOPPED, &ar->flag); | ||
456 | spin_unlock_bh(&ar->lock); | ||
457 | netif_stop_queue(ar->net_dev); | ||
458 | |||
459 | return HTC_SEND_FULL_KEEP; | ||
460 | } | ||
461 | |||
462 | /* TODO this needs to be looked at */ | ||
463 | static void ath6kl_tx_clear_node_map(struct ath6kl *ar, | ||
464 | enum htc_endpoint_id eid, u32 map_no) | ||
465 | { | ||
466 | u32 i; | ||
467 | |||
468 | if (ar->nw_type != ADHOC_NETWORK) | ||
469 | return; | ||
470 | |||
471 | if (!ar->ibss_ps_enable) | ||
472 | return; | ||
473 | |||
474 | if (eid == ar->ctrl_ep) | ||
475 | return; | ||
476 | |||
477 | if (map_no == 0) | ||
478 | return; | ||
479 | |||
480 | map_no--; | ||
481 | ar->node_map[map_no].tx_pend--; | ||
482 | |||
483 | if (ar->node_map[map_no].tx_pend) | ||
484 | return; | ||
485 | |||
486 | if (map_no != (ar->node_num - 1)) | ||
487 | return; | ||
488 | |||
489 | for (i = ar->node_num; i > 0; i--) { | ||
490 | if (ar->node_map[i - 1].tx_pend) | ||
491 | break; | ||
492 | |||
493 | memset(&ar->node_map[i - 1], 0, | ||
494 | sizeof(struct ath6kl_node_mapping)); | ||
495 | ar->node_num--; | ||
496 | } | ||
497 | } | ||
498 | |||
499 | void ath6kl_tx_complete(void *context, struct list_head *packet_queue) | ||
500 | { | ||
501 | struct ath6kl *ar = context; | ||
502 | struct sk_buff_head skb_queue; | ||
503 | struct htc_packet *packet; | ||
504 | struct sk_buff *skb; | ||
505 | struct ath6kl_cookie *ath6kl_cookie; | ||
506 | u32 map_no = 0; | ||
507 | int status; | ||
508 | enum htc_endpoint_id eid; | ||
509 | bool wake_event = false; | ||
510 | bool flushing = false; | ||
511 | |||
512 | skb_queue_head_init(&skb_queue); | ||
513 | |||
514 | /* lock the driver as we update internal state */ | ||
515 | spin_lock_bh(&ar->lock); | ||
516 | |||
517 | /* reap completed packets */ | ||
518 | while (!list_empty(packet_queue)) { | ||
519 | |||
520 | packet = list_first_entry(packet_queue, struct htc_packet, | ||
521 | list); | ||
522 | list_del(&packet->list); | ||
523 | |||
524 | ath6kl_cookie = (struct ath6kl_cookie *)packet->pkt_cntxt; | ||
525 | if (!ath6kl_cookie) | ||
526 | goto fatal; | ||
527 | |||
528 | status = packet->status; | ||
529 | skb = ath6kl_cookie->skb; | ||
530 | eid = packet->endpoint; | ||
531 | map_no = ath6kl_cookie->map_no; | ||
532 | |||
533 | if (!skb || !skb->data) | ||
534 | goto fatal; | ||
535 | |||
536 | packet->buf = skb->data; | ||
537 | |||
538 | __skb_queue_tail(&skb_queue, skb); | ||
539 | |||
540 | if (!status && (packet->act_len != skb->len)) | ||
541 | goto fatal; | ||
542 | |||
543 | ar->tx_pending[eid]--; | ||
544 | |||
545 | if (eid != ar->ctrl_ep) | ||
546 | ar->total_tx_data_pend--; | ||
547 | |||
548 | if (eid == ar->ctrl_ep) { | ||
549 | if (test_bit(WMI_CTRL_EP_FULL, &ar->flag)) | ||
550 | clear_bit(WMI_CTRL_EP_FULL, &ar->flag); | ||
551 | |||
552 | if (ar->tx_pending[eid] == 0) | ||
553 | wake_event = true; | ||
554 | } | ||
555 | |||
556 | if (status) { | ||
557 | if (status == -ECANCELED) | ||
558 | /* a packet was flushed */ | ||
559 | flushing = true; | ||
560 | |||
561 | ar->net_stats.tx_errors++; | ||
562 | |||
563 | if (status != -ENOSPC) | ||
564 | ath6kl_err("tx error, status: 0x%x\n", status); | ||
565 | ath6kl_dbg(ATH6KL_DBG_WLAN_TX, | ||
566 | "%s: skb=0x%p data=0x%p len=0x%x eid=%d %s\n", | ||
567 | __func__, skb, packet->buf, packet->act_len, | ||
568 | eid, "error!"); | ||
569 | } else { | ||
570 | ath6kl_dbg(ATH6KL_DBG_WLAN_TX, | ||
571 | "%s: skb=0x%p data=0x%p len=0x%x eid=%d %s\n", | ||
572 | __func__, skb, packet->buf, packet->act_len, | ||
573 | eid, "OK"); | ||
574 | |||
575 | flushing = false; | ||
576 | ar->net_stats.tx_packets++; | ||
577 | ar->net_stats.tx_bytes += skb->len; | ||
578 | } | ||
579 | |||
580 | ath6kl_tx_clear_node_map(ar, eid, map_no); | ||
581 | |||
582 | ath6kl_free_cookie(ar, ath6kl_cookie); | ||
583 | |||
584 | if (test_bit(NETQ_STOPPED, &ar->flag)) | ||
585 | clear_bit(NETQ_STOPPED, &ar->flag); | ||
586 | } | ||
587 | |||
588 | spin_unlock_bh(&ar->lock); | ||
589 | |||
590 | __skb_queue_purge(&skb_queue); | ||
591 | |||
592 | if (test_bit(CONNECTED, &ar->flag)) { | ||
593 | if (!flushing) | ||
594 | netif_wake_queue(ar->net_dev); | ||
595 | } | ||
596 | |||
597 | if (wake_event) | ||
598 | wake_up(&ar->event_wq); | ||
599 | |||
600 | return; | ||
601 | |||
602 | fatal: | ||
603 | WARN_ON(1); | ||
604 | spin_unlock_bh(&ar->lock); | ||
605 | return; | ||
606 | } | ||
607 | |||
608 | void ath6kl_tx_data_cleanup(struct ath6kl *ar) | ||
609 | { | ||
610 | int i; | ||
611 | |||
612 | /* flush all the data (non-control) streams */ | ||
613 | for (i = 0; i < WMM_NUM_AC; i++) | ||
614 | ath6kl_htc_flush_txep(ar->htc_target, ar->ac2ep_map[i], | ||
615 | ATH6KL_DATA_PKT_TAG); | ||
616 | } | ||
617 | |||
618 | /* Rx functions */ | ||
619 | |||
620 | static void ath6kl_deliver_frames_to_nw_stack(struct net_device *dev, | ||
621 | struct sk_buff *skb) | ||
622 | { | ||
623 | if (!skb) | ||
624 | return; | ||
625 | |||
626 | skb->dev = dev; | ||
627 | |||
628 | if (!(skb->dev->flags & IFF_UP)) { | ||
629 | dev_kfree_skb(skb); | ||
630 | return; | ||
631 | } | ||
632 | |||
633 | skb->protocol = eth_type_trans(skb, skb->dev); | ||
634 | |||
635 | netif_rx_ni(skb); | ||
636 | } | ||
637 | |||
638 | static void ath6kl_alloc_netbufs(struct sk_buff_head *q, u16 num) | ||
639 | { | ||
640 | struct sk_buff *skb; | ||
641 | |||
642 | while (num) { | ||
643 | skb = ath6kl_buf_alloc(ATH6KL_BUFFER_SIZE); | ||
644 | if (!skb) { | ||
645 | ath6kl_err("netbuf allocation failed\n"); | ||
646 | return; | ||
647 | } | ||
648 | skb_queue_tail(q, skb); | ||
649 | num--; | ||
650 | } | ||
651 | } | ||
652 | |||
653 | static struct sk_buff *aggr_get_free_skb(struct aggr_info *p_aggr) | ||
654 | { | ||
655 | struct sk_buff *skb = NULL; | ||
656 | |||
657 | if (skb_queue_len(&p_aggr->free_q) < (AGGR_NUM_OF_FREE_NETBUFS >> 2)) | ||
658 | ath6kl_alloc_netbufs(&p_aggr->free_q, AGGR_NUM_OF_FREE_NETBUFS); | ||
659 | |||
660 | skb = skb_dequeue(&p_aggr->free_q); | ||
661 | |||
662 | return skb; | ||
663 | } | ||
664 | |||
665 | void ath6kl_rx_refill(struct htc_target *target, enum htc_endpoint_id endpoint) | ||
666 | { | ||
667 | struct ath6kl *ar = target->dev->ar; | ||
668 | struct sk_buff *skb; | ||
669 | int rx_buf; | ||
670 | int n_buf_refill; | ||
671 | struct htc_packet *packet; | ||
672 | struct list_head queue; | ||
673 | |||
674 | n_buf_refill = ATH6KL_MAX_RX_BUFFERS - | ||
675 | ath6kl_htc_get_rxbuf_num(ar->htc_target, endpoint); | ||
676 | |||
677 | if (n_buf_refill <= 0) | ||
678 | return; | ||
679 | |||
680 | INIT_LIST_HEAD(&queue); | ||
681 | |||
682 | ath6kl_dbg(ATH6KL_DBG_WLAN_RX, | ||
683 | "%s: providing htc with %d buffers at eid=%d\n", | ||
684 | __func__, n_buf_refill, endpoint); | ||
685 | |||
686 | for (rx_buf = 0; rx_buf < n_buf_refill; rx_buf++) { | ||
687 | skb = ath6kl_buf_alloc(ATH6KL_BUFFER_SIZE); | ||
688 | if (!skb) | ||
689 | break; | ||
690 | |||
691 | packet = (struct htc_packet *) skb->head; | ||
692 | set_htc_rxpkt_info(packet, skb, skb->data, | ||
693 | ATH6KL_BUFFER_SIZE, endpoint); | ||
694 | list_add_tail(&packet->list, &queue); | ||
695 | } | ||
696 | |||
697 | if (!list_empty(&queue)) | ||
698 | ath6kl_htc_add_rxbuf_multiple(ar->htc_target, &queue); | ||
699 | } | ||
700 | |||
701 | void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count) | ||
702 | { | ||
703 | struct htc_packet *packet; | ||
704 | struct sk_buff *skb; | ||
705 | |||
706 | while (count) { | ||
707 | skb = ath6kl_buf_alloc(ATH6KL_AMSDU_BUFFER_SIZE); | ||
708 | if (!skb) | ||
709 | return; | ||
710 | |||
711 | packet = (struct htc_packet *) skb->head; | ||
712 | set_htc_rxpkt_info(packet, skb, skb->data, | ||
713 | ATH6KL_AMSDU_BUFFER_SIZE, 0); | ||
714 | spin_lock_bh(&ar->lock); | ||
715 | list_add_tail(&packet->list, &ar->amsdu_rx_buffer_queue); | ||
716 | spin_unlock_bh(&ar->lock); | ||
717 | count--; | ||
718 | } | ||
719 | } | ||
720 | |||
721 | /* | ||
722 | * Callback to allocate a receive buffer for a pending packet. We use a | ||
723 | * pre-allocated list of buffers of maximum AMSDU size (4K). | ||
724 | */ | ||
725 | struct htc_packet *ath6kl_alloc_amsdu_rxbuf(struct htc_target *target, | ||
726 | enum htc_endpoint_id endpoint, | ||
727 | int len) | ||
728 | { | ||
729 | struct ath6kl *ar = target->dev->ar; | ||
730 | struct htc_packet *packet = NULL; | ||
731 | struct list_head *pkt_pos; | ||
732 | int refill_cnt = 0, depth = 0; | ||
733 | |||
734 | ath6kl_dbg(ATH6KL_DBG_WLAN_RX, "%s: eid=%d, len:%d\n", | ||
735 | __func__, endpoint, len); | ||
736 | |||
737 | if ((len <= ATH6KL_BUFFER_SIZE) || | ||
738 | (len > ATH6KL_AMSDU_BUFFER_SIZE)) | ||
739 | return NULL; | ||
740 | |||
741 | spin_lock_bh(&ar->lock); | ||
742 | |||
743 | if (list_empty(&ar->amsdu_rx_buffer_queue)) { | ||
744 | spin_unlock_bh(&ar->lock); | ||
745 | refill_cnt = ATH6KL_MAX_AMSDU_RX_BUFFERS; | ||
746 | goto refill_buf; | ||
747 | } | ||
748 | |||
749 | packet = list_first_entry(&ar->amsdu_rx_buffer_queue, | ||
750 | struct htc_packet, list); | ||
751 | list_del(&packet->list); | ||
752 | list_for_each(pkt_pos, &ar->amsdu_rx_buffer_queue) | ||
753 | depth++; | ||
754 | |||
755 | refill_cnt = ATH6KL_MAX_AMSDU_RX_BUFFERS - depth; | ||
756 | spin_unlock_bh(&ar->lock); | ||
757 | |||
758 | /* set actual endpoint ID */ | ||
759 | packet->endpoint = endpoint; | ||
760 | |||
761 | refill_buf: | ||
762 | if (refill_cnt >= ATH6KL_AMSDU_REFILL_THRESHOLD) | ||
763 | ath6kl_refill_amsdu_rxbufs(ar, refill_cnt); | ||
764 | |||
765 | return packet; | ||
766 | } | ||
767 | |||
768 | static void aggr_slice_amsdu(struct aggr_info *p_aggr, | ||
769 | struct rxtid *rxtid, struct sk_buff *skb) | ||
770 | { | ||
771 | struct sk_buff *new_skb; | ||
772 | struct ethhdr *hdr; | ||
773 | u16 frame_8023_len, payload_8023_len, mac_hdr_len, amsdu_len; | ||
774 | u8 *framep; | ||
775 | |||
776 | mac_hdr_len = sizeof(struct ethhdr); | ||
777 | framep = skb->data + mac_hdr_len; | ||
778 | amsdu_len = skb->len - mac_hdr_len; | ||
779 | |||
780 | while (amsdu_len > mac_hdr_len) { | ||
781 | hdr = (struct ethhdr *) framep; | ||
782 | payload_8023_len = ntohs(hdr->h_proto); | ||
783 | |||
784 | if (payload_8023_len < MIN_MSDU_SUBFRAME_PAYLOAD_LEN || | ||
785 | payload_8023_len > MAX_MSDU_SUBFRAME_PAYLOAD_LEN) { | ||
786 | ath6kl_err("802.3 AMSDU frame bound check failed. len %d\n", | ||
787 | payload_8023_len); | ||
788 | break; | ||
789 | } | ||
790 | |||
791 | frame_8023_len = payload_8023_len + mac_hdr_len; | ||
792 | new_skb = aggr_get_free_skb(p_aggr); | ||
793 | if (!new_skb) { | ||
794 | ath6kl_err("no buffer available\n"); | ||
795 | break; | ||
796 | } | ||
797 | |||
798 | memcpy(new_skb->data, framep, frame_8023_len); | ||
799 | skb_put(new_skb, frame_8023_len); | ||
800 | if (ath6kl_wmi_dot3_2_dix(new_skb)) { | ||
801 | ath6kl_err("dot3_2_dix error\n"); | ||
802 | dev_kfree_skb(new_skb); | ||
803 | break; | ||
804 | } | ||
805 | |||
806 | skb_queue_tail(&rxtid->q, new_skb); | ||
807 | |||
808 | /* Is this the last subframe within this aggregate ? */ | ||
809 | if ((amsdu_len - frame_8023_len) == 0) | ||
810 | break; | ||
811 | |||
812 | /* Add the length of A-MSDU subframe padding bytes - | ||
813 | * Round to nearest word. | ||
814 | */ | ||
815 | frame_8023_len = ALIGN(frame_8023_len + 3, 3); | ||
816 | |||
817 | framep += frame_8023_len; | ||
818 | amsdu_len -= frame_8023_len; | ||
819 | } | ||
820 | |||
821 | dev_kfree_skb(skb); | ||
822 | } | ||
823 | |||
824 | static void aggr_deque_frms(struct aggr_info *p_aggr, u8 tid, | ||
825 | u16 seq_no, u8 order) | ||
826 | { | ||
827 | struct sk_buff *skb; | ||
828 | struct rxtid *rxtid; | ||
829 | struct skb_hold_q *node; | ||
830 | u16 idx, idx_end, seq_end; | ||
831 | struct rxtid_stats *stats; | ||
832 | |||
833 | if (!p_aggr) | ||
834 | return; | ||
835 | |||
836 | rxtid = &p_aggr->rx_tid[tid]; | ||
837 | stats = &p_aggr->stat[tid]; | ||
838 | |||
839 | idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz); | ||
840 | |||
841 | /* | ||
842 | * idx_end is typically the last possible frame in the window, | ||
843 | * but changes to 'the' seq_no, when BAR comes. If seq_no | ||
844 | * is non-zero, we will go up to that and stop. | ||
845 | * Note: last seq no in current window will occupy the same | ||
846 | * index position as index that is just previous to start. | ||
847 | * An imp point : if win_sz is 7, for seq_no space of 4095, | ||
848 | * then, there would be holes when sequence wrap around occurs. | ||
849 | * Target should judiciously choose the win_sz, based on | ||
850 | * this condition. For 4095, (TID_WINDOW_SZ = 2 x win_sz | ||
851 | * 2, 4, 8, 16 win_sz works fine). | ||
852 | * We must deque from "idx" to "idx_end", including both. | ||
853 | */ | ||
854 | seq_end = seq_no ? seq_no : rxtid->seq_next; | ||
855 | idx_end = AGGR_WIN_IDX(seq_end, rxtid->hold_q_sz); | ||
856 | |||
857 | spin_lock_bh(&rxtid->lock); | ||
858 | |||
859 | do { | ||
860 | node = &rxtid->hold_q[idx]; | ||
861 | if ((order == 1) && (!node->skb)) | ||
862 | break; | ||
863 | |||
864 | if (node->skb) { | ||
865 | if (node->is_amsdu) | ||
866 | aggr_slice_amsdu(p_aggr, rxtid, node->skb); | ||
867 | else | ||
868 | skb_queue_tail(&rxtid->q, node->skb); | ||
869 | node->skb = NULL; | ||
870 | } else | ||
871 | stats->num_hole++; | ||
872 | |||
873 | rxtid->seq_next = ATH6KL_NEXT_SEQ_NO(rxtid->seq_next); | ||
874 | idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz); | ||
875 | } while (idx != idx_end); | ||
876 | |||
877 | spin_unlock_bh(&rxtid->lock); | ||
878 | |||
879 | stats->num_delivered += skb_queue_len(&rxtid->q); | ||
880 | |||
881 | while ((skb = skb_dequeue(&rxtid->q))) | ||
882 | ath6kl_deliver_frames_to_nw_stack(p_aggr->dev, skb); | ||
883 | } | ||
884 | |||
885 | static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid, | ||
886 | u16 seq_no, | ||
887 | bool is_amsdu, struct sk_buff *frame) | ||
888 | { | ||
889 | struct rxtid *rxtid; | ||
890 | struct rxtid_stats *stats; | ||
891 | struct sk_buff *skb; | ||
892 | struct skb_hold_q *node; | ||
893 | u16 idx, st, cur, end; | ||
894 | bool is_queued = false; | ||
895 | u16 extended_end; | ||
896 | |||
897 | rxtid = &agg_info->rx_tid[tid]; | ||
898 | stats = &agg_info->stat[tid]; | ||
899 | |||
900 | stats->num_into_aggr++; | ||
901 | |||
902 | if (!rxtid->aggr) { | ||
903 | if (is_amsdu) { | ||
904 | aggr_slice_amsdu(agg_info, rxtid, frame); | ||
905 | is_queued = true; | ||
906 | stats->num_amsdu++; | ||
907 | while ((skb = skb_dequeue(&rxtid->q))) | ||
908 | ath6kl_deliver_frames_to_nw_stack(agg_info->dev, | ||
909 | skb); | ||
910 | } | ||
911 | return is_queued; | ||
912 | } | ||
913 | |||
914 | /* Check the incoming sequence no, if it's in the window */ | ||
915 | st = rxtid->seq_next; | ||
916 | cur = seq_no; | ||
917 | end = (st + rxtid->hold_q_sz-1) & ATH6KL_MAX_SEQ_NO; | ||
918 | |||
919 | if (((st < end) && (cur < st || cur > end)) || | ||
920 | ((st > end) && (cur > end) && (cur < st))) { | ||
921 | extended_end = (end + rxtid->hold_q_sz - 1) & | ||
922 | ATH6KL_MAX_SEQ_NO; | ||
923 | |||
924 | if (((end < extended_end) && | ||
925 | (cur < end || cur > extended_end)) || | ||
926 | ((end > extended_end) && (cur > extended_end) && | ||
927 | (cur < end))) { | ||
928 | aggr_deque_frms(agg_info, tid, 0, 0); | ||
929 | if (cur >= rxtid->hold_q_sz - 1) | ||
930 | rxtid->seq_next = cur - (rxtid->hold_q_sz - 1); | ||
931 | else | ||
932 | rxtid->seq_next = ATH6KL_MAX_SEQ_NO - | ||
933 | (rxtid->hold_q_sz - 2 - cur); | ||
934 | } else { | ||
935 | /* | ||
936 | * Dequeue only those frames that are outside the | ||
937 | * new shifted window. | ||
938 | */ | ||
939 | if (cur >= rxtid->hold_q_sz - 1) | ||
940 | st = cur - (rxtid->hold_q_sz - 1); | ||
941 | else | ||
942 | st = ATH6KL_MAX_SEQ_NO - | ||
943 | (rxtid->hold_q_sz - 2 - cur); | ||
944 | |||
945 | aggr_deque_frms(agg_info, tid, st, 0); | ||
946 | } | ||
947 | |||
948 | stats->num_oow++; | ||
949 | } | ||
950 | |||
951 | idx = AGGR_WIN_IDX(seq_no, rxtid->hold_q_sz); | ||
952 | |||
953 | node = &rxtid->hold_q[idx]; | ||
954 | |||
955 | spin_lock_bh(&rxtid->lock); | ||
956 | |||
957 | /* | ||
958 | * Is the cur frame duplicate or something beyond our window(hold_q | ||
959 | * -> which is 2x, already)? | ||
960 | * | ||
961 | * 1. Duplicate is easy - drop incoming frame. | ||
962 | * 2. Not falling in current sliding window. | ||
963 | * 2a. is the frame_seq_no preceding current tid_seq_no? | ||
964 | * -> drop the frame. perhaps sender did not get our ACK. | ||
965 | * this is taken care of above. | ||
966 | * 2b. is the frame_seq_no beyond window(st, TID_WINDOW_SZ); | ||
967 | * -> Taken care of it above, by moving window forward. | ||
968 | */ | ||
969 | dev_kfree_skb(node->skb); | ||
970 | stats->num_dups++; | ||
971 | |||
972 | node->skb = frame; | ||
973 | is_queued = true; | ||
974 | node->is_amsdu = is_amsdu; | ||
975 | node->seq_no = seq_no; | ||
976 | |||
977 | if (node->is_amsdu) | ||
978 | stats->num_amsdu++; | ||
979 | else | ||
980 | stats->num_mpdu++; | ||
981 | |||
982 | spin_unlock_bh(&rxtid->lock); | ||
983 | |||
984 | aggr_deque_frms(agg_info, tid, 0, 1); | ||
985 | |||
986 | if (agg_info->timer_scheduled) | ||
987 | rxtid->progress = true; | ||
988 | else | ||
989 | for (idx = 0 ; idx < rxtid->hold_q_sz; idx++) { | ||
990 | if (rxtid->hold_q[idx].skb) { | ||
991 | /* | ||
992 | * There is a frame in the queue and no | ||
993 | * timer so start a timer to ensure that | ||
994 | * the frame doesn't remain stuck | ||
995 | * forever. | ||
996 | */ | ||
997 | agg_info->timer_scheduled = true; | ||
998 | mod_timer(&agg_info->timer, | ||
999 | (jiffies + | ||
1000 | HZ * (AGGR_RX_TIMEOUT) / 1000)); | ||
1001 | rxtid->progress = false; | ||
1002 | rxtid->timer_mon = true; | ||
1003 | break; | ||
1004 | } | ||
1005 | } | ||
1006 | |||
1007 | return is_queued; | ||
1008 | } | ||
1009 | |||
1010 | void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) | ||
1011 | { | ||
1012 | struct ath6kl *ar = target->dev->ar; | ||
1013 | struct sk_buff *skb = packet->pkt_cntxt; | ||
1014 | struct wmi_rx_meta_v2 *meta; | ||
1015 | struct wmi_data_hdr *dhdr; | ||
1016 | int min_hdr_len; | ||
1017 | u8 meta_type, dot11_hdr = 0; | ||
1018 | int status = packet->status; | ||
1019 | enum htc_endpoint_id ept = packet->endpoint; | ||
1020 | bool is_amsdu, prev_ps, ps_state = false; | ||
1021 | struct ath6kl_sta *conn = NULL; | ||
1022 | struct sk_buff *skb1 = NULL; | ||
1023 | struct ethhdr *datap = NULL; | ||
1024 | u16 seq_no, offset; | ||
1025 | u8 tid; | ||
1026 | |||
1027 | ath6kl_dbg(ATH6KL_DBG_WLAN_RX, | ||
1028 | "%s: ar=0x%p eid=%d, skb=0x%p, data=0x%p, len=0x%x status:%d", | ||
1029 | __func__, ar, ept, skb, packet->buf, | ||
1030 | packet->act_len, status); | ||
1031 | |||
1032 | if (status || !(skb->data + HTC_HDR_LENGTH)) { | ||
1033 | ar->net_stats.rx_errors++; | ||
1034 | dev_kfree_skb(skb); | ||
1035 | return; | ||
1036 | } | ||
1037 | |||
1038 | /* | ||
1039 | * Take lock to protect buffer counts and adaptive power throughput | ||
1040 | * state. | ||
1041 | */ | ||
1042 | spin_lock_bh(&ar->lock); | ||
1043 | |||
1044 | ar->net_stats.rx_packets++; | ||
1045 | ar->net_stats.rx_bytes += packet->act_len; | ||
1046 | |||
1047 | skb_put(skb, packet->act_len + HTC_HDR_LENGTH); | ||
1048 | skb_pull(skb, HTC_HDR_LENGTH); | ||
1049 | |||
1050 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, skb->data, skb->len); | ||
1051 | |||
1052 | spin_unlock_bh(&ar->lock); | ||
1053 | |||
1054 | skb->dev = ar->net_dev; | ||
1055 | |||
1056 | if (!test_bit(WMI_ENABLED, &ar->flag)) { | ||
1057 | if (EPPING_ALIGNMENT_PAD > 0) | ||
1058 | skb_pull(skb, EPPING_ALIGNMENT_PAD); | ||
1059 | ath6kl_deliver_frames_to_nw_stack(ar->net_dev, skb); | ||
1060 | return; | ||
1061 | } | ||
1062 | |||
1063 | if (ept == ar->ctrl_ep) { | ||
1064 | ath6kl_wmi_control_rx(ar->wmi, skb); | ||
1065 | return; | ||
1066 | } | ||
1067 | |||
1068 | min_hdr_len = sizeof(struct ethhdr); | ||
1069 | min_hdr_len += sizeof(struct wmi_data_hdr) + | ||
1070 | sizeof(struct ath6kl_llc_snap_hdr); | ||
1071 | |||
1072 | dhdr = (struct wmi_data_hdr *) skb->data; | ||
1073 | |||
1074 | /* | ||
1075 | * In the case of AP mode we may receive NULL data frames | ||
1076 | * that do not have LLC hdr. They are 16 bytes in size. | ||
1077 | * Allow these frames in the AP mode. | ||
1078 | */ | ||
1079 | if (ar->nw_type != AP_NETWORK && | ||
1080 | ((packet->act_len < min_hdr_len) || | ||
1081 | (packet->act_len > WMI_MAX_AMSDU_RX_DATA_FRAME_LENGTH))) { | ||
1082 | ath6kl_info("frame len is too short or too long\n"); | ||
1083 | ar->net_stats.rx_errors++; | ||
1084 | ar->net_stats.rx_length_errors++; | ||
1085 | dev_kfree_skb(skb); | ||
1086 | return; | ||
1087 | } | ||
1088 | |||
1089 | /* Get the Power save state of the STA */ | ||
1090 | if (ar->nw_type == AP_NETWORK) { | ||
1091 | meta_type = wmi_data_hdr_get_meta(dhdr); | ||
1092 | |||
1093 | ps_state = !!((dhdr->info >> WMI_DATA_HDR_PS_SHIFT) & | ||
1094 | WMI_DATA_HDR_PS_MASK); | ||
1095 | |||
1096 | offset = sizeof(struct wmi_data_hdr); | ||
1097 | |||
1098 | switch (meta_type) { | ||
1099 | case 0: | ||
1100 | break; | ||
1101 | case WMI_META_VERSION_1: | ||
1102 | offset += sizeof(struct wmi_rx_meta_v1); | ||
1103 | break; | ||
1104 | case WMI_META_VERSION_2: | ||
1105 | offset += sizeof(struct wmi_rx_meta_v2); | ||
1106 | break; | ||
1107 | default: | ||
1108 | break; | ||
1109 | } | ||
1110 | |||
1111 | datap = (struct ethhdr *) (skb->data + offset); | ||
1112 | conn = ath6kl_find_sta(ar, datap->h_source); | ||
1113 | |||
1114 | if (!conn) { | ||
1115 | dev_kfree_skb(skb); | ||
1116 | return; | ||
1117 | } | ||
1118 | |||
1119 | /* | ||
1120 | * If there is a change in PS state of the STA, | ||
1121 | * take appropriate steps: | ||
1122 | * | ||
1123 | * 1. If Sleep-->Awake, flush the psq for the STA | ||
1124 | * Clear the PVB for the STA. | ||
1125 | * 2. If Awake-->Sleep, Starting queueing frames | ||
1126 | * the STA. | ||
1127 | */ | ||
1128 | prev_ps = !!(conn->sta_flags & STA_PS_SLEEP); | ||
1129 | |||
1130 | if (ps_state) | ||
1131 | conn->sta_flags |= STA_PS_SLEEP; | ||
1132 | else | ||
1133 | conn->sta_flags &= ~STA_PS_SLEEP; | ||
1134 | |||
1135 | if (prev_ps ^ !!(conn->sta_flags & STA_PS_SLEEP)) { | ||
1136 | if (!(conn->sta_flags & STA_PS_SLEEP)) { | ||
1137 | struct sk_buff *skbuff = NULL; | ||
1138 | |||
1139 | spin_lock_bh(&conn->psq_lock); | ||
1140 | while ((skbuff = skb_dequeue(&conn->psq)) | ||
1141 | != NULL) { | ||
1142 | spin_unlock_bh(&conn->psq_lock); | ||
1143 | ath6kl_data_tx(skbuff, ar->net_dev); | ||
1144 | spin_lock_bh(&conn->psq_lock); | ||
1145 | } | ||
1146 | spin_unlock_bh(&conn->psq_lock); | ||
1147 | /* Clear the PVB for this STA */ | ||
1148 | ath6kl_wmi_set_pvb_cmd(ar->wmi, conn->aid, 0); | ||
1149 | } | ||
1150 | } | ||
1151 | |||
1152 | /* drop NULL data frames here */ | ||
1153 | if ((packet->act_len < min_hdr_len) || | ||
1154 | (packet->act_len > | ||
1155 | WMI_MAX_AMSDU_RX_DATA_FRAME_LENGTH)) { | ||
1156 | dev_kfree_skb(skb); | ||
1157 | return; | ||
1158 | } | ||
1159 | } | ||
1160 | |||
1161 | is_amsdu = wmi_data_hdr_is_amsdu(dhdr) ? true : false; | ||
1162 | tid = wmi_data_hdr_get_up(dhdr); | ||
1163 | seq_no = wmi_data_hdr_get_seqno(dhdr); | ||
1164 | meta_type = wmi_data_hdr_get_meta(dhdr); | ||
1165 | dot11_hdr = wmi_data_hdr_get_dot11(dhdr); | ||
1166 | |||
1167 | ath6kl_wmi_data_hdr_remove(ar->wmi, skb); | ||
1168 | |||
1169 | switch (meta_type) { | ||
1170 | case WMI_META_VERSION_1: | ||
1171 | skb_pull(skb, sizeof(struct wmi_rx_meta_v1)); | ||
1172 | break; | ||
1173 | case WMI_META_VERSION_2: | ||
1174 | meta = (struct wmi_rx_meta_v2 *) skb->data; | ||
1175 | if (meta->csum_flags & 0x1) { | ||
1176 | skb->ip_summed = CHECKSUM_COMPLETE; | ||
1177 | skb->csum = (__force __wsum) meta->csum; | ||
1178 | } | ||
1179 | skb_pull(skb, sizeof(struct wmi_rx_meta_v2)); | ||
1180 | break; | ||
1181 | default: | ||
1182 | break; | ||
1183 | } | ||
1184 | |||
1185 | if (dot11_hdr) | ||
1186 | status = ath6kl_wmi_dot11_hdr_remove(ar->wmi, skb); | ||
1187 | else if (!is_amsdu) | ||
1188 | status = ath6kl_wmi_dot3_2_dix(skb); | ||
1189 | |||
1190 | if (status) { | ||
1191 | /* | ||
1192 | * Drop frames that could not be processed (lack of | ||
1193 | * memory, etc.) | ||
1194 | */ | ||
1195 | dev_kfree_skb(skb); | ||
1196 | return; | ||
1197 | } | ||
1198 | |||
1199 | if (!(ar->net_dev->flags & IFF_UP)) { | ||
1200 | dev_kfree_skb(skb); | ||
1201 | return; | ||
1202 | } | ||
1203 | |||
1204 | if (ar->nw_type == AP_NETWORK) { | ||
1205 | datap = (struct ethhdr *) skb->data; | ||
1206 | if (is_multicast_ether_addr(datap->h_dest)) | ||
1207 | /* | ||
1208 | * Bcast/Mcast frames should be sent to the | ||
1209 | * OS stack as well as on the air. | ||
1210 | */ | ||
1211 | skb1 = skb_copy(skb, GFP_ATOMIC); | ||
1212 | else { | ||
1213 | /* | ||
1214 | * Search for a connected STA with dstMac | ||
1215 | * as the Mac address. If found send the | ||
1216 | * frame to it on the air else send the | ||
1217 | * frame up the stack. | ||
1218 | */ | ||
1219 | struct ath6kl_sta *conn = NULL; | ||
1220 | conn = ath6kl_find_sta(ar, datap->h_dest); | ||
1221 | |||
1222 | if (conn && ar->intra_bss) { | ||
1223 | skb1 = skb; | ||
1224 | skb = NULL; | ||
1225 | } else if (conn && !ar->intra_bss) { | ||
1226 | dev_kfree_skb(skb); | ||
1227 | skb = NULL; | ||
1228 | } | ||
1229 | } | ||
1230 | if (skb1) | ||
1231 | ath6kl_data_tx(skb1, ar->net_dev); | ||
1232 | } | ||
1233 | |||
1234 | if (!aggr_process_recv_frm(ar->aggr_cntxt, tid, seq_no, | ||
1235 | is_amsdu, skb)) | ||
1236 | ath6kl_deliver_frames_to_nw_stack(ar->net_dev, skb); | ||
1237 | } | ||
1238 | |||
1239 | static void aggr_timeout(unsigned long arg) | ||
1240 | { | ||
1241 | u8 i, j; | ||
1242 | struct aggr_info *p_aggr = (struct aggr_info *) arg; | ||
1243 | struct rxtid *rxtid; | ||
1244 | struct rxtid_stats *stats; | ||
1245 | |||
1246 | for (i = 0; i < NUM_OF_TIDS; i++) { | ||
1247 | rxtid = &p_aggr->rx_tid[i]; | ||
1248 | stats = &p_aggr->stat[i]; | ||
1249 | |||
1250 | if (!rxtid->aggr || !rxtid->timer_mon || rxtid->progress) | ||
1251 | continue; | ||
1252 | |||
1253 | /* | ||
1254 | * FIXME: these timeouts happen quite fruently, something | ||
1255 | * line once within 60 seconds. Investigate why. | ||
1256 | */ | ||
1257 | stats->num_timeouts++; | ||
1258 | ath6kl_dbg(ATH6KL_DBG_AGGR, | ||
1259 | "aggr timeout (st %d end %d)\n", | ||
1260 | rxtid->seq_next, | ||
1261 | ((rxtid->seq_next + rxtid->hold_q_sz-1) & | ||
1262 | ATH6KL_MAX_SEQ_NO)); | ||
1263 | aggr_deque_frms(p_aggr, i, 0, 0); | ||
1264 | } | ||
1265 | |||
1266 | p_aggr->timer_scheduled = false; | ||
1267 | |||
1268 | for (i = 0; i < NUM_OF_TIDS; i++) { | ||
1269 | rxtid = &p_aggr->rx_tid[i]; | ||
1270 | |||
1271 | if (rxtid->aggr && rxtid->hold_q) { | ||
1272 | for (j = 0; j < rxtid->hold_q_sz; j++) { | ||
1273 | if (rxtid->hold_q[j].skb) { | ||
1274 | p_aggr->timer_scheduled = true; | ||
1275 | rxtid->timer_mon = true; | ||
1276 | rxtid->progress = false; | ||
1277 | break; | ||
1278 | } | ||
1279 | } | ||
1280 | |||
1281 | if (j >= rxtid->hold_q_sz) | ||
1282 | rxtid->timer_mon = false; | ||
1283 | } | ||
1284 | } | ||
1285 | |||
1286 | if (p_aggr->timer_scheduled) | ||
1287 | mod_timer(&p_aggr->timer, | ||
1288 | jiffies + msecs_to_jiffies(AGGR_RX_TIMEOUT)); | ||
1289 | } | ||
1290 | |||
1291 | static void aggr_delete_tid_state(struct aggr_info *p_aggr, u8 tid) | ||
1292 | { | ||
1293 | struct rxtid *rxtid; | ||
1294 | struct rxtid_stats *stats; | ||
1295 | |||
1296 | if (!p_aggr || tid >= NUM_OF_TIDS) | ||
1297 | return; | ||
1298 | |||
1299 | rxtid = &p_aggr->rx_tid[tid]; | ||
1300 | stats = &p_aggr->stat[tid]; | ||
1301 | |||
1302 | if (rxtid->aggr) | ||
1303 | aggr_deque_frms(p_aggr, tid, 0, 0); | ||
1304 | |||
1305 | rxtid->aggr = false; | ||
1306 | rxtid->progress = false; | ||
1307 | rxtid->timer_mon = false; | ||
1308 | rxtid->win_sz = 0; | ||
1309 | rxtid->seq_next = 0; | ||
1310 | rxtid->hold_q_sz = 0; | ||
1311 | |||
1312 | kfree(rxtid->hold_q); | ||
1313 | rxtid->hold_q = NULL; | ||
1314 | |||
1315 | memset(stats, 0, sizeof(struct rxtid_stats)); | ||
1316 | } | ||
1317 | |||
1318 | void aggr_recv_addba_req_evt(struct ath6kl *ar, u8 tid, u16 seq_no, u8 win_sz) | ||
1319 | { | ||
1320 | struct aggr_info *p_aggr = ar->aggr_cntxt; | ||
1321 | struct rxtid *rxtid; | ||
1322 | struct rxtid_stats *stats; | ||
1323 | u16 hold_q_size; | ||
1324 | |||
1325 | if (!p_aggr) | ||
1326 | return; | ||
1327 | |||
1328 | rxtid = &p_aggr->rx_tid[tid]; | ||
1329 | stats = &p_aggr->stat[tid]; | ||
1330 | |||
1331 | if (win_sz < AGGR_WIN_SZ_MIN || win_sz > AGGR_WIN_SZ_MAX) | ||
1332 | ath6kl_dbg(ATH6KL_DBG_WLAN_RX, "%s: win_sz %d, tid %d\n", | ||
1333 | __func__, win_sz, tid); | ||
1334 | |||
1335 | if (rxtid->aggr) | ||
1336 | aggr_delete_tid_state(p_aggr, tid); | ||
1337 | |||
1338 | rxtid->seq_next = seq_no; | ||
1339 | hold_q_size = TID_WINDOW_SZ(win_sz) * sizeof(struct skb_hold_q); | ||
1340 | rxtid->hold_q = kzalloc(hold_q_size, GFP_KERNEL); | ||
1341 | if (!rxtid->hold_q) | ||
1342 | return; | ||
1343 | |||
1344 | rxtid->win_sz = win_sz; | ||
1345 | rxtid->hold_q_sz = TID_WINDOW_SZ(win_sz); | ||
1346 | if (!skb_queue_empty(&rxtid->q)) | ||
1347 | return; | ||
1348 | |||
1349 | rxtid->aggr = true; | ||
1350 | } | ||
1351 | |||
1352 | struct aggr_info *aggr_init(struct net_device *dev) | ||
1353 | { | ||
1354 | struct aggr_info *p_aggr = NULL; | ||
1355 | struct rxtid *rxtid; | ||
1356 | u8 i; | ||
1357 | |||
1358 | p_aggr = kzalloc(sizeof(struct aggr_info), GFP_KERNEL); | ||
1359 | if (!p_aggr) { | ||
1360 | ath6kl_err("failed to alloc memory for aggr_node\n"); | ||
1361 | return NULL; | ||
1362 | } | ||
1363 | |||
1364 | p_aggr->aggr_sz = AGGR_SZ_DEFAULT; | ||
1365 | p_aggr->dev = dev; | ||
1366 | init_timer(&p_aggr->timer); | ||
1367 | p_aggr->timer.function = aggr_timeout; | ||
1368 | p_aggr->timer.data = (unsigned long) p_aggr; | ||
1369 | |||
1370 | p_aggr->timer_scheduled = false; | ||
1371 | skb_queue_head_init(&p_aggr->free_q); | ||
1372 | |||
1373 | ath6kl_alloc_netbufs(&p_aggr->free_q, AGGR_NUM_OF_FREE_NETBUFS); | ||
1374 | |||
1375 | for (i = 0; i < NUM_OF_TIDS; i++) { | ||
1376 | rxtid = &p_aggr->rx_tid[i]; | ||
1377 | rxtid->aggr = false; | ||
1378 | rxtid->progress = false; | ||
1379 | rxtid->timer_mon = false; | ||
1380 | skb_queue_head_init(&rxtid->q); | ||
1381 | spin_lock_init(&rxtid->lock); | ||
1382 | } | ||
1383 | |||
1384 | return p_aggr; | ||
1385 | } | ||
1386 | |||
1387 | void aggr_recv_delba_req_evt(struct ath6kl *ar, u8 tid) | ||
1388 | { | ||
1389 | struct aggr_info *p_aggr = ar->aggr_cntxt; | ||
1390 | struct rxtid *rxtid; | ||
1391 | |||
1392 | if (!p_aggr) | ||
1393 | return; | ||
1394 | |||
1395 | rxtid = &p_aggr->rx_tid[tid]; | ||
1396 | |||
1397 | if (rxtid->aggr) | ||
1398 | aggr_delete_tid_state(p_aggr, tid); | ||
1399 | } | ||
1400 | |||
1401 | void aggr_reset_state(struct aggr_info *aggr_info) | ||
1402 | { | ||
1403 | u8 tid; | ||
1404 | |||
1405 | for (tid = 0; tid < NUM_OF_TIDS; tid++) | ||
1406 | aggr_delete_tid_state(aggr_info, tid); | ||
1407 | } | ||
1408 | |||
1409 | /* clean up our amsdu buffer list */ | ||
1410 | void ath6kl_cleanup_amsdu_rxbufs(struct ath6kl *ar) | ||
1411 | { | ||
1412 | struct htc_packet *packet, *tmp_pkt; | ||
1413 | |||
1414 | spin_lock_bh(&ar->lock); | ||
1415 | if (list_empty(&ar->amsdu_rx_buffer_queue)) { | ||
1416 | spin_unlock_bh(&ar->lock); | ||
1417 | return; | ||
1418 | } | ||
1419 | |||
1420 | list_for_each_entry_safe(packet, tmp_pkt, &ar->amsdu_rx_buffer_queue, | ||
1421 | list) { | ||
1422 | list_del(&packet->list); | ||
1423 | spin_unlock_bh(&ar->lock); | ||
1424 | dev_kfree_skb(packet->pkt_cntxt); | ||
1425 | spin_lock_bh(&ar->lock); | ||
1426 | } | ||
1427 | |||
1428 | spin_unlock_bh(&ar->lock); | ||
1429 | } | ||
1430 | |||
1431 | void aggr_module_destroy(struct aggr_info *aggr_info) | ||
1432 | { | ||
1433 | struct rxtid *rxtid; | ||
1434 | u8 i, k; | ||
1435 | |||
1436 | if (!aggr_info) | ||
1437 | return; | ||
1438 | |||
1439 | if (aggr_info->timer_scheduled) { | ||
1440 | del_timer(&aggr_info->timer); | ||
1441 | aggr_info->timer_scheduled = false; | ||
1442 | } | ||
1443 | |||
1444 | for (i = 0; i < NUM_OF_TIDS; i++) { | ||
1445 | rxtid = &aggr_info->rx_tid[i]; | ||
1446 | if (rxtid->hold_q) { | ||
1447 | for (k = 0; k < rxtid->hold_q_sz; k++) | ||
1448 | dev_kfree_skb(rxtid->hold_q[k].skb); | ||
1449 | kfree(rxtid->hold_q); | ||
1450 | } | ||
1451 | |||
1452 | skb_queue_purge(&rxtid->q); | ||
1453 | } | ||
1454 | |||
1455 | skb_queue_purge(&aggr_info->free_q); | ||
1456 | kfree(aggr_info); | ||
1457 | } | ||
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c new file mode 100644 index 000000000000..f5aa33dd4c42 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/wmi.c | |||
@@ -0,0 +1,2743 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004-2011 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 <linux/ip.h> | ||
18 | #include "core.h" | ||
19 | #include "debug.h" | ||
20 | |||
21 | static int ath6kl_wmi_sync_point(struct wmi *wmi); | ||
22 | |||
23 | static const s32 wmi_rate_tbl[][2] = { | ||
24 | /* {W/O SGI, with SGI} */ | ||
25 | {1000, 1000}, | ||
26 | {2000, 2000}, | ||
27 | {5500, 5500}, | ||
28 | {11000, 11000}, | ||
29 | {6000, 6000}, | ||
30 | {9000, 9000}, | ||
31 | {12000, 12000}, | ||
32 | {18000, 18000}, | ||
33 | {24000, 24000}, | ||
34 | {36000, 36000}, | ||
35 | {48000, 48000}, | ||
36 | {54000, 54000}, | ||
37 | {6500, 7200}, | ||
38 | {13000, 14400}, | ||
39 | {19500, 21700}, | ||
40 | {26000, 28900}, | ||
41 | {39000, 43300}, | ||
42 | {52000, 57800}, | ||
43 | {58500, 65000}, | ||
44 | {65000, 72200}, | ||
45 | {13500, 15000}, | ||
46 | {27000, 30000}, | ||
47 | {40500, 45000}, | ||
48 | {54000, 60000}, | ||
49 | {81000, 90000}, | ||
50 | {108000, 120000}, | ||
51 | {121500, 135000}, | ||
52 | {135000, 150000}, | ||
53 | {0, 0} | ||
54 | }; | ||
55 | |||
56 | /* 802.1d to AC mapping. Refer pg 57 of WMM-test-plan-v1.2 */ | ||
57 | static const u8 up_to_ac[] = { | ||
58 | WMM_AC_BE, | ||
59 | WMM_AC_BK, | ||
60 | WMM_AC_BK, | ||
61 | WMM_AC_BE, | ||
62 | WMM_AC_VI, | ||
63 | WMM_AC_VI, | ||
64 | WMM_AC_VO, | ||
65 | WMM_AC_VO, | ||
66 | }; | ||
67 | |||
68 | void ath6kl_wmi_set_control_ep(struct wmi *wmi, enum htc_endpoint_id ep_id) | ||
69 | { | ||
70 | if (WARN_ON(ep_id == ENDPOINT_UNUSED || ep_id >= ENDPOINT_MAX)) | ||
71 | return; | ||
72 | |||
73 | wmi->ep_id = ep_id; | ||
74 | } | ||
75 | |||
76 | enum htc_endpoint_id ath6kl_wmi_get_control_ep(struct wmi *wmi) | ||
77 | { | ||
78 | return wmi->ep_id; | ||
79 | } | ||
80 | |||
81 | /* Performs DIX to 802.3 encapsulation for transmit packets. | ||
82 | * Assumes the entire DIX header is contigous and that there is | ||
83 | * enough room in the buffer for a 802.3 mac header and LLC+SNAP headers. | ||
84 | */ | ||
85 | int ath6kl_wmi_dix_2_dot3(struct wmi *wmi, struct sk_buff *skb) | ||
86 | { | ||
87 | struct ath6kl_llc_snap_hdr *llc_hdr; | ||
88 | struct ethhdr *eth_hdr; | ||
89 | size_t new_len; | ||
90 | __be16 type; | ||
91 | u8 *datap; | ||
92 | u16 size; | ||
93 | |||
94 | if (WARN_ON(skb == NULL)) | ||
95 | return -EINVAL; | ||
96 | |||
97 | size = sizeof(struct ath6kl_llc_snap_hdr) + sizeof(struct wmi_data_hdr); | ||
98 | if (skb_headroom(skb) < size) | ||
99 | return -ENOMEM; | ||
100 | |||
101 | eth_hdr = (struct ethhdr *) skb->data; | ||
102 | type = eth_hdr->h_proto; | ||
103 | |||
104 | if (!is_ethertype(be16_to_cpu(type))) { | ||
105 | ath6kl_dbg(ATH6KL_DBG_WMI, | ||
106 | "%s: pkt is already in 802.3 format\n", __func__); | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | new_len = skb->len - sizeof(*eth_hdr) + sizeof(*llc_hdr); | ||
111 | |||
112 | skb_push(skb, sizeof(struct ath6kl_llc_snap_hdr)); | ||
113 | datap = skb->data; | ||
114 | |||
115 | eth_hdr->h_proto = cpu_to_be16(new_len); | ||
116 | |||
117 | memcpy(datap, eth_hdr, sizeof(*eth_hdr)); | ||
118 | |||
119 | llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap + sizeof(*eth_hdr)); | ||
120 | llc_hdr->dsap = 0xAA; | ||
121 | llc_hdr->ssap = 0xAA; | ||
122 | llc_hdr->cntl = 0x03; | ||
123 | llc_hdr->org_code[0] = 0x0; | ||
124 | llc_hdr->org_code[1] = 0x0; | ||
125 | llc_hdr->org_code[2] = 0x0; | ||
126 | llc_hdr->eth_type = type; | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static int ath6kl_wmi_meta_add(struct wmi *wmi, struct sk_buff *skb, | ||
132 | u8 *version, void *tx_meta_info) | ||
133 | { | ||
134 | struct wmi_tx_meta_v1 *v1; | ||
135 | struct wmi_tx_meta_v2 *v2; | ||
136 | |||
137 | if (WARN_ON(skb == NULL || version == NULL)) | ||
138 | return -EINVAL; | ||
139 | |||
140 | switch (*version) { | ||
141 | case WMI_META_VERSION_1: | ||
142 | skb_push(skb, WMI_MAX_TX_META_SZ); | ||
143 | v1 = (struct wmi_tx_meta_v1 *) skb->data; | ||
144 | v1->pkt_id = 0; | ||
145 | v1->rate_plcy_id = 0; | ||
146 | *version = WMI_META_VERSION_1; | ||
147 | break; | ||
148 | case WMI_META_VERSION_2: | ||
149 | skb_push(skb, WMI_MAX_TX_META_SZ); | ||
150 | v2 = (struct wmi_tx_meta_v2 *) skb->data; | ||
151 | memcpy(v2, (struct wmi_tx_meta_v2 *) tx_meta_info, | ||
152 | sizeof(struct wmi_tx_meta_v2)); | ||
153 | break; | ||
154 | } | ||
155 | |||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb, | ||
160 | u8 msg_type, bool more_data, | ||
161 | enum wmi_data_hdr_data_type data_type, | ||
162 | u8 meta_ver, void *tx_meta_info) | ||
163 | { | ||
164 | struct wmi_data_hdr *data_hdr; | ||
165 | int ret; | ||
166 | |||
167 | if (WARN_ON(skb == NULL)) | ||
168 | return -EINVAL; | ||
169 | |||
170 | ret = ath6kl_wmi_meta_add(wmi, skb, &meta_ver, tx_meta_info); | ||
171 | if (ret) | ||
172 | return ret; | ||
173 | |||
174 | skb_push(skb, sizeof(struct wmi_data_hdr)); | ||
175 | |||
176 | data_hdr = (struct wmi_data_hdr *)skb->data; | ||
177 | memset(data_hdr, 0, sizeof(struct wmi_data_hdr)); | ||
178 | |||
179 | data_hdr->info = msg_type << WMI_DATA_HDR_MSG_TYPE_SHIFT; | ||
180 | data_hdr->info |= data_type << WMI_DATA_HDR_DATA_TYPE_SHIFT; | ||
181 | |||
182 | if (more_data) | ||
183 | data_hdr->info |= | ||
184 | WMI_DATA_HDR_MORE_MASK << WMI_DATA_HDR_MORE_SHIFT; | ||
185 | |||
186 | data_hdr->info2 = cpu_to_le16(meta_ver << WMI_DATA_HDR_META_SHIFT); | ||
187 | data_hdr->info3 = 0; | ||
188 | |||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | static u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri) | ||
193 | { | ||
194 | struct iphdr *ip_hdr = (struct iphdr *) pkt; | ||
195 | u8 ip_pri; | ||
196 | |||
197 | /* | ||
198 | * Determine IPTOS priority | ||
199 | * | ||
200 | * IP-TOS - 8bits | ||
201 | * : DSCP(6-bits) ECN(2-bits) | ||
202 | * : DSCP - P2 P1 P0 X X X | ||
203 | * where (P2 P1 P0) form 802.1D | ||
204 | */ | ||
205 | ip_pri = ip_hdr->tos >> 5; | ||
206 | ip_pri &= 0x7; | ||
207 | |||
208 | if ((layer2_pri & 0x7) > ip_pri) | ||
209 | return (u8) layer2_pri & 0x7; | ||
210 | else | ||
211 | return ip_pri; | ||
212 | } | ||
213 | |||
214 | int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, struct sk_buff *skb, | ||
215 | u32 layer2_priority, bool wmm_enabled, | ||
216 | u8 *ac) | ||
217 | { | ||
218 | struct wmi_data_hdr *data_hdr; | ||
219 | struct ath6kl_llc_snap_hdr *llc_hdr; | ||
220 | struct wmi_create_pstream_cmd cmd; | ||
221 | u32 meta_size, hdr_size; | ||
222 | u16 ip_type = IP_ETHERTYPE; | ||
223 | u8 stream_exist, usr_pri; | ||
224 | u8 traffic_class = WMM_AC_BE; | ||
225 | u8 *datap; | ||
226 | |||
227 | if (WARN_ON(skb == NULL)) | ||
228 | return -EINVAL; | ||
229 | |||
230 | datap = skb->data; | ||
231 | data_hdr = (struct wmi_data_hdr *) datap; | ||
232 | |||
233 | meta_size = ((le16_to_cpu(data_hdr->info2) >> WMI_DATA_HDR_META_SHIFT) & | ||
234 | WMI_DATA_HDR_META_MASK) ? WMI_MAX_TX_META_SZ : 0; | ||
235 | |||
236 | if (!wmm_enabled) { | ||
237 | /* If WMM is disabled all traffic goes as BE traffic */ | ||
238 | usr_pri = 0; | ||
239 | } else { | ||
240 | hdr_size = sizeof(struct ethhdr); | ||
241 | |||
242 | llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap + | ||
243 | sizeof(struct | ||
244 | wmi_data_hdr) + | ||
245 | meta_size + hdr_size); | ||
246 | |||
247 | if (llc_hdr->eth_type == htons(ip_type)) { | ||
248 | /* | ||
249 | * Extract the endpoint info from the TOS field | ||
250 | * in the IP header. | ||
251 | */ | ||
252 | usr_pri = | ||
253 | ath6kl_wmi_determine_user_priority(((u8 *) llc_hdr) + | ||
254 | sizeof(struct ath6kl_llc_snap_hdr), | ||
255 | layer2_priority); | ||
256 | } else | ||
257 | usr_pri = layer2_priority & 0x7; | ||
258 | } | ||
259 | |||
260 | /* workaround for WMM S5 */ | ||
261 | if ((wmi->traffic_class == WMM_AC_VI) && | ||
262 | ((usr_pri == 5) || (usr_pri == 4))) | ||
263 | usr_pri = 1; | ||
264 | |||
265 | /* Convert user priority to traffic class */ | ||
266 | traffic_class = up_to_ac[usr_pri & 0x7]; | ||
267 | |||
268 | wmi_data_hdr_set_up(data_hdr, usr_pri); | ||
269 | |||
270 | spin_lock_bh(&wmi->lock); | ||
271 | stream_exist = wmi->fat_pipe_exist; | ||
272 | spin_unlock_bh(&wmi->lock); | ||
273 | |||
274 | if (!(stream_exist & (1 << traffic_class))) { | ||
275 | memset(&cmd, 0, sizeof(cmd)); | ||
276 | cmd.traffic_class = traffic_class; | ||
277 | cmd.user_pri = usr_pri; | ||
278 | cmd.inactivity_int = | ||
279 | cpu_to_le32(WMI_IMPLICIT_PSTREAM_INACTIVITY_INT); | ||
280 | /* Implicit streams are created with TSID 0xFF */ | ||
281 | cmd.tsid = WMI_IMPLICIT_PSTREAM; | ||
282 | ath6kl_wmi_create_pstream_cmd(wmi, &cmd); | ||
283 | } | ||
284 | |||
285 | *ac = traffic_class; | ||
286 | |||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | int ath6kl_wmi_dot11_hdr_remove(struct wmi *wmi, struct sk_buff *skb) | ||
291 | { | ||
292 | struct ieee80211_hdr_3addr *pwh, wh; | ||
293 | struct ath6kl_llc_snap_hdr *llc_hdr; | ||
294 | struct ethhdr eth_hdr; | ||
295 | u32 hdr_size; | ||
296 | u8 *datap; | ||
297 | __le16 sub_type; | ||
298 | |||
299 | if (WARN_ON(skb == NULL)) | ||
300 | return -EINVAL; | ||
301 | |||
302 | datap = skb->data; | ||
303 | pwh = (struct ieee80211_hdr_3addr *) datap; | ||
304 | |||
305 | sub_type = pwh->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE); | ||
306 | |||
307 | memcpy((u8 *) &wh, datap, sizeof(struct ieee80211_hdr_3addr)); | ||
308 | |||
309 | /* Strip off the 802.11 header */ | ||
310 | if (sub_type == cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) { | ||
311 | hdr_size = roundup(sizeof(struct ieee80211_qos_hdr), | ||
312 | sizeof(u32)); | ||
313 | skb_pull(skb, hdr_size); | ||
314 | } else if (sub_type == cpu_to_le16(IEEE80211_STYPE_DATA)) | ||
315 | skb_pull(skb, sizeof(struct ieee80211_hdr_3addr)); | ||
316 | |||
317 | datap = skb->data; | ||
318 | llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap); | ||
319 | |||
320 | memset(ð_hdr, 0, sizeof(eth_hdr)); | ||
321 | eth_hdr.h_proto = llc_hdr->eth_type; | ||
322 | |||
323 | switch ((le16_to_cpu(wh.frame_control)) & | ||
324 | (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { | ||
325 | case 0: | ||
326 | memcpy(eth_hdr.h_dest, wh.addr1, ETH_ALEN); | ||
327 | memcpy(eth_hdr.h_source, wh.addr2, ETH_ALEN); | ||
328 | break; | ||
329 | case IEEE80211_FCTL_TODS: | ||
330 | memcpy(eth_hdr.h_dest, wh.addr3, ETH_ALEN); | ||
331 | memcpy(eth_hdr.h_source, wh.addr2, ETH_ALEN); | ||
332 | break; | ||
333 | case IEEE80211_FCTL_FROMDS: | ||
334 | memcpy(eth_hdr.h_dest, wh.addr1, ETH_ALEN); | ||
335 | memcpy(eth_hdr.h_source, wh.addr3, ETH_ALEN); | ||
336 | break; | ||
337 | case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: | ||
338 | break; | ||
339 | } | ||
340 | |||
341 | skb_pull(skb, sizeof(struct ath6kl_llc_snap_hdr)); | ||
342 | skb_push(skb, sizeof(eth_hdr)); | ||
343 | |||
344 | datap = skb->data; | ||
345 | |||
346 | memcpy(datap, ð_hdr, sizeof(eth_hdr)); | ||
347 | |||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | /* | ||
352 | * Performs 802.3 to DIX encapsulation for received packets. | ||
353 | * Assumes the entire 802.3 header is contigous. | ||
354 | */ | ||
355 | int ath6kl_wmi_dot3_2_dix(struct sk_buff *skb) | ||
356 | { | ||
357 | struct ath6kl_llc_snap_hdr *llc_hdr; | ||
358 | struct ethhdr eth_hdr; | ||
359 | u8 *datap; | ||
360 | |||
361 | if (WARN_ON(skb == NULL)) | ||
362 | return -EINVAL; | ||
363 | |||
364 | datap = skb->data; | ||
365 | |||
366 | memcpy(ð_hdr, datap, sizeof(eth_hdr)); | ||
367 | |||
368 | llc_hdr = (struct ath6kl_llc_snap_hdr *) (datap + sizeof(eth_hdr)); | ||
369 | eth_hdr.h_proto = llc_hdr->eth_type; | ||
370 | |||
371 | skb_pull(skb, sizeof(struct ath6kl_llc_snap_hdr)); | ||
372 | datap = skb->data; | ||
373 | |||
374 | memcpy(datap, ð_hdr, sizeof(eth_hdr)); | ||
375 | |||
376 | return 0; | ||
377 | } | ||
378 | |||
379 | int ath6kl_wmi_data_hdr_remove(struct wmi *wmi, struct sk_buff *skb) | ||
380 | { | ||
381 | if (WARN_ON(skb == NULL)) | ||
382 | return -EINVAL; | ||
383 | |||
384 | skb_pull(skb, sizeof(struct wmi_data_hdr)); | ||
385 | |||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | static void ath6kl_wmi_convert_bssinfo_hdr2_to_hdr(struct sk_buff *skb, | ||
390 | u8 *datap) | ||
391 | { | ||
392 | struct wmi_bss_info_hdr2 bih2; | ||
393 | struct wmi_bss_info_hdr *bih; | ||
394 | |||
395 | memcpy(&bih2, datap, sizeof(struct wmi_bss_info_hdr2)); | ||
396 | |||
397 | skb_push(skb, 4); | ||
398 | bih = (struct wmi_bss_info_hdr *) skb->data; | ||
399 | |||
400 | bih->ch = bih2.ch; | ||
401 | bih->frame_type = bih2.frame_type; | ||
402 | bih->snr = bih2.snr; | ||
403 | bih->rssi = a_cpu_to_sle16(bih2.snr - 95); | ||
404 | bih->ie_mask = cpu_to_le32(le16_to_cpu(bih2.ie_mask)); | ||
405 | memcpy(bih->bssid, bih2.bssid, ETH_ALEN); | ||
406 | } | ||
407 | |||
408 | static int ath6kl_wmi_tx_complete_event_rx(u8 *datap, int len) | ||
409 | { | ||
410 | struct tx_complete_msg_v1 *msg_v1; | ||
411 | struct wmi_tx_complete_event *evt; | ||
412 | int index; | ||
413 | u16 size; | ||
414 | |||
415 | evt = (struct wmi_tx_complete_event *) datap; | ||
416 | |||
417 | ath6kl_dbg(ATH6KL_DBG_WMI, "comp: %d %d %d\n", | ||
418 | evt->num_msg, evt->msg_len, evt->msg_type); | ||
419 | |||
420 | if (!AR_DBG_LVL_CHECK(ATH6KL_DBG_WMI)) | ||
421 | return 0; | ||
422 | |||
423 | for (index = 0; index < evt->num_msg; index++) { | ||
424 | size = sizeof(struct wmi_tx_complete_event) + | ||
425 | (index * sizeof(struct tx_complete_msg_v1)); | ||
426 | msg_v1 = (struct tx_complete_msg_v1 *)(datap + size); | ||
427 | |||
428 | ath6kl_dbg(ATH6KL_DBG_WMI, "msg: %d %d %d %d\n", | ||
429 | msg_v1->status, msg_v1->pkt_id, | ||
430 | msg_v1->rate_idx, msg_v1->ack_failures); | ||
431 | } | ||
432 | |||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | static inline struct sk_buff *ath6kl_wmi_get_new_buf(u32 size) | ||
437 | { | ||
438 | struct sk_buff *skb; | ||
439 | |||
440 | skb = ath6kl_buf_alloc(size); | ||
441 | if (!skb) | ||
442 | return NULL; | ||
443 | |||
444 | skb_put(skb, size); | ||
445 | if (size) | ||
446 | memset(skb->data, 0, size); | ||
447 | |||
448 | return skb; | ||
449 | } | ||
450 | |||
451 | /* Send a "simple" wmi command -- one with no arguments */ | ||
452 | static int ath6kl_wmi_simple_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id) | ||
453 | { | ||
454 | struct sk_buff *skb; | ||
455 | int ret; | ||
456 | |||
457 | skb = ath6kl_wmi_get_new_buf(0); | ||
458 | if (!skb) | ||
459 | return -ENOMEM; | ||
460 | |||
461 | ret = ath6kl_wmi_cmd_send(wmi, skb, cmd_id, NO_SYNC_WMIFLAG); | ||
462 | |||
463 | return ret; | ||
464 | } | ||
465 | |||
466 | static int ath6kl_wmi_ready_event_rx(struct wmi *wmi, u8 *datap, int len) | ||
467 | { | ||
468 | struct wmi_ready_event_2 *ev = (struct wmi_ready_event_2 *) datap; | ||
469 | |||
470 | if (len < sizeof(struct wmi_ready_event_2)) | ||
471 | return -EINVAL; | ||
472 | |||
473 | wmi->ready = true; | ||
474 | ath6kl_ready_event(wmi->parent_dev, ev->mac_addr, | ||
475 | le32_to_cpu(ev->sw_version), | ||
476 | le32_to_cpu(ev->abi_version)); | ||
477 | |||
478 | return 0; | ||
479 | } | ||
480 | |||
481 | static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len) | ||
482 | { | ||
483 | struct wmi_connect_event *ev; | ||
484 | u8 *pie, *peie; | ||
485 | |||
486 | if (len < sizeof(struct wmi_connect_event)) | ||
487 | return -EINVAL; | ||
488 | |||
489 | ev = (struct wmi_connect_event *) datap; | ||
490 | |||
491 | ath6kl_dbg(ATH6KL_DBG_WMI, "%s: freq %d bssid %pM\n", | ||
492 | __func__, ev->ch, ev->bssid); | ||
493 | |||
494 | /* Start of assoc rsp IEs */ | ||
495 | pie = ev->assoc_info + ev->beacon_ie_len + | ||
496 | ev->assoc_req_len + (sizeof(u16) * 3); /* capinfo, status, aid */ | ||
497 | |||
498 | /* End of assoc rsp IEs */ | ||
499 | peie = ev->assoc_info + ev->beacon_ie_len + ev->assoc_req_len + | ||
500 | ev->assoc_resp_len; | ||
501 | |||
502 | while (pie < peie) { | ||
503 | switch (*pie) { | ||
504 | case WLAN_EID_VENDOR_SPECIFIC: | ||
505 | if (pie[1] > 3 && pie[2] == 0x00 && pie[3] == 0x50 && | ||
506 | pie[4] == 0xf2 && pie[5] == WMM_OUI_TYPE) { | ||
507 | /* WMM OUT (00:50:F2) */ | ||
508 | if (pie[1] > 5 | ||
509 | && pie[6] == WMM_PARAM_OUI_SUBTYPE) | ||
510 | wmi->is_wmm_enabled = true; | ||
511 | } | ||
512 | break; | ||
513 | } | ||
514 | |||
515 | if (wmi->is_wmm_enabled) | ||
516 | break; | ||
517 | |||
518 | pie += pie[1] + 2; | ||
519 | } | ||
520 | |||
521 | ath6kl_connect_event(wmi->parent_dev, le16_to_cpu(ev->ch), ev->bssid, | ||
522 | le16_to_cpu(ev->listen_intvl), | ||
523 | le16_to_cpu(ev->beacon_intvl), | ||
524 | le32_to_cpu(ev->nw_type), | ||
525 | ev->beacon_ie_len, ev->assoc_req_len, | ||
526 | ev->assoc_resp_len, ev->assoc_info); | ||
527 | |||
528 | return 0; | ||
529 | } | ||
530 | |||
531 | static int ath6kl_wmi_disconnect_event_rx(struct wmi *wmi, u8 *datap, int len) | ||
532 | { | ||
533 | struct wmi_disconnect_event *ev; | ||
534 | wmi->traffic_class = 100; | ||
535 | |||
536 | if (len < sizeof(struct wmi_disconnect_event)) | ||
537 | return -EINVAL; | ||
538 | |||
539 | ev = (struct wmi_disconnect_event *) datap; | ||
540 | |||
541 | wmi->is_wmm_enabled = false; | ||
542 | wmi->pair_crypto_type = NONE_CRYPT; | ||
543 | wmi->grp_crypto_type = NONE_CRYPT; | ||
544 | |||
545 | ath6kl_disconnect_event(wmi->parent_dev, ev->disconn_reason, | ||
546 | ev->bssid, ev->assoc_resp_len, ev->assoc_info, | ||
547 | le16_to_cpu(ev->proto_reason_status)); | ||
548 | |||
549 | return 0; | ||
550 | } | ||
551 | |||
552 | static int ath6kl_wmi_peer_node_event_rx(struct wmi *wmi, u8 *datap, int len) | ||
553 | { | ||
554 | struct wmi_peer_node_event *ev; | ||
555 | |||
556 | if (len < sizeof(struct wmi_peer_node_event)) | ||
557 | return -EINVAL; | ||
558 | |||
559 | ev = (struct wmi_peer_node_event *) datap; | ||
560 | |||
561 | if (ev->event_code == PEER_NODE_JOIN_EVENT) | ||
562 | ath6kl_dbg(ATH6KL_DBG_WMI, "joined node with mac addr: %pM\n", | ||
563 | ev->peer_mac_addr); | ||
564 | else if (ev->event_code == PEER_NODE_LEAVE_EVENT) | ||
565 | ath6kl_dbg(ATH6KL_DBG_WMI, "left node with mac addr: %pM\n", | ||
566 | ev->peer_mac_addr); | ||
567 | |||
568 | return 0; | ||
569 | } | ||
570 | |||
571 | static int ath6kl_wmi_tkip_micerr_event_rx(struct wmi *wmi, u8 *datap, int len) | ||
572 | { | ||
573 | struct wmi_tkip_micerr_event *ev; | ||
574 | |||
575 | if (len < sizeof(struct wmi_tkip_micerr_event)) | ||
576 | return -EINVAL; | ||
577 | |||
578 | ev = (struct wmi_tkip_micerr_event *) datap; | ||
579 | |||
580 | ath6kl_tkip_micerr_event(wmi->parent_dev, ev->key_id, ev->is_mcast); | ||
581 | |||
582 | return 0; | ||
583 | } | ||
584 | |||
585 | static int ath6kl_wlan_parse_beacon(u8 *buf, int frame_len, | ||
586 | struct ath6kl_common_ie *cie) | ||
587 | { | ||
588 | u8 *frm, *efrm; | ||
589 | u8 elemid_ssid = false; | ||
590 | |||
591 | frm = buf; | ||
592 | efrm = (u8 *) (frm + frame_len); | ||
593 | |||
594 | /* | ||
595 | * beacon/probe response frame format | ||
596 | * [8] time stamp | ||
597 | * [2] beacon interval | ||
598 | * [2] capability information | ||
599 | * [tlv] ssid | ||
600 | * [tlv] supported rates | ||
601 | * [tlv] country information | ||
602 | * [tlv] parameter set (FH/DS) | ||
603 | * [tlv] erp information | ||
604 | * [tlv] extended supported rates | ||
605 | * [tlv] WMM | ||
606 | * [tlv] WPA or RSN | ||
607 | * [tlv] Atheros Advanced Capabilities | ||
608 | */ | ||
609 | if ((efrm - frm) < 12) | ||
610 | return -EINVAL; | ||
611 | |||
612 | memset(cie, 0, sizeof(*cie)); | ||
613 | |||
614 | cie->ie_tstamp = frm; | ||
615 | frm += 8; | ||
616 | cie->ie_beaconInt = *(u16 *) frm; | ||
617 | frm += 2; | ||
618 | cie->ie_capInfo = *(u16 *) frm; | ||
619 | frm += 2; | ||
620 | cie->ie_chan = 0; | ||
621 | |||
622 | while (frm < efrm) { | ||
623 | switch (*frm) { | ||
624 | case WLAN_EID_SSID: | ||
625 | if (!elemid_ssid) { | ||
626 | cie->ie_ssid = frm; | ||
627 | elemid_ssid = true; | ||
628 | } | ||
629 | break; | ||
630 | case WLAN_EID_SUPP_RATES: | ||
631 | cie->ie_rates = frm; | ||
632 | break; | ||
633 | case WLAN_EID_COUNTRY: | ||
634 | cie->ie_country = frm; | ||
635 | break; | ||
636 | case WLAN_EID_FH_PARAMS: | ||
637 | break; | ||
638 | case WLAN_EID_DS_PARAMS: | ||
639 | cie->ie_chan = frm[2]; | ||
640 | break; | ||
641 | case WLAN_EID_TIM: | ||
642 | cie->ie_tim = frm; | ||
643 | break; | ||
644 | case WLAN_EID_IBSS_PARAMS: | ||
645 | break; | ||
646 | case WLAN_EID_EXT_SUPP_RATES: | ||
647 | cie->ie_xrates = frm; | ||
648 | break; | ||
649 | case WLAN_EID_ERP_INFO: | ||
650 | if (frm[1] != 1) | ||
651 | return -EINVAL; | ||
652 | |||
653 | cie->ie_erp = frm[2]; | ||
654 | break; | ||
655 | case WLAN_EID_RSN: | ||
656 | cie->ie_rsn = frm; | ||
657 | break; | ||
658 | case WLAN_EID_HT_CAPABILITY: | ||
659 | cie->ie_htcap = frm; | ||
660 | break; | ||
661 | case WLAN_EID_HT_INFORMATION: | ||
662 | cie->ie_htop = frm; | ||
663 | break; | ||
664 | case WLAN_EID_VENDOR_SPECIFIC: | ||
665 | if (frm[1] > 3 && frm[2] == 0x00 && frm[3] == 0x50 && | ||
666 | frm[4] == 0xf2) { | ||
667 | /* OUT Type (00:50:F2) */ | ||
668 | |||
669 | if (frm[5] == WPA_OUI_TYPE) { | ||
670 | /* WPA OUT */ | ||
671 | cie->ie_wpa = frm; | ||
672 | } else if (frm[5] == WMM_OUI_TYPE) { | ||
673 | /* WMM OUT */ | ||
674 | cie->ie_wmm = frm; | ||
675 | } else if (frm[5] == WSC_OUT_TYPE) { | ||
676 | /* WSC OUT */ | ||
677 | cie->ie_wsc = frm; | ||
678 | } | ||
679 | |||
680 | } else if (frm[1] > 3 && frm[2] == 0x00 | ||
681 | && frm[3] == 0x03 && frm[4] == 0x7f | ||
682 | && frm[5] == ATH_OUI_TYPE) { | ||
683 | /* Atheros OUI (00:03:7f) */ | ||
684 | cie->ie_ath = frm; | ||
685 | } | ||
686 | break; | ||
687 | default: | ||
688 | break; | ||
689 | } | ||
690 | frm += frm[1] + 2; | ||
691 | } | ||
692 | |||
693 | if ((cie->ie_rates == NULL) | ||
694 | || (cie->ie_rates[1] > ATH6KL_RATE_MAXSIZE)) | ||
695 | return -EINVAL; | ||
696 | |||
697 | if ((cie->ie_ssid == NULL) | ||
698 | || (cie->ie_ssid[1] > IEEE80211_MAX_SSID_LEN)) | ||
699 | return -EINVAL; | ||
700 | |||
701 | return 0; | ||
702 | } | ||
703 | |||
704 | static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len) | ||
705 | { | ||
706 | struct bss *bss = NULL; | ||
707 | struct wmi_bss_info_hdr *bih; | ||
708 | u8 cached_ssid_len = 0; | ||
709 | u8 cached_ssid[IEEE80211_MAX_SSID_LEN] = { 0 }; | ||
710 | u8 beacon_ssid_len = 0; | ||
711 | u8 *buf, *ie_ssid; | ||
712 | u8 *ni_buf; | ||
713 | int buf_len; | ||
714 | |||
715 | int ret; | ||
716 | |||
717 | if (len <= sizeof(struct wmi_bss_info_hdr)) | ||
718 | return -EINVAL; | ||
719 | |||
720 | bih = (struct wmi_bss_info_hdr *) datap; | ||
721 | bss = wlan_find_node(&wmi->parent_dev->scan_table, bih->bssid); | ||
722 | |||
723 | if (a_sle16_to_cpu(bih->rssi) > 0) { | ||
724 | if (bss == NULL) | ||
725 | return 0; | ||
726 | else | ||
727 | bih->rssi = a_cpu_to_sle16(bss->ni_rssi); | ||
728 | } | ||
729 | |||
730 | buf = datap + sizeof(struct wmi_bss_info_hdr); | ||
731 | len -= sizeof(struct wmi_bss_info_hdr); | ||
732 | |||
733 | ath6kl_dbg(ATH6KL_DBG_WMI, | ||
734 | "bss info evt - ch %u, rssi %02x, bssid \"%pM\"\n", | ||
735 | bih->ch, a_sle16_to_cpu(bih->rssi), bih->bssid); | ||
736 | |||
737 | if (bss != NULL) { | ||
738 | /* | ||
739 | * Free up the node. We are about to allocate a new node. | ||
740 | * In case of hidden AP, beacon will not have ssid, | ||
741 | * but a directed probe response will have it, | ||
742 | * so cache the probe-resp-ssid if already present. | ||
743 | */ | ||
744 | if (wmi->is_probe_ssid && (bih->frame_type == BEACON_FTYPE)) { | ||
745 | ie_ssid = bss->ni_cie.ie_ssid; | ||
746 | if (ie_ssid && (ie_ssid[1] <= IEEE80211_MAX_SSID_LEN) && | ||
747 | (ie_ssid[2] != 0)) { | ||
748 | cached_ssid_len = ie_ssid[1]; | ||
749 | memcpy(cached_ssid, ie_ssid + 2, | ||
750 | cached_ssid_len); | ||
751 | } | ||
752 | } | ||
753 | |||
754 | /* | ||
755 | * Use the current average rssi of associated AP base on | ||
756 | * assumption | ||
757 | * 1. Most os with GUI will update RSSI by | ||
758 | * ath6kl_wmi_get_stats_cmd() periodically. | ||
759 | * 2. ath6kl_wmi_get_stats_cmd(..) will be called when calling | ||
760 | * ath6kl_wmi_startscan_cmd(...) | ||
761 | * The average value of RSSI give end-user better feeling for | ||
762 | * instance value of scan result. It also sync up RSSI info | ||
763 | * in GUI between scan result and RSSI signal icon. | ||
764 | */ | ||
765 | if (memcmp(wmi->parent_dev->bssid, bih->bssid, ETH_ALEN) == 0) { | ||
766 | bih->rssi = a_cpu_to_sle16(bss->ni_rssi); | ||
767 | bih->snr = bss->ni_snr; | ||
768 | } | ||
769 | |||
770 | wlan_node_reclaim(&wmi->parent_dev->scan_table, bss); | ||
771 | } | ||
772 | |||
773 | /* | ||
774 | * beacon/probe response frame format | ||
775 | * [8] time stamp | ||
776 | * [2] beacon interval | ||
777 | * [2] capability information | ||
778 | * [tlv] ssid | ||
779 | */ | ||
780 | beacon_ssid_len = buf[SSID_IE_LEN_INDEX]; | ||
781 | |||
782 | /* | ||
783 | * If ssid is cached for this hidden AP, then change | ||
784 | * buffer len accordingly. | ||
785 | */ | ||
786 | if (wmi->is_probe_ssid && (bih->frame_type == BEACON_FTYPE) && | ||
787 | (cached_ssid_len != 0) && | ||
788 | (beacon_ssid_len == 0 || (cached_ssid_len > beacon_ssid_len && | ||
789 | buf[SSID_IE_LEN_INDEX + 1] == 0))) { | ||
790 | |||
791 | len += (cached_ssid_len - beacon_ssid_len); | ||
792 | } | ||
793 | |||
794 | bss = wlan_node_alloc(len); | ||
795 | if (!bss) | ||
796 | return -ENOMEM; | ||
797 | |||
798 | bss->ni_snr = bih->snr; | ||
799 | bss->ni_rssi = a_sle16_to_cpu(bih->rssi); | ||
800 | |||
801 | if (WARN_ON(!bss->ni_buf)) | ||
802 | return -EINVAL; | ||
803 | |||
804 | /* | ||
805 | * In case of hidden AP, beacon will not have ssid, | ||
806 | * but a directed probe response will have it, | ||
807 | * so place the cached-ssid(probe-resp) in the bss info. | ||
808 | */ | ||
809 | if (wmi->is_probe_ssid && (bih->frame_type == BEACON_FTYPE) && | ||
810 | (cached_ssid_len != 0) && | ||
811 | (beacon_ssid_len == 0 || (beacon_ssid_len && | ||
812 | buf[SSID_IE_LEN_INDEX + 1] == 0))) { | ||
813 | ni_buf = bss->ni_buf; | ||
814 | buf_len = len; | ||
815 | |||
816 | /* | ||
817 | * Copy the first 14 bytes: | ||
818 | * time-stamp(8), beacon-interval(2), | ||
819 | * cap-info(2), ssid-id(1), ssid-len(1). | ||
820 | */ | ||
821 | memcpy(ni_buf, buf, SSID_IE_LEN_INDEX + 1); | ||
822 | |||
823 | ni_buf[SSID_IE_LEN_INDEX] = cached_ssid_len; | ||
824 | ni_buf += (SSID_IE_LEN_INDEX + 1); | ||
825 | |||
826 | buf += (SSID_IE_LEN_INDEX + 1); | ||
827 | buf_len -= (SSID_IE_LEN_INDEX + 1); | ||
828 | |||
829 | memcpy(ni_buf, cached_ssid, cached_ssid_len); | ||
830 | ni_buf += cached_ssid_len; | ||
831 | |||
832 | buf += beacon_ssid_len; | ||
833 | buf_len -= beacon_ssid_len; | ||
834 | |||
835 | if (cached_ssid_len > beacon_ssid_len) | ||
836 | buf_len -= (cached_ssid_len - beacon_ssid_len); | ||
837 | |||
838 | memcpy(ni_buf, buf, buf_len); | ||
839 | } else | ||
840 | memcpy(bss->ni_buf, buf, len); | ||
841 | |||
842 | bss->ni_framelen = len; | ||
843 | |||
844 | ret = ath6kl_wlan_parse_beacon(bss->ni_buf, len, &bss->ni_cie); | ||
845 | if (ret) { | ||
846 | wlan_node_free(bss); | ||
847 | return -EINVAL; | ||
848 | } | ||
849 | |||
850 | /* | ||
851 | * Update the frequency in ie_chan, overwriting of channel number | ||
852 | * which is done in ath6kl_wlan_parse_beacon | ||
853 | */ | ||
854 | bss->ni_cie.ie_chan = le16_to_cpu(bih->ch); | ||
855 | wlan_setup_node(&wmi->parent_dev->scan_table, bss, bih->bssid); | ||
856 | |||
857 | return 0; | ||
858 | } | ||
859 | |||
860 | static int ath6kl_wmi_opt_frame_event_rx(struct wmi *wmi, u8 *datap, int len) | ||
861 | { | ||
862 | struct bss *bss; | ||
863 | struct wmi_opt_rx_info_hdr *bih; | ||
864 | u8 *buf; | ||
865 | |||
866 | if (len <= sizeof(struct wmi_opt_rx_info_hdr)) | ||
867 | return -EINVAL; | ||
868 | |||
869 | bih = (struct wmi_opt_rx_info_hdr *) datap; | ||
870 | buf = datap + sizeof(struct wmi_opt_rx_info_hdr); | ||
871 | len -= sizeof(struct wmi_opt_rx_info_hdr); | ||
872 | |||
873 | ath6kl_dbg(ATH6KL_DBG_WMI, "opt frame event %2.2x:%2.2x\n", | ||
874 | bih->bssid[4], bih->bssid[5]); | ||
875 | |||
876 | bss = wlan_find_node(&wmi->parent_dev->scan_table, bih->bssid); | ||
877 | if (bss != NULL) { | ||
878 | /* Free up the node. We are about to allocate a new node. */ | ||
879 | wlan_node_reclaim(&wmi->parent_dev->scan_table, bss); | ||
880 | } | ||
881 | |||
882 | bss = wlan_node_alloc(len); | ||
883 | if (!bss) | ||
884 | return -ENOMEM; | ||
885 | |||
886 | bss->ni_snr = bih->snr; | ||
887 | bss->ni_cie.ie_chan = le16_to_cpu(bih->ch); | ||
888 | |||
889 | if (WARN_ON(!bss->ni_buf)) | ||
890 | return -EINVAL; | ||
891 | |||
892 | memcpy(bss->ni_buf, buf, len); | ||
893 | wlan_setup_node(&wmi->parent_dev->scan_table, bss, bih->bssid); | ||
894 | |||
895 | return 0; | ||
896 | } | ||
897 | |||
898 | /* Inactivity timeout of a fatpipe(pstream) at the target */ | ||
899 | static int ath6kl_wmi_pstream_timeout_event_rx(struct wmi *wmi, u8 *datap, | ||
900 | int len) | ||
901 | { | ||
902 | struct wmi_pstream_timeout_event *ev; | ||
903 | |||
904 | if (len < sizeof(struct wmi_pstream_timeout_event)) | ||
905 | return -EINVAL; | ||
906 | |||
907 | ev = (struct wmi_pstream_timeout_event *) datap; | ||
908 | |||
909 | /* | ||
910 | * When the pstream (fat pipe == AC) timesout, it means there were | ||
911 | * no thinStreams within this pstream & it got implicitly created | ||
912 | * due to data flow on this AC. We start the inactivity timer only | ||
913 | * for implicitly created pstream. Just reset the host state. | ||
914 | */ | ||
915 | spin_lock_bh(&wmi->lock); | ||
916 | wmi->stream_exist_for_ac[ev->traffic_class] = 0; | ||
917 | wmi->fat_pipe_exist &= ~(1 << ev->traffic_class); | ||
918 | spin_unlock_bh(&wmi->lock); | ||
919 | |||
920 | /* Indicate inactivity to driver layer for this fatpipe (pstream) */ | ||
921 | ath6kl_indicate_tx_activity(wmi->parent_dev, ev->traffic_class, false); | ||
922 | |||
923 | return 0; | ||
924 | } | ||
925 | |||
926 | static int ath6kl_wmi_bitrate_reply_rx(struct wmi *wmi, u8 *datap, int len) | ||
927 | { | ||
928 | struct wmi_bit_rate_reply *reply; | ||
929 | s32 rate; | ||
930 | u32 sgi, index; | ||
931 | |||
932 | if (len < sizeof(struct wmi_bit_rate_reply)) | ||
933 | return -EINVAL; | ||
934 | |||
935 | reply = (struct wmi_bit_rate_reply *) datap; | ||
936 | |||
937 | ath6kl_dbg(ATH6KL_DBG_WMI, "rateindex %d\n", reply->rate_index); | ||
938 | |||
939 | if (reply->rate_index == (s8) RATE_AUTO) { | ||
940 | rate = RATE_AUTO; | ||
941 | } else { | ||
942 | index = reply->rate_index & 0x7f; | ||
943 | sgi = (reply->rate_index & 0x80) ? 1 : 0; | ||
944 | rate = wmi_rate_tbl[index][sgi]; | ||
945 | } | ||
946 | |||
947 | ath6kl_wakeup_event(wmi->parent_dev); | ||
948 | |||
949 | return 0; | ||
950 | } | ||
951 | |||
952 | static int ath6kl_wmi_ratemask_reply_rx(struct wmi *wmi, u8 *datap, int len) | ||
953 | { | ||
954 | if (len < sizeof(struct wmi_fix_rates_reply)) | ||
955 | return -EINVAL; | ||
956 | |||
957 | ath6kl_wakeup_event(wmi->parent_dev); | ||
958 | |||
959 | return 0; | ||
960 | } | ||
961 | |||
962 | static int ath6kl_wmi_ch_list_reply_rx(struct wmi *wmi, u8 *datap, int len) | ||
963 | { | ||
964 | if (len < sizeof(struct wmi_channel_list_reply)) | ||
965 | return -EINVAL; | ||
966 | |||
967 | ath6kl_wakeup_event(wmi->parent_dev); | ||
968 | |||
969 | return 0; | ||
970 | } | ||
971 | |||
972 | static int ath6kl_wmi_tx_pwr_reply_rx(struct wmi *wmi, u8 *datap, int len) | ||
973 | { | ||
974 | struct wmi_tx_pwr_reply *reply; | ||
975 | |||
976 | if (len < sizeof(struct wmi_tx_pwr_reply)) | ||
977 | return -EINVAL; | ||
978 | |||
979 | reply = (struct wmi_tx_pwr_reply *) datap; | ||
980 | ath6kl_txpwr_rx_evt(wmi->parent_dev, reply->dbM); | ||
981 | |||
982 | return 0; | ||
983 | } | ||
984 | |||
985 | static int ath6kl_wmi_keepalive_reply_rx(struct wmi *wmi, u8 *datap, int len) | ||
986 | { | ||
987 | if (len < sizeof(struct wmi_get_keepalive_cmd)) | ||
988 | return -EINVAL; | ||
989 | |||
990 | ath6kl_wakeup_event(wmi->parent_dev); | ||
991 | |||
992 | return 0; | ||
993 | } | ||
994 | |||
995 | static int ath6kl_wmi_scan_complete_rx(struct wmi *wmi, u8 *datap, int len) | ||
996 | { | ||
997 | struct wmi_scan_complete_event *ev; | ||
998 | |||
999 | ev = (struct wmi_scan_complete_event *) datap; | ||
1000 | |||
1001 | if (a_sle32_to_cpu(ev->status) == 0) | ||
1002 | wlan_refresh_inactive_nodes(wmi->parent_dev); | ||
1003 | |||
1004 | ath6kl_scan_complete_evt(wmi->parent_dev, a_sle32_to_cpu(ev->status)); | ||
1005 | wmi->is_probe_ssid = false; | ||
1006 | |||
1007 | return 0; | ||
1008 | } | ||
1009 | |||
1010 | /* | ||
1011 | * Target is reporting a programming error. This is for | ||
1012 | * developer aid only. Target only checks a few common violations | ||
1013 | * and it is responsibility of host to do all error checking. | ||
1014 | * Behavior of target after wmi error event is undefined. | ||
1015 | * A reset is recommended. | ||
1016 | */ | ||
1017 | static int ath6kl_wmi_error_event_rx(struct wmi *wmi, u8 *datap, int len) | ||
1018 | { | ||
1019 | const char *type = "unknown error"; | ||
1020 | struct wmi_cmd_error_event *ev; | ||
1021 | ev = (struct wmi_cmd_error_event *) datap; | ||
1022 | |||
1023 | switch (ev->err_code) { | ||
1024 | case INVALID_PARAM: | ||
1025 | type = "invalid parameter"; | ||
1026 | break; | ||
1027 | case ILLEGAL_STATE: | ||
1028 | type = "invalid state"; | ||
1029 | break; | ||
1030 | case INTERNAL_ERROR: | ||
1031 | type = "internal error"; | ||
1032 | break; | ||
1033 | } | ||
1034 | |||
1035 | ath6kl_dbg(ATH6KL_DBG_WMI, "programming error, cmd=%d %s\n", | ||
1036 | ev->cmd_id, type); | ||
1037 | |||
1038 | return 0; | ||
1039 | } | ||
1040 | |||
1041 | static int ath6kl_wmi_stats_event_rx(struct wmi *wmi, u8 *datap, int len) | ||
1042 | { | ||
1043 | ath6kl_tgt_stats_event(wmi->parent_dev, datap, len); | ||
1044 | |||
1045 | return 0; | ||
1046 | } | ||
1047 | |||
1048 | static u8 ath6kl_wmi_get_upper_threshold(s16 rssi, | ||
1049 | struct sq_threshold_params *sq_thresh, | ||
1050 | u32 size) | ||
1051 | { | ||
1052 | u32 index; | ||
1053 | u8 threshold = (u8) sq_thresh->upper_threshold[size - 1]; | ||
1054 | |||
1055 | /* The list is already in sorted order. Get the next lower value */ | ||
1056 | for (index = 0; index < size; index++) { | ||
1057 | if (rssi < sq_thresh->upper_threshold[index]) { | ||
1058 | threshold = (u8) sq_thresh->upper_threshold[index]; | ||
1059 | break; | ||
1060 | } | ||
1061 | } | ||
1062 | |||
1063 | return threshold; | ||
1064 | } | ||
1065 | |||
1066 | static u8 ath6kl_wmi_get_lower_threshold(s16 rssi, | ||
1067 | struct sq_threshold_params *sq_thresh, | ||
1068 | u32 size) | ||
1069 | { | ||
1070 | u32 index; | ||
1071 | u8 threshold = (u8) sq_thresh->lower_threshold[size - 1]; | ||
1072 | |||
1073 | /* The list is already in sorted order. Get the next lower value */ | ||
1074 | for (index = 0; index < size; index++) { | ||
1075 | if (rssi > sq_thresh->lower_threshold[index]) { | ||
1076 | threshold = (u8) sq_thresh->lower_threshold[index]; | ||
1077 | break; | ||
1078 | } | ||
1079 | } | ||
1080 | |||
1081 | return threshold; | ||
1082 | } | ||
1083 | |||
1084 | static int ath6kl_wmi_send_rssi_threshold_params(struct wmi *wmi, | ||
1085 | struct wmi_rssi_threshold_params_cmd *rssi_cmd) | ||
1086 | { | ||
1087 | struct sk_buff *skb; | ||
1088 | struct wmi_rssi_threshold_params_cmd *cmd; | ||
1089 | |||
1090 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
1091 | if (!skb) | ||
1092 | return -ENOMEM; | ||
1093 | |||
1094 | cmd = (struct wmi_rssi_threshold_params_cmd *) skb->data; | ||
1095 | memcpy(cmd, rssi_cmd, sizeof(struct wmi_rssi_threshold_params_cmd)); | ||
1096 | |||
1097 | return ath6kl_wmi_cmd_send(wmi, skb, WMI_RSSI_THRESHOLD_PARAMS_CMDID, | ||
1098 | NO_SYNC_WMIFLAG); | ||
1099 | } | ||
1100 | |||
1101 | static int ath6kl_wmi_rssi_threshold_event_rx(struct wmi *wmi, u8 *datap, | ||
1102 | int len) | ||
1103 | { | ||
1104 | struct wmi_rssi_threshold_event *reply; | ||
1105 | struct wmi_rssi_threshold_params_cmd cmd; | ||
1106 | struct sq_threshold_params *sq_thresh; | ||
1107 | enum wmi_rssi_threshold_val new_threshold; | ||
1108 | u8 upper_rssi_threshold, lower_rssi_threshold; | ||
1109 | s16 rssi; | ||
1110 | int ret; | ||
1111 | |||
1112 | if (len < sizeof(struct wmi_rssi_threshold_event)) | ||
1113 | return -EINVAL; | ||
1114 | |||
1115 | reply = (struct wmi_rssi_threshold_event *) datap; | ||
1116 | new_threshold = (enum wmi_rssi_threshold_val) reply->range; | ||
1117 | rssi = a_sle16_to_cpu(reply->rssi); | ||
1118 | |||
1119 | sq_thresh = &wmi->sq_threshld[SIGNAL_QUALITY_METRICS_RSSI]; | ||
1120 | |||
1121 | /* | ||
1122 | * Identify the threshold breached and communicate that to the app. | ||
1123 | * After that install a new set of thresholds based on the signal | ||
1124 | * quality reported by the target | ||
1125 | */ | ||
1126 | if (new_threshold) { | ||
1127 | /* Upper threshold breached */ | ||
1128 | if (rssi < sq_thresh->upper_threshold[0]) { | ||
1129 | ath6kl_dbg(ATH6KL_DBG_WMI, | ||
1130 | "spurious upper rssi threshold event: %d\n", | ||
1131 | rssi); | ||
1132 | } else if ((rssi < sq_thresh->upper_threshold[1]) && | ||
1133 | (rssi >= sq_thresh->upper_threshold[0])) { | ||
1134 | new_threshold = WMI_RSSI_THRESHOLD1_ABOVE; | ||
1135 | } else if ((rssi < sq_thresh->upper_threshold[2]) && | ||
1136 | (rssi >= sq_thresh->upper_threshold[1])) { | ||
1137 | new_threshold = WMI_RSSI_THRESHOLD2_ABOVE; | ||
1138 | } else if ((rssi < sq_thresh->upper_threshold[3]) && | ||
1139 | (rssi >= sq_thresh->upper_threshold[2])) { | ||
1140 | new_threshold = WMI_RSSI_THRESHOLD3_ABOVE; | ||
1141 | } else if ((rssi < sq_thresh->upper_threshold[4]) && | ||
1142 | (rssi >= sq_thresh->upper_threshold[3])) { | ||
1143 | new_threshold = WMI_RSSI_THRESHOLD4_ABOVE; | ||
1144 | } else if ((rssi < sq_thresh->upper_threshold[5]) && | ||
1145 | (rssi >= sq_thresh->upper_threshold[4])) { | ||
1146 | new_threshold = WMI_RSSI_THRESHOLD5_ABOVE; | ||
1147 | } else if (rssi >= sq_thresh->upper_threshold[5]) { | ||
1148 | new_threshold = WMI_RSSI_THRESHOLD6_ABOVE; | ||
1149 | } | ||
1150 | } else { | ||
1151 | /* Lower threshold breached */ | ||
1152 | if (rssi > sq_thresh->lower_threshold[0]) { | ||
1153 | ath6kl_dbg(ATH6KL_DBG_WMI, | ||
1154 | "spurious lower rssi threshold event: %d %d\n", | ||
1155 | rssi, sq_thresh->lower_threshold[0]); | ||
1156 | } else if ((rssi > sq_thresh->lower_threshold[1]) && | ||
1157 | (rssi <= sq_thresh->lower_threshold[0])) { | ||
1158 | new_threshold = WMI_RSSI_THRESHOLD6_BELOW; | ||
1159 | } else if ((rssi > sq_thresh->lower_threshold[2]) && | ||
1160 | (rssi <= sq_thresh->lower_threshold[1])) { | ||
1161 | new_threshold = WMI_RSSI_THRESHOLD5_BELOW; | ||
1162 | } else if ((rssi > sq_thresh->lower_threshold[3]) && | ||
1163 | (rssi <= sq_thresh->lower_threshold[2])) { | ||
1164 | new_threshold = WMI_RSSI_THRESHOLD4_BELOW; | ||
1165 | } else if ((rssi > sq_thresh->lower_threshold[4]) && | ||
1166 | (rssi <= sq_thresh->lower_threshold[3])) { | ||
1167 | new_threshold = WMI_RSSI_THRESHOLD3_BELOW; | ||
1168 | } else if ((rssi > sq_thresh->lower_threshold[5]) && | ||
1169 | (rssi <= sq_thresh->lower_threshold[4])) { | ||
1170 | new_threshold = WMI_RSSI_THRESHOLD2_BELOW; | ||
1171 | } else if (rssi <= sq_thresh->lower_threshold[5]) { | ||
1172 | new_threshold = WMI_RSSI_THRESHOLD1_BELOW; | ||
1173 | } | ||
1174 | } | ||
1175 | |||
1176 | /* Calculate and install the next set of thresholds */ | ||
1177 | lower_rssi_threshold = ath6kl_wmi_get_lower_threshold(rssi, sq_thresh, | ||
1178 | sq_thresh->lower_threshold_valid_count); | ||
1179 | upper_rssi_threshold = ath6kl_wmi_get_upper_threshold(rssi, sq_thresh, | ||
1180 | sq_thresh->upper_threshold_valid_count); | ||
1181 | |||
1182 | /* Issue a wmi command to install the thresholds */ | ||
1183 | cmd.thresh_above1_val = a_cpu_to_sle16(upper_rssi_threshold); | ||
1184 | cmd.thresh_below1_val = a_cpu_to_sle16(lower_rssi_threshold); | ||
1185 | cmd.weight = sq_thresh->weight; | ||
1186 | cmd.poll_time = cpu_to_le32(sq_thresh->polling_interval); | ||
1187 | |||
1188 | ret = ath6kl_wmi_send_rssi_threshold_params(wmi, &cmd); | ||
1189 | if (ret) { | ||
1190 | ath6kl_err("unable to configure rssi thresholds\n"); | ||
1191 | return -EIO; | ||
1192 | } | ||
1193 | |||
1194 | return 0; | ||
1195 | } | ||
1196 | |||
1197 | static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len) | ||
1198 | { | ||
1199 | struct wmi_cac_event *reply; | ||
1200 | struct ieee80211_tspec_ie *ts; | ||
1201 | u16 active_tsids, tsinfo; | ||
1202 | u8 tsid, index; | ||
1203 | u8 ts_id; | ||
1204 | |||
1205 | if (len < sizeof(struct wmi_cac_event)) | ||
1206 | return -EINVAL; | ||
1207 | |||
1208 | reply = (struct wmi_cac_event *) datap; | ||
1209 | |||
1210 | if ((reply->cac_indication == CAC_INDICATION_ADMISSION_RESP) && | ||
1211 | (reply->status_code != IEEE80211_TSPEC_STATUS_ADMISS_ACCEPTED)) { | ||
1212 | |||
1213 | ts = (struct ieee80211_tspec_ie *) &(reply->tspec_suggestion); | ||
1214 | tsinfo = le16_to_cpu(ts->tsinfo); | ||
1215 | tsid = (tsinfo >> IEEE80211_WMM_IE_TSPEC_TID_SHIFT) & | ||
1216 | IEEE80211_WMM_IE_TSPEC_TID_MASK; | ||
1217 | |||
1218 | ath6kl_wmi_delete_pstream_cmd(wmi, reply->ac, tsid); | ||
1219 | } else if (reply->cac_indication == CAC_INDICATION_NO_RESP) { | ||
1220 | /* | ||
1221 | * Following assumes that there is only one outstanding | ||
1222 | * ADDTS request when this event is received | ||
1223 | */ | ||
1224 | spin_lock_bh(&wmi->lock); | ||
1225 | active_tsids = wmi->stream_exist_for_ac[reply->ac]; | ||
1226 | spin_unlock_bh(&wmi->lock); | ||
1227 | |||
1228 | for (index = 0; index < sizeof(active_tsids) * 8; index++) { | ||
1229 | if ((active_tsids >> index) & 1) | ||
1230 | break; | ||
1231 | } | ||
1232 | if (index < (sizeof(active_tsids) * 8)) | ||
1233 | ath6kl_wmi_delete_pstream_cmd(wmi, reply->ac, index); | ||
1234 | } | ||
1235 | |||
1236 | /* | ||
1237 | * Clear active tsids and Add missing handling | ||
1238 | * for delete qos stream from AP | ||
1239 | */ | ||
1240 | else if (reply->cac_indication == CAC_INDICATION_DELETE) { | ||
1241 | |||
1242 | ts = (struct ieee80211_tspec_ie *) &(reply->tspec_suggestion); | ||
1243 | tsinfo = le16_to_cpu(ts->tsinfo); | ||
1244 | ts_id = ((tsinfo >> IEEE80211_WMM_IE_TSPEC_TID_SHIFT) & | ||
1245 | IEEE80211_WMM_IE_TSPEC_TID_MASK); | ||
1246 | |||
1247 | spin_lock_bh(&wmi->lock); | ||
1248 | wmi->stream_exist_for_ac[reply->ac] &= ~(1 << ts_id); | ||
1249 | active_tsids = wmi->stream_exist_for_ac[reply->ac]; | ||
1250 | spin_unlock_bh(&wmi->lock); | ||
1251 | |||
1252 | /* Indicate stream inactivity to driver layer only if all tsids | ||
1253 | * within this AC are deleted. | ||
1254 | */ | ||
1255 | if (!active_tsids) { | ||
1256 | ath6kl_indicate_tx_activity(wmi->parent_dev, reply->ac, | ||
1257 | false); | ||
1258 | wmi->fat_pipe_exist &= ~(1 << reply->ac); | ||
1259 | } | ||
1260 | } | ||
1261 | |||
1262 | return 0; | ||
1263 | } | ||
1264 | |||
1265 | static int ath6kl_wmi_send_snr_threshold_params(struct wmi *wmi, | ||
1266 | struct wmi_snr_threshold_params_cmd *snr_cmd) | ||
1267 | { | ||
1268 | struct sk_buff *skb; | ||
1269 | struct wmi_snr_threshold_params_cmd *cmd; | ||
1270 | |||
1271 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
1272 | if (!skb) | ||
1273 | return -ENOMEM; | ||
1274 | |||
1275 | cmd = (struct wmi_snr_threshold_params_cmd *) skb->data; | ||
1276 | memcpy(cmd, snr_cmd, sizeof(struct wmi_snr_threshold_params_cmd)); | ||
1277 | |||
1278 | return ath6kl_wmi_cmd_send(wmi, skb, WMI_SNR_THRESHOLD_PARAMS_CMDID, | ||
1279 | NO_SYNC_WMIFLAG); | ||
1280 | } | ||
1281 | |||
1282 | static int ath6kl_wmi_snr_threshold_event_rx(struct wmi *wmi, u8 *datap, | ||
1283 | int len) | ||
1284 | { | ||
1285 | struct wmi_snr_threshold_event *reply; | ||
1286 | struct sq_threshold_params *sq_thresh; | ||
1287 | struct wmi_snr_threshold_params_cmd cmd; | ||
1288 | enum wmi_snr_threshold_val new_threshold; | ||
1289 | u8 upper_snr_threshold, lower_snr_threshold; | ||
1290 | s16 snr; | ||
1291 | int ret; | ||
1292 | |||
1293 | if (len < sizeof(struct wmi_snr_threshold_event)) | ||
1294 | return -EINVAL; | ||
1295 | |||
1296 | reply = (struct wmi_snr_threshold_event *) datap; | ||
1297 | |||
1298 | new_threshold = (enum wmi_snr_threshold_val) reply->range; | ||
1299 | snr = reply->snr; | ||
1300 | |||
1301 | sq_thresh = &wmi->sq_threshld[SIGNAL_QUALITY_METRICS_SNR]; | ||
1302 | |||
1303 | /* | ||
1304 | * Identify the threshold breached and communicate that to the app. | ||
1305 | * After that install a new set of thresholds based on the signal | ||
1306 | * quality reported by the target. | ||
1307 | */ | ||
1308 | if (new_threshold) { | ||
1309 | /* Upper threshold breached */ | ||
1310 | if (snr < sq_thresh->upper_threshold[0]) { | ||
1311 | ath6kl_dbg(ATH6KL_DBG_WMI, | ||
1312 | "spurious upper snr threshold event: %d\n", | ||
1313 | snr); | ||
1314 | } else if ((snr < sq_thresh->upper_threshold[1]) && | ||
1315 | (snr >= sq_thresh->upper_threshold[0])) { | ||
1316 | new_threshold = WMI_SNR_THRESHOLD1_ABOVE; | ||
1317 | } else if ((snr < sq_thresh->upper_threshold[2]) && | ||
1318 | (snr >= sq_thresh->upper_threshold[1])) { | ||
1319 | new_threshold = WMI_SNR_THRESHOLD2_ABOVE; | ||
1320 | } else if ((snr < sq_thresh->upper_threshold[3]) && | ||
1321 | (snr >= sq_thresh->upper_threshold[2])) { | ||
1322 | new_threshold = WMI_SNR_THRESHOLD3_ABOVE; | ||
1323 | } else if (snr >= sq_thresh->upper_threshold[3]) { | ||
1324 | new_threshold = WMI_SNR_THRESHOLD4_ABOVE; | ||
1325 | } | ||
1326 | } else { | ||
1327 | /* Lower threshold breached */ | ||
1328 | if (snr > sq_thresh->lower_threshold[0]) { | ||
1329 | ath6kl_dbg(ATH6KL_DBG_WMI, | ||
1330 | "spurious lower snr threshold event: %d\n", | ||
1331 | sq_thresh->lower_threshold[0]); | ||
1332 | } else if ((snr > sq_thresh->lower_threshold[1]) && | ||
1333 | (snr <= sq_thresh->lower_threshold[0])) { | ||
1334 | new_threshold = WMI_SNR_THRESHOLD4_BELOW; | ||
1335 | } else if ((snr > sq_thresh->lower_threshold[2]) && | ||
1336 | (snr <= sq_thresh->lower_threshold[1])) { | ||
1337 | new_threshold = WMI_SNR_THRESHOLD3_BELOW; | ||
1338 | } else if ((snr > sq_thresh->lower_threshold[3]) && | ||
1339 | (snr <= sq_thresh->lower_threshold[2])) { | ||
1340 | new_threshold = WMI_SNR_THRESHOLD2_BELOW; | ||
1341 | } else if (snr <= sq_thresh->lower_threshold[3]) { | ||
1342 | new_threshold = WMI_SNR_THRESHOLD1_BELOW; | ||
1343 | } | ||
1344 | } | ||
1345 | |||
1346 | /* Calculate and install the next set of thresholds */ | ||
1347 | lower_snr_threshold = ath6kl_wmi_get_lower_threshold(snr, sq_thresh, | ||
1348 | sq_thresh->lower_threshold_valid_count); | ||
1349 | upper_snr_threshold = ath6kl_wmi_get_upper_threshold(snr, sq_thresh, | ||
1350 | sq_thresh->upper_threshold_valid_count); | ||
1351 | |||
1352 | /* Issue a wmi command to install the thresholds */ | ||
1353 | cmd.thresh_above1_val = upper_snr_threshold; | ||
1354 | cmd.thresh_below1_val = lower_snr_threshold; | ||
1355 | cmd.weight = sq_thresh->weight; | ||
1356 | cmd.poll_time = cpu_to_le32(sq_thresh->polling_interval); | ||
1357 | |||
1358 | ath6kl_dbg(ATH6KL_DBG_WMI, | ||
1359 | "snr: %d, threshold: %d, lower: %d, upper: %d\n", | ||
1360 | snr, new_threshold, | ||
1361 | lower_snr_threshold, upper_snr_threshold); | ||
1362 | |||
1363 | ret = ath6kl_wmi_send_snr_threshold_params(wmi, &cmd); | ||
1364 | if (ret) { | ||
1365 | ath6kl_err("unable to configure snr threshold\n"); | ||
1366 | return -EIO; | ||
1367 | } | ||
1368 | |||
1369 | return 0; | ||
1370 | } | ||
1371 | |||
1372 | static int ath6kl_wmi_aplist_event_rx(struct wmi *wmi, u8 *datap, int len) | ||
1373 | { | ||
1374 | u16 ap_info_entry_size; | ||
1375 | struct wmi_aplist_event *ev = (struct wmi_aplist_event *) datap; | ||
1376 | struct wmi_ap_info_v1 *ap_info_v1; | ||
1377 | u8 index; | ||
1378 | |||
1379 | if (len < sizeof(struct wmi_aplist_event) || | ||
1380 | ev->ap_list_ver != APLIST_VER1) | ||
1381 | return -EINVAL; | ||
1382 | |||
1383 | ap_info_entry_size = sizeof(struct wmi_ap_info_v1); | ||
1384 | ap_info_v1 = (struct wmi_ap_info_v1 *) ev->ap_list; | ||
1385 | |||
1386 | ath6kl_dbg(ATH6KL_DBG_WMI, | ||
1387 | "number of APs in aplist event: %d\n", ev->num_ap); | ||
1388 | |||
1389 | if (len < (int) (sizeof(struct wmi_aplist_event) + | ||
1390 | (ev->num_ap - 1) * ap_info_entry_size)) | ||
1391 | return -EINVAL; | ||
1392 | |||
1393 | /* AP list version 1 contents */ | ||
1394 | for (index = 0; index < ev->num_ap; index++) { | ||
1395 | ath6kl_dbg(ATH6KL_DBG_WMI, "AP#%d BSSID %pM Channel %d\n", | ||
1396 | index, ap_info_v1->bssid, ap_info_v1->channel); | ||
1397 | ap_info_v1++; | ||
1398 | } | ||
1399 | |||
1400 | return 0; | ||
1401 | } | ||
1402 | |||
1403 | int ath6kl_wmi_cmd_send(struct wmi *wmi, struct sk_buff *skb, | ||
1404 | enum wmi_cmd_id cmd_id, enum wmi_sync_flag sync_flag) | ||
1405 | { | ||
1406 | struct wmi_cmd_hdr *cmd_hdr; | ||
1407 | enum htc_endpoint_id ep_id = wmi->ep_id; | ||
1408 | int ret; | ||
1409 | |||
1410 | if (WARN_ON(skb == NULL)) | ||
1411 | return -EINVAL; | ||
1412 | |||
1413 | if (sync_flag >= END_WMIFLAG) { | ||
1414 | dev_kfree_skb(skb); | ||
1415 | return -EINVAL; | ||
1416 | } | ||
1417 | |||
1418 | if ((sync_flag == SYNC_BEFORE_WMIFLAG) || | ||
1419 | (sync_flag == SYNC_BOTH_WMIFLAG)) { | ||
1420 | /* | ||
1421 | * Make sure all data currently queued is transmitted before | ||
1422 | * the cmd execution. Establish a new sync point. | ||
1423 | */ | ||
1424 | ath6kl_wmi_sync_point(wmi); | ||
1425 | } | ||
1426 | |||
1427 | skb_push(skb, sizeof(struct wmi_cmd_hdr)); | ||
1428 | |||
1429 | cmd_hdr = (struct wmi_cmd_hdr *) skb->data; | ||
1430 | cmd_hdr->cmd_id = cpu_to_le16(cmd_id); | ||
1431 | cmd_hdr->info1 = 0; /* added for virtual interface */ | ||
1432 | |||
1433 | /* Only for OPT_TX_CMD, use BE endpoint. */ | ||
1434 | if (cmd_id == WMI_OPT_TX_FRAME_CMDID) { | ||
1435 | ret = ath6kl_wmi_data_hdr_add(wmi, skb, OPT_MSGTYPE, | ||
1436 | false, false, 0, NULL); | ||
1437 | if (ret) { | ||
1438 | dev_kfree_skb(skb); | ||
1439 | return ret; | ||
1440 | } | ||
1441 | ep_id = ath6kl_ac2_endpoint_id(wmi->parent_dev, WMM_AC_BE); | ||
1442 | } | ||
1443 | |||
1444 | ath6kl_control_tx(wmi->parent_dev, skb, ep_id); | ||
1445 | |||
1446 | if ((sync_flag == SYNC_AFTER_WMIFLAG) || | ||
1447 | (sync_flag == SYNC_BOTH_WMIFLAG)) { | ||
1448 | /* | ||
1449 | * Make sure all new data queued waits for the command to | ||
1450 | * execute. Establish a new sync point. | ||
1451 | */ | ||
1452 | ath6kl_wmi_sync_point(wmi); | ||
1453 | } | ||
1454 | |||
1455 | return 0; | ||
1456 | } | ||
1457 | |||
1458 | int ath6kl_wmi_connect_cmd(struct wmi *wmi, enum network_type nw_type, | ||
1459 | enum dot11_auth_mode dot11_auth_mode, | ||
1460 | enum auth_mode auth_mode, | ||
1461 | enum crypto_type pairwise_crypto, | ||
1462 | u8 pairwise_crypto_len, | ||
1463 | enum crypto_type group_crypto, | ||
1464 | u8 group_crypto_len, int ssid_len, u8 *ssid, | ||
1465 | u8 *bssid, u16 channel, u32 ctrl_flags) | ||
1466 | { | ||
1467 | struct sk_buff *skb; | ||
1468 | struct wmi_connect_cmd *cc; | ||
1469 | int ret; | ||
1470 | |||
1471 | wmi->traffic_class = 100; | ||
1472 | |||
1473 | if ((pairwise_crypto == NONE_CRYPT) && (group_crypto != NONE_CRYPT)) | ||
1474 | return -EINVAL; | ||
1475 | |||
1476 | if ((pairwise_crypto != NONE_CRYPT) && (group_crypto == NONE_CRYPT)) | ||
1477 | return -EINVAL; | ||
1478 | |||
1479 | skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_connect_cmd)); | ||
1480 | if (!skb) | ||
1481 | return -ENOMEM; | ||
1482 | |||
1483 | cc = (struct wmi_connect_cmd *) skb->data; | ||
1484 | |||
1485 | if (ssid_len) | ||
1486 | memcpy(cc->ssid, ssid, ssid_len); | ||
1487 | |||
1488 | cc->ssid_len = ssid_len; | ||
1489 | cc->nw_type = nw_type; | ||
1490 | cc->dot11_auth_mode = dot11_auth_mode; | ||
1491 | cc->auth_mode = auth_mode; | ||
1492 | cc->prwise_crypto_type = pairwise_crypto; | ||
1493 | cc->prwise_crypto_len = pairwise_crypto_len; | ||
1494 | cc->grp_crypto_type = group_crypto; | ||
1495 | cc->grp_crypto_len = group_crypto_len; | ||
1496 | cc->ch = cpu_to_le16(channel); | ||
1497 | cc->ctrl_flags = cpu_to_le32(ctrl_flags); | ||
1498 | |||
1499 | if (bssid != NULL) | ||
1500 | memcpy(cc->bssid, bssid, ETH_ALEN); | ||
1501 | |||
1502 | wmi->pair_crypto_type = pairwise_crypto; | ||
1503 | wmi->grp_crypto_type = group_crypto; | ||
1504 | |||
1505 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_CONNECT_CMDID, NO_SYNC_WMIFLAG); | ||
1506 | |||
1507 | return ret; | ||
1508 | } | ||
1509 | |||
1510 | int ath6kl_wmi_reconnect_cmd(struct wmi *wmi, u8 *bssid, u16 channel) | ||
1511 | { | ||
1512 | struct sk_buff *skb; | ||
1513 | struct wmi_reconnect_cmd *cc; | ||
1514 | int ret; | ||
1515 | |||
1516 | wmi->traffic_class = 100; | ||
1517 | |||
1518 | skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_reconnect_cmd)); | ||
1519 | if (!skb) | ||
1520 | return -ENOMEM; | ||
1521 | |||
1522 | cc = (struct wmi_reconnect_cmd *) skb->data; | ||
1523 | cc->channel = cpu_to_le16(channel); | ||
1524 | |||
1525 | if (bssid != NULL) | ||
1526 | memcpy(cc->bssid, bssid, ETH_ALEN); | ||
1527 | |||
1528 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_RECONNECT_CMDID, | ||
1529 | NO_SYNC_WMIFLAG); | ||
1530 | |||
1531 | return ret; | ||
1532 | } | ||
1533 | |||
1534 | int ath6kl_wmi_disconnect_cmd(struct wmi *wmi) | ||
1535 | { | ||
1536 | int ret; | ||
1537 | |||
1538 | wmi->traffic_class = 100; | ||
1539 | |||
1540 | /* Disconnect command does not need to do a SYNC before. */ | ||
1541 | ret = ath6kl_wmi_simple_cmd(wmi, WMI_DISCONNECT_CMDID); | ||
1542 | |||
1543 | return ret; | ||
1544 | } | ||
1545 | |||
1546 | int ath6kl_wmi_startscan_cmd(struct wmi *wmi, enum wmi_scan_type scan_type, | ||
1547 | u32 force_fgscan, u32 is_legacy, | ||
1548 | u32 home_dwell_time, u32 force_scan_interval, | ||
1549 | s8 num_chan, u16 *ch_list) | ||
1550 | { | ||
1551 | struct sk_buff *skb; | ||
1552 | struct wmi_start_scan_cmd *sc; | ||
1553 | s8 size; | ||
1554 | int ret; | ||
1555 | |||
1556 | size = sizeof(struct wmi_start_scan_cmd); | ||
1557 | |||
1558 | if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN)) | ||
1559 | return -EINVAL; | ||
1560 | |||
1561 | if (num_chan > WMI_MAX_CHANNELS) | ||
1562 | return -EINVAL; | ||
1563 | |||
1564 | if (num_chan) | ||
1565 | size += sizeof(u16) * (num_chan - 1); | ||
1566 | |||
1567 | skb = ath6kl_wmi_get_new_buf(size); | ||
1568 | if (!skb) | ||
1569 | return -ENOMEM; | ||
1570 | |||
1571 | sc = (struct wmi_start_scan_cmd *) skb->data; | ||
1572 | sc->scan_type = scan_type; | ||
1573 | sc->force_fg_scan = cpu_to_le32(force_fgscan); | ||
1574 | sc->is_legacy = cpu_to_le32(is_legacy); | ||
1575 | sc->home_dwell_time = cpu_to_le32(home_dwell_time); | ||
1576 | sc->force_scan_intvl = cpu_to_le32(force_scan_interval); | ||
1577 | sc->num_ch = num_chan; | ||
1578 | |||
1579 | if (num_chan) | ||
1580 | memcpy(sc->ch_list, ch_list, num_chan * sizeof(u16)); | ||
1581 | |||
1582 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_START_SCAN_CMDID, | ||
1583 | NO_SYNC_WMIFLAG); | ||
1584 | |||
1585 | return ret; | ||
1586 | } | ||
1587 | |||
1588 | int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u16 fg_start_sec, | ||
1589 | u16 fg_end_sec, u16 bg_sec, | ||
1590 | u16 minact_chdw_msec, u16 maxact_chdw_msec, | ||
1591 | u16 pas_chdw_msec, u8 short_scan_ratio, | ||
1592 | u8 scan_ctrl_flag, u32 max_dfsch_act_time, | ||
1593 | u16 maxact_scan_per_ssid) | ||
1594 | { | ||
1595 | struct sk_buff *skb; | ||
1596 | struct wmi_scan_params_cmd *sc; | ||
1597 | int ret; | ||
1598 | |||
1599 | skb = ath6kl_wmi_get_new_buf(sizeof(*sc)); | ||
1600 | if (!skb) | ||
1601 | return -ENOMEM; | ||
1602 | |||
1603 | sc = (struct wmi_scan_params_cmd *) skb->data; | ||
1604 | sc->fg_start_period = cpu_to_le16(fg_start_sec); | ||
1605 | sc->fg_end_period = cpu_to_le16(fg_end_sec); | ||
1606 | sc->bg_period = cpu_to_le16(bg_sec); | ||
1607 | sc->minact_chdwell_time = cpu_to_le16(minact_chdw_msec); | ||
1608 | sc->maxact_chdwell_time = cpu_to_le16(maxact_chdw_msec); | ||
1609 | sc->pas_chdwell_time = cpu_to_le16(pas_chdw_msec); | ||
1610 | sc->short_scan_ratio = short_scan_ratio; | ||
1611 | sc->scan_ctrl_flags = scan_ctrl_flag; | ||
1612 | sc->max_dfsch_act_time = cpu_to_le32(max_dfsch_act_time); | ||
1613 | sc->maxact_scan_per_ssid = cpu_to_le16(maxact_scan_per_ssid); | ||
1614 | |||
1615 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_SCAN_PARAMS_CMDID, | ||
1616 | NO_SYNC_WMIFLAG); | ||
1617 | return ret; | ||
1618 | } | ||
1619 | |||
1620 | int ath6kl_wmi_bssfilter_cmd(struct wmi *wmi, u8 filter, u32 ie_mask) | ||
1621 | { | ||
1622 | struct sk_buff *skb; | ||
1623 | struct wmi_bss_filter_cmd *cmd; | ||
1624 | int ret; | ||
1625 | |||
1626 | if (filter >= LAST_BSS_FILTER) | ||
1627 | return -EINVAL; | ||
1628 | |||
1629 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
1630 | if (!skb) | ||
1631 | return -ENOMEM; | ||
1632 | |||
1633 | cmd = (struct wmi_bss_filter_cmd *) skb->data; | ||
1634 | cmd->bss_filter = filter; | ||
1635 | cmd->ie_mask = cpu_to_le32(ie_mask); | ||
1636 | |||
1637 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_BSS_FILTER_CMDID, | ||
1638 | NO_SYNC_WMIFLAG); | ||
1639 | return ret; | ||
1640 | } | ||
1641 | |||
1642 | int ath6kl_wmi_probedssid_cmd(struct wmi *wmi, u8 index, u8 flag, | ||
1643 | u8 ssid_len, u8 *ssid) | ||
1644 | { | ||
1645 | struct sk_buff *skb; | ||
1646 | struct wmi_probed_ssid_cmd *cmd; | ||
1647 | int ret; | ||
1648 | |||
1649 | if (index > MAX_PROBED_SSID_INDEX) | ||
1650 | return -EINVAL; | ||
1651 | |||
1652 | if (ssid_len > sizeof(cmd->ssid)) | ||
1653 | return -EINVAL; | ||
1654 | |||
1655 | if ((flag & (DISABLE_SSID_FLAG | ANY_SSID_FLAG)) && (ssid_len > 0)) | ||
1656 | return -EINVAL; | ||
1657 | |||
1658 | if ((flag & SPECIFIC_SSID_FLAG) && !ssid_len) | ||
1659 | return -EINVAL; | ||
1660 | |||
1661 | if (flag & SPECIFIC_SSID_FLAG) | ||
1662 | wmi->is_probe_ssid = true; | ||
1663 | |||
1664 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
1665 | if (!skb) | ||
1666 | return -ENOMEM; | ||
1667 | |||
1668 | cmd = (struct wmi_probed_ssid_cmd *) skb->data; | ||
1669 | cmd->entry_index = index; | ||
1670 | cmd->flag = flag; | ||
1671 | cmd->ssid_len = ssid_len; | ||
1672 | memcpy(cmd->ssid, ssid, ssid_len); | ||
1673 | |||
1674 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_PROBED_SSID_CMDID, | ||
1675 | NO_SYNC_WMIFLAG); | ||
1676 | return ret; | ||
1677 | } | ||
1678 | |||
1679 | int ath6kl_wmi_listeninterval_cmd(struct wmi *wmi, u16 listen_interval, | ||
1680 | u16 listen_beacons) | ||
1681 | { | ||
1682 | struct sk_buff *skb; | ||
1683 | struct wmi_listen_int_cmd *cmd; | ||
1684 | int ret; | ||
1685 | |||
1686 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
1687 | if (!skb) | ||
1688 | return -ENOMEM; | ||
1689 | |||
1690 | cmd = (struct wmi_listen_int_cmd *) skb->data; | ||
1691 | cmd->listen_intvl = cpu_to_le16(listen_interval); | ||
1692 | cmd->num_beacons = cpu_to_le16(listen_beacons); | ||
1693 | |||
1694 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_LISTEN_INT_CMDID, | ||
1695 | NO_SYNC_WMIFLAG); | ||
1696 | return ret; | ||
1697 | } | ||
1698 | |||
1699 | int ath6kl_wmi_powermode_cmd(struct wmi *wmi, u8 pwr_mode) | ||
1700 | { | ||
1701 | struct sk_buff *skb; | ||
1702 | struct wmi_power_mode_cmd *cmd; | ||
1703 | int ret; | ||
1704 | |||
1705 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
1706 | if (!skb) | ||
1707 | return -ENOMEM; | ||
1708 | |||
1709 | cmd = (struct wmi_power_mode_cmd *) skb->data; | ||
1710 | cmd->pwr_mode = pwr_mode; | ||
1711 | wmi->pwr_mode = pwr_mode; | ||
1712 | |||
1713 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_POWER_MODE_CMDID, | ||
1714 | NO_SYNC_WMIFLAG); | ||
1715 | return ret; | ||
1716 | } | ||
1717 | |||
1718 | int ath6kl_wmi_pmparams_cmd(struct wmi *wmi, u16 idle_period, | ||
1719 | u16 ps_poll_num, u16 dtim_policy, | ||
1720 | u16 tx_wakeup_policy, u16 num_tx_to_wakeup, | ||
1721 | u16 ps_fail_event_policy) | ||
1722 | { | ||
1723 | struct sk_buff *skb; | ||
1724 | struct wmi_power_params_cmd *pm; | ||
1725 | int ret; | ||
1726 | |||
1727 | skb = ath6kl_wmi_get_new_buf(sizeof(*pm)); | ||
1728 | if (!skb) | ||
1729 | return -ENOMEM; | ||
1730 | |||
1731 | pm = (struct wmi_power_params_cmd *)skb->data; | ||
1732 | pm->idle_period = cpu_to_le16(idle_period); | ||
1733 | pm->pspoll_number = cpu_to_le16(ps_poll_num); | ||
1734 | pm->dtim_policy = cpu_to_le16(dtim_policy); | ||
1735 | pm->tx_wakeup_policy = cpu_to_le16(tx_wakeup_policy); | ||
1736 | pm->num_tx_to_wakeup = cpu_to_le16(num_tx_to_wakeup); | ||
1737 | pm->ps_fail_event_policy = cpu_to_le16(ps_fail_event_policy); | ||
1738 | |||
1739 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_POWER_PARAMS_CMDID, | ||
1740 | NO_SYNC_WMIFLAG); | ||
1741 | return ret; | ||
1742 | } | ||
1743 | |||
1744 | int ath6kl_wmi_disctimeout_cmd(struct wmi *wmi, u8 timeout) | ||
1745 | { | ||
1746 | struct sk_buff *skb; | ||
1747 | struct wmi_disc_timeout_cmd *cmd; | ||
1748 | int ret; | ||
1749 | |||
1750 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
1751 | if (!skb) | ||
1752 | return -ENOMEM; | ||
1753 | |||
1754 | cmd = (struct wmi_disc_timeout_cmd *) skb->data; | ||
1755 | cmd->discon_timeout = timeout; | ||
1756 | |||
1757 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_DISC_TIMEOUT_CMDID, | ||
1758 | NO_SYNC_WMIFLAG); | ||
1759 | return ret; | ||
1760 | } | ||
1761 | |||
1762 | int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 key_index, | ||
1763 | enum crypto_type key_type, | ||
1764 | u8 key_usage, u8 key_len, | ||
1765 | u8 *key_rsc, u8 *key_material, | ||
1766 | u8 key_op_ctrl, u8 *mac_addr, | ||
1767 | enum wmi_sync_flag sync_flag) | ||
1768 | { | ||
1769 | struct sk_buff *skb; | ||
1770 | struct wmi_add_cipher_key_cmd *cmd; | ||
1771 | int ret; | ||
1772 | |||
1773 | if ((key_index > WMI_MAX_KEY_INDEX) || (key_len > WMI_MAX_KEY_LEN) || | ||
1774 | (key_material == NULL)) | ||
1775 | return -EINVAL; | ||
1776 | |||
1777 | if ((WEP_CRYPT != key_type) && (NULL == key_rsc)) | ||
1778 | return -EINVAL; | ||
1779 | |||
1780 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
1781 | if (!skb) | ||
1782 | return -ENOMEM; | ||
1783 | |||
1784 | cmd = (struct wmi_add_cipher_key_cmd *) skb->data; | ||
1785 | cmd->key_index = key_index; | ||
1786 | cmd->key_type = key_type; | ||
1787 | cmd->key_usage = key_usage; | ||
1788 | cmd->key_len = key_len; | ||
1789 | memcpy(cmd->key, key_material, key_len); | ||
1790 | |||
1791 | if (key_rsc != NULL) | ||
1792 | memcpy(cmd->key_rsc, key_rsc, sizeof(cmd->key_rsc)); | ||
1793 | |||
1794 | cmd->key_op_ctrl = key_op_ctrl; | ||
1795 | |||
1796 | if (mac_addr) | ||
1797 | memcpy(cmd->key_mac_addr, mac_addr, ETH_ALEN); | ||
1798 | |||
1799 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_ADD_CIPHER_KEY_CMDID, | ||
1800 | sync_flag); | ||
1801 | |||
1802 | return ret; | ||
1803 | } | ||
1804 | |||
1805 | int ath6kl_wmi_add_krk_cmd(struct wmi *wmi, u8 *krk) | ||
1806 | { | ||
1807 | struct sk_buff *skb; | ||
1808 | struct wmi_add_krk_cmd *cmd; | ||
1809 | int ret; | ||
1810 | |||
1811 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
1812 | if (!skb) | ||
1813 | return -ENOMEM; | ||
1814 | |||
1815 | cmd = (struct wmi_add_krk_cmd *) skb->data; | ||
1816 | memcpy(cmd->krk, krk, WMI_KRK_LEN); | ||
1817 | |||
1818 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_ADD_KRK_CMDID, NO_SYNC_WMIFLAG); | ||
1819 | |||
1820 | return ret; | ||
1821 | } | ||
1822 | |||
1823 | int ath6kl_wmi_deletekey_cmd(struct wmi *wmi, u8 key_index) | ||
1824 | { | ||
1825 | struct sk_buff *skb; | ||
1826 | struct wmi_delete_cipher_key_cmd *cmd; | ||
1827 | int ret; | ||
1828 | |||
1829 | if (key_index > WMI_MAX_KEY_INDEX) | ||
1830 | return -EINVAL; | ||
1831 | |||
1832 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
1833 | if (!skb) | ||
1834 | return -ENOMEM; | ||
1835 | |||
1836 | cmd = (struct wmi_delete_cipher_key_cmd *) skb->data; | ||
1837 | cmd->key_index = key_index; | ||
1838 | |||
1839 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_DELETE_CIPHER_KEY_CMDID, | ||
1840 | NO_SYNC_WMIFLAG); | ||
1841 | |||
1842 | return ret; | ||
1843 | } | ||
1844 | |||
1845 | int ath6kl_wmi_setpmkid_cmd(struct wmi *wmi, const u8 *bssid, | ||
1846 | const u8 *pmkid, bool set) | ||
1847 | { | ||
1848 | struct sk_buff *skb; | ||
1849 | struct wmi_setpmkid_cmd *cmd; | ||
1850 | int ret; | ||
1851 | |||
1852 | if (bssid == NULL) | ||
1853 | return -EINVAL; | ||
1854 | |||
1855 | if (set && pmkid == NULL) | ||
1856 | return -EINVAL; | ||
1857 | |||
1858 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
1859 | if (!skb) | ||
1860 | return -ENOMEM; | ||
1861 | |||
1862 | cmd = (struct wmi_setpmkid_cmd *) skb->data; | ||
1863 | memcpy(cmd->bssid, bssid, ETH_ALEN); | ||
1864 | if (set) { | ||
1865 | memcpy(cmd->pmkid, pmkid, sizeof(cmd->pmkid)); | ||
1866 | cmd->enable = PMKID_ENABLE; | ||
1867 | } else { | ||
1868 | memset(cmd->pmkid, 0, sizeof(cmd->pmkid)); | ||
1869 | cmd->enable = PMKID_DISABLE; | ||
1870 | } | ||
1871 | |||
1872 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_PMKID_CMDID, | ||
1873 | NO_SYNC_WMIFLAG); | ||
1874 | |||
1875 | return ret; | ||
1876 | } | ||
1877 | |||
1878 | static int ath6kl_wmi_data_sync_send(struct wmi *wmi, struct sk_buff *skb, | ||
1879 | enum htc_endpoint_id ep_id) | ||
1880 | { | ||
1881 | struct wmi_data_hdr *data_hdr; | ||
1882 | int ret; | ||
1883 | |||
1884 | if (WARN_ON(skb == NULL || ep_id == wmi->ep_id)) | ||
1885 | return -EINVAL; | ||
1886 | |||
1887 | skb_push(skb, sizeof(struct wmi_data_hdr)); | ||
1888 | |||
1889 | data_hdr = (struct wmi_data_hdr *) skb->data; | ||
1890 | data_hdr->info = SYNC_MSGTYPE << WMI_DATA_HDR_MSG_TYPE_SHIFT; | ||
1891 | data_hdr->info3 = 0; | ||
1892 | |||
1893 | ret = ath6kl_control_tx(wmi->parent_dev, skb, ep_id); | ||
1894 | |||
1895 | return ret; | ||
1896 | } | ||
1897 | |||
1898 | static int ath6kl_wmi_sync_point(struct wmi *wmi) | ||
1899 | { | ||
1900 | struct sk_buff *skb; | ||
1901 | struct wmi_sync_cmd *cmd; | ||
1902 | struct wmi_data_sync_bufs data_sync_bufs[WMM_NUM_AC]; | ||
1903 | enum htc_endpoint_id ep_id; | ||
1904 | u8 index, num_pri_streams = 0; | ||
1905 | int ret = 0; | ||
1906 | |||
1907 | memset(data_sync_bufs, 0, sizeof(data_sync_bufs)); | ||
1908 | |||
1909 | spin_lock_bh(&wmi->lock); | ||
1910 | |||
1911 | for (index = 0; index < WMM_NUM_AC; index++) { | ||
1912 | if (wmi->fat_pipe_exist & (1 << index)) { | ||
1913 | num_pri_streams++; | ||
1914 | data_sync_bufs[num_pri_streams - 1].traffic_class = | ||
1915 | index; | ||
1916 | } | ||
1917 | } | ||
1918 | |||
1919 | spin_unlock_bh(&wmi->lock); | ||
1920 | |||
1921 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
1922 | if (!skb) { | ||
1923 | ret = -ENOMEM; | ||
1924 | goto free_skb; | ||
1925 | } | ||
1926 | |||
1927 | cmd = (struct wmi_sync_cmd *) skb->data; | ||
1928 | |||
1929 | /* | ||
1930 | * In the SYNC cmd sent on the control Ep, send a bitmap | ||
1931 | * of the data eps on which the Data Sync will be sent | ||
1932 | */ | ||
1933 | cmd->data_sync_map = wmi->fat_pipe_exist; | ||
1934 | |||
1935 | for (index = 0; index < num_pri_streams; index++) { | ||
1936 | data_sync_bufs[index].skb = ath6kl_buf_alloc(0); | ||
1937 | if (data_sync_bufs[index].skb == NULL) { | ||
1938 | ret = -ENOMEM; | ||
1939 | break; | ||
1940 | } | ||
1941 | } | ||
1942 | |||
1943 | /* | ||
1944 | * If buffer allocation for any of the dataSync fails, | ||
1945 | * then do not send the Synchronize cmd on the control ep | ||
1946 | */ | ||
1947 | if (ret) | ||
1948 | goto free_skb; | ||
1949 | |||
1950 | /* | ||
1951 | * Send sync cmd followed by sync data messages on all | ||
1952 | * endpoints being used | ||
1953 | */ | ||
1954 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SYNCHRONIZE_CMDID, | ||
1955 | NO_SYNC_WMIFLAG); | ||
1956 | |||
1957 | if (ret) | ||
1958 | goto free_skb; | ||
1959 | |||
1960 | /* cmd buffer sent, we no longer own it */ | ||
1961 | skb = NULL; | ||
1962 | |||
1963 | for (index = 0; index < num_pri_streams; index++) { | ||
1964 | |||
1965 | if (WARN_ON(!data_sync_bufs[index].skb)) | ||
1966 | break; | ||
1967 | |||
1968 | ep_id = ath6kl_ac2_endpoint_id(wmi->parent_dev, | ||
1969 | data_sync_bufs[index]. | ||
1970 | traffic_class); | ||
1971 | ret = | ||
1972 | ath6kl_wmi_data_sync_send(wmi, data_sync_bufs[index].skb, | ||
1973 | ep_id); | ||
1974 | |||
1975 | if (ret) | ||
1976 | break; | ||
1977 | |||
1978 | data_sync_bufs[index].skb = NULL; | ||
1979 | } | ||
1980 | |||
1981 | free_skb: | ||
1982 | /* free up any resources left over (possibly due to an error) */ | ||
1983 | if (skb) | ||
1984 | dev_kfree_skb(skb); | ||
1985 | |||
1986 | for (index = 0; index < num_pri_streams; index++) { | ||
1987 | if (data_sync_bufs[index].skb != NULL) { | ||
1988 | dev_kfree_skb((struct sk_buff *)data_sync_bufs[index]. | ||
1989 | skb); | ||
1990 | } | ||
1991 | } | ||
1992 | |||
1993 | return ret; | ||
1994 | } | ||
1995 | |||
1996 | int ath6kl_wmi_create_pstream_cmd(struct wmi *wmi, | ||
1997 | struct wmi_create_pstream_cmd *params) | ||
1998 | { | ||
1999 | struct sk_buff *skb; | ||
2000 | struct wmi_create_pstream_cmd *cmd; | ||
2001 | u8 fatpipe_exist_for_ac = 0; | ||
2002 | s32 min_phy = 0; | ||
2003 | s32 nominal_phy = 0; | ||
2004 | int ret; | ||
2005 | |||
2006 | if (!((params->user_pri < 8) && | ||
2007 | (params->user_pri <= 0x7) && | ||
2008 | (up_to_ac[params->user_pri & 0x7] == params->traffic_class) && | ||
2009 | (params->traffic_direc == UPLINK_TRAFFIC || | ||
2010 | params->traffic_direc == DNLINK_TRAFFIC || | ||
2011 | params->traffic_direc == BIDIR_TRAFFIC) && | ||
2012 | (params->traffic_type == TRAFFIC_TYPE_APERIODIC || | ||
2013 | params->traffic_type == TRAFFIC_TYPE_PERIODIC) && | ||
2014 | (params->voice_psc_cap == DISABLE_FOR_THIS_AC || | ||
2015 | params->voice_psc_cap == ENABLE_FOR_THIS_AC || | ||
2016 | params->voice_psc_cap == ENABLE_FOR_ALL_AC) && | ||
2017 | (params->tsid == WMI_IMPLICIT_PSTREAM || | ||
2018 | params->tsid <= WMI_MAX_THINSTREAM))) { | ||
2019 | return -EINVAL; | ||
2020 | } | ||
2021 | |||
2022 | /* | ||
2023 | * Check nominal PHY rate is >= minimalPHY, | ||
2024 | * so that DUT can allow TSRS IE | ||
2025 | */ | ||
2026 | |||
2027 | /* Get the physical rate (units of bps) */ | ||
2028 | min_phy = ((le32_to_cpu(params->min_phy_rate) / 1000) / 1000); | ||
2029 | |||
2030 | /* Check minimal phy < nominal phy rate */ | ||
2031 | if (params->nominal_phy >= min_phy) { | ||
2032 | /* unit of 500 kbps */ | ||
2033 | nominal_phy = (params->nominal_phy * 1000) / 500; | ||
2034 | ath6kl_dbg(ATH6KL_DBG_WMI, | ||
2035 | "TSRS IE enabled::MinPhy %x->NominalPhy ===> %x\n", | ||
2036 | min_phy, nominal_phy); | ||
2037 | |||
2038 | params->nominal_phy = nominal_phy; | ||
2039 | } else { | ||
2040 | params->nominal_phy = 0; | ||
2041 | } | ||
2042 | |||
2043 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
2044 | if (!skb) | ||
2045 | return -ENOMEM; | ||
2046 | |||
2047 | ath6kl_dbg(ATH6KL_DBG_WMI, | ||
2048 | "sending create_pstream_cmd: ac=%d tsid:%d\n", | ||
2049 | params->traffic_class, params->tsid); | ||
2050 | |||
2051 | cmd = (struct wmi_create_pstream_cmd *) skb->data; | ||
2052 | memcpy(cmd, params, sizeof(*cmd)); | ||
2053 | |||
2054 | /* This is an implicitly created Fat pipe */ | ||
2055 | if ((u32) params->tsid == (u32) WMI_IMPLICIT_PSTREAM) { | ||
2056 | spin_lock_bh(&wmi->lock); | ||
2057 | fatpipe_exist_for_ac = (wmi->fat_pipe_exist & | ||
2058 | (1 << params->traffic_class)); | ||
2059 | wmi->fat_pipe_exist |= (1 << params->traffic_class); | ||
2060 | spin_unlock_bh(&wmi->lock); | ||
2061 | } else { | ||
2062 | /* explicitly created thin stream within a fat pipe */ | ||
2063 | spin_lock_bh(&wmi->lock); | ||
2064 | fatpipe_exist_for_ac = (wmi->fat_pipe_exist & | ||
2065 | (1 << params->traffic_class)); | ||
2066 | wmi->stream_exist_for_ac[params->traffic_class] |= | ||
2067 | (1 << params->tsid); | ||
2068 | /* | ||
2069 | * If a thinstream becomes active, the fat pipe automatically | ||
2070 | * becomes active | ||
2071 | */ | ||
2072 | wmi->fat_pipe_exist |= (1 << params->traffic_class); | ||
2073 | spin_unlock_bh(&wmi->lock); | ||
2074 | } | ||
2075 | |||
2076 | /* | ||
2077 | * Indicate activty change to driver layer only if this is the | ||
2078 | * first TSID to get created in this AC explicitly or an implicit | ||
2079 | * fat pipe is getting created. | ||
2080 | */ | ||
2081 | if (!fatpipe_exist_for_ac) | ||
2082 | ath6kl_indicate_tx_activity(wmi->parent_dev, | ||
2083 | params->traffic_class, true); | ||
2084 | |||
2085 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_CREATE_PSTREAM_CMDID, | ||
2086 | NO_SYNC_WMIFLAG); | ||
2087 | return ret; | ||
2088 | } | ||
2089 | |||
2090 | int ath6kl_wmi_delete_pstream_cmd(struct wmi *wmi, u8 traffic_class, u8 tsid) | ||
2091 | { | ||
2092 | struct sk_buff *skb; | ||
2093 | struct wmi_delete_pstream_cmd *cmd; | ||
2094 | u16 active_tsids = 0; | ||
2095 | int ret; | ||
2096 | |||
2097 | if (traffic_class > 3) { | ||
2098 | ath6kl_err("invalid traffic class: %d\n", traffic_class); | ||
2099 | return -EINVAL; | ||
2100 | } | ||
2101 | |||
2102 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
2103 | if (!skb) | ||
2104 | return -ENOMEM; | ||
2105 | |||
2106 | cmd = (struct wmi_delete_pstream_cmd *) skb->data; | ||
2107 | cmd->traffic_class = traffic_class; | ||
2108 | cmd->tsid = tsid; | ||
2109 | |||
2110 | spin_lock_bh(&wmi->lock); | ||
2111 | active_tsids = wmi->stream_exist_for_ac[traffic_class]; | ||
2112 | spin_unlock_bh(&wmi->lock); | ||
2113 | |||
2114 | if (!(active_tsids & (1 << tsid))) { | ||
2115 | dev_kfree_skb(skb); | ||
2116 | ath6kl_dbg(ATH6KL_DBG_WMI, | ||
2117 | "TSID %d doesn't exist for traffic class: %d\n", | ||
2118 | tsid, traffic_class); | ||
2119 | return -ENODATA; | ||
2120 | } | ||
2121 | |||
2122 | ath6kl_dbg(ATH6KL_DBG_WMI, | ||
2123 | "sending delete_pstream_cmd: traffic class: %d tsid=%d\n", | ||
2124 | traffic_class, tsid); | ||
2125 | |||
2126 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_DELETE_PSTREAM_CMDID, | ||
2127 | SYNC_BEFORE_WMIFLAG); | ||
2128 | |||
2129 | spin_lock_bh(&wmi->lock); | ||
2130 | wmi->stream_exist_for_ac[traffic_class] &= ~(1 << tsid); | ||
2131 | active_tsids = wmi->stream_exist_for_ac[traffic_class]; | ||
2132 | spin_unlock_bh(&wmi->lock); | ||
2133 | |||
2134 | /* | ||
2135 | * Indicate stream inactivity to driver layer only if all tsids | ||
2136 | * within this AC are deleted. | ||
2137 | */ | ||
2138 | if (!active_tsids) { | ||
2139 | ath6kl_indicate_tx_activity(wmi->parent_dev, | ||
2140 | traffic_class, false); | ||
2141 | wmi->fat_pipe_exist &= ~(1 << traffic_class); | ||
2142 | } | ||
2143 | |||
2144 | return ret; | ||
2145 | } | ||
2146 | |||
2147 | int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd) | ||
2148 | { | ||
2149 | struct sk_buff *skb; | ||
2150 | struct wmi_set_ip_cmd *cmd; | ||
2151 | int ret; | ||
2152 | |||
2153 | /* Multicast address are not valid */ | ||
2154 | if ((*((u8 *) &ip_cmd->ips[0]) >= 0xE0) || | ||
2155 | (*((u8 *) &ip_cmd->ips[1]) >= 0xE0)) | ||
2156 | return -EINVAL; | ||
2157 | |||
2158 | skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_ip_cmd)); | ||
2159 | if (!skb) | ||
2160 | return -ENOMEM; | ||
2161 | |||
2162 | cmd = (struct wmi_set_ip_cmd *) skb->data; | ||
2163 | memcpy(cmd, ip_cmd, sizeof(struct wmi_set_ip_cmd)); | ||
2164 | |||
2165 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_IP_CMDID, NO_SYNC_WMIFLAG); | ||
2166 | return ret; | ||
2167 | } | ||
2168 | |||
2169 | static int ath6kl_wmi_get_wow_list_event_rx(struct wmi *wmi, u8 * datap, | ||
2170 | int len) | ||
2171 | { | ||
2172 | if (len < sizeof(struct wmi_get_wow_list_reply)) | ||
2173 | return -EINVAL; | ||
2174 | |||
2175 | return 0; | ||
2176 | } | ||
2177 | |||
2178 | static int ath6kl_wmi_cmd_send_xtnd(struct wmi *wmi, struct sk_buff *skb, | ||
2179 | enum wmix_command_id cmd_id, | ||
2180 | enum wmi_sync_flag sync_flag) | ||
2181 | { | ||
2182 | struct wmix_cmd_hdr *cmd_hdr; | ||
2183 | int ret; | ||
2184 | |||
2185 | skb_push(skb, sizeof(struct wmix_cmd_hdr)); | ||
2186 | |||
2187 | cmd_hdr = (struct wmix_cmd_hdr *) skb->data; | ||
2188 | cmd_hdr->cmd_id = cpu_to_le32(cmd_id); | ||
2189 | |||
2190 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_EXTENSION_CMDID, sync_flag); | ||
2191 | |||
2192 | return ret; | ||
2193 | } | ||
2194 | |||
2195 | int ath6kl_wmi_get_challenge_resp_cmd(struct wmi *wmi, u32 cookie, u32 source) | ||
2196 | { | ||
2197 | struct sk_buff *skb; | ||
2198 | struct wmix_hb_challenge_resp_cmd *cmd; | ||
2199 | int ret; | ||
2200 | |||
2201 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
2202 | if (!skb) | ||
2203 | return -ENOMEM; | ||
2204 | |||
2205 | cmd = (struct wmix_hb_challenge_resp_cmd *) skb->data; | ||
2206 | cmd->cookie = cpu_to_le32(cookie); | ||
2207 | cmd->source = cpu_to_le32(source); | ||
2208 | |||
2209 | ret = ath6kl_wmi_cmd_send_xtnd(wmi, skb, WMIX_HB_CHALLENGE_RESP_CMDID, | ||
2210 | NO_SYNC_WMIFLAG); | ||
2211 | return ret; | ||
2212 | } | ||
2213 | |||
2214 | int ath6kl_wmi_get_stats_cmd(struct wmi *wmi) | ||
2215 | { | ||
2216 | return ath6kl_wmi_simple_cmd(wmi, WMI_GET_STATISTICS_CMDID); | ||
2217 | } | ||
2218 | |||
2219 | int ath6kl_wmi_set_tx_pwr_cmd(struct wmi *wmi, u8 dbM) | ||
2220 | { | ||
2221 | struct sk_buff *skb; | ||
2222 | struct wmi_set_tx_pwr_cmd *cmd; | ||
2223 | int ret; | ||
2224 | |||
2225 | skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_tx_pwr_cmd)); | ||
2226 | if (!skb) | ||
2227 | return -ENOMEM; | ||
2228 | |||
2229 | cmd = (struct wmi_set_tx_pwr_cmd *) skb->data; | ||
2230 | cmd->dbM = dbM; | ||
2231 | |||
2232 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_TX_PWR_CMDID, | ||
2233 | NO_SYNC_WMIFLAG); | ||
2234 | |||
2235 | return ret; | ||
2236 | } | ||
2237 | |||
2238 | int ath6kl_wmi_get_tx_pwr_cmd(struct wmi *wmi) | ||
2239 | { | ||
2240 | return ath6kl_wmi_simple_cmd(wmi, WMI_GET_TX_PWR_CMDID); | ||
2241 | } | ||
2242 | |||
2243 | int ath6kl_wmi_set_lpreamble_cmd(struct wmi *wmi, u8 status, u8 preamble_policy) | ||
2244 | { | ||
2245 | struct sk_buff *skb; | ||
2246 | struct wmi_set_lpreamble_cmd *cmd; | ||
2247 | int ret; | ||
2248 | |||
2249 | skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_lpreamble_cmd)); | ||
2250 | if (!skb) | ||
2251 | return -ENOMEM; | ||
2252 | |||
2253 | cmd = (struct wmi_set_lpreamble_cmd *) skb->data; | ||
2254 | cmd->status = status; | ||
2255 | cmd->preamble_policy = preamble_policy; | ||
2256 | |||
2257 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_LPREAMBLE_CMDID, | ||
2258 | NO_SYNC_WMIFLAG); | ||
2259 | return ret; | ||
2260 | } | ||
2261 | |||
2262 | int ath6kl_wmi_set_rts_cmd(struct wmi *wmi, u16 threshold) | ||
2263 | { | ||
2264 | struct sk_buff *skb; | ||
2265 | struct wmi_set_rts_cmd *cmd; | ||
2266 | int ret; | ||
2267 | |||
2268 | skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_rts_cmd)); | ||
2269 | if (!skb) | ||
2270 | return -ENOMEM; | ||
2271 | |||
2272 | cmd = (struct wmi_set_rts_cmd *) skb->data; | ||
2273 | cmd->threshold = cpu_to_le16(threshold); | ||
2274 | |||
2275 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_RTS_CMDID, NO_SYNC_WMIFLAG); | ||
2276 | return ret; | ||
2277 | } | ||
2278 | |||
2279 | int ath6kl_wmi_set_wmm_txop(struct wmi *wmi, enum wmi_txop_cfg cfg) | ||
2280 | { | ||
2281 | struct sk_buff *skb; | ||
2282 | struct wmi_set_wmm_txop_cmd *cmd; | ||
2283 | int ret; | ||
2284 | |||
2285 | if (!((cfg == WMI_TXOP_DISABLED) || (cfg == WMI_TXOP_ENABLED))) | ||
2286 | return -EINVAL; | ||
2287 | |||
2288 | skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_wmm_txop_cmd)); | ||
2289 | if (!skb) | ||
2290 | return -ENOMEM; | ||
2291 | |||
2292 | cmd = (struct wmi_set_wmm_txop_cmd *) skb->data; | ||
2293 | cmd->txop_enable = cfg; | ||
2294 | |||
2295 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_WMM_TXOP_CMDID, | ||
2296 | NO_SYNC_WMIFLAG); | ||
2297 | return ret; | ||
2298 | } | ||
2299 | |||
2300 | int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 keep_alive_intvl) | ||
2301 | { | ||
2302 | struct sk_buff *skb; | ||
2303 | struct wmi_set_keepalive_cmd *cmd; | ||
2304 | int ret; | ||
2305 | |||
2306 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
2307 | if (!skb) | ||
2308 | return -ENOMEM; | ||
2309 | |||
2310 | cmd = (struct wmi_set_keepalive_cmd *) skb->data; | ||
2311 | cmd->keep_alive_intvl = keep_alive_intvl; | ||
2312 | wmi->keep_alive_intvl = keep_alive_intvl; | ||
2313 | |||
2314 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_KEEPALIVE_CMDID, | ||
2315 | NO_SYNC_WMIFLAG); | ||
2316 | return ret; | ||
2317 | } | ||
2318 | |||
2319 | s32 ath6kl_wmi_get_rate(s8 rate_index) | ||
2320 | { | ||
2321 | if (rate_index == RATE_AUTO) | ||
2322 | return 0; | ||
2323 | |||
2324 | return wmi_rate_tbl[(u32) rate_index][0]; | ||
2325 | } | ||
2326 | |||
2327 | void ath6kl_wmi_node_return(struct wmi *wmi, struct bss *bss) | ||
2328 | { | ||
2329 | if (bss) | ||
2330 | wlan_node_return(&wmi->parent_dev->scan_table, bss); | ||
2331 | } | ||
2332 | |||
2333 | struct bss *ath6kl_wmi_find_ssid_node(struct wmi *wmi, u8 * ssid, | ||
2334 | u32 ssid_len, bool is_wpa2, | ||
2335 | bool match_ssid) | ||
2336 | { | ||
2337 | struct bss *node = NULL; | ||
2338 | |||
2339 | node = wlan_find_ssid_node(&wmi->parent_dev->scan_table, ssid, | ||
2340 | ssid_len, is_wpa2, match_ssid); | ||
2341 | return node; | ||
2342 | } | ||
2343 | |||
2344 | struct bss *ath6kl_wmi_find_node(struct wmi *wmi, const u8 * mac_addr) | ||
2345 | { | ||
2346 | struct bss *ni = NULL; | ||
2347 | |||
2348 | ni = wlan_find_node(&wmi->parent_dev->scan_table, mac_addr); | ||
2349 | |||
2350 | return ni; | ||
2351 | } | ||
2352 | |||
2353 | void ath6kl_wmi_node_free(struct wmi *wmi, const u8 * mac_addr) | ||
2354 | { | ||
2355 | struct bss *ni = NULL; | ||
2356 | |||
2357 | ni = wlan_find_node(&wmi->parent_dev->scan_table, mac_addr); | ||
2358 | if (ni != NULL) | ||
2359 | wlan_node_reclaim(&wmi->parent_dev->scan_table, ni); | ||
2360 | |||
2361 | return; | ||
2362 | } | ||
2363 | |||
2364 | static int ath6kl_wmi_get_pmkid_list_event_rx(struct wmi *wmi, u8 *datap, | ||
2365 | u32 len) | ||
2366 | { | ||
2367 | struct wmi_pmkid_list_reply *reply; | ||
2368 | u32 expected_len; | ||
2369 | |||
2370 | if (len < sizeof(struct wmi_pmkid_list_reply)) | ||
2371 | return -EINVAL; | ||
2372 | |||
2373 | reply = (struct wmi_pmkid_list_reply *)datap; | ||
2374 | expected_len = sizeof(reply->num_pmkid) + | ||
2375 | le32_to_cpu(reply->num_pmkid) * WMI_PMKID_LEN; | ||
2376 | |||
2377 | if (len < expected_len) | ||
2378 | return -EINVAL; | ||
2379 | |||
2380 | return 0; | ||
2381 | } | ||
2382 | |||
2383 | static int ath6kl_wmi_addba_req_event_rx(struct wmi *wmi, u8 *datap, int len) | ||
2384 | { | ||
2385 | struct wmi_addba_req_event *cmd = (struct wmi_addba_req_event *) datap; | ||
2386 | |||
2387 | aggr_recv_addba_req_evt(wmi->parent_dev, cmd->tid, | ||
2388 | le16_to_cpu(cmd->st_seq_no), cmd->win_sz); | ||
2389 | |||
2390 | return 0; | ||
2391 | } | ||
2392 | |||
2393 | static int ath6kl_wmi_delba_req_event_rx(struct wmi *wmi, u8 *datap, int len) | ||
2394 | { | ||
2395 | struct wmi_delba_event *cmd = (struct wmi_delba_event *) datap; | ||
2396 | |||
2397 | aggr_recv_delba_req_evt(wmi->parent_dev, cmd->tid); | ||
2398 | |||
2399 | return 0; | ||
2400 | } | ||
2401 | |||
2402 | /* AP mode functions */ | ||
2403 | static int ath6kl_wmi_pspoll_event_rx(struct wmi *wmi, u8 *datap, int len) | ||
2404 | { | ||
2405 | struct wmi_pspoll_event *ev; | ||
2406 | |||
2407 | if (len < sizeof(struct wmi_pspoll_event)) | ||
2408 | return -EINVAL; | ||
2409 | |||
2410 | ev = (struct wmi_pspoll_event *) datap; | ||
2411 | |||
2412 | ath6kl_pspoll_event(wmi->parent_dev, le16_to_cpu(ev->aid)); | ||
2413 | |||
2414 | return 0; | ||
2415 | } | ||
2416 | |||
2417 | static int ath6kl_wmi_dtimexpiry_event_rx(struct wmi *wmi, u8 *datap, int len) | ||
2418 | { | ||
2419 | ath6kl_dtimexpiry_event(wmi->parent_dev); | ||
2420 | |||
2421 | return 0; | ||
2422 | } | ||
2423 | |||
2424 | int ath6kl_wmi_set_pvb_cmd(struct wmi *wmi, u16 aid, bool flag) | ||
2425 | { | ||
2426 | struct sk_buff *skb; | ||
2427 | struct wmi_ap_set_pvb_cmd *cmd; | ||
2428 | int ret; | ||
2429 | |||
2430 | skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_ap_set_pvb_cmd)); | ||
2431 | if (!skb) | ||
2432 | return -ENOMEM; | ||
2433 | |||
2434 | cmd = (struct wmi_ap_set_pvb_cmd *) skb->data; | ||
2435 | cmd->aid = cpu_to_le16(aid); | ||
2436 | cmd->flag = cpu_to_le32(flag); | ||
2437 | |||
2438 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_AP_SET_PVB_CMDID, | ||
2439 | NO_SYNC_WMIFLAG); | ||
2440 | |||
2441 | return 0; | ||
2442 | } | ||
2443 | |||
2444 | int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 rx_meta_ver, | ||
2445 | bool rx_dot11_hdr, bool defrag_on_host) | ||
2446 | { | ||
2447 | struct sk_buff *skb; | ||
2448 | struct wmi_rx_frame_format_cmd *cmd; | ||
2449 | int ret; | ||
2450 | |||
2451 | skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); | ||
2452 | if (!skb) | ||
2453 | return -ENOMEM; | ||
2454 | |||
2455 | cmd = (struct wmi_rx_frame_format_cmd *) skb->data; | ||
2456 | cmd->dot11_hdr = rx_dot11_hdr ? 1 : 0; | ||
2457 | cmd->defrag_on_host = defrag_on_host ? 1 : 0; | ||
2458 | cmd->meta_ver = rx_meta_ver; | ||
2459 | |||
2460 | /* Delete the local aggr state, on host */ | ||
2461 | ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_RX_FRAME_FORMAT_CMDID, | ||
2462 | NO_SYNC_WMIFLAG); | ||
2463 | |||
2464 | return ret; | ||
2465 | } | ||
2466 | |||
2467 | static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb) | ||
2468 | { | ||
2469 | struct wmix_cmd_hdr *cmd; | ||
2470 | u32 len; | ||
2471 | u16 id; | ||
2472 | u8 *datap; | ||
2473 | int ret = 0; | ||
2474 | |||
2475 | if (skb->len < sizeof(struct wmix_cmd_hdr)) { | ||
2476 | ath6kl_err("bad packet 1\n"); | ||
2477 | wmi->stat.cmd_len_err++; | ||
2478 | return -EINVAL; | ||
2479 | } | ||
2480 | |||
2481 | cmd = (struct wmix_cmd_hdr *) skb->data; | ||
2482 | id = le32_to_cpu(cmd->cmd_id); | ||
2483 | |||
2484 | skb_pull(skb, sizeof(struct wmix_cmd_hdr)); | ||
2485 | |||
2486 | datap = skb->data; | ||
2487 | len = skb->len; | ||
2488 | |||
2489 | switch (id) { | ||
2490 | case WMIX_HB_CHALLENGE_RESP_EVENTID: | ||
2491 | break; | ||
2492 | case WMIX_DBGLOG_EVENTID: | ||
2493 | break; | ||
2494 | default: | ||
2495 | ath6kl_err("unknown cmd id 0x%x\n", id); | ||
2496 | wmi->stat.cmd_id_err++; | ||
2497 | ret = -EINVAL; | ||
2498 | break; | ||
2499 | } | ||
2500 | |||
2501 | return ret; | ||
2502 | } | ||
2503 | |||
2504 | /* Control Path */ | ||
2505 | int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) | ||
2506 | { | ||
2507 | struct wmi_cmd_hdr *cmd; | ||
2508 | u32 len; | ||
2509 | u16 id; | ||
2510 | u8 *datap; | ||
2511 | int ret = 0; | ||
2512 | |||
2513 | if (WARN_ON(skb == NULL)) | ||
2514 | return -EINVAL; | ||
2515 | |||
2516 | if (skb->len < sizeof(struct wmi_cmd_hdr)) { | ||
2517 | ath6kl_err("bad packet 1\n"); | ||
2518 | dev_kfree_skb(skb); | ||
2519 | wmi->stat.cmd_len_err++; | ||
2520 | return -EINVAL; | ||
2521 | } | ||
2522 | |||
2523 | cmd = (struct wmi_cmd_hdr *) skb->data; | ||
2524 | id = le16_to_cpu(cmd->cmd_id); | ||
2525 | |||
2526 | skb_pull(skb, sizeof(struct wmi_cmd_hdr)); | ||
2527 | |||
2528 | datap = skb->data; | ||
2529 | len = skb->len; | ||
2530 | |||
2531 | ath6kl_dbg(ATH6KL_DBG_WMI, "%s: wmi id: %d\n", __func__, id); | ||
2532 | ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "msg payload ", datap, len); | ||
2533 | |||
2534 | switch (id) { | ||
2535 | case WMI_GET_BITRATE_CMDID: | ||
2536 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_BITRATE_CMDID\n"); | ||
2537 | ret = ath6kl_wmi_bitrate_reply_rx(wmi, datap, len); | ||
2538 | break; | ||
2539 | case WMI_GET_CHANNEL_LIST_CMDID: | ||
2540 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_CHANNEL_LIST_CMDID\n"); | ||
2541 | ret = ath6kl_wmi_ch_list_reply_rx(wmi, datap, len); | ||
2542 | break; | ||
2543 | case WMI_GET_TX_PWR_CMDID: | ||
2544 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_TX_PWR_CMDID\n"); | ||
2545 | ret = ath6kl_wmi_tx_pwr_reply_rx(wmi, datap, len); | ||
2546 | break; | ||
2547 | case WMI_READY_EVENTID: | ||
2548 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_READY_EVENTID\n"); | ||
2549 | ret = ath6kl_wmi_ready_event_rx(wmi, datap, len); | ||
2550 | break; | ||
2551 | case WMI_CONNECT_EVENTID: | ||
2552 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CONNECT_EVENTID\n"); | ||
2553 | ret = ath6kl_wmi_connect_event_rx(wmi, datap, len); | ||
2554 | break; | ||
2555 | case WMI_DISCONNECT_EVENTID: | ||
2556 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DISCONNECT_EVENTID\n"); | ||
2557 | ret = ath6kl_wmi_disconnect_event_rx(wmi, datap, len); | ||
2558 | break; | ||
2559 | case WMI_PEER_NODE_EVENTID: | ||
2560 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PEER_NODE_EVENTID\n"); | ||
2561 | ret = ath6kl_wmi_peer_node_event_rx(wmi, datap, len); | ||
2562 | break; | ||
2563 | case WMI_TKIP_MICERR_EVENTID: | ||
2564 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TKIP_MICERR_EVENTID\n"); | ||
2565 | ret = ath6kl_wmi_tkip_micerr_event_rx(wmi, datap, len); | ||
2566 | break; | ||
2567 | case WMI_BSSINFO_EVENTID: | ||
2568 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_BSSINFO_EVENTID\n"); | ||
2569 | ath6kl_wmi_convert_bssinfo_hdr2_to_hdr(skb, datap); | ||
2570 | ret = ath6kl_wmi_bssinfo_event_rx(wmi, skb->data, skb->len); | ||
2571 | break; | ||
2572 | case WMI_REGDOMAIN_EVENTID: | ||
2573 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REGDOMAIN_EVENTID\n"); | ||
2574 | break; | ||
2575 | case WMI_PSTREAM_TIMEOUT_EVENTID: | ||
2576 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSTREAM_TIMEOUT_EVENTID\n"); | ||
2577 | ret = ath6kl_wmi_pstream_timeout_event_rx(wmi, datap, len); | ||
2578 | break; | ||
2579 | case WMI_NEIGHBOR_REPORT_EVENTID: | ||
2580 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_NEIGHBOR_REPORT_EVENTID\n"); | ||
2581 | break; | ||
2582 | case WMI_SCAN_COMPLETE_EVENTID: | ||
2583 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SCAN_COMPLETE_EVENTID\n"); | ||
2584 | ret = ath6kl_wmi_scan_complete_rx(wmi, datap, len); | ||
2585 | break; | ||
2586 | case WMI_CMDERROR_EVENTID: | ||
2587 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CMDERROR_EVENTID\n"); | ||
2588 | ret = ath6kl_wmi_error_event_rx(wmi, datap, len); | ||
2589 | break; | ||
2590 | case WMI_REPORT_STATISTICS_EVENTID: | ||
2591 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_STATISTICS_EVENTID\n"); | ||
2592 | ret = ath6kl_wmi_stats_event_rx(wmi, datap, len); | ||
2593 | break; | ||
2594 | case WMI_RSSI_THRESHOLD_EVENTID: | ||
2595 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RSSI_THRESHOLD_EVENTID\n"); | ||
2596 | ret = ath6kl_wmi_rssi_threshold_event_rx(wmi, datap, len); | ||
2597 | break; | ||
2598 | case WMI_ERROR_REPORT_EVENTID: | ||
2599 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ERROR_REPORT_EVENTID\n"); | ||
2600 | break; | ||
2601 | case WMI_OPT_RX_FRAME_EVENTID: | ||
2602 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_OPT_RX_FRAME_EVENTID\n"); | ||
2603 | ret = ath6kl_wmi_opt_frame_event_rx(wmi, datap, len); | ||
2604 | break; | ||
2605 | case WMI_REPORT_ROAM_TBL_EVENTID: | ||
2606 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_ROAM_TBL_EVENTID\n"); | ||
2607 | break; | ||
2608 | case WMI_EXTENSION_EVENTID: | ||
2609 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_EXTENSION_EVENTID\n"); | ||
2610 | ret = ath6kl_wmi_control_rx_xtnd(wmi, skb); | ||
2611 | break; | ||
2612 | case WMI_CAC_EVENTID: | ||
2613 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CAC_EVENTID\n"); | ||
2614 | ret = ath6kl_wmi_cac_event_rx(wmi, datap, len); | ||
2615 | break; | ||
2616 | case WMI_CHANNEL_CHANGE_EVENTID: | ||
2617 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CHANNEL_CHANGE_EVENTID\n"); | ||
2618 | break; | ||
2619 | case WMI_REPORT_ROAM_DATA_EVENTID: | ||
2620 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_ROAM_DATA_EVENTID\n"); | ||
2621 | break; | ||
2622 | case WMI_GET_FIXRATES_CMDID: | ||
2623 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_FIXRATES_CMDID\n"); | ||
2624 | ret = ath6kl_wmi_ratemask_reply_rx(wmi, datap, len); | ||
2625 | break; | ||
2626 | case WMI_TX_RETRY_ERR_EVENTID: | ||
2627 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_RETRY_ERR_EVENTID\n"); | ||
2628 | break; | ||
2629 | case WMI_SNR_THRESHOLD_EVENTID: | ||
2630 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SNR_THRESHOLD_EVENTID\n"); | ||
2631 | ret = ath6kl_wmi_snr_threshold_event_rx(wmi, datap, len); | ||
2632 | break; | ||
2633 | case WMI_LQ_THRESHOLD_EVENTID: | ||
2634 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_LQ_THRESHOLD_EVENTID\n"); | ||
2635 | break; | ||
2636 | case WMI_APLIST_EVENTID: | ||
2637 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_APLIST_EVENTID\n"); | ||
2638 | ret = ath6kl_wmi_aplist_event_rx(wmi, datap, len); | ||
2639 | break; | ||
2640 | case WMI_GET_KEEPALIVE_CMDID: | ||
2641 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_KEEPALIVE_CMDID\n"); | ||
2642 | ret = ath6kl_wmi_keepalive_reply_rx(wmi, datap, len); | ||
2643 | break; | ||
2644 | case WMI_GET_WOW_LIST_EVENTID: | ||
2645 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_WOW_LIST_EVENTID\n"); | ||
2646 | ret = ath6kl_wmi_get_wow_list_event_rx(wmi, datap, len); | ||
2647 | break; | ||
2648 | case WMI_GET_PMKID_LIST_EVENTID: | ||
2649 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_PMKID_LIST_EVENTID\n"); | ||
2650 | ret = ath6kl_wmi_get_pmkid_list_event_rx(wmi, datap, len); | ||
2651 | break; | ||
2652 | case WMI_PSPOLL_EVENTID: | ||
2653 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSPOLL_EVENTID\n"); | ||
2654 | ret = ath6kl_wmi_pspoll_event_rx(wmi, datap, len); | ||
2655 | break; | ||
2656 | case WMI_DTIMEXPIRY_EVENTID: | ||
2657 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DTIMEXPIRY_EVENTID\n"); | ||
2658 | ret = ath6kl_wmi_dtimexpiry_event_rx(wmi, datap, len); | ||
2659 | break; | ||
2660 | case WMI_SET_PARAMS_REPLY_EVENTID: | ||
2661 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SET_PARAMS_REPLY_EVENTID\n"); | ||
2662 | break; | ||
2663 | case WMI_ADDBA_REQ_EVENTID: | ||
2664 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_REQ_EVENTID\n"); | ||
2665 | ret = ath6kl_wmi_addba_req_event_rx(wmi, datap, len); | ||
2666 | break; | ||
2667 | case WMI_ADDBA_RESP_EVENTID: | ||
2668 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_RESP_EVENTID\n"); | ||
2669 | break; | ||
2670 | case WMI_DELBA_REQ_EVENTID: | ||
2671 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DELBA_REQ_EVENTID\n"); | ||
2672 | ret = ath6kl_wmi_delba_req_event_rx(wmi, datap, len); | ||
2673 | break; | ||
2674 | case WMI_REPORT_BTCOEX_CONFIG_EVENTID: | ||
2675 | ath6kl_dbg(ATH6KL_DBG_WMI, | ||
2676 | "WMI_REPORT_BTCOEX_CONFIG_EVENTID\n"); | ||
2677 | break; | ||
2678 | case WMI_REPORT_BTCOEX_STATS_EVENTID: | ||
2679 | ath6kl_dbg(ATH6KL_DBG_WMI, | ||
2680 | "WMI_REPORT_BTCOEX_STATS_EVENTID\n"); | ||
2681 | break; | ||
2682 | case WMI_TX_COMPLETE_EVENTID: | ||
2683 | ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_COMPLETE_EVENTID\n"); | ||
2684 | ret = ath6kl_wmi_tx_complete_event_rx(datap, len); | ||
2685 | break; | ||
2686 | default: | ||
2687 | ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", id); | ||
2688 | wmi->stat.cmd_id_err++; | ||
2689 | ret = -EINVAL; | ||
2690 | break; | ||
2691 | } | ||
2692 | |||
2693 | dev_kfree_skb(skb); | ||
2694 | |||
2695 | return ret; | ||
2696 | } | ||
2697 | |||
2698 | static void ath6kl_wmi_qos_state_init(struct wmi *wmi) | ||
2699 | { | ||
2700 | if (!wmi) | ||
2701 | return; | ||
2702 | |||
2703 | spin_lock_bh(&wmi->lock); | ||
2704 | |||
2705 | wmi->fat_pipe_exist = 0; | ||
2706 | memset(wmi->stream_exist_for_ac, 0, sizeof(wmi->stream_exist_for_ac)); | ||
2707 | |||
2708 | spin_unlock_bh(&wmi->lock); | ||
2709 | } | ||
2710 | |||
2711 | void *ath6kl_wmi_init(struct ath6kl *dev) | ||
2712 | { | ||
2713 | struct wmi *wmi; | ||
2714 | |||
2715 | wmi = kzalloc(sizeof(struct wmi), GFP_KERNEL); | ||
2716 | if (!wmi) | ||
2717 | return NULL; | ||
2718 | |||
2719 | spin_lock_init(&wmi->lock); | ||
2720 | |||
2721 | wmi->parent_dev = dev; | ||
2722 | |||
2723 | ath6kl_wmi_qos_state_init(wmi); | ||
2724 | |||
2725 | wmi->pwr_mode = REC_POWER; | ||
2726 | wmi->phy_mode = WMI_11G_MODE; | ||
2727 | |||
2728 | wmi->pair_crypto_type = NONE_CRYPT; | ||
2729 | wmi->grp_crypto_type = NONE_CRYPT; | ||
2730 | |||
2731 | wmi->ht_allowed[A_BAND_24GHZ] = 1; | ||
2732 | wmi->ht_allowed[A_BAND_5GHZ] = 1; | ||
2733 | |||
2734 | return wmi; | ||
2735 | } | ||
2736 | |||
2737 | void ath6kl_wmi_shutdown(struct wmi *wmi) | ||
2738 | { | ||
2739 | if (!wmi) | ||
2740 | return; | ||
2741 | |||
2742 | kfree(wmi); | ||
2743 | } | ||
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h new file mode 100644 index 000000000000..fe3ddce64087 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/wmi.h | |||
@@ -0,0 +1,2018 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010-2011 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 | * This file contains the definitions of the WMI protocol specified in the | ||
19 | * Wireless Module Interface (WMI). It includes definitions of all the | ||
20 | * commands and events. Commands are messages from the host to the WM. | ||
21 | * Events and Replies are messages from the WM to the host. | ||
22 | */ | ||
23 | |||
24 | #ifndef WMI_H | ||
25 | #define WMI_H | ||
26 | |||
27 | #include <linux/ieee80211.h> | ||
28 | |||
29 | #include "htc.h" | ||
30 | |||
31 | #define HTC_PROTOCOL_VERSION 0x0002 | ||
32 | #define WMI_PROTOCOL_VERSION 0x0002 | ||
33 | #define WMI_CONTROL_MSG_MAX_LEN 256 | ||
34 | #define is_ethertype(type_or_len) ((type_or_len) >= 0x0600) | ||
35 | |||
36 | #define IP_ETHERTYPE 0x0800 | ||
37 | |||
38 | #define WMI_IMPLICIT_PSTREAM 0xFF | ||
39 | #define WMI_MAX_THINSTREAM 15 | ||
40 | |||
41 | #define SSID_IE_LEN_INDEX 13 | ||
42 | |||
43 | /* Host side link management data structures */ | ||
44 | #define SIG_QUALITY_THRESH_LVLS 6 | ||
45 | #define SIG_QUALITY_UPPER_THRESH_LVLS SIG_QUALITY_THRESH_LVLS | ||
46 | #define SIG_QUALITY_LOWER_THRESH_LVLS SIG_QUALITY_THRESH_LVLS | ||
47 | |||
48 | #define A_BAND_24GHZ 0 | ||
49 | #define A_BAND_5GHZ 1 | ||
50 | #define A_NUM_BANDS 2 | ||
51 | |||
52 | /* in ms */ | ||
53 | #define WMI_IMPLICIT_PSTREAM_INACTIVITY_INT 5000 | ||
54 | |||
55 | /* | ||
56 | * There are no signed versions of __le16 and __le32, so for a temporary | ||
57 | * solution come up with our own version. The idea is from fs/ntfs/types.h. | ||
58 | * | ||
59 | * Use a_ prefix so that it doesn't conflict if we get proper support to | ||
60 | * linux/types.h. | ||
61 | */ | ||
62 | typedef __s16 __bitwise a_sle16; | ||
63 | typedef __s32 __bitwise a_sle32; | ||
64 | |||
65 | static inline a_sle32 a_cpu_to_sle32(s32 val) | ||
66 | { | ||
67 | return (__force a_sle32) cpu_to_le32(val); | ||
68 | } | ||
69 | |||
70 | static inline s32 a_sle32_to_cpu(a_sle32 val) | ||
71 | { | ||
72 | return le32_to_cpu((__force __le32) val); | ||
73 | } | ||
74 | |||
75 | static inline a_sle16 a_cpu_to_sle16(s16 val) | ||
76 | { | ||
77 | return (__force a_sle16) cpu_to_le16(val); | ||
78 | } | ||
79 | |||
80 | static inline s16 a_sle16_to_cpu(a_sle16 val) | ||
81 | { | ||
82 | return le16_to_cpu((__force __le16) val); | ||
83 | } | ||
84 | |||
85 | struct sq_threshold_params { | ||
86 | s16 upper_threshold[SIG_QUALITY_UPPER_THRESH_LVLS]; | ||
87 | s16 lower_threshold[SIG_QUALITY_LOWER_THRESH_LVLS]; | ||
88 | u32 upper_threshold_valid_count; | ||
89 | u32 lower_threshold_valid_count; | ||
90 | u32 polling_interval; | ||
91 | u8 weight; | ||
92 | u8 last_rssi; | ||
93 | u8 last_rssi_poll_event; | ||
94 | }; | ||
95 | |||
96 | struct wmi_stats { | ||
97 | u32 cmd_len_err; | ||
98 | u32 cmd_id_err; | ||
99 | }; | ||
100 | |||
101 | struct wmi_data_sync_bufs { | ||
102 | u8 traffic_class; | ||
103 | struct sk_buff *skb; | ||
104 | }; | ||
105 | |||
106 | /* WMM stream classes */ | ||
107 | #define WMM_NUM_AC 4 | ||
108 | #define WMM_AC_BE 0 /* best effort */ | ||
109 | #define WMM_AC_BK 1 /* background */ | ||
110 | #define WMM_AC_VI 2 /* video */ | ||
111 | #define WMM_AC_VO 3 /* voice */ | ||
112 | |||
113 | struct wmi { | ||
114 | bool ready; | ||
115 | u16 stream_exist_for_ac[WMM_NUM_AC]; | ||
116 | u8 fat_pipe_exist; | ||
117 | struct ath6kl *parent_dev; | ||
118 | struct wmi_stats stat; | ||
119 | u8 pwr_mode; | ||
120 | u8 phy_mode; | ||
121 | u8 keep_alive_intvl; | ||
122 | spinlock_t lock; | ||
123 | enum htc_endpoint_id ep_id; | ||
124 | struct sq_threshold_params | ||
125 | sq_threshld[SIGNAL_QUALITY_METRICS_NUM_MAX]; | ||
126 | enum crypto_type pair_crypto_type; | ||
127 | enum crypto_type grp_crypto_type; | ||
128 | bool is_wmm_enabled; | ||
129 | u8 ht_allowed[A_NUM_BANDS]; | ||
130 | u8 traffic_class; | ||
131 | bool is_probe_ssid; | ||
132 | }; | ||
133 | |||
134 | struct host_app_area { | ||
135 | u32 wmi_protocol_ver; | ||
136 | }; | ||
137 | |||
138 | enum wmi_msg_type { | ||
139 | DATA_MSGTYPE = 0x0, | ||
140 | CNTL_MSGTYPE, | ||
141 | SYNC_MSGTYPE, | ||
142 | OPT_MSGTYPE, | ||
143 | }; | ||
144 | |||
145 | /* | ||
146 | * Macros for operating on WMI_DATA_HDR (info) field | ||
147 | */ | ||
148 | |||
149 | #define WMI_DATA_HDR_MSG_TYPE_MASK 0x03 | ||
150 | #define WMI_DATA_HDR_MSG_TYPE_SHIFT 0 | ||
151 | #define WMI_DATA_HDR_UP_MASK 0x07 | ||
152 | #define WMI_DATA_HDR_UP_SHIFT 2 | ||
153 | |||
154 | /* In AP mode, the same bit (b5) is used to indicate Power save state in | ||
155 | * the Rx dir and More data bit state in the tx direction. | ||
156 | */ | ||
157 | #define WMI_DATA_HDR_PS_MASK 0x1 | ||
158 | #define WMI_DATA_HDR_PS_SHIFT 5 | ||
159 | |||
160 | #define WMI_DATA_HDR_MORE_MASK 0x1 | ||
161 | #define WMI_DATA_HDR_MORE_SHIFT 5 | ||
162 | |||
163 | enum wmi_data_hdr_data_type { | ||
164 | WMI_DATA_HDR_DATA_TYPE_802_3 = 0, | ||
165 | WMI_DATA_HDR_DATA_TYPE_802_11, | ||
166 | |||
167 | /* used to be used for the PAL */ | ||
168 | WMI_DATA_HDR_DATA_TYPE_ACL, | ||
169 | }; | ||
170 | |||
171 | #define WMI_DATA_HDR_DATA_TYPE_MASK 0x3 | ||
172 | #define WMI_DATA_HDR_DATA_TYPE_SHIFT 6 | ||
173 | |||
174 | /* Macros for operating on WMI_DATA_HDR (info2) field */ | ||
175 | #define WMI_DATA_HDR_SEQNO_MASK 0xFFF | ||
176 | #define WMI_DATA_HDR_SEQNO_SHIFT 0 | ||
177 | |||
178 | #define WMI_DATA_HDR_AMSDU_MASK 0x1 | ||
179 | #define WMI_DATA_HDR_AMSDU_SHIFT 12 | ||
180 | |||
181 | #define WMI_DATA_HDR_META_MASK 0x7 | ||
182 | #define WMI_DATA_HDR_META_SHIFT 13 | ||
183 | |||
184 | struct wmi_data_hdr { | ||
185 | s8 rssi; | ||
186 | |||
187 | /* | ||
188 | * usage of 'info' field(8-bit): | ||
189 | * | ||
190 | * b1:b0 - WMI_MSG_TYPE | ||
191 | * b4:b3:b2 - UP(tid) | ||
192 | * b5 - Used in AP mode. | ||
193 | * More-data in tx dir, PS in rx. | ||
194 | * b7:b6 - Dot3 header(0), | ||
195 | * Dot11 Header(1), | ||
196 | * ACL data(2) | ||
197 | */ | ||
198 | u8 info; | ||
199 | |||
200 | /* | ||
201 | * usage of 'info2' field(16-bit): | ||
202 | * | ||
203 | * b11:b0 - seq_no | ||
204 | * b12 - A-MSDU? | ||
205 | * b15:b13 - META_DATA_VERSION 0 - 7 | ||
206 | */ | ||
207 | __le16 info2; | ||
208 | __le16 info3; | ||
209 | } __packed; | ||
210 | |||
211 | static inline u8 wmi_data_hdr_get_up(struct wmi_data_hdr *dhdr) | ||
212 | { | ||
213 | return (dhdr->info >> WMI_DATA_HDR_UP_SHIFT) & WMI_DATA_HDR_UP_MASK; | ||
214 | } | ||
215 | |||
216 | static inline void wmi_data_hdr_set_up(struct wmi_data_hdr *dhdr, | ||
217 | u8 usr_pri) | ||
218 | { | ||
219 | dhdr->info &= ~(WMI_DATA_HDR_UP_MASK << WMI_DATA_HDR_UP_SHIFT); | ||
220 | dhdr->info |= usr_pri << WMI_DATA_HDR_UP_SHIFT; | ||
221 | } | ||
222 | |||
223 | static inline u8 wmi_data_hdr_get_dot11(struct wmi_data_hdr *dhdr) | ||
224 | { | ||
225 | u8 data_type; | ||
226 | |||
227 | data_type = (dhdr->info >> WMI_DATA_HDR_DATA_TYPE_SHIFT) & | ||
228 | WMI_DATA_HDR_DATA_TYPE_MASK; | ||
229 | return (data_type == WMI_DATA_HDR_DATA_TYPE_802_11); | ||
230 | } | ||
231 | |||
232 | static inline u16 wmi_data_hdr_get_seqno(struct wmi_data_hdr *dhdr) | ||
233 | { | ||
234 | return (le16_to_cpu(dhdr->info2) >> WMI_DATA_HDR_SEQNO_SHIFT) & | ||
235 | WMI_DATA_HDR_SEQNO_MASK; | ||
236 | } | ||
237 | |||
238 | static inline u8 wmi_data_hdr_is_amsdu(struct wmi_data_hdr *dhdr) | ||
239 | { | ||
240 | return (le16_to_cpu(dhdr->info2) >> WMI_DATA_HDR_AMSDU_SHIFT) & | ||
241 | WMI_DATA_HDR_AMSDU_MASK; | ||
242 | } | ||
243 | |||
244 | static inline u8 wmi_data_hdr_get_meta(struct wmi_data_hdr *dhdr) | ||
245 | { | ||
246 | return (le16_to_cpu(dhdr->info2) >> WMI_DATA_HDR_META_SHIFT) & | ||
247 | WMI_DATA_HDR_META_MASK; | ||
248 | } | ||
249 | |||
250 | /* Tx meta version definitions */ | ||
251 | #define WMI_MAX_TX_META_SZ 12 | ||
252 | #define WMI_META_VERSION_1 0x01 | ||
253 | #define WMI_META_VERSION_2 0x02 | ||
254 | |||
255 | struct wmi_tx_meta_v1 { | ||
256 | /* packet ID to identify the tx request */ | ||
257 | u8 pkt_id; | ||
258 | |||
259 | /* rate policy to be used for the tx of this frame */ | ||
260 | u8 rate_plcy_id; | ||
261 | } __packed; | ||
262 | |||
263 | struct wmi_tx_meta_v2 { | ||
264 | /* | ||
265 | * Offset from start of the WMI header for csum calculation to | ||
266 | * begin. | ||
267 | */ | ||
268 | u8 csum_start; | ||
269 | |||
270 | /* offset from start of WMI header where final csum goes */ | ||
271 | u8 csum_dest; | ||
272 | |||
273 | /* no of bytes over which csum is calculated */ | ||
274 | u8 csum_flags; | ||
275 | } __packed; | ||
276 | |||
277 | struct wmi_rx_meta_v1 { | ||
278 | u8 status; | ||
279 | |||
280 | /* rate index mapped to rate at which this packet was received. */ | ||
281 | u8 rix; | ||
282 | |||
283 | /* rssi of packet */ | ||
284 | u8 rssi; | ||
285 | |||
286 | /* rf channel during packet reception */ | ||
287 | u8 channel; | ||
288 | |||
289 | __le16 flags; | ||
290 | } __packed; | ||
291 | |||
292 | struct wmi_rx_meta_v2 { | ||
293 | __le16 csum; | ||
294 | |||
295 | /* bit 0 set -partial csum valid bit 1 set -test mode */ | ||
296 | u8 csum_flags; | ||
297 | } __packed; | ||
298 | |||
299 | /* Control Path */ | ||
300 | struct wmi_cmd_hdr { | ||
301 | __le16 cmd_id; | ||
302 | |||
303 | /* info1 - 16 bits | ||
304 | * b03:b00 - id | ||
305 | * b15:b04 - unused */ | ||
306 | __le16 info1; | ||
307 | |||
308 | /* for alignment */ | ||
309 | __le16 reserved; | ||
310 | } __packed; | ||
311 | |||
312 | /* List of WMI commands */ | ||
313 | enum wmi_cmd_id { | ||
314 | WMI_CONNECT_CMDID = 0x0001, | ||
315 | WMI_RECONNECT_CMDID, | ||
316 | WMI_DISCONNECT_CMDID, | ||
317 | WMI_SYNCHRONIZE_CMDID, | ||
318 | WMI_CREATE_PSTREAM_CMDID, | ||
319 | WMI_DELETE_PSTREAM_CMDID, | ||
320 | WMI_START_SCAN_CMDID, | ||
321 | WMI_SET_SCAN_PARAMS_CMDID, | ||
322 | WMI_SET_BSS_FILTER_CMDID, | ||
323 | WMI_SET_PROBED_SSID_CMDID, /* 10 */ | ||
324 | WMI_SET_LISTEN_INT_CMDID, | ||
325 | WMI_SET_BMISS_TIME_CMDID, | ||
326 | WMI_SET_DISC_TIMEOUT_CMDID, | ||
327 | WMI_GET_CHANNEL_LIST_CMDID, | ||
328 | WMI_SET_BEACON_INT_CMDID, | ||
329 | WMI_GET_STATISTICS_CMDID, | ||
330 | WMI_SET_CHANNEL_PARAMS_CMDID, | ||
331 | WMI_SET_POWER_MODE_CMDID, | ||
332 | WMI_SET_IBSS_PM_CAPS_CMDID, | ||
333 | WMI_SET_POWER_PARAMS_CMDID, /* 20 */ | ||
334 | WMI_SET_POWERSAVE_TIMERS_POLICY_CMDID, | ||
335 | WMI_ADD_CIPHER_KEY_CMDID, | ||
336 | WMI_DELETE_CIPHER_KEY_CMDID, | ||
337 | WMI_ADD_KRK_CMDID, | ||
338 | WMI_DELETE_KRK_CMDID, | ||
339 | WMI_SET_PMKID_CMDID, | ||
340 | WMI_SET_TX_PWR_CMDID, | ||
341 | WMI_GET_TX_PWR_CMDID, | ||
342 | WMI_SET_ASSOC_INFO_CMDID, | ||
343 | WMI_ADD_BAD_AP_CMDID, /* 30 */ | ||
344 | WMI_DELETE_BAD_AP_CMDID, | ||
345 | WMI_SET_TKIP_COUNTERMEASURES_CMDID, | ||
346 | WMI_RSSI_THRESHOLD_PARAMS_CMDID, | ||
347 | WMI_TARGET_ERROR_REPORT_BITMASK_CMDID, | ||
348 | WMI_SET_ACCESS_PARAMS_CMDID, | ||
349 | WMI_SET_RETRY_LIMITS_CMDID, | ||
350 | WMI_SET_OPT_MODE_CMDID, | ||
351 | WMI_OPT_TX_FRAME_CMDID, | ||
352 | WMI_SET_VOICE_PKT_SIZE_CMDID, | ||
353 | WMI_SET_MAX_SP_LEN_CMDID, /* 40 */ | ||
354 | WMI_SET_ROAM_CTRL_CMDID, | ||
355 | WMI_GET_ROAM_TBL_CMDID, | ||
356 | WMI_GET_ROAM_DATA_CMDID, | ||
357 | WMI_ENABLE_RM_CMDID, | ||
358 | WMI_SET_MAX_OFFHOME_DURATION_CMDID, | ||
359 | WMI_EXTENSION_CMDID, /* Non-wireless extensions */ | ||
360 | WMI_SNR_THRESHOLD_PARAMS_CMDID, | ||
361 | WMI_LQ_THRESHOLD_PARAMS_CMDID, | ||
362 | WMI_SET_LPREAMBLE_CMDID, | ||
363 | WMI_SET_RTS_CMDID, /* 50 */ | ||
364 | WMI_CLR_RSSI_SNR_CMDID, | ||
365 | WMI_SET_FIXRATES_CMDID, | ||
366 | WMI_GET_FIXRATES_CMDID, | ||
367 | WMI_SET_AUTH_MODE_CMDID, | ||
368 | WMI_SET_REASSOC_MODE_CMDID, | ||
369 | WMI_SET_WMM_CMDID, | ||
370 | WMI_SET_WMM_TXOP_CMDID, | ||
371 | WMI_TEST_CMDID, | ||
372 | |||
373 | /* COEX AR6002 only */ | ||
374 | WMI_SET_BT_STATUS_CMDID, | ||
375 | WMI_SET_BT_PARAMS_CMDID, /* 60 */ | ||
376 | |||
377 | WMI_SET_KEEPALIVE_CMDID, | ||
378 | WMI_GET_KEEPALIVE_CMDID, | ||
379 | WMI_SET_APPIE_CMDID, | ||
380 | WMI_GET_APPIE_CMDID, | ||
381 | WMI_SET_WSC_STATUS_CMDID, | ||
382 | |||
383 | /* Wake on Wireless */ | ||
384 | WMI_SET_HOST_SLEEP_MODE_CMDID, | ||
385 | WMI_SET_WOW_MODE_CMDID, | ||
386 | WMI_GET_WOW_LIST_CMDID, | ||
387 | WMI_ADD_WOW_PATTERN_CMDID, | ||
388 | WMI_DEL_WOW_PATTERN_CMDID, /* 70 */ | ||
389 | |||
390 | WMI_SET_FRAMERATES_CMDID, | ||
391 | WMI_SET_AP_PS_CMDID, | ||
392 | WMI_SET_QOS_SUPP_CMDID, | ||
393 | |||
394 | /* WMI_THIN_RESERVED_... mark the start and end | ||
395 | * values for WMI_THIN_RESERVED command IDs. These | ||
396 | * command IDs can be found in wmi_thin.h */ | ||
397 | WMI_THIN_RESERVED_START = 0x8000, | ||
398 | WMI_THIN_RESERVED_END = 0x8fff, | ||
399 | |||
400 | /* Developer commands starts at 0xF000 */ | ||
401 | WMI_SET_BITRATE_CMDID = 0xF000, | ||
402 | WMI_GET_BITRATE_CMDID, | ||
403 | WMI_SET_WHALPARAM_CMDID, | ||
404 | WMI_SET_MAC_ADDRESS_CMDID, | ||
405 | WMI_SET_AKMP_PARAMS_CMDID, | ||
406 | WMI_SET_PMKID_LIST_CMDID, | ||
407 | WMI_GET_PMKID_LIST_CMDID, | ||
408 | WMI_ABORT_SCAN_CMDID, | ||
409 | WMI_SET_TARGET_EVENT_REPORT_CMDID, | ||
410 | |||
411 | /* Unused */ | ||
412 | WMI_UNUSED1, | ||
413 | WMI_UNUSED2, | ||
414 | |||
415 | /* AP mode commands */ | ||
416 | WMI_AP_HIDDEN_SSID_CMDID, | ||
417 | WMI_AP_SET_NUM_STA_CMDID, | ||
418 | WMI_AP_ACL_POLICY_CMDID, | ||
419 | WMI_AP_ACL_MAC_LIST_CMDID, | ||
420 | WMI_AP_CONFIG_COMMIT_CMDID, | ||
421 | WMI_AP_SET_MLME_CMDID, | ||
422 | WMI_AP_SET_PVB_CMDID, | ||
423 | WMI_AP_CONN_INACT_CMDID, | ||
424 | WMI_AP_PROT_SCAN_TIME_CMDID, | ||
425 | WMI_AP_SET_COUNTRY_CMDID, | ||
426 | WMI_AP_SET_DTIM_CMDID, | ||
427 | WMI_AP_MODE_STAT_CMDID, | ||
428 | |||
429 | WMI_SET_IP_CMDID, | ||
430 | WMI_SET_PARAMS_CMDID, | ||
431 | WMI_SET_MCAST_FILTER_CMDID, | ||
432 | WMI_DEL_MCAST_FILTER_CMDID, | ||
433 | |||
434 | WMI_ALLOW_AGGR_CMDID, | ||
435 | WMI_ADDBA_REQ_CMDID, | ||
436 | WMI_DELBA_REQ_CMDID, | ||
437 | WMI_SET_HT_CAP_CMDID, | ||
438 | WMI_SET_HT_OP_CMDID, | ||
439 | WMI_SET_TX_SELECT_RATES_CMDID, | ||
440 | WMI_SET_TX_SGI_PARAM_CMDID, | ||
441 | WMI_SET_RATE_POLICY_CMDID, | ||
442 | |||
443 | WMI_HCI_CMD_CMDID, | ||
444 | WMI_RX_FRAME_FORMAT_CMDID, | ||
445 | WMI_SET_THIN_MODE_CMDID, | ||
446 | WMI_SET_BT_WLAN_CONN_PRECEDENCE_CMDID, | ||
447 | |||
448 | WMI_AP_SET_11BG_RATESET_CMDID, | ||
449 | WMI_SET_PMK_CMDID, | ||
450 | WMI_MCAST_FILTER_CMDID, | ||
451 | |||
452 | /* COEX CMDID AR6003 */ | ||
453 | WMI_SET_BTCOEX_FE_ANT_CMDID, | ||
454 | WMI_SET_BTCOEX_COLOCATED_BT_DEV_CMDID, | ||
455 | WMI_SET_BTCOEX_SCO_CONFIG_CMDID, | ||
456 | WMI_SET_BTCOEX_A2DP_CONFIG_CMDID, | ||
457 | WMI_SET_BTCOEX_ACLCOEX_CONFIG_CMDID, | ||
458 | WMI_SET_BTCOEX_BTINQUIRY_PAGE_CONFIG_CMDID, | ||
459 | WMI_SET_BTCOEX_DEBUG_CMDID, | ||
460 | WMI_SET_BTCOEX_BT_OPERATING_STATUS_CMDID, | ||
461 | WMI_GET_BTCOEX_STATS_CMDID, | ||
462 | WMI_GET_BTCOEX_CONFIG_CMDID, | ||
463 | |||
464 | WMI_SET_DFS_ENABLE_CMDID, /* F034 */ | ||
465 | WMI_SET_DFS_MINRSSITHRESH_CMDID, | ||
466 | WMI_SET_DFS_MAXPULSEDUR_CMDID, | ||
467 | WMI_DFS_RADAR_DETECTED_CMDID, | ||
468 | |||
469 | /* P2P commands */ | ||
470 | WMI_P2P_SET_CONFIG_CMDID, /* F038 */ | ||
471 | WMI_WPS_SET_CONFIG_CMDID, | ||
472 | WMI_SET_REQ_DEV_ATTR_CMDID, | ||
473 | WMI_P2P_FIND_CMDID, | ||
474 | WMI_P2P_STOP_FIND_CMDID, | ||
475 | WMI_P2P_GO_NEG_START_CMDID, | ||
476 | WMI_P2P_LISTEN_CMDID, | ||
477 | |||
478 | WMI_CONFIG_TX_MAC_RULES_CMDID, /* F040 */ | ||
479 | WMI_SET_PROMISCUOUS_MODE_CMDID, | ||
480 | WMI_RX_FRAME_FILTER_CMDID, | ||
481 | WMI_SET_CHANNEL_CMDID, | ||
482 | |||
483 | /* WAC commands */ | ||
484 | WMI_ENABLE_WAC_CMDID, | ||
485 | WMI_WAC_SCAN_REPLY_CMDID, | ||
486 | WMI_WAC_CTRL_REQ_CMDID, | ||
487 | WMI_SET_DIV_PARAMS_CMDID, | ||
488 | |||
489 | WMI_GET_PMK_CMDID, | ||
490 | WMI_SET_PASSPHRASE_CMDID, | ||
491 | WMI_SEND_ASSOC_RES_CMDID, | ||
492 | WMI_SET_ASSOC_REQ_RELAY_CMDID, | ||
493 | WMI_GET_RFKILL_MODE_CMDID, | ||
494 | |||
495 | /* ACS command, consists of sub-commands */ | ||
496 | WMI_ACS_CTRL_CMDID, | ||
497 | |||
498 | /* Ultra low power store / recall commands */ | ||
499 | WMI_STORERECALL_CONFIGURE_CMDID, | ||
500 | WMI_STORERECALL_RECALL_CMDID, | ||
501 | WMI_STORERECALL_HOST_READY_CMDID, | ||
502 | WMI_FORCE_TARGET_ASSERT_CMDID, | ||
503 | WMI_SET_EXCESS_TX_RETRY_THRES_CMDID, | ||
504 | }; | ||
505 | |||
506 | /* WMI_CONNECT_CMDID */ | ||
507 | enum network_type { | ||
508 | INFRA_NETWORK = 0x01, | ||
509 | ADHOC_NETWORK = 0x02, | ||
510 | ADHOC_CREATOR = 0x04, | ||
511 | AP_NETWORK = 0x10, | ||
512 | }; | ||
513 | |||
514 | enum dot11_auth_mode { | ||
515 | OPEN_AUTH = 0x01, | ||
516 | SHARED_AUTH = 0x02, | ||
517 | |||
518 | /* different from IEEE_AUTH_MODE definitions */ | ||
519 | LEAP_AUTH = 0x04, | ||
520 | }; | ||
521 | |||
522 | enum { | ||
523 | AUTH_IDLE, | ||
524 | AUTH_OPEN_IN_PROGRESS, | ||
525 | }; | ||
526 | |||
527 | enum auth_mode { | ||
528 | NONE_AUTH = 0x01, | ||
529 | WPA_AUTH = 0x02, | ||
530 | WPA2_AUTH = 0x04, | ||
531 | WPA_PSK_AUTH = 0x08, | ||
532 | WPA2_PSK_AUTH = 0x10, | ||
533 | WPA_AUTH_CCKM = 0x20, | ||
534 | WPA2_AUTH_CCKM = 0x40, | ||
535 | }; | ||
536 | |||
537 | #define WMI_MIN_CRYPTO_TYPE NONE_CRYPT | ||
538 | #define WMI_MAX_CRYPTO_TYPE (AES_CRYPT + 1) | ||
539 | |||
540 | #define WMI_MIN_KEY_INDEX 0 | ||
541 | #define WMI_MAX_KEY_INDEX 3 | ||
542 | |||
543 | #define WMI_MAX_KEY_LEN 32 | ||
544 | |||
545 | /* | ||
546 | * NB: these values are ordered carefully; there are lots of | ||
547 | * of implications in any reordering. In particular beware | ||
548 | * that 4 is not used to avoid conflicting with IEEE80211_F_PRIVACY. | ||
549 | */ | ||
550 | #define ATH6KL_CIPHER_WEP 0 | ||
551 | #define ATH6KL_CIPHER_TKIP 1 | ||
552 | #define ATH6KL_CIPHER_AES_OCB 2 | ||
553 | #define ATH6KL_CIPHER_AES_CCM 3 | ||
554 | #define ATH6KL_CIPHER_CKIP 5 | ||
555 | #define ATH6KL_CIPHER_CCKM_KRK 6 | ||
556 | #define ATH6KL_CIPHER_NONE 7 /* pseudo value */ | ||
557 | |||
558 | /* | ||
559 | * 802.11 rate set. | ||
560 | */ | ||
561 | #define ATH6KL_RATE_MAXSIZE 15 /* max rates we'll handle */ | ||
562 | |||
563 | #define ATH_OUI_TYPE 0x01 | ||
564 | #define WPA_OUI_TYPE 0x01 | ||
565 | #define WMM_PARAM_OUI_SUBTYPE 0x01 | ||
566 | #define WMM_OUI_TYPE 0x02 | ||
567 | #define WSC_OUT_TYPE 0x04 | ||
568 | |||
569 | enum wmi_connect_ctrl_flags_bits { | ||
570 | CONNECT_ASSOC_POLICY_USER = 0x0001, | ||
571 | CONNECT_SEND_REASSOC = 0x0002, | ||
572 | CONNECT_IGNORE_WPAx_GROUP_CIPHER = 0x0004, | ||
573 | CONNECT_PROFILE_MATCH_DONE = 0x0008, | ||
574 | CONNECT_IGNORE_AAC_BEACON = 0x0010, | ||
575 | CONNECT_CSA_FOLLOW_BSS = 0x0020, | ||
576 | CONNECT_DO_WPA_OFFLOAD = 0x0040, | ||
577 | CONNECT_DO_NOT_DEAUTH = 0x0080, | ||
578 | }; | ||
579 | |||
580 | struct wmi_connect_cmd { | ||
581 | u8 nw_type; | ||
582 | u8 dot11_auth_mode; | ||
583 | u8 auth_mode; | ||
584 | u8 prwise_crypto_type; | ||
585 | u8 prwise_crypto_len; | ||
586 | u8 grp_crypto_type; | ||
587 | u8 grp_crypto_len; | ||
588 | u8 ssid_len; | ||
589 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
590 | __le16 ch; | ||
591 | u8 bssid[ETH_ALEN]; | ||
592 | __le32 ctrl_flags; | ||
593 | } __packed; | ||
594 | |||
595 | /* WMI_RECONNECT_CMDID */ | ||
596 | struct wmi_reconnect_cmd { | ||
597 | /* channel hint */ | ||
598 | __le16 channel; | ||
599 | |||
600 | /* mandatory if set */ | ||
601 | u8 bssid[ETH_ALEN]; | ||
602 | } __packed; | ||
603 | |||
604 | /* WMI_ADD_CIPHER_KEY_CMDID */ | ||
605 | enum key_usage { | ||
606 | PAIRWISE_USAGE = 0x00, | ||
607 | GROUP_USAGE = 0x01, | ||
608 | |||
609 | /* default Tx Key - static WEP only */ | ||
610 | TX_USAGE = 0x02, | ||
611 | }; | ||
612 | |||
613 | /* | ||
614 | * Bit Flag | ||
615 | * Bit 0 - Initialise TSC - default is Initialize | ||
616 | */ | ||
617 | #define KEY_OP_INIT_TSC 0x01 | ||
618 | #define KEY_OP_INIT_RSC 0x02 | ||
619 | |||
620 | /* default initialise the TSC & RSC */ | ||
621 | #define KEY_OP_INIT_VAL 0x03 | ||
622 | #define KEY_OP_VALID_MASK 0x03 | ||
623 | |||
624 | struct wmi_add_cipher_key_cmd { | ||
625 | u8 key_index; | ||
626 | u8 key_type; | ||
627 | |||
628 | /* enum key_usage */ | ||
629 | u8 key_usage; | ||
630 | |||
631 | u8 key_len; | ||
632 | |||
633 | /* key replay sequence counter */ | ||
634 | u8 key_rsc[8]; | ||
635 | |||
636 | u8 key[WLAN_MAX_KEY_LEN]; | ||
637 | |||
638 | /* additional key control info */ | ||
639 | u8 key_op_ctrl; | ||
640 | |||
641 | u8 key_mac_addr[ETH_ALEN]; | ||
642 | } __packed; | ||
643 | |||
644 | /* WMI_DELETE_CIPHER_KEY_CMDID */ | ||
645 | struct wmi_delete_cipher_key_cmd { | ||
646 | u8 key_index; | ||
647 | } __packed; | ||
648 | |||
649 | #define WMI_KRK_LEN 16 | ||
650 | |||
651 | /* WMI_ADD_KRK_CMDID */ | ||
652 | struct wmi_add_krk_cmd { | ||
653 | u8 krk[WMI_KRK_LEN]; | ||
654 | } __packed; | ||
655 | |||
656 | /* WMI_SETPMKID_CMDID */ | ||
657 | |||
658 | #define WMI_PMKID_LEN 16 | ||
659 | |||
660 | enum pmkid_enable_flg { | ||
661 | PMKID_DISABLE = 0, | ||
662 | PMKID_ENABLE = 1, | ||
663 | }; | ||
664 | |||
665 | struct wmi_setpmkid_cmd { | ||
666 | u8 bssid[ETH_ALEN]; | ||
667 | |||
668 | /* enum pmkid_enable_flg */ | ||
669 | u8 enable; | ||
670 | |||
671 | u8 pmkid[WMI_PMKID_LEN]; | ||
672 | } __packed; | ||
673 | |||
674 | /* WMI_START_SCAN_CMD */ | ||
675 | enum wmi_scan_type { | ||
676 | WMI_LONG_SCAN = 0, | ||
677 | WMI_SHORT_SCAN = 1, | ||
678 | }; | ||
679 | |||
680 | struct wmi_start_scan_cmd { | ||
681 | __le32 force_fg_scan; | ||
682 | |||
683 | /* for legacy cisco AP compatibility */ | ||
684 | __le32 is_legacy; | ||
685 | |||
686 | /* max duration in the home channel(msec) */ | ||
687 | __le32 home_dwell_time; | ||
688 | |||
689 | /* time interval between scans (msec) */ | ||
690 | __le32 force_scan_intvl; | ||
691 | |||
692 | /* enum wmi_scan_type */ | ||
693 | u8 scan_type; | ||
694 | |||
695 | /* how many channels follow */ | ||
696 | u8 num_ch; | ||
697 | |||
698 | /* channels in Mhz */ | ||
699 | __le16 ch_list[1]; | ||
700 | } __packed; | ||
701 | |||
702 | /* WMI_SET_SCAN_PARAMS_CMDID */ | ||
703 | #define WMI_SHORTSCANRATIO_DEFAULT 3 | ||
704 | |||
705 | /* | ||
706 | * Warning: scan control flag value of 0xFF is used to disable | ||
707 | * all flags in WMI_SCAN_PARAMS_CMD. Do not add any more | ||
708 | * flags here | ||
709 | */ | ||
710 | enum wmi_scan_ctrl_flags_bits { | ||
711 | |||
712 | /* set if can scan in the connect cmd */ | ||
713 | CONNECT_SCAN_CTRL_FLAGS = 0x01, | ||
714 | |||
715 | /* set if scan for the SSID it is already connected to */ | ||
716 | SCAN_CONNECTED_CTRL_FLAGS = 0x02, | ||
717 | |||
718 | /* set if enable active scan */ | ||
719 | ACTIVE_SCAN_CTRL_FLAGS = 0x04, | ||
720 | |||
721 | /* set if enable roam scan when bmiss and lowrssi */ | ||
722 | ROAM_SCAN_CTRL_FLAGS = 0x08, | ||
723 | |||
724 | /* set if follows customer BSSINFO reporting rule */ | ||
725 | REPORT_BSSINFO_CTRL_FLAGS = 0x10, | ||
726 | |||
727 | /* if disabled, target doesn't scan after a disconnect event */ | ||
728 | ENABLE_AUTO_CTRL_FLAGS = 0x20, | ||
729 | |||
730 | /* | ||
731 | * Scan complete event with canceled status will be generated when | ||
732 | * a scan is prempted before it gets completed. | ||
733 | */ | ||
734 | ENABLE_SCAN_ABORT_EVENT = 0x40 | ||
735 | }; | ||
736 | |||
737 | #define DEFAULT_SCAN_CTRL_FLAGS \ | ||
738 | (CONNECT_SCAN_CTRL_FLAGS | \ | ||
739 | SCAN_CONNECTED_CTRL_FLAGS | \ | ||
740 | ACTIVE_SCAN_CTRL_FLAGS | \ | ||
741 | ROAM_SCAN_CTRL_FLAGS | \ | ||
742 | ENABLE_AUTO_CTRL_FLAGS) | ||
743 | |||
744 | struct wmi_scan_params_cmd { | ||
745 | /* sec */ | ||
746 | __le16 fg_start_period; | ||
747 | |||
748 | /* sec */ | ||
749 | __le16 fg_end_period; | ||
750 | |||
751 | /* sec */ | ||
752 | __le16 bg_period; | ||
753 | |||
754 | /* msec */ | ||
755 | __le16 maxact_chdwell_time; | ||
756 | |||
757 | /* msec */ | ||
758 | __le16 pas_chdwell_time; | ||
759 | |||
760 | /* how many shorts scan for one long */ | ||
761 | u8 short_scan_ratio; | ||
762 | |||
763 | u8 scan_ctrl_flags; | ||
764 | |||
765 | /* msec */ | ||
766 | __le16 minact_chdwell_time; | ||
767 | |||
768 | /* max active scans per ssid */ | ||
769 | __le16 maxact_scan_per_ssid; | ||
770 | |||
771 | /* msecs */ | ||
772 | __le32 max_dfsch_act_time; | ||
773 | } __packed; | ||
774 | |||
775 | /* WMI_SET_BSS_FILTER_CMDID */ | ||
776 | enum wmi_bss_filter { | ||
777 | /* no beacons forwarded */ | ||
778 | NONE_BSS_FILTER = 0x0, | ||
779 | |||
780 | /* all beacons forwarded */ | ||
781 | ALL_BSS_FILTER, | ||
782 | |||
783 | /* only beacons matching profile */ | ||
784 | PROFILE_FILTER, | ||
785 | |||
786 | /* all but beacons matching profile */ | ||
787 | ALL_BUT_PROFILE_FILTER, | ||
788 | |||
789 | /* only beacons matching current BSS */ | ||
790 | CURRENT_BSS_FILTER, | ||
791 | |||
792 | /* all but beacons matching BSS */ | ||
793 | ALL_BUT_BSS_FILTER, | ||
794 | |||
795 | /* beacons matching probed ssid */ | ||
796 | PROBED_SSID_FILTER, | ||
797 | |||
798 | /* marker only */ | ||
799 | LAST_BSS_FILTER, | ||
800 | }; | ||
801 | |||
802 | struct wmi_bss_filter_cmd { | ||
803 | /* see, enum wmi_bss_filter */ | ||
804 | u8 bss_filter; | ||
805 | |||
806 | /* for alignment */ | ||
807 | u8 reserved1; | ||
808 | |||
809 | /* for alignment */ | ||
810 | __le16 reserved2; | ||
811 | |||
812 | __le32 ie_mask; | ||
813 | } __packed; | ||
814 | |||
815 | /* WMI_SET_PROBED_SSID_CMDID */ | ||
816 | #define MAX_PROBED_SSID_INDEX 9 | ||
817 | |||
818 | enum wmi_ssid_flag { | ||
819 | /* disables entry */ | ||
820 | DISABLE_SSID_FLAG = 0, | ||
821 | |||
822 | /* probes specified ssid */ | ||
823 | SPECIFIC_SSID_FLAG = 0x01, | ||
824 | |||
825 | /* probes for any ssid */ | ||
826 | ANY_SSID_FLAG = 0x02, | ||
827 | }; | ||
828 | |||
829 | struct wmi_probed_ssid_cmd { | ||
830 | /* 0 to MAX_PROBED_SSID_INDEX */ | ||
831 | u8 entry_index; | ||
832 | |||
833 | /* see, enum wmi_ssid_flg */ | ||
834 | u8 flag; | ||
835 | |||
836 | u8 ssid_len; | ||
837 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
838 | } __packed; | ||
839 | |||
840 | /* | ||
841 | * WMI_SET_LISTEN_INT_CMDID | ||
842 | * The Listen interval is between 15 and 3000 TUs | ||
843 | */ | ||
844 | struct wmi_listen_int_cmd { | ||
845 | __le16 listen_intvl; | ||
846 | __le16 num_beacons; | ||
847 | } __packed; | ||
848 | |||
849 | /* WMI_SET_POWER_MODE_CMDID */ | ||
850 | enum wmi_power_mode { | ||
851 | REC_POWER = 0x01, | ||
852 | MAX_PERF_POWER, | ||
853 | }; | ||
854 | |||
855 | struct wmi_power_mode_cmd { | ||
856 | /* see, enum wmi_power_mode */ | ||
857 | u8 pwr_mode; | ||
858 | } __packed; | ||
859 | |||
860 | /* | ||
861 | * Policy to determnine whether power save failure event should be sent to | ||
862 | * host during scanning | ||
863 | */ | ||
864 | enum power_save_fail_event_policy { | ||
865 | SEND_POWER_SAVE_FAIL_EVENT_ALWAYS = 1, | ||
866 | IGNORE_POWER_SAVE_FAIL_EVENT_DURING_SCAN = 2, | ||
867 | }; | ||
868 | |||
869 | struct wmi_power_params_cmd { | ||
870 | /* msec */ | ||
871 | __le16 idle_period; | ||
872 | |||
873 | __le16 pspoll_number; | ||
874 | __le16 dtim_policy; | ||
875 | __le16 tx_wakeup_policy; | ||
876 | __le16 num_tx_to_wakeup; | ||
877 | __le16 ps_fail_event_policy; | ||
878 | } __packed; | ||
879 | |||
880 | /* WMI_SET_DISC_TIMEOUT_CMDID */ | ||
881 | struct wmi_disc_timeout_cmd { | ||
882 | /* seconds */ | ||
883 | u8 discon_timeout; | ||
884 | } __packed; | ||
885 | |||
886 | enum dir_type { | ||
887 | UPLINK_TRAFFIC = 0, | ||
888 | DNLINK_TRAFFIC = 1, | ||
889 | BIDIR_TRAFFIC = 2, | ||
890 | }; | ||
891 | |||
892 | enum voiceps_cap_type { | ||
893 | DISABLE_FOR_THIS_AC = 0, | ||
894 | ENABLE_FOR_THIS_AC = 1, | ||
895 | ENABLE_FOR_ALL_AC = 2, | ||
896 | }; | ||
897 | |||
898 | enum traffic_type { | ||
899 | TRAFFIC_TYPE_APERIODIC = 0, | ||
900 | TRAFFIC_TYPE_PERIODIC = 1, | ||
901 | }; | ||
902 | |||
903 | /* WMI_SYNCHRONIZE_CMDID */ | ||
904 | struct wmi_sync_cmd { | ||
905 | u8 data_sync_map; | ||
906 | } __packed; | ||
907 | |||
908 | /* WMI_CREATE_PSTREAM_CMDID */ | ||
909 | struct wmi_create_pstream_cmd { | ||
910 | /* msec */ | ||
911 | __le32 min_service_int; | ||
912 | |||
913 | /* msec */ | ||
914 | __le32 max_service_int; | ||
915 | |||
916 | /* msec */ | ||
917 | __le32 inactivity_int; | ||
918 | |||
919 | /* msec */ | ||
920 | __le32 suspension_int; | ||
921 | |||
922 | __le32 service_start_time; | ||
923 | |||
924 | /* in bps */ | ||
925 | __le32 min_data_rate; | ||
926 | |||
927 | /* in bps */ | ||
928 | __le32 mean_data_rate; | ||
929 | |||
930 | /* in bps */ | ||
931 | __le32 peak_data_rate; | ||
932 | |||
933 | __le32 max_burst_size; | ||
934 | __le32 delay_bound; | ||
935 | |||
936 | /* in bps */ | ||
937 | __le32 min_phy_rate; | ||
938 | |||
939 | __le32 sba; | ||
940 | __le32 medium_time; | ||
941 | |||
942 | /* in octects */ | ||
943 | __le16 nominal_msdu; | ||
944 | |||
945 | /* in octects */ | ||
946 | __le16 max_msdu; | ||
947 | |||
948 | u8 traffic_class; | ||
949 | |||
950 | /* see, enum dir_type */ | ||
951 | u8 traffic_direc; | ||
952 | |||
953 | u8 rx_queue_num; | ||
954 | |||
955 | /* see, enum traffic_type */ | ||
956 | u8 traffic_type; | ||
957 | |||
958 | /* see, enum voiceps_cap_type */ | ||
959 | u8 voice_psc_cap; | ||
960 | u8 tsid; | ||
961 | |||
962 | /* 802.1D user priority */ | ||
963 | u8 user_pri; | ||
964 | |||
965 | /* nominal phy rate */ | ||
966 | u8 nominal_phy; | ||
967 | } __packed; | ||
968 | |||
969 | /* WMI_DELETE_PSTREAM_CMDID */ | ||
970 | struct wmi_delete_pstream_cmd { | ||
971 | u8 tx_queue_num; | ||
972 | u8 rx_queue_num; | ||
973 | u8 traffic_direc; | ||
974 | u8 traffic_class; | ||
975 | u8 tsid; | ||
976 | } __packed; | ||
977 | |||
978 | /* WMI_SET_CHANNEL_PARAMS_CMDID */ | ||
979 | enum wmi_phy_mode { | ||
980 | WMI_11A_MODE = 0x1, | ||
981 | WMI_11G_MODE = 0x2, | ||
982 | WMI_11AG_MODE = 0x3, | ||
983 | WMI_11B_MODE = 0x4, | ||
984 | WMI_11GONLY_MODE = 0x5, | ||
985 | }; | ||
986 | |||
987 | #define WMI_MAX_CHANNELS 32 | ||
988 | |||
989 | /* | ||
990 | * WMI_RSSI_THRESHOLD_PARAMS_CMDID | ||
991 | * Setting the polltime to 0 would disable polling. Threshold values are | ||
992 | * in the ascending order, and should agree to: | ||
993 | * (lowThreshold_lowerVal < lowThreshold_upperVal < highThreshold_lowerVal | ||
994 | * < highThreshold_upperVal) | ||
995 | */ | ||
996 | |||
997 | struct wmi_rssi_threshold_params_cmd { | ||
998 | /* polling time as a factor of LI */ | ||
999 | __le32 poll_time; | ||
1000 | |||
1001 | /* lowest of upper */ | ||
1002 | a_sle16 thresh_above1_val; | ||
1003 | |||
1004 | a_sle16 thresh_above2_val; | ||
1005 | a_sle16 thresh_above3_val; | ||
1006 | a_sle16 thresh_above4_val; | ||
1007 | a_sle16 thresh_above5_val; | ||
1008 | |||
1009 | /* highest of upper */ | ||
1010 | a_sle16 thresh_above6_val; | ||
1011 | |||
1012 | /* lowest of bellow */ | ||
1013 | a_sle16 thresh_below1_val; | ||
1014 | |||
1015 | a_sle16 thresh_below2_val; | ||
1016 | a_sle16 thresh_below3_val; | ||
1017 | a_sle16 thresh_below4_val; | ||
1018 | a_sle16 thresh_below5_val; | ||
1019 | |||
1020 | /* highest of bellow */ | ||
1021 | a_sle16 thresh_below6_val; | ||
1022 | |||
1023 | /* "alpha" */ | ||
1024 | u8 weight; | ||
1025 | |||
1026 | u8 reserved[3]; | ||
1027 | } __packed; | ||
1028 | |||
1029 | /* | ||
1030 | * WMI_SNR_THRESHOLD_PARAMS_CMDID | ||
1031 | * Setting the polltime to 0 would disable polling. | ||
1032 | */ | ||
1033 | |||
1034 | struct wmi_snr_threshold_params_cmd { | ||
1035 | /* polling time as a factor of LI */ | ||
1036 | __le32 poll_time; | ||
1037 | |||
1038 | /* "alpha" */ | ||
1039 | u8 weight; | ||
1040 | |||
1041 | /* lowest of uppper */ | ||
1042 | u8 thresh_above1_val; | ||
1043 | |||
1044 | u8 thresh_above2_val; | ||
1045 | u8 thresh_above3_val; | ||
1046 | |||
1047 | /* highest of upper */ | ||
1048 | u8 thresh_above4_val; | ||
1049 | |||
1050 | /* lowest of bellow */ | ||
1051 | u8 thresh_below1_val; | ||
1052 | |||
1053 | u8 thresh_below2_val; | ||
1054 | u8 thresh_below3_val; | ||
1055 | |||
1056 | /* highest of bellow */ | ||
1057 | u8 thresh_below4_val; | ||
1058 | |||
1059 | u8 reserved[3]; | ||
1060 | } __packed; | ||
1061 | |||
1062 | enum wmi_preamble_policy { | ||
1063 | WMI_IGNORE_BARKER_IN_ERP = 0, | ||
1064 | WMI_DONOT_IGNORE_BARKER_IN_ERP | ||
1065 | }; | ||
1066 | |||
1067 | struct wmi_set_lpreamble_cmd { | ||
1068 | u8 status; | ||
1069 | u8 preamble_policy; | ||
1070 | } __packed; | ||
1071 | |||
1072 | struct wmi_set_rts_cmd { | ||
1073 | __le16 threshold; | ||
1074 | } __packed; | ||
1075 | |||
1076 | /* WMI_SET_TX_PWR_CMDID */ | ||
1077 | struct wmi_set_tx_pwr_cmd { | ||
1078 | /* in dbM units */ | ||
1079 | u8 dbM; | ||
1080 | } __packed; | ||
1081 | |||
1082 | struct wmi_tx_pwr_reply { | ||
1083 | /* in dbM units */ | ||
1084 | u8 dbM; | ||
1085 | } __packed; | ||
1086 | |||
1087 | struct wmi_report_sleep_state_event { | ||
1088 | __le32 sleep_state; | ||
1089 | }; | ||
1090 | |||
1091 | enum wmi_report_sleep_status { | ||
1092 | WMI_REPORT_SLEEP_STATUS_IS_DEEP_SLEEP = 0, | ||
1093 | WMI_REPORT_SLEEP_STATUS_IS_AWAKE | ||
1094 | }; | ||
1095 | enum target_event_report_config { | ||
1096 | /* default */ | ||
1097 | DISCONN_EVT_IN_RECONN = 0, | ||
1098 | |||
1099 | NO_DISCONN_EVT_IN_RECONN | ||
1100 | }; | ||
1101 | |||
1102 | /* Command Replies */ | ||
1103 | |||
1104 | /* WMI_GET_CHANNEL_LIST_CMDID reply */ | ||
1105 | struct wmi_channel_list_reply { | ||
1106 | u8 reserved; | ||
1107 | |||
1108 | /* number of channels in reply */ | ||
1109 | u8 num_ch; | ||
1110 | |||
1111 | /* channel in Mhz */ | ||
1112 | __le16 ch_list[1]; | ||
1113 | } __packed; | ||
1114 | |||
1115 | /* List of Events (target to host) */ | ||
1116 | enum wmi_event_id { | ||
1117 | WMI_READY_EVENTID = 0x1001, | ||
1118 | WMI_CONNECT_EVENTID, | ||
1119 | WMI_DISCONNECT_EVENTID, | ||
1120 | WMI_BSSINFO_EVENTID, | ||
1121 | WMI_CMDERROR_EVENTID, | ||
1122 | WMI_REGDOMAIN_EVENTID, | ||
1123 | WMI_PSTREAM_TIMEOUT_EVENTID, | ||
1124 | WMI_NEIGHBOR_REPORT_EVENTID, | ||
1125 | WMI_TKIP_MICERR_EVENTID, | ||
1126 | WMI_SCAN_COMPLETE_EVENTID, /* 0x100a */ | ||
1127 | WMI_REPORT_STATISTICS_EVENTID, | ||
1128 | WMI_RSSI_THRESHOLD_EVENTID, | ||
1129 | WMI_ERROR_REPORT_EVENTID, | ||
1130 | WMI_OPT_RX_FRAME_EVENTID, | ||
1131 | WMI_REPORT_ROAM_TBL_EVENTID, | ||
1132 | WMI_EXTENSION_EVENTID, | ||
1133 | WMI_CAC_EVENTID, | ||
1134 | WMI_SNR_THRESHOLD_EVENTID, | ||
1135 | WMI_LQ_THRESHOLD_EVENTID, | ||
1136 | WMI_TX_RETRY_ERR_EVENTID, /* 0x1014 */ | ||
1137 | WMI_REPORT_ROAM_DATA_EVENTID, | ||
1138 | WMI_TEST_EVENTID, | ||
1139 | WMI_APLIST_EVENTID, | ||
1140 | WMI_GET_WOW_LIST_EVENTID, | ||
1141 | WMI_GET_PMKID_LIST_EVENTID, | ||
1142 | WMI_CHANNEL_CHANGE_EVENTID, | ||
1143 | WMI_PEER_NODE_EVENTID, | ||
1144 | WMI_PSPOLL_EVENTID, | ||
1145 | WMI_DTIMEXPIRY_EVENTID, | ||
1146 | WMI_WLAN_VERSION_EVENTID, | ||
1147 | WMI_SET_PARAMS_REPLY_EVENTID, | ||
1148 | WMI_ADDBA_REQ_EVENTID, /*0x1020 */ | ||
1149 | WMI_ADDBA_RESP_EVENTID, | ||
1150 | WMI_DELBA_REQ_EVENTID, | ||
1151 | WMI_TX_COMPLETE_EVENTID, | ||
1152 | WMI_HCI_EVENT_EVENTID, | ||
1153 | WMI_ACL_DATA_EVENTID, | ||
1154 | WMI_REPORT_SLEEP_STATE_EVENTID, | ||
1155 | WMI_REPORT_BTCOEX_STATS_EVENTID, | ||
1156 | WMI_REPORT_BTCOEX_CONFIG_EVENTID, | ||
1157 | WMI_GET_PMK_EVENTID, | ||
1158 | |||
1159 | /* DFS Events */ | ||
1160 | WMI_DFS_HOST_ATTACH_EVENTID, | ||
1161 | WMI_DFS_HOST_INIT_EVENTID, | ||
1162 | WMI_DFS_RESET_DELAYLINES_EVENTID, | ||
1163 | WMI_DFS_RESET_RADARQ_EVENTID, | ||
1164 | WMI_DFS_RESET_AR_EVENTID, | ||
1165 | WMI_DFS_RESET_ARQ_EVENTID, | ||
1166 | WMI_DFS_SET_DUR_MULTIPLIER_EVENTID, | ||
1167 | WMI_DFS_SET_BANGRADAR_EVENTID, | ||
1168 | WMI_DFS_SET_DEBUGLEVEL_EVENTID, | ||
1169 | WMI_DFS_PHYERR_EVENTID, | ||
1170 | |||
1171 | /* CCX Evants */ | ||
1172 | WMI_CCX_RM_STATUS_EVENTID, | ||
1173 | |||
1174 | /* P2P Events */ | ||
1175 | WMI_P2P_GO_NEG_RESULT_EVENTID, | ||
1176 | |||
1177 | WMI_WAC_SCAN_DONE_EVENTID, | ||
1178 | WMI_WAC_REPORT_BSS_EVENTID, | ||
1179 | WMI_WAC_START_WPS_EVENTID, | ||
1180 | WMI_WAC_CTRL_REQ_REPLY_EVENTID, | ||
1181 | |||
1182 | /* RFKILL Events */ | ||
1183 | WMI_RFKILL_STATE_CHANGE_EVENTID, | ||
1184 | WMI_RFKILL_GET_MODE_CMD_EVENTID, | ||
1185 | WMI_THIN_RESERVED_START_EVENTID = 0x8000, | ||
1186 | |||
1187 | /* | ||
1188 | * Events in this range are reserved for thinmode | ||
1189 | * See wmi_thin.h for actual definitions | ||
1190 | */ | ||
1191 | WMI_THIN_RESERVED_END_EVENTID = 0x8fff, | ||
1192 | |||
1193 | WMI_SET_CHANNEL_EVENTID, | ||
1194 | WMI_ASSOC_REQ_EVENTID, | ||
1195 | |||
1196 | /* Generic ACS event */ | ||
1197 | WMI_ACS_EVENTID, | ||
1198 | WMI_REPORT_WMM_PARAMS_EVENTID | ||
1199 | }; | ||
1200 | |||
1201 | struct wmi_ready_event_2 { | ||
1202 | __le32 sw_version; | ||
1203 | __le32 abi_version; | ||
1204 | u8 mac_addr[ETH_ALEN]; | ||
1205 | u8 phy_cap; | ||
1206 | } __packed; | ||
1207 | |||
1208 | /* Connect Event */ | ||
1209 | struct wmi_connect_event { | ||
1210 | __le16 ch; | ||
1211 | u8 bssid[ETH_ALEN]; | ||
1212 | __le16 listen_intvl; | ||
1213 | __le16 beacon_intvl; | ||
1214 | __le32 nw_type; | ||
1215 | u8 beacon_ie_len; | ||
1216 | u8 assoc_req_len; | ||
1217 | u8 assoc_resp_len; | ||
1218 | u8 assoc_info[1]; | ||
1219 | } __packed; | ||
1220 | |||
1221 | /* Disconnect Event */ | ||
1222 | enum wmi_disconnect_reason { | ||
1223 | NO_NETWORK_AVAIL = 0x01, | ||
1224 | |||
1225 | /* bmiss */ | ||
1226 | LOST_LINK = 0x02, | ||
1227 | |||
1228 | DISCONNECT_CMD = 0x03, | ||
1229 | BSS_DISCONNECTED = 0x04, | ||
1230 | AUTH_FAILED = 0x05, | ||
1231 | ASSOC_FAILED = 0x06, | ||
1232 | NO_RESOURCES_AVAIL = 0x07, | ||
1233 | CSERV_DISCONNECT = 0x08, | ||
1234 | INVALID_PROFILE = 0x0a, | ||
1235 | DOT11H_CHANNEL_SWITCH = 0x0b, | ||
1236 | PROFILE_MISMATCH = 0x0c, | ||
1237 | CONNECTION_EVICTED = 0x0d, | ||
1238 | IBSS_MERGE = 0xe, | ||
1239 | }; | ||
1240 | |||
1241 | struct wmi_disconnect_event { | ||
1242 | /* reason code, see 802.11 spec. */ | ||
1243 | __le16 proto_reason_status; | ||
1244 | |||
1245 | /* set if known */ | ||
1246 | u8 bssid[ETH_ALEN]; | ||
1247 | |||
1248 | /* see WMI_DISCONNECT_REASON */ | ||
1249 | u8 disconn_reason; | ||
1250 | |||
1251 | u8 assoc_resp_len; | ||
1252 | u8 assoc_info[1]; | ||
1253 | } __packed; | ||
1254 | |||
1255 | /* | ||
1256 | * BSS Info Event. | ||
1257 | * Mechanism used to inform host of the presence and characteristic of | ||
1258 | * wireless networks present. Consists of bss info header followed by | ||
1259 | * the beacon or probe-response frame body. The 802.11 header is no included. | ||
1260 | */ | ||
1261 | enum wmi_bi_ftype { | ||
1262 | BEACON_FTYPE = 0x1, | ||
1263 | PROBERESP_FTYPE, | ||
1264 | ACTION_MGMT_FTYPE, | ||
1265 | PROBEREQ_FTYPE, | ||
1266 | }; | ||
1267 | |||
1268 | struct wmi_bss_info_hdr { | ||
1269 | __le16 ch; | ||
1270 | |||
1271 | /* see, enum wmi_bi_ftype */ | ||
1272 | u8 frame_type; | ||
1273 | |||
1274 | u8 snr; | ||
1275 | a_sle16 rssi; | ||
1276 | u8 bssid[ETH_ALEN]; | ||
1277 | __le32 ie_mask; | ||
1278 | } __packed; | ||
1279 | |||
1280 | /* | ||
1281 | * BSS INFO HDR version 2.0 | ||
1282 | * With 6 bytes HTC header and 6 bytes of WMI header | ||
1283 | * WMI_BSS_INFO_HDR cannot be accommodated in the removed 802.11 management | ||
1284 | * header space. | ||
1285 | * - Reduce the ie_mask to 2 bytes as only two bit flags are used | ||
1286 | * - Remove rssi and compute it on the host. rssi = snr - 95 | ||
1287 | */ | ||
1288 | struct wmi_bss_info_hdr2 { | ||
1289 | __le16 ch; | ||
1290 | |||
1291 | /* see, enum wmi_bi_ftype */ | ||
1292 | u8 frame_type; | ||
1293 | |||
1294 | u8 snr; | ||
1295 | u8 bssid[ETH_ALEN]; | ||
1296 | __le16 ie_mask; | ||
1297 | } __packed; | ||
1298 | |||
1299 | /* Command Error Event */ | ||
1300 | enum wmi_error_code { | ||
1301 | INVALID_PARAM = 0x01, | ||
1302 | ILLEGAL_STATE = 0x02, | ||
1303 | INTERNAL_ERROR = 0x03, | ||
1304 | }; | ||
1305 | |||
1306 | struct wmi_cmd_error_event { | ||
1307 | __le16 cmd_id; | ||
1308 | u8 err_code; | ||
1309 | } __packed; | ||
1310 | |||
1311 | struct wmi_pstream_timeout_event { | ||
1312 | u8 tx_queue_num; | ||
1313 | u8 rx_queue_num; | ||
1314 | u8 traffic_direc; | ||
1315 | u8 traffic_class; | ||
1316 | } __packed; | ||
1317 | |||
1318 | /* | ||
1319 | * The WMI_NEIGHBOR_REPORT Event is generated by the target to inform | ||
1320 | * the host of BSS's it has found that matches the current profile. | ||
1321 | * It can be used by the host to cache PMKs and/to initiate pre-authentication | ||
1322 | * if the BSS supports it. The first bssid is always the current associated | ||
1323 | * BSS. | ||
1324 | * The bssid and bssFlags information repeats according to the number | ||
1325 | * or APs reported. | ||
1326 | */ | ||
1327 | enum wmi_bss_flags { | ||
1328 | WMI_DEFAULT_BSS_FLAGS = 0x00, | ||
1329 | WMI_PREAUTH_CAPABLE_BSS = 0x01, | ||
1330 | WMI_PMKID_VALID_BSS = 0x02, | ||
1331 | }; | ||
1332 | |||
1333 | /* TKIP MIC Error Event */ | ||
1334 | struct wmi_tkip_micerr_event { | ||
1335 | u8 key_id; | ||
1336 | u8 is_mcast; | ||
1337 | } __packed; | ||
1338 | |||
1339 | /* WMI_SCAN_COMPLETE_EVENTID */ | ||
1340 | struct wmi_scan_complete_event { | ||
1341 | a_sle32 status; | ||
1342 | } __packed; | ||
1343 | |||
1344 | #define MAX_OPT_DATA_LEN 1400 | ||
1345 | |||
1346 | /* | ||
1347 | * Special frame receive Event. | ||
1348 | * Mechanism used to inform host of the receiption of the special frames. | ||
1349 | * Consists of special frame info header followed by special frame body. | ||
1350 | * The 802.11 header is not included. | ||
1351 | */ | ||
1352 | struct wmi_opt_rx_info_hdr { | ||
1353 | __le16 ch; | ||
1354 | u8 frame_type; | ||
1355 | s8 snr; | ||
1356 | u8 src_addr[ETH_ALEN]; | ||
1357 | u8 bssid[ETH_ALEN]; | ||
1358 | } __packed; | ||
1359 | |||
1360 | /* Reporting statistic */ | ||
1361 | struct tx_stats { | ||
1362 | __le32 pkt; | ||
1363 | __le32 byte; | ||
1364 | __le32 ucast_pkt; | ||
1365 | __le32 ucast_byte; | ||
1366 | __le32 mcast_pkt; | ||
1367 | __le32 mcast_byte; | ||
1368 | __le32 bcast_pkt; | ||
1369 | __le32 bcast_byte; | ||
1370 | __le32 rts_success_cnt; | ||
1371 | __le32 pkt_per_ac[4]; | ||
1372 | __le32 err_per_ac[4]; | ||
1373 | |||
1374 | __le32 err; | ||
1375 | __le32 fail_cnt; | ||
1376 | __le32 retry_cnt; | ||
1377 | __le32 mult_retry_cnt; | ||
1378 | __le32 rts_fail_cnt; | ||
1379 | a_sle32 ucast_rate; | ||
1380 | } __packed; | ||
1381 | |||
1382 | struct rx_stats { | ||
1383 | __le32 pkt; | ||
1384 | __le32 byte; | ||
1385 | __le32 ucast_pkt; | ||
1386 | __le32 ucast_byte; | ||
1387 | __le32 mcast_pkt; | ||
1388 | __le32 mcast_byte; | ||
1389 | __le32 bcast_pkt; | ||
1390 | __le32 bcast_byte; | ||
1391 | __le32 frgment_pkt; | ||
1392 | |||
1393 | __le32 err; | ||
1394 | __le32 crc_err; | ||
1395 | __le32 key_cache_miss; | ||
1396 | __le32 decrypt_err; | ||
1397 | __le32 dupl_frame; | ||
1398 | a_sle32 ucast_rate; | ||
1399 | } __packed; | ||
1400 | |||
1401 | struct tkip_ccmp_stats { | ||
1402 | __le32 tkip_local_mic_fail; | ||
1403 | __le32 tkip_cnter_measures_invoked; | ||
1404 | __le32 tkip_replays; | ||
1405 | __le32 tkip_fmt_err; | ||
1406 | __le32 ccmp_fmt_err; | ||
1407 | __le32 ccmp_replays; | ||
1408 | } __packed; | ||
1409 | |||
1410 | struct pm_stats { | ||
1411 | __le32 pwr_save_failure_cnt; | ||
1412 | __le16 stop_tx_failure_cnt; | ||
1413 | __le16 atim_tx_failure_cnt; | ||
1414 | __le16 atim_rx_failure_cnt; | ||
1415 | __le16 bcn_rx_failure_cnt; | ||
1416 | } __packed; | ||
1417 | |||
1418 | struct cserv_stats { | ||
1419 | __le32 cs_bmiss_cnt; | ||
1420 | __le32 cs_low_rssi_cnt; | ||
1421 | __le16 cs_connect_cnt; | ||
1422 | __le16 cs_discon_cnt; | ||
1423 | a_sle16 cs_ave_beacon_rssi; | ||
1424 | __le16 cs_roam_count; | ||
1425 | a_sle16 cs_rssi; | ||
1426 | u8 cs_snr; | ||
1427 | u8 cs_ave_beacon_snr; | ||
1428 | u8 cs_last_roam_msec; | ||
1429 | } __packed; | ||
1430 | |||
1431 | struct wlan_net_stats { | ||
1432 | struct tx_stats tx; | ||
1433 | struct rx_stats rx; | ||
1434 | struct tkip_ccmp_stats tkip_ccmp_stats; | ||
1435 | } __packed; | ||
1436 | |||
1437 | struct arp_stats { | ||
1438 | __le32 arp_received; | ||
1439 | __le32 arp_matched; | ||
1440 | __le32 arp_replied; | ||
1441 | } __packed; | ||
1442 | |||
1443 | struct wlan_wow_stats { | ||
1444 | __le32 wow_pkt_dropped; | ||
1445 | __le16 wow_evt_discarded; | ||
1446 | u8 wow_host_pkt_wakeups; | ||
1447 | u8 wow_host_evt_wakeups; | ||
1448 | } __packed; | ||
1449 | |||
1450 | struct wmi_target_stats { | ||
1451 | __le32 lq_val; | ||
1452 | a_sle32 noise_floor_calib; | ||
1453 | struct pm_stats pm_stats; | ||
1454 | struct wlan_net_stats stats; | ||
1455 | struct wlan_wow_stats wow_stats; | ||
1456 | struct arp_stats arp_stats; | ||
1457 | struct cserv_stats cserv_stats; | ||
1458 | } __packed; | ||
1459 | |||
1460 | /* | ||
1461 | * WMI_RSSI_THRESHOLD_EVENTID. | ||
1462 | * Indicate the RSSI events to host. Events are indicated when we breach a | ||
1463 | * thresold value. | ||
1464 | */ | ||
1465 | enum wmi_rssi_threshold_val { | ||
1466 | WMI_RSSI_THRESHOLD1_ABOVE = 0, | ||
1467 | WMI_RSSI_THRESHOLD2_ABOVE, | ||
1468 | WMI_RSSI_THRESHOLD3_ABOVE, | ||
1469 | WMI_RSSI_THRESHOLD4_ABOVE, | ||
1470 | WMI_RSSI_THRESHOLD5_ABOVE, | ||
1471 | WMI_RSSI_THRESHOLD6_ABOVE, | ||
1472 | WMI_RSSI_THRESHOLD1_BELOW, | ||
1473 | WMI_RSSI_THRESHOLD2_BELOW, | ||
1474 | WMI_RSSI_THRESHOLD3_BELOW, | ||
1475 | WMI_RSSI_THRESHOLD4_BELOW, | ||
1476 | WMI_RSSI_THRESHOLD5_BELOW, | ||
1477 | WMI_RSSI_THRESHOLD6_BELOW | ||
1478 | }; | ||
1479 | |||
1480 | struct wmi_rssi_threshold_event { | ||
1481 | a_sle16 rssi; | ||
1482 | u8 range; | ||
1483 | } __packed; | ||
1484 | |||
1485 | enum wmi_snr_threshold_val { | ||
1486 | WMI_SNR_THRESHOLD1_ABOVE = 1, | ||
1487 | WMI_SNR_THRESHOLD1_BELOW, | ||
1488 | WMI_SNR_THRESHOLD2_ABOVE, | ||
1489 | WMI_SNR_THRESHOLD2_BELOW, | ||
1490 | WMI_SNR_THRESHOLD3_ABOVE, | ||
1491 | WMI_SNR_THRESHOLD3_BELOW, | ||
1492 | WMI_SNR_THRESHOLD4_ABOVE, | ||
1493 | WMI_SNR_THRESHOLD4_BELOW | ||
1494 | }; | ||
1495 | |||
1496 | struct wmi_snr_threshold_event { | ||
1497 | /* see, enum wmi_snr_threshold_val */ | ||
1498 | u8 range; | ||
1499 | |||
1500 | u8 snr; | ||
1501 | } __packed; | ||
1502 | |||
1503 | /* WMI_REPORT_ROAM_TBL_EVENTID */ | ||
1504 | #define MAX_ROAM_TBL_CAND 5 | ||
1505 | |||
1506 | struct wmi_bss_roam_info { | ||
1507 | a_sle32 roam_util; | ||
1508 | u8 bssid[ETH_ALEN]; | ||
1509 | s8 rssi; | ||
1510 | s8 rssidt; | ||
1511 | s8 last_rssi; | ||
1512 | s8 util; | ||
1513 | s8 bias; | ||
1514 | |||
1515 | /* for alignment */ | ||
1516 | u8 reserved; | ||
1517 | } __packed; | ||
1518 | |||
1519 | /* WMI_CAC_EVENTID */ | ||
1520 | enum cac_indication { | ||
1521 | CAC_INDICATION_ADMISSION = 0x00, | ||
1522 | CAC_INDICATION_ADMISSION_RESP = 0x01, | ||
1523 | CAC_INDICATION_DELETE = 0x02, | ||
1524 | CAC_INDICATION_NO_RESP = 0x03, | ||
1525 | }; | ||
1526 | |||
1527 | #define WMM_TSPEC_IE_LEN 63 | ||
1528 | |||
1529 | struct wmi_cac_event { | ||
1530 | u8 ac; | ||
1531 | u8 cac_indication; | ||
1532 | u8 status_code; | ||
1533 | u8 tspec_suggestion[WMM_TSPEC_IE_LEN]; | ||
1534 | } __packed; | ||
1535 | |||
1536 | /* WMI_APLIST_EVENTID */ | ||
1537 | |||
1538 | enum aplist_ver { | ||
1539 | APLIST_VER1 = 1, | ||
1540 | }; | ||
1541 | |||
1542 | struct wmi_ap_info_v1 { | ||
1543 | u8 bssid[ETH_ALEN]; | ||
1544 | __le16 channel; | ||
1545 | } __packed; | ||
1546 | |||
1547 | union wmi_ap_info { | ||
1548 | struct wmi_ap_info_v1 ap_info_v1; | ||
1549 | } __packed; | ||
1550 | |||
1551 | struct wmi_aplist_event { | ||
1552 | u8 ap_list_ver; | ||
1553 | u8 num_ap; | ||
1554 | union wmi_ap_info ap_list[1]; | ||
1555 | } __packed; | ||
1556 | |||
1557 | /* Developer Commands */ | ||
1558 | |||
1559 | /* | ||
1560 | * WMI_SET_BITRATE_CMDID | ||
1561 | * | ||
1562 | * Get bit rate cmd uses same definition as set bit rate cmd | ||
1563 | */ | ||
1564 | enum wmi_bit_rate { | ||
1565 | RATE_AUTO = -1, | ||
1566 | RATE_1Mb = 0, | ||
1567 | RATE_2Mb = 1, | ||
1568 | RATE_5_5Mb = 2, | ||
1569 | RATE_11Mb = 3, | ||
1570 | RATE_6Mb = 4, | ||
1571 | RATE_9Mb = 5, | ||
1572 | RATE_12Mb = 6, | ||
1573 | RATE_18Mb = 7, | ||
1574 | RATE_24Mb = 8, | ||
1575 | RATE_36Mb = 9, | ||
1576 | RATE_48Mb = 10, | ||
1577 | RATE_54Mb = 11, | ||
1578 | RATE_MCS_0_20 = 12, | ||
1579 | RATE_MCS_1_20 = 13, | ||
1580 | RATE_MCS_2_20 = 14, | ||
1581 | RATE_MCS_3_20 = 15, | ||
1582 | RATE_MCS_4_20 = 16, | ||
1583 | RATE_MCS_5_20 = 17, | ||
1584 | RATE_MCS_6_20 = 18, | ||
1585 | RATE_MCS_7_20 = 19, | ||
1586 | RATE_MCS_0_40 = 20, | ||
1587 | RATE_MCS_1_40 = 21, | ||
1588 | RATE_MCS_2_40 = 22, | ||
1589 | RATE_MCS_3_40 = 23, | ||
1590 | RATE_MCS_4_40 = 24, | ||
1591 | RATE_MCS_5_40 = 25, | ||
1592 | RATE_MCS_6_40 = 26, | ||
1593 | RATE_MCS_7_40 = 27, | ||
1594 | }; | ||
1595 | |||
1596 | struct wmi_bit_rate_reply { | ||
1597 | /* see, enum wmi_bit_rate */ | ||
1598 | s8 rate_index; | ||
1599 | } __packed; | ||
1600 | |||
1601 | /* | ||
1602 | * WMI_SET_FIXRATES_CMDID | ||
1603 | * | ||
1604 | * Get fix rates cmd uses same definition as set fix rates cmd | ||
1605 | */ | ||
1606 | struct wmi_fix_rates_reply { | ||
1607 | /* see wmi_bit_rate */ | ||
1608 | __le32 fix_rate_mask; | ||
1609 | } __packed; | ||
1610 | |||
1611 | enum roam_data_type { | ||
1612 | /* get the roam time data */ | ||
1613 | ROAM_DATA_TIME = 1, | ||
1614 | }; | ||
1615 | |||
1616 | struct wmi_target_roam_time { | ||
1617 | __le32 disassoc_time; | ||
1618 | __le32 no_txrx_time; | ||
1619 | __le32 assoc_time; | ||
1620 | __le32 allow_txrx_time; | ||
1621 | u8 disassoc_bssid[ETH_ALEN]; | ||
1622 | s8 disassoc_bss_rssi; | ||
1623 | u8 assoc_bssid[ETH_ALEN]; | ||
1624 | s8 assoc_bss_rssi; | ||
1625 | } __packed; | ||
1626 | |||
1627 | enum wmi_txop_cfg { | ||
1628 | WMI_TXOP_DISABLED = 0, | ||
1629 | WMI_TXOP_ENABLED | ||
1630 | }; | ||
1631 | |||
1632 | struct wmi_set_wmm_txop_cmd { | ||
1633 | u8 txop_enable; | ||
1634 | } __packed; | ||
1635 | |||
1636 | struct wmi_set_keepalive_cmd { | ||
1637 | u8 keep_alive_intvl; | ||
1638 | } __packed; | ||
1639 | |||
1640 | struct wmi_get_keepalive_cmd { | ||
1641 | __le32 configured; | ||
1642 | u8 keep_alive_intvl; | ||
1643 | } __packed; | ||
1644 | |||
1645 | /* Notify the WSC registration status to the target */ | ||
1646 | #define WSC_REG_ACTIVE 1 | ||
1647 | #define WSC_REG_INACTIVE 0 | ||
1648 | |||
1649 | #define WOW_MAX_FILTER_LISTS 1 | ||
1650 | #define WOW_MAX_FILTERS_PER_LIST 4 | ||
1651 | #define WOW_PATTERN_SIZE 64 | ||
1652 | #define WOW_MASK_SIZE 64 | ||
1653 | |||
1654 | #define MAC_MAX_FILTERS_PER_LIST 4 | ||
1655 | |||
1656 | struct wow_filter { | ||
1657 | u8 wow_valid_filter; | ||
1658 | u8 wow_filter_id; | ||
1659 | u8 wow_filter_size; | ||
1660 | u8 wow_filter_offset; | ||
1661 | u8 wow_filter_mask[WOW_MASK_SIZE]; | ||
1662 | u8 wow_filter_pattern[WOW_PATTERN_SIZE]; | ||
1663 | } __packed; | ||
1664 | |||
1665 | #define MAX_IP_ADDRS 2 | ||
1666 | |||
1667 | struct wmi_set_ip_cmd { | ||
1668 | /* IP in network byte order */ | ||
1669 | __le32 ips[MAX_IP_ADDRS]; | ||
1670 | } __packed; | ||
1671 | |||
1672 | /* WMI_GET_WOW_LIST_CMD reply */ | ||
1673 | struct wmi_get_wow_list_reply { | ||
1674 | /* number of patterns in reply */ | ||
1675 | u8 num_filters; | ||
1676 | |||
1677 | /* this is filter # x of total num_filters */ | ||
1678 | u8 this_filter_num; | ||
1679 | |||
1680 | u8 wow_mode; | ||
1681 | u8 host_mode; | ||
1682 | struct wow_filter wow_filters[1]; | ||
1683 | } __packed; | ||
1684 | |||
1685 | /* WMI_SET_AKMP_PARAMS_CMD */ | ||
1686 | |||
1687 | struct wmi_pmkid { | ||
1688 | u8 pmkid[WMI_PMKID_LEN]; | ||
1689 | } __packed; | ||
1690 | |||
1691 | /* WMI_GET_PMKID_LIST_CMD Reply */ | ||
1692 | struct wmi_pmkid_list_reply { | ||
1693 | __le32 num_pmkid; | ||
1694 | u8 bssid_list[ETH_ALEN][1]; | ||
1695 | struct wmi_pmkid pmkid_list[1]; | ||
1696 | } __packed; | ||
1697 | |||
1698 | /* WMI_ADDBA_REQ_EVENTID */ | ||
1699 | struct wmi_addba_req_event { | ||
1700 | u8 tid; | ||
1701 | u8 win_sz; | ||
1702 | __le16 st_seq_no; | ||
1703 | |||
1704 | /* f/w response for ADDBA Req; OK (0) or failure (!=0) */ | ||
1705 | u8 status; | ||
1706 | } __packed; | ||
1707 | |||
1708 | /* WMI_ADDBA_RESP_EVENTID */ | ||
1709 | struct wmi_addba_resp_event { | ||
1710 | u8 tid; | ||
1711 | |||
1712 | /* OK (0), failure (!=0) */ | ||
1713 | u8 status; | ||
1714 | |||
1715 | /* three values: not supported(0), 3839, 8k */ | ||
1716 | __le16 amsdu_sz; | ||
1717 | } __packed; | ||
1718 | |||
1719 | /* WMI_DELBA_EVENTID | ||
1720 | * f/w received a DELBA for peer and processed it. | ||
1721 | * Host is notified of this | ||
1722 | */ | ||
1723 | struct wmi_delba_event { | ||
1724 | u8 tid; | ||
1725 | u8 is_peer_initiator; | ||
1726 | __le16 reason_code; | ||
1727 | } __packed; | ||
1728 | |||
1729 | #define PEER_NODE_JOIN_EVENT 0x00 | ||
1730 | #define PEER_NODE_LEAVE_EVENT 0x01 | ||
1731 | #define PEER_FIRST_NODE_JOIN_EVENT 0x10 | ||
1732 | #define PEER_LAST_NODE_LEAVE_EVENT 0x11 | ||
1733 | |||
1734 | struct wmi_peer_node_event { | ||
1735 | u8 event_code; | ||
1736 | u8 peer_mac_addr[ETH_ALEN]; | ||
1737 | } __packed; | ||
1738 | |||
1739 | /* Transmit complete event data structure(s) */ | ||
1740 | |||
1741 | /* version 1 of tx complete msg */ | ||
1742 | struct tx_complete_msg_v1 { | ||
1743 | #define TX_COMPLETE_STATUS_SUCCESS 0 | ||
1744 | #define TX_COMPLETE_STATUS_RETRIES 1 | ||
1745 | #define TX_COMPLETE_STATUS_NOLINK 2 | ||
1746 | #define TX_COMPLETE_STATUS_TIMEOUT 3 | ||
1747 | #define TX_COMPLETE_STATUS_OTHER 4 | ||
1748 | |||
1749 | u8 status; | ||
1750 | |||
1751 | /* packet ID to identify parent packet */ | ||
1752 | u8 pkt_id; | ||
1753 | |||
1754 | /* rate index on successful transmission */ | ||
1755 | u8 rate_idx; | ||
1756 | |||
1757 | /* number of ACK failures in tx attempt */ | ||
1758 | u8 ack_failures; | ||
1759 | } __packed; | ||
1760 | |||
1761 | struct wmi_tx_complete_event { | ||
1762 | /* no of tx comp msgs following this struct */ | ||
1763 | u8 num_msg; | ||
1764 | |||
1765 | /* length in bytes for each individual msg following this struct */ | ||
1766 | u8 msg_len; | ||
1767 | |||
1768 | /* version of tx complete msg data following this struct */ | ||
1769 | u8 msg_type; | ||
1770 | |||
1771 | /* individual messages follow this header */ | ||
1772 | u8 reserved; | ||
1773 | } __packed; | ||
1774 | |||
1775 | /* | ||
1776 | * ------- AP Mode definitions -------------- | ||
1777 | */ | ||
1778 | |||
1779 | /* | ||
1780 | * !!! Warning !!! | ||
1781 | * -Changing the following values needs compilation of both driver and firmware | ||
1782 | */ | ||
1783 | #define AP_MAX_NUM_STA 8 | ||
1784 | |||
1785 | /* Spl. AID used to set DTIM flag in the beacons */ | ||
1786 | #define MCAST_AID 0xFF | ||
1787 | |||
1788 | #define DEF_AP_COUNTRY_CODE "US " | ||
1789 | |||
1790 | /* Used with WMI_AP_SET_NUM_STA_CMDID */ | ||
1791 | |||
1792 | struct wmi_ap_set_pvb_cmd { | ||
1793 | __le32 flag; | ||
1794 | __le16 aid; | ||
1795 | } __packed; | ||
1796 | |||
1797 | struct wmi_rx_frame_format_cmd { | ||
1798 | /* version of meta data for rx packets <0 = default> (0-7 = valid) */ | ||
1799 | u8 meta_ver; | ||
1800 | |||
1801 | /* | ||
1802 | * 1 == leave .11 header intact, | ||
1803 | * 0 == replace .11 header with .3 <default> | ||
1804 | */ | ||
1805 | u8 dot11_hdr; | ||
1806 | |||
1807 | /* | ||
1808 | * 1 == defragmentation is performed by host, | ||
1809 | * 0 == performed by target <default> | ||
1810 | */ | ||
1811 | u8 defrag_on_host; | ||
1812 | |||
1813 | /* for alignment */ | ||
1814 | u8 reserved[1]; | ||
1815 | } __packed; | ||
1816 | |||
1817 | /* AP mode events */ | ||
1818 | |||
1819 | /* WMI_PS_POLL_EVENT */ | ||
1820 | struct wmi_pspoll_event { | ||
1821 | __le16 aid; | ||
1822 | } __packed; | ||
1823 | |||
1824 | struct wmi_per_sta_stat { | ||
1825 | __le32 tx_bytes; | ||
1826 | __le32 tx_pkts; | ||
1827 | __le32 tx_error; | ||
1828 | __le32 tx_discard; | ||
1829 | __le32 rx_bytes; | ||
1830 | __le32 rx_pkts; | ||
1831 | __le32 rx_error; | ||
1832 | __le32 rx_discard; | ||
1833 | __le32 aid; | ||
1834 | } __packed; | ||
1835 | |||
1836 | struct wmi_ap_mode_stat { | ||
1837 | __le32 action; | ||
1838 | struct wmi_per_sta_stat sta[AP_MAX_NUM_STA + 1]; | ||
1839 | } __packed; | ||
1840 | |||
1841 | /* End of AP mode definitions */ | ||
1842 | |||
1843 | /* Extended WMI (WMIX) | ||
1844 | * | ||
1845 | * Extended WMIX commands are encapsulated in a WMI message with | ||
1846 | * cmd=WMI_EXTENSION_CMD. | ||
1847 | * | ||
1848 | * Extended WMI commands are those that are needed during wireless | ||
1849 | * operation, but which are not really wireless commands. This allows, | ||
1850 | * for instance, platform-specific commands. Extended WMI commands are | ||
1851 | * embedded in a WMI command message with WMI_COMMAND_ID=WMI_EXTENSION_CMDID. | ||
1852 | * Extended WMI events are similarly embedded in a WMI event message with | ||
1853 | * WMI_EVENT_ID=WMI_EXTENSION_EVENTID. | ||
1854 | */ | ||
1855 | struct wmix_cmd_hdr { | ||
1856 | __le32 cmd_id; | ||
1857 | } __packed; | ||
1858 | |||
1859 | enum wmix_command_id { | ||
1860 | WMIX_DSETOPEN_REPLY_CMDID = 0x2001, | ||
1861 | WMIX_DSETDATA_REPLY_CMDID, | ||
1862 | WMIX_GPIO_OUTPUT_SET_CMDID, | ||
1863 | WMIX_GPIO_INPUT_GET_CMDID, | ||
1864 | WMIX_GPIO_REGISTER_SET_CMDID, | ||
1865 | WMIX_GPIO_REGISTER_GET_CMDID, | ||
1866 | WMIX_GPIO_INTR_ACK_CMDID, | ||
1867 | WMIX_HB_CHALLENGE_RESP_CMDID, | ||
1868 | WMIX_DBGLOG_CFG_MODULE_CMDID, | ||
1869 | WMIX_PROF_CFG_CMDID, /* 0x200a */ | ||
1870 | WMIX_PROF_ADDR_SET_CMDID, | ||
1871 | WMIX_PROF_START_CMDID, | ||
1872 | WMIX_PROF_STOP_CMDID, | ||
1873 | WMIX_PROF_COUNT_GET_CMDID, | ||
1874 | }; | ||
1875 | |||
1876 | enum wmix_event_id { | ||
1877 | WMIX_DSETOPENREQ_EVENTID = 0x3001, | ||
1878 | WMIX_DSETCLOSE_EVENTID, | ||
1879 | WMIX_DSETDATAREQ_EVENTID, | ||
1880 | WMIX_GPIO_INTR_EVENTID, | ||
1881 | WMIX_GPIO_DATA_EVENTID, | ||
1882 | WMIX_GPIO_ACK_EVENTID, | ||
1883 | WMIX_HB_CHALLENGE_RESP_EVENTID, | ||
1884 | WMIX_DBGLOG_EVENTID, | ||
1885 | WMIX_PROF_COUNT_EVENTID, | ||
1886 | }; | ||
1887 | |||
1888 | /* | ||
1889 | * ------Error Detection support------- | ||
1890 | */ | ||
1891 | |||
1892 | /* | ||
1893 | * WMIX_HB_CHALLENGE_RESP_CMDID | ||
1894 | * Heartbeat Challenge Response command | ||
1895 | */ | ||
1896 | struct wmix_hb_challenge_resp_cmd { | ||
1897 | __le32 cookie; | ||
1898 | __le32 source; | ||
1899 | } __packed; | ||
1900 | |||
1901 | /* End of Extended WMI (WMIX) */ | ||
1902 | |||
1903 | enum wmi_sync_flag { | ||
1904 | NO_SYNC_WMIFLAG = 0, | ||
1905 | |||
1906 | /* transmit all queued data before cmd */ | ||
1907 | SYNC_BEFORE_WMIFLAG, | ||
1908 | |||
1909 | /* any new data waits until cmd execs */ | ||
1910 | SYNC_AFTER_WMIFLAG, | ||
1911 | |||
1912 | SYNC_BOTH_WMIFLAG, | ||
1913 | |||
1914 | /* end marker */ | ||
1915 | END_WMIFLAG | ||
1916 | }; | ||
1917 | |||
1918 | enum htc_endpoint_id ath6kl_wmi_get_control_ep(struct wmi *wmi); | ||
1919 | void ath6kl_wmi_set_control_ep(struct wmi *wmi, enum htc_endpoint_id ep_id); | ||
1920 | int ath6kl_wmi_dix_2_dot3(struct wmi *wmi, struct sk_buff *skb); | ||
1921 | int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb, | ||
1922 | u8 msg_type, bool more_data, | ||
1923 | enum wmi_data_hdr_data_type data_type, | ||
1924 | u8 meta_ver, void *tx_meta_info); | ||
1925 | |||
1926 | int ath6kl_wmi_dot11_hdr_remove(struct wmi *wmi, struct sk_buff *skb); | ||
1927 | int ath6kl_wmi_dot3_2_dix(struct sk_buff *skb); | ||
1928 | int ath6kl_wmi_data_hdr_remove(struct wmi *wmi, struct sk_buff *skb); | ||
1929 | int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, struct sk_buff *skb, | ||
1930 | u32 layer2_priority, bool wmm_enabled, | ||
1931 | u8 *ac); | ||
1932 | |||
1933 | int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb); | ||
1934 | struct bss *ath6kl_wmi_find_node(struct wmi *wmi, const u8 *mac_addr); | ||
1935 | void ath6kl_wmi_node_free(struct wmi *wmi, const u8 *mac_addr); | ||
1936 | |||
1937 | int ath6kl_wmi_cmd_send(struct wmi *wmi, struct sk_buff *skb, | ||
1938 | enum wmi_cmd_id cmd_id, enum wmi_sync_flag sync_flag); | ||
1939 | |||
1940 | int ath6kl_wmi_connect_cmd(struct wmi *wmi, enum network_type nw_type, | ||
1941 | enum dot11_auth_mode dot11_auth_mode, | ||
1942 | enum auth_mode auth_mode, | ||
1943 | enum crypto_type pairwise_crypto, | ||
1944 | u8 pairwise_crypto_len, | ||
1945 | enum crypto_type group_crypto, | ||
1946 | u8 group_crypto_len, int ssid_len, u8 *ssid, | ||
1947 | u8 *bssid, u16 channel, u32 ctrl_flags); | ||
1948 | |||
1949 | int ath6kl_wmi_reconnect_cmd(struct wmi *wmi, u8 *bssid, u16 channel); | ||
1950 | int ath6kl_wmi_disconnect_cmd(struct wmi *wmi); | ||
1951 | int ath6kl_wmi_startscan_cmd(struct wmi *wmi, enum wmi_scan_type scan_type, | ||
1952 | u32 force_fgscan, u32 is_legacy, | ||
1953 | u32 home_dwell_time, u32 force_scan_interval, | ||
1954 | s8 num_chan, u16 *ch_list); | ||
1955 | int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u16 fg_start_sec, | ||
1956 | u16 fg_end_sec, u16 bg_sec, | ||
1957 | u16 minact_chdw_msec, u16 maxact_chdw_msec, | ||
1958 | u16 pas_chdw_msec, u8 short_scan_ratio, | ||
1959 | u8 scan_ctrl_flag, u32 max_dfsch_act_time, | ||
1960 | u16 maxact_scan_per_ssid); | ||
1961 | int ath6kl_wmi_bssfilter_cmd(struct wmi *wmi, u8 filter, u32 ie_mask); | ||
1962 | int ath6kl_wmi_probedssid_cmd(struct wmi *wmi, u8 index, u8 flag, | ||
1963 | u8 ssid_len, u8 *ssid); | ||
1964 | int ath6kl_wmi_listeninterval_cmd(struct wmi *wmi, u16 listen_interval, | ||
1965 | u16 listen_beacons); | ||
1966 | int ath6kl_wmi_powermode_cmd(struct wmi *wmi, u8 pwr_mode); | ||
1967 | int ath6kl_wmi_pmparams_cmd(struct wmi *wmi, u16 idle_period, | ||
1968 | u16 ps_poll_num, u16 dtim_policy, | ||
1969 | u16 tx_wakup_policy, u16 num_tx_to_wakeup, | ||
1970 | u16 ps_fail_event_policy); | ||
1971 | int ath6kl_wmi_disctimeout_cmd(struct wmi *wmi, u8 timeout); | ||
1972 | int ath6kl_wmi_create_pstream_cmd(struct wmi *wmi, | ||
1973 | struct wmi_create_pstream_cmd *pstream); | ||
1974 | int ath6kl_wmi_delete_pstream_cmd(struct wmi *wmi, u8 traffic_class, u8 tsid); | ||
1975 | |||
1976 | int ath6kl_wmi_set_rts_cmd(struct wmi *wmi, u16 threshold); | ||
1977 | int ath6kl_wmi_set_lpreamble_cmd(struct wmi *wmi, u8 status, | ||
1978 | u8 preamble_policy); | ||
1979 | |||
1980 | int ath6kl_wmi_get_challenge_resp_cmd(struct wmi *wmi, u32 cookie, u32 source); | ||
1981 | |||
1982 | int ath6kl_wmi_get_stats_cmd(struct wmi *wmi); | ||
1983 | int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 key_index, | ||
1984 | enum crypto_type key_type, | ||
1985 | u8 key_usage, u8 key_len, | ||
1986 | u8 *key_rsc, u8 *key_material, | ||
1987 | u8 key_op_ctrl, u8 *mac_addr, | ||
1988 | enum wmi_sync_flag sync_flag); | ||
1989 | int ath6kl_wmi_add_krk_cmd(struct wmi *wmi, u8 *krk); | ||
1990 | int ath6kl_wmi_deletekey_cmd(struct wmi *wmi, u8 key_index); | ||
1991 | int ath6kl_wmi_setpmkid_cmd(struct wmi *wmi, const u8 *bssid, | ||
1992 | const u8 *pmkid, bool set); | ||
1993 | int ath6kl_wmi_set_tx_pwr_cmd(struct wmi *wmi, u8 dbM); | ||
1994 | int ath6kl_wmi_get_tx_pwr_cmd(struct wmi *wmi); | ||
1995 | |||
1996 | int ath6kl_wmi_set_wmm_txop(struct wmi *wmi, enum wmi_txop_cfg cfg); | ||
1997 | int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 keep_alive_intvl); | ||
1998 | |||
1999 | s32 ath6kl_wmi_get_rate(s8 rate_index); | ||
2000 | |||
2001 | int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd); | ||
2002 | |||
2003 | struct bss *ath6kl_wmi_find_ssid_node(struct wmi *wmi, u8 *ssid, | ||
2004 | u32 ssid_len, bool is_wpa2, | ||
2005 | bool match_ssid); | ||
2006 | |||
2007 | void ath6kl_wmi_node_return(struct wmi *wmi, struct bss *bss); | ||
2008 | |||
2009 | /* AP mode */ | ||
2010 | int ath6kl_wmi_set_pvb_cmd(struct wmi *wmi, u16 aid, bool flag); | ||
2011 | |||
2012 | int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 rx_meta_version, | ||
2013 | bool rx_dot11_hdr, bool defrag_on_host); | ||
2014 | |||
2015 | void *ath6kl_wmi_init(struct ath6kl *devt); | ||
2016 | void ath6kl_wmi_shutdown(struct wmi *wmi); | ||
2017 | |||
2018 | #endif /* WMI_H */ | ||
diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 0b36fcf8a280..85a54cd2b083 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c | |||
@@ -133,7 +133,7 @@ static int ath_ahb_probe(struct platform_device *pdev) | |||
133 | goto err_free_hw; | 133 | goto err_free_hw; |
134 | } | 134 | } |
135 | 135 | ||
136 | ret = ath9k_init_device(id->driver_data, sc, 0x0, &ath_ahb_bus_ops); | 136 | ret = ath9k_init_device(id->driver_data, sc, &ath_ahb_bus_ops); |
137 | if (ret) { | 137 | if (ret) { |
138 | dev_err(&pdev->dev, "failed to initialize device\n"); | 138 | dev_err(&pdev->dev, "failed to initialize device\n"); |
139 | goto err_irq; | 139 | goto err_irq; |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h index 2339728a7306..a0aadaddd071 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h | |||
@@ -835,108 +835,108 @@ static const u32 ar9300_2p2_baseband_core[][2] = { | |||
835 | 835 | ||
836 | static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = { | 836 | static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = { |
837 | /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ | 837 | /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ |
838 | {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, | 838 | {0x0000a2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, |
839 | {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, | 839 | {0x0000a2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, |
840 | {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, | 840 | {0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, |
841 | {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, | 841 | {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, |
842 | {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, | 842 | {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, |
843 | {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, | 843 | {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, |
844 | {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, | 844 | {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, |
845 | {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, | 845 | {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, |
846 | {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200}, | 846 | {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, |
847 | {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202}, | 847 | {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, |
848 | {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400}, | 848 | {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400}, |
849 | {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402}, | 849 | {0x0000a518, 0x21002220, 0x21002220, 0x16000402, 0x16000402}, |
850 | {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404}, | 850 | {0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404}, |
851 | {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603}, | 851 | {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603}, |
852 | {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02}, | 852 | {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02}, |
853 | {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04}, | 853 | {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04}, |
854 | {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20}, | 854 | {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20}, |
855 | {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20}, | 855 | {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20}, |
856 | {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22}, | 856 | {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22}, |
857 | {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24}, | 857 | {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, |
858 | {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640}, | 858 | {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, |
859 | {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, | 859 | {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, |
860 | {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, | 860 | {0x0000a544, 0x52022470, 0x52022470, 0x3f001861, 0x3f001861}, |
861 | {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, | 861 | {0x0000a548, 0x55022490, 0x55022490, 0x43001a81, 0x43001a81}, |
862 | {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83}, | 862 | {0x0000a54c, 0x59022492, 0x59022492, 0x47001a83, 0x47001a83}, |
863 | {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, | 863 | {0x0000a550, 0x5d022692, 0x5d022692, 0x4a001c84, 0x4a001c84}, |
864 | {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, | 864 | {0x0000a554, 0x61022892, 0x61022892, 0x4e001ce3, 0x4e001ce3}, |
865 | {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, | 865 | {0x0000a558, 0x65024890, 0x65024890, 0x52001ce5, 0x52001ce5}, |
866 | {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9}, | 866 | {0x0000a55c, 0x69024892, 0x69024892, 0x56001ce9, 0x56001ce9}, |
867 | {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb}, | 867 | {0x0000a560, 0x6e024c92, 0x6e024c92, 0x5a001ceb, 0x5a001ceb}, |
868 | {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, | 868 | {0x0000a564, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, |
869 | {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, | 869 | {0x0000a568, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, |
870 | {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, | 870 | {0x0000a56c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, |
871 | {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, | 871 | {0x0000a570, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, |
872 | {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, | 872 | {0x0000a574, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, |
873 | {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, | 873 | {0x0000a578, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, |
874 | {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, | 874 | {0x0000a57c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, |
875 | {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000}, | 875 | {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, |
876 | {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002}, | 876 | {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, |
877 | {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004}, | 877 | {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, |
878 | {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200}, | 878 | {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, |
879 | {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202}, | 879 | {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202}, |
880 | {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400}, | 880 | {0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400}, |
881 | {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402}, | 881 | {0x0000a598, 0x21802220, 0x21802220, 0x16800402, 0x16800402}, |
882 | {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404}, | 882 | {0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404}, |
883 | {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603}, | 883 | {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603}, |
884 | {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02}, | 884 | {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02}, |
885 | {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04}, | 885 | {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04}, |
886 | {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20}, | 886 | {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20}, |
887 | {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20}, | 887 | {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20}, |
888 | {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22}, | 888 | {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22}, |
889 | {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24}, | 889 | {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24}, |
890 | {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640}, | 890 | {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640}, |
891 | {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660}, | 891 | {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660}, |
892 | {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861}, | 892 | {0x0000a5c4, 0x52822470, 0x52822470, 0x3f801861, 0x3f801861}, |
893 | {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81}, | 893 | {0x0000a5c8, 0x55822490, 0x55822490, 0x43801a81, 0x43801a81}, |
894 | {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83}, | 894 | {0x0000a5cc, 0x59822492, 0x59822492, 0x47801a83, 0x47801a83}, |
895 | {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84}, | 895 | {0x0000a5d0, 0x5d822692, 0x5d822692, 0x4a801c84, 0x4a801c84}, |
896 | {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3}, | 896 | {0x0000a5d4, 0x61822892, 0x61822892, 0x4e801ce3, 0x4e801ce3}, |
897 | {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5}, | 897 | {0x0000a5d8, 0x65824890, 0x65824890, 0x52801ce5, 0x52801ce5}, |
898 | {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9}, | 898 | {0x0000a5dc, 0x69824892, 0x69824892, 0x56801ce9, 0x56801ce9}, |
899 | {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb}, | 899 | {0x0000a5e0, 0x6e824c92, 0x6e824c92, 0x5a801ceb, 0x5a801ceb}, |
900 | {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, | 900 | {0x0000a5e4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, |
901 | {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, | 901 | {0x0000a5e8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, |
902 | {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, | 902 | {0x0000a5ec, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, |
903 | {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, | 903 | {0x0000a5f0, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, |
904 | {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, | 904 | {0x0000a5f4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, |
905 | {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, | 905 | {0x0000a5f8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, |
906 | {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, | 906 | {0x0000a5fc, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, |
907 | {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | 907 | {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, |
908 | {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | 908 | {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, |
909 | {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | 909 | {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, |
910 | {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | 910 | {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, |
911 | {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000}, | 911 | {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, |
912 | {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000}, | 912 | {0x0000a614, 0x02004000, 0x02004000, 0x01404000, 0x01404000}, |
913 | {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501}, | 913 | {0x0000a618, 0x02004801, 0x02004801, 0x01404501, 0x01404501}, |
914 | {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501}, | 914 | {0x0000a61c, 0x02808a02, 0x02808a02, 0x02008501, 0x02008501}, |
915 | {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03}, | 915 | {0x0000a620, 0x0380ce03, 0x0380ce03, 0x0280ca03, 0x0280ca03}, |
916 | {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04}, | 916 | {0x0000a624, 0x04411104, 0x04411104, 0x03010c04, 0x03010c04}, |
917 | {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04}, | 917 | {0x0000a628, 0x04411104, 0x04411104, 0x04014c04, 0x04014c04}, |
918 | {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, | 918 | {0x0000a62c, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, |
919 | {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, | 919 | {0x0000a630, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, |
920 | {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, | 920 | {0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, |
921 | {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, | 921 | {0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, |
922 | {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, | 922 | {0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, |
923 | {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, | 923 | {0x0000b2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, |
924 | {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, | 924 | {0x0000b2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, |
925 | {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, | 925 | {0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, |
926 | {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, | 926 | {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, |
927 | {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, | 927 | {0x0000c2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, |
928 | {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, | 928 | {0x0000c2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, |
929 | {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, | 929 | {0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, |
930 | {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, | 930 | {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, |
931 | {0x00016044, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6}, | 931 | {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, |
932 | {0x00016048, 0xae480001, 0xae480001, 0xae480001, 0xae480001}, | 932 | {0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, |
933 | {0x00016068, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c}, | 933 | {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, |
934 | {0x00016444, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6}, | 934 | {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, |
935 | {0x00016448, 0xae480001, 0xae480001, 0xae480001, 0xae480001}, | 935 | {0x00016448, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, |
936 | {0x00016468, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c}, | 936 | {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, |
937 | {0x00016844, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6}, | 937 | {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, |
938 | {0x00016848, 0xae480001, 0xae480001, 0xae480001, 0xae480001}, | 938 | {0x00016848, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, |
939 | {0x00016868, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c}, | 939 | {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, |
940 | }; | 940 | }; |
941 | 941 | ||
942 | static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = { | 942 | static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = { |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index c34bef1bf2b0..cb8bcc4e6091 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | |||
@@ -3418,6 +3418,133 @@ static bool ath9k_hw_ar9300_fill_eeprom(struct ath_hw *ah) | |||
3418 | return true; | 3418 | return true; |
3419 | } | 3419 | } |
3420 | 3420 | ||
3421 | #if defined(CONFIG_ATH9K_DEBUGFS) || defined(CONFIG_ATH9K_HTC_DEBUGFS) | ||
3422 | static u32 ar9003_dump_modal_eeprom(char *buf, u32 len, u32 size, | ||
3423 | struct ar9300_modal_eep_header *modal_hdr) | ||
3424 | { | ||
3425 | PR_EEP("Chain0 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[0])); | ||
3426 | PR_EEP("Chain1 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[1])); | ||
3427 | PR_EEP("Chain2 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[2])); | ||
3428 | PR_EEP("Ant. Common Control", le32_to_cpu(modal_hdr->antCtrlCommon)); | ||
3429 | PR_EEP("Ant. Common Control2", le32_to_cpu(modal_hdr->antCtrlCommon2)); | ||
3430 | PR_EEP("Ant. Gain", modal_hdr->antennaGain); | ||
3431 | PR_EEP("Switch Settle", modal_hdr->switchSettling); | ||
3432 | PR_EEP("Chain0 xatten1DB", modal_hdr->xatten1DB[0]); | ||
3433 | PR_EEP("Chain1 xatten1DB", modal_hdr->xatten1DB[1]); | ||
3434 | PR_EEP("Chain2 xatten1DB", modal_hdr->xatten1DB[2]); | ||
3435 | PR_EEP("Chain0 xatten1Margin", modal_hdr->xatten1Margin[0]); | ||
3436 | PR_EEP("Chain1 xatten1Margin", modal_hdr->xatten1Margin[1]); | ||
3437 | PR_EEP("Chain2 xatten1Margin", modal_hdr->xatten1Margin[2]); | ||
3438 | PR_EEP("Temp Slope", modal_hdr->tempSlope); | ||
3439 | PR_EEP("Volt Slope", modal_hdr->voltSlope); | ||
3440 | PR_EEP("spur Channels0", modal_hdr->spurChans[0]); | ||
3441 | PR_EEP("spur Channels1", modal_hdr->spurChans[1]); | ||
3442 | PR_EEP("spur Channels2", modal_hdr->spurChans[2]); | ||
3443 | PR_EEP("spur Channels3", modal_hdr->spurChans[3]); | ||
3444 | PR_EEP("spur Channels4", modal_hdr->spurChans[4]); | ||
3445 | PR_EEP("Chain0 NF Threshold", modal_hdr->noiseFloorThreshCh[0]); | ||
3446 | PR_EEP("Chain1 NF Threshold", modal_hdr->noiseFloorThreshCh[1]); | ||
3447 | PR_EEP("Chain2 NF Threshold", modal_hdr->noiseFloorThreshCh[2]); | ||
3448 | PR_EEP("xPA Bias Level", modal_hdr->xpaBiasLvl); | ||
3449 | PR_EEP("txFrameToDataStart", modal_hdr->txFrameToDataStart); | ||
3450 | PR_EEP("txFrameToPaOn", modal_hdr->txFrameToPaOn); | ||
3451 | PR_EEP("txFrameToXpaOn", modal_hdr->txFrameToXpaOn); | ||
3452 | PR_EEP("txClip", modal_hdr->txClip); | ||
3453 | PR_EEP("ADC Desired size", modal_hdr->adcDesiredSize); | ||
3454 | PR_EEP("Chain0 ob", modal_hdr->ob[0]); | ||
3455 | PR_EEP("Chain1 ob", modal_hdr->ob[1]); | ||
3456 | PR_EEP("Chain2 ob", modal_hdr->ob[2]); | ||
3457 | |||
3458 | PR_EEP("Chain0 db_stage2", modal_hdr->db_stage2[0]); | ||
3459 | PR_EEP("Chain1 db_stage2", modal_hdr->db_stage2[1]); | ||
3460 | PR_EEP("Chain2 db_stage2", modal_hdr->db_stage2[2]); | ||
3461 | PR_EEP("Chain0 db_stage3", modal_hdr->db_stage3[0]); | ||
3462 | PR_EEP("Chain1 db_stage3", modal_hdr->db_stage3[1]); | ||
3463 | PR_EEP("Chain2 db_stage3", modal_hdr->db_stage3[2]); | ||
3464 | PR_EEP("Chain0 db_stage4", modal_hdr->db_stage4[0]); | ||
3465 | PR_EEP("Chain1 db_stage4", modal_hdr->db_stage4[1]); | ||
3466 | PR_EEP("Chain2 db_stage4", modal_hdr->db_stage4[2]); | ||
3467 | |||
3468 | return len; | ||
3469 | } | ||
3470 | |||
3471 | static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, | ||
3472 | u8 *buf, u32 len, u32 size) | ||
3473 | { | ||
3474 | struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; | ||
3475 | struct ar9300_base_eep_hdr *pBase; | ||
3476 | |||
3477 | if (!dump_base_hdr) { | ||
3478 | len += snprintf(buf + len, size - len, | ||
3479 | "%20s :\n", "2GHz modal Header"); | ||
3480 | len += ar9003_dump_modal_eeprom(buf, len, size, | ||
3481 | &eep->modalHeader2G); | ||
3482 | len += snprintf(buf + len, size - len, | ||
3483 | "%20s :\n", "5GHz modal Header"); | ||
3484 | len += ar9003_dump_modal_eeprom(buf, len, size, | ||
3485 | &eep->modalHeader5G); | ||
3486 | goto out; | ||
3487 | } | ||
3488 | |||
3489 | pBase = &eep->baseEepHeader; | ||
3490 | |||
3491 | PR_EEP("EEPROM Version", ah->eeprom.ar9300_eep.eepromVersion); | ||
3492 | PR_EEP("RegDomain1", le16_to_cpu(pBase->regDmn[0])); | ||
3493 | PR_EEP("RegDomain2", le16_to_cpu(pBase->regDmn[1])); | ||
3494 | PR_EEP("TX Mask", (pBase->txrxMask >> 4)); | ||
3495 | PR_EEP("RX Mask", (pBase->txrxMask & 0x0f)); | ||
3496 | PR_EEP("Allow 5GHz", !!(pBase->opCapFlags.opFlags & | ||
3497 | AR5416_OPFLAGS_11A)); | ||
3498 | PR_EEP("Allow 2GHz", !!(pBase->opCapFlags.opFlags & | ||
3499 | AR5416_OPFLAGS_11G)); | ||
3500 | PR_EEP("Disable 2GHz HT20", !!(pBase->opCapFlags.opFlags & | ||
3501 | AR5416_OPFLAGS_N_2G_HT20)); | ||
3502 | PR_EEP("Disable 2GHz HT40", !!(pBase->opCapFlags.opFlags & | ||
3503 | AR5416_OPFLAGS_N_2G_HT40)); | ||
3504 | PR_EEP("Disable 5Ghz HT20", !!(pBase->opCapFlags.opFlags & | ||
3505 | AR5416_OPFLAGS_N_5G_HT20)); | ||
3506 | PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags.opFlags & | ||
3507 | AR5416_OPFLAGS_N_5G_HT40)); | ||
3508 | PR_EEP("Big Endian", !!(pBase->opCapFlags.eepMisc & 0x01)); | ||
3509 | PR_EEP("RF Silent", pBase->rfSilent); | ||
3510 | PR_EEP("BT option", pBase->blueToothOptions); | ||
3511 | PR_EEP("Device Cap", pBase->deviceCap); | ||
3512 | PR_EEP("Device Type", pBase->deviceType); | ||
3513 | PR_EEP("Power Table Offset", pBase->pwrTableOffset); | ||
3514 | PR_EEP("Tuning Caps1", pBase->params_for_tuning_caps[0]); | ||
3515 | PR_EEP("Tuning Caps2", pBase->params_for_tuning_caps[1]); | ||
3516 | PR_EEP("Enable Tx Temp Comp", !!(pBase->featureEnable & BIT(0))); | ||
3517 | PR_EEP("Enable Tx Volt Comp", !!(pBase->featureEnable & BIT(1))); | ||
3518 | PR_EEP("Enable fast clock", !!(pBase->featureEnable & BIT(2))); | ||
3519 | PR_EEP("Enable doubling", !!(pBase->featureEnable & BIT(3))); | ||
3520 | PR_EEP("Internal regulator", !!(pBase->featureEnable & BIT(4))); | ||
3521 | PR_EEP("Enable Paprd", !!(pBase->featureEnable & BIT(5))); | ||
3522 | PR_EEP("Driver Strength", !!(pBase->miscConfiguration & BIT(0))); | ||
3523 | PR_EEP("Chain mask Reduce", (pBase->miscConfiguration >> 0x3) & 0x1); | ||
3524 | PR_EEP("Write enable Gpio", pBase->eepromWriteEnableGpio); | ||
3525 | PR_EEP("WLAN Disable Gpio", pBase->wlanDisableGpio); | ||
3526 | PR_EEP("WLAN LED Gpio", pBase->wlanLedGpio); | ||
3527 | PR_EEP("Rx Band Select Gpio", pBase->rxBandSelectGpio); | ||
3528 | PR_EEP("Tx Gain", pBase->txrxgain >> 4); | ||
3529 | PR_EEP("Rx Gain", pBase->txrxgain & 0xf); | ||
3530 | PR_EEP("SW Reg", le32_to_cpu(pBase->swreg)); | ||
3531 | |||
3532 | len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress", | ||
3533 | ah->eeprom.ar9300_eep.macAddr); | ||
3534 | out: | ||
3535 | if (len > size) | ||
3536 | len = size; | ||
3537 | |||
3538 | return len; | ||
3539 | } | ||
3540 | #else | ||
3541 | static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, | ||
3542 | u8 *buf, u32 len, u32 size) | ||
3543 | { | ||
3544 | return 0; | ||
3545 | } | ||
3546 | #endif | ||
3547 | |||
3421 | /* XXX: review hardware docs */ | 3548 | /* XXX: review hardware docs */ |
3422 | static int ath9k_hw_ar9300_get_eeprom_ver(struct ath_hw *ah) | 3549 | static int ath9k_hw_ar9300_get_eeprom_ver(struct ath_hw *ah) |
3423 | { | 3550 | { |
@@ -4061,7 +4188,7 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray) | |||
4061 | /* Write the power for duplicated frames - HT40 */ | 4188 | /* Write the power for duplicated frames - HT40 */ |
4062 | 4189 | ||
4063 | /* dup40_cck (LSB), dup40_ofdm, ext20_cck, ext20_ofdm (MSB) */ | 4190 | /* dup40_cck (LSB), dup40_ofdm, ext20_cck, ext20_ofdm (MSB) */ |
4064 | REG_WRITE(ah, 0xa3e0, | 4191 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE(8), |
4065 | POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 24) | | 4192 | POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 24) | |
4066 | POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 16) | | 4193 | POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 16) | |
4067 | POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 8) | | 4194 | POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 8) | |
@@ -4922,25 +5049,7 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, | |||
4922 | "TPC[%02d] 0x%08x\n", i, targetPowerValT2[i]); | 5049 | "TPC[%02d] 0x%08x\n", i, targetPowerValT2[i]); |
4923 | } | 5050 | } |
4924 | 5051 | ||
4925 | /* | 5052 | ah->txpower_limit = regulatory->max_power_level; |
4926 | * This is the TX power we send back to driver core, | ||
4927 | * and it can use to pass to userspace to display our | ||
4928 | * currently configured TX power setting. | ||
4929 | * | ||
4930 | * Since power is rate dependent, use one of the indices | ||
4931 | * from the AR9300_Rates enum to select an entry from | ||
4932 | * targetPowerValT2[] to report. Currently returns the | ||
4933 | * power for HT40 MCS 0, HT20 MCS 0, or OFDM 6 Mbps | ||
4934 | * as CCK power is less interesting (?). | ||
4935 | */ | ||
4936 | i = ALL_TARGET_LEGACY_6_24; /* legacy */ | ||
4937 | if (IS_CHAN_HT40(chan)) | ||
4938 | i = ALL_TARGET_HT40_0_8_16; /* ht40 */ | ||
4939 | else if (IS_CHAN_HT20(chan)) | ||
4940 | i = ALL_TARGET_HT20_0_8_16; /* ht20 */ | ||
4941 | |||
4942 | ah->txpower_limit = targetPowerValT2[i]; | ||
4943 | regulatory->max_power_level = targetPowerValT2[i]; | ||
4944 | 5053 | ||
4945 | /* Write target power array to registers */ | 5054 | /* Write target power array to registers */ |
4946 | ar9003_hw_tx_power_regwrite(ah, targetPowerValT2); | 5055 | ar9003_hw_tx_power_regwrite(ah, targetPowerValT2); |
@@ -5015,6 +5124,7 @@ const struct eeprom_ops eep_ar9300_ops = { | |||
5015 | .check_eeprom = ath9k_hw_ar9300_check_eeprom, | 5124 | .check_eeprom = ath9k_hw_ar9300_check_eeprom, |
5016 | .get_eeprom = ath9k_hw_ar9300_get_eeprom, | 5125 | .get_eeprom = ath9k_hw_ar9300_get_eeprom, |
5017 | .fill_eeprom = ath9k_hw_ar9300_fill_eeprom, | 5126 | .fill_eeprom = ath9k_hw_ar9300_fill_eeprom, |
5127 | .dump_eeprom = ath9k_hw_ar9003_dump_eeprom, | ||
5018 | .get_eeprom_ver = ath9k_hw_ar9300_get_eeprom_ver, | 5128 | .get_eeprom_ver = ath9k_hw_ar9300_get_eeprom_ver, |
5019 | .get_eeprom_rev = ath9k_hw_ar9300_get_eeprom_rev, | 5129 | .get_eeprom_rev = ath9k_hw_ar9300_get_eeprom_rev, |
5020 | .set_board_values = ath9k_hw_ar9300_set_board_values, | 5130 | .set_board_values = ath9k_hw_ar9300_set_board_values, |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index 8ff0b88a29b9..1aadc4757e67 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c | |||
@@ -531,17 +531,18 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, | |||
531 | 531 | ||
532 | /* TODO: byte swap on big endian for ar9300_10 */ | 532 | /* TODO: byte swap on big endian for ar9300_10 */ |
533 | 533 | ||
534 | if ((rxsp->status11 & AR_RxDone) == 0) | 534 | if (!rxs) { |
535 | return -EINPROGRESS; | 535 | if ((rxsp->status11 & AR_RxDone) == 0) |
536 | return -EINPROGRESS; | ||
536 | 537 | ||
537 | if (MS(rxsp->ds_info, AR_DescId) != 0x168c) | 538 | if (MS(rxsp->ds_info, AR_DescId) != 0x168c) |
538 | return -EINVAL; | 539 | return -EINVAL; |
539 | 540 | ||
540 | if ((rxsp->ds_info & (AR_TxRxDesc | AR_CtrlStat)) != 0) | 541 | if ((rxsp->ds_info & (AR_TxRxDesc | AR_CtrlStat)) != 0) |
541 | return -EINPROGRESS; | 542 | return -EINPROGRESS; |
542 | 543 | ||
543 | if (!rxs) | ||
544 | return 0; | 544 | return 0; |
545 | } | ||
545 | 546 | ||
546 | rxs->rs_status = 0; | 547 | rxs->rs_status = 0; |
547 | rxs->rs_flags = 0; | 548 | rxs->rs_flags = 0; |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 1baca8e4715d..a0aaa6855486 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c | |||
@@ -370,7 +370,7 @@ static void ar9003_hw_spur_ofdm_work(struct ath_hw *ah, | |||
370 | else | 370 | else |
371 | spur_subchannel_sd = 0; | 371 | spur_subchannel_sd = 0; |
372 | 372 | ||
373 | spur_freq_sd = ((freq_offset + 10) << 9) / 11; | 373 | spur_freq_sd = (freq_offset << 9) / 11; |
374 | 374 | ||
375 | } else { | 375 | } else { |
376 | if (REG_READ_FIELD(ah, AR_PHY_GEN_CTRL, | 376 | if (REG_READ_FIELD(ah, AR_PHY_GEN_CTRL, |
@@ -379,7 +379,7 @@ static void ar9003_hw_spur_ofdm_work(struct ath_hw *ah, | |||
379 | else | 379 | else |
380 | spur_subchannel_sd = 1; | 380 | spur_subchannel_sd = 1; |
381 | 381 | ||
382 | spur_freq_sd = ((freq_offset - 10) << 9) / 11; | 382 | spur_freq_sd = (freq_offset << 9) / 11; |
383 | 383 | ||
384 | } | 384 | } |
385 | 385 | ||
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 46393f90f16c..c03949eb37c8 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -217,7 +217,6 @@ struct ath_buf_state { | |||
217 | u8 bf_type; | 217 | u8 bf_type; |
218 | u8 bfs_paprd; | 218 | u8 bfs_paprd; |
219 | unsigned long bfs_paprd_timestamp; | 219 | unsigned long bfs_paprd_timestamp; |
220 | enum ath9k_internal_frame_type bfs_ftype; | ||
221 | }; | 220 | }; |
222 | 221 | ||
223 | struct ath_buf { | 222 | struct ath_buf { |
@@ -273,8 +272,6 @@ struct ath_node { | |||
273 | struct ath_tx_control { | 272 | struct ath_tx_control { |
274 | struct ath_txq *txq; | 273 | struct ath_txq *txq; |
275 | struct ath_node *an; | 274 | struct ath_node *an; |
276 | int if_id; | ||
277 | enum ath9k_internal_frame_type frame_type; | ||
278 | u8 paprd; | 275 | u8 paprd; |
279 | }; | 276 | }; |
280 | 277 | ||
@@ -570,7 +567,6 @@ struct ath_ant_comb { | |||
570 | #define PS_WAIT_FOR_PSPOLL_DATA BIT(2) | 567 | #define PS_WAIT_FOR_PSPOLL_DATA BIT(2) |
571 | #define PS_WAIT_FOR_TX_ACK BIT(3) | 568 | #define PS_WAIT_FOR_TX_ACK BIT(3) |
572 | #define PS_BEACON_SYNC BIT(4) | 569 | #define PS_BEACON_SYNC BIT(4) |
573 | #define PS_TSFOOR_SYNC BIT(5) | ||
574 | 570 | ||
575 | struct ath_rate_table; | 571 | struct ath_rate_table; |
576 | 572 | ||
@@ -669,7 +665,7 @@ extern bool is_ath9k_unloaded; | |||
669 | 665 | ||
670 | irqreturn_t ath_isr(int irq, void *dev); | 666 | irqreturn_t ath_isr(int irq, void *dev); |
671 | void ath9k_init_crypto(struct ath_softc *sc); | 667 | void ath9k_init_crypto(struct ath_softc *sc); |
672 | int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, | 668 | int ath9k_init_device(u16 devid, struct ath_softc *sc, |
673 | const struct ath_bus_ops *bus_ops); | 669 | const struct ath_bus_ops *bus_ops); |
674 | void ath9k_deinit_device(struct ath_softc *sc); | 670 | void ath9k_deinit_device(struct ath_softc *sc); |
675 | void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw); | 671 | void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw); |
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 0d13ff74a68b..086c9c816bf7 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c | |||
@@ -522,6 +522,7 @@ static void ath_beacon_config_ap(struct ath_softc *sc, | |||
522 | ath9k_beacon_init(sc, nexttbtt, intval); | 522 | ath9k_beacon_init(sc, nexttbtt, intval); |
523 | sc->beacon.bmisscnt = 0; | 523 | sc->beacon.bmisscnt = 0; |
524 | ath9k_hw_set_interrupts(ah, ah->imask); | 524 | ath9k_hw_set_interrupts(ah, ah->imask); |
525 | ath9k_hw_enable_interrupts(ah); | ||
525 | } | 526 | } |
526 | 527 | ||
527 | /* | 528 | /* |
@@ -648,12 +649,8 @@ static void ath_beacon_config_sta(struct ath_softc *sc, | |||
648 | ath9k_hw_set_sta_beacon_timers(ah, &bs); | 649 | ath9k_hw_set_sta_beacon_timers(ah, &bs); |
649 | ah->imask |= ATH9K_INT_BMISS; | 650 | ah->imask |= ATH9K_INT_BMISS; |
650 | 651 | ||
651 | /* | 652 | ath9k_hw_set_interrupts(ah, ah->imask); |
652 | * If the beacon config is called beacause of TSFOOR, | 653 | ath9k_hw_enable_interrupts(ah); |
653 | * Interrupts will be enabled back at the end of ath9k_tasklet | ||
654 | */ | ||
655 | if (!(sc->ps_flags & PS_TSFOOR_SYNC)) | ||
656 | ath9k_hw_set_interrupts(ah, ah->imask); | ||
657 | } | 654 | } |
658 | 655 | ||
659 | static void ath_beacon_config_adhoc(struct ath_softc *sc, | 656 | static void ath_beacon_config_adhoc(struct ath_softc *sc, |
@@ -687,12 +684,9 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, | |||
687 | ath9k_hw_disable_interrupts(ah); | 684 | ath9k_hw_disable_interrupts(ah); |
688 | ath9k_beacon_init(sc, nexttbtt, intval); | 685 | ath9k_beacon_init(sc, nexttbtt, intval); |
689 | sc->beacon.bmisscnt = 0; | 686 | sc->beacon.bmisscnt = 0; |
690 | /* | 687 | |
691 | * If the beacon config is called beacause of TSFOOR, | 688 | ath9k_hw_set_interrupts(ah, ah->imask); |
692 | * Interrupts will be enabled back at the end of ath9k_tasklet | 689 | ath9k_hw_enable_interrupts(ah); |
693 | */ | ||
694 | if (!(sc->ps_flags & PS_TSFOOR_SYNC)) | ||
695 | ath9k_hw_set_interrupts(ah, ah->imask); | ||
696 | } | 690 | } |
697 | 691 | ||
698 | static bool ath9k_allow_beacon_config(struct ath_softc *sc, | 692 | static bool ath9k_allow_beacon_config(struct ath_softc *sc, |
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index a1250c586e40..ac2da3cce788 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c | |||
@@ -63,6 +63,19 @@ static s16 ath9k_hw_get_default_nf(struct ath_hw *ah, | |||
63 | return ath9k_hw_get_nf_limits(ah, chan)->nominal; | 63 | return ath9k_hw_get_nf_limits(ah, chan)->nominal; |
64 | } | 64 | } |
65 | 65 | ||
66 | s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan) | ||
67 | { | ||
68 | s8 noise = ATH_DEFAULT_NOISE_FLOOR; | ||
69 | |||
70 | if (chan && chan->noisefloor) { | ||
71 | s8 delta = chan->noisefloor - | ||
72 | ath9k_hw_get_default_nf(ah, chan); | ||
73 | if (delta > 0) | ||
74 | noise += delta; | ||
75 | } | ||
76 | return noise; | ||
77 | } | ||
78 | EXPORT_SYMBOL(ath9k_hw_getchan_noise); | ||
66 | 79 | ||
67 | static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah, | 80 | static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah, |
68 | struct ath9k_hw_cal_data *cal, | 81 | struct ath9k_hw_cal_data *cal, |
@@ -378,6 +391,7 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan) | |||
378 | 391 | ||
379 | if (!caldata) { | 392 | if (!caldata) { |
380 | chan->noisefloor = nf; | 393 | chan->noisefloor = nf; |
394 | ah->noise = ath9k_hw_getchan_noise(ah, chan); | ||
381 | return false; | 395 | return false; |
382 | } | 396 | } |
383 | 397 | ||
@@ -385,6 +399,7 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan) | |||
385 | caldata->nfcal_pending = false; | 399 | caldata->nfcal_pending = false; |
386 | ath9k_hw_update_nfcal_hist_buffer(ah, caldata, nfarray); | 400 | ath9k_hw_update_nfcal_hist_buffer(ah, caldata, nfarray); |
387 | chan->noisefloor = h[0].privNF; | 401 | chan->noisefloor = h[0].privNF; |
402 | ah->noise = ath9k_hw_getchan_noise(ah, chan); | ||
388 | return true; | 403 | return true; |
389 | } | 404 | } |
390 | 405 | ||
diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h index 1bef41d1b1ff..05b9dbf81850 100644 --- a/drivers/net/wireless/ath/ath9k/calib.h +++ b/drivers/net/wireless/ath/ath9k/calib.h | |||
@@ -108,6 +108,7 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah, | |||
108 | void ath9k_hw_bstuck_nfcal(struct ath_hw *ah); | 108 | void ath9k_hw_bstuck_nfcal(struct ath_hw *ah); |
109 | void ath9k_hw_reset_calibration(struct ath_hw *ah, | 109 | void ath9k_hw_reset_calibration(struct ath_hw *ah, |
110 | struct ath9k_cal_list *currCal); | 110 | struct ath9k_cal_list *currCal); |
111 | s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan); | ||
111 | 112 | ||
112 | 113 | ||
113 | #endif /* CALIB_H */ | 114 | #endif /* CALIB_H */ |
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index d1eb89611ff7..9bec3b89fb68 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c | |||
@@ -1163,6 +1163,62 @@ static const struct file_operations fops_regdump = { | |||
1163 | .llseek = default_llseek,/* read accesses f_pos */ | 1163 | .llseek = default_llseek,/* read accesses f_pos */ |
1164 | }; | 1164 | }; |
1165 | 1165 | ||
1166 | static ssize_t read_file_base_eeprom(struct file *file, char __user *user_buf, | ||
1167 | size_t count, loff_t *ppos) | ||
1168 | { | ||
1169 | struct ath_softc *sc = file->private_data; | ||
1170 | struct ath_hw *ah = sc->sc_ah; | ||
1171 | u32 len = 0, size = 1500; | ||
1172 | ssize_t retval = 0; | ||
1173 | char *buf; | ||
1174 | |||
1175 | buf = kzalloc(size, GFP_KERNEL); | ||
1176 | if (!buf) | ||
1177 | return -ENOMEM; | ||
1178 | |||
1179 | len = ah->eep_ops->dump_eeprom(ah, true, buf, len, size); | ||
1180 | |||
1181 | retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
1182 | kfree(buf); | ||
1183 | |||
1184 | return retval; | ||
1185 | } | ||
1186 | |||
1187 | static const struct file_operations fops_base_eeprom = { | ||
1188 | .read = read_file_base_eeprom, | ||
1189 | .open = ath9k_debugfs_open, | ||
1190 | .owner = THIS_MODULE, | ||
1191 | .llseek = default_llseek, | ||
1192 | }; | ||
1193 | |||
1194 | static ssize_t read_file_modal_eeprom(struct file *file, char __user *user_buf, | ||
1195 | size_t count, loff_t *ppos) | ||
1196 | { | ||
1197 | struct ath_softc *sc = file->private_data; | ||
1198 | struct ath_hw *ah = sc->sc_ah; | ||
1199 | u32 len = 0, size = 6000; | ||
1200 | char *buf; | ||
1201 | size_t retval; | ||
1202 | |||
1203 | buf = kzalloc(size, GFP_KERNEL); | ||
1204 | if (buf == NULL) | ||
1205 | return -ENOMEM; | ||
1206 | |||
1207 | len = ah->eep_ops->dump_eeprom(ah, false, buf, len, size); | ||
1208 | |||
1209 | retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
1210 | kfree(buf); | ||
1211 | |||
1212 | return retval; | ||
1213 | } | ||
1214 | |||
1215 | static const struct file_operations fops_modal_eeprom = { | ||
1216 | .read = read_file_modal_eeprom, | ||
1217 | .open = ath9k_debugfs_open, | ||
1218 | .owner = THIS_MODULE, | ||
1219 | .llseek = default_llseek, | ||
1220 | }; | ||
1221 | |||
1166 | int ath9k_init_debug(struct ath_hw *ah) | 1222 | int ath9k_init_debug(struct ath_hw *ah) |
1167 | { | 1223 | { |
1168 | struct ath_common *common = ath9k_hw_common(ah); | 1224 | struct ath_common *common = ath9k_hw_common(ah); |
@@ -1206,6 +1262,10 @@ int ath9k_init_debug(struct ath_hw *ah) | |||
1206 | &ah->config.cwm_ignore_extcca); | 1262 | &ah->config.cwm_ignore_extcca); |
1207 | debugfs_create_file("regdump", S_IRUSR, sc->debug.debugfs_phy, sc, | 1263 | debugfs_create_file("regdump", S_IRUSR, sc->debug.debugfs_phy, sc, |
1208 | &fops_regdump); | 1264 | &fops_regdump); |
1265 | debugfs_create_file("base_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc, | ||
1266 | &fops_base_eeprom); | ||
1267 | debugfs_create_file("modal_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc, | ||
1268 | &fops_modal_eeprom); | ||
1209 | 1269 | ||
1210 | debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR, | 1270 | debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR, |
1211 | sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask); | 1271 | sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask); |
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index de99c0da52e4..a3c7d0c247a3 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h | |||
@@ -649,6 +649,8 @@ struct eeprom_ops { | |||
649 | int (*check_eeprom)(struct ath_hw *hw); | 649 | int (*check_eeprom)(struct ath_hw *hw); |
650 | u32 (*get_eeprom)(struct ath_hw *hw, enum eeprom_param param); | 650 | u32 (*get_eeprom)(struct ath_hw *hw, enum eeprom_param param); |
651 | bool (*fill_eeprom)(struct ath_hw *hw); | 651 | bool (*fill_eeprom)(struct ath_hw *hw); |
652 | u32 (*dump_eeprom)(struct ath_hw *hw, bool dump_base_hdr, u8 *buf, | ||
653 | u32 len, u32 size); | ||
652 | int (*get_eeprom_ver)(struct ath_hw *hw); | 654 | int (*get_eeprom_ver)(struct ath_hw *hw); |
653 | int (*get_eeprom_rev)(struct ath_hw *hw); | 655 | int (*get_eeprom_rev)(struct ath_hw *hw); |
654 | void (*set_board_values)(struct ath_hw *hw, struct ath9k_channel *chan); | 656 | void (*set_board_values)(struct ath_hw *hw, struct ath9k_channel *chan); |
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index 47cc95086e6e..ea658e794cbd 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c | |||
@@ -72,6 +72,117 @@ static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) | |||
72 | return __ath9k_hw_4k_fill_eeprom(ah); | 72 | return __ath9k_hw_4k_fill_eeprom(ah); |
73 | } | 73 | } |
74 | 74 | ||
75 | #if defined(CONFIG_ATH9K_DEBUGFS) || defined(CONFIG_ATH9K_HTC_DEBUGFS) | ||
76 | static u32 ath9k_dump_4k_modal_eeprom(char *buf, u32 len, u32 size, | ||
77 | struct modal_eep_4k_header *modal_hdr) | ||
78 | { | ||
79 | PR_EEP("Chain0 Ant. Control", modal_hdr->antCtrlChain[0]); | ||
80 | PR_EEP("Ant. Common Control", modal_hdr->antCtrlCommon); | ||
81 | PR_EEP("Chain0 Ant. Gain", modal_hdr->antennaGainCh[0]); | ||
82 | PR_EEP("Switch Settle", modal_hdr->switchSettling); | ||
83 | PR_EEP("Chain0 TxRxAtten", modal_hdr->txRxAttenCh[0]); | ||
84 | PR_EEP("Chain0 RxTxMargin", modal_hdr->rxTxMarginCh[0]); | ||
85 | PR_EEP("ADC Desired size", modal_hdr->adcDesiredSize); | ||
86 | PR_EEP("PGA Desired size", modal_hdr->pgaDesiredSize); | ||
87 | PR_EEP("Chain0 xlna Gain", modal_hdr->xlnaGainCh[0]); | ||
88 | PR_EEP("txEndToXpaOff", modal_hdr->txEndToXpaOff); | ||
89 | PR_EEP("txEndToRxOn", modal_hdr->txEndToRxOn); | ||
90 | PR_EEP("txFrameToXpaOn", modal_hdr->txFrameToXpaOn); | ||
91 | PR_EEP("CCA Threshold)", modal_hdr->thresh62); | ||
92 | PR_EEP("Chain0 NF Threshold", modal_hdr->noiseFloorThreshCh[0]); | ||
93 | PR_EEP("xpdGain", modal_hdr->xpdGain); | ||
94 | PR_EEP("External PD", modal_hdr->xpd); | ||
95 | PR_EEP("Chain0 I Coefficient", modal_hdr->iqCalICh[0]); | ||
96 | PR_EEP("Chain0 Q Coefficient", modal_hdr->iqCalQCh[0]); | ||
97 | PR_EEP("pdGainOverlap", modal_hdr->pdGainOverlap); | ||
98 | PR_EEP("O/D Bias Version", modal_hdr->version); | ||
99 | PR_EEP("CCK OutputBias", modal_hdr->ob_0); | ||
100 | PR_EEP("BPSK OutputBias", modal_hdr->ob_1); | ||
101 | PR_EEP("QPSK OutputBias", modal_hdr->ob_2); | ||
102 | PR_EEP("16QAM OutputBias", modal_hdr->ob_3); | ||
103 | PR_EEP("64QAM OutputBias", modal_hdr->ob_4); | ||
104 | PR_EEP("CCK Driver1_Bias", modal_hdr->db1_0); | ||
105 | PR_EEP("BPSK Driver1_Bias", modal_hdr->db1_1); | ||
106 | PR_EEP("QPSK Driver1_Bias", modal_hdr->db1_2); | ||
107 | PR_EEP("16QAM Driver1_Bias", modal_hdr->db1_3); | ||
108 | PR_EEP("64QAM Driver1_Bias", modal_hdr->db1_4); | ||
109 | PR_EEP("CCK Driver2_Bias", modal_hdr->db2_0); | ||
110 | PR_EEP("BPSK Driver2_Bias", modal_hdr->db2_1); | ||
111 | PR_EEP("QPSK Driver2_Bias", modal_hdr->db2_2); | ||
112 | PR_EEP("16QAM Driver2_Bias", modal_hdr->db2_3); | ||
113 | PR_EEP("64QAM Driver2_Bias", modal_hdr->db2_4); | ||
114 | PR_EEP("xPA Bias Level", modal_hdr->xpaBiasLvl); | ||
115 | PR_EEP("txFrameToDataStart", modal_hdr->txFrameToDataStart); | ||
116 | PR_EEP("txFrameToPaOn", modal_hdr->txFrameToPaOn); | ||
117 | PR_EEP("HT40 Power Inc.", modal_hdr->ht40PowerIncForPdadc); | ||
118 | PR_EEP("Chain0 bswAtten", modal_hdr->bswAtten[0]); | ||
119 | PR_EEP("Chain0 bswMargin", modal_hdr->bswMargin[0]); | ||
120 | PR_EEP("HT40 Switch Settle", modal_hdr->swSettleHt40); | ||
121 | PR_EEP("Chain0 xatten2Db", modal_hdr->xatten2Db[0]); | ||
122 | PR_EEP("Chain0 xatten2Margin", modal_hdr->xatten2Margin[0]); | ||
123 | PR_EEP("Ant. Diversity ctl1", modal_hdr->antdiv_ctl1); | ||
124 | PR_EEP("Ant. Diversity ctl2", modal_hdr->antdiv_ctl2); | ||
125 | PR_EEP("TX Diversity", modal_hdr->tx_diversity); | ||
126 | |||
127 | return len; | ||
128 | } | ||
129 | |||
130 | static u32 ath9k_hw_4k_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, | ||
131 | u8 *buf, u32 len, u32 size) | ||
132 | { | ||
133 | struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; | ||
134 | struct base_eep_header_4k *pBase = &eep->baseEepHeader; | ||
135 | |||
136 | if (!dump_base_hdr) { | ||
137 | len += snprintf(buf + len, size - len, | ||
138 | "%20s :\n", "2GHz modal Header"); | ||
139 | len += ath9k_dump_4k_modal_eeprom(buf, len, size, | ||
140 | &eep->modalHeader); | ||
141 | goto out; | ||
142 | } | ||
143 | |||
144 | PR_EEP("Major Version", pBase->version >> 12); | ||
145 | PR_EEP("Minor Version", pBase->version & 0xFFF); | ||
146 | PR_EEP("Checksum", pBase->checksum); | ||
147 | PR_EEP("Length", pBase->length); | ||
148 | PR_EEP("RegDomain1", pBase->regDmn[0]); | ||
149 | PR_EEP("RegDomain2", pBase->regDmn[1]); | ||
150 | PR_EEP("TX Mask", pBase->txMask); | ||
151 | PR_EEP("RX Mask", pBase->rxMask); | ||
152 | PR_EEP("Allow 5GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11A)); | ||
153 | PR_EEP("Allow 2GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11G)); | ||
154 | PR_EEP("Disable 2GHz HT20", !!(pBase->opCapFlags & | ||
155 | AR5416_OPFLAGS_N_2G_HT20)); | ||
156 | PR_EEP("Disable 2GHz HT40", !!(pBase->opCapFlags & | ||
157 | AR5416_OPFLAGS_N_2G_HT40)); | ||
158 | PR_EEP("Disable 5Ghz HT20", !!(pBase->opCapFlags & | ||
159 | AR5416_OPFLAGS_N_5G_HT20)); | ||
160 | PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags & | ||
161 | AR5416_OPFLAGS_N_5G_HT40)); | ||
162 | PR_EEP("Big Endian", !!(pBase->eepMisc & 0x01)); | ||
163 | PR_EEP("Cal Bin Major Ver", (pBase->binBuildNumber >> 24) & 0xFF); | ||
164 | PR_EEP("Cal Bin Minor Ver", (pBase->binBuildNumber >> 16) & 0xFF); | ||
165 | PR_EEP("Cal Bin Build", (pBase->binBuildNumber >> 8) & 0xFF); | ||
166 | PR_EEP("TX Gain type", pBase->txGainType); | ||
167 | |||
168 | len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress", | ||
169 | pBase->macAddr); | ||
170 | |||
171 | out: | ||
172 | if (len > size) | ||
173 | len = size; | ||
174 | |||
175 | return len; | ||
176 | } | ||
177 | #else | ||
178 | static u32 ath9k_hw_4k_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, | ||
179 | u8 *buf, u32 len, u32 size) | ||
180 | { | ||
181 | return 0; | ||
182 | } | ||
183 | #endif | ||
184 | |||
185 | |||
75 | #undef SIZE_EEPROM_4K | 186 | #undef SIZE_EEPROM_4K |
76 | 187 | ||
77 | static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) | 188 | static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) |
@@ -238,18 +349,14 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah, | |||
238 | case EEP_ANT_DIV_CTL1: | 349 | case EEP_ANT_DIV_CTL1: |
239 | return pModal->antdiv_ctl1; | 350 | return pModal->antdiv_ctl1; |
240 | case EEP_TXGAIN_TYPE: | 351 | case EEP_TXGAIN_TYPE: |
241 | if (ver_minor >= AR5416_EEP_MINOR_VER_19) | 352 | return pBase->txGainType; |
242 | return pBase->txGainType; | ||
243 | else | ||
244 | return AR5416_EEP_TXGAIN_ORIGINAL; | ||
245 | default: | 353 | default: |
246 | return 0; | 354 | return 0; |
247 | } | 355 | } |
248 | } | 356 | } |
249 | 357 | ||
250 | static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, | 358 | static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, |
251 | struct ath9k_channel *chan, | 359 | struct ath9k_channel *chan) |
252 | int16_t *pTxPowerIndexOffset) | ||
253 | { | 360 | { |
254 | struct ath_common *common = ath9k_hw_common(ah); | 361 | struct ath_common *common = ath9k_hw_common(ah); |
255 | struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; | 362 | struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; |
@@ -356,8 +463,6 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, | |||
356 | REGWRITE_BUFFER_FLUSH(ah); | 463 | REGWRITE_BUFFER_FLUSH(ah); |
357 | } | 464 | } |
358 | } | 465 | } |
359 | |||
360 | *pTxPowerIndexOffset = 0; | ||
361 | } | 466 | } |
362 | 467 | ||
363 | static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, | 468 | static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, |
@@ -580,7 +685,6 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, | |||
580 | struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; | 685 | struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; |
581 | struct modal_eep_4k_header *pModal = &pEepData->modalHeader; | 686 | struct modal_eep_4k_header *pModal = &pEepData->modalHeader; |
582 | int16_t ratesArray[Ar5416RateSize]; | 687 | int16_t ratesArray[Ar5416RateSize]; |
583 | int16_t txPowerIndexOffset = 0; | ||
584 | u8 ht40PowerIncForPdadc = 2; | 688 | u8 ht40PowerIncForPdadc = 2; |
585 | int i; | 689 | int i; |
586 | 690 | ||
@@ -597,11 +701,10 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, | |||
597 | twiceMaxRegulatoryPower, | 701 | twiceMaxRegulatoryPower, |
598 | powerLimit); | 702 | powerLimit); |
599 | 703 | ||
600 | ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset); | 704 | ath9k_hw_set_4k_power_cal_table(ah, chan); |
601 | 705 | ||
602 | regulatory->max_power_level = 0; | 706 | regulatory->max_power_level = 0; |
603 | for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { | 707 | for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { |
604 | ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); | ||
605 | if (ratesArray[i] > MAX_RATE_POWER) | 708 | if (ratesArray[i] > MAX_RATE_POWER) |
606 | ratesArray[i] = MAX_RATE_POWER; | 709 | ratesArray[i] = MAX_RATE_POWER; |
607 | 710 | ||
@@ -612,15 +715,6 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, | |||
612 | if (test) | 715 | if (test) |
613 | return; | 716 | return; |
614 | 717 | ||
615 | /* Update regulatory */ | ||
616 | i = rate6mb; | ||
617 | if (IS_CHAN_HT40(chan)) | ||
618 | i = rateHt40_0; | ||
619 | else if (IS_CHAN_HT20(chan)) | ||
620 | i = rateHt20_0; | ||
621 | |||
622 | regulatory->max_power_level = ratesArray[i]; | ||
623 | |||
624 | if (AR_SREV_9280_20_OR_LATER(ah)) { | 718 | if (AR_SREV_9280_20_OR_LATER(ah)) { |
625 | for (i = 0; i < Ar5416RateSize; i++) | 719 | for (i = 0; i < Ar5416RateSize; i++) |
626 | ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2; | 720 | ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2; |
@@ -1063,6 +1157,7 @@ const struct eeprom_ops eep_4k_ops = { | |||
1063 | .check_eeprom = ath9k_hw_4k_check_eeprom, | 1157 | .check_eeprom = ath9k_hw_4k_check_eeprom, |
1064 | .get_eeprom = ath9k_hw_4k_get_eeprom, | 1158 | .get_eeprom = ath9k_hw_4k_get_eeprom, |
1065 | .fill_eeprom = ath9k_hw_4k_fill_eeprom, | 1159 | .fill_eeprom = ath9k_hw_4k_fill_eeprom, |
1160 | .dump_eeprom = ath9k_hw_4k_dump_eeprom, | ||
1066 | .get_eeprom_ver = ath9k_hw_4k_get_eeprom_ver, | 1161 | .get_eeprom_ver = ath9k_hw_4k_get_eeprom_ver, |
1067 | .get_eeprom_rev = ath9k_hw_4k_get_eeprom_rev, | 1162 | .get_eeprom_rev = ath9k_hw_4k_get_eeprom_rev, |
1068 | .set_board_values = ath9k_hw_4k_set_board_values, | 1163 | .set_board_values = ath9k_hw_4k_set_board_values, |
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index d6f6b192f450..21f180db2381 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c | |||
@@ -76,6 +76,111 @@ static bool ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah) | |||
76 | return __ath9k_hw_ar9287_fill_eeprom(ah); | 76 | return __ath9k_hw_ar9287_fill_eeprom(ah); |
77 | } | 77 | } |
78 | 78 | ||
79 | #if defined(CONFIG_ATH9K_DEBUGFS) || defined(CONFIG_ATH9K_HTC_DEBUGFS) | ||
80 | static u32 ar9287_dump_modal_eeprom(char *buf, u32 len, u32 size, | ||
81 | struct modal_eep_ar9287_header *modal_hdr) | ||
82 | { | ||
83 | PR_EEP("Chain0 Ant. Control", modal_hdr->antCtrlChain[0]); | ||
84 | PR_EEP("Chain1 Ant. Control", modal_hdr->antCtrlChain[1]); | ||
85 | PR_EEP("Ant. Common Control", modal_hdr->antCtrlCommon); | ||
86 | PR_EEP("Chain0 Ant. Gain", modal_hdr->antennaGainCh[0]); | ||
87 | PR_EEP("Chain1 Ant. Gain", modal_hdr->antennaGainCh[1]); | ||
88 | PR_EEP("Switch Settle", modal_hdr->switchSettling); | ||
89 | PR_EEP("Chain0 TxRxAtten", modal_hdr->txRxAttenCh[0]); | ||
90 | PR_EEP("Chain1 TxRxAtten", modal_hdr->txRxAttenCh[1]); | ||
91 | PR_EEP("Chain0 RxTxMargin", modal_hdr->rxTxMarginCh[0]); | ||
92 | PR_EEP("Chain1 RxTxMargin", modal_hdr->rxTxMarginCh[1]); | ||
93 | PR_EEP("ADC Desired size", modal_hdr->adcDesiredSize); | ||
94 | PR_EEP("txEndToXpaOff", modal_hdr->txEndToXpaOff); | ||
95 | PR_EEP("txEndToRxOn", modal_hdr->txEndToRxOn); | ||
96 | PR_EEP("txFrameToXpaOn", modal_hdr->txFrameToXpaOn); | ||
97 | PR_EEP("CCA Threshold)", modal_hdr->thresh62); | ||
98 | PR_EEP("Chain0 NF Threshold", modal_hdr->noiseFloorThreshCh[0]); | ||
99 | PR_EEP("Chain1 NF Threshold", modal_hdr->noiseFloorThreshCh[1]); | ||
100 | PR_EEP("xpdGain", modal_hdr->xpdGain); | ||
101 | PR_EEP("External PD", modal_hdr->xpd); | ||
102 | PR_EEP("Chain0 I Coefficient", modal_hdr->iqCalICh[0]); | ||
103 | PR_EEP("Chain1 I Coefficient", modal_hdr->iqCalICh[1]); | ||
104 | PR_EEP("Chain0 Q Coefficient", modal_hdr->iqCalQCh[0]); | ||
105 | PR_EEP("Chain1 Q Coefficient", modal_hdr->iqCalQCh[1]); | ||
106 | PR_EEP("pdGainOverlap", modal_hdr->pdGainOverlap); | ||
107 | PR_EEP("xPA Bias Level", modal_hdr->xpaBiasLvl); | ||
108 | PR_EEP("txFrameToDataStart", modal_hdr->txFrameToDataStart); | ||
109 | PR_EEP("txFrameToPaOn", modal_hdr->txFrameToPaOn); | ||
110 | PR_EEP("HT40 Power Inc.", modal_hdr->ht40PowerIncForPdadc); | ||
111 | PR_EEP("Chain0 bswAtten", modal_hdr->bswAtten[0]); | ||
112 | PR_EEP("Chain1 bswAtten", modal_hdr->bswAtten[1]); | ||
113 | PR_EEP("Chain0 bswMargin", modal_hdr->bswMargin[0]); | ||
114 | PR_EEP("Chain1 bswMargin", modal_hdr->bswMargin[1]); | ||
115 | PR_EEP("HT40 Switch Settle", modal_hdr->swSettleHt40); | ||
116 | PR_EEP("AR92x7 Version", modal_hdr->version); | ||
117 | PR_EEP("DriverBias1", modal_hdr->db1); | ||
118 | PR_EEP("DriverBias2", modal_hdr->db1); | ||
119 | PR_EEP("CCK OutputBias", modal_hdr->ob_cck); | ||
120 | PR_EEP("PSK OutputBias", modal_hdr->ob_psk); | ||
121 | PR_EEP("QAM OutputBias", modal_hdr->ob_qam); | ||
122 | PR_EEP("PAL_OFF OutputBias", modal_hdr->ob_pal_off); | ||
123 | |||
124 | return len; | ||
125 | } | ||
126 | |||
127 | static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, | ||
128 | u8 *buf, u32 len, u32 size) | ||
129 | { | ||
130 | struct ar9287_eeprom *eep = &ah->eeprom.map9287; | ||
131 | struct base_eep_ar9287_header *pBase = &eep->baseEepHeader; | ||
132 | |||
133 | if (!dump_base_hdr) { | ||
134 | len += snprintf(buf + len, size - len, | ||
135 | "%20s :\n", "2GHz modal Header"); | ||
136 | len += ar9287_dump_modal_eeprom(buf, len, size, | ||
137 | &eep->modalHeader); | ||
138 | goto out; | ||
139 | } | ||
140 | |||
141 | PR_EEP("Major Version", pBase->version >> 12); | ||
142 | PR_EEP("Minor Version", pBase->version & 0xFFF); | ||
143 | PR_EEP("Checksum", pBase->checksum); | ||
144 | PR_EEP("Length", pBase->length); | ||
145 | PR_EEP("RegDomain1", pBase->regDmn[0]); | ||
146 | PR_EEP("RegDomain2", pBase->regDmn[1]); | ||
147 | PR_EEP("TX Mask", pBase->txMask); | ||
148 | PR_EEP("RX Mask", pBase->rxMask); | ||
149 | PR_EEP("Allow 5GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11A)); | ||
150 | PR_EEP("Allow 2GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11G)); | ||
151 | PR_EEP("Disable 2GHz HT20", !!(pBase->opCapFlags & | ||
152 | AR5416_OPFLAGS_N_2G_HT20)); | ||
153 | PR_EEP("Disable 2GHz HT40", !!(pBase->opCapFlags & | ||
154 | AR5416_OPFLAGS_N_2G_HT40)); | ||
155 | PR_EEP("Disable 5Ghz HT20", !!(pBase->opCapFlags & | ||
156 | AR5416_OPFLAGS_N_5G_HT20)); | ||
157 | PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags & | ||
158 | AR5416_OPFLAGS_N_5G_HT40)); | ||
159 | PR_EEP("Big Endian", !!(pBase->eepMisc & 0x01)); | ||
160 | PR_EEP("Cal Bin Major Ver", (pBase->binBuildNumber >> 24) & 0xFF); | ||
161 | PR_EEP("Cal Bin Minor Ver", (pBase->binBuildNumber >> 16) & 0xFF); | ||
162 | PR_EEP("Cal Bin Build", (pBase->binBuildNumber >> 8) & 0xFF); | ||
163 | PR_EEP("Power Table Offset", pBase->pwrTableOffset); | ||
164 | PR_EEP("OpenLoop Power Ctrl", pBase->openLoopPwrCntl); | ||
165 | |||
166 | len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress", | ||
167 | pBase->macAddr); | ||
168 | |||
169 | out: | ||
170 | if (len > size) | ||
171 | len = size; | ||
172 | |||
173 | return len; | ||
174 | } | ||
175 | #else | ||
176 | static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, | ||
177 | u8 *buf, u32 len, u32 size) | ||
178 | { | ||
179 | return 0; | ||
180 | } | ||
181 | #endif | ||
182 | |||
183 | |||
79 | static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah) | 184 | static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah) |
80 | { | 185 | { |
81 | u32 sum = 0, el, integer; | 186 | u32 sum = 0, el, integer; |
@@ -307,8 +412,7 @@ static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah, | |||
307 | } | 412 | } |
308 | 413 | ||
309 | static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah, | 414 | static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah, |
310 | struct ath9k_channel *chan, | 415 | struct ath9k_channel *chan) |
311 | int16_t *pTxPowerIndexOffset) | ||
312 | { | 416 | { |
313 | struct cal_data_per_freq_ar9287 *pRawDataset; | 417 | struct cal_data_per_freq_ar9287 *pRawDataset; |
314 | struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop; | 418 | struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop; |
@@ -444,8 +548,6 @@ static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah, | |||
444 | REGWRITE_BUFFER_FLUSH(ah); | 548 | REGWRITE_BUFFER_FLUSH(ah); |
445 | } | 549 | } |
446 | } | 550 | } |
447 | |||
448 | *pTxPowerIndexOffset = 0; | ||
449 | } | 551 | } |
450 | 552 | ||
451 | static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah, | 553 | static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah, |
@@ -720,7 +822,6 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah, | |||
720 | struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; | 822 | struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; |
721 | struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader; | 823 | struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader; |
722 | int16_t ratesArray[Ar5416RateSize]; | 824 | int16_t ratesArray[Ar5416RateSize]; |
723 | int16_t txPowerIndexOffset = 0; | ||
724 | u8 ht40PowerIncForPdadc = 2; | 825 | u8 ht40PowerIncForPdadc = 2; |
725 | int i; | 826 | int i; |
726 | 827 | ||
@@ -736,11 +837,10 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah, | |||
736 | twiceMaxRegulatoryPower, | 837 | twiceMaxRegulatoryPower, |
737 | powerLimit); | 838 | powerLimit); |
738 | 839 | ||
739 | ath9k_hw_set_ar9287_power_cal_table(ah, chan, &txPowerIndexOffset); | 840 | ath9k_hw_set_ar9287_power_cal_table(ah, chan); |
740 | 841 | ||
741 | regulatory->max_power_level = 0; | 842 | regulatory->max_power_level = 0; |
742 | for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { | 843 | for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { |
743 | ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); | ||
744 | if (ratesArray[i] > MAX_RATE_POWER) | 844 | if (ratesArray[i] > MAX_RATE_POWER) |
745 | ratesArray[i] = MAX_RATE_POWER; | 845 | ratesArray[i] = MAX_RATE_POWER; |
746 | 846 | ||
@@ -751,13 +851,6 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah, | |||
751 | if (test) | 851 | if (test) |
752 | return; | 852 | return; |
753 | 853 | ||
754 | if (IS_CHAN_2GHZ(chan)) | ||
755 | i = rate1l; | ||
756 | else | ||
757 | i = rate6mb; | ||
758 | |||
759 | regulatory->max_power_level = ratesArray[i]; | ||
760 | |||
761 | if (AR_SREV_9280_20_OR_LATER(ah)) { | 854 | if (AR_SREV_9280_20_OR_LATER(ah)) { |
762 | for (i = 0; i < Ar5416RateSize; i++) | 855 | for (i = 0; i < Ar5416RateSize; i++) |
763 | ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2; | 856 | ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2; |
@@ -1003,6 +1096,7 @@ const struct eeprom_ops eep_ar9287_ops = { | |||
1003 | .check_eeprom = ath9k_hw_ar9287_check_eeprom, | 1096 | .check_eeprom = ath9k_hw_ar9287_check_eeprom, |
1004 | .get_eeprom = ath9k_hw_ar9287_get_eeprom, | 1097 | .get_eeprom = ath9k_hw_ar9287_get_eeprom, |
1005 | .fill_eeprom = ath9k_hw_ar9287_fill_eeprom, | 1098 | .fill_eeprom = ath9k_hw_ar9287_fill_eeprom, |
1099 | .dump_eeprom = ath9k_hw_ar9287_dump_eeprom, | ||
1006 | .get_eeprom_ver = ath9k_hw_ar9287_get_eeprom_ver, | 1100 | .get_eeprom_ver = ath9k_hw_ar9287_get_eeprom_ver, |
1007 | .get_eeprom_rev = ath9k_hw_ar9287_get_eeprom_rev, | 1101 | .get_eeprom_rev = ath9k_hw_ar9287_get_eeprom_rev, |
1008 | .set_board_values = ath9k_hw_ar9287_set_board_values, | 1102 | .set_board_values = ath9k_hw_ar9287_set_board_values, |
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index b9540a992616..e7e84be8beed 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c | |||
@@ -133,6 +133,136 @@ static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah) | |||
133 | 133 | ||
134 | #undef SIZE_EEPROM_DEF | 134 | #undef SIZE_EEPROM_DEF |
135 | 135 | ||
136 | #if defined(CONFIG_ATH9K_DEBUGFS) || defined(CONFIG_ATH9K_HTC_DEBUGFS) | ||
137 | static u32 ath9k_def_dump_modal_eeprom(char *buf, u32 len, u32 size, | ||
138 | struct modal_eep_header *modal_hdr) | ||
139 | { | ||
140 | PR_EEP("Chain0 Ant. Control", modal_hdr->antCtrlChain[0]); | ||
141 | PR_EEP("Chain1 Ant. Control", modal_hdr->antCtrlChain[1]); | ||
142 | PR_EEP("Chain2 Ant. Control", modal_hdr->antCtrlChain[2]); | ||
143 | PR_EEP("Ant. Common Control", modal_hdr->antCtrlCommon); | ||
144 | PR_EEP("Chain0 Ant. Gain", modal_hdr->antennaGainCh[0]); | ||
145 | PR_EEP("Chain1 Ant. Gain", modal_hdr->antennaGainCh[1]); | ||
146 | PR_EEP("Chain2 Ant. Gain", modal_hdr->antennaGainCh[2]); | ||
147 | PR_EEP("Switch Settle", modal_hdr->switchSettling); | ||
148 | PR_EEP("Chain0 TxRxAtten", modal_hdr->txRxAttenCh[0]); | ||
149 | PR_EEP("Chain1 TxRxAtten", modal_hdr->txRxAttenCh[1]); | ||
150 | PR_EEP("Chain2 TxRxAtten", modal_hdr->txRxAttenCh[2]); | ||
151 | PR_EEP("Chain0 RxTxMargin", modal_hdr->rxTxMarginCh[0]); | ||
152 | PR_EEP("Chain1 RxTxMargin", modal_hdr->rxTxMarginCh[1]); | ||
153 | PR_EEP("Chain2 RxTxMargin", modal_hdr->rxTxMarginCh[2]); | ||
154 | PR_EEP("ADC Desired size", modal_hdr->adcDesiredSize); | ||
155 | PR_EEP("PGA Desired size", modal_hdr->pgaDesiredSize); | ||
156 | PR_EEP("Chain0 xlna Gain", modal_hdr->xlnaGainCh[0]); | ||
157 | PR_EEP("Chain1 xlna Gain", modal_hdr->xlnaGainCh[1]); | ||
158 | PR_EEP("Chain2 xlna Gain", modal_hdr->xlnaGainCh[2]); | ||
159 | PR_EEP("txEndToXpaOff", modal_hdr->txEndToXpaOff); | ||
160 | PR_EEP("txEndToRxOn", modal_hdr->txEndToRxOn); | ||
161 | PR_EEP("txFrameToXpaOn", modal_hdr->txFrameToXpaOn); | ||
162 | PR_EEP("CCA Threshold)", modal_hdr->thresh62); | ||
163 | PR_EEP("Chain0 NF Threshold", modal_hdr->noiseFloorThreshCh[0]); | ||
164 | PR_EEP("Chain1 NF Threshold", modal_hdr->noiseFloorThreshCh[1]); | ||
165 | PR_EEP("Chain2 NF Threshold", modal_hdr->noiseFloorThreshCh[2]); | ||
166 | PR_EEP("xpdGain", modal_hdr->xpdGain); | ||
167 | PR_EEP("External PD", modal_hdr->xpd); | ||
168 | PR_EEP("Chain0 I Coefficient", modal_hdr->iqCalICh[0]); | ||
169 | PR_EEP("Chain1 I Coefficient", modal_hdr->iqCalICh[1]); | ||
170 | PR_EEP("Chain2 I Coefficient", modal_hdr->iqCalICh[2]); | ||
171 | PR_EEP("Chain0 Q Coefficient", modal_hdr->iqCalQCh[0]); | ||
172 | PR_EEP("Chain1 Q Coefficient", modal_hdr->iqCalQCh[1]); | ||
173 | PR_EEP("Chain2 Q Coefficient", modal_hdr->iqCalQCh[2]); | ||
174 | PR_EEP("pdGainOverlap", modal_hdr->pdGainOverlap); | ||
175 | PR_EEP("Chain0 OutputBias", modal_hdr->ob); | ||
176 | PR_EEP("Chain0 DriverBias", modal_hdr->db); | ||
177 | PR_EEP("xPA Bias Level", modal_hdr->xpaBiasLvl); | ||
178 | PR_EEP("2chain pwr decrease", modal_hdr->pwrDecreaseFor2Chain); | ||
179 | PR_EEP("3chain pwr decrease", modal_hdr->pwrDecreaseFor3Chain); | ||
180 | PR_EEP("txFrameToDataStart", modal_hdr->txFrameToDataStart); | ||
181 | PR_EEP("txFrameToPaOn", modal_hdr->txFrameToPaOn); | ||
182 | PR_EEP("HT40 Power Inc.", modal_hdr->ht40PowerIncForPdadc); | ||
183 | PR_EEP("Chain0 bswAtten", modal_hdr->bswAtten[0]); | ||
184 | PR_EEP("Chain1 bswAtten", modal_hdr->bswAtten[1]); | ||
185 | PR_EEP("Chain2 bswAtten", modal_hdr->bswAtten[2]); | ||
186 | PR_EEP("Chain0 bswMargin", modal_hdr->bswMargin[0]); | ||
187 | PR_EEP("Chain1 bswMargin", modal_hdr->bswMargin[1]); | ||
188 | PR_EEP("Chain2 bswMargin", modal_hdr->bswMargin[2]); | ||
189 | PR_EEP("HT40 Switch Settle", modal_hdr->swSettleHt40); | ||
190 | PR_EEP("Chain0 xatten2Db", modal_hdr->xatten2Db[0]); | ||
191 | PR_EEP("Chain1 xatten2Db", modal_hdr->xatten2Db[1]); | ||
192 | PR_EEP("Chain2 xatten2Db", modal_hdr->xatten2Db[2]); | ||
193 | PR_EEP("Chain0 xatten2Margin", modal_hdr->xatten2Margin[0]); | ||
194 | PR_EEP("Chain1 xatten2Margin", modal_hdr->xatten2Margin[1]); | ||
195 | PR_EEP("Chain2 xatten2Margin", modal_hdr->xatten2Margin[2]); | ||
196 | PR_EEP("Chain1 OutputBias", modal_hdr->ob_ch1); | ||
197 | PR_EEP("Chain1 DriverBias", modal_hdr->db_ch1); | ||
198 | PR_EEP("LNA Control", modal_hdr->lna_ctl); | ||
199 | PR_EEP("XPA Bias Freq0", modal_hdr->xpaBiasLvlFreq[0]); | ||
200 | PR_EEP("XPA Bias Freq1", modal_hdr->xpaBiasLvlFreq[1]); | ||
201 | PR_EEP("XPA Bias Freq2", modal_hdr->xpaBiasLvlFreq[2]); | ||
202 | |||
203 | return len; | ||
204 | } | ||
205 | |||
206 | static u32 ath9k_hw_def_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, | ||
207 | u8 *buf, u32 len, u32 size) | ||
208 | { | ||
209 | struct ar5416_eeprom_def *eep = &ah->eeprom.def; | ||
210 | struct base_eep_header *pBase = &eep->baseEepHeader; | ||
211 | |||
212 | if (!dump_base_hdr) { | ||
213 | len += snprintf(buf + len, size - len, | ||
214 | "%20s :\n", "2GHz modal Header"); | ||
215 | len += ath9k_def_dump_modal_eeprom(buf, len, size, | ||
216 | &eep->modalHeader[0]); | ||
217 | len += snprintf(buf + len, size - len, | ||
218 | "%20s :\n", "5GHz modal Header"); | ||
219 | len += ath9k_def_dump_modal_eeprom(buf, len, size, | ||
220 | &eep->modalHeader[1]); | ||
221 | goto out; | ||
222 | } | ||
223 | |||
224 | PR_EEP("Major Version", pBase->version >> 12); | ||
225 | PR_EEP("Minor Version", pBase->version & 0xFFF); | ||
226 | PR_EEP("Checksum", pBase->checksum); | ||
227 | PR_EEP("Length", pBase->length); | ||
228 | PR_EEP("RegDomain1", pBase->regDmn[0]); | ||
229 | PR_EEP("RegDomain2", pBase->regDmn[1]); | ||
230 | PR_EEP("TX Mask", pBase->txMask); | ||
231 | PR_EEP("RX Mask", pBase->rxMask); | ||
232 | PR_EEP("Allow 5GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11A)); | ||
233 | PR_EEP("Allow 2GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11G)); | ||
234 | PR_EEP("Disable 2GHz HT20", !!(pBase->opCapFlags & | ||
235 | AR5416_OPFLAGS_N_2G_HT20)); | ||
236 | PR_EEP("Disable 2GHz HT40", !!(pBase->opCapFlags & | ||
237 | AR5416_OPFLAGS_N_2G_HT40)); | ||
238 | PR_EEP("Disable 5Ghz HT20", !!(pBase->opCapFlags & | ||
239 | AR5416_OPFLAGS_N_5G_HT20)); | ||
240 | PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags & | ||
241 | AR5416_OPFLAGS_N_5G_HT40)); | ||
242 | PR_EEP("Big Endian", !!(pBase->eepMisc & 0x01)); | ||
243 | PR_EEP("Cal Bin Major Ver", (pBase->binBuildNumber >> 24) & 0xFF); | ||
244 | PR_EEP("Cal Bin Minor Ver", (pBase->binBuildNumber >> 16) & 0xFF); | ||
245 | PR_EEP("Cal Bin Build", (pBase->binBuildNumber >> 8) & 0xFF); | ||
246 | PR_EEP("OpenLoop Power Ctrl", pBase->openLoopPwrCntl); | ||
247 | |||
248 | len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress", | ||
249 | pBase->macAddr); | ||
250 | |||
251 | out: | ||
252 | if (len > size) | ||
253 | len = size; | ||
254 | |||
255 | return len; | ||
256 | } | ||
257 | #else | ||
258 | static u32 ath9k_hw_def_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, | ||
259 | u8 *buf, u32 len, u32 size) | ||
260 | { | ||
261 | return 0; | ||
262 | } | ||
263 | #endif | ||
264 | |||
265 | |||
136 | static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) | 266 | static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) |
137 | { | 267 | { |
138 | struct ar5416_eeprom_def *eep = | 268 | struct ar5416_eeprom_def *eep = |
@@ -693,8 +823,7 @@ static void ath9k_adjust_pdadc_values(struct ath_hw *ah, | |||
693 | } | 823 | } |
694 | 824 | ||
695 | static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, | 825 | static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, |
696 | struct ath9k_channel *chan, | 826 | struct ath9k_channel *chan) |
697 | int16_t *pTxPowerIndexOffset) | ||
698 | { | 827 | { |
699 | #define SM_PD_GAIN(x) SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##x) | 828 | #define SM_PD_GAIN(x) SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##x) |
700 | #define SM_PDGAIN_B(x, y) \ | 829 | #define SM_PDGAIN_B(x, y) \ |
@@ -855,7 +984,6 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, | |||
855 | } | 984 | } |
856 | } | 985 | } |
857 | 986 | ||
858 | *pTxPowerIndexOffset = 0; | ||
859 | #undef SM_PD_GAIN | 987 | #undef SM_PD_GAIN |
860 | #undef SM_PDGAIN_B | 988 | #undef SM_PDGAIN_B |
861 | } | 989 | } |
@@ -1143,7 +1271,6 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, | |||
1143 | struct modal_eep_header *pModal = | 1271 | struct modal_eep_header *pModal = |
1144 | &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); | 1272 | &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); |
1145 | int16_t ratesArray[Ar5416RateSize]; | 1273 | int16_t ratesArray[Ar5416RateSize]; |
1146 | int16_t txPowerIndexOffset = 0; | ||
1147 | u8 ht40PowerIncForPdadc = 2; | 1274 | u8 ht40PowerIncForPdadc = 2; |
1148 | int i, cck_ofdm_delta = 0; | 1275 | int i, cck_ofdm_delta = 0; |
1149 | 1276 | ||
@@ -1160,28 +1287,16 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, | |||
1160 | twiceMaxRegulatoryPower, | 1287 | twiceMaxRegulatoryPower, |
1161 | powerLimit); | 1288 | powerLimit); |
1162 | 1289 | ||
1163 | ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset); | 1290 | ath9k_hw_set_def_power_cal_table(ah, chan); |
1164 | 1291 | ||
1165 | regulatory->max_power_level = 0; | 1292 | regulatory->max_power_level = 0; |
1166 | for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { | 1293 | for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { |
1167 | ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); | ||
1168 | if (ratesArray[i] > MAX_RATE_POWER) | 1294 | if (ratesArray[i] > MAX_RATE_POWER) |
1169 | ratesArray[i] = MAX_RATE_POWER; | 1295 | ratesArray[i] = MAX_RATE_POWER; |
1170 | if (ratesArray[i] > regulatory->max_power_level) | 1296 | if (ratesArray[i] > regulatory->max_power_level) |
1171 | regulatory->max_power_level = ratesArray[i]; | 1297 | regulatory->max_power_level = ratesArray[i]; |
1172 | } | 1298 | } |
1173 | 1299 | ||
1174 | if (!test) { | ||
1175 | i = rate6mb; | ||
1176 | |||
1177 | if (IS_CHAN_HT40(chan)) | ||
1178 | i = rateHt40_0; | ||
1179 | else if (IS_CHAN_HT20(chan)) | ||
1180 | i = rateHt20_0; | ||
1181 | |||
1182 | regulatory->max_power_level = ratesArray[i]; | ||
1183 | } | ||
1184 | |||
1185 | switch(ar5416_get_ntxchains(ah->txchainmask)) { | 1300 | switch(ar5416_get_ntxchains(ah->txchainmask)) { |
1186 | case 1: | 1301 | case 1: |
1187 | break; | 1302 | break; |
@@ -1336,6 +1451,7 @@ const struct eeprom_ops eep_def_ops = { | |||
1336 | .check_eeprom = ath9k_hw_def_check_eeprom, | 1451 | .check_eeprom = ath9k_hw_def_check_eeprom, |
1337 | .get_eeprom = ath9k_hw_def_get_eeprom, | 1452 | .get_eeprom = ath9k_hw_def_get_eeprom, |
1338 | .fill_eeprom = ath9k_hw_def_fill_eeprom, | 1453 | .fill_eeprom = ath9k_hw_def_fill_eeprom, |
1454 | .dump_eeprom = ath9k_hw_def_dump_eeprom, | ||
1339 | .get_eeprom_ver = ath9k_hw_def_get_eeprom_ver, | 1455 | .get_eeprom_ver = ath9k_hw_def_get_eeprom_ver, |
1340 | .get_eeprom_rev = ath9k_hw_def_get_eeprom_rev, | 1456 | .get_eeprom_rev = ath9k_hw_def_get_eeprom_rev, |
1341 | .set_board_values = ath9k_hw_def_set_board_values, | 1457 | .set_board_values = ath9k_hw_def_set_board_values, |
diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index bc713fc28191..5113dd80c99f 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c | |||
@@ -149,6 +149,7 @@ static void ath9k_gen_timer_start(struct ath_hw *ah, | |||
149 | ath9k_hw_disable_interrupts(ah); | 149 | ath9k_hw_disable_interrupts(ah); |
150 | ah->imask |= ATH9K_INT_GENTIMER; | 150 | ah->imask |= ATH9K_INT_GENTIMER; |
151 | ath9k_hw_set_interrupts(ah, ah->imask); | 151 | ath9k_hw_set_interrupts(ah, ah->imask); |
152 | ath9k_hw_enable_interrupts(ah); | ||
152 | } | 153 | } |
153 | } | 154 | } |
154 | 155 | ||
@@ -163,6 +164,7 @@ static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) | |||
163 | ath9k_hw_disable_interrupts(ah); | 164 | ath9k_hw_disable_interrupts(ah); |
164 | ah->imask &= ~ATH9K_INT_GENTIMER; | 165 | ah->imask &= ~ATH9K_INT_GENTIMER; |
165 | ath9k_hw_set_interrupts(ah, ah->imask); | 166 | ath9k_hw_set_interrupts(ah, ah->imask); |
167 | ath9k_hw_enable_interrupts(ah); | ||
166 | } | 168 | } |
167 | } | 169 | } |
168 | 170 | ||
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 5bc022087e65..da5596766d82 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h | |||
@@ -521,8 +521,6 @@ void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb, | |||
521 | 521 | ||
522 | int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv, | 522 | int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv, |
523 | u8 enable_coex); | 523 | u8 enable_coex); |
524 | void ath9k_htc_station_work(struct work_struct *work); | ||
525 | void ath9k_htc_aggr_work(struct work_struct *work); | ||
526 | void ath9k_htc_ani_work(struct work_struct *work); | 524 | void ath9k_htc_ani_work(struct work_struct *work); |
527 | void ath9k_htc_start_ani(struct ath9k_htc_priv *priv); | 525 | void ath9k_htc_start_ani(struct ath9k_htc_priv *priv); |
528 | void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv); | 526 | void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv); |
@@ -542,7 +540,6 @@ int ath9k_htc_tx_get_slot(struct ath9k_htc_priv *priv); | |||
542 | void ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot); | 540 | void ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot); |
543 | void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv); | 541 | void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv); |
544 | void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event); | 542 | void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event); |
545 | void ath9k_htc_tx_failed(struct ath9k_htc_priv *priv); | ||
546 | void ath9k_tx_failed_tasklet(unsigned long data); | 543 | void ath9k_tx_failed_tasklet(unsigned long data); |
547 | void ath9k_htc_tx_cleanup_timer(unsigned long data); | 544 | void ath9k_htc_tx_cleanup_timer(unsigned long data); |
548 | 545 | ||
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 3bea7ea86f0a..19aa5b724887 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c | |||
@@ -666,7 +666,6 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, | |||
666 | return -ENOMEM; | 666 | return -ENOMEM; |
667 | 667 | ||
668 | ah->hw_version.devid = devid; | 668 | ah->hw_version.devid = devid; |
669 | ah->hw_version.subsysid = 0; /* FIXME */ | ||
670 | ah->hw_version.usbdev = drv_info; | 669 | ah->hw_version.usbdev = drv_info; |
671 | ah->ah_flags |= AH_USE_EEPROM; | 670 | ah->ah_flags |= AH_USE_EEPROM; |
672 | ah->reg_ops.read = ath9k_regread; | 671 | ah->reg_ops.read = ath9k_regread; |
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 8dcefe74f4c3..db44e5b0c98b 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c | |||
@@ -1486,6 +1486,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, | |||
1486 | memset(caldata, 0, sizeof(*caldata)); | 1486 | memset(caldata, 0, sizeof(*caldata)); |
1487 | ath9k_init_nfcal_hist_buffer(ah, chan); | 1487 | ath9k_init_nfcal_hist_buffer(ah, chan); |
1488 | } | 1488 | } |
1489 | ah->noise = ath9k_hw_getchan_noise(ah, chan); | ||
1489 | 1490 | ||
1490 | if (bChannelChange && | 1491 | if (bChannelChange && |
1491 | (ah->chip_fullsleep != true) && | 1492 | (ah->chip_fullsleep != true) && |
@@ -2439,15 +2440,18 @@ void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test) | |||
2439 | struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); | 2440 | struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); |
2440 | struct ath9k_channel *chan = ah->curchan; | 2441 | struct ath9k_channel *chan = ah->curchan; |
2441 | struct ieee80211_channel *channel = chan->chan; | 2442 | struct ieee80211_channel *channel = chan->chan; |
2443 | int reg_pwr = min_t(int, MAX_RATE_POWER, regulatory->power_limit); | ||
2444 | int chan_pwr = channel->max_power * 2; | ||
2445 | |||
2446 | if (test) | ||
2447 | reg_pwr = chan_pwr = MAX_RATE_POWER; | ||
2442 | 2448 | ||
2443 | regulatory->power_limit = min(limit, (u32) MAX_RATE_POWER); | 2449 | regulatory->power_limit = min(limit, (u32) MAX_RATE_POWER); |
2444 | 2450 | ||
2445 | ah->eep_ops->set_txpower(ah, chan, | 2451 | ah->eep_ops->set_txpower(ah, chan, |
2446 | ath9k_regd_get_ctl(regulatory, chan), | 2452 | ath9k_regd_get_ctl(regulatory, chan), |
2447 | channel->max_antenna_gain * 2, | 2453 | channel->max_antenna_gain * 2, |
2448 | channel->max_power * 2, | 2454 | chan_pwr, reg_pwr, test); |
2449 | min((u32) MAX_RATE_POWER, | ||
2450 | (u32) regulatory->power_limit), test); | ||
2451 | } | 2455 | } |
2452 | EXPORT_SYMBOL(ath9k_hw_set_txpowerlimit); | 2456 | EXPORT_SYMBOL(ath9k_hw_set_txpowerlimit); |
2453 | 2457 | ||
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index c79889036ec4..4fbcced2828c 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h | |||
@@ -93,6 +93,12 @@ | |||
93 | (_ah)->reg_ops.write_flush((_ah)); \ | 93 | (_ah)->reg_ops.write_flush((_ah)); \ |
94 | } while (0) | 94 | } while (0) |
95 | 95 | ||
96 | #define PR_EEP(_s, _val) \ | ||
97 | do { \ | ||
98 | len += snprintf(buf + len, size - len, "%20s : %10d\n", \ | ||
99 | _s, (_val)); \ | ||
100 | } while (0) | ||
101 | |||
96 | #define SM(_v, _f) (((_v) << _f##_S) & _f) | 102 | #define SM(_v, _f) (((_v) << _f##_S) & _f) |
97 | #define MS(_v, _f) (((_v) & _f) >> _f##_S) | 103 | #define MS(_v, _f) (((_v) & _f) >> _f##_S) |
98 | #define REG_RMW_FIELD(_a, _r, _f, _v) \ | 104 | #define REG_RMW_FIELD(_a, _r, _f, _v) \ |
@@ -438,7 +444,6 @@ struct ath9k_hw_version { | |||
438 | u16 phyRev; | 444 | u16 phyRev; |
439 | u16 analog5GhzRev; | 445 | u16 analog5GhzRev; |
440 | u16 analog2GhzRev; | 446 | u16 analog2GhzRev; |
441 | u16 subsysid; | ||
442 | enum ath_usb_dev usbdev; | 447 | enum ath_usb_dev usbdev; |
443 | }; | 448 | }; |
444 | 449 | ||
@@ -690,6 +695,7 @@ struct ath_hw { | |||
690 | enum nl80211_iftype opmode; | 695 | enum nl80211_iftype opmode; |
691 | enum ath9k_power_mode power_mode; | 696 | enum ath9k_power_mode power_mode; |
692 | 697 | ||
698 | s8 noise; | ||
693 | struct ath9k_hw_cal_data *caldata; | 699 | struct ath9k_hw_cal_data *caldata; |
694 | struct ath9k_pacal_info pacal_info; | 700 | struct ath9k_pacal_info pacal_info; |
695 | struct ar5416Stats stats; | 701 | struct ar5416Stats stats; |
@@ -703,6 +709,7 @@ struct ath_hw { | |||
703 | u32 txdesc_interrupt_mask; | 709 | u32 txdesc_interrupt_mask; |
704 | u32 txeol_interrupt_mask; | 710 | u32 txeol_interrupt_mask; |
705 | u32 txurn_interrupt_mask; | 711 | u32 txurn_interrupt_mask; |
712 | atomic_t intr_ref_cnt; | ||
706 | bool chip_fullsleep; | 713 | bool chip_fullsleep; |
707 | u32 atim_window; | 714 | u32 atim_window; |
708 | 715 | ||
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index aa0ff7e2c922..db38a58e752d 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c | |||
@@ -548,7 +548,7 @@ static void ath9k_init_misc(struct ath_softc *sc) | |||
548 | sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT; | 548 | sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT; |
549 | } | 549 | } |
550 | 550 | ||
551 | static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, | 551 | static int ath9k_init_softc(u16 devid, struct ath_softc *sc, |
552 | const struct ath_bus_ops *bus_ops) | 552 | const struct ath_bus_ops *bus_ops) |
553 | { | 553 | { |
554 | struct ath9k_platform_data *pdata = sc->dev->platform_data; | 554 | struct ath9k_platform_data *pdata = sc->dev->platform_data; |
@@ -563,10 +563,10 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, | |||
563 | 563 | ||
564 | ah->hw = sc->hw; | 564 | ah->hw = sc->hw; |
565 | ah->hw_version.devid = devid; | 565 | ah->hw_version.devid = devid; |
566 | ah->hw_version.subsysid = subsysid; | ||
567 | ah->reg_ops.read = ath9k_ioread32; | 566 | ah->reg_ops.read = ath9k_ioread32; |
568 | ah->reg_ops.write = ath9k_iowrite32; | 567 | ah->reg_ops.write = ath9k_iowrite32; |
569 | ah->reg_ops.rmw = ath9k_reg_rmw; | 568 | ah->reg_ops.rmw = ath9k_reg_rmw; |
569 | atomic_set(&ah->intr_ref_cnt, -1); | ||
570 | sc->sc_ah = ah; | 570 | sc->sc_ah = ah; |
571 | 571 | ||
572 | if (!pdata) { | 572 | if (!pdata) { |
@@ -743,7 +743,7 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) | |||
743 | SET_IEEE80211_PERM_ADDR(hw, common->macaddr); | 743 | SET_IEEE80211_PERM_ADDR(hw, common->macaddr); |
744 | } | 744 | } |
745 | 745 | ||
746 | int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, | 746 | int ath9k_init_device(u16 devid, struct ath_softc *sc, |
747 | const struct ath_bus_ops *bus_ops) | 747 | const struct ath_bus_ops *bus_ops) |
748 | { | 748 | { |
749 | struct ieee80211_hw *hw = sc->hw; | 749 | struct ieee80211_hw *hw = sc->hw; |
@@ -753,7 +753,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, | |||
753 | struct ath_regulatory *reg; | 753 | struct ath_regulatory *reg; |
754 | 754 | ||
755 | /* Bring up device */ | 755 | /* Bring up device */ |
756 | error = ath9k_init_softc(devid, sc, subsysid, bus_ops); | 756 | error = ath9k_init_softc(devid, sc, bus_ops); |
757 | if (error != 0) | 757 | if (error != 0) |
758 | goto error_init; | 758 | goto error_init; |
759 | 759 | ||
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index b6b523a897e5..0f90e1521ffe 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c | |||
@@ -800,6 +800,11 @@ void ath9k_hw_disable_interrupts(struct ath_hw *ah) | |||
800 | { | 800 | { |
801 | struct ath_common *common = ath9k_hw_common(ah); | 801 | struct ath_common *common = ath9k_hw_common(ah); |
802 | 802 | ||
803 | if (!(ah->imask & ATH9K_INT_GLOBAL)) | ||
804 | atomic_set(&ah->intr_ref_cnt, -1); | ||
805 | else | ||
806 | atomic_dec(&ah->intr_ref_cnt); | ||
807 | |||
803 | ath_dbg(common, ATH_DBG_INTERRUPT, "disable IER\n"); | 808 | ath_dbg(common, ATH_DBG_INTERRUPT, "disable IER\n"); |
804 | REG_WRITE(ah, AR_IER, AR_IER_DISABLE); | 809 | REG_WRITE(ah, AR_IER, AR_IER_DISABLE); |
805 | (void) REG_READ(ah, AR_IER); | 810 | (void) REG_READ(ah, AR_IER); |
@@ -821,6 +826,13 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah) | |||
821 | if (!(ah->imask & ATH9K_INT_GLOBAL)) | 826 | if (!(ah->imask & ATH9K_INT_GLOBAL)) |
822 | return; | 827 | return; |
823 | 828 | ||
829 | if (!atomic_inc_and_test(&ah->intr_ref_cnt)) { | ||
830 | ath_dbg(common, ATH_DBG_INTERRUPT, | ||
831 | "Do not enable IER ref count %d\n", | ||
832 | atomic_read(&ah->intr_ref_cnt)); | ||
833 | return; | ||
834 | } | ||
835 | |||
824 | if (AR_SREV_9340(ah)) | 836 | if (AR_SREV_9340(ah)) |
825 | sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; | 837 | sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; |
826 | 838 | ||
@@ -852,7 +864,6 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) | |||
852 | 864 | ||
853 | ath_dbg(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints); | 865 | ath_dbg(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints); |
854 | 866 | ||
855 | /* TODO: global int Ref count */ | ||
856 | mask = ints & ATH9K_INT_COMMON; | 867 | mask = ints & ATH9K_INT_COMMON; |
857 | mask2 = 0; | 868 | mask2 = 0; |
858 | 869 | ||
@@ -929,9 +940,6 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) | |||
929 | REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER); | 940 | REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER); |
930 | } | 941 | } |
931 | 942 | ||
932 | if (ints & ATH9K_INT_GLOBAL) | ||
933 | ath9k_hw_enable_interrupts(ah); | ||
934 | |||
935 | return; | 943 | return; |
936 | } | 944 | } |
937 | EXPORT_SYMBOL(ath9k_hw_set_interrupts); | 945 | EXPORT_SYMBOL(ath9k_hw_set_interrupts); |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 9098aaad97a9..1e7fe8c0e119 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -163,7 +163,7 @@ static void ath_update_survey_nf(struct ath_softc *sc, int channel) | |||
163 | 163 | ||
164 | if (chan->noisefloor) { | 164 | if (chan->noisefloor) { |
165 | survey->filled |= SURVEY_INFO_NOISE_DBM; | 165 | survey->filled |= SURVEY_INFO_NOISE_DBM; |
166 | survey->noise = chan->noisefloor; | 166 | survey->noise = ath9k_hw_getchan_noise(ah, chan); |
167 | } | 167 | } |
168 | } | 168 | } |
169 | 169 | ||
@@ -294,6 +294,7 @@ static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, | |||
294 | ath9k_cmn_update_txpow(ah, sc->curtxpow, | 294 | ath9k_cmn_update_txpow(ah, sc->curtxpow, |
295 | sc->config.txpowlimit, &sc->curtxpow); | 295 | sc->config.txpowlimit, &sc->curtxpow); |
296 | ath9k_hw_set_interrupts(ah, ah->imask); | 296 | ath9k_hw_set_interrupts(ah, ah->imask); |
297 | ath9k_hw_enable_interrupts(ah); | ||
297 | 298 | ||
298 | if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) { | 299 | if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) { |
299 | if (sc->sc_flags & SC_OP_BEACONS) | 300 | if (sc->sc_flags & SC_OP_BEACONS) |
@@ -706,8 +707,7 @@ void ath9k_tasklet(unsigned long data) | |||
706 | */ | 707 | */ |
707 | ath_dbg(common, ATH_DBG_PS, | 708 | ath_dbg(common, ATH_DBG_PS, |
708 | "TSFOOR - Sync with next Beacon\n"); | 709 | "TSFOOR - Sync with next Beacon\n"); |
709 | sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC | | 710 | sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC; |
710 | PS_TSFOOR_SYNC; | ||
711 | } | 711 | } |
712 | 712 | ||
713 | if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) | 713 | if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) |
@@ -886,6 +886,7 @@ static void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) | |||
886 | 886 | ||
887 | ath9k_ps_wakeup(sc); | 887 | ath9k_ps_wakeup(sc); |
888 | spin_lock_bh(&sc->sc_pcu_lock); | 888 | spin_lock_bh(&sc->sc_pcu_lock); |
889 | atomic_set(&ah->intr_ref_cnt, -1); | ||
889 | 890 | ||
890 | ath9k_hw_configpcipowersave(ah, 0, 0); | 891 | ath9k_hw_configpcipowersave(ah, 0, 0); |
891 | 892 | ||
@@ -910,6 +911,7 @@ static void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) | |||
910 | 911 | ||
911 | /* Re-Enable interrupts */ | 912 | /* Re-Enable interrupts */ |
912 | ath9k_hw_set_interrupts(ah, ah->imask); | 913 | ath9k_hw_set_interrupts(ah, ah->imask); |
914 | ath9k_hw_enable_interrupts(ah); | ||
913 | 915 | ||
914 | /* Enable LED */ | 916 | /* Enable LED */ |
915 | ath9k_hw_cfg_output(ah, ah->led_pin, | 917 | ath9k_hw_cfg_output(ah, ah->led_pin, |
@@ -1016,6 +1018,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) | |||
1016 | ath_set_beacon(sc); /* restart beacons */ | 1018 | ath_set_beacon(sc); /* restart beacons */ |
1017 | 1019 | ||
1018 | ath9k_hw_set_interrupts(ah, ah->imask); | 1020 | ath9k_hw_set_interrupts(ah, ah->imask); |
1021 | ath9k_hw_enable_interrupts(ah); | ||
1019 | 1022 | ||
1020 | if (retry_tx) { | 1023 | if (retry_tx) { |
1021 | int i; | 1024 | int i; |
@@ -1130,6 +1133,7 @@ static int ath9k_start(struct ieee80211_hw *hw) | |||
1130 | /* Disable BMISS interrupt when we're not associated */ | 1133 | /* Disable BMISS interrupt when we're not associated */ |
1131 | ah->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); | 1134 | ah->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); |
1132 | ath9k_hw_set_interrupts(ah, ah->imask); | 1135 | ath9k_hw_set_interrupts(ah, ah->imask); |
1136 | ath9k_hw_enable_interrupts(ah); | ||
1133 | 1137 | ||
1134 | ieee80211_wake_queues(hw); | 1138 | ieee80211_wake_queues(hw); |
1135 | 1139 | ||
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index be4ea1329813..5685cf11cfe3 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c | |||
@@ -156,7 +156,6 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
156 | struct ath_softc *sc; | 156 | struct ath_softc *sc; |
157 | struct ieee80211_hw *hw; | 157 | struct ieee80211_hw *hw; |
158 | u8 csz; | 158 | u8 csz; |
159 | u16 subsysid; | ||
160 | u32 val; | 159 | u32 val; |
161 | int ret = 0; | 160 | int ret = 0; |
162 | char hw_name[64]; | 161 | char hw_name[64]; |
@@ -250,8 +249,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
250 | 249 | ||
251 | sc->irq = pdev->irq; | 250 | sc->irq = pdev->irq; |
252 | 251 | ||
253 | pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsysid); | 252 | ret = ath9k_init_device(id->device, sc, &ath_pci_bus_ops); |
254 | ret = ath9k_init_device(id->device, sc, subsysid, &ath_pci_bus_ops); | ||
255 | if (ret) { | 253 | if (ret) { |
256 | dev_err(&pdev->dev, "Failed to initialize device\n"); | 254 | dev_err(&pdev->dev, "Failed to initialize device\n"); |
257 | goto err_init; | 255 | goto err_init; |
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index c04a6c3cac7f..9e3649a3d5ca 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c | |||
@@ -1484,7 +1484,7 @@ static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, | |||
1484 | if (rc->rate_table == NULL) | 1484 | if (rc->rate_table == NULL) |
1485 | return 0; | 1485 | return 0; |
1486 | 1486 | ||
1487 | max = 80 + rc->rate_table->rate_cnt * 1024 + 1; | 1487 | max = 80 + rc->rate_table_size * 1024 + 1; |
1488 | buf = kmalloc(max, GFP_KERNEL); | 1488 | buf = kmalloc(max, GFP_KERNEL); |
1489 | if (buf == NULL) | 1489 | if (buf == NULL) |
1490 | return -ENOMEM; | 1490 | return -ENOMEM; |
@@ -1494,7 +1494,7 @@ static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, | |||
1494 | "HT", "MCS", "Rate", | 1494 | "HT", "MCS", "Rate", |
1495 | "Success", "Retries", "XRetries", "PER"); | 1495 | "Success", "Retries", "XRetries", "PER"); |
1496 | 1496 | ||
1497 | for (i = 0; i < rc->rate_table->rate_cnt; i++) { | 1497 | for (i = 0; i < rc->rate_table_size; i++) { |
1498 | u32 ratekbps = rc->rate_table->info[i].ratekbps; | 1498 | u32 ratekbps = rc->rate_table->info[i].ratekbps; |
1499 | struct ath_rc_stats *stats = &rc->rcstats[i]; | 1499 | struct ath_rc_stats *stats = &rc->rcstats[i]; |
1500 | char mcs[5]; | 1500 | char mcs[5]; |
diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h index c3d850207bee..b7a4bcd3eec7 100644 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h | |||
@@ -221,12 +221,6 @@ struct ath_rate_priv { | |||
221 | struct ath_rc_stats rcstats[RATE_TABLE_SIZE]; | 221 | struct ath_rc_stats rcstats[RATE_TABLE_SIZE]; |
222 | }; | 222 | }; |
223 | 223 | ||
224 | enum ath9k_internal_frame_type { | ||
225 | ATH9K_IFT_NOT_INTERNAL, | ||
226 | ATH9K_IFT_PAUSE, | ||
227 | ATH9K_IFT_UNPAUSE | ||
228 | }; | ||
229 | |||
230 | #ifdef CONFIG_ATH9K_RATE_CONTROL | 224 | #ifdef CONFIG_ATH9K_RATE_CONTROL |
231 | int ath_rate_control_register(void); | 225 | int ath_rate_control_register(void); |
232 | void ath_rate_control_unregister(void); | 226 | void ath_rate_control_unregister(void); |
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 9a4850154fb2..74094022b654 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c | |||
@@ -601,7 +601,6 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) | |||
601 | ath_dbg(common, ATH_DBG_PS, | 601 | ath_dbg(common, ATH_DBG_PS, |
602 | "Reconfigure Beacon timers based on timestamp from the AP\n"); | 602 | "Reconfigure Beacon timers based on timestamp from the AP\n"); |
603 | ath_set_beacon(sc); | 603 | ath_set_beacon(sc); |
604 | sc->ps_flags &= ~PS_TSFOOR_SYNC; | ||
605 | } | 604 | } |
606 | 605 | ||
607 | if (ath_beacon_dtim_pending_cab(skb)) { | 606 | if (ath_beacon_dtim_pending_cab(skb)) { |
@@ -995,6 +994,8 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common, | |||
995 | struct ieee80211_rx_status *rx_status, | 994 | struct ieee80211_rx_status *rx_status, |
996 | bool *decrypt_error) | 995 | bool *decrypt_error) |
997 | { | 996 | { |
997 | struct ath_hw *ah = common->ah; | ||
998 | |||
998 | memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); | 999 | memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); |
999 | 1000 | ||
1000 | /* | 1001 | /* |
@@ -1015,7 +1016,7 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common, | |||
1015 | 1016 | ||
1016 | rx_status->band = hw->conf.channel->band; | 1017 | rx_status->band = hw->conf.channel->band; |
1017 | rx_status->freq = hw->conf.channel->center_freq; | 1018 | rx_status->freq = hw->conf.channel->center_freq; |
1018 | rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + rx_stats->rs_rssi; | 1019 | rx_status->signal = ah->noise + rx_stats->rs_rssi; |
1019 | rx_status->antenna = rx_stats->rs_antenna; | 1020 | rx_status->antenna = rx_stats->rs_antenna; |
1020 | rx_status->flag |= RX_FLAG_MACTIME_MPDU; | 1021 | rx_status->flag |= RX_FLAG_MACTIME_MPDU; |
1021 | 1022 | ||
@@ -1783,11 +1784,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) | |||
1783 | struct ieee80211_rx_status *rxs; | 1784 | struct ieee80211_rx_status *rxs; |
1784 | struct ath_hw *ah = sc->sc_ah; | 1785 | struct ath_hw *ah = sc->sc_ah; |
1785 | struct ath_common *common = ath9k_hw_common(ah); | 1786 | struct ath_common *common = ath9k_hw_common(ah); |
1786 | /* | ||
1787 | * The hw can technically differ from common->hw when using ath9k | ||
1788 | * virtual wiphy so to account for that we iterate over the active | ||
1789 | * wiphys and find the appropriate wiphy and therefore hw. | ||
1790 | */ | ||
1791 | struct ieee80211_hw *hw = sc->hw; | 1787 | struct ieee80211_hw *hw = sc->hw; |
1792 | struct ieee80211_hdr *hdr; | 1788 | struct ieee80211_hdr *hdr; |
1793 | int retval; | 1789 | int retval; |
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index cc595712f518..e1d1e903229b 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c | |||
@@ -551,7 +551,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
551 | if (clear_filter) | 551 | if (clear_filter) |
552 | tid->ac->clear_ps_filter = true; | 552 | tid->ac->clear_ps_filter = true; |
553 | list_splice(&bf_pending, &tid->buf_q); | 553 | list_splice(&bf_pending, &tid->buf_q); |
554 | ath_tx_queue_tid(txq, tid); | 554 | if (!an->sleeping) |
555 | ath_tx_queue_tid(txq, tid); | ||
555 | spin_unlock_bh(&txq->axq_lock); | 556 | spin_unlock_bh(&txq->axq_lock); |
556 | } | 557 | } |
557 | 558 | ||
@@ -1413,7 +1414,8 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, | |||
1413 | */ | 1414 | */ |
1414 | TX_STAT_INC(txctl->txq->axq_qnum, a_queued_sw); | 1415 | TX_STAT_INC(txctl->txq->axq_qnum, a_queued_sw); |
1415 | list_add_tail(&bf->list, &tid->buf_q); | 1416 | list_add_tail(&bf->list, &tid->buf_q); |
1416 | ath_tx_queue_tid(txctl->txq, tid); | 1417 | if (!txctl->an || !txctl->an->sleeping) |
1418 | ath_tx_queue_tid(txctl->txq, tid); | ||
1417 | return; | 1419 | return; |
1418 | } | 1420 | } |
1419 | 1421 | ||
@@ -1777,7 +1779,6 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, | |||
1777 | INIT_LIST_HEAD(&bf_head); | 1779 | INIT_LIST_HEAD(&bf_head); |
1778 | list_add_tail(&bf->list, &bf_head); | 1780 | list_add_tail(&bf->list, &bf_head); |
1779 | 1781 | ||
1780 | bf->bf_state.bfs_ftype = txctl->frame_type; | ||
1781 | bf->bf_state.bfs_paprd = txctl->paprd; | 1782 | bf->bf_state.bfs_paprd = txctl->paprd; |
1782 | 1783 | ||
1783 | if (bf->bf_state.bfs_paprd) | 1784 | if (bf->bf_state.bfs_paprd) |
@@ -1876,7 +1877,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, | |||
1876 | /*****************/ | 1877 | /*****************/ |
1877 | 1878 | ||
1878 | static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, | 1879 | static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, |
1879 | int tx_flags, int ftype, struct ath_txq *txq) | 1880 | int tx_flags, struct ath_txq *txq) |
1880 | { | 1881 | { |
1881 | struct ieee80211_hw *hw = sc->hw; | 1882 | struct ieee80211_hw *hw = sc->hw; |
1882 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | 1883 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); |
@@ -1961,8 +1962,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, | |||
1961 | complete(&sc->paprd_complete); | 1962 | complete(&sc->paprd_complete); |
1962 | } else { | 1963 | } else { |
1963 | ath_debug_stat_tx(sc, bf, ts, txq); | 1964 | ath_debug_stat_tx(sc, bf, ts, txq); |
1964 | ath_tx_complete(sc, skb, tx_flags, | 1965 | ath_tx_complete(sc, skb, tx_flags, txq); |
1965 | bf->bf_state.bfs_ftype, txq); | ||
1966 | } | 1966 | } |
1967 | /* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't | 1967 | /* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't |
1968 | * accidentally reference it later. | 1968 | * accidentally reference it later. |
diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index 172f63f671cf..03a8268ccf21 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h | |||
@@ -101,7 +101,7 @@ enum CountryCode { | |||
101 | CTRY_GERMANY = 276, | 101 | CTRY_GERMANY = 276, |
102 | CTRY_GREECE = 300, | 102 | CTRY_GREECE = 300, |
103 | CTRY_GREENLAND = 304, | 103 | CTRY_GREENLAND = 304, |
104 | CTRY_GRENEDA = 308, | 104 | CTRY_GRENADA = 308, |
105 | CTRY_GUAM = 316, | 105 | CTRY_GUAM = 316, |
106 | CTRY_GUATEMALA = 320, | 106 | CTRY_GUATEMALA = 320, |
107 | CTRY_HAITI = 332, | 107 | CTRY_HAITI = 332, |
diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 24b53839fc3a..bdd2b4d61f2f 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h | |||
@@ -332,7 +332,7 @@ static struct country_code_to_enum_rd allCountries[] = { | |||
332 | {CTRY_GERMANY, ETSI1_WORLD, "DE"}, | 332 | {CTRY_GERMANY, ETSI1_WORLD, "DE"}, |
333 | {CTRY_GREECE, ETSI1_WORLD, "GR"}, | 333 | {CTRY_GREECE, ETSI1_WORLD, "GR"}, |
334 | {CTRY_GREENLAND, ETSI1_WORLD, "GL"}, | 334 | {CTRY_GREENLAND, ETSI1_WORLD, "GL"}, |
335 | {CTRY_GRENEDA, FCC3_FCCA, "GD"}, | 335 | {CTRY_GRENADA, FCC3_FCCA, "GD"}, |
336 | {CTRY_GUAM, FCC1_FCCA, "GU"}, | 336 | {CTRY_GUAM, FCC1_FCCA, "GU"}, |
337 | {CTRY_GUATEMALA, FCC1_FCCA, "GT"}, | 337 | {CTRY_GUATEMALA, FCC1_FCCA, "GT"}, |
338 | {CTRY_HAITI, ETSI1_WORLD, "HT"}, | 338 | {CTRY_HAITI, ETSI1_WORLD, "HT"}, |
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 3cab843afb05..b81a2a1c2618 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig | |||
@@ -114,13 +114,13 @@ config B43_PHY_N | |||
114 | affect other devices support and may provide support for basic needs. | 114 | affect other devices support and may provide support for basic needs. |
115 | 115 | ||
116 | config B43_PHY_LP | 116 | config B43_PHY_LP |
117 | bool "Support for low-power (LP-PHY) devices (EXPERIMENTAL)" | 117 | bool "Support for low-power (LP-PHY) devices" |
118 | depends on B43 && EXPERIMENTAL | 118 | depends on B43 |
119 | default y | 119 | default y |
120 | ---help--- | 120 | ---help--- |
121 | Support for the LP-PHY. | 121 | Support for the LP-PHY. |
122 | The LP-PHY is a low-power PHY built into some notebooks | 122 | The LP-PHY is a low-power PHY built into some notebooks |
123 | and embedded devices. It supports 802.11a/g | 123 | and embedded devices. It supports 802.11a/b/g |
124 | (802.11a support is optional, and currently disabled). | 124 | (802.11a support is optional, and currently disabled). |
125 | 125 | ||
126 | config B43_PHY_HT | 126 | config B43_PHY_HT |
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 26f1ab840cc7..d2661aaff50f 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -37,7 +37,6 @@ | |||
37 | #include <linux/if_arp.h> | 37 | #include <linux/if_arp.h> |
38 | #include <linux/etherdevice.h> | 38 | #include <linux/etherdevice.h> |
39 | #include <linux/firmware.h> | 39 | #include <linux/firmware.h> |
40 | #include <linux/wireless.h> | ||
41 | #include <linux/workqueue.h> | 40 | #include <linux/workqueue.h> |
42 | #include <linux/skbuff.h> | 41 | #include <linux/skbuff.h> |
43 | #include <linux/io.h> | 42 | #include <linux/io.h> |
@@ -115,6 +114,7 @@ MODULE_PARM_DESC(pio, "Use PIO accesses by default: 0=DMA, 1=PIO"); | |||
115 | 114 | ||
116 | #ifdef CONFIG_B43_BCMA | 115 | #ifdef CONFIG_B43_BCMA |
117 | static const struct bcma_device_id b43_bcma_tbl[] = { | 116 | static const struct bcma_device_id b43_bcma_tbl[] = { |
117 | BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x11, BCMA_ANY_CLASS), | ||
118 | BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x17, BCMA_ANY_CLASS), | 118 | BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x17, BCMA_ANY_CLASS), |
119 | BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x18, BCMA_ANY_CLASS), | 119 | BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x18, BCMA_ANY_CLASS), |
120 | BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x1D, BCMA_ANY_CLASS), | 120 | BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x1D, BCMA_ANY_CLASS), |
diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index a610a352102a..ad4e743e4765 100644 --- a/drivers/net/wireless/b43legacy/b43legacy.h +++ b/drivers/net/wireless/b43legacy/b43legacy.h | |||
@@ -14,7 +14,6 @@ | |||
14 | #include <linux/ssb/ssb.h> | 14 | #include <linux/ssb/ssb.h> |
15 | #include <linux/ssb/ssb_driver_chipcommon.h> | 15 | #include <linux/ssb/ssb_driver_chipcommon.h> |
16 | 16 | ||
17 | #include <linux/wireless.h> | ||
18 | #include <net/mac80211.h> | 17 | #include <net/mac80211.h> |
19 | 18 | ||
20 | #include "debugfs.h" | 19 | #include "debugfs.h" |
diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c index 5010c477abdf..c5535adf6991 100644 --- a/drivers/net/wireless/b43legacy/dma.c +++ b/drivers/net/wireless/b43legacy/dma.c | |||
@@ -42,10 +42,9 @@ | |||
42 | 42 | ||
43 | /* 32bit DMA ops. */ | 43 | /* 32bit DMA ops. */ |
44 | static | 44 | static |
45 | struct b43legacy_dmadesc_generic *op32_idx2desc( | 45 | struct b43legacy_dmadesc32 *op32_idx2desc(struct b43legacy_dmaring *ring, |
46 | struct b43legacy_dmaring *ring, | 46 | int slot, |
47 | int slot, | 47 | struct b43legacy_dmadesc_meta **meta) |
48 | struct b43legacy_dmadesc_meta **meta) | ||
49 | { | 48 | { |
50 | struct b43legacy_dmadesc32 *desc; | 49 | struct b43legacy_dmadesc32 *desc; |
51 | 50 | ||
@@ -53,11 +52,11 @@ struct b43legacy_dmadesc_generic *op32_idx2desc( | |||
53 | desc = ring->descbase; | 52 | desc = ring->descbase; |
54 | desc = &(desc[slot]); | 53 | desc = &(desc[slot]); |
55 | 54 | ||
56 | return (struct b43legacy_dmadesc_generic *)desc; | 55 | return (struct b43legacy_dmadesc32 *)desc; |
57 | } | 56 | } |
58 | 57 | ||
59 | static void op32_fill_descriptor(struct b43legacy_dmaring *ring, | 58 | static void op32_fill_descriptor(struct b43legacy_dmaring *ring, |
60 | struct b43legacy_dmadesc_generic *desc, | 59 | struct b43legacy_dmadesc32 *desc, |
61 | dma_addr_t dmaaddr, u16 bufsize, | 60 | dma_addr_t dmaaddr, u16 bufsize, |
62 | int start, int end, int irq) | 61 | int start, int end, int irq) |
63 | { | 62 | { |
@@ -67,7 +66,7 @@ static void op32_fill_descriptor(struct b43legacy_dmaring *ring, | |||
67 | u32 addr; | 66 | u32 addr; |
68 | u32 addrext; | 67 | u32 addrext; |
69 | 68 | ||
70 | slot = (int)(&(desc->dma32) - descbase); | 69 | slot = (int)(desc - descbase); |
71 | B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); | 70 | B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); |
72 | 71 | ||
73 | addr = (u32)(dmaaddr & ~SSB_DMA_TRANSLATION_MASK); | 72 | addr = (u32)(dmaaddr & ~SSB_DMA_TRANSLATION_MASK); |
@@ -87,8 +86,8 @@ static void op32_fill_descriptor(struct b43legacy_dmaring *ring, | |||
87 | ctl |= (addrext << B43legacy_DMA32_DCTL_ADDREXT_SHIFT) | 86 | ctl |= (addrext << B43legacy_DMA32_DCTL_ADDREXT_SHIFT) |
88 | & B43legacy_DMA32_DCTL_ADDREXT_MASK; | 87 | & B43legacy_DMA32_DCTL_ADDREXT_MASK; |
89 | 88 | ||
90 | desc->dma32.control = cpu_to_le32(ctl); | 89 | desc->control = cpu_to_le32(ctl); |
91 | desc->dma32.address = cpu_to_le32(addr); | 90 | desc->address = cpu_to_le32(addr); |
92 | } | 91 | } |
93 | 92 | ||
94 | static void op32_poke_tx(struct b43legacy_dmaring *ring, int slot) | 93 | static void op32_poke_tx(struct b43legacy_dmaring *ring, int slot) |
@@ -128,121 +127,6 @@ static void op32_set_current_rxslot(struct b43legacy_dmaring *ring, | |||
128 | (u32)(slot * sizeof(struct b43legacy_dmadesc32))); | 127 | (u32)(slot * sizeof(struct b43legacy_dmadesc32))); |
129 | } | 128 | } |
130 | 129 | ||
131 | static const struct b43legacy_dma_ops dma32_ops = { | ||
132 | .idx2desc = op32_idx2desc, | ||
133 | .fill_descriptor = op32_fill_descriptor, | ||
134 | .poke_tx = op32_poke_tx, | ||
135 | .tx_suspend = op32_tx_suspend, | ||
136 | .tx_resume = op32_tx_resume, | ||
137 | .get_current_rxslot = op32_get_current_rxslot, | ||
138 | .set_current_rxslot = op32_set_current_rxslot, | ||
139 | }; | ||
140 | |||
141 | /* 64bit DMA ops. */ | ||
142 | static | ||
143 | struct b43legacy_dmadesc_generic *op64_idx2desc( | ||
144 | struct b43legacy_dmaring *ring, | ||
145 | int slot, | ||
146 | struct b43legacy_dmadesc_meta | ||
147 | **meta) | ||
148 | { | ||
149 | struct b43legacy_dmadesc64 *desc; | ||
150 | |||
151 | *meta = &(ring->meta[slot]); | ||
152 | desc = ring->descbase; | ||
153 | desc = &(desc[slot]); | ||
154 | |||
155 | return (struct b43legacy_dmadesc_generic *)desc; | ||
156 | } | ||
157 | |||
158 | static void op64_fill_descriptor(struct b43legacy_dmaring *ring, | ||
159 | struct b43legacy_dmadesc_generic *desc, | ||
160 | dma_addr_t dmaaddr, u16 bufsize, | ||
161 | int start, int end, int irq) | ||
162 | { | ||
163 | struct b43legacy_dmadesc64 *descbase = ring->descbase; | ||
164 | int slot; | ||
165 | u32 ctl0 = 0; | ||
166 | u32 ctl1 = 0; | ||
167 | u32 addrlo; | ||
168 | u32 addrhi; | ||
169 | u32 addrext; | ||
170 | |||
171 | slot = (int)(&(desc->dma64) - descbase); | ||
172 | B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); | ||
173 | |||
174 | addrlo = (u32)(dmaaddr & 0xFFFFFFFF); | ||
175 | addrhi = (((u64)dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK); | ||
176 | addrext = (((u64)dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK) | ||
177 | >> SSB_DMA_TRANSLATION_SHIFT; | ||
178 | addrhi |= ring->dev->dma.translation; | ||
179 | if (slot == ring->nr_slots - 1) | ||
180 | ctl0 |= B43legacy_DMA64_DCTL0_DTABLEEND; | ||
181 | if (start) | ||
182 | ctl0 |= B43legacy_DMA64_DCTL0_FRAMESTART; | ||
183 | if (end) | ||
184 | ctl0 |= B43legacy_DMA64_DCTL0_FRAMEEND; | ||
185 | if (irq) | ||
186 | ctl0 |= B43legacy_DMA64_DCTL0_IRQ; | ||
187 | ctl1 |= (bufsize - ring->frameoffset) | ||
188 | & B43legacy_DMA64_DCTL1_BYTECNT; | ||
189 | ctl1 |= (addrext << B43legacy_DMA64_DCTL1_ADDREXT_SHIFT) | ||
190 | & B43legacy_DMA64_DCTL1_ADDREXT_MASK; | ||
191 | |||
192 | desc->dma64.control0 = cpu_to_le32(ctl0); | ||
193 | desc->dma64.control1 = cpu_to_le32(ctl1); | ||
194 | desc->dma64.address_low = cpu_to_le32(addrlo); | ||
195 | desc->dma64.address_high = cpu_to_le32(addrhi); | ||
196 | } | ||
197 | |||
198 | static void op64_poke_tx(struct b43legacy_dmaring *ring, int slot) | ||
199 | { | ||
200 | b43legacy_dma_write(ring, B43legacy_DMA64_TXINDEX, | ||
201 | (u32)(slot * sizeof(struct b43legacy_dmadesc64))); | ||
202 | } | ||
203 | |||
204 | static void op64_tx_suspend(struct b43legacy_dmaring *ring) | ||
205 | { | ||
206 | b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL, | ||
207 | b43legacy_dma_read(ring, B43legacy_DMA64_TXCTL) | ||
208 | | B43legacy_DMA64_TXSUSPEND); | ||
209 | } | ||
210 | |||
211 | static void op64_tx_resume(struct b43legacy_dmaring *ring) | ||
212 | { | ||
213 | b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL, | ||
214 | b43legacy_dma_read(ring, B43legacy_DMA64_TXCTL) | ||
215 | & ~B43legacy_DMA64_TXSUSPEND); | ||
216 | } | ||
217 | |||
218 | static int op64_get_current_rxslot(struct b43legacy_dmaring *ring) | ||
219 | { | ||
220 | u32 val; | ||
221 | |||
222 | val = b43legacy_dma_read(ring, B43legacy_DMA64_RXSTATUS); | ||
223 | val &= B43legacy_DMA64_RXSTATDPTR; | ||
224 | |||
225 | return (val / sizeof(struct b43legacy_dmadesc64)); | ||
226 | } | ||
227 | |||
228 | static void op64_set_current_rxslot(struct b43legacy_dmaring *ring, | ||
229 | int slot) | ||
230 | { | ||
231 | b43legacy_dma_write(ring, B43legacy_DMA64_RXINDEX, | ||
232 | (u32)(slot * sizeof(struct b43legacy_dmadesc64))); | ||
233 | } | ||
234 | |||
235 | static const struct b43legacy_dma_ops dma64_ops = { | ||
236 | .idx2desc = op64_idx2desc, | ||
237 | .fill_descriptor = op64_fill_descriptor, | ||
238 | .poke_tx = op64_poke_tx, | ||
239 | .tx_suspend = op64_tx_suspend, | ||
240 | .tx_resume = op64_tx_resume, | ||
241 | .get_current_rxslot = op64_get_current_rxslot, | ||
242 | .set_current_rxslot = op64_set_current_rxslot, | ||
243 | }; | ||
244 | |||
245 | |||
246 | static inline int free_slots(struct b43legacy_dmaring *ring) | 130 | static inline int free_slots(struct b43legacy_dmaring *ring) |
247 | { | 131 | { |
248 | return (ring->nr_slots - ring->used_slots); | 132 | return (ring->nr_slots - ring->used_slots); |
@@ -358,14 +242,6 @@ return 0; | |||
358 | static u16 b43legacy_dmacontroller_base(enum b43legacy_dmatype type, | 242 | static u16 b43legacy_dmacontroller_base(enum b43legacy_dmatype type, |
359 | int controller_idx) | 243 | int controller_idx) |
360 | { | 244 | { |
361 | static const u16 map64[] = { | ||
362 | B43legacy_MMIO_DMA64_BASE0, | ||
363 | B43legacy_MMIO_DMA64_BASE1, | ||
364 | B43legacy_MMIO_DMA64_BASE2, | ||
365 | B43legacy_MMIO_DMA64_BASE3, | ||
366 | B43legacy_MMIO_DMA64_BASE4, | ||
367 | B43legacy_MMIO_DMA64_BASE5, | ||
368 | }; | ||
369 | static const u16 map32[] = { | 245 | static const u16 map32[] = { |
370 | B43legacy_MMIO_DMA32_BASE0, | 246 | B43legacy_MMIO_DMA32_BASE0, |
371 | B43legacy_MMIO_DMA32_BASE1, | 247 | B43legacy_MMIO_DMA32_BASE1, |
@@ -375,11 +251,6 @@ static u16 b43legacy_dmacontroller_base(enum b43legacy_dmatype type, | |||
375 | B43legacy_MMIO_DMA32_BASE5, | 251 | B43legacy_MMIO_DMA32_BASE5, |
376 | }; | 252 | }; |
377 | 253 | ||
378 | if (type == B43legacy_DMA_64BIT) { | ||
379 | B43legacy_WARN_ON(!(controller_idx >= 0 && | ||
380 | controller_idx < ARRAY_SIZE(map64))); | ||
381 | return map64[controller_idx]; | ||
382 | } | ||
383 | B43legacy_WARN_ON(!(controller_idx >= 0 && | 254 | B43legacy_WARN_ON(!(controller_idx >= 0 && |
384 | controller_idx < ARRAY_SIZE(map32))); | 255 | controller_idx < ARRAY_SIZE(map32))); |
385 | return map32[controller_idx]; | 256 | return map32[controller_idx]; |
@@ -491,25 +362,15 @@ static int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev, | |||
491 | 362 | ||
492 | might_sleep(); | 363 | might_sleep(); |
493 | 364 | ||
494 | offset = (type == B43legacy_DMA_64BIT) ? | 365 | offset = B43legacy_DMA32_RXCTL; |
495 | B43legacy_DMA64_RXCTL : B43legacy_DMA32_RXCTL; | ||
496 | b43legacy_write32(dev, mmio_base + offset, 0); | 366 | b43legacy_write32(dev, mmio_base + offset, 0); |
497 | for (i = 0; i < 10; i++) { | 367 | for (i = 0; i < 10; i++) { |
498 | offset = (type == B43legacy_DMA_64BIT) ? | 368 | offset = B43legacy_DMA32_RXSTATUS; |
499 | B43legacy_DMA64_RXSTATUS : B43legacy_DMA32_RXSTATUS; | ||
500 | value = b43legacy_read32(dev, mmio_base + offset); | 369 | value = b43legacy_read32(dev, mmio_base + offset); |
501 | if (type == B43legacy_DMA_64BIT) { | 370 | value &= B43legacy_DMA32_RXSTATE; |
502 | value &= B43legacy_DMA64_RXSTAT; | 371 | if (value == B43legacy_DMA32_RXSTAT_DISABLED) { |
503 | if (value == B43legacy_DMA64_RXSTAT_DISABLED) { | 372 | i = -1; |
504 | i = -1; | 373 | break; |
505 | break; | ||
506 | } | ||
507 | } else { | ||
508 | value &= B43legacy_DMA32_RXSTATE; | ||
509 | if (value == B43legacy_DMA32_RXSTAT_DISABLED) { | ||
510 | i = -1; | ||
511 | break; | ||
512 | } | ||
513 | } | 374 | } |
514 | msleep(1); | 375 | msleep(1); |
515 | } | 376 | } |
@@ -533,43 +394,24 @@ static int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev, | |||
533 | might_sleep(); | 394 | might_sleep(); |
534 | 395 | ||
535 | for (i = 0; i < 10; i++) { | 396 | for (i = 0; i < 10; i++) { |
536 | offset = (type == B43legacy_DMA_64BIT) ? | 397 | offset = B43legacy_DMA32_TXSTATUS; |
537 | B43legacy_DMA64_TXSTATUS : B43legacy_DMA32_TXSTATUS; | ||
538 | value = b43legacy_read32(dev, mmio_base + offset); | 398 | value = b43legacy_read32(dev, mmio_base + offset); |
539 | if (type == B43legacy_DMA_64BIT) { | 399 | value &= B43legacy_DMA32_TXSTATE; |
540 | value &= B43legacy_DMA64_TXSTAT; | 400 | if (value == B43legacy_DMA32_TXSTAT_DISABLED || |
541 | if (value == B43legacy_DMA64_TXSTAT_DISABLED || | 401 | value == B43legacy_DMA32_TXSTAT_IDLEWAIT || |
542 | value == B43legacy_DMA64_TXSTAT_IDLEWAIT || | 402 | value == B43legacy_DMA32_TXSTAT_STOPPED) |
543 | value == B43legacy_DMA64_TXSTAT_STOPPED) | 403 | break; |
544 | break; | ||
545 | } else { | ||
546 | value &= B43legacy_DMA32_TXSTATE; | ||
547 | if (value == B43legacy_DMA32_TXSTAT_DISABLED || | ||
548 | value == B43legacy_DMA32_TXSTAT_IDLEWAIT || | ||
549 | value == B43legacy_DMA32_TXSTAT_STOPPED) | ||
550 | break; | ||
551 | } | ||
552 | msleep(1); | 404 | msleep(1); |
553 | } | 405 | } |
554 | offset = (type == B43legacy_DMA_64BIT) ? B43legacy_DMA64_TXCTL : | 406 | offset = B43legacy_DMA32_TXCTL; |
555 | B43legacy_DMA32_TXCTL; | ||
556 | b43legacy_write32(dev, mmio_base + offset, 0); | 407 | b43legacy_write32(dev, mmio_base + offset, 0); |
557 | for (i = 0; i < 10; i++) { | 408 | for (i = 0; i < 10; i++) { |
558 | offset = (type == B43legacy_DMA_64BIT) ? | 409 | offset = B43legacy_DMA32_TXSTATUS; |
559 | B43legacy_DMA64_TXSTATUS : B43legacy_DMA32_TXSTATUS; | ||
560 | value = b43legacy_read32(dev, mmio_base + offset); | 410 | value = b43legacy_read32(dev, mmio_base + offset); |
561 | if (type == B43legacy_DMA_64BIT) { | 411 | value &= B43legacy_DMA32_TXSTATE; |
562 | value &= B43legacy_DMA64_TXSTAT; | 412 | if (value == B43legacy_DMA32_TXSTAT_DISABLED) { |
563 | if (value == B43legacy_DMA64_TXSTAT_DISABLED) { | 413 | i = -1; |
564 | i = -1; | 414 | break; |
565 | break; | ||
566 | } | ||
567 | } else { | ||
568 | value &= B43legacy_DMA32_TXSTATE; | ||
569 | if (value == B43legacy_DMA32_TXSTAT_DISABLED) { | ||
570 | i = -1; | ||
571 | break; | ||
572 | } | ||
573 | } | 415 | } |
574 | msleep(1); | 416 | msleep(1); |
575 | } | 417 | } |
@@ -601,9 +443,6 @@ static bool b43legacy_dma_mapping_error(struct b43legacy_dmaring *ring, | |||
601 | if ((u64)addr + buffersize > (1ULL << 32)) | 443 | if ((u64)addr + buffersize > (1ULL << 32)) |
602 | goto address_error; | 444 | goto address_error; |
603 | break; | 445 | break; |
604 | case B43legacy_DMA_64BIT: | ||
605 | /* Currently we can't have addresses beyond 64 bits in the kernel. */ | ||
606 | break; | ||
607 | } | 446 | } |
608 | 447 | ||
609 | /* The address is OK. */ | 448 | /* The address is OK. */ |
@@ -617,7 +456,7 @@ address_error: | |||
617 | } | 456 | } |
618 | 457 | ||
619 | static int setup_rx_descbuffer(struct b43legacy_dmaring *ring, | 458 | static int setup_rx_descbuffer(struct b43legacy_dmaring *ring, |
620 | struct b43legacy_dmadesc_generic *desc, | 459 | struct b43legacy_dmadesc32 *desc, |
621 | struct b43legacy_dmadesc_meta *meta, | 460 | struct b43legacy_dmadesc_meta *meta, |
622 | gfp_t gfp_flags) | 461 | gfp_t gfp_flags) |
623 | { | 462 | { |
@@ -653,8 +492,7 @@ static int setup_rx_descbuffer(struct b43legacy_dmaring *ring, | |||
653 | 492 | ||
654 | meta->skb = skb; | 493 | meta->skb = skb; |
655 | meta->dmaaddr = dmaaddr; | 494 | meta->dmaaddr = dmaaddr; |
656 | ring->ops->fill_descriptor(ring, desc, dmaaddr, | 495 | op32_fill_descriptor(ring, desc, dmaaddr, ring->rx_buffersize, 0, 0, 0); |
657 | ring->rx_buffersize, 0, 0, 0); | ||
658 | 496 | ||
659 | rxhdr = (struct b43legacy_rxhdr_fw3 *)(skb->data); | 497 | rxhdr = (struct b43legacy_rxhdr_fw3 *)(skb->data); |
660 | rxhdr->frame_len = 0; | 498 | rxhdr->frame_len = 0; |
@@ -671,11 +509,11 @@ static int alloc_initial_descbuffers(struct b43legacy_dmaring *ring) | |||
671 | { | 509 | { |
672 | int i; | 510 | int i; |
673 | int err = -ENOMEM; | 511 | int err = -ENOMEM; |
674 | struct b43legacy_dmadesc_generic *desc; | 512 | struct b43legacy_dmadesc32 *desc; |
675 | struct b43legacy_dmadesc_meta *meta; | 513 | struct b43legacy_dmadesc_meta *meta; |
676 | 514 | ||
677 | for (i = 0; i < ring->nr_slots; i++) { | 515 | for (i = 0; i < ring->nr_slots; i++) { |
678 | desc = ring->ops->idx2desc(ring, i, &meta); | 516 | desc = op32_idx2desc(ring, i, &meta); |
679 | 517 | ||
680 | err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL); | 518 | err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL); |
681 | if (err) { | 519 | if (err) { |
@@ -692,7 +530,7 @@ out: | |||
692 | 530 | ||
693 | err_unwind: | 531 | err_unwind: |
694 | for (i--; i >= 0; i--) { | 532 | for (i--; i >= 0; i--) { |
695 | desc = ring->ops->idx2desc(ring, i, &meta); | 533 | desc = op32_idx2desc(ring, i, &meta); |
696 | 534 | ||
697 | unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0); | 535 | unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0); |
698 | dev_kfree_skb(meta->skb); | 536 | dev_kfree_skb(meta->skb); |
@@ -710,83 +548,35 @@ static int dmacontroller_setup(struct b43legacy_dmaring *ring) | |||
710 | u32 value; | 548 | u32 value; |
711 | u32 addrext; | 549 | u32 addrext; |
712 | u32 trans = ring->dev->dma.translation; | 550 | u32 trans = ring->dev->dma.translation; |
551 | u32 ringbase = (u32)(ring->dmabase); | ||
713 | 552 | ||
714 | if (ring->tx) { | 553 | if (ring->tx) { |
715 | if (ring->type == B43legacy_DMA_64BIT) { | 554 | addrext = (ringbase & SSB_DMA_TRANSLATION_MASK) |
716 | u64 ringbase = (u64)(ring->dmabase); | 555 | >> SSB_DMA_TRANSLATION_SHIFT; |
717 | 556 | value = B43legacy_DMA32_TXENABLE; | |
718 | addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK) | 557 | value |= (addrext << B43legacy_DMA32_TXADDREXT_SHIFT) |
719 | >> SSB_DMA_TRANSLATION_SHIFT; | 558 | & B43legacy_DMA32_TXADDREXT_MASK; |
720 | value = B43legacy_DMA64_TXENABLE; | 559 | b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL, value); |
721 | value |= (addrext << B43legacy_DMA64_TXADDREXT_SHIFT) | 560 | b43legacy_dma_write(ring, B43legacy_DMA32_TXRING, |
722 | & B43legacy_DMA64_TXADDREXT_MASK; | 561 | (ringbase & ~SSB_DMA_TRANSLATION_MASK) |
723 | b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL, | 562 | | trans); |
724 | value); | ||
725 | b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGLO, | ||
726 | (ringbase & 0xFFFFFFFF)); | ||
727 | b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGHI, | ||
728 | ((ringbase >> 32) | ||
729 | & ~SSB_DMA_TRANSLATION_MASK) | ||
730 | | trans); | ||
731 | } else { | ||
732 | u32 ringbase = (u32)(ring->dmabase); | ||
733 | |||
734 | addrext = (ringbase & SSB_DMA_TRANSLATION_MASK) | ||
735 | >> SSB_DMA_TRANSLATION_SHIFT; | ||
736 | value = B43legacy_DMA32_TXENABLE; | ||
737 | value |= (addrext << B43legacy_DMA32_TXADDREXT_SHIFT) | ||
738 | & B43legacy_DMA32_TXADDREXT_MASK; | ||
739 | b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL, | ||
740 | value); | ||
741 | b43legacy_dma_write(ring, B43legacy_DMA32_TXRING, | ||
742 | (ringbase & | ||
743 | ~SSB_DMA_TRANSLATION_MASK) | ||
744 | | trans); | ||
745 | } | ||
746 | } else { | 563 | } else { |
747 | err = alloc_initial_descbuffers(ring); | 564 | err = alloc_initial_descbuffers(ring); |
748 | if (err) | 565 | if (err) |
749 | goto out; | 566 | goto out; |
750 | if (ring->type == B43legacy_DMA_64BIT) { | 567 | |
751 | u64 ringbase = (u64)(ring->dmabase); | 568 | addrext = (ringbase & SSB_DMA_TRANSLATION_MASK) |
752 | 569 | >> SSB_DMA_TRANSLATION_SHIFT; | |
753 | addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK) | 570 | value = (ring->frameoffset << |
754 | >> SSB_DMA_TRANSLATION_SHIFT; | 571 | B43legacy_DMA32_RXFROFF_SHIFT); |
755 | value = (ring->frameoffset << | 572 | value |= B43legacy_DMA32_RXENABLE; |
756 | B43legacy_DMA64_RXFROFF_SHIFT); | 573 | value |= (addrext << B43legacy_DMA32_RXADDREXT_SHIFT) |
757 | value |= B43legacy_DMA64_RXENABLE; | 574 | & B43legacy_DMA32_RXADDREXT_MASK; |
758 | value |= (addrext << B43legacy_DMA64_RXADDREXT_SHIFT) | 575 | b43legacy_dma_write(ring, B43legacy_DMA32_RXCTL, value); |
759 | & B43legacy_DMA64_RXADDREXT_MASK; | 576 | b43legacy_dma_write(ring, B43legacy_DMA32_RXRING, |
760 | b43legacy_dma_write(ring, B43legacy_DMA64_RXCTL, | 577 | (ringbase & ~SSB_DMA_TRANSLATION_MASK) |
761 | value); | 578 | | trans); |
762 | b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGLO, | 579 | b43legacy_dma_write(ring, B43legacy_DMA32_RXINDEX, 200); |
763 | (ringbase & 0xFFFFFFFF)); | ||
764 | b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGHI, | ||
765 | ((ringbase >> 32) & | ||
766 | ~SSB_DMA_TRANSLATION_MASK) | | ||
767 | trans); | ||
768 | b43legacy_dma_write(ring, B43legacy_DMA64_RXINDEX, | ||
769 | 200); | ||
770 | } else { | ||
771 | u32 ringbase = (u32)(ring->dmabase); | ||
772 | |||
773 | addrext = (ringbase & SSB_DMA_TRANSLATION_MASK) | ||
774 | >> SSB_DMA_TRANSLATION_SHIFT; | ||
775 | value = (ring->frameoffset << | ||
776 | B43legacy_DMA32_RXFROFF_SHIFT); | ||
777 | value |= B43legacy_DMA32_RXENABLE; | ||
778 | value |= (addrext << | ||
779 | B43legacy_DMA32_RXADDREXT_SHIFT) | ||
780 | & B43legacy_DMA32_RXADDREXT_MASK; | ||
781 | b43legacy_dma_write(ring, B43legacy_DMA32_RXCTL, | ||
782 | value); | ||
783 | b43legacy_dma_write(ring, B43legacy_DMA32_RXRING, | ||
784 | (ringbase & | ||
785 | ~SSB_DMA_TRANSLATION_MASK) | ||
786 | | trans); | ||
787 | b43legacy_dma_write(ring, B43legacy_DMA32_RXINDEX, | ||
788 | 200); | ||
789 | } | ||
790 | } | 580 | } |
791 | 581 | ||
792 | out: | 582 | out: |
@@ -799,19 +589,11 @@ static void dmacontroller_cleanup(struct b43legacy_dmaring *ring) | |||
799 | if (ring->tx) { | 589 | if (ring->tx) { |
800 | b43legacy_dmacontroller_tx_reset(ring->dev, ring->mmio_base, | 590 | b43legacy_dmacontroller_tx_reset(ring->dev, ring->mmio_base, |
801 | ring->type); | 591 | ring->type); |
802 | if (ring->type == B43legacy_DMA_64BIT) { | 592 | b43legacy_dma_write(ring, B43legacy_DMA32_TXRING, 0); |
803 | b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGLO, 0); | ||
804 | b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGHI, 0); | ||
805 | } else | ||
806 | b43legacy_dma_write(ring, B43legacy_DMA32_TXRING, 0); | ||
807 | } else { | 593 | } else { |
808 | b43legacy_dmacontroller_rx_reset(ring->dev, ring->mmio_base, | 594 | b43legacy_dmacontroller_rx_reset(ring->dev, ring->mmio_base, |
809 | ring->type); | 595 | ring->type); |
810 | if (ring->type == B43legacy_DMA_64BIT) { | 596 | b43legacy_dma_write(ring, B43legacy_DMA32_RXRING, 0); |
811 | b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGLO, 0); | ||
812 | b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGHI, 0); | ||
813 | } else | ||
814 | b43legacy_dma_write(ring, B43legacy_DMA32_RXRING, 0); | ||
815 | } | 597 | } |
816 | } | 598 | } |
817 | 599 | ||
@@ -823,7 +605,7 @@ static void free_all_descbuffers(struct b43legacy_dmaring *ring) | |||
823 | if (!ring->used_slots) | 605 | if (!ring->used_slots) |
824 | return; | 606 | return; |
825 | for (i = 0; i < ring->nr_slots; i++) { | 607 | for (i = 0; i < ring->nr_slots; i++) { |
826 | ring->ops->idx2desc(ring, i, &meta); | 608 | op32_idx2desc(ring, i, &meta); |
827 | 609 | ||
828 | if (!meta->skb) { | 610 | if (!meta->skb) { |
829 | B43legacy_WARN_ON(!ring->tx); | 611 | B43legacy_WARN_ON(!ring->tx); |
@@ -844,9 +626,6 @@ static u64 supported_dma_mask(struct b43legacy_wldev *dev) | |||
844 | u32 tmp; | 626 | u32 tmp; |
845 | u16 mmio_base; | 627 | u16 mmio_base; |
846 | 628 | ||
847 | tmp = b43legacy_read32(dev, SSB_TMSHIGH); | ||
848 | if (tmp & SSB_TMSHIGH_DMA64) | ||
849 | return DMA_BIT_MASK(64); | ||
850 | mmio_base = b43legacy_dmacontroller_base(0, 0); | 629 | mmio_base = b43legacy_dmacontroller_base(0, 0); |
851 | b43legacy_write32(dev, | 630 | b43legacy_write32(dev, |
852 | mmio_base + B43legacy_DMA32_TXCTL, | 631 | mmio_base + B43legacy_DMA32_TXCTL, |
@@ -865,8 +644,6 @@ static enum b43legacy_dmatype dma_mask_to_engine_type(u64 dmamask) | |||
865 | return B43legacy_DMA_30BIT; | 644 | return B43legacy_DMA_30BIT; |
866 | if (dmamask == DMA_BIT_MASK(32)) | 645 | if (dmamask == DMA_BIT_MASK(32)) |
867 | return B43legacy_DMA_32BIT; | 646 | return B43legacy_DMA_32BIT; |
868 | if (dmamask == DMA_BIT_MASK(64)) | ||
869 | return B43legacy_DMA_64BIT; | ||
870 | B43legacy_WARN_ON(1); | 647 | B43legacy_WARN_ON(1); |
871 | return B43legacy_DMA_30BIT; | 648 | return B43legacy_DMA_30BIT; |
872 | } | 649 | } |
@@ -937,10 +714,6 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev, | |||
937 | ring->nr_slots = nr_slots; | 714 | ring->nr_slots = nr_slots; |
938 | ring->mmio_base = b43legacy_dmacontroller_base(type, controller_index); | 715 | ring->mmio_base = b43legacy_dmacontroller_base(type, controller_index); |
939 | ring->index = controller_index; | 716 | ring->index = controller_index; |
940 | if (type == B43legacy_DMA_64BIT) | ||
941 | ring->ops = &dma64_ops; | ||
942 | else | ||
943 | ring->ops = &dma32_ops; | ||
944 | if (for_tx) { | 717 | if (for_tx) { |
945 | ring->tx = 1; | 718 | ring->tx = 1; |
946 | ring->current_slot = -1; | 719 | ring->current_slot = -1; |
@@ -1247,12 +1020,11 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring, | |||
1247 | struct sk_buff **in_skb) | 1020 | struct sk_buff **in_skb) |
1248 | { | 1021 | { |
1249 | struct sk_buff *skb = *in_skb; | 1022 | struct sk_buff *skb = *in_skb; |
1250 | const struct b43legacy_dma_ops *ops = ring->ops; | ||
1251 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1023 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1252 | u8 *header; | 1024 | u8 *header; |
1253 | int slot, old_top_slot, old_used_slots; | 1025 | int slot, old_top_slot, old_used_slots; |
1254 | int err; | 1026 | int err; |
1255 | struct b43legacy_dmadesc_generic *desc; | 1027 | struct b43legacy_dmadesc32 *desc; |
1256 | struct b43legacy_dmadesc_meta *meta; | 1028 | struct b43legacy_dmadesc_meta *meta; |
1257 | struct b43legacy_dmadesc_meta *meta_hdr; | 1029 | struct b43legacy_dmadesc_meta *meta_hdr; |
1258 | struct sk_buff *bounce_skb; | 1030 | struct sk_buff *bounce_skb; |
@@ -1265,7 +1037,7 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring, | |||
1265 | 1037 | ||
1266 | /* Get a slot for the header. */ | 1038 | /* Get a slot for the header. */ |
1267 | slot = request_slot(ring); | 1039 | slot = request_slot(ring); |
1268 | desc = ops->idx2desc(ring, slot, &meta_hdr); | 1040 | desc = op32_idx2desc(ring, slot, &meta_hdr); |
1269 | memset(meta_hdr, 0, sizeof(*meta_hdr)); | 1041 | memset(meta_hdr, 0, sizeof(*meta_hdr)); |
1270 | 1042 | ||
1271 | header = &(ring->txhdr_cache[slot * sizeof( | 1043 | header = &(ring->txhdr_cache[slot * sizeof( |
@@ -1287,12 +1059,12 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring, | |||
1287 | ring->used_slots = old_used_slots; | 1059 | ring->used_slots = old_used_slots; |
1288 | return -EIO; | 1060 | return -EIO; |
1289 | } | 1061 | } |
1290 | ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr, | 1062 | op32_fill_descriptor(ring, desc, meta_hdr->dmaaddr, |
1291 | sizeof(struct b43legacy_txhdr_fw3), 1, 0, 0); | 1063 | sizeof(struct b43legacy_txhdr_fw3), 1, 0, 0); |
1292 | 1064 | ||
1293 | /* Get a slot for the payload. */ | 1065 | /* Get a slot for the payload. */ |
1294 | slot = request_slot(ring); | 1066 | slot = request_slot(ring); |
1295 | desc = ops->idx2desc(ring, slot, &meta); | 1067 | desc = op32_idx2desc(ring, slot, &meta); |
1296 | memset(meta, 0, sizeof(*meta)); | 1068 | memset(meta, 0, sizeof(*meta)); |
1297 | 1069 | ||
1298 | meta->skb = skb; | 1070 | meta->skb = skb; |
@@ -1328,12 +1100,12 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring, | |||
1328 | } | 1100 | } |
1329 | } | 1101 | } |
1330 | 1102 | ||
1331 | ops->fill_descriptor(ring, desc, meta->dmaaddr, | 1103 | op32_fill_descriptor(ring, desc, meta->dmaaddr, |
1332 | skb->len, 0, 1, 1); | 1104 | skb->len, 0, 1, 1); |
1333 | 1105 | ||
1334 | wmb(); /* previous stuff MUST be done */ | 1106 | wmb(); /* previous stuff MUST be done */ |
1335 | /* Now transfer the whole frame. */ | 1107 | /* Now transfer the whole frame. */ |
1336 | ops->poke_tx(ring, next_slot(ring, slot)); | 1108 | op32_poke_tx(ring, next_slot(ring, slot)); |
1337 | return 0; | 1109 | return 0; |
1338 | 1110 | ||
1339 | out_free_bounce: | 1111 | out_free_bounce: |
@@ -1429,7 +1201,6 @@ out_unlock: | |||
1429 | void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, | 1201 | void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, |
1430 | const struct b43legacy_txstatus *status) | 1202 | const struct b43legacy_txstatus *status) |
1431 | { | 1203 | { |
1432 | const struct b43legacy_dma_ops *ops; | ||
1433 | struct b43legacy_dmaring *ring; | 1204 | struct b43legacy_dmaring *ring; |
1434 | struct b43legacy_dmadesc_meta *meta; | 1205 | struct b43legacy_dmadesc_meta *meta; |
1435 | int retry_limit; | 1206 | int retry_limit; |
@@ -1442,10 +1213,9 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, | |||
1442 | spin_lock(&ring->lock); | 1213 | spin_lock(&ring->lock); |
1443 | 1214 | ||
1444 | B43legacy_WARN_ON(!ring->tx); | 1215 | B43legacy_WARN_ON(!ring->tx); |
1445 | ops = ring->ops; | ||
1446 | while (1) { | 1216 | while (1) { |
1447 | B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); | 1217 | B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); |
1448 | ops->idx2desc(ring, slot, &meta); | 1218 | op32_idx2desc(ring, slot, &meta); |
1449 | 1219 | ||
1450 | if (meta->skb) | 1220 | if (meta->skb) |
1451 | unmap_descbuffer(ring, meta->dmaaddr, | 1221 | unmap_descbuffer(ring, meta->dmaaddr, |
@@ -1528,8 +1298,7 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, | |||
1528 | static void dma_rx(struct b43legacy_dmaring *ring, | 1298 | static void dma_rx(struct b43legacy_dmaring *ring, |
1529 | int *slot) | 1299 | int *slot) |
1530 | { | 1300 | { |
1531 | const struct b43legacy_dma_ops *ops = ring->ops; | 1301 | struct b43legacy_dmadesc32 *desc; |
1532 | struct b43legacy_dmadesc_generic *desc; | ||
1533 | struct b43legacy_dmadesc_meta *meta; | 1302 | struct b43legacy_dmadesc_meta *meta; |
1534 | struct b43legacy_rxhdr_fw3 *rxhdr; | 1303 | struct b43legacy_rxhdr_fw3 *rxhdr; |
1535 | struct sk_buff *skb; | 1304 | struct sk_buff *skb; |
@@ -1537,7 +1306,7 @@ static void dma_rx(struct b43legacy_dmaring *ring, | |||
1537 | int err; | 1306 | int err; |
1538 | dma_addr_t dmaaddr; | 1307 | dma_addr_t dmaaddr; |
1539 | 1308 | ||
1540 | desc = ops->idx2desc(ring, *slot, &meta); | 1309 | desc = op32_idx2desc(ring, *slot, &meta); |
1541 | 1310 | ||
1542 | sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize); | 1311 | sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize); |
1543 | skb = meta->skb; | 1312 | skb = meta->skb; |
@@ -1589,7 +1358,7 @@ static void dma_rx(struct b43legacy_dmaring *ring, | |||
1589 | s32 tmp = len; | 1358 | s32 tmp = len; |
1590 | 1359 | ||
1591 | while (1) { | 1360 | while (1) { |
1592 | desc = ops->idx2desc(ring, *slot, &meta); | 1361 | desc = op32_idx2desc(ring, *slot, &meta); |
1593 | /* recycle the descriptor buffer. */ | 1362 | /* recycle the descriptor buffer. */ |
1594 | sync_descbuffer_for_device(ring, meta->dmaaddr, | 1363 | sync_descbuffer_for_device(ring, meta->dmaaddr, |
1595 | ring->rx_buffersize); | 1364 | ring->rx_buffersize); |
@@ -1626,13 +1395,12 @@ drop: | |||
1626 | 1395 | ||
1627 | void b43legacy_dma_rx(struct b43legacy_dmaring *ring) | 1396 | void b43legacy_dma_rx(struct b43legacy_dmaring *ring) |
1628 | { | 1397 | { |
1629 | const struct b43legacy_dma_ops *ops = ring->ops; | ||
1630 | int slot; | 1398 | int slot; |
1631 | int current_slot; | 1399 | int current_slot; |
1632 | int used_slots = 0; | 1400 | int used_slots = 0; |
1633 | 1401 | ||
1634 | B43legacy_WARN_ON(ring->tx); | 1402 | B43legacy_WARN_ON(ring->tx); |
1635 | current_slot = ops->get_current_rxslot(ring); | 1403 | current_slot = op32_get_current_rxslot(ring); |
1636 | B43legacy_WARN_ON(!(current_slot >= 0 && current_slot < | 1404 | B43legacy_WARN_ON(!(current_slot >= 0 && current_slot < |
1637 | ring->nr_slots)); | 1405 | ring->nr_slots)); |
1638 | 1406 | ||
@@ -1641,7 +1409,7 @@ void b43legacy_dma_rx(struct b43legacy_dmaring *ring) | |||
1641 | dma_rx(ring, &slot); | 1409 | dma_rx(ring, &slot); |
1642 | update_max_used_slots(ring, ++used_slots); | 1410 | update_max_used_slots(ring, ++used_slots); |
1643 | } | 1411 | } |
1644 | ops->set_current_rxslot(ring, slot); | 1412 | op32_set_current_rxslot(ring, slot); |
1645 | ring->current_slot = slot; | 1413 | ring->current_slot = slot; |
1646 | } | 1414 | } |
1647 | 1415 | ||
@@ -1651,7 +1419,7 @@ static void b43legacy_dma_tx_suspend_ring(struct b43legacy_dmaring *ring) | |||
1651 | 1419 | ||
1652 | spin_lock_irqsave(&ring->lock, flags); | 1420 | spin_lock_irqsave(&ring->lock, flags); |
1653 | B43legacy_WARN_ON(!ring->tx); | 1421 | B43legacy_WARN_ON(!ring->tx); |
1654 | ring->ops->tx_suspend(ring); | 1422 | op32_tx_suspend(ring); |
1655 | spin_unlock_irqrestore(&ring->lock, flags); | 1423 | spin_unlock_irqrestore(&ring->lock, flags); |
1656 | } | 1424 | } |
1657 | 1425 | ||
@@ -1661,7 +1429,7 @@ static void b43legacy_dma_tx_resume_ring(struct b43legacy_dmaring *ring) | |||
1661 | 1429 | ||
1662 | spin_lock_irqsave(&ring->lock, flags); | 1430 | spin_lock_irqsave(&ring->lock, flags); |
1663 | B43legacy_WARN_ON(!ring->tx); | 1431 | B43legacy_WARN_ON(!ring->tx); |
1664 | ring->ops->tx_resume(ring); | 1432 | op32_tx_resume(ring); |
1665 | spin_unlock_irqrestore(&ring->lock, flags); | 1433 | spin_unlock_irqrestore(&ring->lock, flags); |
1666 | } | 1434 | } |
1667 | 1435 | ||
diff --git a/drivers/net/wireless/b43legacy/dma.h b/drivers/net/wireless/b43legacy/dma.h index 686941c242fc..504a58767e95 100644 --- a/drivers/net/wireless/b43legacy/dma.h +++ b/drivers/net/wireless/b43legacy/dma.h | |||
@@ -82,90 +82,6 @@ struct b43legacy_dmadesc32 { | |||
82 | #define B43legacy_DMA32_DCTL_FRAMESTART 0x80000000 | 82 | #define B43legacy_DMA32_DCTL_FRAMESTART 0x80000000 |
83 | 83 | ||
84 | 84 | ||
85 | |||
86 | /*** 64-bit DMA Engine. ***/ | ||
87 | |||
88 | /* 64-bit DMA controller registers. */ | ||
89 | #define B43legacy_DMA64_TXCTL 0x00 | ||
90 | #define B43legacy_DMA64_TXENABLE 0x00000001 | ||
91 | #define B43legacy_DMA64_TXSUSPEND 0x00000002 | ||
92 | #define B43legacy_DMA64_TXLOOPBACK 0x00000004 | ||
93 | #define B43legacy_DMA64_TXFLUSH 0x00000010 | ||
94 | #define B43legacy_DMA64_TXADDREXT_MASK 0x00030000 | ||
95 | #define B43legacy_DMA64_TXADDREXT_SHIFT 16 | ||
96 | #define B43legacy_DMA64_TXINDEX 0x04 | ||
97 | #define B43legacy_DMA64_TXRINGLO 0x08 | ||
98 | #define B43legacy_DMA64_TXRINGHI 0x0C | ||
99 | #define B43legacy_DMA64_TXSTATUS 0x10 | ||
100 | #define B43legacy_DMA64_TXSTATDPTR 0x00001FFF | ||
101 | #define B43legacy_DMA64_TXSTAT 0xF0000000 | ||
102 | #define B43legacy_DMA64_TXSTAT_DISABLED 0x00000000 | ||
103 | #define B43legacy_DMA64_TXSTAT_ACTIVE 0x10000000 | ||
104 | #define B43legacy_DMA64_TXSTAT_IDLEWAIT 0x20000000 | ||
105 | #define B43legacy_DMA64_TXSTAT_STOPPED 0x30000000 | ||
106 | #define B43legacy_DMA64_TXSTAT_SUSP 0x40000000 | ||
107 | #define B43legacy_DMA64_TXERROR 0x14 | ||
108 | #define B43legacy_DMA64_TXERRDPTR 0x0001FFFF | ||
109 | #define B43legacy_DMA64_TXERR 0xF0000000 | ||
110 | #define B43legacy_DMA64_TXERR_NOERR 0x00000000 | ||
111 | #define B43legacy_DMA64_TXERR_PROT 0x10000000 | ||
112 | #define B43legacy_DMA64_TXERR_UNDERRUN 0x20000000 | ||
113 | #define B43legacy_DMA64_TXERR_TRANSFER 0x30000000 | ||
114 | #define B43legacy_DMA64_TXERR_DESCREAD 0x40000000 | ||
115 | #define B43legacy_DMA64_TXERR_CORE 0x50000000 | ||
116 | #define B43legacy_DMA64_RXCTL 0x20 | ||
117 | #define B43legacy_DMA64_RXENABLE 0x00000001 | ||
118 | #define B43legacy_DMA64_RXFROFF_MASK 0x000000FE | ||
119 | #define B43legacy_DMA64_RXFROFF_SHIFT 1 | ||
120 | #define B43legacy_DMA64_RXDIRECTFIFO 0x00000100 | ||
121 | #define B43legacy_DMA64_RXADDREXT_MASK 0x00030000 | ||
122 | #define B43legacy_DMA64_RXADDREXT_SHIFT 16 | ||
123 | #define B43legacy_DMA64_RXINDEX 0x24 | ||
124 | #define B43legacy_DMA64_RXRINGLO 0x28 | ||
125 | #define B43legacy_DMA64_RXRINGHI 0x2C | ||
126 | #define B43legacy_DMA64_RXSTATUS 0x30 | ||
127 | #define B43legacy_DMA64_RXSTATDPTR 0x00001FFF | ||
128 | #define B43legacy_DMA64_RXSTAT 0xF0000000 | ||
129 | #define B43legacy_DMA64_RXSTAT_DISABLED 0x00000000 | ||
130 | #define B43legacy_DMA64_RXSTAT_ACTIVE 0x10000000 | ||
131 | #define B43legacy_DMA64_RXSTAT_IDLEWAIT 0x20000000 | ||
132 | #define B43legacy_DMA64_RXSTAT_STOPPED 0x30000000 | ||
133 | #define B43legacy_DMA64_RXSTAT_SUSP 0x40000000 | ||
134 | #define B43legacy_DMA64_RXERROR 0x34 | ||
135 | #define B43legacy_DMA64_RXERRDPTR 0x0001FFFF | ||
136 | #define B43legacy_DMA64_RXERR 0xF0000000 | ||
137 | #define B43legacy_DMA64_RXERR_NOERR 0x00000000 | ||
138 | #define B43legacy_DMA64_RXERR_PROT 0x10000000 | ||
139 | #define B43legacy_DMA64_RXERR_UNDERRUN 0x20000000 | ||
140 | #define B43legacy_DMA64_RXERR_TRANSFER 0x30000000 | ||
141 | #define B43legacy_DMA64_RXERR_DESCREAD 0x40000000 | ||
142 | #define B43legacy_DMA64_RXERR_CORE 0x50000000 | ||
143 | |||
144 | /* 64-bit DMA descriptor. */ | ||
145 | struct b43legacy_dmadesc64 { | ||
146 | __le32 control0; | ||
147 | __le32 control1; | ||
148 | __le32 address_low; | ||
149 | __le32 address_high; | ||
150 | } __packed; | ||
151 | #define B43legacy_DMA64_DCTL0_DTABLEEND 0x10000000 | ||
152 | #define B43legacy_DMA64_DCTL0_IRQ 0x20000000 | ||
153 | #define B43legacy_DMA64_DCTL0_FRAMEEND 0x40000000 | ||
154 | #define B43legacy_DMA64_DCTL0_FRAMESTART 0x80000000 | ||
155 | #define B43legacy_DMA64_DCTL1_BYTECNT 0x00001FFF | ||
156 | #define B43legacy_DMA64_DCTL1_ADDREXT_MASK 0x00030000 | ||
157 | #define B43legacy_DMA64_DCTL1_ADDREXT_SHIFT 16 | ||
158 | |||
159 | |||
160 | |||
161 | struct b43legacy_dmadesc_generic { | ||
162 | union { | ||
163 | struct b43legacy_dmadesc32 dma32; | ||
164 | struct b43legacy_dmadesc64 dma64; | ||
165 | } __packed; | ||
166 | } __packed; | ||
167 | |||
168 | |||
169 | /* Misc DMA constants */ | 85 | /* Misc DMA constants */ |
170 | #define B43legacy_DMA_RINGMEMSIZE PAGE_SIZE | 86 | #define B43legacy_DMA_RINGMEMSIZE PAGE_SIZE |
171 | #define B43legacy_DMA0_RX_FRAMEOFFSET 30 | 87 | #define B43legacy_DMA0_RX_FRAMEOFFSET 30 |
@@ -197,35 +113,12 @@ struct b43legacy_dmadesc_meta { | |||
197 | bool is_last_fragment; | 113 | bool is_last_fragment; |
198 | }; | 114 | }; |
199 | 115 | ||
200 | struct b43legacy_dmaring; | ||
201 | |||
202 | /* Lowlevel DMA operations that differ between 32bit and 64bit DMA. */ | ||
203 | struct b43legacy_dma_ops { | ||
204 | struct b43legacy_dmadesc_generic * (*idx2desc) | ||
205 | (struct b43legacy_dmaring *ring, | ||
206 | int slot, | ||
207 | struct b43legacy_dmadesc_meta | ||
208 | **meta); | ||
209 | void (*fill_descriptor)(struct b43legacy_dmaring *ring, | ||
210 | struct b43legacy_dmadesc_generic *desc, | ||
211 | dma_addr_t dmaaddr, u16 bufsize, | ||
212 | int start, int end, int irq); | ||
213 | void (*poke_tx)(struct b43legacy_dmaring *ring, int slot); | ||
214 | void (*tx_suspend)(struct b43legacy_dmaring *ring); | ||
215 | void (*tx_resume)(struct b43legacy_dmaring *ring); | ||
216 | int (*get_current_rxslot)(struct b43legacy_dmaring *ring); | ||
217 | void (*set_current_rxslot)(struct b43legacy_dmaring *ring, int slot); | ||
218 | }; | ||
219 | |||
220 | enum b43legacy_dmatype { | 116 | enum b43legacy_dmatype { |
221 | B43legacy_DMA_30BIT = 30, | 117 | B43legacy_DMA_30BIT = 30, |
222 | B43legacy_DMA_32BIT = 32, | 118 | B43legacy_DMA_32BIT = 32, |
223 | B43legacy_DMA_64BIT = 64, | ||
224 | }; | 119 | }; |
225 | 120 | ||
226 | struct b43legacy_dmaring { | 121 | struct b43legacy_dmaring { |
227 | /* Lowlevel DMA ops. */ | ||
228 | const struct b43legacy_dma_ops *ops; | ||
229 | /* Kernel virtual base address of the ring memory. */ | 122 | /* Kernel virtual base address of the ring memory. */ |
230 | void *descbase; | 123 | void *descbase; |
231 | /* Meta data about all descriptors. */ | 124 | /* Meta data about all descriptors. */ |
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 04c03b212a5e..aae8dfcb852e 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c | |||
@@ -35,7 +35,6 @@ | |||
35 | #include <linux/if_arp.h> | 35 | #include <linux/if_arp.h> |
36 | #include <linux/etherdevice.h> | 36 | #include <linux/etherdevice.h> |
37 | #include <linux/firmware.h> | 37 | #include <linux/firmware.h> |
38 | #include <linux/wireless.h> | ||
39 | #include <linux/workqueue.h> | 38 | #include <linux/workqueue.h> |
40 | #include <linux/sched.h> | 39 | #include <linux/sched.h> |
41 | #include <linux/skbuff.h> | 40 | #include <linux/skbuff.h> |
@@ -3785,7 +3784,8 @@ static int b43legacy_wireless_init(struct ssb_device *dev) | |||
3785 | INIT_WORK(&wl->beacon_update_trigger, b43legacy_beacon_update_trigger_work); | 3784 | INIT_WORK(&wl->beacon_update_trigger, b43legacy_beacon_update_trigger_work); |
3786 | 3785 | ||
3787 | ssb_set_devtypedata(dev, wl); | 3786 | ssb_set_devtypedata(dev, wl); |
3788 | b43legacyinfo(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id); | 3787 | b43legacyinfo(wl, "Broadcom %04X WLAN found (core revision %u)\n", |
3788 | dev->bus->chip_id, dev->id.revision); | ||
3789 | err = 0; | 3789 | err = 0; |
3790 | out: | 3790 | out: |
3791 | return err; | 3791 | return err; |
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 553f66b67c16..f303df43ed3f 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c | |||
@@ -32,6 +32,7 @@ | |||
32 | 32 | ||
33 | #include <linux/sched.h> | 33 | #include <linux/sched.h> |
34 | #include <linux/slab.h> | 34 | #include <linux/slab.h> |
35 | #include <net/cfg80211-wext.h> | ||
35 | #include "ipw2200.h" | 36 | #include "ipw2200.h" |
36 | 37 | ||
37 | 38 | ||
diff --git a/drivers/net/wireless/iwlegacy/iwl-3945-led.c b/drivers/net/wireless/iwlegacy/iwl-3945-led.c index abd923558d48..7a7f0f38c8ab 100644 --- a/drivers/net/wireless/iwlegacy/iwl-3945-led.c +++ b/drivers/net/wireless/iwlegacy/iwl-3945-led.c | |||
@@ -32,7 +32,6 @@ | |||
32 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
33 | #include <linux/skbuff.h> | 33 | #include <linux/skbuff.h> |
34 | #include <linux/netdevice.h> | 34 | #include <linux/netdevice.h> |
35 | #include <linux/wireless.h> | ||
36 | #include <net/mac80211.h> | 35 | #include <net/mac80211.h> |
37 | #include <linux/etherdevice.h> | 36 | #include <linux/etherdevice.h> |
38 | #include <asm/unaligned.h> | 37 | #include <asm/unaligned.h> |
diff --git a/drivers/net/wireless/iwlegacy/iwl-3945-rs.c b/drivers/net/wireless/iwlegacy/iwl-3945-rs.c index 977bd2477c6a..0cc5177d738d 100644 --- a/drivers/net/wireless/iwlegacy/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlegacy/iwl-3945-rs.c | |||
@@ -28,7 +28,6 @@ | |||
28 | #include <linux/init.h> | 28 | #include <linux/init.h> |
29 | #include <linux/skbuff.h> | 29 | #include <linux/skbuff.h> |
30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
31 | #include <linux/wireless.h> | ||
32 | #include <net/mac80211.h> | 31 | #include <net/mac80211.h> |
33 | 32 | ||
34 | #include <linux/netdevice.h> | 33 | #include <linux/netdevice.h> |
diff --git a/drivers/net/wireless/iwlegacy/iwl-3945.c b/drivers/net/wireless/iwlegacy/iwl-3945.c index 73fe3cdf796b..f7c0a7438476 100644 --- a/drivers/net/wireless/iwlegacy/iwl-3945.c +++ b/drivers/net/wireless/iwlegacy/iwl-3945.c | |||
@@ -34,7 +34,6 @@ | |||
34 | #include <linux/sched.h> | 34 | #include <linux/sched.h> |
35 | #include <linux/skbuff.h> | 35 | #include <linux/skbuff.h> |
36 | #include <linux/netdevice.h> | 36 | #include <linux/netdevice.h> |
37 | #include <linux/wireless.h> | ||
38 | #include <linux/firmware.h> | 37 | #include <linux/firmware.h> |
39 | #include <linux/etherdevice.h> | 38 | #include <linux/etherdevice.h> |
40 | #include <asm/unaligned.h> | 39 | #include <asm/unaligned.h> |
diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-led.c b/drivers/net/wireless/iwlegacy/iwl-4965-led.c index 26d324e30692..6862fdcaee62 100644 --- a/drivers/net/wireless/iwlegacy/iwl-4965-led.c +++ b/drivers/net/wireless/iwlegacy/iwl-4965-led.c | |||
@@ -32,7 +32,6 @@ | |||
32 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
33 | #include <linux/skbuff.h> | 33 | #include <linux/skbuff.h> |
34 | #include <linux/netdevice.h> | 34 | #include <linux/netdevice.h> |
35 | #include <linux/wireless.h> | ||
36 | #include <net/mac80211.h> | 35 | #include <net/mac80211.h> |
37 | #include <linux/etherdevice.h> | 36 | #include <linux/etherdevice.h> |
38 | #include <asm/unaligned.h> | 37 | #include <asm/unaligned.h> |
diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-rs.c b/drivers/net/wireless/iwlegacy/iwl-4965-rs.c index 9b65153bdd01..57ebe214e68c 100644 --- a/drivers/net/wireless/iwlegacy/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlegacy/iwl-4965-rs.c | |||
@@ -27,7 +27,6 @@ | |||
27 | #include <linux/init.h> | 27 | #include <linux/init.h> |
28 | #include <linux/skbuff.h> | 28 | #include <linux/skbuff.h> |
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <linux/wireless.h> | ||
31 | #include <net/mac80211.h> | 30 | #include <net/mac80211.h> |
32 | 31 | ||
33 | #include <linux/netdevice.h> | 32 | #include <linux/netdevice.h> |
diff --git a/drivers/net/wireless/iwlegacy/iwl-4965.c b/drivers/net/wireless/iwlegacy/iwl-4965.c index ecdc6e557428..86f4fce193e4 100644 --- a/drivers/net/wireless/iwlegacy/iwl-4965.c +++ b/drivers/net/wireless/iwlegacy/iwl-4965.c | |||
@@ -33,7 +33,6 @@ | |||
33 | #include <linux/sched.h> | 33 | #include <linux/sched.h> |
34 | #include <linux/skbuff.h> | 34 | #include <linux/skbuff.h> |
35 | #include <linux/netdevice.h> | 35 | #include <linux/netdevice.h> |
36 | #include <linux/wireless.h> | ||
37 | #include <net/mac80211.h> | 36 | #include <net/mac80211.h> |
38 | #include <linux/etherdevice.h> | 37 | #include <linux/etherdevice.h> |
39 | #include <asm/unaligned.h> | 38 | #include <asm/unaligned.h> |
diff --git a/drivers/net/wireless/iwlegacy/iwl-led.c b/drivers/net/wireless/iwlegacy/iwl-led.c index bda0d61b2c0d..dc568a474c5d 100644 --- a/drivers/net/wireless/iwlegacy/iwl-led.c +++ b/drivers/net/wireless/iwlegacy/iwl-led.c | |||
@@ -33,7 +33,6 @@ | |||
33 | #include <linux/delay.h> | 33 | #include <linux/delay.h> |
34 | #include <linux/skbuff.h> | 34 | #include <linux/skbuff.h> |
35 | #include <linux/netdevice.h> | 35 | #include <linux/netdevice.h> |
36 | #include <linux/wireless.h> | ||
37 | #include <net/mac80211.h> | 36 | #include <net/mac80211.h> |
38 | #include <linux/etherdevice.h> | 37 | #include <linux/etherdevice.h> |
39 | #include <asm/unaligned.h> | 38 | #include <asm/unaligned.h> |
diff --git a/drivers/net/wireless/iwlegacy/iwl3945-base.c b/drivers/net/wireless/iwlegacy/iwl3945-base.c index 795826a014ed..015739d204f2 100644 --- a/drivers/net/wireless/iwlegacy/iwl3945-base.c +++ b/drivers/net/wireless/iwlegacy/iwl3945-base.c | |||
@@ -40,7 +40,6 @@ | |||
40 | #include <linux/sched.h> | 40 | #include <linux/sched.h> |
41 | #include <linux/skbuff.h> | 41 | #include <linux/skbuff.h> |
42 | #include <linux/netdevice.h> | 42 | #include <linux/netdevice.h> |
43 | #include <linux/wireless.h> | ||
44 | #include <linux/firmware.h> | 43 | #include <linux/firmware.h> |
45 | #include <linux/etherdevice.h> | 44 | #include <linux/etherdevice.h> |
46 | #include <linux/if_arp.h> | 45 | #include <linux/if_arp.h> |
diff --git a/drivers/net/wireless/iwlegacy/iwl4965-base.c b/drivers/net/wireless/iwlegacy/iwl4965-base.c index 14334668034e..6bc5575c8dff 100644 --- a/drivers/net/wireless/iwlegacy/iwl4965-base.c +++ b/drivers/net/wireless/iwlegacy/iwl4965-base.c | |||
@@ -40,7 +40,6 @@ | |||
40 | #include <linux/sched.h> | 40 | #include <linux/sched.h> |
41 | #include <linux/skbuff.h> | 41 | #include <linux/skbuff.h> |
42 | #include <linux/netdevice.h> | 42 | #include <linux/netdevice.h> |
43 | #include <linux/wireless.h> | ||
44 | #include <linux/firmware.h> | 43 | #include <linux/firmware.h> |
45 | #include <linux/etherdevice.h> | 44 | #include <linux/etherdevice.h> |
46 | #include <linux/if_arp.h> | 45 | #include <linux/if_arp.h> |
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index ad3bdba6beed..1d7572f9887f 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig | |||
@@ -111,20 +111,3 @@ config IWLWIFI_DEVICE_SVTOOL | |||
111 | NL80211_TESTMODE. svtool is a software validation tool that runs in | 111 | NL80211_TESTMODE. svtool is a software validation tool that runs in |
112 | the user space and interacts with the device in the kernel space | 112 | the user space and interacts with the device in the kernel space |
113 | through the generic netlink message via NL80211_TESTMODE channel. | 113 | through the generic netlink message via NL80211_TESTMODE channel. |
114 | |||
115 | config IWL_P2P | ||
116 | bool "iwlwifi experimental P2P support" | ||
117 | depends on IWLAGN | ||
118 | help | ||
119 | This option enables experimental P2P support for some devices | ||
120 | based on microcode support. Since P2P support is still under | ||
121 | development, this option may even enable it for some devices | ||
122 | now that turn out to not support it in the future due to | ||
123 | microcode restrictions. | ||
124 | |||
125 | To determine if your microcode supports the experimental P2P | ||
126 | offered by this option, check if the driver advertises AP | ||
127 | support when it is loaded. | ||
128 | |||
129 | Say Y only if you want to experiment with P2P. | ||
130 | |||
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 01b49eb8c8ec..ccdbed567171 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c | |||
@@ -30,7 +30,6 @@ | |||
30 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
31 | #include <linux/skbuff.h> | 31 | #include <linux/skbuff.h> |
32 | #include <linux/netdevice.h> | 32 | #include <linux/netdevice.h> |
33 | #include <linux/wireless.h> | ||
34 | #include <net/mac80211.h> | 33 | #include <net/mac80211.h> |
35 | #include <linux/etherdevice.h> | 34 | #include <linux/etherdevice.h> |
36 | #include <asm/unaligned.h> | 35 | #include <asm/unaligned.h> |
@@ -46,8 +45,12 @@ | |||
46 | #include "iwl-agn-hw.h" | 45 | #include "iwl-agn-hw.h" |
47 | 46 | ||
48 | /* Highest firmware API version supported */ | 47 | /* Highest firmware API version supported */ |
49 | #define IWL1000_UCODE_API_MAX 5 | 48 | #define IWL1000_UCODE_API_MAX 6 |
50 | #define IWL100_UCODE_API_MAX 5 | 49 | #define IWL100_UCODE_API_MAX 6 |
50 | |||
51 | /* Oldest version we won't warn about */ | ||
52 | #define IWL1000_UCODE_API_OK 5 | ||
53 | #define IWL100_UCODE_API_OK 5 | ||
51 | 54 | ||
52 | /* Lowest firmware API version supported */ | 55 | /* Lowest firmware API version supported */ |
53 | #define IWL1000_UCODE_API_MIN 1 | 56 | #define IWL1000_UCODE_API_MIN 1 |
@@ -135,8 +138,7 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) | |||
135 | priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE; | 138 | priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE; |
136 | priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE; | 139 | priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE; |
137 | 140 | ||
138 | priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | | 141 | priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ); |
139 | BIT(IEEE80211_BAND_5GHZ); | ||
140 | 142 | ||
141 | priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); | 143 | priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); |
142 | if (priv->cfg->rx_with_siso_diversity) | 144 | if (priv->cfg->rx_with_siso_diversity) |
@@ -201,12 +203,13 @@ static struct iwl_base_params iwl1000_base_params = { | |||
201 | static struct iwl_ht_params iwl1000_ht_params = { | 203 | static struct iwl_ht_params iwl1000_ht_params = { |
202 | .ht_greenfield_support = true, | 204 | .ht_greenfield_support = true, |
203 | .use_rts_for_aggregation = true, /* use rts/cts protection */ | 205 | .use_rts_for_aggregation = true, /* use rts/cts protection */ |
204 | .smps_mode = IEEE80211_SMPS_STATIC, | 206 | .smps_mode = IEEE80211_SMPS_DYNAMIC, |
205 | }; | 207 | }; |
206 | 208 | ||
207 | #define IWL_DEVICE_1000 \ | 209 | #define IWL_DEVICE_1000 \ |
208 | .fw_name_pre = IWL1000_FW_PRE, \ | 210 | .fw_name_pre = IWL1000_FW_PRE, \ |
209 | .ucode_api_max = IWL1000_UCODE_API_MAX, \ | 211 | .ucode_api_max = IWL1000_UCODE_API_MAX, \ |
212 | .ucode_api_ok = IWL1000_UCODE_API_OK, \ | ||
210 | .ucode_api_min = IWL1000_UCODE_API_MIN, \ | 213 | .ucode_api_min = IWL1000_UCODE_API_MIN, \ |
211 | .eeprom_ver = EEPROM_1000_EEPROM_VERSION, \ | 214 | .eeprom_ver = EEPROM_1000_EEPROM_VERSION, \ |
212 | .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ | 215 | .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ |
@@ -228,6 +231,7 @@ struct iwl_cfg iwl1000_bg_cfg = { | |||
228 | #define IWL_DEVICE_100 \ | 231 | #define IWL_DEVICE_100 \ |
229 | .fw_name_pre = IWL100_FW_PRE, \ | 232 | .fw_name_pre = IWL100_FW_PRE, \ |
230 | .ucode_api_max = IWL100_UCODE_API_MAX, \ | 233 | .ucode_api_max = IWL100_UCODE_API_MAX, \ |
234 | .ucode_api_ok = IWL100_UCODE_API_OK, \ | ||
231 | .ucode_api_min = IWL100_UCODE_API_MIN, \ | 235 | .ucode_api_min = IWL100_UCODE_API_MIN, \ |
232 | .eeprom_ver = EEPROM_1000_EEPROM_VERSION, \ | 236 | .eeprom_ver = EEPROM_1000_EEPROM_VERSION, \ |
233 | .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ | 237 | .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index 0e13f0bb2e17..54d931d614fb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c | |||
@@ -30,7 +30,6 @@ | |||
30 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
31 | #include <linux/skbuff.h> | 31 | #include <linux/skbuff.h> |
32 | #include <linux/netdevice.h> | 32 | #include <linux/netdevice.h> |
33 | #include <linux/wireless.h> | ||
34 | #include <net/mac80211.h> | 33 | #include <net/mac80211.h> |
35 | #include <linux/etherdevice.h> | 34 | #include <linux/etherdevice.h> |
36 | #include <asm/unaligned.h> | 35 | #include <asm/unaligned.h> |
@@ -47,10 +46,16 @@ | |||
47 | #include "iwl-6000-hw.h" | 46 | #include "iwl-6000-hw.h" |
48 | 47 | ||
49 | /* Highest firmware API version supported */ | 48 | /* Highest firmware API version supported */ |
50 | #define IWL2030_UCODE_API_MAX 5 | 49 | #define IWL2030_UCODE_API_MAX 6 |
51 | #define IWL2000_UCODE_API_MAX 5 | 50 | #define IWL2000_UCODE_API_MAX 6 |
52 | #define IWL105_UCODE_API_MAX 5 | 51 | #define IWL105_UCODE_API_MAX 6 |
53 | #define IWL135_UCODE_API_MAX 5 | 52 | #define IWL135_UCODE_API_MAX 6 |
53 | |||
54 | /* Oldest version we won't warn about */ | ||
55 | #define IWL2030_UCODE_API_OK 5 | ||
56 | #define IWL2000_UCODE_API_OK 5 | ||
57 | #define IWL105_UCODE_API_OK 5 | ||
58 | #define IWL135_UCODE_API_OK 5 | ||
54 | 59 | ||
55 | /* Lowest firmware API version supported */ | 60 | /* Lowest firmware API version supported */ |
56 | #define IWL2030_UCODE_API_MIN 5 | 61 | #define IWL2030_UCODE_API_MIN 5 |
@@ -130,8 +135,7 @@ static int iwl2000_hw_set_hw_params(struct iwl_priv *priv) | |||
130 | priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE; | 135 | priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE; |
131 | priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE; | 136 | priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE; |
132 | 137 | ||
133 | priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | | 138 | priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ); |
134 | BIT(IEEE80211_BAND_5GHZ); | ||
135 | 139 | ||
136 | priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); | 140 | priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); |
137 | if (priv->cfg->rx_with_siso_diversity) | 141 | if (priv->cfg->rx_with_siso_diversity) |
@@ -217,6 +221,7 @@ static struct iwl_base_params iwl2000_base_params = { | |||
217 | .wd_timeout = IWL_DEF_WD_TIMEOUT, | 221 | .wd_timeout = IWL_DEF_WD_TIMEOUT, |
218 | .max_event_log_size = 512, | 222 | .max_event_log_size = 512, |
219 | .shadow_reg_enable = true, | 223 | .shadow_reg_enable = true, |
224 | .hd_v2 = true, | ||
220 | }; | 225 | }; |
221 | 226 | ||
222 | 227 | ||
@@ -236,6 +241,7 @@ static struct iwl_base_params iwl2030_base_params = { | |||
236 | .wd_timeout = IWL_LONG_WD_TIMEOUT, | 241 | .wd_timeout = IWL_LONG_WD_TIMEOUT, |
237 | .max_event_log_size = 512, | 242 | .max_event_log_size = 512, |
238 | .shadow_reg_enable = true, | 243 | .shadow_reg_enable = true, |
244 | .hd_v2 = true, | ||
239 | }; | 245 | }; |
240 | 246 | ||
241 | static struct iwl_ht_params iwl2000_ht_params = { | 247 | static struct iwl_ht_params iwl2000_ht_params = { |
@@ -256,6 +262,7 @@ static struct iwl_bt_params iwl2030_bt_params = { | |||
256 | #define IWL_DEVICE_2000 \ | 262 | #define IWL_DEVICE_2000 \ |
257 | .fw_name_pre = IWL2000_FW_PRE, \ | 263 | .fw_name_pre = IWL2000_FW_PRE, \ |
258 | .ucode_api_max = IWL2000_UCODE_API_MAX, \ | 264 | .ucode_api_max = IWL2000_UCODE_API_MAX, \ |
265 | .ucode_api_ok = IWL2000_UCODE_API_OK, \ | ||
259 | .ucode_api_min = IWL2000_UCODE_API_MIN, \ | 266 | .ucode_api_min = IWL2000_UCODE_API_MIN, \ |
260 | .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ | 267 | .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ |
261 | .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ | 268 | .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ |
@@ -280,6 +287,7 @@ struct iwl_cfg iwl2000_2bg_cfg = { | |||
280 | #define IWL_DEVICE_2030 \ | 287 | #define IWL_DEVICE_2030 \ |
281 | .fw_name_pre = IWL2030_FW_PRE, \ | 288 | .fw_name_pre = IWL2030_FW_PRE, \ |
282 | .ucode_api_max = IWL2030_UCODE_API_MAX, \ | 289 | .ucode_api_max = IWL2030_UCODE_API_MAX, \ |
290 | .ucode_api_ok = IWL2030_UCODE_API_OK, \ | ||
283 | .ucode_api_min = IWL2030_UCODE_API_MIN, \ | 291 | .ucode_api_min = IWL2030_UCODE_API_MIN, \ |
284 | .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ | 292 | .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ |
285 | .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ | 293 | .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ |
@@ -306,6 +314,7 @@ struct iwl_cfg iwl2030_2bg_cfg = { | |||
306 | #define IWL_DEVICE_105 \ | 314 | #define IWL_DEVICE_105 \ |
307 | .fw_name_pre = IWL105_FW_PRE, \ | 315 | .fw_name_pre = IWL105_FW_PRE, \ |
308 | .ucode_api_max = IWL105_UCODE_API_MAX, \ | 316 | .ucode_api_max = IWL105_UCODE_API_MAX, \ |
317 | .ucode_api_ok = IWL105_UCODE_API_OK, \ | ||
309 | .ucode_api_min = IWL105_UCODE_API_MIN, \ | 318 | .ucode_api_min = IWL105_UCODE_API_MIN, \ |
310 | .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ | 319 | .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ |
311 | .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ | 320 | .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ |
@@ -332,6 +341,7 @@ struct iwl_cfg iwl105_bgn_cfg = { | |||
332 | #define IWL_DEVICE_135 \ | 341 | #define IWL_DEVICE_135 \ |
333 | .fw_name_pre = IWL135_FW_PRE, \ | 342 | .fw_name_pre = IWL135_FW_PRE, \ |
334 | .ucode_api_max = IWL135_UCODE_API_MAX, \ | 343 | .ucode_api_max = IWL135_UCODE_API_MAX, \ |
344 | .ucode_api_ok = IWL135_UCODE_API_OK, \ | ||
335 | .ucode_api_min = IWL135_UCODE_API_MIN, \ | 345 | .ucode_api_min = IWL135_UCODE_API_MIN, \ |
336 | .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ | 346 | .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ |
337 | .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ | 347 | .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index c95cefd529dc..a9adee5634d8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c | |||
@@ -31,7 +31,6 @@ | |||
31 | #include <linux/sched.h> | 31 | #include <linux/sched.h> |
32 | #include <linux/skbuff.h> | 32 | #include <linux/skbuff.h> |
33 | #include <linux/netdevice.h> | 33 | #include <linux/netdevice.h> |
34 | #include <linux/wireless.h> | ||
35 | #include <net/mac80211.h> | 34 | #include <net/mac80211.h> |
36 | #include <linux/etherdevice.h> | 35 | #include <linux/etherdevice.h> |
37 | #include <asm/unaligned.h> | 36 | #include <asm/unaligned.h> |
@@ -84,12 +83,12 @@ static void iwl5000_nic_config(struct iwl_priv *priv) | |||
84 | } | 83 | } |
85 | 84 | ||
86 | static struct iwl_sensitivity_ranges iwl5000_sensitivity = { | 85 | static struct iwl_sensitivity_ranges iwl5000_sensitivity = { |
87 | .min_nrg_cck = 95, | 86 | .min_nrg_cck = 100, |
88 | .max_nrg_cck = 0, /* not used, set to 0 */ | 87 | .max_nrg_cck = 0, /* not used, set to 0 */ |
89 | .auto_corr_min_ofdm = 90, | 88 | .auto_corr_min_ofdm = 90, |
90 | .auto_corr_min_ofdm_mrc = 170, | 89 | .auto_corr_min_ofdm_mrc = 170, |
91 | .auto_corr_min_ofdm_x1 = 120, | 90 | .auto_corr_min_ofdm_x1 = 105, |
92 | .auto_corr_min_ofdm_mrc_x1 = 240, | 91 | .auto_corr_min_ofdm_mrc_x1 = 220, |
93 | 92 | ||
94 | .auto_corr_max_ofdm = 120, | 93 | .auto_corr_max_ofdm = 120, |
95 | .auto_corr_max_ofdm_mrc = 210, | 94 | .auto_corr_max_ofdm_mrc = 210, |
@@ -98,10 +97,10 @@ static struct iwl_sensitivity_ranges iwl5000_sensitivity = { | |||
98 | 97 | ||
99 | .auto_corr_min_cck = 125, | 98 | .auto_corr_min_cck = 125, |
100 | .auto_corr_max_cck = 200, | 99 | .auto_corr_max_cck = 200, |
101 | .auto_corr_min_cck_mrc = 170, | 100 | .auto_corr_min_cck_mrc = 200, |
102 | .auto_corr_max_cck_mrc = 400, | 101 | .auto_corr_max_cck_mrc = 400, |
103 | .nrg_th_cck = 95, | 102 | .nrg_th_cck = 100, |
104 | .nrg_th_ofdm = 95, | 103 | .nrg_th_ofdm = 100, |
105 | 104 | ||
106 | .barker_corr_th_min = 190, | 105 | .barker_corr_th_min = 190, |
107 | .barker_corr_th_min_mrc = 390, | 106 | .barker_corr_th_min_mrc = 390, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 973d1972e8cc..339de88d9ae2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c | |||
@@ -30,7 +30,6 @@ | |||
30 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
31 | #include <linux/skbuff.h> | 31 | #include <linux/skbuff.h> |
32 | #include <linux/netdevice.h> | 32 | #include <linux/netdevice.h> |
33 | #include <linux/wireless.h> | ||
34 | #include <net/mac80211.h> | 33 | #include <net/mac80211.h> |
35 | #include <linux/etherdevice.h> | 34 | #include <linux/etherdevice.h> |
36 | #include <asm/unaligned.h> | 35 | #include <asm/unaligned.h> |
@@ -50,7 +49,10 @@ | |||
50 | /* Highest firmware API version supported */ | 49 | /* Highest firmware API version supported */ |
51 | #define IWL6000_UCODE_API_MAX 4 | 50 | #define IWL6000_UCODE_API_MAX 4 |
52 | #define IWL6050_UCODE_API_MAX 5 | 51 | #define IWL6050_UCODE_API_MAX 5 |
53 | #define IWL6000G2_UCODE_API_MAX 5 | 52 | #define IWL6000G2_UCODE_API_MAX 6 |
53 | |||
54 | /* Oldest version we won't warn about */ | ||
55 | #define IWL6000G2_UCODE_API_OK 5 | ||
54 | 56 | ||
55 | /* Lowest firmware API version supported */ | 57 | /* Lowest firmware API version supported */ |
56 | #define IWL6000_UCODE_API_MIN 4 | 58 | #define IWL6000_UCODE_API_MIN 4 |
@@ -111,7 +113,7 @@ static void iwl6000_nic_config(struct iwl_priv *priv) | |||
111 | } | 113 | } |
112 | 114 | ||
113 | static struct iwl_sensitivity_ranges iwl6000_sensitivity = { | 115 | static struct iwl_sensitivity_ranges iwl6000_sensitivity = { |
114 | .min_nrg_cck = 97, | 116 | .min_nrg_cck = 110, |
115 | .max_nrg_cck = 0, /* not used, set to 0 */ | 117 | .max_nrg_cck = 0, /* not used, set to 0 */ |
116 | .auto_corr_min_ofdm = 80, | 118 | .auto_corr_min_ofdm = 80, |
117 | .auto_corr_min_ofdm_mrc = 128, | 119 | .auto_corr_min_ofdm_mrc = 128, |
@@ -127,11 +129,11 @@ static struct iwl_sensitivity_ranges iwl6000_sensitivity = { | |||
127 | .auto_corr_max_cck = 175, | 129 | .auto_corr_max_cck = 175, |
128 | .auto_corr_min_cck_mrc = 160, | 130 | .auto_corr_min_cck_mrc = 160, |
129 | .auto_corr_max_cck_mrc = 310, | 131 | .auto_corr_max_cck_mrc = 310, |
130 | .nrg_th_cck = 97, | 132 | .nrg_th_cck = 110, |
131 | .nrg_th_ofdm = 100, | 133 | .nrg_th_ofdm = 110, |
132 | 134 | ||
133 | .barker_corr_th_min = 190, | 135 | .barker_corr_th_min = 190, |
134 | .barker_corr_th_min_mrc = 390, | 136 | .barker_corr_th_min_mrc = 336, |
135 | .nrg_th_cca = 62, | 137 | .nrg_th_cca = 62, |
136 | }; | 138 | }; |
137 | 139 | ||
@@ -365,8 +367,9 @@ static struct iwl_bt_params iwl6000_bt_params = { | |||
365 | }; | 367 | }; |
366 | 368 | ||
367 | #define IWL_DEVICE_6005 \ | 369 | #define IWL_DEVICE_6005 \ |
368 | .fw_name_pre = IWL6005_FW_PRE, \ | 370 | .fw_name_pre = IWL6005_FW_PRE, \ |
369 | .ucode_api_max = IWL6000G2_UCODE_API_MAX, \ | 371 | .ucode_api_max = IWL6000G2_UCODE_API_MAX, \ |
372 | .ucode_api_ok = IWL6000G2_UCODE_API_OK, \ | ||
370 | .ucode_api_min = IWL6000G2_UCODE_API_MIN, \ | 373 | .ucode_api_min = IWL6000G2_UCODE_API_MIN, \ |
371 | .eeprom_ver = EEPROM_6005_EEPROM_VERSION, \ | 374 | .eeprom_ver = EEPROM_6005_EEPROM_VERSION, \ |
372 | .eeprom_calib_ver = EEPROM_6005_TX_POWER_VERSION, \ | 375 | .eeprom_calib_ver = EEPROM_6005_TX_POWER_VERSION, \ |
@@ -393,8 +396,9 @@ struct iwl_cfg iwl6005_2bg_cfg = { | |||
393 | }; | 396 | }; |
394 | 397 | ||
395 | #define IWL_DEVICE_6030 \ | 398 | #define IWL_DEVICE_6030 \ |
396 | .fw_name_pre = IWL6030_FW_PRE, \ | 399 | .fw_name_pre = IWL6030_FW_PRE, \ |
397 | .ucode_api_max = IWL6000G2_UCODE_API_MAX, \ | 400 | .ucode_api_max = IWL6000G2_UCODE_API_MAX, \ |
401 | .ucode_api_ok = IWL6000G2_UCODE_API_OK, \ | ||
398 | .ucode_api_min = IWL6000G2_UCODE_API_MIN, \ | 402 | .ucode_api_min = IWL6000G2_UCODE_API_MIN, \ |
399 | .eeprom_ver = EEPROM_6030_EEPROM_VERSION, \ | 403 | .eeprom_ver = EEPROM_6030_EEPROM_VERSION, \ |
400 | .eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION, \ | 404 | .eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION, \ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c index 72d6297602b8..1789e3af8101 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c | |||
@@ -505,28 +505,53 @@ static int iwl_enhance_sensitivity_write(struct iwl_priv *priv) | |||
505 | 505 | ||
506 | iwl_prepare_legacy_sensitivity_tbl(priv, data, &cmd.enhance_table[0]); | 506 | iwl_prepare_legacy_sensitivity_tbl(priv, data, &cmd.enhance_table[0]); |
507 | 507 | ||
508 | cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX] = | 508 | if (priv->cfg->base_params->hd_v2) { |
509 | HD_INA_NON_SQUARE_DET_OFDM_DATA; | 509 | cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX] = |
510 | cmd.enhance_table[HD_INA_NON_SQUARE_DET_CCK_INDEX] = | 510 | HD_INA_NON_SQUARE_DET_OFDM_DATA_V2; |
511 | HD_INA_NON_SQUARE_DET_CCK_DATA; | 511 | cmd.enhance_table[HD_INA_NON_SQUARE_DET_CCK_INDEX] = |
512 | cmd.enhance_table[HD_CORR_11_INSTEAD_OF_CORR_9_EN_INDEX] = | 512 | HD_INA_NON_SQUARE_DET_CCK_DATA_V2; |
513 | HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA; | 513 | cmd.enhance_table[HD_CORR_11_INSTEAD_OF_CORR_9_EN_INDEX] = |
514 | cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_INDEX] = | 514 | HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V2; |
515 | HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA; | 515 | cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_INDEX] = |
516 | cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] = | 516 | HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V2; |
517 | HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA; | 517 | cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] = |
518 | cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_INDEX] = | 518 | HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2; |
519 | HD_OFDM_NON_SQUARE_DET_SLOPE_DATA; | 519 | cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_INDEX] = |
520 | cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_INDEX] = | 520 | HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V2; |
521 | HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA; | 521 | cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_INDEX] = |
522 | cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_MRC_INDEX] = | 522 | HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V2; |
523 | HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA; | 523 | cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_MRC_INDEX] = |
524 | cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] = | 524 | HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V2; |
525 | HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA; | 525 | cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] = |
526 | cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_INDEX] = | 526 | HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2; |
527 | HD_CCK_NON_SQUARE_DET_SLOPE_DATA; | 527 | cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_INDEX] = |
528 | cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_INDEX] = | 528 | HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V2; |
529 | HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA; | 529 | cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_INDEX] = |
530 | HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V2; | ||
531 | } else { | ||
532 | cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX] = | ||
533 | HD_INA_NON_SQUARE_DET_OFDM_DATA_V1; | ||
534 | cmd.enhance_table[HD_INA_NON_SQUARE_DET_CCK_INDEX] = | ||
535 | HD_INA_NON_SQUARE_DET_CCK_DATA_V1; | ||
536 | cmd.enhance_table[HD_CORR_11_INSTEAD_OF_CORR_9_EN_INDEX] = | ||
537 | HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V1; | ||
538 | cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_INDEX] = | ||
539 | HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V1; | ||
540 | cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] = | ||
541 | HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1; | ||
542 | cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_INDEX] = | ||
543 | HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V1; | ||
544 | cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_INDEX] = | ||
545 | HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V1; | ||
546 | cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_MRC_INDEX] = | ||
547 | HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V1; | ||
548 | cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] = | ||
549 | HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1; | ||
550 | cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_INDEX] = | ||
551 | HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V1; | ||
552 | cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_INDEX] = | ||
553 | HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V1; | ||
554 | } | ||
530 | 555 | ||
531 | /* Update uCode's "work" table, and copy it to DSP */ | 556 | /* Update uCode's "work" table, and copy it to DSP */ |
532 | cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE; | 557 | cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h index 0e5b842529c4..47c43042ba4f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h | |||
@@ -92,8 +92,8 @@ | |||
92 | 92 | ||
93 | #define IWLAGN_CMD_FIFO_NUM 7 | 93 | #define IWLAGN_CMD_FIFO_NUM 7 |
94 | #define IWLAGN_NUM_QUEUES 20 | 94 | #define IWLAGN_NUM_QUEUES 20 |
95 | #define IWLAGN_NUM_AMPDU_QUEUES 10 | 95 | #define IWLAGN_NUM_AMPDU_QUEUES 9 |
96 | #define IWLAGN_FIRST_AMPDU_QUEUE 10 | 96 | #define IWLAGN_FIRST_AMPDU_QUEUE 11 |
97 | 97 | ||
98 | /* Fixed (non-configurable) rx data from phy */ | 98 | /* Fixed (non-configurable) rx data from phy */ |
99 | 99 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 3bee0f119bcd..4edb6cfc5488 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c | |||
@@ -753,18 +753,6 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, | |||
753 | return added; | 753 | return added; |
754 | } | 754 | } |
755 | 755 | ||
756 | static int iwl_fill_offch_tx(struct iwl_priv *priv, void *data, size_t maxlen) | ||
757 | { | ||
758 | struct sk_buff *skb = priv->offchan_tx_skb; | ||
759 | |||
760 | if (skb->len < maxlen) | ||
761 | maxlen = skb->len; | ||
762 | |||
763 | memcpy(data, skb->data, maxlen); | ||
764 | |||
765 | return maxlen; | ||
766 | } | ||
767 | |||
768 | int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) | 756 | int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) |
769 | { | 757 | { |
770 | struct iwl_host_cmd cmd = { | 758 | struct iwl_host_cmd cmd = { |
@@ -807,7 +795,7 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) | |||
807 | scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH; | 795 | scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH; |
808 | scan->quiet_time = IWL_ACTIVE_QUIET_TIME; | 796 | scan->quiet_time = IWL_ACTIVE_QUIET_TIME; |
809 | 797 | ||
810 | if (priv->scan_type != IWL_SCAN_OFFCH_TX && | 798 | if (priv->scan_type != IWL_SCAN_ROC && |
811 | iwl_is_any_associated(priv)) { | 799 | iwl_is_any_associated(priv)) { |
812 | u16 interval = 0; | 800 | u16 interval = 0; |
813 | u32 extra; | 801 | u32 extra; |
@@ -816,7 +804,7 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) | |||
816 | 804 | ||
817 | IWL_DEBUG_INFO(priv, "Scanning while associated...\n"); | 805 | IWL_DEBUG_INFO(priv, "Scanning while associated...\n"); |
818 | switch (priv->scan_type) { | 806 | switch (priv->scan_type) { |
819 | case IWL_SCAN_OFFCH_TX: | 807 | case IWL_SCAN_ROC: |
820 | WARN_ON(1); | 808 | WARN_ON(1); |
821 | break; | 809 | break; |
822 | case IWL_SCAN_RADIO_RESET: | 810 | case IWL_SCAN_RADIO_RESET: |
@@ -838,10 +826,11 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) | |||
838 | scan->suspend_time = cpu_to_le32(scan_suspend_time); | 826 | scan->suspend_time = cpu_to_le32(scan_suspend_time); |
839 | IWL_DEBUG_SCAN(priv, "suspend_time 0x%X beacon interval %d\n", | 827 | IWL_DEBUG_SCAN(priv, "suspend_time 0x%X beacon interval %d\n", |
840 | scan_suspend_time, interval); | 828 | scan_suspend_time, interval); |
841 | } else if (priv->scan_type == IWL_SCAN_OFFCH_TX) { | 829 | } else if (priv->scan_type == IWL_SCAN_ROC) { |
842 | scan->suspend_time = 0; | 830 | scan->suspend_time = 0; |
843 | scan->max_out_time = | 831 | scan->max_out_time = 0; |
844 | cpu_to_le32(1024 * priv->offchan_tx_timeout); | 832 | scan->quiet_time = 0; |
833 | scan->quiet_plcp_th = 0; | ||
845 | } | 834 | } |
846 | 835 | ||
847 | switch (priv->scan_type) { | 836 | switch (priv->scan_type) { |
@@ -869,8 +858,8 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) | |||
869 | } else | 858 | } else |
870 | IWL_DEBUG_SCAN(priv, "Start passive scan.\n"); | 859 | IWL_DEBUG_SCAN(priv, "Start passive scan.\n"); |
871 | break; | 860 | break; |
872 | case IWL_SCAN_OFFCH_TX: | 861 | case IWL_SCAN_ROC: |
873 | IWL_DEBUG_SCAN(priv, "Start offchannel TX scan.\n"); | 862 | IWL_DEBUG_SCAN(priv, "Start ROC scan.\n"); |
874 | break; | 863 | break; |
875 | } | 864 | } |
876 | 865 | ||
@@ -988,19 +977,13 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) | |||
988 | IWL_MAX_SCAN_SIZE - sizeof(*scan)); | 977 | IWL_MAX_SCAN_SIZE - sizeof(*scan)); |
989 | break; | 978 | break; |
990 | case IWL_SCAN_RADIO_RESET: | 979 | case IWL_SCAN_RADIO_RESET: |
980 | case IWL_SCAN_ROC: | ||
991 | /* use bcast addr, will not be transmitted but must be valid */ | 981 | /* use bcast addr, will not be transmitted but must be valid */ |
992 | cmd_len = iwl_fill_probe_req(priv, | 982 | cmd_len = iwl_fill_probe_req(priv, |
993 | (struct ieee80211_mgmt *)scan->data, | 983 | (struct ieee80211_mgmt *)scan->data, |
994 | iwl_bcast_addr, NULL, 0, | 984 | iwl_bcast_addr, NULL, 0, |
995 | IWL_MAX_SCAN_SIZE - sizeof(*scan)); | 985 | IWL_MAX_SCAN_SIZE - sizeof(*scan)); |
996 | break; | 986 | break; |
997 | case IWL_SCAN_OFFCH_TX: | ||
998 | cmd_len = iwl_fill_offch_tx(priv, scan->data, | ||
999 | IWL_MAX_SCAN_SIZE | ||
1000 | - sizeof(*scan) | ||
1001 | - sizeof(struct iwl_scan_channel)); | ||
1002 | scan->scan_flags |= IWL_SCAN_FLAGS_ACTION_FRAME_TX; | ||
1003 | break; | ||
1004 | default: | 987 | default: |
1005 | BUG(); | 988 | BUG(); |
1006 | } | 989 | } |
@@ -1021,18 +1004,18 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) | |||
1021 | is_active, n_probes, | 1004 | is_active, n_probes, |
1022 | (void *)&scan->data[cmd_len]); | 1005 | (void *)&scan->data[cmd_len]); |
1023 | break; | 1006 | break; |
1024 | case IWL_SCAN_OFFCH_TX: { | 1007 | case IWL_SCAN_ROC: { |
1025 | struct iwl_scan_channel *scan_ch; | 1008 | struct iwl_scan_channel *scan_ch; |
1026 | 1009 | ||
1027 | scan->channel_count = 1; | 1010 | scan->channel_count = 1; |
1028 | 1011 | ||
1029 | scan_ch = (void *)&scan->data[cmd_len]; | 1012 | scan_ch = (void *)&scan->data[cmd_len]; |
1030 | scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE; | 1013 | scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE; |
1031 | scan_ch->channel = | 1014 | scan_ch->channel = |
1032 | cpu_to_le16(priv->offchan_tx_chan->hw_value); | 1015 | cpu_to_le16(priv->hw_roc_channel->hw_value); |
1033 | scan_ch->active_dwell = | 1016 | scan_ch->active_dwell = |
1034 | cpu_to_le16(priv->offchan_tx_timeout); | 1017 | scan_ch->passive_dwell = |
1035 | scan_ch->passive_dwell = 0; | 1018 | cpu_to_le16(priv->hw_roc_duration); |
1036 | 1019 | ||
1037 | /* Set txpower levels to defaults */ | 1020 | /* Set txpower levels to defaults */ |
1038 | scan_ch->dsp_atten = 110; | 1021 | scan_ch->dsp_atten = 110; |
@@ -1041,7 +1024,7 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) | |||
1041 | * power level: | 1024 | * power level: |
1042 | * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3; | 1025 | * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3; |
1043 | */ | 1026 | */ |
1044 | if (priv->offchan_tx_chan->band == IEEE80211_BAND_5GHZ) | 1027 | if (priv->hw_roc_channel->band == IEEE80211_BAND_5GHZ) |
1045 | scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3; | 1028 | scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3; |
1046 | else | 1029 | else |
1047 | scan_ch->tx_gain = ((1 << 5) | (5 << 3)); | 1030 | scan_ch->tx_gain = ((1 << 5) | (5 << 3)); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 3789ff4bf53b..1fa438e20f0a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c | |||
@@ -27,7 +27,6 @@ | |||
27 | #include <linux/init.h> | 27 | #include <linux/init.h> |
28 | #include <linux/skbuff.h> | 28 | #include <linux/skbuff.h> |
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <linux/wireless.h> | ||
31 | #include <net/mac80211.h> | 30 | #include <net/mac80211.h> |
32 | 31 | ||
33 | #include <linux/netdevice.h> | 32 | #include <linux/netdevice.h> |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index d42ef1763a71..d562e9359d97 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | |||
@@ -337,10 +337,10 @@ int iwlagn_set_pan_params(struct iwl_priv *priv) | |||
337 | cmd.slots[0].type = 0; /* BSS */ | 337 | cmd.slots[0].type = 0; /* BSS */ |
338 | cmd.slots[1].type = 1; /* PAN */ | 338 | cmd.slots[1].type = 1; /* PAN */ |
339 | 339 | ||
340 | if (priv->hw_roc_channel) { | 340 | if (priv->hw_roc_setup) { |
341 | /* both contexts must be used for this to happen */ | 341 | /* both contexts must be used for this to happen */ |
342 | slot1 = priv->hw_roc_duration; | 342 | slot1 = IWL_MIN_SLOT_TIME; |
343 | slot0 = IWL_MIN_SLOT_TIME; | 343 | slot0 = 3000; |
344 | } else if (ctx_bss->vif && ctx_pan->vif) { | 344 | } else if (ctx_bss->vif && ctx_pan->vif) { |
345 | int bcnint = ctx_pan->beacon_int; | 345 | int bcnint = ctx_pan->beacon_int; |
346 | int dtim = ctx_pan->vif->bss_conf.dtim_period ?: 1; | 346 | int dtim = ctx_pan->vif->bss_conf.dtim_period ?: 1; |
@@ -437,23 +437,6 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) | |||
437 | /* always get timestamp with Rx frame */ | 437 | /* always get timestamp with Rx frame */ |
438 | ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK; | 438 | ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK; |
439 | 439 | ||
440 | if (ctx->ctxid == IWL_RXON_CTX_PAN && priv->hw_roc_channel) { | ||
441 | struct ieee80211_channel *chan = priv->hw_roc_channel; | ||
442 | |||
443 | iwl_set_rxon_channel(priv, chan, ctx); | ||
444 | iwl_set_flags_for_band(priv, ctx, chan->band, NULL); | ||
445 | ctx->staging.filter_flags |= | ||
446 | RXON_FILTER_ASSOC_MSK | | ||
447 | RXON_FILTER_PROMISC_MSK | | ||
448 | RXON_FILTER_CTL2HOST_MSK; | ||
449 | ctx->staging.dev_type = RXON_DEV_TYPE_P2P; | ||
450 | new_assoc = true; | ||
451 | |||
452 | if (memcmp(&ctx->staging, &ctx->active, | ||
453 | sizeof(ctx->staging)) == 0) | ||
454 | return 0; | ||
455 | } | ||
456 | |||
457 | /* | 440 | /* |
458 | * force CTS-to-self frames protection if RTS-CTS is not preferred | 441 | * force CTS-to-self frames protection if RTS-CTS is not preferred |
459 | * one aggregation protection method | 442 | * one aggregation protection method |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 53bb59ee719d..9bc26da62768 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c | |||
@@ -128,11 +128,10 @@ static void iwlagn_tx_cmd_protection(struct iwl_priv *priv, | |||
128 | * handle build REPLY_TX command notification. | 128 | * handle build REPLY_TX command notification. |
129 | */ | 129 | */ |
130 | static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv, | 130 | static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv, |
131 | struct sk_buff *skb, | 131 | struct sk_buff *skb, |
132 | struct iwl_tx_cmd *tx_cmd, | 132 | struct iwl_tx_cmd *tx_cmd, |
133 | struct ieee80211_tx_info *info, | 133 | struct ieee80211_tx_info *info, |
134 | struct ieee80211_hdr *hdr, | 134 | struct ieee80211_hdr *hdr, u8 sta_id) |
135 | u8 std_id) | ||
136 | { | 135 | { |
137 | __le16 fc = hdr->frame_control; | 136 | __le16 fc = hdr->frame_control; |
138 | __le32 tx_flags = tx_cmd->tx_flags; | 137 | __le32 tx_flags = tx_cmd->tx_flags; |
@@ -157,7 +156,7 @@ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv, | |||
157 | tx_flags |= TX_CMD_FLG_IGNORE_BT; | 156 | tx_flags |= TX_CMD_FLG_IGNORE_BT; |
158 | 157 | ||
159 | 158 | ||
160 | tx_cmd->sta_id = std_id; | 159 | tx_cmd->sta_id = sta_id; |
161 | if (ieee80211_has_morefrags(fc)) | 160 | if (ieee80211_has_morefrags(fc)) |
162 | tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK; | 161 | tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK; |
163 | 162 | ||
@@ -189,9 +188,9 @@ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv, | |||
189 | #define RTS_DFAULT_RETRY_LIMIT 60 | 188 | #define RTS_DFAULT_RETRY_LIMIT 60 |
190 | 189 | ||
191 | static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv, | 190 | static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv, |
192 | struct iwl_tx_cmd *tx_cmd, | 191 | struct iwl_tx_cmd *tx_cmd, |
193 | struct ieee80211_tx_info *info, | 192 | struct ieee80211_tx_info *info, |
194 | __le16 fc) | 193 | __le16 fc) |
195 | { | 194 | { |
196 | u32 rate_flags; | 195 | u32 rate_flags; |
197 | int rate_idx; | 196 | int rate_idx; |
@@ -334,14 +333,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
334 | unsigned long flags; | 333 | unsigned long flags; |
335 | bool is_agg = false; | 334 | bool is_agg = false; |
336 | 335 | ||
337 | /* | 336 | if (info->control.vif) |
338 | * If the frame needs to go out off-channel, then | ||
339 | * we'll have put the PAN context to that channel, | ||
340 | * so make the frame go out there. | ||
341 | */ | ||
342 | if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) | ||
343 | ctx = &priv->contexts[IWL_RXON_CTX_PAN]; | ||
344 | else if (info->control.vif) | ||
345 | ctx = iwl_rxon_ctx_from_vif(info->control.vif); | 337 | ctx = iwl_rxon_ctx_from_vif(info->control.vif); |
346 | 338 | ||
347 | spin_lock_irqsave(&priv->lock, flags); | 339 | spin_lock_irqsave(&priv->lock, flags); |
@@ -407,7 +399,9 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
407 | */ | 399 | */ |
408 | hdr->frame_control |= | 400 | hdr->frame_control |= |
409 | cpu_to_le16(IEEE80211_FCTL_MOREDATA); | 401 | cpu_to_le16(IEEE80211_FCTL_MOREDATA); |
410 | } else | 402 | } else if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) |
403 | txq_id = IWL_AUX_QUEUE; | ||
404 | else | ||
411 | txq_id = ctx->ac_to_queue[skb_get_queue_mapping(skb)]; | 405 | txq_id = ctx->ac_to_queue[skb_get_queue_mapping(skb)]; |
412 | 406 | ||
413 | /* irqs already disabled/saved above when locking priv->lock */ | 407 | /* irqs already disabled/saved above when locking priv->lock */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index b0ae4de7f083..33894dde1ae3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -35,7 +35,6 @@ | |||
35 | #include <linux/sched.h> | 35 | #include <linux/sched.h> |
36 | #include <linux/skbuff.h> | 36 | #include <linux/skbuff.h> |
37 | #include <linux/netdevice.h> | 37 | #include <linux/netdevice.h> |
38 | #include <linux/wireless.h> | ||
39 | #include <linux/firmware.h> | 38 | #include <linux/firmware.h> |
40 | #include <linux/etherdevice.h> | 39 | #include <linux/etherdevice.h> |
41 | #include <linux/if_arp.h> | 40 | #include <linux/if_arp.h> |
@@ -614,6 +613,87 @@ static int iwl_alloc_fw_desc(struct iwl_priv *priv, struct fw_desc *desc, | |||
614 | return 0; | 613 | return 0; |
615 | } | 614 | } |
616 | 615 | ||
616 | static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags) | ||
617 | { | ||
618 | static const u8 iwlagn_bss_ac_to_fifo[] = { | ||
619 | IWL_TX_FIFO_VO, | ||
620 | IWL_TX_FIFO_VI, | ||
621 | IWL_TX_FIFO_BE, | ||
622 | IWL_TX_FIFO_BK, | ||
623 | }; | ||
624 | static const u8 iwlagn_bss_ac_to_queue[] = { | ||
625 | 0, 1, 2, 3, | ||
626 | }; | ||
627 | static const u8 iwlagn_pan_ac_to_fifo[] = { | ||
628 | IWL_TX_FIFO_VO_IPAN, | ||
629 | IWL_TX_FIFO_VI_IPAN, | ||
630 | IWL_TX_FIFO_BE_IPAN, | ||
631 | IWL_TX_FIFO_BK_IPAN, | ||
632 | }; | ||
633 | static const u8 iwlagn_pan_ac_to_queue[] = { | ||
634 | 7, 6, 5, 4, | ||
635 | }; | ||
636 | int i; | ||
637 | |||
638 | /* | ||
639 | * The default context is always valid, | ||
640 | * the PAN context depends on uCode. | ||
641 | */ | ||
642 | priv->valid_contexts = BIT(IWL_RXON_CTX_BSS); | ||
643 | if (ucode_flags & IWL_UCODE_TLV_FLAGS_PAN) | ||
644 | priv->valid_contexts |= BIT(IWL_RXON_CTX_PAN); | ||
645 | |||
646 | for (i = 0; i < NUM_IWL_RXON_CTX; i++) | ||
647 | priv->contexts[i].ctxid = i; | ||
648 | |||
649 | priv->contexts[IWL_RXON_CTX_BSS].always_active = true; | ||
650 | priv->contexts[IWL_RXON_CTX_BSS].is_active = true; | ||
651 | priv->contexts[IWL_RXON_CTX_BSS].rxon_cmd = REPLY_RXON; | ||
652 | priv->contexts[IWL_RXON_CTX_BSS].rxon_timing_cmd = REPLY_RXON_TIMING; | ||
653 | priv->contexts[IWL_RXON_CTX_BSS].rxon_assoc_cmd = REPLY_RXON_ASSOC; | ||
654 | priv->contexts[IWL_RXON_CTX_BSS].qos_cmd = REPLY_QOS_PARAM; | ||
655 | priv->contexts[IWL_RXON_CTX_BSS].ap_sta_id = IWL_AP_ID; | ||
656 | priv->contexts[IWL_RXON_CTX_BSS].wep_key_cmd = REPLY_WEPKEY; | ||
657 | priv->contexts[IWL_RXON_CTX_BSS].ac_to_fifo = iwlagn_bss_ac_to_fifo; | ||
658 | priv->contexts[IWL_RXON_CTX_BSS].ac_to_queue = iwlagn_bss_ac_to_queue; | ||
659 | priv->contexts[IWL_RXON_CTX_BSS].exclusive_interface_modes = | ||
660 | BIT(NL80211_IFTYPE_ADHOC); | ||
661 | priv->contexts[IWL_RXON_CTX_BSS].interface_modes = | ||
662 | BIT(NL80211_IFTYPE_STATION); | ||
663 | priv->contexts[IWL_RXON_CTX_BSS].ap_devtype = RXON_DEV_TYPE_AP; | ||
664 | priv->contexts[IWL_RXON_CTX_BSS].ibss_devtype = RXON_DEV_TYPE_IBSS; | ||
665 | priv->contexts[IWL_RXON_CTX_BSS].station_devtype = RXON_DEV_TYPE_ESS; | ||
666 | priv->contexts[IWL_RXON_CTX_BSS].unused_devtype = RXON_DEV_TYPE_ESS; | ||
667 | |||
668 | priv->contexts[IWL_RXON_CTX_PAN].rxon_cmd = REPLY_WIPAN_RXON; | ||
669 | priv->contexts[IWL_RXON_CTX_PAN].rxon_timing_cmd = | ||
670 | REPLY_WIPAN_RXON_TIMING; | ||
671 | priv->contexts[IWL_RXON_CTX_PAN].rxon_assoc_cmd = | ||
672 | REPLY_WIPAN_RXON_ASSOC; | ||
673 | priv->contexts[IWL_RXON_CTX_PAN].qos_cmd = REPLY_WIPAN_QOS_PARAM; | ||
674 | priv->contexts[IWL_RXON_CTX_PAN].ap_sta_id = IWL_AP_ID_PAN; | ||
675 | priv->contexts[IWL_RXON_CTX_PAN].wep_key_cmd = REPLY_WIPAN_WEPKEY; | ||
676 | priv->contexts[IWL_RXON_CTX_PAN].bcast_sta_id = IWLAGN_PAN_BCAST_ID; | ||
677 | priv->contexts[IWL_RXON_CTX_PAN].station_flags = STA_FLG_PAN_STATION; | ||
678 | priv->contexts[IWL_RXON_CTX_PAN].ac_to_fifo = iwlagn_pan_ac_to_fifo; | ||
679 | priv->contexts[IWL_RXON_CTX_PAN].ac_to_queue = iwlagn_pan_ac_to_queue; | ||
680 | priv->contexts[IWL_RXON_CTX_PAN].mcast_queue = IWL_IPAN_MCAST_QUEUE; | ||
681 | priv->contexts[IWL_RXON_CTX_PAN].interface_modes = | ||
682 | BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP); | ||
683 | |||
684 | if (ucode_flags & IWL_UCODE_TLV_FLAGS_P2P) | ||
685 | priv->contexts[IWL_RXON_CTX_PAN].interface_modes |= | ||
686 | BIT(NL80211_IFTYPE_P2P_CLIENT) | | ||
687 | BIT(NL80211_IFTYPE_P2P_GO); | ||
688 | |||
689 | priv->contexts[IWL_RXON_CTX_PAN].ap_devtype = RXON_DEV_TYPE_CP; | ||
690 | priv->contexts[IWL_RXON_CTX_PAN].station_devtype = RXON_DEV_TYPE_2STA; | ||
691 | priv->contexts[IWL_RXON_CTX_PAN].unused_devtype = RXON_DEV_TYPE_P2P; | ||
692 | |||
693 | BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2); | ||
694 | } | ||
695 | |||
696 | |||
617 | struct iwlagn_ucode_capabilities { | 697 | struct iwlagn_ucode_capabilities { |
618 | u32 max_probe_length; | 698 | u32 max_probe_length; |
619 | u32 standard_phy_calibration_size; | 699 | u32 standard_phy_calibration_size; |
@@ -952,6 +1032,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | |||
952 | int err; | 1032 | int err; |
953 | struct iwlagn_firmware_pieces pieces; | 1033 | struct iwlagn_firmware_pieces pieces; |
954 | const unsigned int api_max = priv->cfg->ucode_api_max; | 1034 | const unsigned int api_max = priv->cfg->ucode_api_max; |
1035 | unsigned int api_ok = priv->cfg->ucode_api_ok; | ||
955 | const unsigned int api_min = priv->cfg->ucode_api_min; | 1036 | const unsigned int api_min = priv->cfg->ucode_api_min; |
956 | u32 api_ver; | 1037 | u32 api_ver; |
957 | char buildstr[25]; | 1038 | char buildstr[25]; |
@@ -962,10 +1043,13 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | |||
962 | IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE, | 1043 | IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE, |
963 | }; | 1044 | }; |
964 | 1045 | ||
1046 | if (!api_ok) | ||
1047 | api_ok = api_max; | ||
1048 | |||
965 | memset(&pieces, 0, sizeof(pieces)); | 1049 | memset(&pieces, 0, sizeof(pieces)); |
966 | 1050 | ||
967 | if (!ucode_raw) { | 1051 | if (!ucode_raw) { |
968 | if (priv->fw_index <= priv->cfg->ucode_api_max) | 1052 | if (priv->fw_index <= api_ok) |
969 | IWL_ERR(priv, | 1053 | IWL_ERR(priv, |
970 | "request for firmware file '%s' failed.\n", | 1054 | "request for firmware file '%s' failed.\n", |
971 | priv->firmware_name); | 1055 | priv->firmware_name); |
@@ -1011,12 +1095,18 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | |||
1011 | goto try_again; | 1095 | goto try_again; |
1012 | } | 1096 | } |
1013 | 1097 | ||
1014 | if (api_ver != api_max) | 1098 | if (api_ver < api_ok) { |
1015 | IWL_ERR(priv, | 1099 | if (api_ok != api_max) |
1016 | "Firmware has old API version. Expected v%u, " | 1100 | IWL_ERR(priv, "Firmware has old API version, " |
1017 | "got v%u. New firmware can be obtained " | 1101 | "expected v%u through v%u, got v%u.\n", |
1018 | "from http://www.intellinuxwireless.org.\n", | 1102 | api_ok, api_max, api_ver); |
1019 | api_max, api_ver); | 1103 | else |
1104 | IWL_ERR(priv, "Firmware has old API version, " | ||
1105 | "expected v%u, got v%u.\n", | ||
1106 | api_max, api_ver); | ||
1107 | IWL_ERR(priv, "New firmware can be obtained from " | ||
1108 | "http://www.intellinuxwireless.org/.\n"); | ||
1109 | } | ||
1020 | } | 1110 | } |
1021 | 1111 | ||
1022 | if (build) | 1112 | if (build) |
@@ -1143,17 +1233,23 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | |||
1143 | priv->new_scan_threshold_behaviour = | 1233 | priv->new_scan_threshold_behaviour = |
1144 | !!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWSCAN); | 1234 | !!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWSCAN); |
1145 | 1235 | ||
1146 | if ((priv->cfg->sku & EEPROM_SKU_CAP_IPAN_ENABLE) && | 1236 | if (!(priv->cfg->sku & EEPROM_SKU_CAP_IPAN_ENABLE)) |
1147 | (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN)) { | 1237 | ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_PAN; |
1148 | priv->valid_contexts |= BIT(IWL_RXON_CTX_PAN); | ||
1149 | priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN; | ||
1150 | } else | ||
1151 | priv->sta_key_max_num = STA_KEY_MAX_NUM; | ||
1152 | 1238 | ||
1153 | if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS)) | 1239 | /* |
1240 | * if not PAN, then don't support P2P -- might be a uCode | ||
1241 | * packaging bug or due to the eeprom check above | ||
1242 | */ | ||
1243 | if (!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN)) | ||
1244 | ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_P2P; | ||
1245 | |||
1246 | if (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN) { | ||
1247 | priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN; | ||
1154 | priv->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM; | 1248 | priv->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM; |
1155 | else | 1249 | } else { |
1250 | priv->sta_key_max_num = STA_KEY_MAX_NUM; | ||
1156 | priv->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; | 1251 | priv->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; |
1252 | } | ||
1157 | 1253 | ||
1158 | /* | 1254 | /* |
1159 | * figure out the offset of chain noise reset and gain commands | 1255 | * figure out the offset of chain noise reset and gain commands |
@@ -1169,6 +1265,9 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | |||
1169 | priv->phy_calib_chain_noise_gain_cmd = | 1265 | priv->phy_calib_chain_noise_gain_cmd = |
1170 | ucode_capa.standard_phy_calibration_size + 1; | 1266 | ucode_capa.standard_phy_calibration_size + 1; |
1171 | 1267 | ||
1268 | /* initialize all valid contexts */ | ||
1269 | iwl_init_context(priv, ucode_capa.flags); | ||
1270 | |||
1172 | /************************************************** | 1271 | /************************************************** |
1173 | * This is still part of probe() in a sense... | 1272 | * This is still part of probe() in a sense... |
1174 | * | 1273 | * |
@@ -1765,6 +1864,13 @@ static void __iwl_down(struct iwl_priv *priv) | |||
1765 | 1864 | ||
1766 | iwl_scan_cancel_timeout(priv, 200); | 1865 | iwl_scan_cancel_timeout(priv, 200); |
1767 | 1866 | ||
1867 | /* | ||
1868 | * If active, scanning won't cancel it, so say it expired. | ||
1869 | * No race since we hold the mutex here and a new one | ||
1870 | * can't come in at this time. | ||
1871 | */ | ||
1872 | ieee80211_remain_on_channel_expired(priv->hw); | ||
1873 | |||
1768 | exit_pending = test_and_set_bit(STATUS_EXIT_PENDING, &priv->status); | 1874 | exit_pending = test_and_set_bit(STATUS_EXIT_PENDING, &priv->status); |
1769 | 1875 | ||
1770 | /* Stop TX queues watchdog. We need to have STATUS_EXIT_PENDING bit set | 1876 | /* Stop TX queues watchdog. We need to have STATUS_EXIT_PENDING bit set |
@@ -1955,94 +2061,6 @@ static void iwl_bg_restart(struct work_struct *data) | |||
1955 | } | 2061 | } |
1956 | } | 2062 | } |
1957 | 2063 | ||
1958 | static int iwl_mac_offchannel_tx(struct ieee80211_hw *hw, struct sk_buff *skb, | ||
1959 | struct ieee80211_channel *chan, | ||
1960 | enum nl80211_channel_type channel_type, | ||
1961 | unsigned int wait) | ||
1962 | { | ||
1963 | struct iwl_priv *priv = hw->priv; | ||
1964 | int ret; | ||
1965 | |||
1966 | /* Not supported if we don't have PAN */ | ||
1967 | if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN))) { | ||
1968 | ret = -EOPNOTSUPP; | ||
1969 | goto free; | ||
1970 | } | ||
1971 | |||
1972 | /* Not supported on pre-P2P firmware */ | ||
1973 | if (!(priv->contexts[IWL_RXON_CTX_PAN].interface_modes & | ||
1974 | BIT(NL80211_IFTYPE_P2P_CLIENT))) { | ||
1975 | ret = -EOPNOTSUPP; | ||
1976 | goto free; | ||
1977 | } | ||
1978 | |||
1979 | mutex_lock(&priv->mutex); | ||
1980 | |||
1981 | if (!priv->contexts[IWL_RXON_CTX_PAN].is_active) { | ||
1982 | /* | ||
1983 | * If the PAN context is free, use the normal | ||
1984 | * way of doing remain-on-channel offload + TX. | ||
1985 | */ | ||
1986 | ret = 1; | ||
1987 | goto out; | ||
1988 | } | ||
1989 | |||
1990 | /* TODO: queue up if scanning? */ | ||
1991 | if (test_bit(STATUS_SCANNING, &priv->status) || | ||
1992 | priv->offchan_tx_skb) { | ||
1993 | ret = -EBUSY; | ||
1994 | goto out; | ||
1995 | } | ||
1996 | |||
1997 | /* | ||
1998 | * max_scan_ie_len doesn't include the blank SSID or the header, | ||
1999 | * so need to add that again here. | ||
2000 | */ | ||
2001 | if (skb->len > hw->wiphy->max_scan_ie_len + 24 + 2) { | ||
2002 | ret = -ENOBUFS; | ||
2003 | goto out; | ||
2004 | } | ||
2005 | |||
2006 | priv->offchan_tx_skb = skb; | ||
2007 | priv->offchan_tx_timeout = wait; | ||
2008 | priv->offchan_tx_chan = chan; | ||
2009 | |||
2010 | ret = iwl_scan_initiate(priv, priv->contexts[IWL_RXON_CTX_PAN].vif, | ||
2011 | IWL_SCAN_OFFCH_TX, chan->band); | ||
2012 | if (ret) | ||
2013 | priv->offchan_tx_skb = NULL; | ||
2014 | out: | ||
2015 | mutex_unlock(&priv->mutex); | ||
2016 | free: | ||
2017 | if (ret < 0) | ||
2018 | kfree_skb(skb); | ||
2019 | |||
2020 | return ret; | ||
2021 | } | ||
2022 | |||
2023 | static int iwl_mac_offchannel_tx_cancel_wait(struct ieee80211_hw *hw) | ||
2024 | { | ||
2025 | struct iwl_priv *priv = hw->priv; | ||
2026 | int ret; | ||
2027 | |||
2028 | mutex_lock(&priv->mutex); | ||
2029 | |||
2030 | if (!priv->offchan_tx_skb) { | ||
2031 | ret = -EINVAL; | ||
2032 | goto unlock; | ||
2033 | } | ||
2034 | |||
2035 | priv->offchan_tx_skb = NULL; | ||
2036 | |||
2037 | ret = iwl_scan_cancel_timeout(priv, 200); | ||
2038 | if (ret) | ||
2039 | ret = -EIO; | ||
2040 | unlock: | ||
2041 | mutex_unlock(&priv->mutex); | ||
2042 | |||
2043 | return ret; | ||
2044 | } | ||
2045 | |||
2046 | /***************************************************************************** | 2064 | /***************************************************************************** |
2047 | * | 2065 | * |
2048 | * mac80211 entry point functions | 2066 | * mac80211 entry point functions |
@@ -3198,35 +3216,34 @@ done: | |||
3198 | IWL_DEBUG_MAC80211(priv, "leave\n"); | 3216 | IWL_DEBUG_MAC80211(priv, "leave\n"); |
3199 | } | 3217 | } |
3200 | 3218 | ||
3201 | static void iwlagn_disable_roc(struct iwl_priv *priv) | 3219 | void iwlagn_disable_roc(struct iwl_priv *priv) |
3202 | { | 3220 | { |
3203 | struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN]; | 3221 | struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN]; |
3204 | struct ieee80211_channel *chan = ACCESS_ONCE(priv->hw->conf.channel); | ||
3205 | 3222 | ||
3206 | lockdep_assert_held(&priv->mutex); | 3223 | lockdep_assert_held(&priv->mutex); |
3207 | 3224 | ||
3208 | if (!ctx->is_active) | 3225 | if (!priv->hw_roc_setup) |
3209 | return; | 3226 | return; |
3210 | 3227 | ||
3211 | ctx->staging.dev_type = RXON_DEV_TYPE_2STA; | 3228 | ctx->staging.dev_type = RXON_DEV_TYPE_P2P; |
3212 | ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; | 3229 | ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; |
3213 | iwl_set_rxon_channel(priv, chan, ctx); | ||
3214 | iwl_set_flags_for_band(priv, ctx, chan->band, NULL); | ||
3215 | 3230 | ||
3216 | priv->hw_roc_channel = NULL; | 3231 | priv->hw_roc_channel = NULL; |
3217 | 3232 | ||
3233 | memset(ctx->staging.node_addr, 0, ETH_ALEN); | ||
3234 | |||
3218 | iwlagn_commit_rxon(priv, ctx); | 3235 | iwlagn_commit_rxon(priv, ctx); |
3219 | 3236 | ||
3220 | ctx->is_active = false; | 3237 | ctx->is_active = false; |
3238 | priv->hw_roc_setup = false; | ||
3221 | } | 3239 | } |
3222 | 3240 | ||
3223 | static void iwlagn_bg_roc_done(struct work_struct *work) | 3241 | static void iwlagn_disable_roc_work(struct work_struct *work) |
3224 | { | 3242 | { |
3225 | struct iwl_priv *priv = container_of(work, struct iwl_priv, | 3243 | struct iwl_priv *priv = container_of(work, struct iwl_priv, |
3226 | hw_roc_work.work); | 3244 | hw_roc_disable_work.work); |
3227 | 3245 | ||
3228 | mutex_lock(&priv->mutex); | 3246 | mutex_lock(&priv->mutex); |
3229 | ieee80211_remain_on_channel_expired(priv->hw); | ||
3230 | iwlagn_disable_roc(priv); | 3247 | iwlagn_disable_roc(priv); |
3231 | mutex_unlock(&priv->mutex); | 3248 | mutex_unlock(&priv->mutex); |
3232 | } | 3249 | } |
@@ -3237,33 +3254,63 @@ static int iwl_mac_remain_on_channel(struct ieee80211_hw *hw, | |||
3237 | int duration) | 3254 | int duration) |
3238 | { | 3255 | { |
3239 | struct iwl_priv *priv = hw->priv; | 3256 | struct iwl_priv *priv = hw->priv; |
3257 | struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN]; | ||
3240 | int err = 0; | 3258 | int err = 0; |
3241 | 3259 | ||
3242 | if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN))) | 3260 | if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN))) |
3243 | return -EOPNOTSUPP; | 3261 | return -EOPNOTSUPP; |
3244 | 3262 | ||
3245 | if (!(priv->contexts[IWL_RXON_CTX_PAN].interface_modes & | 3263 | if (!(ctx->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT))) |
3246 | BIT(NL80211_IFTYPE_P2P_CLIENT))) | ||
3247 | return -EOPNOTSUPP; | 3264 | return -EOPNOTSUPP; |
3248 | 3265 | ||
3249 | mutex_lock(&priv->mutex); | 3266 | mutex_lock(&priv->mutex); |
3250 | 3267 | ||
3251 | if (priv->contexts[IWL_RXON_CTX_PAN].is_active || | 3268 | /* |
3252 | test_bit(STATUS_SCAN_HW, &priv->status)) { | 3269 | * TODO: Remove this hack! Firmware needs to be updated |
3270 | * to allow longer off-channel periods in scanning for | ||
3271 | * this use case, based on a flag (and we'll need an API | ||
3272 | * flag in the firmware when it has that). | ||
3273 | */ | ||
3274 | if (iwl_is_associated(priv, IWL_RXON_CTX_BSS) && duration > 80) | ||
3275 | duration = 80; | ||
3276 | |||
3277 | if (test_bit(STATUS_SCAN_HW, &priv->status)) { | ||
3253 | err = -EBUSY; | 3278 | err = -EBUSY; |
3254 | goto out; | 3279 | goto out; |
3255 | } | 3280 | } |
3256 | 3281 | ||
3257 | priv->contexts[IWL_RXON_CTX_PAN].is_active = true; | ||
3258 | priv->hw_roc_channel = channel; | 3282 | priv->hw_roc_channel = channel; |
3259 | priv->hw_roc_chantype = channel_type; | 3283 | priv->hw_roc_chantype = channel_type; |
3260 | priv->hw_roc_duration = DIV_ROUND_UP(duration * 1000, 1024); | 3284 | priv->hw_roc_duration = duration; |
3261 | iwlagn_commit_rxon(priv, &priv->contexts[IWL_RXON_CTX_PAN]); | 3285 | cancel_delayed_work(&priv->hw_roc_disable_work); |
3262 | queue_delayed_work(priv->workqueue, &priv->hw_roc_work, | 3286 | |
3263 | msecs_to_jiffies(duration + 20)); | 3287 | if (!ctx->is_active) { |
3288 | ctx->is_active = true; | ||
3289 | ctx->staging.dev_type = RXON_DEV_TYPE_P2P; | ||
3290 | memcpy(ctx->staging.node_addr, | ||
3291 | priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr, | ||
3292 | ETH_ALEN); | ||
3293 | memcpy(ctx->staging.bssid_addr, | ||
3294 | priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr, | ||
3295 | ETH_ALEN); | ||
3296 | err = iwlagn_commit_rxon(priv, ctx); | ||
3297 | if (err) | ||
3298 | goto out; | ||
3299 | ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK | | ||
3300 | RXON_FILTER_PROMISC_MSK | | ||
3301 | RXON_FILTER_CTL2HOST_MSK; | ||
3302 | |||
3303 | err = iwlagn_commit_rxon(priv, ctx); | ||
3304 | if (err) { | ||
3305 | iwlagn_disable_roc(priv); | ||
3306 | goto out; | ||
3307 | } | ||
3308 | priv->hw_roc_setup = true; | ||
3309 | } | ||
3264 | 3310 | ||
3265 | msleep(IWL_MIN_SLOT_TIME); /* TU is almost ms */ | 3311 | err = iwl_scan_initiate(priv, ctx->vif, IWL_SCAN_ROC, channel->band); |
3266 | ieee80211_ready_on_channel(priv->hw); | 3312 | if (err) |
3313 | iwlagn_disable_roc(priv); | ||
3267 | 3314 | ||
3268 | out: | 3315 | out: |
3269 | mutex_unlock(&priv->mutex); | 3316 | mutex_unlock(&priv->mutex); |
@@ -3278,9 +3325,8 @@ static int iwl_mac_cancel_remain_on_channel(struct ieee80211_hw *hw) | |||
3278 | if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN))) | 3325 | if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN))) |
3279 | return -EOPNOTSUPP; | 3326 | return -EOPNOTSUPP; |
3280 | 3327 | ||
3281 | cancel_delayed_work_sync(&priv->hw_roc_work); | ||
3282 | |||
3283 | mutex_lock(&priv->mutex); | 3328 | mutex_lock(&priv->mutex); |
3329 | iwl_scan_cancel_timeout(priv, priv->hw_roc_duration); | ||
3284 | iwlagn_disable_roc(priv); | 3330 | iwlagn_disable_roc(priv); |
3285 | mutex_unlock(&priv->mutex); | 3331 | mutex_unlock(&priv->mutex); |
3286 | 3332 | ||
@@ -3305,7 +3351,8 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) | |||
3305 | INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush); | 3351 | INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush); |
3306 | INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency); | 3352 | INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency); |
3307 | INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config); | 3353 | INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config); |
3308 | INIT_DELAYED_WORK(&priv->hw_roc_work, iwlagn_bg_roc_done); | 3354 | INIT_DELAYED_WORK(&priv->hw_roc_disable_work, |
3355 | iwlagn_disable_roc_work); | ||
3309 | 3356 | ||
3310 | iwl_setup_scan_deferred_work(priv); | 3357 | iwl_setup_scan_deferred_work(priv); |
3311 | 3358 | ||
@@ -3337,6 +3384,7 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv) | |||
3337 | 3384 | ||
3338 | cancel_work_sync(&priv->bt_full_concurrency); | 3385 | cancel_work_sync(&priv->bt_full_concurrency); |
3339 | cancel_work_sync(&priv->bt_runtime_config); | 3386 | cancel_work_sync(&priv->bt_runtime_config); |
3387 | cancel_delayed_work_sync(&priv->hw_roc_disable_work); | ||
3340 | 3388 | ||
3341 | del_timer_sync(&priv->statistics_periodic); | 3389 | del_timer_sync(&priv->statistics_periodic); |
3342 | del_timer_sync(&priv->ucode_trace); | 3390 | del_timer_sync(&priv->ucode_trace); |
@@ -3489,8 +3537,6 @@ struct ieee80211_ops iwlagn_hw_ops = { | |||
3489 | .tx_last_beacon = iwl_mac_tx_last_beacon, | 3537 | .tx_last_beacon = iwl_mac_tx_last_beacon, |
3490 | .remain_on_channel = iwl_mac_remain_on_channel, | 3538 | .remain_on_channel = iwl_mac_remain_on_channel, |
3491 | .cancel_remain_on_channel = iwl_mac_cancel_remain_on_channel, | 3539 | .cancel_remain_on_channel = iwl_mac_cancel_remain_on_channel, |
3492 | .offchannel_tx = iwl_mac_offchannel_tx, | ||
3493 | .offchannel_tx_cancel_wait = iwl_mac_offchannel_tx_cancel_wait, | ||
3494 | .rssi_callback = iwl_mac_rssi_callback, | 3540 | .rssi_callback = iwl_mac_rssi_callback, |
3495 | CFG80211_TESTMODE_CMD(iwl_testmode_cmd) | 3541 | CFG80211_TESTMODE_CMD(iwl_testmode_cmd) |
3496 | CFG80211_TESTMODE_DUMP(iwl_testmode_dump) | 3542 | CFG80211_TESTMODE_DUMP(iwl_testmode_dump) |
@@ -3519,28 +3565,6 @@ static int iwl_set_hw_params(struct iwl_priv *priv) | |||
3519 | return priv->cfg->lib->set_hw_params(priv); | 3565 | return priv->cfg->lib->set_hw_params(priv); |
3520 | } | 3566 | } |
3521 | 3567 | ||
3522 | static const u8 iwlagn_bss_ac_to_fifo[] = { | ||
3523 | IWL_TX_FIFO_VO, | ||
3524 | IWL_TX_FIFO_VI, | ||
3525 | IWL_TX_FIFO_BE, | ||
3526 | IWL_TX_FIFO_BK, | ||
3527 | }; | ||
3528 | |||
3529 | static const u8 iwlagn_bss_ac_to_queue[] = { | ||
3530 | 0, 1, 2, 3, | ||
3531 | }; | ||
3532 | |||
3533 | static const u8 iwlagn_pan_ac_to_fifo[] = { | ||
3534 | IWL_TX_FIFO_VO_IPAN, | ||
3535 | IWL_TX_FIFO_VI_IPAN, | ||
3536 | IWL_TX_FIFO_BE_IPAN, | ||
3537 | IWL_TX_FIFO_BK_IPAN, | ||
3538 | }; | ||
3539 | |||
3540 | static const u8 iwlagn_pan_ac_to_queue[] = { | ||
3541 | 7, 6, 5, 4, | ||
3542 | }; | ||
3543 | |||
3544 | /* This function both allocates and initializes hw and priv. */ | 3568 | /* This function both allocates and initializes hw and priv. */ |
3545 | static struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg) | 3569 | static struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg) |
3546 | { | 3570 | { |
@@ -3563,65 +3587,6 @@ out: | |||
3563 | return hw; | 3587 | return hw; |
3564 | } | 3588 | } |
3565 | 3589 | ||
3566 | static void iwl_init_context(struct iwl_priv *priv) | ||
3567 | { | ||
3568 | int i; | ||
3569 | |||
3570 | /* | ||
3571 | * The default context is always valid, | ||
3572 | * more may be discovered when firmware | ||
3573 | * is loaded. | ||
3574 | */ | ||
3575 | priv->valid_contexts = BIT(IWL_RXON_CTX_BSS); | ||
3576 | |||
3577 | for (i = 0; i < NUM_IWL_RXON_CTX; i++) | ||
3578 | priv->contexts[i].ctxid = i; | ||
3579 | |||
3580 | priv->contexts[IWL_RXON_CTX_BSS].always_active = true; | ||
3581 | priv->contexts[IWL_RXON_CTX_BSS].is_active = true; | ||
3582 | priv->contexts[IWL_RXON_CTX_BSS].rxon_cmd = REPLY_RXON; | ||
3583 | priv->contexts[IWL_RXON_CTX_BSS].rxon_timing_cmd = REPLY_RXON_TIMING; | ||
3584 | priv->contexts[IWL_RXON_CTX_BSS].rxon_assoc_cmd = REPLY_RXON_ASSOC; | ||
3585 | priv->contexts[IWL_RXON_CTX_BSS].qos_cmd = REPLY_QOS_PARAM; | ||
3586 | priv->contexts[IWL_RXON_CTX_BSS].ap_sta_id = IWL_AP_ID; | ||
3587 | priv->contexts[IWL_RXON_CTX_BSS].wep_key_cmd = REPLY_WEPKEY; | ||
3588 | priv->contexts[IWL_RXON_CTX_BSS].ac_to_fifo = iwlagn_bss_ac_to_fifo; | ||
3589 | priv->contexts[IWL_RXON_CTX_BSS].ac_to_queue = iwlagn_bss_ac_to_queue; | ||
3590 | priv->contexts[IWL_RXON_CTX_BSS].exclusive_interface_modes = | ||
3591 | BIT(NL80211_IFTYPE_ADHOC); | ||
3592 | priv->contexts[IWL_RXON_CTX_BSS].interface_modes = | ||
3593 | BIT(NL80211_IFTYPE_STATION); | ||
3594 | priv->contexts[IWL_RXON_CTX_BSS].ap_devtype = RXON_DEV_TYPE_AP; | ||
3595 | priv->contexts[IWL_RXON_CTX_BSS].ibss_devtype = RXON_DEV_TYPE_IBSS; | ||
3596 | priv->contexts[IWL_RXON_CTX_BSS].station_devtype = RXON_DEV_TYPE_ESS; | ||
3597 | priv->contexts[IWL_RXON_CTX_BSS].unused_devtype = RXON_DEV_TYPE_ESS; | ||
3598 | |||
3599 | priv->contexts[IWL_RXON_CTX_PAN].rxon_cmd = REPLY_WIPAN_RXON; | ||
3600 | priv->contexts[IWL_RXON_CTX_PAN].rxon_timing_cmd = | ||
3601 | REPLY_WIPAN_RXON_TIMING; | ||
3602 | priv->contexts[IWL_RXON_CTX_PAN].rxon_assoc_cmd = | ||
3603 | REPLY_WIPAN_RXON_ASSOC; | ||
3604 | priv->contexts[IWL_RXON_CTX_PAN].qos_cmd = REPLY_WIPAN_QOS_PARAM; | ||
3605 | priv->contexts[IWL_RXON_CTX_PAN].ap_sta_id = IWL_AP_ID_PAN; | ||
3606 | priv->contexts[IWL_RXON_CTX_PAN].wep_key_cmd = REPLY_WIPAN_WEPKEY; | ||
3607 | priv->contexts[IWL_RXON_CTX_PAN].bcast_sta_id = IWLAGN_PAN_BCAST_ID; | ||
3608 | priv->contexts[IWL_RXON_CTX_PAN].station_flags = STA_FLG_PAN_STATION; | ||
3609 | priv->contexts[IWL_RXON_CTX_PAN].ac_to_fifo = iwlagn_pan_ac_to_fifo; | ||
3610 | priv->contexts[IWL_RXON_CTX_PAN].ac_to_queue = iwlagn_pan_ac_to_queue; | ||
3611 | priv->contexts[IWL_RXON_CTX_PAN].mcast_queue = IWL_IPAN_MCAST_QUEUE; | ||
3612 | priv->contexts[IWL_RXON_CTX_PAN].interface_modes = | ||
3613 | BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP); | ||
3614 | #ifdef CONFIG_IWL_P2P | ||
3615 | priv->contexts[IWL_RXON_CTX_PAN].interface_modes |= | ||
3616 | BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO); | ||
3617 | #endif | ||
3618 | priv->contexts[IWL_RXON_CTX_PAN].ap_devtype = RXON_DEV_TYPE_CP; | ||
3619 | priv->contexts[IWL_RXON_CTX_PAN].station_devtype = RXON_DEV_TYPE_2STA; | ||
3620 | priv->contexts[IWL_RXON_CTX_PAN].unused_devtype = RXON_DEV_TYPE_P2P; | ||
3621 | |||
3622 | BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2); | ||
3623 | } | ||
3624 | |||
3625 | int iwl_probe(struct iwl_bus *bus, struct iwl_cfg *cfg) | 3590 | int iwl_probe(struct iwl_bus *bus, struct iwl_cfg *cfg) |
3626 | { | 3591 | { |
3627 | int err = 0; | 3592 | int err = 0; |
@@ -3724,9 +3689,6 @@ int iwl_probe(struct iwl_bus *bus, struct iwl_cfg *cfg) | |||
3724 | priv->hw->wiphy->n_addresses++; | 3689 | priv->hw->wiphy->n_addresses++; |
3725 | } | 3690 | } |
3726 | 3691 | ||
3727 | /* initialize all valid contexts */ | ||
3728 | iwl_init_context(priv); | ||
3729 | |||
3730 | /************************ | 3692 | /************************ |
3731 | * 5. Setup HW constants | 3693 | * 5. Setup HW constants |
3732 | ************************/ | 3694 | ************************/ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index d941c4c98e4b..df2960ae92aa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h | |||
@@ -209,6 +209,7 @@ u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx, u8 valid); | |||
209 | /* scan */ | 209 | /* scan */ |
210 | int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif); | 210 | int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif); |
211 | void iwlagn_post_scan(struct iwl_priv *priv); | 211 | void iwlagn_post_scan(struct iwl_priv *priv); |
212 | void iwlagn_disable_roc(struct iwl_priv *priv); | ||
212 | 213 | ||
213 | /* station mgmt */ | 214 | /* station mgmt */ |
214 | int iwlagn_manage_ibss_station(struct iwl_priv *priv, | 215 | int iwlagn_manage_ibss_station(struct iwl_priv *priv, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index e9e9d1d1778d..0016c61b3000 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h | |||
@@ -3067,17 +3067,29 @@ struct iwl_missed_beacon_notif { | |||
3067 | /* number of additional entries for enhanced tbl */ | 3067 | /* number of additional entries for enhanced tbl */ |
3068 | #define ENHANCE_HD_TABLE_ENTRIES (ENHANCE_HD_TABLE_SIZE - HD_TABLE_SIZE) | 3068 | #define ENHANCE_HD_TABLE_ENTRIES (ENHANCE_HD_TABLE_SIZE - HD_TABLE_SIZE) |
3069 | 3069 | ||
3070 | #define HD_INA_NON_SQUARE_DET_OFDM_DATA cpu_to_le16(0) | 3070 | #define HD_INA_NON_SQUARE_DET_OFDM_DATA_V1 cpu_to_le16(0) |
3071 | #define HD_INA_NON_SQUARE_DET_CCK_DATA cpu_to_le16(0) | 3071 | #define HD_INA_NON_SQUARE_DET_CCK_DATA_V1 cpu_to_le16(0) |
3072 | #define HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA cpu_to_le16(0) | 3072 | #define HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V1 cpu_to_le16(0) |
3073 | #define HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA cpu_to_le16(668) | 3073 | #define HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V1 cpu_to_le16(668) |
3074 | #define HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA cpu_to_le16(4) | 3074 | #define HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1 cpu_to_le16(4) |
3075 | #define HD_OFDM_NON_SQUARE_DET_SLOPE_DATA cpu_to_le16(486) | 3075 | #define HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V1 cpu_to_le16(486) |
3076 | #define HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA cpu_to_le16(37) | 3076 | #define HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V1 cpu_to_le16(37) |
3077 | #define HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA cpu_to_le16(853) | 3077 | #define HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V1 cpu_to_le16(853) |
3078 | #define HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA cpu_to_le16(4) | 3078 | #define HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1 cpu_to_le16(4) |
3079 | #define HD_CCK_NON_SQUARE_DET_SLOPE_DATA cpu_to_le16(476) | 3079 | #define HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V1 cpu_to_le16(476) |
3080 | #define HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA cpu_to_le16(99) | 3080 | #define HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V1 cpu_to_le16(99) |
3081 | |||
3082 | #define HD_INA_NON_SQUARE_DET_OFDM_DATA_V2 cpu_to_le16(1) | ||
3083 | #define HD_INA_NON_SQUARE_DET_CCK_DATA_V2 cpu_to_le16(1) | ||
3084 | #define HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V2 cpu_to_le16(1) | ||
3085 | #define HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V2 cpu_to_le16(600) | ||
3086 | #define HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2 cpu_to_le16(40) | ||
3087 | #define HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V2 cpu_to_le16(486) | ||
3088 | #define HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V2 cpu_to_le16(45) | ||
3089 | #define HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V2 cpu_to_le16(853) | ||
3090 | #define HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2 cpu_to_le16(60) | ||
3091 | #define HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V2 cpu_to_le16(476) | ||
3092 | #define HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V2 cpu_to_le16(99) | ||
3081 | 3093 | ||
3082 | 3094 | ||
3083 | /* Control field in struct iwl_sensitivity_cmd */ | 3095 | /* Control field in struct iwl_sensitivity_cmd */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index cf376f62b2f6..e269987cd64c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include "iwl-io.h" | 40 | #include "iwl-io.h" |
41 | #include "iwl-power.h" | 41 | #include "iwl-power.h" |
42 | #include "iwl-sta.h" | 42 | #include "iwl-sta.h" |
43 | #include "iwl-agn.h" | ||
43 | #include "iwl-helpers.h" | 44 | #include "iwl-helpers.h" |
44 | #include "iwl-agn.h" | 45 | #include "iwl-agn.h" |
45 | #include "iwl-trans.h" | 46 | #include "iwl-trans.h" |
@@ -1273,8 +1274,12 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | |||
1273 | IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n", | 1274 | IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n", |
1274 | viftype, vif->addr); | 1275 | viftype, vif->addr); |
1275 | 1276 | ||
1277 | cancel_delayed_work_sync(&priv->hw_roc_disable_work); | ||
1278 | |||
1276 | mutex_lock(&priv->mutex); | 1279 | mutex_lock(&priv->mutex); |
1277 | 1280 | ||
1281 | iwlagn_disable_roc(priv); | ||
1282 | |||
1278 | if (!iwl_is_ready_rf(priv)) { | 1283 | if (!iwl_is_ready_rf(priv)) { |
1279 | IWL_WARN(priv, "Try to add interface when device not ready\n"); | 1284 | IWL_WARN(priv, "Try to add interface when device not ready\n"); |
1280 | err = -EINVAL; | 1285 | err = -EINVAL; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 02817a438550..42bcb469d32c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h | |||
@@ -136,6 +136,7 @@ struct iwl_mod_params { | |||
136 | * @max_event_log_size: size of event log buffer size for ucode event logging | 136 | * @max_event_log_size: size of event log buffer size for ucode event logging |
137 | * @shadow_reg_enable: HW shadhow register bit | 137 | * @shadow_reg_enable: HW shadhow register bit |
138 | * @no_idle_support: do not support idle mode | 138 | * @no_idle_support: do not support idle mode |
139 | * @hd_v2: v2 of enhanced sensitivity value, used for 2000 series and up | ||
139 | */ | 140 | */ |
140 | struct iwl_base_params { | 141 | struct iwl_base_params { |
141 | int eeprom_size; | 142 | int eeprom_size; |
@@ -158,6 +159,7 @@ struct iwl_base_params { | |||
158 | u32 max_event_log_size; | 159 | u32 max_event_log_size; |
159 | const bool shadow_reg_enable; | 160 | const bool shadow_reg_enable; |
160 | const bool no_idle_support; | 161 | const bool no_idle_support; |
162 | const bool hd_v2; | ||
161 | }; | 163 | }; |
162 | /* | 164 | /* |
163 | * @advanced_bt_coexist: support advanced bt coexist | 165 | * @advanced_bt_coexist: support advanced bt coexist |
@@ -194,6 +196,8 @@ struct iwl_ht_params { | |||
194 | * (.ucode) will be added to filename before loading from disk. The | 196 | * (.ucode) will be added to filename before loading from disk. The |
195 | * filename is constructed as fw_name_pre<api>.ucode. | 197 | * filename is constructed as fw_name_pre<api>.ucode. |
196 | * @ucode_api_max: Highest version of uCode API supported by driver. | 198 | * @ucode_api_max: Highest version of uCode API supported by driver. |
199 | * @ucode_api_ok: oldest version of the uCode API that is OK to load | ||
200 | * without a warning, for use in transitions | ||
197 | * @ucode_api_min: Lowest version of uCode API supported by driver. | 201 | * @ucode_api_min: Lowest version of uCode API supported by driver. |
198 | * @valid_tx_ant: valid transmit antenna | 202 | * @valid_tx_ant: valid transmit antenna |
199 | * @valid_rx_ant: valid receive antenna | 203 | * @valid_rx_ant: valid receive antenna |
@@ -237,6 +241,7 @@ struct iwl_cfg { | |||
237 | const char *name; | 241 | const char *name; |
238 | const char *fw_name_pre; | 242 | const char *fw_name_pre; |
239 | const unsigned int ucode_api_max; | 243 | const unsigned int ucode_api_max; |
244 | const unsigned int ucode_api_ok; | ||
240 | const unsigned int ucode_api_min; | 245 | const unsigned int ucode_api_min; |
241 | u8 valid_tx_ant; | 246 | u8 valid_tx_ant; |
242 | u8 valid_rx_ant; | 247 | u8 valid_rx_ant; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 6c9790cac8d0..dd34c7c502fa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h | |||
@@ -230,12 +230,23 @@ struct iwl_channel_info { | |||
230 | #define IWL_TX_FIFO_BE_IPAN 4 | 230 | #define IWL_TX_FIFO_BE_IPAN 4 |
231 | #define IWL_TX_FIFO_VI_IPAN IWL_TX_FIFO_VI | 231 | #define IWL_TX_FIFO_VI_IPAN IWL_TX_FIFO_VI |
232 | #define IWL_TX_FIFO_VO_IPAN 5 | 232 | #define IWL_TX_FIFO_VO_IPAN 5 |
233 | /* re-uses the VO FIFO, uCode will properly flush/schedule */ | ||
234 | #define IWL_TX_FIFO_AUX 5 | ||
233 | #define IWL_TX_FIFO_UNUSED -1 | 235 | #define IWL_TX_FIFO_UNUSED -1 |
234 | 236 | ||
235 | /* Minimum number of queues. MAX_NUM is defined in hw specific files. | 237 | /* AUX (TX during scan dwell) queue */ |
236 | * Set the minimum to accommodate the 4 standard TX queues, 1 command | 238 | #define IWL_AUX_QUEUE 10 |
237 | * queue, 2 (unused) HCCA queues, and 4 HT queues (one for each AC) */ | 239 | |
238 | #define IWL_MIN_NUM_QUEUES 10 | 240 | /* |
241 | * Minimum number of queues. MAX_NUM is defined in hw specific files. | ||
242 | * Set the minimum to accommodate | ||
243 | * - 4 standard TX queues | ||
244 | * - the command queue | ||
245 | * - 4 PAN TX queues | ||
246 | * - the PAN multicast queue, and | ||
247 | * - the AUX (TX during scan dwell) queue. | ||
248 | */ | ||
249 | #define IWL_MIN_NUM_QUEUES 11 | ||
239 | 250 | ||
240 | /* | 251 | /* |
241 | * Command queue depends on iPAN support. | 252 | * Command queue depends on iPAN support. |
@@ -564,11 +575,13 @@ enum iwl_ucode_tlv_type { | |||
564 | * @IWL_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behaviour on hidden SSID, | 575 | * @IWL_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behaviour on hidden SSID, |
565 | * treats good CRC threshold as a boolean | 576 | * treats good CRC threshold as a boolean |
566 | * @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w). | 577 | * @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w). |
578 | * @IWL_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P. | ||
567 | */ | 579 | */ |
568 | enum iwl_ucode_tlv_flag { | 580 | enum iwl_ucode_tlv_flag { |
569 | IWL_UCODE_TLV_FLAGS_PAN = BIT(0), | 581 | IWL_UCODE_TLV_FLAGS_PAN = BIT(0), |
570 | IWL_UCODE_TLV_FLAGS_NEWSCAN = BIT(1), | 582 | IWL_UCODE_TLV_FLAGS_NEWSCAN = BIT(1), |
571 | IWL_UCODE_TLV_FLAGS_MFP = BIT(2), | 583 | IWL_UCODE_TLV_FLAGS_MFP = BIT(2), |
584 | IWL_UCODE_TLV_FLAGS_P2P = BIT(3), | ||
572 | }; | 585 | }; |
573 | 586 | ||
574 | struct iwl_ucode_tlv { | 587 | struct iwl_ucode_tlv { |
@@ -1168,7 +1181,7 @@ struct iwl_rxon_context { | |||
1168 | enum iwl_scan_type { | 1181 | enum iwl_scan_type { |
1169 | IWL_SCAN_NORMAL, | 1182 | IWL_SCAN_NORMAL, |
1170 | IWL_SCAN_RADIO_RESET, | 1183 | IWL_SCAN_RADIO_RESET, |
1171 | IWL_SCAN_OFFCH_TX, | 1184 | IWL_SCAN_ROC, |
1172 | }; | 1185 | }; |
1173 | 1186 | ||
1174 | enum iwlagn_ucode_type { | 1187 | enum iwlagn_ucode_type { |
@@ -1438,15 +1451,11 @@ struct iwl_priv { | |||
1438 | 1451 | ||
1439 | /* remain-on-channel offload support */ | 1452 | /* remain-on-channel offload support */ |
1440 | struct ieee80211_channel *hw_roc_channel; | 1453 | struct ieee80211_channel *hw_roc_channel; |
1441 | struct delayed_work hw_roc_work; | 1454 | struct delayed_work hw_roc_disable_work; |
1442 | enum nl80211_channel_type hw_roc_chantype; | 1455 | enum nl80211_channel_type hw_roc_chantype; |
1443 | int hw_roc_duration; | 1456 | int hw_roc_duration; |
1444 | bool hw_roc_setup; | 1457 | bool hw_roc_setup; |
1445 | 1458 | ||
1446 | struct sk_buff *offchan_tx_skb; | ||
1447 | int offchan_tx_timeout; | ||
1448 | struct ieee80211_channel *offchan_tx_chan; | ||
1449 | |||
1450 | /* bt coex */ | 1459 | /* bt coex */ |
1451 | u8 bt_enable_flag; | 1460 | u8 bt_enable_flag; |
1452 | u8 bt_status; | 1461 | u8 bt_status; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index a67ae56d5464..1a5252d8ca73 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c | |||
@@ -31,7 +31,6 @@ | |||
31 | #include <linux/delay.h> | 31 | #include <linux/delay.h> |
32 | #include <linux/skbuff.h> | 32 | #include <linux/skbuff.h> |
33 | #include <linux/netdevice.h> | 33 | #include <linux/netdevice.h> |
34 | #include <linux/wireless.h> | ||
35 | #include <net/mac80211.h> | 34 | #include <net/mac80211.h> |
36 | #include <linux/etherdevice.h> | 35 | #include <linux/etherdevice.h> |
37 | #include <asm/unaligned.h> | 36 | #include <asm/unaligned.h> |
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index dd6937e97055..28e59319f581 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c | |||
@@ -103,6 +103,12 @@ static void iwl_complete_scan(struct iwl_priv *priv, bool aborted) | |||
103 | ieee80211_scan_completed(priv->hw, aborted); | 103 | ieee80211_scan_completed(priv->hw, aborted); |
104 | } | 104 | } |
105 | 105 | ||
106 | if (priv->scan_type == IWL_SCAN_ROC) { | ||
107 | ieee80211_remain_on_channel_expired(priv->hw); | ||
108 | priv->hw_roc_channel = NULL; | ||
109 | schedule_delayed_work(&priv->hw_roc_disable_work, 10 * HZ); | ||
110 | } | ||
111 | |||
106 | priv->scan_type = IWL_SCAN_NORMAL; | 112 | priv->scan_type = IWL_SCAN_NORMAL; |
107 | priv->scan_vif = NULL; | 113 | priv->scan_vif = NULL; |
108 | priv->scan_request = NULL; | 114 | priv->scan_request = NULL; |
@@ -211,6 +217,9 @@ static void iwl_rx_scan_start_notif(struct iwl_priv *priv, | |||
211 | le32_to_cpu(notif->tsf_high), | 217 | le32_to_cpu(notif->tsf_high), |
212 | le32_to_cpu(notif->tsf_low), | 218 | le32_to_cpu(notif->tsf_low), |
213 | notif->status, notif->beacon_timer); | 219 | notif->status, notif->beacon_timer); |
220 | |||
221 | if (priv->scan_type == IWL_SCAN_ROC) | ||
222 | ieee80211_ready_on_channel(priv->hw); | ||
214 | } | 223 | } |
215 | 224 | ||
216 | /* Service SCAN_RESULTS_NOTIFICATION (0x83) */ | 225 | /* Service SCAN_RESULTS_NOTIFICATION (0x83) */ |
@@ -370,7 +379,7 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv, | |||
370 | 379 | ||
371 | IWL_DEBUG_SCAN(priv, "Starting %sscan...\n", | 380 | IWL_DEBUG_SCAN(priv, "Starting %sscan...\n", |
372 | scan_type == IWL_SCAN_NORMAL ? "" : | 381 | scan_type == IWL_SCAN_NORMAL ? "" : |
373 | scan_type == IWL_SCAN_OFFCH_TX ? "offchan TX " : | 382 | scan_type == IWL_SCAN_ROC ? "remain-on-channel " : |
374 | "internal short "); | 383 | "internal short "); |
375 | 384 | ||
376 | set_bit(STATUS_SCANNING, &priv->status); | 385 | set_bit(STATUS_SCANNING, &priv->status); |
@@ -565,10 +574,10 @@ static void iwl_bg_scan_completed(struct work_struct *work) | |||
565 | goto out_settings; | 574 | goto out_settings; |
566 | } | 575 | } |
567 | 576 | ||
568 | if (priv->scan_type == IWL_SCAN_OFFCH_TX && priv->offchan_tx_skb) { | 577 | if (priv->scan_type == IWL_SCAN_ROC) { |
569 | ieee80211_tx_status_irqsafe(priv->hw, | 578 | ieee80211_remain_on_channel_expired(priv->hw); |
570 | priv->offchan_tx_skb); | 579 | priv->hw_roc_channel = NULL; |
571 | priv->offchan_tx_skb = NULL; | 580 | schedule_delayed_work(&priv->hw_roc_disable_work, 10 * HZ); |
572 | } | 581 | } |
573 | 582 | ||
574 | if (priv->scan_type != IWL_SCAN_NORMAL && !aborted) { | 583 | if (priv->scan_type != IWL_SCAN_NORMAL && !aborted) { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.c b/drivers/net/wireless/iwlwifi/iwl-trans.c index 41f0de914008..3001bfb46e25 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans.c | |||
@@ -750,6 +750,7 @@ static const struct queue_to_fifo_ac iwlagn_default_queue_to_tx_fifo[] = { | |||
750 | { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, }, | 750 | { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, }, |
751 | { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, }, | 751 | { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, }, |
752 | { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, }, | 752 | { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, }, |
753 | { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, }, | ||
753 | }; | 754 | }; |
754 | 755 | ||
755 | static const struct queue_to_fifo_ac iwlagn_ipan_queue_to_tx_fifo[] = { | 756 | static const struct queue_to_fifo_ac iwlagn_ipan_queue_to_tx_fifo[] = { |
@@ -763,6 +764,7 @@ static const struct queue_to_fifo_ac iwlagn_ipan_queue_to_tx_fifo[] = { | |||
763 | { IWL_TX_FIFO_VO_IPAN, IEEE80211_AC_VO, }, | 764 | { IWL_TX_FIFO_VO_IPAN, IEEE80211_AC_VO, }, |
764 | { IWL_TX_FIFO_BE_IPAN, 2, }, | 765 | { IWL_TX_FIFO_BE_IPAN, 2, }, |
765 | { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, }, | 766 | { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, }, |
767 | { IWL_TX_FIFO_AUX, IWL_AC_UNSET, }, | ||
766 | }; | 768 | }; |
767 | static void iwl_trans_tx_start(struct iwl_priv *priv) | 769 | static void iwl_trans_tx_start(struct iwl_priv *priv) |
768 | { | 770 | { |
@@ -848,10 +850,12 @@ static void iwl_trans_tx_start(struct iwl_priv *priv) | |||
848 | /* reset to 0 to enable all the queue first */ | 850 | /* reset to 0 to enable all the queue first */ |
849 | priv->txq_ctx_active_msk = 0; | 851 | priv->txq_ctx_active_msk = 0; |
850 | 852 | ||
851 | BUILD_BUG_ON(ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo) != 10); | 853 | BUILD_BUG_ON(ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo) != |
852 | BUILD_BUG_ON(ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo) != 10); | 854 | IWLAGN_FIRST_AMPDU_QUEUE); |
855 | BUILD_BUG_ON(ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo) != | ||
856 | IWLAGN_FIRST_AMPDU_QUEUE); | ||
853 | 857 | ||
854 | for (i = 0; i < 10; i++) { | 858 | for (i = 0; i < IWLAGN_FIRST_AMPDU_QUEUE; i++) { |
855 | int fifo = queue_to_fifo[i].fifo; | 859 | int fifo = queue_to_fifo[i].fifo; |
856 | int ac = queue_to_fifo[i].ac; | 860 | int ac = queue_to_fifo[i].ac; |
857 | 861 | ||
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index b456a53b64b1..85b3169c40d7 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include "decl.h" | 19 | #include "decl.h" |
20 | #include "cfg.h" | 20 | #include "cfg.h" |
21 | #include "cmd.h" | 21 | #include "cmd.h" |
22 | #include "mesh.h" | ||
22 | 23 | ||
23 | 24 | ||
24 | #define CHAN2G(_channel, _freq, _flags) { \ | 25 | #define CHAN2G(_channel, _freq, _flags) { \ |
@@ -442,13 +443,16 @@ static int lbs_cfg_set_channel(struct wiphy *wiphy, | |||
442 | struct lbs_private *priv = wiphy_priv(wiphy); | 443 | struct lbs_private *priv = wiphy_priv(wiphy); |
443 | int ret = -ENOTSUPP; | 444 | int ret = -ENOTSUPP; |
444 | 445 | ||
445 | lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d", | 446 | lbs_deb_enter_args(LBS_DEB_CFG80211, "iface %s freq %d, type %d", |
446 | channel->center_freq, channel_type); | 447 | netdev_name(netdev), channel->center_freq, channel_type); |
447 | 448 | ||
448 | if (channel_type != NL80211_CHAN_NO_HT) | 449 | if (channel_type != NL80211_CHAN_NO_HT) |
449 | goto out; | 450 | goto out; |
450 | 451 | ||
451 | ret = lbs_set_channel(priv, channel->hw_value); | 452 | if (netdev == priv->mesh_dev) |
453 | ret = lbs_mesh_set_channel(priv, channel->hw_value); | ||
454 | else | ||
455 | ret = lbs_set_channel(priv, channel->hw_value); | ||
452 | 456 | ||
453 | out: | 457 | out: |
454 | lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); | 458 | lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); |
@@ -708,7 +712,7 @@ static void lbs_scan_worker(struct work_struct *work) | |||
708 | 712 | ||
709 | if (priv->scan_channel < priv->scan_req->n_channels) { | 713 | if (priv->scan_channel < priv->scan_req->n_channels) { |
710 | cancel_delayed_work(&priv->scan_work); | 714 | cancel_delayed_work(&priv->scan_work); |
711 | if (!priv->stopping) | 715 | if (netif_running(priv->dev)) |
712 | queue_delayed_work(priv->work_thread, &priv->scan_work, | 716 | queue_delayed_work(priv->work_thread, &priv->scan_work, |
713 | msecs_to_jiffies(300)); | 717 | msecs_to_jiffies(300)); |
714 | } | 718 | } |
@@ -1292,6 +1296,9 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev, | |||
1292 | int ret = 0; | 1296 | int ret = 0; |
1293 | u8 preamble = RADIO_PREAMBLE_SHORT; | 1297 | u8 preamble = RADIO_PREAMBLE_SHORT; |
1294 | 1298 | ||
1299 | if (dev == priv->mesh_dev) | ||
1300 | return -EOPNOTSUPP; | ||
1301 | |||
1295 | lbs_deb_enter(LBS_DEB_CFG80211); | 1302 | lbs_deb_enter(LBS_DEB_CFG80211); |
1296 | 1303 | ||
1297 | if (!sme->bssid) { | 1304 | if (!sme->bssid) { |
@@ -1402,28 +1409,23 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev, | |||
1402 | return ret; | 1409 | return ret; |
1403 | } | 1410 | } |
1404 | 1411 | ||
1405 | static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev, | 1412 | int lbs_disconnect(struct lbs_private *priv, u16 reason) |
1406 | u16 reason_code) | ||
1407 | { | 1413 | { |
1408 | struct lbs_private *priv = wiphy_priv(wiphy); | ||
1409 | struct cmd_ds_802_11_deauthenticate cmd; | 1414 | struct cmd_ds_802_11_deauthenticate cmd; |
1410 | 1415 | int ret; | |
1411 | lbs_deb_enter_args(LBS_DEB_CFG80211, "reason_code %d", reason_code); | ||
1412 | |||
1413 | /* store for lbs_cfg_ret_disconnect() */ | ||
1414 | priv->disassoc_reason = reason_code; | ||
1415 | 1416 | ||
1416 | memset(&cmd, 0, sizeof(cmd)); | 1417 | memset(&cmd, 0, sizeof(cmd)); |
1417 | cmd.hdr.size = cpu_to_le16(sizeof(cmd)); | 1418 | cmd.hdr.size = cpu_to_le16(sizeof(cmd)); |
1418 | /* Mildly ugly to use a locally store my own BSSID ... */ | 1419 | /* Mildly ugly to use a locally store my own BSSID ... */ |
1419 | memcpy(cmd.macaddr, &priv->assoc_bss, ETH_ALEN); | 1420 | memcpy(cmd.macaddr, &priv->assoc_bss, ETH_ALEN); |
1420 | cmd.reasoncode = cpu_to_le16(reason_code); | 1421 | cmd.reasoncode = cpu_to_le16(reason); |
1421 | 1422 | ||
1422 | if (lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd)) | 1423 | ret = lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd); |
1423 | return -EFAULT; | 1424 | if (ret) |
1425 | return ret; | ||
1424 | 1426 | ||
1425 | cfg80211_disconnected(priv->dev, | 1427 | cfg80211_disconnected(priv->dev, |
1426 | priv->disassoc_reason, | 1428 | reason, |
1427 | NULL, 0, | 1429 | NULL, 0, |
1428 | GFP_KERNEL); | 1430 | GFP_KERNEL); |
1429 | priv->connect_status = LBS_DISCONNECTED; | 1431 | priv->connect_status = LBS_DISCONNECTED; |
@@ -1431,6 +1433,21 @@ static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev, | |||
1431 | return 0; | 1433 | return 0; |
1432 | } | 1434 | } |
1433 | 1435 | ||
1436 | static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev, | ||
1437 | u16 reason_code) | ||
1438 | { | ||
1439 | struct lbs_private *priv = wiphy_priv(wiphy); | ||
1440 | |||
1441 | if (dev == priv->mesh_dev) | ||
1442 | return -EOPNOTSUPP; | ||
1443 | |||
1444 | lbs_deb_enter_args(LBS_DEB_CFG80211, "reason_code %d", reason_code); | ||
1445 | |||
1446 | /* store for lbs_cfg_ret_disconnect() */ | ||
1447 | priv->disassoc_reason = reason_code; | ||
1448 | |||
1449 | return lbs_disconnect(priv, reason_code); | ||
1450 | } | ||
1434 | 1451 | ||
1435 | static int lbs_cfg_set_default_key(struct wiphy *wiphy, | 1452 | static int lbs_cfg_set_default_key(struct wiphy *wiphy, |
1436 | struct net_device *netdev, | 1453 | struct net_device *netdev, |
@@ -1439,6 +1456,9 @@ static int lbs_cfg_set_default_key(struct wiphy *wiphy, | |||
1439 | { | 1456 | { |
1440 | struct lbs_private *priv = wiphy_priv(wiphy); | 1457 | struct lbs_private *priv = wiphy_priv(wiphy); |
1441 | 1458 | ||
1459 | if (netdev == priv->mesh_dev) | ||
1460 | return -EOPNOTSUPP; | ||
1461 | |||
1442 | lbs_deb_enter(LBS_DEB_CFG80211); | 1462 | lbs_deb_enter(LBS_DEB_CFG80211); |
1443 | 1463 | ||
1444 | if (key_index != priv->wep_tx_key) { | 1464 | if (key_index != priv->wep_tx_key) { |
@@ -1460,6 +1480,9 @@ static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev, | |||
1460 | u16 key_type; | 1480 | u16 key_type; |
1461 | int ret = 0; | 1481 | int ret = 0; |
1462 | 1482 | ||
1483 | if (netdev == priv->mesh_dev) | ||
1484 | return -EOPNOTSUPP; | ||
1485 | |||
1463 | lbs_deb_enter(LBS_DEB_CFG80211); | 1486 | lbs_deb_enter(LBS_DEB_CFG80211); |
1464 | 1487 | ||
1465 | lbs_deb_assoc("add_key: cipher 0x%x, mac_addr %pM\n", | 1488 | lbs_deb_assoc("add_key: cipher 0x%x, mac_addr %pM\n", |
@@ -1603,6 +1626,9 @@ static int lbs_get_survey(struct wiphy *wiphy, struct net_device *dev, | |||
1603 | s8 signal, noise; | 1626 | s8 signal, noise; |
1604 | int ret; | 1627 | int ret; |
1605 | 1628 | ||
1629 | if (dev == priv->mesh_dev) | ||
1630 | return -EOPNOTSUPP; | ||
1631 | |||
1606 | if (idx != 0) | 1632 | if (idx != 0) |
1607 | ret = -ENOENT; | 1633 | ret = -ENOENT; |
1608 | 1634 | ||
@@ -1636,6 +1662,9 @@ static int lbs_change_intf(struct wiphy *wiphy, struct net_device *dev, | |||
1636 | struct lbs_private *priv = wiphy_priv(wiphy); | 1662 | struct lbs_private *priv = wiphy_priv(wiphy); |
1637 | int ret = 0; | 1663 | int ret = 0; |
1638 | 1664 | ||
1665 | if (dev == priv->mesh_dev) | ||
1666 | return -EOPNOTSUPP; | ||
1667 | |||
1639 | lbs_deb_enter(LBS_DEB_CFG80211); | 1668 | lbs_deb_enter(LBS_DEB_CFG80211); |
1640 | 1669 | ||
1641 | switch (type) { | 1670 | switch (type) { |
@@ -1959,6 +1988,9 @@ static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev, | |||
1959 | struct cfg80211_bss *bss; | 1988 | struct cfg80211_bss *bss; |
1960 | DECLARE_SSID_BUF(ssid_buf); | 1989 | DECLARE_SSID_BUF(ssid_buf); |
1961 | 1990 | ||
1991 | if (dev == priv->mesh_dev) | ||
1992 | return -EOPNOTSUPP; | ||
1993 | |||
1962 | lbs_deb_enter(LBS_DEB_CFG80211); | 1994 | lbs_deb_enter(LBS_DEB_CFG80211); |
1963 | 1995 | ||
1964 | if (!params->channel) { | 1996 | if (!params->channel) { |
@@ -1995,6 +2027,9 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev) | |||
1995 | struct cmd_ds_802_11_ad_hoc_stop cmd; | 2027 | struct cmd_ds_802_11_ad_hoc_stop cmd; |
1996 | int ret = 0; | 2028 | int ret = 0; |
1997 | 2029 | ||
2030 | if (dev == priv->mesh_dev) | ||
2031 | return -EOPNOTSUPP; | ||
2032 | |||
1998 | lbs_deb_enter(LBS_DEB_CFG80211); | 2033 | lbs_deb_enter(LBS_DEB_CFG80211); |
1999 | 2034 | ||
2000 | memset(&cmd, 0, sizeof(cmd)); | 2035 | memset(&cmd, 0, sizeof(cmd)); |
@@ -2117,6 +2152,8 @@ int lbs_cfg_register(struct lbs_private *priv) | |||
2117 | BIT(NL80211_IFTYPE_ADHOC); | 2152 | BIT(NL80211_IFTYPE_ADHOC); |
2118 | if (lbs_rtap_supported(priv)) | 2153 | if (lbs_rtap_supported(priv)) |
2119 | wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); | 2154 | wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); |
2155 | if (lbs_mesh_activated(priv)) | ||
2156 | wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MESH_POINT); | ||
2120 | 2157 | ||
2121 | wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &lbs_band_2ghz; | 2158 | wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &lbs_band_2ghz; |
2122 | 2159 | ||
diff --git a/drivers/net/wireless/libertas/cfg.h b/drivers/net/wireless/libertas/cfg.h index 4f46bb744bee..a02ee151710e 100644 --- a/drivers/net/wireless/libertas/cfg.h +++ b/drivers/net/wireless/libertas/cfg.h | |||
@@ -17,5 +17,6 @@ void lbs_send_disconnect_notification(struct lbs_private *priv); | |||
17 | void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event); | 17 | void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event); |
18 | 18 | ||
19 | void lbs_scan_deinit(struct lbs_private *priv); | 19 | void lbs_scan_deinit(struct lbs_private *priv); |
20 | int lbs_disconnect(struct lbs_private *priv, u16 reason); | ||
20 | 21 | ||
21 | #endif | 22 | #endif |
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index dbd24a4607ec..e08ab1de3d9d 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c | |||
@@ -1088,7 +1088,7 @@ void __lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd, | |||
1088 | if (!cmd->callback || cmd->callback == lbs_cmd_async_callback) | 1088 | if (!cmd->callback || cmd->callback == lbs_cmd_async_callback) |
1089 | __lbs_cleanup_and_insert_cmd(priv, cmd); | 1089 | __lbs_cleanup_and_insert_cmd(priv, cmd); |
1090 | priv->cur_cmd = NULL; | 1090 | priv->cur_cmd = NULL; |
1091 | wake_up_interruptible(&priv->waitq); | 1091 | wake_up(&priv->waitq); |
1092 | } | 1092 | } |
1093 | 1093 | ||
1094 | void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd, | 1094 | void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd, |
@@ -1627,7 +1627,7 @@ struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, | |||
1627 | lbs_deb_host("PREP_CMD: cmdnode is NULL\n"); | 1627 | lbs_deb_host("PREP_CMD: cmdnode is NULL\n"); |
1628 | 1628 | ||
1629 | /* Wake up main thread to execute next command */ | 1629 | /* Wake up main thread to execute next command */ |
1630 | wake_up_interruptible(&priv->waitq); | 1630 | wake_up(&priv->waitq); |
1631 | cmdnode = ERR_PTR(-ENOBUFS); | 1631 | cmdnode = ERR_PTR(-ENOBUFS); |
1632 | goto done; | 1632 | goto done; |
1633 | } | 1633 | } |
@@ -1647,7 +1647,7 @@ struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, | |||
1647 | 1647 | ||
1648 | cmdnode->cmdwaitqwoken = 0; | 1648 | cmdnode->cmdwaitqwoken = 0; |
1649 | lbs_queue_cmd(priv, cmdnode); | 1649 | lbs_queue_cmd(priv, cmdnode); |
1650 | wake_up_interruptible(&priv->waitq); | 1650 | wake_up(&priv->waitq); |
1651 | 1651 | ||
1652 | done: | 1652 | done: |
1653 | lbs_deb_leave_args(LBS_DEB_HOST, "ret %p", cmdnode); | 1653 | lbs_deb_leave_args(LBS_DEB_HOST, "ret %p", cmdnode); |
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index da0b05bb89fe..9304e6fc421f 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h | |||
@@ -43,10 +43,14 @@ int lbs_start_card(struct lbs_private *priv); | |||
43 | void lbs_stop_card(struct lbs_private *priv); | 43 | void lbs_stop_card(struct lbs_private *priv); |
44 | void lbs_host_to_card_done(struct lbs_private *priv); | 44 | void lbs_host_to_card_done(struct lbs_private *priv); |
45 | 45 | ||
46 | int lbs_start_iface(struct lbs_private *priv); | ||
47 | int lbs_stop_iface(struct lbs_private *priv); | ||
48 | |||
46 | int lbs_rtap_supported(struct lbs_private *priv); | 49 | int lbs_rtap_supported(struct lbs_private *priv); |
47 | 50 | ||
48 | int lbs_set_mac_address(struct net_device *dev, void *addr); | 51 | int lbs_set_mac_address(struct net_device *dev, void *addr); |
49 | void lbs_set_multicast_list(struct net_device *dev); | 52 | void lbs_set_multicast_list(struct net_device *dev); |
53 | void lbs_update_mcast(struct lbs_private *priv); | ||
50 | 54 | ||
51 | int lbs_suspend(struct lbs_private *priv); | 55 | int lbs_suspend(struct lbs_private *priv); |
52 | int lbs_resume(struct lbs_private *priv); | 56 | int lbs_resume(struct lbs_private *priv); |
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index adb3490e3cf5..814838916b82 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h | |||
@@ -6,7 +6,6 @@ | |||
6 | #ifndef _LBS_DEV_H_ | 6 | #ifndef _LBS_DEV_H_ |
7 | #define _LBS_DEV_H_ | 7 | #define _LBS_DEV_H_ |
8 | 8 | ||
9 | #include "mesh.h" | ||
10 | #include "defs.h" | 9 | #include "defs.h" |
11 | #include "host.h" | 10 | #include "host.h" |
12 | 11 | ||
@@ -22,6 +21,17 @@ struct sleep_params { | |||
22 | uint16_t sp_reserved; | 21 | uint16_t sp_reserved; |
23 | }; | 22 | }; |
24 | 23 | ||
24 | /* Mesh statistics */ | ||
25 | struct lbs_mesh_stats { | ||
26 | u32 fwd_bcast_cnt; /* Fwd: Broadcast counter */ | ||
27 | u32 fwd_unicast_cnt; /* Fwd: Unicast counter */ | ||
28 | u32 fwd_drop_ttl; /* Fwd: TTL zero */ | ||
29 | u32 fwd_drop_rbt; /* Fwd: Recently Broadcasted */ | ||
30 | u32 fwd_drop_noroute; /* Fwd: No route to Destination */ | ||
31 | u32 fwd_drop_nobuf; /* Fwd: Run out of internal buffers */ | ||
32 | u32 drop_blind; /* Rx: Dropped by blinding table */ | ||
33 | u32 tx_failed_cnt; /* Tx: Failed transmissions */ | ||
34 | }; | ||
25 | 35 | ||
26 | /* Private structure for the MV device */ | 36 | /* Private structure for the MV device */ |
27 | struct lbs_private { | 37 | struct lbs_private { |
@@ -36,7 +46,6 @@ struct lbs_private { | |||
36 | /* CFG80211 */ | 46 | /* CFG80211 */ |
37 | struct wireless_dev *wdev; | 47 | struct wireless_dev *wdev; |
38 | bool wiphy_registered; | 48 | bool wiphy_registered; |
39 | bool stopping; | ||
40 | struct cfg80211_scan_request *scan_req; | 49 | struct cfg80211_scan_request *scan_req; |
41 | u8 assoc_bss[ETH_ALEN]; | 50 | u8 assoc_bss[ETH_ALEN]; |
42 | u8 disassoc_reason; | 51 | u8 disassoc_reason; |
@@ -86,11 +95,14 @@ struct lbs_private { | |||
86 | 95 | ||
87 | /* Hardware access */ | 96 | /* Hardware access */ |
88 | void *card; | 97 | void *card; |
98 | bool iface_running; | ||
89 | u8 fw_ready; | 99 | u8 fw_ready; |
90 | u8 surpriseremoved; | 100 | u8 surpriseremoved; |
91 | u8 setup_fw_on_resume; | 101 | u8 setup_fw_on_resume; |
92 | int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb); | 102 | int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb); |
93 | void (*reset_card) (struct lbs_private *priv); | 103 | void (*reset_card) (struct lbs_private *priv); |
104 | int (*power_save) (struct lbs_private *priv); | ||
105 | int (*power_restore) (struct lbs_private *priv); | ||
94 | int (*enter_deep_sleep) (struct lbs_private *priv); | 106 | int (*enter_deep_sleep) (struct lbs_private *priv); |
95 | int (*exit_deep_sleep) (struct lbs_private *priv); | 107 | int (*exit_deep_sleep) (struct lbs_private *priv); |
96 | int (*reset_deep_sleep_wakeup) (struct lbs_private *priv); | 108 | int (*reset_deep_sleep_wakeup) (struct lbs_private *priv); |
@@ -172,4 +184,16 @@ struct lbs_private { | |||
172 | 184 | ||
173 | extern struct cmd_confirm_sleep confirm_sleep; | 185 | extern struct cmd_confirm_sleep confirm_sleep; |
174 | 186 | ||
187 | /* Check if there is an interface active. */ | ||
188 | static inline int lbs_iface_active(struct lbs_private *priv) | ||
189 | { | ||
190 | int r; | ||
191 | |||
192 | r = netif_running(priv->dev); | ||
193 | if (priv->mesh_dev); | ||
194 | r |= netif_running(priv->dev); | ||
195 | |||
196 | return r; | ||
197 | } | ||
198 | |||
175 | #endif | 199 | #endif |
diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c index 4dfb3bfd2cf3..885ddc1c4fed 100644 --- a/drivers/net/wireless/libertas/ethtool.c +++ b/drivers/net/wireless/libertas/ethtool.c | |||
@@ -5,6 +5,7 @@ | |||
5 | 5 | ||
6 | #include "decl.h" | 6 | #include "decl.h" |
7 | #include "cmd.h" | 7 | #include "cmd.h" |
8 | #include "mesh.h" | ||
8 | 9 | ||
9 | 10 | ||
10 | static void lbs_ethtool_get_drvinfo(struct net_device *dev, | 11 | static void lbs_ethtool_get_drvinfo(struct net_device *dev, |
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 387786e1b394..c962e21762dc 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/mmc/sdio_ids.h> | 39 | #include <linux/mmc/sdio_ids.h> |
40 | #include <linux/mmc/sdio.h> | 40 | #include <linux/mmc/sdio.h> |
41 | #include <linux/mmc/host.h> | 41 | #include <linux/mmc/host.h> |
42 | #include <linux/pm_runtime.h> | ||
42 | 43 | ||
43 | #include "host.h" | 44 | #include "host.h" |
44 | #include "decl.h" | 45 | #include "decl.h" |
@@ -47,6 +48,8 @@ | |||
47 | #include "cmd.h" | 48 | #include "cmd.h" |
48 | #include "if_sdio.h" | 49 | #include "if_sdio.h" |
49 | 50 | ||
51 | static void if_sdio_interrupt(struct sdio_func *func); | ||
52 | |||
50 | /* The if_sdio_remove() callback function is called when | 53 | /* The if_sdio_remove() callback function is called when |
51 | * user removes this module from kernel space or ejects | 54 | * user removes this module from kernel space or ejects |
52 | * the card from the slot. The driver handles these 2 cases | 55 | * the card from the slot. The driver handles these 2 cases |
@@ -757,6 +760,136 @@ out: | |||
757 | return ret; | 760 | return ret; |
758 | } | 761 | } |
759 | 762 | ||
763 | /********************************************************************/ | ||
764 | /* Power management */ | ||
765 | /********************************************************************/ | ||
766 | |||
767 | static int if_sdio_power_on(struct if_sdio_card *card) | ||
768 | { | ||
769 | struct sdio_func *func = card->func; | ||
770 | struct lbs_private *priv = card->priv; | ||
771 | struct mmc_host *host = func->card->host; | ||
772 | int ret; | ||
773 | |||
774 | sdio_claim_host(func); | ||
775 | |||
776 | ret = sdio_enable_func(func); | ||
777 | if (ret) | ||
778 | goto release; | ||
779 | |||
780 | /* For 1-bit transfers to the 8686 model, we need to enable the | ||
781 | * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0 | ||
782 | * bit to allow access to non-vendor registers. */ | ||
783 | if ((card->model == MODEL_8686) && | ||
784 | (host->caps & MMC_CAP_SDIO_IRQ) && | ||
785 | (host->ios.bus_width == MMC_BUS_WIDTH_1)) { | ||
786 | u8 reg; | ||
787 | |||
788 | func->card->quirks |= MMC_QUIRK_LENIENT_FN0; | ||
789 | reg = sdio_f0_readb(func, SDIO_CCCR_IF, &ret); | ||
790 | if (ret) | ||
791 | goto disable; | ||
792 | |||
793 | reg |= SDIO_BUS_ECSI; | ||
794 | sdio_f0_writeb(func, reg, SDIO_CCCR_IF, &ret); | ||
795 | if (ret) | ||
796 | goto disable; | ||
797 | } | ||
798 | |||
799 | card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret); | ||
800 | if (ret) | ||
801 | goto disable; | ||
802 | |||
803 | card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8; | ||
804 | if (ret) | ||
805 | goto disable; | ||
806 | |||
807 | card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16; | ||
808 | if (ret) | ||
809 | goto disable; | ||
810 | |||
811 | sdio_release_host(func); | ||
812 | ret = if_sdio_prog_firmware(card); | ||
813 | sdio_claim_host(func); | ||
814 | if (ret) | ||
815 | goto disable; | ||
816 | |||
817 | /* | ||
818 | * Get rx_unit if the chip is SD8688 or newer. | ||
819 | * SD8385 & SD8686 do not have rx_unit. | ||
820 | */ | ||
821 | if ((card->model != MODEL_8385) | ||
822 | && (card->model != MODEL_8686)) | ||
823 | card->rx_unit = if_sdio_read_rx_unit(card); | ||
824 | else | ||
825 | card->rx_unit = 0; | ||
826 | |||
827 | /* | ||
828 | * Set up the interrupt handler late. | ||
829 | * | ||
830 | * If we set it up earlier, the (buggy) hardware generates a spurious | ||
831 | * interrupt, even before the interrupt has been enabled, with | ||
832 | * CCCR_INTx = 0. | ||
833 | * | ||
834 | * We register the interrupt handler late so that we can handle any | ||
835 | * spurious interrupts, and also to avoid generation of that known | ||
836 | * spurious interrupt in the first place. | ||
837 | */ | ||
838 | ret = sdio_claim_irq(func, if_sdio_interrupt); | ||
839 | if (ret) | ||
840 | goto disable; | ||
841 | |||
842 | /* | ||
843 | * Enable interrupts now that everything is set up | ||
844 | */ | ||
845 | sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret); | ||
846 | if (ret) | ||
847 | goto release_irq; | ||
848 | |||
849 | sdio_release_host(func); | ||
850 | |||
851 | /* | ||
852 | * FUNC_INIT is required for SD8688 WLAN/BT multiple functions | ||
853 | */ | ||
854 | if (card->model == MODEL_8688) { | ||
855 | struct cmd_header cmd; | ||
856 | |||
857 | memset(&cmd, 0, sizeof(cmd)); | ||
858 | |||
859 | lbs_deb_sdio("send function INIT command\n"); | ||
860 | if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd), | ||
861 | lbs_cmd_copyback, (unsigned long) &cmd)) | ||
862 | netdev_alert(priv->dev, "CMD_FUNC_INIT cmd failed\n"); | ||
863 | } | ||
864 | |||
865 | priv->fw_ready = 1; | ||
866 | |||
867 | return 0; | ||
868 | |||
869 | release_irq: | ||
870 | sdio_release_irq(func); | ||
871 | disable: | ||
872 | sdio_disable_func(func); | ||
873 | release: | ||
874 | sdio_release_host(func); | ||
875 | return ret; | ||
876 | } | ||
877 | |||
878 | static int if_sdio_power_off(struct if_sdio_card *card) | ||
879 | { | ||
880 | struct sdio_func *func = card->func; | ||
881 | struct lbs_private *priv = card->priv; | ||
882 | |||
883 | priv->fw_ready = 0; | ||
884 | |||
885 | sdio_claim_host(func); | ||
886 | sdio_release_irq(func); | ||
887 | sdio_disable_func(func); | ||
888 | sdio_release_host(func); | ||
889 | return 0; | ||
890 | } | ||
891 | |||
892 | |||
760 | /*******************************************************************/ | 893 | /*******************************************************************/ |
761 | /* Libertas callbacks */ | 894 | /* Libertas callbacks */ |
762 | /*******************************************************************/ | 895 | /*******************************************************************/ |
@@ -923,6 +1056,32 @@ static void if_sdio_reset_card(struct lbs_private *priv) | |||
923 | schedule_work(&card_reset_work); | 1056 | schedule_work(&card_reset_work); |
924 | } | 1057 | } |
925 | 1058 | ||
1059 | static int if_sdio_power_save(struct lbs_private *priv) | ||
1060 | { | ||
1061 | struct if_sdio_card *card = priv->card; | ||
1062 | int ret; | ||
1063 | |||
1064 | flush_workqueue(card->workqueue); | ||
1065 | |||
1066 | ret = if_sdio_power_off(card); | ||
1067 | |||
1068 | /* Let runtime PM know the card is powered off */ | ||
1069 | pm_runtime_put_sync(&card->func->dev); | ||
1070 | |||
1071 | return ret; | ||
1072 | } | ||
1073 | |||
1074 | static int if_sdio_power_restore(struct lbs_private *priv) | ||
1075 | { | ||
1076 | struct if_sdio_card *card = priv->card; | ||
1077 | |||
1078 | /* Make sure the card will not be powered off by runtime PM */ | ||
1079 | pm_runtime_get_sync(&card->func->dev); | ||
1080 | |||
1081 | return if_sdio_power_on(card); | ||
1082 | } | ||
1083 | |||
1084 | |||
926 | /*******************************************************************/ | 1085 | /*******************************************************************/ |
927 | /* SDIO callbacks */ | 1086 | /* SDIO callbacks */ |
928 | /*******************************************************************/ | 1087 | /*******************************************************************/ |
@@ -976,7 +1135,6 @@ static int if_sdio_probe(struct sdio_func *func, | |||
976 | int ret, i; | 1135 | int ret, i; |
977 | unsigned int model; | 1136 | unsigned int model; |
978 | struct if_sdio_packet *packet; | 1137 | struct if_sdio_packet *packet; |
979 | struct mmc_host *host = func->card->host; | ||
980 | 1138 | ||
981 | lbs_deb_enter(LBS_DEB_SDIO); | 1139 | lbs_deb_enter(LBS_DEB_SDIO); |
982 | 1140 | ||
@@ -1033,45 +1191,6 @@ static int if_sdio_probe(struct sdio_func *func, | |||
1033 | goto free; | 1191 | goto free; |
1034 | } | 1192 | } |
1035 | 1193 | ||
1036 | sdio_claim_host(func); | ||
1037 | |||
1038 | ret = sdio_enable_func(func); | ||
1039 | if (ret) | ||
1040 | goto release; | ||
1041 | |||
1042 | /* For 1-bit transfers to the 8686 model, we need to enable the | ||
1043 | * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0 | ||
1044 | * bit to allow access to non-vendor registers. */ | ||
1045 | if ((card->model == MODEL_8686) && | ||
1046 | (host->caps & MMC_CAP_SDIO_IRQ) && | ||
1047 | (host->ios.bus_width == MMC_BUS_WIDTH_1)) { | ||
1048 | u8 reg; | ||
1049 | |||
1050 | func->card->quirks |= MMC_QUIRK_LENIENT_FN0; | ||
1051 | reg = sdio_f0_readb(func, SDIO_CCCR_IF, &ret); | ||
1052 | if (ret) | ||
1053 | goto release_int; | ||
1054 | |||
1055 | reg |= SDIO_BUS_ECSI; | ||
1056 | sdio_f0_writeb(func, reg, SDIO_CCCR_IF, &ret); | ||
1057 | if (ret) | ||
1058 | goto release_int; | ||
1059 | } | ||
1060 | |||
1061 | card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret); | ||
1062 | if (ret) | ||
1063 | goto release_int; | ||
1064 | |||
1065 | card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8; | ||
1066 | if (ret) | ||
1067 | goto release_int; | ||
1068 | |||
1069 | card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16; | ||
1070 | if (ret) | ||
1071 | goto release_int; | ||
1072 | |||
1073 | sdio_release_host(func); | ||
1074 | |||
1075 | sdio_set_drvdata(func, card); | 1194 | sdio_set_drvdata(func, card); |
1076 | 1195 | ||
1077 | lbs_deb_sdio("class = 0x%X, vendor = 0x%X, " | 1196 | lbs_deb_sdio("class = 0x%X, vendor = 0x%X, " |
@@ -1079,14 +1198,11 @@ static int if_sdio_probe(struct sdio_func *func, | |||
1079 | func->class, func->vendor, func->device, | 1198 | func->class, func->vendor, func->device, |
1080 | model, (unsigned)card->ioport); | 1199 | model, (unsigned)card->ioport); |
1081 | 1200 | ||
1082 | ret = if_sdio_prog_firmware(card); | ||
1083 | if (ret) | ||
1084 | goto reclaim; | ||
1085 | 1201 | ||
1086 | priv = lbs_add_card(card, &func->dev); | 1202 | priv = lbs_add_card(card, &func->dev); |
1087 | if (!priv) { | 1203 | if (!priv) { |
1088 | ret = -ENOMEM; | 1204 | ret = -ENOMEM; |
1089 | goto reclaim; | 1205 | goto free; |
1090 | } | 1206 | } |
1091 | 1207 | ||
1092 | card->priv = priv; | 1208 | card->priv = priv; |
@@ -1097,62 +1213,21 @@ static int if_sdio_probe(struct sdio_func *func, | |||
1097 | priv->exit_deep_sleep = if_sdio_exit_deep_sleep; | 1213 | priv->exit_deep_sleep = if_sdio_exit_deep_sleep; |
1098 | priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup; | 1214 | priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup; |
1099 | priv->reset_card = if_sdio_reset_card; | 1215 | priv->reset_card = if_sdio_reset_card; |
1216 | priv->power_save = if_sdio_power_save; | ||
1217 | priv->power_restore = if_sdio_power_restore; | ||
1100 | 1218 | ||
1101 | sdio_claim_host(func); | 1219 | ret = if_sdio_power_on(card); |
1102 | |||
1103 | /* | ||
1104 | * Get rx_unit if the chip is SD8688 or newer. | ||
1105 | * SD8385 & SD8686 do not have rx_unit. | ||
1106 | */ | ||
1107 | if ((card->model != MODEL_8385) | ||
1108 | && (card->model != MODEL_8686)) | ||
1109 | card->rx_unit = if_sdio_read_rx_unit(card); | ||
1110 | else | ||
1111 | card->rx_unit = 0; | ||
1112 | |||
1113 | /* | ||
1114 | * Set up the interrupt handler late. | ||
1115 | * | ||
1116 | * If we set it up earlier, the (buggy) hardware generates a spurious | ||
1117 | * interrupt, even before the interrupt has been enabled, with | ||
1118 | * CCCR_INTx = 0. | ||
1119 | * | ||
1120 | * We register the interrupt handler late so that we can handle any | ||
1121 | * spurious interrupts, and also to avoid generation of that known | ||
1122 | * spurious interrupt in the first place. | ||
1123 | */ | ||
1124 | ret = sdio_claim_irq(func, if_sdio_interrupt); | ||
1125 | if (ret) | ||
1126 | goto disable; | ||
1127 | |||
1128 | /* | ||
1129 | * Enable interrupts now that everything is set up | ||
1130 | */ | ||
1131 | sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret); | ||
1132 | sdio_release_host(func); | ||
1133 | if (ret) | 1220 | if (ret) |
1134 | goto reclaim; | 1221 | goto err_activate_card; |
1135 | |||
1136 | priv->fw_ready = 1; | ||
1137 | |||
1138 | /* | ||
1139 | * FUNC_INIT is required for SD8688 WLAN/BT multiple functions | ||
1140 | */ | ||
1141 | if (card->model == MODEL_8688) { | ||
1142 | struct cmd_header cmd; | ||
1143 | |||
1144 | memset(&cmd, 0, sizeof(cmd)); | ||
1145 | |||
1146 | lbs_deb_sdio("send function INIT command\n"); | ||
1147 | if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd), | ||
1148 | lbs_cmd_copyback, (unsigned long) &cmd)) | ||
1149 | netdev_alert(priv->dev, "CMD_FUNC_INIT cmd failed\n"); | ||
1150 | } | ||
1151 | 1222 | ||
1152 | ret = lbs_start_card(priv); | 1223 | ret = lbs_start_card(priv); |
1224 | if_sdio_power_off(card); | ||
1153 | if (ret) | 1225 | if (ret) |
1154 | goto err_activate_card; | 1226 | goto err_activate_card; |
1155 | 1227 | ||
1228 | /* Tell PM core that we don't need the card to be powered now */ | ||
1229 | pm_runtime_put_noidle(&func->dev); | ||
1230 | |||
1156 | out: | 1231 | out: |
1157 | lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); | 1232 | lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); |
1158 | 1233 | ||
@@ -1161,14 +1236,6 @@ out: | |||
1161 | err_activate_card: | 1236 | err_activate_card: |
1162 | flush_workqueue(card->workqueue); | 1237 | flush_workqueue(card->workqueue); |
1163 | lbs_remove_card(priv); | 1238 | lbs_remove_card(priv); |
1164 | reclaim: | ||
1165 | sdio_claim_host(func); | ||
1166 | release_int: | ||
1167 | sdio_release_irq(func); | ||
1168 | disable: | ||
1169 | sdio_disable_func(func); | ||
1170 | release: | ||
1171 | sdio_release_host(func); | ||
1172 | free: | 1239 | free: |
1173 | destroy_workqueue(card->workqueue); | 1240 | destroy_workqueue(card->workqueue); |
1174 | while (card->packets) { | 1241 | while (card->packets) { |
@@ -1195,6 +1262,9 @@ static void if_sdio_remove(struct sdio_func *func) | |||
1195 | 1262 | ||
1196 | card = sdio_get_drvdata(func); | 1263 | card = sdio_get_drvdata(func); |
1197 | 1264 | ||
1265 | /* Undo decrement done above in if_sdio_probe */ | ||
1266 | pm_runtime_get_noresume(&func->dev); | ||
1267 | |||
1198 | if (user_rmmod && (card->model == MODEL_8688)) { | 1268 | if (user_rmmod && (card->model == MODEL_8688)) { |
1199 | /* | 1269 | /* |
1200 | * FUNC_SHUTDOWN is required for SD8688 WLAN/BT | 1270 | * FUNC_SHUTDOWN is required for SD8688 WLAN/BT |
@@ -1219,11 +1289,6 @@ static void if_sdio_remove(struct sdio_func *func) | |||
1219 | flush_workqueue(card->workqueue); | 1289 | flush_workqueue(card->workqueue); |
1220 | destroy_workqueue(card->workqueue); | 1290 | destroy_workqueue(card->workqueue); |
1221 | 1291 | ||
1222 | sdio_claim_host(func); | ||
1223 | sdio_release_irq(func); | ||
1224 | sdio_disable_func(func); | ||
1225 | sdio_release_host(func); | ||
1226 | |||
1227 | while (card->packets) { | 1292 | while (card->packets) { |
1228 | packet = card->packets; | 1293 | packet = card->packets; |
1229 | card->packets = card->packets->next; | 1294 | card->packets = card->packets->next; |
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index e0286cfbc91d..622ae6de0d8b 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c | |||
@@ -531,10 +531,6 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card, | |||
531 | goto out; | 531 | goto out; |
532 | err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG, | 532 | err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG, |
533 | IF_SPI_CIC_CMD_DOWNLOAD_OVER); | 533 | IF_SPI_CIC_CMD_DOWNLOAD_OVER); |
534 | goto out; | ||
535 | |||
536 | lbs_deb_spi("waiting for helper to boot...\n"); | ||
537 | |||
538 | out: | 534 | out: |
539 | if (err) | 535 | if (err) |
540 | pr_err("failed to load helper firmware (err=%d)\n", err); | 536 | pr_err("failed to load helper firmware (err=%d)\n", err); |
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index b5acc393a65a..0c846f5a646a 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c | |||
@@ -324,7 +324,7 @@ static int if_usb_probe(struct usb_interface *intf, | |||
324 | } | 324 | } |
325 | kparam_unblock_sysfs_write(fw_name); | 325 | kparam_unblock_sysfs_write(fw_name); |
326 | 326 | ||
327 | if (!(priv = lbs_add_card(cardp, &udev->dev))) | 327 | if (!(priv = lbs_add_card(cardp, &intf->dev))) |
328 | goto err_prog_firmware; | 328 | goto err_prog_firmware; |
329 | 329 | ||
330 | cardp->priv = priv; | 330 | cardp->priv = priv; |
@@ -956,7 +956,7 @@ static int if_usb_prog_firmware(struct if_usb_card *cardp, | |||
956 | priv->dnld_sent = DNLD_RES_RECEIVED; | 956 | priv->dnld_sent = DNLD_RES_RECEIVED; |
957 | spin_unlock_irqrestore(&priv->driver_lock, flags); | 957 | spin_unlock_irqrestore(&priv->driver_lock, flags); |
958 | 958 | ||
959 | wake_up_interruptible(&priv->waitq); | 959 | wake_up(&priv->waitq); |
960 | 960 | ||
961 | return ret; | 961 | return ret; |
962 | } | 962 | } |
@@ -1112,6 +1112,15 @@ static int if_usb_suspend(struct usb_interface *intf, pm_message_t message) | |||
1112 | if (priv->psstate != PS_STATE_FULL_POWER) | 1112 | if (priv->psstate != PS_STATE_FULL_POWER) |
1113 | return -1; | 1113 | return -1; |
1114 | 1114 | ||
1115 | #ifdef CONFIG_OLPC | ||
1116 | if (machine_is_olpc()) { | ||
1117 | if (priv->wol_criteria == EHS_REMOVE_WAKEUP) | ||
1118 | olpc_ec_wakeup_clear(EC_SCI_SRC_WLAN); | ||
1119 | else | ||
1120 | olpc_ec_wakeup_set(EC_SCI_SRC_WLAN); | ||
1121 | } | ||
1122 | #endif | ||
1123 | |||
1115 | ret = lbs_suspend(priv); | 1124 | ret = lbs_suspend(priv); |
1116 | if (ret) | 1125 | if (ret) |
1117 | goto out; | 1126 | goto out; |
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 2fdeb81ce5b2..d1c1d52931f1 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include "cfg.h" | 23 | #include "cfg.h" |
24 | #include "debugfs.h" | 24 | #include "debugfs.h" |
25 | #include "cmd.h" | 25 | #include "cmd.h" |
26 | #include "mesh.h" | ||
26 | 27 | ||
27 | #define DRIVER_RELEASE_VERSION "323.p0" | 28 | #define DRIVER_RELEASE_VERSION "323.p0" |
28 | const char lbs_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION | 29 | const char lbs_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION |
@@ -98,6 +99,37 @@ u8 lbs_data_rate_to_fw_index(u32 rate) | |||
98 | return 0; | 99 | return 0; |
99 | } | 100 | } |
100 | 101 | ||
102 | int lbs_start_iface(struct lbs_private *priv) | ||
103 | { | ||
104 | struct cmd_ds_802_11_mac_address cmd; | ||
105 | int ret; | ||
106 | |||
107 | if (priv->power_restore) { | ||
108 | ret = priv->power_restore(priv); | ||
109 | if (ret) | ||
110 | return ret; | ||
111 | } | ||
112 | |||
113 | cmd.hdr.size = cpu_to_le16(sizeof(cmd)); | ||
114 | cmd.action = cpu_to_le16(CMD_ACT_SET); | ||
115 | memcpy(cmd.macadd, priv->current_addr, ETH_ALEN); | ||
116 | |||
117 | ret = lbs_cmd_with_response(priv, CMD_802_11_MAC_ADDRESS, &cmd); | ||
118 | if (ret) { | ||
119 | lbs_deb_net("set MAC address failed\n"); | ||
120 | goto err; | ||
121 | } | ||
122 | |||
123 | lbs_update_channel(priv); | ||
124 | |||
125 | priv->iface_running = true; | ||
126 | return 0; | ||
127 | |||
128 | err: | ||
129 | if (priv->power_save) | ||
130 | priv->power_save(priv); | ||
131 | return ret; | ||
132 | } | ||
101 | 133 | ||
102 | /** | 134 | /** |
103 | * lbs_dev_open - open the ethX interface | 135 | * lbs_dev_open - open the ethX interface |
@@ -111,23 +143,64 @@ static int lbs_dev_open(struct net_device *dev) | |||
111 | int ret = 0; | 143 | int ret = 0; |
112 | 144 | ||
113 | lbs_deb_enter(LBS_DEB_NET); | 145 | lbs_deb_enter(LBS_DEB_NET); |
146 | if (!priv->iface_running) { | ||
147 | ret = lbs_start_iface(priv); | ||
148 | if (ret) | ||
149 | goto out; | ||
150 | } | ||
114 | 151 | ||
115 | spin_lock_irq(&priv->driver_lock); | 152 | spin_lock_irq(&priv->driver_lock); |
116 | priv->stopping = false; | ||
117 | 153 | ||
118 | if (priv->connect_status == LBS_CONNECTED) | 154 | netif_carrier_off(dev); |
119 | netif_carrier_on(dev); | ||
120 | else | ||
121 | netif_carrier_off(dev); | ||
122 | 155 | ||
123 | if (!priv->tx_pending_len) | 156 | if (!priv->tx_pending_len) |
124 | netif_wake_queue(dev); | 157 | netif_wake_queue(dev); |
125 | 158 | ||
126 | spin_unlock_irq(&priv->driver_lock); | 159 | spin_unlock_irq(&priv->driver_lock); |
160 | |||
161 | out: | ||
127 | lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); | 162 | lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); |
128 | return ret; | 163 | return ret; |
129 | } | 164 | } |
130 | 165 | ||
166 | static bool lbs_command_queue_empty(struct lbs_private *priv) | ||
167 | { | ||
168 | unsigned long flags; | ||
169 | bool ret; | ||
170 | spin_lock_irqsave(&priv->driver_lock, flags); | ||
171 | ret = priv->cur_cmd == NULL && list_empty(&priv->cmdpendingq); | ||
172 | spin_unlock_irqrestore(&priv->driver_lock, flags); | ||
173 | return ret; | ||
174 | } | ||
175 | |||
176 | int lbs_stop_iface(struct lbs_private *priv) | ||
177 | { | ||
178 | unsigned long flags; | ||
179 | int ret = 0; | ||
180 | |||
181 | lbs_deb_enter(LBS_DEB_MAIN); | ||
182 | |||
183 | spin_lock_irqsave(&priv->driver_lock, flags); | ||
184 | priv->iface_running = false; | ||
185 | kfree_skb(priv->currenttxskb); | ||
186 | priv->currenttxskb = NULL; | ||
187 | priv->tx_pending_len = 0; | ||
188 | spin_unlock_irqrestore(&priv->driver_lock, flags); | ||
189 | |||
190 | cancel_work_sync(&priv->mcast_work); | ||
191 | |||
192 | /* Disable command processing, and wait for all commands to complete */ | ||
193 | lbs_deb_main("waiting for commands to complete\n"); | ||
194 | wait_event(priv->waitq, lbs_command_queue_empty(priv)); | ||
195 | lbs_deb_main("all commands completed\n"); | ||
196 | |||
197 | if (priv->power_save) | ||
198 | ret = priv->power_save(priv); | ||
199 | |||
200 | lbs_deb_leave(LBS_DEB_MAIN); | ||
201 | return ret; | ||
202 | } | ||
203 | |||
131 | /** | 204 | /** |
132 | * lbs_eth_stop - close the ethX interface | 205 | * lbs_eth_stop - close the ethX interface |
133 | * | 206 | * |
@@ -140,18 +213,25 @@ static int lbs_eth_stop(struct net_device *dev) | |||
140 | 213 | ||
141 | lbs_deb_enter(LBS_DEB_NET); | 214 | lbs_deb_enter(LBS_DEB_NET); |
142 | 215 | ||
216 | if (priv->connect_status == LBS_CONNECTED) | ||
217 | lbs_disconnect(priv, WLAN_REASON_DEAUTH_LEAVING); | ||
218 | |||
143 | spin_lock_irq(&priv->driver_lock); | 219 | spin_lock_irq(&priv->driver_lock); |
144 | priv->stopping = true; | ||
145 | netif_stop_queue(dev); | 220 | netif_stop_queue(dev); |
146 | spin_unlock_irq(&priv->driver_lock); | 221 | spin_unlock_irq(&priv->driver_lock); |
147 | 222 | ||
148 | schedule_work(&priv->mcast_work); | 223 | lbs_update_mcast(priv); |
149 | cancel_delayed_work_sync(&priv->scan_work); | 224 | cancel_delayed_work_sync(&priv->scan_work); |
150 | if (priv->scan_req) { | 225 | if (priv->scan_req) { |
151 | cfg80211_scan_done(priv->scan_req, false); | 226 | cfg80211_scan_done(priv->scan_req, false); |
152 | priv->scan_req = NULL; | 227 | priv->scan_req = NULL; |
153 | } | 228 | } |
154 | 229 | ||
230 | netif_carrier_off(priv->dev); | ||
231 | |||
232 | if (!lbs_iface_active(priv)) | ||
233 | lbs_stop_iface(priv); | ||
234 | |||
155 | lbs_deb_leave(LBS_DEB_NET); | 235 | lbs_deb_leave(LBS_DEB_NET); |
156 | return 0; | 236 | return 0; |
157 | } | 237 | } |
@@ -169,7 +249,7 @@ void lbs_host_to_card_done(struct lbs_private *priv) | |||
169 | /* Wake main thread if commands are pending */ | 249 | /* Wake main thread if commands are pending */ |
170 | if (!priv->cur_cmd || priv->tx_pending_len > 0) { | 250 | if (!priv->cur_cmd || priv->tx_pending_len > 0) { |
171 | if (!priv->wakeup_dev_required) | 251 | if (!priv->wakeup_dev_required) |
172 | wake_up_interruptible(&priv->waitq); | 252 | wake_up(&priv->waitq); |
173 | } | 253 | } |
174 | 254 | ||
175 | spin_unlock_irqrestore(&priv->driver_lock, flags); | 255 | spin_unlock_irqrestore(&priv->driver_lock, flags); |
@@ -182,29 +262,24 @@ int lbs_set_mac_address(struct net_device *dev, void *addr) | |||
182 | int ret = 0; | 262 | int ret = 0; |
183 | struct lbs_private *priv = dev->ml_priv; | 263 | struct lbs_private *priv = dev->ml_priv; |
184 | struct sockaddr *phwaddr = addr; | 264 | struct sockaddr *phwaddr = addr; |
185 | struct cmd_ds_802_11_mac_address cmd; | ||
186 | 265 | ||
187 | lbs_deb_enter(LBS_DEB_NET); | 266 | lbs_deb_enter(LBS_DEB_NET); |
188 | 267 | ||
268 | /* | ||
269 | * Can only set MAC address when all interfaces are down, to be written | ||
270 | * to the hardware when one of them is brought up. | ||
271 | */ | ||
272 | if (lbs_iface_active(priv)) | ||
273 | return -EBUSY; | ||
274 | |||
189 | /* In case it was called from the mesh device */ | 275 | /* In case it was called from the mesh device */ |
190 | dev = priv->dev; | 276 | dev = priv->dev; |
191 | 277 | ||
192 | cmd.hdr.size = cpu_to_le16(sizeof(cmd)); | ||
193 | cmd.action = cpu_to_le16(CMD_ACT_SET); | ||
194 | memcpy(cmd.macadd, phwaddr->sa_data, ETH_ALEN); | ||
195 | |||
196 | ret = lbs_cmd_with_response(priv, CMD_802_11_MAC_ADDRESS, &cmd); | ||
197 | if (ret) { | ||
198 | lbs_deb_net("set MAC address failed\n"); | ||
199 | goto done; | ||
200 | } | ||
201 | |||
202 | memcpy(priv->current_addr, phwaddr->sa_data, ETH_ALEN); | 278 | memcpy(priv->current_addr, phwaddr->sa_data, ETH_ALEN); |
203 | memcpy(dev->dev_addr, phwaddr->sa_data, ETH_ALEN); | 279 | memcpy(dev->dev_addr, phwaddr->sa_data, ETH_ALEN); |
204 | if (priv->mesh_dev) | 280 | if (priv->mesh_dev) |
205 | memcpy(priv->mesh_dev->dev_addr, phwaddr->sa_data, ETH_ALEN); | 281 | memcpy(priv->mesh_dev->dev_addr, phwaddr->sa_data, ETH_ALEN); |
206 | 282 | ||
207 | done: | ||
208 | lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); | 283 | lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); |
209 | return ret; | 284 | return ret; |
210 | } | 285 | } |
@@ -258,18 +333,18 @@ static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd, | |||
258 | return i; | 333 | return i; |
259 | } | 334 | } |
260 | 335 | ||
261 | static void lbs_set_mcast_worker(struct work_struct *work) | 336 | void lbs_update_mcast(struct lbs_private *priv) |
262 | { | 337 | { |
263 | struct lbs_private *priv = container_of(work, struct lbs_private, mcast_work); | ||
264 | struct cmd_ds_mac_multicast_adr mcast_cmd; | 338 | struct cmd_ds_mac_multicast_adr mcast_cmd; |
265 | int dev_flags; | 339 | int dev_flags = 0; |
266 | int nr_addrs; | 340 | int nr_addrs; |
267 | int old_mac_control = priv->mac_control; | 341 | int old_mac_control = priv->mac_control; |
268 | 342 | ||
269 | lbs_deb_enter(LBS_DEB_NET); | 343 | lbs_deb_enter(LBS_DEB_NET); |
270 | 344 | ||
271 | dev_flags = priv->dev->flags; | 345 | if (netif_running(priv->dev)) |
272 | if (priv->mesh_dev) | 346 | dev_flags |= priv->dev->flags; |
347 | if (priv->mesh_dev && netif_running(priv->mesh_dev)) | ||
273 | dev_flags |= priv->mesh_dev->flags; | 348 | dev_flags |= priv->mesh_dev->flags; |
274 | 349 | ||
275 | if (dev_flags & IFF_PROMISC) { | 350 | if (dev_flags & IFF_PROMISC) { |
@@ -315,6 +390,12 @@ static void lbs_set_mcast_worker(struct work_struct *work) | |||
315 | lbs_deb_leave(LBS_DEB_NET); | 390 | lbs_deb_leave(LBS_DEB_NET); |
316 | } | 391 | } |
317 | 392 | ||
393 | static void lbs_set_mcast_worker(struct work_struct *work) | ||
394 | { | ||
395 | struct lbs_private *priv = container_of(work, struct lbs_private, mcast_work); | ||
396 | lbs_update_mcast(priv); | ||
397 | } | ||
398 | |||
318 | void lbs_set_multicast_list(struct net_device *dev) | 399 | void lbs_set_multicast_list(struct net_device *dev) |
319 | { | 400 | { |
320 | struct lbs_private *priv = dev->ml_priv; | 401 | struct lbs_private *priv = dev->ml_priv; |
@@ -647,7 +728,7 @@ static void lbs_cmd_timeout_handler(unsigned long data) | |||
647 | if (priv->dnld_sent == DNLD_CMD_SENT) | 728 | if (priv->dnld_sent == DNLD_CMD_SENT) |
648 | priv->dnld_sent = DNLD_RES_RECEIVED; | 729 | priv->dnld_sent = DNLD_RES_RECEIVED; |
649 | 730 | ||
650 | wake_up_interruptible(&priv->waitq); | 731 | wake_up(&priv->waitq); |
651 | out: | 732 | out: |
652 | spin_unlock_irqrestore(&priv->driver_lock, flags); | 733 | spin_unlock_irqrestore(&priv->driver_lock, flags); |
653 | lbs_deb_leave(LBS_DEB_CMD); | 734 | lbs_deb_leave(LBS_DEB_CMD); |
@@ -889,10 +970,6 @@ void lbs_remove_card(struct lbs_private *priv) | |||
889 | lbs_remove_mesh(priv); | 970 | lbs_remove_mesh(priv); |
890 | lbs_scan_deinit(priv); | 971 | lbs_scan_deinit(priv); |
891 | 972 | ||
892 | dev = priv->dev; | ||
893 | |||
894 | cancel_work_sync(&priv->mcast_work); | ||
895 | |||
896 | /* worker thread destruction blocks on the in-flight command which | 973 | /* worker thread destruction blocks on the in-flight command which |
897 | * should have been cleared already in lbs_stop_card(). | 974 | * should have been cleared already in lbs_stop_card(). |
898 | */ | 975 | */ |
@@ -950,17 +1027,18 @@ int lbs_start_card(struct lbs_private *priv) | |||
950 | if (ret) | 1027 | if (ret) |
951 | goto done; | 1028 | goto done; |
952 | 1029 | ||
1030 | if (!lbs_disablemesh) | ||
1031 | lbs_init_mesh(priv); | ||
1032 | else | ||
1033 | pr_info("%s: mesh disabled\n", dev->name); | ||
1034 | |||
953 | if (lbs_cfg_register(priv)) { | 1035 | if (lbs_cfg_register(priv)) { |
954 | pr_err("cannot register device\n"); | 1036 | pr_err("cannot register device\n"); |
955 | goto done; | 1037 | goto done; |
956 | } | 1038 | } |
957 | 1039 | ||
958 | lbs_update_channel(priv); | 1040 | if (lbs_mesh_activated(priv)) |
959 | 1041 | lbs_start_mesh(priv); | |
960 | if (!lbs_disablemesh) | ||
961 | lbs_init_mesh(priv); | ||
962 | else | ||
963 | pr_info("%s: mesh disabled\n", dev->name); | ||
964 | 1042 | ||
965 | lbs_debugfs_init_one(priv, dev); | 1043 | lbs_debugfs_init_one(priv, dev); |
966 | 1044 | ||
@@ -978,8 +1056,6 @@ EXPORT_SYMBOL_GPL(lbs_start_card); | |||
978 | void lbs_stop_card(struct lbs_private *priv) | 1056 | void lbs_stop_card(struct lbs_private *priv) |
979 | { | 1057 | { |
980 | struct net_device *dev; | 1058 | struct net_device *dev; |
981 | struct cmd_ctrl_node *cmdnode; | ||
982 | unsigned long flags; | ||
983 | 1059 | ||
984 | lbs_deb_enter(LBS_DEB_MAIN); | 1060 | lbs_deb_enter(LBS_DEB_MAIN); |
985 | 1061 | ||
@@ -992,30 +1068,6 @@ void lbs_stop_card(struct lbs_private *priv) | |||
992 | 1068 | ||
993 | lbs_debugfs_remove_one(priv); | 1069 | lbs_debugfs_remove_one(priv); |
994 | lbs_deinit_mesh(priv); | 1070 | lbs_deinit_mesh(priv); |
995 | |||
996 | /* Delete the timeout of the currently processing command */ | ||
997 | del_timer_sync(&priv->command_timer); | ||
998 | del_timer_sync(&priv->auto_deepsleep_timer); | ||
999 | |||
1000 | /* Flush pending command nodes */ | ||
1001 | spin_lock_irqsave(&priv->driver_lock, flags); | ||
1002 | lbs_deb_main("clearing pending commands\n"); | ||
1003 | list_for_each_entry(cmdnode, &priv->cmdpendingq, list) { | ||
1004 | cmdnode->result = -ENOENT; | ||
1005 | cmdnode->cmdwaitqwoken = 1; | ||
1006 | wake_up(&cmdnode->cmdwait_q); | ||
1007 | } | ||
1008 | |||
1009 | /* Flush the command the card is currently processing */ | ||
1010 | if (priv->cur_cmd) { | ||
1011 | lbs_deb_main("clearing current command\n"); | ||
1012 | priv->cur_cmd->result = -ENOENT; | ||
1013 | priv->cur_cmd->cmdwaitqwoken = 1; | ||
1014 | wake_up(&priv->cur_cmd->cmdwait_q); | ||
1015 | } | ||
1016 | lbs_deb_main("done clearing commands\n"); | ||
1017 | spin_unlock_irqrestore(&priv->driver_lock, flags); | ||
1018 | |||
1019 | unregister_netdev(dev); | 1071 | unregister_netdev(dev); |
1020 | 1072 | ||
1021 | out: | 1073 | out: |
@@ -1036,7 +1088,7 @@ void lbs_queue_event(struct lbs_private *priv, u32 event) | |||
1036 | 1088 | ||
1037 | kfifo_in(&priv->event_fifo, (unsigned char *) &event, sizeof(u32)); | 1089 | kfifo_in(&priv->event_fifo, (unsigned char *) &event, sizeof(u32)); |
1038 | 1090 | ||
1039 | wake_up_interruptible(&priv->waitq); | 1091 | wake_up(&priv->waitq); |
1040 | 1092 | ||
1041 | spin_unlock_irqrestore(&priv->driver_lock, flags); | 1093 | spin_unlock_irqrestore(&priv->driver_lock, flags); |
1042 | lbs_deb_leave(LBS_DEB_THREAD); | 1094 | lbs_deb_leave(LBS_DEB_THREAD); |
@@ -1054,7 +1106,7 @@ void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx) | |||
1054 | BUG_ON(resp_idx > 1); | 1106 | BUG_ON(resp_idx > 1); |
1055 | priv->resp_idx = resp_idx; | 1107 | priv->resp_idx = resp_idx; |
1056 | 1108 | ||
1057 | wake_up_interruptible(&priv->waitq); | 1109 | wake_up(&priv->waitq); |
1058 | 1110 | ||
1059 | lbs_deb_leave(LBS_DEB_THREAD); | 1111 | lbs_deb_leave(LBS_DEB_THREAD); |
1060 | } | 1112 | } |
diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c index 8e3104d990fb..e87c031b298f 100644 --- a/drivers/net/wireless/libertas/mesh.c +++ b/drivers/net/wireless/libertas/mesh.c | |||
@@ -129,6 +129,19 @@ static int lbs_mesh_config(struct lbs_private *priv, uint16_t action, | |||
129 | return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv); | 129 | return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv); |
130 | } | 130 | } |
131 | 131 | ||
132 | int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel) | ||
133 | { | ||
134 | return lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, channel); | ||
135 | } | ||
136 | |||
137 | static uint16_t lbs_mesh_get_channel(struct lbs_private *priv) | ||
138 | { | ||
139 | struct wireless_dev *mesh_wdev = priv->mesh_dev->ieee80211_ptr; | ||
140 | if (mesh_wdev->channel) | ||
141 | return mesh_wdev->channel->hw_value; | ||
142 | else | ||
143 | return 1; | ||
144 | } | ||
132 | 145 | ||
133 | /*************************************************************************** | 146 | /*************************************************************************** |
134 | * Mesh sysfs support | 147 | * Mesh sysfs support |
@@ -812,7 +825,6 @@ static void lbs_persist_config_remove(struct net_device *dev) | |||
812 | */ | 825 | */ |
813 | int lbs_init_mesh(struct lbs_private *priv) | 826 | int lbs_init_mesh(struct lbs_private *priv) |
814 | { | 827 | { |
815 | struct net_device *dev = priv->dev; | ||
816 | int ret = 0; | 828 | int ret = 0; |
817 | 829 | ||
818 | lbs_deb_enter(LBS_DEB_MESH); | 830 | lbs_deb_enter(LBS_DEB_MESH); |
@@ -837,11 +849,9 @@ int lbs_init_mesh(struct lbs_private *priv) | |||
837 | useful */ | 849 | useful */ |
838 | 850 | ||
839 | priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID; | 851 | priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID; |
840 | if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, | 852 | if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1)) { |
841 | priv->channel)) { | ||
842 | priv->mesh_tlv = TLV_TYPE_MESH_ID; | 853 | priv->mesh_tlv = TLV_TYPE_MESH_ID; |
843 | if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, | 854 | if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1)) |
844 | priv->channel)) | ||
845 | priv->mesh_tlv = 0; | 855 | priv->mesh_tlv = 0; |
846 | } | 856 | } |
847 | } else | 857 | } else |
@@ -851,23 +861,16 @@ int lbs_init_mesh(struct lbs_private *priv) | |||
851 | * 0x100+37; Do not invoke command with old TLV. | 861 | * 0x100+37; Do not invoke command with old TLV. |
852 | */ | 862 | */ |
853 | priv->mesh_tlv = TLV_TYPE_MESH_ID; | 863 | priv->mesh_tlv = TLV_TYPE_MESH_ID; |
854 | if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, | 864 | if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1)) |
855 | priv->channel)) | ||
856 | priv->mesh_tlv = 0; | 865 | priv->mesh_tlv = 0; |
857 | } | 866 | } |
858 | 867 | ||
859 | /* Stop meshing until interface is brought up */ | 868 | /* Stop meshing until interface is brought up */ |
860 | lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, priv->channel); | 869 | lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, 1); |
861 | 870 | ||
862 | if (priv->mesh_tlv) { | 871 | if (priv->mesh_tlv) { |
863 | sprintf(priv->mesh_ssid, "mesh"); | 872 | sprintf(priv->mesh_ssid, "mesh"); |
864 | priv->mesh_ssid_len = 4; | 873 | priv->mesh_ssid_len = 4; |
865 | |||
866 | lbs_add_mesh(priv); | ||
867 | |||
868 | if (device_create_file(&dev->dev, &dev_attr_lbs_mesh)) | ||
869 | netdev_err(dev, "cannot register lbs_mesh attribute\n"); | ||
870 | |||
871 | ret = 1; | 874 | ret = 1; |
872 | } | 875 | } |
873 | 876 | ||
@@ -875,6 +878,13 @@ int lbs_init_mesh(struct lbs_private *priv) | |||
875 | return ret; | 878 | return ret; |
876 | } | 879 | } |
877 | 880 | ||
881 | void lbs_start_mesh(struct lbs_private *priv) | ||
882 | { | ||
883 | lbs_add_mesh(priv); | ||
884 | |||
885 | if (device_create_file(&priv->dev->dev, &dev_attr_lbs_mesh)) | ||
886 | netdev_err(priv->dev, "cannot register lbs_mesh attribute\n"); | ||
887 | } | ||
878 | 888 | ||
879 | int lbs_deinit_mesh(struct lbs_private *priv) | 889 | int lbs_deinit_mesh(struct lbs_private *priv) |
880 | { | 890 | { |
@@ -904,7 +914,8 @@ static int lbs_mesh_stop(struct net_device *dev) | |||
904 | struct lbs_private *priv = dev->ml_priv; | 914 | struct lbs_private *priv = dev->ml_priv; |
905 | 915 | ||
906 | lbs_deb_enter(LBS_DEB_MESH); | 916 | lbs_deb_enter(LBS_DEB_MESH); |
907 | lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, priv->channel); | 917 | lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, |
918 | lbs_mesh_get_channel(priv)); | ||
908 | 919 | ||
909 | spin_lock_irq(&priv->driver_lock); | 920 | spin_lock_irq(&priv->driver_lock); |
910 | 921 | ||
@@ -913,7 +924,9 @@ static int lbs_mesh_stop(struct net_device *dev) | |||
913 | 924 | ||
914 | spin_unlock_irq(&priv->driver_lock); | 925 | spin_unlock_irq(&priv->driver_lock); |
915 | 926 | ||
916 | schedule_work(&priv->mcast_work); | 927 | lbs_update_mcast(priv); |
928 | if (!lbs_iface_active(priv)) | ||
929 | lbs_stop_iface(priv); | ||
917 | 930 | ||
918 | lbs_deb_leave(LBS_DEB_MESH); | 931 | lbs_deb_leave(LBS_DEB_MESH); |
919 | return 0; | 932 | return 0; |
@@ -931,6 +944,11 @@ static int lbs_mesh_dev_open(struct net_device *dev) | |||
931 | int ret = 0; | 944 | int ret = 0; |
932 | 945 | ||
933 | lbs_deb_enter(LBS_DEB_NET); | 946 | lbs_deb_enter(LBS_DEB_NET); |
947 | if (!priv->iface_running) { | ||
948 | ret = lbs_start_iface(priv); | ||
949 | if (ret) | ||
950 | goto out; | ||
951 | } | ||
934 | 952 | ||
935 | spin_lock_irq(&priv->driver_lock); | 953 | spin_lock_irq(&priv->driver_lock); |
936 | 954 | ||
@@ -947,7 +965,8 @@ static int lbs_mesh_dev_open(struct net_device *dev) | |||
947 | 965 | ||
948 | spin_unlock_irq(&priv->driver_lock); | 966 | spin_unlock_irq(&priv->driver_lock); |
949 | 967 | ||
950 | ret = lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, priv->channel); | 968 | ret = lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, |
969 | lbs_mesh_get_channel(priv)); | ||
951 | 970 | ||
952 | out: | 971 | out: |
953 | lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); | 972 | lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); |
@@ -971,18 +990,32 @@ static const struct net_device_ops mesh_netdev_ops = { | |||
971 | static int lbs_add_mesh(struct lbs_private *priv) | 990 | static int lbs_add_mesh(struct lbs_private *priv) |
972 | { | 991 | { |
973 | struct net_device *mesh_dev = NULL; | 992 | struct net_device *mesh_dev = NULL; |
993 | struct wireless_dev *mesh_wdev; | ||
974 | int ret = 0; | 994 | int ret = 0; |
975 | 995 | ||
976 | lbs_deb_enter(LBS_DEB_MESH); | 996 | lbs_deb_enter(LBS_DEB_MESH); |
977 | 997 | ||
978 | /* Allocate a virtual mesh device */ | 998 | /* Allocate a virtual mesh device */ |
999 | mesh_wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); | ||
1000 | if (!mesh_wdev) { | ||
1001 | lbs_deb_mesh("init mshX wireless device failed\n"); | ||
1002 | ret = -ENOMEM; | ||
1003 | goto done; | ||
1004 | } | ||
1005 | |||
979 | mesh_dev = alloc_netdev(0, "msh%d", ether_setup); | 1006 | mesh_dev = alloc_netdev(0, "msh%d", ether_setup); |
980 | if (!mesh_dev) { | 1007 | if (!mesh_dev) { |
981 | lbs_deb_mesh("init mshX device failed\n"); | 1008 | lbs_deb_mesh("init mshX device failed\n"); |
982 | ret = -ENOMEM; | 1009 | ret = -ENOMEM; |
983 | goto done; | 1010 | goto err_free_wdev; |
984 | } | 1011 | } |
1012 | |||
1013 | mesh_wdev->iftype = NL80211_IFTYPE_MESH_POINT; | ||
1014 | mesh_wdev->wiphy = priv->wdev->wiphy; | ||
1015 | mesh_wdev->netdev = mesh_dev; | ||
1016 | |||
985 | mesh_dev->ml_priv = priv; | 1017 | mesh_dev->ml_priv = priv; |
1018 | mesh_dev->ieee80211_ptr = mesh_wdev; | ||
986 | priv->mesh_dev = mesh_dev; | 1019 | priv->mesh_dev = mesh_dev; |
987 | 1020 | ||
988 | mesh_dev->netdev_ops = &mesh_netdev_ops; | 1021 | mesh_dev->netdev_ops = &mesh_netdev_ops; |
@@ -996,7 +1029,7 @@ static int lbs_add_mesh(struct lbs_private *priv) | |||
996 | ret = register_netdev(mesh_dev); | 1029 | ret = register_netdev(mesh_dev); |
997 | if (ret) { | 1030 | if (ret) { |
998 | pr_err("cannot register mshX virtual interface\n"); | 1031 | pr_err("cannot register mshX virtual interface\n"); |
999 | goto err_free; | 1032 | goto err_free_netdev; |
1000 | } | 1033 | } |
1001 | 1034 | ||
1002 | ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group); | 1035 | ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group); |
@@ -1012,9 +1045,12 @@ static int lbs_add_mesh(struct lbs_private *priv) | |||
1012 | err_unregister: | 1045 | err_unregister: |
1013 | unregister_netdev(mesh_dev); | 1046 | unregister_netdev(mesh_dev); |
1014 | 1047 | ||
1015 | err_free: | 1048 | err_free_netdev: |
1016 | free_netdev(mesh_dev); | 1049 | free_netdev(mesh_dev); |
1017 | 1050 | ||
1051 | err_free_wdev: | ||
1052 | kfree(mesh_wdev); | ||
1053 | |||
1018 | done: | 1054 | done: |
1019 | lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret); | 1055 | lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret); |
1020 | return ret; | 1056 | return ret; |
@@ -1035,6 +1071,7 @@ void lbs_remove_mesh(struct lbs_private *priv) | |||
1035 | lbs_persist_config_remove(mesh_dev); | 1071 | lbs_persist_config_remove(mesh_dev); |
1036 | unregister_netdev(mesh_dev); | 1072 | unregister_netdev(mesh_dev); |
1037 | priv->mesh_dev = NULL; | 1073 | priv->mesh_dev = NULL; |
1074 | kfree(mesh_dev->ieee80211_ptr); | ||
1038 | free_netdev(mesh_dev); | 1075 | free_netdev(mesh_dev); |
1039 | lbs_deb_leave(LBS_DEB_MESH); | 1076 | lbs_deb_leave(LBS_DEB_MESH); |
1040 | } | 1077 | } |
diff --git a/drivers/net/wireless/libertas/mesh.h b/drivers/net/wireless/libertas/mesh.h index 50144913f2ab..6603f341c874 100644 --- a/drivers/net/wireless/libertas/mesh.h +++ b/drivers/net/wireless/libertas/mesh.h | |||
@@ -9,30 +9,25 @@ | |||
9 | #include <net/lib80211.h> | 9 | #include <net/lib80211.h> |
10 | 10 | ||
11 | #include "host.h" | 11 | #include "host.h" |
12 | #include "dev.h" | ||
12 | 13 | ||
13 | #ifdef CONFIG_LIBERTAS_MESH | 14 | #ifdef CONFIG_LIBERTAS_MESH |
14 | 15 | ||
15 | /* Mesh statistics */ | ||
16 | struct lbs_mesh_stats { | ||
17 | u32 fwd_bcast_cnt; /* Fwd: Broadcast counter */ | ||
18 | u32 fwd_unicast_cnt; /* Fwd: Unicast counter */ | ||
19 | u32 fwd_drop_ttl; /* Fwd: TTL zero */ | ||
20 | u32 fwd_drop_rbt; /* Fwd: Recently Broadcasted */ | ||
21 | u32 fwd_drop_noroute; /* Fwd: No route to Destination */ | ||
22 | u32 fwd_drop_nobuf; /* Fwd: Run out of internal buffers */ | ||
23 | u32 drop_blind; /* Rx: Dropped by blinding table */ | ||
24 | u32 tx_failed_cnt; /* Tx: Failed transmissions */ | ||
25 | }; | ||
26 | |||
27 | |||
28 | struct net_device; | 16 | struct net_device; |
29 | struct lbs_private; | ||
30 | 17 | ||
31 | int lbs_init_mesh(struct lbs_private *priv); | 18 | int lbs_init_mesh(struct lbs_private *priv); |
19 | void lbs_start_mesh(struct lbs_private *priv); | ||
32 | int lbs_deinit_mesh(struct lbs_private *priv); | 20 | int lbs_deinit_mesh(struct lbs_private *priv); |
33 | 21 | ||
34 | void lbs_remove_mesh(struct lbs_private *priv); | 22 | void lbs_remove_mesh(struct lbs_private *priv); |
35 | 23 | ||
24 | static inline bool lbs_mesh_activated(struct lbs_private *priv) | ||
25 | { | ||
26 | /* Mesh SSID is only programmed after successful init */ | ||
27 | return priv->mesh_ssid_len != 0; | ||
28 | } | ||
29 | |||
30 | int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel); | ||
36 | 31 | ||
37 | /* Sending / Receiving */ | 32 | /* Sending / Receiving */ |
38 | 33 | ||
@@ -67,11 +62,13 @@ void lbs_mesh_ethtool_get_strings(struct net_device *dev, | |||
67 | 62 | ||
68 | #define lbs_init_mesh(priv) | 63 | #define lbs_init_mesh(priv) |
69 | #define lbs_deinit_mesh(priv) | 64 | #define lbs_deinit_mesh(priv) |
65 | #define lbs_start_mesh(priv) | ||
70 | #define lbs_add_mesh(priv) | 66 | #define lbs_add_mesh(priv) |
71 | #define lbs_remove_mesh(priv) | 67 | #define lbs_remove_mesh(priv) |
72 | #define lbs_mesh_set_dev(priv, dev, rxpd) (dev) | 68 | #define lbs_mesh_set_dev(priv, dev, rxpd) (dev) |
73 | #define lbs_mesh_set_txpd(priv, dev, txpd) | 69 | #define lbs_mesh_set_txpd(priv, dev, txpd) |
74 | #define lbs_mesh_config(priv, enable, chan) | 70 | #define lbs_mesh_set_channel(priv, channel) (0) |
71 | #define lbs_mesh_activated(priv) (false) | ||
75 | 72 | ||
76 | #endif | 73 | #endif |
77 | 74 | ||
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index bfb8898ae518..62e10eeadd7e 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include "radiotap.h" | 15 | #include "radiotap.h" |
16 | #include "decl.h" | 16 | #include "decl.h" |
17 | #include "dev.h" | 17 | #include "dev.h" |
18 | #include "mesh.h" | ||
18 | 19 | ||
19 | struct eth803hdr { | 20 | struct eth803hdr { |
20 | u8 dest_addr[6]; | 21 | u8 dest_addr[6]; |
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index a6e85134cfe1..8f127520d786 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include "decl.h" | 12 | #include "decl.h" |
13 | #include "defs.h" | 13 | #include "defs.h" |
14 | #include "dev.h" | 14 | #include "dev.h" |
15 | #include "mesh.h" | ||
15 | 16 | ||
16 | /** | 17 | /** |
17 | * convert_radiotap_rate_to_mv - converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE | 18 | * convert_radiotap_rate_to_mv - converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE |
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 031cd89b1768..34b79fc91e39 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c | |||
@@ -612,6 +612,12 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, | |||
612 | rx_status.freq = data->channel->center_freq; | 612 | rx_status.freq = data->channel->center_freq; |
613 | rx_status.band = data->channel->band; | 613 | rx_status.band = data->channel->band; |
614 | rx_status.rate_idx = info->control.rates[0].idx; | 614 | rx_status.rate_idx = info->control.rates[0].idx; |
615 | if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS) | ||
616 | rx_status.flag |= RX_FLAG_HT; | ||
617 | if (info->control.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | ||
618 | rx_status.flag |= RX_FLAG_40MHZ; | ||
619 | if (info->control.rates[0].flags & IEEE80211_TX_RC_SHORT_GI) | ||
620 | rx_status.flag |= RX_FLAG_SHORT_GI; | ||
615 | /* TODO: simulate real signal strength (and optional packet loss) */ | 621 | /* TODO: simulate real signal strength (and optional packet loss) */ |
616 | rx_status.signal = data->power_level - 50; | 622 | rx_status.signal = data->power_level - 50; |
617 | 623 | ||
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 352d2c5da1fc..6fd53e4e3fe6 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c | |||
@@ -547,7 +547,7 @@ mwifiex_dump_station_info(struct mwifiex_private *priv, | |||
547 | sinfo->tx_bytes = priv->stats.tx_bytes; | 547 | sinfo->tx_bytes = priv->stats.tx_bytes; |
548 | sinfo->rx_packets = priv->stats.rx_packets; | 548 | sinfo->rx_packets = priv->stats.rx_packets; |
549 | sinfo->tx_packets = priv->stats.tx_packets; | 549 | sinfo->tx_packets = priv->stats.tx_packets; |
550 | sinfo->signal = priv->w_stats.qual.level; | 550 | sinfo->signal = priv->qual_level; |
551 | sinfo->txrate.legacy = rate.rate; | 551 | sinfo->txrate.legacy = rate.rate; |
552 | 552 | ||
553 | return ret; | 553 | return ret; |
@@ -793,139 +793,6 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv) | |||
793 | } | 793 | } |
794 | 794 | ||
795 | /* | 795 | /* |
796 | * This function informs the CFG802.11 subsystem of a new BSS connection. | ||
797 | * | ||
798 | * The following information are sent to the CFG802.11 subsystem | ||
799 | * to register the new BSS connection. If we do not register the new BSS, | ||
800 | * a kernel panic will result. | ||
801 | * - MAC address | ||
802 | * - Capabilities | ||
803 | * - Beacon period | ||
804 | * - RSSI value | ||
805 | * - Channel | ||
806 | * - Supported rates IE | ||
807 | * - Extended capabilities IE | ||
808 | * - DS parameter set IE | ||
809 | * - HT Capability IE | ||
810 | * - Vendor Specific IE (221) | ||
811 | * - WPA IE | ||
812 | * - RSN IE | ||
813 | */ | ||
814 | static int mwifiex_inform_bss_from_scan_result(struct mwifiex_private *priv, | ||
815 | struct mwifiex_802_11_ssid *ssid) | ||
816 | { | ||
817 | struct mwifiex_bssdescriptor *scan_table; | ||
818 | int i, j; | ||
819 | struct ieee80211_channel *chan; | ||
820 | u8 *ie, *ie_buf; | ||
821 | u32 ie_len; | ||
822 | u8 *beacon; | ||
823 | int beacon_size; | ||
824 | u8 element_id, element_len; | ||
825 | |||
826 | #define MAX_IE_BUF 2048 | ||
827 | ie_buf = kzalloc(MAX_IE_BUF, GFP_KERNEL); | ||
828 | if (!ie_buf) { | ||
829 | dev_err(priv->adapter->dev, "%s: failed to alloc ie_buf\n", | ||
830 | __func__); | ||
831 | return -ENOMEM; | ||
832 | } | ||
833 | |||
834 | scan_table = priv->adapter->scan_table; | ||
835 | for (i = 0; i < priv->adapter->num_in_scan_table; i++) { | ||
836 | if (ssid) { | ||
837 | /* Inform specific BSS only */ | ||
838 | if (memcmp(ssid->ssid, scan_table[i].ssid.ssid, | ||
839 | ssid->ssid_len)) | ||
840 | continue; | ||
841 | } | ||
842 | memset(ie_buf, 0, MAX_IE_BUF); | ||
843 | ie_buf[0] = WLAN_EID_SSID; | ||
844 | ie_buf[1] = scan_table[i].ssid.ssid_len; | ||
845 | memcpy(&ie_buf[sizeof(struct ieee_types_header)], | ||
846 | scan_table[i].ssid.ssid, ie_buf[1]); | ||
847 | |||
848 | ie = ie_buf + ie_buf[1] + sizeof(struct ieee_types_header); | ||
849 | ie_len = ie_buf[1] + sizeof(struct ieee_types_header); | ||
850 | |||
851 | ie[0] = WLAN_EID_SUPP_RATES; | ||
852 | |||
853 | for (j = 0; j < sizeof(scan_table[i].supported_rates); j++) { | ||
854 | if (!scan_table[i].supported_rates[j]) | ||
855 | break; | ||
856 | else | ||
857 | ie[j + sizeof(struct ieee_types_header)] = | ||
858 | scan_table[i].supported_rates[j]; | ||
859 | } | ||
860 | |||
861 | ie[1] = j; | ||
862 | ie_len += ie[1] + sizeof(struct ieee_types_header); | ||
863 | |||
864 | beacon = scan_table[i].beacon_buf; | ||
865 | beacon_size = scan_table[i].beacon_buf_size; | ||
866 | |||
867 | /* Skip time stamp, beacon interval and capability */ | ||
868 | |||
869 | if (beacon) { | ||
870 | beacon += sizeof(scan_table[i].beacon_period) | ||
871 | + sizeof(scan_table[i].time_stamp) + | ||
872 | +sizeof(scan_table[i].cap_info_bitmap); | ||
873 | |||
874 | beacon_size -= sizeof(scan_table[i].beacon_period) | ||
875 | + sizeof(scan_table[i].time_stamp) | ||
876 | + sizeof(scan_table[i].cap_info_bitmap); | ||
877 | } | ||
878 | |||
879 | while (beacon_size >= sizeof(struct ieee_types_header)) { | ||
880 | ie = ie_buf + ie_len; | ||
881 | element_id = *beacon; | ||
882 | element_len = *(beacon + 1); | ||
883 | if (beacon_size < (int) element_len + | ||
884 | sizeof(struct ieee_types_header)) { | ||
885 | dev_err(priv->adapter->dev, "%s: in processing" | ||
886 | " IE, bytes left < IE length\n", | ||
887 | __func__); | ||
888 | break; | ||
889 | } | ||
890 | switch (element_id) { | ||
891 | case WLAN_EID_EXT_CAPABILITY: | ||
892 | case WLAN_EID_DS_PARAMS: | ||
893 | case WLAN_EID_HT_CAPABILITY: | ||
894 | case WLAN_EID_VENDOR_SPECIFIC: | ||
895 | case WLAN_EID_RSN: | ||
896 | case WLAN_EID_BSS_AC_ACCESS_DELAY: | ||
897 | ie[0] = element_id; | ||
898 | ie[1] = element_len; | ||
899 | memcpy(&ie[sizeof(struct ieee_types_header)], | ||
900 | (u8 *) beacon | ||
901 | + sizeof(struct ieee_types_header), | ||
902 | element_len); | ||
903 | ie_len += ie[1] + | ||
904 | sizeof(struct ieee_types_header); | ||
905 | break; | ||
906 | default: | ||
907 | break; | ||
908 | } | ||
909 | beacon += element_len + | ||
910 | sizeof(struct ieee_types_header); | ||
911 | beacon_size -= element_len + | ||
912 | sizeof(struct ieee_types_header); | ||
913 | } | ||
914 | chan = ieee80211_get_channel(priv->wdev->wiphy, | ||
915 | scan_table[i].freq); | ||
916 | cfg80211_inform_bss(priv->wdev->wiphy, chan, | ||
917 | scan_table[i].mac_address, | ||
918 | 0, scan_table[i].cap_info_bitmap, | ||
919 | scan_table[i].beacon_period, | ||
920 | ie_buf, ie_len, | ||
921 | scan_table[i].rssi, GFP_KERNEL); | ||
922 | } | ||
923 | |||
924 | kfree(ie_buf); | ||
925 | return 0; | ||
926 | } | ||
927 | |||
928 | /* | ||
929 | * This function connects with a BSS. | 796 | * This function connects with a BSS. |
930 | * | 797 | * |
931 | * This function handles both Infra and Ad-Hoc modes. It also performs | 798 | * This function handles both Infra and Ad-Hoc modes. It also performs |
@@ -937,8 +804,7 @@ static int mwifiex_inform_bss_from_scan_result(struct mwifiex_private *priv, | |||
937 | * For Infra mode, the function returns failure if the specified SSID | 804 | * For Infra mode, the function returns failure if the specified SSID |
938 | * is not found in scan table. However, for Ad-Hoc mode, it can create | 805 | * is not found in scan table. However, for Ad-Hoc mode, it can create |
939 | * the IBSS if it does not exist. On successful completion in either case, | 806 | * the IBSS if it does not exist. On successful completion in either case, |
940 | * the function notifies the CFG802.11 subsystem of the new BSS connection, | 807 | * the function notifies the CFG802.11 subsystem of the new BSS connection. |
941 | * otherwise the kernel will panic. | ||
942 | */ | 808 | */ |
943 | static int | 809 | static int |
944 | mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, | 810 | mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, |
@@ -946,11 +812,11 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, | |||
946 | struct cfg80211_connect_params *sme, bool privacy) | 812 | struct cfg80211_connect_params *sme, bool privacy) |
947 | { | 813 | { |
948 | struct mwifiex_802_11_ssid req_ssid; | 814 | struct mwifiex_802_11_ssid req_ssid; |
949 | struct mwifiex_ssid_bssid ssid_bssid; | ||
950 | int ret, auth_type = 0; | 815 | int ret, auth_type = 0; |
816 | struct cfg80211_bss *bss = NULL; | ||
817 | u8 is_scanning_required = 0; | ||
951 | 818 | ||
952 | memset(&req_ssid, 0, sizeof(struct mwifiex_802_11_ssid)); | 819 | memset(&req_ssid, 0, sizeof(struct mwifiex_802_11_ssid)); |
953 | memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid)); | ||
954 | 820 | ||
955 | req_ssid.ssid_len = ssid_len; | 821 | req_ssid.ssid_len = ssid_len; |
956 | if (ssid_len > IEEE80211_MAX_SSID_LEN) { | 822 | if (ssid_len > IEEE80211_MAX_SSID_LEN) { |
@@ -1028,30 +894,48 @@ done: | |||
1028 | return -EFAULT; | 894 | return -EFAULT; |
1029 | } | 895 | } |
1030 | 896 | ||
897 | /* | ||
898 | * Scan entries are valid for some time (15 sec). So we can save one | ||
899 | * active scan time if we just try cfg80211_get_bss first. If it fails | ||
900 | * then request scan and cfg80211_get_bss() again for final output. | ||
901 | */ | ||
902 | while (1) { | ||
903 | if (is_scanning_required) { | ||
904 | /* Do specific SSID scanning */ | ||
905 | if (mwifiex_request_scan(priv, &req_ssid)) { | ||
906 | dev_err(priv->adapter->dev, "scan error\n"); | ||
907 | return -EFAULT; | ||
908 | } | ||
909 | } | ||
1031 | 910 | ||
1032 | memcpy(&ssid_bssid.ssid, &req_ssid, sizeof(struct mwifiex_802_11_ssid)); | 911 | /* Find the BSS we want using available scan results */ |
1033 | 912 | if (mode == NL80211_IFTYPE_ADHOC) | |
1034 | if (mode != NL80211_IFTYPE_ADHOC) { | 913 | bss = cfg80211_get_bss(priv->wdev->wiphy, channel, |
1035 | if (mwifiex_find_best_bss(priv, &ssid_bssid)) | 914 | bssid, ssid, ssid_len, |
1036 | return -EFAULT; | 915 | WLAN_CAPABILITY_IBSS, |
1037 | /* Inform the BSS information to kernel, otherwise | 916 | WLAN_CAPABILITY_IBSS); |
1038 | * kernel will give a panic after successful assoc */ | 917 | else |
1039 | if (mwifiex_inform_bss_from_scan_result(priv, &req_ssid)) | 918 | bss = cfg80211_get_bss(priv->wdev->wiphy, channel, |
1040 | return -EFAULT; | 919 | bssid, ssid, ssid_len, |
920 | WLAN_CAPABILITY_ESS, | ||
921 | WLAN_CAPABILITY_ESS); | ||
922 | |||
923 | if (!bss) { | ||
924 | if (is_scanning_required) { | ||
925 | dev_warn(priv->adapter->dev, "assoc: requested " | ||
926 | "bss not found in scan results\n"); | ||
927 | break; | ||
928 | } | ||
929 | is_scanning_required = 1; | ||
930 | } else { | ||
931 | dev_dbg(priv->adapter->dev, "info: trying to associate to %s and bssid %pM\n", | ||
932 | (char *) req_ssid.ssid, bss->bssid); | ||
933 | memcpy(&priv->cfg_bssid, bss->bssid, ETH_ALEN); | ||
934 | break; | ||
935 | } | ||
1041 | } | 936 | } |
1042 | 937 | ||
1043 | dev_dbg(priv->adapter->dev, "info: trying to associate to %s and bssid %pM\n", | 938 | if (mwifiex_bss_start(priv, bss, &req_ssid)) |
1044 | (char *) req_ssid.ssid, ssid_bssid.bssid); | ||
1045 | |||
1046 | memcpy(&priv->cfg_bssid, ssid_bssid.bssid, 6); | ||
1047 | |||
1048 | /* Connect to BSS by ESSID */ | ||
1049 | memset(&ssid_bssid.bssid, 0, ETH_ALEN); | ||
1050 | |||
1051 | if (!netif_queue_stopped(priv->netdev)) | ||
1052 | netif_stop_queue(priv->netdev); | ||
1053 | |||
1054 | if (mwifiex_bss_start(priv, &ssid_bssid)) | ||
1055 | return -EFAULT; | 939 | return -EFAULT; |
1056 | 940 | ||
1057 | if (mode == NL80211_IFTYPE_ADHOC) { | 941 | if (mode == NL80211_IFTYPE_ADHOC) { |
@@ -1416,13 +1300,8 @@ mwifiex_cfg80211_results(struct work_struct *work) | |||
1416 | MWIFIEX_SCAN_TYPE_ACTIVE; | 1300 | MWIFIEX_SCAN_TYPE_ACTIVE; |
1417 | scan_req->chan_list[i].scan_time = 0; | 1301 | scan_req->chan_list[i].scan_time = 0; |
1418 | } | 1302 | } |
1419 | if (mwifiex_set_user_scan_ioctl(priv, scan_req)) { | 1303 | if (mwifiex_set_user_scan_ioctl(priv, scan_req)) |
1420 | ret = -EFAULT; | 1304 | ret = -EFAULT; |
1421 | goto done; | ||
1422 | } | ||
1423 | if (mwifiex_inform_bss_from_scan_result(priv, NULL)) | ||
1424 | ret = -EFAULT; | ||
1425 | done: | ||
1426 | priv->scan_result_status = ret; | 1305 | priv->scan_result_status = ret; |
1427 | dev_dbg(priv->adapter->dev, "info: %s: sending scan results\n", | 1306 | dev_dbg(priv->adapter->dev, "info: %s: sending scan results\n", |
1428 | __func__); | 1307 | __func__); |
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 4fee0993b186..f23ec72ed4fe 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h | |||
@@ -821,6 +821,14 @@ struct host_cmd_ds_txpwr_cfg { | |||
821 | __le32 mode; | 821 | __le32 mode; |
822 | } __packed; | 822 | } __packed; |
823 | 823 | ||
824 | struct mwifiex_bcn_param { | ||
825 | u8 bssid[ETH_ALEN]; | ||
826 | u8 rssi; | ||
827 | __le32 timestamp[2]; | ||
828 | __le16 beacon_period; | ||
829 | __le16 cap_info_bitmap; | ||
830 | } __packed; | ||
831 | |||
824 | #define MWIFIEX_USER_SCAN_CHAN_MAX 50 | 832 | #define MWIFIEX_USER_SCAN_CHAN_MAX 50 |
825 | 833 | ||
826 | #define MWIFIEX_MAX_SSID_LIST_LENGTH 10 | 834 | #define MWIFIEX_MAX_SSID_LIST_LENGTH 10 |
@@ -862,13 +870,6 @@ struct mwifiex_user_scan_ssid { | |||
862 | 870 | ||
863 | struct mwifiex_user_scan_cfg { | 871 | struct mwifiex_user_scan_cfg { |
864 | /* | 872 | /* |
865 | * Flag set to keep the previous scan table intact | ||
866 | * | ||
867 | * If set, the scan results will accumulate, replacing any previous | ||
868 | * matched entries for a BSS with the new scan data | ||
869 | */ | ||
870 | u8 keep_previous_scan; | ||
871 | /* | ||
872 | * BSS mode to be sent in the firmware command | 873 | * BSS mode to be sent in the firmware command |
873 | */ | 874 | */ |
874 | u8 bss_mode; | 875 | u8 bss_mode; |
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 3f1559e61320..26e685a31bc0 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c | |||
@@ -152,19 +152,6 @@ static int mwifiex_init_priv(struct mwifiex_private *priv) | |||
152 | static int mwifiex_allocate_adapter(struct mwifiex_adapter *adapter) | 152 | static int mwifiex_allocate_adapter(struct mwifiex_adapter *adapter) |
153 | { | 153 | { |
154 | int ret; | 154 | int ret; |
155 | u32 buf_size; | ||
156 | struct mwifiex_bssdescriptor *temp_scan_table; | ||
157 | |||
158 | /* Allocate buffer to store the BSSID list */ | ||
159 | buf_size = sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP; | ||
160 | temp_scan_table = kzalloc(buf_size, GFP_KERNEL); | ||
161 | if (!temp_scan_table) { | ||
162 | dev_err(adapter->dev, "%s: failed to alloc temp_scan_table\n", | ||
163 | __func__); | ||
164 | return -ENOMEM; | ||
165 | } | ||
166 | |||
167 | adapter->scan_table = temp_scan_table; | ||
168 | 155 | ||
169 | /* Allocate command buffer */ | 156 | /* Allocate command buffer */ |
170 | ret = mwifiex_alloc_cmd_buffer(adapter); | 157 | ret = mwifiex_alloc_cmd_buffer(adapter); |
@@ -222,14 +209,8 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) | |||
222 | adapter->active_scan_time = MWIFIEX_ACTIVE_SCAN_CHAN_TIME; | 209 | adapter->active_scan_time = MWIFIEX_ACTIVE_SCAN_CHAN_TIME; |
223 | adapter->passive_scan_time = MWIFIEX_PASSIVE_SCAN_CHAN_TIME; | 210 | adapter->passive_scan_time = MWIFIEX_PASSIVE_SCAN_CHAN_TIME; |
224 | 211 | ||
225 | adapter->num_in_scan_table = 0; | ||
226 | memset(adapter->scan_table, 0, | ||
227 | (sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP)); | ||
228 | adapter->scan_probes = 1; | 212 | adapter->scan_probes = 1; |
229 | 213 | ||
230 | memset(adapter->bcn_buf, 0, sizeof(adapter->bcn_buf)); | ||
231 | adapter->bcn_buf_end = adapter->bcn_buf; | ||
232 | |||
233 | adapter->multiple_dtim = 1; | 214 | adapter->multiple_dtim = 1; |
234 | 215 | ||
235 | adapter->local_listen_interval = 0; /* default value in firmware | 216 | adapter->local_listen_interval = 0; /* default value in firmware |
@@ -326,8 +307,6 @@ mwifiex_free_adapter(struct mwifiex_adapter *adapter) | |||
326 | del_timer(&adapter->cmd_timer); | 307 | del_timer(&adapter->cmd_timer); |
327 | 308 | ||
328 | dev_dbg(adapter->dev, "info: free scan table\n"); | 309 | dev_dbg(adapter->dev, "info: free scan table\n"); |
329 | kfree(adapter->scan_table); | ||
330 | adapter->scan_table = NULL; | ||
331 | 310 | ||
332 | adapter->if_ops.cleanup_if(adapter); | 311 | adapter->if_ops.cleanup_if(adapter); |
333 | 312 | ||
diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index f6bcc868562f..e0b68e7c8ca2 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h | |||
@@ -134,7 +134,6 @@ struct mwifiex_ver_ext { | |||
134 | struct mwifiex_bss_info { | 134 | struct mwifiex_bss_info { |
135 | u32 bss_mode; | 135 | u32 bss_mode; |
136 | struct mwifiex_802_11_ssid ssid; | 136 | struct mwifiex_802_11_ssid ssid; |
137 | u32 scan_table_idx; | ||
138 | u32 bss_chan; | 137 | u32 bss_chan; |
139 | u32 region_code; | 138 | u32 region_code; |
140 | u32 media_connected; | 139 | u32 media_connected; |
@@ -307,10 +306,12 @@ struct mwifiex_ds_read_eeprom { | |||
307 | u8 value[MAX_EEPROM_DATA]; | 306 | u8 value[MAX_EEPROM_DATA]; |
308 | }; | 307 | }; |
309 | 308 | ||
309 | #define IEEE_MAX_IE_SIZE 256 | ||
310 | |||
310 | struct mwifiex_ds_misc_gen_ie { | 311 | struct mwifiex_ds_misc_gen_ie { |
311 | u32 type; | 312 | u32 type; |
312 | u32 len; | 313 | u32 len; |
313 | u8 ie_data[IW_CUSTOM_MAX]; | 314 | u8 ie_data[IEEE_MAX_IE_SIZE]; |
314 | }; | 315 | }; |
315 | 316 | ||
316 | struct mwifiex_ds_misc_cmd { | 317 | struct mwifiex_ds_misc_cmd { |
diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 644e2e405cb5..5cdad92277fa 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c | |||
@@ -224,32 +224,6 @@ mwifiex_setup_rates_from_bssdesc(struct mwifiex_private *priv, | |||
224 | } | 224 | } |
225 | 225 | ||
226 | /* | 226 | /* |
227 | * This function updates the scan entry TSF timestamps to reflect | ||
228 | * a new association. | ||
229 | */ | ||
230 | static void | ||
231 | mwifiex_update_tsf_timestamps(struct mwifiex_private *priv, | ||
232 | struct mwifiex_bssdescriptor *new_bss_desc) | ||
233 | { | ||
234 | struct mwifiex_adapter *adapter = priv->adapter; | ||
235 | u32 table_idx; | ||
236 | long long new_tsf_base; | ||
237 | signed long long tsf_delta; | ||
238 | |||
239 | memcpy(&new_tsf_base, new_bss_desc->time_stamp, sizeof(new_tsf_base)); | ||
240 | |||
241 | tsf_delta = new_tsf_base - new_bss_desc->network_tsf; | ||
242 | |||
243 | dev_dbg(adapter->dev, "info: TSF: update TSF timestamps, " | ||
244 | "0x%016llx -> 0x%016llx\n", | ||
245 | new_bss_desc->network_tsf, new_tsf_base); | ||
246 | |||
247 | for (table_idx = 0; table_idx < adapter->num_in_scan_table; | ||
248 | table_idx++) | ||
249 | adapter->scan_table[table_idx].network_tsf += tsf_delta; | ||
250 | } | ||
251 | |||
252 | /* | ||
253 | * This function appends a WAPI IE. | 227 | * This function appends a WAPI IE. |
254 | * | 228 | * |
255 | * This function is called from the network join command preparation routine. | 229 | * This function is called from the network join command preparation routine. |
@@ -639,12 +613,6 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, | |||
639 | 613 | ||
640 | priv->curr_bss_params.band = (u8) bss_desc->bss_band; | 614 | priv->curr_bss_params.band = (u8) bss_desc->bss_band; |
641 | 615 | ||
642 | /* | ||
643 | * Adjust the timestamps in the scan table to be relative to the newly | ||
644 | * associated AP's TSF | ||
645 | */ | ||
646 | mwifiex_update_tsf_timestamps(priv, bss_desc); | ||
647 | |||
648 | if (bss_desc->wmm_ie.vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC) | 616 | if (bss_desc->wmm_ie.vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC) |
649 | priv->curr_bss_params.wmm_enabled = true; | 617 | priv->curr_bss_params.wmm_enabled = true; |
650 | else | 618 | else |
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 0415e3d1c317..48b4d95219fb 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c | |||
@@ -849,6 +849,7 @@ mwifiex_add_card(void *card, struct semaphore *sem, | |||
849 | { | 849 | { |
850 | int i; | 850 | int i; |
851 | struct mwifiex_adapter *adapter; | 851 | struct mwifiex_adapter *adapter; |
852 | char fmt[64]; | ||
852 | 853 | ||
853 | if (down_interruptible(sem)) | 854 | if (down_interruptible(sem)) |
854 | goto exit_sem_err; | 855 | goto exit_sem_err; |
@@ -897,6 +898,9 @@ mwifiex_add_card(void *card, struct semaphore *sem, | |||
897 | 898 | ||
898 | up(sem); | 899 | up(sem); |
899 | 900 | ||
901 | mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1); | ||
902 | dev_notice(adapter->dev, "driver_version = %s\n", fmt); | ||
903 | |||
900 | return 0; | 904 | return 0; |
901 | 905 | ||
902 | err_add_intf: | 906 | err_add_intf: |
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 2215c3c97354..e6b6c0cfb63e 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h | |||
@@ -54,6 +54,8 @@ struct mwifiex_drv_mode { | |||
54 | }; | 54 | }; |
55 | 55 | ||
56 | 56 | ||
57 | #define MWIFIEX_MAX_AP 64 | ||
58 | |||
57 | #define MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT (5 * HZ) | 59 | #define MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT (5 * HZ) |
58 | 60 | ||
59 | #define MWIFIEX_TIMER_10S 10000 | 61 | #define MWIFIEX_TIMER_10S 10000 |
@@ -227,27 +229,10 @@ struct ieee_types_header { | |||
227 | u8 len; | 229 | u8 len; |
228 | } __packed; | 230 | } __packed; |
229 | 231 | ||
230 | struct ieee_obss_scan_param { | ||
231 | u16 obss_scan_passive_dwell; | ||
232 | u16 obss_scan_active_dwell; | ||
233 | u16 bss_chan_width_trigger_scan_int; | ||
234 | u16 obss_scan_passive_total; | ||
235 | u16 obss_scan_active_total; | ||
236 | u16 bss_width_chan_trans_delay; | ||
237 | u16 obss_scan_active_threshold; | ||
238 | } __packed; | ||
239 | |||
240 | struct ieee_types_obss_scan_param { | ||
241 | struct ieee_types_header ieee_hdr; | ||
242 | struct ieee_obss_scan_param obss_scan; | ||
243 | } __packed; | ||
244 | |||
245 | #define MWIFIEX_SUPPORTED_RATES 14 | 232 | #define MWIFIEX_SUPPORTED_RATES 14 |
246 | 233 | ||
247 | #define MWIFIEX_SUPPORTED_RATES_EXT 32 | 234 | #define MWIFIEX_SUPPORTED_RATES_EXT 32 |
248 | 235 | ||
249 | #define IEEE_MAX_IE_SIZE 256 | ||
250 | |||
251 | struct ieee_types_vendor_specific { | 236 | struct ieee_types_vendor_specific { |
252 | struct ieee_types_vendor_header vend_hdr; | 237 | struct ieee_types_vendor_header vend_hdr; |
253 | u8 data[IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_vendor_header)]; | 238 | u8 data[IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_vendor_header)]; |
@@ -291,8 +276,6 @@ struct mwifiex_bssdescriptor { | |||
291 | u16 bss_co_2040_offset; | 276 | u16 bss_co_2040_offset; |
292 | u8 *bcn_ext_cap; | 277 | u8 *bcn_ext_cap; |
293 | u16 ext_cap_offset; | 278 | u16 ext_cap_offset; |
294 | struct ieee_types_obss_scan_param *bcn_obss_scan; | ||
295 | u16 overlap_bss_offset; | ||
296 | struct ieee_types_vendor_specific *bcn_wpa_ie; | 279 | struct ieee_types_vendor_specific *bcn_wpa_ie; |
297 | u16 wpa_offset; | 280 | u16 wpa_offset; |
298 | struct ieee_types_generic *bcn_rsn_ie; | 281 | struct ieee_types_generic *bcn_rsn_ie; |
@@ -301,8 +284,6 @@ struct mwifiex_bssdescriptor { | |||
301 | u16 wapi_offset; | 284 | u16 wapi_offset; |
302 | u8 *beacon_buf; | 285 | u8 *beacon_buf; |
303 | u32 beacon_buf_size; | 286 | u32 beacon_buf_size; |
304 | u32 beacon_buf_size_max; | ||
305 | |||
306 | }; | 287 | }; |
307 | 288 | ||
308 | struct mwifiex_current_bss_params { | 289 | struct mwifiex_current_bss_params { |
@@ -468,7 +449,7 @@ struct mwifiex_private { | |||
468 | struct dentry *dfs_dev_dir; | 449 | struct dentry *dfs_dev_dir; |
469 | #endif | 450 | #endif |
470 | u8 nick_name[16]; | 451 | u8 nick_name[16]; |
471 | struct iw_statistics w_stats; | 452 | u8 qual_level, qual_noise; |
472 | u16 current_key_index; | 453 | u16 current_key_index; |
473 | struct semaphore async_sem; | 454 | struct semaphore async_sem; |
474 | u8 scan_pending_on_block; | 455 | u8 scan_pending_on_block; |
@@ -624,15 +605,11 @@ struct mwifiex_adapter { | |||
624 | u32 scan_processing; | 605 | u32 scan_processing; |
625 | u16 region_code; | 606 | u16 region_code; |
626 | struct mwifiex_802_11d_domain_reg domain_reg; | 607 | struct mwifiex_802_11d_domain_reg domain_reg; |
627 | struct mwifiex_bssdescriptor *scan_table; | ||
628 | u32 num_in_scan_table; | ||
629 | u16 scan_probes; | 608 | u16 scan_probes; |
630 | u32 scan_mode; | 609 | u32 scan_mode; |
631 | u16 specific_scan_time; | 610 | u16 specific_scan_time; |
632 | u16 active_scan_time; | 611 | u16 active_scan_time; |
633 | u16 passive_scan_time; | 612 | u16 passive_scan_time; |
634 | u8 bcn_buf[MAX_SCAN_BEACON_BUFFER]; | ||
635 | u8 *bcn_buf_end; | ||
636 | u8 fw_bands; | 613 | u8 fw_bands; |
637 | u8 adhoc_start_band; | 614 | u8 adhoc_start_band; |
638 | u8 config_bands; | 615 | u8 config_bands; |
@@ -765,13 +742,6 @@ void mwifiex_queue_scan_cmd(struct mwifiex_private *priv, | |||
765 | struct cmd_ctrl_node *cmd_node); | 742 | struct cmd_ctrl_node *cmd_node); |
766 | int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, | 743 | int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, |
767 | struct host_cmd_ds_command *resp); | 744 | struct host_cmd_ds_command *resp); |
768 | s32 mwifiex_find_ssid_in_list(struct mwifiex_private *priv, | ||
769 | struct mwifiex_802_11_ssid *ssid, u8 *bssid, | ||
770 | u32 mode); | ||
771 | s32 mwifiex_find_bssid_in_list(struct mwifiex_private *priv, u8 *bssid, | ||
772 | u32 mode); | ||
773 | int mwifiex_find_best_network(struct mwifiex_private *priv, | ||
774 | struct mwifiex_ssid_bssid *req_ssid_bssid); | ||
775 | s32 mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1, | 745 | s32 mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1, |
776 | struct mwifiex_802_11_ssid *ssid2); | 746 | struct mwifiex_802_11_ssid *ssid2); |
777 | int mwifiex_associate(struct mwifiex_private *priv, | 747 | int mwifiex_associate(struct mwifiex_private *priv, |
@@ -782,7 +752,6 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, | |||
782 | int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, | 752 | int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, |
783 | struct host_cmd_ds_command *resp); | 753 | struct host_cmd_ds_command *resp); |
784 | void mwifiex_reset_connect_state(struct mwifiex_private *priv); | 754 | void mwifiex_reset_connect_state(struct mwifiex_private *priv); |
785 | void mwifiex_2040_coex_event(struct mwifiex_private *priv); | ||
786 | u8 mwifiex_band_to_radio_type(u8 band); | 755 | u8 mwifiex_band_to_radio_type(u8 band); |
787 | int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac); | 756 | int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac); |
788 | int mwifiex_adhoc_start(struct mwifiex_private *priv, | 757 | int mwifiex_adhoc_start(struct mwifiex_private *priv, |
@@ -922,8 +891,8 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv, | |||
922 | int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist, | 891 | int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist, |
923 | struct net_device *dev); | 892 | struct net_device *dev); |
924 | int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter); | 893 | int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter); |
925 | int mwifiex_bss_start(struct mwifiex_private *priv, | 894 | int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, |
926 | struct mwifiex_ssid_bssid *ssid_bssid); | 895 | struct mwifiex_802_11_ssid *req_ssid); |
927 | int mwifiex_set_hs_params(struct mwifiex_private *priv, | 896 | int mwifiex_set_hs_params(struct mwifiex_private *priv, |
928 | u16 action, int cmd_type, | 897 | u16 action, int cmd_type, |
929 | struct mwifiex_ds_hs_cfg *hscfg); | 898 | struct mwifiex_ds_hs_cfg *hscfg); |
@@ -934,8 +903,6 @@ int mwifiex_get_signal_info(struct mwifiex_private *priv, | |||
934 | struct mwifiex_ds_get_signal *signal); | 903 | struct mwifiex_ds_get_signal *signal); |
935 | int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, | 904 | int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, |
936 | struct mwifiex_rate_cfg *rate); | 905 | struct mwifiex_rate_cfg *rate); |
937 | int mwifiex_find_best_bss(struct mwifiex_private *priv, | ||
938 | struct mwifiex_ssid_bssid *ssid_bssid); | ||
939 | int mwifiex_request_scan(struct mwifiex_private *priv, | 906 | int mwifiex_request_scan(struct mwifiex_private *priv, |
940 | struct mwifiex_802_11_ssid *req_ssid); | 907 | struct mwifiex_802_11_ssid *req_ssid); |
941 | int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv, | 908 | int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv, |
@@ -984,12 +951,20 @@ int mwifiex_main_process(struct mwifiex_adapter *); | |||
984 | 951 | ||
985 | int mwifiex_bss_set_channel(struct mwifiex_private *, | 952 | int mwifiex_bss_set_channel(struct mwifiex_private *, |
986 | struct mwifiex_chan_freq_power *cfp); | 953 | struct mwifiex_chan_freq_power *cfp); |
987 | int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *, | ||
988 | struct mwifiex_ssid_bssid *); | ||
989 | int mwifiex_set_radio_band_cfg(struct mwifiex_private *, | 954 | int mwifiex_set_radio_band_cfg(struct mwifiex_private *, |
990 | struct mwifiex_ds_band_cfg *); | 955 | struct mwifiex_ds_band_cfg *); |
991 | int mwifiex_get_bss_info(struct mwifiex_private *, | 956 | int mwifiex_get_bss_info(struct mwifiex_private *, |
992 | struct mwifiex_bss_info *); | 957 | struct mwifiex_bss_info *); |
958 | int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, | ||
959 | u8 *bssid, s32 rssi, u8 *ie_buf, | ||
960 | size_t ie_len, u16 beacon_period, | ||
961 | u16 cap_info_bitmap, | ||
962 | struct mwifiex_bssdescriptor *bss_desc); | ||
963 | int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, | ||
964 | struct mwifiex_bssdescriptor *bss_entry, | ||
965 | u8 *ie_buf, u32 ie_len); | ||
966 | int mwifiex_check_network_compatibility(struct mwifiex_private *priv, | ||
967 | struct mwifiex_bssdescriptor *bss_desc); | ||
993 | 968 | ||
994 | #ifdef CONFIG_DEBUG_FS | 969 | #ifdef CONFIG_DEBUG_FS |
995 | void mwifiex_debugfs_init(void); | 970 | void mwifiex_debugfs_init(void); |
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 6f88c8ab5de5..b28241c6e737 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c | |||
@@ -172,36 +172,6 @@ mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1, | |||
172 | } | 172 | } |
173 | 173 | ||
174 | /* | 174 | /* |
175 | * Sends IOCTL request to get the best BSS. | ||
176 | * | ||
177 | * This function allocates the IOCTL request buffer, fills it | ||
178 | * with requisite parameters and calls the IOCTL handler. | ||
179 | */ | ||
180 | int mwifiex_find_best_bss(struct mwifiex_private *priv, | ||
181 | struct mwifiex_ssid_bssid *ssid_bssid) | ||
182 | { | ||
183 | struct mwifiex_ssid_bssid tmp_ssid_bssid; | ||
184 | u8 *mac; | ||
185 | |||
186 | if (!ssid_bssid) | ||
187 | return -1; | ||
188 | |||
189 | memcpy(&tmp_ssid_bssid, ssid_bssid, | ||
190 | sizeof(struct mwifiex_ssid_bssid)); | ||
191 | |||
192 | if (!mwifiex_bss_ioctl_find_bss(priv, &tmp_ssid_bssid)) { | ||
193 | memcpy(ssid_bssid, &tmp_ssid_bssid, | ||
194 | sizeof(struct mwifiex_ssid_bssid)); | ||
195 | mac = (u8 *) &ssid_bssid->bssid; | ||
196 | dev_dbg(priv->adapter->dev, "cmd: found network: ssid=%s," | ||
197 | " %pM\n", ssid_bssid->ssid.ssid, mac); | ||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | return -1; | ||
202 | } | ||
203 | |||
204 | /* | ||
205 | * Sends IOCTL request to start a scan with user configurations. | 175 | * Sends IOCTL request to start a scan with user configurations. |
206 | * | 176 | * |
207 | * This function allocates the IOCTL request buffer, fills it | 177 | * This function allocates the IOCTL request buffer, fills it |
@@ -286,8 +256,7 @@ mwifiex_is_network_compatible_for_static_wep(struct mwifiex_private *priv, | |||
286 | */ | 256 | */ |
287 | static bool | 257 | static bool |
288 | mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv, | 258 | mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv, |
289 | struct mwifiex_bssdescriptor *bss_desc, | 259 | struct mwifiex_bssdescriptor *bss_desc) |
290 | int index) | ||
291 | { | 260 | { |
292 | if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED | 261 | if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED |
293 | && priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled | 262 | && priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled |
@@ -298,9 +267,9 @@ mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv, | |||
298 | * LinkSys WRT54G && bss_desc->privacy | 267 | * LinkSys WRT54G && bss_desc->privacy |
299 | */ | 268 | */ |
300 | ) { | 269 | ) { |
301 | dev_dbg(priv->adapter->dev, "info: %s: WPA: index=%d" | 270 | dev_dbg(priv->adapter->dev, "info: %s: WPA:" |
302 | " wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s " | 271 | " wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s " |
303 | "EncMode=%#x privacy=%#x\n", __func__, index, | 272 | "EncMode=%#x privacy=%#x\n", __func__, |
304 | (bss_desc->bcn_wpa_ie) ? | 273 | (bss_desc->bcn_wpa_ie) ? |
305 | (*(bss_desc->bcn_wpa_ie)). | 274 | (*(bss_desc->bcn_wpa_ie)). |
306 | vend_hdr.element_id : 0, | 275 | vend_hdr.element_id : 0, |
@@ -324,8 +293,7 @@ mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv, | |||
324 | */ | 293 | */ |
325 | static bool | 294 | static bool |
326 | mwifiex_is_network_compatible_for_wpa2(struct mwifiex_private *priv, | 295 | mwifiex_is_network_compatible_for_wpa2(struct mwifiex_private *priv, |
327 | struct mwifiex_bssdescriptor *bss_desc, | 296 | struct mwifiex_bssdescriptor *bss_desc) |
328 | int index) | ||
329 | { | 297 | { |
330 | if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED | 298 | if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED |
331 | && !priv->sec_info.wpa_enabled && priv->sec_info.wpa2_enabled | 299 | && !priv->sec_info.wpa_enabled && priv->sec_info.wpa2_enabled |
@@ -336,9 +304,9 @@ mwifiex_is_network_compatible_for_wpa2(struct mwifiex_private *priv, | |||
336 | * LinkSys WRT54G && bss_desc->privacy | 304 | * LinkSys WRT54G && bss_desc->privacy |
337 | */ | 305 | */ |
338 | ) { | 306 | ) { |
339 | dev_dbg(priv->adapter->dev, "info: %s: WPA2: index=%d" | 307 | dev_dbg(priv->adapter->dev, "info: %s: WPA2: " |
340 | " wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s " | 308 | " wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s " |
341 | "EncMode=%#x privacy=%#x\n", __func__, index, | 309 | "EncMode=%#x privacy=%#x\n", __func__, |
342 | (bss_desc->bcn_wpa_ie) ? | 310 | (bss_desc->bcn_wpa_ie) ? |
343 | (*(bss_desc->bcn_wpa_ie)). | 311 | (*(bss_desc->bcn_wpa_ie)). |
344 | vend_hdr.element_id : 0, | 312 | vend_hdr.element_id : 0, |
@@ -383,8 +351,7 @@ mwifiex_is_network_compatible_for_adhoc_aes(struct mwifiex_private *priv, | |||
383 | */ | 351 | */ |
384 | static bool | 352 | static bool |
385 | mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv, | 353 | mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv, |
386 | struct mwifiex_bssdescriptor *bss_desc, | 354 | struct mwifiex_bssdescriptor *bss_desc) |
387 | int index) | ||
388 | { | 355 | { |
389 | if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED | 356 | if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED |
390 | && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled | 357 | && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled |
@@ -395,9 +362,9 @@ mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv, | |||
395 | && priv->sec_info.encryption_mode | 362 | && priv->sec_info.encryption_mode |
396 | && bss_desc->privacy) { | 363 | && bss_desc->privacy) { |
397 | dev_dbg(priv->adapter->dev, "info: %s: dynamic " | 364 | dev_dbg(priv->adapter->dev, "info: %s: dynamic " |
398 | "WEP: index=%d wpa_ie=%#x wpa2_ie=%#x " | 365 | "WEP: wpa_ie=%#x wpa2_ie=%#x " |
399 | "EncMode=%#x privacy=%#x\n", | 366 | "EncMode=%#x privacy=%#x\n", |
400 | __func__, index, | 367 | __func__, |
401 | (bss_desc->bcn_wpa_ie) ? | 368 | (bss_desc->bcn_wpa_ie) ? |
402 | (*(bss_desc->bcn_wpa_ie)). | 369 | (*(bss_desc->bcn_wpa_ie)). |
403 | vend_hdr.element_id : 0, | 370 | vend_hdr.element_id : 0, |
@@ -430,42 +397,41 @@ mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv, | |||
430 | * Compatibility is not matched while roaming, except for mode. | 397 | * Compatibility is not matched while roaming, except for mode. |
431 | */ | 398 | */ |
432 | static s32 | 399 | static s32 |
433 | mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode) | 400 | mwifiex_is_network_compatible(struct mwifiex_private *priv, |
401 | struct mwifiex_bssdescriptor *bss_desc, u32 mode) | ||
434 | { | 402 | { |
435 | struct mwifiex_adapter *adapter = priv->adapter; | 403 | struct mwifiex_adapter *adapter = priv->adapter; |
436 | struct mwifiex_bssdescriptor *bss_desc; | ||
437 | 404 | ||
438 | bss_desc = &adapter->scan_table[index]; | ||
439 | bss_desc->disable_11n = false; | 405 | bss_desc->disable_11n = false; |
440 | 406 | ||
441 | /* Don't check for compatibility if roaming */ | 407 | /* Don't check for compatibility if roaming */ |
442 | if (priv->media_connected && (priv->bss_mode == NL80211_IFTYPE_STATION) | 408 | if (priv->media_connected && (priv->bss_mode == NL80211_IFTYPE_STATION) |
443 | && (bss_desc->bss_mode == NL80211_IFTYPE_STATION)) | 409 | && (bss_desc->bss_mode == NL80211_IFTYPE_STATION)) |
444 | return index; | 410 | return 0; |
445 | 411 | ||
446 | if (priv->wps.session_enable) { | 412 | if (priv->wps.session_enable) { |
447 | dev_dbg(adapter->dev, | 413 | dev_dbg(adapter->dev, |
448 | "info: return success directly in WPS period\n"); | 414 | "info: return success directly in WPS period\n"); |
449 | return index; | 415 | return 0; |
450 | } | 416 | } |
451 | 417 | ||
452 | if (mwifiex_is_network_compatible_for_wapi(priv, bss_desc)) { | 418 | if (mwifiex_is_network_compatible_for_wapi(priv, bss_desc)) { |
453 | dev_dbg(adapter->dev, "info: return success for WAPI AP\n"); | 419 | dev_dbg(adapter->dev, "info: return success for WAPI AP\n"); |
454 | return index; | 420 | return 0; |
455 | } | 421 | } |
456 | 422 | ||
457 | if (bss_desc->bss_mode == mode) { | 423 | if (bss_desc->bss_mode == mode) { |
458 | if (mwifiex_is_network_compatible_for_no_sec(priv, bss_desc)) { | 424 | if (mwifiex_is_network_compatible_for_no_sec(priv, bss_desc)) { |
459 | /* No security */ | 425 | /* No security */ |
460 | return index; | 426 | return 0; |
461 | } else if (mwifiex_is_network_compatible_for_static_wep(priv, | 427 | } else if (mwifiex_is_network_compatible_for_static_wep(priv, |
462 | bss_desc)) { | 428 | bss_desc)) { |
463 | /* Static WEP enabled */ | 429 | /* Static WEP enabled */ |
464 | dev_dbg(adapter->dev, "info: Disable 11n in WEP mode.\n"); | 430 | dev_dbg(adapter->dev, "info: Disable 11n in WEP mode.\n"); |
465 | bss_desc->disable_11n = true; | 431 | bss_desc->disable_11n = true; |
466 | return index; | 432 | return 0; |
467 | } else if (mwifiex_is_network_compatible_for_wpa(priv, bss_desc, | 433 | } else if (mwifiex_is_network_compatible_for_wpa(priv, |
468 | index)) { | 434 | bss_desc)) { |
469 | /* WPA enabled */ | 435 | /* WPA enabled */ |
470 | if (((priv->adapter->config_bands & BAND_GN | 436 | if (((priv->adapter->config_bands & BAND_GN |
471 | || priv->adapter->config_bands & BAND_AN) | 437 | || priv->adapter->config_bands & BAND_AN) |
@@ -483,9 +449,9 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode) | |||
483 | return -1; | 449 | return -1; |
484 | } | 450 | } |
485 | } | 451 | } |
486 | return index; | 452 | return 0; |
487 | } else if (mwifiex_is_network_compatible_for_wpa2(priv, | 453 | } else if (mwifiex_is_network_compatible_for_wpa2(priv, |
488 | bss_desc, index)) { | 454 | bss_desc)) { |
489 | /* WPA2 enabled */ | 455 | /* WPA2 enabled */ |
490 | if (((priv->adapter->config_bands & BAND_GN | 456 | if (((priv->adapter->config_bands & BAND_GN |
491 | || priv->adapter->config_bands & BAND_AN) | 457 | || priv->adapter->config_bands & BAND_AN) |
@@ -503,22 +469,22 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode) | |||
503 | return -1; | 469 | return -1; |
504 | } | 470 | } |
505 | } | 471 | } |
506 | return index; | 472 | return 0; |
507 | } else if (mwifiex_is_network_compatible_for_adhoc_aes(priv, | 473 | } else if (mwifiex_is_network_compatible_for_adhoc_aes(priv, |
508 | bss_desc)) { | 474 | bss_desc)) { |
509 | /* Ad-hoc AES enabled */ | 475 | /* Ad-hoc AES enabled */ |
510 | return index; | 476 | return 0; |
511 | } else if (mwifiex_is_network_compatible_for_dynamic_wep(priv, | 477 | } else if (mwifiex_is_network_compatible_for_dynamic_wep(priv, |
512 | bss_desc, index)) { | 478 | bss_desc)) { |
513 | /* Dynamic WEP enabled */ | 479 | /* Dynamic WEP enabled */ |
514 | return index; | 480 | return 0; |
515 | } | 481 | } |
516 | 482 | ||
517 | /* Security doesn't match */ | 483 | /* Security doesn't match */ |
518 | dev_dbg(adapter->dev, "info: %s: failed: index=%d " | 484 | dev_dbg(adapter->dev, "info: %s: failed: " |
519 | "wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode" | 485 | "wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode" |
520 | "=%#x privacy=%#x\n", | 486 | "=%#x privacy=%#x\n", |
521 | __func__, index, | 487 | __func__, |
522 | (bss_desc->bcn_wpa_ie) ? | 488 | (bss_desc->bcn_wpa_ie) ? |
523 | (*(bss_desc->bcn_wpa_ie)).vend_hdr. | 489 | (*(bss_desc->bcn_wpa_ie)).vend_hdr. |
524 | element_id : 0, | 490 | element_id : 0, |
@@ -538,52 +504,6 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode) | |||
538 | } | 504 | } |
539 | 505 | ||
540 | /* | 506 | /* |
541 | * This function finds the best SSID in the scan list. | ||
542 | * | ||
543 | * It searches the scan table for the best SSID that also matches the current | ||
544 | * adapter network preference (mode, security etc.). | ||
545 | */ | ||
546 | static s32 | ||
547 | mwifiex_find_best_network_in_list(struct mwifiex_private *priv) | ||
548 | { | ||
549 | struct mwifiex_adapter *adapter = priv->adapter; | ||
550 | u32 mode = priv->bss_mode; | ||
551 | s32 best_net = -1; | ||
552 | s32 best_rssi = 0; | ||
553 | u32 i; | ||
554 | |||
555 | dev_dbg(adapter->dev, "info: num of BSSIDs = %d\n", | ||
556 | adapter->num_in_scan_table); | ||
557 | |||
558 | for (i = 0; i < adapter->num_in_scan_table; i++) { | ||
559 | switch (mode) { | ||
560 | case NL80211_IFTYPE_STATION: | ||
561 | case NL80211_IFTYPE_ADHOC: | ||
562 | if (mwifiex_is_network_compatible(priv, i, mode) >= 0) { | ||
563 | if (SCAN_RSSI(adapter->scan_table[i].rssi) > | ||
564 | best_rssi) { | ||
565 | best_rssi = SCAN_RSSI(adapter-> | ||
566 | scan_table[i].rssi); | ||
567 | best_net = i; | ||
568 | } | ||
569 | } | ||
570 | break; | ||
571 | case NL80211_IFTYPE_UNSPECIFIED: | ||
572 | default: | ||
573 | if (SCAN_RSSI(adapter->scan_table[i].rssi) > | ||
574 | best_rssi) { | ||
575 | best_rssi = SCAN_RSSI(adapter->scan_table[i]. | ||
576 | rssi); | ||
577 | best_net = i; | ||
578 | } | ||
579 | break; | ||
580 | } | ||
581 | } | ||
582 | |||
583 | return best_net; | ||
584 | } | ||
585 | |||
586 | /* | ||
587 | * This function creates a channel list for the driver to scan, based | 507 | * This function creates a channel list for the driver to scan, based |
588 | * on region/band information. | 508 | * on region/band information. |
589 | * | 509 | * |
@@ -1161,34 +1081,13 @@ mwifiex_ret_802_11_scan_get_tlv_ptrs(struct mwifiex_adapter *adapter, | |||
1161 | } | 1081 | } |
1162 | 1082 | ||
1163 | /* | 1083 | /* |
1164 | * This function interprets a BSS scan response returned from the firmware. | 1084 | * This function parses provided beacon buffer and updates |
1165 | * | 1085 | * respective fields in bss descriptor structure. |
1166 | * The various fixed fields and IEs are parsed and passed back for a BSS | ||
1167 | * probe response or beacon from scan command. Information is recorded as | ||
1168 | * needed in the scan table for that entry. | ||
1169 | * | ||
1170 | * The following IE types are recognized and parsed - | ||
1171 | * - SSID | ||
1172 | * - Supported rates | ||
1173 | * - FH parameters set | ||
1174 | * - DS parameters set | ||
1175 | * - CF parameters set | ||
1176 | * - IBSS parameters set | ||
1177 | * - ERP information | ||
1178 | * - Extended supported rates | ||
1179 | * - Vendor specific (221) | ||
1180 | * - RSN IE | ||
1181 | * - WAPI IE | ||
1182 | * - HT capability | ||
1183 | * - HT operation | ||
1184 | * - BSS Coexistence 20/40 | ||
1185 | * - Extended capability | ||
1186 | * - Overlapping BSS scan parameters | ||
1187 | */ | 1086 | */ |
1188 | static int | 1087 | int |
1189 | mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter, | 1088 | mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, |
1190 | struct mwifiex_bssdescriptor *bss_entry, | 1089 | struct mwifiex_bssdescriptor *bss_entry, |
1191 | u8 **beacon_info, u32 *bytes_left) | 1090 | u8 *ie_buf, u32 ie_len) |
1192 | { | 1091 | { |
1193 | int ret = 0; | 1092 | int ret = 0; |
1194 | u8 element_id; | 1093 | u8 element_id; |
@@ -1196,135 +1095,43 @@ mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter, | |||
1196 | struct ieee_types_ds_param_set *ds_param_set; | 1095 | struct ieee_types_ds_param_set *ds_param_set; |
1197 | struct ieee_types_cf_param_set *cf_param_set; | 1096 | struct ieee_types_cf_param_set *cf_param_set; |
1198 | struct ieee_types_ibss_param_set *ibss_param_set; | 1097 | struct ieee_types_ibss_param_set *ibss_param_set; |
1199 | __le16 beacon_interval; | ||
1200 | __le16 capabilities; | ||
1201 | u8 *current_ptr; | 1098 | u8 *current_ptr; |
1202 | u8 *rate; | 1099 | u8 *rate; |
1203 | u8 element_len; | 1100 | u8 element_len; |
1204 | u16 total_ie_len; | 1101 | u16 total_ie_len; |
1205 | u8 bytes_to_copy; | 1102 | u8 bytes_to_copy; |
1206 | u8 rate_size; | 1103 | u8 rate_size; |
1207 | u16 beacon_size; | ||
1208 | u8 found_data_rate_ie; | 1104 | u8 found_data_rate_ie; |
1209 | u32 bytes_left_for_current_beacon; | 1105 | u32 bytes_left; |
1210 | struct ieee_types_vendor_specific *vendor_ie; | 1106 | struct ieee_types_vendor_specific *vendor_ie; |
1211 | const u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 }; | 1107 | const u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 }; |
1212 | const u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 }; | 1108 | const u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 }; |
1213 | 1109 | ||
1214 | found_data_rate_ie = false; | 1110 | found_data_rate_ie = false; |
1215 | rate_size = 0; | 1111 | rate_size = 0; |
1216 | beacon_size = 0; | 1112 | current_ptr = ie_buf; |
1217 | 1113 | bytes_left = ie_len; | |
1218 | if (*bytes_left >= sizeof(beacon_size)) { | 1114 | bss_entry->beacon_buf = ie_buf; |
1219 | /* Extract & convert beacon size from the command buffer */ | 1115 | bss_entry->beacon_buf_size = ie_len; |
1220 | memcpy(&beacon_size, *beacon_info, sizeof(beacon_size)); | ||
1221 | *bytes_left -= sizeof(beacon_size); | ||
1222 | *beacon_info += sizeof(beacon_size); | ||
1223 | } | ||
1224 | |||
1225 | if (!beacon_size || beacon_size > *bytes_left) { | ||
1226 | *beacon_info += *bytes_left; | ||
1227 | *bytes_left = 0; | ||
1228 | return -1; | ||
1229 | } | ||
1230 | |||
1231 | /* Initialize the current working beacon pointer for this BSS | ||
1232 | iteration */ | ||
1233 | current_ptr = *beacon_info; | ||
1234 | |||
1235 | /* Advance the return beacon pointer past the current beacon */ | ||
1236 | *beacon_info += beacon_size; | ||
1237 | *bytes_left -= beacon_size; | ||
1238 | |||
1239 | bytes_left_for_current_beacon = beacon_size; | ||
1240 | |||
1241 | memcpy(bss_entry->mac_address, current_ptr, ETH_ALEN); | ||
1242 | dev_dbg(adapter->dev, "info: InterpretIE: AP MAC Addr: %pM\n", | ||
1243 | bss_entry->mac_address); | ||
1244 | |||
1245 | current_ptr += ETH_ALEN; | ||
1246 | bytes_left_for_current_beacon -= ETH_ALEN; | ||
1247 | |||
1248 | if (bytes_left_for_current_beacon < 12) { | ||
1249 | dev_err(adapter->dev, "InterpretIE: not enough bytes left\n"); | ||
1250 | return -1; | ||
1251 | } | ||
1252 | |||
1253 | /* | ||
1254 | * Next 4 fields are RSSI, time stamp, beacon interval, | ||
1255 | * and capability information | ||
1256 | */ | ||
1257 | |||
1258 | /* RSSI is 1 byte long */ | ||
1259 | bss_entry->rssi = (s32) (*current_ptr); | ||
1260 | dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%02X\n", *current_ptr); | ||
1261 | current_ptr += 1; | ||
1262 | bytes_left_for_current_beacon -= 1; | ||
1263 | |||
1264 | /* | ||
1265 | * The RSSI is not part of the beacon/probe response. After we have | ||
1266 | * advanced current_ptr past the RSSI field, save the remaining | ||
1267 | * data for use at the application layer | ||
1268 | */ | ||
1269 | bss_entry->beacon_buf = current_ptr; | ||
1270 | bss_entry->beacon_buf_size = bytes_left_for_current_beacon; | ||
1271 | |||
1272 | /* Time stamp is 8 bytes long */ | ||
1273 | memcpy(bss_entry->time_stamp, current_ptr, 8); | ||
1274 | current_ptr += 8; | ||
1275 | bytes_left_for_current_beacon -= 8; | ||
1276 | |||
1277 | /* Beacon interval is 2 bytes long */ | ||
1278 | memcpy(&beacon_interval, current_ptr, 2); | ||
1279 | bss_entry->beacon_period = le16_to_cpu(beacon_interval); | ||
1280 | current_ptr += 2; | ||
1281 | bytes_left_for_current_beacon -= 2; | ||
1282 | |||
1283 | /* Capability information is 2 bytes long */ | ||
1284 | memcpy(&capabilities, current_ptr, 2); | ||
1285 | dev_dbg(adapter->dev, "info: InterpretIE: capabilities=0x%X\n", | ||
1286 | capabilities); | ||
1287 | bss_entry->cap_info_bitmap = le16_to_cpu(capabilities); | ||
1288 | current_ptr += 2; | ||
1289 | bytes_left_for_current_beacon -= 2; | ||
1290 | |||
1291 | /* Rest of the current buffer are IE's */ | ||
1292 | dev_dbg(adapter->dev, "info: InterpretIE: IELength for this AP = %d\n", | ||
1293 | bytes_left_for_current_beacon); | ||
1294 | |||
1295 | if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) { | ||
1296 | dev_dbg(adapter->dev, "info: InterpretIE: AP WEP enabled\n"); | ||
1297 | bss_entry->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; | ||
1298 | } else { | ||
1299 | bss_entry->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL; | ||
1300 | } | ||
1301 | |||
1302 | if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_IBSS) | ||
1303 | bss_entry->bss_mode = NL80211_IFTYPE_ADHOC; | ||
1304 | else | ||
1305 | bss_entry->bss_mode = NL80211_IFTYPE_STATION; | ||
1306 | |||
1307 | 1116 | ||
1308 | /* Process variable IE */ | 1117 | /* Process variable IE */ |
1309 | while (bytes_left_for_current_beacon >= 2) { | 1118 | while (bytes_left >= 2) { |
1310 | element_id = *current_ptr; | 1119 | element_id = *current_ptr; |
1311 | element_len = *(current_ptr + 1); | 1120 | element_len = *(current_ptr + 1); |
1312 | total_ie_len = element_len + sizeof(struct ieee_types_header); | 1121 | total_ie_len = element_len + sizeof(struct ieee_types_header); |
1313 | 1122 | ||
1314 | if (bytes_left_for_current_beacon < total_ie_len) { | 1123 | if (bytes_left < total_ie_len) { |
1315 | dev_err(adapter->dev, "err: InterpretIE: in processing" | 1124 | dev_err(adapter->dev, "err: InterpretIE: in processing" |
1316 | " IE, bytes left < IE length\n"); | 1125 | " IE, bytes left < IE length\n"); |
1317 | bytes_left_for_current_beacon = 0; | 1126 | return -1; |
1318 | ret = -1; | ||
1319 | continue; | ||
1320 | } | 1127 | } |
1321 | switch (element_id) { | 1128 | switch (element_id) { |
1322 | case WLAN_EID_SSID: | 1129 | case WLAN_EID_SSID: |
1323 | bss_entry->ssid.ssid_len = element_len; | 1130 | bss_entry->ssid.ssid_len = element_len; |
1324 | memcpy(bss_entry->ssid.ssid, (current_ptr + 2), | 1131 | memcpy(bss_entry->ssid.ssid, (current_ptr + 2), |
1325 | element_len); | 1132 | element_len); |
1326 | dev_dbg(adapter->dev, "info: InterpretIE: ssid: %-32s\n", | 1133 | dev_dbg(adapter->dev, "info: InterpretIE: ssid: " |
1327 | bss_entry->ssid.ssid); | 1134 | "%-32s\n", bss_entry->ssid.ssid); |
1328 | break; | 1135 | break; |
1329 | 1136 | ||
1330 | case WLAN_EID_SUPP_RATES: | 1137 | case WLAN_EID_SUPP_RATES: |
@@ -1471,13 +1278,6 @@ mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter, | |||
1471 | sizeof(struct ieee_types_header) - | 1278 | sizeof(struct ieee_types_header) - |
1472 | bss_entry->beacon_buf); | 1279 | bss_entry->beacon_buf); |
1473 | break; | 1280 | break; |
1474 | case WLAN_EID_OVERLAP_BSS_SCAN_PARAM: | ||
1475 | bss_entry->bcn_obss_scan = | ||
1476 | (struct ieee_types_obss_scan_param *) | ||
1477 | current_ptr; | ||
1478 | bss_entry->overlap_bss_offset = (u16) (current_ptr - | ||
1479 | bss_entry->beacon_buf); | ||
1480 | break; | ||
1481 | default: | 1281 | default: |
1482 | break; | 1282 | break; |
1483 | } | 1283 | } |
@@ -1485,577 +1285,13 @@ mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter, | |||
1485 | current_ptr += element_len + 2; | 1285 | current_ptr += element_len + 2; |
1486 | 1286 | ||
1487 | /* Need to account for IE ID and IE Len */ | 1287 | /* Need to account for IE ID and IE Len */ |
1488 | bytes_left_for_current_beacon -= (element_len + 2); | 1288 | bytes_left -= (element_len + 2); |
1489 | 1289 | ||
1490 | } /* while (bytes_left_for_current_beacon > 2) */ | 1290 | } /* while (bytes_left > 2) */ |
1491 | return ret; | 1291 | return ret; |
1492 | } | 1292 | } |
1493 | 1293 | ||
1494 | /* | 1294 | /* |
1495 | * This function adjusts the pointers used in beacon buffers to reflect | ||
1496 | * shifts. | ||
1497 | * | ||
1498 | * The memory allocated for beacon buffers is of fixed sizes where all the | ||
1499 | * saved beacons must be stored. New beacons are added in the free portion | ||
1500 | * of this memory, space permitting; while duplicate beacon buffers are | ||
1501 | * placed at the same start location. However, since duplicate beacon | ||
1502 | * buffers may not match the size of the old one, all the following buffers | ||
1503 | * in the memory must be shifted to either make space, or to fill up freed | ||
1504 | * up space. | ||
1505 | * | ||
1506 | * This function is used to update the beacon buffer pointers that are past | ||
1507 | * an existing beacon buffer that is updated with a new one of different | ||
1508 | * size. The pointers are shifted by a fixed amount, either forward or | ||
1509 | * backward. | ||
1510 | * | ||
1511 | * the following pointers in every affected beacon buffers are changed, if | ||
1512 | * present - | ||
1513 | * - WPA IE pointer | ||
1514 | * - RSN IE pointer | ||
1515 | * - WAPI IE pointer | ||
1516 | * - HT capability IE pointer | ||
1517 | * - HT information IE pointer | ||
1518 | * - BSS coexistence 20/40 IE pointer | ||
1519 | * - Extended capability IE pointer | ||
1520 | * - Overlapping BSS scan parameter IE pointer | ||
1521 | */ | ||
1522 | static void | ||
1523 | mwifiex_adjust_beacon_buffer_ptrs(struct mwifiex_private *priv, u8 advance, | ||
1524 | u8 *bcn_store, u32 rem_bcn_size, | ||
1525 | u32 num_of_ent) | ||
1526 | { | ||
1527 | struct mwifiex_adapter *adapter = priv->adapter; | ||
1528 | u32 adj_idx; | ||
1529 | for (adj_idx = 0; adj_idx < num_of_ent; adj_idx++) { | ||
1530 | if (adapter->scan_table[adj_idx].beacon_buf > bcn_store) { | ||
1531 | |||
1532 | if (advance) | ||
1533 | adapter->scan_table[adj_idx].beacon_buf += | ||
1534 | rem_bcn_size; | ||
1535 | else | ||
1536 | adapter->scan_table[adj_idx].beacon_buf -= | ||
1537 | rem_bcn_size; | ||
1538 | |||
1539 | if (adapter->scan_table[adj_idx].bcn_wpa_ie) | ||
1540 | adapter->scan_table[adj_idx].bcn_wpa_ie = | ||
1541 | (struct ieee_types_vendor_specific *) | ||
1542 | (adapter->scan_table[adj_idx].beacon_buf + | ||
1543 | adapter->scan_table[adj_idx].wpa_offset); | ||
1544 | if (adapter->scan_table[adj_idx].bcn_rsn_ie) | ||
1545 | adapter->scan_table[adj_idx].bcn_rsn_ie = | ||
1546 | (struct ieee_types_generic *) | ||
1547 | (adapter->scan_table[adj_idx].beacon_buf + | ||
1548 | adapter->scan_table[adj_idx].rsn_offset); | ||
1549 | if (adapter->scan_table[adj_idx].bcn_wapi_ie) | ||
1550 | adapter->scan_table[adj_idx].bcn_wapi_ie = | ||
1551 | (struct ieee_types_generic *) | ||
1552 | (adapter->scan_table[adj_idx].beacon_buf + | ||
1553 | adapter->scan_table[adj_idx].wapi_offset); | ||
1554 | if (adapter->scan_table[adj_idx].bcn_ht_cap) | ||
1555 | adapter->scan_table[adj_idx].bcn_ht_cap = | ||
1556 | (struct ieee80211_ht_cap *) | ||
1557 | (adapter->scan_table[adj_idx].beacon_buf + | ||
1558 | adapter->scan_table[adj_idx].ht_cap_offset); | ||
1559 | |||
1560 | if (adapter->scan_table[adj_idx].bcn_ht_info) | ||
1561 | adapter->scan_table[adj_idx].bcn_ht_info = | ||
1562 | (struct ieee80211_ht_info *) | ||
1563 | (adapter->scan_table[adj_idx].beacon_buf + | ||
1564 | adapter->scan_table[adj_idx].ht_info_offset); | ||
1565 | if (adapter->scan_table[adj_idx].bcn_bss_co_2040) | ||
1566 | adapter->scan_table[adj_idx].bcn_bss_co_2040 = | ||
1567 | (u8 *) | ||
1568 | (adapter->scan_table[adj_idx].beacon_buf + | ||
1569 | adapter->scan_table[adj_idx].bss_co_2040_offset); | ||
1570 | if (adapter->scan_table[adj_idx].bcn_ext_cap) | ||
1571 | adapter->scan_table[adj_idx].bcn_ext_cap = | ||
1572 | (u8 *) | ||
1573 | (adapter->scan_table[adj_idx].beacon_buf + | ||
1574 | adapter->scan_table[adj_idx].ext_cap_offset); | ||
1575 | if (adapter->scan_table[adj_idx].bcn_obss_scan) | ||
1576 | adapter->scan_table[adj_idx].bcn_obss_scan = | ||
1577 | (struct ieee_types_obss_scan_param *) | ||
1578 | (adapter->scan_table[adj_idx].beacon_buf + | ||
1579 | adapter->scan_table[adj_idx].overlap_bss_offset); | ||
1580 | } | ||
1581 | } | ||
1582 | } | ||
1583 | |||
1584 | /* | ||
1585 | * This function updates the pointers used in beacon buffer for given bss | ||
1586 | * descriptor to reflect shifts | ||
1587 | * | ||
1588 | * Following pointers are updated | ||
1589 | * - WPA IE pointer | ||
1590 | * - RSN IE pointer | ||
1591 | * - WAPI IE pointer | ||
1592 | * - HT capability IE pointer | ||
1593 | * - HT information IE pointer | ||
1594 | * - BSS coexistence 20/40 IE pointer | ||
1595 | * - Extended capability IE pointer | ||
1596 | * - Overlapping BSS scan parameter IE pointer | ||
1597 | */ | ||
1598 | static void | ||
1599 | mwifiex_update_beacon_buffer_ptrs(struct mwifiex_bssdescriptor *beacon) | ||
1600 | { | ||
1601 | if (beacon->bcn_wpa_ie) | ||
1602 | beacon->bcn_wpa_ie = (struct ieee_types_vendor_specific *) | ||
1603 | (beacon->beacon_buf + beacon->wpa_offset); | ||
1604 | if (beacon->bcn_rsn_ie) | ||
1605 | beacon->bcn_rsn_ie = (struct ieee_types_generic *) | ||
1606 | (beacon->beacon_buf + beacon->rsn_offset); | ||
1607 | if (beacon->bcn_wapi_ie) | ||
1608 | beacon->bcn_wapi_ie = (struct ieee_types_generic *) | ||
1609 | (beacon->beacon_buf + beacon->wapi_offset); | ||
1610 | if (beacon->bcn_ht_cap) | ||
1611 | beacon->bcn_ht_cap = (struct ieee80211_ht_cap *) | ||
1612 | (beacon->beacon_buf + beacon->ht_cap_offset); | ||
1613 | if (beacon->bcn_ht_info) | ||
1614 | beacon->bcn_ht_info = (struct ieee80211_ht_info *) | ||
1615 | (beacon->beacon_buf + beacon->ht_info_offset); | ||
1616 | if (beacon->bcn_bss_co_2040) | ||
1617 | beacon->bcn_bss_co_2040 = (u8 *) (beacon->beacon_buf + | ||
1618 | beacon->bss_co_2040_offset); | ||
1619 | if (beacon->bcn_ext_cap) | ||
1620 | beacon->bcn_ext_cap = (u8 *) (beacon->beacon_buf + | ||
1621 | beacon->ext_cap_offset); | ||
1622 | if (beacon->bcn_obss_scan) | ||
1623 | beacon->bcn_obss_scan = (struct ieee_types_obss_scan_param *) | ||
1624 | (beacon->beacon_buf + beacon->overlap_bss_offset); | ||
1625 | } | ||
1626 | |||
1627 | /* | ||
1628 | * This function stores a beacon or probe response for a BSS returned | ||
1629 | * in the scan. | ||
1630 | * | ||
1631 | * This stores a new scan response or an update for a previous scan response. | ||
1632 | * New entries need to verify that they do not exceed the total amount of | ||
1633 | * memory allocated for the table. | ||
1634 | * | ||
1635 | * Replacement entries need to take into consideration the amount of space | ||
1636 | * currently allocated for the beacon/probe response and adjust the entry | ||
1637 | * as needed. | ||
1638 | * | ||
1639 | * A small amount of extra pad (SCAN_BEACON_ENTRY_PAD) is generally reserved | ||
1640 | * for an entry in case it is a beacon since a probe response for the | ||
1641 | * network will by larger per the standard. This helps to reduce the | ||
1642 | * amount of memory copying to fit a new probe response into an entry | ||
1643 | * already occupied by a network's previously stored beacon. | ||
1644 | */ | ||
1645 | static void | ||
1646 | mwifiex_ret_802_11_scan_store_beacon(struct mwifiex_private *priv, | ||
1647 | u32 beacon_idx, u32 num_of_ent, | ||
1648 | struct mwifiex_bssdescriptor *new_beacon) | ||
1649 | { | ||
1650 | struct mwifiex_adapter *adapter = priv->adapter; | ||
1651 | u8 *bcn_store; | ||
1652 | u32 new_bcn_size; | ||
1653 | u32 old_bcn_size; | ||
1654 | u32 bcn_space; | ||
1655 | |||
1656 | if (adapter->scan_table[beacon_idx].beacon_buf) { | ||
1657 | |||
1658 | new_bcn_size = new_beacon->beacon_buf_size; | ||
1659 | old_bcn_size = adapter->scan_table[beacon_idx].beacon_buf_size; | ||
1660 | bcn_space = adapter->scan_table[beacon_idx].beacon_buf_size_max; | ||
1661 | bcn_store = adapter->scan_table[beacon_idx].beacon_buf; | ||
1662 | |||
1663 | /* Set the max to be the same as current entry unless changed | ||
1664 | below */ | ||
1665 | new_beacon->beacon_buf_size_max = bcn_space; | ||
1666 | if (new_bcn_size == old_bcn_size) { | ||
1667 | /* | ||
1668 | * Beacon is the same size as the previous entry. | ||
1669 | * Replace the previous contents with the scan result | ||
1670 | */ | ||
1671 | memcpy(bcn_store, new_beacon->beacon_buf, | ||
1672 | new_beacon->beacon_buf_size); | ||
1673 | |||
1674 | } else if (new_bcn_size <= bcn_space) { | ||
1675 | /* | ||
1676 | * New beacon size will fit in the amount of space | ||
1677 | * we have previously allocated for it | ||
1678 | */ | ||
1679 | |||
1680 | /* Copy the new beacon buffer entry over the old one */ | ||
1681 | memcpy(bcn_store, new_beacon->beacon_buf, new_bcn_size); | ||
1682 | |||
1683 | /* | ||
1684 | * If the old beacon size was less than the maximum | ||
1685 | * we had alloted for the entry, and the new entry | ||
1686 | * is even smaller, reset the max size to the old | ||
1687 | * beacon entry and compress the storage space | ||
1688 | * (leaving a new pad space of (old_bcn_size - | ||
1689 | * new_bcn_size). | ||
1690 | */ | ||
1691 | if (old_bcn_size < bcn_space | ||
1692 | && new_bcn_size <= old_bcn_size) { | ||
1693 | /* | ||
1694 | * Old Beacon size is smaller than the alloted | ||
1695 | * storage size. Shrink the alloted storage | ||
1696 | * space. | ||
1697 | */ | ||
1698 | dev_dbg(adapter->dev, "info: AppControl:" | ||
1699 | " smaller duplicate beacon " | ||
1700 | "(%d), old = %d, new = %d, space = %d," | ||
1701 | "left = %d\n", | ||
1702 | beacon_idx, old_bcn_size, new_bcn_size, | ||
1703 | bcn_space, | ||
1704 | (int)(sizeof(adapter->bcn_buf) - | ||
1705 | (adapter->bcn_buf_end - | ||
1706 | adapter->bcn_buf))); | ||
1707 | |||
1708 | /* | ||
1709 | * memmove (since the memory overlaps) the | ||
1710 | * data after the beacon we just stored to the | ||
1711 | * end of the current beacon. This cleans up | ||
1712 | * any unused space the old larger beacon was | ||
1713 | * using in the buffer | ||
1714 | */ | ||
1715 | memmove(bcn_store + old_bcn_size, | ||
1716 | bcn_store + bcn_space, | ||
1717 | adapter->bcn_buf_end - (bcn_store + | ||
1718 | bcn_space)); | ||
1719 | |||
1720 | /* | ||
1721 | * Decrement the end pointer by the difference | ||
1722 | * between the old larger size and the new | ||
1723 | * smaller size since we are using less space | ||
1724 | * due to the new beacon being smaller | ||
1725 | */ | ||
1726 | adapter->bcn_buf_end -= | ||
1727 | (bcn_space - old_bcn_size); | ||
1728 | |||
1729 | /* Set the maximum storage size to the old | ||
1730 | beacon size */ | ||
1731 | new_beacon->beacon_buf_size_max = old_bcn_size; | ||
1732 | |||
1733 | /* Adjust beacon buffer pointers that are past | ||
1734 | the current */ | ||
1735 | mwifiex_adjust_beacon_buffer_ptrs(priv, 0, | ||
1736 | bcn_store, (bcn_space - old_bcn_size), | ||
1737 | num_of_ent); | ||
1738 | } | ||
1739 | } else if (adapter->bcn_buf_end + (new_bcn_size - bcn_space) | ||
1740 | < (adapter->bcn_buf + sizeof(adapter->bcn_buf))) { | ||
1741 | /* | ||
1742 | * Beacon is larger than space previously allocated | ||
1743 | * (bcn_space) and there is enough space left in the | ||
1744 | * beaconBuffer to store the additional data | ||
1745 | */ | ||
1746 | dev_dbg(adapter->dev, "info: AppControl:" | ||
1747 | " larger duplicate beacon (%d), " | ||
1748 | "old = %d, new = %d, space = %d, left = %d\n", | ||
1749 | beacon_idx, old_bcn_size, new_bcn_size, | ||
1750 | bcn_space, | ||
1751 | (int)(sizeof(adapter->bcn_buf) - | ||
1752 | (adapter->bcn_buf_end - | ||
1753 | adapter->bcn_buf))); | ||
1754 | |||
1755 | /* | ||
1756 | * memmove (since the memory overlaps) the data | ||
1757 | * after the beacon we just stored to the end of | ||
1758 | * the current beacon. This moves the data for | ||
1759 | * the beacons after this further in memory to | ||
1760 | * make space for the new larger beacon we are | ||
1761 | * about to copy in. | ||
1762 | */ | ||
1763 | memmove(bcn_store + new_bcn_size, | ||
1764 | bcn_store + bcn_space, | ||
1765 | adapter->bcn_buf_end - (bcn_store + bcn_space)); | ||
1766 | |||
1767 | /* Copy the new beacon buffer entry over the old one */ | ||
1768 | memcpy(bcn_store, new_beacon->beacon_buf, new_bcn_size); | ||
1769 | |||
1770 | /* Move the beacon end pointer by the amount of new | ||
1771 | beacon data we are adding */ | ||
1772 | adapter->bcn_buf_end += (new_bcn_size - bcn_space); | ||
1773 | |||
1774 | /* | ||
1775 | * This entry is bigger than the alloted max space | ||
1776 | * previously reserved. Increase the max space to | ||
1777 | * be equal to the new beacon size | ||
1778 | */ | ||
1779 | new_beacon->beacon_buf_size_max = new_bcn_size; | ||
1780 | |||
1781 | /* Adjust beacon buffer pointers that are past the | ||
1782 | current */ | ||
1783 | mwifiex_adjust_beacon_buffer_ptrs(priv, 1, bcn_store, | ||
1784 | (new_bcn_size - bcn_space), | ||
1785 | num_of_ent); | ||
1786 | } else { | ||
1787 | /* | ||
1788 | * Beacon is larger than the previously allocated space, | ||
1789 | * but there is not enough free space to store the | ||
1790 | * additional data. | ||
1791 | */ | ||
1792 | dev_err(adapter->dev, "AppControl: larger duplicate " | ||
1793 | " beacon (%d), old = %d new = %d, space = %d," | ||
1794 | " left = %d\n", beacon_idx, old_bcn_size, | ||
1795 | new_bcn_size, bcn_space, | ||
1796 | (int)(sizeof(adapter->bcn_buf) - | ||
1797 | (adapter->bcn_buf_end - adapter->bcn_buf))); | ||
1798 | |||
1799 | /* Storage failure, keep old beacon intact */ | ||
1800 | new_beacon->beacon_buf_size = old_bcn_size; | ||
1801 | if (new_beacon->bcn_wpa_ie) | ||
1802 | new_beacon->wpa_offset = | ||
1803 | adapter->scan_table[beacon_idx]. | ||
1804 | wpa_offset; | ||
1805 | if (new_beacon->bcn_rsn_ie) | ||
1806 | new_beacon->rsn_offset = | ||
1807 | adapter->scan_table[beacon_idx]. | ||
1808 | rsn_offset; | ||
1809 | if (new_beacon->bcn_wapi_ie) | ||
1810 | new_beacon->wapi_offset = | ||
1811 | adapter->scan_table[beacon_idx]. | ||
1812 | wapi_offset; | ||
1813 | if (new_beacon->bcn_ht_cap) | ||
1814 | new_beacon->ht_cap_offset = | ||
1815 | adapter->scan_table[beacon_idx]. | ||
1816 | ht_cap_offset; | ||
1817 | if (new_beacon->bcn_ht_info) | ||
1818 | new_beacon->ht_info_offset = | ||
1819 | adapter->scan_table[beacon_idx]. | ||
1820 | ht_info_offset; | ||
1821 | if (new_beacon->bcn_bss_co_2040) | ||
1822 | new_beacon->bss_co_2040_offset = | ||
1823 | adapter->scan_table[beacon_idx]. | ||
1824 | bss_co_2040_offset; | ||
1825 | if (new_beacon->bcn_ext_cap) | ||
1826 | new_beacon->ext_cap_offset = | ||
1827 | adapter->scan_table[beacon_idx]. | ||
1828 | ext_cap_offset; | ||
1829 | if (new_beacon->bcn_obss_scan) | ||
1830 | new_beacon->overlap_bss_offset = | ||
1831 | adapter->scan_table[beacon_idx]. | ||
1832 | overlap_bss_offset; | ||
1833 | } | ||
1834 | /* Point the new entry to its permanent storage space */ | ||
1835 | new_beacon->beacon_buf = bcn_store; | ||
1836 | mwifiex_update_beacon_buffer_ptrs(new_beacon); | ||
1837 | } else { | ||
1838 | /* | ||
1839 | * No existing beacon data exists for this entry, check to see | ||
1840 | * if we can fit it in the remaining space | ||
1841 | */ | ||
1842 | if (adapter->bcn_buf_end + new_beacon->beacon_buf_size + | ||
1843 | SCAN_BEACON_ENTRY_PAD < (adapter->bcn_buf + | ||
1844 | sizeof(adapter->bcn_buf))) { | ||
1845 | |||
1846 | /* | ||
1847 | * Copy the beacon buffer data from the local entry to | ||
1848 | * the adapter dev struct buffer space used to store | ||
1849 | * the raw beacon data for each entry in the scan table | ||
1850 | */ | ||
1851 | memcpy(adapter->bcn_buf_end, new_beacon->beacon_buf, | ||
1852 | new_beacon->beacon_buf_size); | ||
1853 | |||
1854 | /* Update the beacon ptr to point to the table save | ||
1855 | area */ | ||
1856 | new_beacon->beacon_buf = adapter->bcn_buf_end; | ||
1857 | new_beacon->beacon_buf_size_max = | ||
1858 | (new_beacon->beacon_buf_size + | ||
1859 | SCAN_BEACON_ENTRY_PAD); | ||
1860 | |||
1861 | mwifiex_update_beacon_buffer_ptrs(new_beacon); | ||
1862 | |||
1863 | /* Increment the end pointer by the size reserved */ | ||
1864 | adapter->bcn_buf_end += new_beacon->beacon_buf_size_max; | ||
1865 | |||
1866 | dev_dbg(adapter->dev, "info: AppControl: beacon[%02d]" | ||
1867 | " sz=%03d, used = %04d, left = %04d\n", | ||
1868 | beacon_idx, | ||
1869 | new_beacon->beacon_buf_size, | ||
1870 | (int)(adapter->bcn_buf_end - adapter->bcn_buf), | ||
1871 | (int)(sizeof(adapter->bcn_buf) - | ||
1872 | (adapter->bcn_buf_end - | ||
1873 | adapter->bcn_buf))); | ||
1874 | } else { | ||
1875 | /* No space for new beacon */ | ||
1876 | dev_dbg(adapter->dev, "info: AppControl: no space for" | ||
1877 | " beacon (%d): %pM sz=%03d, left=%03d\n", | ||
1878 | beacon_idx, new_beacon->mac_address, | ||
1879 | new_beacon->beacon_buf_size, | ||
1880 | (int)(sizeof(adapter->bcn_buf) - | ||
1881 | (adapter->bcn_buf_end - | ||
1882 | adapter->bcn_buf))); | ||
1883 | |||
1884 | /* Storage failure; clear storage records for this | ||
1885 | bcn */ | ||
1886 | new_beacon->beacon_buf = NULL; | ||
1887 | new_beacon->beacon_buf_size = 0; | ||
1888 | new_beacon->beacon_buf_size_max = 0; | ||
1889 | new_beacon->bcn_wpa_ie = NULL; | ||
1890 | new_beacon->wpa_offset = 0; | ||
1891 | new_beacon->bcn_rsn_ie = NULL; | ||
1892 | new_beacon->rsn_offset = 0; | ||
1893 | new_beacon->bcn_wapi_ie = NULL; | ||
1894 | new_beacon->wapi_offset = 0; | ||
1895 | new_beacon->bcn_ht_cap = NULL; | ||
1896 | new_beacon->ht_cap_offset = 0; | ||
1897 | new_beacon->bcn_ht_info = NULL; | ||
1898 | new_beacon->ht_info_offset = 0; | ||
1899 | new_beacon->bcn_bss_co_2040 = NULL; | ||
1900 | new_beacon->bss_co_2040_offset = 0; | ||
1901 | new_beacon->bcn_ext_cap = NULL; | ||
1902 | new_beacon->ext_cap_offset = 0; | ||
1903 | new_beacon->bcn_obss_scan = NULL; | ||
1904 | new_beacon->overlap_bss_offset = 0; | ||
1905 | } | ||
1906 | } | ||
1907 | } | ||
1908 | |||
1909 | /* | ||
1910 | * This function restores a beacon buffer of the current BSS descriptor. | ||
1911 | */ | ||
1912 | static void mwifiex_restore_curr_bcn(struct mwifiex_private *priv) | ||
1913 | { | ||
1914 | struct mwifiex_adapter *adapter = priv->adapter; | ||
1915 | struct mwifiex_bssdescriptor *curr_bss = | ||
1916 | &priv->curr_bss_params.bss_descriptor; | ||
1917 | unsigned long flags; | ||
1918 | |||
1919 | if (priv->curr_bcn_buf && | ||
1920 | ((adapter->bcn_buf_end + priv->curr_bcn_size) < | ||
1921 | (adapter->bcn_buf + sizeof(adapter->bcn_buf)))) { | ||
1922 | spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags); | ||
1923 | |||
1924 | /* restore the current beacon buffer */ | ||
1925 | memcpy(adapter->bcn_buf_end, priv->curr_bcn_buf, | ||
1926 | priv->curr_bcn_size); | ||
1927 | curr_bss->beacon_buf = adapter->bcn_buf_end; | ||
1928 | curr_bss->beacon_buf_size = priv->curr_bcn_size; | ||
1929 | adapter->bcn_buf_end += priv->curr_bcn_size; | ||
1930 | |||
1931 | /* adjust the pointers in the current BSS descriptor */ | ||
1932 | if (curr_bss->bcn_wpa_ie) | ||
1933 | curr_bss->bcn_wpa_ie = | ||
1934 | (struct ieee_types_vendor_specific *) | ||
1935 | (curr_bss->beacon_buf + | ||
1936 | curr_bss->wpa_offset); | ||
1937 | |||
1938 | if (curr_bss->bcn_rsn_ie) | ||
1939 | curr_bss->bcn_rsn_ie = (struct ieee_types_generic *) | ||
1940 | (curr_bss->beacon_buf + | ||
1941 | curr_bss->rsn_offset); | ||
1942 | |||
1943 | if (curr_bss->bcn_ht_cap) | ||
1944 | curr_bss->bcn_ht_cap = (struct ieee80211_ht_cap *) | ||
1945 | (curr_bss->beacon_buf + | ||
1946 | curr_bss->ht_cap_offset); | ||
1947 | |||
1948 | if (curr_bss->bcn_ht_info) | ||
1949 | curr_bss->bcn_ht_info = (struct ieee80211_ht_info *) | ||
1950 | (curr_bss->beacon_buf + | ||
1951 | curr_bss->ht_info_offset); | ||
1952 | |||
1953 | if (curr_bss->bcn_bss_co_2040) | ||
1954 | curr_bss->bcn_bss_co_2040 = | ||
1955 | (u8 *) (curr_bss->beacon_buf + | ||
1956 | curr_bss->bss_co_2040_offset); | ||
1957 | |||
1958 | if (curr_bss->bcn_ext_cap) | ||
1959 | curr_bss->bcn_ext_cap = (u8 *) (curr_bss->beacon_buf + | ||
1960 | curr_bss->ext_cap_offset); | ||
1961 | |||
1962 | if (curr_bss->bcn_obss_scan) | ||
1963 | curr_bss->bcn_obss_scan = | ||
1964 | (struct ieee_types_obss_scan_param *) | ||
1965 | (curr_bss->beacon_buf + | ||
1966 | curr_bss->overlap_bss_offset); | ||
1967 | |||
1968 | spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags); | ||
1969 | |||
1970 | dev_dbg(adapter->dev, "info: current beacon restored %d\n", | ||
1971 | priv->curr_bcn_size); | ||
1972 | } else { | ||
1973 | dev_warn(adapter->dev, | ||
1974 | "curr_bcn_buf not saved or bcn_buf has no space\n"); | ||
1975 | } | ||
1976 | } | ||
1977 | |||
1978 | /* | ||
1979 | * This function post processes the scan table after a new scan command has | ||
1980 | * completed. | ||
1981 | * | ||
1982 | * It inspects each entry of the scan table and tries to find an entry that | ||
1983 | * matches with our current associated/joined network from the scan. If | ||
1984 | * one is found, the stored copy of the BSS descriptor of our current network | ||
1985 | * is updated. | ||
1986 | * | ||
1987 | * It also debug dumps the current scan table contents after processing is over. | ||
1988 | */ | ||
1989 | static void | ||
1990 | mwifiex_process_scan_results(struct mwifiex_private *priv) | ||
1991 | { | ||
1992 | struct mwifiex_adapter *adapter = priv->adapter; | ||
1993 | s32 j; | ||
1994 | u32 i; | ||
1995 | unsigned long flags; | ||
1996 | |||
1997 | if (priv->media_connected) { | ||
1998 | |||
1999 | j = mwifiex_find_ssid_in_list(priv, &priv->curr_bss_params. | ||
2000 | bss_descriptor.ssid, | ||
2001 | priv->curr_bss_params. | ||
2002 | bss_descriptor.mac_address, | ||
2003 | priv->bss_mode); | ||
2004 | |||
2005 | if (j >= 0) { | ||
2006 | spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags); | ||
2007 | priv->curr_bss_params.bss_descriptor.bcn_wpa_ie = NULL; | ||
2008 | priv->curr_bss_params.bss_descriptor.wpa_offset = 0; | ||
2009 | priv->curr_bss_params.bss_descriptor.bcn_rsn_ie = NULL; | ||
2010 | priv->curr_bss_params.bss_descriptor.rsn_offset = 0; | ||
2011 | priv->curr_bss_params.bss_descriptor.bcn_wapi_ie = NULL; | ||
2012 | priv->curr_bss_params.bss_descriptor.wapi_offset = 0; | ||
2013 | priv->curr_bss_params.bss_descriptor.bcn_ht_cap = NULL; | ||
2014 | priv->curr_bss_params.bss_descriptor.ht_cap_offset = | ||
2015 | 0; | ||
2016 | priv->curr_bss_params.bss_descriptor.bcn_ht_info = NULL; | ||
2017 | priv->curr_bss_params.bss_descriptor.ht_info_offset = | ||
2018 | 0; | ||
2019 | priv->curr_bss_params.bss_descriptor.bcn_bss_co_2040 = | ||
2020 | NULL; | ||
2021 | priv->curr_bss_params.bss_descriptor. | ||
2022 | bss_co_2040_offset = 0; | ||
2023 | priv->curr_bss_params.bss_descriptor.bcn_ext_cap = NULL; | ||
2024 | priv->curr_bss_params.bss_descriptor.ext_cap_offset = 0; | ||
2025 | priv->curr_bss_params.bss_descriptor. | ||
2026 | bcn_obss_scan = NULL; | ||
2027 | priv->curr_bss_params.bss_descriptor. | ||
2028 | overlap_bss_offset = 0; | ||
2029 | priv->curr_bss_params.bss_descriptor.beacon_buf = NULL; | ||
2030 | priv->curr_bss_params.bss_descriptor.beacon_buf_size = | ||
2031 | 0; | ||
2032 | priv->curr_bss_params.bss_descriptor. | ||
2033 | beacon_buf_size_max = 0; | ||
2034 | |||
2035 | dev_dbg(adapter->dev, "info: Found current ssid/bssid" | ||
2036 | " in list @ index #%d\n", j); | ||
2037 | /* Make a copy of current BSSID descriptor */ | ||
2038 | memcpy(&priv->curr_bss_params.bss_descriptor, | ||
2039 | &adapter->scan_table[j], | ||
2040 | sizeof(priv->curr_bss_params.bss_descriptor)); | ||
2041 | |||
2042 | mwifiex_save_curr_bcn(priv); | ||
2043 | spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags); | ||
2044 | |||
2045 | } else { | ||
2046 | mwifiex_restore_curr_bcn(priv); | ||
2047 | } | ||
2048 | } | ||
2049 | |||
2050 | for (i = 0; i < adapter->num_in_scan_table; i++) | ||
2051 | dev_dbg(adapter->dev, "info: scan:(%02d) %pM " | ||
2052 | "RSSI[%03d], SSID[%s]\n", | ||
2053 | i, adapter->scan_table[i].mac_address, | ||
2054 | (s32) adapter->scan_table[i].rssi, | ||
2055 | adapter->scan_table[i].ssid.ssid); | ||
2056 | } | ||
2057 | |||
2058 | /* | ||
2059 | * This function converts radio type scan parameter to a band configuration | 1295 | * This function converts radio type scan parameter to a band configuration |
2060 | * to be used in join command. | 1296 | * to be used in join command. |
2061 | */ | 1297 | */ |
@@ -2072,175 +1308,6 @@ mwifiex_radio_type_to_band(u8 radio_type) | |||
2072 | } | 1308 | } |
2073 | 1309 | ||
2074 | /* | 1310 | /* |
2075 | * This function deletes a specific indexed entry from the scan table. | ||
2076 | * | ||
2077 | * This also compacts the remaining entries and adjusts any buffering | ||
2078 | * of beacon/probe response data if needed. | ||
2079 | */ | ||
2080 | static void | ||
2081 | mwifiex_scan_delete_table_entry(struct mwifiex_private *priv, s32 table_idx) | ||
2082 | { | ||
2083 | struct mwifiex_adapter *adapter = priv->adapter; | ||
2084 | u32 del_idx; | ||
2085 | u32 beacon_buf_adj; | ||
2086 | u8 *beacon_buf; | ||
2087 | |||
2088 | /* | ||
2089 | * Shift the saved beacon buffer data for the scan table back over the | ||
2090 | * entry being removed. Update the end of buffer pointer. Save the | ||
2091 | * deleted buffer allocation size for pointer adjustments for entries | ||
2092 | * compacted after the deleted index. | ||
2093 | */ | ||
2094 | beacon_buf_adj = adapter->scan_table[table_idx].beacon_buf_size_max; | ||
2095 | |||
2096 | dev_dbg(adapter->dev, "info: Scan: Delete Entry %d, beacon buffer " | ||
2097 | "removal = %d bytes\n", table_idx, beacon_buf_adj); | ||
2098 | |||
2099 | /* Check if the table entry had storage allocated for its beacon */ | ||
2100 | if (beacon_buf_adj) { | ||
2101 | beacon_buf = adapter->scan_table[table_idx].beacon_buf; | ||
2102 | |||
2103 | /* | ||
2104 | * Remove the entry's buffer space, decrement the table end | ||
2105 | * pointer by the amount we are removing | ||
2106 | */ | ||
2107 | adapter->bcn_buf_end -= beacon_buf_adj; | ||
2108 | |||
2109 | dev_dbg(adapter->dev, "info: scan: delete entry %d," | ||
2110 | " compact data: %p <- %p (sz = %d)\n", | ||
2111 | table_idx, beacon_buf, | ||
2112 | beacon_buf + beacon_buf_adj, | ||
2113 | (int)(adapter->bcn_buf_end - beacon_buf)); | ||
2114 | |||
2115 | /* | ||
2116 | * Compact data storage. Copy all data after the deleted | ||
2117 | * entry's end address (beacon_buf + beacon_buf_adj) back | ||
2118 | * to the original start address (beacon_buf). | ||
2119 | * | ||
2120 | * Scan table entries affected by the move will have their | ||
2121 | * entry pointer adjusted below. | ||
2122 | * | ||
2123 | * Use memmove since the dest/src memory regions overlap. | ||
2124 | */ | ||
2125 | memmove(beacon_buf, beacon_buf + beacon_buf_adj, | ||
2126 | adapter->bcn_buf_end - beacon_buf); | ||
2127 | } | ||
2128 | |||
2129 | dev_dbg(adapter->dev, | ||
2130 | "info: Scan: Delete Entry %d, num_in_scan_table = %d\n", | ||
2131 | table_idx, adapter->num_in_scan_table); | ||
2132 | |||
2133 | /* Shift all of the entries after the table_idx back by one, compacting | ||
2134 | the table and removing the requested entry */ | ||
2135 | for (del_idx = table_idx; (del_idx + 1) < adapter->num_in_scan_table; | ||
2136 | del_idx++) { | ||
2137 | /* Copy the next entry over this one */ | ||
2138 | memcpy(adapter->scan_table + del_idx, | ||
2139 | adapter->scan_table + del_idx + 1, | ||
2140 | sizeof(struct mwifiex_bssdescriptor)); | ||
2141 | |||
2142 | /* | ||
2143 | * Adjust this entry's pointer to its beacon buffer based on | ||
2144 | * the removed/compacted entry from the deleted index. Don't | ||
2145 | * decrement if the buffer pointer is NULL (no data stored for | ||
2146 | * this entry). | ||
2147 | */ | ||
2148 | if (adapter->scan_table[del_idx].beacon_buf) { | ||
2149 | adapter->scan_table[del_idx].beacon_buf -= | ||
2150 | beacon_buf_adj; | ||
2151 | if (adapter->scan_table[del_idx].bcn_wpa_ie) | ||
2152 | adapter->scan_table[del_idx].bcn_wpa_ie = | ||
2153 | (struct ieee_types_vendor_specific *) | ||
2154 | (adapter->scan_table[del_idx]. | ||
2155 | beacon_buf + | ||
2156 | adapter->scan_table[del_idx]. | ||
2157 | wpa_offset); | ||
2158 | if (adapter->scan_table[del_idx].bcn_rsn_ie) | ||
2159 | adapter->scan_table[del_idx].bcn_rsn_ie = | ||
2160 | (struct ieee_types_generic *) | ||
2161 | (adapter->scan_table[del_idx]. | ||
2162 | beacon_buf + | ||
2163 | adapter->scan_table[del_idx]. | ||
2164 | rsn_offset); | ||
2165 | if (adapter->scan_table[del_idx].bcn_wapi_ie) | ||
2166 | adapter->scan_table[del_idx].bcn_wapi_ie = | ||
2167 | (struct ieee_types_generic *) | ||
2168 | (adapter->scan_table[del_idx].beacon_buf | ||
2169 | + adapter->scan_table[del_idx]. | ||
2170 | wapi_offset); | ||
2171 | if (adapter->scan_table[del_idx].bcn_ht_cap) | ||
2172 | adapter->scan_table[del_idx].bcn_ht_cap = | ||
2173 | (struct ieee80211_ht_cap *) | ||
2174 | (adapter->scan_table[del_idx].beacon_buf | ||
2175 | + adapter->scan_table[del_idx]. | ||
2176 | ht_cap_offset); | ||
2177 | |||
2178 | if (adapter->scan_table[del_idx].bcn_ht_info) | ||
2179 | adapter->scan_table[del_idx].bcn_ht_info = | ||
2180 | (struct ieee80211_ht_info *) | ||
2181 | (adapter->scan_table[del_idx].beacon_buf | ||
2182 | + adapter->scan_table[del_idx]. | ||
2183 | ht_info_offset); | ||
2184 | if (adapter->scan_table[del_idx].bcn_bss_co_2040) | ||
2185 | adapter->scan_table[del_idx].bcn_bss_co_2040 = | ||
2186 | (u8 *) | ||
2187 | (adapter->scan_table[del_idx].beacon_buf | ||
2188 | + adapter->scan_table[del_idx]. | ||
2189 | bss_co_2040_offset); | ||
2190 | if (adapter->scan_table[del_idx].bcn_ext_cap) | ||
2191 | adapter->scan_table[del_idx].bcn_ext_cap = | ||
2192 | (u8 *) | ||
2193 | (adapter->scan_table[del_idx].beacon_buf | ||
2194 | + adapter->scan_table[del_idx]. | ||
2195 | ext_cap_offset); | ||
2196 | if (adapter->scan_table[del_idx].bcn_obss_scan) | ||
2197 | adapter->scan_table[del_idx]. | ||
2198 | bcn_obss_scan = | ||
2199 | (struct ieee_types_obss_scan_param *) | ||
2200 | (adapter->scan_table[del_idx].beacon_buf | ||
2201 | + adapter->scan_table[del_idx]. | ||
2202 | overlap_bss_offset); | ||
2203 | } | ||
2204 | } | ||
2205 | |||
2206 | /* The last entry is invalid now that it has been deleted or moved | ||
2207 | back */ | ||
2208 | memset(adapter->scan_table + adapter->num_in_scan_table - 1, | ||
2209 | 0x00, sizeof(struct mwifiex_bssdescriptor)); | ||
2210 | |||
2211 | adapter->num_in_scan_table--; | ||
2212 | } | ||
2213 | |||
2214 | /* | ||
2215 | * This function deletes all occurrences of a given SSID from the scan table. | ||
2216 | * | ||
2217 | * This iterates through the scan table and deletes all entries that match | ||
2218 | * the given SSID. It also compacts the remaining scan table entries. | ||
2219 | */ | ||
2220 | static int | ||
2221 | mwifiex_scan_delete_ssid_table_entry(struct mwifiex_private *priv, | ||
2222 | struct mwifiex_802_11_ssid *del_ssid) | ||
2223 | { | ||
2224 | s32 table_idx = -1; | ||
2225 | |||
2226 | dev_dbg(priv->adapter->dev, "info: scan: delete ssid entry: %-32s\n", | ||
2227 | del_ssid->ssid); | ||
2228 | |||
2229 | /* If the requested SSID is found in the table, delete it. Then keep | ||
2230 | searching the table for multiple entires for the SSID until no | ||
2231 | more are found */ | ||
2232 | while ((table_idx = mwifiex_find_ssid_in_list(priv, del_ssid, NULL, | ||
2233 | NL80211_IFTYPE_UNSPECIFIED)) >= 0) { | ||
2234 | dev_dbg(priv->adapter->dev, | ||
2235 | "info: Scan: Delete SSID Entry: Found Idx = %d\n", | ||
2236 | table_idx); | ||
2237 | mwifiex_scan_delete_table_entry(priv, table_idx); | ||
2238 | } | ||
2239 | |||
2240 | return table_idx == -1 ? -1 : 0; | ||
2241 | } | ||
2242 | |||
2243 | /* | ||
2244 | * This is an internal function used to start a scan based on an input | 1311 | * This is an internal function used to start a scan based on an input |
2245 | * configuration. | 1312 | * configuration. |
2246 | * | 1313 | * |
@@ -2258,7 +1325,6 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, | |||
2258 | struct mwifiex_ie_types_chan_list_param_set *chan_list_out; | 1325 | struct mwifiex_ie_types_chan_list_param_set *chan_list_out; |
2259 | u32 buf_size; | 1326 | u32 buf_size; |
2260 | struct mwifiex_chan_scan_param_set *scan_chan_list; | 1327 | struct mwifiex_chan_scan_param_set *scan_chan_list; |
2261 | u8 keep_previous_scan; | ||
2262 | u8 filtered_scan; | 1328 | u8 filtered_scan; |
2263 | u8 scan_current_chan_only; | 1329 | u8 scan_current_chan_only; |
2264 | u8 max_chan_per_scan; | 1330 | u8 max_chan_per_scan; |
@@ -2295,24 +1361,11 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, | |||
2295 | return -ENOMEM; | 1361 | return -ENOMEM; |
2296 | } | 1362 | } |
2297 | 1363 | ||
2298 | keep_previous_scan = false; | ||
2299 | |||
2300 | mwifiex_scan_setup_scan_config(priv, user_scan_in, | 1364 | mwifiex_scan_setup_scan_config(priv, user_scan_in, |
2301 | &scan_cfg_out->config, &chan_list_out, | 1365 | &scan_cfg_out->config, &chan_list_out, |
2302 | scan_chan_list, &max_chan_per_scan, | 1366 | scan_chan_list, &max_chan_per_scan, |
2303 | &filtered_scan, &scan_current_chan_only); | 1367 | &filtered_scan, &scan_current_chan_only); |
2304 | 1368 | ||
2305 | if (user_scan_in) | ||
2306 | keep_previous_scan = user_scan_in->keep_previous_scan; | ||
2307 | |||
2308 | |||
2309 | if (!keep_previous_scan) { | ||
2310 | memset(adapter->scan_table, 0x00, | ||
2311 | sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP); | ||
2312 | adapter->num_in_scan_table = 0; | ||
2313 | adapter->bcn_buf_end = adapter->bcn_buf; | ||
2314 | } | ||
2315 | |||
2316 | ret = mwifiex_scan_channel_list(priv, max_chan_per_scan, filtered_scan, | 1369 | ret = mwifiex_scan_channel_list(priv, max_chan_per_scan, filtered_scan, |
2317 | &scan_cfg_out->config, chan_list_out, | 1370 | &scan_cfg_out->config, chan_list_out, |
2318 | scan_chan_list); | 1371 | scan_chan_list); |
@@ -2379,6 +1432,107 @@ int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd, | |||
2379 | } | 1432 | } |
2380 | 1433 | ||
2381 | /* | 1434 | /* |
1435 | * This function checks compatibility of requested network with current | ||
1436 | * driver settings. | ||
1437 | */ | ||
1438 | int mwifiex_check_network_compatibility(struct mwifiex_private *priv, | ||
1439 | struct mwifiex_bssdescriptor *bss_desc) | ||
1440 | { | ||
1441 | int ret = -1; | ||
1442 | |||
1443 | if (!bss_desc) | ||
1444 | return -1; | ||
1445 | |||
1446 | if ((mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv, | ||
1447 | (u8) bss_desc->bss_band, (u16) bss_desc->channel))) { | ||
1448 | switch (priv->bss_mode) { | ||
1449 | case NL80211_IFTYPE_STATION: | ||
1450 | case NL80211_IFTYPE_ADHOC: | ||
1451 | ret = mwifiex_is_network_compatible(priv, bss_desc, | ||
1452 | priv->bss_mode); | ||
1453 | if (ret) | ||
1454 | dev_err(priv->adapter->dev, "cannot find ssid " | ||
1455 | "%s\n", bss_desc->ssid.ssid); | ||
1456 | break; | ||
1457 | default: | ||
1458 | ret = 0; | ||
1459 | } | ||
1460 | } | ||
1461 | |||
1462 | return ret; | ||
1463 | } | ||
1464 | |||
1465 | static int | ||
1466 | mwifiex_update_curr_bss_params(struct mwifiex_private *priv, | ||
1467 | u8 *bssid, s32 rssi, const u8 *ie_buf, | ||
1468 | size_t ie_len, u16 beacon_period, u16 cap_info_bitmap) | ||
1469 | { | ||
1470 | struct mwifiex_bssdescriptor *bss_desc = NULL; | ||
1471 | int ret; | ||
1472 | unsigned long flags; | ||
1473 | u8 *beacon_ie; | ||
1474 | |||
1475 | /* Allocate and fill new bss descriptor */ | ||
1476 | bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor), | ||
1477 | GFP_KERNEL); | ||
1478 | if (!bss_desc) { | ||
1479 | dev_err(priv->adapter->dev, " failed to alloc bss_desc\n"); | ||
1480 | return -ENOMEM; | ||
1481 | } | ||
1482 | beacon_ie = kzalloc(ie_len, GFP_KERNEL); | ||
1483 | if (!bss_desc) { | ||
1484 | dev_err(priv->adapter->dev, " failed to alloc bss_desc\n"); | ||
1485 | return -ENOMEM; | ||
1486 | } | ||
1487 | memcpy(beacon_ie, ie_buf, ie_len); | ||
1488 | |||
1489 | ret = mwifiex_fill_new_bss_desc(priv, bssid, rssi, beacon_ie, | ||
1490 | ie_len, beacon_period, | ||
1491 | cap_info_bitmap, bss_desc); | ||
1492 | if (ret) | ||
1493 | goto done; | ||
1494 | |||
1495 | ret = mwifiex_check_network_compatibility(priv, bss_desc); | ||
1496 | if (ret) | ||
1497 | goto done; | ||
1498 | |||
1499 | /* Update current bss descriptor parameters */ | ||
1500 | spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags); | ||
1501 | priv->curr_bss_params.bss_descriptor.bcn_wpa_ie = NULL; | ||
1502 | priv->curr_bss_params.bss_descriptor.wpa_offset = 0; | ||
1503 | priv->curr_bss_params.bss_descriptor.bcn_rsn_ie = NULL; | ||
1504 | priv->curr_bss_params.bss_descriptor.rsn_offset = 0; | ||
1505 | priv->curr_bss_params.bss_descriptor.bcn_wapi_ie = NULL; | ||
1506 | priv->curr_bss_params.bss_descriptor.wapi_offset = 0; | ||
1507 | priv->curr_bss_params.bss_descriptor.bcn_ht_cap = NULL; | ||
1508 | priv->curr_bss_params.bss_descriptor.ht_cap_offset = | ||
1509 | 0; | ||
1510 | priv->curr_bss_params.bss_descriptor.bcn_ht_info = NULL; | ||
1511 | priv->curr_bss_params.bss_descriptor.ht_info_offset = | ||
1512 | 0; | ||
1513 | priv->curr_bss_params.bss_descriptor.bcn_bss_co_2040 = | ||
1514 | NULL; | ||
1515 | priv->curr_bss_params.bss_descriptor. | ||
1516 | bss_co_2040_offset = 0; | ||
1517 | priv->curr_bss_params.bss_descriptor.bcn_ext_cap = NULL; | ||
1518 | priv->curr_bss_params.bss_descriptor.ext_cap_offset = 0; | ||
1519 | priv->curr_bss_params.bss_descriptor.beacon_buf = NULL; | ||
1520 | priv->curr_bss_params.bss_descriptor.beacon_buf_size = | ||
1521 | 0; | ||
1522 | |||
1523 | /* Make a copy of current BSSID descriptor */ | ||
1524 | memcpy(&priv->curr_bss_params.bss_descriptor, bss_desc, | ||
1525 | sizeof(priv->curr_bss_params.bss_descriptor)); | ||
1526 | mwifiex_save_curr_bcn(priv); | ||
1527 | spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags); | ||
1528 | |||
1529 | done: | ||
1530 | kfree(bss_desc); | ||
1531 | kfree(beacon_ie); | ||
1532 | return 0; | ||
1533 | } | ||
1534 | |||
1535 | /* | ||
2382 | * This function handles the command response of scan. | 1536 | * This function handles the command response of scan. |
2383 | * | 1537 | * |
2384 | * The response buffer for the scan command has the following | 1538 | * The response buffer for the scan command has the following |
@@ -2404,21 +1558,16 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, | |||
2404 | struct mwifiex_adapter *adapter = priv->adapter; | 1558 | struct mwifiex_adapter *adapter = priv->adapter; |
2405 | struct cmd_ctrl_node *cmd_node; | 1559 | struct cmd_ctrl_node *cmd_node; |
2406 | struct host_cmd_ds_802_11_scan_rsp *scan_rsp; | 1560 | struct host_cmd_ds_802_11_scan_rsp *scan_rsp; |
2407 | struct mwifiex_bssdescriptor *bss_new_entry = NULL; | ||
2408 | struct mwifiex_ie_types_data *tlv_data; | 1561 | struct mwifiex_ie_types_data *tlv_data; |
2409 | struct mwifiex_ie_types_tsf_timestamp *tsf_tlv; | 1562 | struct mwifiex_ie_types_tsf_timestamp *tsf_tlv; |
2410 | u8 *bss_info; | 1563 | u8 *bss_info; |
2411 | u32 scan_resp_size; | 1564 | u32 scan_resp_size; |
2412 | u32 bytes_left; | 1565 | u32 bytes_left; |
2413 | u32 num_in_table; | ||
2414 | u32 bss_idx; | ||
2415 | u32 idx; | 1566 | u32 idx; |
2416 | u32 tlv_buf_size; | 1567 | u32 tlv_buf_size; |
2417 | long long tsf_val; | ||
2418 | struct mwifiex_chan_freq_power *cfp; | 1568 | struct mwifiex_chan_freq_power *cfp; |
2419 | struct mwifiex_ie_types_chan_band_list_param_set *chan_band_tlv; | 1569 | struct mwifiex_ie_types_chan_band_list_param_set *chan_band_tlv; |
2420 | struct chan_band_param_set *chan_band; | 1570 | struct chan_band_param_set *chan_band; |
2421 | u8 band; | ||
2422 | u8 is_bgscan_resp; | 1571 | u8 is_bgscan_resp; |
2423 | unsigned long flags; | 1572 | unsigned long flags; |
2424 | 1573 | ||
@@ -2430,7 +1579,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, | |||
2430 | scan_rsp = &resp->params.scan_resp; | 1579 | scan_rsp = &resp->params.scan_resp; |
2431 | 1580 | ||
2432 | 1581 | ||
2433 | if (scan_rsp->number_of_sets > IW_MAX_AP) { | 1582 | if (scan_rsp->number_of_sets > MWIFIEX_MAX_AP) { |
2434 | dev_err(adapter->dev, "SCAN_RESP: too many AP returned (%d)\n", | 1583 | dev_err(adapter->dev, "SCAN_RESP: too many AP returned (%d)\n", |
2435 | scan_rsp->number_of_sets); | 1584 | scan_rsp->number_of_sets); |
2436 | ret = -1; | 1585 | ret = -1; |
@@ -2447,7 +1596,6 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, | |||
2447 | "info: SCAN_RESP: returned %d APs before parsing\n", | 1596 | "info: SCAN_RESP: returned %d APs before parsing\n", |
2448 | scan_rsp->number_of_sets); | 1597 | scan_rsp->number_of_sets); |
2449 | 1598 | ||
2450 | num_in_table = adapter->num_in_scan_table; | ||
2451 | bss_info = scan_rsp->bss_desc_and_tlv_buffer; | 1599 | bss_info = scan_rsp->bss_desc_and_tlv_buffer; |
2452 | 1600 | ||
2453 | /* | 1601 | /* |
@@ -2479,125 +1627,147 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, | |||
2479 | (struct mwifiex_ie_types_data **) | 1627 | (struct mwifiex_ie_types_data **) |
2480 | &chan_band_tlv); | 1628 | &chan_band_tlv); |
2481 | 1629 | ||
2482 | /* | ||
2483 | * Process each scan response returned (scan_rsp->number_of_sets). | ||
2484 | * Save the information in the bss_new_entry and then insert into the | ||
2485 | * driver scan table either as an update to an existing entry | ||
2486 | * or as an addition at the end of the table | ||
2487 | */ | ||
2488 | bss_new_entry = kzalloc(sizeof(struct mwifiex_bssdescriptor), | ||
2489 | GFP_KERNEL); | ||
2490 | if (!bss_new_entry) { | ||
2491 | dev_err(adapter->dev, " failed to alloc bss_new_entry\n"); | ||
2492 | return -ENOMEM; | ||
2493 | } | ||
2494 | |||
2495 | for (idx = 0; idx < scan_rsp->number_of_sets && bytes_left; idx++) { | 1630 | for (idx = 0; idx < scan_rsp->number_of_sets && bytes_left; idx++) { |
2496 | /* Zero out the bss_new_entry we are about to store info in */ | 1631 | u8 bssid[ETH_ALEN]; |
2497 | memset(bss_new_entry, 0x00, | 1632 | s32 rssi; |
2498 | sizeof(struct mwifiex_bssdescriptor)); | 1633 | const u8 *ie_buf; |
2499 | 1634 | size_t ie_len; | |
2500 | if (mwifiex_interpret_bss_desc_with_ie(adapter, bss_new_entry, | 1635 | int channel = -1; |
2501 | &bss_info, | 1636 | u64 network_tsf = 0; |
2502 | &bytes_left)) { | 1637 | u16 beacon_size = 0; |
2503 | /* Error parsing/interpreting scan response, skipped */ | 1638 | u32 curr_bcn_bytes; |
2504 | dev_err(adapter->dev, "SCAN_RESP: " | 1639 | u32 freq; |
2505 | "mwifiex_interpret_bss_desc_with_ie " | 1640 | u16 beacon_period; |
2506 | "returned ERROR\n"); | 1641 | u16 cap_info_bitmap; |
2507 | continue; | 1642 | u8 *current_ptr; |
1643 | struct mwifiex_bcn_param *bcn_param; | ||
1644 | |||
1645 | if (bytes_left >= sizeof(beacon_size)) { | ||
1646 | /* Extract & convert beacon size from command buffer */ | ||
1647 | memcpy(&beacon_size, bss_info, sizeof(beacon_size)); | ||
1648 | bytes_left -= sizeof(beacon_size); | ||
1649 | bss_info += sizeof(beacon_size); | ||
2508 | } | 1650 | } |
2509 | 1651 | ||
2510 | /* Process the data fields and IEs returned for this BSS */ | 1652 | if (!beacon_size || beacon_size > bytes_left) { |
2511 | dev_dbg(adapter->dev, "info: SCAN_RESP: BSSID = %pM\n", | 1653 | bss_info += bytes_left; |
2512 | bss_new_entry->mac_address); | 1654 | bytes_left = 0; |
1655 | return -1; | ||
1656 | } | ||
2513 | 1657 | ||
2514 | /* Search the scan table for the same bssid */ | 1658 | /* Initialize the current working beacon pointer for this BSS |
2515 | for (bss_idx = 0; bss_idx < num_in_table; bss_idx++) { | 1659 | * iteration */ |
2516 | if (memcmp(bss_new_entry->mac_address, | 1660 | current_ptr = bss_info; |
2517 | adapter->scan_table[bss_idx].mac_address, | 1661 | |
2518 | sizeof(bss_new_entry->mac_address))) { | 1662 | /* Advance the return beacon pointer past the current beacon */ |
2519 | continue; | 1663 | bss_info += beacon_size; |
1664 | bytes_left -= beacon_size; | ||
1665 | |||
1666 | curr_bcn_bytes = beacon_size; | ||
1667 | |||
1668 | /* | ||
1669 | * First 5 fields are bssid, RSSI, time stamp, beacon interval, | ||
1670 | * and capability information | ||
1671 | */ | ||
1672 | if (curr_bcn_bytes < sizeof(struct mwifiex_bcn_param)) { | ||
1673 | dev_err(adapter->dev, "InterpretIE: not enough bytes left\n"); | ||
1674 | continue; | ||
1675 | } | ||
1676 | bcn_param = (struct mwifiex_bcn_param *)current_ptr; | ||
1677 | current_ptr += sizeof(*bcn_param); | ||
1678 | curr_bcn_bytes -= sizeof(*bcn_param); | ||
1679 | |||
1680 | memcpy(bssid, bcn_param->bssid, ETH_ALEN); | ||
1681 | |||
1682 | rssi = (s32) (bcn_param->rssi); | ||
1683 | dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%02X\n", | ||
1684 | rssi); | ||
1685 | |||
1686 | beacon_period = le16_to_cpu(bcn_param->beacon_period); | ||
1687 | |||
1688 | cap_info_bitmap = le16_to_cpu(bcn_param->cap_info_bitmap); | ||
1689 | dev_dbg(adapter->dev, "info: InterpretIE: capabilities=0x%X\n", | ||
1690 | cap_info_bitmap); | ||
1691 | |||
1692 | /* Rest of the current buffer are IE's */ | ||
1693 | ie_buf = current_ptr; | ||
1694 | ie_len = curr_bcn_bytes; | ||
1695 | dev_dbg(adapter->dev, "info: InterpretIE: IELength for this AP" | ||
1696 | " = %d\n", curr_bcn_bytes); | ||
1697 | |||
1698 | while (curr_bcn_bytes >= sizeof(struct ieee_types_header)) { | ||
1699 | u8 element_id, element_len; | ||
1700 | |||
1701 | element_id = *current_ptr; | ||
1702 | element_len = *(current_ptr + 1); | ||
1703 | if (curr_bcn_bytes < element_len + | ||
1704 | sizeof(struct ieee_types_header)) { | ||
1705 | dev_err(priv->adapter->dev, "%s: in processing" | ||
1706 | " IE, bytes left < IE length\n", | ||
1707 | __func__); | ||
1708 | goto done; | ||
2520 | } | 1709 | } |
2521 | /* | 1710 | if (element_id == WLAN_EID_DS_PARAMS) { |
2522 | * If the SSID matches as well, it is a | 1711 | channel = *(u8 *) (current_ptr + |
2523 | * duplicate of this entry. Keep the bss_idx | 1712 | sizeof(struct ieee_types_header)); |
2524 | * set to this entry so we replace the old | ||
2525 | * contents in the table | ||
2526 | */ | ||
2527 | if ((bss_new_entry->ssid.ssid_len | ||
2528 | == adapter->scan_table[bss_idx]. ssid.ssid_len) | ||
2529 | && (!memcmp(bss_new_entry->ssid.ssid, | ||
2530 | adapter->scan_table[bss_idx].ssid.ssid, | ||
2531 | bss_new_entry->ssid.ssid_len))) { | ||
2532 | dev_dbg(adapter->dev, "info: SCAN_RESP:" | ||
2533 | " duplicate of index: %d\n", bss_idx); | ||
2534 | break; | 1713 | break; |
2535 | } | 1714 | } |
2536 | } | 1715 | |
2537 | /* | 1716 | current_ptr += element_len + |
2538 | * If the bss_idx is equal to the number of entries in | 1717 | sizeof(struct ieee_types_header); |
2539 | * the table, the new entry was not a duplicate; append | 1718 | curr_bcn_bytes -= element_len + |
2540 | * it to the scan table | 1719 | sizeof(struct ieee_types_header); |
2541 | */ | ||
2542 | if (bss_idx == num_in_table) { | ||
2543 | /* Range check the bss_idx, keep it limited to | ||
2544 | the last entry */ | ||
2545 | if (bss_idx == IW_MAX_AP) | ||
2546 | bss_idx--; | ||
2547 | else | ||
2548 | num_in_table++; | ||
2549 | } | 1720 | } |
2550 | 1721 | ||
2551 | /* | 1722 | /* |
2552 | * Save the beacon/probe response returned for later application | ||
2553 | * retrieval. Duplicate beacon/probe responses are updated if | ||
2554 | * possible | ||
2555 | */ | ||
2556 | mwifiex_ret_802_11_scan_store_beacon(priv, bss_idx, | ||
2557 | num_in_table, bss_new_entry); | ||
2558 | /* | ||
2559 | * If the TSF TLV was appended to the scan results, save this | 1723 | * If the TSF TLV was appended to the scan results, save this |
2560 | * entry's TSF value in the networkTSF field.The networkTSF is | 1724 | * entry's TSF value in the networkTSF field.The networkTSF is |
2561 | * the firmware's TSF value at the time the beacon or probe | 1725 | * the firmware's TSF value at the time the beacon or probe |
2562 | * response was received. | 1726 | * response was received. |
2563 | */ | 1727 | */ |
2564 | if (tsf_tlv) { | 1728 | if (tsf_tlv) |
2565 | memcpy(&tsf_val, &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE] | 1729 | memcpy(&network_tsf, |
2566 | , sizeof(tsf_val)); | 1730 | &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE], |
2567 | memcpy(&bss_new_entry->network_tsf, &tsf_val, | 1731 | sizeof(network_tsf)); |
2568 | sizeof(bss_new_entry->network_tsf)); | 1732 | |
2569 | } | 1733 | if (channel != -1) { |
2570 | band = BAND_G; | 1734 | struct ieee80211_channel *chan; |
2571 | if (chan_band_tlv) { | 1735 | u8 band; |
2572 | chan_band = &chan_band_tlv->chan_band_param[idx]; | 1736 | |
2573 | band = mwifiex_radio_type_to_band(chan_band->radio_type | 1737 | band = BAND_G; |
2574 | & (BIT(0) | BIT(1))); | 1738 | if (chan_band_tlv) { |
2575 | } | 1739 | chan_band = |
2576 | 1740 | &chan_band_tlv->chan_band_param[idx]; | |
2577 | /* Save the band designation for this entry for use in join */ | 1741 | band = mwifiex_radio_type_to_band( |
2578 | bss_new_entry->bss_band = band; | 1742 | chan_band->radio_type |
2579 | cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv, | 1743 | & (BIT(0) | BIT(1))); |
2580 | (u8) bss_new_entry->bss_band, | 1744 | } |
2581 | (u16)bss_new_entry->channel); | ||
2582 | 1745 | ||
2583 | if (cfp) | 1746 | cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211( |
2584 | bss_new_entry->freq = cfp->freq; | 1747 | priv, (u8)band, (u16)channel); |
2585 | else | ||
2586 | bss_new_entry->freq = 0; | ||
2587 | 1748 | ||
2588 | /* Copy the locally created bss_new_entry to the scan table */ | 1749 | freq = cfp ? cfp->freq : 0; |
2589 | memcpy(&adapter->scan_table[bss_idx], bss_new_entry, | ||
2590 | sizeof(adapter->scan_table[bss_idx])); | ||
2591 | 1750 | ||
2592 | } | 1751 | chan = ieee80211_get_channel(priv->wdev->wiphy, freq); |
2593 | 1752 | ||
2594 | dev_dbg(adapter->dev, | 1753 | if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) { |
2595 | "info: SCAN_RESP: Scanned %2d APs, %d valid, %d total\n", | 1754 | cfg80211_inform_bss(priv->wdev->wiphy, chan, |
2596 | scan_rsp->number_of_sets, | 1755 | bssid, network_tsf, cap_info_bitmap, |
2597 | num_in_table - adapter->num_in_scan_table, num_in_table); | 1756 | beacon_period, ie_buf, ie_len, rssi, |
1757 | GFP_KERNEL); | ||
2598 | 1758 | ||
2599 | /* Update the total number of BSSIDs in the scan table */ | 1759 | if (priv->media_connected && !memcmp(bssid, |
2600 | adapter->num_in_scan_table = num_in_table; | 1760 | priv->curr_bss_params.bss_descriptor |
1761 | .mac_address, ETH_ALEN)) | ||
1762 | mwifiex_update_curr_bss_params(priv, | ||
1763 | bssid, rssi, ie_buf, | ||
1764 | ie_len, beacon_period, | ||
1765 | cap_info_bitmap); | ||
1766 | } | ||
1767 | } else { | ||
1768 | dev_dbg(adapter->dev, "missing BSS channel IE\n"); | ||
1769 | } | ||
1770 | } | ||
2601 | 1771 | ||
2602 | spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); | 1772 | spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); |
2603 | if (list_empty(&adapter->scan_pending_q)) { | 1773 | if (list_empty(&adapter->scan_pending_q)) { |
@@ -2605,12 +1775,6 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, | |||
2605 | spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); | 1775 | spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); |
2606 | adapter->scan_processing = false; | 1776 | adapter->scan_processing = false; |
2607 | spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); | 1777 | spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); |
2608 | /* | ||
2609 | * Process the resulting scan table: | ||
2610 | * - Remove any bad ssids | ||
2611 | * - Update our current BSS information from scan data | ||
2612 | */ | ||
2613 | mwifiex_process_scan_results(priv); | ||
2614 | 1778 | ||
2615 | /* Need to indicate IOCTL complete */ | 1779 | /* Need to indicate IOCTL complete */ |
2616 | if (adapter->curr_cmd->wait_q_enabled) { | 1780 | if (adapter->curr_cmd->wait_q_enabled) { |
@@ -2636,7 +1800,6 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, | |||
2636 | } | 1800 | } |
2637 | 1801 | ||
2638 | done: | 1802 | done: |
2639 | kfree((u8 *) bss_new_entry); | ||
2640 | return ret; | 1803 | return ret; |
2641 | } | 1804 | } |
2642 | 1805 | ||
@@ -2663,141 +1826,6 @@ int mwifiex_cmd_802_11_bg_scan_query(struct host_cmd_ds_command *cmd) | |||
2663 | } | 1826 | } |
2664 | 1827 | ||
2665 | /* | 1828 | /* |
2666 | * This function finds a SSID in the scan table. | ||
2667 | * | ||
2668 | * A BSSID may optionally be provided to qualify the SSID. | ||
2669 | * For non-Auto mode, further check is made to make sure the | ||
2670 | * BSS found in the scan table is compatible with the current | ||
2671 | * settings of the driver. | ||
2672 | */ | ||
2673 | s32 | ||
2674 | mwifiex_find_ssid_in_list(struct mwifiex_private *priv, | ||
2675 | struct mwifiex_802_11_ssid *ssid, u8 *bssid, | ||
2676 | u32 mode) | ||
2677 | { | ||
2678 | struct mwifiex_adapter *adapter = priv->adapter; | ||
2679 | s32 net = -1, j; | ||
2680 | u8 best_rssi = 0; | ||
2681 | u32 i; | ||
2682 | |||
2683 | dev_dbg(adapter->dev, "info: num of entries in table = %d\n", | ||
2684 | adapter->num_in_scan_table); | ||
2685 | |||
2686 | /* | ||
2687 | * Loop through the table until the maximum is reached or until a match | ||
2688 | * is found based on the bssid field comparison | ||
2689 | */ | ||
2690 | for (i = 0; | ||
2691 | i < adapter->num_in_scan_table && (!bssid || (bssid && net < 0)); | ||
2692 | i++) { | ||
2693 | if (!mwifiex_ssid_cmp(&adapter->scan_table[i].ssid, ssid) && | ||
2694 | (!bssid | ||
2695 | || !memcmp(adapter->scan_table[i].mac_address, bssid, | ||
2696 | ETH_ALEN)) | ||
2697 | && | ||
2698 | (mwifiex_get_cfp_by_band_and_channel_from_cfg80211 | ||
2699 | (priv, (u8) adapter->scan_table[i].bss_band, | ||
2700 | (u16) adapter->scan_table[i].channel))) { | ||
2701 | switch (mode) { | ||
2702 | case NL80211_IFTYPE_STATION: | ||
2703 | case NL80211_IFTYPE_ADHOC: | ||
2704 | j = mwifiex_is_network_compatible(priv, i, | ||
2705 | mode); | ||
2706 | |||
2707 | if (j >= 0) { | ||
2708 | if (SCAN_RSSI | ||
2709 | (adapter->scan_table[i].rssi) > | ||
2710 | best_rssi) { | ||
2711 | best_rssi = SCAN_RSSI(adapter-> | ||
2712 | scan_table | ||
2713 | [i].rssi); | ||
2714 | net = i; | ||
2715 | } | ||
2716 | } else { | ||
2717 | if (net == -1) | ||
2718 | net = j; | ||
2719 | } | ||
2720 | break; | ||
2721 | case NL80211_IFTYPE_UNSPECIFIED: | ||
2722 | default: | ||
2723 | /* | ||
2724 | * Do not check compatibility if the mode | ||
2725 | * requested is Auto/Unknown. Allows generic | ||
2726 | * find to work without verifying against the | ||
2727 | * Adapter security settings | ||
2728 | */ | ||
2729 | if (SCAN_RSSI(adapter->scan_table[i].rssi) > | ||
2730 | best_rssi) { | ||
2731 | best_rssi = SCAN_RSSI(adapter-> | ||
2732 | scan_table[i].rssi); | ||
2733 | net = i; | ||
2734 | } | ||
2735 | break; | ||
2736 | } | ||
2737 | } | ||
2738 | } | ||
2739 | |||
2740 | return net; | ||
2741 | } | ||
2742 | |||
2743 | /* | ||
2744 | * This function finds a specific compatible BSSID in the scan list. | ||
2745 | * | ||
2746 | * This function loops through the scan table looking for a compatible | ||
2747 | * match. If a BSSID matches, but the BSS is found to be not compatible | ||
2748 | * the function ignores it and continues to search through the rest of | ||
2749 | * the entries in case there is an AP with multiple SSIDs assigned to | ||
2750 | * the same BSSID. | ||
2751 | */ | ||
2752 | s32 | ||
2753 | mwifiex_find_bssid_in_list(struct mwifiex_private *priv, u8 *bssid, | ||
2754 | u32 mode) | ||
2755 | { | ||
2756 | struct mwifiex_adapter *adapter = priv->adapter; | ||
2757 | s32 net = -1; | ||
2758 | u32 i; | ||
2759 | |||
2760 | if (!bssid) | ||
2761 | return -1; | ||
2762 | |||
2763 | dev_dbg(adapter->dev, "info: FindBSSID: Num of BSSIDs = %d\n", | ||
2764 | adapter->num_in_scan_table); | ||
2765 | |||
2766 | /* | ||
2767 | * Look through the scan table for a compatible match. The ret return | ||
2768 | * variable will be equal to the index in the scan table (greater | ||
2769 | * than zero) if the network is compatible. The loop will continue | ||
2770 | * past a matched bssid that is not compatible in case there is an | ||
2771 | * AP with multiple SSIDs assigned to the same BSSID | ||
2772 | */ | ||
2773 | for (i = 0; net < 0 && i < adapter->num_in_scan_table; i++) { | ||
2774 | if (!memcmp | ||
2775 | (adapter->scan_table[i].mac_address, bssid, ETH_ALEN) | ||
2776 | && mwifiex_get_cfp_by_band_and_channel_from_cfg80211 | ||
2777 | (priv, | ||
2778 | (u8) adapter-> | ||
2779 | scan_table[i]. | ||
2780 | bss_band, | ||
2781 | (u16) adapter-> | ||
2782 | scan_table[i]. | ||
2783 | channel)) { | ||
2784 | switch (mode) { | ||
2785 | case NL80211_IFTYPE_STATION: | ||
2786 | case NL80211_IFTYPE_ADHOC: | ||
2787 | net = mwifiex_is_network_compatible(priv, i, | ||
2788 | mode); | ||
2789 | break; | ||
2790 | default: | ||
2791 | net = i; | ||
2792 | break; | ||
2793 | } | ||
2794 | } | ||
2795 | } | ||
2796 | |||
2797 | return net; | ||
2798 | } | ||
2799 | |||
2800 | /* | ||
2801 | * This function inserts scan command node to the scan pending queue. | 1829 | * This function inserts scan command node to the scan pending queue. |
2802 | */ | 1830 | */ |
2803 | void | 1831 | void |
@@ -2814,42 +1842,6 @@ mwifiex_queue_scan_cmd(struct mwifiex_private *priv, | |||
2814 | } | 1842 | } |
2815 | 1843 | ||
2816 | /* | 1844 | /* |
2817 | * This function finds an AP with specific ssid in the scan list. | ||
2818 | */ | ||
2819 | int mwifiex_find_best_network(struct mwifiex_private *priv, | ||
2820 | struct mwifiex_ssid_bssid *req_ssid_bssid) | ||
2821 | { | ||
2822 | struct mwifiex_adapter *adapter = priv->adapter; | ||
2823 | struct mwifiex_bssdescriptor *req_bss; | ||
2824 | s32 i; | ||
2825 | |||
2826 | memset(req_ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid)); | ||
2827 | |||
2828 | i = mwifiex_find_best_network_in_list(priv); | ||
2829 | |||
2830 | if (i >= 0) { | ||
2831 | req_bss = &adapter->scan_table[i]; | ||
2832 | memcpy(&req_ssid_bssid->ssid, &req_bss->ssid, | ||
2833 | sizeof(struct mwifiex_802_11_ssid)); | ||
2834 | memcpy((u8 *) &req_ssid_bssid->bssid, | ||
2835 | (u8 *) &req_bss->mac_address, ETH_ALEN); | ||
2836 | |||
2837 | /* Make sure we are in the right mode */ | ||
2838 | if (priv->bss_mode == NL80211_IFTYPE_UNSPECIFIED) | ||
2839 | priv->bss_mode = req_bss->bss_mode; | ||
2840 | } | ||
2841 | |||
2842 | if (!req_ssid_bssid->ssid.ssid_len) | ||
2843 | return -1; | ||
2844 | |||
2845 | dev_dbg(adapter->dev, "info: Best network found = [%s], " | ||
2846 | "[%pM]\n", req_ssid_bssid->ssid.ssid, | ||
2847 | req_ssid_bssid->bssid); | ||
2848 | |||
2849 | return 0; | ||
2850 | } | ||
2851 | |||
2852 | /* | ||
2853 | * This function sends a scan command for all available channels to the | 1845 | * This function sends a scan command for all available channels to the |
2854 | * firmware, filtered on a specific SSID. | 1846 | * firmware, filtered on a specific SSID. |
2855 | */ | 1847 | */ |
@@ -2874,8 +1866,6 @@ static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv, | |||
2874 | return ret; | 1866 | return ret; |
2875 | } | 1867 | } |
2876 | 1868 | ||
2877 | mwifiex_scan_delete_ssid_table_entry(priv, req_ssid); | ||
2878 | |||
2879 | scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), GFP_KERNEL); | 1869 | scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), GFP_KERNEL); |
2880 | if (!scan_cfg) { | 1870 | if (!scan_cfg) { |
2881 | dev_err(adapter->dev, "failed to alloc scan_cfg\n"); | 1871 | dev_err(adapter->dev, "failed to alloc scan_cfg\n"); |
@@ -2884,7 +1874,6 @@ static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv, | |||
2884 | 1874 | ||
2885 | memcpy(scan_cfg->ssid_list[0].ssid, req_ssid->ssid, | 1875 | memcpy(scan_cfg->ssid_list[0].ssid, req_ssid->ssid, |
2886 | req_ssid->ssid_len); | 1876 | req_ssid->ssid_len); |
2887 | scan_cfg->keep_previous_scan = true; | ||
2888 | 1877 | ||
2889 | ret = mwifiex_scan_networks(priv, scan_cfg); | 1878 | ret = mwifiex_scan_networks(priv, scan_cfg); |
2890 | 1879 | ||
@@ -3010,6 +1999,39 @@ mwifiex_save_curr_bcn(struct mwifiex_private *priv) | |||
3010 | curr_bss->beacon_buf_size); | 1999 | curr_bss->beacon_buf_size); |
3011 | dev_dbg(priv->adapter->dev, "info: current beacon saved %d\n", | 2000 | dev_dbg(priv->adapter->dev, "info: current beacon saved %d\n", |
3012 | priv->curr_bcn_size); | 2001 | priv->curr_bcn_size); |
2002 | |||
2003 | curr_bss->beacon_buf = priv->curr_bcn_buf; | ||
2004 | |||
2005 | /* adjust the pointers in the current BSS descriptor */ | ||
2006 | if (curr_bss->bcn_wpa_ie) | ||
2007 | curr_bss->bcn_wpa_ie = | ||
2008 | (struct ieee_types_vendor_specific *) | ||
2009 | (curr_bss->beacon_buf + | ||
2010 | curr_bss->wpa_offset); | ||
2011 | |||
2012 | if (curr_bss->bcn_rsn_ie) | ||
2013 | curr_bss->bcn_rsn_ie = (struct ieee_types_generic *) | ||
2014 | (curr_bss->beacon_buf + | ||
2015 | curr_bss->rsn_offset); | ||
2016 | |||
2017 | if (curr_bss->bcn_ht_cap) | ||
2018 | curr_bss->bcn_ht_cap = (struct ieee80211_ht_cap *) | ||
2019 | (curr_bss->beacon_buf + | ||
2020 | curr_bss->ht_cap_offset); | ||
2021 | |||
2022 | if (curr_bss->bcn_ht_info) | ||
2023 | curr_bss->bcn_ht_info = (struct ieee80211_ht_info *) | ||
2024 | (curr_bss->beacon_buf + | ||
2025 | curr_bss->ht_info_offset); | ||
2026 | |||
2027 | if (curr_bss->bcn_bss_co_2040) | ||
2028 | curr_bss->bcn_bss_co_2040 = | ||
2029 | (u8 *) (curr_bss->beacon_buf + | ||
2030 | curr_bss->bss_co_2040_offset); | ||
2031 | |||
2032 | if (curr_bss->bcn_ext_cap) | ||
2033 | curr_bss->bcn_ext_cap = (u8 *) (curr_bss->beacon_buf + | ||
2034 | curr_bss->ext_cap_offset); | ||
3013 | } | 2035 | } |
3014 | 2036 | ||
3015 | /* | 2037 | /* |
diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index fc265cab0907..f204810e8338 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c | |||
@@ -130,8 +130,8 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv) | |||
130 | if (netif_carrier_ok(priv->netdev)) | 130 | if (netif_carrier_ok(priv->netdev)) |
131 | netif_carrier_off(priv->netdev); | 131 | netif_carrier_off(priv->netdev); |
132 | /* Reset wireless stats signal info */ | 132 | /* Reset wireless stats signal info */ |
133 | priv->w_stats.qual.level = 0; | 133 | priv->qual_level = 0; |
134 | priv->w_stats.qual.noise = 0; | 134 | priv->qual_noise = 0; |
135 | } | 135 | } |
136 | 136 | ||
137 | /* | 137 | /* |
@@ -299,11 +299,6 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) | |||
299 | 299 | ||
300 | case EVENT_BG_SCAN_REPORT: | 300 | case EVENT_BG_SCAN_REPORT: |
301 | dev_dbg(adapter->dev, "event: BGS_REPORT\n"); | 301 | dev_dbg(adapter->dev, "event: BGS_REPORT\n"); |
302 | /* Clear the previous scan result */ | ||
303 | memset(adapter->scan_table, 0x00, | ||
304 | sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP); | ||
305 | adapter->num_in_scan_table = 0; | ||
306 | adapter->bcn_buf_end = adapter->bcn_buf; | ||
307 | ret = mwifiex_send_cmd_async(priv, | 302 | ret = mwifiex_send_cmd_async(priv, |
308 | HostCmd_CMD_802_11_BG_SCAN_QUERY, | 303 | HostCmd_CMD_802_11_BG_SCAN_QUERY, |
309 | HostCmd_ACT_GEN_GET, 0, NULL); | 304 | HostCmd_ACT_GEN_GET, 0, NULL); |
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index c34ff8c4f4f8..3fca219bcfb6 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c | |||
@@ -142,90 +142,142 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv, | |||
142 | } | 142 | } |
143 | 143 | ||
144 | /* | 144 | /* |
145 | * This function fills bss descriptor structure using provided | ||
146 | * information. | ||
147 | */ | ||
148 | int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, | ||
149 | u8 *bssid, s32 rssi, u8 *ie_buf, | ||
150 | size_t ie_len, u16 beacon_period, | ||
151 | u16 cap_info_bitmap, | ||
152 | struct mwifiex_bssdescriptor *bss_desc) | ||
153 | { | ||
154 | int ret; | ||
155 | |||
156 | memcpy(bss_desc->mac_address, bssid, ETH_ALEN); | ||
157 | bss_desc->rssi = rssi; | ||
158 | bss_desc->beacon_buf = ie_buf; | ||
159 | bss_desc->beacon_buf_size = ie_len; | ||
160 | bss_desc->beacon_period = beacon_period; | ||
161 | bss_desc->cap_info_bitmap = cap_info_bitmap; | ||
162 | if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) { | ||
163 | dev_dbg(priv->adapter->dev, "info: InterpretIE: AP WEP enabled\n"); | ||
164 | bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; | ||
165 | } else { | ||
166 | bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL; | ||
167 | } | ||
168 | if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_IBSS) | ||
169 | bss_desc->bss_mode = NL80211_IFTYPE_ADHOC; | ||
170 | else | ||
171 | bss_desc->bss_mode = NL80211_IFTYPE_STATION; | ||
172 | |||
173 | ret = mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc, | ||
174 | ie_buf, ie_len); | ||
175 | |||
176 | return ret; | ||
177 | } | ||
178 | |||
179 | /* | ||
145 | * In Ad-Hoc mode, the IBSS is created if not found in scan list. | 180 | * In Ad-Hoc mode, the IBSS is created if not found in scan list. |
146 | * In both Ad-Hoc and infra mode, an deauthentication is performed | 181 | * In both Ad-Hoc and infra mode, an deauthentication is performed |
147 | * first. | 182 | * first. |
148 | */ | 183 | */ |
149 | int mwifiex_bss_start(struct mwifiex_private *priv, | 184 | int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, |
150 | struct mwifiex_ssid_bssid *ssid_bssid) | 185 | struct mwifiex_802_11_ssid *req_ssid) |
151 | { | 186 | { |
152 | int ret; | 187 | int ret; |
153 | struct mwifiex_adapter *adapter = priv->adapter; | 188 | struct mwifiex_adapter *adapter = priv->adapter; |
154 | s32 i = -1; | 189 | struct mwifiex_bssdescriptor *bss_desc = NULL; |
190 | u8 *beacon_ie = NULL; | ||
155 | 191 | ||
156 | priv->scan_block = false; | 192 | priv->scan_block = false; |
157 | if (!ssid_bssid) | 193 | |
158 | return -1; | 194 | if (bss) { |
195 | /* Allocate and fill new bss descriptor */ | ||
196 | bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor), | ||
197 | GFP_KERNEL); | ||
198 | if (!bss_desc) { | ||
199 | dev_err(priv->adapter->dev, " failed to alloc bss_desc\n"); | ||
200 | return -ENOMEM; | ||
201 | } | ||
202 | beacon_ie = kzalloc(bss->len_beacon_ies, GFP_KERNEL); | ||
203 | if (!beacon_ie) { | ||
204 | dev_err(priv->adapter->dev, " failed to alloc bss_desc\n"); | ||
205 | return -ENOMEM; | ||
206 | } | ||
207 | memcpy(beacon_ie, bss->information_elements, | ||
208 | bss->len_beacon_ies); | ||
209 | ret = mwifiex_fill_new_bss_desc(priv, bss->bssid, bss->signal, | ||
210 | beacon_ie, bss->len_beacon_ies, | ||
211 | bss->beacon_interval, | ||
212 | bss->capability, bss_desc); | ||
213 | if (ret) | ||
214 | goto done; | ||
215 | } | ||
159 | 216 | ||
160 | if (priv->bss_mode == NL80211_IFTYPE_STATION) { | 217 | if (priv->bss_mode == NL80211_IFTYPE_STATION) { |
161 | /* Infra mode */ | 218 | /* Infra mode */ |
162 | ret = mwifiex_deauthenticate(priv, NULL); | 219 | ret = mwifiex_deauthenticate(priv, NULL); |
163 | if (ret) | 220 | if (ret) |
164 | return ret; | 221 | goto done; |
165 | 222 | ||
166 | /* Search for the requested SSID in the scan table */ | 223 | ret = mwifiex_check_network_compatibility(priv, bss_desc); |
167 | if (ssid_bssid->ssid.ssid_len) | 224 | if (ret) |
168 | i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid, | 225 | goto done; |
169 | NULL, NL80211_IFTYPE_STATION); | 226 | |
170 | else | 227 | dev_dbg(adapter->dev, "info: SSID found in scan list ... " |
171 | i = mwifiex_find_bssid_in_list(priv, | 228 | "associating...\n"); |
172 | (u8 *) &ssid_bssid->bssid, | ||
173 | NL80211_IFTYPE_STATION); | ||
174 | if (i < 0) | ||
175 | return -1; | ||
176 | 229 | ||
177 | dev_dbg(adapter->dev, | 230 | if (!netif_queue_stopped(priv->netdev)) |
178 | "info: SSID found in scan list ... associating...\n"); | 231 | netif_stop_queue(priv->netdev); |
179 | 232 | ||
180 | /* Clear any past association response stored for | 233 | /* Clear any past association response stored for |
181 | * application retrieval */ | 234 | * application retrieval */ |
182 | priv->assoc_rsp_size = 0; | 235 | priv->assoc_rsp_size = 0; |
183 | ret = mwifiex_associate(priv, &adapter->scan_table[i]); | 236 | ret = mwifiex_associate(priv, bss_desc); |
184 | if (ret) | 237 | if (bss) |
185 | return ret; | 238 | cfg80211_put_bss(bss); |
186 | } else { | 239 | } else { |
187 | /* Adhoc mode */ | 240 | /* Adhoc mode */ |
188 | /* If the requested SSID matches current SSID, return */ | 241 | /* If the requested SSID matches current SSID, return */ |
189 | if (ssid_bssid->ssid.ssid_len && | 242 | if (bss_desc && bss_desc->ssid.ssid_len && |
190 | (!mwifiex_ssid_cmp | 243 | (!mwifiex_ssid_cmp |
191 | (&priv->curr_bss_params.bss_descriptor.ssid, | 244 | (&priv->curr_bss_params.bss_descriptor.ssid, |
192 | &ssid_bssid->ssid))) | 245 | &bss_desc->ssid))) { |
246 | kfree(bss_desc); | ||
247 | kfree(beacon_ie); | ||
193 | return 0; | 248 | return 0; |
249 | } | ||
194 | 250 | ||
195 | /* Exit Adhoc mode first */ | 251 | /* Exit Adhoc mode first */ |
196 | dev_dbg(adapter->dev, "info: Sending Adhoc Stop\n"); | 252 | dev_dbg(adapter->dev, "info: Sending Adhoc Stop\n"); |
197 | ret = mwifiex_deauthenticate(priv, NULL); | 253 | ret = mwifiex_deauthenticate(priv, NULL); |
198 | if (ret) | 254 | if (ret) |
199 | return ret; | 255 | goto done; |
200 | 256 | ||
201 | priv->adhoc_is_link_sensed = false; | 257 | priv->adhoc_is_link_sensed = false; |
202 | 258 | ||
203 | /* Search for the requested network in the scan table */ | 259 | ret = mwifiex_check_network_compatibility(priv, bss_desc); |
204 | if (ssid_bssid->ssid.ssid_len) | 260 | |
205 | i = mwifiex_find_ssid_in_list(priv, | 261 | if (!netif_queue_stopped(priv->netdev)) |
206 | &ssid_bssid->ssid, NULL, | 262 | netif_stop_queue(priv->netdev); |
207 | NL80211_IFTYPE_ADHOC); | 263 | |
208 | else | 264 | if (!ret) { |
209 | i = mwifiex_find_bssid_in_list(priv, | ||
210 | (u8 *)&ssid_bssid->bssid, | ||
211 | NL80211_IFTYPE_ADHOC); | ||
212 | |||
213 | if (i >= 0) { | ||
214 | dev_dbg(adapter->dev, "info: network found in scan" | 265 | dev_dbg(adapter->dev, "info: network found in scan" |
215 | " list. Joining...\n"); | 266 | " list. Joining...\n"); |
216 | ret = mwifiex_adhoc_join(priv, &adapter->scan_table[i]); | 267 | ret = mwifiex_adhoc_join(priv, bss_desc); |
217 | if (ret) | 268 | if (bss) |
218 | return ret; | 269 | cfg80211_put_bss(bss); |
219 | } else { | 270 | } else { |
220 | dev_dbg(adapter->dev, "info: Network not found in " | 271 | dev_dbg(adapter->dev, "info: Network not found in " |
221 | "the list, creating adhoc with ssid = %s\n", | 272 | "the list, creating adhoc with ssid = %s\n", |
222 | ssid_bssid->ssid.ssid); | 273 | req_ssid->ssid); |
223 | ret = mwifiex_adhoc_start(priv, &ssid_bssid->ssid); | 274 | ret = mwifiex_adhoc_start(priv, req_ssid); |
224 | if (ret) | ||
225 | return ret; | ||
226 | } | 275 | } |
227 | } | 276 | } |
228 | 277 | ||
278 | done: | ||
279 | kfree(bss_desc); | ||
280 | kfree(beacon_ie); | ||
229 | return ret; | 281 | return ret; |
230 | } | 282 | } |
231 | 283 | ||
@@ -376,7 +428,6 @@ int mwifiex_get_bss_info(struct mwifiex_private *priv, | |||
376 | { | 428 | { |
377 | struct mwifiex_adapter *adapter = priv->adapter; | 429 | struct mwifiex_adapter *adapter = priv->adapter; |
378 | struct mwifiex_bssdescriptor *bss_desc; | 430 | struct mwifiex_bssdescriptor *bss_desc; |
379 | s32 tbl_idx; | ||
380 | 431 | ||
381 | if (!info) | 432 | if (!info) |
382 | return -1; | 433 | return -1; |
@@ -394,17 +445,6 @@ int mwifiex_get_bss_info(struct mwifiex_private *priv, | |||
394 | 445 | ||
395 | info->region_code = adapter->region_code; | 446 | info->region_code = adapter->region_code; |
396 | 447 | ||
397 | /* Scan table index if connected */ | ||
398 | info->scan_table_idx = 0; | ||
399 | if (priv->media_connected) { | ||
400 | tbl_idx = | ||
401 | mwifiex_find_ssid_in_list(priv, &bss_desc->ssid, | ||
402 | bss_desc->mac_address, | ||
403 | priv->bss_mode); | ||
404 | if (tbl_idx >= 0) | ||
405 | info->scan_table_idx = tbl_idx; | ||
406 | } | ||
407 | |||
408 | info->media_connected = priv->media_connected; | 448 | info->media_connected = priv->media_connected; |
409 | 449 | ||
410 | info->max_power_level = priv->max_tx_power_level; | 450 | info->max_power_level = priv->max_tx_power_level; |
@@ -586,50 +626,6 @@ static int mwifiex_bss_ioctl_ibss_channel(struct mwifiex_private *priv, | |||
586 | } | 626 | } |
587 | 627 | ||
588 | /* | 628 | /* |
589 | * IOCTL request handler to find a particular BSS. | ||
590 | * | ||
591 | * The BSS can be searched with either a BSSID or a SSID. If none of | ||
592 | * these are provided, just the best BSS (best RSSI) is returned. | ||
593 | */ | ||
594 | int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *priv, | ||
595 | struct mwifiex_ssid_bssid *ssid_bssid) | ||
596 | { | ||
597 | struct mwifiex_adapter *adapter = priv->adapter; | ||
598 | struct mwifiex_bssdescriptor *bss_desc; | ||
599 | u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; | ||
600 | u8 mac[ETH_ALEN]; | ||
601 | int i = 0; | ||
602 | |||
603 | if (memcmp(ssid_bssid->bssid, zero_mac, sizeof(zero_mac))) { | ||
604 | i = mwifiex_find_bssid_in_list(priv, | ||
605 | (u8 *) ssid_bssid->bssid, | ||
606 | priv->bss_mode); | ||
607 | if (i < 0) { | ||
608 | memcpy(mac, ssid_bssid->bssid, sizeof(mac)); | ||
609 | dev_err(adapter->dev, "cannot find bssid %pM\n", mac); | ||
610 | return -1; | ||
611 | } | ||
612 | bss_desc = &adapter->scan_table[i]; | ||
613 | memcpy(&ssid_bssid->ssid, &bss_desc->ssid, | ||
614 | sizeof(struct mwifiex_802_11_ssid)); | ||
615 | } else if (ssid_bssid->ssid.ssid_len) { | ||
616 | i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid, NULL, | ||
617 | priv->bss_mode); | ||
618 | if (i < 0) { | ||
619 | dev_err(adapter->dev, "cannot find ssid %s\n", | ||
620 | ssid_bssid->ssid.ssid); | ||
621 | return -1; | ||
622 | } | ||
623 | bss_desc = &adapter->scan_table[i]; | ||
624 | memcpy(ssid_bssid->bssid, bss_desc->mac_address, ETH_ALEN); | ||
625 | } else { | ||
626 | return mwifiex_find_best_network(priv, ssid_bssid); | ||
627 | } | ||
628 | |||
629 | return 0; | ||
630 | } | ||
631 | |||
632 | /* | ||
633 | * IOCTL request handler to change Ad-Hoc channel. | 629 | * IOCTL request handler to change Ad-Hoc channel. |
634 | * | 630 | * |
635 | * This function allocates the IOCTL request buffer, fills it | 631 | * This function allocates the IOCTL request buffer, fills it |
@@ -653,6 +649,8 @@ mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel) | |||
653 | struct mwifiex_bss_info bss_info; | 649 | struct mwifiex_bss_info bss_info; |
654 | struct mwifiex_ssid_bssid ssid_bssid; | 650 | struct mwifiex_ssid_bssid ssid_bssid; |
655 | u16 curr_chan = 0; | 651 | u16 curr_chan = 0; |
652 | struct cfg80211_bss *bss = NULL; | ||
653 | struct ieee80211_channel *chan; | ||
656 | 654 | ||
657 | memset(&bss_info, 0, sizeof(bss_info)); | 655 | memset(&bss_info, 0, sizeof(bss_info)); |
658 | 656 | ||
@@ -688,12 +686,20 @@ mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel) | |||
688 | ret = -1; | 686 | ret = -1; |
689 | goto done; | 687 | goto done; |
690 | } | 688 | } |
691 | /* Start/Join Adhoc network */ | ||
692 | memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid)); | ||
693 | memcpy(&ssid_bssid.ssid, &bss_info.ssid, | ||
694 | sizeof(struct mwifiex_802_11_ssid)); | ||
695 | 689 | ||
696 | ret = mwifiex_bss_start(priv, &ssid_bssid); | 690 | chan = __ieee80211_get_channel(priv->wdev->wiphy, |
691 | ieee80211_channel_to_frequency(channel, | ||
692 | priv->curr_bss_params.band)); | ||
693 | |||
694 | /* Find the BSS we want using available scan results */ | ||
695 | bss = cfg80211_get_bss(priv->wdev->wiphy, chan, bss_info.bssid, | ||
696 | bss_info.ssid.ssid, bss_info.ssid.ssid_len, | ||
697 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); | ||
698 | if (!bss) | ||
699 | wiphy_warn(priv->wdev->wiphy, "assoc: bss %pM not in scan results\n", | ||
700 | bss_info.bssid); | ||
701 | |||
702 | ret = mwifiex_bss_start(priv, bss, &bss_info.ssid); | ||
697 | done: | 703 | done: |
698 | return ret; | 704 | return ret; |
699 | } | 705 | } |
@@ -1280,9 +1286,9 @@ int mwifiex_get_signal_info(struct mwifiex_private *priv, | |||
1280 | 1286 | ||
1281 | if (!status) { | 1287 | if (!status) { |
1282 | if (signal->selector & BCN_RSSI_AVG_MASK) | 1288 | if (signal->selector & BCN_RSSI_AVG_MASK) |
1283 | priv->w_stats.qual.level = signal->bcn_rssi_avg; | 1289 | priv->qual_level = signal->bcn_rssi_avg; |
1284 | if (signal->selector & BCN_NF_AVG_MASK) | 1290 | if (signal->selector & BCN_NF_AVG_MASK) |
1285 | priv->w_stats.qual.noise = signal->bcn_nf_avg; | 1291 | priv->qual_noise = signal->bcn_nf_avg; |
1286 | } | 1292 | } |
1287 | 1293 | ||
1288 | return status; | 1294 | return status; |
@@ -1341,18 +1347,8 @@ int | |||
1341 | mwifiex_get_stats_info(struct mwifiex_private *priv, | 1347 | mwifiex_get_stats_info(struct mwifiex_private *priv, |
1342 | struct mwifiex_ds_get_stats *log) | 1348 | struct mwifiex_ds_get_stats *log) |
1343 | { | 1349 | { |
1344 | int ret; | 1350 | return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_GET_LOG, |
1345 | |||
1346 | ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_GET_LOG, | ||
1347 | HostCmd_ACT_GEN_GET, 0, log); | 1351 | HostCmd_ACT_GEN_GET, 0, log); |
1348 | |||
1349 | if (!ret) { | ||
1350 | priv->w_stats.discard.fragment = log->fcs_error; | ||
1351 | priv->w_stats.discard.retries = log->retry; | ||
1352 | priv->w_stats.discard.misc = log->ack_failure; | ||
1353 | } | ||
1354 | |||
1355 | return ret; | ||
1356 | } | 1352 | } |
1357 | 1353 | ||
1358 | /* | 1354 | /* |
@@ -1594,7 +1590,7 @@ mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len) | |||
1594 | { | 1590 | { |
1595 | struct mwifiex_ds_misc_gen_ie gen_ie; | 1591 | struct mwifiex_ds_misc_gen_ie gen_ie; |
1596 | 1592 | ||
1597 | if (ie_len > IW_CUSTOM_MAX) | 1593 | if (ie_len > IEEE_MAX_IE_SIZE) |
1598 | return -EFAULT; | 1594 | return -EFAULT; |
1599 | 1595 | ||
1600 | gen_ie.type = MWIFIEX_IE_TYPE_GEN_IE; | 1596 | gen_ie.type = MWIFIEX_IE_TYPE_GEN_IE; |
diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index bbb9beb206b1..33747e131a96 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/ieee80211.h> | 9 | #include <linux/ieee80211.h> |
10 | #include <net/iw_handler.h> | 10 | #include <net/iw_handler.h> |
11 | #include <net/cfg80211.h> | 11 | #include <net/cfg80211.h> |
12 | #include <net/cfg80211-wext.h> | ||
12 | 13 | ||
13 | #include "hermes.h" | 14 | #include "hermes.h" |
14 | #include "hermes_rid.h" | 15 | #include "hermes_rid.h" |
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 6e0c61145b18..0c13840a7de5 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c | |||
@@ -36,13 +36,11 @@ | |||
36 | #include <linux/mii.h> | 36 | #include <linux/mii.h> |
37 | #include <linux/usb.h> | 37 | #include <linux/usb.h> |
38 | #include <linux/usb/cdc.h> | 38 | #include <linux/usb/cdc.h> |
39 | #include <linux/wireless.h> | ||
40 | #include <linux/ieee80211.h> | 39 | #include <linux/ieee80211.h> |
41 | #include <linux/if_arp.h> | 40 | #include <linux/if_arp.h> |
42 | #include <linux/ctype.h> | 41 | #include <linux/ctype.h> |
43 | #include <linux/spinlock.h> | 42 | #include <linux/spinlock.h> |
44 | #include <linux/slab.h> | 43 | #include <linux/slab.h> |
45 | #include <net/iw_handler.h> | ||
46 | #include <net/cfg80211.h> | 44 | #include <net/cfg80211.h> |
47 | #include <linux/usb/usbnet.h> | 45 | #include <linux/usb/usbnet.h> |
48 | #include <linux/usb/rndis_host.h> | 46 | #include <linux/usb/rndis_host.h> |
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 76bcc3547976..daa32fc9398b 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c | |||
@@ -645,11 +645,6 @@ static void rt2400pci_start_queue(struct data_queue *queue) | |||
645 | rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); | 645 | rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); |
646 | break; | 646 | break; |
647 | case QID_BEACON: | 647 | case QID_BEACON: |
648 | /* | ||
649 | * Allow the tbtt tasklet to be scheduled. | ||
650 | */ | ||
651 | tasklet_enable(&rt2x00dev->tbtt_tasklet); | ||
652 | |||
653 | rt2x00pci_register_read(rt2x00dev, CSR14, ®); | 648 | rt2x00pci_register_read(rt2x00dev, CSR14, ®); |
654 | rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); | 649 | rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); |
655 | rt2x00_set_field32(®, CSR14_TBCN, 1); | 650 | rt2x00_set_field32(®, CSR14_TBCN, 1); |
@@ -715,7 +710,7 @@ static void rt2400pci_stop_queue(struct data_queue *queue) | |||
715 | /* | 710 | /* |
716 | * Wait for possibly running tbtt tasklets. | 711 | * Wait for possibly running tbtt tasklets. |
717 | */ | 712 | */ |
718 | tasklet_disable(&rt2x00dev->tbtt_tasklet); | 713 | tasklet_kill(&rt2x00dev->tbtt_tasklet); |
719 | break; | 714 | break; |
720 | default: | 715 | default: |
721 | break; | 716 | break; |
@@ -982,12 +977,6 @@ static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev, | |||
982 | if (state == STATE_RADIO_IRQ_ON) { | 977 | if (state == STATE_RADIO_IRQ_ON) { |
983 | rt2x00pci_register_read(rt2x00dev, CSR7, ®); | 978 | rt2x00pci_register_read(rt2x00dev, CSR7, ®); |
984 | rt2x00pci_register_write(rt2x00dev, CSR7, reg); | 979 | rt2x00pci_register_write(rt2x00dev, CSR7, reg); |
985 | |||
986 | /* | ||
987 | * Enable tasklets. | ||
988 | */ | ||
989 | tasklet_enable(&rt2x00dev->txstatus_tasklet); | ||
990 | tasklet_enable(&rt2x00dev->rxdone_tasklet); | ||
991 | } | 980 | } |
992 | 981 | ||
993 | /* | 982 | /* |
@@ -1011,8 +1000,9 @@ static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev, | |||
1011 | * Ensure that all tasklets are finished before | 1000 | * Ensure that all tasklets are finished before |
1012 | * disabling the interrupts. | 1001 | * disabling the interrupts. |
1013 | */ | 1002 | */ |
1014 | tasklet_disable(&rt2x00dev->txstatus_tasklet); | 1003 | tasklet_kill(&rt2x00dev->txstatus_tasklet); |
1015 | tasklet_disable(&rt2x00dev->rxdone_tasklet); | 1004 | tasklet_kill(&rt2x00dev->rxdone_tasklet); |
1005 | tasklet_kill(&rt2x00dev->tbtt_tasklet); | ||
1016 | } | 1006 | } |
1017 | } | 1007 | } |
1018 | 1008 | ||
@@ -1347,22 +1337,25 @@ static void rt2400pci_txstatus_tasklet(unsigned long data) | |||
1347 | /* | 1337 | /* |
1348 | * Enable all TXDONE interrupts again. | 1338 | * Enable all TXDONE interrupts again. |
1349 | */ | 1339 | */ |
1350 | spin_lock_irq(&rt2x00dev->irqmask_lock); | 1340 | if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) { |
1341 | spin_lock_irq(&rt2x00dev->irqmask_lock); | ||
1351 | 1342 | ||
1352 | rt2x00pci_register_read(rt2x00dev, CSR8, ®); | 1343 | rt2x00pci_register_read(rt2x00dev, CSR8, ®); |
1353 | rt2x00_set_field32(®, CSR8_TXDONE_TXRING, 0); | 1344 | rt2x00_set_field32(®, CSR8_TXDONE_TXRING, 0); |
1354 | rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, 0); | 1345 | rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, 0); |
1355 | rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, 0); | 1346 | rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, 0); |
1356 | rt2x00pci_register_write(rt2x00dev, CSR8, reg); | 1347 | rt2x00pci_register_write(rt2x00dev, CSR8, reg); |
1357 | 1348 | ||
1358 | spin_unlock_irq(&rt2x00dev->irqmask_lock); | 1349 | spin_unlock_irq(&rt2x00dev->irqmask_lock); |
1350 | } | ||
1359 | } | 1351 | } |
1360 | 1352 | ||
1361 | static void rt2400pci_tbtt_tasklet(unsigned long data) | 1353 | static void rt2400pci_tbtt_tasklet(unsigned long data) |
1362 | { | 1354 | { |
1363 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; | 1355 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; |
1364 | rt2x00lib_beacondone(rt2x00dev); | 1356 | rt2x00lib_beacondone(rt2x00dev); |
1365 | rt2400pci_enable_interrupt(rt2x00dev, CSR8_TBCN_EXPIRE); | 1357 | if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) |
1358 | rt2400pci_enable_interrupt(rt2x00dev, CSR8_TBCN_EXPIRE); | ||
1366 | } | 1359 | } |
1367 | 1360 | ||
1368 | static void rt2400pci_rxdone_tasklet(unsigned long data) | 1361 | static void rt2400pci_rxdone_tasklet(unsigned long data) |
@@ -1370,7 +1363,7 @@ static void rt2400pci_rxdone_tasklet(unsigned long data) | |||
1370 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; | 1363 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; |
1371 | if (rt2x00pci_rxdone(rt2x00dev)) | 1364 | if (rt2x00pci_rxdone(rt2x00dev)) |
1372 | tasklet_schedule(&rt2x00dev->rxdone_tasklet); | 1365 | tasklet_schedule(&rt2x00dev->rxdone_tasklet); |
1373 | else | 1366 | else if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) |
1374 | rt2400pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); | 1367 | rt2400pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); |
1375 | } | 1368 | } |
1376 | 1369 | ||
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index c288d951c034..b46c3b8866fa 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c | |||
@@ -735,11 +735,6 @@ static void rt2500pci_start_queue(struct data_queue *queue) | |||
735 | rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); | 735 | rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); |
736 | break; | 736 | break; |
737 | case QID_BEACON: | 737 | case QID_BEACON: |
738 | /* | ||
739 | * Allow the tbtt tasklet to be scheduled. | ||
740 | */ | ||
741 | tasklet_enable(&rt2x00dev->tbtt_tasklet); | ||
742 | |||
743 | rt2x00pci_register_read(rt2x00dev, CSR14, ®); | 738 | rt2x00pci_register_read(rt2x00dev, CSR14, ®); |
744 | rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); | 739 | rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); |
745 | rt2x00_set_field32(®, CSR14_TBCN, 1); | 740 | rt2x00_set_field32(®, CSR14_TBCN, 1); |
@@ -805,7 +800,7 @@ static void rt2500pci_stop_queue(struct data_queue *queue) | |||
805 | /* | 800 | /* |
806 | * Wait for possibly running tbtt tasklets. | 801 | * Wait for possibly running tbtt tasklets. |
807 | */ | 802 | */ |
808 | tasklet_disable(&rt2x00dev->tbtt_tasklet); | 803 | tasklet_kill(&rt2x00dev->tbtt_tasklet); |
809 | break; | 804 | break; |
810 | default: | 805 | default: |
811 | break; | 806 | break; |
@@ -1137,12 +1132,6 @@ static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev, | |||
1137 | if (state == STATE_RADIO_IRQ_ON) { | 1132 | if (state == STATE_RADIO_IRQ_ON) { |
1138 | rt2x00pci_register_read(rt2x00dev, CSR7, ®); | 1133 | rt2x00pci_register_read(rt2x00dev, CSR7, ®); |
1139 | rt2x00pci_register_write(rt2x00dev, CSR7, reg); | 1134 | rt2x00pci_register_write(rt2x00dev, CSR7, reg); |
1140 | |||
1141 | /* | ||
1142 | * Enable tasklets. | ||
1143 | */ | ||
1144 | tasklet_enable(&rt2x00dev->txstatus_tasklet); | ||
1145 | tasklet_enable(&rt2x00dev->rxdone_tasklet); | ||
1146 | } | 1135 | } |
1147 | 1136 | ||
1148 | /* | 1137 | /* |
@@ -1165,8 +1154,9 @@ static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev, | |||
1165 | /* | 1154 | /* |
1166 | * Ensure that all tasklets are finished. | 1155 | * Ensure that all tasklets are finished. |
1167 | */ | 1156 | */ |
1168 | tasklet_disable(&rt2x00dev->txstatus_tasklet); | 1157 | tasklet_kill(&rt2x00dev->txstatus_tasklet); |
1169 | tasklet_disable(&rt2x00dev->rxdone_tasklet); | 1158 | tasklet_kill(&rt2x00dev->rxdone_tasklet); |
1159 | tasklet_kill(&rt2x00dev->tbtt_tasklet); | ||
1170 | } | 1160 | } |
1171 | } | 1161 | } |
1172 | 1162 | ||
@@ -1479,22 +1469,25 @@ static void rt2500pci_txstatus_tasklet(unsigned long data) | |||
1479 | /* | 1469 | /* |
1480 | * Enable all TXDONE interrupts again. | 1470 | * Enable all TXDONE interrupts again. |
1481 | */ | 1471 | */ |
1482 | spin_lock_irq(&rt2x00dev->irqmask_lock); | 1472 | if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) { |
1473 | spin_lock_irq(&rt2x00dev->irqmask_lock); | ||
1483 | 1474 | ||
1484 | rt2x00pci_register_read(rt2x00dev, CSR8, ®); | 1475 | rt2x00pci_register_read(rt2x00dev, CSR8, ®); |
1485 | rt2x00_set_field32(®, CSR8_TXDONE_TXRING, 0); | 1476 | rt2x00_set_field32(®, CSR8_TXDONE_TXRING, 0); |
1486 | rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, 0); | 1477 | rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, 0); |
1487 | rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, 0); | 1478 | rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, 0); |
1488 | rt2x00pci_register_write(rt2x00dev, CSR8, reg); | 1479 | rt2x00pci_register_write(rt2x00dev, CSR8, reg); |
1489 | 1480 | ||
1490 | spin_unlock_irq(&rt2x00dev->irqmask_lock); | 1481 | spin_unlock_irq(&rt2x00dev->irqmask_lock); |
1482 | } | ||
1491 | } | 1483 | } |
1492 | 1484 | ||
1493 | static void rt2500pci_tbtt_tasklet(unsigned long data) | 1485 | static void rt2500pci_tbtt_tasklet(unsigned long data) |
1494 | { | 1486 | { |
1495 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; | 1487 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; |
1496 | rt2x00lib_beacondone(rt2x00dev); | 1488 | rt2x00lib_beacondone(rt2x00dev); |
1497 | rt2500pci_enable_interrupt(rt2x00dev, CSR8_TBCN_EXPIRE); | 1489 | if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) |
1490 | rt2500pci_enable_interrupt(rt2x00dev, CSR8_TBCN_EXPIRE); | ||
1498 | } | 1491 | } |
1499 | 1492 | ||
1500 | static void rt2500pci_rxdone_tasklet(unsigned long data) | 1493 | static void rt2500pci_rxdone_tasklet(unsigned long data) |
@@ -1502,7 +1495,7 @@ static void rt2500pci_rxdone_tasklet(unsigned long data) | |||
1502 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; | 1495 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; |
1503 | if (rt2x00pci_rxdone(rt2x00dev)) | 1496 | if (rt2x00pci_rxdone(rt2x00dev)) |
1504 | tasklet_schedule(&rt2x00dev->rxdone_tasklet); | 1497 | tasklet_schedule(&rt2x00dev->rxdone_tasklet); |
1505 | else | 1498 | else if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) |
1506 | rt2500pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); | 1499 | rt2500pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); |
1507 | } | 1500 | } |
1508 | 1501 | ||
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index ebc17ad61dec..cabf249aa55b 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c | |||
@@ -200,13 +200,6 @@ static void rt2800pci_start_queue(struct data_queue *queue) | |||
200 | rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg); | 200 | rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg); |
201 | break; | 201 | break; |
202 | case QID_BEACON: | 202 | case QID_BEACON: |
203 | /* | ||
204 | * Allow beacon tasklets to be scheduled for periodic | ||
205 | * beacon updates. | ||
206 | */ | ||
207 | tasklet_enable(&rt2x00dev->tbtt_tasklet); | ||
208 | tasklet_enable(&rt2x00dev->pretbtt_tasklet); | ||
209 | |||
210 | rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, ®); | 203 | rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, ®); |
211 | rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); | 204 | rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); |
212 | rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); | 205 | rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); |
@@ -269,10 +262,13 @@ static void rt2800pci_stop_queue(struct data_queue *queue) | |||
269 | rt2x00pci_register_write(rt2x00dev, INT_TIMER_EN, reg); | 262 | rt2x00pci_register_write(rt2x00dev, INT_TIMER_EN, reg); |
270 | 263 | ||
271 | /* | 264 | /* |
272 | * Wait for tbtt tasklets to finish. | 265 | * Wait for current invocation to finish. The tasklet |
266 | * won't be scheduled anymore afterwards since we disabled | ||
267 | * the TBTT and PRE TBTT timer. | ||
273 | */ | 268 | */ |
274 | tasklet_disable(&rt2x00dev->tbtt_tasklet); | 269 | tasklet_kill(&rt2x00dev->tbtt_tasklet); |
275 | tasklet_disable(&rt2x00dev->pretbtt_tasklet); | 270 | tasklet_kill(&rt2x00dev->pretbtt_tasklet); |
271 | |||
276 | break; | 272 | break; |
277 | default: | 273 | default: |
278 | break; | 274 | break; |
@@ -437,14 +433,6 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev, | |||
437 | if (state == STATE_RADIO_IRQ_ON) { | 433 | if (state == STATE_RADIO_IRQ_ON) { |
438 | rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, ®); | 434 | rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, ®); |
439 | rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg); | 435 | rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg); |
440 | |||
441 | /* | ||
442 | * Enable tasklets. The beacon related tasklets are | ||
443 | * enabled when the beacon queue is started. | ||
444 | */ | ||
445 | tasklet_enable(&rt2x00dev->txstatus_tasklet); | ||
446 | tasklet_enable(&rt2x00dev->rxdone_tasklet); | ||
447 | tasklet_enable(&rt2x00dev->autowake_tasklet); | ||
448 | } | 436 | } |
449 | 437 | ||
450 | spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); | 438 | spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); |
@@ -472,12 +460,13 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev, | |||
472 | 460 | ||
473 | if (state == STATE_RADIO_IRQ_OFF) { | 461 | if (state == STATE_RADIO_IRQ_OFF) { |
474 | /* | 462 | /* |
475 | * Ensure that all tasklets are finished before | 463 | * Wait for possibly running tasklets to finish. |
476 | * disabling the interrupts. | ||
477 | */ | 464 | */ |
478 | tasklet_disable(&rt2x00dev->txstatus_tasklet); | 465 | tasklet_kill(&rt2x00dev->txstatus_tasklet); |
479 | tasklet_disable(&rt2x00dev->rxdone_tasklet); | 466 | tasklet_kill(&rt2x00dev->rxdone_tasklet); |
480 | tasklet_disable(&rt2x00dev->autowake_tasklet); | 467 | tasklet_kill(&rt2x00dev->autowake_tasklet); |
468 | tasklet_kill(&rt2x00dev->tbtt_tasklet); | ||
469 | tasklet_kill(&rt2x00dev->pretbtt_tasklet); | ||
481 | } | 470 | } |
482 | } | 471 | } |
483 | 472 | ||
@@ -813,14 +802,16 @@ static void rt2800pci_pretbtt_tasklet(unsigned long data) | |||
813 | { | 802 | { |
814 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; | 803 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; |
815 | rt2x00lib_pretbtt(rt2x00dev); | 804 | rt2x00lib_pretbtt(rt2x00dev); |
816 | rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_PRE_TBTT); | 805 | if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) |
806 | rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_PRE_TBTT); | ||
817 | } | 807 | } |
818 | 808 | ||
819 | static void rt2800pci_tbtt_tasklet(unsigned long data) | 809 | static void rt2800pci_tbtt_tasklet(unsigned long data) |
820 | { | 810 | { |
821 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; | 811 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; |
822 | rt2x00lib_beacondone(rt2x00dev); | 812 | rt2x00lib_beacondone(rt2x00dev); |
823 | rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_TBTT); | 813 | if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) |
814 | rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_TBTT); | ||
824 | } | 815 | } |
825 | 816 | ||
826 | static void rt2800pci_rxdone_tasklet(unsigned long data) | 817 | static void rt2800pci_rxdone_tasklet(unsigned long data) |
@@ -828,7 +819,7 @@ static void rt2800pci_rxdone_tasklet(unsigned long data) | |||
828 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; | 819 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; |
829 | if (rt2x00pci_rxdone(rt2x00dev)) | 820 | if (rt2x00pci_rxdone(rt2x00dev)) |
830 | tasklet_schedule(&rt2x00dev->rxdone_tasklet); | 821 | tasklet_schedule(&rt2x00dev->rxdone_tasklet); |
831 | else | 822 | else if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) |
832 | rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RX_DONE); | 823 | rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RX_DONE); |
833 | } | 824 | } |
834 | 825 | ||
@@ -836,7 +827,8 @@ static void rt2800pci_autowake_tasklet(unsigned long data) | |||
836 | { | 827 | { |
837 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; | 828 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; |
838 | rt2800pci_wakeup(rt2x00dev); | 829 | rt2800pci_wakeup(rt2x00dev); |
839 | rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_AUTO_WAKEUP); | 830 | if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) |
831 | rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_AUTO_WAKEUP); | ||
840 | } | 832 | } |
841 | 833 | ||
842 | static void rt2800pci_txstatus_interrupt(struct rt2x00_dev *rt2x00dev) | 834 | static void rt2800pci_txstatus_interrupt(struct rt2x00_dev *rt2x00dev) |
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 0955c941317f..92ff6a72a2bb 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c | |||
@@ -946,7 +946,6 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) | |||
946 | tasklet_init(&rt2x00dev->taskletname, \ | 946 | tasklet_init(&rt2x00dev->taskletname, \ |
947 | rt2x00dev->ops->lib->taskletname, \ | 947 | rt2x00dev->ops->lib->taskletname, \ |
948 | (unsigned long)rt2x00dev); \ | 948 | (unsigned long)rt2x00dev); \ |
949 | tasklet_disable(&rt2x00dev->taskletname); \ | ||
950 | } | 949 | } |
951 | 950 | ||
952 | RT2X00_TASKLET_INIT(txstatus_tasklet); | 951 | RT2X00_TASKLET_INIT(txstatus_tasklet); |
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 53110b83bf6e..058ef4b19d1d 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c | |||
@@ -1142,11 +1142,6 @@ static void rt61pci_start_queue(struct data_queue *queue) | |||
1142 | rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); | 1142 | rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); |
1143 | break; | 1143 | break; |
1144 | case QID_BEACON: | 1144 | case QID_BEACON: |
1145 | /* | ||
1146 | * Allow the tbtt tasklet to be scheduled. | ||
1147 | */ | ||
1148 | tasklet_enable(&rt2x00dev->tbtt_tasklet); | ||
1149 | |||
1150 | rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); | 1145 | rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); |
1151 | rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); | 1146 | rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); |
1152 | rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); | 1147 | rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); |
@@ -1230,7 +1225,7 @@ static void rt61pci_stop_queue(struct data_queue *queue) | |||
1230 | /* | 1225 | /* |
1231 | * Wait for possibly running tbtt tasklets. | 1226 | * Wait for possibly running tbtt tasklets. |
1232 | */ | 1227 | */ |
1233 | tasklet_disable(&rt2x00dev->tbtt_tasklet); | 1228 | tasklet_kill(&rt2x00dev->tbtt_tasklet); |
1234 | break; | 1229 | break; |
1235 | default: | 1230 | default: |
1236 | break; | 1231 | break; |
@@ -1731,13 +1726,6 @@ static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev, | |||
1731 | 1726 | ||
1732 | rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, ®); | 1727 | rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, ®); |
1733 | rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg); | 1728 | rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg); |
1734 | |||
1735 | /* | ||
1736 | * Enable tasklets. | ||
1737 | */ | ||
1738 | tasklet_enable(&rt2x00dev->txstatus_tasklet); | ||
1739 | tasklet_enable(&rt2x00dev->rxdone_tasklet); | ||
1740 | tasklet_enable(&rt2x00dev->autowake_tasklet); | ||
1741 | } | 1729 | } |
1742 | 1730 | ||
1743 | /* | 1731 | /* |
@@ -1772,9 +1760,10 @@ static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev, | |||
1772 | /* | 1760 | /* |
1773 | * Ensure that all tasklets are finished. | 1761 | * Ensure that all tasklets are finished. |
1774 | */ | 1762 | */ |
1775 | tasklet_disable(&rt2x00dev->txstatus_tasklet); | 1763 | tasklet_kill(&rt2x00dev->txstatus_tasklet); |
1776 | tasklet_disable(&rt2x00dev->rxdone_tasklet); | 1764 | tasklet_kill(&rt2x00dev->rxdone_tasklet); |
1777 | tasklet_disable(&rt2x00dev->autowake_tasklet); | 1765 | tasklet_kill(&rt2x00dev->autowake_tasklet); |
1766 | tasklet_kill(&rt2x00dev->tbtt_tasklet); | ||
1778 | } | 1767 | } |
1779 | } | 1768 | } |
1780 | 1769 | ||
@@ -2300,22 +2289,24 @@ static void rt61pci_txstatus_tasklet(unsigned long data) | |||
2300 | { | 2289 | { |
2301 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; | 2290 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; |
2302 | rt61pci_txdone(rt2x00dev); | 2291 | rt61pci_txdone(rt2x00dev); |
2303 | rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_TXDONE); | 2292 | if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) |
2293 | rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_TXDONE); | ||
2304 | } | 2294 | } |
2305 | 2295 | ||
2306 | static void rt61pci_tbtt_tasklet(unsigned long data) | 2296 | static void rt61pci_tbtt_tasklet(unsigned long data) |
2307 | { | 2297 | { |
2308 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; | 2298 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; |
2309 | rt2x00lib_beacondone(rt2x00dev); | 2299 | rt2x00lib_beacondone(rt2x00dev); |
2310 | rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_BEACON_DONE); | 2300 | if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) |
2301 | rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_BEACON_DONE); | ||
2311 | } | 2302 | } |
2312 | 2303 | ||
2313 | static void rt61pci_rxdone_tasklet(unsigned long data) | 2304 | static void rt61pci_rxdone_tasklet(unsigned long data) |
2314 | { | 2305 | { |
2315 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; | 2306 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; |
2316 | if (rt2x00pci_rxdone(rt2x00dev)) | 2307 | if (rt2x00pci_rxdone(rt2x00dev)) |
2317 | rt2x00pci_rxdone(rt2x00dev); | 2308 | tasklet_schedule(&rt2x00dev->rxdone_tasklet); |
2318 | else | 2309 | else if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) |
2319 | rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RXDONE); | 2310 | rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RXDONE); |
2320 | } | 2311 | } |
2321 | 2312 | ||
@@ -2325,7 +2316,8 @@ static void rt61pci_autowake_tasklet(unsigned long data) | |||
2325 | rt61pci_wakeup(rt2x00dev); | 2316 | rt61pci_wakeup(rt2x00dev); |
2326 | rt2x00pci_register_write(rt2x00dev, | 2317 | rt2x00pci_register_write(rt2x00dev, |
2327 | M2H_CMD_DONE_CSR, 0xffffffff); | 2318 | M2H_CMD_DONE_CSR, 0xffffffff); |
2328 | rt61pci_enable_mcu_interrupt(rt2x00dev, MCU_INT_MASK_CSR_TWAKEUP); | 2319 | if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) |
2320 | rt61pci_enable_mcu_interrupt(rt2x00dev, MCU_INT_MASK_CSR_TWAKEUP); | ||
2329 | } | 2321 | } |
2330 | 2322 | ||
2331 | static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance) | 2323 | static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance) |
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index 56f12358389d..9983fa18065a 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c | |||
@@ -218,7 +218,6 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw) | |||
218 | struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); | 218 | struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); |
219 | struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); | 219 | struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); |
220 | u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor; | 220 | u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor; |
221 | u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport; | ||
222 | u8 num4bytes = pcipriv->ndis_adapter.num4bytes; | 221 | u8 num4bytes = pcipriv->ndis_adapter.num4bytes; |
223 | /*Retrieve original configuration settings. */ | 222 | /*Retrieve original configuration settings. */ |
224 | u8 linkctrl_reg = pcipriv->ndis_adapter.linkctrl_reg; | 223 | u8 linkctrl_reg = pcipriv->ndis_adapter.linkctrl_reg; |
@@ -254,9 +253,8 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw) | |||
254 | udelay(50); | 253 | udelay(50); |
255 | 254 | ||
256 | /*4 Disable Pci Bridge ASPM */ | 255 | /*4 Disable Pci Bridge ASPM */ |
257 | rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, | 256 | pci_write_config_byte(rtlpci->pdev, (num4bytes << 2), |
258 | pcicfg_addrport + (num4bytes << 2)); | 257 | pcibridge_linkctrlreg); |
259 | rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, pcibridge_linkctrlreg); | ||
260 | 258 | ||
261 | udelay(50); | 259 | udelay(50); |
262 | } | 260 | } |
@@ -277,7 +275,6 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw) | |||
277 | u8 pcibridge_devnum = pcipriv->ndis_adapter.pcibridge_devnum; | 275 | u8 pcibridge_devnum = pcipriv->ndis_adapter.pcibridge_devnum; |
278 | u8 pcibridge_funcnum = pcipriv->ndis_adapter.pcibridge_funcnum; | 276 | u8 pcibridge_funcnum = pcipriv->ndis_adapter.pcibridge_funcnum; |
279 | u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor; | 277 | u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor; |
280 | u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport; | ||
281 | u8 num4bytes = pcipriv->ndis_adapter.num4bytes; | 278 | u8 num4bytes = pcipriv->ndis_adapter.num4bytes; |
282 | u16 aspmlevel; | 279 | u16 aspmlevel; |
283 | u8 u_pcibridge_aspmsetting; | 280 | u8 u_pcibridge_aspmsetting; |
@@ -293,8 +290,6 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw) | |||
293 | } | 290 | } |
294 | 291 | ||
295 | /*4 Enable Pci Bridge ASPM */ | 292 | /*4 Enable Pci Bridge ASPM */ |
296 | rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, | ||
297 | pcicfg_addrport + (num4bytes << 2)); | ||
298 | 293 | ||
299 | u_pcibridge_aspmsetting = | 294 | u_pcibridge_aspmsetting = |
300 | pcipriv->ndis_adapter.pcibridge_linkctrlreg | | 295 | pcipriv->ndis_adapter.pcibridge_linkctrlreg | |
@@ -303,7 +298,8 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw) | |||
303 | if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL) | 298 | if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL) |
304 | u_pcibridge_aspmsetting &= ~BIT(0); | 299 | u_pcibridge_aspmsetting &= ~BIT(0); |
305 | 300 | ||
306 | rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, u_pcibridge_aspmsetting); | 301 | pci_write_config_byte(rtlpci->pdev, (num4bytes << 2), |
302 | u_pcibridge_aspmsetting); | ||
307 | 303 | ||
308 | RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, | 304 | RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, |
309 | ("PlatformEnableASPM():PciBridge busnumber[%x], " | 305 | ("PlatformEnableASPM():PciBridge busnumber[%x], " |
@@ -335,25 +331,18 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw) | |||
335 | 331 | ||
336 | static bool rtl_pci_get_amd_l1_patch(struct ieee80211_hw *hw) | 332 | static bool rtl_pci_get_amd_l1_patch(struct ieee80211_hw *hw) |
337 | { | 333 | { |
338 | struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); | 334 | struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); |
339 | u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport; | ||
340 | 335 | ||
341 | bool status = false; | 336 | bool status = false; |
342 | u8 offset_e0; | 337 | u8 offset_e0; |
343 | unsigned offset_e4; | 338 | unsigned offset_e4; |
344 | 339 | ||
345 | rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, | 340 | pci_write_config_byte(rtlpci->pdev, 0xe0, 0xa0); |
346 | pcicfg_addrport + 0xE0); | ||
347 | rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, 0xA0); | ||
348 | 341 | ||
349 | rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, | 342 | pci_read_config_byte(rtlpci->pdev, 0xe0, &offset_e0); |
350 | pcicfg_addrport + 0xE0); | ||
351 | rtl_pci_raw_read_port_uchar(PCI_CONF_DATA, &offset_e0); | ||
352 | 343 | ||
353 | if (offset_e0 == 0xA0) { | 344 | if (offset_e0 == 0xA0) { |
354 | rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, | 345 | pci_read_config_dword(rtlpci->pdev, 0xe4, &offset_e4); |
355 | pcicfg_addrport + 0xE4); | ||
356 | rtl_pci_raw_read_port_ulong(PCI_CONF_DATA, &offset_e4); | ||
357 | if (offset_e4 & BIT(23)) | 346 | if (offset_e4 & BIT(23)) |
358 | status = true; | 347 | status = true; |
359 | } | 348 | } |
@@ -364,17 +353,15 @@ static bool rtl_pci_get_amd_l1_patch(struct ieee80211_hw *hw) | |||
364 | static void rtl_pci_get_linkcontrol_field(struct ieee80211_hw *hw) | 353 | static void rtl_pci_get_linkcontrol_field(struct ieee80211_hw *hw) |
365 | { | 354 | { |
366 | struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); | 355 | struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); |
356 | struct rtl_pci *rtlpci = rtl_pcidev(pcipriv); | ||
367 | u8 capabilityoffset = pcipriv->ndis_adapter.pcibridge_pciehdr_offset; | 357 | u8 capabilityoffset = pcipriv->ndis_adapter.pcibridge_pciehdr_offset; |
368 | u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport; | ||
369 | u8 linkctrl_reg; | 358 | u8 linkctrl_reg; |
370 | u8 num4bbytes; | 359 | u8 num4bbytes; |
371 | 360 | ||
372 | num4bbytes = (capabilityoffset + 0x10) / 4; | 361 | num4bbytes = (capabilityoffset + 0x10) / 4; |
373 | 362 | ||
374 | /*Read Link Control Register */ | 363 | /*Read Link Control Register */ |
375 | rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, | 364 | pci_read_config_byte(rtlpci->pdev, (num4bbytes << 2), &linkctrl_reg); |
376 | pcicfg_addrport + (num4bbytes << 2)); | ||
377 | rtl_pci_raw_read_port_uchar(PCI_CONF_DATA, &linkctrl_reg); | ||
378 | 365 | ||
379 | pcipriv->ndis_adapter.pcibridge_linkctrlreg = linkctrl_reg; | 366 | pcipriv->ndis_adapter.pcibridge_linkctrlreg = linkctrl_reg; |
380 | } | 367 | } |
@@ -1718,10 +1705,6 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev, | |||
1718 | PCI_SLOT(bridge_pdev->devfn); | 1705 | PCI_SLOT(bridge_pdev->devfn); |
1719 | pcipriv->ndis_adapter.pcibridge_funcnum = | 1706 | pcipriv->ndis_adapter.pcibridge_funcnum = |
1720 | PCI_FUNC(bridge_pdev->devfn); | 1707 | PCI_FUNC(bridge_pdev->devfn); |
1721 | pcipriv->ndis_adapter.pcicfg_addrport = | ||
1722 | (pcipriv->ndis_adapter.pcibridge_busnum << 16) | | ||
1723 | (pcipriv->ndis_adapter.pcibridge_devnum << 11) | | ||
1724 | (pcipriv->ndis_adapter.pcibridge_funcnum << 8) | (1 << 31); | ||
1725 | pcipriv->ndis_adapter.pcibridge_pciehdr_offset = | 1708 | pcipriv->ndis_adapter.pcibridge_pciehdr_offset = |
1726 | pci_pcie_cap(bridge_pdev); | 1709 | pci_pcie_cap(bridge_pdev); |
1727 | pcipriv->ndis_adapter.num4bytes = | 1710 | pcipriv->ndis_adapter.num4bytes = |
diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h index c53c62046747..a24e505b202b 100644 --- a/drivers/net/wireless/rtlwifi/pci.h +++ b/drivers/net/wireless/rtlwifi/pci.h | |||
@@ -212,7 +212,6 @@ struct mp_adapter { | |||
212 | u16 pcibridge_vendorid; | 212 | u16 pcibridge_vendorid; |
213 | u16 pcibridge_deviceid; | 213 | u16 pcibridge_deviceid; |
214 | 214 | ||
215 | u32 pcicfg_addrport; | ||
216 | u8 num4bytes; | 215 | u8 num4bytes; |
217 | 216 | ||
218 | u8 pcibridge_pciehdr_offset; | 217 | u8 pcibridge_pciehdr_offset; |
@@ -273,29 +272,4 @@ static inline void pci_write32_async(struct rtl_priv *rtlpriv, | |||
273 | writel(val, (u8 __iomem *) rtlpriv->io.pci_mem_start + addr); | 272 | writel(val, (u8 __iomem *) rtlpriv->io.pci_mem_start + addr); |
274 | } | 273 | } |
275 | 274 | ||
276 | static inline void rtl_pci_raw_write_port_ulong(u32 port, u32 val) | ||
277 | { | ||
278 | outl(val, port); | ||
279 | } | ||
280 | |||
281 | static inline void rtl_pci_raw_write_port_uchar(u32 port, u8 val) | ||
282 | { | ||
283 | outb(val, port); | ||
284 | } | ||
285 | |||
286 | static inline void rtl_pci_raw_read_port_uchar(u32 port, u8 *pval) | ||
287 | { | ||
288 | *pval = inb(port); | ||
289 | } | ||
290 | |||
291 | static inline void rtl_pci_raw_read_port_ushort(u32 port, u16 *pval) | ||
292 | { | ||
293 | *pval = inw(port); | ||
294 | } | ||
295 | |||
296 | static inline void rtl_pci_raw_read_port_ulong(u32 port, u32 *pval) | ||
297 | { | ||
298 | *pval = inl(port); | ||
299 | } | ||
300 | |||
301 | #endif | 275 | #endif |
diff --git a/drivers/net/wireless/wl1251/cmd.h b/drivers/net/wireless/wl1251/cmd.h index 79ca5273c9e9..ee4f2b391822 100644 --- a/drivers/net/wireless/wl1251/cmd.h +++ b/drivers/net/wireless/wl1251/cmd.h | |||
@@ -269,7 +269,7 @@ struct cmd_join { | |||
269 | u8 bss_type; | 269 | u8 bss_type; |
270 | u8 channel; | 270 | u8 channel; |
271 | u8 ssid_len; | 271 | u8 ssid_len; |
272 | u8 ssid[IW_ESSID_MAX_SIZE]; | 272 | u8 ssid[IEEE80211_MAX_SSID_LEN]; |
273 | u8 ctrl; /* JOIN_CMD_CTRL_* */ | 273 | u8 ctrl; /* JOIN_CMD_CTRL_* */ |
274 | u8 tx_mgt_frame_rate; /* OBSOLETE */ | 274 | u8 tx_mgt_frame_rate; /* OBSOLETE */ |
275 | u8 tx_mgt_frame_mod; /* OBSOLETE */ | 275 | u8 tx_mgt_frame_mod; /* OBSOLETE */ |
diff --git a/drivers/net/wireless/wl1251/wl12xx_80211.h b/drivers/net/wireless/wl1251/wl12xx_80211.h index 1417b1445c3d..04ed51495772 100644 --- a/drivers/net/wireless/wl1251/wl12xx_80211.h +++ b/drivers/net/wireless/wl1251/wl12xx_80211.h | |||
@@ -76,7 +76,7 @@ struct wl12xx_ie_header { | |||
76 | 76 | ||
77 | struct wl12xx_ie_ssid { | 77 | struct wl12xx_ie_ssid { |
78 | struct wl12xx_ie_header header; | 78 | struct wl12xx_ie_header header; |
79 | char ssid[IW_ESSID_MAX_SIZE]; | 79 | char ssid[IEEE80211_MAX_SSID_LEN]; |
80 | } __packed; | 80 | } __packed; |
81 | 81 | ||
82 | struct wl12xx_ie_rates { | 82 | struct wl12xx_ie_rates { |
diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h index 1f7037292c15..bba077ecd945 100644 --- a/drivers/net/wireless/wl12xx/cmd.h +++ b/drivers/net/wireless/wl12xx/cmd.h | |||
@@ -239,7 +239,7 @@ struct wl1271_cmd_join { | |||
239 | u8 bss_type; | 239 | u8 bss_type; |
240 | u8 channel; | 240 | u8 channel; |
241 | u8 ssid_len; | 241 | u8 ssid_len; |
242 | u8 ssid[IW_ESSID_MAX_SIZE]; | 242 | u8 ssid[IEEE80211_MAX_SSID_LEN]; |
243 | u8 ctrl; /* JOIN_CMD_CTRL_* */ | 243 | u8 ctrl; /* JOIN_CMD_CTRL_* */ |
244 | u8 reserved[3]; | 244 | u8 reserved[3]; |
245 | } __packed; | 245 | } __packed; |
@@ -528,7 +528,7 @@ struct wl1271_cmd_bss_start { | |||
528 | /* wl1271_ssid_type */ | 528 | /* wl1271_ssid_type */ |
529 | u8 ssid_type; | 529 | u8 ssid_type; |
530 | u8 ssid_len; | 530 | u8 ssid_len; |
531 | u8 ssid[IW_ESSID_MAX_SIZE]; | 531 | u8 ssid[IEEE80211_MAX_SSID_LEN]; |
532 | u8 padding_1[2]; | 532 | u8 padding_1[2]; |
533 | 533 | ||
534 | /* Basic rate set */ | 534 | /* Basic rate set */ |
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index e58c22d21e39..3418299e17c8 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c | |||
@@ -1997,7 +1997,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, | |||
1997 | wl1271_power_off(wl); | 1997 | wl1271_power_off(wl); |
1998 | 1998 | ||
1999 | memset(wl->bssid, 0, ETH_ALEN); | 1999 | memset(wl->bssid, 0, ETH_ALEN); |
2000 | memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1); | 2000 | memset(wl->ssid, 0, IEEE80211_MAX_SSID_LEN + 1); |
2001 | wl->ssid_len = 0; | 2001 | wl->ssid_len = 0; |
2002 | wl->bss_type = MAX_BSS_TYPE; | 2002 | wl->bss_type = MAX_BSS_TYPE; |
2003 | wl->set_bss_type = MAX_BSS_TYPE; | 2003 | wl->set_bss_type = MAX_BSS_TYPE; |
diff --git a/drivers/net/wireless/wl12xx/scan.h b/drivers/net/wireless/wl12xx/scan.h index d882e4da71b7..0b2a2987439d 100644 --- a/drivers/net/wireless/wl12xx/scan.h +++ b/drivers/net/wireless/wl12xx/scan.h | |||
@@ -77,7 +77,7 @@ struct basic_scan_params { | |||
77 | u8 ssid_len; | 77 | u8 ssid_len; |
78 | /* in order to align */ | 78 | /* in order to align */ |
79 | u8 padding1[2]; | 79 | u8 padding1[2]; |
80 | u8 ssid[IW_ESSID_MAX_SIZE]; | 80 | u8 ssid[IEEE80211_MAX_SSID_LEN]; |
81 | /* Band to scan */ | 81 | /* Band to scan */ |
82 | u8 band; | 82 | u8 band; |
83 | u8 use_ssid_list; | 83 | u8 use_ssid_list; |
@@ -167,7 +167,7 @@ struct wl1271_cmd_sched_scan_config { | |||
167 | u8 filter_type; | 167 | u8 filter_type; |
168 | 168 | ||
169 | u8 ssid_len; /* For SCAN_SSID_FILTER_SPECIFIC */ | 169 | u8 ssid_len; /* For SCAN_SSID_FILTER_SPECIFIC */ |
170 | u8 ssid[IW_ESSID_MAX_SIZE]; | 170 | u8 ssid[IEEE80211_MAX_SSID_LEN]; |
171 | 171 | ||
172 | u8 n_probe_reqs; /* Number of probes requests per channel */ | 172 | u8 n_probe_reqs; /* Number of probes requests per channel */ |
173 | 173 | ||
@@ -194,7 +194,7 @@ enum { | |||
194 | struct wl1271_ssid { | 194 | struct wl1271_ssid { |
195 | u8 type; | 195 | u8 type; |
196 | u8 len; | 196 | u8 len; |
197 | u8 ssid[IW_ESSID_MAX_SIZE]; | 197 | u8 ssid[IEEE80211_MAX_SSID_LEN]; |
198 | /* u8 padding[2]; */ | 198 | /* u8 padding[2]; */ |
199 | } __packed; | 199 | } __packed; |
200 | 200 | ||
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 1a8751eb8140..0bc29356ebe4 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h | |||
@@ -309,7 +309,7 @@ struct wl1271_scan { | |||
309 | unsigned long scanned_ch[BITS_TO_LONGS(WL1271_MAX_CHANNELS)]; | 309 | unsigned long scanned_ch[BITS_TO_LONGS(WL1271_MAX_CHANNELS)]; |
310 | bool failed; | 310 | bool failed; |
311 | u8 state; | 311 | u8 state; |
312 | u8 ssid[IW_ESSID_MAX_SIZE+1]; | 312 | u8 ssid[IEEE80211_MAX_SSID_LEN+1]; |
313 | size_t ssid_len; | 313 | size_t ssid_len; |
314 | }; | 314 | }; |
315 | 315 | ||
@@ -415,7 +415,7 @@ struct wl1271 { | |||
415 | u8 mac_addr[ETH_ALEN]; | 415 | u8 mac_addr[ETH_ALEN]; |
416 | u8 bss_type; | 416 | u8 bss_type; |
417 | u8 set_bss_type; | 417 | u8 set_bss_type; |
418 | u8 ssid[IW_ESSID_MAX_SIZE + 1]; | 418 | u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; |
419 | u8 ssid_len; | 419 | u8 ssid_len; |
420 | int channel; | 420 | int channel; |
421 | 421 | ||
diff --git a/drivers/net/wireless/wl12xx/wl12xx_80211.h b/drivers/net/wireless/wl12xx/wl12xx_80211.h index 18fe542360f2..f334ea081722 100644 --- a/drivers/net/wireless/wl12xx/wl12xx_80211.h +++ b/drivers/net/wireless/wl12xx/wl12xx_80211.h | |||
@@ -77,7 +77,7 @@ struct wl12xx_ie_header { | |||
77 | 77 | ||
78 | struct wl12xx_ie_ssid { | 78 | struct wl12xx_ie_ssid { |
79 | struct wl12xx_ie_header header; | 79 | struct wl12xx_ie_header header; |
80 | char ssid[IW_ESSID_MAX_SIZE]; | 80 | char ssid[IEEE80211_MAX_SSID_LEN]; |
81 | } __packed; | 81 | } __packed; |
82 | 82 | ||
83 | struct wl12xx_ie_rates { | 83 | struct wl12xx_ie_rates { |