diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx')
-rw-r--r-- | drivers/net/wireless/wl12xx/Kconfig | 12 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271.h | 13 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_acx.c | 83 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_acx.h | 89 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_boot.c | 10 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_debugfs.c | 215 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_event.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_main.c | 220 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_rx.c | 28 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_rx.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_scan.c | 5 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_testmode.c | 12 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_tx.c | 132 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_tx.h | 3 |
14 files changed, 617 insertions, 209 deletions
diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index b447559f1db5..02ad4bc15976 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig | |||
@@ -18,6 +18,16 @@ config WL1271 | |||
18 | If you choose to build a module, it'll be called wl1271. Say N if | 18 | If you choose to build a module, it'll be called wl1271. Say N if |
19 | unsure. | 19 | unsure. |
20 | 20 | ||
21 | config WL1271_HT | ||
22 | bool "TI wl1271 802.11 HT support (EXPERIMENTAL)" | ||
23 | depends on WL1271 && EXPERIMENTAL | ||
24 | default n | ||
25 | ---help--- | ||
26 | This will enable 802.11 HT support for TI wl1271 chipset. | ||
27 | |||
28 | That configuration is temporary due to the code incomplete and | ||
29 | still in testing process. | ||
30 | |||
21 | config WL1271_SPI | 31 | config WL1271_SPI |
22 | tristate "TI wl1271 SPI support" | 32 | tristate "TI wl1271 SPI support" |
23 | depends on WL1271 && SPI_MASTER | 33 | depends on WL1271 && SPI_MASTER |
@@ -42,5 +52,5 @@ config WL1271_SDIO | |||
42 | 52 | ||
43 | config WL12XX_PLATFORM_DATA | 53 | config WL12XX_PLATFORM_DATA |
44 | bool | 54 | bool |
45 | depends on WL1271_SDIO != n | 55 | depends on WL1271_SDIO != n || WL1251_SDIO != n |
46 | default y | 56 | default y |
diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 8a4cd763e5a2..ab53162b4343 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h | |||
@@ -351,6 +351,7 @@ struct wl1271 { | |||
351 | #define WL1271_FLAG_IDLE_REQUESTED (11) | 351 | #define WL1271_FLAG_IDLE_REQUESTED (11) |
352 | #define WL1271_FLAG_PSPOLL_FAILURE (12) | 352 | #define WL1271_FLAG_PSPOLL_FAILURE (12) |
353 | #define WL1271_FLAG_STA_STATE_SENT (13) | 353 | #define WL1271_FLAG_STA_STATE_SENT (13) |
354 | #define WL1271_FLAG_FW_TX_BUSY (14) | ||
354 | unsigned long flags; | 355 | unsigned long flags; |
355 | 356 | ||
356 | struct wl1271_partition_set part; | 357 | struct wl1271_partition_set part; |
@@ -397,6 +398,7 @@ struct wl1271 { | |||
397 | struct work_struct tx_work; | 398 | struct work_struct tx_work; |
398 | 399 | ||
399 | /* Pending TX frames */ | 400 | /* Pending TX frames */ |
401 | unsigned long tx_frames_map[BITS_TO_LONGS(ACX_TX_DESCRIPTORS)]; | ||
400 | struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS]; | 402 | struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS]; |
401 | int tx_frames_cnt; | 403 | int tx_frames_cnt; |
402 | 404 | ||
@@ -432,7 +434,12 @@ struct wl1271 { | |||
432 | /* Our association ID */ | 434 | /* Our association ID */ |
433 | u16 aid; | 435 | u16 aid; |
434 | 436 | ||
435 | /* currently configured rate set */ | 437 | /* |
438 | * currently configured rate set: | ||
439 | * bits 0-15 - 802.11abg rates | ||
440 | * bits 16-23 - 802.11n MCS index mask | ||
441 | * support only 1 stream, thus only 8 bits for the MCS rates (0-7). | ||
442 | */ | ||
436 | u32 sta_rate_set; | 443 | u32 sta_rate_set; |
437 | u32 basic_rate_set; | 444 | u32 basic_rate_set; |
438 | u32 basic_rate; | 445 | u32 basic_rate; |
@@ -509,4 +516,8 @@ int wl1271_plt_stop(struct wl1271 *wl); | |||
509 | #define WL1271_PRE_POWER_ON_SLEEP 20 /* in miliseconds */ | 516 | #define WL1271_PRE_POWER_ON_SLEEP 20 /* in miliseconds */ |
510 | #define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */ | 517 | #define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */ |
511 | 518 | ||
519 | /* Macros to handle wl1271.sta_rate_set */ | ||
520 | #define HW_BG_RATES_MASK 0xffff | ||
521 | #define HW_HT_RATES_OFFSET 16 | ||
522 | |||
512 | #endif | 523 | #endif |
diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c index 618993405262..bd7f95f4eef3 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.c +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c | |||
@@ -1226,6 +1226,89 @@ out: | |||
1226 | return ret; | 1226 | return ret; |
1227 | } | 1227 | } |
1228 | 1228 | ||
1229 | int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, | ||
1230 | struct ieee80211_sta_ht_cap *ht_cap, | ||
1231 | bool allow_ht_operation) | ||
1232 | { | ||
1233 | struct wl1271_acx_ht_capabilities *acx; | ||
1234 | u8 mac_address[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | ||
1235 | int ret = 0; | ||
1236 | |||
1237 | wl1271_debug(DEBUG_ACX, "acx ht capabilities setting"); | ||
1238 | |||
1239 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
1240 | if (!acx) { | ||
1241 | ret = -ENOMEM; | ||
1242 | goto out; | ||
1243 | } | ||
1244 | |||
1245 | /* Allow HT Operation ? */ | ||
1246 | if (allow_ht_operation) { | ||
1247 | acx->ht_capabilites = | ||
1248 | WL1271_ACX_FW_CAP_HT_OPERATION; | ||
1249 | if (ht_cap->cap & IEEE80211_HT_CAP_GRN_FLD) | ||
1250 | acx->ht_capabilites |= | ||
1251 | WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT; | ||
1252 | if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20) | ||
1253 | acx->ht_capabilites |= | ||
1254 | WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS; | ||
1255 | if (ht_cap->cap & IEEE80211_HT_CAP_LSIG_TXOP_PROT) | ||
1256 | acx->ht_capabilites |= | ||
1257 | WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION; | ||
1258 | |||
1259 | /* get data from A-MPDU parameters field */ | ||
1260 | acx->ampdu_max_length = ht_cap->ampdu_factor; | ||
1261 | acx->ampdu_min_spacing = ht_cap->ampdu_density; | ||
1262 | |||
1263 | memcpy(acx->mac_address, mac_address, ETH_ALEN); | ||
1264 | } else { /* HT operations are not allowed */ | ||
1265 | acx->ht_capabilites = 0; | ||
1266 | } | ||
1267 | |||
1268 | ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx)); | ||
1269 | if (ret < 0) { | ||
1270 | wl1271_warning("acx ht capabilities setting failed: %d", ret); | ||
1271 | goto out; | ||
1272 | } | ||
1273 | |||
1274 | out: | ||
1275 | kfree(acx); | ||
1276 | return ret; | ||
1277 | } | ||
1278 | |||
1279 | int wl1271_acx_set_ht_information(struct wl1271 *wl, | ||
1280 | u16 ht_operation_mode) | ||
1281 | { | ||
1282 | struct wl1271_acx_ht_information *acx; | ||
1283 | int ret = 0; | ||
1284 | |||
1285 | wl1271_debug(DEBUG_ACX, "acx ht information setting"); | ||
1286 | |||
1287 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
1288 | if (!acx) { | ||
1289 | ret = -ENOMEM; | ||
1290 | goto out; | ||
1291 | } | ||
1292 | |||
1293 | acx->ht_protection = | ||
1294 | (u8)(ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION); | ||
1295 | acx->rifs_mode = 0; | ||
1296 | acx->gf_protection = 0; | ||
1297 | acx->ht_tx_burst_limit = 0; | ||
1298 | acx->dual_cts_protection = 0; | ||
1299 | |||
1300 | ret = wl1271_cmd_configure(wl, ACX_HT_BSS_OPERATION, acx, sizeof(*acx)); | ||
1301 | |||
1302 | if (ret < 0) { | ||
1303 | wl1271_warning("acx ht information setting failed: %d", ret); | ||
1304 | goto out; | ||
1305 | } | ||
1306 | |||
1307 | out: | ||
1308 | kfree(acx); | ||
1309 | return ret; | ||
1310 | } | ||
1311 | |||
1229 | int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime) | 1312 | int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime) |
1230 | { | 1313 | { |
1231 | struct wl1271_acx_fw_tsf_information *tsf_info; | 1314 | struct wl1271_acx_fw_tsf_information *tsf_info; |
diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h index ebb341d36e8c..b7c490845f3e 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h | |||
@@ -61,7 +61,8 @@ | |||
61 | WL1271_ACX_INTR_HW_AVAILABLE | \ | 61 | WL1271_ACX_INTR_HW_AVAILABLE | \ |
62 | WL1271_ACX_INTR_DATA) | 62 | WL1271_ACX_INTR_DATA) |
63 | 63 | ||
64 | #define WL1271_INTR_MASK (WL1271_ACX_INTR_EVENT_A | \ | 64 | #define WL1271_INTR_MASK (WL1271_ACX_INTR_WATCHDOG | \ |
65 | WL1271_ACX_INTR_EVENT_A | \ | ||
65 | WL1271_ACX_INTR_EVENT_B | \ | 66 | WL1271_ACX_INTR_EVENT_B | \ |
66 | WL1271_ACX_INTR_HW_AVAILABLE | \ | 67 | WL1271_ACX_INTR_HW_AVAILABLE | \ |
67 | WL1271_ACX_INTR_DATA) | 68 | WL1271_ACX_INTR_DATA) |
@@ -964,6 +965,87 @@ struct wl1271_acx_rssi_snr_avg_weights { | |||
964 | u8 snr_data; | 965 | u8 snr_data; |
965 | }; | 966 | }; |
966 | 967 | ||
968 | /* | ||
969 | * ACX_PEER_HT_CAP | ||
970 | * Configure HT capabilities - declare the capabilities of the peer | ||
971 | * we are connected to. | ||
972 | */ | ||
973 | struct wl1271_acx_ht_capabilities { | ||
974 | struct acx_header header; | ||
975 | |||
976 | /* | ||
977 | * bit 0 - Allow HT Operation | ||
978 | * bit 1 - Allow Greenfield format in TX | ||
979 | * bit 2 - Allow Short GI in TX | ||
980 | * bit 3 - Allow L-SIG TXOP Protection in TX | ||
981 | * bit 4 - Allow HT Control fields in TX. | ||
982 | * Note, driver will still leave space for HT control in packets | ||
983 | * regardless of the value of this field. FW will be responsible | ||
984 | * to drop the HT field from any frame when this Bit set to 0. | ||
985 | * bit 5 - Allow RD initiation in TXOP. FW is allowed to initate RD. | ||
986 | * Exact policy setting for this feature is TBD. | ||
987 | * Note, this bit can only be set to 1 if bit 3 is set to 1. | ||
988 | */ | ||
989 | __le32 ht_capabilites; | ||
990 | |||
991 | /* | ||
992 | * Indicates to which peer these capabilities apply. | ||
993 | * For infrastructure use ff:ff:ff:ff:ff:ff that indicates relevance | ||
994 | * for all peers. | ||
995 | * Only valid for IBSS/DLS operation. | ||
996 | */ | ||
997 | u8 mac_address[ETH_ALEN]; | ||
998 | |||
999 | /* | ||
1000 | * This the maximum A-MPDU length supported by the AP. The FW may not | ||
1001 | * exceed this length when sending A-MPDUs | ||
1002 | */ | ||
1003 | u8 ampdu_max_length; | ||
1004 | |||
1005 | /* This is the minimal spacing required when sending A-MPDUs to the AP*/ | ||
1006 | u8 ampdu_min_spacing; | ||
1007 | } __packed; | ||
1008 | |||
1009 | /* HT Capabilites Fw Bit Mask Mapping */ | ||
1010 | #define WL1271_ACX_FW_CAP_HT_OPERATION BIT(0) | ||
1011 | #define WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT BIT(1) | ||
1012 | #define WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS BIT(2) | ||
1013 | #define WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION BIT(3) | ||
1014 | #define WL1271_ACX_FW_CAP_HT_CONTROL_FIELDS BIT(4) | ||
1015 | #define WL1271_ACX_FW_CAP_RD_INITIATION BIT(5) | ||
1016 | |||
1017 | |||
1018 | /* | ||
1019 | * ACX_HT_BSS_OPERATION | ||
1020 | * Configure HT capabilities - AP rules for behavior in the BSS. | ||
1021 | */ | ||
1022 | struct wl1271_acx_ht_information { | ||
1023 | struct acx_header header; | ||
1024 | |||
1025 | /* Values: 0 - RIFS not allowed, 1 - RIFS allowed */ | ||
1026 | u8 rifs_mode; | ||
1027 | |||
1028 | /* Values: 0 - 3 like in spec */ | ||
1029 | u8 ht_protection; | ||
1030 | |||
1031 | /* Values: 0 - GF protection not required, 1 - GF protection required */ | ||
1032 | u8 gf_protection; | ||
1033 | |||
1034 | /*Values: 0 - TX Burst limit not required, 1 - TX Burst Limit required*/ | ||
1035 | u8 ht_tx_burst_limit; | ||
1036 | |||
1037 | /* | ||
1038 | * Values: 0 - Dual CTS protection not required, | ||
1039 | * 1 - Dual CTS Protection required | ||
1040 | * Note: When this value is set to 1 FW will protect all TXOP with RTS | ||
1041 | * frame and will not use CTS-to-self regardless of the value of the | ||
1042 | * ACX_CTS_PROTECTION information element | ||
1043 | */ | ||
1044 | u8 dual_cts_protection; | ||
1045 | |||
1046 | u8 padding[3]; | ||
1047 | } __packed; | ||
1048 | |||
967 | struct wl1271_acx_fw_tsf_information { | 1049 | struct wl1271_acx_fw_tsf_information { |
968 | struct acx_header header; | 1050 | struct acx_header header; |
969 | 1051 | ||
@@ -1093,6 +1175,11 @@ int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid); | |||
1093 | int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable, | 1175 | int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable, |
1094 | s16 thold, u8 hyst); | 1176 | s16 thold, u8 hyst); |
1095 | int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl); | 1177 | int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl); |
1178 | int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, | ||
1179 | struct ieee80211_sta_ht_cap *ht_cap, | ||
1180 | bool allow_ht_operation); | ||
1181 | int wl1271_acx_set_ht_information(struct wl1271 *wl, | ||
1182 | u16 ht_operation_mode); | ||
1096 | int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); | 1183 | int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); |
1097 | 1184 | ||
1098 | #endif /* __WL1271_ACX_H__ */ | 1185 | #endif /* __WL1271_ACX_H__ */ |
diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c index b91021242098..5b190728ca55 100644 --- a/drivers/net/wireless/wl12xx/wl1271_boot.c +++ b/drivers/net/wireless/wl12xx/wl1271_boot.c | |||
@@ -471,20 +471,19 @@ int wl1271_boot(struct wl1271 *wl) | |||
471 | { | 471 | { |
472 | int ret = 0; | 472 | int ret = 0; |
473 | u32 tmp, clk, pause; | 473 | u32 tmp, clk, pause; |
474 | int ref_clock = wl->ref_clock; | ||
475 | 474 | ||
476 | wl1271_boot_hw_version(wl); | 475 | wl1271_boot_hw_version(wl); |
477 | 476 | ||
478 | if (ref_clock == 0 || ref_clock == 2 || ref_clock == 4) | 477 | if (wl->ref_clock == 0 || wl->ref_clock == 2 || wl->ref_clock == 4) |
479 | /* ref clk: 19.2/38.4/38.4-XTAL */ | 478 | /* ref clk: 19.2/38.4/38.4-XTAL */ |
480 | clk = 0x3; | 479 | clk = 0x3; |
481 | else if (ref_clock == 1 || ref_clock == 3) | 480 | else if (wl->ref_clock == 1 || wl->ref_clock == 3) |
482 | /* ref clk: 26/52 */ | 481 | /* ref clk: 26/52 */ |
483 | clk = 0x5; | 482 | clk = 0x5; |
484 | else | 483 | else |
485 | return -EINVAL; | 484 | return -EINVAL; |
486 | 485 | ||
487 | if (ref_clock != 0) { | 486 | if (wl->ref_clock != 0) { |
488 | u16 val; | 487 | u16 val; |
489 | /* Set clock type (open drain) */ | 488 | /* Set clock type (open drain) */ |
490 | val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE); | 489 | val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE); |
@@ -529,8 +528,7 @@ int wl1271_boot(struct wl1271 *wl) | |||
529 | 528 | ||
530 | wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); | 529 | wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); |
531 | 530 | ||
532 | /* 2 */ | 531 | clk |= (wl->ref_clock << 1) << 4; |
533 | clk |= (ref_clock << 1) << 4; | ||
534 | wl1271_write32(wl, DRPW_SCRATCH_START, clk); | 532 | wl1271_write32(wl, DRPW_SCRATCH_START, clk); |
535 | 533 | ||
536 | wl1271_set_partition(wl, &part_table[PART_WORK]); | 534 | wl1271_set_partition(wl, &part_table[PART_WORK]); |
diff --git a/drivers/net/wireless/wl12xx/wl1271_debugfs.c b/drivers/net/wireless/wl12xx/wl1271_debugfs.c index 66c2b90ddfd4..3468b849852e 100644 --- a/drivers/net/wireless/wl12xx/wl1271_debugfs.c +++ b/drivers/net/wireless/wl12xx/wl1271_debugfs.c | |||
@@ -35,17 +35,28 @@ | |||
35 | #define WL1271_DEBUGFS_STATS_LIFETIME 1000 | 35 | #define WL1271_DEBUGFS_STATS_LIFETIME 1000 |
36 | 36 | ||
37 | /* debugfs macros idea from mac80211 */ | 37 | /* debugfs macros idea from mac80211 */ |
38 | #define DEBUGFS_FORMAT_BUFFER_SIZE 100 | ||
39 | static int wl1271_format_buffer(char __user *userbuf, size_t count, | ||
40 | loff_t *ppos, char *fmt, ...) | ||
41 | { | ||
42 | va_list args; | ||
43 | char buf[DEBUGFS_FORMAT_BUFFER_SIZE]; | ||
44 | int res; | ||
38 | 45 | ||
39 | #define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ | 46 | va_start(args, fmt); |
47 | res = vscnprintf(buf, sizeof(buf), fmt, args); | ||
48 | va_end(args); | ||
49 | |||
50 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | ||
51 | } | ||
52 | |||
53 | #define DEBUGFS_READONLY_FILE(name, fmt, value...) \ | ||
40 | static ssize_t name## _read(struct file *file, char __user *userbuf, \ | 54 | static ssize_t name## _read(struct file *file, char __user *userbuf, \ |
41 | size_t count, loff_t *ppos) \ | 55 | size_t count, loff_t *ppos) \ |
42 | { \ | 56 | { \ |
43 | struct wl1271 *wl = file->private_data; \ | 57 | struct wl1271 *wl = file->private_data; \ |
44 | char buf[buflen]; \ | 58 | return wl1271_format_buffer(userbuf, count, ppos, \ |
45 | int res; \ | 59 | fmt "\n", ##value); \ |
46 | \ | ||
47 | res = scnprintf(buf, buflen, fmt "\n", ##value); \ | ||
48 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ | ||
49 | } \ | 60 | } \ |
50 | \ | 61 | \ |
51 | static const struct file_operations name## _ops = { \ | 62 | static const struct file_operations name## _ops = { \ |
@@ -69,20 +80,17 @@ static const struct file_operations name## _ops = { \ | |||
69 | wl->debugfs.name = NULL; \ | 80 | wl->debugfs.name = NULL; \ |
70 | } while (0) | 81 | } while (0) |
71 | 82 | ||
72 | #define DEBUGFS_FWSTATS_FILE(sub, name, buflen, fmt) \ | 83 | #define DEBUGFS_FWSTATS_FILE(sub, name, fmt) \ |
73 | static ssize_t sub## _ ##name## _read(struct file *file, \ | 84 | static ssize_t sub## _ ##name## _read(struct file *file, \ |
74 | char __user *userbuf, \ | 85 | char __user *userbuf, \ |
75 | size_t count, loff_t *ppos) \ | 86 | size_t count, loff_t *ppos) \ |
76 | { \ | 87 | { \ |
77 | struct wl1271 *wl = file->private_data; \ | 88 | struct wl1271 *wl = file->private_data; \ |
78 | char buf[buflen]; \ | ||
79 | int res; \ | ||
80 | \ | 89 | \ |
81 | wl1271_debugfs_update_stats(wl); \ | 90 | wl1271_debugfs_update_stats(wl); \ |
82 | \ | 91 | \ |
83 | res = scnprintf(buf, buflen, fmt "\n", \ | 92 | return wl1271_format_buffer(userbuf, count, ppos, fmt "\n", \ |
84 | wl->stats.fw_stats->sub.name); \ | 93 | wl->stats.fw_stats->sub.name); \ |
85 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ | ||
86 | } \ | 94 | } \ |
87 | \ | 95 | \ |
88 | static const struct file_operations sub## _ ##name## _ops = { \ | 96 | static const struct file_operations sub## _ ##name## _ops = { \ |
@@ -126,100 +134,99 @@ static int wl1271_open_file_generic(struct inode *inode, struct file *file) | |||
126 | return 0; | 134 | return 0; |
127 | } | 135 | } |
128 | 136 | ||
129 | DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, 20, "%u"); | 137 | DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, "%u"); |
130 | 138 | ||
131 | DEBUGFS_FWSTATS_FILE(rx, out_of_mem, 20, "%u"); | 139 | DEBUGFS_FWSTATS_FILE(rx, out_of_mem, "%u"); |
132 | DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, 20, "%u"); | 140 | DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, "%u"); |
133 | DEBUGFS_FWSTATS_FILE(rx, hw_stuck, 20, "%u"); | 141 | DEBUGFS_FWSTATS_FILE(rx, hw_stuck, "%u"); |
134 | DEBUGFS_FWSTATS_FILE(rx, dropped, 20, "%u"); | 142 | DEBUGFS_FWSTATS_FILE(rx, dropped, "%u"); |
135 | DEBUGFS_FWSTATS_FILE(rx, fcs_err, 20, "%u"); | 143 | DEBUGFS_FWSTATS_FILE(rx, fcs_err, "%u"); |
136 | DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, 20, "%u"); | 144 | DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, "%u"); |
137 | DEBUGFS_FWSTATS_FILE(rx, path_reset, 20, "%u"); | 145 | DEBUGFS_FWSTATS_FILE(rx, path_reset, "%u"); |
138 | DEBUGFS_FWSTATS_FILE(rx, reset_counter, 20, "%u"); | 146 | DEBUGFS_FWSTATS_FILE(rx, reset_counter, "%u"); |
139 | 147 | ||
140 | DEBUGFS_FWSTATS_FILE(dma, rx_requested, 20, "%u"); | 148 | DEBUGFS_FWSTATS_FILE(dma, rx_requested, "%u"); |
141 | DEBUGFS_FWSTATS_FILE(dma, rx_errors, 20, "%u"); | 149 | DEBUGFS_FWSTATS_FILE(dma, rx_errors, "%u"); |
142 | DEBUGFS_FWSTATS_FILE(dma, tx_requested, 20, "%u"); | 150 | DEBUGFS_FWSTATS_FILE(dma, tx_requested, "%u"); |
143 | DEBUGFS_FWSTATS_FILE(dma, tx_errors, 20, "%u"); | 151 | DEBUGFS_FWSTATS_FILE(dma, tx_errors, "%u"); |
144 | 152 | ||
145 | DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, 20, "%u"); | 153 | DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, "%u"); |
146 | DEBUGFS_FWSTATS_FILE(isr, fiqs, 20, "%u"); | 154 | DEBUGFS_FWSTATS_FILE(isr, fiqs, "%u"); |
147 | DEBUGFS_FWSTATS_FILE(isr, rx_headers, 20, "%u"); | 155 | DEBUGFS_FWSTATS_FILE(isr, rx_headers, "%u"); |
148 | DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, 20, "%u"); | 156 | DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, "%u"); |
149 | DEBUGFS_FWSTATS_FILE(isr, rx_rdys, 20, "%u"); | 157 | DEBUGFS_FWSTATS_FILE(isr, rx_rdys, "%u"); |
150 | DEBUGFS_FWSTATS_FILE(isr, irqs, 20, "%u"); | 158 | DEBUGFS_FWSTATS_FILE(isr, irqs, "%u"); |
151 | DEBUGFS_FWSTATS_FILE(isr, tx_procs, 20, "%u"); | 159 | DEBUGFS_FWSTATS_FILE(isr, tx_procs, "%u"); |
152 | DEBUGFS_FWSTATS_FILE(isr, decrypt_done, 20, "%u"); | 160 | DEBUGFS_FWSTATS_FILE(isr, decrypt_done, "%u"); |
153 | DEBUGFS_FWSTATS_FILE(isr, dma0_done, 20, "%u"); | 161 | DEBUGFS_FWSTATS_FILE(isr, dma0_done, "%u"); |
154 | DEBUGFS_FWSTATS_FILE(isr, dma1_done, 20, "%u"); | 162 | DEBUGFS_FWSTATS_FILE(isr, dma1_done, "%u"); |
155 | DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, 20, "%u"); | 163 | DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, "%u"); |
156 | DEBUGFS_FWSTATS_FILE(isr, commands, 20, "%u"); | 164 | DEBUGFS_FWSTATS_FILE(isr, commands, "%u"); |
157 | DEBUGFS_FWSTATS_FILE(isr, rx_procs, 20, "%u"); | 165 | DEBUGFS_FWSTATS_FILE(isr, rx_procs, "%u"); |
158 | DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, 20, "%u"); | 166 | DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, "%u"); |
159 | DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, 20, "%u"); | 167 | DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, "%u"); |
160 | DEBUGFS_FWSTATS_FILE(isr, pci_pm, 20, "%u"); | 168 | DEBUGFS_FWSTATS_FILE(isr, pci_pm, "%u"); |
161 | DEBUGFS_FWSTATS_FILE(isr, wakeups, 20, "%u"); | 169 | DEBUGFS_FWSTATS_FILE(isr, wakeups, "%u"); |
162 | DEBUGFS_FWSTATS_FILE(isr, low_rssi, 20, "%u"); | 170 | DEBUGFS_FWSTATS_FILE(isr, low_rssi, "%u"); |
163 | 171 | ||
164 | DEBUGFS_FWSTATS_FILE(wep, addr_key_count, 20, "%u"); | 172 | DEBUGFS_FWSTATS_FILE(wep, addr_key_count, "%u"); |
165 | DEBUGFS_FWSTATS_FILE(wep, default_key_count, 20, "%u"); | 173 | DEBUGFS_FWSTATS_FILE(wep, default_key_count, "%u"); |
166 | /* skipping wep.reserved */ | 174 | /* skipping wep.reserved */ |
167 | DEBUGFS_FWSTATS_FILE(wep, key_not_found, 20, "%u"); | 175 | DEBUGFS_FWSTATS_FILE(wep, key_not_found, "%u"); |
168 | DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, 20, "%u"); | 176 | DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, "%u"); |
169 | DEBUGFS_FWSTATS_FILE(wep, packets, 20, "%u"); | 177 | DEBUGFS_FWSTATS_FILE(wep, packets, "%u"); |
170 | DEBUGFS_FWSTATS_FILE(wep, interrupt, 20, "%u"); | 178 | DEBUGFS_FWSTATS_FILE(wep, interrupt, "%u"); |
171 | 179 | ||
172 | DEBUGFS_FWSTATS_FILE(pwr, ps_enter, 20, "%u"); | 180 | DEBUGFS_FWSTATS_FILE(pwr, ps_enter, "%u"); |
173 | DEBUGFS_FWSTATS_FILE(pwr, elp_enter, 20, "%u"); | 181 | DEBUGFS_FWSTATS_FILE(pwr, elp_enter, "%u"); |
174 | DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, 20, "%u"); | 182 | DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, "%u"); |
175 | DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, 20, "%u"); | 183 | DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, "%u"); |
176 | DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, 20, "%u"); | 184 | DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, "%u"); |
177 | DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, 20, "%u"); | 185 | DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, "%u"); |
178 | DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, 20, "%u"); | 186 | DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, "%u"); |
179 | DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, 20, "%u"); | 187 | DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, "%u"); |
180 | DEBUGFS_FWSTATS_FILE(pwr, power_save_off, 20, "%u"); | 188 | DEBUGFS_FWSTATS_FILE(pwr, power_save_off, "%u"); |
181 | DEBUGFS_FWSTATS_FILE(pwr, enable_ps, 20, "%u"); | 189 | DEBUGFS_FWSTATS_FILE(pwr, enable_ps, "%u"); |
182 | DEBUGFS_FWSTATS_FILE(pwr, disable_ps, 20, "%u"); | 190 | DEBUGFS_FWSTATS_FILE(pwr, disable_ps, "%u"); |
183 | DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, 20, "%u"); | 191 | DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, "%u"); |
184 | /* skipping cont_miss_bcns_spread for now */ | 192 | /* skipping cont_miss_bcns_spread for now */ |
185 | DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, 20, "%u"); | 193 | DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, "%u"); |
186 | 194 | ||
187 | DEBUGFS_FWSTATS_FILE(mic, rx_pkts, 20, "%u"); | 195 | DEBUGFS_FWSTATS_FILE(mic, rx_pkts, "%u"); |
188 | DEBUGFS_FWSTATS_FILE(mic, calc_failure, 20, "%u"); | 196 | DEBUGFS_FWSTATS_FILE(mic, calc_failure, "%u"); |
189 | 197 | ||
190 | DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, 20, "%u"); | 198 | DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, "%u"); |
191 | DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, 20, "%u"); | 199 | DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, "%u"); |
192 | DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, 20, "%u"); | 200 | DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, "%u"); |
193 | DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, 20, "%u"); | 201 | DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, "%u"); |
194 | DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, 20, "%u"); | 202 | DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, "%u"); |
195 | DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, 20, "%u"); | 203 | DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, "%u"); |
196 | 204 | ||
197 | DEBUGFS_FWSTATS_FILE(event, heart_beat, 20, "%u"); | 205 | DEBUGFS_FWSTATS_FILE(event, heart_beat, "%u"); |
198 | DEBUGFS_FWSTATS_FILE(event, calibration, 20, "%u"); | 206 | DEBUGFS_FWSTATS_FILE(event, calibration, "%u"); |
199 | DEBUGFS_FWSTATS_FILE(event, rx_mismatch, 20, "%u"); | 207 | DEBUGFS_FWSTATS_FILE(event, rx_mismatch, "%u"); |
200 | DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, 20, "%u"); | 208 | DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, "%u"); |
201 | DEBUGFS_FWSTATS_FILE(event, rx_pool, 20, "%u"); | 209 | DEBUGFS_FWSTATS_FILE(event, rx_pool, "%u"); |
202 | DEBUGFS_FWSTATS_FILE(event, oom_late, 20, "%u"); | 210 | DEBUGFS_FWSTATS_FILE(event, oom_late, "%u"); |
203 | DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, 20, "%u"); | 211 | DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, "%u"); |
204 | DEBUGFS_FWSTATS_FILE(event, tx_stuck, 20, "%u"); | 212 | DEBUGFS_FWSTATS_FILE(event, tx_stuck, "%u"); |
205 | 213 | ||
206 | DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, 20, "%u"); | 214 | DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, "%u"); |
207 | DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, 20, "%u"); | 215 | DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, "%u"); |
208 | DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, 20, "%u"); | 216 | DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, "%u"); |
209 | DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, 20, "%u"); | 217 | DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, "%u"); |
210 | DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, 20, "%u"); | 218 | DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, "%u"); |
211 | DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, 20, "%u"); | 219 | DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, "%u"); |
212 | DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, 20, "%u"); | 220 | DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, "%u"); |
213 | 221 | ||
214 | DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, 20, "%u"); | 222 | DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, "%u"); |
215 | DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, 20, "%u"); | 223 | DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, "%u"); |
216 | DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data, | 224 | DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data, "%u"); |
217 | 20, "%u"); | 225 | DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, "%u"); |
218 | DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, 20, "%u"); | 226 | DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, "%u"); |
219 | DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, 20, "%u"); | 227 | |
220 | 228 | DEBUGFS_READONLY_FILE(retry_count, "%u", wl->stats.retry_count); | |
221 | DEBUGFS_READONLY_FILE(retry_count, 20, "%u", wl->stats.retry_count); | 229 | DEBUGFS_READONLY_FILE(excessive_retries, "%u", |
222 | DEBUGFS_READONLY_FILE(excessive_retries, 20, "%u", | ||
223 | wl->stats.excessive_retries); | 230 | wl->stats.excessive_retries); |
224 | 231 | ||
225 | static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, | 232 | static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, |
diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c index 7b3f50382963..38ccef7d73a5 100644 --- a/drivers/net/wireless/wl12xx/wl1271_event.c +++ b/drivers/net/wireless/wl12xx/wl1271_event.c | |||
@@ -134,8 +134,6 @@ static int wl1271_event_ps_report(struct wl1271 *wl, | |||
134 | 134 | ||
135 | /* go to extremely low power mode */ | 135 | /* go to extremely low power mode */ |
136 | wl1271_ps_elp_sleep(wl); | 136 | wl1271_ps_elp_sleep(wl); |
137 | if (ret < 0) | ||
138 | break; | ||
139 | break; | 137 | break; |
140 | case EVENT_EXIT_POWER_SAVE_FAIL: | 138 | case EVENT_EXIT_POWER_SAVE_FAIL: |
141 | wl1271_debug(DEBUG_PSM, "PSM exit failed"); | 139 | wl1271_debug(DEBUG_PSM, "PSM exit failed"); |
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 48a4b9961ae6..f5b1d19bc88d 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c | |||
@@ -481,9 +481,9 @@ static void wl1271_fw_status(struct wl1271 *wl, | |||
481 | total += cnt; | 481 | total += cnt; |
482 | } | 482 | } |
483 | 483 | ||
484 | /* if more blocks are available now, schedule some tx work */ | 484 | /* if more blocks are available now, tx work can be scheduled */ |
485 | if (total && !skb_queue_empty(&wl->tx_queue)) | 485 | if (total) |
486 | ieee80211_queue_work(wl->hw, &wl->tx_work); | 486 | clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); |
487 | 487 | ||
488 | /* update the host-chipset time offset */ | 488 | /* update the host-chipset time offset */ |
489 | getnstimeofday(&ts); | 489 | getnstimeofday(&ts); |
@@ -529,6 +529,15 @@ static void wl1271_irq_work(struct work_struct *work) | |||
529 | 529 | ||
530 | intr &= WL1271_INTR_MASK; | 530 | intr &= WL1271_INTR_MASK; |
531 | 531 | ||
532 | if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) { | ||
533 | wl1271_error("watchdog interrupt received! " | ||
534 | "starting recovery."); | ||
535 | ieee80211_queue_work(wl->hw, &wl->recovery_work); | ||
536 | |||
537 | /* restarting the chip. ignore any other interrupt. */ | ||
538 | goto out; | ||
539 | } | ||
540 | |||
532 | if (intr & WL1271_ACX_INTR_DATA) { | 541 | if (intr & WL1271_ACX_INTR_DATA) { |
533 | wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA"); | 542 | wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA"); |
534 | 543 | ||
@@ -537,6 +546,16 @@ static void wl1271_irq_work(struct work_struct *work) | |||
537 | (wl->tx_results_count & 0xff)) | 546 | (wl->tx_results_count & 0xff)) |
538 | wl1271_tx_complete(wl); | 547 | wl1271_tx_complete(wl); |
539 | 548 | ||
549 | /* Check if any tx blocks were freed */ | ||
550 | if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) && | ||
551 | !skb_queue_empty(&wl->tx_queue)) { | ||
552 | /* | ||
553 | * In order to avoid starvation of the TX path, | ||
554 | * call the work function directly. | ||
555 | */ | ||
556 | wl1271_tx_work_locked(wl); | ||
557 | } | ||
558 | |||
540 | wl1271_rx(wl, wl->fw_status); | 559 | wl1271_rx(wl, wl->fw_status); |
541 | } | 560 | } |
542 | 561 | ||
@@ -851,12 +870,32 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
851 | struct ieee80211_sta *sta = txinfo->control.sta; | 870 | struct ieee80211_sta *sta = txinfo->control.sta; |
852 | unsigned long flags; | 871 | unsigned long flags; |
853 | 872 | ||
854 | /* peek into the rates configured in the STA entry */ | 873 | /* |
874 | * peek into the rates configured in the STA entry. | ||
875 | * The rates set after connection stage, The first block only BG sets: | ||
876 | * the compare is for bit 0-16 of sta_rate_set. The second block add | ||
877 | * HT rates in case of HT supported. | ||
878 | */ | ||
855 | spin_lock_irqsave(&wl->wl_lock, flags); | 879 | spin_lock_irqsave(&wl->wl_lock, flags); |
856 | if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) { | 880 | if (sta && |
881 | (sta->supp_rates[conf->channel->band] != | ||
882 | (wl->sta_rate_set & HW_BG_RATES_MASK))) { | ||
857 | wl->sta_rate_set = sta->supp_rates[conf->channel->band]; | 883 | wl->sta_rate_set = sta->supp_rates[conf->channel->band]; |
858 | set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags); | 884 | set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags); |
859 | } | 885 | } |
886 | |||
887 | #ifdef CONFIG_WL1271_HT | ||
888 | if (sta && | ||
889 | sta->ht_cap.ht_supported && | ||
890 | ((wl->sta_rate_set >> HW_HT_RATES_OFFSET) != | ||
891 | sta->ht_cap.mcs.rx_mask[0])) { | ||
892 | /* Clean MCS bits before setting them */ | ||
893 | wl->sta_rate_set &= HW_BG_RATES_MASK; | ||
894 | wl->sta_rate_set |= | ||
895 | (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET); | ||
896 | set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags); | ||
897 | } | ||
898 | #endif | ||
860 | spin_unlock_irqrestore(&wl->wl_lock, flags); | 899 | spin_unlock_irqrestore(&wl->wl_lock, flags); |
861 | 900 | ||
862 | /* queue the packet */ | 901 | /* queue the packet */ |
@@ -867,7 +906,8 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
867 | * before that, the tx_work will not be initialized! | 906 | * before that, the tx_work will not be initialized! |
868 | */ | 907 | */ |
869 | 908 | ||
870 | ieee80211_queue_work(wl->hw, &wl->tx_work); | 909 | if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags)) |
910 | ieee80211_queue_work(wl->hw, &wl->tx_work); | ||
871 | 911 | ||
872 | /* | 912 | /* |
873 | * The workqueue is slow to process the tx_queue and we need stop | 913 | * The workqueue is slow to process the tx_queue and we need stop |
@@ -919,18 +959,19 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, | |||
919 | struct wiphy *wiphy = hw->wiphy; | 959 | struct wiphy *wiphy = hw->wiphy; |
920 | int retries = WL1271_BOOT_RETRIES; | 960 | int retries = WL1271_BOOT_RETRIES; |
921 | int ret = 0; | 961 | int ret = 0; |
962 | bool booted = false; | ||
922 | 963 | ||
923 | wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", | 964 | wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", |
924 | vif->type, vif->addr); | 965 | vif->type, vif->addr); |
925 | 966 | ||
926 | mutex_lock(&wl->mutex); | 967 | mutex_lock(&wl->mutex); |
927 | if (wl->vif) { | 968 | if (wl->vif) { |
969 | wl1271_debug(DEBUG_MAC80211, | ||
970 | "multiple vifs are not supported yet"); | ||
928 | ret = -EBUSY; | 971 | ret = -EBUSY; |
929 | goto out; | 972 | goto out; |
930 | } | 973 | } |
931 | 974 | ||
932 | wl->vif = vif; | ||
933 | |||
934 | switch (vif->type) { | 975 | switch (vif->type) { |
935 | case NL80211_IFTYPE_STATION: | 976 | case NL80211_IFTYPE_STATION: |
936 | wl->bss_type = BSS_TYPE_STA_BSS; | 977 | wl->bss_type = BSS_TYPE_STA_BSS; |
@@ -968,15 +1009,8 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, | |||
968 | if (ret < 0) | 1009 | if (ret < 0) |
969 | goto irq_disable; | 1010 | goto irq_disable; |
970 | 1011 | ||
971 | wl->state = WL1271_STATE_ON; | 1012 | booted = true; |
972 | wl1271_info("firmware booted (%s)", wl->chip.fw_ver); | 1013 | break; |
973 | |||
974 | /* update hw/fw version info in wiphy struct */ | ||
975 | wiphy->hw_version = wl->chip.id; | ||
976 | strncpy(wiphy->fw_version, wl->chip.fw_ver, | ||
977 | sizeof(wiphy->fw_version)); | ||
978 | |||
979 | goto out; | ||
980 | 1014 | ||
981 | irq_disable: | 1015 | irq_disable: |
982 | wl1271_disable_interrupts(wl); | 1016 | wl1271_disable_interrupts(wl); |
@@ -994,8 +1028,21 @@ power_off: | |||
994 | wl1271_power_off(wl); | 1028 | wl1271_power_off(wl); |
995 | } | 1029 | } |
996 | 1030 | ||
997 | wl1271_error("firmware boot failed despite %d retries", | 1031 | if (!booted) { |
998 | WL1271_BOOT_RETRIES); | 1032 | wl1271_error("firmware boot failed despite %d retries", |
1033 | WL1271_BOOT_RETRIES); | ||
1034 | goto out; | ||
1035 | } | ||
1036 | |||
1037 | wl->vif = vif; | ||
1038 | wl->state = WL1271_STATE_ON; | ||
1039 | wl1271_info("firmware booted (%s)", wl->chip.fw_ver); | ||
1040 | |||
1041 | /* update hw/fw version info in wiphy struct */ | ||
1042 | wiphy->hw_version = wl->chip.id; | ||
1043 | strncpy(wiphy->fw_version, wl->chip.fw_ver, | ||
1044 | sizeof(wiphy->fw_version)); | ||
1045 | |||
999 | out: | 1046 | out: |
1000 | mutex_unlock(&wl->mutex); | 1047 | mutex_unlock(&wl->mutex); |
1001 | 1048 | ||
@@ -1025,6 +1072,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl) | |||
1025 | wl->scan.state = WL1271_SCAN_STATE_IDLE; | 1072 | wl->scan.state = WL1271_SCAN_STATE_IDLE; |
1026 | kfree(wl->scan.scanned_ch); | 1073 | kfree(wl->scan.scanned_ch); |
1027 | wl->scan.scanned_ch = NULL; | 1074 | wl->scan.scanned_ch = NULL; |
1075 | wl->scan.req = NULL; | ||
1028 | ieee80211_scan_completed(wl->hw, true); | 1076 | ieee80211_scan_completed(wl->hw, true); |
1029 | } | 1077 | } |
1030 | 1078 | ||
@@ -1312,8 +1360,10 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) | |||
1312 | 1360 | ||
1313 | mutex_lock(&wl->mutex); | 1361 | mutex_lock(&wl->mutex); |
1314 | 1362 | ||
1315 | if (unlikely(wl->state == WL1271_STATE_OFF)) | 1363 | if (unlikely(wl->state == WL1271_STATE_OFF)) { |
1364 | ret = -EAGAIN; | ||
1316 | goto out; | 1365 | goto out; |
1366 | } | ||
1317 | 1367 | ||
1318 | ret = wl1271_ps_elp_wakeup(wl, false); | 1368 | ret = wl1271_ps_elp_wakeup(wl, false); |
1319 | if (ret < 0) | 1369 | if (ret < 0) |
@@ -1536,6 +1586,11 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
1536 | 1586 | ||
1537 | mutex_lock(&wl->mutex); | 1587 | mutex_lock(&wl->mutex); |
1538 | 1588 | ||
1589 | if (unlikely(wl->state == WL1271_STATE_OFF)) { | ||
1590 | ret = -EAGAIN; | ||
1591 | goto out_unlock; | ||
1592 | } | ||
1593 | |||
1539 | ret = wl1271_ps_elp_wakeup(wl, false); | 1594 | ret = wl1271_ps_elp_wakeup(wl, false); |
1540 | if (ret < 0) | 1595 | if (ret < 0) |
1541 | goto out_unlock; | 1596 | goto out_unlock; |
@@ -1645,6 +1700,16 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw, | |||
1645 | 1700 | ||
1646 | mutex_lock(&wl->mutex); | 1701 | mutex_lock(&wl->mutex); |
1647 | 1702 | ||
1703 | if (wl->state == WL1271_STATE_OFF) { | ||
1704 | /* | ||
1705 | * We cannot return -EBUSY here because cfg80211 will expect | ||
1706 | * a call to ieee80211_scan_completed if we do - in this case | ||
1707 | * there won't be any call. | ||
1708 | */ | ||
1709 | ret = -EAGAIN; | ||
1710 | goto out; | ||
1711 | } | ||
1712 | |||
1648 | ret = wl1271_ps_elp_wakeup(wl, false); | 1713 | ret = wl1271_ps_elp_wakeup(wl, false); |
1649 | if (ret < 0) | 1714 | if (ret < 0) |
1650 | goto out; | 1715 | goto out; |
@@ -1666,8 +1731,10 @@ static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) | |||
1666 | 1731 | ||
1667 | mutex_lock(&wl->mutex); | 1732 | mutex_lock(&wl->mutex); |
1668 | 1733 | ||
1669 | if (unlikely(wl->state == WL1271_STATE_OFF)) | 1734 | if (unlikely(wl->state == WL1271_STATE_OFF)) { |
1735 | ret = -EAGAIN; | ||
1670 | goto out; | 1736 | goto out; |
1737 | } | ||
1671 | 1738 | ||
1672 | ret = wl1271_ps_elp_wakeup(wl, false); | 1739 | ret = wl1271_ps_elp_wakeup(wl, false); |
1673 | if (ret < 0) | 1740 | if (ret < 0) |
@@ -1709,6 +1776,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1709 | { | 1776 | { |
1710 | enum wl1271_cmd_ps_mode mode; | 1777 | enum wl1271_cmd_ps_mode mode; |
1711 | struct wl1271 *wl = hw->priv; | 1778 | struct wl1271 *wl = hw->priv; |
1779 | struct ieee80211_sta *sta = ieee80211_find_sta(vif, bss_conf->bssid); | ||
1712 | bool do_join = false; | 1780 | bool do_join = false; |
1713 | bool set_assoc = false; | 1781 | bool set_assoc = false; |
1714 | int ret; | 1782 | int ret; |
@@ -1717,6 +1785,9 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1717 | 1785 | ||
1718 | mutex_lock(&wl->mutex); | 1786 | mutex_lock(&wl->mutex); |
1719 | 1787 | ||
1788 | if (unlikely(wl->state == WL1271_STATE_OFF)) | ||
1789 | goto out; | ||
1790 | |||
1720 | ret = wl1271_ps_elp_wakeup(wl, false); | 1791 | ret = wl1271_ps_elp_wakeup(wl, false); |
1721 | if (ret < 0) | 1792 | if (ret < 0) |
1722 | goto out; | 1793 | goto out; |
@@ -1927,6 +1998,37 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1927 | } | 1998 | } |
1928 | } | 1999 | } |
1929 | 2000 | ||
2001 | /* | ||
2002 | * Takes care of: New association with HT enable, | ||
2003 | * HT information change in beacon. | ||
2004 | */ | ||
2005 | if (sta && | ||
2006 | (changed & BSS_CHANGED_HT) && | ||
2007 | (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { | ||
2008 | ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true); | ||
2009 | if (ret < 0) { | ||
2010 | wl1271_warning("Set ht cap true failed %d", ret); | ||
2011 | goto out_sleep; | ||
2012 | } | ||
2013 | ret = wl1271_acx_set_ht_information(wl, | ||
2014 | bss_conf->ht_operation_mode); | ||
2015 | if (ret < 0) { | ||
2016 | wl1271_warning("Set ht information failed %d", ret); | ||
2017 | goto out_sleep; | ||
2018 | } | ||
2019 | } | ||
2020 | /* | ||
2021 | * Takes care of: New association without HT, | ||
2022 | * Disassociation. | ||
2023 | */ | ||
2024 | else if (sta && (changed & BSS_CHANGED_ASSOC)) { | ||
2025 | ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, false); | ||
2026 | if (ret < 0) { | ||
2027 | wl1271_warning("Set ht cap false failed %d", ret); | ||
2028 | goto out_sleep; | ||
2029 | } | ||
2030 | } | ||
2031 | |||
1930 | if (changed & BSS_CHANGED_ARP_FILTER) { | 2032 | if (changed & BSS_CHANGED_ARP_FILTER) { |
1931 | __be32 addr = bss_conf->arp_addr_list[0]; | 2033 | __be32 addr = bss_conf->arp_addr_list[0]; |
1932 | WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS); | 2034 | WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS); |
@@ -1966,6 +2068,11 @@ static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue, | |||
1966 | 2068 | ||
1967 | wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue); | 2069 | wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue); |
1968 | 2070 | ||
2071 | if (unlikely(wl->state == WL1271_STATE_OFF)) { | ||
2072 | ret = -EAGAIN; | ||
2073 | goto out; | ||
2074 | } | ||
2075 | |||
1969 | ret = wl1271_ps_elp_wakeup(wl, false); | 2076 | ret = wl1271_ps_elp_wakeup(wl, false); |
1970 | if (ret < 0) | 2077 | if (ret < 0) |
1971 | goto out; | 2078 | goto out; |
@@ -2009,6 +2116,9 @@ static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw) | |||
2009 | 2116 | ||
2010 | mutex_lock(&wl->mutex); | 2117 | mutex_lock(&wl->mutex); |
2011 | 2118 | ||
2119 | if (unlikely(wl->state == WL1271_STATE_OFF)) | ||
2120 | goto out; | ||
2121 | |||
2012 | ret = wl1271_ps_elp_wakeup(wl, false); | 2122 | ret = wl1271_ps_elp_wakeup(wl, false); |
2013 | if (ret < 0) | 2123 | if (ret < 0) |
2014 | goto out; | 2124 | goto out; |
@@ -2030,14 +2140,14 @@ static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx, | |||
2030 | { | 2140 | { |
2031 | struct wl1271 *wl = hw->priv; | 2141 | struct wl1271 *wl = hw->priv; |
2032 | struct ieee80211_conf *conf = &hw->conf; | 2142 | struct ieee80211_conf *conf = &hw->conf; |
2033 | 2143 | ||
2034 | if (idx != 0) | 2144 | if (idx != 0) |
2035 | return -ENOENT; | 2145 | return -ENOENT; |
2036 | 2146 | ||
2037 | survey->channel = conf->channel; | 2147 | survey->channel = conf->channel; |
2038 | survey->filled = SURVEY_INFO_NOISE_DBM; | 2148 | survey->filled = SURVEY_INFO_NOISE_DBM; |
2039 | survey->noise = wl->noise; | 2149 | survey->noise = wl->noise; |
2040 | 2150 | ||
2041 | return 0; | 2151 | return 0; |
2042 | } | 2152 | } |
2043 | 2153 | ||
@@ -2107,14 +2217,14 @@ static struct ieee80211_channel wl1271_channels[] = { | |||
2107 | /* mapping to indexes for wl1271_rates */ | 2217 | /* mapping to indexes for wl1271_rates */ |
2108 | static const u8 wl1271_rate_to_idx_2ghz[] = { | 2218 | static const u8 wl1271_rate_to_idx_2ghz[] = { |
2109 | /* MCS rates are used only with 11n */ | 2219 | /* MCS rates are used only with 11n */ |
2110 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */ | 2220 | 7, /* CONF_HW_RXTX_RATE_MCS7 */ |
2111 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */ | 2221 | 6, /* CONF_HW_RXTX_RATE_MCS6 */ |
2112 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */ | 2222 | 5, /* CONF_HW_RXTX_RATE_MCS5 */ |
2113 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */ | 2223 | 4, /* CONF_HW_RXTX_RATE_MCS4 */ |
2114 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */ | 2224 | 3, /* CONF_HW_RXTX_RATE_MCS3 */ |
2115 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */ | 2225 | 2, /* CONF_HW_RXTX_RATE_MCS2 */ |
2116 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */ | 2226 | 1, /* CONF_HW_RXTX_RATE_MCS1 */ |
2117 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */ | 2227 | 0, /* CONF_HW_RXTX_RATE_MCS0 */ |
2118 | 2228 | ||
2119 | 11, /* CONF_HW_RXTX_RATE_54 */ | 2229 | 11, /* CONF_HW_RXTX_RATE_54 */ |
2120 | 10, /* CONF_HW_RXTX_RATE_48 */ | 2230 | 10, /* CONF_HW_RXTX_RATE_48 */ |
@@ -2134,12 +2244,34 @@ static const u8 wl1271_rate_to_idx_2ghz[] = { | |||
2134 | 0 /* CONF_HW_RXTX_RATE_1 */ | 2244 | 0 /* CONF_HW_RXTX_RATE_1 */ |
2135 | }; | 2245 | }; |
2136 | 2246 | ||
2247 | /* 11n STA capabilities */ | ||
2248 | #define HW_RX_HIGHEST_RATE 72 | ||
2249 | |||
2250 | #ifdef CONFIG_WL1271_HT | ||
2251 | #define WL1271_HT_CAP { \ | ||
2252 | .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \ | ||
2253 | .ht_supported = true, \ | ||
2254 | .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \ | ||
2255 | .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \ | ||
2256 | .mcs = { \ | ||
2257 | .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \ | ||
2258 | .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \ | ||
2259 | .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \ | ||
2260 | }, \ | ||
2261 | } | ||
2262 | #else | ||
2263 | #define WL1271_HT_CAP { \ | ||
2264 | .ht_supported = false, \ | ||
2265 | } | ||
2266 | #endif | ||
2267 | |||
2137 | /* can't be const, mac80211 writes to this */ | 2268 | /* can't be const, mac80211 writes to this */ |
2138 | static struct ieee80211_supported_band wl1271_band_2ghz = { | 2269 | static struct ieee80211_supported_band wl1271_band_2ghz = { |
2139 | .channels = wl1271_channels, | 2270 | .channels = wl1271_channels, |
2140 | .n_channels = ARRAY_SIZE(wl1271_channels), | 2271 | .n_channels = ARRAY_SIZE(wl1271_channels), |
2141 | .bitrates = wl1271_rates, | 2272 | .bitrates = wl1271_rates, |
2142 | .n_bitrates = ARRAY_SIZE(wl1271_rates), | 2273 | .n_bitrates = ARRAY_SIZE(wl1271_rates), |
2274 | .ht_cap = WL1271_HT_CAP, | ||
2143 | }; | 2275 | }; |
2144 | 2276 | ||
2145 | /* 5 GHz data rates for WL1273 */ | 2277 | /* 5 GHz data rates for WL1273 */ |
@@ -2222,14 +2354,14 @@ static struct ieee80211_channel wl1271_channels_5ghz[] = { | |||
2222 | /* mapping to indexes for wl1271_rates_5ghz */ | 2354 | /* mapping to indexes for wl1271_rates_5ghz */ |
2223 | static const u8 wl1271_rate_to_idx_5ghz[] = { | 2355 | static const u8 wl1271_rate_to_idx_5ghz[] = { |
2224 | /* MCS rates are used only with 11n */ | 2356 | /* MCS rates are used only with 11n */ |
2225 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */ | 2357 | 7, /* CONF_HW_RXTX_RATE_MCS7 */ |
2226 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */ | 2358 | 6, /* CONF_HW_RXTX_RATE_MCS6 */ |
2227 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */ | 2359 | 5, /* CONF_HW_RXTX_RATE_MCS5 */ |
2228 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */ | 2360 | 4, /* CONF_HW_RXTX_RATE_MCS4 */ |
2229 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */ | 2361 | 3, /* CONF_HW_RXTX_RATE_MCS3 */ |
2230 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */ | 2362 | 2, /* CONF_HW_RXTX_RATE_MCS2 */ |
2231 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */ | 2363 | 1, /* CONF_HW_RXTX_RATE_MCS1 */ |
2232 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */ | 2364 | 0, /* CONF_HW_RXTX_RATE_MCS0 */ |
2233 | 2365 | ||
2234 | 7, /* CONF_HW_RXTX_RATE_54 */ | 2366 | 7, /* CONF_HW_RXTX_RATE_54 */ |
2235 | 6, /* CONF_HW_RXTX_RATE_48 */ | 2367 | 6, /* CONF_HW_RXTX_RATE_48 */ |
@@ -2254,6 +2386,7 @@ static struct ieee80211_supported_band wl1271_band_5ghz = { | |||
2254 | .n_channels = ARRAY_SIZE(wl1271_channels_5ghz), | 2386 | .n_channels = ARRAY_SIZE(wl1271_channels_5ghz), |
2255 | .bitrates = wl1271_rates_5ghz, | 2387 | .bitrates = wl1271_rates_5ghz, |
2256 | .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz), | 2388 | .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz), |
2389 | .ht_cap = WL1271_HT_CAP, | ||
2257 | }; | 2390 | }; |
2258 | 2391 | ||
2259 | static const u8 *wl1271_band_rate_to_idx[] = { | 2392 | static const u8 *wl1271_band_rate_to_idx[] = { |
@@ -2281,18 +2414,18 @@ static const struct ieee80211_ops wl1271_ops = { | |||
2281 | }; | 2414 | }; |
2282 | 2415 | ||
2283 | 2416 | ||
2284 | u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate) | 2417 | u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band) |
2285 | { | 2418 | { |
2286 | u8 idx; | 2419 | u8 idx; |
2287 | 2420 | ||
2288 | BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *)); | 2421 | BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *)); |
2289 | 2422 | ||
2290 | if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) { | 2423 | if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) { |
2291 | wl1271_error("Illegal RX rate from HW: %d", rate); | 2424 | wl1271_error("Illegal RX rate from HW: %d", rate); |
2292 | return 0; | 2425 | return 0; |
2293 | } | 2426 | } |
2294 | 2427 | ||
2295 | idx = wl1271_band_rate_to_idx[wl->band][rate]; | 2428 | idx = wl1271_band_rate_to_idx[band][rate]; |
2296 | if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) { | 2429 | if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) { |
2297 | wl1271_error("Unsupported RX rate from HW: %d", rate); | 2430 | wl1271_error("Unsupported RX rate from HW: %d", rate); |
2298 | return 0; | 2431 | return 0; |
@@ -2521,6 +2654,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void) | |||
2521 | wl->sg_enabled = true; | 2654 | wl->sg_enabled = true; |
2522 | wl->hw_pg_ver = -1; | 2655 | wl->hw_pg_ver = -1; |
2523 | 2656 | ||
2657 | memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map)); | ||
2524 | for (i = 0; i < ACX_TX_DESCRIPTORS; i++) | 2658 | for (i = 0; i < ACX_TX_DESCRIPTORS; i++) |
2525 | wl->tx_frames[i] = NULL; | 2659 | wl->tx_frames[i] = NULL; |
2526 | 2660 | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c index bea133b6e489..cacfee56a0d0 100644 --- a/drivers/net/wireless/wl12xx/wl1271_rx.c +++ b/drivers/net/wireless/wl12xx/wl1271_rx.c | |||
@@ -48,10 +48,24 @@ static void wl1271_rx_status(struct wl1271 *wl, | |||
48 | struct ieee80211_rx_status *status, | 48 | struct ieee80211_rx_status *status, |
49 | u8 beacon) | 49 | u8 beacon) |
50 | { | 50 | { |
51 | enum ieee80211_band desc_band; | ||
52 | |||
51 | memset(status, 0, sizeof(struct ieee80211_rx_status)); | 53 | memset(status, 0, sizeof(struct ieee80211_rx_status)); |
52 | 54 | ||
53 | status->band = wl->band; | 55 | status->band = wl->band; |
54 | status->rate_idx = wl1271_rate_to_idx(wl, desc->rate); | 56 | |
57 | if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG) | ||
58 | desc_band = IEEE80211_BAND_2GHZ; | ||
59 | else | ||
60 | desc_band = IEEE80211_BAND_5GHZ; | ||
61 | |||
62 | status->rate_idx = wl1271_rate_to_idx(desc->rate, desc_band); | ||
63 | |||
64 | #ifdef CONFIG_WL1271_HT | ||
65 | /* 11n support */ | ||
66 | if (desc->rate <= CONF_HW_RXTX_RATE_MCS0) | ||
67 | status->flag |= RX_FLAG_HT; | ||
68 | #endif | ||
55 | 69 | ||
56 | status->signal = desc->rssi; | 70 | status->signal = desc->rssi; |
57 | 71 | ||
@@ -170,10 +184,14 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status) | |||
170 | while (pkt_offset < buf_size) { | 184 | while (pkt_offset < buf_size) { |
171 | pkt_length = wl1271_rx_get_buf_size(status, | 185 | pkt_length = wl1271_rx_get_buf_size(status, |
172 | drv_rx_counter); | 186 | drv_rx_counter); |
173 | if (wl1271_rx_handle_data(wl, | 187 | /* |
174 | wl->aggr_buf + pkt_offset, | 188 | * the handle data call can only fail in memory-outage |
175 | pkt_length) < 0) | 189 | * conditions, in that case the received frame will just |
176 | break; | 190 | * be dropped. |
191 | */ | ||
192 | wl1271_rx_handle_data(wl, | ||
193 | wl->aggr_buf + pkt_offset, | ||
194 | pkt_length); | ||
177 | wl->rx_counter++; | 195 | wl->rx_counter++; |
178 | drv_rx_counter++; | 196 | drv_rx_counter++; |
179 | drv_rx_counter &= NUM_RX_PKT_DESC_MOD_MASK; | 197 | drv_rx_counter &= NUM_RX_PKT_DESC_MOD_MASK; |
diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.h b/drivers/net/wireless/wl12xx/wl1271_rx.h index 13a232333b13..6d41981ce53f 100644 --- a/drivers/net/wireless/wl12xx/wl1271_rx.h +++ b/drivers/net/wireless/wl12xx/wl1271_rx.h | |||
@@ -116,6 +116,6 @@ struct wl1271_rx_descriptor { | |||
116 | } __packed; | 116 | } __packed; |
117 | 117 | ||
118 | void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status); | 118 | void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status); |
119 | u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate); | 119 | u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); |
120 | 120 | ||
121 | #endif | 121 | #endif |
diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.c b/drivers/net/wireless/wl12xx/wl1271_scan.c index 909bb47995b6..e0661a543a35 100644 --- a/drivers/net/wireless/wl12xx/wl1271_scan.c +++ b/drivers/net/wireless/wl12xx/wl1271_scan.c | |||
@@ -48,14 +48,15 @@ void wl1271_scan_complete_work(struct work_struct *work) | |||
48 | wl->scan.state = WL1271_SCAN_STATE_IDLE; | 48 | wl->scan.state = WL1271_SCAN_STATE_IDLE; |
49 | kfree(wl->scan.scanned_ch); | 49 | kfree(wl->scan.scanned_ch); |
50 | wl->scan.scanned_ch = NULL; | 50 | wl->scan.scanned_ch = NULL; |
51 | mutex_unlock(&wl->mutex); | 51 | wl->scan.req = NULL; |
52 | |||
53 | ieee80211_scan_completed(wl->hw, false); | 52 | ieee80211_scan_completed(wl->hw, false); |
54 | 53 | ||
55 | if (wl->scan.failed) { | 54 | if (wl->scan.failed) { |
56 | wl1271_info("Scan completed due to error."); | 55 | wl1271_info("Scan completed due to error."); |
57 | ieee80211_queue_work(wl->hw, &wl->recovery_work); | 56 | ieee80211_queue_work(wl->hw, &wl->recovery_work); |
58 | } | 57 | } |
58 | mutex_unlock(&wl->mutex); | ||
59 | |||
59 | } | 60 | } |
60 | 61 | ||
61 | 62 | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_testmode.c b/drivers/net/wireless/wl12xx/wl1271_testmode.c index a3aa84386c88..55ec4428922b 100644 --- a/drivers/net/wireless/wl12xx/wl1271_testmode.c +++ b/drivers/net/wireless/wl12xx/wl1271_testmode.c | |||
@@ -37,6 +37,7 @@ enum wl1271_tm_commands { | |||
37 | WL1271_TM_CMD_CONFIGURE, | 37 | WL1271_TM_CMD_CONFIGURE, |
38 | WL1271_TM_CMD_NVS_PUSH, | 38 | WL1271_TM_CMD_NVS_PUSH, |
39 | WL1271_TM_CMD_SET_PLT_MODE, | 39 | WL1271_TM_CMD_SET_PLT_MODE, |
40 | WL1271_TM_CMD_RECOVER, | ||
40 | 41 | ||
41 | __WL1271_TM_CMD_AFTER_LAST | 42 | __WL1271_TM_CMD_AFTER_LAST |
42 | }; | 43 | }; |
@@ -248,6 +249,15 @@ static int wl1271_tm_cmd_set_plt_mode(struct wl1271 *wl, struct nlattr *tb[]) | |||
248 | return ret; | 249 | return ret; |
249 | } | 250 | } |
250 | 251 | ||
252 | static int wl1271_tm_cmd_recover(struct wl1271 *wl, struct nlattr *tb[]) | ||
253 | { | ||
254 | wl1271_debug(DEBUG_TESTMODE, "testmode cmd recover"); | ||
255 | |||
256 | ieee80211_queue_work(wl->hw, &wl->recovery_work); | ||
257 | |||
258 | return 0; | ||
259 | } | ||
260 | |||
251 | int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len) | 261 | int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len) |
252 | { | 262 | { |
253 | struct wl1271 *wl = hw->priv; | 263 | struct wl1271 *wl = hw->priv; |
@@ -272,6 +282,8 @@ int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len) | |||
272 | return wl1271_tm_cmd_nvs_push(wl, tb); | 282 | return wl1271_tm_cmd_nvs_push(wl, tb); |
273 | case WL1271_TM_CMD_SET_PLT_MODE: | 283 | case WL1271_TM_CMD_SET_PLT_MODE: |
274 | return wl1271_tm_cmd_set_plt_mode(wl, tb); | 284 | return wl1271_tm_cmd_set_plt_mode(wl, tb); |
285 | case WL1271_TM_CMD_RECOVER: | ||
286 | return wl1271_tm_cmd_recover(wl, tb); | ||
275 | default: | 287 | default: |
276 | return -EOPNOTSUPP; | 288 | return -EOPNOTSUPP; |
277 | } | 289 | } |
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c index e3dc13c4d01a..279be5b98d9f 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.c +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c | |||
@@ -30,17 +30,26 @@ | |||
30 | #include "wl1271_ps.h" | 30 | #include "wl1271_ps.h" |
31 | #include "wl1271_tx.h" | 31 | #include "wl1271_tx.h" |
32 | 32 | ||
33 | static int wl1271_tx_id(struct wl1271 *wl, struct sk_buff *skb) | 33 | static int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb) |
34 | { | 34 | { |
35 | int i; | 35 | int id; |
36 | for (i = 0; i < ACX_TX_DESCRIPTORS; i++) | 36 | |
37 | if (wl->tx_frames[i] == NULL) { | 37 | id = find_first_zero_bit(wl->tx_frames_map, ACX_TX_DESCRIPTORS); |
38 | wl->tx_frames[i] = skb; | 38 | if (id >= ACX_TX_DESCRIPTORS) |
39 | wl->tx_frames_cnt++; | 39 | return -EBUSY; |
40 | return i; | 40 | |
41 | } | 41 | __set_bit(id, wl->tx_frames_map); |
42 | wl->tx_frames[id] = skb; | ||
43 | wl->tx_frames_cnt++; | ||
44 | return id; | ||
45 | } | ||
42 | 46 | ||
43 | return -EBUSY; | 47 | static void wl1271_free_tx_id(struct wl1271 *wl, int id) |
48 | { | ||
49 | if (__test_and_clear_bit(id, wl->tx_frames_map)) { | ||
50 | wl->tx_frames[id] = NULL; | ||
51 | wl->tx_frames_cnt--; | ||
52 | } | ||
44 | } | 53 | } |
45 | 54 | ||
46 | static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, | 55 | static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, |
@@ -52,10 +61,10 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, | |||
52 | int id, ret = -EBUSY; | 61 | int id, ret = -EBUSY; |
53 | 62 | ||
54 | if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE) | 63 | if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE) |
55 | return -EBUSY; | 64 | return -EAGAIN; |
56 | 65 | ||
57 | /* allocate free identifier for the packet */ | 66 | /* allocate free identifier for the packet */ |
58 | id = wl1271_tx_id(wl, skb); | 67 | id = wl1271_alloc_tx_id(wl, skb); |
59 | if (id < 0) | 68 | if (id < 0) |
60 | return id; | 69 | return id; |
61 | 70 | ||
@@ -79,8 +88,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, | |||
79 | "tx_allocate: size: %d, blocks: %d, id: %d", | 88 | "tx_allocate: size: %d, blocks: %d, id: %d", |
80 | total_len, total_blocks, id); | 89 | total_len, total_blocks, id); |
81 | } else { | 90 | } else { |
82 | wl->tx_frames[id] = NULL; | 91 | wl1271_free_tx_id(wl, id); |
83 | wl->tx_frames_cnt--; | ||
84 | } | 92 | } |
85 | 93 | ||
86 | return ret; | 94 | return ret; |
@@ -201,41 +209,67 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) | |||
201 | rate_set >>= 1; | 209 | rate_set >>= 1; |
202 | } | 210 | } |
203 | 211 | ||
212 | #ifdef CONFIG_WL1271_HT | ||
213 | /* MCS rates indication are on bits 16 - 23 */ | ||
214 | rate_set >>= HW_HT_RATES_OFFSET - band->n_bitrates; | ||
215 | |||
216 | for (bit = 0; bit < 8; bit++) { | ||
217 | if (rate_set & 0x1) | ||
218 | enabled_rates |= (CONF_HW_BIT_RATE_MCS_0 << bit); | ||
219 | rate_set >>= 1; | ||
220 | } | ||
221 | #endif | ||
222 | |||
204 | return enabled_rates; | 223 | return enabled_rates; |
205 | } | 224 | } |
206 | 225 | ||
207 | void wl1271_tx_work(struct work_struct *work) | 226 | static void handle_tx_low_watermark(struct wl1271 *wl) |
227 | { | ||
228 | unsigned long flags; | ||
229 | |||
230 | if (test_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags) && | ||
231 | skb_queue_len(&wl->tx_queue) <= WL1271_TX_QUEUE_LOW_WATERMARK) { | ||
232 | /* firmware buffer has space, restart queues */ | ||
233 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
234 | ieee80211_wake_queues(wl->hw); | ||
235 | clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags); | ||
236 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
237 | } | ||
238 | } | ||
239 | |||
240 | void wl1271_tx_work_locked(struct wl1271 *wl) | ||
208 | { | 241 | { |
209 | struct wl1271 *wl = container_of(work, struct wl1271, tx_work); | ||
210 | struct sk_buff *skb; | 242 | struct sk_buff *skb; |
211 | bool woken_up = false; | 243 | bool woken_up = false; |
212 | u32 sta_rates = 0; | 244 | u32 sta_rates = 0; |
213 | u32 buf_offset; | 245 | u32 buf_offset = 0; |
246 | bool sent_packets = false; | ||
214 | int ret; | 247 | int ret; |
215 | 248 | ||
216 | /* check if the rates supported by the AP have changed */ | 249 | /* check if the rates supported by the AP have changed */ |
217 | if (unlikely(test_and_clear_bit(WL1271_FLAG_STA_RATES_CHANGED, | 250 | if (unlikely(test_and_clear_bit(WL1271_FLAG_STA_RATES_CHANGED, |
218 | &wl->flags))) { | 251 | &wl->flags))) { |
219 | unsigned long flags; | 252 | unsigned long flags; |
253 | |||
220 | spin_lock_irqsave(&wl->wl_lock, flags); | 254 | spin_lock_irqsave(&wl->wl_lock, flags); |
221 | sta_rates = wl->sta_rate_set; | 255 | sta_rates = wl->sta_rate_set; |
222 | spin_unlock_irqrestore(&wl->wl_lock, flags); | 256 | spin_unlock_irqrestore(&wl->wl_lock, flags); |
223 | } | 257 | } |
224 | 258 | ||
225 | mutex_lock(&wl->mutex); | ||
226 | |||
227 | if (unlikely(wl->state == WL1271_STATE_OFF)) | 259 | if (unlikely(wl->state == WL1271_STATE_OFF)) |
228 | goto out; | 260 | goto out; |
229 | 261 | ||
230 | /* if rates have changed, re-configure the rate policy */ | 262 | /* if rates have changed, re-configure the rate policy */ |
231 | if (unlikely(sta_rates)) { | 263 | if (unlikely(sta_rates)) { |
264 | ret = wl1271_ps_elp_wakeup(wl, false); | ||
265 | if (ret < 0) | ||
266 | goto out; | ||
267 | woken_up = true; | ||
268 | |||
232 | wl->rate_set = wl1271_tx_enabled_rates_get(wl, sta_rates); | 269 | wl->rate_set = wl1271_tx_enabled_rates_get(wl, sta_rates); |
233 | wl1271_acx_rate_policies(wl); | 270 | wl1271_acx_rate_policies(wl); |
234 | } | 271 | } |
235 | 272 | ||
236 | /* Prepare the transfer buffer, by aggregating all | ||
237 | * available packets */ | ||
238 | buf_offset = 0; | ||
239 | while ((skb = skb_dequeue(&wl->tx_queue))) { | 273 | while ((skb = skb_dequeue(&wl->tx_queue))) { |
240 | if (!woken_up) { | 274 | if (!woken_up) { |
241 | ret = wl1271_ps_elp_wakeup(wl, false); | 275 | ret = wl1271_ps_elp_wakeup(wl, false); |
@@ -245,13 +279,25 @@ void wl1271_tx_work(struct work_struct *work) | |||
245 | } | 279 | } |
246 | 280 | ||
247 | ret = wl1271_prepare_tx_frame(wl, skb, buf_offset); | 281 | ret = wl1271_prepare_tx_frame(wl, skb, buf_offset); |
248 | if (ret == -EBUSY) { | 282 | if (ret == -EAGAIN) { |
283 | /* | ||
284 | * Aggregation buffer is full. | ||
285 | * Flush buffer and try again. | ||
286 | */ | ||
287 | skb_queue_head(&wl->tx_queue, skb); | ||
288 | wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, | ||
289 | buf_offset, true); | ||
290 | sent_packets = true; | ||
291 | buf_offset = 0; | ||
292 | continue; | ||
293 | } else if (ret == -EBUSY) { | ||
249 | /* | 294 | /* |
250 | * Either the firmware buffer is full, or the | 295 | * Firmware buffer is full. |
251 | * aggregation buffer is. | ||
252 | * Queue back last skb, and stop aggregating. | 296 | * Queue back last skb, and stop aggregating. |
253 | */ | 297 | */ |
254 | skb_queue_head(&wl->tx_queue, skb); | 298 | skb_queue_head(&wl->tx_queue, skb); |
299 | /* No work left, avoid scheduling redundant tx work */ | ||
300 | set_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); | ||
255 | goto out_ack; | 301 | goto out_ack; |
256 | } else if (ret < 0) { | 302 | } else if (ret < 0) { |
257 | dev_kfree_skb(skb); | 303 | dev_kfree_skb(skb); |
@@ -265,14 +311,25 @@ out_ack: | |||
265 | if (buf_offset) { | 311 | if (buf_offset) { |
266 | wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, | 312 | wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, |
267 | buf_offset, true); | 313 | buf_offset, true); |
314 | sent_packets = true; | ||
315 | } | ||
316 | if (sent_packets) { | ||
268 | /* interrupt the firmware with the new packets */ | 317 | /* interrupt the firmware with the new packets */ |
269 | wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count); | 318 | wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count); |
319 | handle_tx_low_watermark(wl); | ||
270 | } | 320 | } |
271 | 321 | ||
272 | out: | 322 | out: |
273 | if (woken_up) | 323 | if (woken_up) |
274 | wl1271_ps_elp_sleep(wl); | 324 | wl1271_ps_elp_sleep(wl); |
325 | } | ||
326 | |||
327 | void wl1271_tx_work(struct work_struct *work) | ||
328 | { | ||
329 | struct wl1271 *wl = container_of(work, struct wl1271, tx_work); | ||
275 | 330 | ||
331 | mutex_lock(&wl->mutex); | ||
332 | wl1271_tx_work_locked(wl); | ||
276 | mutex_unlock(&wl->mutex); | 333 | mutex_unlock(&wl->mutex); |
277 | } | 334 | } |
278 | 335 | ||
@@ -298,7 +355,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, | |||
298 | if (result->status == TX_SUCCESS) { | 355 | if (result->status == TX_SUCCESS) { |
299 | if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) | 356 | if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) |
300 | info->flags |= IEEE80211_TX_STAT_ACK; | 357 | info->flags |= IEEE80211_TX_STAT_ACK; |
301 | rate = wl1271_rate_to_idx(wl, result->rate_class_index); | 358 | rate = wl1271_rate_to_idx(result->rate_class_index, wl->band); |
302 | retries = result->ack_failures; | 359 | retries = result->ack_failures; |
303 | } else if (result->status == TX_RETRY_EXCEEDED) { | 360 | } else if (result->status == TX_RETRY_EXCEEDED) { |
304 | wl->stats.excessive_retries++; | 361 | wl->stats.excessive_retries++; |
@@ -335,8 +392,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, | |||
335 | 392 | ||
336 | /* return the packet to the stack */ | 393 | /* return the packet to the stack */ |
337 | ieee80211_tx_status(wl->hw, skb); | 394 | ieee80211_tx_status(wl->hw, skb); |
338 | wl->tx_frames[result->id] = NULL; | 395 | wl1271_free_tx_id(wl, result->id); |
339 | wl->tx_frames_cnt--; | ||
340 | } | 396 | } |
341 | 397 | ||
342 | /* Called upon reception of a TX complete interrupt */ | 398 | /* Called upon reception of a TX complete interrupt */ |
@@ -375,19 +431,6 @@ void wl1271_tx_complete(struct wl1271 *wl) | |||
375 | 431 | ||
376 | wl->tx_results_count++; | 432 | wl->tx_results_count++; |
377 | } | 433 | } |
378 | |||
379 | if (test_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags) && | ||
380 | skb_queue_len(&wl->tx_queue) <= WL1271_TX_QUEUE_LOW_WATERMARK) { | ||
381 | unsigned long flags; | ||
382 | |||
383 | /* firmware buffer has space, restart queues */ | ||
384 | wl1271_debug(DEBUG_TX, "tx_complete: waking queues"); | ||
385 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
386 | ieee80211_wake_queues(wl->hw); | ||
387 | clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags); | ||
388 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
389 | ieee80211_queue_work(wl->hw, &wl->tx_work); | ||
390 | } | ||
391 | } | 434 | } |
392 | 435 | ||
393 | /* caller must hold wl->mutex */ | 436 | /* caller must hold wl->mutex */ |
@@ -402,14 +445,19 @@ void wl1271_tx_reset(struct wl1271 *wl) | |||
402 | ieee80211_tx_status(wl->hw, skb); | 445 | ieee80211_tx_status(wl->hw, skb); |
403 | } | 446 | } |
404 | 447 | ||
448 | /* | ||
449 | * Make sure the driver is at a consistent state, in case this | ||
450 | * function is called from a context other than interface removal. | ||
451 | */ | ||
452 | handle_tx_low_watermark(wl); | ||
453 | |||
405 | for (i = 0; i < ACX_TX_DESCRIPTORS; i++) | 454 | for (i = 0; i < ACX_TX_DESCRIPTORS; i++) |
406 | if (wl->tx_frames[i] != NULL) { | 455 | if (wl->tx_frames[i] != NULL) { |
407 | skb = wl->tx_frames[i]; | 456 | skb = wl->tx_frames[i]; |
408 | wl->tx_frames[i] = NULL; | 457 | wl1271_free_tx_id(wl, i); |
409 | wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); | 458 | wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); |
410 | ieee80211_tx_status(wl->hw, skb); | 459 | ieee80211_tx_status(wl->hw, skb); |
411 | } | 460 | } |
412 | wl->tx_frames_cnt = 0; | ||
413 | } | 461 | } |
414 | 462 | ||
415 | #define WL1271_TX_FLUSH_TIMEOUT 500000 | 463 | #define WL1271_TX_FLUSH_TIMEOUT 500000 |
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.h b/drivers/net/wireless/wl12xx/wl1271_tx.h index d12a129ad11c..9dc6f228c0de 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.h +++ b/drivers/net/wireless/wl12xx/wl1271_tx.h | |||
@@ -140,10 +140,11 @@ static inline int wl1271_tx_get_queue(int queue) | |||
140 | } | 140 | } |
141 | 141 | ||
142 | void wl1271_tx_work(struct work_struct *work); | 142 | void wl1271_tx_work(struct work_struct *work); |
143 | void wl1271_tx_work_locked(struct wl1271 *wl); | ||
143 | void wl1271_tx_complete(struct wl1271 *wl); | 144 | void wl1271_tx_complete(struct wl1271 *wl); |
144 | void wl1271_tx_reset(struct wl1271 *wl); | 145 | void wl1271_tx_reset(struct wl1271 *wl); |
145 | void wl1271_tx_flush(struct wl1271 *wl); | 146 | void wl1271_tx_flush(struct wl1271 *wl); |
146 | u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate); | 147 | u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); |
147 | u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set); | 148 | u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set); |
148 | 149 | ||
149 | #endif | 150 | #endif |